From 5f168f8020be562d1f2c98a1f9c961b01e69c36d Mon Sep 17 00:00:00 2001 From: Felix Queissner Date: Wed, 19 Aug 2015 16:26:28 +0200 Subject: [PATCH] Refactors tsvm.hpp into more subfiles for better structure. --- Makefile | 80 ++-- scripts/main.ts | 6 +- src/init.c | 10 +- src/malloc.c | 8 +- src/vm.cpp | 1 + trainOS.pro | 12 +- trainscript/common.h | 1 + trainscript/executioncontext.hpp | 34 ++ trainscript/instruction.hpp | 24 ++ trainscript/instructions.hpp | 404 +++++++++++++++++++ trainscript/method.hpp | 22 ++ trainscript/module.hpp | 32 ++ trainscript/scriptmethod.hpp | 42 ++ trainscript/trainscript.tab.hpp | 128 ------ trainscript/trainscript.y | 1 + trainscript/tsvm.cpp | 6 +- trainscript/tsvm.hpp | 646 +------------------------------ trainscript/type.hpp | 56 +++ trainscript/types.hpp | 13 + trainscript/variable.hpp | 55 +++ trainscript/vm.hpp | 14 + 21 files changed, 780 insertions(+), 815 deletions(-) create mode 100644 trainscript/executioncontext.hpp create mode 100644 trainscript/instruction.hpp create mode 100644 trainscript/instructions.hpp create mode 100644 trainscript/method.hpp create mode 100644 trainscript/module.hpp create mode 100644 trainscript/scriptmethod.hpp delete mode 100644 trainscript/trainscript.tab.hpp create mode 100644 trainscript/type.hpp create mode 100644 trainscript/types.hpp create mode 100644 trainscript/variable.hpp create mode 100644 trainscript/vm.hpp diff --git a/Makefile b/Makefile index ef3437e..b905f16 100644 --- a/Makefile +++ b/Makefile @@ -35,94 +35,112 @@ kernel: obj/tsvm.o obj/dynamic.o obj/intr_common_handler.o obj/multiboot.o obj/s # src/console.c obj/console.o: src/console.c include/console.h include/stdlib.h \ include/varargs.h include/config.h include/malloc.h - $(CC) $(FLAGS) $(CCFLAGS) -o $@ -c src/console.c + $(CC) -iquoteobj $(FLAGS) $(CCFLAGS) -o $@ -c src/console.c # src/init.c obj/init.o: src/init.c include/kernel.h include/stdlib.h include/varargs.h \ include/config.h include/malloc.h include/console.h include/interrupts.h \ include/cpustate.h include/pmm.h include/multiboot.h include/vmm.h \ include/timer.h include/serial.h - $(CC) $(FLAGS) $(CCFLAGS) -o $@ -c src/init.c + $(CC) -iquoteobj $(FLAGS) $(CCFLAGS) -o $@ -c src/init.c # src/interrupts.c obj/interrupts.o: src/interrupts.c include/interrupts.h include/cpustate.h \ include/console.h include/stdlib.h include/varargs.h include/config.h \ include/malloc.h include/io.h src/intr_stubs.h - $(CC) $(FLAGS) $(CCFLAGS) -o $@ -c src/interrupts.c + $(CC) -iquoteobj $(FLAGS) $(CCFLAGS) -o $@ -c src/interrupts.c # src/malloc.c obj/malloc.o: src/malloc.c include/kernel.h include/stdlib.h \ include/varargs.h include/config.h include/malloc.h include/console.h \ include/serial.h - $(CC) $(FLAGS) $(CCFLAGS) -o $@ -c src/malloc.c + $(CC) -iquoteobj $(FLAGS) $(CCFLAGS) -o $@ -c src/malloc.c # src/pmm.c obj/pmm.o: src/pmm.c include/pmm.h include/multiboot.h include/kernel.h \ include/stdlib.h include/varargs.h include/config.h include/malloc.h \ include/console.h - $(CC) $(FLAGS) $(CCFLAGS) -o $@ -c src/pmm.c + $(CC) -iquoteobj $(FLAGS) $(CCFLAGS) -o $@ -c src/pmm.c # src/serial.c obj/serial.o: src/serial.c include/io.h include/serial.h include/stdlib.h \ include/varargs.h include/config.h include/malloc.h - $(CC) $(FLAGS) $(CCFLAGS) -o $@ -c src/serial.c + $(CC) -iquoteobj $(FLAGS) $(CCFLAGS) -o $@ -c src/serial.c # src/stdlib.c obj/stdlib.o: src/stdlib.c include/stdlib.h include/varargs.h \ include/config.h include/malloc.h include/kernel.h - $(CC) $(FLAGS) $(CCFLAGS) -o $@ -c src/stdlib.c + $(CC) -iquoteobj $(FLAGS) $(CCFLAGS) -o $@ -c src/stdlib.c # src/timer.c obj/timer.o: src/timer.c include/timer.h include/kernel.h \ include/interrupts.h include/cpustate.h - $(CC) $(FLAGS) $(CCFLAGS) -o $@ -c src/timer.c + $(CC) -iquoteobj $(FLAGS) $(CCFLAGS) -o $@ -c src/timer.c # src/vmm.c obj/vmm.o: src/vmm.c include/config.h include/vmm.h include/pmm.h \ include/multiboot.h include/stdlib.h include/varargs.h include/malloc.h \ include/console.h include/kernel.h - $(CC) $(FLAGS) $(CCFLAGS) -o $@ -c src/vmm.c + $(CC) -iquoteobj $(FLAGS) $(CCFLAGS) -o $@ -c src/vmm.c # trainscript/tsvm.cpp obj/tsvm.o: trainscript/tsvm.cpp include/stdlib.h include/varargs.h \ include/config.h include/malloc.h include/console.h trainscript/common.h \ - trainscript/tsvm.hpp include/ker/string.hpp include/ker/vector.hpp \ - include/ker/new.hpp include/ker/dictionary.hpp include/kernel.h \ - include/ker/pair.hpp trainscript/typeid.hpp \ - trainscript/trainscript.tab.hpp trainscript/trainscript.l.h \ - include/string.h - $(CXX) $(FLAGS) $(CXXFLAGS) -o $@ -c trainscript/tsvm.cpp + trainscript/tsvm.hpp trainscript/vm.hpp trainscript/module.hpp \ + include/ker/string.hpp include/ker/dictionary.hpp include/kernel.h \ + include/ker/pair.hpp include/ker/vector.hpp include/ker/new.hpp \ + trainscript/variable.hpp trainscript/type.hpp trainscript/types.hpp \ + trainscript/typeid.hpp trainscript/method.hpp \ + trainscript/instructions.hpp trainscript/instruction.hpp \ + trainscript/executioncontext.hpp trainscript/scriptmethod.hpp \ + obj/trainscript.tab.hpp trainscript/trainscript.l.h include/string.h + $(CXX) -iquoteobj $(FLAGS) $(CXXFLAGS) -o $@ -c trainscript/tsvm.cpp # src/cplusplus.cpp obj/cplusplus.o: src/cplusplus.cpp include/stdlib.h include/varargs.h \ include/config.h include/malloc.h include/console.h include/ker/new.hpp - $(CXX) $(FLAGS) $(CXXFLAGS) -o $@ -c src/cplusplus.cpp + $(CXX) -iquoteobj $(FLAGS) $(CXXFLAGS) -o $@ -c src/cplusplus.cpp # src/vm.cpp obj/vm.o: src/vm.cpp include/stdlib.h include/varargs.h include/config.h \ - include/malloc.h include/timer.h include/dynamic.h \ - src/../trainscript/tsvm.hpp include/console.h include/ker/string.hpp \ - include/ker/vector.hpp include/ker/new.hpp include/ker/dictionary.hpp \ - include/kernel.h include/ker/pair.hpp src/../trainscript/typeid.hpp - $(CXX) $(FLAGS) $(CXXFLAGS) -o $@ -c src/vm.cpp + include/malloc.h include/timer.h include/dynamic.h include/console.h \ + src/../trainscript/tsvm.hpp src/../trainscript/vm.hpp \ + src/../trainscript/module.hpp include/ker/string.hpp \ + include/ker/dictionary.hpp include/kernel.h include/ker/pair.hpp \ + include/ker/vector.hpp include/ker/new.hpp \ + src/../trainscript/variable.hpp src/../trainscript/type.hpp \ + src/../trainscript/types.hpp src/../trainscript/typeid.hpp \ + src/../trainscript/method.hpp src/../trainscript/instructions.hpp \ + src/../trainscript/instruction.hpp \ + src/../trainscript/executioncontext.hpp \ + src/../trainscript/scriptmethod.hpp + $(CXX) -iquoteobj $(FLAGS) $(CXXFLAGS) -o $@ -c src/vm.cpp # obj/trainscript.yy.cpp obj/trainscript.yy.o: obj/trainscript.yy.cpp include/string.h \ include/stdlib.h include/varargs.h include/config.h include/malloc.h \ - trainscript/common.h trainscript/tsvm.hpp include/console.h \ - include/ker/string.hpp include/ker/vector.hpp include/ker/new.hpp \ - include/ker/dictionary.hpp include/kernel.h include/ker/pair.hpp \ - trainscript/typeid.hpp obj/trainscript.tab.hpp - $(CXX) -iquotetrainscript $(FLAGS) $(CXXFLAGS) -o $@ -c obj/trainscript.yy.cpp + trainscript/common.h trainscript/tsvm.hpp trainscript/vm.hpp \ + trainscript/module.hpp include/ker/string.hpp include/ker/dictionary.hpp \ + include/kernel.h include/ker/pair.hpp include/ker/vector.hpp \ + include/ker/new.hpp trainscript/variable.hpp trainscript/type.hpp \ + trainscript/types.hpp trainscript/typeid.hpp trainscript/method.hpp \ + trainscript/instructions.hpp trainscript/instruction.hpp \ + trainscript/executioncontext.hpp trainscript/scriptmethod.hpp \ + obj/trainscript.tab.hpp + $(CXX) -iquotetrainscript -iquoteobj $(FLAGS) $(CXXFLAGS) -o $@ -c obj/trainscript.yy.cpp # obj/trainscript.tab.cpp obj/trainscript.tab.o: obj/trainscript.tab.cpp include/stdlib.h \ - include/varargs.h include/config.h include/malloc.h trainscript/common.h \ - trainscript/tsvm.hpp include/console.h include/ker/string.hpp \ - include/ker/vector.hpp include/ker/new.hpp include/ker/dictionary.hpp \ - include/kernel.h include/ker/pair.hpp trainscript/typeid.hpp \ + include/varargs.h include/config.h include/malloc.h include/console.h \ + trainscript/common.h trainscript/tsvm.hpp trainscript/vm.hpp \ + trainscript/module.hpp include/ker/string.hpp include/ker/dictionary.hpp \ + include/kernel.h include/ker/pair.hpp include/ker/vector.hpp \ + include/ker/new.hpp trainscript/variable.hpp trainscript/type.hpp \ + trainscript/types.hpp trainscript/typeid.hpp trainscript/method.hpp \ + trainscript/instructions.hpp trainscript/instruction.hpp \ + trainscript/executioncontext.hpp trainscript/scriptmethod.hpp \ trainscript/trainscript.l.h include/string.h - $(CXX) -iquotetrainscript $(FLAGS) $(CXXFLAGS) -o $@ -c obj/trainscript.tab.cpp + $(CXX) -iquotetrainscript -iquoteobj $(FLAGS) $(CXXFLAGS) -o $@ -c obj/trainscript.tab.cpp # asm/dynamic.S obj/dynamic.o: asm/dynamic.S diff --git a/scripts/main.ts b/scripts/main.ts index 0923997..d247b60 100644 --- a/scripts/main.ts +++ b/scripts/main.ts @@ -1,5 +1,9 @@ VAR global : INT; +# OBJ timer : "/sys/timer"; +# OBJ heap : "/sys/malloc"; +# OBJ interrupts : "/sys/interrupt"; + PUB main() | i : INT BEGIN 0 -> i; @@ -12,5 +16,5 @@ END PUB fun() -> i : INT BEGIN - 30 -> i; + 60 -> i; END diff --git a/src/init.c b/src/init.c index ebf7332..ab8f496 100644 --- a/src/init.c +++ b/src/init.c @@ -16,7 +16,7 @@ void die(const char *msg) void die_extra(const char *msg, const char *extra) { kputs("\n"); - ksetcolor(COLOR_RED, COLOR_WHITE); + ksetcolor(COLOR_LIGHTMAGENTA, COLOR_BLACK); kputs(msg); if((extra != nullptr) && (strlen(extra) > 0)) { kputs(": '"); @@ -102,14 +102,14 @@ static void dumpMB(const MultibootStructure *mbHeader) // TODO: MB_BOOTDEVICE if(mbHeader->flags & MB_COMMANDLINE) { - kprintf("Commandline: %s\n", mbHeader->commandline); + kprintf("Commandline: %s\n", (const char*)mbHeader->commandline); } if(mbHeader->flags & MB_MODULES) { const MultibootModule *mod = (const MultibootModule *)mbHeader->modules; for(size_t i = 0; i < mbHeader->moduleCount; i++) { - kprintf("Module %s [%d - %d]\n", mod[i].name, mod[i].start, mod[i].end); + kprintf("Module %s [%d - %d]\n", (const char*)mod[i].name, mod[i].start, mod[i].end); } } if(mbHeader->flags & MB_SYMS_AOUT) @@ -136,7 +136,7 @@ static void dumpMB(const MultibootStructure *mbHeader) // TODO: MB_CONFIG_TABLE if(mbHeader->flags & MB_BOOTLOADER_NAME) { - kprintf("Bootloader Name: %s\n", mbHeader->bootLoaderName); + kprintf("Bootloader Name: %s\n", (const char*)mbHeader->bootLoaderName); } // TODO: MB_APS_TABLE } @@ -204,7 +204,7 @@ void init(const MultibootStructure *mbHeader) cpp_init(); putsuccess(); - timer_add_callback(1, update_statusbar); + timer_add_callback(1, update_statusbar); vm_start(); diff --git a/src/malloc.c b/src/malloc.c index 1a01c2a..b7bc8fa 100644 --- a/src/malloc.c +++ b/src/malloc.c @@ -46,7 +46,7 @@ size_t allocatedMemory = 0; static const size_t minimumAllocSize = 2 * sizeof(List); static char * const malloc_heap_start = (char *)0x400000; -static char * const malloc_heap_end = (char *)0x10000000; +static char * const malloc_heap_end = (char *)0x800000; List *listBegin = nullptr; @@ -69,16 +69,18 @@ void malloc_print_list(int freeList) list, list->next, list->used ? list->allocationFile : "", - list->used ? list->allocationLine : "", + list->used ? list->allocationLine : 0, list->used, list->length); + /* kprintf("[%x -> %x] (%s:%d) %d %d\n", list, list->next, list->used ? list->allocationFile : "", - list->used ? list->allocationLine : "", + list->used ? list->allocationLine : 0, list->used, list->length); + */ if(list->used) { count++; } diff --git a/src/vm.cpp b/src/vm.cpp index ce3fc31..05d8af9 100644 --- a/src/vm.cpp +++ b/src/vm.cpp @@ -1,6 +1,7 @@ #include #include #include +#include #include "../trainscript/tsvm.hpp" using namespace ker; diff --git a/trainOS.pro b/trainOS.pro index 4f63c0a..d372190 100644 --- a/trainOS.pro +++ b/trainOS.pro @@ -43,7 +43,17 @@ HEADERS += \ include/dynamic.h \ include/config.h \ include/serial.h \ - include/malloc.h + include/malloc.h \ + trainscript/instruction.hpp \ + trainscript/method.hpp \ + trainscript/module.hpp \ + trainscript/scriptmethod.hpp \ + trainscript/type.hpp \ + trainscript/types.hpp \ + trainscript/variable.hpp \ + trainscript/executioncontext.hpp \ + trainscript/vm.hpp \ + trainscript/instructions.hpp DISTFILES += \ asm/intr_common_handler.S \ diff --git a/trainscript/common.h b/trainscript/common.h index d8c5f25..fe959ad 100644 --- a/trainscript/common.h +++ b/trainscript/common.h @@ -41,6 +41,7 @@ struct ParserData } } die_extra("ParserData::strdup", "out of strings"); + return nullptr; } }; diff --git a/trainscript/executioncontext.hpp b/trainscript/executioncontext.hpp new file mode 100644 index 0000000..20a17db --- /dev/null +++ b/trainscript/executioncontext.hpp @@ -0,0 +1,34 @@ +#pragma once +#include +#include +#include + +#include "variable.hpp" + +namespace trainscript +{ + class Module; + + class ExecutionContext : + public ker::Dictionary + { + public: + Module * const module = nullptr; + + ExecutionContext(Module *mod) : + ker::Dictionary(), + module(mod) + { + + } + + Variable *get(const ker::String &name) + { + if(this->contains(name)) { + return this->at(name); + } else { + return nullptr; + } + } + }; +} diff --git a/trainscript/instruction.hpp b/trainscript/instruction.hpp new file mode 100644 index 0000000..c04c9f4 --- /dev/null +++ b/trainscript/instruction.hpp @@ -0,0 +1,24 @@ +#pragma once +#include + +#include "executioncontext.hpp" + +namespace trainscript +{ + class Instruction + { + public: + virtual ~Instruction() { } + + virtual Variable execute(ExecutionContext &context) const = 0; + + virtual Type expectedResult(ExecutionContext &) const { + return Type::Void; + } + + virtual bool validate(ExecutionContext &, ker::String &errorCode) const { + errorCode = ""; + return true; + } + }; +} diff --git a/trainscript/instructions.hpp b/trainscript/instructions.hpp new file mode 100644 index 0000000..6c4b09a --- /dev/null +++ b/trainscript/instructions.hpp @@ -0,0 +1,404 @@ +#pragma once +#include +#include "module.hpp" + +#include "method.hpp" +#include "instruction.hpp" + +namespace trainscript +{ + class Block : + public Instruction + { + public: + ker::Vector instructions; + + ~Block() { + for(auto *instr : instructions) delete instr; + } + + bool validate(ExecutionContext &context, ker::String &errorCode) const { + errorCode = ""; + for(auto *instr : instructions) { + if(instr->validate(context, errorCode) == false) + return false; + } + return true; + } + + Variable execute(ExecutionContext &context) const override { + for(auto *instr : instructions) { + instr->execute(context); + } + return Variable::Void; + } + }; + + class ConstantExpression : + public Instruction + { + public: + Variable value; + ConstantExpression(Variable value) : value(value) { } + + Variable execute(ExecutionContext &) const override { + return this->value; + } + + Type expectedResult(ExecutionContext &) const override { + return this->value.type; + } + }; + + class VariableExpression : + public Instruction + { + public: + ker::String variableName; + VariableExpression(ker::String variableName) : variableName(variableName) { } + + Variable execute(ExecutionContext &context) const override { + auto *var = context.get(this->variableName); + if(var == nullptr) { + die_extra("VariableExpression.VariableNotFound", this->variableName.str()); + } + return *var; + } + + bool validate(ExecutionContext &context, ker::String &errorCode) const override { + errorCode = ""; + if(context.get(this->variableName) == nullptr) { + errorCode = "Variable " + this->variableName + " not found."; + return false; + } + return true; + } + + Type expectedResult(ExecutionContext &context) const override { + Variable *var = context.get(this->variableName); + if(var == nullptr) { + return Type::Invalid; + } else { + return var->type; + } + } + }; + + + class VariableAssignmentExpression : + public Instruction + { + public: + ker::String variableName; + Instruction *expression; + VariableAssignmentExpression(ker::String variableName, Instruction *expression) : + variableName(variableName), + expression(expression) + { + + } + + Variable execute(ExecutionContext &context) const override { + if(this->expression == nullptr) { + die("VariableAssignmentExpression.ExpressionMissing"); + } + Variable result = this->expression->execute(context); + + Variable *target = context.get(this->variableName); + if(target == nullptr) { + die_extra("VariableAssignmentExpression.VariableNotFound", this->variableName.str()); + } + + if(target->type != result.type) { + die_extra("VariableAssignmentExpression.ExpectedType", result.type.name()); + } + + switch(target->type.id) { + case TypeID::Int: target->integer = result.integer; break; + case TypeID::Real: target->real = result.real; break; + case TypeID::Bool: target->boolean = result.boolean; break; + default: break; + } + + return result; + } + + bool validate(ExecutionContext &context, ker::String &errorCode) const override { + errorCode = ""; + if(this->expression == nullptr) { + errorCode = "Missing expression."; + return false; + } + Type result = this->expression->expectedResult(context); + if(result == Type::Invalid) { + errorCode = "Expression returns invalid type."; + return false; + } + if(result == Type::Void) { + errorCode = "Void cannot be assigned to a variable"; + return false; + } + Variable *var = context.get(this->variableName); + if(var == nullptr) { + errorCode = "Variable " + this->variableName + " not found."; + return false; + } + if(var->type != result) { + errorCode = "Variable assignment has invalid type."; + return false; + } + if(this->expression->validate(context, errorCode) == false) + return false; + return true; + } + + Type expectedResult(ExecutionContext &context) const override { + if(this->expression == nullptr) { + return Type::Invalid; + } else { + return this->expression->expectedResult(context); + } + } + }; + + class MethodInvokeExpression : + public Instruction + { + public: + ker::String methodName; + ker::Vector parameters; + + MethodInvokeExpression(ker::String methodName) : + methodName(methodName) + { + + } + + Variable execute(ExecutionContext &context) const override + { + Method *method = context.module->method(this->methodName.str()); + if(method == nullptr) { + die_extra("MethodInvokeExpression.MethodNotFound", this->methodName.str()); + } + + ker::Vector vars(this->parameters.length()); + vars.resize(this->parameters.length()); + for(size_t i = 0; i < vars.length(); i++) { + vars[i] = this->parameters.at(i)->execute(context); + } + + return method->invoke(vars); + } + + bool validate(ExecutionContext &context, ker::String &errorCode) const override { + Method *method = context.module->method(this->methodName.str()); + if(method == nullptr) { + errorCode = "The method " + this->methodName + " does not exist."; + return false; + } + + ker::Vector arguments = method->arguments(); + if(arguments.length() != this->parameters.length()) { + errorCode = "Argument count mismatch."; + return false; + } + for(size_t i = 0; i < arguments.length(); i++) { + if(this->parameters[i]->expectedResult(context) != arguments[i]) { + errorCode = "Argument type mismatch."; + return false; + } + if(this->parameters[i]->validate(context, errorCode) == false) + return false; + } + + return true; + } + + Type expectedResult(ExecutionContext &context) const override { + Method *method = context.module->method(this->methodName.str()); + if(method == nullptr) { + return Type::Invalid; + } + return method->returnType(); + } + }; + + template + class ArithmeticExpression : + public Instruction + { + public: + Instruction *lhs, *rhs; + + ArithmeticExpression(Instruction *lhs, Instruction *rhs) : + lhs(lhs), + rhs(rhs) + { + + } + + Variable execute(ExecutionContext &context) const override { + if(this->lhs == nullptr) { + die_extra("ArithmeticExpression.ExpressionMissing", "Left-hand side"); + } + if(this->rhs == nullptr) { + die_extra("ArithmeticExpression.ExpressionMissing", "Right-hand side"); + } + + Variable left = this->lhs->execute(context); + Variable right = this->rhs->execute(context); + + if(left.type != right.type) { + die("ArithmeticExpression.TypeMismatch"); + } + + Variable result = OP(left, right); + + if(result.type.usable() == false) { + die_extra("ArithmeticExpression.InvalidResult", result.type.name()); + } + return result; + } + + bool validate(ExecutionContext &context, ker::String &errorCode) const override { + errorCode = ""; + if(this->lhs == nullptr) { + errorCode = "Left part of operand is missing."; + return false; + } + if(this->rhs == nullptr) { + errorCode = "Right part of operand is missing."; + return false; + } + Type lhsType = this->lhs->expectedResult(context); + Type rhsType = this->rhs->expectedResult(context); + if(lhsType != rhsType) { + errorCode = "Types of operands do not match."; + return false; + } + if(lhsType == Type::Invalid) { + errorCode = "Invalid type can't be used for operand."; + return false; + } + if(rhsType == Type::Void) { + errorCode = "VOID type can't be used for operand."; + return false; + } + + if(this->lhs->validate(context, errorCode) == false) + return false; + if(this->rhs->validate(context, errorCode) == false) + return false; + + return true; + } + + Type expectedResult(ExecutionContext &context) const override { + if(this->lhs == nullptr) { + return Type::Invalid; + } else { + return this->lhs->expectedResult(context); + } + } + }; + + class IfExpression : + public Instruction + { + public: + Instruction *condition; + Instruction *blockTrue; + Instruction *blockFalse; + + IfExpression(Instruction *condition, Instruction *blockTrue, Instruction *blockFalse) : + condition(condition), + blockTrue(blockTrue), + blockFalse(blockFalse) + { + + } + + Variable execute(ExecutionContext &context) const override { + if(this->condition == nullptr) { + die("IfExpression.ConditionMissing"); + } + + Variable result = this->condition->execute(context); + if(result.type != Type::Boolean) { + die_extra("IfExpression.TypeMismatch", result.type.name()); + } + if((result.boolean == true) && (this->blockTrue != nullptr)) { + this->blockTrue->execute(context); + } + if((result.boolean == false) && (this->blockFalse != nullptr)) { + this->blockFalse->execute(context); + } + return Variable::Void; + } + }; + + class RepeatEndlessExpression : + public Instruction + { + public: + Instruction *block; + + RepeatEndlessExpression(Instruction *block) : + block(block) + { + + } + + Variable execute(ExecutionContext &context) const override { + if(this->block == nullptr) { + die("RepeatEndlessExpression.BlockMissing"); + } + + while(true) + { + Variable result = this->block->execute(context); + (void)result; + } + return Variable::Void; + } + }; + + + class RepeatWhileExpression : + public Instruction + { + public: + Instruction *condition; + Instruction *block; + + RepeatWhileExpression(Instruction *condition, Instruction *block) : + condition(condition), + block(block) + { + + } + + Variable execute(ExecutionContext &context) const override { + if(this->condition == nullptr) { + die("RepeatWhileExpression.ConditionMissing"); + } + if(this->block == nullptr) { + die("RepeatWhileExpression.BlockMissing"); + } + + while(true) + { + Variable cond = this->condition->execute(context); + if(cond.type != Type::Boolean) { + return Variable::Invalid; + } + if(cond.boolean == false) { + break; + } + + this->block->execute(context); + } + return Variable::Void; + } + }; +} diff --git a/trainscript/method.hpp b/trainscript/method.hpp new file mode 100644 index 0000000..f50d44d --- /dev/null +++ b/trainscript/method.hpp @@ -0,0 +1,22 @@ +#pragma once +#include +#include + +#include "type.hpp" + +namespace trainscript +{ + class Method + { + public: + virtual ~Method() { } + + virtual Variable invoke(ker::Vector arguments) = 0; + + virtual bool validate(ker::String &errorCode) const = 0; + + virtual ker::Vector arguments() const = 0; + + virtual Type returnType() const = 0; + }; +} diff --git a/trainscript/module.hpp b/trainscript/module.hpp new file mode 100644 index 0000000..8977c43 --- /dev/null +++ b/trainscript/module.hpp @@ -0,0 +1,32 @@ +#pragma once +#include +#include +#include + +#include "variable.hpp" +#include "method.hpp" + +namespace trainscript +{ + class Module + { + public: + ker::Dictionary variables; + ker::Dictionary methods; + public: + Module(); + ~Module(); + + Method *method(const char *name) + { + return this->methods.get(name); + } + + Variable *variable(const char *name) + { + return this->variables.get(name); + } + + bool validate(ker::String &errorCode) const; + }; +} diff --git a/trainscript/scriptmethod.hpp b/trainscript/scriptmethod.hpp new file mode 100644 index 0000000..2a060c7 --- /dev/null +++ b/trainscript/scriptmethod.hpp @@ -0,0 +1,42 @@ +#pragma once + +#include "module.hpp" +#include "method.hpp" + +namespace trainscript +{ + class ScriptMethod : + public Method + { + public: + Module *module; + Instruction *block; + bool isPublic; + ker::Vector> mArguments; + ker::Dictionary mLocals; + ker::Pair mReturnValue; + + ScriptMethod(Module *module, Instruction *block) : module(module), block(block) + { + + } + + Variable invoke(ker::Vector arguments) override; + + bool validate(ker::String &errorCode) const override; + + ker::Vector arguments() const override + { + ker::Vector args(this->mArguments.length()); + for(size_t i = 0; i < args.length(); i++) { + args[i] = this->mArguments[i].second; + } + return args; + } + + Type returnType() const override + { + return this->mReturnValue.second; + } + }; +} diff --git a/trainscript/trainscript.tab.hpp b/trainscript/trainscript.tab.hpp deleted file mode 100644 index d4df285..0000000 --- a/trainscript/trainscript.tab.hpp +++ /dev/null @@ -1,128 +0,0 @@ -/* A Bison parser, made by GNU Bison 3.0.4. */ - -/* Bison interface for Yacc-like parsers in C - - Copyright (C) 1984, 1989-1990, 2000-2015 Free Software Foundation, Inc. - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . */ - -/* As a special exception, you may create a larger work that contains - part or all of the Bison parser skeleton and distribute that work - under terms of your choice, so long as that work isn't itself a - parser generator using the skeleton or a modified version thereof - as a parser skeleton. Alternatively, if you modify or redistribute - the parser skeleton itself, you may (at your option) remove this - special exception, which will cause the skeleton and the resulting - Bison output files to be licensed under the GNU General Public - License without this special exception. - - This special exception was added by the Free Software Foundation in - version 2.2 of Bison. */ - -#ifndef YY_YY_TRAINSCRIPT_TRAINSCRIPT_TAB_HPP_INCLUDED -# define YY_YY_TRAINSCRIPT_TRAINSCRIPT_TAB_HPP_INCLUDED -/* Debug traces. */ -#ifndef YYDEBUG -# define YYDEBUG 0 -#endif -#if YYDEBUG -extern int yydebug; -#endif - -/* Token type. */ -#ifndef YYTOKENTYPE -# define YYTOKENTYPE - enum yytokentype - { - TAB = 258, - TYPENAME = 259, - SEMICOLON = 260, - COLON = 261, - COMMA = 262, - PIPE = 263, - PLUS = 264, - MINUS = 265, - MULTIPLY = 266, - DIVIDE = 267, - MODULO = 268, - LBRACKET = 269, - RBRACKET = 270, - RARROW = 271, - LARROW = 272, - OP_LT = 273, - OP_LE = 274, - OP_GT = 275, - OP_GE = 276, - OP_EQ = 277, - OP_NEQ = 278, - REAL = 279, - INT = 280, - IDENTIFIER = 281, - KW_PUB = 282, - KW_PRI = 283, - KW_VAR = 284, - KW_PTR = 285, - KW_VOID = 286, - KW_INT = 287, - KW_REAL = 288, - KW_TEXT = 289, - KW_BOOL = 290, - KW_BEGIN = 291, - KW_END = 292, - KW_IF = 293, - KW_THEN = 294, - KW_ELSE = 295, - KW_ELSEIF = 296, - KW_REPEAT = 297, - KW_FROM = 298, - KW_TO = 299, - KW_UNTIL = 300, - KW_WHILE = 301, - KW_DO = 302 - }; -#endif - -/* Value type. */ -#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED - -union YYSTYPE -{ -#line 44 "trainscript/trainscript.y" /* yacc.c:1909 */ - - float fval; - int ival; - char *text; - int indentation; - trainscript::Type type; - VariableDeclaration varDecl; - MethodDeclaration method; - MethodBody *body; - MethodHeader methodHeader; - trainscript::Instruction *instruction; - LocalVariable *local; - ExpressionList *expressions; - -#line 117 "trainscript/trainscript.tab.hpp" /* yacc.c:1909 */ -}; - -typedef union YYSTYPE YYSTYPE; -# define YYSTYPE_IS_TRIVIAL 1 -# define YYSTYPE_IS_DECLARED 1 -#endif - - - -int yyparse (ParserData * context); - -#endif /* !YY_YY_TRAINSCRIPT_TRAINSCRIPT_TAB_HPP_INCLUDED */ diff --git a/trainscript/trainscript.y b/trainscript/trainscript.y index 8dd848e..5846c7d 100644 --- a/trainscript/trainscript.y +++ b/trainscript/trainscript.y @@ -1,6 +1,7 @@ %{ #include #include +#include #include "common.h" diff --git a/trainscript/tsvm.cpp b/trainscript/tsvm.cpp index ed84a82..83f069d 100644 --- a/trainscript/tsvm.cpp +++ b/trainscript/tsvm.cpp @@ -10,8 +10,6 @@ namespace trainscript { - bool verbose = false; - const Type Type::Invalid = { TypeID::Invalid, 0 }; const Type Type::Void = { TypeID::Void, 0 }; const Type Type::Int = { TypeID::Int, 0 }; @@ -94,7 +92,7 @@ namespace trainscript Variable ScriptMethod::invoke(ker::Vector arguments) { - LocalContext context(this->module); + ExecutionContext context(this->module); ker::Vector temporaries; @@ -143,7 +141,7 @@ namespace trainscript return false; } - LocalContext context(this->module); + ExecutionContext context(this->module); for(auto var : this->module->variables) { diff --git a/trainscript/tsvm.hpp b/trainscript/tsvm.hpp index f92d9b3..37326b8 100644 --- a/trainscript/tsvm.hpp +++ b/trainscript/tsvm.hpp @@ -1,644 +1,6 @@ #pragma once -extern "C" { -#include -#include -} - -#include -#include -#include - -#include "typeid.hpp" - -namespace trainscript -{ - using Int = int32_t; - using Real = float; - using Void = void; - using Bool = bool; - - extern bool verbose; - - struct Text - { - size_t length; - char *data; - }; - - struct Type - { - TypeID id; - int pointer; - - Type reference() const { - return { id, pointer + 1 }; - } - - Type dereference() const { - return { id, pointer - 1 }; - } - - bool usable() const { - return (this->id != TypeID::Invalid) && - ((this->id != TypeID::Void) || (this->pointer > 0)); - } - - bool operator ==(const Type &other) const { - return (this->id == other.id) && - (this->pointer == other.pointer); - } - - bool operator !=(const Type &other) const { - return (this->id != other.id) || - (this->pointer != other.pointer); - } - - const char *name() const { - switch(id) { - case TypeID::Invalid: return "INVALID"; - case TypeID::Void: return "VOID"; - case TypeID::Int: return "INT"; - case TypeID::Real: return "REAL"; - case TypeID::Text: return "TEXT"; - case TypeID::Bool: return "BOOL"; - default: return "unknown"; - } - } - - static const Type Invalid; - static const Type Void; - static const Type Int; - static const Type Real; - static const Type Text; - static const Type Boolean; - }; - - struct Variable - { - Type type; - union { - Int integer; - Real real; - Text text; - Bool boolean; - }; - - void printval() const - { - switch(this->type.id) { - case TypeID::Int: kprintf("%d", this->integer); break; - case TypeID::Real: kprintf("%f", this->real); break; - case TypeID::Bool: kprintf("%s", this->boolean ? "TRUE" : "FALSE"); break; - default: kprintf("???"); break; - } - } - - static const Variable Invalid; - static const Variable Void; - static const Variable Int; - static const Variable Real; - static const Variable Text; - static const Variable Boolean; - }; - - static inline Variable mkvar(Int value) { - Variable v = Variable::Int; - v.integer = value; - return v; - } - - static inline Variable mkvar(Real value) { - Variable v = Variable::Real; - v.real = value; - return v; - } - - static inline Variable mkbool(Bool value) { - Variable v = Variable::Boolean; - v.boolean = value; - return v; - } - - class Module; - - class LocalContext : - public ker::Dictionary - { - public: - Module * const module = nullptr; - - LocalContext(Module *mod) : - ker::Dictionary(), - module(mod) - { - - } - - Variable *get(const ker::String &name) - { - if(this->contains(name)) { - return this->at(name); - } else { - return nullptr; - } - } - }; - - class Instruction - { - public: - virtual ~Instruction() { } - - virtual Variable execute(LocalContext &context) const = 0; - - virtual Type expectedResult(LocalContext &) const { - return Type::Void; - } - - virtual bool validate(LocalContext &, ker::String &errorCode) const { - errorCode = ""; - return true; - } - }; - - class Block : - public Instruction - { - public: - ker::Vector instructions; - - ~Block() { - for(auto *instr : instructions) delete instr; - } - - bool validate(LocalContext &context, ker::String &errorCode) const { - errorCode = ""; - for(auto *instr : instructions) { - if(instr->validate(context, errorCode) == false) - return false; - } - return true; - } - - Variable execute(LocalContext &context) const override { - for(auto *instr : instructions) { - instr->execute(context); - } - return Variable::Void; - } - }; - - class Method - { - public: - virtual ~Method() { } - - virtual Variable invoke(ker::Vector arguments) = 0; - - virtual bool validate(ker::String &errorCode) const = 0; - - virtual ker::Vector arguments() const = 0; - - virtual Type returnType() const = 0; - }; - - class ScriptMethod : - public Method - { - public: - Module *module; - Instruction *block; - bool isPublic; - ker::Vector> mArguments; - ker::Dictionary mLocals; - ker::Pair mReturnValue; - - ScriptMethod(Module *module, Instruction *block) : module(module), block(block) - { - - } - - Variable invoke(ker::Vector arguments) override; - - bool validate(ker::String &errorCode) const override; - - ker::Vector arguments() const override - { - ker::Vector args(this->mArguments.length()); - for(size_t i = 0; i < args.length(); i++) { - args[i] = this->mArguments[i].second; - } - return args; - } - - Type returnType() const override - { - return this->mReturnValue.second; - } - }; - - class Module - { - public: - ker::Dictionary variables; - ker::Dictionary methods; - public: - Module(); - ~Module(); - - Method *method(const char *name) - { - return this->methods.get(name); - } - - Variable *variable(const char *name) - { - return this->variables.get(name); - } - - bool validate(ker::String &errorCode) const; - }; - - class VM - { - public: - static Module *load(const void *buffer, size_t length); - - static Module *load(const char *text); - }; - - - - - - // Instructions - - class ConstantExpression : - public Instruction - { - public: - Variable value; - ConstantExpression(Variable value) : value(value) { } - - Variable execute(LocalContext &) const override { - return this->value; - } - - Type expectedResult(LocalContext &) const override { - return this->value.type; - } - }; - - class VariableExpression : - public Instruction - { - public: - ker::String variableName; - VariableExpression(ker::String variableName) : variableName(variableName) { } - - Variable execute(LocalContext &context) const override { - auto *var = context.get(this->variableName); - if(var == nullptr) { - die_extra("VariableExpression.VariableNotFound", this->variableName.str()); - } - return *var; - } - - bool validate(LocalContext &context, ker::String &errorCode) const override { - errorCode = ""; - if(context.get(this->variableName) == nullptr) { - errorCode = "Variable " + this->variableName + " not found."; - return false; - } - return true; - } - - Type expectedResult(LocalContext &context) const override { - Variable *var = context.get(this->variableName); - if(var == nullptr) { - return Type::Invalid; - } else { - return var->type; - } - } - }; - - - class VariableAssignmentExpression : - public Instruction - { - public: - ker::String variableName; - Instruction *expression; - VariableAssignmentExpression(ker::String variableName, Instruction *expression) : - variableName(variableName), - expression(expression) - { - - } - - Variable execute(LocalContext &context) const override { - if(this->expression == nullptr) { - die("VariableAssignmentExpression.ExpressionMissing"); - } - Variable result = this->expression->execute(context); - - Variable *target = context.get(this->variableName); - if(target == nullptr) { - die_extra("VariableAssignmentExpression.VariableNotFound", this->variableName.str()); - } - - if(target->type != result.type) { - die_extra("VariableAssignmentExpression.ExpectedType", result.type.name()); - } - - switch(target->type.id) { - case TypeID::Int: target->integer = result.integer; break; - case TypeID::Real: target->real = result.real; break; - case TypeID::Bool: target->boolean = result.boolean; break; - default: break; - } - - return result; - } - - bool validate(LocalContext &context, ker::String &errorCode) const override { - errorCode = ""; - if(this->expression == nullptr) { - errorCode = "Missing expression."; - return false; - } - Type result = this->expression->expectedResult(context); - if(result == Type::Invalid) { - errorCode = "Expression returns invalid type."; - return false; - } - if(result == Type::Void) { - errorCode = "Void cannot be assigned to a variable"; - return false; - } - Variable *var = context.get(this->variableName); - if(var == nullptr) { - errorCode = "Variable " + this->variableName + " not found."; - return false; - } - if(var->type != result) { - errorCode = "Variable assignment has invalid type."; - return false; - } - if(this->expression->validate(context, errorCode) == false) - return false; - return true; - } - - Type expectedResult(LocalContext &context) const override { - if(this->expression == nullptr) { - return Type::Invalid; - } else { - return this->expression->expectedResult(context); - } - } - }; - - class MethodInvokeExpression : - public Instruction - { - public: - ker::String methodName; - ker::Vector parameters; - - MethodInvokeExpression(ker::String methodName) : - methodName(methodName) - { - - } - - Variable execute(LocalContext &context) const override - { - Method *method = context.module->method(this->methodName.str()); - if(method == nullptr) { - die_extra("MethodInvokeExpression.MethodNotFound", this->methodName.str()); - } - - ker::Vector vars(this->parameters.length()); - vars.resize(this->parameters.length()); - for(size_t i = 0; i < vars.length(); i++) { - vars[i] = this->parameters.at(i)->execute(context); - } - - return method->invoke(vars); - } - - bool validate(LocalContext &context, ker::String &errorCode) const override { - Method *method = context.module->method(this->methodName.str()); - if(method == nullptr) { - errorCode = "The method " + this->methodName + " does not exist."; - return false; - } - - ker::Vector arguments = method->arguments(); - if(arguments.length() != this->parameters.length()) { - errorCode = "Argument count mismatch."; - return false; - } - for(size_t i = 0; i < arguments.length(); i++) { - if(this->parameters[i]->expectedResult(context) != arguments[i]) { - errorCode = "Argument type mismatch."; - return false; - } - if(this->parameters[i]->validate(context, errorCode) == false) - return false; - } - - return true; - } - - Type expectedResult(LocalContext &context) const override { - Method *method = context.module->method(this->methodName.str()); - if(method == nullptr) { - return Type::Invalid; - } - return method->returnType(); - } - }; - - template - class ArithmeticExpression : - public Instruction - { - public: - Instruction *lhs, *rhs; - - ArithmeticExpression(Instruction *lhs, Instruction *rhs) : - lhs(lhs), - rhs(rhs) - { - - } - - Variable execute(LocalContext &context) const override { - if(this->lhs == nullptr) { - die_extra("ArithmeticExpression.ExpressionMissing", "Left-hand side"); - } - if(this->rhs == nullptr) { - die_extra("ArithmeticExpression.ExpressionMissing", "Right-hand side"); - } - - Variable left = this->lhs->execute(context); - Variable right = this->rhs->execute(context); - - if(left.type != right.type) { - die("ArithmeticExpression.TypeMismatch"); - } - - Variable result = OP(left, right); - - if(result.type.usable() == false) { - die_extra("ArithmeticExpression.InvalidResult", result.type.name()); - } - return result; - } - - bool validate(LocalContext &context, ker::String &errorCode) const override { - errorCode = ""; - if(this->lhs == nullptr) { - errorCode = "Left part of operand is missing."; - return false; - } - if(this->rhs == nullptr) { - errorCode = "Right part of operand is missing."; - return false; - } - Type lhsType = this->lhs->expectedResult(context); - Type rhsType = this->rhs->expectedResult(context); - if(lhsType != rhsType) { - errorCode = "Types of operands do not match."; - return false; - } - if(lhsType == Type::Invalid) { - errorCode = "Invalid type can't be used for operand."; - return false; - } - if(rhsType == Type::Void) { - errorCode = "VOID type can't be used for operand."; - return false; - } - - if(this->lhs->validate(context, errorCode) == false) - return false; - if(this->rhs->validate(context, errorCode) == false) - return false; - - return true; - } - - Type expectedResult(LocalContext &context) const override { - if(this->lhs == nullptr) { - return Type::Invalid; - } else { - return this->lhs->expectedResult(context); - } - } - }; - - class IfExpression : - public Instruction - { - public: - Instruction *condition; - Instruction *blockTrue; - Instruction *blockFalse; - - IfExpression(Instruction *condition, Instruction *blockTrue, Instruction *blockFalse) : - condition(condition), - blockTrue(blockTrue), - blockFalse(blockFalse) - { - - } - - Variable execute(LocalContext &context) const override { - if(this->condition == nullptr) { - die("IfExpression.ConditionMissing"); - } - - Variable result = this->condition->execute(context); - if(result.type != Type::Boolean) { - die_extra("IfExpression.TypeMismatch", result.type.name()); - } - if((result.boolean == true) && (this->blockTrue != nullptr)) { - this->blockTrue->execute(context); - } - if((result.boolean == false) && (this->blockFalse != nullptr)) { - this->blockFalse->execute(context); - } - return Variable::Void; - } - }; - - class RepeatEndlessExpression : - public Instruction - { - public: - Instruction *block; - - RepeatEndlessExpression(Instruction *block) : - block(block) - { - - } - - Variable execute(LocalContext &context) const override { - if(this->block == nullptr) { - die("RepeatEndlessExpression.BlockMissing"); - } - - while(true) - { - Variable result = this->block->execute(context); - (void)result; - } - return Variable::Void; - } - }; - - - class RepeatWhileExpression : - public Instruction - { - public: - Instruction *condition; - Instruction *block; - - RepeatWhileExpression(Instruction *condition, Instruction *block) : - condition(condition), - block(block) - { - - } - - Variable execute(LocalContext &context) const override { - if(this->condition == nullptr) { - die("RepeatWhileExpression.ConditionMissing"); - } - if(this->block == nullptr) { - die("RepeatWhileExpression.BlockMissing"); - } - - while(true) - { - Variable cond = this->condition->execute(context); - if(cond.type != Type::Boolean) { - return Variable::Invalid; - } - if(cond.boolean == false) { - break; - } - - this->block->execute(context); - } - return Variable::Void; - } - }; -} +#include "vm.hpp" +#include "method.hpp" +#include "instructions.hpp" +#include "scriptmethod.hpp" diff --git a/trainscript/type.hpp b/trainscript/type.hpp new file mode 100644 index 0000000..ca37aa5 --- /dev/null +++ b/trainscript/type.hpp @@ -0,0 +1,56 @@ +#pragma once +#include + +#include "types.hpp" +#include "typeid.hpp" + +namespace trainscript +{ + struct Type + { + TypeID id; + int pointer; + + Type reference() const { + return { id, pointer + 1 }; + } + + Type dereference() const { + return { id, pointer - 1 }; + } + + bool usable() const { + return (this->id != TypeID::Invalid) && + ((this->id != TypeID::Void) || (this->pointer > 0)); + } + + bool operator ==(const Type &other) const { + return (this->id == other.id) && + (this->pointer == other.pointer); + } + + bool operator !=(const Type &other) const { + return (this->id != other.id) || + (this->pointer != other.pointer); + } + + const char *name() const { + switch(id) { + case TypeID::Invalid: return "INVALID"; + case TypeID::Void: return "VOID"; + case TypeID::Int: return "INT"; + case TypeID::Real: return "REAL"; + case TypeID::Text: return "TEXT"; + case TypeID::Bool: return "BOOL"; + default: return "unknown"; + } + } + + static const Type Invalid; + static const Type Void; + static const Type Int; + static const Type Real; + static const Type Text; + static const Type Boolean; + }; +} diff --git a/trainscript/types.hpp b/trainscript/types.hpp new file mode 100644 index 0000000..691a046 --- /dev/null +++ b/trainscript/types.hpp @@ -0,0 +1,13 @@ +#pragma once +#include + +#include + +namespace trainscript +{ + using Int = int32_t; + using Real = float; + using Void = void; + using Bool = bool; + using Text = ker::String; +} diff --git a/trainscript/variable.hpp b/trainscript/variable.hpp new file mode 100644 index 0000000..62dbbd9 --- /dev/null +++ b/trainscript/variable.hpp @@ -0,0 +1,55 @@ +#pragma once +#include + +#include "type.hpp" + +namespace trainscript +{ + struct Variable + { + Type type; + union { + Int integer; + Real real; + // Text text; + Bool boolean; + }; + +#if defined(TSVM_PRINTVAL) + void printval() const + { + switch(this->type.id) { + case TypeID::Int: kprintf("%d", this->integer); break; + case TypeID::Real: kprintf("%f", this->real); break; + case TypeID::Bool: kprintf("%s", this->boolean ? "TRUE" : "FALSE"); break; + default: kprintf("???"); break; + } + } +#endif + + static const Variable Invalid; + static const Variable Void; + static const Variable Int; + static const Variable Real; + static const Variable Text; + static const Variable Boolean; + }; + + static inline Variable mkvar(Int value) { + Variable v = Variable::Int; + v.integer = value; + return v; + } + + static inline Variable mkvar(Real value) { + Variable v = Variable::Real; + v.real = value; + return v; + } + + static inline Variable mkbool(Bool value) { + Variable v = Variable::Boolean; + v.boolean = value; + return v; + } +} diff --git a/trainscript/vm.hpp b/trainscript/vm.hpp new file mode 100644 index 0000000..7a9a26e --- /dev/null +++ b/trainscript/vm.hpp @@ -0,0 +1,14 @@ +#pragma once +#include +#include "module.hpp" + +namespace trainscript +{ + class VM + { + public: + static Module *load(const void *buffer, size_t length); + + static Module *load(const char *text); + }; +}