Removes old trainVm from trainOs.

This commit is contained in:
Felix Queißner 2015-10-06 15:23:15 +02:00
parent bf33a7f308
commit 395e2ebb60
28 changed files with 179 additions and 2781 deletions

View file

@ -2,9 +2,6 @@
Artifact=kernel Artifact=kernel
TempDir=obj TempDir=obj
SourceDir=asm src SourceDir=asm src
Files=trainscript/trainscript.y trainscript/trainscript.l
Files=trainscript/tsvm.cpp trainscript/variable.cpp trainscript/type.cpp
Files=trainscript/type-operators.cpp.tt
AdditionalObjects=obj/main.o AdditionalObjects=obj/main.o
LexUseCpp LexUseCpp

122
Makefile
View file

@ -8,13 +8,12 @@ CXX = g++
LD = g++ LD = g++
LEX = flex LEX = flex
YACC = bison YACC = bison
TEMPLE = mono /home/felix/projects/temple/bin/Debug/temple.exe
# File Lists # File Lists
SRCS_AS = asm/dynamic.S asm/intr_common_handler.S asm/multiboot.S asm/start.S SRCS_AS = asm/dynamic.S asm/intr_common_handler.S asm/multiboot.S asm/start.S
SRCS_CC = src/console.c src/init.c src/interrupts.c src/malloc.c src/pmm.c src/serial.c src/stdlib.c src/timer.c src/vmm.c SRCS_CC = src/console.c src/init.c src/interrupts.c src/malloc.c src/pmm.c src/serial.c src/stdlib.c src/timer.c src/vmm.c
SRCS_CXX = trainscript/tsvm.cpp trainscript/variable.cpp trainscript/type.cpp src/cplusplus.cpp src/vm.cpp obj/trainscript.yy.cpp obj/trainscript.tab.cpp obj/type-operators.cpp SRCS_CXX = src/cplusplus.cpp src/cpp-test.cpp src/vm.cpp
OBJS = obj/tsvm.o obj/variable.o obj/type.o obj/dynamic.o obj/intr_common_handler.o obj/multiboot.o obj/start.o obj/console.o obj/init.o obj/interrupts.o obj/malloc.o obj/pmm.o obj/serial.o obj/stdlib.o obj/timer.o obj/vmm.o obj/cplusplus.o obj/vm.o obj/trainscript.yy.o obj/trainscript.tab.o obj/type-operators.o obj/main.o OBJS = obj/dynamic.o obj/intr_common_handler.o obj/multiboot.o obj/start.o obj/console.o obj/init.o obj/interrupts.o obj/malloc.o obj/pmm.o obj/serial.o obj/stdlib.o obj/timer.o obj/vmm.o obj/cplusplus.o obj/cpp-test.o obj/vm.o obj/main.o
# Flags # Flags
FLAGS = -m32 -Dnullptr=0 -D__cdecl="__attribute__((cdecl))" -mno-sse -mno-sse2 -mno-mmx FLAGS = -m32 -Dnullptr=0 -D__cdecl="__attribute__((cdecl))" -mno-sse -mno-sse2 -mno-mmx
@ -28,142 +27,78 @@ all: kernel
.PHONY: clean .PHONY: clean
clean: clean:
$(RM) obj/trainscript.yy.cpp obj/trainscript.tab.cpp obj/type-operators.cpp obj/tsvm.o obj/variable.o obj/type.o obj/dynamic.o obj/intr_common_handler.o obj/multiboot.o obj/start.o obj/console.o obj/init.o obj/interrupts.o obj/malloc.o obj/pmm.o obj/serial.o obj/stdlib.o obj/timer.o obj/vmm.o obj/cplusplus.o obj/vm.o obj/trainscript.yy.o obj/trainscript.tab.o obj/type-operators.o obj/main.o $(RM) obj/dynamic.o obj/intr_common_handler.o obj/multiboot.o obj/start.o obj/console.o obj/init.o obj/interrupts.o obj/malloc.o obj/pmm.o obj/serial.o obj/stdlib.o obj/timer.o obj/vmm.o obj/cplusplus.o obj/cpp-test.o obj/vm.o obj/main.o
kernel: obj/tsvm.o obj/variable.o obj/type.o obj/dynamic.o obj/intr_common_handler.o obj/multiboot.o obj/start.o obj/console.o obj/init.o obj/interrupts.o obj/malloc.o obj/pmm.o obj/serial.o obj/stdlib.o obj/timer.o obj/vmm.o obj/cplusplus.o obj/vm.o obj/trainscript.yy.o obj/trainscript.tab.o obj/type-operators.o obj/main.o kernel: obj/dynamic.o obj/intr_common_handler.o obj/multiboot.o obj/start.o obj/console.o obj/init.o obj/interrupts.o obj/malloc.o obj/pmm.o obj/serial.o obj/stdlib.o obj/timer.o obj/vmm.o obj/cplusplus.o obj/cpp-test.o obj/vm.o obj/main.o
$(LD) $(FLAGS) $(LDFLAGS) -o $@ obj/tsvm.o obj/variable.o obj/type.o obj/dynamic.o obj/intr_common_handler.o obj/multiboot.o obj/start.o obj/console.o obj/init.o obj/interrupts.o obj/malloc.o obj/pmm.o obj/serial.o obj/stdlib.o obj/timer.o obj/vmm.o obj/cplusplus.o obj/vm.o obj/trainscript.yy.o obj/trainscript.tab.o obj/type-operators.o obj/main.o $(LD) $(FLAGS) $(LDFLAGS) -o $@ obj/dynamic.o obj/intr_common_handler.o obj/multiboot.o obj/start.o obj/console.o obj/init.o obj/interrupts.o obj/malloc.o obj/pmm.o obj/serial.o obj/stdlib.o obj/timer.o obj/vmm.o obj/cplusplus.o obj/cpp-test.o obj/vm.o obj/main.o
# src/console.c # src/console.c
obj/console.o: src/console.c include/console.h include/stdlib.h \ obj/console.o: src/console.c include/console.h include/stdlib.h \
include/varargs.h include/config.h include/malloc.h include/varargs.h include/config.h include/malloc.h
$(CC) -iquoteobj $(FLAGS) $(CCFLAGS) -o $@ -c src/console.c $(CC) $(FLAGS) $(CCFLAGS) -o $@ -c src/console.c
# src/init.c # src/init.c
obj/init.o: src/init.c include/kernel.h include/stdlib.h include/varargs.h \ 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/config.h include/malloc.h include/console.h include/interrupts.h \
include/cpustate.h include/pmm.h include/multiboot.h include/vmm.h \ include/cpustate.h include/pmm.h include/multiboot.h include/vmm.h \
include/timer.h include/serial.h include/timer.h include/serial.h
$(CC) -iquoteobj $(FLAGS) $(CCFLAGS) -o $@ -c src/init.c $(CC) $(FLAGS) $(CCFLAGS) -o $@ -c src/init.c
# src/interrupts.c # src/interrupts.c
obj/interrupts.o: src/interrupts.c include/interrupts.h include/cpustate.h \ 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/console.h include/stdlib.h include/varargs.h include/config.h \
include/malloc.h include/io.h src/intr_stubs.h include/malloc.h include/io.h src/intr_stubs.h
$(CC) -iquoteobj $(FLAGS) $(CCFLAGS) -o $@ -c src/interrupts.c $(CC) $(FLAGS) $(CCFLAGS) -o $@ -c src/interrupts.c
# src/malloc.c # src/malloc.c
obj/malloc.o: src/malloc.c include/kernel.h include/stdlib.h \ 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/varargs.h include/config.h include/malloc.h include/console.h \
include/serial.h include/serial.h
$(CC) -iquoteobj $(FLAGS) $(CCFLAGS) -o $@ -c src/malloc.c $(CC) $(FLAGS) $(CCFLAGS) -o $@ -c src/malloc.c
# src/pmm.c # src/pmm.c
obj/pmm.o: src/pmm.c include/pmm.h include/multiboot.h include/kernel.h \ 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/stdlib.h include/varargs.h include/config.h include/malloc.h \
include/console.h include/console.h
$(CC) -iquoteobj $(FLAGS) $(CCFLAGS) -o $@ -c src/pmm.c $(CC) $(FLAGS) $(CCFLAGS) -o $@ -c src/pmm.c
# src/serial.c # src/serial.c
obj/serial.o: src/serial.c include/io.h include/serial.h include/stdlib.h \ obj/serial.o: src/serial.c include/io.h include/serial.h include/stdlib.h \
include/varargs.h include/config.h include/malloc.h include/varargs.h include/config.h include/malloc.h
$(CC) -iquoteobj $(FLAGS) $(CCFLAGS) -o $@ -c src/serial.c $(CC) $(FLAGS) $(CCFLAGS) -o $@ -c src/serial.c
# src/stdlib.c # src/stdlib.c
obj/stdlib.o: src/stdlib.c include/stdlib.h include/varargs.h \ obj/stdlib.o: src/stdlib.c include/stdlib.h include/varargs.h \
include/config.h include/malloc.h include/kernel.h include/config.h include/malloc.h include/kernel.h
$(CC) -iquoteobj $(FLAGS) $(CCFLAGS) -o $@ -c src/stdlib.c $(CC) $(FLAGS) $(CCFLAGS) -o $@ -c src/stdlib.c
# src/timer.c # src/timer.c
obj/timer.o: src/timer.c include/timer.h include/kernel.h \ obj/timer.o: src/timer.c include/timer.h include/kernel.h \
include/interrupts.h include/cpustate.h include/interrupts.h include/cpustate.h
$(CC) -iquoteobj $(FLAGS) $(CCFLAGS) -o $@ -c src/timer.c $(CC) $(FLAGS) $(CCFLAGS) -o $@ -c src/timer.c
# src/vmm.c # src/vmm.c
obj/vmm.o: src/vmm.c include/config.h include/vmm.h include/pmm.h \ 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/multiboot.h include/stdlib.h include/varargs.h include/malloc.h \
include/console.h include/kernel.h include/console.h include/kernel.h
$(CC) -iquoteobj $(FLAGS) $(CCFLAGS) -o $@ -c src/vmm.c $(CC) $(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 \
include/ker/vector.hpp include/ker/new.hpp include/ker/dictionary.hpp \
include/kernel.h include/ker/pair.hpp trainscript/tsvm.hpp \
trainscript/vm.hpp trainscript/module.hpp include/ker/string.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
# trainscript/variable.cpp
obj/variable.o: trainscript/variable.cpp include/kernel.h include/console.h \
trainscript/variable.hpp include/ker/string.hpp include/stdlib.h \
include/varargs.h include/config.h include/malloc.h trainscript/type.hpp \
trainscript/types.hpp trainscript/typeid.hpp
$(CXX) -iquoteobj $(FLAGS) $(CXXFLAGS) -o $@ -c trainscript/variable.cpp
# trainscript/type.cpp
obj/type.o: trainscript/type.cpp include/kernel.h include/console.h \
trainscript/type.hpp trainscript/types.hpp include/ker/string.hpp \
include/stdlib.h include/varargs.h include/config.h include/malloc.h \
trainscript/typeid.hpp trainscript/variable.hpp
$(CXX) -iquoteobj $(FLAGS) $(CXXFLAGS) -o $@ -c trainscript/type.cpp
# src/cplusplus.cpp # src/cplusplus.cpp
obj/cplusplus.o: src/cplusplus.cpp include/stdlib.h include/varargs.h \ 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 include/config.h include/malloc.h include/console.h include/ker/new.hpp
$(CXX) -iquoteobj $(FLAGS) $(CXXFLAGS) -o $@ -c src/cplusplus.cpp $(CXX) $(FLAGS) $(CXXFLAGS) -o $@ -c src/cplusplus.cpp
# src/cpp-test.cpp
obj/cpp-test.o: src/cpp-test.cpp include/console.h include/ker/string.hpp \
include/stdlib.h include/varargs.h include/config.h include/malloc.h \
include/ker/vector.hpp include/ker/new.hpp include/ker/dictionary.hpp \
include/kernel.h include/ker/pair.hpp
$(CXX) $(FLAGS) $(CXXFLAGS) -o $@ -c src/cpp-test.cpp
# src/vm.cpp # src/vm.cpp
obj/vm.o: src/vm.cpp include/stdlib.h include/varargs.h include/config.h \ obj/vm.o: src/vm.cpp include/stdlib.h include/varargs.h include/config.h \
include/malloc.h include/timer.h include/dynamic.h include/console.h \ include/malloc.h include/timer.h include/dynamic.h include/console.h
src/../trainscript/tsvm.hpp src/../trainscript/vm.hpp \ $(CXX) $(FLAGS) $(CXXFLAGS) -o $@ -c src/vm.cpp
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 include/ker/vector.hpp include/ker/new.hpp \
include/ker/dictionary.hpp include/kernel.h include/ker/pair.hpp \
trainscript/tsvm.hpp trainscript/vm.hpp trainscript/module.hpp \
include/ker/string.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 include/console.h \
trainscript/common.h include/ker/vector.hpp include/ker/new.hpp \
include/ker/dictionary.hpp include/kernel.h include/ker/pair.hpp \
trainscript/tsvm.hpp trainscript/vm.hpp trainscript/module.hpp \
include/ker/string.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 -iquoteobj $(FLAGS) $(CXXFLAGS) -o $@ -c obj/trainscript.tab.cpp
# obj/type-operators.cpp
obj/type-operators.o: obj/type-operators.cpp include/kernel.h \
include/console.h trainscript/type.hpp trainscript/types.hpp \
include/ker/string.hpp include/stdlib.h include/varargs.h \
include/config.h include/malloc.h trainscript/typeid.hpp \
trainscript/variable.hpp
$(CXX) -iquotetrainscript -iquoteobj $(FLAGS) $(CXXFLAGS) -o $@ -c obj/type-operators.cpp
# asm/dynamic.S # asm/dynamic.S
obj/dynamic.o: asm/dynamic.S obj/dynamic.o: asm/dynamic.S
@ -181,15 +116,6 @@ obj/multiboot.o: asm/multiboot.S
obj/start.o: asm/start.S obj/start.o: asm/start.S
$(AS) $(FLAGS) $(ASFLAGS) -o $@ -c asm/start.S $(AS) $(FLAGS) $(ASFLAGS) -o $@ -c asm/start.S
obj/trainscript.yy.cpp: trainscript/trainscript.l
$(LEX) --header-file=trainscript/trainscript.l.h -o obj/trainscript.yy.cpp -d trainscript/trainscript.l
obj/trainscript.tab.cpp: trainscript/trainscript.y
$(YACC) -o obj/trainscript.tab.cpp -d trainscript/trainscript.y
obj/type-operators.cpp: trainscript/type-operators.cpp.tt
$(TEMPLE) trainscript/type-operators.cpp.tt obj/type-operators.cpp
# Custom Targets # Custom Targets
obj/main.o: scripts/main.ts obj/main.o: scripts/main.ts
objcopy -B i386 -I binary -O elf32-i386 \ objcopy -B i386 -I binary -O elf32-i386 \

147
src/cpp-test.cpp Normal file
View file

@ -0,0 +1,147 @@
#include "console.h"
#include <ker/string.hpp>
#include <ker/vector.hpp>
#include <ker/dictionary.hpp>
using namespace ker;
String strfn()
{
return String("keks");
}
void put(Vector<int> &v)
{
kprintf("v[%d]: ", v.length());
for(int i : v) { kprintf("%d,", i); }
kprintf("\n");
}
void put(Vector<String> &v)
{
kprintf("v[%d]: ", v.length());
for(String &s : v) { kprintf("[%s],", s.str()); }
kprintf("\n");
}
void put(Dictionary<int, int> &d)
{
kprintf("dict: ");
for(auto &it : d)
{
kprintf("[%d -> %d] ", it.first, it.second);
}
kprintf("\n");
}
void put(Dictionary<String, String> &d)
{
kprintf("dict: ");
for(auto &it : d)
{
kprintf("[%s -> %s] ", it.first.str(), it.second.str());
}
kprintf("\n");
}
void cpp_test()
{
kprintf("Testing ker::String:\n");
{
String a("hello");
String b(a);
String c;
String d(strfn());
String e;
c = a;
e = strfn();
kprintf("'%s' '%s' '%s' '%s' '%s'\n", a.str(), b.str(), c.str(), d.str(), e.str());
}
kprintf("Testing ker::Pair:\n");
{
Pair<int, int> a(10, 20);
Pair<String, String> b("Hey", "Affe");
Pair<int, int> c(a);
Pair<String, String> d(b);
Pair<int, int> e; e = a;
Pair<String, String> f; f = b;
kprintf("'%d,%d' '%d,%d' '%d,%d'\n", a.first, a.second, c.first, c.second, e.first, e.second);
kprintf("'%s,%s' '%s,%s' '%s,%s'\n", b.first.str(), b.second.str(), d.first.str(), d.second.str(), f.first.str(), f.second.str());
}
kprintf("Testing ker::Vector:\n");
{
Vector<int> a;
a.append(1);
a.append(2);
a.append(3);
Vector<int> c;
Vector<int> b(a);
c = a;
put(a);
put(b);
put(c);
}
{
Vector<String> a;
a.append("x");
a.append("y");
a.append("z");
Vector<String> c;
Vector<String> b(a);
c = a;
put(a);
put(b);
put(c);
}
kprintf("Testing ker::Dictionary:\n");
{
kprintf("int -> int\n");
Dictionary<int, int> a;
a.add(1, 30);
a.add(2, 20);
a.add(3, 10);
kprintf("%d %d\n", a.contains(1), a.contains(4));
kprintf("%d %d\n", a.at(1), a.at(3));
kprintf("%d %d\n", a[1], a[3]);
Dictionary<int, int> b(a);
Dictionary<int, int> c;
c = a;
put(a);
put(b);
put(c);
}
{
kprintf("String -> String\n");
Dictionary<String, String> a;
a.add("x", "30");
a.add("y", "20");
a.add("z", "10");
kprintf("%d %d\n", a.contains("x"), a.contains("w"));
kprintf("%s %s\n", a.at("x").str(), a.at("z").str());
kprintf("%s %s\n", a["x"].str(), a["z"].str());
Dictionary<String, String> b(a);
Dictionary<String, String> c;
c = a;
put(a);
put(b);
put(c);
}
}

View file

@ -2,10 +2,6 @@
#include <timer.h> #include <timer.h>
#include <dynamic.h> #include <dynamic.h>
#include <console.h> #include <console.h>
#include "../trainscript/tsvm.hpp"
using namespace ker;
using namespace trainscript;
extern "C" { extern "C" {
extern const char mainscript_start; extern const char mainscript_start;
@ -13,173 +9,6 @@ extern "C" {
extern const char mainscript_size; extern const char mainscript_size;
} }
void cpp_test();
class NativeMethod :
public Method
{
private:
void *function;
ker::Vector<Type> parameters;
public:
NativeMethod(const char *arguments, void *fn) :
function(fn)
{
Type *current = nullptr;
while(*arguments) {
switch(*arguments) {
case '*':
if(current == nullptr) die("NativeMethod.ctor.InvalidPointerSpec");
current->pointer++;
break;
case 'i':
current = &this->parameters.append(Type::Int);
break;
case 'r':
current = &this->parameters.append(Type::Real);
break;
case 't':
current = &this->parameters.append(Type::Text);
break;
default:
die("NativeMethod.ctor.InvalidArgumentList");
}
arguments++;
}
}
Variable invoke(Vector<Variable> arguments) override;
bool validate(ker::String &errorCode) const
{
if(this->function == nullptr) {
errorCode = "Native method with nullptr interface.";
return false;
}
return true;
}
Vector<Type> arguments() const {
return this->parameters;
}
Type returnType() const {
return Type::Int;
}
};
/**
* @brief Invokes a cdecl function
* @param arguments Arguments passed to the c function
* @return uint32_t return value of the c function
*/
Variable NativeMethod::invoke(Vector<Variable> arguments)
{
if(this->function == nullptr) {
return Variable::Invalid;
}
// Copy arguments
size_t stackSize = 0;
for(size_t i = 0; i < arguments.length(); i++) {
if(arguments[i].type() != this->parameters[i]) {
die_extra("NativeMethod.InvalidArgumentType", arguments[i].type().name());
}
// Special case TEXT: Copy const char * instead of object
if(arguments[i].type() == Type::Text) {
stackSize += sizeof(const char *);
} else {
stackSize += arguments[i].type().size();
}
}
uint8_t *stack = (uint8_t*)malloc(stackSize);
uint8_t *stackPtr = stack;
for(size_t i = 0; i < arguments.length(); i++) {
size_t size = arguments[i].type().size();
void *data = arguments[i].data();
if(arguments[i].type() == Type::Text) {
// Copy const char *
const char *text = arguments[i].value<Text>();
memcpy(stackPtr, &text, sizeof(const char *));
stackPtr += sizeof(const char *);
}
else {
if(size > 0) {
memcpy(stackPtr, data, size);
stackPtr += size;
}
}
}
dynamic_call(this->function, stack, stackSize);
free(stack);
return Type::Int.createInstance();
}
extern "C" void __cdecl printInt(int i) {
kprintf("{%d}\n", i);
}
extern "C" void __cdecl print2Int(int a, int b) {
kprintf("{%d;%d}\n", a, b);
}
extern "C" void __cdecl printStr(const char *text) {
kprintf("{%s}", text);
}
struct NativeModuleDef
{
const char *name;
const char *signature;
void *function;
};
NativeModuleDef consoleModule[] = {
{ "printInt", "i", (void*)printInt },
{ "printStr", "t", (void*)printStr },
{ "print2Int", "ii", (void*)print2Int },
{ 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 {
@ -190,184 +19,8 @@ extern "C" void vm_start()
(uint32_t)&mainscript_size (uint32_t)&mainscript_size
}; };
// cpp_test(); (void)mainfile;
kprintf("Parse kernel module: "); kprintf("No implementation of Conductance here yet.\n");
KernelVM vm;
Module *module = vm.load(mainfile.ptr, mainfile.size);
if(module == nullptr) {
kprintf("Could not load module :(\n");
return;
}
kprintf("Module successfully loaded :)\n");
String errorCode;
if(module->validate(errorCode) == false) {
kprintf("Module validation failed: \x12\x06%s\x12\x07\n", errorCode.str());
return;
}
Method *main = module->method("main");
if(main == nullptr) {
kprintf("Script has no main method.\n");
return;
}
main->invoke({ });
for(auto &pair : module->variables) {
kprintf("%s : %s -> %s\n",
pair.first.str(),
pair.second->type().name(),
pair.second->toString().str());
}
delete module;
} }
String strfn()
{
return String("keks");
}
void put(Vector<int> &v)
{
kprintf("v[%d]: ", v.length());
for(int i : v) { kprintf("%d,", i); }
kprintf("\n");
}
void put(Vector<String> &v)
{
kprintf("v[%d]: ", v.length());
for(String &s : v) { kprintf("[%s],", s.str()); }
kprintf("\n");
}
void put(Dictionary<int, int> &d)
{
kprintf("dict: ");
for(auto &it : d)
{
kprintf("[%d -> %d] ", it.first, it.second);
}
kprintf("\n");
}
void put(Dictionary<String, String> &d)
{
kprintf("dict: ");
for(auto &it : d)
{
kprintf("[%s -> %s] ", it.first.str(), it.second.str());
}
kprintf("\n");
}
void cpp_test()
{
kprintf("Testing ker::String:\n");
{
String a("hello");
String b(a);
String c;
String d(strfn());
String e;
c = a;
e = strfn();
kprintf("'%s' '%s' '%s' '%s' '%s'\n", a.str(), b.str(), c.str(), d.str(), e.str());
}
kprintf("Testing ker::Pair:\n");
{
Pair<int, int> a(10, 20);
Pair<String, String> b("Hey", "Affe");
Pair<int, int> c(a);
Pair<String, String> d(b);
Pair<int, int> e; e = a;
Pair<String, String> f; f = b;
kprintf("'%d,%d' '%d,%d' '%d,%d'\n", a.first, a.second, c.first, c.second, e.first, e.second);
kprintf("'%s,%s' '%s,%s' '%s,%s'\n", b.first.str(), b.second.str(), d.first.str(), d.second.str(), f.first.str(), f.second.str());
}
kprintf("Testing ker::Vector:\n");
{
Vector<int> a;
a.append(1);
a.append(2);
a.append(3);
Vector<int> c;
Vector<int> b(a);
c = a;
put(a);
put(b);
put(c);
}
{
Vector<String> a;
a.append("x");
a.append("y");
a.append("z");
Vector<String> c;
Vector<String> b(a);
c = a;
put(a);
put(b);
put(c);
}
kprintf("Testing ker::Dictionary:\n");
{
kprintf("int -> int\n");
Dictionary<int, int> a;
a.add(1, 30);
a.add(2, 20);
a.add(3, 10);
kprintf("%d %d\n", a.contains(1), a.contains(4));
kprintf("%d %d\n", a.at(1), a.at(3));
kprintf("%d %d\n", a[1], a[3]);
Dictionary<int, int> b(a);
Dictionary<int, int> c;
c = a;
put(a);
put(b);
put(c);
}
{
kprintf("String -> String\n");
Dictionary<String, String> a;
a.add("x", "30");
a.add("y", "20");
a.add("z", "10");
kprintf("%d %d\n", a.contains("x"), a.contains("w"));
kprintf("%s %s\n", a.at("x").str(), a.at("z").str());
kprintf("%s %s\n", a["x"].str(), a["z"].str());
Dictionary<String, String> b(a);
Dictionary<String, String> c;
c = a;
put(a);
put(b);
put(c);
}
}

View file

@ -10,15 +10,12 @@ SOURCES += \
src/malloc.c \ src/malloc.c \
src/pmm.c \ src/pmm.c \
src/stdlib.c \ src/stdlib.c \
src/vmm.c \ src/vmm.c \
trainscript/tsvm.cpp \
trainscript/main.cpp \
src/timer.c \ src/timer.c \
src/cplusplus.cpp \ src/cplusplus.cpp \
src/vm.cpp \ src/vm.cpp \
src/serial.c \ src/serial.c \
trainscript/variable.cpp \ src/cpp-test.cpp
trainscript/type.cpp
HEADERS += \ HEADERS += \
include/console.h \ include/console.h \
@ -32,9 +29,6 @@ HEADERS += \
include/stdlib.h \ include/stdlib.h \
include/varargs.h \ include/varargs.h \
include/vmm.h \ include/vmm.h \
trainscript/common.h \
trainscript/tsvm.hpp \
trainscript/typeid.hpp \
include/timer.h \ include/timer.h \
include/ker/string.hpp \ include/ker/string.hpp \
include/ker/pair.hpp \ include/ker/pair.hpp \
@ -45,36 +39,20 @@ HEADERS += \
include/dynamic.h \ include/dynamic.h \
include/config.h \ include/config.h \
include/serial.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 += \ DISTFILES += \
asm/intr_common_handler.S \ asm/intr_common_handler.S \
asm/multiboot.S \ asm/multiboot.S \
asm/start.S \ asm/start.S \
trainscript.md \ trainscript.md \
Makefile \ Makefile \
trainscript/trainscript.l \
trainscript/file01.ts \
trainscript/Makefile \
trainscript/trainscript.y \
trainscript/file02.ts \
kernel.ld \ kernel.ld \
Depfile \ Depfile \
Makefile.new \ Makefile.new \
scripts/main.ts \ scripts/main.ts \
asm/dynamic.S \ asm/dynamic.S \
README.md \ README.md
trainscript/type-operators.cpp.tt
QMAKE_INCDIR = QMAKE_INCDIR =

View file

@ -1,34 +0,0 @@
# -fsanitize=address
CFLAGS=-g
CCFLAGS=$(CFLAGS) -std=c++11 -c
LFLAGS=$(CFLAGS) -o tsvm
LEX=flex
YACC=bison
all: trainscript.tab.o lex.yy.o tsvm.o main.o
g++ $(LFLAGS) lex.yy.o trainscript.tab.o tsvm.o main.o
main.o: main.cpp tsvm.hpp common.h
g++ $(CCFLAGS) -c main.cpp -o main.o
tsvm.o: tsvm.cpp tsvm.hpp common.h
g++ $(CCFLAGS) -c tsvm.cpp -o tsvm.o
lex.yy.o: lexyy.cpp tsvm.hpp common.h
g++ $(CCFLAGS) -c lex.yy.cpp -o lex.yy.o
trainscript.tab.o: lex.yy.cpp trainscript_tab.cpp tsvm.hpp common.h
g++ $(CCFLAGS) -c trainscript.tab.cpp -o trainscript.tab.o
lex.yy.cpp: trainscript.l
$(LEX) --header-file=trainscript.l.h trainscript.l
mv lex.yy.c lex.yy.cpp
trainscript.tab.cpp: trainscript.y
$(YACC) -d trainscript.y
mv trainscript.tab.c trainscript.tab.cpp
.PHONY: clean
clean:
rm *.o trainscript.tab.cpp trainscript.l.h lex.yy.cpp

View file

@ -1,98 +0,0 @@
#pragma once
#include <stddef.h>
#include <inttypes.h>
#include <ker/vector.hpp>
#include <ker/dictionary.hpp>
#include "tsvm.hpp"
#define ECHO do { } while(0)
void yyerror(void *scanner, const char *s);
#define YY_EXTRA_TYPE ParserData*
#define YY_INPUT(buf,result,max_size) \
{ \
if(yyextra->index >= yyextra->length) \
result = YY_NULL; \
else { \
buf[0] = yyextra->buffer[yyextra->index++]; \
result = 1; \
} \
}
struct ParserData
{
char *buffer;
size_t index;
size_t length;
trainscript::Module *module;
void *scanner;
ker::Vector<char*> strings;
ker::Dictionary<ker::String, ker::String> objects;
char *strdup(const char *str)
{
for(size_t i = 0; i < this->strings.length(); i++) {
if(strcmp(this->strings[i], str) == 0) {
return this->strings[i];
}
}
char *nstr = ::strdup(str);
this->strings.append(nstr);
return nstr;
}
};
struct VariableDeclaration
{
char *name;
trainscript::Type type;
};
struct ObjectDeclaration
{
char *name;
char *moduleName;
};
struct LocalVariable
{
char *name;
trainscript::Type type;
LocalVariable *next;
};
struct MethodHeader
{
bool isPublic;
char *name;
LocalVariable *returnValue;
LocalVariable *locals;
LocalVariable *arguments;
};
struct MethodBody
{
int indentation;
trainscript::Instruction *instruction;
MethodBody *next;
};
struct MethodDeclaration
{
MethodHeader header;
trainscript::Instruction *body;
};
struct ExpressionList
{
trainscript::Instruction *instruction;
ExpressionList *next;
};
// Variable declaration

View file

@ -1,34 +0,0 @@
#pragma once
#include <inttypes.h>
#include <ker/string.hpp>
#include <ker/dictionary.hpp>
#include "variable.hpp"
namespace trainscript
{
class Module;
class ExecutionContext :
public ker::Dictionary<ker::String, Variable*>
{
public:
Module * const module = nullptr;
ExecutionContext(Module *mod) :
ker::Dictionary<ker::String, Variable*>(),
module(mod)
{
}
Variable *get(const ker::String &name)
{
if(this->contains(name)) {
return this->at(name);
} else {
return nullptr;
}
}
};
}

View file

@ -1,66 +0,0 @@
VAR global : INT;
PUB main() | i : INT
BEGIN
afraid(15, 34) i;
0 -> i;
WHILE i < 5 DO
BEGIN
print(i);
i + 1 -> i;
END
print(factorial(4), fibonacci(8), problem1(10));
REPEAT
BEGIN
print(1);
sleep'(5);
END
END
# Sleep implementation
PRI sleep'(time : INT) | init : INT
BEGIN
timer_get() init;
WHILE (timer_get() - init) < time DO
0; # do nothing
END
# Calculates factorial (number!)
PRI factorial(number : INT) result : INT
BEGIN
IF number > 1 THEN
number * factorial(number - 1) result;
ELSE
1 result;
END
# Recursive test
PRI fibonacci(n : INT) f : INT
BEGIN
IF n = 0 THEN
0 f;
ELSEIF n = 1 THEN
1 f;
ELSE
fibonacci(n - 1) + fibonacci(n - 2) f;
END
# If we list all the natural numbers below 10 that are
# multiples of 3 or 5, we get 3, 5, 6 and 9. The sum of
# these multiples is 23.
# Find the sum of all the multiples of 3 or 5 below 1000.
PRI problem1(max : INT) r : INT | iter : INT
BEGIN
1 iter;
0 r;
WHILE iter < max DO
BEGIN
IF (iter % 5) = 0 THEN
r + iter r;
ELSEIF (iter % 3) = 0 THEN
r + iter r;
iter + 1 iter;
END
END

View file

@ -1,38 +0,0 @@
# Trainscript Test File
VAR v1' : REAL;
VAR v2' : REAL;
# Execute some stuff
PUB main(x : INT) c : INT
physics();
factorial(2);
42 c;
# Physics exercise with elastic collision
PRI physics() | m1:REAL, v1:REAL, m2:REAL, v2:REAL
# Wagen 1
4.0 m1;
1.2 v1;
# Wagen 2
5.0 m2;
0.6 v2;
(((m1 - m2) * v1) + (2. * m2 * v2)) / (m1 + m2) v1';
(((m2 - m1) * v2) + (2. * m1 * v1)) / (m1 + m2) v2';
# Recursive test
PUB fibonacci(n : INT) f : INT
#IF n = 0
0 f;
#ELSEIF n = 1
1 f;
#ELSE
fibonacci(n - 1) + fibonacci(n - 2) f;
PUB factorial(number : INT) result : INT
#IF number <= 1
1 result;
#ELSE
number * factorial(number - 1) result;

View file

@ -1,24 +0,0 @@
#pragma once
#include <inttypes.h>
#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;
}
};
}

