Adds module support to trainscript. Moves global methods to /sys/* objects.

This commit is contained in:
Felix Queissner 2015-08-21 17:32:48 +02:00
parent 81ad6c3406
commit d0d88a17f3
12 changed files with 187 additions and 51 deletions

View file

@ -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 \

View file

@ -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.

View file

@ -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);

View file

@ -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

View file

@ -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());

View file

@ -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;

View file

@ -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;

View file

@ -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);
} }

View file

@ -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"); }
%% %%
/* /*

View file

@ -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; }

View file

@ -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) {

View file

@ -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);
}; };
} }