Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make Result<T> type builtin #498

Merged
merged 3 commits into from Mar 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion .run/spicetest.run.xml
@@ -1,5 +1,5 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="spicetest" type="CMakeGoogleTestRunConfigurationType" factoryName="Google Test" PROGRAM_PARAMS="--update-refs=false" REDIRECT_INPUT="false" ELEVATE="false" USE_EXTERNAL_CONSOLE="false" EMULATE_TERMINAL="false" PASS_PARENT_ENVS_2="true" PROJECT_NAME="Spice" TARGET_NAME="spicetest" CONFIG_NAME="Debug" RUN_TARGET_PROJECT_NAME="Spice" RUN_TARGET_NAME="spicetest" TEST_MODE="SUITE_TEST">
<configuration default="false" name="spicetest" type="CMakeGoogleTestRunConfigurationType" factoryName="Google Test" PROGRAM_PARAMS="--update-refs=false" REDIRECT_INPUT="false" ELEVATE="false" USE_EXTERNAL_CONSOLE="false" EMULATE_TERMINAL="false" PASS_PARENT_ENVS_2="true" PROJECT_NAME="Spice" TARGET_NAME="spicetest" CONFIG_NAME="Debug" RUN_TARGET_PROJECT_NAME="Spice" RUN_TARGET_NAME="spicetest" TEST_CLASS="BootstrapCompilerTests" TEST_MODE="SUITE_TEST">
<envs>
<env name="LLVM_BUILD_INCLUDE_DIR" value="D:/LLVM/build-release/include" />
<env name="LLVM_INCLUDE_DIR" value="D:/LLVM/llvm/include" />
Expand Down
101 changes: 74 additions & 27 deletions docs/docs/language/builtin-types.md
Expand Up @@ -19,50 +19,97 @@ The `String` builtin type offers the following constructors:
- `void String()`: Initialize empty
- `void String(string)`: Initialize with a raw `string` as start value
- `void String(char)`: Initialize with a single char
- `void String(String)`: Initialize by copying another `String` (copy constructor)
- `void String(const String&)`: Initialize by copying another `String` (copy constructor)
- `void String(int)`: Initialize with an initial size
- `void String(long)`: Initialize with an initial size

### Methods
The `String` builtin type offers the following methods:

- `void append(string)`: Appends a raw string
- `void append(String)`: Appends a string
- `void append(const String&)`: Appends a string
- `void append(char)`: Appends a single char
- `char* getRaw()`: Returns a char* to the heap allocated value
- `long getLength()`: Returns the length of the string in chars
- `string getRaw()`: Returns a char* to the heap allocated value
- `unsigned long getLength()`: Returns the length of the string in chars
- `bool isEmpty()`: Checks if the string has a length of 0
- `long getCapacity()`: Returns the allocated space in bytes
- `unsigned long getCapacity()`: Returns the allocated space in bytes
- `bool isFull()`: Checks if the length is equal with the capacity
- `void clear()`: Clear the value of the string
- `long find(string, int)`: Returns the index, where a substring was found, starting from a start index
- `long find(string, long)`: Returns the index, where a substring was found, starting from a start index
- `long find(string, short)`: Returns the index, where a substring was found, starting from a start index
- `long find(string, unsigned int)`: Returns the index, where a substring was found, starting from a start index
- `long find(string, unsigned long)`: Returns the index, where a substring was found, starting from a start index
- `long find(char, unsigned long)`: Returns the index, where a subchar was found, starting from a start index
- `long rfind(string, unsigned int)`: Returns the index, where a substring was found, starting from reversed at a start index
- `long rfind(string, unsigned long)`: Returns the index, where a substring was found, starting from reversed at a start index
- `long rfind(char, unsigned long)`: Returns the index, where a subchar was found, starting from reversed at a start index
- `bool contains(string)`: Checks if the string contains a substring
- `bool startsWith(string)`: Checks if the string starts with a substring
- `bool endsWith(string)`: Checks if the string ends with a substring
- `void reverse()`: Reverses the value of the string
- `String substring(int, long)`: Returns the substring from start index `x` and length `y`
- `String substring(long, long)`: Returns the substring from start index `x` and length `y`
- `String substring(short, long)`: Returns the substring from start index `x` and length `y`
- `void reserve(int)`: Increase the capacity to the given number
- `void reserve(long)`: Increase the capacity to the given number
- `void reserve(short)`: Increase the capacity to the given number
- `void replace(string, string, unsigned long)`: Replaces a substring with another string, starting from a start index
- `void replaceAll(string, string)`: Replaces all occurrences of a substring with another string
- `void replaceAll(char, char)`: Replaces all occurrences of a subchar with another char
- `String getSubstring(unsigned int, long)`: Returns the substring from start index `x` and length `y`
- `String getSubstring(unsigned long, long)`: Returns the substring from start index `x` and length `y`
- `String getSubstring(unsigned short, long)`: Returns the substring from start index `x` and length `y`
- `void reserve(unsigned int)`: Increase the capacity to the given number
- `void reserve(unsigned long)`: Increase the capacity to the given number
- `void reserve(unsigned short)`: Increase the capacity to the given number

