Variable refactoring pt.1 - Change union to pointer.
This commit is contained in:
parent
5f168f8020
commit
996bef56a6
12 changed files with 258 additions and 105 deletions
2
Depfile
2
Depfile
|
@ -2,7 +2,7 @@
|
||||||
Artifact=kernel
|
Artifact=kernel
|
||||||
TempDir=obj
|
TempDir=obj
|
||||||
SourceDir=asm src
|
SourceDir=asm src
|
||||||
Files=trainscript/trainscript.y trainscript/trainscript.l trainscript/tsvm.cpp
|
Files=trainscript/trainscript.y trainscript/trainscript.l trainscript/tsvm.cpp trainscript/variable.cpp
|
||||||
AdditionalObjects=obj/main.o
|
AdditionalObjects=obj/main.o
|
||||||
|
|
||||||
LexUseCpp
|
LexUseCpp
|
||||||
|
|
17
Makefile
17
Makefile
|
@ -12,8 +12,8 @@ YACC = bison
|
||||||
# File Lists
|
# File Lists
|
||||||
SRCS_AS = asm/dynamic.S asm/intr_common_handler.S asm/multiboot.S asm/start.S
|
SRCS_AS = asm/dynamic.S asm/intr_common_handler.S asm/multiboot.S asm/start.S
|
||||||
SRCS_CC = src/console.c src/init.c src/interrupts.c src/malloc.c src/pmm.c src/serial.c src/stdlib.c src/timer.c src/vmm.c
|
SRCS_CC = src/console.c src/init.c src/interrupts.c src/malloc.c src/pmm.c src/serial.c src/stdlib.c src/timer.c src/vmm.c
|
||||||
SRCS_CXX = trainscript/tsvm.cpp src/cplusplus.cpp src/vm.cpp obj/trainscript.yy.cpp obj/trainscript.tab.cpp
|
SRCS_CXX = trainscript/tsvm.cpp trainscript/variable.cpp src/cplusplus.cpp src/vm.cpp obj/trainscript.yy.cpp obj/trainscript.tab.cpp
|
||||||
OBJS = obj/tsvm.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/main.o
|
OBJS = obj/tsvm.o obj/variable.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/main.o
|
||||||
|
|
||||||
# Flags
|
# Flags
|
||||||
FLAGS = -m32 -Dnullptr=0 -D__cdecl="__attribute__((cdecl))" -mno-sse -mno-sse2 -mno-mmx
|
FLAGS = -m32 -Dnullptr=0 -D__cdecl="__attribute__((cdecl))" -mno-sse -mno-sse2 -mno-mmx
|
||||||
|
@ -27,10 +27,10 @@ all: kernel
|
||||||
|
|
||||||
.PHONY: clean
|
.PHONY: clean
|
||||||
clean:
|
clean:
|
||||||
$(RM) obj/trainscript.yy.cpp obj/trainscript.tab.cpp obj/tsvm.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/main.o
|
$(RM) obj/trainscript.yy.cpp obj/trainscript.tab.cpp obj/tsvm.o obj/variable.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/main.o
|
||||||
|
|
||||||
kernel: obj/tsvm.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/main.o
|
kernel: obj/tsvm.o obj/variable.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/main.o
|
||||||
$(LD) $(FLAGS) $(LDFLAGS) -o $@ obj/tsvm.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/main.o
|
$(LD) $(FLAGS) $(LDFLAGS) -o $@ obj/tsvm.o obj/variable.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/main.o
|
||||||
|
|
||||||
# src/console.c
|
# src/console.c
|
||||||
obj/console.o: src/console.c include/console.h include/stdlib.h \
|
obj/console.o: src/console.c include/console.h include/stdlib.h \
|
||||||
|
@ -96,6 +96,13 @@ obj/tsvm.o: trainscript/tsvm.cpp include/stdlib.h include/varargs.h \
|
||||||
obj/trainscript.tab.hpp trainscript/trainscript.l.h include/string.h
|
obj/trainscript.tab.hpp trainscript/trainscript.l.h include/string.h
|
||||||
$(CXX) -iquoteobj $(FLAGS) $(CXXFLAGS) -o $@ -c trainscript/tsvm.cpp
|
$(CXX) -iquoteobj $(FLAGS) $(CXXFLAGS) -o $@ -c trainscript/tsvm.cpp
|
||||||
|
|
||||||
|
# trainscript/variable.cpp
|
||||||
|
obj/variable.o: trainscript/variable.cpp include/kernel.h \
|
||||||
|
trainscript/variable.hpp 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
|
||||||
|
$(CXX) -iquoteobj $(FLAGS) $(CXXFLAGS) -o $@ -c trainscript/variable.cpp
|
||||||
|
|
||||||
# src/cplusplus.cpp
|
# src/cplusplus.cpp
|
||||||
obj/cplusplus.o: src/cplusplus.cpp include/stdlib.h include/varargs.h \
|
obj/cplusplus.o: src/cplusplus.cpp include/stdlib.h include/varargs.h \
|
||||||
include/config.h include/malloc.h include/console.h include/ker/new.hpp
|
include/config.h include/malloc.h include/console.h include/ker/new.hpp
|
||||||
|
|
21
README.md
21
README.md
|
@ -48,7 +48,26 @@ It also features a surveillance mode that logs all allocations / frees. It can b
|
||||||
|0x20 - 0x27| IRQ0 - IRQ7 |
|
|0x20 - 0x27| IRQ0 - IRQ7 |
|
||||||
|0x28 - 0x2F| IRQ8 - IRQ15 |
|
|0x28 - 0x2F| IRQ8 - IRQ15 |
|
||||||
|
|
||||||
###
|
## Virtual Machine Architecture
|
||||||
|
|
||||||
|
### Type Format
|
||||||
|
The virtual machine supports 5 base types:
|
||||||
|
|
||||||
|
| Name | Description | Size |
|
||||||
|
|---------|------------------------------------------------|--------|
|
||||||
|
| Void | A type that specifies a non-existent value. | 0 |
|
||||||
|
| Int | An integral number. | 32 |
|
||||||
|
| Real | A decimal number. | 32/64¹ |
|
||||||
|
| Text | A string value containing a sequence of bytes. | any² |
|
||||||
|
| Bool | A boolen value, either `true` or `false`. | 1³ |
|
||||||
|
|
||||||
|
¹) A real number is either a float (32 bits) or a double (64 bits) depending on the configuration in `types.hpp`.
|
||||||
|
²) A string value is sized the length of the string in bytes plus the size of the length specifier (32 bits).
|
||||||
|
³) A boolean is representet as a 1 bit value but due to architecture limitations it is stored with 32 bits.
|
||||||
|
|
||||||
|
### Variable Format
|
||||||
|
Variables are stored in a `type+pointer` format where `type` stores the type of the variable and `pointer` either a pointer to the variable value or, if `type` is a pointer type, the pointer value of the variable.
|
||||||
|
|
||||||
|
|
||||||
## OS Architecture
|
## OS Architecture
|
||||||
To be done.
|
To be done.
|
||||||
|
|
31
src/vm.cpp
31
src/vm.cpp
|
@ -82,33 +82,22 @@ Variable NativeMethod::invoke(Vector<Variable> arguments)
|
||||||
// Copy arguments
|
// Copy arguments
|
||||||
size_t stackSize = 0;
|
size_t stackSize = 0;
|
||||||
for(size_t i = 0; i < arguments.length(); i++) {
|
for(size_t i = 0; i < arguments.length(); i++) {
|
||||||
if(arguments[i].type != this->parameters[i]) {
|
if(arguments[i].type() != this->parameters[i]) {
|
||||||
// die_extra("NativeMethod.InvalidArgumentType", arguments[i].type.name());
|
// die_extra("NativeMethod.InvalidArgumentType", arguments[i].type.name());
|
||||||
}
|
}
|
||||||
switch(arguments[i].type.id) {
|
stackSize += arguments[i].type().size();
|
||||||
case TypeID::Bool: stackSize += sizeof(Int); break;
|
|
||||||
case TypeID::Int: stackSize += sizeof(Int); break;
|
|
||||||
case TypeID::Real: stackSize += sizeof(Real); break;
|
|
||||||
default: die_extra("NativeMethod.InvalidArgument", arguments[i].type.name()); break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t *stack = (uint8_t*)malloc(stackSize);
|
uint8_t *stack = (uint8_t*)malloc(stackSize);
|
||||||
uint8_t *stackPtr = stack;
|
uint8_t *stackPtr = stack;
|
||||||
for(size_t i = 0; i < arguments.length(); i++) {
|
for(size_t i = 0; i < arguments.length(); i++) {
|
||||||
switch(arguments[i].type.id) {
|
|
||||||
case TypeID::Bool:
|
size_t size = arguments[i].type().size();
|
||||||
*reinterpret_cast<Int*>(stackPtr) = arguments[i].boolean ? 1 : 0;
|
void *data = arguments[i].data();
|
||||||
stackPtr += sizeof(Int);
|
|
||||||
break;
|
if(size > 0) {
|
||||||
case TypeID::Int:
|
memcpy(stackPtr, data, size);
|
||||||
*reinterpret_cast<Int*>(stackPtr) = arguments[i].integer;
|
stackPtr += size;
|
||||||
stackPtr += sizeof(Int);
|
|
||||||
break;
|
|
||||||
case TypeID::Real:
|
|
||||||
*reinterpret_cast<Real*>(stackPtr) = arguments[i].real;
|
|
||||||
stackPtr += sizeof(Real);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -116,7 +105,7 @@ Variable NativeMethod::invoke(Vector<Variable> arguments)
|
||||||
|
|
||||||
free(stack);
|
free(stack);
|
||||||
|
|
||||||
return mkvar((Int)0);
|
return Type::Int.createInstance();
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" void __cdecl printInt(int i) {
|
extern "C" void __cdecl printInt(int i) {
|
||||||
|
|
|
@ -16,7 +16,8 @@ SOURCES += \
|
||||||
src/timer.c \
|
src/timer.c \
|
||||||
src/cplusplus.cpp \
|
src/cplusplus.cpp \
|
||||||
src/vm.cpp \
|
src/vm.cpp \
|
||||||
src/serial.c
|
src/serial.c \
|
||||||
|
trainscript/variable.cpp
|
||||||
|
|
||||||
HEADERS += \
|
HEADERS += \
|
||||||
include/console.h \
|
include/console.h \
|
||||||
|
|
|
@ -49,7 +49,7 @@ struct ParserData
|
||||||
struct VariableDeclaration
|
struct VariableDeclaration
|
||||||
{
|
{
|
||||||
char *name;
|
char *name;
|
||||||
trainscript::Variable variable;
|
trainscript::Type type;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct LocalVariable
|
struct LocalVariable
|
||||||
|
|
|
@ -46,7 +46,7 @@ namespace trainscript
|
||||||
}
|
}
|
||||||
|
|
||||||
Type expectedResult(ExecutionContext &) const override {
|
Type expectedResult(ExecutionContext &) const override {
|
||||||
return this->value.type;
|
return this->value.type();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -79,7 +79,7 @@ namespace trainscript
|
||||||
if(var == nullptr) {
|
if(var == nullptr) {
|
||||||
return Type::Invalid;
|
return Type::Invalid;
|
||||||
} else {
|
} else {
|
||||||
return var->type;
|
return var->type();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -109,18 +109,13 @@ namespace trainscript
|
||||||
die_extra("VariableAssignmentExpression.VariableNotFound", this->variableName.str());
|
die_extra("VariableAssignmentExpression.VariableNotFound", this->variableName.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
if(target->type != result.type) {
|
if(target->type() != result.type()) {
|
||||||
die_extra("VariableAssignmentExpression.ExpectedType", result.type.name());
|
die_extra("VariableAssignmentExpression.ExpectedType", result.type().name());
|
||||||
}
|
}
|
||||||
|
|
||||||
switch(target->type.id) {
|
*target = result;
|
||||||
case TypeID::Int: target->integer = result.integer; break;
|
|
||||||
case TypeID::Real: target->real = result.real; break;
|
|
||||||
case TypeID::Bool: target->boolean = result.boolean; break;
|
|
||||||
default: break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
return *target;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool validate(ExecutionContext &context, ker::String &errorCode) const override {
|
bool validate(ExecutionContext &context, ker::String &errorCode) const override {
|
||||||
|
@ -143,7 +138,7 @@ namespace trainscript
|
||||||
errorCode = "Variable " + this->variableName + " not found.";
|
errorCode = "Variable " + this->variableName + " not found.";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if(var->type != result) {
|
if(var->type() != result) {
|
||||||
errorCode = "Variable assignment has invalid type.";
|
errorCode = "Variable assignment has invalid type.";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -248,14 +243,14 @@ namespace trainscript
|
||||||
Variable left = this->lhs->execute(context);
|
Variable left = this->lhs->execute(context);
|
||||||
Variable right = this->rhs->execute(context);
|
Variable right = this->rhs->execute(context);
|
||||||
|
|
||||||
if(left.type != right.type) {
|
if(left.type() != right.type()) {
|
||||||
die("ArithmeticExpression.TypeMismatch");
|
die("ArithmeticExpression.TypeMismatch");
|
||||||
}
|
}
|
||||||
|
|
||||||
Variable result = OP(left, right);
|
Variable result = OP(left, right);
|
||||||
|
|
||||||
if(result.type.usable() == false) {
|
if(result.type().usable() == false) {
|
||||||
die_extra("ArithmeticExpression.InvalidResult", result.type.name());
|
die_extra("ArithmeticExpression.InvalidResult", result.type().name());
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -324,13 +319,13 @@ namespace trainscript
|
||||||
}
|
}
|
||||||
|
|
||||||
Variable result = this->condition->execute(context);
|
Variable result = this->condition->execute(context);
|
||||||
if(result.type != Type::Boolean) {
|
if(result.type() != Type::Bool) {
|
||||||
die_extra("IfExpression.TypeMismatch", result.type.name());
|
die_extra("IfExpression.TypeMismatch", result.type().name());
|
||||||
}
|
}
|
||||||
if((result.boolean == true) && (this->blockTrue != nullptr)) {
|
if((result.value<Bool>() == true) && (this->blockTrue != nullptr)) {
|
||||||
this->blockTrue->execute(context);
|
this->blockTrue->execute(context);
|
||||||
}
|
}
|
||||||
if((result.boolean == false) && (this->blockFalse != nullptr)) {
|
if((result.value<Bool>() == false) && (this->blockFalse != nullptr)) {
|
||||||
this->blockFalse->execute(context);
|
this->blockFalse->execute(context);
|
||||||
}
|
}
|
||||||
return Variable::Void;
|
return Variable::Void;
|
||||||
|
@ -389,10 +384,10 @@ namespace trainscript
|
||||||
while(true)
|
while(true)
|
||||||
{
|
{
|
||||||
Variable cond = this->condition->execute(context);
|
Variable cond = this->condition->execute(context);
|
||||||
if(cond.type != Type::Boolean) {
|
if(cond.type() != Type::Bool) {
|
||||||
return Variable::Invalid;
|
return Variable::Invalid;
|
||||||
}
|
}
|
||||||
if(cond.boolean == false) {
|
if(cond.value<Bool>() == false) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -145,7 +145,7 @@ void yyerror(void *scanner, const char *s);
|
||||||
input:
|
input:
|
||||||
%empty
|
%empty
|
||||||
| input variableDeclaration SEMICOLON {
|
| input variableDeclaration SEMICOLON {
|
||||||
auto *var = new Variable($2.variable);
|
auto *var = new Variable($2.type.createInstance());
|
||||||
context->module->variables.add( ker::String($2.name), var );
|
context->module->variables.add( ker::String($2.name), var );
|
||||||
}
|
}
|
||||||
| input method {
|
| input method {
|
||||||
|
@ -328,9 +328,9 @@ elseIfLoop:
|
||||||
;
|
;
|
||||||
|
|
||||||
expression:
|
expression:
|
||||||
INT { $$ = new ConstantExpression(mkvar($1)); }
|
INT { $$ = new ConstantExpression(Variable::fromInt($1)); }
|
||||||
| REAL { $$ = new ConstantExpression(mkvar($1)); }
|
| REAL { $$ = new ConstantExpression(Variable::fromReal($1)); }
|
||||||
// | TEXT { $$ = new ConstantExpression(mkvar($1)); }
|
// | TEXT { $$ = new ConstantExpression(Variable::fromText($1)); }
|
||||||
| IDENTIFIER { $$ = new VariableExpression($1); }
|
| IDENTIFIER { $$ = new VariableExpression($1); }
|
||||||
| IDENTIFIER LBRACKET expressionList RBRACKET {
|
| IDENTIFIER LBRACKET expressionList RBRACKET {
|
||||||
auto *call = new MethodInvokeExpression($1);
|
auto *call = new MethodInvokeExpression($1);
|
||||||
|
@ -379,8 +379,7 @@ expressionList:
|
||||||
variableDeclaration:
|
variableDeclaration:
|
||||||
KW_VAR IDENTIFIER COLON typeName {
|
KW_VAR IDENTIFIER COLON typeName {
|
||||||
$$.name = $2;
|
$$.name = $2;
|
||||||
$$.variable.type = $4;
|
$$.type = $4;
|
||||||
$$.variable.integer = 0; // Initialize with zeroes
|
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
|
|
|
@ -15,14 +15,14 @@ namespace trainscript
|
||||||
const Type Type::Int = { TypeID::Int, 0 };
|
const Type Type::Int = { TypeID::Int, 0 };
|
||||||
const Type Type::Real = { TypeID::Real, 0 };
|
const Type Type::Real = { TypeID::Real, 0 };
|
||||||
const Type Type::Text = { TypeID::Text, 0 };
|
const Type Type::Text = { TypeID::Text, 0 };
|
||||||
const Type Type::Boolean = { TypeID::Bool, 0 };
|
const Type Type::Bool = { TypeID::Bool, 0 };
|
||||||
|
|
||||||
const Variable Variable::Invalid = { Type::Invalid, 0 };
|
const Variable Variable::Invalid = { Type::Invalid, 0 };
|
||||||
const Variable Variable::Void = { Type::Void, 0 };
|
const Variable Variable::Void = { Type::Void, 0 };
|
||||||
const Variable Variable::Int = { Type::Int, 0 };
|
const Variable Variable::Int = { Type::Int, 0 };
|
||||||
const Variable Variable::Real = { Type::Real, 0 };
|
const Variable Variable::Real = { Type::Real, 0 };
|
||||||
const Variable Variable::Text = { Type::Text, 0 };
|
const Variable Variable::Text = { Type::Text, 0 };
|
||||||
const Variable Variable::Boolean = { Type::Boolean, 0 };
|
const Variable Variable::Bool = { Type::Bool, 0 };
|
||||||
|
|
||||||
bool Module::validate(ker::String &errorCode) const
|
bool Module::validate(ker::String &errorCode) const
|
||||||
{
|
{
|
||||||
|
@ -101,9 +101,7 @@ namespace trainscript
|
||||||
context.add(var.first, var.second);
|
context.add(var.first, var.second);
|
||||||
}
|
}
|
||||||
|
|
||||||
Variable returnVariable = {
|
Variable returnVariable = this->mReturnValue.second.createInstance();
|
||||||
this->mReturnValue.second, 0
|
|
||||||
};
|
|
||||||
|
|
||||||
if(this->mReturnValue.second.usable()) {
|
if(this->mReturnValue.second.usable()) {
|
||||||
context.add(this->mReturnValue.first, &returnVariable);
|
context.add(this->mReturnValue.first, &returnVariable);
|
||||||
|
@ -112,7 +110,7 @@ namespace trainscript
|
||||||
die_extra("ScriptMethod::invoke", "Invalid argument count.");
|
die_extra("ScriptMethod::invoke", "Invalid argument count.");
|
||||||
}
|
}
|
||||||
for(size_t i = 0; i < this->mArguments.length(); i++) {
|
for(size_t i = 0; i < this->mArguments.length(); i++) {
|
||||||
if(this->mArguments[i].second != arguments[i].type) {
|
if(this->mArguments[i].second != arguments[i].type()) {
|
||||||
die_extra("ScriptMethod::invoke", "Invalid argument type.");
|
die_extra("ScriptMethod::invoke", "Invalid argument type.");
|
||||||
}
|
}
|
||||||
auto *v = new Variable(arguments[i]);
|
auto *v = new Variable(arguments[i]);
|
||||||
|
@ -120,7 +118,7 @@ namespace trainscript
|
||||||
context.add(this->mArguments[i].first, v);
|
context.add(this->mArguments[i].first, v);
|
||||||
}
|
}
|
||||||
for(auto local : this->mLocals) {
|
for(auto local : this->mLocals) {
|
||||||
auto *v = new Variable { local.second, 0 };
|
auto *v = new Variable(local.second.createInstance());
|
||||||
temporaries.append(v);
|
temporaries.append(v);
|
||||||
context.add(local.first, v);
|
context.add(local.first, v);
|
||||||
}
|
}
|
||||||
|
@ -148,9 +146,7 @@ namespace trainscript
|
||||||
context.add(var.first, var.second);
|
context.add(var.first, var.second);
|
||||||
}
|
}
|
||||||
|
|
||||||
Variable returnVariable = {
|
Variable returnVariable = this->mReturnValue.second.createInstance();
|
||||||
this->mReturnValue.second, 0
|
|
||||||
};
|
|
||||||
|
|
||||||
if(this->mReturnValue.second.usable()) {
|
if(this->mReturnValue.second.usable()) {
|
||||||
if(context.get(this->mReturnValue.first) != nullptr) {
|
if(context.get(this->mReturnValue.first) != nullptr) {
|
||||||
|
@ -165,14 +161,14 @@ namespace trainscript
|
||||||
errorCode = "Parameter overlaps a variable.";
|
errorCode = "Parameter overlaps a variable.";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
context.add(this->mArguments[i].first, new Variable { this->mArguments[i].second, 0 });
|
context.add(this->mArguments[i].first, new Variable(this->mArguments[i].second.createInstance()));
|
||||||
}
|
}
|
||||||
for(auto local : this->mLocals) {
|
for(auto local : this->mLocals) {
|
||||||
if(context.get(local.first) != nullptr) {
|
if(context.get(local.first) != nullptr) {
|
||||||
errorCode = "Local variable overlaps a variable.";
|
errorCode = "Local variable overlaps a variable.";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
context.add(local.first, new Variable { local.second, 0 });
|
context.add(local.first, new Variable(local.second.createInstance()));
|
||||||
}
|
}
|
||||||
|
|
||||||
if(this->block->validate(context, errorCode) == false) {
|
if(this->block->validate(context, errorCode) == false) {
|
||||||
|
@ -184,6 +180,7 @@ namespace trainscript
|
||||||
|
|
||||||
namespace ops
|
namespace ops
|
||||||
{
|
{
|
||||||
|
/*
|
||||||
Variable add(Variable lhs, Variable rhs)
|
Variable add(Variable lhs, Variable rhs)
|
||||||
{
|
{
|
||||||
switch(lhs.type.id) {
|
switch(lhs.type.id) {
|
||||||
|
@ -297,5 +294,7 @@ namespace trainscript
|
||||||
return Variable::Invalid;
|
return Variable::Invalid;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,8 @@
|
||||||
|
|
||||||
namespace trainscript
|
namespace trainscript
|
||||||
{
|
{
|
||||||
|
class Variable;
|
||||||
|
|
||||||
struct Type
|
struct Type
|
||||||
{
|
{
|
||||||
TypeID id;
|
TypeID id;
|
||||||
|
@ -35,6 +37,12 @@ namespace trainscript
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *name() const {
|
const char *name() const {
|
||||||
|
if(this->pointer > 0) {
|
||||||
|
static char str[64];
|
||||||
|
strcpy(str, this->dereference().name());
|
||||||
|
strcat(str, "*");
|
||||||
|
return str;
|
||||||
|
} else {
|
||||||
switch(id) {
|
switch(id) {
|
||||||
case TypeID::Invalid: return "INVALID";
|
case TypeID::Invalid: return "INVALID";
|
||||||
case TypeID::Void: return "VOID";
|
case TypeID::Void: return "VOID";
|
||||||
|
@ -42,15 +50,36 @@ namespace trainscript
|
||||||
case TypeID::Real: return "REAL";
|
case TypeID::Real: return "REAL";
|
||||||
case TypeID::Text: return "TEXT";
|
case TypeID::Text: return "TEXT";
|
||||||
case TypeID::Bool: return "BOOL";
|
case TypeID::Bool: return "BOOL";
|
||||||
default: return "unknown";
|
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(Int);
|
||||||
|
case TypeID::Real: return sizeof(Real);
|
||||||
|
case TypeID::Text: return sizeof(Text);
|
||||||
|
case TypeID::Bool: return sizeof(Bool);
|
||||||
|
default: die("Type::size.UnknownTypeID");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Variable createInstance() const;
|
||||||
|
|
||||||
static const Type Invalid;
|
static const Type Invalid;
|
||||||
static const Type Void;
|
static const Type Void;
|
||||||
static const Type Int;
|
static const Type Int;
|
||||||
static const Type Real;
|
static const Type Real;
|
||||||
static const Type Text;
|
static const Type Text;
|
||||||
static const Type Boolean;
|
static const Type Bool;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
77
trainscript/variable.cpp
Normal file
77
trainscript/variable.cpp
Normal file
|
@ -0,0 +1,77 @@
|
||||||
|
#include <kernel.h>
|
||||||
|
#include "variable.hpp"
|
||||||
|
|
||||||
|
namespace trainscript
|
||||||
|
{
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Variable &Variable::operator =(const Variable &other)
|
||||||
|
{
|
||||||
|
if(this->mType != other.mType) {
|
||||||
|
die_extra("Variable.operator=", "Type mismatch.");
|
||||||
|
}
|
||||||
|
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 {
|
||||||
|
this->mValue = other.mValue;
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
Variable Type::createInstance() const
|
||||||
|
{
|
||||||
|
void *value = nullptr;
|
||||||
|
if(this->pointer > 0) {
|
||||||
|
switch(this->id) {
|
||||||
|
#define CREATE(type, initial) case TypeID::type: \
|
||||||
|
value = new trainscript::type(initial); \
|
||||||
|
break
|
||||||
|
CREATE(Bool, false);
|
||||||
|
CREATE(Int, 0);
|
||||||
|
CREATE(Real, 0.0);
|
||||||
|
CREATE(Text, "");
|
||||||
|
default:
|
||||||
|
die("Type::createInstance.InvalidTypeID");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Variable(*this, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#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)
|
||||||
|
}
|
|
@ -5,15 +5,66 @@
|
||||||
|
|
||||||
namespace trainscript
|
namespace trainscript
|
||||||
{
|
{
|
||||||
struct Variable
|
class Variable
|
||||||
{
|
{
|
||||||
Type type;
|
friend class Type;
|
||||||
union {
|
private:
|
||||||
Int integer;
|
Type mType;
|
||||||
Real real;
|
void *mValue;
|
||||||
// Text text;
|
private:
|
||||||
Bool boolean;
|
// 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(other.mType),
|
||||||
|
mValue(nullptr)
|
||||||
|
{
|
||||||
|
*this = other;
|
||||||
|
}
|
||||||
|
|
||||||
|
Variable(Variable &&other) :
|
||||||
|
mType(other.mType),
|
||||||
|
mValue(other.mValue)
|
||||||
|
{
|
||||||
|
other.mType = Type::Invalid;
|
||||||
|
other.mValue = nullptr;
|
||||||
|
}
|
||||||
|
~Variable();
|
||||||
|
|
||||||
|
Variable &operator =(const Variable &other);
|
||||||
|
|
||||||
|
void *data() const
|
||||||
|
{
|
||||||
|
return this->mValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
#if defined(TSVM_PRINTVAL)
|
#if defined(TSVM_PRINTVAL)
|
||||||
void printval() const
|
void printval() const
|
||||||
|
@ -27,29 +78,16 @@ namespace trainscript
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
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 Invalid;
|
||||||
static const Variable Void;
|
static const Variable Void;
|
||||||
static const Variable Int;
|
static const Variable Int;
|
||||||
static const Variable Real;
|
static const Variable Real;
|
||||||
static const Variable Text;
|
static const Variable Text;
|
||||||
static const Variable Boolean;
|
static const Variable Bool;
|
||||||
};
|
};
|
||||||
|
|
||||||
static inline Variable mkvar(Int value) {
|
|
||||||
Variable v = Variable::Int;
|
|
||||||
v.integer = value;
|
|
||||||
return v;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline Variable mkvar(Real value) {
|
|
||||||
Variable v = Variable::Real;
|
|
||||||
v.real = value;
|
|
||||||
return v;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline Variable mkbool(Bool value) {
|
|
||||||
Variable v = Variable::Boolean;
|
|
||||||
v.boolean = value;
|
|
||||||
return v;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue