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()) {
|
if (variables.find(i.outputId) != variables.end()) {
|
||||||
return variables[i.outputId];
|
return variables[i.outputId];
|
||||||
} else {
|
} else {
|
||||||
Error::syntaxError("Unknown variable", i.line, i.lineContent);
|
Error::syntaxError("Unknown variable " + i.outputId, i.line, i.lineContent);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -55,6 +55,63 @@ namespace Solstice {
|
|||||||
return "int";
|
return "int";
|
||||||
break;
|
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::Puts:
|
||||||
case SolNodeType::If:
|
case SolNodeType::If:
|
||||||
case SolNodeType::While:
|
case SolNodeType::While:
|
||||||
@@ -602,6 +659,7 @@ namespace Solstice {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case SolNodeType::FunctionCall: {
|
case SolNodeType::FunctionCall: {
|
||||||
|
checkNodeReturnType(*this);
|
||||||
// Take care of in built functions
|
// Take care of in built functions
|
||||||
// This will be removed when inline ground is added
|
// This will be removed when inline ground is added
|
||||||
if (children[0].outputId == "input") {
|
if (children[0].outputId == "input") {
|
||||||
@@ -635,6 +693,10 @@ namespace Solstice {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case SolNodeType::Return: {
|
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;
|
SolGroundCodeBlock codeBlock;
|
||||||
GroundInstruction returnInstruction = groundCreateInstruction(RETURN);
|
GroundInstruction returnInstruction = groundCreateInstruction(RETURN);
|
||||||
groundAddReferenceToInstruction(&returnInstruction, groundCreateReference(VALREF, children[0].outputId.data()));
|
groundAddReferenceToInstruction(&returnInstruction, groundCreateReference(VALREF, children[0].outputId.data()));
|
||||||
@@ -654,21 +716,34 @@ namespace Solstice {
|
|||||||
strcpy(retType, function.returnType.c_str());
|
strcpy(retType, function.returnType.c_str());
|
||||||
groundAddReferenceToInstruction(&inst, groundCreateReference(FNREF, fnName));
|
groundAddReferenceToInstruction(&inst, groundCreateReference(FNREF, fnName));
|
||||||
groundAddReferenceToInstruction(&inst, groundCreateReference(TYPEREF, retType));
|
groundAddReferenceToInstruction(&inst, groundCreateReference(TYPEREF, retType));
|
||||||
|
|
||||||
|
// Scope Management
|
||||||
auto variablebackup = variables;
|
auto variablebackup = variables;
|
||||||
variables.clear();
|
std::string oldRetType = currentFunctionRetType;
|
||||||
|
|
||||||
|
variables.clear();
|
||||||
|
currentFunctionRetType = function.returnType;
|
||||||
|
|
||||||
for (auto& pair : function.parameters) {
|
for (auto& pair : function.parameters) {
|
||||||
groundAddReferenceToInstruction(&inst, groundCreateReference(TYPEREF, pair.second.data()));
|
groundAddReferenceToInstruction(&inst, groundCreateReference(TYPEREF, pair.second.data()));
|
||||||
groundAddReferenceToInstruction(&inst, groundCreateReference(DIRREF, pair.first.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);
|
codeBlock.code.push_back(inst);
|
||||||
code.push_back(codeBlock);
|
code.push_back(codeBlock);
|
||||||
codeBlock.code.clear();
|
codeBlock.code.clear();
|
||||||
|
|
||||||
|
// Generate body code with local variables visible
|
||||||
auto childCode = function.content->generateCode();
|
auto childCode = function.content->generateCode();
|
||||||
code.insert(code.end(), childCode.begin(), childCode.end());
|
code.insert(code.end(), childCode.begin(), childCode.end());
|
||||||
|
|
||||||
codeBlock.code.push_back(groundCreateInstruction(ENDFUN));
|
codeBlock.code.push_back(groundCreateInstruction(ENDFUN));
|
||||||
code.push_back(codeBlock);
|
code.push_back(codeBlock);
|
||||||
|
|
||||||
|
// Restore Scope
|
||||||
|
variables = variablebackup;
|
||||||
|
currentFunctionRetType = oldRetType;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user