Skip to content

Commit

Permalink
fix: direct curried functions should execute properly, not only when …
Browse files Browse the repository at this point in the history
…part of an assignment
  • Loading branch information
alexdovzhanyn committed Sep 5, 2024
1 parent 36c3ddc commit b2e4292
Show file tree
Hide file tree
Showing 2 changed files with 55 additions and 34 deletions.
83 changes: 49 additions & 34 deletions src/compiler/CodeGen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ namespace Theta {
} else if (node->getNodeType() == ASTNode::FUNCTION_DECLARATION) {
// The only time we should get here is if we have a function defined inside a function,
// because the normal function declaration flow goes through the generateAssignment flow
simplifyNestedFunctionDeclaration(dynamic_pointer_cast<FunctionDeclarationNode>(node), module);
return generateClosureFunctionDeclaration(dynamic_pointer_cast<FunctionDeclarationNode>(node), module);
} else if (node->getNodeType() == ASTNode::FUNCTION_INVOCATION) {
return generateFunctionInvocation(dynamic_pointer_cast<FunctionInvocationNode>(node), module);
} else if (node->getNodeType() == ASTNode::CONTROL_FLOW) {
Expand Down Expand Up @@ -201,12 +201,29 @@ namespace Theta {

}

shared_ptr<FunctionDeclarationNode> originalDeclaration = dynamic_pointer_cast<FunctionDeclarationNode>(assignmentNode->getRight());
return generateClosureFunctionDeclaration(
dynamic_pointer_cast<FunctionDeclarationNode>(assignmentNode->getRight()),
module,
[module, idxOfAssignment, isLastInBlock](const BinaryenExpressionRef &addressRefExpression) {
if (isLastInBlock) return addressRefExpression;

shared_ptr<FunctionDeclarationNode> simplifiedDeclaration = simplifyNestedFunctionDeclaration(
originalDeclaration,
module
return BinaryenLocalSet(
module,
idxOfAssignment,
addressRefExpression
);
},
make_pair(assignmentIdentifier, idxOfAssignment)
);
}

BinaryenExpressionRef CodeGen::generateClosureFunctionDeclaration(
shared_ptr<FunctionDeclarationNode> function,
BinaryenModuleRef &module,
std::function<BinaryenExpressionRef(const BinaryenExpressionRef&)> returnValueFormatter,
optional<pair<string, int>> assignmentIdentifierPair
) {
shared_ptr<FunctionDeclarationNode> simplifiedDeclaration = simplifyNestedFunctionDeclaration(function, module);

// Generating a unique hash for this function is necessary because it will be stored on the module globally,
// so we need to make sure there are no naming collisions
Expand All @@ -223,49 +240,45 @@ namespace Theta {
simplifiedDeclaration
);

// If an assignmentIdentifier was passed in, this function is being assigned to a variable.
// We need to add some items to the scope to make the function available elsewhere
if (assignmentIdentifierPair) {
simplifiedDeclaration->setMappedBinaryenIndex(assignmentIdentifierPair->second);

string localQualifiedFunctionName = Compiler::getQualifiedFunctionIdentifier(
assignmentIdentifierPair->first,
function
);

// Assign it in scope to the lhs identifier so we can always look it up later when it is referenced. This
// way the caller does not need to know the global function name in order to call it
scope.insert(globalQualifiedFunctionName, simplifiedDeclaration);
scopeReferences.insert(localQualifiedFunctionName, globalQualifiedFunctionName);

// Also insert the assignment identifier into scope referenecs so that if we want to return a reference to the function
// using the identifier, we can do that. This will overwrite any previous scope references with that identifier, so only
// the most recent identifier of a given name can be returned as a reference
scopeReferences.insert(assignmentIdentifierPair->first, globalQualifiedFunctionName);
}

pair<WasmClosure, vector<BinaryenExpressionRef>> storage = generateAndStoreClosure(
globalQualifiedFunctionName,
simplifiedDeclaration,
originalDeclaration,
function,
module
);

simplifiedDeclaration->setMappedBinaryenIndex(idxOfAssignment);

string localQualifiedFunctionName = Compiler::getQualifiedFunctionIdentifier(
assignmentIdentifier,
originalDeclaration
);

// Assign it in scope to the lhs identifier so we can always look it up later when it is referenced. This
// way the caller does not need to know the global function name in order to call it
scope.insert(globalQualifiedFunctionName, simplifiedDeclaration);
scopeReferences.insert(localQualifiedFunctionName, globalQualifiedFunctionName);

// Also insert the assignment identifier into scope referenecs so that if we want to return a reference to the function
// using the identifier, we can do that. This will overwrite any previous scope references with that identifier, so only
// the most recent identifier of a given name can be returned as a reference
scopeReferences.insert(assignmentIdentifier, globalQualifiedFunctionName);

vector<BinaryenExpressionRef> expressions = storage.second;

BinaryenExpressionRef addressRefExpression = BinaryenConst(
module,
BinaryenLiteralInt32(storage.first.getPointer().getAddress())
);

BinaryenExpressionRef returnedValueExpression = returnValueFormatter(addressRefExpression);

// Returns a reference to the closure memory address
if (isLastInBlock) {
expressions.push_back(addressRefExpression);
} else {
expressions.push_back(
BinaryenLocalSet(
module,
idxOfAssignment,
addressRefExpression
)
);
}
expressions.push_back(returnedValueExpression);

BinaryenExpressionRef* blockExpressions = new BinaryenExpressionRef[expressions.size()];
for (int i = 0; i < expressions.size(); i++) {
Expand Down Expand Up @@ -437,6 +450,8 @@ namespace Theta {

exit(1);
}

cout << "created simplified function declaration" << endl;

return simplifiedDeclaration;
}
Expand Down
6 changes: 6 additions & 0 deletions src/compiler/CodeGen.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,12 @@ namespace Theta {
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 Down

0 comments on commit b2e4292

Please sign in to comment.