More reliable scoping

This commit is contained in:
2025-08-25 13:35:22 +10:00
parent 5bd8519517
commit 16660c6a8d
3 changed files with 30 additions and 72 deletions

0
docs/writing-a-program Normal file
View File

25
docs/writing-a-program.md Normal file
View File

@@ -0,0 +1,25 @@
## Writing programs with Ground
Ground is a very easy language to learn. In this guide, you will learn how to write a simple calculator in Ground, as well as best practices (which there aren't many of, since Ground is so simple).
Note: This assumes you've read and understand the syntax.md document in this folder.
### Let's start!
Open a new file with the `.grnd` extension. Should look something like this:
```
```
(Real empty in that file.)
Let's add some code! Create a label for the start, since we'll loop back once we've calculated, and ask for the user's input:
```
@start
stdout "Calculation: "
stdin &calc
```
At the calc variable, we have whatever the user typed in. This should look something like `9+10`, `1 / 3` or who knows what else. But first we should organise this data. Let's create a loop to iterate through this input, and a counter to keep moving forward:

View File

@@ -39,7 +39,6 @@
#include <variant> #include <variant>
#include <vector> #include <vector>
#include <map> #include <map>
#include <stack>
#include <fstream> #include <fstream>
#include <cstdlib> #include <cstdlib>
#include <filesystem> #include <filesystem>
@@ -269,12 +268,6 @@ map<string, Function> functions;
*/ */
vector<Literal> fnArgs; vector<Literal> fnArgs;
/*
localArgStack stack
This keeps track of all the local arguments in functions that are being called.
*/
stack<vector<Direct>> localArgStack;
/* /*
error function error function
Takes a string (which is a debug message) and prints it to the console, letting the Takes a string (which is a debug message) and prints it to the console, letting the
@@ -563,9 +556,6 @@ Literal exec(vector<Instruction> in, bool executingFunction) {
bool existed = variables.count(varRef.varName) > 0; bool existed = variables.count(varRef.varName) > 0;
variables[varRef.varName] = varContents; variables[varRef.varName] = varContents;
if (!localArgStack.empty() && !existed) {
localArgStack.top().push_back(varRef);
}
} }
break; break;
/* /*
@@ -639,9 +629,6 @@ Literal exec(vector<Instruction> in, bool executingFunction) {
if (lists[listref.listName].val.size() > ref) { if (lists[listref.listName].val.size() > ref) {
bool existed = variables.count(var.varName) > 0; bool existed = variables.count(var.varName) > 0;
variables[var.varName] = lists[listref.listName].val[ref]; variables[var.varName] = lists[listref.listName].val[ref];
if (!localArgStack.empty() && !existed) {
localArgStack.top().push_back(var);
}
} else { } else {
error("Index " + to_string(ref) + " out of range of list " + listref.listName); error("Index " + to_string(ref) + " out of range of list " + listref.listName);
} }
@@ -695,9 +682,6 @@ Literal exec(vector<Instruction> in, bool executingFunction) {
newLit.val = instr[ref]; newLit.val = instr[ref];
bool existed = variables.count(var.varName) > 0; bool existed = variables.count(var.varName) > 0;
variables[var.varName] = newLit; variables[var.varName] = newLit;
if (!localArgStack.empty() && !existed) {
localArgStack.top().push_back(var);
}
} else { } else {
error("Index " + to_string(ref) + " out of range of string " + instr); error("Index " + to_string(ref) + " out of range of string " + instr);
} }
@@ -809,9 +793,6 @@ Literal exec(vector<Instruction> in, bool executingFunction) {
newLit.val = int(lists[ref.listName].val.size()); newLit.val = int(lists[ref.listName].val.size());
bool existed = variables.count(var.varName) > 0; bool existed = variables.count(var.varName) > 0;
variables[var.varName] = newLit; variables[var.varName] = newLit;
if (!localArgStack.empty() && !existed) {
localArgStack.top().push_back(var);
}
} else { } else {
error("Couldn't find the list " + ref.listName); error("Couldn't find the list " + ref.listName);
} }
@@ -850,9 +831,6 @@ Literal exec(vector<Instruction> in, bool executingFunction) {
newLit.val = int(ref.size()); newLit.val = int(ref.size());
bool existed = variables.count(var.varName) > 0; bool existed = variables.count(var.varName) > 0;
variables[var.varName] = newLit; variables[var.varName] = newLit;
if (!localArgStack.empty() && !existed) {
localArgStack.top().push_back(var);
}
break; break;
} }
@@ -890,9 +868,6 @@ Literal exec(vector<Instruction> in, bool executingFunction) {
newLit.val = stoi(toConv); newLit.val = stoi(toConv);
bool existed = variables.count(ref.varName) > 0; bool existed = variables.count(ref.varName) > 0;
variables[ref.varName] = newLit; variables[ref.varName] = newLit;
if (!localArgStack.empty() && !existed) {
localArgStack.top().push_back(ref);
}
} else { } else {
error("Cannot convert the value " + toConv + " to an int"); error("Cannot convert the value " + toConv + " to an int");
} }
@@ -932,9 +907,6 @@ Literal exec(vector<Instruction> in, bool executingFunction) {
newLit.val = stod(toConv); newLit.val = stod(toConv);
bool existed = variables.count(ref.varName) > 0; bool existed = variables.count(ref.varName) > 0;
variables[ref.varName] = newLit; variables[ref.varName] = newLit;
if (!localArgStack.empty() && !existed) {
localArgStack.top().push_back(ref);
}
} else { } else {
error("Cannot convert the value " + toConv + " to a decimal"); error("Cannot convert the value " + toConv + " to a decimal");
} }
@@ -983,9 +955,6 @@ Literal exec(vector<Instruction> in, bool executingFunction) {
bool existed = variables.count(ref.varName) > 0; bool existed = variables.count(ref.varName) > 0;
variables[ref.varName] = newLit; variables[ref.varName] = newLit;
if (!localArgStack.empty() && !existed) {
localArgStack.top().push_back(ref);
}
} }
break; break;
@@ -1006,9 +975,6 @@ Literal exec(vector<Instruction> in, bool executingFunction) {
userLit.val = userIn; userLit.val = userIn;
bool existed = variables.count(varRef.varName) > 0; bool existed = variables.count(varRef.varName) > 0;
variables[varRef.varName] = userLit; variables[varRef.varName] = userLit;
if (!localArgStack.empty() && !existed) {
localArgStack.top().push_back(varRef);
}
} else { } else {
error("First argument of stdin must be a direct reference"); error("First argument of stdin must be a direct reference");
} }
@@ -1069,9 +1035,6 @@ Literal exec(vector<Instruction> in, bool executingFunction) {
bool existed = variables.count(varRef.varName) > 0; bool existed = variables.count(varRef.varName) > 0;
variables[varRef.varName] = final; variables[varRef.varName] = final;
if (!localArgStack.empty() && !existed) {
localArgStack.top().push_back(varRef);
}
} }
break; break;
/* /*
@@ -1122,9 +1085,6 @@ Literal exec(vector<Instruction> in, bool executingFunction) {
bool existed = variables.count(varRef.varName) > 0; bool existed = variables.count(varRef.varName) > 0;
variables[varRef.varName] = final; variables[varRef.varName] = final;
if (!localArgStack.empty() && !existed) {
localArgStack.top().push_back(varRef);
}
} }
break; break;
/* /*
@@ -1175,9 +1135,6 @@ Literal exec(vector<Instruction> in, bool executingFunction) {
bool existed = variables.count(varRef.varName) > 0; bool existed = variables.count(varRef.varName) > 0;
variables[varRef.varName] = final; variables[varRef.varName] = final;
if (!localArgStack.empty() && !existed) {
localArgStack.top().push_back(varRef);
}
} }
break; break;
/* /*
@@ -1240,9 +1197,6 @@ Literal exec(vector<Instruction> in, bool executingFunction) {
bool existed = variables.count(varRef.varName) > 0; bool existed = variables.count(varRef.varName) > 0;
variables[varRef.varName] = final; variables[varRef.varName] = final;
if (!localArgStack.empty() && !existed) {
localArgStack.top().push_back(varRef);
}
} }
break; break;
/* /*
@@ -1299,9 +1253,6 @@ Literal exec(vector<Instruction> in, bool executingFunction) {
bool existed = variables.count(varRef.varName) > 0; bool existed = variables.count(varRef.varName) > 0;
variables[varRef.varName] = final; variables[varRef.varName] = final;
if (!localArgStack.empty() && !existed) {
localArgStack.top().push_back(varRef);
}
} }
break; break;
/* /*
@@ -1358,9 +1309,6 @@ Literal exec(vector<Instruction> in, bool executingFunction) {
bool existed = variables.count(varRef.varName) > 0; bool existed = variables.count(varRef.varName) > 0;
variables[varRef.varName] = final; variables[varRef.varName] = final;
if (!localArgStack.empty() && !existed) {
localArgStack.top().push_back(varRef);
}
} }
break; break;
/* /*
@@ -1394,9 +1342,6 @@ Literal exec(vector<Instruction> in, bool executingFunction) {
bool existed = variables.count(varRef.varName) > 0; bool existed = variables.count(varRef.varName) > 0;
variables[varRef.varName] = boolean; variables[varRef.varName] = boolean;
if (!localArgStack.empty() && !existed) {
localArgStack.top().push_back(varRef);
}
} }
break; break;
/* /*
@@ -1453,9 +1398,6 @@ Literal exec(vector<Instruction> in, bool executingFunction) {
bool existed = variables.count(varRef.varName) > 0; bool existed = variables.count(varRef.varName) > 0;
variables[varRef.varName] = final; variables[varRef.varName] = final;
if (!localArgStack.empty() && !existed) {
localArgStack.top().push_back(varRef);
}
} }
break; break;
/* /*
@@ -1512,9 +1454,6 @@ Literal exec(vector<Instruction> in, bool executingFunction) {
bool existed = variables.count(varRef.varName) > 0; bool existed = variables.count(varRef.varName) > 0;
variables[varRef.varName] = final; variables[varRef.varName] = final;
if (!localArgStack.empty() && !existed) {
localArgStack.top().push_back(varRef);
}
} }
break; break;
/* /*
@@ -1704,7 +1643,8 @@ Literal exec(vector<Instruction> in, bool executingFunction) {
" arguments, got " + to_string(fnArgs.size())); " arguments, got " + to_string(fnArgs.size()));
} }
localArgStack.push(vector<Direct>()); // Create backup of variables to be restored
map<string, Literal> scopeBackup = variables;
// Create function arguments with type checking // Create function arguments with type checking
for (int m = 0; m < functions[ref.fnName].args.size(); m++) { for (int m = 0; m < functions[ref.fnName].args.size(); m++) {
@@ -1718,17 +1658,13 @@ Literal exec(vector<Instruction> in, bool executingFunction) {
// Create the variable // Create the variable
variables[arg.ref.varName] = fnArgs[m]; variables[arg.ref.varName] = fnArgs[m];
localArgStack.top().push_back(arg.ref);
} }
// Call the function // Call the function
Literal retVal = exec(functions[ref.fnName].instructions, true); Literal retVal = exec(functions[ref.fnName].instructions, true);
// Remove variables that were declared in this scope // Restore scope
for (Direct delref : localArgStack.top()) { variables = scopeBackup;
variables.erase(delref.varName);
}
localArgStack.pop();
// Clear function arguments for next call // Clear function arguments for next call
fnArgs.clear(); fnArgs.clear();
@@ -1736,9 +1672,6 @@ Literal exec(vector<Instruction> in, bool executingFunction) {
// Now, assign the return value in the current scope. // Now, assign the return value in the current scope.
bool existed = variables.count(returnRef.varName) > 0; bool existed = variables.count(returnRef.varName) > 0;
variables[returnRef.varName] = retVal; variables[returnRef.varName] = retVal;
if (!localArgStack.empty() && !existed) {
localArgStack.top().push_back(returnRef);
}
} }
break; break;
case Instructions::Use: case Instructions::Use: