Adds better debugging output. Also adds a return; to free :P

This commit is contained in:
Felix Queissner 2015-08-16 23:40:34 +02:00
parent 2faadc29e9
commit d55ff69193
17 changed files with 175 additions and 82 deletions

View file

@ -40,7 +40,7 @@ obj/console.o: src/console.c include/console.h include/stdlib.h \
# src/init.c # src/init.c
obj/init.o: src/init.c include/kernel.h include/stdlib.h include/varargs.h \ obj/init.o: src/init.c include/kernel.h include/stdlib.h include/varargs.h \
include/console.h include/interrupts.h include/cpustate.h include/pmm.h \ include/console.h include/interrupts.h include/cpustate.h include/pmm.h \
include/multiboot.h include/vmm.h include/timer.h include/multiboot.h include/vmm.h include/config.h include/timer.h
$(CC) $(FLAGS) $(CCFLAGS) -o $@ -c src/init.c $(CC) $(FLAGS) $(CCFLAGS) -o $@ -c src/init.c
# src/interrupts.c # src/interrupts.c
@ -69,8 +69,9 @@ obj/timer.o: src/timer.c include/timer.h include/kernel.h \
$(CC) $(FLAGS) $(CCFLAGS) -o $@ -c src/timer.c $(CC) $(FLAGS) $(CCFLAGS) -o $@ -c src/timer.c
# src/vmm.c # src/vmm.c
obj/vmm.o: src/vmm.c include/vmm.h include/pmm.h include/multiboot.h \ obj/vmm.o: src/vmm.c include/config.h include/vmm.h include/pmm.h \
include/stdlib.h include/varargs.h include/console.h include/kernel.h include/multiboot.h include/stdlib.h include/varargs.h include/console.h \
include/kernel.h
$(CC) $(FLAGS) $(CCFLAGS) -o $@ -c src/vmm.c $(CC) $(FLAGS) $(CCFLAGS) -o $@ -c src/vmm.c
# trainscript/tsvm.cpp # trainscript/tsvm.cpp

5
include/config.h Normal file
View file

@ -0,0 +1,5 @@
#pragma once
/*
#define USE_VIRTUAL_MEMORY_MANAGEMENT
//*/

View file

@ -46,12 +46,6 @@ 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) {
@ -82,11 +76,6 @@ namespace ker
return cat; 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 };
@ -122,6 +111,12 @@ namespace ker
return this->mText[index]; return this->mText[index];
} }
String & operator = (const String &other)
{
this->copyFrom(other.mText, other.mLength);
return *this;
}
bool operator ==(const String &other) const bool operator ==(const String &other) const
{ {
return this->equals(other); return this->equals(other);
@ -131,6 +126,12 @@ namespace ker
{ {
return !this->equals(other); return !this->equals(other);
} }
String operator +(const String &other) const
{
return this->append(other);
}
private: private:
void copyFrom(const uint8_t *bytes, size_t length) void copyFrom(const uint8_t *bytes, size_t length)
{ {
@ -142,6 +143,18 @@ namespace ker
this->mLength = length; this->mLength = length;
this->mText[this->mLength] = 0; // last byte is always 0 this->mText[this->mLength] = 0; // last byte is always 0
} }
public:
static String concat(const String &lhs, const String &rhs)
{
return lhs.append(rhs);
}
static String fromNumber(int32_t number, int radix = 10)
{
static char buffer[64];
itoa(number, buffer, radix);
return String(buffer);
}
}; };

View file

@ -8,6 +8,8 @@ extern "C" {
void die(const char *msg); void die(const char *msg);
void die_extra(const char *msg, const char *extra);
#if defined(__cplusplus) #if defined(__cplusplus)
} }
#endif #endif

View file

@ -95,6 +95,28 @@ static inline size_t strlen(const char *str)
return size; return size;
} }
static inline int strcmp(const char *p1, const char *p2)
{
while(*p1) {
if(*p2 == 0) {
return 1;
}
if(*p2 > *p1) {
return -1;
}
if(*p1 > *p2) {
return 1;
}
p1++;
p2++;
}
if (*p2) {
return -1;
}
return 0;
}
static inline void *calloc(size_t size) static inline void *calloc(size_t size)
{ {
void *mem = malloc(size); void *mem = malloc(size);

View file

@ -1,11 +1,14 @@
#pragma once #pragma once
#include <inttypes.h> #include <inttypes.h>
#include <config.h>
#if defined(__cplusplus) #if defined(__cplusplus)
extern "C" { extern "C" {
#endif #endif
#if defined(USE_VIRTUAL_MEMORY_MANAGEMENT)
#define VM_PRESENT 0x01 #define VM_PRESENT 0x01
#define VM_WRITABLE 0x02 #define VM_WRITABLE 0x02
#define VM_USER 0x04 #define VM_USER 0x04
@ -24,6 +27,8 @@ void vmm_init(void);
*/ */
void vmm_map(uintptr_t virtual, uintptr_t physical, uint32_t flags); void vmm_map(uintptr_t virtual, uintptr_t physical, uint32_t flags);
#endif
#if defined(__cplusplus) #if defined(__cplusplus)
} }
#endif #endif

View file

@ -3,11 +3,10 @@ VAR global : INT;
PUB main() | i : INT PUB main() | i : INT
BEGIN BEGIN
0 -> i; 0 -> i;
# Print numbers from 1 to 5 WHILE ((i + 1) -> i) <= 50 DO
WHILE ((i + 1) -> i) <= 5 DO
BEGIN BEGIN
printInt(i); printInt(i);
sleep(20); sleep(2);
END END
END END

View file

@ -4,18 +4,28 @@
#include <interrupts.h> #include <interrupts.h>
#include <pmm.h> #include <pmm.h>
#include <vmm.h> #include <vmm.h>
#include <timer.h> #include <timer.h>
#include <config.h>
void die(const char *msg) void die(const char *msg)
{ {
kputs("\n"); die_extra(msg, "");
ksetcolor(COLOR_RED, COLOR_WHITE); }
kputs(msg);
while(1) void die_extra(const char *msg, const char *extra)
{ {
__asm__ volatile ("cli; hlt;"); kputs("\n");
} ksetcolor(COLOR_RED, COLOR_WHITE);
kputs(msg);
if((extra != nullptr) && (strlen(extra) > 0)) {
kputs(": '");
kputs(extra);
kputc('\'');
}
while(1)
{
__asm__ volatile ("cli; hlt;");
}
} }
extern size_t mallocCount; extern size_t mallocCount;
@ -156,12 +166,14 @@ void init(const MultibootStructure *mbHeader)
pmm_init(mbHeader); pmm_init(mbHeader);
putsuccess(); putsuccess();
// uint32_t freeMem = pmm_calc_free(); uint32_t freeMem = pmm_calc_free();
//kprintf("Free memory: %d B, %d kB, %d MB\n", freeMem, freeMem >> 10, freeMem >> 20); kprintf("Free memory: %d B, %d kB, %d MB\n", freeMem, freeMem >> 10, freeMem >> 20);
kputs("Initialize virtual memory management: "); #if defined(USE_VIRTUAL_MEMORY_MANAGEMENT)
kputs("Initialize virtual memory management: ");
vmm_init(); vmm_init();
putsuccess(); putsuccess();
#endif
kputs("Initialize interrupts:"); kputs("Initialize interrupts:");
intr_init(); intr_init();
@ -171,12 +183,14 @@ void init(const MultibootStructure *mbHeader)
irq_enable(); irq_enable();
putsuccess(); putsuccess();
#if defined(USE_VIRTUAL_MEMORY_MANAGEMENT)
kputs("Prepare heap memory:"); kputs("Prepare heap memory:");
for(uintptr_t ptr = 0x400000; ptr < 0x800000; ptr += 4096) for(uintptr_t ptr = 0x400000; ptr < 0x800000; ptr += 4096)
{ {
vmm_map(ptr, (uintptr_t)pmm_alloc(), VM_PROGRAM); vmm_map(ptr, (uintptr_t)pmm_alloc(), VM_PROGRAM);
} }
putsuccess(); putsuccess();
#endif
kputs("Initialize timer:"); kputs("Initialize timer:");
timer_init(); timer_init();
@ -188,8 +202,6 @@ void init(const MultibootStructure *mbHeader)
timer_add_callback(1, update_statusbar); timer_add_callback(1, update_statusbar);
debug_test();
vm_start(); vm_start();
kputs("\x12\x04trainOS stopped.\x12\x07!\n"); kputs("\x12\x04trainOS stopped.\x12\x07!\n");

View file

@ -173,7 +173,10 @@ void *malloc(size_t len)
void free(void *p) void free(void *p)
{ {
freeCount++; freeCount++;
return;
struct __freelist *fp1, *fp2, *fpnew; struct __freelist *fp1, *fp2, *fpnew;
char *cp1, *cp2, *cpnew; char *cp1, *cp2, *cpnew;

View file

@ -66,7 +66,7 @@ Variable NativeMethod::invoke(Vector<Variable> arguments)
case TypeID::Bool: stackSize += sizeof(Int); break; case TypeID::Bool: stackSize += sizeof(Int); break;
case TypeID::Int: stackSize += sizeof(Int); break; case TypeID::Int: stackSize += sizeof(Int); break;
case TypeID::Real: stackSize += sizeof(Real); break; case TypeID::Real: stackSize += sizeof(Real); break;
default: die("invalid argument type."); break; default: die_extra("NativeMethod.InvalidArgument", arguments[i].type.name()); break;
} }
} }
@ -85,7 +85,6 @@ Variable NativeMethod::invoke(Vector<Variable> arguments)
*reinterpret_cast<Real*>(stack) = arguments[i].real; *reinterpret_cast<Real*>(stack) = arguments[i].real;
stack += sizeof(Real); stack += sizeof(Real);
break; break;
default: die("invalid argument type."); break;
} }
} }