View file

@ -1,567 +0,0 @@
#pragma once
#include <stdlib.h>
#include "module.hpp"
#include "method.hpp"
#include "instruction.hpp"
namespace trainscript
{
class Block :
public Instruction
{
public:
ker::Vector<Instruction*> 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(const 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 VariableRefExpression :
public Instruction
{
public:
ker::String variableName;
VariableRefExpression(ker::String variableName) : variableName(variableName) { }
Variable execute(ExecutionContext &context) const override {
auto *var = context.get(this->variableName);
if(var == nullptr) {
die_extra("VariableRefExpression.VariableNotFound", this->variableName.str());
}
Variable ref = var->type().reference().createInstance();
ref.value<void*>() = var->data();
return ref;
}
bool validate(ExecutionContext &context, ker::String &errorCode) const override {
errorCode = "";
Variable *var = context.get(this->variableName);
if(var == 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().reference();
}
}
};
class PointerValExpression :
public Instruction
{
public:
Instruction *expression;
PointerValExpression(Instruction *expression) :
expression(expression) { }
Variable execute(ExecutionContext &context) const override {
Variable result = this->expression->execute(context);
if(result.type().pointer == 0) {
die_extra("PointerValExpression.InvalidType", "Cannot dereference non-pointer type");
}
Variable ref = result.type().dereference().createInstance();
// Some hacky variable assignment
Variable tmp(ref); // use temporary variable for copying data
void *buf = tmp.data(); // Store original pointer
tmp.setData(result.value<void*>()); // Replace original pointer for correct copy
ref = tmp; // Copy data with copy operator
tmp.setData(buf); // Reset orignal pointer for deletion
return ref;
}
bool validate(ExecutionContext &context, ker::String &errorCode) const override {
errorCode = "";
if(this->expression == nullptr) {
errorCode = "Expression missing";
return false;
}
if(this->expression->expectedResult(context).pointer == 0) {
errorCode = "Expression has non-pointer type.";
return false;
}
return true;
}
Type expectedResult(ExecutionContext &context) const override {
return this->expression->expectedResult(context).dereference();
}
};
class PointerValAssignmentExpression :
public Instruction
{
public:
Instruction *expression;
Instruction *target;
PointerValAssignmentExpression(Instruction *target, Instruction *expression) :
expression(expression),
target(target)
{ }
Variable execute(ExecutionContext &context) const override {
Variable src = this->expression->execute(context);
Variable dst = this->target->execute(context);
if(dst.type().pointer == 0) {
die_extra("PointerValAssignmentExpression.InvalidType", "Cannot dereference non-pointer type");
}
// Some hacky variable assignment
Variable tmp(src); // use temporary variable for copying data
void *buf = tmp.data(); // Store original pointer
tmp.setData(dst.value<void*>()); // Replace original pointer for correct copy
tmp = src; // Copy data with copy operator
tmp.setData(buf); // Reset orignal pointer for deletion
return src; // Return expression value
}
bool validate(ExecutionContext &context, ker::String &errorCode) const override {
errorCode = "";
if(this->expression == nullptr) {
errorCode = "Expression missing";
return false;
}
if(this->target == nullptr) {
errorCode = "Target missing";
return false;
}
Type src = this->expression->expectedResult(context);
Type dst = this->target->expectedResult(context);
if(dst.pointer == 0) {
errorCode = "Target has non-pointer type.";
return false;
}
if(dst.dereference() != src) {
errorCode = "Type mismatch.";
return false;
}
return true;
}
Type expectedResult(ExecutionContext &context) const override {
return this->expression->expectedResult(context).dereference();
}
};
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());
}
*target = result;
return *target;
}
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 moduleName;
ker::String methodName;
ker::Vector<Instruction*> parameters;
MethodInvokeExpression(const ker::String moduleName, const ker::String &methodName) :
moduleName(moduleName),
methodName(methodName)
{
}
Variable execute(ExecutionContext &context) const override
{
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) {
die_extra("MethodInvokeExpression.MethodNotFound", this->methodName.str());
}
ker::Vector<Variable> vars(this->parameters.length());
vars.resize(this->parameters.length());
for(size_t i = 0; i < vars.length(); i++) {
vars[i].replace(this->parameters.at(i)->execute(context));
}
return method->invoke(vars);
}
bool validate(ExecutionContext &context, ker::String &errorCode) const override {
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) {
errorCode = "The method " + this->methodName + " does not exist.";
return false;
}
ker::Vector<Type> 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();
}
};
class ArithmeticExpression :
public Instruction
{
public:
Operation op;
Instruction *lhs, *rhs;
ArithmeticExpression(Instruction *lhs, Instruction *rhs, Operation op) :
op(op),
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");
}
if(left.type().hasOperator(this->op) == false) {
die_extra("ArithmeticExpression.InvalidOperator", "The operator was not defined for this type.");
}
Variable result = left.type().apply(left, this->op, 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(lhsType.hasOperator(this->op) == false) {
errorCode = "The operator is not defined for this type.";
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::Bool) {
die_extra("IfExpression.TypeMismatch", result.type().name());
}
if((result.value<Bool>() == true) && (this->blockTrue != nullptr)) {
this->blockTrue->execute(context);
}
if((result.value<Bool>() == 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::Bool) {
return Variable::Invalid;
}
if(cond.value<Bool>() == false) {
break;
}
this->block->execute(context);
}
return Variable::Void;
}
};
}

