diff --git a/src/parser.cpp b/src/parser.cpp index 5415798..4a2718d 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -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 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; - variables.clear(); + 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; }