Adds semantic language validation.
This commit is contained in:
parent
3e2bf8ff10
commit
620f337bc2
11 changed files with 399 additions and 128 deletions
16
Makefile
16
Makefile
|
@ -77,9 +77,9 @@ obj/vmm.o: src/vmm.c include/vmm.h include/pmm.h include/multiboot.h \
|
||||||
obj/tsvm.o: trainscript/tsvm.cpp include/stdlib.h include/varargs.h \
|
obj/tsvm.o: trainscript/tsvm.cpp include/stdlib.h include/varargs.h \
|
||||||
include/console.h trainscript/common.h trainscript/tsvm.hpp \
|
include/console.h trainscript/common.h trainscript/tsvm.hpp \
|
||||||
include/ker/string.hpp include/ker/vector.hpp include/ker/new.hpp \
|
include/ker/string.hpp include/ker/vector.hpp include/ker/new.hpp \
|
||||||
include/ker/dictionary.hpp include/ker/pair.hpp trainscript/typeid.hpp \
|
include/ker/dictionary.hpp include/kernel.h include/ker/pair.hpp \
|
||||||
trainscript/trainscript.tab.hpp trainscript/trainscript.l.h \
|
trainscript/typeid.hpp trainscript/trainscript.tab.hpp \
|
||||||
include/string.h
|
trainscript/trainscript.l.h include/string.h
|
||||||
$(CXX) $(FLAGS) $(CXXFLAGS) -o $@ -c trainscript/tsvm.cpp
|
$(CXX) $(FLAGS) $(CXXFLAGS) -o $@ -c trainscript/tsvm.cpp
|
||||||
|
|
||||||
# src/cplusplus.cpp
|
# src/cplusplus.cpp
|
||||||
|
@ -91,7 +91,7 @@ obj/cplusplus.o: src/cplusplus.cpp include/stdlib.h include/varargs.h \
|
||||||
obj/vm.o: src/vm.cpp include/stdlib.h include/varargs.h include/timer.h \
|
obj/vm.o: src/vm.cpp include/stdlib.h include/varargs.h include/timer.h \
|
||||||
src/../trainscript/tsvm.hpp include/console.h include/ker/string.hpp \
|
src/../trainscript/tsvm.hpp include/console.h include/ker/string.hpp \
|
||||||
include/ker/vector.hpp include/ker/new.hpp include/ker/dictionary.hpp \
|
include/ker/vector.hpp include/ker/new.hpp include/ker/dictionary.hpp \
|
||||||
include/ker/pair.hpp src/../trainscript/typeid.hpp
|
include/kernel.h include/ker/pair.hpp src/../trainscript/typeid.hpp
|
||||||
$(CXX) $(FLAGS) $(CXXFLAGS) -o $@ -c src/vm.cpp
|
$(CXX) $(FLAGS) $(CXXFLAGS) -o $@ -c src/vm.cpp
|
||||||
|
|
||||||
# obj/trainscript.yy.cpp
|
# obj/trainscript.yy.cpp
|
||||||
|
@ -99,15 +99,17 @@ obj/trainscript.yy.o: obj/trainscript.yy.cpp include/string.h \
|
||||||
include/stdlib.h include/varargs.h trainscript/common.h \
|
include/stdlib.h include/varargs.h trainscript/common.h \
|
||||||
trainscript/tsvm.hpp include/console.h include/ker/string.hpp \
|
trainscript/tsvm.hpp include/console.h include/ker/string.hpp \
|
||||||
include/ker/vector.hpp include/ker/new.hpp include/ker/dictionary.hpp \
|
include/ker/vector.hpp include/ker/new.hpp include/ker/dictionary.hpp \
|
||||||
include/ker/pair.hpp trainscript/typeid.hpp obj/trainscript.tab.hpp
|
include/kernel.h include/ker/pair.hpp trainscript/typeid.hpp \
|
||||||
|
obj/trainscript.tab.hpp
|
||||||
$(CXX) -iquotetrainscript $(FLAGS) $(CXXFLAGS) -o $@ -c obj/trainscript.yy.cpp
|
$(CXX) -iquotetrainscript $(FLAGS) $(CXXFLAGS) -o $@ -c obj/trainscript.yy.cpp
|
||||||
|
|
||||||
# obj/trainscript.tab.cpp
|
# obj/trainscript.tab.cpp
|
||||||
obj/trainscript.tab.o: obj/trainscript.tab.cpp include/stdlib.h \
|
obj/trainscript.tab.o: obj/trainscript.tab.cpp include/stdlib.h \
|
||||||
include/varargs.h trainscript/common.h trainscript/tsvm.hpp \
|
include/varargs.h trainscript/common.h trainscript/tsvm.hpp \
|
||||||
include/console.h include/ker/string.hpp include/ker/vector.hpp \
|
include/console.h include/ker/string.hpp include/ker/vector.hpp \
|
||||||
include/ker/new.hpp include/ker/dictionary.hpp include/ker/pair.hpp \
|
include/ker/new.hpp include/ker/dictionary.hpp include/kernel.h \
|
||||||
trainscript/typeid.hpp trainscript/trainscript.l.h include/string.h
|
include/ker/pair.hpp trainscript/typeid.hpp trainscript/trainscript.l.h \
|
||||||
|
include/string.h
|
||||||
$(CXX) -iquotetrainscript $(FLAGS) $(CXXFLAGS) -o $@ -c obj/trainscript.tab.cpp
|
$(CXX) -iquotetrainscript $(FLAGS) $(CXXFLAGS) -o $@ -c obj/trainscript.tab.cpp
|
||||||
|
|
||||||
# asm/intr_common_handler.S
|
# asm/intr_common_handler.S
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <kernel.h>
|
||||||
|
|
||||||
#include "pair.hpp"
|
#include "pair.hpp"
|
||||||
#include "vector.hpp"
|
#include "vector.hpp"
|
||||||
|
|
||||||
|
@ -10,7 +12,8 @@ namespace ker
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
typedef Pair<Key, Value> Entry;
|
typedef Pair<Key, Value> Entry;
|
||||||
public:
|
static Value _default;
|
||||||
|
public:
|
||||||
Vector<Entry> contents;
|
Vector<Entry> contents;
|
||||||
public:
|
public:
|
||||||
Dictionary() :
|
Dictionary() :
|
||||||
|
@ -45,16 +48,21 @@ namespace ker
|
||||||
return pair.second;
|
return pair.second;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
die("Key not found in dictionary.");
|
||||||
|
return _default;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Value &at(const Key &key) const
|
const Value &at(const Key &key) const
|
||||||
{
|
{
|
||||||
|
static Value _default;
|
||||||
for(auto &&pair : this->contents)
|
for(auto &&pair : this->contents)
|
||||||
{
|
{
|
||||||
if(pair.first == key) {
|
if(pair.first == key) {
|
||||||
return pair.second;
|
return pair.second;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
die("Key not found in dictionary.");
|
||||||
|
return _default;
|
||||||
}
|
}
|
||||||
|
|
||||||
Value get(const Key &key) const
|
Value get(const Key &key) const
|
||||||
|
@ -122,4 +130,7 @@ namespace ker
|
||||||
return this->contents.end();
|
return this->contents.end();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template<typename Key, typename Value>
|
||||||
|
Value Dictionary<Key, Value>::_default = Value();
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,13 +30,7 @@ namespace ker
|
||||||
{
|
{
|
||||||
other.mText = nullptr;
|
other.mText = nullptr;
|
||||||
other.mLength = 0;
|
other.mLength = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
String & operator = (const String &other)
|
|
||||||
{
|
|
||||||
this->copyFrom(other.mText, other.mLength);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
String(const char *text) :
|
String(const char *text) :
|
||||||
mText(nullptr),
|
mText(nullptr),
|
||||||
|
@ -52,6 +46,12 @@ namespace ker
|
||||||
this->copyFrom(bytes, length);
|
this->copyFrom(bytes, length);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String & operator = (const String &other)
|
||||||
|
{
|
||||||
|
this->copyFrom(other.mText, other.mLength);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
~String()
|
~String()
|
||||||
{
|
{
|
||||||
if(this->mText != nullptr) {
|
if(this->mText != nullptr) {
|
||||||
|
@ -72,6 +72,21 @@ namespace ker
|
||||||
return memcmp(this->mText, other.mText, this->mLength) == 0;
|
return memcmp(this->mText, other.mText, this->mLength) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String append(const String &other) const
|
||||||
|
{
|
||||||
|
uint8_t *data = (uint8_t*)malloc(this->mLength + other.mLength);
|
||||||
|
memcpy(&data[0], this->mText, this->mLength);
|
||||||
|
memcpy(&data[this->mLength], other.mText, other.mLength);
|
||||||
|
String cat(data, this->mLength + other.mLength);
|
||||||
|
free(data);
|
||||||
|
return cat;
|
||||||
|
}
|
||||||
|
|
||||||
|
static String concat(const String &lhs, const String &rhs)
|
||||||
|
{
|
||||||
|
return lhs.append(rhs);
|
||||||
|
}
|
||||||
|
|
||||||
const uint8_t *text() const
|
const uint8_t *text() const
|
||||||
{
|
{
|
||||||
static const uint8_t empty[] = { 0 };
|
static const uint8_t empty[] = { 0 };
|
||||||
|
@ -128,4 +143,15 @@ namespace ker
|
||||||
this->mText[this->mLength] = 0; // last byte is always 0
|
this->mText[this->mLength] = 0; // last byte is always 0
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
static String operator + (const char *lhs, const String &rhs)
|
||||||
|
{
|
||||||
|
return String::concat(lhs, rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
static String operator + (const String &lhs, const char *rhs)
|
||||||
|
{
|
||||||
|
return String::concat(lhs, rhs);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -2,65 +2,10 @@ VAR global : INT;
|
||||||
|
|
||||||
PUB main() | i : INT
|
PUB main() | i : INT
|
||||||
BEGIN
|
BEGIN
|
||||||
afraid(15, 34) → i;
|
fun(1) -> 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
|
END
|
||||||
|
|
||||||
# Sleep implementation
|
PUB fun() -> i : INT
|
||||||
PRI sleep'(time : INT) | init : INT
|
|
||||||
BEGIN
|
BEGIN
|
||||||
timer_get() → init;
|
10 -> i;
|
||||||
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
|
END
|
||||||
|
|
|
@ -183,7 +183,6 @@ void kprintf(const char *format, ...)
|
||||||
{
|
{
|
||||||
c = *(format++);
|
c = *(format++);
|
||||||
int i;
|
int i;
|
||||||
float f;
|
|
||||||
char *str;
|
char *str;
|
||||||
switch(c)
|
switch(c)
|
||||||
{
|
{
|
||||||
|
|
43
src/vm.cpp
43
src/vm.cpp
|
@ -13,13 +13,6 @@ extern "C" {
|
||||||
|
|
||||||
void cpp_test();
|
void cpp_test();
|
||||||
|
|
||||||
class PrintMethod :
|
|
||||||
public Method
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
Variable invoke(Vector<Variable> arguments) override;
|
|
||||||
};
|
|
||||||
|
|
||||||
class NativeMethod :
|
class NativeMethod :
|
||||||
public Method
|
public Method
|
||||||
{
|
{
|
||||||
|
@ -33,18 +26,24 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
Variable invoke(Vector<Variable> arguments) override;
|
Variable invoke(Vector<Variable> arguments) override;
|
||||||
};
|
|
||||||
|
|
||||||
Variable PrintMethod::invoke(Vector<Variable> arguments)
|
bool validate(ker::String &errorCode) const
|
||||||
{
|
{
|
||||||
for(auto &var : arguments)
|
if(this->function == nullptr) {
|
||||||
{
|
errorCode = "Native method with nullptr interface.";
|
||||||
var.printval();
|
return false;
|
||||||
kprintf(" ");
|
}
|
||||||
}
|
return true;
|
||||||
kprintf("\n");
|
}
|
||||||
return Variable::Void;
|
|
||||||
}
|
Vector<Type> arguments() const {
|
||||||
|
return Vector<Type>();
|
||||||
|
}
|
||||||
|
|
||||||
|
Type returnType() const {
|
||||||
|
return Type::Int;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
static void copyCode(uint8_t **ptr, const uint8_t *src, size_t length)
|
static void copyCode(uint8_t **ptr, const uint8_t *src, size_t length)
|
||||||
{
|
{
|
||||||
|
@ -169,9 +168,11 @@ extern "C" void vm_start()
|
||||||
|
|
||||||
kprintf("Module successfully loaded :)\n");
|
kprintf("Module successfully loaded :)\n");
|
||||||
|
|
||||||
module->methods.add("print", new PrintMethod());
|
String errorCode;
|
||||||
|
if(module->validate(errorCode) == false) {
|
||||||
module->methods.add("afraid", new NativeMethod(reinterpret_cast<void*>(&cCodeFunction)));
|
kprintf("Module validation failed: %s\n", errorCode.str());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
NativeModuleDef *mod = methods;
|
NativeModuleDef *mod = methods;
|
||||||
while(mod->name != nullptr) {
|
while(mod->name != nullptr) {
|
||||||
|
|
|
@ -39,7 +39,7 @@ struct VariableDeclaration
|
||||||
struct LocalVariable
|
struct LocalVariable
|
||||||
{
|
{
|
||||||
char *name;
|
char *name;
|
||||||
trainscript::Variable variable;
|
trainscript::Type type;
|
||||||
LocalVariable *next;
|
LocalVariable *next;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,66 @@
|
||||||
|
VAR global : INT;
|
||||||
|
|
||||||
VAR res : INT;
|
PUB main() | i : INT
|
||||||
|
|
||||||
PUB main(x : INT) → c : INT
|
|
||||||
BEGIN
|
BEGIN
|
||||||
# factorial(10) → res;
|
afraid(15, 34) → i;
|
||||||
# fibonacci(7) → res;
|
0 -> i;
|
||||||
problem1(1000) → res;
|
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
|
END
|
||||||
|
|
|
@ -154,18 +154,18 @@ input:
|
||||||
ScriptMethod *method = new ScriptMethod(mod, $2.body);
|
ScriptMethod *method = new ScriptMethod(mod, $2.body);
|
||||||
method->isPublic = $2.header.isPublic;
|
method->isPublic = $2.header.isPublic;
|
||||||
if($2.header.returnValue) {
|
if($2.header.returnValue) {
|
||||||
method->returnValue = ker::Pair<ker::String, Variable>(
|
method->mReturnValue = ker::Pair<ker::String, Type>(
|
||||||
$2.header.returnValue->name,
|
$2.header.returnValue->name,
|
||||||
$2.header.returnValue->variable);
|
$2.header.returnValue->type);
|
||||||
}
|
}
|
||||||
LocalVariable *local = $2.header.locals;
|
LocalVariable *local = $2.header.locals;
|
||||||
while(local) {
|
while(local) {
|
||||||
method->locals.add( local->name, local->variable );
|
method->mLocals.add( local->name, local->type );
|
||||||
local = local->next;
|
local = local->next;
|
||||||
}
|
}
|
||||||
LocalVariable *arg = $2.header.arguments;
|
LocalVariable *arg = $2.header.arguments;
|
||||||
while(arg) {
|
while(arg) {
|
||||||
method->arguments.append( { arg->name, arg->variable } );
|
method->mArguments.append( { arg->name, arg->type} );
|
||||||
arg = arg->next;
|
arg = arg->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -277,8 +277,7 @@ argument:
|
||||||
IDENTIFIER COLON typeName {
|
IDENTIFIER COLON typeName {
|
||||||
$$ = new LocalVariable();
|
$$ = new LocalVariable();
|
||||||
$$->name = $1;
|
$$->name = $1;
|
||||||
$$->variable.type = $3;
|
$$->type = $3;
|
||||||
$$->variable.integer = 0; // zero value
|
|
||||||
$$->next = nullptr;
|
$$->next = nullptr;
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
|
@ -28,6 +28,17 @@ namespace trainscript
|
||||||
const Variable Variable::Text = { Type::Text, 0 };
|
const Variable Variable::Text = { Type::Text, 0 };
|
||||||
const Variable Variable::Boolean = { Type::Boolean, 0 };
|
const Variable Variable::Boolean = { Type::Boolean, 0 };
|
||||||
|
|
||||||
|
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::load(const void *buffer, size_t length)
|
Module *VM::load(const void *buffer, size_t length)
|
||||||
{
|
{
|
||||||
void *internalStorage = malloc(length);
|
void *internalStorage = malloc(length);
|
||||||
|
@ -85,28 +96,78 @@ namespace trainscript
|
||||||
context.add(var.first, var.second);
|
context.add(var.first, var.second);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(this->returnValue.second.type.usable()) {
|
Variable returnVariable = {
|
||||||
context.add(this->returnValue.first, &this->returnValue.second);
|
this->mReturnValue.second, 0
|
||||||
|
};
|
||||||
|
|
||||||
|
if(this->mReturnValue.second.usable()) {
|
||||||
|
context.add(this->mReturnValue.first, &returnVariable);
|
||||||
}
|
}
|
||||||
if(arguments.length() != this->arguments.length()) {
|
if(arguments.length() != this->mArguments.length()) {
|
||||||
return Variable::Invalid;
|
return Variable::Invalid;
|
||||||
}
|
}
|
||||||
for(size_t i = 0; i < this->arguments.length(); i++) {
|
for(size_t i = 0; i < this->mArguments.length(); i++) {
|
||||||
if(this->arguments[i].second.type != arguments[i].type) {
|
if(this->mArguments[i].second != arguments[i].type) {
|
||||||
return Variable::Invalid;
|
return Variable::Invalid;
|
||||||
}
|
}
|
||||||
context.add(this->arguments[i].first, new Variable(arguments[i]));
|
context.add(this->mArguments[i].first, new Variable(arguments[i]));
|
||||||
}
|
}
|
||||||
for(auto local : this->locals) {
|
for(auto local : this->mLocals) {
|
||||||
context.add(local.first, new Variable(local.second));
|
context.add(local.first, new Variable { local.second, 0 });
|
||||||
}
|
}
|
||||||
|
|
||||||
this->block->execute(context);
|
this->block->execute(context);
|
||||||
|
|
||||||
return this->returnValue.second;
|
return returnVariable;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ScriptMethod::validate(ker::String &errorCode) const
|
||||||
|
{
|
||||||
|
if(this->block == nullptr) {
|
||||||
|
errorCode = "Method block is not set.";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
LocalContext context(this->module);
|
||||||
|
|
||||||
|
for(auto var : this->module->variables)
|
||||||
|
{
|
||||||
|
context.add(var.first, var.second);
|
||||||
|
}
|
||||||
|
|
||||||
|
Variable returnVariable = {
|
||||||
|
this->mReturnValue.second, 0
|
||||||
|
};
|
||||||
|
|
||||||
|
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, 0 });
|
||||||
|
}
|
||||||
|
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, 0 });
|
||||||
|
}
|
||||||
|
|
||||||
|
if(this->block->validate(context, errorCode) == false) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
namespace ops
|
namespace ops
|
||||||
{
|
{
|
||||||
|
|
|
@ -5,15 +5,10 @@ extern "C" {
|
||||||
#include <console.h>
|
#include <console.h>
|
||||||
}
|
}
|
||||||
|
|
||||||
// #include <map>
|
|
||||||
|
|
||||||
#include <ker/string.hpp>
|
#include <ker/string.hpp>
|
||||||
#include <ker/vector.hpp>
|
#include <ker/vector.hpp>
|
||||||
#include <ker/dictionary.hpp>
|
#include <ker/dictionary.hpp>
|
||||||
|
|
||||||
// #include <vector>
|
|
||||||
// #include <string.h>
|
|
||||||
|
|
||||||
#include "typeid.hpp"
|
#include "typeid.hpp"
|
||||||
|
|
||||||
namespace trainscript
|
namespace trainscript
|
||||||
|
@ -144,6 +139,15 @@ namespace trainscript
|
||||||
virtual ~Instruction() { }
|
virtual ~Instruction() { }
|
||||||
|
|
||||||
virtual Variable execute(LocalContext &context) const = 0;
|
virtual Variable execute(LocalContext &context) const = 0;
|
||||||
|
|
||||||
|
virtual Type expectedResult(LocalContext &) const {
|
||||||
|
return Type::Void;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual bool validate(LocalContext &, ker::String &errorCode) const {
|
||||||
|
errorCode = "";
|
||||||
|
return true;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class Block :
|
class Block :
|
||||||
|
@ -156,6 +160,15 @@ namespace trainscript
|
||||||
for(auto *instr : instructions) delete instr;
|
for(auto *instr : instructions) delete instr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool validate(LocalContext &context, ker::String &errorCode) const {
|
||||||
|
errorCode = "";
|
||||||
|
for(auto *instr : instructions) {
|
||||||
|
if(instr->validate(context, errorCode) == false)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
Variable execute(LocalContext &context) const override {
|
Variable execute(LocalContext &context) const override {
|
||||||
for(auto *instr : instructions) {
|
for(auto *instr : instructions) {
|
||||||
instr->execute(context);
|
instr->execute(context);
|
||||||
|
@ -167,8 +180,15 @@ namespace trainscript
|
||||||
class Method
|
class Method
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
virtual ~Method() { }
|
virtual ~Method() { }
|
||||||
virtual Variable invoke(ker::Vector<Variable> arguments) = 0;
|
|
||||||
|
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;
|
||||||
};
|
};
|
||||||
|
|
||||||
class ScriptMethod :
|
class ScriptMethod :
|
||||||
|
@ -178,9 +198,9 @@ namespace trainscript
|
||||||
Module *module;
|
Module *module;
|
||||||
Instruction *block;
|
Instruction *block;
|
||||||
bool isPublic;
|
bool isPublic;
|
||||||
ker::Vector<ker::Pair<ker::String, Variable>> arguments;
|
ker::Vector<ker::Pair<ker::String, Type>> mArguments;
|
||||||
ker::Dictionary<ker::String, Variable> locals;
|
ker::Dictionary<ker::String, Type> mLocals;
|
||||||
ker::Pair<ker::String, Variable> returnValue;
|
ker::Pair<ker::String, Type> mReturnValue;
|
||||||
|
|
||||||
ScriptMethod(Module *module, Instruction *block) : module(module), block(block)
|
ScriptMethod(Module *module, Instruction *block) : module(module), block(block)
|
||||||
{
|
{
|
||||||
|
@ -188,6 +208,22 @@ namespace trainscript
|
||||||
}
|
}
|
||||||
|
|
||||||
Variable invoke(ker::Vector<Variable> arguments) override;
|
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;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class Module
|
class Module
|
||||||
|
@ -208,6 +244,8 @@ namespace trainscript
|
||||||
{
|
{
|
||||||
return this->variables.get(name);
|
return this->variables.get(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool validate(ker::String &errorCode) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
class VM
|
class VM
|
||||||
|
@ -231,9 +269,13 @@ namespace trainscript
|
||||||
Variable value;
|
Variable value;
|
||||||
ConstantExpression(Variable value) : value(value) { }
|
ConstantExpression(Variable value) : value(value) { }
|
||||||
|
|
||||||
Variable execute(LocalContext &context) const override {
|
Variable execute(LocalContext &) const override {
|
||||||
return this->value;
|
return this->value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Type expectedResult(LocalContext &) const override {
|
||||||
|
return this->value.type;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class VariableExpression :
|
class VariableExpression :
|
||||||
|
@ -250,6 +292,24 @@ namespace trainscript
|
||||||
}
|
}
|
||||||
return *var;
|
return *var;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool validate(LocalContext &context, ker::String &errorCode) const override {
|
||||||
|
errorCode = "";
|
||||||
|
if(context.get(this->variableName) == nullptr) {
|
||||||
|
errorCode = "Variable " + this->variableName + " not found.";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Type expectedResult(LocalContext &context) const override {
|
||||||
|
Variable *var = context.get(this->variableName);
|
||||||
|
if(var == nullptr) {
|
||||||
|
return Type::Invalid;
|
||||||
|
} else {
|
||||||
|
return var->type;
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -290,6 +350,43 @@ namespace trainscript
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool validate(LocalContext &context, ker::String &errorCode) const override {
|
||||||
|
errorCode = "";
|
||||||
|
if(this->expression == nullptr) {
|
||||||
|
errorCode = "Missing expression.";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Type result = this->expression->expectedResult(context);
|
||||||
|
if(result == Type::Invalid) {
|
||||||
|
errorCode = "Expression returns invalid type.";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if(result == Type::Void) {
|
||||||
|
errorCode = "Void cannot be assigned to a variable";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Variable *var = context.get(this->variableName);
|
||||||
|
if(var == nullptr) {
|
||||||
|
errorCode = "Variable " + this->variableName + " not found.";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if(var->type != result) {
|
||||||
|
errorCode = "Variable assignment has invalid type.";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if(this->expression->validate(context, errorCode) == false)
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Type expectedResult(LocalContext &context) const override {
|
||||||
|
if(this->expression == nullptr) {
|
||||||
|
return Type::Invalid;
|
||||||
|
} else {
|
||||||
|
return this->expression->expectedResult(context);
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class MethodInvokeExpression :
|
class MethodInvokeExpression :
|
||||||
|
@ -320,6 +417,38 @@ namespace trainscript
|
||||||
|
|
||||||
return method->invoke(vars);
|
return method->invoke(vars);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool validate(LocalContext &context, ker::String &errorCode) const override {
|
||||||
|
Method *method = context.module->method(this->methodName.str());
|
||||||
|
if(method == nullptr) {
|
||||||
|
errorCode = "The method " + this->methodName + " does not exist.";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ker::Vector<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(LocalContext &context) const override {
|
||||||
|
Method *method = context.module->method(this->methodName.str());
|
||||||
|
if(method == nullptr) {
|
||||||
|
return Type::Invalid;
|
||||||
|
}
|
||||||
|
return method->returnType();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template<Variable (*OP)(Variable, Variable)>
|
template<Variable (*OP)(Variable, Variable)>
|
||||||
|
@ -353,6 +482,47 @@ namespace trainscript
|
||||||
|
|
||||||
return OP(left, right);
|
return OP(left, right);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool validate(LocalContext &context, ker::String &errorCode) const override {
|
||||||
|
errorCode = "";
|
||||||
|
if(this->lhs == nullptr) {
|
||||||
|
errorCode = "Left part of operand is missing.";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if(this->rhs == nullptr) {
|
||||||
|
errorCode = "Right part of operand is missing.";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Type lhsType = this->lhs->expectedResult(context);
|
||||||
|
Type rhsType = this->rhs->expectedResult(context);
|
||||||
|
if(lhsType != rhsType) {
|
||||||
|
errorCode = "Types of operands do not match.";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if(lhsType == Type::Invalid) {
|
||||||
|
errorCode = "Invalid type can't be used for operand.";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if(rhsType == Type::Void) {
|
||||||
|
errorCode = "VOID type can't be used for operand.";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(this->lhs->validate(context, errorCode) == false)
|
||||||
|
return false;
|
||||||
|
if(this->rhs->validate(context, errorCode) == false)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Type expectedResult(LocalContext &context) const override {
|
||||||
|
if(this->lhs == nullptr) {
|
||||||
|
return Type::Invalid;
|
||||||
|
} else {
|
||||||
|
return this->lhs->expectedResult(context);
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class IfExpression :
|
class IfExpression :
|
||||||
|
|
Loading…
Reference in a new issue