forked from ground/ground
Function arguments, start of scoping
This commit is contained in:
109
src/main.cpp
109
src/main.cpp
@@ -239,13 +239,18 @@ struct Instruction {
|
|||||||
vector<variant<Literal, ValueRef, ListRef, FunctionRef, TypeRef, Direct, Line>> args;
|
vector<variant<Literal, ValueRef, ListRef, FunctionRef, TypeRef, Direct, Line>> args;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct FnArg {
|
||||||
|
Direct ref;
|
||||||
|
Types type;
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Function struct
|
Function struct
|
||||||
Contains information needed to run a Ground function.
|
Contains information needed to run a Ground function.
|
||||||
*/
|
*/
|
||||||
struct Function {
|
struct Function {
|
||||||
Types returnType;
|
Types returnType;
|
||||||
vector<pair<Direct, Types>> args;
|
vector<FnArg> args;
|
||||||
vector<Instruction> instructions;
|
vector<Instruction> instructions;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -263,9 +268,9 @@ vector<Literal> fnArgs;
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
localArgStack stack
|
localArgStack stack
|
||||||
Contains the variables in a scope
|
This keeps track of all the local arguments in functions that are being called.
|
||||||
*/
|
*/
|
||||||
stack<vector<Literal>> localArgStack;
|
stack<vector<Direct>> localArgStack;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
error function
|
error function
|
||||||
@@ -376,6 +381,21 @@ Types getType(string in) {
|
|||||||
return Types::Int;
|
return Types::Int;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
getLitType function
|
||||||
|
This function determines the type of a value inside a Literal based on the
|
||||||
|
holds_alternative() function. Returns a type from the Types enum class.
|
||||||
|
*/
|
||||||
|
Types getLitType(Literal in) {
|
||||||
|
if (holds_alternative<int>(in.val)) return Types::Int;
|
||||||
|
if (holds_alternative<double>(in.val)) return Types::Double;
|
||||||
|
if (holds_alternative<bool>(in.val)) return Types::Bool;
|
||||||
|
if (holds_alternative<string>(in.val)) return Types::String;
|
||||||
|
if (holds_alternative<char>(in.val)) return Types::Char;
|
||||||
|
error("Literal for some reason has a weird type. This is not an issue with your program, but an issue with the Ground interpreter.");
|
||||||
|
return Types::Int;
|
||||||
|
}
|
||||||
|
|
||||||
bool processingFunction = false;
|
bool processingFunction = false;
|
||||||
string procFnName = "";
|
string procFnName = "";
|
||||||
|
|
||||||
@@ -1488,29 +1508,29 @@ Literal exec(vector<Instruction> in) {
|
|||||||
error("Second argument of function must be a function reference");
|
error("Second argument of function must be a function reference");
|
||||||
}
|
}
|
||||||
|
|
||||||
Types argType;
|
// Parse function arguments (type-direct pairs)
|
||||||
Direct ref;
|
if ((l.args.size() - 2) % 2 != 0) {
|
||||||
bool expectingType = true;
|
error("Function arguments must be in type-direct pairs");
|
||||||
for (int m = 2; m < l.args.size(); m++) {
|
|
||||||
if (expectingType) {
|
|
||||||
if (holds_alternative<TypeRef>(l.args[m])) {
|
|
||||||
argType = get<TypeRef>(l.args[m]).type;
|
|
||||||
} else {
|
|
||||||
error("Functions expect a type reference, then a direct reference. Missing a type reference.");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (holds_alternative<Direct>(l.args[m])) {
|
|
||||||
ref = get<Direct>(l.args[m]);
|
|
||||||
} else {
|
|
||||||
error("Functions expect a type reference, then a direct reference. Missing a direct reference.");
|
|
||||||
}
|
|
||||||
newFunction.args.push_back(pair(ref, argType));
|
|
||||||
}
|
|
||||||
expectingType = !expectingType;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!expectingType) {
|
for (int m = 2; m < l.args.size(); m += 2) {
|
||||||
error("Incomplete function definition, expecting a direct reference after type reference");
|
FnArg newArg;
|
||||||
|
|
||||||
|
// Get type
|
||||||
|
if (holds_alternative<TypeRef>(l.args[m])) {
|
||||||
|
newArg.type = get<TypeRef>(l.args[m]).type;
|
||||||
|
} else {
|
||||||
|
error("Expected type reference in function argument definition");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get direct reference
|
||||||
|
if (m + 1 < l.args.size() && holds_alternative<Direct>(l.args[m + 1])) {
|
||||||
|
newArg.ref = get<Direct>(l.args[m + 1]);
|
||||||
|
} else {
|
||||||
|
error("Expected direct reference after type reference in function argument definition");
|
||||||
|
}
|
||||||
|
|
||||||
|
newFunction.args.push_back(newArg);
|
||||||
}
|
}
|
||||||
|
|
||||||
functions[fnName] = newFunction;
|
functions[fnName] = newFunction;
|
||||||
@@ -1578,12 +1598,53 @@ Literal exec(vector<Instruction> in) {
|
|||||||
error("Second argument of call must be a direct reference");
|
error("Second argument of call must be a direct reference");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check if function exists
|
||||||
|
if (functions.find(ref.fnName) == functions.end()) {
|
||||||
|
error("Function " + ref.fnName + " not found");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check argument count
|
||||||
|
if (fnArgs.size() != functions[ref.fnName].args.size()) {
|
||||||
|
error("Function " + ref.fnName + " expects " +
|
||||||
|
to_string(functions[ref.fnName].args.size()) +
|
||||||
|
" arguments, got " + to_string(fnArgs.size()));
|
||||||
|
}
|
||||||
|
|
||||||
|
localArgStack.push(vector<Direct>());
|
||||||
|
|
||||||
|
// Create function arguments with type checking
|
||||||
|
for (int m = 0; m < functions[ref.fnName].args.size(); m++) {
|
||||||
|
FnArg arg = functions[ref.fnName].args[m];
|
||||||
|
|
||||||
|
// Type checking - now with error reporting
|
||||||
|
if (arg.type != getLitType(fnArgs[m])) {
|
||||||
|
error("Function " + ref.fnName + " argument " + to_string(m + 1) +
|
||||||
|
" type mismatch. Expected type does not match provided argument type.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the variable
|
||||||
|
variables[arg.ref.varName] = fnArgs[m];
|
||||||
|
localArgStack.top().push_back(arg.ref);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Call the function
|
||||||
variables[returnRef.varName] = exec(functions[ref.fnName].instructions);
|
variables[returnRef.varName] = exec(functions[ref.fnName].instructions);
|
||||||
|
|
||||||
|
// Remove variables that were declared in this scope
|
||||||
|
for (Direct delref : localArgStack.top()) {
|
||||||
|
variables.erase(delref.varName);
|
||||||
|
}
|
||||||
|
localArgStack.pop();
|
||||||
|
|
||||||
|
// Clear function arguments for next call
|
||||||
|
fnArgs.clear();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case Instructions::Use:
|
case Instructions::Use:
|
||||||
|
cout << "Still to be implemented" << endl;
|
||||||
break;
|
break;
|
||||||
case Instructions::Extern:
|
case Instructions::Extern:
|
||||||
|
cout << "Still to be implemented" << endl;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
cout << "Still to be implemented" << endl;
|
cout << "Still to be implemented" << endl;
|
||||||
|
@@ -1,10 +1,14 @@
|
|||||||
fun -int !dingle -string &silly
|
fun -int !dingle -string &silly
|
||||||
stdlnout "This is inside the function"
|
stdlnout "This is inside the function"
|
||||||
|
stdout "The function argument is "
|
||||||
|
stdlnout $silly
|
||||||
return 10
|
return 10
|
||||||
endfun
|
endfun
|
||||||
|
|
||||||
stdlnout "This is outside the function"
|
stdlnout "This is outside the function"
|
||||||
|
|
||||||
|
pusharg "heheheha"
|
||||||
call !dingle &var
|
call !dingle &var
|
||||||
|
|
||||||
|
stdout "Function returned "
|
||||||
stdlnout $var
|
stdlnout $var
|
||||||
|
Reference in New Issue
Block a user