### Static functions
The `String` builtin type offers the following static functions:

- `getRawLength(string)`: Returns the length of a raw string
- `isRawEqual(string, string)`: Checks if two raw strings are equal in value

### Operators
The `String` builtin type overrides the following operators:

- `String operator+(String, String)`: Concatenates two strings and returns the result
- `String operator+(String, string)`: Concatenates a string and a raw string and returns the result
- `String operator+(string, String)`: Concatenates a raw string and a string and returns the result
- `String operator+(string, string)`: Concatenates two raw strings and returns the result
- `String operator+(const String&, const String&)`: Concatenates two strings and returns the result
- `String operator+(const String&, const string&)`: Concatenates a string and a raw string and returns the result
- `String operator+(const String&, const char&)`: Concatenates a string and a raw string and returns the result
- `String operator+(const string&, const String&)`: Concatenates a raw string and a string and returns the result
- `String operator+(const string&, const string&)`: Concatenates two raw strings and returns the result
- `String operator+(const string&, const char&)`: Concatenates two raw strings and returns the result
- `void operator+=(String&, String)`: Appends a string
- `void operator+=(String&, string)`: Appends a raw string
- `void operator+=(String&, string)`: Appends a single char
- `String operator*(String, int)`: Concatenates a string with itself n times
- `String operator*(String, long)`: Concatenates a string with itself n times
- `String operator*(String, short)`: Concatenates a string with itself n times
- `String operator*(int, String)`: Concatenates a string with itself n times
- `String operator*(long, String)`: Concatenates a string with itself n times
- `String operator*(short, String)`: Concatenates a string with itself n times
- `void operator+=(String&, char)`: Appends a single char
- `String operator*(const String&, int)`: Concatenates a string with itself n times
- `String operator*(const String&, long)`: Concatenates a string with itself n times
- `String operator*(const String&, short)`: Concatenates a string with itself n times
- `String operator*(int, const String&)`: Concatenates a string with itself n times
- `String operator*(long, const String&)`: Concatenates a string with itself n times
- `String operator*(short, const String&)`: Concatenates a string with itself n times
- `void operator*=(String&, int)`: Concatenates with itself n times
- `void operator*=(String&, long)`: Concatenates with itself n times
- `void operator*=(String&, short)`: Concatenates with itself n times
- `bool operator==(String, String)`: Checks if two strings are equal in value
- `bool operator!=(String, String)`: Checks if two strings are unequal in value
- `bool operator==(const String&, const String&)`: Checks if two strings are equal in value
- `bool operator==(const String&, string)`: Checks if two strings are equal in value
- `bool operator==(string, const String&)`: Checks if two strings are equal in value
- `bool operator!=(const String&, const String&)`: Checks if two strings are unequal in value
- `bool operator!=(const String&, string)`: Checks if two strings are unequal in value
- `bool operator!=(string, const String&)`: Checks if two strings are unequal in value

## The `Result` data type
The `Result<T>` builtin type is a generic type, which is used to return a value or an error. It is used to handle errors

### Constructors
The `Result<T>` builtin type offers the following constructors:

