diff --git a/.github/workflows/cmake-single-platform-linux.yml b/.github/workflows/cmake-single-platform-linux.yml new file mode 100644 index 0000000..3b4b3dc --- /dev/null +++ b/.github/workflows/cmake-single-platform-linux.yml @@ -0,0 +1,168 @@ +name: CMake on a single platform on Linux + +on: + push: + branches: [ "master" ] + pull_request: + branches: [ "master" ] + +env: + # Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.) + BUILD_TYPE: Release + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + + - name: Initialize submodules + run: git submodule update --init --recursive + + - name: Install Wasmer + run: curl https://get.wasmer.io -sSfL | WASMER_DIR=lib/wasmer sh + + - name: Upload Wasmer as artifact + uses: actions/upload-artifact@v4 + with: + name: wasmer + path: ${{ github.workspace }}/lib/wasmer + + - name: Cache CMake build + uses: actions/cache@v3 + with: + path: build + key: ${{ runner.os }}-build-${{ github.sha }} + restore-keys: | + ${{ runner.os }}-build- + + - name: Cache CMake dependencies + uses: actions/cache@v3 + with: + path: | + .cache + key: ${{ runner.os }}-cmake-${{ github.sha }} + restore-keys: | + ${{ runner.os }}-cmake- + + - name: Install libreadline-dev + run: sudo apt-get install -y libreadline-dev + + - name: Build project + working-directory: ${{ github.workspace }} + run: ./build.sh + + - name: Upload build artifacts + uses: actions/upload-artifact@v4 + with: + name: build + path: ${{ github.workspace }}/build + + lexer-test: + runs-on: ubuntu-latest + needs: build + + steps: + - uses: actions/checkout@v4 + + - name: Download build artifacts + uses: actions/download-artifact@v4 + with: + name: build + path: ${{ github.workspace }}/build + + - name: Download Wasmer artifacts + uses: actions/download-artifact@v4 + with: + name: wasmer + path: ${{ github.workspace }}/lib/wasmer + + - name: Make LexerTest Executable + run: chmod +x ${{ github.workspace }}/build/LexerTest + + - name: Output Wasmer directory + run: ls -laR ${{ github.workspace }}/lib/wasmer + + - name: Run Lexer Test + working-directory: ${{ github.workspace }}/build + run: ./LexerTest + + parser-test: + runs-on: ubuntu-latest + needs: build + + steps: + - uses: actions/checkout@v4 + + - name: Download build artifacts + uses: actions/download-artifact@v4 + with: + name: build + path: ${{ github.workspace }}/build + + - name: Download Wasmer artifacts + uses: actions/download-artifact@v4 + with: + name: wasmer + path: ${{ github.workspace }}/lib/wasmer + + - name: Make ParserTest Executable + run: chmod +x ${{ github.workspace }}/build/ParserTest + + - name: Run Parser Test + working-directory: ${{ github.workspace }}/build + run: ./ParserTest + + typechecker-test: + runs-on: ubuntu-latest + needs: build + + steps: + - uses: actions/checkout@v4 + + - name: Download build artifacts + uses: actions/download-artifact@v4 + with: + name: build + path: ${{ github.workspace }}/build + + - name: Download Wasmer artifacts + uses: actions/download-artifact@v4 + with: + name: wasmer + path: ${{ github.workspace }}/lib/wasmer + + - name: Make TypeCheckerTest Executable + run: chmod +x ${{ github.workspace }}/build/TypeCheckerTest + + - name: Run TypeChecker Test + working-directory: ${{ github.workspace }}/build + run: ./TypeCheckerTest + + codegen-test: + runs-on: ubuntu-latest + needs: build + + steps: + - uses: actions/checkout@v4 + + - name: Download build artifacts + uses: actions/download-artifact@v4 + with: + name: build + path: ${{ github.workspace }}/build + + - name: Download Wasmer artifacts + uses: actions/download-artifact@v4 + with: + name: wasmer + path: ${{ github.workspace }}/lib/wasmer + + - name: Make CodegenTest Executable + run: chmod +x ${{ github.workspace }}/build/CodegenTest + + - name: Run Codegen Test + working-directory: ${{ github.workspace }}/build + run: ./CodegenTest + diff --git a/.github/workflows/cmake-single-platform.yml b/.github/workflows/cmake-single-platform.yml index e182b5a..babe6b1 100644 --- a/.github/workflows/cmake-single-platform.yml +++ b/.github/workflows/cmake-single-platform.yml @@ -24,7 +24,7 @@ jobs: run: curl https://get.wasmer.io -sSfL | WASMER_DIR=lib/wasmer sh - name: Upload Wasmer as artifact - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v4 with: name: wasmer path: ${{ github.workspace }}/lib/wasmer @@ -51,7 +51,7 @@ jobs: run: ./build.sh - name: Upload build artifacts - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v4 with: name: build path: ${{ github.workspace }}/build @@ -64,13 +64,13 @@ jobs: - uses: actions/checkout@v4 - name: Download build artifacts - uses: actions/download-artifact@v2 + uses: actions/download-artifact@v4 with: name: build path: ${{ github.workspace }}/build - name: Download Wasmer artifacts - uses: actions/download-artifact@v2 + uses: actions/download-artifact@v4 with: name: wasmer path: ${{ github.workspace }}/lib/wasmer @@ -93,13 +93,13 @@ jobs: - uses: actions/checkout@v4 - name: Download build artifacts - uses: actions/download-artifact@v2 + uses: actions/download-artifact@v4 with: name: build path: ${{ github.workspace }}/build - name: Download Wasmer artifacts - uses: actions/download-artifact@v2 + uses: actions/download-artifact@v4 with: name: wasmer path: ${{ github.workspace }}/lib/wasmer @@ -119,13 +119,13 @@ jobs: - uses: actions/checkout@v4 - name: Download build artifacts - uses: actions/download-artifact@v2 + uses: actions/download-artifact@v4 with: name: build path: ${{ github.workspace }}/build - name: Download Wasmer artifacts - uses: actions/download-artifact@v2 + uses: actions/download-artifact@v4 with: name: wasmer path: ${{ github.workspace }}/lib/wasmer @@ -145,13 +145,13 @@ jobs: - uses: actions/checkout@v4 - name: Download build artifacts - uses: actions/download-artifact@v2 + uses: actions/download-artifact@v4 with: name: build path: ${{ github.workspace }}/build - name: Download Wasmer artifacts - uses: actions/download-artifact@v2 + uses: actions/download-artifact@v4 with: name: wasmer path: ${{ github.workspace }}/lib/wasmer diff --git a/build.sh b/build.sh index a86a269..4b0b593 100755 --- a/build.sh +++ b/build.sh @@ -6,6 +6,7 @@ if [ ! -d "build" ]; then mkdir build fi cd build +g++ --version cmake .. make cd .. diff --git a/src/compiler/CodeGen.cpp b/src/compiler/CodeGen.cpp index c1b40f9..babeb6d 100644 --- a/src/compiler/CodeGen.cpp +++ b/src/compiler/CodeGen.cpp @@ -29,6 +29,8 @@ #ifdef __APPLE__ #include #endif +#pragma push_macro("RETURN") +#undef RETURN namespace Theta { BinaryenModuleRef CodeGen::generateWasmFromAST(shared_ptr ast) { @@ -86,7 +88,7 @@ namespace Theta { if (node->getNodeType() == ASTNode::SOURCE) { generateSource(dynamic_pointer_cast(node), module); } else if (node->getNodeType() == ASTNode::CAPSULE) { - return generateCapsule(dynamic_pointer_cast(node), module); + generateCapsule(dynamic_pointer_cast(node), module); } else if (node->getNodeType() == ASTNode::ASSIGNMENT) { return generateAssignment(dynamic_pointer_cast(node), module); } else if (node->getNodeType() == ASTNode::BLOCK) { @@ -123,7 +125,7 @@ namespace Theta { return nullptr; } - BinaryenExpressionRef CodeGen::generateCapsule(shared_ptr capsuleNode, BinaryenModuleRef &module) { + void CodeGen::generateCapsule(shared_ptr capsuleNode, BinaryenModuleRef &module) { vector> capsuleElements = dynamic_pointer_cast(capsuleNode->getValue())->getElements(); hoistCapsuleElements(capsuleElements); @@ -513,7 +515,7 @@ namespace Theta { collectClosureScope(node->getParent(), identifiersToFind, parameters, bodyExpressions); } - BinaryenExpressionRef CodeGen::generateFunctionDeclaration( + void CodeGen::generateFunctionDeclaration( string identifier, shared_ptr fnDeclNode, BinaryenModuleRef &module, @@ -690,18 +692,20 @@ namespace Theta { // If a refIdentifier was passed, that means we have an existing closure // in memory that we want to populate. if (refIdentifier != "") { + BinaryenExpressionRef closureArgs[2] = { + BinaryenLocalGet( + module, + scope.lookup(refIdentifier).value()->getMappedBinaryenIndex(), + BinaryenTypeInt32() + ), + BinaryenConst(module, BinaryenLiteralInt32(addressToPopulate.getAddress())) + }; + expressions.push_back( BinaryenCall( module, "Theta.Function.populateClosure", - (BinaryenExpressionRef[]){ - BinaryenLocalGet( - module, - scope.lookup(refIdentifier).value()->getMappedBinaryenIndex(), - BinaryenTypeInt32() - ), - BinaryenConst(module, BinaryenLiteralInt32(addressToPopulate.getAddress())) - }, + closureArgs, 2, BinaryenTypeNone() ) @@ -1061,10 +1065,12 @@ namespace Theta { throw runtime_error("Invalid operand types for binary operation"); } + BinaryenExpressionRef args[2] = { binaryenLeft, binaryenRight }; + return BinaryenCall( module, "Theta.Math.pow", - (BinaryenExpressionRef[]){ binaryenLeft, binaryenRight }, + args, 2, BinaryenTypeInt64() ); @@ -1153,6 +1159,8 @@ namespace Theta { if (op == Lexemes::GT && dataType == DataTypes::NUMBER) return BinaryenGtSInt64(); if (op == Lexemes::LTEQ && dataType == DataTypes::NUMBER) return BinaryenLeSInt64(); if (op == Lexemes::GTEQ && dataType == DataTypes::NUMBER) return BinaryenGeSInt64(); + + throw runtime_error("No matching WASM opcode for binary operation: " + binOpNode->getOperator()); } BinaryenType CodeGen::getBinaryenTypeFromTypeDeclaration(shared_ptr typeDeclaration) { @@ -1162,6 +1170,8 @@ namespace Theta { // Function references are returned as i32 pointers to a closure in the function table if (typeDeclaration->getType() == DataTypes::FUNCTION) return BinaryenTypeInt32(); + + throw runtime_error("No matching WASM type for TypeDeclaration: " + typeDeclaration->getType()); } BinaryenType CodeGen::getBinaryenStorageTypeFromTypeDeclaration(shared_ptr typeDeclaration) { @@ -1397,3 +1407,4 @@ namespace Theta { return stream.str(); } } +#pragma pop_macro("RETURN") diff --git a/src/compiler/CodeGen.hpp b/src/compiler/CodeGen.hpp index aa5914b..0e91a1d 100644 --- a/src/compiler/CodeGen.hpp +++ b/src/compiler/CodeGen.hpp @@ -21,7 +21,7 @@ #include #include #include - +#include using namespace std; namespace Theta { @@ -29,11 +29,11 @@ namespace Theta { public: BinaryenModuleRef generateWasmFromAST(shared_ptr ast); BinaryenExpressionRef generate(shared_ptr node, BinaryenModuleRef &module); - BinaryenExpressionRef generateCapsule(shared_ptr node, BinaryenModuleRef &module); + void generateCapsule(shared_ptr node, BinaryenModuleRef &module); BinaryenExpressionRef generateAssignment(shared_ptr node, BinaryenModuleRef &module); BinaryenExpressionRef generateBlock(shared_ptr node, BinaryenModuleRef &module); BinaryenExpressionRef generateReturn(shared_ptr node, BinaryenModuleRef &module); - BinaryenExpressionRef generateFunctionDeclaration( + void generateFunctionDeclaration( string identifier, shared_ptr node, BinaryenModuleRef &module, diff --git a/src/compiler/StandardLibrary.hpp b/src/compiler/StandardLibrary.hpp index 194d646..7e169d7 100644 --- a/src/compiler/StandardLibrary.hpp +++ b/src/compiler/StandardLibrary.hpp @@ -110,12 +110,15 @@ namespace Theta { BinaryenLocalGet(module, 2, BinaryenTypeInt64()) }; + BinaryenType paramTypes[2] = { BinaryenTypeInt64(), BinaryenTypeInt64() }; + BinaryenType varTypes[1] = { BinaryenTypeInt64() }; + BinaryenFunctionRef powFn = BinaryenAddFunction( module, "Theta.Math.pow", - BinaryenTypeCreate((BinaryenType[]){ BinaryenTypeInt64(), BinaryenTypeInt64() }, 2), + BinaryenTypeCreate(paramTypes, 2), BinaryenTypeInt64(), - (BinaryenType[]){ BinaryenTypeInt64() }, + varTypes, 1, BinaryenBlock( module, diff --git a/src/compiler/SymbolTable.hpp b/src/compiler/SymbolTable.hpp index c8dfa1b..726e0c5 100644 --- a/src/compiler/SymbolTable.hpp +++ b/src/compiler/SymbolTable.hpp @@ -2,6 +2,7 @@ #include #include +#include using namespace std; namespace Theta {