Start work on lists

This commit is contained in:
2025-08-10 13:31:28 +10:00
parent f43f79b869
commit 2e388c6e68
4 changed files with 231 additions and 8 deletions

View File

@@ -1,5 +1,4 @@
compiler "g++";
binary "ground";
source "src/main.cpp";
flag "O3";
compile;

View File

@@ -32,6 +32,18 @@ Reference a line (a line reference) with a percent symbol before a line number:
jump %10
```
(WORK IN PROGRESS) Alternatively, set a label and jump to that (setting labels will be discussed below):
```
jump %myLabel
```
Reference a list (a list reference) with an asterisk:
```
setlist *myList $value1 $value2 # and so on
```
### Keywords
Note: &var can be replaced with any direct reference. $value can be replaced with a literal value or a value reference. %1 can be replaced with a line reference.
@@ -54,7 +66,7 @@ Usage: `jump %1`
Ends the program. Requires an integer for a status code.
Usage: `end $value`
Usage: `end $intvalue`
#### stdin
@@ -80,6 +92,30 @@ Allows you to set a variable to a value.
Usage: `set &var $value`
#### setlist
Allows you to initialize a list.
Usage: `setlist *list $value1 $value2 $value3...`
#### setlistat (WORK IN PROGRESS)
Sets a list item at an index. The item at the index must already exist. Lists are index 0.
Usage: `setlistat *list $intvalue $value`
#### getlistat
Gets a list item at an index, and puts it in the variable provided. The item at the index must already exist. Lists are index 0.
Usage: `getlistat *list $intvalue &var`
#### getlistsize
Gets the size of a list and puts it in the variable provided.
Usage: `getlistsize *list &var`
#### add
Adds two numbers. Numbers mean an integer or a double. Outputs to a direct reference.

View File

@@ -49,7 +49,12 @@ using namespace std;
function, interpreter function, Instruction struct
*/
enum class Instructions {
Jump, Stdout, Stdin, Stdlnout, Add, Subtract, Multiply, Divide, Equal, Inequal, Greater, Lesser, If, End, Set, Empty
Jump, If,
Stdout, Stdin, Stdlnout,
Add, Subtract, Multiply, Divide,
Equal, Inequal, Greater, Lesser,
End, Set, Empty,
Setlist, Getlistat, Setlistat, Getlistsize
};
/*
@@ -67,7 +72,7 @@ enum class Instructions {
See also parser function
*/
enum class Types {
Int, Double, String, Char, Bool, Value, Direct, Line
Int, Double, String, Char, Bool, Value, Direct, Line, ListRef
};
/*
@@ -86,12 +91,61 @@ struct Literal {
variant<int, double, bool, string, char> val;
};
/*
List struct
Contains literal values inside a vector. For example, if the following
program was written:
setlist #myNums 3 5 9 13
The List struct which would be created and stored should look like this:
{
val = {
Literal {
val = 3
},
Literal {
val = 5
},
Literal {
val = 9
},
Literal {
val = 13
},
}
}
All elements in the list must be of the same type. See also Literal struct.
*/
struct List {
vector<Literal> val;
};
/*
ListRef struct
Contains the name of a list referenced by the program. For example, if the
following program was written:
setlist #myNums 3 5 9 13
The ListRef struct should look like this:
{
listName = "myNums";
}
*/
struct ListRef {
string listName;
};
/*
variables map
Contains all variables made while running the program. See also Literal struct.
*/
map<string, Literal> variables;
/*
lists map
Contains all lists made while running the program. See also List struct.
*/
map<string, List> lists;
/*
ValueRef struct
If the program being executed makes a value reference, it is stored in a ValueRef
@@ -161,7 +215,7 @@ struct Line {
*/
struct Instruction {
Instructions inst = Instructions::Empty;
vector<variant<Literal, ValueRef, Direct, Line>> args;
vector<variant<Literal, ValueRef, ListRef, Direct, Line>> args;
};
/*
@@ -224,7 +278,12 @@ bool isDirect(string in) {
}
bool isLine(string in) {
if (in.size() >= 1 && in[0] == '%' && isInt(in.substr(1))) return true;
if (in.size() >= 1 && in[0] == '%') return true;
else return false;
}
bool isListRef(string in) {
if (in.size() >= 1 && in[0] == '*') return true;
else return false;
}
@@ -242,6 +301,7 @@ Types getType(string in) {
if (isValue(in)) return Types::Value;
if (isDirect(in)) return Types::Direct;
if (isLine(in)) return Types::Line;
if (isListRef(in)) return Types::ListRef;
error("Could not determine type of \"" + in + "\"");
return Types::Int;
}
@@ -368,6 +428,114 @@ void exec(vector<Instruction> in) {
variables[varName] = varContents;
}
break;
/*
setlist instruction
This instruction takes a potentially infinite amount of arguments and
saves them to a list (vector) with name listName.
*/
case Instructions::Setlist:
if (l.args.size() < 2) {
error("Could not find all arguments required for Setlist inbuilt");
}
{
string listName;
List listContents;
if (holds_alternative<ListRef>(l.args[0])) {
listName = get<ListRef>(l.args[0]).listName;
} else {
error("First argument of setlist must be a list reference");
}
bool first = true;
for (variant<Literal, ValueRef, ListRef, Direct, Line> k : l.args) {
if (holds_alternative<Literal>(k)) {
listContents.val.push_back(get<Literal>(k));
} else {
if (!first) error("All arguments after first in setlist must be values");
first = false;
}
}
lists[listName] = listContents;
}
break;
/*
getlistat instruction
This instruction gets a list item from a list and an index and saves the
value to a variable.
*/
case Instructions::Getlistat:
if (l.args.size() < 3) {
error("Could not find all arguments required for Getlistat inbuilt");
}
{
ListRef listref;
int ref;
Direct var;
if (holds_alternative<ListRef>(l.args[0])) {
listref = get<ListRef>(l.args[0]);
} else {
error("First argument of getlistat must be a list reference");
}
if (holds_alternative<Literal>(l.args[1])) {
if (holds_alternative<int>(get<Literal>(l.args[1]).val)) {
ref = get<int>(get<Literal>(l.args[1]).val);
} else {
error("Second argument of getlistat must be an integer literal");
}
} else {
error("Second argument of getlistat must be an integer literal");
}
if (holds_alternative<Direct>(l.args[2])) {
var = get<Direct>(l.args[2]);
} else {
error("Third argument of getlistat must be a direct reference");
}
if (lists.find(listref.listName) != lists.end()) {
if (lists[listref.listName].val.size() > ref) {
variables[var.varName] = lists[listref.listName].val[ref];
} else {
error("Index " + to_string(ref) + " out of range of list " + listref.listName);
}
} else {
error("Unknown list: " + listref.listName);
}
}
break;
case Instructions::Getlistsize:
if (l.args.size() < 2) {
error("Could not find all arguments required for Getlistsize inbuilt");
}
{
ListRef ref;
Direct var;
if (holds_alternative<ListRef>(l.args[0])) {
ref = get<ListRef>(l.args[0]);
} else {
error("First argument of getlistsize must be a list reference");
}
if (holds_alternative<Direct>(l.args[1])) {
var = get<Direct>(l.args[1]);
} else {
error("Second argument of getlistsize must be a direct reference");
}
Literal newLit;
if (lists.find(ref.listName) != lists.end()) {
newLit.val = int(lists[ref.listName].val.size());
variables[var.varName] = newLit;
} else {
error("Couldn't find the list " + ref.listName);
}
break;
}
/*
stdin instruction
This instruction takes input from the standard character input via
@@ -375,7 +543,7 @@ void exec(vector<Instruction> in) {
*/
case Instructions::Stdin:
if (l.args.size() < 1) {
error("Could not find all arguments require for Stdin inbuilt");
error("Could not find all arguments required for Stdin inbuilt");
}
if (holds_alternative<Direct>(l.args[0])) {
string userIn;
@@ -980,6 +1148,10 @@ vector<Instruction> parser(vector<vector<string>> in) {
else if (i == "inequal") newInst.inst = Instructions::Inequal;
else if (i == "end") newInst.inst = Instructions::End;
else if (i == "set") newInst.inst = Instructions::Set;
else if (i == "setlist") newInst.inst = Instructions::Setlist;
else if (i == "setlistat") newInst.inst = Instructions::Setlistat;
else if (i == "getlistat") newInst.inst = Instructions::Getlistat;
else if (i == "getlistsize") newInst.inst = Instructions::Getlistsize;
else error("Unexpected token: " + i);
} else {
Types type = getType(i);
@@ -1005,6 +1177,13 @@ vector<Instruction> parser(vector<vector<string>> in) {
newInst.args.push_back(newLine);
}
break;
case Types::ListRef:
{
ListRef newLR;
newLR.listName = i.substr(1);
newInst.args.push_back(newLR);
}
break;
case Types::String:
{
Literal newLiteral;

9
tests/lists.grnd Normal file
View File

@@ -0,0 +1,9 @@
setlist *favNums "hello" "there" "general" "kenobi"
set &count 0
getlistat *favNums $count &tmp
stdlnout $tmp
add $count 1 &count
getlistsize *favNums &tmp2
inequal $count $tmp2 &tmp3
if $tmp3 %3
stdlnout "finished!"