Variable refactoring pt.1 - Change union to pointer.

This commit is contained in:
Felix Queissner 2015-08-19 19:07:49 +02:00
parent 5f168f8020
commit 996bef56a6
12 changed files with 258 additions and 105 deletions

View file

@ -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

View file

@ -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

View file

@ -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.

View file

@ -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) {

View file

@ -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 \

View file

@ -49,7 +49,7 @@ struct ParserData
struct VariableDeclaration struct VariableDeclaration
{ {
char *name; char *name;
trainscript::Variable variable; trainscript::Type type;
}; };
struct LocalVariable struct LocalVariable

View file

@ -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;
} }

View file

@ -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
} }
; ;

View file

@ -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;
} }
} }
*/
} }
} }

View file

@ -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
View 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)
}

View file

@ -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;
}
} }