View file

@ -1,84 +0,0 @@
#include "common.h"
#include "tsvm.hpp"
#include <string>
#include <fstream>
#include <vector>
using namespace std;
using namespace trainscript;
bool filedata(string name, vector<char> &buffer)
{
std::ifstream file(name.c_str(), std::ios::binary);
file.seekg(0, std::ios::end);
std::streamsize len = file.tellg();
file.seekg(0, std::ios::beg);
if(len == -1)
return false;
printf("size: %d\n", len);
buffer.resize(len);
file.read(buffer.data(), buffer.size());
return true;
}
int main(int argc, char** argv)
{
if(argc < 2) {
printf("tsvm <file>\n");
return 1;
}
vector<char> buffer;
if(filedata(argv[1], buffer) == false) {
printf("File not found\n");
return 2;
}
Module *module = VM::load(buffer.data(), buffer.size());
if(module == nullptr) {
printf("Could not compile file.\n");
return 3;
}
Method *scriptMain = module->method("main");
if(scriptMain== nullptr) {
printf("'main' method not found.\n");
return 4;
}
printf("run...\n");
Variable result = scriptMain->invoke({ mkvar(10) });
if(result.type.usable()) {
printf("done: ");
result.printval();
printf("\n");
} else {
printf("done.\n");
}
// Debug some stuff out:
for(auto &var : module->variables) {
printf("Variable: %s : %s = ",
var.first.c_str(),
typeName(var.second->type.id));
var.second->printval();
printf("\n");
}
if(result.type == Type::Int) {
return result.integer;
} else {
return 0;
}
}

