Skip to content

Commit

Permalink
Make Result<T> type builtin (#498)
Browse files Browse the repository at this point in the history
  • Loading branch information
marcauberer committed Mar 17, 2024
1 parent d4177e8 commit 2ae1c28
Show file tree
Hide file tree
Showing 27 changed files with 417 additions and 369 deletions.
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

0 comments on commit 2ae1c28

Please sign in to comment.