Type rework, start struct work

This commit is contained in:
2025-09-20 15:17:22 +10:00
parent 1147383ece
commit 39dc320f5d
2 changed files with 253 additions and 23 deletions

View File

@@ -34,6 +34,7 @@
Happy coding!
*/
#include <cinttypes>
#include <iostream>
#include <string>
#include <variant>
@@ -78,7 +79,8 @@ enum class Instructions {
Getstrcharat, Getstrsize,
Stoi, Stod, Tostring,
Fun, Return, Endfun, Pusharg, Call, Local,
Use, Extern, Error, Catch, Try, Exception
Use, Extern, Error, Catch, Try, Exception,
Struct, Endstruct, Init
};
/*
@@ -96,7 +98,7 @@ enum class Instructions {
See also parser function
*/
enum class Types {
Int, Double, String, Char, Bool, Value, Direct, Line, List, ListRef, Label, Type, Function
Int, Double, String, Char, Bool, Value, Direct, Line, List, ListRef, Label, Type, Function, Other
};
// Forward declaration of Literal for list
@@ -130,21 +132,8 @@ struct List {
vector<Literal> val;
};
/*
Literal struct
Contains literal values. For example, if the following line was written:
stdout "Hello world!"
The Literal struct in the instruction should look like this:
{
val = "Hello world!"; // I am ignoring the variant for simplicity
// of documenting the code
}
All value references are swapped out for their respective Literal they
point to. See also variables map, parser function, interpreter function
*/
struct Literal {
variant<int, double, bool, string, char, List> val;
};
// Forward definition of literal for the legendary struct struct
struct Literal;
/*
Direct struct
@@ -161,6 +150,8 @@ struct Direct {
};
struct TypeRef {
bool isCustomType = false;
string customType;
Types type;
};
@@ -277,6 +268,31 @@ struct Function {
vector<Label> labels;
};
/*
Struct struct
This struct stores data for structures in Ground.
*/
struct Struct {
map<string, Literal> values;
map<string, Function> functions;
};
/*
Literal struct
Contains literal values. For example, if the following line was written:
stdout "Hello world!"
The Literal struct in the instruction should look like this:
{
val = "Hello world!"; // I am ignoring the variant for simplicity
// of documenting the code
}
All value references are swapped out for their respective Literal they
point to. See also variables map, parser function, interpreter function
*/
struct Literal {
variant<int, double, bool, string, char, List, Struct> val;
};
// C-compatible enum and types for developing libraries for Ground in C
typedef enum {
GROUND_INT,
@@ -303,6 +319,12 @@ typedef struct {
*/
map<string, Function> functions;
/*
structs map
Contains structs (see the Struct struct for more info)
*/
map<string, Struct> structs;
/*
fnArgs vector
Containst the arguments to be passed to a function
@@ -439,11 +461,8 @@ bool isListRef(string in) {
}
bool isType(string in) {
if (in.size() >= 1 && in[0] == '-') {
string type = in.substr(1);
if (type == "string" || type == "char" || type == "bool" || type == "double" || type == "int" || type == "list") return true;
else return false;
} else return false;
if (in.size() > 1 && in[0] == '-') return true;
else return false;
}
bool isFunction(string in) {
@@ -492,8 +511,12 @@ Types getLitType(Literal in) {
bool processingFunction = false;
string procFnName = "";
bool processingStruct = false;
string procStructName = "";
bool inFunction = false;
// Stack of strings for keeping track of which thing we're importing
stack<string> importing;
@@ -536,9 +559,116 @@ Literal exec(vector<Instruction> in, bool executingFunction) {
procFnName = "";
continue;
} else {
if (processingStruct) {
structs[procStructName].functions[procFnName].instructions.push_back(l);
}
functions[procFnName].instructions.push_back(l);
continue;
}
} else if (processingStruct) {
if (l.inst == Instructions::Endstruct) {
processingStruct = false;
procStructName = "";
} else if (l.inst == Instructions::Fun) {
if (l.args.size() < 2) {
error("Could not find all arguments required for Fun inbuilt");
}
Function newFunction;
if (holds_alternative<TypeRef>(l.args[0])) {
newFunction.returnType = get<TypeRef>(l.args[0]).type;
} else {
error("First argument of function must be a type reference");
}
string fnName;
if (holds_alternative<FunctionRef>(l.args[1])) {
fnName = get<FunctionRef>(l.args[1]).fnName;
} else {
error("Second argument of function must be a function reference");
}
if (importing.size() > 0) {
fnName = importing.top() + ":" + fnName;
}
// Parse function arguments (type-direct pairs)
if ((l.args.size() - 2) % 2 != 0) {
error("Function arguments must be in type-direct pairs");
}
for (int m = 2; m < l.args.size(); m += 2) {
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;
processingFunction = true;
procFnName = fnName;
} else if (l.inst == Instructions::Init) {
if (l.args.size() < 2) {
error("Could not find all arguments required for Init inbuilt");
}
{
Direct varRef;
TypeRef type;
if (holds_alternative<Direct>(l.args[0])) {
varRef = get<Direct>(l.args[0]);
} else {
error("First argument of init must be a direct reference");
}
if (holds_alternative<TypeRef>(l.args[1])) {
type = get<TypeRef>(l.args[1]);
} else {
error("Second argument of init must be a type reference");
}
Literal newVal;
if (type.isCustomType) {
newVal.val = structs[type.customType];
} else {
Literal newVal;
switch (type.type) {
case Types::Int:
newVal.val = 0;
break;
case Types::Double:
newVal.val = double(0.0);
break;
case Types::String:
newVal.val = "";
break;
case Types::Char:
newVal.val = '\0';
break;
case Types::Bool:
newVal.val = false;
break;
default:
error("You dingus you werent supposed to get here");
}
}
variables[varRef.varName] = newVal;
}
}
continue;
}
// Pre process value references and labels
for (int j = 0; j < l.args.size(); j++) {
@@ -766,6 +896,51 @@ Literal exec(vector<Instruction> in, bool executingFunction) {
variables[varRef.varName] = varContents;
}
break;
case Instructions::Init:
if (l.args.size() < 2) {
error("Could not find all arguments required for Init inbuilt");
}
{
Direct varRef;
TypeRef type;
if (holds_alternative<Direct>(l.args[0])) {
varRef = get<Direct>(l.args[0]);
} else {
error("First argument of init must be a direct reference");
}
if (holds_alternative<TypeRef>(l.args[1])) {
type = get<TypeRef>(l.args[1]);
} else {
error("Second argument of init must be a type reference");
}
Literal newVal;
if (type.isCustomType) {
newVal.val = structs[type.customType];
} else {
switch (type.type) {
case Types::Int:
newVal.val = 0;
break;
case Types::Double:
newVal.val = double(0.0);
break;
case Types::String:
newVal.val = "";
break;
case Types::Char:
newVal.val = '\0';
break;
case Types::Bool:
newVal.val = false;
break;
default:
error("You dingus you werent supposed to get here");
}
}
variables[varRef.varName] = newVal;
}
break;
/*
setlist instruction
This instruction takes a potentially infinite amount of arguments and
@@ -1880,6 +2055,25 @@ Literal exec(vector<Instruction> in, bool executingFunction) {
procFnName = fnName;
}
break;
case Instructions::Struct:
if (l.args.size() < 1) {
error("Could not find all arguments required for Struct inbuilt");
}
{
string structName;
if (holds_alternative<TypeRef>(l.args[0])) {
} else {
error("First argument of struct must be a type reference");
}
Struct newStruct;
structs[structName] = newStruct;
processingStruct = true;
procStructName = structName;
}
break;
/*
return instruction
Exits a function.
@@ -2381,6 +2575,9 @@ vector<Instruction> parser(vector<vector<string>> in) {
else if (i == "call") newInst.inst = Instructions::Call;
else if (i == "use") newInst.inst = Instructions::Use;
else if (i == "extern") newInst.inst = Instructions::Extern;
else if (i == "struct") newInst.inst = Instructions::Struct;
else if (i == "endstruct") newInst.inst = Instructions::Endstruct;
else if (i == "init") newInst.inst = Instructions::Init;
else error("Unexpected token: " + i);
} else {
Types type = getType(i);
@@ -2412,7 +2609,11 @@ vector<Instruction> parser(vector<vector<string>> in) {
else if (type == "int") newType.type = Types::Int;
else if (type == "bool") newType.type = Types::Bool;
else if (type == "list") newType.type = Types::List;
else error("Ground could not find type. This is an error with the interpreter, not your code. This line of code should never be reached.", "undefinedError");
else {
newType.isCustomType = true;
newType.customType = type;
newType.type = Types::Other;
}
newInst.args.push_back(newType);
}
break;

29
tests/struct.grnd Normal file
View File

@@ -0,0 +1,29 @@
struct -point
init &xpos -int
init &ypos -int
fun -void !init -int &x -int &y
set &xpos $x
set &ypos $y
return
endfun
fun -string !toString
# do stuff
return "placeholder"
endfun
fun -int !dingle
return 23
endfun
endstruct
pusharg 43 32
init &myPoint -point
set &myPoint.xpos 17
set &myPoint.ypos 23
!myPoint.dingle &out
println $myPoint