Skip to content

Commit

Permalink
Merge pull request #26 from alexdovzhanyn/function-closures
Browse files Browse the repository at this point in the history
Indirect function calls
  • Loading branch information
alexdovzhanyn authored Sep 5, 2024
2 parents 0d759f9 + b2e4292 commit d641294
Show file tree
Hide file tree
Showing 45 changed files with 1,733 additions and 402 deletions.
10 changes: 10 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,16 @@ file(GLOB TEST_SRC_FILES "${TEST_DIR}/*.cpp")
# Add executable for the main program
add_executable(theta ${SRC_FILES} ${MAIN_SRC})

# Add a custom command to copy the WAT file
set(WAT_FILE_SRC "${CMAKE_SOURCE_DIR}/src/wasm/ThetaLangCore.wat")
set(WAT_FILE_DEST "${CMAKE_BINARY_DIR}/wasm")
add_custom_target(copy_wat ALL
COMMAND ${CMAKE_COMMAND} -E make_directory ${WAT_FILE_DEST}
COMMAND ${CMAKE_COMMAND} -E copy ${WAT_FILE_SRC} ${WAT_FILE_DEST}
COMMENT "Copying WAT file to build directory"
)
add_dependencies(copy_wat theta)

# Add the readline library
if (WIN32)
# Add the readline library
Expand Down
8 changes: 4 additions & 4 deletions src/cli/cli.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,10 @@ namespace Theta {
Theta::Compiler::getInstance().compile(sourceFile, outFile, isEmitTokens, isEmitAST, isEmitWAT);
}

static string makeLink(string url, string text = "") {
return "\x1B]8;;" + url + "\x1B\\" + (text != "" ? text : url) + "\x1B]8;;\x1B\\";
}

private:
static void printUsageInstructions() {
cout << "Theta Language Compiler CLI" << endl;
Expand Down Expand Up @@ -121,9 +125,5 @@ namespace Theta {

cout << endl << endl << "Exiting ITH..." << endl;
}

static string makeLink(string url, string text = "") {
return "\x1B]8;;" + url + "\x1B\\" + (text != "" ? text : url) + "\x1B]8;;\x1B\\";
}
};
}
1,014 changes: 976 additions & 38 deletions src/compiler/CodeGen.cpp

Large diffs are not rendered by default.

103 changes: 98 additions & 5 deletions src/compiler/CodeGen.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include "../parser/ast/LiteralNode.hpp"
#include "../parser/ast/SourceNode.hpp"
#include "compiler/SymbolTableStack.hpp"
#include "compiler/WasmClosure.hpp"
#include "parser/ast/ASTNodeList.hpp"
#include "parser/ast/AssignmentNode.hpp"
#include "parser/ast/CapsuleNode.hpp"
Expand All @@ -16,7 +17,10 @@
#include "parser/ast/TypeDeclarationNode.hpp"
#include "parser/ast/FunctionInvocationNode.hpp"
#include "parser/ast/ControlFlowNode.hpp"
#include "compiler/FunctionMetaData.hpp"
#include <binaryen-c.h>
#include <set>
#include <unordered_map>

using namespace std;

