forked from ground/ground
Type rework, start struct work
This commit is contained in:
247
src/main.cpp
247
src/main.cpp
@@ -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
29
tests/struct.grnd
Normal 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
|
||||
Reference in New Issue
Block a user