- `void Result(const T&)`: Initialize Result object with a value
- `void Result(const Error&)`: Initialize Result object with an error

### Methods
The `Result<T>` builtin type offers the following methods:

- `T unwrap()`: Returns the value of the Result object. If the Result object contains an error, the program will panic
- `Error getErr()`: Returns the error of the Result object. If no error is present, an error object with error code 0 is returned.
- `bool isOk()`: Checks if the Result object contains a value
- `bool isErr()`: Checks if the Result object contains an error

### Static functions
The `Result<T>` builtin type offers the following static functions:

- `Result<T> ok(const T&)`: Returns a Result object with a value
- `Result<T> err(const Error&)`: Returns a Result object with an error
- `Result<T> err(int, string)`: Returns a Result object with an error, constructed with an error code and an error message
- `Result<T> err(string)`: Returns a Result object with an error, constructed with an error message
2 changes: 1 addition & 1 deletion docs/requirements.txt
@@ -1,5 +1,5 @@
mkdocs-material==9.5.13
mkdocs-material[imaging]==9.5.12
mkdocs-material[imaging]==9.5.13
mkdocs-minify-plugin==0.8.0
mkdocs-git-revision-date-localized-plugin==1.2.4
mkdocs-git-committers-plugin-2==2.3.0
Expand Down
8 changes: 6 additions & 2 deletions src-bootstrap/global/runtime-module-manager.spice
@@ -1,12 +1,14 @@

const string STRING_RT_IMPORT_NAME = "__rt_string";
const string RESULT_RT_IMPORT_NAME = "__rt_result";
const string MEMORY_RT_IMPORT_NAME = "__rt_memory";
const string RTTI_RT_IMPORT_NAME = "__rt_rtti";

public type RuntimeModule enum {
STRING_RT = 1,
ARRAY_RT = 2,
OBJECT_RT = 4
RESULT_RT = 2,
ARRAY_RT = 4,
OBJECT_RT = 8
}

