├── tests ├── basic │ ├── Allocation.out │ ├── References.out │ ├── External.out │ ├── Export.out │ ├── Require.out │ ├── While.out │ ├── Import.out │ ├── Nullable.out │ ├── Unions.out │ ├── Overloading.out │ ├── Operators.out │ ├── Enum.out │ ├── Interface.out │ ├── Generics.out │ ├── Arrays.out │ ├── Precedence.out │ ├── Recursion.out │ ├── Strings.out │ ├── While.strela │ ├── Require.strela │ ├── Import.strela │ ├── Allocation.strela │ ├── External.strela │ ├── References.strela │ ├── Recursion.strela │ ├── Overloading.strela │ ├── Operators.strela │ ├── Unions.strela │ ├── Nullable.strela │ ├── Generics.strela │ ├── Precedence.strela │ ├── Enum.strela │ ├── Export.strela │ ├── Arrays.strela │ ├── Interface.strela │ └── Strings.strela └── Std │ ├── Collections │ ├── List.out │ ├── Map.out │ ├── List.strela │ └── Map.strela │ ├── JSON.out │ └── JSON.strela ├── .travis.yml ├── .gitignore ├── includetest.sh ├── .github └── workflows │ └── ccpp.yml ├── src ├── VM │ ├── Opcode.cpp │ ├── VMObject.h │ ├── VMObject.cpp │ ├── GC.h │ ├── VMType.h │ ├── Debugger.h │ ├── VM.h │ ├── VMValue.h │ ├── ByteCodeChunk.h │ ├── GC.cpp │ ├── Opcode.h │ ├── VMValue.cpp │ └── ByteCodeChunk.cpp ├── Ast │ ├── InterfaceFieldDecl.cpp │ ├── TypeDecl.cpp │ ├── TypeAliasDecl.cpp │ ├── GenericParam.h │ ├── AssignExpr.h │ ├── EnumDecl.cpp │ ├── LitExpr.h │ ├── BoolType.h │ ├── IdExpr.h │ ├── NullType.h │ ├── TypeType.h │ ├── VoidType.h │ ├── BlockStmt.h │ ├── RetStmt.h │ ├── EnumElement.h │ ├── ExprStmt.h │ ├── UnaryExpr.h │ ├── ArrayTypeExpr.h │ ├── InvalidType.h │ ├── PointerType.h │ ├── PostfixExpr.h │ ├── ThisExpr.h │ ├── NullableTypeExpr.h │ ├── UnionTypeExpr.h │ ├── WhileStmt.h │ ├── OverloadedFuncType.h │ ├── CallExpr.h │ ├── IfStmt.h │ ├── BinopExpr.h │ ├── ArrayLitExpr.h │ ├── FloatType.h │ ├── ScopeExpr.h │ ├── NewExpr.h │ ├── IsExpr.h │ ├── EnumDecl.h │ ├── GenericReificationExpr.h │ ├── InterfaceMethodDecl.cpp │ ├── Stmt.h │ ├── Param.h │ ├── TypeAliasDecl.h │ ├── FieldDecl.h │ ├── Node.h │ ├── CastExpr.h │ ├── SubscriptExpr.h │ ├── TypeDecl.h │ ├── FuncType.h │ ├── ArrayType.h │ ├── VarDecl.h │ ├── InterfaceFieldDecl.h │ ├── MapLitExpr.h │ ├── UnionType.h │ ├── IntType.h │ ├── InterfaceMethodDecl.h │ ├── InterfaceDecl.cpp │ ├── FuncType.cpp │ ├── Expr.h │ ├── FuncDecl.h │ ├── ArrayType.cpp │ ├── InterfaceDecl.h │ ├── ClassDecl.h │ ├── ModDecl.h │ ├── ImportStmt.h │ ├── types.cpp │ ├── nodes.h │ ├── ModDecl.cpp │ ├── ClassDecl.cpp │ ├── Token.h │ ├── UnionType.cpp │ └── Token.cpp ├── SourceFile.cpp ├── utils.h ├── TypeInfo.cpp ├── IStmtVisitor.h ├── SourceFile.h ├── Decompiler.h ├── Lexer.h ├── Scope.h ├── Pass.h ├── IExprVisitor.h ├── Scope.cpp ├── exceptions.h ├── TypeInfo.h ├── utils.cpp ├── Pass.cpp ├── NameResolver.h ├── ByteCodeCompiler.h ├── NodePrinter.h ├── Parser.h ├── TypeChecker.h └── Decompiler.cpp ├── examples ├── Fib.strela ├── Client.strela └── Server.strela ├── Std ├── Math.strela ├── Lang │ └── Compiler.strela ├── csockets.strela ├── cstdio.strela ├── Math │ └── Lina.strela ├── IO.strela ├── Collections.strela ├── Net.strela ├── Net │ └── HTTP.strela └── core.strela ├── install.bat ├── LICENSE ├── Makefile ├── test.sh ├── strela.sln ├── flame.html ├── readme.md └── docs └── syntax.md /tests/basic/Allocation.out: -------------------------------------------------------------------------------- 1 | Foo::bar() 2 | -------------------------------------------------------------------------------- /tests/basic/References.out: -------------------------------------------------------------------------------- 1 | 1337 2 | 42 3 | 42 4 | -------------------------------------------------------------------------------- /tests/basic/External.out: -------------------------------------------------------------------------------- 1 | 32 2 | 16 3 | 8 4 | 4 5 | 2 6 | -------------------------------------------------------------------------------- /tests/Std/Collections/List.out: -------------------------------------------------------------------------------- 1 | 2 2 | 1 3 | 2 4 | A 5 | B 6 | 0 7 | -------------------------------------------------------------------------------- /tests/basic/Export.out: -------------------------------------------------------------------------------- 1 | Export.foo called 2 | Export.bar called 3 | -------------------------------------------------------------------------------- /tests/basic/Require.out: -------------------------------------------------------------------------------- 1 | Export.foo called 2 | Export.bar called 3 | -------------------------------------------------------------------------------- /tests/basic/While.out: -------------------------------------------------------------------------------- 1 | 10 2 | 9 3 | 8 4 | 7 5 | 6 6 | 5 7 | 4 8 | 3 9 | 2 10 | 1 11 | -------------------------------------------------------------------------------- /tests/basic/Import.out: -------------------------------------------------------------------------------- 1 | Export.foo called 2 | Export.bar called 3 | Export.Baz.frob(Bumm) called: 13 4 | -------------------------------------------------------------------------------- /tests/basic/Nullable.out: -------------------------------------------------------------------------------- 1 | Value is: null 2 | Value is: Hello, world 3 | Value is: Goodbye, world 4 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | addons: 2 | apt: 3 | packages: 4 | - libffi-dev 5 | language: cpp 6 | script: make test -------------------------------------------------------------------------------- /tests/basic/Unions.out: -------------------------------------------------------------------------------- 1 | Union is an int and its value is 1337 2 | Union is a String and its value is Hello 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /release 2 | /debug 3 | /Release 4 | /Debug 5 | **/.vscode 6 | /.vs 7 | /x64 8 | *.sbc 9 | *.vcxproj.user -------------------------------------------------------------------------------- /tests/basic/Overloading.out: -------------------------------------------------------------------------------- 1 | foo String called: this is a string 2 | foo int called: 1337 3 | foo float called: 0.2 4 | -------------------------------------------------------------------------------- /tests/basic/Operators.out: -------------------------------------------------------------------------------- 1 | 5 2 | 15 3 | 10 4 | 5 5 | 15 6 | 25 7 | 20 8 | 10 9 | 30 10 | 31 11 | 30 12 | 0 13 | 30 14 | -------------------------------------------------------------------------------- /tests/basic/Enum.out: -------------------------------------------------------------------------------- 1 | a == Foo.A 2 | a != Foo.B 3 | Foo.A != Foo.B 4 | Foo.A == Foo.A 5 | a == Foo.B 6 | b == Foo.B 7 | c == Foo.B 8 | -------------------------------------------------------------------------------- /tests/basic/Interface.out: -------------------------------------------------------------------------------- 1 | My name is Darth Vader. 2 | I am your father. 3 | My name is Master Yoda. 4 | Do or do not. There is no try. 5 | -------------------------------------------------------------------------------- /tests/Std/Collections/Map.out: -------------------------------------------------------------------------------- 1 | twenty one = 21 2 | fourty two = 42 3 | thirteen = 13 4 | United States 5 | Great Britain 6 | Deutschland 7 | -1 8 | -------------------------------------------------------------------------------- /tests/basic/Generics.out: -------------------------------------------------------------------------------- 1 | init() called: String 2 | init() called: 123 3 | init() called: 1.5 4 | Value is: String 5 | Value is: 123 6 | Value is: 1.5 7 | -------------------------------------------------------------------------------- /tests/basic/Arrays.out: -------------------------------------------------------------------------------- 1 | String array length: 4 2 | First 3 | Second 4 | Third 5 | Fourth 6 | Int array length: 3 7 | 1 8 | 2 9 | 3 10 | Custom array subscript called: 0, 1 11 | -------------------------------------------------------------------------------- /tests/Std/JSON.out: -------------------------------------------------------------------------------- 1 | 1234 2 | 12.34000 3 | -1234 4 | -12.34000 5 | "A" 6 | null 7 | true 8 | false 9 | {} 10 | [] 11 | [0,1,2,3,4,5] 12 | {"a":1,"b":2} 13 | {"a":[],"b":[0,[],{},null]} 14 | -------------------------------------------------------------------------------- /includetest.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | for f in $(find . -type f -name '*.h'); do 3 | echo $f 4 | printf "#include \"$f\"\nint main() { return 0; }\n" | g++ --std=c++11 -x c++ -o /dev/null -; 5 | done -------------------------------------------------------------------------------- /tests/basic/Precedence.out: -------------------------------------------------------------------------------- 1 | 1 + 2 * 3 + 4 == 11 2 | -1 * 1 == -1 3 | 1 + 1 > 1 4 | 1 + 2 == 2 + 1 5 | true || false == false 6 | !true == false 7 | 1 + 2 > 1 && 2 + 4 < 10 8 | 1 + 2 >= 3 9 | 1 + 2 <= 3 10 | -------------------------------------------------------------------------------- /tests/basic/Recursion.out: -------------------------------------------------------------------------------- 1 | Depth: 0 2 | Depth: 1 3 | Depth: 2 4 | Depth: 3 5 | Depth: 4 6 | Depth: 5 7 | Depth: 6 8 | Depth: 7 9 | Depth: 8 10 | Depth: 9 11 | Depth: 10 12 | Depth 10 reached. Ending recursion. 13 | -------------------------------------------------------------------------------- /.github/workflows/ccpp.yml: -------------------------------------------------------------------------------- 1 | name: C/C++ CI 2 | 3 | on: [push] 4 | 5 | jobs: 6 | build: 7 | 8 | runs-on: ubuntu-latest 9 | 10 | steps: 11 | - uses: actions/checkout@v2 12 | - name: make test 13 | run: make test 14 | -------------------------------------------------------------------------------- /tests/basic/Strings.out: -------------------------------------------------------------------------------- 1 | 0 2 | 4 3 | ABC 4 | A 5 | Hello, world! 6 | 3 7 | Hello darkness 8 | true 9 | false 10 | true 11 | false 12 | true 13 | false 14 | Quit 15 | X 16 | Y 17 | Z 18 | 3 19 | New York 20 | 1 21 | 1 22 | Go 23 | 24 | 123456 25 | 123.456 26 | Hallo, world 27 | -------------------------------------------------------------------------------- /tests/basic/While.strela: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Stephan Unverwerth 2 | // This code is licensed under MIT license (See LICENSE for details) 3 | 4 | module While { 5 | import Std.IO.*; 6 | 7 | function main(args: String[]): int { 8 | var i = 10; 9 | while(i > 0) { 10 | println(i); 11 | i = i - 1; 12 | } 13 | return 0; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/VM/Opcode.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Stephan Unverwerth 2 | // This code is licensed under MIT license (See LICENSE for details) 3 | 4 | #include "Opcode.h" 5 | 6 | namespace Strela { 7 | 8 | #define AS_INFO(X, A, T) { #X, A, VMValue::Type::T }, 9 | OpcodeInfo opcodeInfo[] { 10 | OPCODES(AS_INFO) 11 | }; 12 | #undef AS_INFO 13 | } -------------------------------------------------------------------------------- /tests/basic/Require.strela: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Stephan Unverwerth 2 | // This code is licensed under MIT license (See LICENSE for details) 3 | 4 | module Require { 5 | import Std.IO.*; 6 | 7 | import Export; 8 | 9 | function main(args: String[]): int { 10 | Export.foo(); 11 | Export.bar(); 12 | return 0; 13 | } 14 | } -------------------------------------------------------------------------------- /src/Ast/InterfaceFieldDecl.cpp: -------------------------------------------------------------------------------- 1 | #include "InterfaceFieldDecl.h" 2 | #include "Expr.h" 3 | 4 | #include 5 | 6 | namespace Strela { 7 | std::string InterfaceFieldDecl::getDescription() { 8 | std::stringstream sstr; 9 | sstr << "var " << name << ": " << typeExpr->typeValue->getFullName(); 10 | return sstr.str(); 11 | } 12 | } -------------------------------------------------------------------------------- /src/Ast/TypeDecl.cpp: -------------------------------------------------------------------------------- 1 | #include "TypeDecl.h" 2 | #include "ModDecl.h" 3 | 4 | namespace Strela { 5 | std::string TypeDecl::getFullName() { 6 | ModDecl* mod = parent ? parent->as() : nullptr; 7 | if (mod && !mod->_name.empty()) { 8 | return mod->getFullName() + "." + _name; 9 | } 10 | return _name; 11 | } 12 | } -------------------------------------------------------------------------------- /src/Ast/TypeAliasDecl.cpp: -------------------------------------------------------------------------------- 1 | #include "TypeAliasDecl.h" 2 | #include "Expr.h" 3 | 4 | namespace Strela { 5 | Node* TypeAliasDecl::getMember(const std::string& name) { 6 | return typeExpr->typeValue->getMember(name); 7 | } 8 | 9 | std::vector TypeAliasDecl::getMethods(const std::string& name) { 10 | return typeExpr->typeValue->getMethods(name); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/SourceFile.cpp: -------------------------------------------------------------------------------- 1 | #include "SourceFile.h" 2 | #include 3 | 4 | namespace Strela { 5 | std::string SourceFile::getLine(int line) const { 6 | std::stringstream sstr; 7 | for (auto& tok: tokens) { 8 | if (tok.line > line) break; 9 | if (tok.line == line) sstr << tok.trivia << tok.value; 10 | } 11 | return sstr.str(); 12 | } 13 | } -------------------------------------------------------------------------------- /tests/basic/Import.strela: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Stephan Unverwerth 2 | // This code is licensed under MIT license (See LICENSE for details) 3 | 4 | module Import { 5 | import Std.IO.*; 6 | 7 | import Export.*; 8 | 9 | function main(args: String[]): int { 10 | foo(); 11 | bar(); 12 | 13 | var baz = new Baz; 14 | baz.frob(makeBumm(13)); 15 | 16 | return 0; 17 | } 18 | } -------------------------------------------------------------------------------- /src/Ast/GenericParam.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Stephan Unverwerth 2 | // This code is licensed under MIT license (See LICENSE for details) 3 | 4 | #ifndef Strela_Ast_AstGenericParam_h 5 | #define Strela_Ast_AstGenericParam_h 6 | 7 | #include "TypeDecl.h" 8 | 9 | namespace Strela { 10 | class GenericParam: public TypeDecl { 11 | public: 12 | STRELA_GET_TYPE(Strela::GenericParam, Strela::TypeDecl); 13 | }; 14 | } 15 | 16 | #endif -------------------------------------------------------------------------------- /src/VM/VMObject.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Stephan Unverwerth 2 | // This code is licensed under MIT license (See LICENSE for details) 3 | 4 | #ifndef Strela_VM_VMObject_h 5 | #define Strela_VM_VMObject_h 6 | 7 | #include "VMValue.h" 8 | 9 | #include 10 | 11 | namespace Strela { 12 | class VMType; 13 | 14 | struct VMObject { 15 | bool marked = false; 16 | const VMType* type; 17 | char data[]; 18 | }; 19 | } 20 | 21 | #endif -------------------------------------------------------------------------------- /src/Ast/AssignExpr.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Stephan Unverwerth 2 | // This code is licensed under MIT license (See LICENSE for details) 3 | 4 | #ifndef Strela_Ast_AstAssignExpr_h 5 | #define Strela_Ast_AstAssignExpr_h 6 | 7 | #include "BinopExpr.h" 8 | 9 | namespace Strela { 10 | class AssignExpr: public BinopExpr { 11 | public: 12 | STRELA_GET_TYPE(Strela::AssignExpr, Strela::BinopExpr); 13 | STRELA_IMPL_EXPR_VISITOR; 14 | }; 15 | } 16 | 17 | #endif -------------------------------------------------------------------------------- /src/Ast/EnumDecl.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Stephan Unverwerth 2 | // This code is licensed under MIT license (See LICENSE for details) 3 | 4 | #include "EnumDecl.h" 5 | #include "EnumElement.h" 6 | 7 | namespace Strela { 8 | Node* EnumDecl::getMember(const std::string& name) { 9 | for (auto&& element: elements) { 10 | if (element->name == name) { 11 | return element; 12 | } 13 | } 14 | return nullptr; 15 | } 16 | } -------------------------------------------------------------------------------- /tests/basic/Allocation.strela: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Stephan Unverwerth 2 | // This code is licensed under MIT license (See LICENSE for details) 3 | 4 | module Allocation { 5 | import Std.IO.*; 6 | 7 | class Foo { 8 | function bar() { 9 | println("Foo::bar()"); 10 | } 11 | } 12 | 13 | function main(args: String[]): int { 14 | // alloc string 15 | var foo = new Foo; 16 | foo.bar(); 17 | return 0; 18 | } 19 | } -------------------------------------------------------------------------------- /tests/basic/External.strela: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Stephan Unverwerth 2 | // This code is licensed under MIT license (See LICENSE for details) 3 | 4 | module External { 5 | import Std.IO.*; 6 | 7 | external function sqrt(v: float): float; 8 | 9 | function main(args: String[]): int { 10 | println(sqrt(1024)); 11 | println(sqrt(256)); 12 | println(sqrt(64)); 13 | println(sqrt(16)); 14 | println(sqrt(4)); 15 | return 0; 16 | } 17 | } -------------------------------------------------------------------------------- /src/VM/VMObject.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Stephan Unverwerth 2 | // This code is licensed under MIT license (See LICENSE for details) 3 | 4 | #include "VMObject.h" 5 | 6 | namespace Strela { 7 | /*VMObject::VMObject(size_t numfields): fields(numfields) { 8 | } 9 | 10 | VMValue VMObject::getField(size_t index) { 11 | return fields[index]; 12 | } 13 | 14 | void VMObject::setField(size_t index, const VMValue& val) { 15 | fields[index] = val; 16 | }*/ 17 | } -------------------------------------------------------------------------------- /src/Ast/LitExpr.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Stephan Unverwerth 2 | // This code is licensed under MIT license (See LICENSE for details) 3 | 4 | #ifndef Strela_Ast_AstLitExpr_h 5 | #define Strela_Ast_AstLitExpr_h 6 | 7 | #include "Expr.h" 8 | #include "Token.h" 9 | 10 | namespace Strela { 11 | class LitExpr: public Expr { 12 | public: 13 | STRELA_GET_TYPE(Strela::LitExpr, Strela::Expr); 14 | STRELA_IMPL_EXPR_VISITOR; 15 | 16 | public: 17 | Token token; 18 | }; 19 | } 20 | 21 | #endif -------------------------------------------------------------------------------- /src/Ast/BoolType.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Stephan Unverwerth 2 | // This code is licensed under MIT license (See LICENSE for details) 3 | 4 | #ifndef Strela_Ast_BoolType_h 5 | #define Strela_Ast_BoolType_h 6 | 7 | #include "TypeDecl.h" 8 | 9 | namespace Strela { 10 | class BoolType: public TypeDecl { 11 | public: 12 | BoolType() { _name = "bool"; } 13 | STRELA_GET_TYPE(Strela::BoolType, Strela::TypeDecl); 14 | 15 | public: 16 | static BoolType instance; 17 | }; 18 | } 19 | 20 | #endif -------------------------------------------------------------------------------- /src/Ast/IdExpr.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Stephan Unverwerth 2 | // This code is licensed under MIT license (See LICENSE for details) 3 | 4 | #ifndef Strela_Ast_AstIdExpr_h 5 | #define Strela_Ast_AstIdExpr_h 6 | 7 | #include "Expr.h" 8 | 9 | #include 10 | 11 | namespace Strela { 12 | class IdExpr: public Expr { 13 | public: 14 | STRELA_GET_TYPE(Strela::IdExpr, Strela::Expr); 15 | STRELA_IMPL_EXPR_VISITOR; 16 | 17 | public: 18 | std::string name; 19 | }; 20 | } 21 | 22 | #endif -------------------------------------------------------------------------------- /src/Ast/NullType.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Stephan Unverwerth 2 | // This code is licensed under MIT license (See LICENSE for details) 3 | 4 | #ifndef Strela_Ast_NullType_h 5 | #define Strela_Ast_NullType_h 6 | 7 | #include "TypeDecl.h" 8 | 9 | namespace Strela { 10 | class NullType: public TypeDecl { 11 | public: 12 | NullType() { _name = "null"; } 13 | STRELA_GET_TYPE(Strela::NullType, Strela::TypeDecl); 14 | 15 | public: 16 | static NullType instance; 17 | }; 18 | } 19 | 20 | #endif -------------------------------------------------------------------------------- /src/Ast/TypeType.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Stephan Unverwerth 2 | // This code is licensed under MIT license (See LICENSE for details) 3 | 4 | #ifndef Strela_Ast_TypeType_h 5 | #define Strela_Ast_TypeType_h 6 | 7 | #include "TypeDecl.h" 8 | 9 | namespace Strela { 10 | class TypeType: public TypeDecl { 11 | public: 12 | TypeType() { _name = "Type"; } 13 | STRELA_GET_TYPE(Strela::TypeType, Strela::TypeDecl); 14 | 15 | public: 16 | static TypeType instance; 17 | }; 18 | } 19 | 20 | #endif -------------------------------------------------------------------------------- /src/Ast/VoidType.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Stephan Unverwerth 2 | // This code is licensed under MIT license (See LICENSE for details) 3 | 4 | #ifndef Strela_Ast_VoidType_h 5 | #define Strela_Ast_VoidType_h 6 | 7 | #include "TypeDecl.h" 8 | 9 | namespace Strela { 10 | class VoidType: public TypeDecl { 11 | public: 12 | VoidType() { _name = "void"; } 13 | STRELA_GET_TYPE(Strela::VoidType, Strela::TypeDecl); 14 | 15 | public: 16 | static VoidType instance; 17 | }; 18 | } 19 | 20 | #endif -------------------------------------------------------------------------------- /tests/basic/References.strela: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Stephan Unverwerth 2 | // This code is licensed under MIT license (See LICENSE for details) 3 | 4 | module References { 5 | import Std.IO.*; 6 | 7 | function main(args: String[]): int { 8 | var value1 = "1337"; 9 | var value2 = "42"; 10 | var ref = value1; 11 | 12 | println(ref); 13 | ref = value2; 14 | println(ref); 15 | value2 = "2448"; 16 | println(ref); 17 | 18 | return 0; 19 | } 20 | } -------------------------------------------------------------------------------- /src/Ast/BlockStmt.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Stephan Unverwerth 2 | // This code is licensed under MIT license (See LICENSE for details) 3 | 4 | #ifndef Strela_Ast_AstBlockStmt_h 5 | #define Strela_Ast_AstBlockStmt_h 6 | 7 | #include "Stmt.h" 8 | 9 | #include 10 | 11 | namespace Strela { 12 | class BlockStmt: public Stmt { 13 | public: 14 | STRELA_GET_TYPE(Strela::BlockStmt, Strela::Stmt); 15 | STRELA_IMPL_STMT_VISITOR; 16 | 17 | public: 18 | std::vector stmts; 19 | }; 20 | } 21 | #endif -------------------------------------------------------------------------------- /src/Ast/RetStmt.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Stephan Unverwerth 2 | // This code is licensed under MIT license (See LICENSE for details) 3 | 4 | #ifndef Strela_Ast_AstRetStmt_h 5 | #define Strela_Ast_AstRetStmt_h 6 | 7 | #include "Stmt.h" 8 | 9 | namespace Strela { 10 | class Expr; 11 | 12 | class RetStmt: public Stmt { 13 | public: 14 | STRELA_GET_TYPE(Strela::RetStmt, Strela::Stmt); 15 | STRELA_IMPL_STMT_VISITOR; 16 | 17 | public: 18 | Expr* expression = nullptr; 19 | }; 20 | } 21 | 22 | #endif -------------------------------------------------------------------------------- /src/Ast/EnumElement.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Stephan Unverwerth 2 | // This code is licensed under MIT license (See LICENSE for details) 3 | 4 | #ifndef Strela_Ast_AstEnumElement_h 5 | #define Strela_Ast_AstEnumElement_h 6 | 7 | #include "Node.h" 8 | 9 | #include 10 | 11 | namespace Strela { 12 | class EnumElement: public Node { 13 | public: 14 | STRELA_GET_TYPE(Strela::EnumElement, Strela::Node); 15 | 16 | public: 17 | std::string name; 18 | int index = 0; 19 | }; 20 | } 21 | 22 | #endif -------------------------------------------------------------------------------- /src/Ast/ExprStmt.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Stephan Unverwerth 2 | // This code is licensed under MIT license (See LICENSE for details) 3 | 4 | #ifndef Strela_Ast_AstExprStmt_h 5 | #define Strela_Ast_AstExprStmt_h 6 | 7 | #include "Stmt.h" 8 | 9 | namespace Strela { 10 | class Expr; 11 | 12 | class ExprStmt: public Stmt { 13 | public: 14 | STRELA_GET_TYPE(Strela::ExprStmt, Strela::Stmt); 15 | STRELA_IMPL_STMT_VISITOR; 16 | 17 | public: 18 | Expr* expression = nullptr; 19 | }; 20 | } 21 | 22 | #endif -------------------------------------------------------------------------------- /src/Ast/UnaryExpr.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Stephan Unverwerth 2 | // This code is licensed under MIT license (See LICENSE for details) 3 | 4 | #ifndef Strela_Ast_AstUnaryExpr_h 5 | #define Strela_Ast_AstUnaryExpr_h 6 | 7 | #include "Expr.h" 8 | 9 | namespace Strela { 10 | class UnaryExpr: public Expr { 11 | public: 12 | STRELA_GET_TYPE(Strela::UnaryExpr, Strela::Expr); 13 | STRELA_IMPL_EXPR_VISITOR; 14 | 15 | public: 16 | TokenType op; 17 | Expr* target = nullptr; 18 | }; 19 | } 20 | 21 | #endif -------------------------------------------------------------------------------- /src/Ast/ArrayTypeExpr.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Stephan Unverwerth 2 | // This code is licensed under MIT license (See LICENSE for details) 3 | 4 | #ifndef Strela_Ast_AstArrayTypeExpr_h 5 | #define Strela_Ast_AstArrayTypeExpr_h 6 | 7 | #include "Expr.h" 8 | 9 | namespace Strela { 10 | 11 | class ArrayTypeExpr: public Expr { 12 | public: 13 | STRELA_GET_TYPE(Strela::ArrayTypeExpr, Strela::Expr); 14 | STRELA_IMPL_EXPR_VISITOR; 15 | 16 | public: 17 | Expr* baseTypeExpr = nullptr; 18 | }; 19 | } 20 | 21 | #endif -------------------------------------------------------------------------------- /src/Ast/InvalidType.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Stephan Unverwerth 2 | // This code is licensed under MIT license (See LICENSE for details) 3 | 4 | #ifndef Strela_Ast_InvalidType_h 5 | #define Strela_Ast_InvalidType_h 6 | 7 | #include "TypeDecl.h" 8 | 9 | namespace Strela { 10 | class InvalidType: public TypeDecl { 11 | public: 12 | InvalidType() { _name = "$invalid"; } 13 | STRELA_GET_TYPE(Strela::InvalidType, Strela::TypeDecl); 14 | 15 | public: 16 | static InvalidType instance; 17 | }; 18 | } 19 | 20 | #endif -------------------------------------------------------------------------------- /src/Ast/PointerType.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Stephan Unverwerth 2 | // This code is licensed under MIT license (See LICENSE for details) 3 | 4 | #ifndef Strela_Ast_PointerType_h 5 | #define Strela_Ast_PointerType_h 6 | 7 | #include "TypeDecl.h" 8 | 9 | namespace Strela { 10 | class PointerType: public TypeDecl { 11 | public: 12 | PointerType() { _name = "Ptr"; } 13 | STRELA_GET_TYPE(Strela::PointerType, Strela::TypeDecl); 14 | 15 | public: 16 | static PointerType instance; 17 | }; 18 | } 19 | 20 | #endif -------------------------------------------------------------------------------- /src/Ast/PostfixExpr.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Stephan Unverwerth 2 | // This code is licensed under MIT license (See LICENSE for details) 3 | 4 | #ifndef Strela_Ast_AstPostfixExpr_h 5 | #define Strela_Ast_AstPostfixExpr_h 6 | 7 | #include "Expr.h" 8 | 9 | namespace Strela { 10 | class PostfixExpr: public Expr { 11 | public: 12 | STRELA_GET_TYPE(Strela::PostfixExpr, Strela::Expr); 13 | STRELA_IMPL_EXPR_VISITOR; 14 | 15 | public: 16 | TokenType op; 17 | Expr* target = nullptr; 18 | }; 19 | } 20 | 21 | #endif -------------------------------------------------------------------------------- /src/Ast/ThisExpr.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Stephan Unverwerth 2 | // This code is licensed under MIT license (See LICENSE for details) 3 | 4 | #ifndef Strela_Ast_AstThisExpr_h 5 | #define Strela_Ast_AstThisExpr_h 6 | 7 | #include "Expr.h" 8 | 9 | namespace Strela { 10 | class ClassDecl; 11 | 12 | class ThisExpr: public Expr { 13 | public: 14 | STRELA_GET_TYPE(Strela::ThisExpr, Strela::Expr); 15 | STRELA_IMPL_EXPR_VISITOR; 16 | 17 | public: 18 | ClassDecl* _class = nullptr; 19 | }; 20 | } 21 | 22 | #endif -------------------------------------------------------------------------------- /src/Ast/NullableTypeExpr.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Stephan Unverwerth 2 | // This code is licensed under MIT license (See LICENSE for details) 3 | 4 | #ifndef Strela_Ast_AstNullableTypeExpr_h 5 | #define Strela_Ast_AstNullableTypeExpr_h 6 | 7 | #include "Expr.h" 8 | 9 | namespace Strela { 10 | class NullableTypeExpr: public Expr { 11 | public: 12 | STRELA_GET_TYPE(Strela::NullableTypeExpr, Strela::Expr); 13 | STRELA_IMPL_EXPR_VISITOR; 14 | 15 | public: 16 | Expr* baseTypeExpr = nullptr; 17 | }; 18 | } 19 | 20 | #endif -------------------------------------------------------------------------------- /src/utils.h: -------------------------------------------------------------------------------- 1 | #ifndef Strela_utils_h 2 | #define Strela_utils_h 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | namespace Strela { 9 | std::string escape(const std::string& str); 10 | std::string unescape(const std::string& str); 11 | 12 | template T unique(const T& values) { 13 | std::set set; 14 | set.insert(values.begin(), values.end()); 15 | T result; 16 | result.assign(set.begin(), set.end()); 17 | return result; 18 | } 19 | } 20 | 21 | #endif -------------------------------------------------------------------------------- /src/Ast/UnionTypeExpr.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Stephan Unverwerth 2 | // This code is licensed under MIT license (See LICENSE for details) 3 | 4 | #ifndef Strela_Ast_AstUnionTypeExpr_h 5 | #define Strela_Ast_AstUnionTypeExpr_h 6 | 7 | #include "Expr.h" 8 | 9 | namespace Strela { 10 | 11 | class UnionTypeExpr: public Expr { 12 | public: 13 | STRELA_GET_TYPE(Strela::UnionTypeExpr, Strela::Expr); 14 | STRELA_IMPL_EXPR_VISITOR; 15 | 16 | public: 17 | Expr* base = nullptr; 18 | Expr* next = nullptr; 19 | }; 20 | } 21 | 22 | #endif -------------------------------------------------------------------------------- /src/Ast/WhileStmt.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Stephan Unverwerth 2 | // This code is licensed under MIT license (See LICENSE for details) 3 | 4 | #ifndef Strela_Ast_AstWhileStmt_h 5 | #define Strela_Ast_AstWhileStmt_h 6 | 7 | #include "Stmt.h" 8 | 9 | namespace Strela { 10 | class Expr; 11 | 12 | class WhileStmt: public Stmt { 13 | public: 14 | STRELA_GET_TYPE(Strela::WhileStmt, Strela::Stmt); 15 | STRELA_IMPL_STMT_VISITOR; 16 | 17 | public: 18 | Expr* condition = nullptr; 19 | Stmt* body = nullptr; 20 | }; 21 | } 22 | 23 | #endif -------------------------------------------------------------------------------- /src/TypeInfo.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Stephan Unverwerth 2 | // This code is licensed under MIT license (See LICENSE for details) 3 | 4 | #include "TypeInfo.h" 5 | 6 | namespace Strela { 7 | 8 | bool TypeInfo::extends(const TypeInfo* tid) const { 9 | if (tid == this) return false; 10 | if (!parent) return false; 11 | if (tid == parent) return true; 12 | 13 | auto it = extCache.find(tid); 14 | if (it != extCache.end()) return it->second; 15 | 16 | bool ext = parent->extends(tid); 17 | extCache.insert(std::make_pair(tid, ext)); 18 | return ext; 19 | } 20 | } -------------------------------------------------------------------------------- /tests/basic/Recursion.strela: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Stephan Unverwerth 2 | // This code is licensed under MIT license (See LICENSE for details) 3 | 4 | module Recursion { 5 | import Std.IO.*; 6 | 7 | 8 | function foo(depth: int) { 9 | if (depth > 10) { 10 | println("Depth 10 reached. Ending recursion."); 11 | return; 12 | } 13 | print("Depth: "); 14 | println(depth); 15 | foo(depth+1); 16 | } 17 | 18 | function main(args: String[]): int { 19 | foo(0); 20 | return 0; 21 | } 22 | } -------------------------------------------------------------------------------- /src/Ast/OverloadedFuncType.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Stephan Unverwerth 2 | // This code is licensed under MIT license (See LICENSE for details) 3 | 4 | #ifndef Strela_Ast_OverloadedFuncType_h 5 | #define Strela_Ast_OverloadedFuncType_h 6 | 7 | #include "TypeDecl.h" 8 | 9 | namespace Strela { 10 | class OverloadedFuncType: public TypeDecl { 11 | public: 12 | OverloadedFuncType() { _name = "$overloaded"; } 13 | STRELA_GET_TYPE(Strela::OverloadedFuncType, Strela::TypeDecl); 14 | 15 | public: 16 | static OverloadedFuncType instance; 17 | }; 18 | } 19 | 20 | #endif -------------------------------------------------------------------------------- /src/Ast/CallExpr.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Stephan Unverwerth 2 | // This code is licensed under MIT license (See LICENSE for details) 3 | 4 | #ifndef Strela_Ast_AstCallExpr_h 5 | #define Strela_Ast_AstCallExpr_h 6 | 7 | #include "Expr.h" 8 | 9 | #include 10 | #include 11 | 12 | namespace Strela { 13 | class CallExpr: public Expr { 14 | public: 15 | STRELA_GET_TYPE(Strela::CallExpr, Strela::Expr); 16 | STRELA_IMPL_EXPR_VISITOR; 17 | 18 | public: 19 | Expr* callTarget = nullptr; 20 | std::vector arguments; 21 | }; 22 | } 23 | 24 | #endif -------------------------------------------------------------------------------- /src/Ast/IfStmt.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Stephan Unverwerth 2 | // This code is licensed under MIT license (See LICENSE for details) 3 | 4 | #ifndef Strela_Ast_AstIfStmt_h 5 | #define Strela_Ast_AstIfStmt_h 6 | 7 | #include "Stmt.h" 8 | 9 | namespace Strela { 10 | class Expr; 11 | 12 | class IfStmt: public Stmt { 13 | public: 14 | STRELA_GET_TYPE(Strela::IfStmt, Strela::Stmt); 15 | STRELA_IMPL_STMT_VISITOR; 16 | 17 | public: 18 | Expr* condition = nullptr; 19 | Stmt* trueBranch = nullptr; 20 | Stmt* falseBranch = nullptr; 21 | }; 22 | } 23 | 24 | #endif -------------------------------------------------------------------------------- /examples/Fib.strela: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Stephan Unverwerth 2 | // This code is licensed under MIT license (See LICENSE for details) 3 | 4 | module Fib { 5 | import Std.IO.*; 6 | 7 | function fibonacci(i: int): int { 8 | if (i < 2) return i; 9 | return fibonacci(i-1) + fibonacci(i-2); 10 | } 11 | 12 | function main(args: String[]): int { 13 | println("Hello, world!"); 14 | println("Calculating fibonacci(40)."); 15 | println("This may take a while..."); 16 | print("fibonacci(40) is "); 17 | println(fibonacci(40)); 18 | return 0; 19 | } 20 | } -------------------------------------------------------------------------------- /src/Ast/BinopExpr.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Stephan Unverwerth 2 | // This code is licensed under MIT license (See LICENSE for details) 3 | 4 | #ifndef Strela_Ast_AstBinopExpr_h 5 | #define Strela_Ast_AstBinopExpr_h 6 | 7 | #include "Expr.h" 8 | 9 | namespace Strela { 10 | 11 | class BinopExpr: public Expr { 12 | public: 13 | STRELA_GET_TYPE(Strela::BinopExpr, Strela::Expr); 14 | STRELA_IMPL_EXPR_VISITOR; 15 | 16 | public: 17 | TokenType op; 18 | Expr* left = nullptr; 19 | Expr* right = nullptr; 20 | FuncDecl* function = nullptr; 21 | }; 22 | } 23 | 24 | #endif -------------------------------------------------------------------------------- /src/IStmtVisitor.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Stephan Unverwerth 2 | // This code is licensed under MIT license (See LICENSE for details) 3 | 4 | #ifndef Strela_IStmtVisitor_h 5 | #define Strela_IStmtVisitor_h 6 | 7 | namespace Strela { 8 | class IStmtVisitor { 9 | public: 10 | virtual void visit(class VarDecl&) = 0; 11 | virtual void visit(class RetStmt&) = 0; 12 | virtual void visit(class BlockStmt&) = 0; 13 | virtual void visit(class ExprStmt&) = 0; 14 | virtual void visit(class IfStmt&) = 0; 15 | virtual void visit(class WhileStmt&) = 0; 16 | }; 17 | } 18 | 19 | #endif -------------------------------------------------------------------------------- /src/Ast/ArrayLitExpr.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Stephan Unverwerth 2 | // This code is licensed under MIT license (See LICENSE for details) 3 | 4 | #ifndef Strela_Ast_AstArrayLitExpr_h 5 | #define Strela_Ast_AstArrayLitExpr_h 6 | 7 | #include "Expr.h" 8 | #include "Token.h" 9 | 10 | namespace Strela { 11 | class FuncDecl; 12 | 13 | class ArrayLitExpr: public Expr { 14 | public: 15 | STRELA_GET_TYPE(Strela::ArrayLitExpr, Strela::Expr); 16 | STRELA_IMPL_EXPR_VISITOR; 17 | 18 | public: 19 | std::vector elements; 20 | FuncDecl* constructor = nullptr; 21 | }; 22 | } 23 | 24 | #endif -------------------------------------------------------------------------------- /src/Ast/FloatType.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Stephan Unverwerth 2 | // This code is licensed under MIT license (See LICENSE for details) 3 | 4 | #ifndef Strela_Ast_FloatType_h 5 | #define Strela_Ast_FloatType_h 6 | 7 | #include "TypeDecl.h" 8 | 9 | namespace Strela { 10 | class FloatType: public TypeDecl { 11 | public: 12 | FloatType(const std::string& name, int bytes): bytes(bytes) { this->_name = name; } 13 | STRELA_GET_TYPE(Strela::FloatType, Strela::TypeDecl); 14 | 15 | public: 16 | int bytes; 17 | 18 | static FloatType f64; 19 | static FloatType f32; 20 | }; 21 | } 22 | 23 | #endif -------------------------------------------------------------------------------- /src/Ast/ScopeExpr.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Stephan Unverwerth 2 | // This code is licensed under MIT license (See LICENSE for details) 3 | 4 | #ifndef Strela_Ast_AstScopeExpr_h 5 | #define Strela_Ast_AstScopeExpr_h 6 | 7 | #include "Expr.h" 8 | 9 | #include 10 | 11 | namespace Strela { 12 | class Symbol; 13 | 14 | class ScopeExpr: public Expr { 15 | public: 16 | STRELA_GET_TYPE(Strela::ScopeExpr, Strela::Expr); 17 | STRELA_IMPL_EXPR_VISITOR; 18 | 19 | public: 20 | Expr* scopeTarget = nullptr; 21 | std::string name; 22 | Symbol* symbol = nullptr; 23 | }; 24 | } 25 | 26 | #endif -------------------------------------------------------------------------------- /src/Ast/NewExpr.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Stephan Unverwerth 2 | // This code is licensed under MIT license (See LICENSE for details) 3 | 4 | #ifndef Strela_Ast_AstNewExpr_h 5 | #define Strela_Ast_AstNewExpr_h 6 | 7 | #include "Expr.h" 8 | 9 | #include 10 | #include 11 | 12 | namespace Strela { 13 | 14 | class NewExpr: public Expr { 15 | public: 16 | STRELA_GET_TYPE(Strela::NewExpr, Strela::Expr); 17 | STRELA_IMPL_EXPR_VISITOR; 18 | 19 | public: 20 | Expr* typeExpr = nullptr; 21 | std::vector arguments; 22 | FuncDecl* initMethod = nullptr; 23 | }; 24 | } 25 | 26 | #endif -------------------------------------------------------------------------------- /src/Ast/IsExpr.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Stephan Unverwerth 2 | // This code is licensed under MIT license (See LICENSE for details) 3 | 4 | #ifndef Strela_Ast_AstIsExpr_h 5 | #define Strela_Ast_AstIsExpr_h 6 | 7 | #include "Expr.h" 8 | 9 | namespace Strela { 10 | class Implementation; 11 | 12 | class IsExpr: public Expr { 13 | public: 14 | STRELA_GET_TYPE(Strela::IsExpr, Strela::Expr); 15 | STRELA_IMPL_EXPR_VISITOR; 16 | 17 | public: 18 | int typeTag; 19 | Implementation* implementation = nullptr; 20 | Expr* target = nullptr; 21 | Expr* typeExpr = nullptr; 22 | }; 23 | } 24 | 25 | #endif -------------------------------------------------------------------------------- /src/SourceFile.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Stephan Unverwerth 2 | // This code is licensed under MIT license (See LICENSE for details) 3 | 4 | #ifndef Strela_SourceFile_h 5 | #define Strela_SourceFile_h 6 | 7 | #include "Ast/Token.h" 8 | 9 | #include 10 | #include 11 | 12 | namespace Strela { 13 | class SourceFile { 14 | public: 15 | SourceFile(const std::string& filename, const std::vector& tokens): filename(filename), tokens(tokens) {} 16 | std::string getLine(int line) const; 17 | 18 | public: 19 | std::string filename; 20 | std::vector tokens; 21 | }; 22 | } 23 | 24 | #endif -------------------------------------------------------------------------------- /src/Ast/EnumDecl.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Stephan Unverwerth 2 | // This code is licensed under MIT license (See LICENSE for details) 3 | 4 | #ifndef Strela_Ast_AstEnumDecl_h 5 | #define Strela_Ast_AstEnumDecl_h 6 | 7 | #include "TypeDecl.h" 8 | 9 | #include 10 | 11 | namespace Strela { 12 | class EnumElement; 13 | 14 | class EnumDecl: public TypeDecl { 15 | public: 16 | STRELA_GET_TYPE(Strela::EnumDecl, Strela::TypeDecl); 17 | 18 | Node* getMember(const std::string& name) override; 19 | 20 | public: 21 | std::vector elements; 22 | bool isExported = false; 23 | }; 24 | } 25 | 26 | #endif -------------------------------------------------------------------------------- /src/Ast/GenericReificationExpr.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Stephan Unverwerth 2 | // This code is licensed under MIT license (See LICENSE for details) 3 | 4 | #ifndef Strela_Ast_AstGenericReificationExpr_h 5 | #define Strela_Ast_AstGenericReificationExpr_h 6 | 7 | #include "Expr.h" 8 | 9 | #include 10 | 11 | namespace Strela { 12 | 13 | class GenericReificationExpr: public Expr { 14 | public: 15 | STRELA_GET_TYPE(Strela::GenericReificationExpr, Strela::Expr); 16 | STRELA_IMPL_EXPR_VISITOR; 17 | 18 | public: 19 | Expr* baseTypeExpr = nullptr; 20 | std::vector genericArguments; 21 | }; 22 | } 23 | 24 | #endif -------------------------------------------------------------------------------- /src/Ast/InterfaceMethodDecl.cpp: -------------------------------------------------------------------------------- 1 | #include "InterfaceMethodDecl.h" 2 | #include "Param.h" 3 | #include "Expr.h" 4 | 5 | #include 6 | 7 | namespace Strela { 8 | std::string InterfaceMethodDecl::getDescription() { 9 | std::stringstream sstr; 10 | sstr << "function " << name << "("; 11 | for (auto& param: params) { 12 | if (param != params.front()) { 13 | sstr << ", "; 14 | } 15 | sstr << param->name << ": " << param->declType->getFullName(); 16 | } 17 | sstr << "): " << returnTypeExpr->typeValue->getFullName(); 18 | 19 | return sstr.str(); 20 | } 21 | } -------------------------------------------------------------------------------- /src/Ast/Stmt.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Stephan Unverwerth 2 | // This code is licensed under MIT license (See LICENSE for details) 3 | 4 | #ifndef Strela_Ast_AstStmt_h 5 | #define Strela_Ast_AstStmt_h 6 | 7 | #include "Node.h" 8 | #include "../IStmtVisitor.h" 9 | 10 | #include 11 | 12 | #define STRELA_IMPL_STMT_VISITOR void accept(Strela::IStmtVisitor& v) override { v.visit(*this); } 13 | 14 | namespace Strela { 15 | class Stmt: public Node { 16 | public: 17 | STRELA_GET_TYPE(Strela::Stmt, Strela::Node); 18 | virtual void accept(IStmtVisitor&) = 0; 19 | 20 | public: 21 | bool returns = false; 22 | }; 23 | } 24 | 25 | #endif -------------------------------------------------------------------------------- /Std/Math.strela: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Stephan Unverwerth 2 | // This code is licensed under MIT license (See LICENSE for details) 3 | 4 | module Std.Math { 5 | import Std.cstdio.*; 6 | 7 | export function frand(): f64 { 8 | return (rand() as f64 / 2147483647 as f64) - 0.5; 9 | //return (rand() as f64 / 65535 as f64) - 0.5; 10 | } 11 | 12 | export function clamp(f: f64): f64 { 13 | if (f > 1.0) return 1.0; 14 | if (f < 0.0) return 0.0; 15 | return f; 16 | } 17 | 18 | export function clamp(f: f32): f32 { 19 | if (f > 1.0) return 1.0; 20 | if (f < 0.0) return 0.0; 21 | return f; 22 | } 23 | } -------------------------------------------------------------------------------- /src/Ast/Param.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Stephan Unverwerth 2 | // This code is licensed under MIT license (See LICENSE for details) 3 | 4 | #ifndef Strela_Ast_AstParam_h 5 | #define Strela_Ast_AstParam_h 6 | 7 | #include "Node.h" 8 | #include "InvalidType.h" 9 | 10 | #include 11 | 12 | namespace Strela { 13 | class Expr; 14 | class TypeDecl; 15 | 16 | class Param: public Node { 17 | public: 18 | STRELA_GET_TYPE(Strela::Param, Strela::Node); 19 | 20 | public: 21 | int index = 0; 22 | std::string name; 23 | Expr* typeExpr = nullptr; 24 | TypeDecl* declType = &InvalidType::instance; 25 | }; 26 | } 27 | 28 | #endif -------------------------------------------------------------------------------- /src/Ast/TypeAliasDecl.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Stephan Unverwerth 2 | // This code is licensed under MIT license (See LICENSE for details) 3 | 4 | #ifndef Strela_Ast_TypeAliasDecl_h 5 | #define Strela_Ast_TypeAliasDecl_h 6 | 7 | #include "TypeDecl.h" 8 | 9 | namespace Strela { 10 | class Expr; 11 | 12 | class TypeAliasDecl: public TypeDecl { 13 | public: 14 | STRELA_GET_TYPE(Strela::TypeAliasDecl, Strela::TypeDecl); 15 | 16 | Node* getMember(const std::string& name) override; 17 | std::vector getMethods(const std::string& name) override; 18 | 19 | public: 20 | Expr* typeExpr = nullptr; 21 | bool isExported = false; 22 | }; 23 | } 24 | 25 | #endif -------------------------------------------------------------------------------- /src/Decompiler.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Stephan Unverwerth 2 | // This code is licensed under MIT license (See LICENSE for details) 3 | 4 | #ifndef Strela_Decompiler_h 5 | #define Strela_Decompiler_h 6 | 7 | #include 8 | #include 9 | 10 | namespace Strela { 11 | class ByteCodeChunk; 12 | class VMValue; 13 | 14 | class Decompiler { 15 | public: 16 | Decompiler(const ByteCodeChunk& chunk): chunk(chunk) {} 17 | 18 | void listing() const; 19 | uint64_t getArg(size_t pos) const; 20 | 21 | private: 22 | void printValue(const VMValue& v) const; 23 | 24 | private: 25 | const ByteCodeChunk& chunk; 26 | }; 27 | } 28 | 29 | #endif -------------------------------------------------------------------------------- /src/Ast/FieldDecl.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Stephan Unverwerth 2 | // This code is licensed under MIT license (See LICENSE for details) 3 | 4 | #ifndef Strela_Ast_AstFieldDecl_h 5 | #define Strela_Ast_AstFieldDecl_h 6 | 7 | #include "Stmt.h" 8 | #include "InvalidType.h" 9 | 10 | #include 11 | 12 | namespace Strela { 13 | class TypeDecl; 14 | class Expr; 15 | 16 | class FieldDecl: public Node { 17 | public: 18 | STRELA_GET_TYPE(Strela::FieldDecl, Strela::Node); 19 | 20 | public: 21 | std::string name; 22 | Expr* typeExpr = nullptr; 23 | TypeDecl* declType = &InvalidType::instance; 24 | 25 | int index = 0; 26 | }; 27 | } 28 | 29 | #endif -------------------------------------------------------------------------------- /src/Ast/Node.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Stephan Unverwerth 2 | // This code is licensed under MIT license (See LICENSE for details) 3 | 4 | #ifndef Strela_Ast_AstNode_h 5 | #define Strela_Ast_AstNode_h 6 | 7 | #include "../TypeInfo.h" 8 | #include "Token.h" 9 | 10 | #include 11 | 12 | namespace Strela { 13 | class SourceFile; 14 | class Node { 15 | public: 16 | Node() {} 17 | virtual ~Node() {} 18 | STRELA_BASE_TYPE(Strela::Node); 19 | 20 | public: 21 | Node* parent = nullptr; 22 | int line = 0; 23 | int lineend = 0; 24 | int column = 0; 25 | const SourceFile* source = nullptr; 26 | int firstToken = 0; 27 | }; 28 | } 29 | #endif -------------------------------------------------------------------------------- /src/Ast/CastExpr.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Stephan Unverwerth 2 | // This code is licensed under MIT license (See LICENSE for details) 3 | 4 | #ifndef Strela_Ast_AstCastExpr_h 5 | #define Strela_Ast_AstCastExpr_h 6 | 7 | #include "Expr.h" 8 | #include "Token.h" 9 | 10 | namespace Strela { 11 | class Implementation; 12 | 13 | class CastExpr: public Expr { 14 | public: 15 | STRELA_GET_TYPE(Strela::CastExpr, Strela::Expr); 16 | STRELA_IMPL_EXPR_VISITOR; 17 | 18 | public: 19 | Expr* sourceExpr = nullptr; 20 | Expr* targetTypeExpr = nullptr; 21 | TypeDecl* targetType = nullptr; 22 | Implementation* implementation = nullptr; 23 | }; 24 | } 25 | 26 | #endif -------------------------------------------------------------------------------- /src/Ast/SubscriptExpr.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Stephan Unverwerth 2 | // This code is licensed under MIT license (See LICENSE for details) 3 | 4 | #ifndef Strela_Ast_AstSubscriptExpr_h 5 | #define Strela_Ast_AstSubscriptExpr_h 6 | 7 | #include "Expr.h" 8 | 9 | #include 10 | #include 11 | 12 | namespace Strela { 13 | class FuncDecl; 14 | 15 | class SubscriptExpr: public Expr { 16 | public: 17 | STRELA_GET_TYPE(Strela::SubscriptExpr, Strela::Expr); 18 | STRELA_IMPL_EXPR_VISITOR; 19 | 20 | public: 21 | Expr* callTarget = nullptr; 22 | std::vector arguments; 23 | FuncDecl* subscriptFunction = nullptr; 24 | }; 25 | } 26 | 27 | #endif -------------------------------------------------------------------------------- /src/Ast/TypeDecl.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Stephan Unverwerth 2 | // This code is licensed under MIT license (See LICENSE for details) 3 | 4 | #ifndef Strela_Ast_TypeDecl_h 5 | #define Strela_Ast_TypeDecl_h 6 | 7 | #include "Node.h" 8 | 9 | #include 10 | #include 11 | 12 | namespace Strela { 13 | class TypeDecl: public Node { 14 | public: 15 | STRELA_GET_TYPE(Strela::TypeDecl, Strela::Node); 16 | virtual Node* getMember(const std::string& name) { return nullptr; } 17 | virtual std::vector getMethods(const std::string& name) { return {}; } 18 | std::string getFullName(); 19 | 20 | public: 21 | std::string _name; 22 | }; 23 | } 24 | 25 | #endif -------------------------------------------------------------------------------- /src/Ast/FuncType.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Stephan Unverwerth 2 | // This code is licensed under MIT license (See LICENSE for details) 3 | 4 | #ifndef Strela_Ast_FuncType_h 5 | #define Strela_Ast_FuncType_h 6 | 7 | #include "TypeDecl.h" 8 | 9 | #include 10 | 11 | namespace Strela { 12 | class FuncType: public TypeDecl { 13 | public: 14 | STRELA_GET_TYPE(Strela::FuncType, Strela::TypeDecl); 15 | 16 | static FuncType* get(TypeDecl* returnType, const std::vector& paramTypes); 17 | 18 | public: 19 | std::vector paramTypes; 20 | TypeDecl* returnType = nullptr; 21 | 22 | static std::vector funcTypes; 23 | }; 24 | } 25 | 26 | #endif -------------------------------------------------------------------------------- /tests/basic/Overloading.strela: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Stephan Unverwerth 2 | // This code is licensed under MIT license (See LICENSE for details) 3 | 4 | module Overloading { 5 | import Std.IO.*; 6 | 7 | function foo(val: int) { 8 | print("foo int called: "); 9 | println(val); 10 | } 11 | 12 | function foo(val: float) { 13 | print("foo float called: "); 14 | println(val); 15 | } 16 | 17 | function foo(val: String) { 18 | print("foo String called: "); 19 | println(val); 20 | } 21 | 22 | function main(args: String[]): int { 23 | foo("this is a string"); 24 | foo(1337); 25 | foo(0.2); 26 | return 0; 27 | } 28 | } -------------------------------------------------------------------------------- /tests/Std/Collections/List.strela: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Stephan Unverwerth 2 | // This code is licensed under MIT license (See LICENSE for details) 3 | 4 | module Tests.Collections.List { 5 | import Std.IO.println; 6 | import Std.Collections.List; 7 | 8 | function main(args: String[]): int { 9 | var list = new List; 10 | list.append(1); 11 | list.append(2); 12 | println(list.length); 13 | println(list[0]); 14 | println(list[1]); 15 | 16 | var list2: List = ["A", "B"]; 17 | println(list2[0]); 18 | println(list2[1]); 19 | 20 | list2.remove(0); 21 | list2.remove(1); 22 | 23 | println(list2.length); 24 | return 0; 25 | } 26 | } -------------------------------------------------------------------------------- /src/Ast/ArrayType.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Stephan Unverwerth 2 | // This code is licensed under MIT license (See LICENSE for details) 3 | 4 | #ifndef Strela_Ast_ArrayType_h 5 | #define Strela_Ast_ArrayType_h 6 | 7 | #include "TypeDecl.h" 8 | 9 | namespace Strela { 10 | class FieldDecl; 11 | 12 | class ArrayType: public TypeDecl { 13 | public: 14 | STRELA_GET_TYPE(Strela::ArrayType, Strela::TypeDecl); 15 | 16 | Node* getMember(const std::string& name) override; 17 | 18 | static ArrayType* get(TypeDecl* base); 19 | 20 | public: 21 | TypeDecl* baseType = nullptr; 22 | FieldDecl* lengthField = nullptr; 23 | static std::map arrayTypes; 24 | }; 25 | } 26 | 27 | #endif -------------------------------------------------------------------------------- /tests/basic/Operators.strela: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Stephan Unverwerth 2 | // This code is licensed under MIT license (See LICENSE for details) 3 | 4 | module Operators { 5 | import Std.IO.*; 6 | 7 | function main(args: String[]): int { 8 | var i: int = 5; 9 | println(i); 10 | 11 | i += 10; println(i); 12 | i -= 5; println(i); 13 | i /= 2; println(i); 14 | i *= 3; println(i); 15 | 16 | i = i + 10; println(i); 17 | i = i - 5; println(i); 18 | i = i / 2; println(i); 19 | i = i * 3; println(i); 20 | 21 | i++; println(i); 22 | i--; println(i); 23 | 24 | println(i % 5); 25 | println(i % 31); 26 | return 0; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/Ast/VarDecl.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Stephan Unverwerth 2 | // This code is licensed under MIT license (See LICENSE for details) 3 | 4 | #ifndef Strela_Ast_AstVarDecl_h 5 | #define Strela_Ast_AstVarDecl_h 6 | 7 | #include "Stmt.h" 8 | #include "InvalidType.h" 9 | 10 | #include 11 | 12 | namespace Strela { 13 | class Expr; 14 | class TypeDecl; 15 | 16 | class VarDecl: public Stmt { 17 | public: 18 | STRELA_GET_TYPE(Strela::VarDecl, Strela::Stmt); 19 | STRELA_IMPL_STMT_VISITOR; 20 | 21 | public: 22 | std::string name; 23 | Expr* typeExpr = nullptr; 24 | Expr* initializer = nullptr; 25 | TypeDecl* declType = &InvalidType::instance; 26 | 27 | int index = 0; 28 | }; 29 | } 30 | 31 | #endif -------------------------------------------------------------------------------- /tests/basic/Unions.strela: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Stephan Unverwerth 2 | // This code is licensed under MIT license (See LICENSE for details) 3 | 4 | module Unions { 5 | import Std.IO.*; 6 | 7 | function printUnion(union: int | String) { 8 | if (union is int) { 9 | print("Union is an int and its value is "); 10 | println(union); 11 | } 12 | else { 13 | print("Union is a String and its value is "); 14 | println(union); 15 | } 16 | } 17 | 18 | function main(args: String[]): int { 19 | 20 | var union: String | int; 21 | 22 | union = 1337; 23 | printUnion(union); 24 | 25 | union = "Hello"; 26 | printUnion(union); 27 | 28 | return 0; 29 | } 30 | } -------------------------------------------------------------------------------- /src/Ast/InterfaceFieldDecl.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Stephan Unverwerth 2 | // This code is licensed under MIT license (See LICENSE for details) 3 | 4 | #ifndef Strela_Ast_AstInterfaceFieldDecl_h 5 | #define Strela_Ast_AstInterfaceFieldDecl_h 6 | 7 | #include "Node.h" 8 | #include "InvalidType.h" 9 | 10 | #include 11 | 12 | namespace Strela { 13 | class Expr; 14 | class TypeDecl; 15 | 16 | class InterfaceFieldDecl: public Node { 17 | public: 18 | STRELA_GET_TYPE(Strela::InterfaceFieldDecl, Strela::Node); 19 | std::string getDescription(); 20 | 21 | public: 22 | std::string name; 23 | Expr* typeExpr = nullptr; 24 | TypeDecl* declType = &InvalidType::instance; 25 | 26 | int index = 0; 27 | }; 28 | } 29 | 30 | #endif -------------------------------------------------------------------------------- /tests/basic/Nullable.strela: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Stephan Unverwerth 2 | // This code is licensed under MIT license (See LICENSE for details) 3 | 4 | module Nullable { 5 | import Std.IO.*; 6 | 7 | function tryPrint(val: String?) { 8 | if (val is String) { 9 | print("Value is: "); 10 | println(val); 11 | } 12 | else { 13 | println("Value is: null"); 14 | } 15 | } 16 | 17 | function main(args: String[]): int { 18 | var value = "Hello, world"; 19 | var ref: String?; 20 | 21 | ref = null; 22 | tryPrint(ref); 23 | 24 | ref = value; 25 | tryPrint(ref); 26 | 27 | ref = "Goodbye, world"; 28 | tryPrint(ref); 29 | 30 | return 0; 31 | } 32 | } -------------------------------------------------------------------------------- /src/Ast/MapLitExpr.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Stephan Unverwerth 2 | // This code is licensed under MIT license (See LICENSE for details) 3 | 4 | #ifndef Strela_Ast_AstMapLitExpr_h 5 | #define Strela_Ast_AstMapLitExpr_h 6 | 7 | #include "Expr.h" 8 | #include "Token.h" 9 | 10 | namespace Strela { 11 | class FuncDecl; 12 | class TypeDecl; 13 | 14 | class MapLitExpr: public Expr { 15 | public: 16 | STRELA_GET_TYPE(Strela::MapLitExpr, Strela::Expr); 17 | STRELA_IMPL_EXPR_VISITOR; 18 | 19 | public: 20 | std::vector keys; 21 | std::vector values; 22 | FuncDecl* constructor = nullptr; 23 | TypeDecl* keyArrayType = &InvalidType::instance; 24 | TypeDecl* valueArrayType = &InvalidType::instance; 25 | }; 26 | } 27 | 28 | #endif -------------------------------------------------------------------------------- /src/Ast/UnionType.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Stephan Unverwerth 2 | // This code is licensed under MIT license (See LICENSE for details) 3 | 4 | #ifndef Strela_Ast_UnionType_h 5 | #define Strela_Ast_UnionType_h 6 | 7 | #include "TypeDecl.h" 8 | 9 | #include 10 | #include 11 | 12 | namespace Strela { 13 | class UnionType: public TypeDecl { 14 | public: 15 | STRELA_GET_TYPE(Strela::UnionType, Strela::TypeDecl); 16 | 17 | static UnionType* get(TypeDecl* left, TypeDecl* right); 18 | TypeDecl* getComplementaryType(TypeDecl* t); 19 | int getTypeTag(TypeDecl* t); 20 | bool containsType(TypeDecl* t); 21 | 22 | public: 23 | std::set containedTypes; 24 | 25 | static std::vector unionTypes; 26 | }; 27 | } 28 | 29 | #endif -------------------------------------------------------------------------------- /tests/basic/Generics.strela: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Stephan Unverwerth 2 | // This code is licensed under MIT license (See LICENSE for details) 3 | 4 | module Generics { 5 | import Std.IO.*; 6 | 7 | class Foo { 8 | var val: T; 9 | function display() { 10 | print("Value is: "); 11 | println(this.val); 12 | } 13 | 14 | function init(v: T) { 15 | print("init() called: "); 16 | println(v); 17 | this.val = v; 18 | } 19 | } 20 | 21 | function main(args: String[]): int { 22 | var s = new Foo("String"); 23 | var i = new Foo(123); 24 | var f = new Foo(1.5); 25 | 26 | s.display(); 27 | i.display(); 28 | f.display(); 29 | return 0; 30 | } 31 | } -------------------------------------------------------------------------------- /tests/basic/Precedence.strela: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Stephan Unverwerth 2 | // This code is licensed under MIT license (See LICENSE for details) 3 | 4 | module Precedence { 5 | import Std.IO.*; 6 | 7 | 8 | function main(args: String[]): int { 9 | if (1 + 2 * 3 + 4 == 11) println("1 + 2 * 3 + 4 == 11"); 10 | if (-1 * 1 == -1) println("-1 * 1 == -1"); 11 | if (1 + 1 > 1) println("1 + 1 > 1"); 12 | if (1 + 2 == 2 + 1) println("1 + 2 == 2 + 1"); 13 | if (true || false == false) println("true || false == false"); 14 | if (!true == false) println("!true == false"); 15 | if (1 + 2 > 1 && 2 + 4 < 10) println("1 + 2 > 1 && 2 + 4 < 10"); 16 | if (1 + 2 >= 3) println("1 + 2 >= 3"); 17 | if (1 + 2 <= 3) println("1 + 2 <= 3"); 18 | return 0; 19 | } 20 | } -------------------------------------------------------------------------------- /Std/Lang/Compiler.strela: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Stephan Unverwerth 2 | // This code is licensed under MIT license (See LICENSE for details) 3 | 4 | module Std.Lang.Compiler { 5 | import Std.IO.*; 6 | import Compiler.Parser.*; 7 | import Compiler.Lexer.*; 8 | import Compiler.Ast.*; 9 | 10 | 11 | function help() { 12 | println("-- The strela compiler --"); 13 | println("Syntax: strela infile [outfile]"); 14 | } 15 | 16 | function main(args: String[]): i32 { 17 | if (args.length < 2) { 18 | help(); 19 | return 1; 20 | } 21 | 22 | var inFile = new File(args[0], "rb"); 23 | var lexer = new Lexer(inFile); 24 | var parser = new Parser(lexer, null); 25 | var mod = parser.parseModule(); 26 | 27 | return 0; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/Lexer.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Stephan Unverwerth 2 | // This code is licensed under MIT license (See LICENSE for details) 3 | 4 | #ifndef Strela_Lexer_h 5 | #define Strela_Lexer_h 6 | 7 | #include "Ast/Token.h" 8 | #include "Pass.h" 9 | 10 | #include 11 | #include 12 | 13 | namespace Strela { 14 | /** 15 | * Lexer for the strela language 16 | */ 17 | class Lexer: public Pass { 18 | public: 19 | Lexer(std::istream& in): in(in), line(1), column(1) {} 20 | std::vector tokenize(); 21 | 22 | private: 23 | int get(); 24 | int peek(); 25 | bool eof(); 26 | bool match(char c); 27 | 28 | private: 29 | int numtokens = 0; 30 | std::istream& in; 31 | int line; 32 | int column; 33 | int ch; 34 | }; 35 | } 36 | 37 | #endif -------------------------------------------------------------------------------- /tests/basic/Enum.strela: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Stephan Unverwerth 2 | // This code is licensed under MIT license (See LICENSE for details) 3 | 4 | module Enum { 5 | import Std.IO.*; 6 | 7 | enum Foo { 8 | A, 9 | B, 10 | C 11 | } 12 | 13 | function main(args: String[]): int { 14 | var a = Foo.A; 15 | var b = Foo.B; 16 | var c = Foo.C; 17 | 18 | if (a == Foo.A) println("a == Foo.A"); 19 | if (a != Foo.B) println("a != Foo.B"); 20 | if (Foo.A != Foo.B) println("Foo.A != Foo.B"); 21 | if (Foo.A == Foo.A) println("Foo.A == Foo.A"); 22 | 23 | a = b; 24 | c = b; 25 | 26 | if (a == Foo.B) println("a == Foo.B"); 27 | if (b == Foo.B) println("b == Foo.B"); 28 | if (c == Foo.B) println("c == Foo.B"); 29 | 30 | return 0; 31 | } 32 | } -------------------------------------------------------------------------------- /src/Ast/IntType.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Stephan Unverwerth 2 | // This code is licensed under MIT license (See LICENSE for details) 3 | 4 | #ifndef Strela_Ast_IntType_h 5 | #define Strela_Ast_IntType_h 6 | 7 | #include "TypeDecl.h" 8 | 9 | namespace Strela { 10 | class IntType: public TypeDecl { 11 | public: 12 | IntType(const std::string& name, bool isSigned, int bytes): isSigned(isSigned), bytes(bytes) { this->_name = name; } 13 | STRELA_GET_TYPE(Strela::IntType, Strela::TypeDecl); 14 | 15 | public: 16 | bool isSigned; 17 | int bytes; 18 | 19 | static IntType u8; 20 | static IntType u16; 21 | static IntType u32; 22 | static IntType u64; 23 | static IntType i8; 24 | static IntType i16; 25 | static IntType i32; 26 | static IntType i64; 27 | }; 28 | } 29 | 30 | #endif -------------------------------------------------------------------------------- /src/VM/GC.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Stephan Unverwerth 2 | // This code is licensed under MIT license (See LICENSE for details) 3 | 4 | #ifndef Strela_VM_GC_h 5 | #define Strela_VM_GC_h 6 | 7 | #include "VMValue.h" 8 | #include "VMObject.h" 9 | #include "VMType.h" 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | namespace Strela { 16 | /** 17 | * Naive mark-and-sweep collector 18 | */ 19 | class GC { 20 | public: 21 | void* allocObject(const VMType* type); 22 | void* allocArray(const VMType* type, uint64_t length); 23 | 24 | void collect(std::vector& stack); 25 | 26 | void lock(void* obj); 27 | void unlock(void* obj); 28 | 29 | private: 30 | void mark(VMObject* object); 31 | 32 | private: 33 | std::list objects; 34 | std::set lockList; 35 | }; 36 | } 37 | 38 | #endif -------------------------------------------------------------------------------- /tests/basic/Export.strela: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Stephan Unverwerth 2 | // This code is licensed under MIT license (See LICENSE for details) 3 | 4 | module Export { 5 | import Std.IO.*; 6 | 7 | export class Baz { 8 | function frob(a: Bumm) { 9 | print("Export.Baz.frob(Bumm) called: "); 10 | println(a.num); 11 | } 12 | } 13 | 14 | class Bumm { 15 | var num: int; 16 | 17 | function init(num: int) { 18 | this.num = num; 19 | } 20 | } 21 | 22 | export function foo() { 23 | println("Export.foo called"); 24 | } 25 | 26 | export function bar() { 27 | println("Export.bar called"); 28 | } 29 | 30 | export function makeBumm(num: int): Bumm { 31 | return new Bumm(num); 32 | } 33 | 34 | function main(args: String[]): int { 35 | foo(); 36 | bar(); 37 | return 0; 38 | } 39 | } -------------------------------------------------------------------------------- /src/Ast/InterfaceMethodDecl.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Stephan Unverwerth 2 | // This code is licensed under MIT license (See LICENSE for details) 3 | 4 | #ifndef Strela_Ast_AstInterfaceMethodDecl_h 5 | #define Strela_Ast_AstInterfaceMethodDecl_h 6 | 7 | #include "Node.h" 8 | 9 | #include 10 | #include 11 | 12 | namespace Strela { 13 | class BlockStmt; 14 | class Param; 15 | class Expr; 16 | class ByteCodeChunk; 17 | class FuncType; 18 | class TypeDecl; 19 | 20 | class InterfaceMethodDecl: public Node { 21 | public: 22 | STRELA_GET_TYPE(Strela::InterfaceMethodDecl, Strela::Node); 23 | std::string getDescription(); 24 | 25 | public: 26 | bool isExported = false; 27 | std::string name; 28 | std::vector params; 29 | Expr* returnTypeExpr = nullptr; 30 | FuncType* type = nullptr; 31 | size_t index = 0; 32 | }; 33 | } 34 | 35 | #endif -------------------------------------------------------------------------------- /tests/Std/JSON.strela: -------------------------------------------------------------------------------- 1 | module JSON { 2 | import Std.JSON; 3 | import Std.IO.println; 4 | 5 | function main(args: String[]): int { 6 | println(JSON.serialize(JSON.parse("1234"))); 7 | println(JSON.serialize(JSON.parse("12.34"))); 8 | println(JSON.serialize(JSON.parse("-1234"))); 9 | println(JSON.serialize(JSON.parse("-12.34"))); 10 | println(JSON.serialize(JSON.parse("\"A\""))); 11 | println(JSON.serialize(JSON.parse("null"))); 12 | println(JSON.serialize(JSON.parse("true"))); 13 | println(JSON.serialize(JSON.parse("false"))); 14 | println(JSON.serialize(JSON.parse("{}"))); 15 | println(JSON.serialize(JSON.parse("[]"))); 16 | 17 | println(JSON.serialize(JSON.parse("[0,1,2,3,4,5]"))); 18 | println(JSON.serialize(JSON.parse("{\"a\":1,\"b\":2}"))); 19 | println(JSON.serialize(JSON.parse("{\"a\":[],\"b\":[0,[],{},null]}"))); 20 | return 0; 21 | } 22 | } -------------------------------------------------------------------------------- /src/VM/VMType.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Stephan Unverwerth 2 | // This code is licensed under MIT license (See LICENSE for details) 3 | 4 | #ifndef Strela_VM_VMType_h 5 | #define Strela_VM_VMType_h 6 | 7 | #include 8 | #include 9 | 10 | namespace Strela { 11 | class VMType; 12 | 13 | class VMField { 14 | public: 15 | std::string name; 16 | VMType* type; 17 | size_t offset; 18 | }; 19 | 20 | class VMType { 21 | public: 22 | size_t index; 23 | std::string name; 24 | bool isObject = false; 25 | bool isArray = false; 26 | bool isEnum = false; 27 | VMType* arrayType = nullptr; 28 | size_t size = 0; 29 | size_t alignment = 0; 30 | size_t objectSize = 0; 31 | size_t objectAlignment = 0; 32 | std::vector fields; 33 | std::vector enumValues; 34 | std::vector unionTypes; 35 | }; 36 | } 37 | 38 | #endif -------------------------------------------------------------------------------- /src/Ast/InterfaceDecl.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Stephan Unverwerth 2 | // This code is licensed under MIT license (See LICENSE for details) 3 | 4 | #include "InterfaceDecl.h" 5 | #include "InterfaceMethodDecl.h" 6 | #include "InterfaceFieldDecl.h" 7 | 8 | namespace Strela { 9 | Node* InterfaceDecl::getMember(const std::string& name) { 10 | for (auto&& method: methods) { 11 | if (method->name == name) { 12 | return method; 13 | } 14 | } 15 | for (auto&& field: fields) { 16 | if (field->name == name) { 17 | return field; 18 | } 19 | } 20 | return nullptr; 21 | } 22 | 23 | std::vector InterfaceDecl::getMethods(const std::string& name) { 24 | std::vector result; 25 | for (auto&& method: methods) { 26 | if (method->name == name) { 27 | result.push_back(method); 28 | } 29 | } 30 | return result; 31 | } 32 | } -------------------------------------------------------------------------------- /install.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | set STRELAPATH=%HOMEDRIVE%%HOMEPATH%\.strela 3 | 4 | if not exist "Release\strela.exe" ( 5 | echo !!! strela.exe does not exist. Please build the Visual Studio project in release mode and rerun this script 6 | exit /B 1 7 | ) 8 | 9 | echo ### Creating strela folder in %STRELAPATH% 10 | if not exist "%STRELAPATH%" ( 11 | mkdir %STRELAPATH% 12 | echo ### Done 13 | ) else ( 14 | echo ### Already exists 15 | ) 16 | 17 | echo ### Creating lib folder in %STRELAPATH% 18 | if not exist "%STRELAPATH%\lib" ( 19 | mkdir %STRELAPATH%\lib 20 | echo ### Done 21 | ) else ( 22 | echo ### Already exists 23 | ) 24 | 25 | 26 | echo ### Copying strela.exe 27 | if exist %STRELAPATH%\strela.exe.old del %STRELAPATH%\strela.exe.old 28 | if exist %STRELAPATH%\strela.exe ren %STRELAPATH%\strela.exe strela.exe.old 29 | copy Release\strela.exe %STRELAPATH% 30 | echo ### Done 31 | 32 | echo ### Copying standard library 33 | xcopy /E /I /Y /F Std %STRELAPATH%\lib\Std 34 | echo ### Done -------------------------------------------------------------------------------- /src/Scope.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Stephan Unverwerth 2 | // This code is licensed under MIT license (See LICENSE for details) 3 | 4 | #ifndef Strela_Scope_h 5 | #define Strela_Scope_h 6 | 7 | #include 8 | 9 | namespace Strela { 10 | class Node; 11 | 12 | class Symbol { 13 | public: 14 | Symbol(Node* node): node(node) {} 15 | 16 | public: 17 | Node* node; 18 | // for overloaded functions 19 | Symbol* next = nullptr; 20 | }; 21 | 22 | class Scope { 23 | public: 24 | Scope(Scope* parent): parent(parent) {} 25 | ~Scope(); 26 | 27 | Scope* getParent(); 28 | void setParent(Scope* p); 29 | void add(const std::string& name, Node* node); 30 | Symbol* find(const std::string& name); 31 | 32 | private: 33 | void add(const std::string& name, Symbol* symbol); 34 | 35 | private: 36 | Scope* parent; 37 | std::map symbols; 38 | }; 39 | } 40 | 41 | #endif -------------------------------------------------------------------------------- /tests/basic/Arrays.strela: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Stephan Unverwerth 2 | // This code is licensed under MIT license (See LICENSE for details) 3 | 4 | module Arrays { 5 | import Std.IO.*; 6 | 7 | class Custom { 8 | function [](a: int, b: int) { 9 | print("Custom array subscript called: "); 10 | print(a); 11 | print(", "); 12 | println(b); 13 | } 14 | } 15 | 16 | function main(args: String[]): int { 17 | var arr = ["First", "Second", "Third", "Fourth"]; 18 | print("String array length: "); 19 | println(arr.length); 20 | println(arr[0]); 21 | println(arr[1]); 22 | println(arr[2]); 23 | println(arr[3]); 24 | 25 | var arr2 = [1,2,3]; 26 | print("Int array length: "); 27 | println(arr2.length); 28 | println(arr2[0]); 29 | println(arr2[1]); 30 | println(arr2[2]); 31 | 32 | var c = new Custom; 33 | c[0,1]; 34 | 35 | return 0; 36 | } 37 | } -------------------------------------------------------------------------------- /src/Ast/FuncType.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Stephan Unverwerth 2 | // This code is licensed under MIT license (See LICENSE for details) 3 | 4 | #include "FuncType.h" 5 | 6 | #include 7 | 8 | namespace Strela { 9 | FuncType* FuncType::get(TypeDecl* returnType, const std::vector& paramTypes) { 10 | for (auto&& ftype: funcTypes) { 11 | if (ftype->returnType == returnType && ftype->paramTypes == paramTypes) return ftype; 12 | } 13 | 14 | std::stringstream sstr; 15 | sstr << "("; 16 | for (auto&& p: paramTypes) { 17 | sstr << p->getFullName(); 18 | if (&p != ¶mTypes.back()) { 19 | sstr << ", "; 20 | } 21 | } 22 | sstr << "): " << returnType->getFullName(); 23 | auto ftype = new FuncType(); 24 | ftype->_name = sstr.str(); 25 | ftype->returnType = returnType; 26 | ftype->paramTypes = paramTypes; 27 | funcTypes.push_back(ftype); 28 | return ftype; 29 | } 30 | } -------------------------------------------------------------------------------- /src/Ast/Expr.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Stephan Unverwerth 2 | // This code is licensed under MIT license (See LICENSE for details) 3 | 4 | #ifndef Strela_Ast_AstExpr_h 5 | #define Strela_Ast_AstExpr_h 6 | 7 | #include "Node.h" 8 | #include "../IExprVisitor.h" 9 | #include "InvalidType.h" 10 | #include 11 | 12 | #define STRELA_IMPL_EXPR_VISITOR void accept(Strela::IExprVisitor& v) override { v.visit(*this); } 13 | 14 | namespace Strela { 15 | class TypeDecl; 16 | class FuncDecl; 17 | 18 | class Refinement { 19 | public: 20 | Node* node; 21 | TypeDecl* type; 22 | }; 23 | 24 | class Expr: public Node { 25 | public: 26 | STRELA_GET_TYPE(Strela::Expr, Strela::Node); 27 | virtual void accept(IExprVisitor&) = 0; 28 | 29 | public: 30 | TypeDecl* type = &InvalidType::instance; 31 | TypeDecl* typeValue = &InvalidType::instance; 32 | Node* node = nullptr; 33 | Expr* arrayIndex = nullptr; 34 | Expr* context = nullptr; 35 | std::vector candidates; 36 | }; 37 | } 38 | 39 | #endif -------------------------------------------------------------------------------- /src/Ast/FuncDecl.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Stephan Unverwerth 2 | // This code is licensed under MIT license (See LICENSE for details) 3 | 4 | #ifndef Strela_Ast_AstFuncDecl_h 5 | #define Strela_Ast_AstFuncDecl_h 6 | 7 | #include "Node.h" 8 | 9 | #include 10 | #include 11 | 12 | namespace Strela { 13 | class Param; 14 | class Expr; 15 | class FuncType; 16 | class Stmt; 17 | class VM; 18 | 19 | typedef void(*BuiltinFunction)(VM&); 20 | 21 | class FuncDecl: public Node { 22 | public: 23 | STRELA_GET_TYPE(Strela::FuncDecl, Strela::Node); 24 | 25 | public: 26 | bool returns = false; 27 | bool isExported = false; 28 | std::string name; 29 | std::vector params; 30 | Expr* returnTypeExpr = nullptr; 31 | FuncType* declType = nullptr; 32 | std::vector stmts; 33 | size_t opcodeStart = 0xdeadbeef; 34 | int numVariables = 0; 35 | bool isPrototype = false; 36 | bool isExternal = false; 37 | BuiltinFunction builtin = nullptr; 38 | }; 39 | } 40 | 41 | #endif -------------------------------------------------------------------------------- /tests/Std/Collections/Map.strela: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Stephan Unverwerth 2 | // This code is licensed under MIT license (See LICENSE for details) 3 | 4 | module Tests.Collections.Map { 5 | import Std.IO.print; 6 | import Std.IO.println; 7 | import Std.Collections.Map; 8 | 9 | function main(args: String[]): int { 10 | var map = new Map; 11 | map.set("twenty one", 21); 12 | map.set("fourty two", 42); 13 | map.set("thirteen", 13); 14 | 15 | print("twenty one = "); 16 | println(map["twenty one"]); 17 | print("fourty two = "); 18 | println(map["fourty two"]); 19 | print("thirteen = "); 20 | println(map["thirteen"]); 21 | 22 | var map2: Map = { 23 | "US": "United States", 24 | "GB": "Great Britain", 25 | "DE": "Deutschland" 26 | }; 27 | 28 | println(map2["US"]); 29 | println(map2["GB"]); 30 | println(map2["DE"]); 31 | 32 | map2.remove("US"); 33 | println(map2.keyIndex("US")); 34 | 35 | return 0; 36 | } 37 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Stephan Unverwerth 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/Pass.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Stephan Unverwerth 2 | // This code is licensed under MIT license (See LICENSE for details) 3 | 4 | #ifndef Strela_Pass_h 5 | #define Strela_Pass_h 6 | 7 | #include 8 | 9 | namespace Strela { 10 | class Node; 11 | struct Token; 12 | class SourceFile; 13 | 14 | class Pass { 15 | public: 16 | bool hadErrors(); 17 | bool hadWarnings(); 18 | 19 | protected: 20 | void info(const std::string& msg); 21 | void info(const Node& n, const std::string& msg); 22 | void info(const SourceFile& file, const Token& n, const std::string& msg); 23 | 24 | void warning(const std::string& msg); 25 | void warning(const Node& n, const std::string& msg); 26 | void warning(const SourceFile& file, const Token& n, const std::string& msg); 27 | 28 | void error(const std::string& msg); 29 | void error(const Node& n, const std::string& msg); 30 | void error(const SourceFile& file, const Token& n, const std::string& msg); 31 | 32 | private: 33 | bool hasErrors = false; 34 | bool hasWarnings = false; 35 | }; 36 | } 37 | 38 | #endif -------------------------------------------------------------------------------- /src/VM/Debugger.h: -------------------------------------------------------------------------------- 1 | #ifndef Strela_VM_Debugger_h 2 | #define Strela_VM_Debugger_h 3 | 4 | #include "Opcode.h" 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | namespace Strela { 11 | class VM; 12 | class VMType; 13 | 14 | struct Breakpoint { 15 | size_t address; 16 | Opcode originalOpcode; 17 | bool once; 18 | }; 19 | 20 | class Debugger { 21 | public: 22 | Debugger(unsigned short port, VM& vm); 23 | ~Debugger(); 24 | 25 | int run(); 26 | 27 | void addBreakpoint(size_t address, bool once); 28 | void addBreakpoint(const std::string& file, size_t line, bool once); 29 | void removeBreakpoint(const std::string& file, size_t line); 30 | void removeBreakpoints(const std::string& file); 31 | void step(); 32 | 33 | private: 34 | void write(const std::string& text); 35 | void write(const VMType& type, const void* val); 36 | 37 | int socket = -1; 38 | VM& vm; 39 | std::map breakpoints; 40 | std::deque commands; 41 | std::string buffer; 42 | }; 43 | } 44 | 45 | #endif -------------------------------------------------------------------------------- /src/Ast/ArrayType.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Stephan Unverwerth 2 | // This code is licensed under MIT license (See LICENSE for details) 3 | 4 | #include "ArrayType.h" 5 | #include "FieldDecl.h" 6 | #include "IdExpr.h" 7 | #include "IntType.h" 8 | 9 | namespace Strela { 10 | ArrayType* ArrayType::get(TypeDecl* base) { 11 | auto it = arrayTypes.find(base); 12 | if (it != arrayTypes.end()) return it->second; 13 | auto atype = new ArrayType(); 14 | atype->_name = base->getFullName() + "[]"; 15 | atype->baseType = base; 16 | atype->lengthField = new FieldDecl(); 17 | atype->lengthField->parent = atype; 18 | atype->lengthField->name = "length"; 19 | atype->lengthField->typeExpr = new IdExpr(); 20 | static_cast(atype->lengthField->typeExpr)->name = "u64"; 21 | atype->lengthField->declType = atype->lengthField->typeExpr->type = &IntType::u64; 22 | atype->lengthField->index = 0; 23 | arrayTypes.insert(std::make_pair(base, atype)); 24 | return atype; 25 | } 26 | 27 | Node* ArrayType::getMember(const std::string& name) { 28 | return name == "length" ? lengthField : nullptr; 29 | } 30 | } -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | CC=g++ 2 | LNFLAGS=-lffi -ldl 3 | SRCDIR=./src 4 | SRCDIRS=$(shell find $(SRCDIR) -type d) 5 | SRC=$(foreach dir, $(SRCDIRS), $(wildcard $(dir)/*.cpp)) 6 | 7 | ifndef DEBUG 8 | CXXFLAGS=-std=c++11 -MMD -MP -O3 9 | OBJDIR=Release 10 | EXECUTABLE=Release/strela 11 | else 12 | CXXFLAGS=-std=c++11 -g -MMD -MP -D _DEBUG 13 | OBJDIR=Debug 14 | EXECUTABLE=Debug/strela 15 | endif 16 | 17 | OBJDIRS=$(pathsubst $(SRCDIRS)/%,$(OBJDIRS)/%,$(SRCDIRS)) 18 | _OBJ=$(SRC:.cpp=.o) 19 | OBJ=$(patsubst $(SRCDIR)/%,$(OBJDIR)/%,$(_OBJ)) 20 | DEPS = ${OBJ:.o=.d} 21 | 22 | .PHONY: clean install install-home test 23 | 24 | strela: $(EXECUTABLE) 25 | 26 | $(EXECUTABLE): $(OBJ) 27 | $(CC) $^ $(CXXFLAGS) $(LNFLAGS) -o $@ 28 | 29 | $(OBJDIR)/%.o: $(SRCDIR)/%.cpp 30 | @[ -d $(@D) ] || mkdir -p $(@D) 31 | $(CC) $< $(CXXFLAGS) -c -o $@ 32 | 33 | install: strela 34 | install Release/strela /usr/local/bin/strela 35 | install -d /usr/local/lib/strela 36 | cp -r Std /usr/local/lib/strela 37 | 38 | install-home: strela 39 | install Release/strela ~/bin/strela 40 | install -d ~/.strela/lib/ 41 | cp -r Std ~/.strela/lib 42 | 43 | clean: 44 | rm -rf Release Debug 45 | 46 | test: strela 47 | bash ./test.sh 48 | 49 | -include ${DEPS} 50 | -------------------------------------------------------------------------------- /examples/Client.strela: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Stephan Unverwerth 2 | // This code is licensed under MIT license (See LICENSE for details) 3 | 4 | module Examples.Client { 5 | import Std.Net.HTTP.*; 6 | import Std.Net.IPAddr; 7 | import Std.IO.*; 8 | 9 | function main(args: String[]): int { 10 | 11 | var client = new Client; 12 | client.connect(new IPAddr(216, 58, 208, 35), 80); // google 13 | var request = new Request; 14 | request.path = "/search?q=test"; 15 | request.headers.set("Host", "www.google.de"); 16 | request.headers.set("User-Agent", "strela language test client"); 17 | request.headers.set("Accept", "text/html,*/*"); 18 | request.headers.set("Accept-Charset", "utf-8"); 19 | request.headers.set("Accept-Language", "de-DE,de;q=0.9,en-US;q=0.8,en;q=0.7"); 20 | request.headers.set("Connection", "close"); 21 | 22 | var response = client.request(request); 23 | var i: int = 0; 24 | while (i < response.headers.keys.length) { 25 | println(response.headers.keys[i] + ": " + response.headers.values[i]); 26 | i++; 27 | } 28 | println(response.body); 29 | 30 | return 0; 31 | } 32 | } -------------------------------------------------------------------------------- /Std/csockets.strela: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Stephan Unverwerth 2 | // This code is licensed under MIT license (See LICENSE for details) 3 | 4 | module Std.csockets { 5 | 6 | export class sockaddr_in { 7 | var family: u16; 8 | var port: u16; 9 | var addr: u32; 10 | var pad1: i64; 11 | } 12 | 13 | export external function socket(domain: i32, socktype: i32, protocol: i32): i32; 14 | export external function connect(sock: i32, addr: sockaddr_in, len: i32): i32; 15 | export external function bind(sock: i32, addr: sockaddr_in, len: i32): i32; 16 | export external function listen(sock: i32, backlog: i32): i32; 17 | export external function accept(sock: i32, addr: sockaddr_in, len: Ptr): i32; 18 | export external function shutdown(sock: i32, how: i32): i32; 19 | export external function recv(sock: i32, buffer: String, len: i32, flags: i32): i32; 20 | export external function send(sock: i32, buffer: String, len: i32, flags: i32): i32; 21 | export external function close(sock: i32): i32; 22 | 23 | export external function htons(val: u16): u16; 24 | export external function htonl(val: u32): u32; 25 | export external function ntohs(val: u16): u16; 26 | export external function ntohl(val: u32): u32; 27 | } -------------------------------------------------------------------------------- /src/Ast/InterfaceDecl.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Stephan Unverwerth 2 | // This code is licensed under MIT license (See LICENSE for details) 3 | 4 | #ifndef Strela_Ast_AstInterfaceDecl_h 5 | #define Strela_Ast_AstInterfaceDecl_h 6 | 7 | #include "TypeDecl.h" 8 | 9 | #include 10 | #include 11 | 12 | namespace Strela { 13 | class InterfaceDecl; 14 | class InterfaceMethodDecl; 15 | class InterfaceFieldDecl; 16 | class ClassDecl; 17 | class FuncDecl; 18 | class FieldDecl; 19 | 20 | class Implementation { 21 | public: 22 | InterfaceDecl* interface; 23 | ClassDecl* _class; 24 | std::vector classMethods; 25 | std::vector classFields; 26 | }; 27 | 28 | class InterfaceDecl: public TypeDecl { 29 | public: 30 | STRELA_GET_TYPE(Strela::InterfaceDecl, Strela::TypeDecl); 31 | 32 | Node* getMember(const std::string& name) override; 33 | std::vector getMethods(const std::string& name) override; 34 | 35 | public: 36 | bool isExported = false; 37 | std::vector methods; 38 | std::vector fields; 39 | 40 | std::map implementations; 41 | }; 42 | } 43 | 44 | #endif -------------------------------------------------------------------------------- /src/Ast/ClassDecl.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Stephan Unverwerth 2 | // This code is licensed under MIT license (See LICENSE for details) 3 | 4 | #ifndef Strela_Ast_AstClassDecl_h 5 | #define Strela_Ast_AstClassDecl_h 6 | 7 | #include "TypeDecl.h" 8 | 9 | #include 10 | #include 11 | 12 | namespace Strela { 13 | class FuncDecl; 14 | class FieldDecl; 15 | class GenericParam; 16 | 17 | class ClassDecl: public TypeDecl { 18 | public: 19 | ClassDecl() = default; 20 | ClassDecl(const std::string& name) { this->_name = name; } 21 | STRELA_GET_TYPE(Strela::ClassDecl, Strela::TypeDecl); 22 | 23 | Node* getMember(const std::string& name) override; 24 | std::vector getMethods(const std::string& name) override; 25 | 26 | ClassDecl* getReifiedClass(const std::vector& typeArgs); 27 | 28 | public: 29 | bool isResolved = false; 30 | bool isExported = false; 31 | std::vector genericParams; 32 | std::vector genericArguments; 33 | std::vector methods; 34 | std::vector fields; 35 | static ClassDecl* String; 36 | std::vector reifiedClasses; 37 | ClassDecl* genericBase = nullptr; 38 | }; 39 | } 40 | 41 | #endif -------------------------------------------------------------------------------- /src/IExprVisitor.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Stephan Unverwerth 2 | // This code is licensed under MIT license (See LICENSE for details) 3 | 4 | #ifndef Strela_IExprVisitor_h 5 | #define Strela_IExprVisitor_h 6 | 7 | namespace Strela { 8 | class IExprVisitor { 9 | public: 10 | virtual void visit(class IdExpr&) = 0; 11 | virtual void visit(class LitExpr&) = 0; 12 | virtual void visit(class CallExpr&) = 0; 13 | virtual void visit(class BinopExpr&) = 0; 14 | virtual void visit(class ScopeExpr&) = 0; 15 | virtual void visit(class NewExpr&) = 0; 16 | virtual void visit(class AssignExpr&) = 0; 17 | virtual void visit(class PostfixExpr&) = 0; 18 | virtual void visit(class UnaryExpr&) = 0; 19 | virtual void visit(class ThisExpr&) = 0; 20 | virtual void visit(class CastExpr&) = 0; 21 | virtual void visit(class IsExpr&) = 0; 22 | virtual void visit(class ArrayLitExpr&) = 0; 23 | virtual void visit(class SubscriptExpr&) = 0; 24 | virtual void visit(class ArrayTypeExpr&) = 0; 25 | virtual void visit(class MapLitExpr&) = 0; 26 | virtual void visit(class NullableTypeExpr&) = 0; 27 | virtual void visit(class UnionTypeExpr&) = 0; 28 | virtual void visit(class GenericReificationExpr&) = 0; 29 | }; 30 | } 31 | 32 | #endif -------------------------------------------------------------------------------- /src/Ast/ModDecl.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Stephan Unverwerth 2 | // This code is licensed under MIT license (See LICENSE for details) 3 | 4 | #ifndef Strela_Ast_AstModDecl_h 5 | #define Strela_Ast_AstModDecl_h 6 | 7 | #include "TypeDecl.h" 8 | 9 | #include 10 | #include 11 | 12 | namespace Strela { 13 | class FuncDecl; 14 | class ClassDecl; 15 | class InterfaceDecl; 16 | class EnumDecl; 17 | class ImportStmt; 18 | class TypeAliasDecl; 19 | 20 | class ModDecl: public TypeDecl { 21 | public: 22 | STRELA_GET_TYPE(Strela::ModDecl, Strela::TypeDecl); 23 | 24 | Node* getMember(const std::string& name) override; 25 | ClassDecl* getClass(const std::string& name); 26 | TypeAliasDecl* getAlias(const std::string& name); 27 | EnumDecl* getEnum(const std::string& name); 28 | std::vector getFunctions(const std::string& name); 29 | void addFunction(FuncDecl* func); 30 | void addClass(ClassDecl* cls); 31 | 32 | public: 33 | std::vector imports; 34 | std::vector functions; 35 | std::vector classes; 36 | std::vector interfaces; 37 | std::vector enums; 38 | std::vector typeAliases; 39 | std::string filename; 40 | }; 41 | } 42 | 43 | #endif -------------------------------------------------------------------------------- /src/Scope.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Stephan Unverwerth 2 | // This code is licensed under MIT license (See LICENSE for details) 3 | 4 | #include "Scope.h" 5 | #include "exceptions.h" 6 | #include "Ast/FuncDecl.h" 7 | 8 | namespace Strela { 9 | Scope* Scope::getParent() { 10 | return parent; 11 | } 12 | 13 | Scope::~Scope() { 14 | for (auto&& it: symbols) { 15 | //delete it.second; 16 | } 17 | } 18 | 19 | void Scope::add(const std::string& name, Node* node) { 20 | add(name, new Symbol(node)); 21 | } 22 | 23 | void Scope::add(const std::string& name, Symbol* symbol) { 24 | auto it = symbols.find(name); 25 | if (it != symbols.end()) { 26 | if (symbol->node->as() && it->second->node->as()) { 27 | symbol->next = it->second; 28 | it->second = symbol; 29 | } 30 | else { 31 | throw DuplicateSymbolException("Duplicate symbol " + name); 32 | } 33 | } 34 | 35 | symbols.insert(std::make_pair(name, symbol)); 36 | } 37 | 38 | Symbol* Scope::find(const std::string& name) { 39 | auto it = symbols.find(name); 40 | if (it != symbols.end()) return it->second; 41 | if (parent) return parent->find(name); 42 | return nullptr; 43 | } 44 | 45 | void Scope::setParent(Scope* p) { 46 | parent = p; 47 | } 48 | } -------------------------------------------------------------------------------- /test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | STRELA=Release/strela 4 | if [ $# -gt 0 ]; then 5 | if [ -d $1 ]; then 6 | DIR=$1 7 | else 8 | DIR="" 9 | fi 10 | else 11 | DIR="tests/" 12 | fi 13 | 14 | if [ $DIR ]; then 15 | ok=0; 16 | err=0; 17 | for fn in `find $DIR -type f -name '*.strela'`; do 18 | TESTDIR=`dirname $fn` 19 | if [ "$CURDIR" != "$TESTDIR" ]; then 20 | echo -e "\n>>> $TESTDIR" 21 | CURDIR="$TESTDIR" 22 | fi 23 | 24 | if $0 $fn; then 25 | ok=$((ok+1)) 26 | else 27 | err=$((err+1)) 28 | fi 29 | done 30 | echo '' 31 | if [ $err -gt 0 ]; then 32 | printf "\033[41;30m" 33 | elif [ $err -eq 0 ]; then 34 | printf "\033[42;30m" 35 | fi 36 | echo -e "Ran $((err+ok)) tests. $ok ok, $err failed.\033[0m" 37 | exit $err 38 | else 39 | MODNAME=`basename $1 .strela` 40 | DIRNAME=`dirname $1` 41 | printf "$1 " 42 | if output=$($STRELA --search ./ --timeout 5 $1); then 43 | echo "$output" | diff -u --strip-trailing-cr $DIRNAME/$MODNAME.out - # &>/dev/null 44 | if [ $? == 0 ]; then 45 | echo -e "\033[32mOK\033[0m" 46 | exit 0 47 | else 48 | echo -e "\033[31mDiff\033[0m" 49 | exit 1 50 | fi 51 | else 52 | echo -e "\033[31mError\033[0m" 53 | exit -1 54 | fi 55 | 56 | fi -------------------------------------------------------------------------------- /src/Ast/ImportStmt.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Stephan Unverwerth 2 | // This code is licensed under MIT license (See LICENSE for details) 3 | 4 | #ifndef Strela_Ast_AstImportStmt_h 5 | #define Strela_Ast_AstImportStmt_h 6 | 7 | #include "Node.h" 8 | 9 | #include 10 | #include 11 | 12 | namespace Strela { 13 | class ModDecl; 14 | 15 | class ImportStmt: public Node { 16 | public: 17 | STRELA_GET_TYPE(Strela::ImportStmt, Strela::Node); 18 | 19 | std::string getFullName(const char* separator = ".") { 20 | std::string result; 21 | for (size_t i = 0; i < parts.size(); ++i) { 22 | result += parts[i]; 23 | if (i < parts.size() - 1) { 24 | result += separator; 25 | } 26 | } 27 | return result; 28 | } 29 | 30 | std::string getBaseName(const char* separator = ".") { 31 | std::string result; 32 | for (size_t i = 0; i < parts.size() - 1; ++i) { 33 | result += parts[i]; 34 | if (i < parts.size() - 2) { 35 | result += separator; 36 | } 37 | } 38 | return result; 39 | } 40 | 41 | public: 42 | std::vector parts; 43 | bool all; 44 | bool importModule = false; 45 | ModDecl* module = nullptr; 46 | }; 47 | } 48 | 49 | #endif -------------------------------------------------------------------------------- /tests/basic/Interface.strela: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Stephan Unverwerth 2 | // This code is licensed under MIT license (See LICENSE for details) 3 | 4 | module Interface { 5 | import Std.IO.*; 6 | 7 | interface ForceUser { 8 | function getName(): String; 9 | function foo(i: int): String; 10 | } 11 | 12 | class Vader { 13 | var name: String; 14 | 15 | function init() { 16 | this.name = "Darth Vader"; 17 | } 18 | 19 | function getName(): String { 20 | return this.name; 21 | } 22 | 23 | function foo(i: int): String { 24 | return "I am your father."; 25 | } 26 | } 27 | 28 | class Yoda { 29 | var name: String; 30 | 31 | function init() { 32 | this.name = "Master Yoda"; 33 | } 34 | 35 | function getName(): String { 36 | return this.name; 37 | } 38 | 39 | function foo(i: int): String { 40 | return "Do or do not. There is no try."; 41 | } 42 | } 43 | 44 | function printFoo(user: ForceUser) { 45 | print("My name is "); 46 | print(user.getName()); 47 | println("."); 48 | println(user.foo(1)); 49 | } 50 | 51 | function main(args: String[]): int { 52 | var vader = new Vader; 53 | var yoda = new Yoda; 54 | 55 | printFoo(vader); 56 | printFoo(yoda); 57 | 58 | return 0; 59 | } 60 | } -------------------------------------------------------------------------------- /src/Ast/types.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Stephan Unverwerth 2 | // This code is licensed under MIT license (See LICENSE for details) 3 | 4 | #include "VoidType.h" 5 | #include "BoolType.h" 6 | #include "NullType.h" 7 | #include "VoidType.h" 8 | #include "TypeType.h" 9 | #include "OverloadedFuncType.h" 10 | #include "IntType.h" 11 | #include "FloatType.h" 12 | #include "FuncType.h" 13 | #include "ClassDecl.h" 14 | #include "InvalidType.h" 15 | #include "ArrayType.h" 16 | #include "PointerType.h" 17 | #include "Token.h" 18 | 19 | namespace Strela { 20 | VoidType VoidType::instance; 21 | NullType NullType::instance; 22 | BoolType BoolType::instance; 23 | TypeType TypeType::instance; 24 | OverloadedFuncType OverloadedFuncType::instance; 25 | 26 | IntType IntType::u8("u8", false, 1); 27 | IntType IntType::u16("u16", false, 2); 28 | IntType IntType::u32("u32", false, 4); 29 | IntType IntType::u64("u64", false, 8); 30 | IntType IntType::i8("i8", true, 1); 31 | IntType IntType::i16("i16", true, 2); 32 | IntType IntType::i32("i32", true, 4); 33 | IntType IntType::i64("i64", true, 8); 34 | 35 | FloatType FloatType::f32("f32", 4); 36 | FloatType FloatType::f64("f64", 8); 37 | 38 | InvalidType InvalidType::instance; 39 | 40 | ClassDecl* ClassDecl::String = nullptr; 41 | 42 | PointerType PointerType::instance; 43 | 44 | std::map ArrayType::arrayTypes; 45 | std::vector FuncType::funcTypes; 46 | } -------------------------------------------------------------------------------- /src/VM/VM.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Stephan Unverwerth 2 | // This code is licensed under MIT license (See LICENSE for details) 3 | 4 | #ifndef Strela_VM_VM_h 5 | #define Strela_VM_VM_h 6 | 7 | #include "Opcode.h" 8 | #include "VMValue.h" 9 | #include "GC.h" 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | struct Frame { 16 | size_t bp; 17 | size_t ip; 18 | }; 19 | 20 | namespace Strela { 21 | class ByteCodeChunk; 22 | 23 | class VM { 24 | public: 25 | VM(ByteCodeChunk& chunk, const std::vector& arguments); 26 | VMValue run(); 27 | void step(size_t maxOps); 28 | 29 | std::string printCallStack(); 30 | 31 | void push(const VMValue& val); 32 | VMValue pop(); 33 | void pop(size_t num); 34 | VMValue peek(size_t idx); 35 | void poke(size_t idx, const VMValue& val); 36 | 37 | template T read(); 38 | 39 | void checkRead(const VMValue& val, int64_t offset); 40 | void checkWrite(const VMValue& val, int64_t offset); 41 | 42 | void writeSample(); 43 | 44 | public: 45 | enum { 46 | RUNNING, 47 | STOPPED, 48 | FINISHED, 49 | } status; 50 | 51 | bool halt = false; 52 | VMValue exitCode; 53 | int numallocs = 0; 54 | ByteCodeChunk& chunk; 55 | Opcode op; 56 | GC gc; 57 | size_t ip; 58 | size_t bp; 59 | std::vector stack; 60 | std::vector callStack; 61 | }; 62 | } 63 | 64 | #endif -------------------------------------------------------------------------------- /Std/cstdio.strela: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Stephan Unverwerth 2 | // This code is licensed under MIT license (See LICENSE for details) 3 | 4 | module Std.cstdio { 5 | // File IO 6 | export external function fopen(name: String, mode: String): u32; 7 | export external function fclose(file: u32): i32; 8 | export external function feof(file: u32): i32; 9 | export external function fread(buffer: Ptr, size: u32, count: u32, file: u32): u32; 10 | export external function fwrite(buffer: Ptr, size: u32, count: u32, file: u32): u32; 11 | export external function fgetc(file: u32): i32; 12 | export external function ungetc(ch: i32, file: u32): i32; 13 | export external function fseek(file: u32, offset: i32, whence: i32): i32; 14 | export external function ftell(file: u32): i32; 15 | 16 | // Strings 17 | export external function strlen(str: String): i32; 18 | export external function itoa(val: i32, str: String, base: i32): u64; 19 | export external function atoi(str: String): i32; 20 | 21 | // Random 22 | export external function rand(): i32; 23 | 24 | // Math 25 | export external function sqrt(f: f64): f64; 26 | export external function sin(r: f64): f64; 27 | export external function cos(r: f64): f64; 28 | export external function tan(r: f64): f64; 29 | 30 | export external function sqrtf(f: f32): f32; 31 | export external function sinf(r: f32): f32; 32 | export external function cosf(r: f32): f32; 33 | export external function tanf(r: f32): f32; 34 | } -------------------------------------------------------------------------------- /strela.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.27004.2005 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "strela", "strela.vcxproj", "{814F10EC-003D-488E-967B-83EE8276E315}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|x64 = Debug|x64 11 | Debug|x86 = Debug|x86 12 | Release|x64 = Release|x64 13 | Release|x86 = Release|x86 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {814F10EC-003D-488E-967B-83EE8276E315}.Debug|x64.ActiveCfg = Debug|x64 17 | {814F10EC-003D-488E-967B-83EE8276E315}.Debug|x64.Build.0 = Debug|x64 18 | {814F10EC-003D-488E-967B-83EE8276E315}.Debug|x86.ActiveCfg = Debug|Win32 19 | {814F10EC-003D-488E-967B-83EE8276E315}.Debug|x86.Build.0 = Debug|Win32 20 | {814F10EC-003D-488E-967B-83EE8276E315}.Release|x64.ActiveCfg = Release|x64 21 | {814F10EC-003D-488E-967B-83EE8276E315}.Release|x64.Build.0 = Release|x64 22 | {814F10EC-003D-488E-967B-83EE8276E315}.Release|x86.ActiveCfg = Release|Win32 23 | {814F10EC-003D-488E-967B-83EE8276E315}.Release|x86.Build.0 = Release|Win32 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | GlobalSection(ExtensibilityGlobals) = postSolution 29 | SolutionGuid = {2CD8ECBE-4610-4EED-B381-56BAA7F9406C} 30 | EndGlobalSection 31 | EndGlobal 32 | -------------------------------------------------------------------------------- /src/exceptions.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Stephan Unverwerth 2 | // This code is licensed under MIT license (See LICENSE for details) 3 | 4 | #ifndef Strela_exceptions_h 5 | #define Strela_exceptions_h 6 | 7 | #include 8 | #include 9 | 10 | namespace Strela { 11 | 12 | class Exception: public std::runtime_error { 13 | public: 14 | Exception(const std::string& msg): std::runtime_error(msg) {} 15 | }; 16 | 17 | class LexerException: public Exception { 18 | public: 19 | LexerException(const std::string& msg): Exception(msg) {} 20 | }; 21 | 22 | class ParseException: public Exception { 23 | public: 24 | ParseException(const std::string& msg): Exception(msg) {} 25 | }; 26 | 27 | class MissingTokenException: public ParseException { 28 | public: 29 | MissingTokenException(const std::string& msg): ParseException(msg) {} 30 | }; 31 | 32 | class UnexpectedTokenException: public ParseException { 33 | public: 34 | UnexpectedTokenException(const std::string& msg): ParseException(msg) {} 35 | }; 36 | 37 | class DuplicateSymbolException: public Exception { 38 | public: 39 | DuplicateSymbolException(const std::string& msg): Exception(msg) {} 40 | }; 41 | 42 | class UnresolvedSymbolException: public Exception { 43 | public: 44 | UnresolvedSymbolException(const std::string& msg): Exception(msg) {} 45 | }; 46 | 47 | class TypeException: public Exception { 48 | public: 49 | TypeException(const std::string& msg): Exception(msg) {} 50 | }; 51 | } 52 | 53 | #endif -------------------------------------------------------------------------------- /tests/basic/Strings.strela: -------------------------------------------------------------------------------- 1 | module Strings { 2 | import Std.IO.println; 3 | 4 | function main(args: String[]): int { 5 | var empty = new String; 6 | println(empty.length()); 7 | 8 | var four = new String(4); 9 | println(four.length()); 10 | 11 | var fromarray = new String([65 as u8, 66 as u8, 67 as u8]); 12 | println(fromarray); 13 | 14 | var fromarrayslice = new String([65 as u8, 66 as u8, 67 as u8], 1); 15 | println(fromarrayslice); 16 | 17 | var frompair = new String("Hello", ", world!"); 18 | println(frompair); 19 | 20 | println(fromarray.length()); 21 | 22 | println("Hello" + " darkness"); 23 | 24 | println("A" != "B"); 25 | println("A" != "A"); 26 | println("A" != ""); 27 | 28 | println("A" == "B"); 29 | println("A" == "A"); 30 | println("A" == ""); 31 | 32 | println("Quite".substr(0, 4)); 33 | 34 | println("XYZ"[0]); 35 | println("XYZ"[1]); 36 | println("XYZ"[2]); 37 | 38 | var cities = "London,New York,Berlin"; 39 | 40 | var parts = cities.split(","); 41 | println(parts.length); 42 | println(parts[1]); 43 | 44 | println(cities.split("###").length); 45 | println(cities.split("").length); 46 | 47 | println(" \t\r\n Go \n\r\n\t\r".trim()); 48 | println(" ".trim()); 49 | 50 | println("123456".toInt()); 51 | println("123.456".toFloat()); 52 | 53 | println("Hello, world".replace("e", "a")); 54 | 55 | return 0; 56 | } 57 | } -------------------------------------------------------------------------------- /flame.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 62 | 63 | -------------------------------------------------------------------------------- /src/Ast/nodes.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Stephan Unverwerth 2 | // This code is licensed under MIT license (See LICENSE for details) 3 | 4 | #ifndef Strela_Ast_nodes_h 5 | #define Strela_Ast_nodes_h 6 | 7 | #include "ArrayLitExpr.h" 8 | #include "ArrayTypeExpr.h" 9 | #include "AssignExpr.h" 10 | #include "BinopExpr.h" 11 | #include "BlockStmt.h" 12 | #include "CallExpr.h" 13 | #include "CastExpr.h" 14 | #include "EnumElement.h" 15 | #include "Expr.h" 16 | #include "ExprStmt.h" 17 | #include "FieldDecl.h" 18 | #include "FuncDecl.h" 19 | #include "GenericParam.h" 20 | #include "GenericReificationExpr.h" 21 | #include "IdExpr.h" 22 | #include "IfStmt.h" 23 | #include "ImportStmt.h" 24 | #include "InterfaceDecl.h" 25 | #include "InterfaceMethodDecl.h" 26 | #include "InterfaceFieldDecl.h" 27 | #include "IsExpr.h" 28 | #include "LitExpr.h" 29 | #include "MapLitExpr.h" 30 | #include "NewExpr.h" 31 | #include "Node.h" 32 | #include "NullableTypeExpr.h" 33 | #include "Param.h" 34 | #include "PostfixExpr.h" 35 | #include "RetStmt.h" 36 | #include "ScopeExpr.h" 37 | #include "Stmt.h" 38 | #include "SubscriptExpr.h" 39 | #include "ThisExpr.h" 40 | #include "TypeAliasDecl.h" 41 | #include "TypeDecl.h" 42 | #include "UnaryExpr.h" 43 | #include "UnionTypeExpr.h" 44 | #include "VarDecl.h" 45 | #include "WhileStmt.h" 46 | 47 | // types 48 | #include "ArrayType.h" 49 | #include "BoolType.h" 50 | #include "ClassDecl.h" 51 | #include "EnumDecl.h" 52 | #include "FloatType.h" 53 | #include "FuncType.h" 54 | #include "IntType.h" 55 | #include "InvalidType.h" 56 | #include "ModDecl.h" 57 | #include "NullType.h" 58 | #include "OverloadedFuncType.h" 59 | #include "PointerType.h" 60 | #include "TypeType.h" 61 | #include "UnionType.h" 62 | #include "VoidType.h" 63 | 64 | 65 | #endif -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # Strela programming language 2 | Strela is a static and strongly typed object oriented programming language with heavy focus on composition and language assisted delegation. 3 | 4 | ***Development status is pre-pre-pre-alpha! Here be dragons!*** 5 | 6 | ![C/C++ CI](https://github.com/sunverwerth/strela/workflows/C/C++%20CI/badge.svg?branch=master) 7 | 8 | ## Setup 9 | git clone git@github.com:sunverwerth/strela.git 10 | cd strela 11 | make test && make install-home 12 | 13 | The included MSVC project file has been tested with Visual Studio Community 2017. 14 | 15 | ## Basic usage 16 | strela [options] input-file 17 | 18 | where `input-file` is either a .strela module or a module compiled to strela bytecode. 19 | 20 | ## Command line options 21 | --dump dumps decompiled bytecode to stdout and exits. 22 | --pretty pretty-prints the parsed code to stdout and exits. 23 | --timeout kills the running program after seconds. 24 | --search sets additional search path for imports. 25 | --write-bytecode writes compiled bytecode to and exits. 26 | 27 | ## Examples 28 | 29 | ### Hello.strela 30 | ```ts 31 | module Hello { 32 | import Std.IO.println; 33 | 34 | function main(): int { 35 | println("Hello, world!"); 36 | return 0; 37 | } 38 | } 39 | ``` 40 | 41 | ### Fib.strela 42 | ```ts 43 | module Fib { 44 | import Std.IO.println; 45 | 46 | function fib(n: int): int { 47 | if (n < 2) { 48 | return n; 49 | } 50 | else { 51 | return fib(n - 1) + fib(n - 2); 52 | } 53 | } 54 | 55 | function main(): int { 56 | println(fib(40)); 57 | return 0; 58 | } 59 | } 60 | ``` 61 | -------------------------------------------------------------------------------- /src/TypeInfo.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Stephan Unverwerth 2 | // This code is licensed under MIT license (See LICENSE for details) 3 | 4 | #ifndef Strela_TypeInfo_h 5 | #define Strela_TypeInfo_h 6 | 7 | #include 8 | 9 | #define STRELA_GET_TYPE(CLS, PAR) \ 10 | const TypeInfo* getTypeInfo() const override { return CLS::getStaticTypeInfo(); } \ 11 | static const TypeInfo* getStaticTypeInfo() { static TypeInfo dummy(#CLS, PAR::getStaticTypeInfo()); return &dummy; } 12 | 13 | #define STRELA_BASE_TYPE(CLS) \ 14 | virtual const TypeInfo* getTypeInfo() const { return CLS::getStaticTypeInfo(); } \ 15 | template T* as() { return getTypeInfo()->extendsOrEquals() ? static_cast(this) : nullptr; } \ 16 | template const T* as() const { return getTypeInfo()->extendsOrEquals() ? static_cast(this) : nullptr; } \ 17 | static const TypeInfo* getStaticTypeInfo() { static TypeInfo dummy(#CLS, nullptr); return &dummy; } 18 | 19 | namespace Strela { 20 | 21 | struct TypeInfo { 22 | TypeInfo(const char* name, const TypeInfo* parent): name(name), parent(parent) {} 23 | 24 | bool extends(const TypeInfo* tid) const; 25 | 26 | template bool extends() const { 27 | return extends(T::getStaticTypeInfo()); 28 | } 29 | 30 | template bool extendsOrEquals() const { 31 | const auto ti = T::getStaticTypeInfo(); 32 | return ti == this || extends(ti); 33 | } 34 | 35 | template bool is() const { 36 | return T::getStaticTypeInfo() == this; 37 | } 38 | 39 | const char* getName() const { return name; } 40 | const TypeInfo* getParent() const { return parent; } 41 | 42 | private: 43 | mutable std::map extCache; 44 | const char* name; 45 | const TypeInfo* parent; 46 | }; 47 | } 48 | 49 | 50 | #endif -------------------------------------------------------------------------------- /src/utils.cpp: -------------------------------------------------------------------------------- 1 | #include "utils.h" 2 | 3 | namespace Strela { 4 | 5 | std::string unescape(const std::string& str) { 6 | std::string unescaped; 7 | for (size_t i = 0; i < str.size(); ++i) { 8 | if (str[i] == '\\') { 9 | if (i < str.size() - 1) { 10 | char c = str[++i]; 11 | switch (c) { 12 | case '0': unescaped += '0'; break; 13 | case 'r': unescaped += '\r'; break; 14 | case 'n': unescaped += '\n'; break; 15 | case 't': unescaped += '\t'; break; 16 | case 'e': unescaped += '\x1b'; break; 17 | case '\\': unescaped += '\\'; break; 18 | case '"': unescaped += '"'; break; 19 | default: 20 | unescaped += '\\'; 21 | unescaped += c; 22 | } 23 | continue; 24 | } 25 | } 26 | unescaped += str[i]; 27 | } 28 | return unescaped; 29 | } 30 | 31 | std::string escape(const std::string& str) { 32 | std::string escaped; 33 | for (size_t i = 0; i < str.size(); ++i) { 34 | switch (str[i]) { 35 | case '\0': escaped += "\\0"; break; 36 | case '\r': escaped += "\\r"; break; 37 | case '\n': escaped += "\\n"; break; 38 | case '\t': escaped += "\\t"; break; 39 | case '\x1b': escaped += "\\e"; break; 40 | case '\\': escaped += "\\\\"; break; 41 | case '"': escaped += "\\\""; break; 42 | default: 43 | escaped += str[i]; 44 | } 45 | } 46 | return escaped; 47 | } 48 | } -------------------------------------------------------------------------------- /src/VM/VMValue.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Stephan Unverwerth 2 | // This code is licensed under MIT license (See LICENSE for details) 3 | 4 | #ifndef Strela_VM_VMValue_h 5 | #define Strela_VM_VMValue_h 6 | 7 | #include 8 | #include 9 | 10 | namespace Strela { 11 | struct VMObject; 12 | 13 | struct VMValue { 14 | VMValue(); 15 | explicit VMValue(int64_t val); 16 | explicit VMValue(double val); 17 | explicit VMValue(bool val); 18 | explicit VMValue(void* val); 19 | 20 | VMValue operator==(const VMValue& other) const; 21 | VMValue operator!=(const VMValue& other) const; 22 | VMValue operator<(const VMValue& other) const; 23 | VMValue operator>(const VMValue& other) const; 24 | VMValue operator<=(const VMValue& other) const; 25 | VMValue operator>=(const VMValue& other) const; 26 | VMValue operator&&(const VMValue& other) const; 27 | VMValue operator||(const VMValue& other) const; 28 | 29 | VMValue operator+(const VMValue& other) const; 30 | VMValue operator-(const VMValue& other) const; 31 | VMValue operator*(const VMValue& other) const; 32 | VMValue operator/(const VMValue& other) const; 33 | 34 | VMValue operator!() const; 35 | operator bool() const; 36 | 37 | bool equals(const VMValue& other) const; 38 | std::string dump() const; 39 | 40 | union { 41 | int64_t integer; 42 | float f32; 43 | double f64; 44 | bool boolean; 45 | void* object; 46 | } value; 47 | 48 | enum class Type { 49 | null, 50 | integer, 51 | floating, 52 | boolean, 53 | object 54 | } type; 55 | }; 56 | 57 | std::ostream& operator<<(std::ostream& str, const VMValue&); 58 | std::istream& operator>>(std::istream& str, VMValue&); 59 | 60 | } 61 | 62 | #endif -------------------------------------------------------------------------------- /src/Ast/ModDecl.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Stephan Unverwerth 2 | // This code is licensed under MIT license (See LICENSE for details) 3 | 4 | #include "ModDecl.h" 5 | #include "FuncDecl.h" 6 | #include "ClassDecl.h" 7 | #include "EnumDecl.h" 8 | #include "TypeAliasDecl.h" 9 | 10 | namespace Strela { 11 | Node* ModDecl::getMember(const std::string& name) { 12 | for (auto&& func: functions) { 13 | if (func->name == name) { 14 | return func; 15 | } 16 | } 17 | for (auto&& cls: classes) { 18 | if (cls->_name == name) { 19 | return cls; 20 | } 21 | } 22 | return nullptr; 23 | } 24 | 25 | ClassDecl* ModDecl::getClass(const std::string& name) { 26 | for (auto&& cls: classes) { 27 | if (cls->_name == name) { 28 | return cls; 29 | } 30 | } 31 | return nullptr; 32 | } 33 | 34 | TypeAliasDecl* ModDecl::getAlias(const std::string& name) { 35 | for (auto&& alias: typeAliases) { 36 | if (alias->_name == name) { 37 | return alias; 38 | } 39 | } 40 | return nullptr; 41 | } 42 | 43 | EnumDecl* ModDecl::getEnum(const std::string& name) { 44 | for (auto&& en: enums) { 45 | if (en->_name == name) { 46 | return en; 47 | } 48 | } 49 | return nullptr; 50 | } 51 | 52 | std::vector ModDecl::getFunctions(const std::string& name) { 53 | std::vector funcs; 54 | for (auto&& function: functions) { 55 | if (function->name == name) { 56 | funcs.push_back(function); 57 | } 58 | } 59 | return funcs; 60 | } 61 | 62 | void ModDecl::addFunction(FuncDecl* func) { 63 | functions.push_back(func); 64 | } 65 | 66 | void ModDecl::addClass(ClassDecl* cls) { 67 | classes.push_back(cls); 68 | } 69 | } -------------------------------------------------------------------------------- /src/Ast/ClassDecl.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Stephan Unverwerth 2 | // This code is licensed under MIT license (See LICENSE for details) 3 | 4 | #include "ClassDecl.h" 5 | #include "FuncDecl.h" 6 | #include "FieldDecl.h" 7 | #include "../Parser.h" 8 | 9 | namespace Strela { 10 | Node* ClassDecl::getMember(const std::string& name) { 11 | for (auto&& method: methods) { 12 | if (method->name == name) { 13 | return method; 14 | } 15 | } 16 | for (auto&& field: fields) { 17 | if (field->name == name) { 18 | return field; 19 | } 20 | } 21 | return nullptr; 22 | } 23 | 24 | std::vector ClassDecl::getMethods(const std::string& name) { 25 | std::vector met; 26 | for (auto&& method: methods) { 27 | if (method->name == name) { 28 | met.push_back(method); 29 | } 30 | } 31 | return met; 32 | } 33 | 34 | ClassDecl* ClassDecl::getReifiedClass(const std::vector& typeArgs) { 35 | for (auto& rc: reifiedClasses) { 36 | bool found = true; 37 | for (int i = 0; i < typeArgs.size(); ++i) { 38 | if (typeArgs[i] != rc->genericArguments[i]) { 39 | found = false; 40 | break; 41 | } 42 | } 43 | if (found) { 44 | return rc; 45 | } 46 | } 47 | 48 | // copy class definition 49 | Parser parser(*source, firstToken); 50 | auto cls = parser.parseClassDecl(parent); 51 | cls->genericBase = this; 52 | // set type arguments 53 | cls->genericArguments = typeArgs; 54 | cls->_name += "<"; 55 | for (auto&& t: typeArgs) { 56 | cls->_name += t->getFullName(); 57 | if (&t != &typeArgs.back()) { 58 | cls->_name += ","; 59 | } 60 | } 61 | cls->_name += ">"; 62 | reifiedClasses.push_back(cls); 63 | return cls; 64 | } 65 | } -------------------------------------------------------------------------------- /examples/Server.strela: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Stephan Unverwerth 2 | // This code is licensed under MIT license (See LICENSE for details) 3 | 4 | module Examples.Server { 5 | import Std.Net.HTTP; 6 | import Std.IO.*; 7 | 8 | function help() { 9 | println("Usage: strela Server.strela "); 10 | } 11 | 12 | function main(args: String[]): int { 13 | if (args.length < 1) { 14 | help(); 15 | return 1; 16 | } 17 | 18 | var port = args[0].toInt(); 19 | var server = new HTTP.Server(0, port); 20 | 21 | var i: u8 = 64; 22 | while (true) { 23 | var request = server.accept(); 24 | 25 | if (request.headers.has("Host")) { 26 | println(request.method + " request for http://" + request.headers["Host"] + request.path); 27 | } 28 | else { 29 | println(request.method + " request for http://" + request.path); 30 | } 31 | 32 | var response = new HTTP.Response; 33 | response.statusCode = 200; 34 | response.statusMessage = "OK"; 35 | response.headers.set("Content-type", "text/html"); 36 | 37 | response.body = "

