Removes old trainVm from trainOs.
This commit is contained in:
parent
bf33a7f308
commit
395e2ebb60
28 changed files with 179 additions and 2781 deletions
3
Depfile
3
Depfile
|
@ -2,9 +2,6 @@
|
|||
Artifact=kernel
|
||||
TempDir=obj
|
||||
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
|
||||
|
||||
LexUseCpp
|
||||
|
|
122
Makefile
122
Makefile
|
@ -8,13 +8,12 @@ CXX = g++
|
|||
LD = g++
|
||||
LEX = flex
|
||||
YACC = bison
|
||||
TEMPLE = mono /home/felix/projects/temple/bin/Debug/temple.exe
|
||||
|
||||
# File Lists
|
||||
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_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
|
||||
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
|
||||
SRCS_CXX = src/cplusplus.cpp src/cpp-test.cpp src/vm.cpp
|
||||
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 = -m32 -Dnullptr=0 -D__cdecl="__attribute__((cdecl))" -mno-sse -mno-sse2 -mno-mmx
|
||||
|
@ -28,142 +27,78 @@ all: kernel
|
|||
|
||||
.PHONY: 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
|
||||
$(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
|
||||
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/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
|
||||
obj/console.o: src/console.c include/console.h include/stdlib.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
|
||||
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) -iquoteobj $(FLAGS) $(CCFLAGS) -o $@ -c src/init.c
|
||||
$(CC) $(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) -iquoteobj $(FLAGS) $(CCFLAGS) -o $@ -c src/interrupts.c
|
||||
$(CC) $(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) -iquoteobj $(FLAGS) $(CCFLAGS) -o $@ -c src/malloc.c
|
||||
$(CC) $(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) -iquoteobj $(FLAGS) $(CCFLAGS) -o $@ -c src/pmm.c
|
||||
$(CC) $(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) -iquoteobj $(FLAGS) $(CCFLAGS) -o $@ -c src/serial.c
|
||||
$(CC) $(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) -iquoteobj $(FLAGS) $(CCFLAGS) -o $@ -c src/stdlib.c
|
||||
$(CC) $(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) -iquoteobj $(FLAGS) $(CCFLAGS) -o $@ -c src/timer.c
|
||||
$(CC) $(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) -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 \
|
||||
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
|
||||
$(CC) $(FLAGS) $(CCFLAGS) -o $@ -c src/vmm.c
|
||||
|
||||
# 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) -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
|
||||
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 \
|
||||
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 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
|
||||
include/malloc.h include/timer.h include/dynamic.h include/console.h
|
||||
$(CXX) $(FLAGS) $(CXXFLAGS) -o $@ -c src/vm.cpp
|
||||
|
||||
# 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
|
||||
$(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
|
||||
obj/main.o: scripts/main.ts
|
||||
objcopy -B i386 -I binary -O elf32-i386 \
|
||||
|
|
147
src/cpp-test.cpp
Normal file
147
src/cpp-test.cpp
Normal 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);
|
||||
}
|
||||
}
|
351
src/vm.cpp
351
src/vm.cpp
|
@ -2,10 +2,6 @@
|
|||
#include <timer.h>
|
||||
#include <dynamic.h>
|
||||
#include <console.h>
|
||||
#include "../trainscript/tsvm.hpp"
|
||||
|
||||
using namespace ker;
|
||||
using namespace trainscript;
|
||||
|
||||
extern "C" {
|
||||
extern const char mainscript_start;
|
||||
|
@ -13,173 +9,6 @@ extern "C" {
|
|||
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()
|
||||
{
|
||||
struct {
|
||||
|
@ -190,184 +19,8 @@ extern "C" void vm_start()
|
|||
(uint32_t)&mainscript_size
|
||||
};
|
||||
|
||||
// cpp_test();
|
||||
(void)mainfile;
|
||||
|
||||
kprintf("Parse kernel module: ");
|
||||
|
||||
KernelVM vm;
|
||||
|
||||
Module *module = vm.load(mainfile.ptr, mainfile.size);
|
||||
if(module == nullptr) {
|
||||
kprintf("Could not load module :(\n");
|
||||
return;
|
||||
kprintf("No implementation of Conductance here yet.\n");
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
|
28
trainOS.pro
28
trainOS.pro
|
@ -11,14 +11,11 @@ SOURCES += \
|
|||
src/pmm.c \
|
||||
src/stdlib.c \
|
||||
src/vmm.c \
|
||||
trainscript/tsvm.cpp \
|
||||
trainscript/main.cpp \
|
||||
src/timer.c \
|
||||
src/cplusplus.cpp \
|
||||
src/vm.cpp \
|
||||
src/serial.c \
|
||||
trainscript/variable.cpp \
|
||||
trainscript/type.cpp
|
||||
src/cpp-test.cpp
|
||||
|
||||
HEADERS += \
|
||||
include/console.h \
|
||||
|
@ -32,9 +29,6 @@ HEADERS += \
|
|||
include/stdlib.h \
|
||||
include/varargs.h \
|
||||
include/vmm.h \
|
||||
trainscript/common.h \
|
||||
trainscript/tsvm.hpp \
|
||||
trainscript/typeid.hpp \
|
||||
include/timer.h \
|
||||
include/ker/string.hpp \
|
||||
include/ker/pair.hpp \
|
||||
|
@ -45,17 +39,7 @@ HEADERS += \
|
|||
include/dynamic.h \
|
||||
include/config.h \
|
||||
include/serial.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
|
||||
include/malloc.h
|
||||
|
||||
DISTFILES += \
|
||||
asm/intr_common_handler.S \
|
||||
|
@ -63,18 +47,12 @@ DISTFILES += \
|
|||
asm/start.S \
|
||||
trainscript.md \
|
||||
Makefile \
|
||||
trainscript/trainscript.l \
|
||||
trainscript/file01.ts \
|
||||
trainscript/Makefile \
|
||||
trainscript/trainscript.y \
|
||||
trainscript/file02.ts \
|
||||
kernel.ld \
|
||||
Depfile \
|
||||
Makefile.new \
|
||||
scripts/main.ts \
|
||||
asm/dynamic.S \
|
||||
README.md \
|
||||
trainscript/type-operators.cpp.tt
|
||||
README.md
|
||||
|
||||
QMAKE_INCDIR =
|
||||
|
||||
|
|
|
@ -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
|
|
@ -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
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
|
@ -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
|
|
@ -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;
|
|
@ -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;
|
||||
}
|
||||
};
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
};
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -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;
|
||||
};
|
||||
}
|
|
@ -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;
|
||||
};
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
};
|
||||
}
|
|
@ -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; }
|
||||
*/
|
|
@ -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);
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -1,6 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include "vm.hpp"
|
||||
#include "method.hpp"
|
||||
#include "instructions.hpp"
|
||||
#include "scriptmethod.hpp"
|
|
@ -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 ?>
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
};
|
||||
}
|
|
@ -1,14 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
namespace trainscript
|
||||
{
|
||||
enum class TypeID
|
||||
{
|
||||
Invalid = 0,
|
||||
Void = 1,
|
||||
Int = 2,
|
||||
Real = 3,
|
||||
Text = 4,
|
||||
Bool = 5
|
||||
};
|
||||
}
|
|
@ -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*;
|
||||
}
|
|
@ -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 "???";
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
};
|
||||
}
|
|
@ -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);
|
||||
};
|
||||
}
|
Loading…
Reference in a new issue