View file

@ -1,22 +0,0 @@
#pragma once
#include <inttypes.h>
#include <ker/string.hpp>
#include "type.hpp"
namespace trainscript
{
class Method
{
public:
virtual ~Method() { }
virtual Variable invoke(ker::Vector<Variable> arguments) = 0;
virtual bool validate(ker::String &errorCode) const = 0;
virtual ker::Vector<Type> arguments() const = 0;
virtual Type returnType() const = 0;
};
}

View file

@ -1,38 +0,0 @@
#pragma once
#include <inttypes.h>
#include <ker/string.hpp>
#include <ker/dictionary.hpp>
#include "variable.hpp"
#include "method.hpp"
namespace trainscript
{
class Module
{
public:
ker::Dictionary<ker::String, Variable*> variables;
ker::Dictionary<ker::String, Method*> methods;
ker::Dictionary<ker::String, Module*> objects;
public:
Module();
~Module();
Module *object(const ker::String &name)
{
return this->objects.get(name);
}
Method *method(const ker::String &name)
{
return this->methods.get(name);
}
Variable *variable(const ker::String &name)
{
return this->variables.get(name);
}
bool validate(ker::String &errorCode) const;
};
}

View file

@ -1,42 +0,0 @@
#pragma once
#include "module.hpp"
#include "method.hpp"
namespace trainscript
{
class ScriptMethod :
public Method
{
public:
Module *module;
Instruction *block;
bool isPublic;
ker::Vector<ker::Pair<ker::String, Type>> mArguments;
ker::Dictionary<ker::String, Type> mLocals;
ker::Pair<ker::String, Type> mReturnValue;
ScriptMethod(Module *module, Instruction *block) : module(module), block(block)
{
}
Variable invoke(ker::Vector<Variable> arguments) override;
bool validate(ker::String &errorCode) const override;
ker::Vector<Type> arguments() const override
{
ker::Vector<Type> 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;
}
};
}