Expand All @@ -29,7 +33,18 @@ namespace Theta {
BinaryenExpressionRef generateAssignment(shared_ptr<AssignmentNode> node, BinaryenModuleRef &module);
BinaryenExpressionRef generateBlock(shared_ptr<ASTNodeList> node, BinaryenModuleRef &module);
BinaryenExpressionRef generateReturn(shared_ptr<ReturnNode> node, BinaryenModuleRef &module);
BinaryenExpressionRef generateFunctionDeclaration(string identifier, shared_ptr<FunctionDeclarationNode> node, BinaryenModuleRef &module, bool addToExports = false);
BinaryenExpressionRef generateFunctionDeclaration(
string identifier,
shared_ptr<FunctionDeclarationNode> node,
BinaryenModuleRef &module,
bool addToExports = false
);
BinaryenExpressionRef generateClosureFunctionDeclaration(
shared_ptr<FunctionDeclarationNode> node,
BinaryenModuleRef &module,
std::function<BinaryenExpressionRef(const BinaryenExpressionRef&)> returnValueFormatter = [](const BinaryenExpressionRef &addrExpr) { return addrExpr; },
optional<pair<string, int>> assignmentIdentifierPair = nullopt
);
BinaryenExpressionRef generateFunctionInvocation(shared_ptr<FunctionInvocationNode> node, BinaryenModuleRef &module);
BinaryenExpressionRef generateControlFlow(shared_ptr<ControlFlowNode> controlFlowNode, BinaryenModuleRef &module);
BinaryenExpressionRef generateIdentifier(shared_ptr<IdentifierNode> node, BinaryenModuleRef &module);
Expand All @@ -41,17 +56,95 @@ namespace Theta {
BinaryenExpressionRef generateExponentOperation(shared_ptr<BinaryOperationNode> node, BinaryenModuleRef &module);
void generateSource(shared_ptr<SourceNode> node, BinaryenModuleRef &module);

private:
SymbolTableStack scope;
shared_ptr<FunctionDeclarationNode> simplifyNestedFunctionDeclaration(
shared_ptr<FunctionDeclarationNode> node,
BinaryenModuleRef &module
);

private:
SymbolTableStack<shared_ptr<ASTNode>> scope;
SymbolTableStack<string> scopeReferences;
string FN_TABLE_NAME = "ThetaFunctionRefs";
string STRINGREF_TABLE = "ThetaStringRefs";
string MEMORY_NAME = "0";
int memoryOffset = 0;
int stringRefOffset = 1;
unordered_map<string, WasmClosure> functionNameToClosureTemplateMap;
string LOCAL_IDX_SCOPE_KEY = "ThetaLang.internal.localIdxCounter";

BinaryenExpressionRef generateStringBinaryOperation(string op, BinaryenExpressionRef left, BinaryenExpressionRef right, BinaryenModuleRef &module);
BinaryenModuleRef initializeWasmModule();

BinaryenExpressionRef generateStringBinaryOperation(
string op,
BinaryenExpressionRef left,
BinaryenExpressionRef right,
BinaryenModuleRef &modul
);

vector<Pointer<PointerType::Data>> generateFunctionInvocationArgMemoryInsertions(
shared_ptr<FunctionInvocationNode> funcInvNode,
vector<BinaryenExpressionRef> &expressions,
BinaryenModuleRef &module,
string refIdentifier = ""
);

BinaryenExpressionRef generateCallIndirectForNewClosure(
shared_ptr<FunctionInvocationNode> funcInvNode,
shared_ptr<ASTNode> ref,
string refIdentifier,
BinaryenModuleRef &module
);

BinaryenExpressionRef generateCallIndirectForExistingClosure(
shared_ptr<FunctionInvocationNode> funcInvNode,
shared_ptr<ASTNode> ref,
string refIdentifier,
BinaryenModuleRef &module
);

static BinaryenOp getBinaryenOpFromBinOpNode(shared_ptr<BinaryOperationNode> node);
static BinaryenType getBinaryenTypeFromTypeDeclaration(shared_ptr<TypeDeclarationNode> node);
static BinaryenType getBinaryenStorageTypeFromTypeDeclaration(shared_ptr<TypeDeclarationNode> node);

template<typename Node>
static FunctionMetaData getFunctionMetaData(shared_ptr<Node> node);

static FunctionMetaData getFunctionMetaDataFromTypeDeclaration(shared_ptr<TypeDeclarationNode> type);

static FunctionMetaData getDerivedFunctionMetaData(
shared_ptr<FunctionInvocationNode> inv,
shared_ptr<FunctionInvocationNode> ref
);

void hoistCapsuleElements(vector<shared_ptr<ASTNode>> elements);
void hoistCapsuleElements(vector<shared_ptr<ASTNode>> ielements);
void bindIdentifierToScope(shared_ptr<ASTNode> ast);
void registerModuleFunctions(BinaryenModuleRef &module);

bool checkIsLastInBlock(shared_ptr<ASTNode> node);

pair<WasmClosure, vector<BinaryenExpressionRef>> generateAndStoreClosure(
string qualifiedReferenceFunctionName,
shared_ptr<FunctionDeclarationNode> simplifiedReference,
shared_ptr<FunctionDeclarationNode> originalReference,
BinaryenModuleRef &module
);

vector<BinaryenExpressionRef> generateClosureMemoryStore(WasmClosure &closure, BinaryenModuleRef &module);

void collectClosureScope(
shared_ptr<ASTNode> node,
set<string> &identifiersToFind,
vector<shared_ptr<ASTNode>> &parameters,
vector<shared_ptr<ASTNode>> &bodyExpression
);

string generateFunctionHash(shared_ptr<FunctionDeclarationNode> function);

int getByteSizeForType(shared_ptr<TypeDeclarationNode> type);
int getByteSizeForType(BinaryenType type);

BinaryenModuleRef importCoreLangWasm();

string resolveAbsolutePath(string relativePath);
};
}
42 changes: 42 additions & 0 deletions src/compiler/Compiler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,8 @@ namespace Theta {
if (node->getNodeType() == ASTNode::FUNCTION_DECLARATION) {
shared_ptr<FunctionDeclarationNode> declarationNode = dynamic_pointer_cast<FunctionDeclarationNode>(node);
params = declarationNode->getParameters()->getElements();
} else if (node->getNodeType() == ASTNode::TYPE_DECLARATION) {
return getQualifiedFunctionIdentifierFromTypeSignature(variableName, dynamic_pointer_cast<TypeDeclarationNode>(node));
} else {
shared_ptr<FunctionInvocationNode> invocationNode = dynamic_pointer_cast<FunctionInvocationNode>(node);
params = invocationNode->getParameters()->getElements();
Expand All @@ -243,6 +245,25 @@ namespace Theta {
return functionIdentifier;
}

string Compiler::getQualifiedFunctionIdentifierFromTypeSignature(string variableName, shared_ptr<TypeDeclarationNode> typeSig) {
vector<shared_ptr<ASTNode>> params;

// If typeSig is a function, and it has a value, that means the function takes in no parameters and only has a return value
if (typeSig->getType() == DataTypes::FUNCTION && typeSig->getValue() == nullptr) {
params.resize(typeSig->getElements().size() - 1);
copy(typeSig->getElements().begin(), typeSig->getElements().end() - 1, params.begin());
}

string functionIdentifier = variableName + to_string(params.size());

for (auto param : params) {
shared_ptr<TypeDeclarationNode> p = dynamic_pointer_cast<TypeDeclarationNode>(param);
functionIdentifier += p->getType();
}

return functionIdentifier;
}

vector<shared_ptr<ASTNode>> Compiler::findAllInTree(shared_ptr<ASTNode> node, ASTNode::Types nodeType) {
if (node->getNodeType() == nodeType) return { node };

Expand Down Expand Up @@ -284,4 +305,25 @@ namespace Theta {

return {};
}

shared_ptr<TypeDeclarationNode> Compiler::deepCopyTypeDeclaration(shared_ptr<TypeDeclarationNode> original, shared_ptr<ASTNode> parent) {
shared_ptr<TypeDeclarationNode> copy = make_shared<TypeDeclarationNode>(original->getType(), parent);

if (original->getValue()) {
copy->setValue(deepCopyTypeDeclaration(dynamic_pointer_cast<TypeDeclarationNode>(original->getValue()), copy));
} else if (original->getLeft()) {
copy->setLeft(deepCopyTypeDeclaration(dynamic_pointer_cast<TypeDeclarationNode>(original->getLeft()), copy));
copy->setRight(deepCopyTypeDeclaration(dynamic_pointer_cast<TypeDeclarationNode>(original->getRight()), copy));
} else if (original->getElements().size() > 0) {
vector<shared_ptr<ASTNode>> copyChildren;

for (int i = 0; i < original->getElements().size(); i++) {
copyChildren.push_back(deepCopyTypeDeclaration(dynamic_pointer_cast<TypeDeclarationNode>(original->getElements().at(i)), copy));
}

copy->setElements(copyChildren);
}

return copy;
}
}
19 changes: 19 additions & 0 deletions src/compiler/Compiler.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include "CodeGen.hpp"
#include "compiler/optimization/OptimizationPass.hpp"
#include "compiler/optimization/LiteralInlinerPass.hpp"
#include "parser/ast/TypeDeclarationNode.hpp"

using namespace std;

Expand Down Expand Up @@ -110,6 +111,15 @@ namespace Theta {
* @return string The unique identifier for the function.
*/
static string getQualifiedFunctionIdentifier(string variableName, shared_ptr<ASTNode> node);

/**
* @brief Generates a unique function identifier based on the function's name and its type signature
*
* @param variableName The base name of the function.
* @param typeSig The type signature of the function.
* @return string The unique identifier for the function.
*/
static string getQualifiedFunctionIdentifierFromTypeSignature(string variableName, shared_ptr<TypeDeclarationNode> typeSig);

/**
* @brief Finds all AST nodes of a specific type within the tree rooted at a given node.
Expand All @@ -120,6 +130,15 @@ namespace Theta {
*/
static vector<shared_ptr<ASTNode>> findAllInTree(shared_ptr<ASTNode> node, ASTNode::Types type);

/**
* @brief Creates a deep copy of a type declaration node, useful for cases where type information
* needs to be duplicated without referencing the original.
*
* @param original The original type declaration node to copy.
* @return shared_ptr<TypeDeclarationNode> The deep-copied type declaration node.
*/
static shared_ptr<TypeDeclarationNode> deepCopyTypeDeclaration(shared_ptr<TypeDeclarationNode> node, shared_ptr<ASTNode> parent);

shared_ptr<map<string, string>> filesByCapsuleName;
private:
/**
Expand Down
30 changes: 30 additions & 0 deletions src/compiler/FunctionMetaData.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
#pragma once

#include "binaryen-c.h"

namespace Theta {
class FunctionMetaData {
public:
FunctionMetaData(
int totalParams,
BinaryenType* paramTypes,
BinaryenType resultType
) : arity(totalParams), params(paramTypes), returnType(resultType) {
paramType = BinaryenTypeCreate(params, arity);
};

int getArity() { return arity; }

BinaryenType* getParams() { return params; }

BinaryenType getParamType() { return paramType; }

BinaryenType getReturnType() { return returnType; }

private:
int arity;
BinaryenType* params;
BinaryenType paramType;
BinaryenType returnType;
};
}
23 changes: 23 additions & 0 deletions src/compiler/Pointer.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@


namespace Theta {
enum PointerType {
Function,
Closure,
Data
};

template<PointerType type>
class Pointer {
public:
Pointer() : address(-1) {}
Pointer(int addr) : address(addr) {}

PointerType getType() { return type; }

int getAddress() { return address; }

private:
int address;
};
}
14 changes: 7 additions & 7 deletions src/compiler/SymbolTable.hpp
Original file line number Diff line number Diff line change
@@ -1,26 +1,26 @@
#pragma once

#include <memory>
#include "../parser/ast/TypeDeclarationNode.hpp"
#include "parser/ast/ASTNode.hpp"
#include <map>
using namespace std;

namespace Theta {
template<typename T>
class SymbolTable {
public:
void insert(const string &name, shared_ptr<ASTNode> type) {
table[name] = type;
void insert(const string &name, T value) {
table[name] = value;
}

shared_ptr<ASTNode> lookup(const string &name) {
optional<T> lookup(const string &name) {
auto it = table.find(name);

if (it != table.end()) return it->second;

return nullptr;
return nullopt;
}

private:
map<string, shared_ptr<ASTNode>> table;
map<string, T> table;
};
}
Loading

0 comments on commit d641294

Please sign in to comment.