Skip to content

Commit

Permalink
Add toString functions for type std
Browse files Browse the repository at this point in the history
  • Loading branch information
marcauberer committed Nov 19, 2023
1 parent 87e183a commit 94211e8
Show file tree
Hide file tree
Showing 28 changed files with 163 additions and 110 deletions.
8 changes: 5 additions & 3 deletions media/test-project/test.spice
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import "../../src-bootstrap/lexer/Reader.spice";
//import "../../src-bootstrap/reader/reader";
import "std/type/int";

f<int> main() {
Reader reader = Reader("./test.spice");

//Reader reader = Reader("./test.spice");
String str = toString(123);
printf("%s", str);
}
2 changes: 1 addition & 1 deletion src-bootstrap/reader/code-loc.spice
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ public f<String> CodeLoc.toString() {
* @return Pretty code location
*/
public f<String> CodeLoc.toPrettyString() {
String codeLocStr = String(intTy.toString(this.line));
String codeLocStr = String(toString(this.line));
if this.sourceFilePath.empty() {
return toString(line) + ":" + toString(this.col);
}
Expand Down
10 changes: 7 additions & 3 deletions src-bootstrap/reader/reader.spice
Original file line number Diff line number Diff line change
@@ -1,18 +1,22 @@
// Imports
import "std/io/filepath";
import "std/io/file";
import "std/type/result";
import "../reader/code-loc";

public type Reader struct {
FileInputStream file
File file
string filename
char curChar = '\0'
bool moreToRead = true
unsigned long line = 1l
unsigned long col = 0l
}

public p Reader.ctor(const string inputFileName) {
this.file = openFile(inputFileName, MODE_READ);
this.filename = inputFileName;
Result<File> result = openFile(inputFileName, MODE_READ);
this.file = result.unwrap();
if !file.isOpen() {

}
Expand All @@ -37,7 +41,7 @@ public f<char> Reader.getChar() {
* @return CodeLoc Code location
*/
public f<CodeLoc> Reader.getCodeLoc() {
return CodeLoc(this.cursorPos, this.line, this.col);
return CodeLoc(this.line, this.col, this.filename);
}

/**
Expand Down
1 change: 1 addition & 0 deletions src/SourceFile.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ void SourceFile::runLexer() {
// Create error handlers for lexer and parser
antlrCtx.lexerErrorHandler = std::make_unique<AntlrThrowingErrorListener>(ThrowingErrorListenerMode::LEXER, filePath);
antlrCtx.parserErrorHandler = std::make_unique<AntlrThrowingErrorListener>(ThrowingErrorListenerMode::PARSER, filePath);
std::ifstream test;

// Tokenize input
antlrCtx.inputStream = std::make_unique<antlr4::ANTLRInputStream>(fileInputStream);
Expand Down
2 changes: 1 addition & 1 deletion src/Spice.g4
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ structDef: topLevelDefAttr? specifierLst? TYPE TYPE_IDENTIFIER (LESS typeLst GRE
interfaceDef: specifierLst? TYPE TYPE_IDENTIFIER (LESS typeLst GREATER)? INTERFACE LBRACE signature+ RBRACE;
enumDef: specifierLst? TYPE TYPE_IDENTIFIER ENUM LBRACE enumItemLst RBRACE;
genericTypeDef: TYPE TYPE_IDENTIFIER typeAltsLst SEMICOLON;
aliasDef: TYPE TYPE_IDENTIFIER ALIAS dataType SEMICOLON;
aliasDef: specifierLst? TYPE TYPE_IDENTIFIER ALIAS dataType SEMICOLON;
globalVarDef: dataType TYPE_IDENTIFIER (ASSIGN constant)? SEMICOLON;
extDecl: topLevelDefAttr? EXT (F LESS dataType GREATER | P) (IDENTIFIER | TYPE_IDENTIFIER) LPAREN (typeLst ELLIPSIS?)? RPAREN SEMICOLON;

Expand Down
2 changes: 2 additions & 0 deletions src/ast/ASTNodes.h
Original file line number Diff line number Diff line change
Expand Up @@ -446,12 +446,14 @@ class AliasDefNode : public ASTNode {
std::any accept(ParallelizableASTVisitor *visitor) const override { return visitor->visitAliasDef(this); }

// Public get methods
[[nodiscard]] SpecifierLstNode *specifierLst() const { return getChild<SpecifierLstNode>(); }
[[nodiscard]] DataTypeNode *dataType() const { return getChild<DataTypeNode>(); }

// Public members
std::string aliasName;
std::string dataTypeString;
SymbolTableEntry *entry = nullptr;
TypeSpecifiers aliasSpecifiers = TypeSpecifiers::of(TY_ALIAS);
SymbolTableEntry *aliasedTypeContainerEntry = nullptr;
};

Expand Down
21 changes: 19 additions & 2 deletions src/irgenerator/OpRuleConversionManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -495,12 +495,20 @@ LLVMExprResult OpRuleConversionManager::getEqualInst(const ASTNode *node, LLVMEx
if (lhsSTy.isPtr() && rhsSTy.isPtr())
return {.value = builder.CreateICmpEQ(lhsV(), rhsV())};

// Check if one value is of type pointer and one is of type int
// Check if lhs is of type pointer and rhs is of type int
if (lhsT->isPointerTy() && rhsT->isIntegerTy(32)) {
llvm::Value *lhsInt = builder.CreatePtrToInt(lhsV(), rhsT);
return {.value = builder.CreateICmpEQ(lhsInt, rhsV())};
}

// Check if one value is a string and the other one is a char*
if ((lhsSTy.is(TY_STRING) && rhsSTy.isPtrOf(TY_CHAR)) || (lhsSTy.isPtrOf(TY_CHAR) && rhsSTy.is(TY_STRING))) {
// Generate call to the function isRawEqual(string, string) of the string std
llvm::Function *opFct = stdFunctionManager.getStringIsRawEqualStringStringFct();
llvm::Value *result = builder.CreateCall(opFct, {lhsV(), rhsV()});
return {.value = result};
}

// Check for primitive type combinations
switch (getTypeCombination(lhsSTy, rhsSTy)) {
case COMB(TY_DOUBLE, TY_DOUBLE):
Expand Down Expand Up @@ -620,12 +628,21 @@ LLVMExprResult OpRuleConversionManager::getNotEqualInst(const ASTNode *node, LLV
if (lhsSTy.isPtr() && rhsSTy.isPtr())
return {.value = builder.CreateICmpNE(lhsV(), rhsV())};

// Check if one value is of type pointer and one is of type int
// Check if lhs is of type pointer and rhs is of type int
if (lhsT->isPointerTy() && rhsT->isIntegerTy(32)) {
llvm::Value *lhsInt = builder.CreatePtrToInt(lhsV(), rhsT);
return {.value = builder.CreateICmpNE(lhsInt, rhsV())};
}

// Check if one value is a string and the other one is a char*
if ((lhsSTy.is(TY_STRING) && rhsSTy.isPtrOf(TY_CHAR)) || (lhsSTy.isPtrOf(TY_CHAR) && rhsSTy.is(TY_STRING))) {
// Generate call to the function isRawEqual(string, string) of the string std
llvm::Function *opFct = stdFunctionManager.getStringIsRawEqualStringStringFct();
llvm::Value *result = builder.CreateCall(opFct, {lhsV(), rhsV()});
// Negate the result
return {.value = builder.CreateNot(result)};
}

switch (getTypeCombination(lhsSTy, rhsSTy)) {
case COMB(TY_DOUBLE, TY_DOUBLE):
return {.value = builder.CreateFCmpONE(lhsV(), rhsV())};
Expand Down
10 changes: 10 additions & 0 deletions src/symboltablebuilder/SymbolTableBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -320,6 +320,16 @@ std::any SymbolTableBuilder::visitAliasDef(AliasDefNode *node) {
if (rootScope->lookupStrict(node->aliasName))
throw SemanticError(node, DUPLICATE_SYMBOL, "Duplicate symbol '" + node->aliasName + "'");

// Build alias specifiers
if (SpecifierLstNode *specifierLst = node->specifierLst(); specifierLst) {
for (const SpecifierNode *specifier : specifierLst->specifiers()) {
if (specifier->type == SpecifierNode::TY_PUBLIC)
node->aliasSpecifiers.isPublic = true;
else
throw SemanticError(specifier, SPECIFIER_AT_ILLEGAL_CONTEXT, "Cannot use this specifier on an alias definition");
}
}

// Add the alias to the symbol table
node->entry = rootScope->insert(node->aliasName, node);

Expand Down
8 changes: 8 additions & 0 deletions src/typechecker/OpRuleManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -294,6 +294,10 @@ ExprResult OpRuleManager::getEqualResultType(ASTNode *node, SymbolType lhs, Symb
if (lhs.isPtr() && rhs.is(TY_INT))
return ExprResult(SymbolType(TY_BOOL));

// Allow 'string == char*' and vice versa straight away
if ((lhs.is(TY_STRING) && rhs.isPtrOf(TY_CHAR)) || (lhs.isPtrOf(TY_CHAR) && rhs.is(TY_STRING)))
return ExprResult(SymbolType(TY_BOOL));

// Check primitive type combinations
return ExprResult(validateBinaryOperation(node, EQUAL_OP_RULES, ARRAY_LENGTH(EQUAL_OP_RULES), "==", lhs, rhs));
}
Expand All @@ -316,6 +320,10 @@ ExprResult OpRuleManager::getNotEqualResultType(ASTNode *node, SymbolType lhs, S
if (lhs.isPtr() && rhs.is(TY_INT))
return ExprResult(SymbolType(TY_BOOL));

// Allow 'string != char*' and vice versa straight away
if ((lhs.is(TY_STRING) && rhs.isPtrOf(TY_CHAR)) || (lhs.isPtrOf(TY_CHAR) && rhs.is(TY_STRING)))
return ExprResult(SymbolType(TY_BOOL));

// Check primitive type combinations
return ExprResult(validateBinaryOperation(node, NOT_EQUAL_OP_RULES, ARRAY_LENGTH(NOT_EQUAL_OP_RULES), "!=", lhs, rhs));
}
Expand Down
5 changes: 3 additions & 2 deletions src/typechecker/TypeCheckerPrepare.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -569,8 +569,9 @@ std::any TypeChecker::visitAliasDefPrepare(AliasDefNode *node) {
assert(node->entry != nullptr && node->aliasedTypeContainerEntry != nullptr);

// Update type of alias entry
const SymbolType symbolType(TY_ALIAS, node->dataTypeString);
node->entry->updateType(symbolType, false);
SymbolType aliasType(TY_ALIAS, node->dataTypeString);
aliasType.specifiers = node->aliasSpecifiers;
node->entry->updateType(aliasType, false);

// Update type of the aliased type container entry
auto aliasedType = std::any_cast<SymbolType>(visit(node->dataType()));
Expand Down
13 changes: 6 additions & 7 deletions std/io/file_linux.spice
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
import "std/type/result";
import "std/type/error";

// File open modes
public const string MODE_READ = "r";
public const string MODE_WRITE = "w";
Expand All @@ -20,9 +23,7 @@ const int SEEK_SET = 0;
const int SEEK_CUR = 1;
const int SEEK_END = 2;

public type FilePtr struct {
byte* ptr
}
public type FilePtr alias byte*;

public type File struct {
FilePtr* filePtr
Expand Down Expand Up @@ -57,11 +58,9 @@ public f<int> createFile(string path) {
*
* @return File pointer
*/
public f<File> openFile(string path, string mode) {
public f<Result<File>> openFile(string path, string mode) {
FilePtr* fp = fopen(path, mode);
// Insert check for pointer being 0 and throw an exception
File openedFile = File { fp };
return openedFile;
return fp != nil<FilePtr*> ? ok(fp) : err(fp, Error("Failed to open file '" + path + "'"));
}

/**
Expand Down
13 changes: 6 additions & 7 deletions std/io/file_windows.spice
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
import "std/type/result";
import "std/type/error";

// File open modes
public const string MODE_READ = "r";
public const string MODE_WRITE = "w";
Expand All @@ -20,9 +23,7 @@ const int SEEK_SET = 0;
const int SEEK_CUR = 1;
const int SEEK_END = 2;

public type FilePtr struct {
byte* ptr
}
public type FilePtr alias byte*;

public type File struct {
FilePtr* filePtr
Expand Down Expand Up @@ -57,11 +58,9 @@ public f<int> createFile(string path) {
*
* @return File pointer
*/
public f<File> openFile(string path, string mode) {
public f<Result<File>> openFile(string path, string mode) {
FilePtr* fp = fopen(path, mode);
// Insert check for pointer being 0 and throw an exception
File openedFile = File { fp };
return openedFile;
return fp != nil<FilePtr*> ? ok(fp) : err(fp, Error("Failed to open file '" + path + "'"));
}

/**
Expand Down
26 changes: 23 additions & 3 deletions std/runtime/string_rt.spice
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,23 @@ public p String.ctor(const String& value) {
}
}

public p String.ctor<IntLong>(IntLong initialSize) {
this.length = (unsigned long) initialSize;
this.capacity = initialSize > INITIAL_ALLOC_COUNT ? (unsigned long) initialSize * RESIZE_FACTOR : INITIAL_ALLOC_COUNT;

// Allocate space for the initial number of elements
unsafe {
unsigned long requiredBytes = this.capacity + 1l; // +1 because of null terminator
Result<heap byte*> allocResult = sAlloc(requiredBytes);
this.contents = (heap char*) allocResult.unwrap();
}

// Save initial value
unsafe {
this.contents[0] = '\0';
}
}

/**
* Appends the given string to the current one
*
Expand Down Expand Up @@ -529,7 +546,7 @@ public f<String> String.getSubstring<IntLongShort>(unsigned IntLongShort startId
*/
public p String.reserve<IntLongShort>(unsigned IntLongShort charCount) {
if charCount > this.capacity {
this.resize(charCount);
this.resize((unsigned long) charCount);
}
}

Expand All @@ -538,11 +555,11 @@ public p String.reserve<IntLongShort>(unsigned IntLongShort charCount) {
*
* @param newLength new length of the string after resizing
*/
p String.resize<IntLongShort>(unsigned IntLongShort newLength) {
p String.resize(unsigned long newLength) {
// Allocate the new memory
unsafe {
heap char* oldAddress = this.contents;
unsigned long requiredBytes = newLength + 1; // +1 because of null terminator
unsigned long requiredBytes = newLength + 1l; // +1 because of null terminator
Result<heap byte*> allocResult = sRealloc((heap byte*) oldAddress, requiredBytes);
this.contents = (heap char*) allocResult.unwrap();
}
Expand All @@ -559,6 +576,9 @@ p String.resize<IntLongShort>(unsigned IntLongShort newLength) {
* @return Length of the input string
*/
public f<unsigned long> getRawLength(string input) {
// Handle nullptr gracefully
if (char*) input == nil<char*> { return 0l; }
// Otherwise count the chars until the null terminator
result = 0l;
while input[result] != '\0' {
result++;
Expand Down
10 changes: 7 additions & 3 deletions std/type/byte.spice
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@ public const int SIZE = 8;
public const int MIN_VALUE = 0;
public const int MAX_VALUE = 255;

// External functions
ext f<unsigned int> snprintf(char*, unsigned long, string, byte);

// Converts a byte to a double
public f<double> toDouble(byte input) {
return 0.0 + ((int) input);
Expand All @@ -28,9 +31,10 @@ public f<char> toChar(byte input) {
}

// Converts a byte to a string
public f<string> toString(byte input) {
// ToDo: Impmenet
return "0";
public f<String> toString(byte input) {
const unsigned int length = snprintf(nil<char*>, 0l, "%hhu", input);
result = String(length);
snprintf((char*) result.getRaw(), length + 1l, "%hhu", input);
}

// Converts a byte to a bool
Expand Down
5 changes: 3 additions & 2 deletions std/type/char.spice
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,9 @@ public f<byte> toByte(char input) {
}

// Converts a char to a string
public f<string> toString(char input) {
return "0";
public f<String> toString(char input) {
result = String();
result += input;
}

// Converts a char to a bool
Expand Down
9 changes: 6 additions & 3 deletions std/type/double.spice
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ public const int SIZE = 64;
public const double MIN_VALUE = -1.7976931348623157e+308;
public const double MAX_VALUE = 1.7976931348623157e+308;

ext f<unsigned int> snprintf(char*, unsigned long, string, double);

// Converts a double to an int
public f<int> toInt(double input) {
return (int) input;
Expand All @@ -18,9 +20,10 @@ public f<long> toLong(double input) {
}

// Converts a double to a string
public f<string> toString(double input) {
// ToDo: Implement
return "";
public f<String> toString(double input) {
const unsigned int length = snprintf(nil<char*>, 0l, "%f", input);
result = String(length); // Assuming this length is enough
snprintf((char*) result.getRaw(), length + 1l, "%f", input);
}

// Converts a double to a boolean
Expand Down
20 changes: 6 additions & 14 deletions std/type/int.spice
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@ public const int SIZE = 32;
public const int MIN_VALUE = -2147483648;
public const int MAX_VALUE = 2147483647;

// External functions
ext f<unsigned int> snprintf(char*, unsigned long, string, int);

// Converts an int to a double
public f<double> toDouble(int input) {
return 0.0 + input;
Expand Down Expand Up @@ -29,20 +32,9 @@ public f<char> toChar(int input) {

// Converts an int to a string
public f<String> toString(const int input) {
if input == 0 { return String("0"); }

String str;
bool isNeg = input < 0;
unsigned int uInput = isNeg ? -input : input;

while (uInput != 0) {
str.append((char) (uInput % 10 + 48 /* ASCII for '0' */));
uInput = uInput / 10;
}
if isNeg { str.append('-'); }

str.reverse();
return str;
const unsigned int length = snprintf(nil<char*>, 0l, "%d", input);
result = String(length);
snprintf((char*) result.getRaw(), length + 1l, "%d", input);
}

// Converts an int to a boolean
Expand Down
Loading

0 comments on commit 94211e8

Please sign in to comment.