View file

@ -1,79 +0,0 @@
%{
#include <stdlib.h>
#include "common.h"
#include "trainscript.tab.hpp"
%}
%option noyywrap
%option never-interactive
%option reentrant
%option bison-bridge
%option yylineno
%x strparse
%%
\#[^\n]* ; // Eat all the comments!
[ \t]+ ; // Eat all the whitespace!
\; { return SEMICOLON; }
\: { return COLON; }
\, { return COMMA; }
\| { return PIPE; }
\( { return LBRACKET; }
\) { return RBRACKET; }
\+ { return PLUS; }
\- { return MINUS; }
\* { return MULTIPLY; }
\/ { return DIVIDE; }
\% { return MODULO; }
\-\>|→ { return RARROW; }
\<\-|← { return LARROW; }
\< { return OP_LT; }
\<\= { return OP_LE; }
\> { return OP_GT; }
\>\= { return OP_GE; }
\= { return OP_EQ; }
\≠|\=\/\= { return OP_NEQ; }
VAR { return KW_VAR; }
PUB { return KW_PUB; }
PRI { return KW_PRI; }
OBJ { return KW_OBJ; }
PTR { return KW_PTR; }
VAL { return KW_VAL; }
REF { return KW_REF; }
VOID { return KW_VOID; }
INT { return KW_INT; }
REAL { return KW_REAL; }
TEXT { return KW_TEXT; }
BOOL { return KW_BOOL; }
BEGIN { return KW_BEGIN; }
END { return KW_END; }
IF { return KW_IF; }
THEN { return KW_THEN; }
ELSE { return KW_ELSE; }
ELSEIF { return KW_ELSEIF; }
REPEAT { return KW_REPEAT; }
FROM { return KW_FROM; }
TO { return KW_TO; }
UNTIL { return KW_UNTIL; }
WHILE { return KW_WHILE; }
DO { return KW_DO; }
"\"" BEGIN(strparse);
<strparse>[^\"]* { yylval->text = yyextra->strdup(yytext); return TEXT; }
<strparse>"\"" BEGIN(INITIAL);
[0-9]+\.[0-9]* { yylval->fval = atof(yytext); return REAL; }
[0-9]+ { yylval->ival = atoi(yytext); return INT; }
[a-zA-Z0-9'_]+ { yylval->text = yyextra->strdup(yytext); return IDENTIFIER; }
\. { return DOT; }
. { yyerror(NULL, "illegal token"); }
%%
/*
\t { return TAB; }
*/

View file

@ -1,434 +0,0 @@
%{
#include <stdio.h>
#include <stdlib.h>
#include <console.h>
#include "common.h"
#include "tsvm.hpp"
using namespace trainscript;
typedef union YYSTYPE YYSTYPE;
// stuff from flex that bison needs to know about:
int yylex (YYSTYPE * yylval_param , void *yyscanner);
void yyerror(void *scanner, const char *s);
#define scanner context->scanner
%}
%pure-parser
%lex-param {void * scanner}
%parse-param {ParserData * context}
%union {
float fval;
int ival;
char *text;
int indentation;
trainscript::Type type;
VariableDeclaration varDecl;
ObjectDeclaration objDecl;
MethodDeclaration method;
MethodBody *body;
MethodHeader methodHeader;
trainscript::Instruction *instruction;
LocalVariable *local;
ExpressionList *expressions;
}
%token TAB
%token TYPENAME
%token SEMICOLON
%token COLON
%token DOT
%token COMMA
%token PIPE
%token PLUS
%token MINUS
%token MULTIPLY
%token DIVIDE
%token MODULO
%token LBRACKET
%token RBRACKET
%token RARROW
%token LARROW
%token OP_LT
%token OP_LE
%token OP_GT
%token OP_GE
%token OP_EQ
%token OP_NEQ
%token <fval> REAL
%token <ival> INT
%token <text> IDENTIFIER
%token <text> TEXT
%token KW_PUB
%token KW_PRI
%token KW_VAR
%token KW_OBJ
%token KW_PTR
%token KW_VAL
%token KW_REF
%token KW_VOID
%token KW_INT
%token KW_REAL
%token KW_TEXT
%token KW_BOOL
%token KW_BEGIN
%token KW_END
%token KW_IF
%token KW_THEN
%token KW_ELSE
%token KW_ELSEIF
%token KW_REPEAT
%token KW_FROM
%token KW_TO
%token KW_UNTIL
%token KW_WHILE
%token KW_DO
%type <type> typeName
%type <varDecl> variableDeclaration
%type <objDecl> objectDeclaration
// %type <indentation> indentation
%type <method> method
%type <methodHeader> methodDeclaration
%type <instruction> block
%type <body> body
%type <local> argument
%type <local> arguments
%type <local> argumentList
%type <local> methodLocals
%type <local> methodLocalList
%type <instruction> instruction
%type <instruction> expression
%type <instruction> condition
%type <instruction> elseIfLoop
%type <instruction> loop
%type <expressions> expressionList
%start input
%left PLUS MINUS MULTIPLY DIVIDE MODULO RARROW
%left OP_LT OP_LE OP_GT OP_GE OP_EQ OP_NEQ
%right KW_IF KW_THEN KW_ELSEIF KW_ELSE
%%
input:
%empty
| input variableDeclaration SEMICOLON {
auto *var = new Variable($2.type.createInstance());
context->module->variables.add( ker::String($2.name), var );
}
| input objectDeclaration SEMICOLON {
context->objects.add($2.name, $2.moduleName);
}
| input method {
using namespace trainscript;
auto *mod = context->module;
ScriptMethod *method = new ScriptMethod(mod, $2.body);
method->isPublic = $2.header.isPublic;
if($2.header.returnValue) {
method->mReturnValue = ker::Pair<ker::String, Type>(
$2.header.returnValue->name,
$2.header.returnValue->type);
}
LocalVariable *local = $2.header.locals;
while(local) {
method->mLocals.add( local->name, local->type );
LocalVariable *tmp = local;
local = local->next;
delete tmp;
}
LocalVariable *arg = $2.header.arguments;
while(arg) {
method->mArguments.append( { arg->name, arg->type} );
LocalVariable *tmp = local;
arg = arg->next;
delete tmp;
}
context->module->methods.add( $2.header.name, method );
}
;
method:
methodDeclaration block {
$$.header = $1;
$$.body = $2;
}
;
block:
KW_BEGIN body KW_END {
auto *block = new Block();
MethodBody *mb = $2;
while(mb) {
if(mb->instruction != nullptr) {
block->instructions.append(mb->instruction);
}
MethodBody *tmp = mb;
mb = mb->next;
delete tmp;
}
$$ = block;
}
;
body:
%empty { $$ = nullptr; }
| body instruction {
auto *body = new MethodBody();
body->indentation = 0;
body->instruction = $2;
if($1 == nullptr) {
$$ = body;
} else {
$$ = $1;
auto *it = $1;
while(it->next) { it = it->next; }
it->next = body;
}
}
;
methodDeclaration:
KW_PUB IDENTIFIER LBRACKET arguments RBRACKET methodLocals {
$$.isPublic = true;
$$.arguments = $4;
$$.locals = $6;
$$.returnValue = nullptr;
$$.name = $2;
}
| KW_PRI IDENTIFIER LBRACKET arguments RBRACKET methodLocals {
$$.isPublic = false;
$$.arguments = $4;
$$.locals = $6;
$$.returnValue = nullptr;
$$.name = $2;
}
| KW_PUB IDENTIFIER LBRACKET arguments RBRACKET RARROW argument methodLocals {
$$.isPublic = true;
$$.arguments = $4;
$$.locals = $8;
$$.returnValue = $7;
$$.name = $2;
}
| KW_PRI IDENTIFIER LBRACKET arguments RBRACKET RARROW argument methodLocals {
$$.isPublic = false;
$$.arguments = $4;
$$.locals = $8;
$$.returnValue = $7;
$$.name = $2;
}
;
methodLocals:
%empty { $$ = nullptr; }
| PIPE methodLocalList { $$ = $2; }
;
methodLocalList:
argument { $$ = $1; }
| methodLocalList COMMA argument {
auto *it = $1;
while(it->next) { it = it->next; }
it->next = $3;
$$ = $1;
}
;
arguments:
%empty { $$ = nullptr; }
| argumentList { $$ = $1; }
;
argumentList:
argument { $$ = $1; }
| argumentList COMMA argument {
auto *it = $1;
while(it->next) { it = it->next; }
it->next = $3;
$$ = $1;
}
;
argument:
IDENTIFIER COLON typeName {
$$ = new LocalVariable();
$$->name = $1;
$$->type = $3;
$$->next = nullptr;
}
;
instruction:
block { $$ = $1; }
| expression SEMICOLON { $$ = $1; }
| condition { $$ = $1; }
| loop { $$ = $1; }
;
loop:
KW_REPEAT instruction { $$ = new RepeatEndlessExpression($2); }
| KW_WHILE expression KW_DO instruction { $$ = new RepeatWhileExpression($2, $4); }
;
condition:
KW_IF expression KW_THEN instruction elseIfLoop { $$ = new IfExpression($2, $4, $5); }
;
elseIfLoop:
%empty { $$ = nullptr; }
| elseIfLoop KW_ELSEIF expression KW_THEN instruction {
if($$ == nullptr) {
$$ = new IfExpression($3, $5, nullptr);
} else {
IfExpression *exp = (IfExpression*)$1;
while(exp->blockFalse != nullptr) {
exp = (IfExpression*)exp->blockFalse;
}
exp->blockFalse = new IfExpression($3, $5, nullptr);
$$ = $1;
}
}
| elseIfLoop KW_ELSE instruction {
if($$ == nullptr) {
$$ = $3;
} else {
IfExpression *exp = (IfExpression*)$1;
while(exp->blockFalse != nullptr) {
exp = (IfExpression*)exp->blockFalse;
}
exp->blockFalse = $3;
$$ = $1;
}
}
;
expression:
INT { $$ = new ConstantExpression(Variable::fromInt($1)); }
| REAL { $$ = new ConstantExpression(Variable::fromReal($1)); }
| TEXT { $$ = new ConstantExpression(Variable::fromText($1)); }
| IDENTIFIER { $$ = new VariableExpression($1); }
| KW_REF LBRACKET IDENTIFIER RBRACKET { $$ = new VariableRefExpression($3); }
| KW_VAL LBRACKET expression RBRACKET { $$ = new PointerValExpression($3); }
| IDENTIFIER LBRACKET expressionList RBRACKET {
auto *call = new MethodInvokeExpression("", $1);
auto *list = $3;
while(list) {
call->parameters.append(list->instruction);
list = list->next;
}
$$ = 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; }
| expression PLUS expression { $$ = new ArithmeticExpression($1, $3, Operation::Add); }
| expression MINUS expression { $$ = new ArithmeticExpression($1, $3, Operation::Subtract); }
| expression MULTIPLY expression { $$ = new ArithmeticExpression($1, $3, Operation::Multiply); }
| expression DIVIDE expression { $$ = new ArithmeticExpression($1, $3, Operation::Divide); }
| expression MODULO expression { $$ = new ArithmeticExpression($1, $3, Operation::Modulo); }
| expression OP_LT expression { $$ = new ArithmeticExpression($1, $3, Operation::Less); }
| expression OP_LE expression { $$ = new ArithmeticExpression($1, $3, Operation::LessEquals); }
| expression OP_GT expression { $$ = new ArithmeticExpression($1, $3, Operation::Greater); }
| expression OP_GE expression { $$ = new ArithmeticExpression($1, $3, Operation::GreaterEquals); }
| expression OP_EQ expression { $$ = new ArithmeticExpression($1, $3, Operation::Equals); }
| expression OP_NEQ expression { $$ = new ArithmeticExpression($1, $3, Operation::Inequals); }
| expression RARROW IDENTIFIER { $$ = new VariableAssignmentExpression($3, $1); }
| expression RARROW KW_VAL LBRACKET expression RBRACKET {
$$ = new PointerValAssignmentExpression($5, $1);
}
;
expressionList:
%empty { $$ = nullptr; }
| expression {
$$ = new ExpressionList();
$$->instruction = $1;
$$->next = nullptr;
}
| expressionList COMMA expression {
auto *list = new ExpressionList();
list->instruction = $3;
list->next = nullptr;
auto *it = $1;
while(it->next) { it = it->next; }
it->next = list;
$$ = $1;
}
;
variableDeclaration:
KW_VAR IDENTIFIER COLON typeName {
$$.name = $2;
$$.type = $4;
}
;
objectDeclaration:
KW_OBJ IDENTIFIER COLON TEXT {
$$.name = $2;
$$.moduleName = $4;
}
;
typeName:
KW_VOID { $$ = Type::Void; }
| KW_INT { $$ = Type::Int; }
| KW_REAL { $$ = Type::Real; }
| KW_TEXT { $$ = Type::Text; }
| KW_BOOL { $$ = Type::Bool; }
| KW_PTR LBRACKET typeName RBRACKET { $$ = $3.reference(); }
;
%%
#undef scanner
#include "trainscript.l.h"
void yyerror(void *scanner, const char *s) {
if(scanner == nullptr) {
kprintf("Error: %s\n", s);
return;
}
int line = 0; // yyget_lineno(scanner);
int col = 0; //yyget_column(scanner);
char *text = yyget_text(scanner);
kprintf(
"[%d:%d] Error: %s at '%s'\n",
line, col,
s,
text);
}

View file

@ -1,183 +0,0 @@
#include <stdlib.h>
#include <console.h>
#include "common.h"
#include "tsvm.hpp"
#include "trainscript.tab.hpp"
#include "trainscript.l.h"
namespace trainscript
{
bool Module::validate(ker::String &errorCode) const
{
errorCode = "";
for(auto method : this->methods) {
if(method.second->validate(errorCode) == false) {
return false;
}
}
return true;
}
Module *VM::create(const ker::String &)
{
return nullptr;
}
Module *VM::load(const void *buffer, size_t length)
{
char *internalStorage = (char*)malloc(length);
memcpy(internalStorage, buffer, length);
Module *module = new Module();
ParserData data;
memset(&data, 0, sizeof(data));
data.buffer = reinterpret_cast<char*>(internalStorage);
data.index = 0;
data.length = length;
data.module = module;
yylex_init_extra(&data, &data.scanner);
bool valid = yyparse(&data) == 0;
yylex_destroy(data.scanner);
free(internalStorage);
for(char *ptr : data.strings) {
free(ptr);
}
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) {
return module;
} else {
delete module;
return nullptr;
}
}
Module *VM::load(const char *text)
{
return VM::load(reinterpret_cast<const void*>(text), static_cast<size_t>(strlen(text)));
}
Module::Module() :
variables()
{
}
Module::~Module()
{
for(auto val : methods) {
delete val.second;
}
for(auto val : variables) {
delete val.second;
}
for(auto obj : objects) {
delete obj.second;
}
}
Variable ScriptMethod::invoke(ker::Vector<Variable> arguments)
{
ExecutionContext context(this->module);
ker::Vector<Variable*> temporaries;
for(auto var : this->module->variables)
{
context.add(var.first, var.second);
}
Variable returnVariable = this->mReturnValue.second.createInstance();
if(this->mReturnValue.second.usable()) {
context.add(this->mReturnValue.first, &returnVariable);
}
if(arguments.length() != this->mArguments.length()) {
die_extra("ScriptMethod::invoke", "Invalid argument count.");
}
for(size_t i = 0; i < this->mArguments.length(); i++) {
if(this->mArguments[i].second != arguments[i].type()) {
die_extra("ScriptMethod::invoke", "Invalid argument type.");
}
auto *v = new Variable(arguments[i]);
temporaries.append(v);
context.add(this->mArguments[i].first, v);
}
for(auto local : this->mLocals) {
auto *v = new Variable(local.second.createInstance());
temporaries.append(v);
context.add(local.first, v);
}
this->block->execute(context);
for(auto *var : temporaries) {
delete var;
}
return returnVariable;
}
bool ScriptMethod::validate(ker::String &errorCode) const
{
if(this->block == nullptr) {
errorCode = "Method block is not set.";
return false;
}
ExecutionContext context(this->module);
for(auto var : this->module->variables)
{
context.add(var.first, var.second);
}
Variable returnVariable = this->mReturnValue.second.createInstance();
if(this->mReturnValue.second.usable()) {
if(context.get(this->mReturnValue.first) != nullptr) {
errorCode = "Return variable overlaps a variable.";
return false;
}
context.add(this->mReturnValue.first, &returnVariable);
}
for(size_t i = 0; i < this->mArguments.length(); i++) {
if(context.get(this->mArguments[i].first) != nullptr) {
errorCode = "Parameter overlaps a variable.";
return false;
}
context.add(this->mArguments[i].first, new Variable(this->mArguments[i].second.createInstance()));
}
for(auto local : this->mLocals) {
if(context.get(local.first) != nullptr) {
errorCode = "Local variable overlaps a variable.";
return false;
}
context.add(local.first, new Variable(local.second.createInstance()));
}
if(this->block->validate(context, errorCode) == false) {
return false;
}
return true;
}
}

View file

@ -1,6 +0,0 @@
#pragma once
#include "vm.hpp"
#include "method.hpp"
#include "instructions.hpp"
#include "scriptmethod.hpp"

View file

@ -1,89 +0,0 @@
#include <kernel.h>
#include <console.h>
#include "type.hpp"
#include "variable.hpp"<?
ops = {
{ "add" },
{ "subtract" },
{ "multiply" },
{ "divide" },
{ "modulo" },
{ "lt", "Bool" },
{ "le", "Bool" },
{ "gt", "Bool" },
{ "ge", "Bool" },
{ "eq", "Bool" },
{ "ieq", "Bool" },
}
types = {
Invalid = { }, -- no operators at all, all nil
Int = {
add = "+",
subtract = "-",
multiply = "*",
divide = "/",
modulo = "%",
lt = "<",
le = "<=",
gt = ">",
ge = ">=",
eq = "==",
ieq = "!="
},
Real = {
add = "+",
subtract = "-",
multiply = "*",
divide = "/",
lt = "<",
le = "<=",
gt = ">",
ge = ">=",
eq = "==",
ieq = "!="
},
Bool = {
add = "||",
multiply = "&&",
eq = "==",
ieq = "!="
},
Text = {
add = "+",
eq = "==",
ieq = "!="
}
}
?>
namespace trainscript
{
<? for type,desc in pairs(types) do
for _, _op in ipairs(ops) do
local op = _op[1]
local rt = _op[2] or type
if desc[op] then
local name = type .. "_" .. op;
local sign = desc[op];
?>static Variable <[name]>(const Variable &lhs, const Variable &rhs)
{
return Variable::from<[rt]>(lhs.value<<[type]>>() <[sign]> rhs.value<<[type]>>());
}
<? end
end
end
for type,desc in pairs(types) do ?>
TypeOps <[type]>Operators = {<?
for _, _op in ipairs(ops) do
local op = _op[1] ?>
<?
if desc[op] == nil then
?>nullptr,<?
else
?><[type]>_<[op]>,<?
end
end ?>
};<? end ?>
}

View file

@ -1,41 +0,0 @@
#include <kernel.h>
#include <console.h>
#include "type.hpp"
#include "variable.hpp"
namespace trainscript
{
extern TypeOps InvalidOperators;
extern TypeOps IntOperators;
extern TypeOps RealOperators;
extern TypeOps TextOperators;
extern TypeOps BoolOperators;
const Type Type::Invalid = { TypeID::Invalid, 0, &InvalidOperators };
const Type Type::Void = { TypeID::Void, 0, &InvalidOperators };
const Type Type::Int = { TypeID::Int, 0, &IntOperators };
const Type Type::Real = { TypeID::Real, 0, &RealOperators };
const Type Type::Text = { TypeID::Text, 0, &TextOperators };
const Type Type::Bool = { TypeID::Bool, 0, &BoolOperators };
bool Type::hasOperator(Operation op) const
{
return this->operators->ops[(int)op] != nullptr;
}
Variable Type::apply(const Variable &lhs, Operation op, const Variable &rhs) const
{
if(this->hasOperator(op) == false) {
kprintf("[invalid op: apply %d to %s]", (int)op, this->name());
return Variable::Invalid;
}
return this->operators->ops[(int)op](lhs, rhs);
}
Variable Type::createInstance() const
{
Variable v;
v.setType(*this);
return v;
}
}

View file

@ -1,128 +0,0 @@
#pragma once
#include <inttypes.h>
#include "types.hpp"
#include "typeid.hpp"
namespace trainscript
{
class Variable;
using Operator = Variable (*)(const Variable & rhs, const Variable &lhs);
enum class Operation
{
Add = 0,
Subtract,
Multiply,
Divide,
Modulo,
Less,
LessEquals,
Greater,
GreaterEquals,
Equals,
Inequals,
LIMIT
};
struct TypeOps {
Operator ops[(int)Operation::LIMIT];
};
struct Type
{
TypeID id;
int pointer;
const TypeOps *operators;
Type reference() const {
return Type { id, pointer + 1, operators };
}
Type dereference() const {
return Type { id, pointer - 1, operators };
}
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 {
if(this->pointer > 0) {
static char str[64];
strcpy(str, this->dereference().name());
strcat(str, "*");
return str;
} else {
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>";
}
}
}
size_t size() const
{
if(this->pointer > 0) {
return sizeof(void*);
} else {
switch(id) {
case TypeID::Invalid: return 0;
case TypeID::Void: return 0;
case TypeID::Int: return sizeof(trainscript::Int);
case TypeID::Real: return sizeof(trainscript::Real);
case TypeID::Text: return sizeof(trainscript::Text);
case TypeID::Bool: return sizeof(trainscript::Bool);
default: die("Type::size.UnknownTypeID");
}
}
return 0;
}
/**
* @brief Creates an instance of this type.
* @return Variable with a value of this type.
*/
Variable createInstance() const;
/**
* @brief Checks if the type has the operation defined.
* @param op Operation that should be checked
* @return True if the operation is defined, else false
*/
bool hasOperator(Operation op) const;
/**
* @brief Applies the operation to the operands.
* @param lhs Left hand side
* @param op Operation
* @param rhs Right hand side
* @return Result of the operation or Variable::Invalid if operation is not defined.
*/
Variable apply(const Variable &lhs, Operation op, const Variable &rhs) const;
static const Type Invalid;
static const Type Void;
static const Type Int;
static const Type Real;
static const Type Text;
static const Type Bool;
};
}

