Refactors type system: Types now provide operators instead of prebuilt ones. Known bug: Second parameter gets lost.

This commit is contained in:
Felix Queissner 2015-08-20 17:28:41 +02:00
parent 996bef56a6
commit 2e858d8d91
11 changed files with 306 additions and 206 deletions

View file

@ -2,7 +2,9 @@
Artifact=kernel
TempDir=obj
SourceDir=asm src
Files=trainscript/trainscript.y trainscript/trainscript.l trainscript/tsvm.cpp trainscript/variable.cpp
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
@ -15,6 +17,7 @@ CXX=g++
LD=g++
LEX=flex
YACC=bison
TEMPLE=mono /home/felix/projects/temple/bin/Debug/temple.exe
# Flags
FLAGS=-m32 -Dnullptr=0 -D__cdecl="__attribute__((cdecl))" -mno-sse -mno-sse2 -mno-mmx

View file

@ -8,12 +8,13 @@ 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 src/cplusplus.cpp src/vm.cpp obj/trainscript.yy.cpp obj/trainscript.tab.cpp
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
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
# Flags
FLAGS = -m32 -Dnullptr=0 -D__cdecl="__attribute__((cdecl))" -mno-sse -mno-sse2 -mno-mmx
@ -27,10 +28,10 @@ all: kernel
.PHONY: clean
clean:
$(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
$(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
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/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/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
# src/console.c
obj/console.o: src/console.c include/console.h include/stdlib.h \
@ -97,12 +98,19 @@ obj/tsvm.o: trainscript/tsvm.cpp include/stdlib.h include/varargs.h \
$(CXX) -iquoteobj $(FLAGS) $(CXXFLAGS) -o $@ -c trainscript/tsvm.cpp
# trainscript/variable.cpp
obj/variable.o: trainscript/variable.cpp include/kernel.h \
obj/variable.o: trainscript/variable.cpp include/kernel.h include/console.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
# trainscript/type.cpp
obj/type.o: trainscript/type.cpp include/kernel.h include/console.h \
trainscript/type.hpp trainscript/types.hpp include/ker/string.hpp \
include/stdlib.h include/varargs.h include/config.h include/malloc.h \
trainscript/typeid.hpp trainscript/variable.hpp
$(CXX) -iquoteobj $(FLAGS) $(CXXFLAGS) -o $@ -c trainscript/type.cpp
# src/cplusplus.cpp
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
@ -149,6 +157,14 @@ obj/trainscript.tab.o: obj/trainscript.tab.cpp include/stdlib.h \
trainscript/trainscript.l.h include/string.h
$(CXX) -iquotetrainscript -iquoteobj $(FLAGS) $(CXXFLAGS) -o $@ -c obj/trainscript.tab.cpp
# obj/type-operators.cpp
obj/type-operators.o: obj/type-operators.cpp include/kernel.h \
include/console.h trainscript/type.hpp trainscript/types.hpp \
include/ker/string.hpp include/stdlib.h include/varargs.h \
include/config.h include/malloc.h trainscript/typeid.hpp \
trainscript/variable.hpp
$(CXX) -iquotetrainscript -iquoteobj $(FLAGS) $(CXXFLAGS) -o $@ -c obj/type-operators.cpp
# asm/dynamic.S
obj/dynamic.o: asm/dynamic.S
$(AS) $(FLAGS) $(ASFLAGS) -o $@ -c asm/dynamic.S
@ -171,6 +187,9 @@ obj/trainscript.yy.cpp: 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 \

View file

@ -17,7 +17,8 @@ SOURCES += \
src/cplusplus.cpp \
src/vm.cpp \
src/serial.c \
trainscript/variable.cpp
trainscript/variable.cpp \
trainscript/type.cpp
HEADERS += \
include/console.h \
@ -72,7 +73,8 @@ DISTFILES += \
Makefile.new \
scripts/main.ts \
asm/dynamic.S \
README.md
README.md \
trainscript/type-operators.cpp.tt
QMAKE_INCDIR =

View file

@ -39,7 +39,7 @@ namespace trainscript
{
public:
Variable value;
ConstantExpression(Variable value) : value(value) { }
ConstantExpression(const Variable &value) : value(value) { }
Variable execute(ExecutionContext &) const override {
return this->value;
@ -179,7 +179,7 @@ namespace trainscript
ker::Vector<Variable> vars(this->parameters.length());
vars.resize(this->parameters.length());
for(size_t i = 0; i < vars.length(); i++) {
vars[i] = this->parameters.at(i)->execute(context);
vars[i].replace(this->parameters.at(i)->execute(context));
}
return method->invoke(vars);
@ -218,14 +218,15 @@ namespace trainscript
}
};
template<Variable (*OP)(Variable, Variable)>
class ArithmeticExpression :
public Instruction
{
public:
Operation op;
Instruction *lhs, *rhs;
ArithmeticExpression(Instruction *lhs, Instruction *rhs) :
ArithmeticExpression(Instruction *lhs, Instruction *rhs, Operation op) :
op(op),
lhs(lhs),
rhs(rhs)
{
@ -247,7 +248,11 @@ namespace trainscript
die("ArithmeticExpression.TypeMismatch");
}
Variable result = OP(left, right);
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());
@ -280,6 +285,11 @@ namespace trainscript
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)

View file

@ -9,23 +9,6 @@
using namespace trainscript;
namespace trainscript {
namespace ops {
Variable add(Variable lhs, Variable rhs);
Variable subtract(Variable lhs, Variable rhs);
Variable multiply(Variable lhs, Variable rhs);
Variable divide(Variable lhs, Variable rhs);
Variable modulo(Variable lhs, Variable rhs);
Variable equals(Variable lhs, Variable rhs);
Variable inequals(Variable lhs, Variable rhs);
Variable less(Variable lhs, Variable rhs);
Variable lessEqual(Variable lhs, Variable rhs);
Variable greater(Variable lhs, Variable rhs);
Variable greaterEqual(Variable lhs, Variable rhs);
}
}
typedef union YYSTYPE YYSTYPE;
// stuff from flex that bison needs to know about:
@ -162,12 +145,16 @@ input:
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 );
@ -189,7 +176,9 @@ block:
if(mb->instruction != nullptr) {
block->instructions.append(mb->instruction);
}
MethodBody *tmp = mb;
mb = mb->next;
delete mb;
}
$$ = block;
}
@ -342,17 +331,17 @@ expression:
$$ = call;
}
| LBRACKET expression RBRACKET { $$ = $2; }
| expression PLUS expression { $$ = new ArithmeticExpression<trainscript::ops::add>($1, $3); }
| expression MINUS expression { $$ = new ArithmeticExpression<trainscript::ops::subtract>($1, $3); }
| expression MULTIPLY expression { $$ = new ArithmeticExpression<trainscript::ops::multiply>($1, $3); }
| expression DIVIDE expression { $$ = new ArithmeticExpression<trainscript::ops::divide>($1, $3); }
| expression MODULO expression { $$ = new ArithmeticExpression<trainscript::ops::modulo>($1, $3); }
| expression OP_LT expression { $$ = new ArithmeticExpression<trainscript::ops::less>($1, $3); }
| expression OP_LE expression { $$ = new ArithmeticExpression<trainscript::ops::lessEqual>($1, $3); }
| expression OP_GT expression { $$ = new ArithmeticExpression<trainscript::ops::greater>($1, $3); }
| expression OP_GE expression { $$ = new ArithmeticExpression<trainscript::ops::greaterEqual>($1, $3); }
| expression OP_EQ expression { $$ = new ArithmeticExpression<trainscript::ops::equals>($1, $3); }
| expression OP_NEQ expression { $$ = new ArithmeticExpression<trainscript::ops::inequals>($1, $3); }
| 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); }
;
@ -384,12 +373,12 @@ variableDeclaration:
;
typeName:
KW_VOID { $$.id = TypeID::Void; $$.pointer = 0; }
| KW_INT { $$.id = TypeID::Int; $$.pointer = 0; }
| KW_REAL { $$.id = TypeID::Real; $$.pointer = 0; }
| KW_TEXT { $$.id = TypeID::Text; $$.pointer = 0; }
| KW_BOOL { $$.id = TypeID::Bool; $$.pointer = 0; }
| KW_PTR LBRACKET typeName RBRACKET { $$ = $3; $$.pointer++; }
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(); }
;
%%