View file

@ -1,8 +1,11 @@
#include "vmm.h" #include <config.h>
#include "pmm.h" #include <vmm.h>
#include "stdlib.h" #include <pmm.h>
#include "console.h" #include <stdlib.h>
#include "kernel.h" #include <console.h>
#include <kernel.h>
#if defined(USE_VIRTUAL_MEMORY_MANAGEMENT)
typedef struct typedef struct
{ {
@ -79,3 +82,5 @@ void vmm_init(void)
cr0 |= (1 << 31); cr0 |= (1 << 31);
__asm__ volatile("mov %0, %%cr0" : : "r" (cr0)); __asm__ volatile("mov %0, %%cr0" : : "r" (cr0));
} }
#endif

View file

@ -39,7 +39,8 @@ HEADERS += \
include/ker/dictionary.hpp \ include/ker/dictionary.hpp \
include/string.h \ include/string.h \
include/ker/new.hpp \ include/ker/new.hpp \
include/dynamic.h include/dynamic.h \
include/config.h
DISTFILES += \ DISTFILES += \
asm/intr_common_handler.S \ asm/intr_common_handler.S \

View file

@ -21,14 +21,29 @@ void yyerror(void *scanner, const char *s);
} \ } \
} }
typedef struct struct ParserData
{ {
char *buffer; char *buffer;
size_t index; size_t index;
size_t length; size_t length;
trainscript::Module *module; trainscript::Module *module;
void *scanner; void *scanner;
} ParserData; char* strings[256];
char *strdup(const char *str)
{
for(size_t i = 0; i < 256; i++) {
if(this->strings[i] == nullptr) {
return this->strings[i] = ::strdup(str);
}
else if(strcmp(this->strings[i], str) == 0) {
return this->strings[i];
}
}
die_extra("ParserData::strdup", "out of strings");
}
};
struct VariableDeclaration struct VariableDeclaration
{ {

View file

@ -58,7 +58,7 @@ WHILE { return KW_WHILE; }
DO { return KW_DO; } DO { return KW_DO; }
[0-9]+\.[0-9]* { yylval->fval = atof(yytext); return REAL; } [0-9]+\.[0-9]* { yylval->fval = atof(yytext); return REAL; }
[0-9]+ { yylval->ival = atoi(yytext); return INT; } [0-9]+ { yylval->ival = atoi(yytext); return INT; }
[a-zA-Z0-9'_]+ { yylval->text = strdup(yytext); return IDENTIFIER; } [a-zA-Z0-9'_]+ { yylval->text = yyextra->strdup(yytext); return IDENTIFIER; }
. { yyerror(NULL, "illegal token"); } . { yyerror(NULL, "illegal token"); }
%% %%
/* /*

View file

@ -58,6 +58,12 @@ namespace trainscript
yylex_destroy(data.scanner); yylex_destroy(data.scanner);
free(internalStorage); free(internalStorage);
for(size_t i = 0; i < 256; i++) {
if(data.strings[i] != nullptr) {
free(data.strings[i]);
}
}
if(valid) { if(valid) {
return module; return module;
} else { } else {
@ -104,11 +110,11 @@ namespace trainscript
context.add(this->mReturnValue.first, &returnVariable); context.add(this->mReturnValue.first, &returnVariable);
} }
if(arguments.length() != this->mArguments.length()) { if(arguments.length() != this->mArguments.length()) {
return Variable::Invalid; 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) {
return Variable::Invalid; die_extra("ScriptMethod::invoke", "Invalid argument type.");
} }
context.add(this->mArguments[i].first, new Variable(arguments[i])); context.add(this->mArguments[i].first, new Variable(arguments[i]));
} }
@ -176,7 +182,7 @@ namespace trainscript
switch(lhs.type.id) { switch(lhs.type.id) {
case TypeID::Int:return mkvar(lhs.integer + rhs.integer); case TypeID::Int:return mkvar(lhs.integer + rhs.integer);
case TypeID::Real: return mkvar(lhs.real + rhs.real); case TypeID::Real: return mkvar(lhs.real + rhs.real);
default: kprintf("addition not supported for %s.\n", typeName(lhs.type.id)); return Variable::Invalid; default: kprintf("addition not supported for %s.\n", lhs.type.name()); return Variable::Invalid;
} }
} }
@ -185,7 +191,7 @@ namespace trainscript
switch(lhs.type.id) { switch(lhs.type.id) {
case TypeID::Int: return mkvar(lhs.integer - rhs.integer); case TypeID::Int: return mkvar(lhs.integer - rhs.integer);
case TypeID::Real:return mkvar(lhs.real - rhs.real); case TypeID::Real:return mkvar(lhs.real - rhs.real);
default: kprintf("subtraction not supported for %s.\n", typeName(lhs.type.id)); return Variable::Invalid; default: kprintf("subtraction not supported for %s.\n", lhs.type.name()); return Variable::Invalid;
} }
} }
@ -194,7 +200,7 @@ namespace trainscript
switch(lhs.type.id) { switch(lhs.type.id) {
case TypeID::Int: return mkvar(lhs.integer * rhs.integer); case TypeID::Int: return mkvar(lhs.integer * rhs.integer);
case TypeID::Real: return mkvar(lhs.real * rhs.real); case TypeID::Real: return mkvar(lhs.real * rhs.real);
default: kprintf("multiplication not supported for %s.\n", typeName(lhs.type.id)); return Variable::Invalid; default: kprintf("multiplication not supported for %s.\n", lhs.type.name()); return Variable::Invalid;
} }
} }
@ -203,7 +209,7 @@ namespace trainscript
switch(lhs.type.id) { switch(lhs.type.id) {
case TypeID::Int: return mkvar(lhs.integer / rhs.integer); case TypeID::Int: return mkvar(lhs.integer / rhs.integer);
case TypeID::Real: return mkvar(lhs.real / rhs.real); case TypeID::Real: return mkvar(lhs.real / rhs.real);
default: kprintf("division not supported for %s.\n", typeName(lhs.type.id)); return Variable::Invalid; default: kprintf("division not supported for %s.\n", lhs.type.name()); return Variable::Invalid;
} }
} }
@ -212,7 +218,7 @@ namespace trainscript
switch(lhs.type.id) { switch(lhs.type.id) {
case TypeID::Int: return mkvar(lhs.integer % rhs.integer); case TypeID::Int: return mkvar(lhs.integer % rhs.integer);
// case TypeID::Real: mkvar(lhs.real % rhs.real); // case TypeID::Real: mkvar(lhs.real % rhs.real);
default: kprintf("modulo not supported for %s.\n", typeName(lhs.type.id)); return Variable::Invalid; default: kprintf("modulo not supported for %s.\n", lhs.type.name()); return Variable::Invalid;
} }
} }
@ -223,7 +229,7 @@ namespace trainscript
case TypeID::Real: return mkbool(lhs.real == rhs.real); case TypeID::Real: return mkbool(lhs.real == rhs.real);
case TypeID::Bool: return mkbool(lhs.boolean == rhs.boolean); case TypeID::Bool: return mkbool(lhs.boolean == rhs.boolean);
default: default:
kprintf("equals not supported for %s.\n", typeName(lhs.type.id)); kprintf("equals not supported for %s.\n", lhs.type.name());
return Variable::Invalid; return Variable::Invalid;
} }
} }
@ -235,7 +241,7 @@ namespace trainscript
case TypeID::Real: return mkbool(lhs.real != rhs.real); case TypeID::Real: return mkbool(lhs.real != rhs.real);
case TypeID::Bool: return mkbool(lhs.boolean != rhs.boolean); case TypeID::Bool: return mkbool(lhs.boolean != rhs.boolean);
default: default:
kprintf("inequals not supported for %s.\n", typeName(lhs.type.id)); kprintf("inequals not supported for %s.\n", lhs.type.name());
return Variable::Invalid; return Variable::Invalid;
} }
} }
@ -247,7 +253,7 @@ namespace trainscript
case TypeID::Int: return mkbool(lhs.integer < rhs.integer); case TypeID::Int: return mkbool(lhs.integer < rhs.integer);
case TypeID::Real: return mkbool(lhs.real < rhs.real); case TypeID::Real: return mkbool(lhs.real < rhs.real);
default: default:
kprintf("equals not supported for %s.\n", typeName(lhs.type.id)); kprintf("equals not supported for %s.\n", lhs.type.name());
return Variable::Invalid; return Variable::Invalid;
} }
} }
@ -258,7 +264,7 @@ namespace trainscript
case TypeID::Int: return mkbool(lhs.integer <= rhs.integer); case TypeID::Int: return mkbool(lhs.integer <= rhs.integer);
case TypeID::Real: return mkbool(lhs.real <= rhs.real); case TypeID::Real: return mkbool(lhs.real <= rhs.real);
default: default:
kprintf("equals not supported for %s.\n", typeName(lhs.type.id)); kprintf("equals not supported for %s.\n", lhs.type.name());
return Variable::Invalid; return Variable::Invalid;
} }
} }
@ -269,7 +275,7 @@ namespace trainscript
case TypeID::Int: return mkbool(lhs.integer > rhs.integer); case TypeID::Int: return mkbool(lhs.integer > rhs.integer);
case TypeID::Real: return mkbool(lhs.real > rhs.real); case TypeID::Real: return mkbool(lhs.real > rhs.real);
default: default:
kprintf("equals not supported for %s.\n", typeName(lhs.type.id)); kprintf("equals not supported for %s.\n", lhs.type.name());
return Variable::Invalid; return Variable::Invalid;
} }
} }
@ -280,7 +286,7 @@ namespace trainscript
case TypeID::Int: return mkbool(lhs.integer >= rhs.integer); case TypeID::Int: return mkbool(lhs.integer >= rhs.integer);
case TypeID::Real: return mkbool(lhs.real >= rhs.real); case TypeID::Real: return mkbool(lhs.real >= rhs.real);
default: default:
kprintf("equals not supported for %s.\n", typeName(lhs.type.id)); kprintf("equals not supported for %s.\n", lhs.type.name());
return Variable::Invalid; return Variable::Invalid;
} }
} }

View file

@ -54,6 +54,18 @@ namespace trainscript
(this->pointer != other.pointer); (this->pointer != other.pointer);
} }
const char *name() const {
switch(id) {
case TypeID::Invalid: return "INVALID";
case TypeID::Void: return "VOID";
case TypeID::Int: return "INT";
case TypeID::Real: return "REAL";
case TypeID::Text: return "TEXT";
case TypeID::Bool: return "BOOL";
default: return "unknown";
}
}
static const Type Invalid; static const Type Invalid;
static const Type Void; static const Type Void;
static const Type Int; static const Type Int;
@ -288,7 +300,7 @@ namespace trainscript
Variable execute(LocalContext &context) const override { Variable execute(LocalContext &context) const override {
auto *var = context.get(this->variableName); auto *var = context.get(this->variableName);
if(var == nullptr) { if(var == nullptr) {
return Variable::Invalid; die_extra("VariableExpression.VariableNotFound", this->variableName.str());
} }
return *var; return *var;
} }
@ -328,17 +340,17 @@ namespace trainscript
Variable execute(LocalContext &context) const override { Variable execute(LocalContext &context) const override {
if(this->expression == nullptr) { if(this->expression == nullptr) {
return Variable::Invalid; die("VariableAssignmentExpression.ExpressionMissing");
} }
Variable result = this->expression->execute(context); Variable result = this->expression->execute(context);
Variable *target = context.get(this->variableName); Variable *target = context.get(this->variableName);
if(target == nullptr) { if(target == nullptr) {
return Variable::Invalid; die_extra("VariableAssignmentExpression.VariableNotFound", this->variableName.str());
} }
if(target->type != result.type) { if(target->type != result.type) {
return Variable::Invalid; die_extra("VariableAssignmentExpression.ExpectedType", result.type.name());
} }
switch(target->type.id) { switch(target->type.id) {
@ -406,7 +418,7 @@ namespace trainscript
{ {
Method *method = context.module->method(this->methodName.str()); Method *method = context.module->method(this->methodName.str());
if(method == nullptr) { if(method == nullptr) {
return Variable::Invalid; die_extra("MethodInvokeExpression.MethodNotFound", this->methodName.str());
} }
ker::Vector<Variable> vars(this->parameters.length()); ker::Vector<Variable> vars(this->parameters.length());
@ -467,20 +479,25 @@ namespace trainscript
Variable execute(LocalContext &context) const override { Variable execute(LocalContext &context) const override {
if(this->lhs == nullptr) { if(this->lhs == nullptr) {
return Variable::Invalid; die_extra("ArithmeticExpression.ExpressionMissing", "Left-hand side");
} }
if(this->rhs == nullptr) { if(this->rhs == nullptr) {
return Variable::Invalid; die_extra("ArithmeticExpression.ExpressionMissing", "Right-hand side");
} }
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) {
return Variable::Invalid; die("ArithmeticExpression.TypeMismatch");
} }
return OP(left, right); Variable result = OP(left, right);
if(result.type.usable() == false) {
die_extra("ArithmeticExpression.InvalidResult", result.type.name());
}
return result;
} }
bool validate(LocalContext &context, ker::String &errorCode) const override { bool validate(LocalContext &context, ker::String &errorCode) const override {
@ -543,12 +560,12 @@ namespace trainscript
Variable execute(LocalContext &context) const override { Variable execute(LocalContext &context) const override {
if(this->condition == nullptr) { if(this->condition == nullptr) {
return Variable::Invalid; die("IfExpression.ConditionMissing");
} }
Variable result = this->condition->execute(context); Variable result = this->condition->execute(context);
if(result.type != Type::Boolean) { if(result.type != Type::Boolean) {
return Variable::Invalid; die_extra("IfExpression.TypeMismatch", result.type.name());
} }
if((result.boolean == true) && (this->blockTrue != nullptr)) { if((result.boolean == true) && (this->blockTrue != nullptr)) {
this->blockTrue->execute(context); this->blockTrue->execute(context);
@ -574,7 +591,7 @@ namespace trainscript
Variable execute(LocalContext &context) const override { Variable execute(LocalContext &context) const override {
if(this->block == nullptr) { if(this->block == nullptr) {
return Variable::Invalid; die("RepeatEndlessExpression.BlockMissing");
} }
while(true) while(true)
@ -603,10 +620,10 @@ namespace trainscript
Variable execute(LocalContext &context) const override { Variable execute(LocalContext &context) const override {
if(this->condition == nullptr) { if(this->condition == nullptr) {
return Variable::Invalid; die("RepeatWhileExpression.ConditionMissing");
} }
if(this->block == nullptr) { if(this->block == nullptr) {
return Variable::Invalid; die("RepeatWhileExpression.BlockMissing");
} }
while(true) while(true)

View file

@ -11,16 +11,4 @@ namespace trainscript
Text = 4, Text = 4,
Bool = 5, Bool = 5,
}; };
static const char *typeName(TypeID id) {
switch(id) {
case TypeID::Invalid: return "INVALID";
case TypeID::Void: return "VOID";
case TypeID::Int: return "INT";
case TypeID::Real: return "REAL";
case TypeID::Text: return "TEXT";
case TypeID::Bool: return "BOOL";
default: return "unknown";
}
}
} }