View file

@ -1,14 +0,0 @@
#pragma once
namespace trainscript
{
enum class TypeID
{
Invalid = 0,
Void = 1,
Int = 2,
Real = 3,
Text = 4,
Bool = 5
};
}

View file

@ -1,14 +0,0 @@
#pragma once
#include <inttypes.h>
#include <ker/string.hpp>
namespace trainscript
{
using Int = int32_t;
using Real = float;
using Void = void;
using Bool = bool;
using Text = ker::String;
using Pointer = void*;
}

View file

@ -1,143 +0,0 @@
#include <kernel.h>
#include <console.h>
#include "variable.hpp"
#include "type.hpp"
namespace trainscript
{
const Variable Variable::Invalid = { Type::Invalid, 0 };
const Variable Variable::Void = { Type::Void, 0 };
const Variable Variable::Int = { Type::Int, 0 };
const Variable Variable::Real = { Type::Real, 0 };
const Variable Variable::Text = { Type::Text, 0 };
const Variable Variable::Bool = { Type::Bool, 0 };
Variable::~Variable()
{
// Only free non-pointer types.
if(this->mType.pointer == 0) {
switch(this->mType.id) {
#define DELETE(type) case TypeID::type: \
delete reinterpret_cast<trainscript::type*>(this->mValue); \
break
DELETE(Bool);
DELETE(Int);
DELETE(Real);
DELETE(Text);
#undef DELETE
}
} else {
delete reinterpret_cast<trainscript::Pointer*>(this->mValue); \
}
}
void Variable::replace(const Variable &other)
{
this->setType(other.mType);
*this = other;
}
void Variable::setType(const Type &type)
{
if(this->mValue != nullptr) {
die_extra("Variable::setType.AlreadyInitialized", "Variable was already initialized!");
}
this->mType = type;
this->mValue = nullptr;
if(mType.pointer == 0) {
switch(mType.id) {
#define CREATE(type, initial) case TypeID::type: \
this->mValue = new trainscript::type(initial); \
break
CREATE(Bool, false);
CREATE(Int, 0);
CREATE(Real, 0.0);
CREATE(Text, "");
#undef CREATE
case TypeID::Invalid:
case TypeID::Void:
// Ignore INVALID or VOID type.
break;
default:
die_extra("Variable::setType.InvalidTypeID", mType.name());
break;
}
} else {
this->mValue = new trainscript::Pointer(nullptr); \
}
}
Variable &Variable::operator =(const Variable &other)
{
if(this->mType != other.mType) {
kprintf("[%s -> %s]", other.mType.name(), this->mType.name());
die_extra("Variable.operator=", "Type mismatch.");
}
if(this->mType == Type::Void) {
// Just don't do anything when assigning void.
return *this;
}
if(this->mValue == nullptr) {
kprintf("[Variable.type: %s]", this->mType.name());
die_extra("Variable.operator=", "Invalid variable: value == nullptr");
}
if(this->mType.pointer == 0) {
switch(this->mType.id) {
#define COPY(type) case TypeID::type: \
*reinterpret_cast<trainscript::type*>(this->mValue) = *reinterpret_cast<trainscript::type*>(other.mValue); \
break
COPY(Bool);
COPY(Int);
COPY(Real);
COPY(Text);
#undef COPY
}
} else {
*reinterpret_cast<trainscript::Pointer*>(this->mValue) = *reinterpret_cast<trainscript::Pointer*>(other.mValue); \
}
return *this;
}
#define fromType(type) Variable Variable::from##type(trainscript::type i) \
{ \
Variable var = Type::type.createInstance(); \
var.value<trainscript::type>() = i; \
return var; \
}
fromType(Int)
fromType(Real)
fromType(Text)
fromType(Bool)
ker::String Variable::toString() const
{
if(this->mType.pointer > 0) {
return "0x" + ker::String::fromNumber(*reinterpret_cast<int32_t*>(this->mValue), 16);
}
trainscript::Int iVal;
trainscript::Real rVal;
switch(this->mType.id) {
case TypeID::Bool:
if(*reinterpret_cast<trainscript::Bool*>(this->mValue) == true)
return "TRUE";
else
return "FALSE";
case TypeID::Int:
iVal = *reinterpret_cast<trainscript::Int*>(this->mValue);
return ker::String::fromNumber(iVal, 10);
case TypeID::Real:
rVal = *reinterpret_cast<trainscript::Real*>(this->mValue);
// return ker::String::fromNumber(rVal);
return "<REAL missing>";
case TypeID::Text:
return *reinterpret_cast<trainscript::Text*>(this->mValue);
case TypeID::Void:
return "VOID";
case TypeID::Invalid:
return "INVALID";
}
return "???";
}
}

