Skip to content

Commit

Permalink
Add internal string objects (#198)
Browse files Browse the repository at this point in the history
* Allow long type as array index

* Add test for string object

* Extend time std

* Extend string runtime std

* Add opNotEquals operator
  • Loading branch information
marcauberer authored Sep 2, 2022
1 parent 6f9191e commit 41e267a
Show file tree
Hide file tree
Showing 123 changed files with 669 additions and 271 deletions.
2 changes: 1 addition & 1 deletion .github/dependabot.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ updates:
assignees:
- spicelang/compiler-team

# Github Actions
# GitHub Actions
- package-ecosystem: github-actions
directory: /
schedule:
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ jobs:
- name: Set up Go
uses: actions/setup-go@v3
with:
go-version: 1.18
go-version: 1.19

- name: Restore Go modules cache
uses: actions/cache@v3
Expand Down Expand Up @@ -222,7 +222,7 @@ jobs:
- name: Run GoReleaser
uses: goreleaser/goreleaser-action@v3
with:
version: v1.10.3
version: v1.11.2
args: release --rm-dist
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
Expand Down
2 changes: 1 addition & 1 deletion .run/Spice_run.run.xml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="Spice_run" type="CMakeRunConfiguration" factoryName="Application" PROGRAM_PARAMS="run -O2 ../../src-bootstrap/main.spice" REDIRECT_INPUT="false" ELEVATE="false" USE_EXTERNAL_CONSOLE="false" PASS_PARENT_ENVS_2="true" PROJECT_NAME="Spice" TARGET_NAME="Spice_run" CONFIG_NAME="Debug" RUN_TARGET_PROJECT_NAME="Spice" RUN_TARGET_NAME="Spice_run">
<configuration default="false" name="Spice_run" type="CMakeRunConfiguration" factoryName="Application" PROGRAM_PARAMS="run -O2 ../../media/test-project/os-test.spice" REDIRECT_INPUT="false" ELEVATE="false" USE_EXTERNAL_CONSOLE="false" PASS_PARENT_ENVS_2="true" PROJECT_NAME="Spice" TARGET_NAME="Spice_run" CONFIG_NAME="Debug" RUN_TARGET_PROJECT_NAME="Spice" RUN_TARGET_NAME="Spice_run">
<envs>
<env name="RUN_TESTS" value="OFF" />
<env name="SPICE_STD_DIR" value="$PROJECT_DIR$/std" />
Expand Down
11 changes: 10 additions & 1 deletion media/test-project/os-test.spice
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,18 @@ f<int> main() {
printf("Hello %s!", p1.getSecond());
}*/

import "std/net/http" as http;
/*import "std/net/http" as http;

f<int> main() {
http::HttpServer server = http::HttpServer();
server.serve("/test", "Hello World!");
}*/

import "std/runtime/string_rt" as _rt_str;

f<int> main() {
_rt_str::String s1 = _rt_str::String('H');
s1.append("ello");

printf("Equals: %d", s1.opEquals("Hell2"));
}
2 changes: 1 addition & 1 deletion src-bootstrap/exception/SemanticError.spice
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ public type ErrorType enum {
NUMBER_OF_FIELDS_NOT_MATCHING,
FIELD_TYPE_NOT_MATCHING,
ARRAY_SIZE_INVALID,
ARRAY_INDEX_NO_INTEGER,
ARRAY_INDEX_NOT_INT_OR_LONG,
ARRAY_ITEM_TYPE_NOT_MATCHING,
EXPECTED_ARRAY_TYPE,
SIZEOF_DYNAMIC_SIZED_ARRAY,
Expand Down
11 changes: 6 additions & 5 deletions src/analyzer/AnalyzerVisitor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -901,7 +901,7 @@ std::any AnalyzerVisitor::visitForeachLoop(ForeachLoopNode *node) {

// Check if index type is int
if (!indexType.is(TY_INT))
throw SemanticError(node->idxVarDecl()->codeLoc, ARRAY_INDEX_NO_INTEGER,
throw SemanticError(node->idxVarDecl()->codeLoc, ARRAY_INDEX_NOT_INT_OR_LONG,
"Index in foreach loop must be of type int. You provided " + indexType.getName(false));
} else {
// Declare the variable with the default index variable name
Expand Down Expand Up @@ -1657,8 +1657,8 @@ std::any AnalyzerVisitor::visitPostfixUnaryExpr(PostfixUnaryExprNode *node) {
AssignExprNode *indexExpr = node->assignExpr()[subscriptCounter++];
auto indexType = any_cast<SymbolType>(visit(indexExpr));

if (!indexType.is(TY_INT))
throw SemanticError(node->codeLoc, ARRAY_INDEX_NO_INTEGER, "Array index must be of type int");
if (!indexType.isOneOf({TY_INT, TY_LONG}))
throw SemanticError(node->codeLoc, ARRAY_INDEX_NOT_INT_OR_LONG, "Array index must be of type int or long");
if (!lhs.isOneOf({TY_ARRAY, TY_STRING, TY_PTR}))
throw SemanticError(node->codeLoc, OPERATOR_WRONG_DATA_TYPE,
"Can only apply subscript operator on array type, got " + lhs.getName(true));
Expand Down Expand Up @@ -2070,8 +2070,9 @@ std::any AnalyzerVisitor::visitArrayInitialization(ArrayInitializationNode *node
if (actualItemType.is(TY_DYN)) { // Not enough info to perform type inference, because of empty array {}
if (expectedType.is(TY_DYN))
throw SemanticError(node->codeLoc, UNEXPECTED_DYN_TYPE_SA, "Not enough information to perform type inference");
if (expectedType.is(TY_DYN))
throw SemanticError(node->codeLoc, ARRAY_ITEM_TYPE_NOT_MATCHING, "Cannot assign an array to a primitive data type");
if (!expectedType.isArray())
throw SemanticError(node->codeLoc, ARRAY_ITEM_TYPE_NOT_MATCHING,
"Cannot initialize array for type " + expectedType.getName() + "");
actualItemType = expectedType.getContainedTy();
}

Expand Down
4 changes: 2 additions & 2 deletions src/exception/SemanticError.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -108,8 +108,8 @@ std::string SemanticError::getMessagePrefix(SemanticErrorType type) {
return "The type of a field value does not match the declaration";
case ARRAY_SIZE_INVALID:
return "Array size invalid";
case ARRAY_INDEX_NO_INTEGER:
return "Array index not of type int";
case ARRAY_INDEX_NOT_INT_OR_LONG:
return "Array index not of type int or long";
case ARRAY_ITEM_TYPE_NOT_MATCHING:
return "Array item type not matching";
case EXPECTED_ARRAY_TYPE:
Expand Down
2 changes: 1 addition & 1 deletion src/exception/SemanticError.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ enum SemanticErrorType {
NUMBER_OF_FIELDS_NOT_MATCHING,
FIELD_TYPE_NOT_MATCHING,
ARRAY_SIZE_INVALID,
ARRAY_INDEX_NO_INTEGER,
ARRAY_INDEX_NOT_INT_OR_LONG,
ARRAY_ITEM_TYPE_NOT_MATCHING,
EXPECTED_ARRAY_TYPE,
SIZEOF_DYNAMIC_SIZED_ARRAY,
Expand Down
32 changes: 16 additions & 16 deletions src/generator/OpRuleConversionsManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ llvm::Value *OpRuleConversionsManager::getPlusEqualInst(llvm::Value *lhs, llvm::
// ToDo(@marcauberer): Insert call to appendChar in the runtime lib
throw IRError(codeLoc, COMING_SOON_IR, "The compiler does not support the '+=' operator for lhs=string and rhs=char yet");
case COMB(TY_STRING, TY_STRING):
// ToDo(@marcauberer): Insert call to concatStrings in the runtime lib
// ToDo(@marcauberer): Insert call to append in the runtime lib
throw IRError(codeLoc, COMING_SOON_IR, "The compiler does not support the '+=' operator for lhs=string and rhs=string yet");
case COMB(TY_PTR, TY_INT): // fallthrough
case COMB(TY_PTR, TY_SHORT): // fallthrough
Expand Down Expand Up @@ -466,7 +466,7 @@ llvm::Value *OpRuleConversionsManager::getEqualInst(llvm::Value *lhs, llvm::Valu
case COMB(TY_CHAR, TY_CHAR):
return builder->CreateICmpEQ(lhs, rhs);
case COMB(TY_STRING, TY_STRING):
// ToDo(@marcauberer): Insert call to concatStrings in the runtime lib
// ToDo(@marcauberer): Insert call to opEquals in the runtime lib
throw IRError(codeLoc, COMING_SOON_IR, "The compiler does not support the '==' operator for lhs=string and rhs=string yet");
case COMB(TY_BOOL, TY_BOOL):
return builder->CreateICmpEQ(lhs, rhs);
Expand Down Expand Up @@ -571,7 +571,7 @@ llvm::Value *OpRuleConversionsManager::getNotEqualInst(llvm::Value *lhs, llvm::V
case COMB(TY_CHAR, TY_CHAR):
return builder->CreateICmpNE(lhs, rhs);
case COMB(TY_STRING, TY_STRING):
// ToDo(@marcauberer): Insert call to concatStrings in the runtime lib
// ToDo(@marcauberer): Insert call to opNotEquals in the runtime lib
throw IRError(codeLoc, COMING_SOON_IR, "The compiler does not support the '!=' operator for lhs=string and rhs=string yet");
case COMB(TY_BOOL, TY_BOOL):
return builder->CreateICmpNE(lhs, rhs);
Expand Down Expand Up @@ -944,7 +944,7 @@ llvm::Value *OpRuleConversionsManager::getPlusInst(llvm::Value *lhs, llvm::Value
case COMB(TY_CHAR, TY_CHAR):
return builder->CreateAdd(lhs, rhs);
case COMB(TY_STRING, TY_STRING):
// ToDo(@marcauberer): Insert call to concatStrings in the runtime lib
// ToDo(@marcauberer): Insert call to append in the runtime lib
throw IRError(codeLoc, COMING_SOON_IR, "The compiler does not support the '+' operator for lhs=string and rhs=string yet");
case COMB(TY_PTR, TY_INT): // fallthrough
case COMB(TY_PTR, TY_SHORT): // fallthrough
Expand Down Expand Up @@ -1054,11 +1054,11 @@ llvm::Value *OpRuleConversionsManager::getMulInst(llvm::Value *lhs, llvm::Value
return builder->CreateMul(lhsLong, rhs);
}
case COMB(TY_INT, TY_CHAR): {
// ToDo(@marcauberer): Insert call to concatStrings in the runtime lib
// ToDo(@marcauberer): Insert call to opMul in the runtime lib
throw IRError(codeLoc, COMING_SOON_IR, "The compiler does not support the '*' operator for lhs=int and rhs=char yet");
}
case COMB(TY_INT, TY_STRING): {
// ToDo(@marcauberer): Insert call to concatStrings in the runtime lib
// ToDo(@marcauberer): Insert call to opMul in the runtime lib
throw IRError(codeLoc, COMING_SOON_IR, "The compiler does not support the '*' operator for lhs=int and rhs=string yet");
}
case COMB(TY_SHORT, TY_DOUBLE): {
Expand All @@ -1076,11 +1076,11 @@ llvm::Value *OpRuleConversionsManager::getMulInst(llvm::Value *lhs, llvm::Value
return builder->CreateMul(lhsLong, rhs);
}
case COMB(TY_SHORT, TY_CHAR): {
// ToDo(@marcauberer): Insert call to concatStrings in the runtime lib
// ToDo(@marcauberer): Insert call to opMul in the runtime lib
throw IRError(codeLoc, COMING_SOON_IR, "The compiler does not support the '*' operator for lhs=short and rhs=char yet");
}
case COMB(TY_SHORT, TY_STRING): {
// ToDo(@marcauberer): Insert call to concatStrings in the runtime lib
// ToDo(@marcauberer): Insert call to opMul in the runtime lib
throw IRError(codeLoc, COMING_SOON_IR, "The compiler does not support the '*' operator for lhs=short and rhs=string yet");
}
case COMB(TY_LONG, TY_DOUBLE): {
Expand All @@ -1095,37 +1095,37 @@ llvm::Value *OpRuleConversionsManager::getMulInst(llvm::Value *lhs, llvm::Value
case COMB(TY_LONG, TY_LONG):
return builder->CreateMul(lhs, rhs);
case COMB(TY_LONG, TY_CHAR): {
// ToDo(@marcauberer): Insert call to concatStrings in the runtime lib
// ToDo(@marcauberer): Insert call to opMul in the runtime lib
throw IRError(codeLoc, COMING_SOON_IR, "The compiler does not support the '*' operator for lhs=long and rhs=char yet");
}
case COMB(TY_LONG, TY_STRING): {
// ToDo(@marcauberer): Insert call to concatStrings in the runtime lib
// ToDo(@marcauberer): Insert call to opMul in the runtime lib
throw IRError(codeLoc, COMING_SOON_IR, "The compiler does not support the '*' operator for lhs=long and rhs=string yet");
}
case COMB(TY_BYTE, TY_BYTE):
return builder->CreateMul(lhs, rhs);
case COMB(TY_CHAR, TY_INT): {
// ToDo(@marcauberer): Insert call to concatStrings in the runtime lib
// ToDo(@marcauberer): Insert call to opMul in the runtime lib
throw IRError(codeLoc, COMING_SOON_IR, "The compiler does not support the '*' operator for lhs=char and rhs=int yet");
}
case COMB(TY_CHAR, TY_SHORT): {
// ToDo(@marcauberer): Insert call to concatStrings in the runtime lib
// ToDo(@marcauberer): Insert call to opMul in the runtime lib
throw IRError(codeLoc, COMING_SOON_IR, "The compiler does not support the '*' operator for lhs=char and rhs=short yet");
}
case COMB(TY_CHAR, TY_LONG): {
// ToDo(@marcauberer): Insert call to concatStrings in the runtime lib
// ToDo(@marcauberer): Insert call to opMul in the runtime lib
throw IRError(codeLoc, COMING_SOON_IR, "The compiler does not support the '*' operator for lhs=char and rhs=long yet");
}
case COMB(TY_STRING, TY_INT): {
// ToDo(@marcauberer): Insert call to concatStrings in the runtime lib
// ToDo(@marcauberer): Insert call to opMul in the runtime lib
throw IRError(codeLoc, COMING_SOON_IR, "The compiler does not support the '*' operator for lhs=string and rhs=int yet");
}
case COMB(TY_STRING, TY_SHORT): {
// ToDo(@marcauberer): Insert call to concatStrings in the runtime lib
// ToDo(@marcauberer): Insert call to opMul in the runtime lib
throw IRError(codeLoc, COMING_SOON_IR, "The compiler does not support the '*' operator for lhs=string and rhs=short yet");
}
case COMB(TY_STRING, TY_LONG): {
// ToDo(@marcauberer): Insert call to concatStrings in the runtime lib
// ToDo(@marcauberer): Insert call to opMul in the runtime lib
throw IRError(codeLoc, COMING_SOON_IR, "The compiler does not support the '*' operator for lhs=string and rhs=long yet");
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/linker/LinkerInterface.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,6 @@ class LinkerInterface {
const ThreadFactory &threadFactory;
const CliOptions &cliOptions;
std::vector<std::string> objectFilePaths;
std::vector<std::string> linkerFlags = {"-no-pie"};
std::vector<std::string> linkerFlags = {"-no-pie", "-flto"};
std::string outputPath;
};
31 changes: 29 additions & 2 deletions src/parser/AstBuilderVisitor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1577,11 +1577,38 @@ int64_t AstBuilderVisitor::parseLong(antlr4::tree::TerminalNode *terminal) {

int8_t AstBuilderVisitor::parseChar(antlr4::tree::TerminalNode *terminal) {
std::string input = terminal->toString();
if (input.length() != 3) {
if (input.length() == 3) { // Normal char literals
return input[1];
} else if (input.length() == 4 && input[1] == '\\') { // Char literals with escape sequence
switch (input[2]) {
case '\'':
return '\'';
case '"':
return '\"';
case '\\':
return '\\';
case 'n':
return '\n';
case 'r':
return '\r';
case 't':
return '\t';
case 'b':
return '\b';
case 'f':
return '\f';
case 'v':
return '\v';
case '0':
return '\0';
default:
CodeLoc codeLoc = CodeLoc(terminal->getSymbol(), fileName);
throw LexerParserError(codeLoc, PARSING_FAILED, "Invalid escape sequence " + input);
}
} else {
CodeLoc codeLoc = CodeLoc(terminal->getSymbol(), fileName);
throw LexerParserError(codeLoc, PARSING_FAILED, "Invalid char literal " + input);
}
return input[1];
}

std::string AstBuilderVisitor::parseString(std::string input) {
Expand Down
4 changes: 2 additions & 2 deletions src/symbol/SymbolType.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -53,10 +53,10 @@ SymbolType SymbolType::toArray(const CodeLoc &codeLoc, int size) const {
* @return Base type
*/
SymbolType SymbolType::getContainedTy() const {
if (typeChain.empty()) // GCOV_EXCL_LINE
throw std::runtime_error("Internal compiler error: Cannot get contained type of empty type"); // GCOV_EXCL_LINE
if (typeChain.top().superType == TY_STRING)
return SymbolType(TY_CHAR);
if (typeChain.size() < 2) // GCOV_EXCL_LINE
throw std::runtime_error("Internal compiler error: Cannot get contained type of type with type chain < 2"); // GCOV_EXCL_LINE
TypeChain newTypeChain = typeChain;
newTypeChain.pop();
return SymbolType(newTypeChain);
Expand Down
Loading

0 comments on commit 41e267a

Please sign in to comment.