View file

@ -10,20 +10,6 @@
namespace trainscript
{
const Type Type::Invalid = { TypeID::Invalid, 0 };
const Type Type::Void = { TypeID::Void, 0 };
const Type Type::Int = { TypeID::Int, 0 };
const Type Type::Real = { TypeID::Real, 0 };
const Type Type::Text = { TypeID::Text, 0 };
const Type Type::Bool = { TypeID::Bool, 0 };
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 };
bool Module::validate(ker::String &errorCode) const
{
errorCode = "";
@ -177,124 +163,4 @@ namespace trainscript
return true;
}
namespace ops
{
/*
Variable add(Variable lhs, Variable rhs)
{
switch(lhs.type.id) {
case TypeID::Int:return mkvar(lhs.integer + rhs.integer);
case TypeID::Real: return mkvar(lhs.real + rhs.real);
default: kprintf("addition not supported for %s.\n", lhs.type.name()); return Variable::Invalid;
}
}
Variable subtract(Variable lhs, Variable rhs)
{
switch(lhs.type.id) {
case TypeID::Int: return mkvar(lhs.integer - rhs.integer);
case TypeID::Real:return mkvar(lhs.real - rhs.real);
default: kprintf("subtraction not supported for %s.\n", lhs.type.name()); return Variable::Invalid;
}
}
Variable multiply(Variable lhs, Variable rhs)
{
switch(lhs.type.id) {
case TypeID::Int: return mkvar(lhs.integer * rhs.integer);
case TypeID::Real: return mkvar(lhs.real * rhs.real);
default: kprintf("multiplication not supported for %s.\n", lhs.type.name()); return Variable::Invalid;
}
}
Variable divide(Variable lhs, Variable rhs)
{
switch(lhs.type.id) {
case TypeID::Int: return mkvar(lhs.integer / rhs.integer);
case TypeID::Real: return mkvar(lhs.real / rhs.real);
default: kprintf("division not supported for %s.\n", lhs.type.name()); return Variable::Invalid;
}
}
Variable modulo(Variable lhs, Variable rhs)
{
switch(lhs.type.id) {
case TypeID::Int: return mkvar(lhs.integer % rhs.integer);
// case TypeID::Real: mkvar(lhs.real % rhs.real);
default: kprintf("modulo not supported for %s.\n", lhs.type.name()); return Variable::Invalid;
}
}
Variable equals(Variable lhs, Variable rhs)
{
switch(lhs.type.id) {
case TypeID::Int: return mkbool(lhs.integer == rhs.integer);
case TypeID::Real: return mkbool(lhs.real == rhs.real);
case TypeID::Bool: return mkbool(lhs.boolean == rhs.boolean);
default:
kprintf("equals not supported for %s.\n", lhs.type.name());
return Variable::Invalid;
}
}
Variable inequals(Variable lhs, Variable rhs)
{
switch(lhs.type.id) {
case TypeID::Int: return mkbool(lhs.integer != rhs.integer);
case TypeID::Real: return mkbool(lhs.real != rhs.real);
case TypeID::Bool: return mkbool(lhs.boolean != rhs.boolean);
default:
kprintf("inequals not supported for %s.\n", lhs.type.name());
return Variable::Invalid;
}
}
Variable less(Variable lhs, Variable rhs)
{
switch(lhs.type.id) {
case TypeID::Int: return mkbool(lhs.integer < rhs.integer);
case TypeID::Real: return mkbool(lhs.real < rhs.real);
default:
kprintf("equals not supported for %s.\n", lhs.type.name());
return Variable::Invalid;
}
}
Variable lessEqual(Variable lhs, Variable rhs)
{
switch(lhs.type.id) {
case TypeID::Int: return mkbool(lhs.integer <= rhs.integer);
case TypeID::Real: return mkbool(lhs.real <= rhs.real);
default:
kprintf("equals not supported for %s.\n", lhs.type.name());
return Variable::Invalid;
}
}
Variable greater(Variable lhs, Variable rhs)
{
switch(lhs.type.id) {
case TypeID::Int: return mkbool(lhs.integer > rhs.integer);
case TypeID::Real: return mkbool(lhs.real > rhs.real);
default:
kprintf("equals not supported for %s.\n", lhs.type.name());
return Variable::Invalid;
}
}
Variable greaterEqual(Variable lhs, Variable rhs)
{
switch(lhs.type.id) {
case TypeID::Int: return mkbool(lhs.integer >= rhs.integer);
case TypeID::Real: return mkbool(lhs.real >= rhs.real);
default:
kprintf("equals not supported for %s.\n", lhs.type.name());
return Variable::Invalid;
}
}
*/
}
}

View file

@ -0,0 +1,89 @@
#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 ?>
}

41
trainscript/type.cpp Normal file
View file

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

View file

@ -8,17 +8,40 @@ 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 { id, pointer + 1 };
return Type { id, pointer + 1, operators };
}
Type dereference() const {
return { id, pointer - 1 };
return Type { id, pointer - 1, operators };
}
bool usable() const {
@ -73,8 +96,28 @@ namespace trainscript
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;

View file

@ -1,8 +1,17 @@
#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.
@ -20,11 +29,51 @@ namespace trainscript
}
}
void Variable::replace(const Variable &other)
{
this->setType(other.mType);
*this = other;
}
void Variable::setType(const Type &type)
{
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;
}
}
}
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: \
@ -42,26 +91,6 @@ namespace trainscript
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) \
{ \

View file

@ -28,9 +28,10 @@ namespace trainscript
}
Variable(const Variable &other) :
mType(other.mType),
mValue(nullptr)
mType(),
mValue()
{
this->setType(other.mType);
*this = other;
}
@ -45,6 +46,14 @@ namespace trainscript
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;