forked from ground/ground
Type rework, start struct work
This commit is contained in:
245
src/main.cpp
245
src/main.cpp
@@ -34,6 +34,7 @@
|
|||||||
Happy coding!
|
Happy coding!
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <cinttypes>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <variant>
|
#include <variant>
|
||||||
@@ -78,7 +79,8 @@ enum class Instructions {
|
|||||||
Getstrcharat, Getstrsize,
|
Getstrcharat, Getstrsize,
|
||||||
Stoi, Stod, Tostring,
|
Stoi, Stod, Tostring,
|
||||||
Fun, Return, Endfun, Pusharg, Call, Local,
|
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
|
See also parser function
|
||||||
*/
|
*/
|
||||||
enum class Types {
|
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
|
// Forward declaration of Literal for list
|
||||||
@@ -130,21 +132,8 @@ struct List {
|
|||||||
vector<Literal> val;
|
vector<Literal> val;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
// Forward definition of literal for the legendary struct struct
|
||||||
Literal struct
|
struct Literal;
|
||||||
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;
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Direct struct
|
Direct struct
|
||||||
@@ -161,6 +150,8 @@ struct Direct {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct TypeRef {
|
struct TypeRef {
|
||||||
|
bool isCustomType = false;
|
||||||
|
string customType;
|
||||||
Types type;
|
Types type;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -277,6 +268,31 @@ struct Function {
|
|||||||
vector<Label> labels;
|
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
|
// C-compatible enum and types for developing libraries for Ground in C
|
||||||
typedef enum {
|
typedef enum {
|
||||||
GROUND_INT,
|
GROUND_INT,
|
||||||
@@ -303,6 +319,12 @@ typedef struct {
|
|||||||
*/
|
*/
|
||||||
map<string, Function> functions;
|
map<string, Function> functions;
|
||||||
|
|
||||||
|
/*
|
||||||
|
structs map
|
||||||
|
Contains structs (see the Struct struct for more info)
|
||||||
|
*/
|
||||||
|
map<string, Struct> structs;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
fnArgs vector
|
fnArgs vector
|
||||||
Containst the arguments to be passed to a function
|
Containst the arguments to be passed to a function
|
||||||
@@ -439,11 +461,8 @@ bool isListRef(string in) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool isType(string in) {
|
bool isType(string in) {
|
||||||
if (in.size() >= 1 && in[0] == '-') {
|
if (in.size() > 1 && in[0] == '-') return true;
|
||||||
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;
|
||||||
} else return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isFunction(string in) {
|
bool isFunction(string in) {
|
||||||
@@ -492,8 +511,12 @@ Types getLitType(Literal in) {
|
|||||||
bool processingFunction = false;
|
bool processingFunction = false;
|
||||||
string procFnName = "";
|
string procFnName = "";
|
||||||
|
|
||||||
|
bool processingStruct = false;
|
||||||
|
string procStructName = "";
|
||||||
|
|
||||||
bool inFunction = false;
|
bool inFunction = false;
|
||||||
|
|
||||||
|
|
||||||
// Stack of strings for keeping track of which thing we're importing
|
// Stack of strings for keeping track of which thing we're importing
|
||||||
stack<string> importing;
|
stack<string> importing;
|
||||||
|
|
||||||
@@ -536,9 +559,116 @@ Literal exec(vector<Instruction> in, bool executingFunction) {
|
|||||||
procFnName = "";
|
procFnName = "";
|
||||||
continue;
|
continue;
|
||||||
} else {
|
} else {
|
||||||
|
if (processingStruct) {
|
||||||
|
structs[procStructName].functions[procFnName].instructions.push_back(l);
|
||||||
|
}
|
||||||
functions[procFnName].instructions.push_back(l);
|
functions[procFnName].instructions.push_back(l);
|
||||||
continue;
|
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
|
// Pre process value references and labels
|
||||||
for (int j = 0; j < l.args.size(); j++) {
|
for (int j = 0; j < l.args.size(); j++) {
|
||||||
@@ -766,6 +896,51 @@ Literal exec(vector<Instruction> in, bool executingFunction) {
|
|||||||
variables[varRef.varName] = varContents;
|
variables[varRef.varName] = varContents;
|
||||||
}
|
}
|
||||||
break;
|
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
|
setlist instruction
|
||||||
This instruction takes a potentially infinite amount of arguments and
|
This instruction takes a potentially infinite amount of arguments and
|
||||||
@@ -1880,6 +2055,25 @@ Literal exec(vector<Instruction> in, bool executingFunction) {
|
|||||||
procFnName = fnName;
|
procFnName = fnName;
|
||||||
}
|
}
|
||||||
break;
|
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
|
return instruction
|
||||||
Exits a function.
|
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 == "call") newInst.inst = Instructions::Call;
|
||||||
else if (i == "use") newInst.inst = Instructions::Use;
|
else if (i == "use") newInst.inst = Instructions::Use;
|
||||||
else if (i == "extern") newInst.inst = Instructions::Extern;
|
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 error("Unexpected token: " + i);
|
||||||
} else {
|
} else {
|
||||||
Types type = getType(i);
|
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 == "int") newType.type = Types::Int;
|
||||||
else if (type == "bool") newType.type = Types::Bool;
|
else if (type == "bool") newType.type = Types::Bool;
|
||||||
else if (type == "list") newType.type = Types::List;
|
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);
|
newInst.args.push_back(newType);
|
||||||
}
|
}
|
||||||
break;
|
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