View file

@ -1,104 +0,0 @@
#pragma once
#include <inttypes.h>
#include <ker/string.hpp>
#include "type.hpp"
namespace trainscript
{
class Variable
{
friend class Type;
private:
Type mType;
void *mValue;
private:
// To be called by Type::createInstance
Variable(const Type &type, void *value) :
mType(type),
mValue(value)
{
}
public:
Variable() :
mType(Type::Invalid),
mValue(nullptr)
{
}
Variable(const Variable &other) :
mType(),
mValue()
{
this->setType(other.mType);
*this = other;
}
Variable(Variable &&other) :
mType(other.mType),
mValue(other.mValue)
{
other.mType = Type::Invalid;
other.mValue = nullptr;
}
~Variable();
Variable &operator =(const Variable &other);
/**
* @brief Replaces the value and type of this variable.
* @param other The reference variable to copy.
*/
void replace(const Variable &other);
void setType(const Type &type);
void *data() const
{
return this->mValue;
}
/**
* @brief Sets the data pointer.
* @param data The new data pointer
* @remarks The old data pointer will be replaced,
* there will be no cleanup and the new data
* pointer will be deleted by the Variable.
*/
void setData(void *data) {
this->mValue = data;
}
template<typename T>
T& value()
{
return *reinterpret_cast<T*>(this->mValue);
}
template<typename T>
const T& value() const
{
return *reinterpret_cast<T*>(this->mValue);
}
const Type &type() const {
return this->mType;
}
ker::String toString() const;
static Variable fromInt(trainscript::Int i);
static Variable fromReal(trainscript::Real r);
static Variable fromText(trainscript::Text t);
static Variable fromBool(Bool b);
static const Variable Invalid;
static const Variable Void;
static const Variable Int;
static const Variable Real;
static const Variable Text;
static const Variable Bool;
};
}

View file

@ -1,21 +0,0 @@
#pragma once
#include <stdlib.h>
#include "module.hpp"
namespace trainscript
{
class VM
{
public:
Module *load(const void *buffer, size_t length);
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);
};
}