forked from solstice/solstice
Type checking for functions
This commit is contained in:
@@ -21,7 +21,7 @@ namespace Solstice {
|
||||
if (variables.find(i.outputId) != variables.end()) {
|
||||
return variables[i.outputId];
|
||||
} else {
|
||||
Error::syntaxError("Unknown variable", i.line, i.lineContent);
|
||||
Error::syntaxError("Unknown variable " + i.outputId, i.line, i.lineContent);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -55,6 +55,63 @@ namespace Solstice {
|
||||
return "int";
|
||||
break;
|
||||
}
|
||||
case SolNodeType::FunctionCall: {
|
||||
if (i.children[0].outputId == "input") {
|
||||
if (i.children.size() > 1) {
|
||||
ensure(i.children[1], "string", "input function argument");
|
||||
}
|
||||
return "string";
|
||||
}
|
||||
|
||||
std::string funcName = i.children[0].outputId;
|
||||
if (variables.find(funcName) == variables.end()) {
|
||||
Error::syntaxError("Unknown function " + funcName, i.line, i.lineContent);
|
||||
}
|
||||
std::string signature = variables[funcName];
|
||||
|
||||
// Parse signature: fun(arg1, arg2) retType
|
||||
if (signature.rfind("fun(", 0) != 0) {
|
||||
// Not a function signature, maybe it's a variable being called?
|
||||
Error::typingError(funcName + " is not a function", i.line, i.lineContent);
|
||||
}
|
||||
|
||||
size_t endParen = signature.find(')');
|
||||
if (endParen == std::string::npos) {
|
||||
Error::typingError("Invalid function signature for " + funcName, i.line, i.lineContent);
|
||||
}
|
||||
|
||||
std::string argsStr = signature.substr(4, endParen - 4);
|
||||
std::string retType = signature.substr(endParen + 2); // skip ") "
|
||||
|
||||
std::vector<std::string> expectedArgs;
|
||||
if (!argsStr.empty()) {
|
||||
size_t start = 0;
|
||||
size_t end = argsStr.find(", ");
|
||||
while (end != std::string::npos) {
|
||||
expectedArgs.push_back(argsStr.substr(start, end - start));
|
||||
start = end + 2;
|
||||
end = argsStr.find(", ", start);
|
||||
}
|
||||
expectedArgs.push_back(argsStr.substr(start));
|
||||
}
|
||||
|
||||
// Check arguments
|
||||
// children[0] is function name, children[1..] are args
|
||||
if (i.children.size() - 1 != expectedArgs.size()) {
|
||||
Error::typingError("Expected " + std::to_string(expectedArgs.size()) + " arguments for " + funcName + ", got " + std::to_string(i.children.size() - 1), i.line, i.lineContent);
|
||||
return "none";
|
||||
}
|
||||
|
||||
for (size_t k = 0; k < expectedArgs.size(); ++k) {
|
||||
std::string argType = checkNodeReturnType(i.children[k + 1]);
|
||||
if (argType != expectedArgs[k]) {
|
||||
Error::typingError("Expected argument " + std::to_string(k + 1) + " of " + funcName + " to be " + expectedArgs[k] + ", got " + argType, i.children[k + 1].line, i.children[k + 1].lineContent);
|
||||
}
|
||||
}
|
||||
|
||||
return retType;
|
||||
break;
|
||||
}
|
||||
case SolNodeType::Puts:
|
||||
case SolNodeType::If:
|
||||
case SolNodeType::While:
|
||||
@@ -602,6 +659,7 @@ namespace Solstice {
|
||||
break;
|
||||
}
|
||||
case SolNodeType::FunctionCall: {
|
||||
checkNodeReturnType(*this);
|
||||
// Take care of in built functions
|
||||
// This will be removed when inline ground is added
|
||||
if (children[0].outputId == "input") {
|
||||
@@ -635,6 +693,10 @@ namespace Solstice {
|
||||
break;
|
||||
}
|
||||
case SolNodeType::Return: {
|
||||
std::string retType = checkNodeReturnType(children[0]);
|
||||
if (currentFunctionRetType != "" && retType != currentFunctionRetType) {
|
||||
Error::typingError("Expected return type " + currentFunctionRetType + " but got " + retType, children[0].line, children[0].lineContent);
|
||||
}
|
||||
SolGroundCodeBlock codeBlock;
|
||||
GroundInstruction returnInstruction = groundCreateInstruction(RETURN);
|
||||
groundAddReferenceToInstruction(&returnInstruction, groundCreateReference(VALREF, children[0].outputId.data()));
|
||||
@@ -654,21 +716,34 @@ namespace Solstice {
|
||||
strcpy(retType, function.returnType.c_str());
|
||||
groundAddReferenceToInstruction(&inst, groundCreateReference(FNREF, fnName));
|
||||
groundAddReferenceToInstruction(&inst, groundCreateReference(TYPEREF, retType));
|
||||
|
||||
// Scope Management
|
||||
auto variablebackup = variables;
|
||||
std::string oldRetType = currentFunctionRetType;
|
||||
|
||||
variables.clear();
|
||||
currentFunctionRetType = function.returnType;
|
||||
|
||||
for (auto& pair : function.parameters) {
|
||||
groundAddReferenceToInstruction(&inst, groundCreateReference(TYPEREF, pair.second.data()));
|
||||
groundAddReferenceToInstruction(&inst, groundCreateReference(DIRREF, pair.first.data()));
|
||||
variables[pair.second] = pair.first;
|
||||
variables[pair.first] = pair.second; // Correctly map Name -> Type
|
||||
}
|
||||
variables = variablebackup;
|
||||
|
||||
codeBlock.code.push_back(inst);
|
||||
code.push_back(codeBlock);
|
||||
codeBlock.code.clear();
|
||||
|
||||
// Generate body code with local variables visible
|
||||
auto childCode = function.content->generateCode();
|
||||
code.insert(code.end(), childCode.begin(), childCode.end());
|
||||
|
||||
codeBlock.code.push_back(groundCreateInstruction(ENDFUN));
|
||||
code.push_back(codeBlock);
|
||||
|
||||
// Restore Scope
|
||||
variables = variablebackup;
|
||||
currentFunctionRetType = oldRetType;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user