type ModuleNamePair struct {
Expand Down Expand Up @@ -73,6 +75,8 @@ public f<ModuleNamePair> RuntimeModuleManager.resolveNamePair(RuntimeModule requ
switch requestedModule {
case RuntimeModule::STRING_RT:
return ModuleNamePair{STRING_RT_IMPORT_NAME, "string_rt"};
case RuntimeModule::RESULT_RT:
return ModuleNamePair{RESULT_RT_IMPORT_NAME, "result_rt"};
case RuntimeModule::ARRAY_RT:
return ModuleNamePair{MEMORY_RT_IMPORT_NAME, "memory_rt"};
case RuntimeModule::OBJECT_RT:
Expand Down
1 change: 0 additions & 1 deletion src-bootstrap/reader/reader.spice
@@ -1,7 +1,6 @@
// Std imports
import "std/io/filepath";
import "std/io/file";
import "std/type/result";
import "std/type/error";
import "std/os/os";

Expand Down
2 changes: 1 addition & 1 deletion src/ast/ASTBuilder.cpp
Expand Up @@ -1502,7 +1502,7 @@ std::string ASTBuilder::getIdentifier(TerminalNode *terminal) {
std::string identifier = terminal->getText();

// Check if the identifier is 'String' and this is no std source file
bool isReserved = identifier == STROBJ_NAME && !sourceFile->stdFile;
bool isReserved = !sourceFile->stdFile && (identifier == STROBJ_NAME || identifier == RESULTOBJ_NAME);
// Check if the list of reserved keywords contains the given identifier
isReserved |= std::find(std::begin(RESERVED_KEYWORDS), std::end(RESERVED_KEYWORDS), identifier) != std::end(RESERVED_KEYWORDS);
// Print error message
Expand Down
2 changes: 2 additions & 0 deletions src/global/RuntimeModuleManager.cpp
Expand Up @@ -59,6 +59,8 @@ ModuleNamePair RuntimeModuleManager::resolveNamePair(RuntimeModule runtimeModule
switch (runtimeModule) {
case STRING_RT:
return {STRING_RT_IMPORT_NAME, "string_rt"};
case RESULT_RT:
return {RESULT_RT_IMPORT_NAME, "result_rt"};
case MEMORY_RT:
return {MEMORY_RT_IMPORT_NAME, "memory_rt"};
case RTTI_RT:
Expand Down
27 changes: 20 additions & 7 deletions src/global/RuntimeModuleManager.h
Expand Up @@ -15,29 +15,42 @@ class SourceFile;
class Scope;

const char *const STRING_RT_IMPORT_NAME = "__rt_string";
const char *const RESULT_RT_IMPORT_NAME = "__rt_result";
const char *const MEMORY_RT_IMPORT_NAME = "__rt_memory";
const char *const RTTI_RT_IMPORT_NAME = "__rt_rtti";

enum RuntimeModule : uint8_t {
STRING_RT = 1 << 0,
MEMORY_RT = 1 << 1,
RTTI_RT = 1 << 2,
RESULT_RT = 1 << 1,
MEMORY_RT = 1 << 2,
RTTI_RT = 1 << 3,
};

const std::unordered_map<const char *, RuntimeModule> TYPE_NAME_TO_RT_MODULE_MAPPING = {
{STROBJ_NAME, STRING_RT},
{RESULTOBJ_NAME, RESULT_RT},
};

const std::unordered_map<const char *, RuntimeModule> FCT_NAME_TO_RT_MODULE_MAPPING = {
{"sAlloc", MEMORY_RT}, {"sRealloc", MEMORY_RT}, {"sCopy", MEMORY_RT}, {"sDealloc", MEMORY_RT},
{"sNew", MEMORY_RT}, {"sPlacementNew", MEMORY_RT}, {"sDelete", MEMORY_RT},
// Memory RT
{"sAlloc", MEMORY_RT},
{"sRealloc", MEMORY_RT},
{"sCopy", MEMORY_RT},
{"sDealloc", MEMORY_RT},
{"sNew", MEMORY_RT},
{"sPlacementNew", MEMORY_RT},
{"sDelete", MEMORY_RT},
// Result RT
{"ok", RESULT_RT},
{"err", RESULT_RT},
};

// This serves for the compiler to detect if a source file is a specific runtime module
const std::unordered_map<RuntimeModule, const char *> IDENTIFYING_TOP_LEVEL_NAMES = {
{STRING_RT, STROBJ_NAME}, // String struct
{MEMORY_RT, "sAlloc"}, // sAlloc function
{RTTI_RT, TIOBJ_NAME}, // TypeInfo struct
{STRING_RT, STROBJ_NAME}, // String struct
{RESULT_RT, RESULTOBJ_NAME}, // Result struct
{MEMORY_RT, "sAlloc"}, // sAlloc function
{RTTI_RT, TIOBJ_NAME}, // TypeInfo struct
};

struct ModuleNamePair {
Expand Down
1 change: 1 addition & 0 deletions src/symboltablebuilder/SymbolType.h
Expand Up @@ -24,6 +24,7 @@ class Interface;

// Constants
const char *const STROBJ_NAME = "String";
const char *const RESULTOBJ_NAME = "Result";
const char *const ERROBJ_NAME = "Error";
const char *const TIOBJ_NAME = "TypeInfo";
const char *const IITERATOR_NAME = "IIterator";
Expand Down
1 change: 0 additions & 1 deletion std/data/doubly-linked-list.spice
@@ -1,4 +1,3 @@
import "std/type/result";
import "std/type/error";

// Add generic type definitions
Expand Down
1 change: 0 additions & 1 deletion std/data/hash-table.spice
@@ -1,6 +1,5 @@
import "std/data/vector";
import "std/data/linked-list";
import "std/type/result";
import "std/type/error";
import "std/math/hash";

Expand Down
1 change: 0 additions & 1 deletion std/data/linked-list.spice
@@ -1,4 +1,3 @@
import "std/type/result";
import "std/type/error";
import "std/iterator/iterable";
import "std/iterator/iterator";
Expand Down
1 change: 0 additions & 1 deletion std/data/map.spice
@@ -1,5 +1,4 @@
import "std/data/red-black-tree";
import "std/type/result";

// Add generic type definitions
type K dyn;
Expand Down
1 change: 0 additions & 1 deletion std/data/queue.spice
@@ -1,4 +1,3 @@
import "std/type/result";
import "std/type/error";

// Constants
Expand Down
1 change: 0 additions & 1 deletion std/data/red-black-tree.spice
@@ -1,4 +1,3 @@
import "std/type/result";
import "std/type/error";

// Add generic type definitions
Expand Down
1 change: 0 additions & 1 deletion std/data/stack.spice
@@ -1,4 +1,3 @@
import "std/type/result";
import "std/type/error";

// Constants
Expand Down
1 change: 0 additions & 1 deletion std/data/unordered-map.spice
@@ -1,5 +1,4 @@
import "std/data/hash-table";
import "std/type/result";

// Add generic type definitions
type K dyn;
Expand Down
1 change: 0 additions & 1 deletion std/data/vector.spice
@@ -1,4 +1,3 @@
import "std/type/result";
import "std/type/error";
import "std/iterator/iterable";
import "std/iterator/iterator";
Expand Down
1 change: 0 additions & 1 deletion std/io/file.spice
@@ -1,4 +1,3 @@
import "std/type/result";
import "std/type/error";

// File open modes
Expand Down
2 changes: 0 additions & 2 deletions std/runtime/memory_rt.spice
@@ -1,7 +1,5 @@
#![core.compiler.alwaysKeepOnNameCollision = true]

import "std/type/result";

// Link external functions
ext f<heap byte*> malloc(unsigned long);
ext f<heap byte*> realloc(heap byte*, unsigned long);
Expand Down
2 changes: 2 additions & 0 deletions std/type/result.spice → std/runtime/result_rt.spice
@@ -1,3 +1,5 @@
#![core.compiler.alwaysKeepOnNameCollision = true]

import "std/type/error";

// Generic types
Expand Down
26 changes: 13 additions & 13 deletions std/runtime/string_rt.spice
Expand Up @@ -251,11 +251,11 @@ public f<bool> operator==(const String& a, const String& b) {
return true;
}

public f<bool> operator==(const String& a, const string& b) {
public f<bool> operator==(const String& a, string b) {
return isRawEqual(a.getRaw(), b);
}

public f<bool> operator==(const string& a, const String& b) {
public f<bool> operator==(string a, const String& b) {
return isRawEqual(a, b.getRaw());
}

Expand Down Expand Up @@ -294,7 +294,7 @@ public inline f<string> String.getRaw() {
*
* @return Current length of the string
*/
public inline f<long> String.getLength() {
public inline f<unsigned long> String.getLength() {
return this.length;
}

Expand All @@ -310,7 +310,7 @@ public inline f<bool> String.isEmpty() {
*
* @return Current capacity of the string
*/
public inline f<long> String.getCapacity() {
public inline f<unsigned long> String.getCapacity() {
return this.capacity;
}

Expand Down Expand Up @@ -417,24 +417,24 @@ public f<long> String.rfind(string needle, unsigned long startIndex = 0l) {
}

/**
* Searches for a subchar in a string from the back. Returns -1 if the char was not found.
* Searches for a substring in a string from the back. Returns -1 if the string was not found.
*
* @param startIndex Index where to start the search
* @return Index, where the subchar was found / -1
* @return Index, where the substring was found / -1
*/
public f<long> String.rfind(char needle, unsigned long startIndex = 0l) {
const String needleStr = String(needle);
return this.rfind(needleStr.getRaw(), startIndex);
public f<long> String.rfind(string needle, unsigned int startIndex) {
return this.rfind(needle, (unsigned long) startIndex);
}

/**
* Searches for a substring in a string from the back. Returns -1 if the string was not found.
* Searches for a subchar in a string from the back. Returns -1 if the char was not found.
*
* @param startIndex Index where to start the search
* @return Index, where the substring was found / -1
* @return Index, where the subchar was found / -1
*/
public f<long> String.rfind(string needle, unsigned int startIndex) {
return this.rfind(needle, (unsigned long) startIndex);
public f<long> String.rfind(char needle, unsigned long startIndex = 0l) {
const String needleStr = String(needle);
return this.rfind(needleStr.getRaw(), startIndex);
}

/**
Expand Down