Hello, world!"; 38 | response.body = response.body + [i]; 39 | response.body = response.body + "

"; 40 | 41 | println("Returning " + request.path); 42 | 43 | request.respond(response); 44 | 45 | i++; 46 | } 47 | server.close(); 48 | 49 | return 0; 50 | } 51 | } -------------------------------------------------------------------------------- /src/Pass.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Stephan Unverwerth 2 | // This code is licensed under MIT license (See LICENSE for details) 3 | 4 | #include "Pass.h" 5 | #include "Ast/Node.h" 6 | #include "Ast/Token.h" 7 | #include "SourceFile.h" 8 | 9 | #include 10 | 11 | namespace Strela { 12 | 13 | bool Pass::hadErrors() { 14 | return hasErrors; 15 | } 16 | 17 | bool Pass::hadWarnings() { 18 | return hasWarnings; 19 | } 20 | 21 | void Pass::info(const std::string& msg) { 22 | std::cerr << "\033[1;34m" << msg << "\033[0m\n"; 23 | } 24 | 25 | void Pass::info(const Node& n, const std::string& msg) { 26 | std::cerr << "\033[1;34m"; 27 | if (n.source) { 28 | std::cerr << n.source->filename << ":" << n.line << ":" << n.column << " "; 29 | } 30 | std::cerr << msg << "\033[0m\n"; 31 | } 32 | 33 | void Pass::info(const SourceFile& file, const Token& n, const std::string& msg) { 34 | std::cerr << "\033[1;34m" << file.filename << ":" << n.line << ":" << n.column << " " << msg << "\033[0m\n"; 35 | } 36 | 37 | void Pass::warning(const std::string& msg) { 38 | hasWarnings = true; 39 | std::cerr << "\033[1;33mWarning: " << msg << "\033[0m\n"; 40 | } 41 | 42 | void Pass::warning(const Node& n, const std::string& msg) { 43 | hasWarnings = true; 44 | std::cerr << "\033[1;33m"; 45 | if (n.source) { 46 | std::cerr << n.source->filename << ":" << n.line << ":" << n.column << " "; 47 | } 48 | std::cerr << "Warning: " << msg << "\033[0m\n"; 49 | } 50 | 51 | void Pass::warning(const SourceFile& file, const Token& n, const std::string& msg) { 52 | hasWarnings = true; 53 | std::cerr << "\033[1;33m" << file.filename << ":" << n.line << ":" << n.column << " Warning: " << msg << "\033[0m\n"; 54 | } 55 | 56 | void Pass::error(const std::string& msg) { 57 | hasErrors = true; 58 | std::cerr << "\033[1;31mError: " << msg << "\033[0m\n"; 59 | } 60 | 61 | void Pass::error(const Node& n, const std::string& msg) { 62 | hasErrors = true; 63 | std::cerr << "\033[1;31m"; 64 | if (n.source) { 65 | std::cerr << n.source->filename << ":" << n.line << ":" << n.column << " "; 66 | } 67 | std::cerr << "Error: " << msg << "\033[0m\n"; 68 | } 69 | 70 | void Pass::error(const SourceFile& file, const Token& n, const std::string& msg) { 71 | hasErrors = true; 72 | std::cerr << "\033[1;31m" << file.filename << ":" << n.line << ":" << n.column << " Error: " << msg << "\033[0m\n"; 73 | } 74 | } -------------------------------------------------------------------------------- /Std/Math/Lina.strela: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Stephan Unverwerth 2 | // This code is licensed under MIT license (See LICENSE for details) 3 | 4 | module Std.Math.Lina { 5 | 6 | import Std.cstdio.*; 7 | 8 | export class Vec { 9 | var x: f64; 10 | var y: f64; 11 | var z: f64; 12 | 13 | function init() {} 14 | 15 | function init(x: f64, y: f64, z: f64) { 16 | this.x = x; 17 | this.y = y; 18 | this.z = z; 19 | } 20 | 21 | function set(other: Vec) { 22 | this.x = other.x; 23 | this.y = other.y; 24 | this.z = other.z; 25 | } 26 | 27 | function magnitude(): f64 { 28 | return sqrt(this.x * this.x + this.y * this.y + this.z * this.z); 29 | } 30 | 31 | function normalize() { 32 | var ol = 1.0 / this.magnitude(); 33 | this.x = this.x * ol; 34 | this.y = this.y * ol; 35 | this.z = this.z * ol; 36 | } 37 | 38 | function dot(other: Vec): f64 { 39 | return this.x * other.x + this.y * other.y + this.z * other.z; 40 | } 41 | 42 | function -(other: Vec): Vec { 43 | return new Vec(this.x - other.x, this.y - other.y, this.z - other.z); 44 | } 45 | 46 | function +(other: Vec): Vec { 47 | return new Vec(this.x + other.x, this.y + other.y, this.z + other.z); 48 | } 49 | 50 | function *(v: f64): Vec { 51 | return new Vec(this.x * v, this.y * v, this.z * v); 52 | } 53 | 54 | function /(v: f64): Vec { 55 | return new Vec(this.x / v, this.y / v, this.z / v); 56 | } 57 | 58 | function neg(): Vec { 59 | return new Vec(-this.x, -this.y, -this.z); 60 | } 61 | 62 | function normalized(): Vec { 63 | var ol = 1.0 / this.magnitude(); 64 | return new Vec(this.x * ol, this.y * ol, this.z * ol); 65 | } 66 | 67 | function +=(other: Vec) { 68 | this.x = this.x + other.x; 69 | this.y = this.y + other.y; 70 | this.z = this.z + other.z; 71 | } 72 | 73 | function -=(other: Vec) { 74 | this.x = this.x - other.x; 75 | this.y = this.y - other.y; 76 | this.z = this.z - other.z; 77 | } 78 | 79 | function *=(v: f64) { 80 | this.x = this.x * v; 81 | this.y = this.y * v; 82 | this.z = this.z * v; 83 | } 84 | } 85 | 86 | export function reflect(dir: Vec, n: Vec): Vec { 87 | return dir - n * dir.dot(n) * 2.0; 88 | } 89 | 90 | export function lerp(a: Vec, b: Vec, f: f64): Vec { 91 | return a * (1.0 - f) + b * f; 92 | } 93 | } -------------------------------------------------------------------------------- /src/NameResolver.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Stephan Unverwerth 2 | // This code is licensed under MIT license (See LICENSE for details) 3 | 4 | #ifndef Strela_NameResolver_h 5 | #define Strela_NameResolver_h 6 | 7 | #include "IStmtVisitor.h" 8 | #include "IExprVisitor.h" 9 | #include "Pass.h" 10 | 11 | #include 12 | 13 | namespace Strela { 14 | class Scope; 15 | class Node; 16 | class ModDecl; 17 | class ClassDecl; 18 | class FuncDecl; 19 | class Param; 20 | class FieldDecl; 21 | class ImportStmt; 22 | class InterfaceDecl; 23 | class InterfaceMethodDecl; 24 | class InterfaceFieldDecl; 25 | class TypeAliasDecl; 26 | 27 | class NameResolver: public Pass, public IStmtVisitor, public IExprVisitor { 28 | public: 29 | NameResolver(Scope* globals); 30 | void resolve(ModDecl&); 31 | void resolve(ClassDecl&); 32 | void resolve(FuncDecl&); 33 | void resolve(Param&); 34 | void resolve(ImportStmt&); 35 | void resolve(InterfaceDecl&); 36 | void resolve(InterfaceMethodDecl&); 37 | void resolve(InterfaceFieldDecl&); 38 | void resolve(TypeAliasDecl&); 39 | void resolve(FieldDecl&); 40 | 41 | void visit(BlockStmt&) override; 42 | void visit(ExprStmt&) override; 43 | void visit(IfStmt&) override; 44 | void visit(RetStmt&) override; 45 | void visit(VarDecl&) override; 46 | void visit(WhileStmt&) override; 47 | 48 | void visit(ArrayLitExpr&) override; 49 | void visit(ArrayTypeExpr&) override; 50 | void visit(AssignExpr&) override; 51 | void visit(BinopExpr&) override; 52 | void visit(CallExpr&) override; 53 | void visit(CastExpr&) override; 54 | void visit(GenericReificationExpr&) override; 55 | void visit(IdExpr&) override; 56 | void visit(IsExpr&) override; 57 | void visit(LitExpr&) override {} 58 | void visit(MapLitExpr&) override; 59 | void visit(NewExpr&) override; 60 | void visit(NullableTypeExpr&) override; 61 | void visit(PostfixExpr&) override; 62 | void visit(ScopeExpr&) override; 63 | void visit(SubscriptExpr&) override; 64 | void visit(ThisExpr&) override {}; 65 | void visit(UnaryExpr&) override; 66 | void visit(UnionTypeExpr&) override; 67 | 68 | int resolveGenerics(ModDecl&); 69 | 70 | template void visitChildren(T& children) { 71 | for (auto&& child: children) { 72 | visitChild(child); 73 | } 74 | } 75 | 76 | template void visitChild(T& child) { 77 | if (child) { 78 | child->accept(*this); 79 | } 80 | } 81 | 82 | private: 83 | Scope* scope; 84 | }; 85 | } 86 | #endif -------------------------------------------------------------------------------- /docs/syntax.md: -------------------------------------------------------------------------------- 1 | # Strela Language Syntax 2 | 3 | Every strela source file represents a module and must at its root contain a module declaration. 4 | 5 | ## Comments 6 | ```TS 7 | /** 8 | * Block comments can span multiple lines 9 | */ 10 | 11 | // Line comments are terminated by a new line 12 | ``` 13 | 14 | ## Module 15 | ```TS 16 | module Foo.Bar.Test { 17 | // Import symbols into current scope 18 | import ...; 19 | 20 | // Define classes 21 | class Name {...} 22 | 23 | // Define interfaces 24 | interface Name {...} 25 | 26 | // Define enums 27 | enum name {...} 28 | 29 | // Define functions 30 | function name() {...} 31 | } 32 | ``` 33 | 34 | ## Imports 35 | ```TS 36 | // import module A.B (if file A/B.strela exists) else symbol B from module A (if file A.strela exists) 37 | import A.B; 38 | 39 | // import all exported symbols from module A.B (if file A/B.strela exists) 40 | import A.B.*; 41 | ``` 42 | 43 | ## Classes 44 | ```TS 45 | // Defines a class named Private that is private to the module 46 | class Private { 47 | } 48 | 49 | // Defines class named Public that is exported from the module 50 | export class Public { 51 | } 52 | 53 | class Foo { 54 | // Defines a constructor for the class 55 | function init() {} 56 | 57 | // Defines a method named `foo` for the class 58 | function foo() {} 59 | 60 | // Defines a method named `bar` for the class, returning an `int` 61 | function bar(): int { return 0; } 62 | 63 | // Defined a field named `field` of type `int` 64 | var field: int; 65 | } 66 | ``` 67 | 68 | ## Interfaces 69 | ```TS 70 | [export] interface Bar { 71 | function member(); 72 | var field: int; 73 | } 74 | ``` 75 | 76 | ## Enumeration 77 | ```TS 78 | [export] enum Colors { 79 | Red, Green, Blue 80 | } 81 | ``` 82 | 83 | ## Generic Types 84 | ```TS 85 | [export] class Generic { 86 | var field: T; 87 | function member(arg: T) {} 88 | } 89 | ``` 90 | 91 | ## Functions 92 | ```TS 93 | // Function `name` takes 2 `int` arguments and returns `bool` 94 | function name(a: int, b: int): bool { 95 | return true; 96 | } 97 | ``` 98 | 99 | ## Entry Point 100 | ```TS 101 | //No arguments 102 | function main(): int { 103 | return 0; 104 | } 105 | 106 | // With cmd line arguments 107 | function main(args: String[]): int { // cmd line arguments 108 | return 0; 109 | } 110 | ``` 111 | 112 | ## Variables 113 | ```TS 114 | // Explicit type 115 | var a: int; 116 | 117 | // Explicit type with initializer 118 | var a: int = 0; 119 | 120 | // Implicit type from initializer 121 | var a = 10; 122 | 123 | // Allocate instance of Foo (calls Foo::init() if exists) 124 | var obj = new Foo; 125 | 126 | // Allocate instance of Foo with arguments (calls Foo::init(a,b,c)) 127 | var obj = new Foo(1, 2, 3); 128 | ``` -------------------------------------------------------------------------------- /src/ByteCodeCompiler.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Stephan Unverwerth 2 | // This code is licensed under MIT license (See LICENSE for details) 3 | 4 | #ifndef Strela_ByteCodeCompiler_h 5 | #define Strela_ByteCodeCompiler_h 6 | 7 | #include "IStmtVisitor.h" 8 | #include "IExprVisitor.h" 9 | #include "Pass.h" 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | namespace Strela { 16 | class ByteCodeChunk; 17 | class Expr; 18 | class Node; 19 | class VMType; 20 | class TypeDecl; 21 | class FuncDecl; 22 | class ClassDecl; 23 | class ModDecl; 24 | class FieldDecl; 25 | class Param; 26 | 27 | class ByteCodeCompiler: public Pass, public IStmtVisitor, public IExprVisitor { 28 | public: 29 | ByteCodeCompiler(ByteCodeChunk&); 30 | void compile(ModDecl&); 31 | void compile(ClassDecl&); 32 | void compile(FuncDecl&); 33 | void compile(FieldDecl&); 34 | void compile(Param&); 35 | 36 | void visit(BlockStmt&) override; 37 | void visit(ExprStmt&) override; 38 | void visit(IfStmt&) override; 39 | void visit(RetStmt&) override; 40 | void visit(VarDecl&) override; 41 | void visit(WhileStmt&) override; 42 | 43 | void visit(ArrayLitExpr&) override; 44 | void visit(ArrayTypeExpr&) override {} 45 | void visit(AssignExpr&) override; 46 | void visit(BinopExpr&) override; 47 | void visit(CallExpr&) override; 48 | void visit(CastExpr&) override; 49 | void visit(GenericReificationExpr&) override {} 50 | void visit(IdExpr&) override; 51 | void visit(IsExpr&) override; 52 | void visit(LitExpr&) override; 53 | void visit(MapLitExpr&) override; 54 | void visit(NewExpr&) override; 55 | void visit(NullableTypeExpr&) override {} 56 | void visit(PostfixExpr&) override; 57 | void visit(ScopeExpr&) override; 58 | void visit(SubscriptExpr&) override; 59 | void visit(ThisExpr&) override; 60 | void visit(UnaryExpr&) override; 61 | void visit(UnionTypeExpr&) override {} 62 | 63 | template void visitChildren(T& children) { 64 | for (auto&& child: children) { 65 | child->accept(*this); 66 | } 67 | } 68 | 69 | template void visitChild(T& child) { 70 | if (child) child->accept(*this); 71 | } 72 | 73 | private: 74 | void addFixup(size_t address, FuncDecl* function, bool immediate); 75 | VMType* mapType(TypeDecl* type); 76 | 77 | private: 78 | struct Fixup { 79 | size_t address; 80 | FuncDecl* function; 81 | bool immediate; 82 | }; 83 | std::vector functionFixups; 84 | FuncDecl* function = nullptr; 85 | std::map typeMap; 86 | 87 | public: 88 | ByteCodeChunk& chunk; 89 | ClassDecl* _class = nullptr; 90 | }; 91 | } 92 | #endif -------------------------------------------------------------------------------- /src/Ast/Token.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Stephan Unverwerth 2 | // This code is licensed under MIT license (See LICENSE for details) 3 | 4 | #ifndef Strela_Ast_Token_h 5 | #define Strela_Ast_Token_h 6 | 7 | #include 8 | #include 9 | 10 | namespace Strela { 11 | #define TOKENS(X) \ 12 | X(Amp) \ 13 | X(AmpAmp) \ 14 | X(AmpEquals) \ 15 | X(As) \ 16 | X(Asterisk) \ 17 | X(AsteriskEquals) \ 18 | X(Boolean) \ 19 | X(BracketClose) \ 20 | X(BracketOpen) \ 21 | X(Caret) \ 22 | X(CaretEquals) \ 23 | X(Class) \ 24 | X(Colon) \ 25 | X(Comma) \ 26 | X(CurlyClose) \ 27 | X(CurlyOpen) \ 28 | X(Else) \ 29 | X(Enum) \ 30 | X(Eof) \ 31 | X(Equals) \ 32 | X(EqualsEquals) \ 33 | X(ExclamationMark) \ 34 | X(ExclamationMarkEquals) \ 35 | X(Export) \ 36 | X(External) \ 37 | X(Float) \ 38 | X(Function) \ 39 | X(GreaterThan) \ 40 | X(GreaterThanEquals) \ 41 | X(Identifier) \ 42 | X(If) \ 43 | X(Import) \ 44 | X(Integer) \ 45 | X(Interface) \ 46 | X(Invalid) \ 47 | X(Is) \ 48 | X(LessThan) \ 49 | X(LessThanEquals) \ 50 | X(Minus) \ 51 | X(MinusEquals) \ 52 | X(MinusMinus) \ 53 | X(Module) \ 54 | X(Mutable) \ 55 | X(New) \ 56 | X(Null) \ 57 | X(ParenClose) \ 58 | X(ParenOpen) \ 59 | X(Percent) \ 60 | X(PercentEquals) \ 61 | X(Period) \ 62 | X(Pipe) \ 63 | X(PipeEquals) \ 64 | X(PipePipe) \ 65 | X(Plus) \ 66 | X(PlusEquals) \ 67 | X(PlusPlus) \ 68 | X(QuestionMark) \ 69 | X(Return) \ 70 | X(Semicolon) \ 71 | X(Slash) \ 72 | X(SlashEquals) \ 73 | X(String) \ 74 | X(This) \ 75 | X(Tilde) \ 76 | X(Type) \ 77 | X(Var) \ 78 | X(While) \ 79 | 80 | 81 | #define AS_ENUM(X) X, 82 | enum class TokenType { 83 | TOKENS(AS_ENUM) 84 | }; 85 | #undef AS_ENUM 86 | 87 | struct Token { 88 | public: 89 | Token() = default; 90 | Token(TokenType type, const std::string& trivia, const std::string& value, int line, int column, int index): type(type), trivia(trivia), value(value), line(line), column(column), index(index) {} 91 | public: 92 | TokenType type; 93 | std::string value; 94 | std::string trivia; 95 | int line; 96 | int column; 97 | int index; 98 | 99 | double floatVal(); 100 | int64_t intVal(); 101 | bool boolVal(); 102 | }; 103 | 104 | std::ostream& operator<<(std::ostream& stream, const Token& t); 105 | std::string getTokenName(TokenType type); 106 | std::string getTokenVal(TokenType type); 107 | } 108 | 109 | #endif -------------------------------------------------------------------------------- /src/VM/ByteCodeChunk.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Stephan Unverwerth 2 | // This code is licensed under MIT license (See LICENSE for details) 3 | 4 | #ifndef Strela_VM_ByteCodeChunk_h 5 | #define Strela_VM_ByteCodeChunk_h 6 | 7 | #include "Opcode.h" 8 | #include "VMValue.h" 9 | #include "VMType.h" 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #ifdef __APPLE__ 17 | #include 18 | #else 19 | #include 20 | #endif 21 | 22 | 23 | namespace Strela { 24 | class TypeDecl; 25 | class FuncDecl; 26 | class SourceFile; 27 | 28 | class ForeignFunction { 29 | public: 30 | ForeignFunction(const std::string& name, TypeDecl* returnType, const std::vector& argTypes): name(name), returnType(returnType), argTypes(argTypes) {} 31 | 32 | std::string name; 33 | TypeDecl* returnType; 34 | std::vector argTypes; 35 | 36 | typedef void(*callback)(void); 37 | 38 | mutable ffi_type** ffi_argTypes = nullptr; 39 | mutable ffi_cif cif; 40 | mutable callback ptr = nullptr; 41 | }; 42 | 43 | struct SourceLine { 44 | size_t address; 45 | size_t file; 46 | size_t line; 47 | }; 48 | 49 | struct VarInfo { 50 | int offset; 51 | std::string name; 52 | VMType* type; 53 | }; 54 | 55 | struct FunctionInfo { 56 | std::string name; 57 | std::vector variables; 58 | }; 59 | 60 | class ByteCodeChunk { 61 | public: 62 | std::vector constants; 63 | std::vector opcodes; 64 | std::map functions; 65 | std::vector foreignFunctions; 66 | std::vector types; 67 | size_t main; 68 | std::vector files; 69 | std::vector lines; 70 | 71 | const SourceLine* getLine(size_t address) const; 72 | void setLine(const SourceFile* file, size_t line); 73 | void addFunction(size_t address, const FunctionInfo& func); 74 | int addConstant(VMValue c); 75 | int addForeignFunction(FuncDecl& n); 76 | int addOp(Opcode code); 77 | int addOp(Opcode code, size_t argSize, const void* arg); 78 | int addOp(Opcode code, size_t argSize1, const void* arg1, size_t argSize2, const void* arg2); 79 | template struct identity { using type = T; }; 80 | template int addOp(Opcode code, const typename identity::type& arg) { 81 | return addOp(code, sizeof(T), &arg); 82 | } 83 | template int addOp(Opcode code, const typename identity::type& arg, const typename identity::type& arg2) { 84 | return addOp(code, sizeof(T), &arg, sizeof(T2), &arg2); 85 | } 86 | void writeArgument(size_t pos, uint64_t arg); 87 | void write(size_t pos, void* data, size_t size); 88 | }; 89 | 90 | std::ostream& operator<<(std::ostream& str, const ByteCodeChunk& chunk); 91 | std::istream& operator>>(std::istream& str, ByteCodeChunk& chunk); 92 | } 93 | 94 | #endif -------------------------------------------------------------------------------- /Std/IO.strela: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Stephan Unverwerth 2 | // This code is licensed under MIT license (See LICENSE for details) 3 | 4 | module Std.IO { 5 | import Std.cstdio.*; 6 | 7 | export function print(v: u8): void {} 8 | export function print(v: u16): void {} 9 | export function print(v: u32): void {} 10 | export function print(v: u64): void {} 11 | export function print(v: i8): void {} 12 | export function print(v: i16): void {} 13 | export function print(v: i32): void {} 14 | export function print(v: i64): void {} 15 | export function print(v: f32): void {} 16 | export function print(v: f64): void {} 17 | export function print(v: String): void {} 18 | export function print(v: bool): void {} 19 | 20 | export function println(v: i8): void { print(v); print("\n"); } 21 | export function println(v: i16): void { print(v); print("\n"); } 22 | export function println(v: i32): void { print(v); print("\n"); } 23 | export function println(v: i64): void { print(v); print("\n"); } 24 | export function println(v: u8): void { print(v); print("\n"); } 25 | export function println(v: u16): void { print(v); print("\n"); } 26 | export function println(v: u32): void { print(v); print("\n"); } 27 | export function println(v: u64): void { print(v); print("\n"); } 28 | export function println(v: f32): void { print(v); print("\n"); } 29 | export function println(v: f64): void { print(v); print("\n"); } 30 | export function println(v: String): void { print(v); print("\n"); } 31 | export function println(v: bool): void { print(v); print("\n"); } 32 | 33 | export class File { 34 | var handle: u32; 35 | var name: String; 36 | 37 | function init(name: String, mode: String) { 38 | this.name = name; 39 | this.handle = fopen(name, mode); 40 | } 41 | 42 | function good(): bool { 43 | return this.handle > 0; 44 | } 45 | 46 | function write(str: String) { 47 | fwrite(str, strlen(str), 1, this.handle); 48 | } 49 | 50 | function write(n: u8) { 51 | fwrite(n, 1, 1, this.handle); 52 | } 53 | 54 | function write(n: u16) { 55 | fwrite(n, 2, 1, this.handle); 56 | } 57 | 58 | function close() { 59 | fclose(this.handle); 60 | } 61 | 62 | function isEof(): bool { 63 | return feof(this.handle) != 0; 64 | } 65 | 66 | function getc(): String { 67 | var ch = fgetc(this.handle); 68 | if (ch < 0) return ""; 69 | return new String([ch as u8]); 70 | } 71 | 72 | function peek(): String { 73 | var ch = fgetc(this.handle); 74 | ungetc(ch, this.handle); 75 | 76 | if (ch < 0) return ""; 77 | return new String([ch as u8]); 78 | } 79 | 80 | function readAll(): String { 81 | fseek(this.handle, 0, 2); 82 | var len = ftell(this.handle); 83 | fseek(this.handle, 0, 0); 84 | var str = new String(len); 85 | fread(str, len, 1, this.handle); 86 | return str; 87 | } 88 | } 89 | } -------------------------------------------------------------------------------- /src/NodePrinter.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Stephan Unverwerth 2 | // This code is licensed under MIT license (See LICENSE for details) 3 | 4 | #ifndef Strela_NodePrinter_h 5 | #define Strela_NodePrinter_h 6 | 7 | #include "IStmtVisitor.h" 8 | #include "IExprVisitor.h" 9 | 10 | #include 11 | #include 12 | 13 | namespace Strela { 14 | class ModDecl; 15 | class ClassDecl; 16 | class FuncDecl; 17 | class EnumDecl; 18 | class EnumElement; 19 | class InterfaceDecl; 20 | class InterfaceMethodDecl; 21 | class TypeAliasDecl; 22 | class ImportStmt; 23 | class Param; 24 | class FieldDecl; 25 | class GenericParam; 26 | 27 | class NodePrinter: public IStmtVisitor, public IExprVisitor { 28 | public: 29 | void print(ModDecl&); 30 | void print(ClassDecl&); 31 | void print(FuncDecl&); 32 | void print(EnumDecl&); 33 | void print(EnumElement&); 34 | void print(InterfaceDecl&); 35 | void print(InterfaceMethodDecl&); 36 | void print(TypeAliasDecl&); 37 | void print(ImportStmt&); 38 | void print(Param&); 39 | void print(FieldDecl&); 40 | void print(GenericParam&); 41 | 42 | void visit(VarDecl&) override; 43 | void visit(IdExpr&) override; 44 | void visit(RetStmt&) override; 45 | void visit(LitExpr&) override; 46 | void visit(BlockStmt&) override; 47 | void visit(CallExpr&) override; 48 | void visit(ExprStmt&) override; 49 | void visit(BinopExpr&) override; 50 | void visit(ScopeExpr&) override; 51 | void visit(IfStmt&) override; 52 | void visit(NewExpr&) override; 53 | void visit(AssignExpr&) override; 54 | void visit(WhileStmt&) override; 55 | void visit(PostfixExpr&) override; 56 | void visit(ArrayTypeExpr&) override; 57 | void visit(UnaryExpr&) override; 58 | void visit(ThisExpr&) override; 59 | void visit(CastExpr&) override; 60 | void visit(IsExpr&) override; 61 | void visit(UnionTypeExpr&) override; 62 | void visit(ArrayLitExpr&) override; 63 | void visit(SubscriptExpr&) override; 64 | void visit(MapLitExpr&) override; 65 | void visit(NullableTypeExpr&) override; 66 | void visit(GenericReificationExpr&) override; 67 | 68 | void push(); 69 | void pop(); 70 | 71 | template void visitChildren(T& children) { 72 | for (auto&& child: children) { 73 | child->accept(*this); 74 | } 75 | } 76 | 77 | template void visitChild(T& child) { 78 | if (child) child->accept(*this); 79 | } 80 | 81 | template void list(const T& children, const std::string& separator) { 82 | for (auto&& child: children) { 83 | child->accept(*this); 84 | if (&child != &children.back()) { 85 | std::cout << separator; 86 | } 87 | } 88 | } 89 | 90 | private: 91 | void indent(); 92 | int indentation = 0; 93 | std::string indentstring; 94 | }; 95 | } 96 | #endif -------------------------------------------------------------------------------- /src/Parser.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Stephan Unverwerth 2 | // This code is licensed under MIT license (See LICENSE for details) 3 | 4 | #ifndef Strela_Parser_h 5 | #define Strela_Parser_h 6 | 7 | #include "Ast/nodes.h" 8 | #include "Ast/Token.h" 9 | #include "SourceFile.h" 10 | #include "Pass.h" 11 | 12 | #include 13 | #include 14 | 15 | namespace Strela { 16 | class Parser: public Pass { 17 | public: 18 | Parser(const SourceFile& source, int starttoken = 0): source(source), tokens(source.tokens), token(tokens.begin() + starttoken) {} 19 | 20 | ModDecl* parseModDecl(); 21 | IdExpr* parseIdExpr(Node* parent); 22 | FuncDecl* parseFuncDecl(Node* parent, bool external = false); 23 | Param* parseParam(Node* parent); 24 | VarDecl* parseVarDecl(Node* parent); 25 | BlockStmt* parseBlockStmt(Node* parent); 26 | ClassDecl* parseClassDecl(Node* parent); 27 | FieldDecl* parseFieldDecl(Node* parent); 28 | EnumDecl* parseEnumDecl(Node* parent); 29 | ImportStmt* parseImportStmt(Node* parent); 30 | InterfaceDecl* parseInterfaceDecl(Node* parent); 31 | InterfaceMethodDecl* parseInterfaceMethodDecl(Node* parent); 32 | InterfaceFieldDecl* parseInterfaceFieldDecl(Node* parent); 33 | TypeAliasDecl* parseTypeAliasDecl(Node* parent); 34 | 35 | Stmt* parseStmt(Node* parent); 36 | RetStmt* parseRetStmt(Node* parent); 37 | ExprStmt* parseExprStmt(Node* parent); 38 | IfStmt* parseIfStmt(Node* parent); 39 | WhileStmt* parseWhileStmt(Node* parent); 40 | 41 | Expr* parseExpr(Node* parent, int precedence = 0); 42 | NewExpr* parseNewExpr(Node* parent); 43 | LitExpr* parseLitExpr(Node* parent); 44 | CallExpr* parseCallExpr(Node* parent, Expr* callTarget); 45 | ArrayLitExpr* parseArrayLitExpr(Node* parent); 46 | MapLitExpr* parseMapLitExpr(Node* parent); 47 | SubscriptExpr* parseSubscriptExpr(Node* parent, Expr* callTarget); 48 | 49 | Expr* parseTypeExpr(Node* parent); 50 | GenericReificationExpr* parseGenericReificationExpr(Node* parent, Expr* target); 51 | 52 | bool match(TokenType type); 53 | bool matchExpr(); 54 | bool matchSecondary(); 55 | bool matchUnary(); 56 | bool matchTypeSecondary(); 57 | bool matchBinary(); 58 | void expect(TokenType type); 59 | Token eat(TokenType type); 60 | bool eatOptional(TokenType type); 61 | Token eat(); 62 | bool eof(); 63 | void expected(TokenType expectedType); 64 | void expected(const std::string& expected); 65 | 66 | private: 67 | const std::vector& tokens; 68 | const SourceFile& source; 69 | std::vector::const_iterator token; 70 | 71 | int numVariables = 0; 72 | 73 | template T* addPosition(T* node, const Token& tok) { 74 | node->line = tok.line; 75 | node->lineend = (token - 1)->line; 76 | node->column = tok.column; 77 | node->source = &source; 78 | node->firstToken = tok.index; 79 | return node; 80 | } 81 | 82 | }; 83 | } 84 | 85 | #endif -------------------------------------------------------------------------------- /Std/Collections.strela: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Stephan Unverwerth 2 | // This code is licensed under MIT license (See LICENSE for details) 3 | 4 | module Std.Collections { 5 | /** 6 | * Contiguous storage resizable list 7 | */ 8 | export class List { 9 | var array: T[]; 10 | var length: int; 11 | 12 | function init() { 13 | this.array = new T[](1); 14 | this.length = 0; 15 | } 16 | 17 | function init(capacity: int) { 18 | this.array = new T[](capacity); 19 | this.length = 0; 20 | } 21 | 22 | function init(data: T[]) { 23 | this.array = data; 24 | this.length = data.length; 25 | } 26 | 27 | function append(value: T) { 28 | if (this.array.length < this.length + 1) { 29 | var newArray = new T[](this.array.length * 2 + 1); 30 | var i = 0; 31 | while(i < this.array.length) { 32 | newArray[i] = this.array[i]; 33 | i++; 34 | } 35 | this.array = newArray; 36 | } 37 | 38 | this.array[this.length] = value; 39 | this.length = this.length + 1; 40 | } 41 | 42 | function set(index: int, value: T) { 43 | this.array[index] = value; 44 | } 45 | 46 | function remove(index: int) { 47 | var i = index; 48 | var l = this.length - 1; 49 | while (i < l) { 50 | this.array[i] = this.array[i + 1]; 51 | i++; 52 | } 53 | this.length = this.length - 1; 54 | } 55 | 56 | function [](i: int): T { 57 | return this.array[i]; 58 | } 59 | } 60 | 61 | /** 62 | * Key-Value storage 63 | */ 64 | export class Map { 65 | var keys: List; 66 | var values: List; 67 | 68 | function init() { 69 | this.keys = new List; 70 | this.values = new List; 71 | } 72 | 73 | function init(keys: K[], values: V[]) { 74 | this.keys = new List(keys); 75 | this.values = new List(values); 76 | } 77 | 78 | function has(key: K): bool { 79 | return this.keyIndex(key) >= 0; 80 | } 81 | 82 | function keyIndex(key: K): int { 83 | var i: int = 0; 84 | while (i < this.keys.length) { 85 | if (this.keys[i] == key) return i; 86 | i++; 87 | } 88 | return -1; 89 | } 90 | 91 | function set(key: K, val: V) { 92 | var idx = this.keyIndex(key); 93 | if (idx >= 0) { 94 | this.values.set(idx, val); 95 | } 96 | else { 97 | this.keys.append(key); 98 | this.values.append(val); 99 | } 100 | } 101 | 102 | function remove(key: K) { 103 | var idx = this.keyIndex(key); 104 | if (idx >= 0) { 105 | this.keys.remove(idx); 106 | this.values.remove(idx); 107 | } 108 | } 109 | 110 | function [](key: K): V { 111 | return this.values[this.keyIndex(key)]; 112 | } 113 | } 114 | } -------------------------------------------------------------------------------- /src/Ast/UnionType.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Stephan Unverwerth 2 | // This code is licensed under MIT license (See LICENSE for details) 3 | 4 | #include "UnionType.h" 5 | #include "../exceptions.h" 6 | #include "TypeAliasDecl.h" 7 | #include "Expr.h" 8 | 9 | #include 10 | 11 | namespace Strela { 12 | std::set mergeTypes(TypeDecl* left, TypeDecl* right) { 13 | std::set set; 14 | if (auto unionLeft = left->as()) { 15 | set.insert(unionLeft->containedTypes.begin(), unionLeft->containedTypes.end()); 16 | } 17 | else { 18 | set.insert(left); 19 | } 20 | if (auto unionRight = right->as()) { 21 | set.insert(unionRight->containedTypes.begin(), unionRight->containedTypes.end()); 22 | } 23 | else { 24 | set.insert(right); 25 | } 26 | return set; 27 | } 28 | 29 | std::string getUnionName(const UnionType* unionType) { 30 | std::stringstream sstr; 31 | for (auto&& type: unionType->containedTypes) { 32 | if (&type != &*unionType->containedTypes.begin()) { 33 | sstr << "|"; 34 | } 35 | if (auto ut = type->as()) { 36 | if (ut == unionType) { 37 | sstr << "*self*"; 38 | continue; 39 | } 40 | } 41 | sstr << type->getFullName(); 42 | } 43 | return sstr.str(); 44 | } 45 | 46 | int UnionType::getTypeTag(TypeDecl* t) { 47 | if (auto alias = t->as()) { 48 | t = alias->typeExpr->typeValue; 49 | } 50 | 51 | int tag = 0; 52 | for (auto&& type: containedTypes) { 53 | if (type == t) return tag; 54 | if (auto alias = type->as()) { 55 | if (alias->typeExpr->typeValue == t) { 56 | return tag; 57 | } 58 | } 59 | ++tag; 60 | } 61 | return -1; // TODO: error handling 62 | } 63 | 64 | bool UnionType::containsType(TypeDecl* t) { 65 | for (auto& ct: containedTypes) { 66 | if (ct == t) { 67 | return true; 68 | } 69 | if (auto alias = ct->as()) { 70 | if (alias->typeExpr->typeValue == t) { 71 | return true; 72 | } 73 | } 74 | } 75 | return false; 76 | } 77 | 78 | TypeDecl* UnionType::getComplementaryType(TypeDecl* t) { 79 | if (containedTypes.size() != 2) throw Exception("Calling UnionType::getComplementaryType() on union without exactly 2 contained types."); 80 | for (auto& ct: containedTypes) { 81 | if (ct != t) return ct; 82 | } 83 | return nullptr; // TODO: error handling 84 | } 85 | 86 | UnionType* UnionType::get(TypeDecl* left, TypeDecl* right) { 87 | auto set = mergeTypes(left, right); 88 | for (auto& un: unionTypes) { 89 | if (un->containedTypes == set) { 90 | return un; 91 | } 92 | } 93 | 94 | auto ut = new UnionType(); 95 | ut->containedTypes = set; 96 | ut->_name = getUnionName(ut); 97 | unionTypes.push_back(ut); 98 | return ut; 99 | } 100 | 101 | std::vector UnionType::unionTypes; 102 | } -------------------------------------------------------------------------------- /src/VM/GC.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Stephan Unverwerth 2 | // This code is licensed under MIT license (See LICENSE for details) 3 | 4 | #include "GC.h" 5 | #include "VMType.h" 6 | 7 | #include 8 | 9 | namespace Strela { 10 | void* GC::allocObject(const VMType* type) { 11 | auto obj = (VMObject*)calloc(sizeof(VMObject) + type->objectSize, 1); 12 | obj->type = type; 13 | objects.push_back(obj); 14 | //std::cout << "Alloc object " << type->name << "\n"; 15 | return obj + 1; 16 | } 17 | 18 | void* GC::allocArray(const VMType* type, uint64_t length) { 19 | auto obj = (VMObject*)calloc(sizeof(VMObject) + sizeof(uint64_t) + type->arrayType->size * length, 1); 20 | obj->type = type; 21 | memcpy(obj->data, &length, sizeof(length)); 22 | objects.push_back(obj); 23 | //std::cout << "Alloc array " << type->name << "\n"; 24 | return obj + 1; 25 | } 26 | 27 | void GC::collect(std::vector& stack) { 28 | if (objects.empty()) return; 29 | 30 | for (auto&& val: stack) { 31 | if (val.type == VMValue::Type::object && val.value.object) { 32 | mark((VMObject*)val.value.object - 1); 33 | } 34 | } 35 | 36 | for (auto&& obj: lockList) { 37 | mark(obj); 38 | } 39 | 40 | auto it = objects.begin(); 41 | while (it != objects.end()) { 42 | auto obj = *it; 43 | if (obj->marked) { 44 | obj->marked = false; 45 | ++it; 46 | } 47 | else { 48 | //std::cout << "Free " << obj->type->name << "\n"; 49 | free(obj); 50 | it = objects.erase(it); 51 | } 52 | } 53 | } 54 | 55 | void GC::mark(VMObject* object) { 56 | if (object == nullptr) return; 57 | if (object->marked) return; 58 | if (object->type == nullptr) return; 59 | 60 | const auto& type = object->type; 61 | 62 | object->marked = true; 63 | 64 | if (type->isArray) { 65 | if (type->arrayType->isArray || type->arrayType->isObject) { 66 | char* ptr = object->data; 67 | uint64_t length; 68 | memcpy(&length, ptr, 8); 69 | ptr += 8; 70 | while (length--) { 71 | if (*(void**)ptr) { 72 | mark(*(VMObject**)ptr - 1); 73 | } 74 | ptr += 8; 75 | } 76 | } 77 | } 78 | else if (type->unionTypes.size()) { 79 | uint64_t tag = *(uint64_t*)object->data; 80 | void* ref = *(void**)&object->data[8]; 81 | VMType* refType = type->unionTypes[tag]; 82 | if (ref && (refType->isObject || refType->isArray)) { 83 | mark((VMObject*)ref - 1); 84 | } 85 | } 86 | else { 87 | for (auto&& field: type->fields) { 88 | if (field.type == nullptr || !(field.type->isArray || field.type->isObject)) continue; 89 | if (*(void**)&object->data[field.offset]) { 90 | mark(*(VMObject**)&object->data[field.offset] - 1); 91 | } 92 | } 93 | } 94 | } 95 | 96 | 97 | void GC::lock(void* obj) { 98 | lockList.insert((VMObject*)obj - 1); 99 | } 100 | 101 | void GC::unlock(void* obj) { 102 | lockList.erase((VMObject*)obj - 1); 103 | } 104 | } -------------------------------------------------------------------------------- /src/Ast/Token.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Stephan Unverwerth 2 | // This code is licensed under MIT license (See LICENSE for details) 3 | 4 | #include "Token.h" 5 | 6 | #include 7 | #include 8 | 9 | namespace Strela { 10 | #define AS_PAIR(X) {TokenType::X, #X}, 11 | std::map tokenNames { 12 | TOKENS(AS_PAIR) 13 | }; 14 | #undef AS_PAIR 15 | 16 | std::ostream& operator<<(std::ostream& stream, const Token& t) { 17 | return stream << tokenNames[t.type] << " '" << t.value << "'"; 18 | } 19 | 20 | std::string getTokenName(TokenType type) { 21 | return tokenNames[type]; 22 | } 23 | 24 | std::string getTokenVal(TokenType type) { 25 | switch (type) { 26 | case TokenType::Amp: return "&"; 27 | case TokenType::AmpAmp: return "&&"; 28 | case TokenType::AmpEquals: return "&="; 29 | case TokenType::Asterisk: return "*"; 30 | case TokenType::AsteriskEquals: return "*="; 31 | case TokenType::BracketClose: return "]"; 32 | case TokenType::BracketOpen: return "["; 33 | case TokenType::Caret: return "^"; 34 | case TokenType::CaretEquals: return "^="; 35 | case TokenType::Class: return "class"; 36 | case TokenType::Colon: return ":"; 37 | case TokenType::Comma: return ","; 38 | case TokenType::CurlyClose: return "}"; 39 | case TokenType::CurlyOpen: return "{"; 40 | case TokenType::Else: return "else"; 41 | case TokenType::Equals: return "="; 42 | case TokenType::EqualsEquals: return "=="; 43 | case TokenType::ExclamationMark: return "!"; 44 | case TokenType::Export: return "export"; 45 | case TokenType::Import: return "import"; 46 | case TokenType::ExclamationMarkEquals: return "!="; 47 | case TokenType::Function: return "function"; 48 | case TokenType::GreaterThan: return ">"; 49 | case TokenType::GreaterThanEquals: return ">="; 50 | case TokenType::If: return "if"; 51 | case TokenType::Interface: return "interface"; 52 | case TokenType::LessThan: return "<"; 53 | case TokenType::LessThanEquals: return "<="; 54 | case TokenType::Minus: return "-"; 55 | case TokenType::MinusEquals: return "-="; 56 | case TokenType::MinusMinus: return "--"; 57 | case TokenType::Module: return "module"; 58 | case TokenType::Mutable: return "mutable"; 59 | case TokenType::New: return "new"; 60 | case TokenType::Null: return "null"; 61 | case TokenType::ParenClose: return ")"; 62 | case TokenType::ParenOpen: return "("; 63 | case TokenType::Percent: return "%"; 64 | case TokenType::PercentEquals: return "%="; 65 | case TokenType::Period: return "."; 66 | case TokenType::Pipe: return "|"; 67 | case TokenType::PipeEquals: return "|="; 68 | case TokenType::PipePipe: return "||"; 69 | case TokenType::Plus: return "+"; 70 | case TokenType::PlusEquals: return "+="; 71 | case TokenType::PlusPlus: return "++"; 72 | case TokenType::QuestionMark: return "?"; 73 | case TokenType::Return: return "return"; 74 | case TokenType::Semicolon: return ";"; 75 | case TokenType::Slash: return "/"; 76 | case TokenType::SlashEquals: return "/="; 77 | case TokenType::Tilde: return "~"; 78 | case TokenType::Var: return "var"; 79 | case TokenType::While: return "while"; 80 | case TokenType::Enum: return "enum"; 81 | default: return ""; 82 | } 83 | } 84 | 85 | double Token::floatVal() { 86 | return std::stod(value); 87 | } 88 | 89 | int64_t Token::intVal() { 90 | return std::stoll(value); 91 | } 92 | 93 | bool Token::boolVal() { 94 | return value == "true"; 95 | } 96 | } -------------------------------------------------------------------------------- /src/VM/Opcode.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Stephan Unverwerth 2 | // This code is licensed under MIT license (See LICENSE for details) 3 | 4 | #ifndef Strela_VM_Opcode_h 5 | #define Strela_VM_Opcode_h 6 | 7 | #include "VMValue.h" 8 | 9 | namespace Strela { 10 | #define OPCODES(X) \ 11 | X(Trap, 0, null) \ 12 | X(ReturnVoid, 0, null) \ 13 | X(Return, 0, null) \ 14 | X(Const, 2, integer) \ 15 | X(I8, 1, integer) \ 16 | X(I16, 2, integer) \ 17 | X(I32, 4, integer) \ 18 | X(I64, 8, integer) \ 19 | X(U8, 1, integer) \ 20 | X(U16, 2, integer) \ 21 | X(U32, 4, integer) \ 22 | X(U64, 8, integer) \ 23 | X(F32, 4, floating) \ 24 | X(F64, 8, floating) \ 25 | X(Grow, 1, integer) \ 26 | X(Var, 1, integer) \ 27 | X(StoreVar, 1, integer) \ 28 | X(Ptr8, 1, integer) \ 29 | X(Ptr16, 1, integer) \ 30 | X(Ptr32, 1, integer) \ 31 | X(Ptr64, 1, integer) \ 32 | X(Ptr64Var, 2, integer) \ 33 | X(ObjPtr64, 1, integer) \ 34 | X(ObjPtr64Var, 2, integer) \ 35 | X(PtrInd8, 1, integer) \ 36 | X(PtrInd16, 1, integer) \ 37 | X(PtrInd32, 1, integer) \ 38 | X(PtrInd64, 1, integer) \ 39 | X(ObjPtrInd64, 1, integer) \ 40 | X(StorePtr8, 1, integer) \ 41 | X(StorePtr16, 1, integer) \ 42 | X(StorePtr32, 1, integer) \ 43 | X(StorePtr64, 1, integer) \ 44 | X(StorePtr64Var, 2, integer) \ 45 | X(StorePtrInd8, 1, integer) \ 46 | X(StorePtrInd16, 1, integer) \ 47 | X(StorePtrInd32, 1, integer) \ 48 | X(StorePtrInd64, 1, integer) \ 49 | X(Call, 1, integer) \ 50 | X(CallImm, 5, integer) \ 51 | X(NativeCall, 0, null) \ 52 | X(BuiltinCall, 8, integer) \ 53 | X(Jmp, 0, null) \ 54 | X(JmpIf, 0, null) \ 55 | X(JmpIfNot, 0, null) \ 56 | X(CmpEQ, 0, null) \ 57 | X(CmpNE, 0, null) \ 58 | X(CmpLTI, 0, null) \ 59 | X(CmpLTF32, 0, null) \ 60 | X(CmpLTF64, 0, null) \ 61 | X(CmpGTI, 0, null) \ 62 | X(CmpGTF32, 0, null) \ 63 | X(CmpGTF64, 0, null) \ 64 | X(CmpLTE, 0, null) \ 65 | X(CmpGTE, 0, null) \ 66 | X(Not, 0, null) \ 67 | X(AddI, 0, null) \ 68 | X(AddF32, 0, null) \ 69 | X(AddF64, 0, null) \ 70 | X(SubI, 0, null) \ 71 | X(SubF32, 0, null) \ 72 | X(SubF64, 0, null) \ 73 | X(MulI, 0, null) \ 74 | X(MulF32, 0, null) \ 75 | X(MulF64, 0, null) \ 76 | X(DivI, 0, null) \ 77 | X(DivF32, 0, null) \ 78 | X(DivF64, 0, null) \ 79 | X(ModI, 0, null) \ 80 | X(New, 2, integer) \ 81 | X(Array, 0, null) \ 82 | X(Null, 0, null) \ 83 | X(Repeat, 0, null) \ 84 | X(Pop, 0, null) \ 85 | X(PrintI, 0, null) \ 86 | X(PrintF32, 0, null) \ 87 | X(PrintF64, 0, null) \ 88 | X(PrintS, 0, null) \ 89 | X(PrintN, 0, null) \ 90 | X(PrintO, 0, null) \ 91 | X(PrintB, 0, null) \ 92 | X(AndL, 0, null) \ 93 | X(OrL, 0, null) \ 94 | X(Swap, 0, null) \ 95 | X(I64tF32, 0, null) \ 96 | X(I64tF64, 0, null) \ 97 | X(F32tI64, 0, null) \ 98 | X(F64tI64, 0, null) \ 99 | X(F64tF32, 0, null) \ 100 | X(F32tF64, 0, null) \ 101 | X(Peek, 1, integer) \ 102 | X(Mov8, 0, null) \ 103 | X(Mov16, 0, null) \ 104 | X(Mov32, 0, null) \ 105 | X(Mov64, 0, null) \ 106 | X(CmpType, 8, integer) \ 107 | 108 | #define AS_ENUM(X, A, T) X, 109 | enum class Opcode: unsigned char { 110 | OPCODES(AS_ENUM) 111 | }; 112 | #undef AS_ENUM 113 | 114 | #define AS_COUNT(C, A, T) + 1 115 | const int numOpcodes = 0 OPCODES(AS_COUNT); 116 | #undef AS_COUNT 117 | 118 | struct OpcodeInfo { 119 | const char* name; 120 | unsigned char argWidth; 121 | VMValue::Type argType; 122 | }; 123 | 124 | struct AddrMode { 125 | int dest: 2; 126 | int src1: 3; 127 | int src2: 3; 128 | }; 129 | 130 | extern OpcodeInfo opcodeInfo[]; 131 | } 132 | 133 | #endif -------------------------------------------------------------------------------- /Std/Net.strela: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Stephan Unverwerth 2 | // This code is licensed under MIT license (See LICENSE for details) 3 | 4 | module Std.Net { 5 | import Std.csockets; 6 | import Std.cstdio.*; 7 | import Std.Collections.List; 8 | import Std.IO.*; 9 | 10 | export class IPAddr { 11 | var a: u8; 12 | var b: u8; 13 | var c: u8; 14 | var d: u8; 15 | 16 | function init(a: u8, b: u8, c: u8, d: u8) { 17 | this.a = a; 18 | this.b = b; 19 | this.c = c; 20 | this.d = d; 21 | } 22 | 23 | function toInt(): u32 { 24 | var i: u32 = this.d + this.c * 256 + this.b * 65536 + this.a * 16777216; 25 | return i; 26 | } 27 | } 28 | 29 | /* 30 | AF_UNIX 1 31 | AF_INET 2 32 | AF_INET6 10 33 | */ 34 | 35 | export class Socket { 36 | var handle: i32; 37 | var errorflag: bool; 38 | 39 | function init(s: i32) { 40 | this.handle = s; 41 | this.errorflag = this.handle >= 0; 42 | } 43 | 44 | function init(ip: u32, port: u16) { 45 | this.handle = csockets.socket(2, 1, 0); 46 | this.errorflag = this.handle < 0; 47 | if (this.errorflag) { 48 | return; 49 | } 50 | this.bind(ip, port); 51 | } 52 | 53 | function init() { 54 | this.handle = csockets.socket(2, 1, 0); 55 | this.errorflag = this.handle >= 0; 56 | } 57 | 58 | function connect(ip: u32, port: u16): i32 { 59 | var addr = new csockets.sockaddr_in; 60 | addr.family = 2; 61 | addr.addr = csockets.htonl(ip); 62 | addr.port = csockets.htons(port); 63 | var result = csockets.connect(this.handle, addr, 16); 64 | this.errorflag = result == -1; 65 | return result; 66 | } 67 | 68 | function isValid(): bool { 69 | return !this.errorflag; 70 | } 71 | 72 | function readLine(): String { 73 | var tmp = "X"; 74 | var buf = new List; 75 | 76 | while (true) { 77 | var result = csockets.recv(this.handle, tmp, 1, 0); 78 | if (result <= 0) { 79 | this.errorflag = true; 80 | return ""; 81 | } 82 | buf.append(tmp.data[0]); 83 | if (tmp == "\n") { 84 | return new String(buf.array, buf.length); 85 | } 86 | } 87 | 88 | return new String(buf.array, buf.length); 89 | } 90 | 91 | function read(num: int): String { 92 | var tmp = new String(num); 93 | var result = ""; 94 | while (result.length() < num) { 95 | var numRead = csockets.recv(this.handle, tmp, num, 0); 96 | if (numRead < 0) { 97 | this.errorflag = true; 98 | return result; 99 | } 100 | if (numRead > 0) { 101 | result = result + tmp.substr(0, numRead); 102 | num = num - numRead; 103 | } 104 | } 105 | return result; 106 | } 107 | 108 | function write(str: String) { 109 | var remaining = str.length(); 110 | while (remaining > 0) { 111 | var written = csockets.send(this.handle, str, remaining, 0); 112 | if (written < 0) { 113 | this.errorflag = true; 114 | return; 115 | } 116 | if (written > 0) { 117 | remaining = remaining - written; 118 | str = str.substr(written, remaining); 119 | } 120 | } 121 | } 122 | 123 | function bind(ip: u32, port: u16) { 124 | var addr = new csockets.sockaddr_in; 125 | addr.family = 2; 126 | addr.addr = csockets.htonl(ip); 127 | addr.port = csockets.htons(port); 128 | 129 | csockets.bind(this.handle, addr, 16); 130 | } 131 | 132 | function listen() { 133 | csockets.listen(this.handle, 1); 134 | } 135 | 136 | function accept(): Socket { 137 | var addr = new csockets.sockaddr_in; 138 | var len: u32 = 16; 139 | var newsock = csockets.accept(this.handle, addr, len); 140 | return new Socket(newsock); 141 | } 142 | 143 | function shutdown() { 144 | csockets.shutdown(this.handle, 0); 145 | } 146 | 147 | function close() { 148 | csockets.close(this.handle); 149 | } 150 | } 151 | } -------------------------------------------------------------------------------- /Std/Net/HTTP.strela: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Stephan Unverwerth 2 | // This code is licensed under MIT license (See LICENSE for details) 3 | 4 | module Std.Net.HTTP { 5 | import Std.Net.Socket; 6 | import Std.Net.IPAddr; 7 | import Std.Collections.Map; 8 | import Std.IO.*; 9 | 10 | export class Client { 11 | var socket: Socket; 12 | 13 | function init() { 14 | this.socket = new Socket; 15 | } 16 | 17 | function connect(ip: u32, port: u16) { 18 | this.socket.connect(ip, port); 19 | } 20 | 21 | function connect(ip: IPAddr, port: u16) { 22 | this.socket.connect(ip.toInt(), port); 23 | } 24 | 25 | function request(request: Request): Response { 26 | this.socket.write(request.method + " " + request.path + " HTTP/1.1\r\n"); 27 | var i: int = 0; 28 | while (i < request.headers.keys.length) { 29 | this.socket.write(request.headers.keys[i]); 30 | this.socket.write(": "); 31 | this.socket.write(request.headers.values[i]); 32 | this.socket.write("\r\n"); 33 | 34 | i++; 35 | } 36 | this.socket.write("\r\n"); 37 | 38 | var response = new Response(); 39 | var line = this.socket.readLine(); 40 | while (line != "\r\n" && line != "") { 41 | line = this.socket.readLine(); 42 | var parts = line.split(":"); 43 | if (parts.length == 2) { 44 | response.headers.set(parts[0].trim(), parts[1].trim()); 45 | } 46 | } 47 | 48 | line = this.socket.readLine(); 49 | while (line != "") { 50 | response.body = response.body + line; 51 | line = this.socket.readLine(); 52 | } 53 | return response; 54 | } 55 | } 56 | 57 | export class Server { 58 | var socket: Socket; 59 | 60 | function init(address: i32, port: u16) { 61 | this.socket = new Socket(address, port); 62 | this.socket.listen(); 63 | } 64 | 65 | function accept(): Request { 66 | var sock = this.socket.accept(); 67 | var request = new Request; 68 | request.socket = sock; 69 | 70 | var line = sock.readLine(); 71 | 72 | var parts = line.split(" "); 73 | request.method = parts[0]; 74 | request.path = parts[1]; 75 | 76 | while (line != "\r\n") { 77 | line = sock.readLine(); 78 | var parts = line.split(":", 2); 79 | if (parts.length == 2) { 80 | request.headers.set(parts[0].trim(), parts[1].trim()); 81 | } 82 | } 83 | 84 | return request; 85 | } 86 | 87 | function close() { 88 | this.socket.shutdown(); 89 | this.socket.close(); 90 | } 91 | } 92 | 93 | export class Request { 94 | var socket: Socket; 95 | var path: String; 96 | var headers: Map; 97 | var body: String; 98 | var method: String; 99 | 100 | function init() { 101 | this.path = ""; 102 | this.body = ""; 103 | this.method = "GET"; 104 | this.headers = new Map; 105 | } 106 | 107 | function respond(response: Response) { 108 | this.socket.write("HTTP/1.1 " + toString(response.statusCode) + " " + response.statusMessage + "\r\n"); 109 | var i: int = 0; 110 | while (i < response.headers.keys.length) { 111 | this.socket.write(response.headers.keys[i]); 112 | this.socket.write(": "); 113 | this.socket.write(response.headers.values[i]); 114 | this.socket.write("\r\n"); 115 | i++; 116 | } 117 | this.socket.write("Connection: close\r\n"); 118 | this.socket.write("\r\n"); 119 | this.socket.write(response.body); 120 | this.socket.shutdown(); 121 | this.socket.close(); 122 | } 123 | } 124 | 125 | export class Response { 126 | var statusCode: u16; 127 | var statusMessage: String; 128 | var headers: Map; 129 | var body: String; 130 | 131 | function init() { 132 | this.statusMessage = ""; 133 | this.body = ""; 134 | this.headers = new Map; 135 | } 136 | } 137 | } -------------------------------------------------------------------------------- /src/TypeChecker.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Stephan Unverwerth 2 | // This code is licensed under MIT license (See LICENSE for details) 3 | 4 | #ifndef Strela_TypeChecker_h 5 | #define Strela_TypeChecker_h 6 | 7 | #include "IStmtVisitor.h" 8 | #include "IExprVisitor.h" 9 | #include "Pass.h" 10 | #include "Ast/TypeDecl.h" 11 | #include "Ast/InvalidType.h" 12 | 13 | #include 14 | #include 15 | #include 16 | 17 | namespace Strela { 18 | class Refinement; 19 | class TypeDecl; 20 | class Node; 21 | class Stmt; 22 | class Expr; 23 | class Param; 24 | class FuncDecl; 25 | class ClassDecl; 26 | class ModDecl; 27 | class InterfaceDecl; 28 | 29 | class TypeChecker: public Pass, public IStmtVisitor, public IExprVisitor { 30 | public: 31 | TypeChecker(); 32 | void check(ModDecl&); 33 | void check(ClassDecl&); 34 | void check(FuncDecl&); 35 | 36 | void visit(BlockStmt&) override; 37 | void visit(ExprStmt&) override; 38 | void visit(IfStmt&) override; 39 | void visit(RetStmt&) override; 40 | void visit(VarDecl&) override; 41 | void visit(WhileStmt&) override; 42 | 43 | void visit(ArrayLitExpr&) override; 44 | void visit(ArrayTypeExpr&) override {} 45 | void visit(AssignExpr&) override; 46 | void visit(BinopExpr&) override; 47 | void visit(CallExpr&) override; 48 | void visit(CastExpr&) override; 49 | void visit(GenericReificationExpr&) override {} 50 | void visit(IdExpr&) override; 51 | void visit(IsExpr&) override; 52 | void visit(LitExpr&) override; 53 | void visit(MapLitExpr&) override; 54 | void visit(NewExpr&) override; 55 | void visit(NullableTypeExpr&) override {} 56 | void visit(PostfixExpr&) override; 57 | void visit(ScopeExpr&) override; 58 | void visit(SubscriptExpr&) override; 59 | void visit(ThisExpr&) override; 60 | void visit(UnaryExpr&) override; 61 | void visit(UnionTypeExpr&) override {} 62 | 63 | template void visitChildren(T& children) { 64 | for (auto&& child: children) { 65 | child->accept(*this); 66 | } 67 | } 68 | 69 | template void visitChild(T& child) { 70 | if (child) child->accept(*this); 71 | } 72 | 73 | template bool unify(T&& child, TypeDecl* with) { 74 | auto oldExpectedType = expectedType; 75 | expectedType = with; 76 | bool success = true; 77 | if (child) { 78 | child->accept(*this); 79 | if (expectedType && !isAssignableFrom(expectedType, getType(child))) { 80 | if (child->type != &InvalidType::instance) { 81 | error(*child, child->type->getFullName() + " is not coercible to " + expectedType->getFullName()); 82 | success = false; 83 | } 84 | } 85 | else if (expectedType) { 86 | child = addCast(child, expectedType); 87 | } 88 | } 89 | expectedType = oldExpectedType; 90 | return success; 91 | } 92 | 93 | template bool unifyChildren(T& children, TypeDecl* with) { 94 | auto oldExpectedType = expectedType; 95 | expectedType = with; 96 | bool success = true; 97 | for (auto&& child: children) { 98 | if (child) { 99 | child->accept(*this); 100 | if (expectedType && !isAssignableFrom(expectedType, getType(child))) { 101 | if (child->type != &InvalidType::instance) { 102 | error(*child, child->type->getFullName() + " is not coercible to " + expectedType->getFullName()); 103 | success = false; 104 | } 105 | } 106 | else if (expectedType) { 107 | child = addCast(child, expectedType); 108 | } 109 | } 110 | } 111 | expectedType = oldExpectedType; 112 | return success; 113 | } 114 | 115 | void negateRefinements(); 116 | 117 | std::vector getTypes(const std::vector& arguments); 118 | TypeDecl* getType(Expr* expr); 119 | TypeDecl* getType(VarDecl* var); 120 | TypeDecl* getType(Param* param); 121 | 122 | private: 123 | std::vector findOverload(Expr* target, const std::vector& argtypes); 124 | std::vector findOverload(const std::vector& funcs, const std::vector& args); 125 | std::vector findOverload(const std::vector& funcs, const std::vector& argTypes); 126 | 127 | void printMissingMembers(ClassDecl* cls, InterfaceDecl* iface); 128 | 129 | FuncDecl* function = nullptr; 130 | BlockStmt* block = nullptr; 131 | ClassDecl* _class = nullptr; 132 | TypeDecl* expectedType = nullptr; 133 | 134 | bool returns = false; 135 | 136 | std::vector>> refinements; 137 | }; 138 | } 139 | #endif -------------------------------------------------------------------------------- /src/Decompiler.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Stephan Unverwerth 2 | // This code is licensed under MIT license (See LICENSE for details) 3 | 4 | #include "Decompiler.h" 5 | #include "VM/ByteCodeChunk.h" 6 | #include "VM/VMObject.h" 7 | #include "SourceFile.h" 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | namespace Strela { 15 | std::string escape(const std::string&); 16 | 17 | void Decompiler::printValue(const VMValue& c) const { 18 | std::cout << std::dec; 19 | if (c.type == VMValue::Type::integer) std::cout << "int(" << c.value.integer << ")"; 20 | else if (c.type == VMValue::Type::floating) std::cout << "float(" << c.value.f64 << ")"; 21 | else if (c.type == VMValue::Type::boolean) std::cout << (c.value.boolean ? "true" : "false"); 22 | else if (c.type == VMValue::Type::null) std::cout << "null"; 23 | else if (c.type == VMValue::Type::object) { 24 | std::cout << "\"" << escape((const char*)c.value.object) << "\""; 25 | } 26 | else std::cout << "???"; 27 | } 28 | 29 | void Decompiler::listing() const { 30 | std::cout << "; Constants\n"; 31 | for (size_t i = 0; i < chunk.constants.size(); ++i) { 32 | auto c = chunk.constants[i]; 33 | std::cout << std::dec << i << ": "; 34 | printValue(c); 35 | std::cout << "\n"; 36 | } 37 | 38 | for (size_t i = 0; i < chunk.opcodes.size(); ++i) { 39 | auto function = chunk.functions.find(i); 40 | if (function != chunk.functions.end()) { 41 | std::cout << "\n; " << function->second.name << "\n"; 42 | } 43 | 44 | size_t opStart = i; 45 | auto op = (Opcode)chunk.opcodes[i]; 46 | auto info = opcodeInfo[(int)op]; 47 | 48 | auto numArgs = info.argWidth; 49 | int width = numArgs + 1; 50 | std::vector args; 51 | for (int a = 0; a < numArgs; ++a) { 52 | args.push_back((unsigned char)chunk.opcodes[++i]); 53 | } 54 | auto arg = getArg(opStart); 55 | 56 | std::cout << "0x" << std::right << std::setw(8) << std::setfill('0') << std::hex << opStart << " " << std::setw(2) << (int)op << " "; 57 | 58 | for (int a = 0; a < 4; ++a) { 59 | if (a < args.size()) { 60 | std::cout << std::setw(2) << (int)args[a] << " "; 61 | } 62 | else { 63 | std::cout << ".. "; 64 | } 65 | } 66 | 67 | std::cout << std::left << std::setfill(' ') << std::setw(16); 68 | 69 | if ((int)op > numOpcodes) { 70 | std::cout << "???"; 71 | } 72 | else { 73 | std::cout << info.name; 74 | } 75 | 76 | if (op == Opcode::Call || op == Opcode::Jmp || op == Opcode::JmpIf || op == Opcode::JmpIfNot) { 77 | int cpos = i - width - opcodeInfo[(int)Opcode::Const].argWidth; 78 | if (cpos >= 0 && (Opcode)chunk.opcodes[cpos] == Opcode::Const) { 79 | auto constIndex = getArg(cpos); 80 | auto address = chunk.constants[constIndex].value.integer; 81 | auto it = chunk.functions.find(address); 82 | if (it != chunk.functions.end()) { 83 | std::cout << it->second.name; 84 | } 85 | else { 86 | int diff = (int)address - (int)opStart; 87 | std::cout << std::dec << (diff > 0 ? "+" : "") << diff; 88 | } 89 | std::cout << " (0x" << std::setw(8) << std::setfill('0') << std::hex << std::right << address << ")"; 90 | } 91 | else { 92 | std::cout << "(dynamic)"; 93 | } 94 | } 95 | else if (op == Opcode::CallImm) { 96 | arg &= 0xffffffff; 97 | auto it = chunk.functions.find(arg); 98 | if (it != chunk.functions.end()) { 99 | std::cout << it->second.name; 100 | } 101 | else { 102 | int diff = (int)arg - (int)opStart; 103 | std::cout << std::dec << (diff > 0 ? "+" : "") << diff; 104 | } 105 | std::cout << " (0x" << std::setw(8) << std::setfill('0') << std::hex << std::right << arg << ")"; 106 | } 107 | else if (op == Opcode::New) { 108 | if (arg < chunk.types.size()) { 109 | std::cout << chunk.types[arg]->name << " "; 110 | } 111 | } 112 | else if (op == Opcode::ObjPtr64Var) { 113 | int offset = arg & 0xff; 114 | int var = (arg & 0xff00) >> 8; 115 | std::cout << std::dec << "(object)var_" << var << "[" << offset << "] "; 116 | } 117 | else if (op == Opcode::Ptr64Var) { 118 | int offset = arg & 0xff; 119 | int var = (arg & 0xff00) >> 8; 120 | std::cout << std::dec << "var_" << var << "[" << offset << "] "; 121 | } 122 | else if (args.size()) { 123 | std::cout << std::dec; 124 | if (op == Opcode::Const) { 125 | auto c = chunk.constants[arg]; 126 | printValue(c); 127 | } 128 | else { 129 | if (op == Opcode::ReturnVoid || op == Opcode::Return) { 130 | if (arg > 0) { 131 | std::cout << "pop "<< (int)arg; 132 | } 133 | } 134 | else if (op == Opcode::F32) { 135 | std::cout << *(float*)&arg; 136 | } 137 | else if (op == Opcode::F64) { 138 | std::cout << *(double*)&arg; 139 | } 140 | else { 141 | std::cout << (int)arg; 142 | } 143 | } 144 | } 145 | std::cout << "\n"; 146 | } 147 | } 148 | 149 | uint64_t Decompiler::getArg(size_t pos) const { 150 | auto op = chunk.opcodes[pos]; 151 | auto numargs = opcodeInfo[(int)op].argWidth; 152 | uint64_t arg = 0; 153 | if (numargs > sizeof(arg)) numargs = sizeof(arg); 154 | memcpy(&arg, &chunk.opcodes[pos + 1], numargs); 155 | return arg; 156 | } 157 | } -------------------------------------------------------------------------------- /src/VM/VMValue.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Stephan Unverwerth 2 | // This code is licensed under MIT license (See LICENSE for details) 3 | 4 | #include "VMValue.h" 5 | #include "VMObject.h" 6 | 7 | #include 8 | 9 | namespace Strela { 10 | #define VMVALUE_OP(OP) \ 11 | if (type == Type::integer) return VMValue(int64_t(value.integer OP other.value.integer)); \ 12 | else if (type == Type::floating) return VMValue(double(value.f64 OP other.value.f64)); \ 13 | else if (type == Type::boolean) return VMValue(bool(value.boolean OP other.value.boolean)); \ 14 | else return VMValue(); 15 | 16 | #define VMVALUE_OP_LOG(OP) \ 17 | if (type == Type::integer) return VMValue(bool(value.integer OP other.value.integer)); \ 18 | else if (type == Type::floating) return VMValue(bool(value.f64 OP other.value.f64)); \ 19 | else if (type == Type::boolean) return VMValue(bool(value.boolean OP other.value.boolean)); \ 20 | else return VMValue(); 21 | 22 | VMValue::VMValue(): type(Type::null) { value.integer = 0; } 23 | VMValue::VMValue(int64_t val) : type(Type::integer) { value.integer = val; } 24 | VMValue::VMValue(double val) : type(Type::floating) { value.f64 = val; } 25 | VMValue::VMValue(bool val) : type(Type::boolean) { value.boolean = val; } 26 | VMValue::VMValue(void* val) : type(Type::object) { value.object = val; } 27 | 28 | VMValue VMValue::operator==(const VMValue& other) const { 29 | VMVALUE_OP_LOG(==); 30 | } 31 | 32 | VMValue VMValue::operator!=(const VMValue& other) const { 33 | VMVALUE_OP_LOG(!=); 34 | } 35 | 36 | VMValue VMValue::operator<(const VMValue& other) const { 37 | VMVALUE_OP_LOG(<); 38 | } 39 | 40 | VMValue VMValue::operator>(const VMValue& other) const { 41 | VMVALUE_OP_LOG(>); 42 | } 43 | 44 | VMValue VMValue::operator<=(const VMValue& other) const { 45 | VMVALUE_OP_LOG(<=); 46 | } 47 | 48 | VMValue VMValue::operator>=(const VMValue& other) const { 49 | VMVALUE_OP_LOG(>=); 50 | } 51 | 52 | VMValue VMValue::operator&&(const VMValue& other) const { 53 | VMVALUE_OP_LOG(&&); 54 | } 55 | 56 | VMValue VMValue::operator||(const VMValue& other) const { 57 | VMVALUE_OP_LOG(||); 58 | } 59 | 60 | 61 | VMValue VMValue::operator+(const VMValue& other) const { 62 | VMVALUE_OP(+); 63 | } 64 | 65 | VMValue VMValue::operator-(const VMValue& other) const { 66 | VMVALUE_OP(-); 67 | } 68 | 69 | VMValue VMValue::operator*(const VMValue& other) const { 70 | VMVALUE_OP(*); 71 | } 72 | 73 | VMValue VMValue::operator/(const VMValue& other) const { 74 | VMVALUE_OP(/); 75 | } 76 | 77 | VMValue VMValue::operator!() const { 78 | return VMValue(!bool(*this)); 79 | } 80 | 81 | VMValue::operator bool() const { 82 | if (type == Type::integer) return value.integer != 0; 83 | else if (type == Type::floating) return value.f64 != 0; 84 | else if (type == Type::boolean) return value.boolean; 85 | else if (type == Type::null) return false; 86 | else if (type == Type::object) return value.object != nullptr; 87 | else return false; 88 | } 89 | 90 | bool VMValue::equals(const VMValue& other) const { 91 | if (type != other.type) return false; 92 | 93 | if (type == Type::integer) return value.integer == other.value.integer; 94 | else if (type == Type::floating) return value.f64 == other.value.f64; 95 | else if (type == Type::boolean) return value.boolean == other.value.boolean; 96 | else if (type == Type::null) return true; 97 | else if (type == Type::object) return value.object == other.value.object; 98 | else return false; 99 | } 100 | 101 | std::string VMValue::dump() const { 102 | switch (type) { 103 | case Type::boolean: return std::string("bool: ") + (value.boolean ? "true" : "false"); 104 | case Type::integer: return "int: " + std::to_string(value.integer); 105 | case Type::floating: return "float: " + std::to_string(value.f64); 106 | case Type::null: return "null"; 107 | case Type::object: return "[object]"; 108 | } 109 | } 110 | 111 | struct StringConst { 112 | bool marked; 113 | VMType* type; 114 | uint64_t* str; 115 | uint64_t len; 116 | char chars[]; 117 | }; 118 | 119 | std::ostream& operator<<(std::ostream& str, const VMValue& v) { 120 | if (v.type == VMValue::Type::integer) { 121 | str.write("i", 1); 122 | str.write((const char*)&v.value.integer, 8); 123 | } 124 | else if (v.type == VMValue::Type::floating) { 125 | str.write("d", 1); 126 | str.write((const char*)&v.value.f64, 8); 127 | } 128 | else if (v.type == VMValue::Type::boolean) { 129 | str.write("b", 1); 130 | str.write((const char*)&v.value.boolean, 1); 131 | } 132 | else if (v.type == VMValue::Type::object) { 133 | str.write("s", 1); 134 | /*StringConst* string = v.value.object; 135 | uint64_t len = strlen(v.value.string); 136 | str.write((const char*)&len, 8); 137 | str.write(v.value.string, len);*/ 138 | } 139 | else if (v.type == VMValue::Type::null) { 140 | str.write("n", 1); 141 | } 142 | 143 | return str; 144 | } 145 | 146 | std::istream& operator>>(std::istream& str, VMValue& v) { 147 | char t; 148 | str.read(&t, 1); 149 | 150 | if (t == 'i') { 151 | v.type = VMValue::Type::integer; 152 | str.read((char*)&v.value.integer, 8); 153 | } 154 | else if (t == 'd') { 155 | v.type = VMValue::Type::floating; 156 | str.read((char*)&v.value.f64, 8); 157 | } 158 | else if (t == 'b') { 159 | v.type = VMValue::Type::boolean; 160 | str.read((char*)&v.value.boolean, 1); 161 | } 162 | else if (t == 's') { 163 | uint64_t len; 164 | str.read((char*)&len, 8); 165 | 166 | struct StringConst { 167 | bool marked; 168 | VMType* type; 169 | uint64_t* str; 170 | uint64_t len; 171 | char chars[]; 172 | }; 173 | 174 | StringConst* string = (StringConst*)calloc(1, sizeof(StringConst) + len + 1 ); 175 | 176 | str.read(string->chars, len); 177 | string->chars[len] = 0; 178 | string->marked = true; 179 | string->type = nullptr; 180 | string->str = &string->len; 181 | 182 | v.type = VMValue::Type::object; 183 | v.value.object = string; 184 | } 185 | else if (t == 'n') { 186 | v.type = VMValue::Type::null; 187 | } 188 | 189 | return str; 190 | } 191 | 192 | } -------------------------------------------------------------------------------- /Std/core.strela: -------------------------------------------------------------------------------- 1 | module core { 2 | export class String { 3 | var data: u8[]; 4 | 5 | function init() { 6 | this.data = new u8[](1); 7 | } 8 | 9 | function init(length: int) { 10 | this.data = new u8[](length + 1); 11 | } 12 | 13 | function init(data: u8[]) { 14 | this.data = new u8[](data.length + 1); 15 | var i: int = 0; 16 | while (i < data.length) { 17 | this.data[i] = data[i]; 18 | i++; 19 | } 20 | } 21 | 22 | function init(data: u8[], length: int) { 23 | this.data = new u8[](length + 1); 24 | var i: int = 0; 25 | while (i < length) { 26 | this.data[i] = data[i]; 27 | i++; 28 | } 29 | } 30 | 31 | function init(a: String, b: String) { 32 | var alength = a.length(); 33 | var blength = b.length(); 34 | this.data = new u8[](alength + blength + 1); 35 | var i: int = 0; 36 | while (i < alength) { 37 | this.data[i] = a.data[i]; 38 | i++; 39 | } 40 | var j: int = 0; 41 | while (j < blength) { 42 | this.data[i] = b.data[j]; 43 | j++; 44 | i++; 45 | } 46 | } 47 | 48 | function length(): int { 49 | return this.data.length - 1; 50 | } 51 | 52 | function +(other: String): String { 53 | return new String(this, other); 54 | } 55 | 56 | function !=(other: String): bool { 57 | return !(this == other); 58 | } 59 | 60 | function ==(other: String): bool { 61 | var len = this.length(); 62 | if (len != other.length()) { 63 | return false; 64 | } 65 | var i: int = 0; 66 | while (i < len) { 67 | if (this.data[i] != other.data[i]) { 68 | return false; 69 | } 70 | i++; 71 | } 72 | return true; 73 | } 74 | 75 | function substr(start: int, length: int): String { 76 | var str = new String(length); 77 | var i: int = 0; 78 | while (i < length) { 79 | str.data[i] = this.data[start + i]; 80 | i++; 81 | } 82 | return str; 83 | } 84 | 85 | function [](i: int): String { 86 | if (i < 0 || i >= this.length()) return ""; 87 | 88 | var str = new String(1); 89 | str.data[0] = this.data[i]; 90 | return str; 91 | } 92 | 93 | function split(separator: String): String[] { 94 | return this.split(separator, 0); 95 | } 96 | 97 | function split(separator: String, max: int): String[] { 98 | 99 | if (separator.length() == 0) return [this]; 100 | 101 | var ch = separator.data[0]; 102 | 103 | // Count substrings 104 | var count = 1; 105 | var i = 0; 106 | while (i < this.length() && (count < max || max == 0)) { 107 | if (this.data[i] == ch) { 108 | count++; 109 | } 110 | i++; 111 | } 112 | 113 | var parts = new String[](count); 114 | 115 | var start = 0; 116 | i = 0; 117 | count = 0; 118 | while (i < this.length() && (count < (max - 1) || max == 0)) { 119 | if (this.data[i] == ch) { 120 | parts[count] = this.substr(start, i - start); 121 | count++; 122 | start = i + 1; 123 | } 124 | i++; 125 | } 126 | parts[count] = this.substr(start, this.length() - start); 127 | 128 | return parts; 129 | } 130 | 131 | function trim(): String { 132 | var length = this.length(); 133 | if (length == 0) return this; 134 | 135 | var start: int = 0; 136 | var end: int = length - 1; 137 | while (start < length && this.data[start] < 33) { 138 | start++; 139 | } 140 | while (end > start && this.data[end] < 33) { 141 | end--; 142 | } 143 | return this.substr(start, end - start + 1); 144 | } 145 | 146 | function replace(what: String, with: String): String { 147 | var length = this.length(); 148 | var str = new String(length); 149 | var i: int = 0; 150 | while (i < length) { 151 | var ch = this.data[i]; 152 | if (ch == what.data[0]) { 153 | ch = with.data[0]; 154 | } 155 | str.data[i] = ch; 156 | i++; 157 | } 158 | return str; 159 | } 160 | 161 | function toInt(): int { 162 | var val: int = 0; 163 | var i: int = 0; 164 | while (i < this.length()) { 165 | val *= 10; 166 | var ch = this.data[i]; 167 | if (ch < 48 || ch > 57) return 0; 168 | val += ch - 48; 169 | i++; 170 | } 171 | return val; 172 | } 173 | 174 | function toFloat(): float { 175 | var val = 0.0; 176 | 177 | var frac = false; 178 | var mag = 1.0; 179 | var sign = 1.0; 180 | 181 | var i: int = 0; 182 | if (this[0] == "-") { 183 | sign = -1.0; 184 | i++; 185 | } 186 | while (i < this.length()) { 187 | var ch = this.data[i]; 188 | 189 | if (ch == 46 && !frac) { 190 | frac = true; 191 | } 192 | else if (ch < 48 || ch > 57) { 193 | return 0; 194 | } 195 | else { 196 | val *= 10; 197 | val += ch - 48; 198 | if (frac) { 199 | mag = mag * 0.1; 200 | } 201 | } 202 | i++; 203 | } 204 | return sign * val * mag; 205 | } 206 | } 207 | 208 | export function toString(val: int): String { 209 | var str = new String(20); 210 | var i: int = str.length() - 1; 211 | var sign = val < 0; 212 | if (sign) { 213 | val = -val; 214 | } 215 | while (val > 9) { 216 | str.data[i] = 48 + val % 10; 217 | i = i - 1; 218 | val = val / 10; 219 | } 220 | str.data[i] = 48 + val % 10; 221 | i = i - 1; 222 | 223 | if (sign) return "-" + str.substr(i + 1, str.length() - i - 1); 224 | else return str.substr(i + 1, str.length() - i - 1); 225 | } 226 | 227 | export function toString(val: float, decimals: int): String { 228 | var intPart = val as int; 229 | val = val - intPart; 230 | if (val < 0.0) { 231 | val = val * -1.0; 232 | } 233 | 234 | if (val > 0.0) { 235 | var f: int = 1; 236 | while (decimals > 0) { 237 | f = f * 10; 238 | decimals--; 239 | } 240 | return toString(intPart) + "." + toString((val * f) as int); 241 | } 242 | else { 243 | return toString(intPart); 244 | } 245 | } 246 | } -------------------------------------------------------------------------------- /src/VM/ByteCodeChunk.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Stephan Unverwerth 2 | // This code is licensed under MIT license (See LICENSE for details) 3 | 4 | #include "ByteCodeChunk.h" 5 | #include "../exceptions.h" 6 | #include "../Ast/FuncDecl.h" 7 | #include "../Ast/FuncType.h" 8 | 9 | #include 10 | 11 | namespace Strela { 12 | int ByteCodeChunk::addConstant(VMValue c) { 13 | for (int i = 0; i < constants.size(); ++i) { 14 | if ( 15 | c.type == VMValue::Type::object 16 | && constants[i].type == VMValue::Type::object 17 | && !strcmp((const char*)c.value.object, (const char*)constants[i].value.object) 18 | ) { 19 | return i; 20 | } 21 | else if (constants[i].equals(c)) { 22 | return i; 23 | } 24 | } 25 | constants.push_back(c); 26 | return constants.size() - 1; 27 | } 28 | 29 | int ByteCodeChunk::addForeignFunction(FuncDecl& n) { 30 | for (int i = 0; i < foreignFunctions.size(); ++i) { 31 | if ( 32 | foreignFunctions[i].name == n.name && 33 | foreignFunctions[i].returnType == n.declType->returnType && 34 | foreignFunctions[i].argTypes == n.declType->paramTypes 35 | ) { 36 | return i; 37 | } 38 | } 39 | foreignFunctions.push_back(ForeignFunction(n.name, n.declType->returnType, n.declType->paramTypes)); 40 | return foreignFunctions.size() - 1; 41 | } 42 | 43 | int ByteCodeChunk::addOp(Opcode code) { 44 | if (opcodeInfo[(unsigned char)code].argWidth > 0) throw Exception(std::string("Opcode ") + opcodeInfo[(unsigned char)code].name + " requires arguments."); 45 | opcodes.push_back(code); 46 | return opcodes.size() - 1; 47 | } 48 | 49 | int ByteCodeChunk::addOp(Opcode code, size_t argSize, const void* arg) { 50 | auto opwidth = opcodeInfo[(unsigned char)code].argWidth; 51 | if (opwidth != argSize) throw Exception(std::string("Opcode ") + opcodeInfo[(unsigned char)code].name + " has mismatching argument size. " 52 | + std::to_string(opwidth) + " expected but got " + std::to_string(argSize) 53 | ); 54 | auto opAddr = opcodes.size(); 55 | opcodes.push_back(code); 56 | opcodes.resize(opcodes.size() + argSize); 57 | memcpy(&opcodes[opAddr + 1], arg, argSize); 58 | return opAddr; 59 | } 60 | 61 | int ByteCodeChunk::addOp(Opcode code, size_t argSize1, const void* arg1, size_t argSize2, const void* arg2) { 62 | auto opwidth = opcodeInfo[(unsigned char)code].argWidth; 63 | if (opwidth != argSize1 + argSize2) throw Exception(std::string("Opcode ") + opcodeInfo[(unsigned char)code].name + " has mismatching argument size. " 64 | + std::to_string(opwidth) + " expected but got " + std::to_string(argSize1 + argSize2) 65 | ); 66 | auto opAddr = opcodes.size(); 67 | opcodes.push_back(code); 68 | opcodes.resize(opcodes.size() + argSize1 + argSize2); 69 | memcpy(&opcodes[opAddr + 1], arg1, argSize1); 70 | memcpy(&opcodes[opAddr + 1 + argSize1], arg2, argSize2); 71 | return opAddr; 72 | } 73 | 74 | void ByteCodeChunk::addFunction(size_t address, const FunctionInfo& func) { 75 | functions.insert(std::make_pair(address, func)); 76 | } 77 | 78 | void ByteCodeChunk::writeArgument(size_t pos, uint64_t arg) { 79 | auto numargs = opcodeInfo[(int)opcodes[pos++]].argWidth; 80 | if (pos + numargs > opcodes.size()) { 81 | opcodes.resize(pos + numargs); 82 | } 83 | memcpy(&opcodes[pos], &arg, numargs); 84 | } 85 | 86 | void ByteCodeChunk::write(size_t pos, void* data, size_t size) { 87 | memcpy(&opcodes[pos], data, size); 88 | } 89 | 90 | std::ostream& operator<<(std::ostream& str, const ByteCodeChunk& chunk) { 91 | str.write("STBC", 4); 92 | 93 | uint32_t numFunctions = chunk.functions.size(); 94 | str.write((const char*)&numFunctions, 4); 95 | for (auto&& function: chunk.functions) { 96 | uint64_t offset = function.first; 97 | uint64_t len = function.second.name.size(); 98 | const char* name = function.second.name.c_str(); 99 | str.write((const char*)&offset, 8); 100 | str.write((const char*)&len, 8); 101 | str.write((const char*)name, len); 102 | } 103 | 104 | uint32_t numConstants = chunk.constants.size(); 105 | str.write((const char*)&numConstants, 4); 106 | for (auto&& constant: chunk.constants) { 107 | str << constant; 108 | } 109 | 110 | uint64_t main = chunk.main; 111 | str.write((const char*)&main, 8); 112 | 113 | uint64_t numOpcodes = chunk.opcodes.size(); 114 | str.write((const char*)&numOpcodes, 8); 115 | str.write((const char*)chunk.opcodes.data(), sizeof(char) * numOpcodes); 116 | 117 | return str; 118 | } 119 | 120 | std::istream& operator>>(std::istream& str, ByteCodeChunk& chunk) { 121 | chunk.constants.clear(); 122 | chunk.functions.clear(); 123 | chunk.opcodes.clear(); 124 | 125 | char magic[5]{0}; 126 | str.read((char*)&magic, 4); 127 | if (strcmp(magic, "STBC")) { 128 | throw std::runtime_error("Invalid bytecode format"); 129 | } 130 | 131 | uint32_t numFunctions; 132 | str.read((char*)&numFunctions, 4); 133 | for (size_t i = 0; i < numFunctions; ++i) { 134 | uint64_t offset; 135 | str.read((char*)&offset, 8); 136 | uint64_t len; 137 | str.read((char*)&len, 8); 138 | char* name = new char[len + 1]; 139 | name[len] = 0; 140 | str.read((char*)name, len); 141 | chunk.functions.insert(std::make_pair(offset, FunctionInfo{std::string(name)})); 142 | delete[] name; 143 | } 144 | 145 | uint32_t numConstants; 146 | str.read((char*)&numConstants, 4); 147 | for (size_t i = 0; i < numConstants; ++i) { 148 | VMValue constant; 149 | str >> constant; 150 | chunk.constants.push_back(constant); 151 | } 152 | 153 | uint64_t main; 154 | str.read((char*)&main, 8); 155 | chunk.main = main; 156 | 157 | uint64_t numOpcodes; 158 | str.read((char*)&numOpcodes, 8); 159 | for (size_t i = 0; i < numOpcodes; ++i) { 160 | Opcode op; 161 | str.read((char*)&op, 1); 162 | chunk.opcodes.push_back(op); 163 | } 164 | 165 | return str; 166 | } 167 | 168 | const SourceLine* ByteCodeChunk::getLine(size_t address) const { 169 | for (int i = 0; i < lines.size(); ++i) { 170 | if (lines[i].address > address) { 171 | if (i == 0) return nullptr; 172 | return &lines[i - 1]; 173 | } 174 | } 175 | return nullptr; 176 | } 177 | 178 | void ByteCodeChunk::setLine(const SourceFile* file, size_t line) { 179 | for (size_t i = 0; i < files.size(); ++i) { 180 | if (files[i] == file) { 181 | if (!lines.empty() && lines.back().file == i && lines.back().line == line) { 182 | return; 183 | } 184 | lines.push_back({ opcodes.size(), i, line }); 185 | return; 186 | } 187 | } 188 | files.push_back(file); 189 | lines.push_back({ opcodes.size(), files.size() - 1, line }); 190 | } 191 | } --------------------------------------------------------------------------------