Adds module support to trainscript. Moves global methods to /sys/* objects.
This commit is contained in:
parent
81ad6c3406
commit
d0d88a17f3
12 changed files with 187 additions and 51 deletions
22
Makefile
22
Makefile
|
@ -87,9 +87,9 @@ obj/vmm.o: src/vmm.c include/config.h include/vmm.h include/pmm.h \
|
||||||
# trainscript/tsvm.cpp
|
# trainscript/tsvm.cpp
|
||||||
obj/tsvm.o: trainscript/tsvm.cpp include/stdlib.h include/varargs.h \
|
obj/tsvm.o: trainscript/tsvm.cpp include/stdlib.h include/varargs.h \
|
||||||
include/config.h include/malloc.h include/console.h trainscript/common.h \
|
include/config.h include/malloc.h include/console.h trainscript/common.h \
|
||||||
trainscript/tsvm.hpp trainscript/vm.hpp trainscript/module.hpp \
|
include/ker/vector.hpp include/ker/new.hpp include/ker/dictionary.hpp \
|
||||||
include/ker/string.hpp include/ker/dictionary.hpp include/kernel.h \
|
include/kernel.h include/ker/pair.hpp trainscript/tsvm.hpp \
|
||||||
include/ker/pair.hpp include/ker/vector.hpp include/ker/new.hpp \
|
trainscript/vm.hpp trainscript/module.hpp include/ker/string.hpp \
|
||||||
trainscript/variable.hpp trainscript/type.hpp trainscript/types.hpp \
|
trainscript/variable.hpp trainscript/type.hpp trainscript/types.hpp \
|
||||||
trainscript/typeid.hpp trainscript/method.hpp \
|
trainscript/typeid.hpp trainscript/method.hpp \
|
||||||
trainscript/instructions.hpp trainscript/instruction.hpp \
|
trainscript/instructions.hpp trainscript/instruction.hpp \
|
||||||
|
@ -134,10 +134,10 @@ obj/vm.o: src/vm.cpp include/stdlib.h include/varargs.h include/config.h \
|
||||||
# obj/trainscript.yy.cpp
|
# obj/trainscript.yy.cpp
|
||||||
obj/trainscript.yy.o: obj/trainscript.yy.cpp include/string.h \
|
obj/trainscript.yy.o: obj/trainscript.yy.cpp include/string.h \
|
||||||
include/stdlib.h include/varargs.h include/config.h include/malloc.h \
|
include/stdlib.h include/varargs.h include/config.h include/malloc.h \
|
||||||
trainscript/common.h trainscript/tsvm.hpp trainscript/vm.hpp \
|
trainscript/common.h include/ker/vector.hpp include/ker/new.hpp \
|
||||||
trainscript/module.hpp include/ker/string.hpp include/ker/dictionary.hpp \
|
include/ker/dictionary.hpp include/kernel.h include/ker/pair.hpp \
|
||||||
include/kernel.h include/ker/pair.hpp include/ker/vector.hpp \
|
trainscript/tsvm.hpp trainscript/vm.hpp trainscript/module.hpp \
|
||||||
include/ker/new.hpp trainscript/variable.hpp trainscript/type.hpp \
|
include/ker/string.hpp trainscript/variable.hpp trainscript/type.hpp \
|
||||||
trainscript/types.hpp trainscript/typeid.hpp trainscript/method.hpp \
|
trainscript/types.hpp trainscript/typeid.hpp trainscript/method.hpp \
|
||||||
trainscript/instructions.hpp trainscript/instruction.hpp \
|
trainscript/instructions.hpp trainscript/instruction.hpp \
|
||||||
trainscript/executioncontext.hpp trainscript/scriptmethod.hpp \
|
trainscript/executioncontext.hpp trainscript/scriptmethod.hpp \
|
||||||
|
@ -147,10 +147,10 @@ obj/trainscript.yy.o: obj/trainscript.yy.cpp include/string.h \
|
||||||
# obj/trainscript.tab.cpp
|
# obj/trainscript.tab.cpp
|
||||||
obj/trainscript.tab.o: obj/trainscript.tab.cpp include/stdlib.h \
|
obj/trainscript.tab.o: obj/trainscript.tab.cpp include/stdlib.h \
|
||||||
include/varargs.h include/config.h include/malloc.h include/console.h \
|
include/varargs.h include/config.h include/malloc.h include/console.h \
|
||||||
trainscript/common.h trainscript/tsvm.hpp trainscript/vm.hpp \
|
trainscript/common.h include/ker/vector.hpp include/ker/new.hpp \
|
||||||
trainscript/module.hpp include/ker/string.hpp include/ker/dictionary.hpp \
|
include/ker/dictionary.hpp include/kernel.h include/ker/pair.hpp \
|
||||||
include/kernel.h include/ker/pair.hpp include/ker/vector.hpp \
|
trainscript/tsvm.hpp trainscript/vm.hpp trainscript/module.hpp \
|
||||||
include/ker/new.hpp trainscript/variable.hpp trainscript/type.hpp \
|
include/ker/string.hpp trainscript/variable.hpp trainscript/type.hpp \
|
||||||
trainscript/types.hpp trainscript/typeid.hpp trainscript/method.hpp \
|
trainscript/types.hpp trainscript/typeid.hpp trainscript/method.hpp \
|
||||||
trainscript/instructions.hpp trainscript/instruction.hpp \
|
trainscript/instructions.hpp trainscript/instruction.hpp \
|
||||||
trainscript/executioncontext.hpp trainscript/scriptmethod.hpp \
|
trainscript/executioncontext.hpp trainscript/scriptmethod.hpp \
|
||||||
|
|
19
README.md
19
README.md
|
@ -12,6 +12,7 @@ Also it leaks memory. A lot of memory.
|
||||||
- Fixing Memory Leaks
|
- Fixing Memory Leaks
|
||||||
- Adding support for Modules
|
- Adding support for Modules
|
||||||
- Adding support for Pointer Types
|
- Adding support for Pointer Types
|
||||||
|
-
|
||||||
|
|
||||||
## Guidlines
|
## Guidlines
|
||||||
- Calls to `die` or `die_extra` should follow the following scheme: `ContextName.ErrorName`
|
- Calls to `die` or `die_extra` should follow the following scheme: `ContextName.ErrorName`
|
||||||
|
@ -69,6 +70,24 @@ The virtual machine supports 5 base types:
|
||||||
### Variable Format
|
### Variable Format
|
||||||
Variables are stored in a `type+pointer` format where `type` stores the type of the variable and `pointer` either a pointer to the variable value or, if `type` is a pointer type, the pointer value of the variable.
|
Variables are stored in a `type+pointer` format where `type` stores the type of the variable and `pointer` either a pointer to the variable value or, if `type` is a pointer type, the pointer value of the variable.
|
||||||
|
|
||||||
|
### Native Interoperation
|
||||||
|
The virtual machine features a `NativeMethod` that allows calling a C function (`result_t __cdecl name(args...)`) from the
|
||||||
|
virtual machine. Parameters are passed as the VM types declared in `types.hpp`, except for ker::String which is passed as a `const char*`.
|
||||||
|
|
||||||
|
### Native Modules
|
||||||
|
The kernel provides native modules that can be used to interoperate with the kernel and the system hardware.
|
||||||
|
|
||||||
|
Following modules are planned:
|
||||||
|
|
||||||
|
#### Timer
|
||||||
|
The timer module provides interaction with the system timer.
|
||||||
|
|
||||||
|
#### Memory
|
||||||
|
The memory module allows allocating and freeing memory as well as getting predefined named memory areas.
|
||||||
|
|
||||||
|
#### Interrupts
|
||||||
|
The interrupt module allows handling interrupts by the current module.
|
||||||
|
|
||||||
|
|
||||||
## OS Architecture
|
## OS Architecture
|
||||||
To be done.
|
To be done.
|
||||||
|
|
|
@ -66,6 +66,11 @@ namespace ker
|
||||||
return memcmp(this->mText, other.mText, this->mLength) == 0;
|
return memcmp(this->mText, other.mText, this->mLength) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool equals(const char *other) const
|
||||||
|
{
|
||||||
|
return strcmp(this->str(), other) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
String append(const String &other) const
|
String append(const String &other) const
|
||||||
{
|
{
|
||||||
uint8_t *data = (uint8_t*)malloc(this->mLength + other.mLength);
|
uint8_t *data = (uint8_t*)malloc(this->mLength + other.mLength);
|
||||||
|
@ -122,11 +127,21 @@ namespace ker
|
||||||
return this->equals(other);
|
return this->equals(other);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool operator ==(const char *other) const
|
||||||
|
{
|
||||||
|
return this->equals(other);
|
||||||
|
}
|
||||||
|
|
||||||
bool operator !=(const String &other) const
|
bool operator !=(const String &other) const
|
||||||
{
|
{
|
||||||
return !this->equals(other);
|
return !this->equals(other);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool operator !=(const char *other) const
|
||||||
|
{
|
||||||
|
return !this->equals(other);
|
||||||
|
}
|
||||||
|
|
||||||
String operator +(const String &other) const
|
String operator +(const String &other) const
|
||||||
{
|
{
|
||||||
return this->append(other);
|
return this->append(other);
|
||||||
|
|
|
@ -1,24 +1,25 @@
|
||||||
VAR global : INT;
|
VAR global : INT;
|
||||||
|
|
||||||
# OBJ timer : "/sys/timer";
|
OBJ timer : "/sys/timer";
|
||||||
# OBJ heap : "/sys/malloc";
|
OBJ console : "/sys/console";
|
||||||
# OBJ interrupts : "/sys/interrupt";
|
|
||||||
|
VAR ptr : PTR(INT);
|
||||||
|
|
||||||
PUB main() | i : INT, str : TEXT
|
PUB main() | i : INT, str : TEXT
|
||||||
BEGIN
|
BEGIN
|
||||||
0 -> i;
|
0 -> i;
|
||||||
"Hello " -> str;
|
"Hello " -> str;
|
||||||
printStr(str + "World!");
|
console.printStr(str + "World!");
|
||||||
WHILE ((i + 1) -> i) <= fun() DO
|
WHILE ((i + 1) -> i) <= fun() DO
|
||||||
BEGIN
|
BEGIN
|
||||||
hlp(i, fun() - i);
|
hlp(i, fun() - i);
|
||||||
sleep(2);
|
timer.sleep(2);
|
||||||
END
|
END
|
||||||
END
|
END
|
||||||
|
|
||||||
PRI hlp(i : INT, j : INT)
|
PRI hlp(i : INT, j : INT)
|
||||||
BEGIN
|
BEGIN
|
||||||
print2Int(i, j);
|
console.print2Int(i, j);
|
||||||
END
|
END
|
||||||
|
|
||||||
PUB fun() -> i : INT
|
PUB fun() -> i : INT
|
||||||
|
|
51
src/vm.cpp
51
src/vm.cpp
|
@ -141,16 +141,45 @@ struct NativeModuleDef
|
||||||
void *function;
|
void *function;
|
||||||
};
|
};
|
||||||
|
|
||||||
NativeModuleDef methods[] = {
|
NativeModuleDef consoleModule[] = {
|
||||||
{ "sleep", "i", (void*)sleep },
|
|
||||||
{ "timer_get", "", (void*)timer_get },
|
|
||||||
{ "timer_set", "i", (void*)timer_set },
|
|
||||||
{ "printInt", "i", (void*)printInt },
|
{ "printInt", "i", (void*)printInt },
|
||||||
{ "printStr", "t", (void*)printStr },
|
{ "printStr", "t", (void*)printStr },
|
||||||
{ "print2Int", "ii", (void*)print2Int },
|
{ "print2Int", "ii", (void*)print2Int },
|
||||||
{ nullptr, nullptr, 0 }
|
{ nullptr, nullptr, 0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static NativeModuleDef timerModule[] = {
|
||||||
|
{ "sleep", "i", (void*)sleep },
|
||||||
|
{ "timer_get", "", (void*)timer_get },
|
||||||
|
{ "timer_set", "i", (void*)timer_set },
|
||||||
|
{ nullptr, nullptr, 0 }
|
||||||
|
};
|
||||||
|
|
||||||
|
class KernelVM : public VM
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Module *createNative(NativeModuleDef *mod)
|
||||||
|
{
|
||||||
|
Module *module = new Module();
|
||||||
|
while(mod->name != nullptr) {
|
||||||
|
module->methods.add(mod->name, new NativeMethod(mod->signature, mod->function));
|
||||||
|
mod++;
|
||||||
|
}
|
||||||
|
return module;
|
||||||
|
}
|
||||||
|
|
||||||
|
Module *create(const ker::String &name) override
|
||||||
|
{
|
||||||
|
if(name == "/sys/timer") {
|
||||||
|
return createNative(timerModule);
|
||||||
|
}
|
||||||
|
if(name == "/sys/console") {
|
||||||
|
return createNative(consoleModule);
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
extern "C" void vm_start()
|
extern "C" void vm_start()
|
||||||
{
|
{
|
||||||
struct {
|
struct {
|
||||||
|
@ -164,7 +193,10 @@ extern "C" void vm_start()
|
||||||
// cpp_test();
|
// cpp_test();
|
||||||
|
|
||||||
kprintf("Parse kernel module: ");
|
kprintf("Parse kernel module: ");
|
||||||
Module *module = VM::load(mainfile.ptr, mainfile.size);
|
|
||||||
|
KernelVM vm;
|
||||||
|
|
||||||
|
Module *module = vm.load(mainfile.ptr, mainfile.size);
|
||||||
if(module == nullptr) {
|
if(module == nullptr) {
|
||||||
kprintf("Could not load module :(\n");
|
kprintf("Could not load module :(\n");
|
||||||
return;
|
return;
|
||||||
|
@ -172,15 +204,6 @@ extern "C" void vm_start()
|
||||||
|
|
||||||
kprintf("Module successfully loaded :)\n");
|
kprintf("Module successfully loaded :)\n");
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Load native modules
|
|
||||||
NativeModuleDef *mod = methods;
|
|
||||||
while(mod->name != nullptr) {
|
|
||||||
module->methods.add(mod->name, new NativeMethod(mod->signature, mod->function));
|
|
||||||
mod++;
|
|
||||||
}
|
|
||||||
|
|
||||||
String errorCode;
|
String errorCode;
|
||||||
if(module->validate(errorCode) == false) {
|
if(module->validate(errorCode) == false) {
|
||||||
kprintf("Module validation failed: \x12\x06%s\x12\x07\n", errorCode.str());
|
kprintf("Module validation failed: \x12\x06%s\x12\x07\n", errorCode.str());
|
||||||
|
|
|
@ -2,6 +2,8 @@
|
||||||
|
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
|
#include <ker/vector.hpp>
|
||||||
|
#include <ker/dictionary.hpp>
|
||||||
|
|
||||||
#include "tsvm.hpp"
|
#include "tsvm.hpp"
|
||||||
|
|
||||||
|
@ -28,20 +30,19 @@ struct ParserData
|
||||||
size_t length;
|
size_t length;
|
||||||
trainscript::Module *module;
|
trainscript::Module *module;
|
||||||
void *scanner;
|
void *scanner;
|
||||||
char* strings[256];
|
ker::Vector<char*> strings;
|
||||||
|
ker::Dictionary<ker::String, ker::String> objects;
|
||||||
|
|
||||||
char *strdup(const char *str)
|
char *strdup(const char *str)
|
||||||
{
|
{
|
||||||
for(size_t i = 0; i < 256; i++) {
|
for(size_t i = 0; i < this->strings.length(); i++) {
|
||||||
if(this->strings[i] == nullptr) {
|
if(strcmp(this->strings[i], str) == 0) {
|
||||||
return this->strings[i] = ::strdup(str);
|
|
||||||
}
|
|
||||||
else if(strcmp(this->strings[i], str) == 0) {
|
|
||||||
return this->strings[i];
|
return this->strings[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
die_extra("ParserData::strdup", "out of strings");
|
char *nstr = ::strdup(str);
|
||||||
return nullptr;
|
this->strings.append(nstr);
|
||||||
|
return nstr;
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
@ -52,6 +53,12 @@ struct VariableDeclaration
|
||||||
trainscript::Type type;
|
trainscript::Type type;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct ObjectDeclaration
|
||||||
|
{
|
||||||
|
char *name;
|
||||||
|
char *moduleName;
|
||||||
|
};
|
||||||
|
|
||||||
struct LocalVariable
|
struct LocalVariable
|
||||||
{
|
{
|
||||||
char *name;
|
char *name;
|
||||||
|
|
|
@ -160,10 +160,12 @@ namespace trainscript
|
||||||
public Instruction
|
public Instruction
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
ker::String moduleName;
|
||||||
ker::String methodName;
|
ker::String methodName;
|
||||||
ker::Vector<Instruction*> parameters;
|
ker::Vector<Instruction*> parameters;
|
||||||
|
|
||||||
MethodInvokeExpression(ker::String methodName) :
|
MethodInvokeExpression(const ker::String moduleName, const ker::String &methodName) :
|
||||||
|
moduleName(moduleName),
|
||||||
methodName(methodName)
|
methodName(methodName)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
@ -171,7 +173,17 @@ namespace trainscript
|
||||||
|
|
||||||
Variable execute(ExecutionContext &context) const override
|
Variable execute(ExecutionContext &context) const override
|
||||||
{
|
{
|
||||||
Method *method = context.module->method(this->methodName.str());
|
Module *module = nullptr;
|
||||||
|
if((this->moduleName.length() == 0) || (this->moduleName == ker::String("this"))) {
|
||||||
|
module = context.module;
|
||||||
|
} else {
|
||||||
|
module = context.module->object(this->moduleName);
|
||||||
|
}
|
||||||
|
if(module == nullptr) {
|
||||||
|
die_extra("MethodInvokeExpression.InvalidModule", this->moduleName.str());
|
||||||
|
}
|
||||||
|
|
||||||
|
Method *method = module->method(this->methodName.str());
|
||||||
if(method == nullptr) {
|
if(method == nullptr) {
|
||||||
die_extra("MethodInvokeExpression.MethodNotFound", this->methodName.str());
|
die_extra("MethodInvokeExpression.MethodNotFound", this->methodName.str());
|
||||||
}
|
}
|
||||||
|
@ -186,7 +198,15 @@ namespace trainscript
|
||||||
}
|
}
|
||||||
|
|
||||||
bool validate(ExecutionContext &context, ker::String &errorCode) const override {
|
bool validate(ExecutionContext &context, ker::String &errorCode) const override {
|
||||||
Method *method = context.module->method(this->methodName.str());
|
|
||||||
|
Module *module = nullptr;
|
||||||
|
if((this->moduleName.length() == 0) || (this->moduleName == ker::String("this"))) {
|
||||||
|
module = context.module;
|
||||||
|
} else {
|
||||||
|
module = context.module->object(this->moduleName);
|
||||||
|
}
|
||||||
|
|
||||||
|
Method *method = module->method(this->methodName.str());
|
||||||
if(method == nullptr) {
|
if(method == nullptr) {
|
||||||
errorCode = "The method " + this->methodName + " does not exist.";
|
errorCode = "The method " + this->methodName + " does not exist.";
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -13,16 +13,22 @@ namespace trainscript
|
||||||
public:
|
public:
|
||||||
ker::Dictionary<ker::String, Variable*> variables;
|
ker::Dictionary<ker::String, Variable*> variables;
|
||||||
ker::Dictionary<ker::String, Method*> methods;
|
ker::Dictionary<ker::String, Method*> methods;
|
||||||
|
ker::Dictionary<ker::String, Module*> objects;
|
||||||
public:
|
public:
|
||||||
Module();
|
Module();
|
||||||
~Module();
|
~Module();
|
||||||
|
|
||||||
Method *method(const char *name)
|
Module *object(const ker::String &name)
|
||||||
|
{
|
||||||
|
return this->objects.get(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
Method *method(const ker::String &name)
|
||||||
{
|
{
|
||||||
return this->methods.get(name);
|
return this->methods.get(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
Variable *variable(const char *name)
|
Variable *variable(const ker::String &name)
|
||||||
{
|
{
|
||||||
return this->variables.get(name);
|
return this->variables.get(name);
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,6 +40,7 @@ VAR { return KW_VAR; }
|
||||||
PUB { return KW_PUB; }
|
PUB { return KW_PUB; }
|
||||||
PRI { return KW_PRI; }
|
PRI { return KW_PRI; }
|
||||||
PTR { return KW_PTR; }
|
PTR { return KW_PTR; }
|
||||||
|
OBJ { return KW_OBJ; }
|
||||||
|
|
||||||
VOID { return KW_VOID; }
|
VOID { return KW_VOID; }
|
||||||
INT { return KW_INT; }
|
INT { return KW_INT; }
|
||||||
|
@ -67,6 +68,7 @@ DO { return KW_DO; }
|
||||||
[0-9]+\.[0-9]* { yylval->fval = atof(yytext); return REAL; }
|
[0-9]+\.[0-9]* { yylval->fval = atof(yytext); return REAL; }
|
||||||
[0-9]+ { yylval->ival = atoi(yytext); return INT; }
|
[0-9]+ { yylval->ival = atoi(yytext); return INT; }
|
||||||
[a-zA-Z0-9'_]+ { yylval->text = yyextra->strdup(yytext); return IDENTIFIER; }
|
[a-zA-Z0-9'_]+ { yylval->text = yyextra->strdup(yytext); return IDENTIFIER; }
|
||||||
|
\. { return DOT; }
|
||||||
. { yyerror(NULL, "illegal token"); }
|
. { yyerror(NULL, "illegal token"); }
|
||||||
%%
|
%%
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -32,6 +32,7 @@ void yyerror(void *scanner, const char *s);
|
||||||
int indentation;
|
int indentation;
|
||||||
trainscript::Type type;
|
trainscript::Type type;
|
||||||
VariableDeclaration varDecl;
|
VariableDeclaration varDecl;
|
||||||
|
ObjectDeclaration objDecl;
|
||||||
MethodDeclaration method;
|
MethodDeclaration method;
|
||||||
MethodBody *body;
|
MethodBody *body;
|
||||||
MethodHeader methodHeader;
|
MethodHeader methodHeader;
|
||||||
|
@ -44,6 +45,7 @@ void yyerror(void *scanner, const char *s);
|
||||||
%token TYPENAME
|
%token TYPENAME
|
||||||
%token SEMICOLON
|
%token SEMICOLON
|
||||||
%token COLON
|
%token COLON
|
||||||
|
%token DOT
|
||||||
%token COMMA
|
%token COMMA
|
||||||
%token PIPE
|
%token PIPE
|
||||||
%token PLUS
|
%token PLUS
|
||||||
|
@ -71,6 +73,7 @@ void yyerror(void *scanner, const char *s);
|
||||||
%token KW_PUB
|
%token KW_PUB
|
||||||
%token KW_PRI
|
%token KW_PRI
|
||||||
%token KW_VAR
|
%token KW_VAR
|
||||||
|
%token KW_OBJ
|
||||||
%token KW_PTR
|
%token KW_PTR
|
||||||
|
|
||||||
%token KW_VOID
|
%token KW_VOID
|
||||||
|
@ -95,7 +98,7 @@ void yyerror(void *scanner, const char *s);
|
||||||
|
|
||||||
%type <type> typeName
|
%type <type> typeName
|
||||||
%type <varDecl> variableDeclaration
|
%type <varDecl> variableDeclaration
|
||||||
|
%type <objDecl> objectDeclaration
|
||||||
// %type <indentation> indentation
|
// %type <indentation> indentation
|
||||||
|
|
||||||
%type <method> method
|
%type <method> method
|
||||||
|
@ -132,6 +135,9 @@ input:
|
||||||
auto *var = new Variable($2.type.createInstance());
|
auto *var = new Variable($2.type.createInstance());
|
||||||
context->module->variables.add( ker::String($2.name), var );
|
context->module->variables.add( ker::String($2.name), var );
|
||||||
}
|
}
|
||||||
|
| input objectDeclaration SEMICOLON {
|
||||||
|
context->objects.add($2.name, $2.moduleName);
|
||||||
|
}
|
||||||
| input method {
|
| input method {
|
||||||
using namespace trainscript;
|
using namespace trainscript;
|
||||||
auto *mod = context->module;
|
auto *mod = context->module;
|
||||||
|
@ -323,7 +329,7 @@ expression:
|
||||||
| TEXT { $$ = new ConstantExpression(Variable::fromText($1)); }
|
| TEXT { $$ = new ConstantExpression(Variable::fromText($1)); }
|
||||||
| IDENTIFIER { $$ = new VariableExpression($1); }
|
| IDENTIFIER { $$ = new VariableExpression($1); }
|
||||||
| IDENTIFIER LBRACKET expressionList RBRACKET {
|
| IDENTIFIER LBRACKET expressionList RBRACKET {
|
||||||
auto *call = new MethodInvokeExpression($1);
|
auto *call = new MethodInvokeExpression("", $1);
|
||||||
auto *list = $3;
|
auto *list = $3;
|
||||||
while(list) {
|
while(list) {
|
||||||
call->parameters.append(list->instruction);
|
call->parameters.append(list->instruction);
|
||||||
|
@ -331,6 +337,15 @@ expression:
|
||||||
}
|
}
|
||||||
$$ = call;
|
$$ = call;
|
||||||
}
|
}
|
||||||
|
| IDENTIFIER DOT IDENTIFIER LBRACKET expressionList RBRACKET {
|
||||||
|
auto *call = new MethodInvokeExpression($1, $3);
|
||||||
|
auto *list = $5;
|
||||||
|
while(list) {
|
||||||
|
call->parameters.append(list->instruction);
|
||||||
|
list = list->next;
|
||||||
|
}
|
||||||
|
$$ = call;
|
||||||
|
}
|
||||||
| LBRACKET expression RBRACKET { $$ = $2; }
|
| LBRACKET expression RBRACKET { $$ = $2; }
|
||||||
| expression PLUS expression { $$ = new ArithmeticExpression($1, $3, Operation::Add); }
|
| expression PLUS expression { $$ = new ArithmeticExpression($1, $3, Operation::Add); }
|
||||||
| expression MINUS expression { $$ = new ArithmeticExpression($1, $3, Operation::Subtract); }
|
| expression MINUS expression { $$ = new ArithmeticExpression($1, $3, Operation::Subtract); }
|
||||||
|
@ -373,6 +388,13 @@ variableDeclaration:
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
|
objectDeclaration:
|
||||||
|
KW_OBJ IDENTIFIER COLON TEXT {
|
||||||
|
$$.name = $2;
|
||||||
|
$$.moduleName = $4;
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
typeName:
|
typeName:
|
||||||
KW_VOID { $$ = Type::Void; }
|
KW_VOID { $$ = Type::Void; }
|
||||||
| KW_INT { $$ = Type::Int; }
|
| KW_INT { $$ = Type::Int; }
|
||||||
|
|
|
@ -21,6 +21,11 @@ namespace trainscript
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Module *VM::create(const ker::String &)
|
||||||
|
{
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
Module *VM::load(const void *buffer, size_t length)
|
Module *VM::load(const void *buffer, size_t length)
|
||||||
{
|
{
|
||||||
char *internalStorage = (char*)malloc(length);
|
char *internalStorage = (char*)malloc(length);
|
||||||
|
@ -41,10 +46,19 @@ namespace trainscript
|
||||||
|
|
||||||
free(internalStorage);
|
free(internalStorage);
|
||||||
|
|
||||||
for(size_t i = 0; i < 256; i++) {
|
for(char *ptr : data.strings) {
|
||||||
if(data.strings[i] != nullptr) {
|
free(ptr);
|
||||||
free(data.strings[i]);
|
}
|
||||||
|
|
||||||
|
for(const ker::Pair<ker::String, ker::String> &mod : data.objects)
|
||||||
|
{
|
||||||
|
Module *obj = this->create(mod.second);
|
||||||
|
if(obj == nullptr) {
|
||||||
|
kprintf("Module \"%s\" not found.\n", mod.second.str());
|
||||||
|
delete module;
|
||||||
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
module->objects.add(mod.first, obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(valid) {
|
if(valid) {
|
||||||
|
|
|
@ -7,8 +7,15 @@ namespace trainscript
|
||||||
class VM
|
class VM
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
static Module *load(const void *buffer, size_t length);
|
Module *load(const void *buffer, size_t length);
|
||||||
|
|
||||||
static Module *load(const char *text);
|
Module *load(const char *text);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Creates a module by the module name.
|
||||||
|
* @param name The name of the module
|
||||||
|
* @return New module or nullptr if the named module does not exist.
|
||||||
|
*/
|
||||||
|
virtual Module *create(const ker::String &name);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue