mirror of
https://github.com/krgamestudios/Toy.git
synced 2026-04-15 23:04:08 +10:00
Import and export are working
This commit is contained in:
@@ -30,9 +30,9 @@ DONE: Address circular references
|
|||||||
DONE: are compounds shallow or deep copies? Deep copies
|
DONE: are compounds shallow or deep copies? Deep copies
|
||||||
DONE: third output stream, for lexer/parser/compiler/interpreter errors
|
DONE: third output stream, for lexer/parser/compiler/interpreter errors
|
||||||
DONE: Assertion-based test scripts
|
DONE: Assertion-based test scripts
|
||||||
|
DONE: Import/export keywords
|
||||||
|
|
||||||
|
|
||||||
TODO: Import/export keywords
|
|
||||||
TODO: slice and dot notation around the builtin _index function
|
TODO: slice and dot notation around the builtin _index function
|
||||||
TODO: ternary operator
|
TODO: ternary operator
|
||||||
TODO: Nullish types?
|
TODO: Nullish types?
|
||||||
|
|||||||
37
scripts/test/imports-and-exports.toy
Normal file
37
scripts/test/imports-and-exports.toy
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
//test basic import/export
|
||||||
|
{
|
||||||
|
var variable: int = 42;
|
||||||
|
export variable as field;
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
import field as value;
|
||||||
|
assert value == 42, "import/export failed";
|
||||||
|
}
|
||||||
|
|
||||||
|
//test functions using import/export
|
||||||
|
{
|
||||||
|
fn f() {
|
||||||
|
import field;
|
||||||
|
|
||||||
|
assert field == 42, "import in function failed";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//test importing/exporting of functions
|
||||||
|
{
|
||||||
|
fn func() {
|
||||||
|
return 69;
|
||||||
|
}
|
||||||
|
|
||||||
|
export func;
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
import func;
|
||||||
|
assert func() == 69, "import/export of functions failed";
|
||||||
|
}
|
||||||
|
|
||||||
|
//TODO: test that variables retain their types with the typeOf keyword
|
||||||
|
|
||||||
|
print "All good";
|
||||||
@@ -716,6 +716,26 @@ static void writeCompilerWithJumps(Compiler* compiler, Node* node, void* breakAd
|
|||||||
compiler->bytecode[compiler->count++] = (unsigned char)OP_VAR_ASSIGN; //1 byte
|
compiler->bytecode[compiler->count++] = (unsigned char)OP_VAR_ASSIGN; //1 byte
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case NODE_IMPORT: {
|
||||||
|
//push the identifier, and the alias
|
||||||
|
writeLiteralToCompiler(compiler, node->import.identifier);
|
||||||
|
writeLiteralToCompiler(compiler, node->import.alias);
|
||||||
|
|
||||||
|
//push the import opcode
|
||||||
|
compiler->bytecode[compiler->count++] = (unsigned char)OP_IMPORT; //1 byte
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case NODE_EXPORT: {
|
||||||
|
//push the identifier, and the alias
|
||||||
|
writeLiteralToCompiler(compiler, node->import.identifier);
|
||||||
|
writeLiteralToCompiler(compiler, node->import.alias);
|
||||||
|
|
||||||
|
//push the import opcode
|
||||||
|
compiler->bytecode[compiler->count++] = (unsigned char)OP_EXPORT; //1 byte
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -81,6 +81,11 @@ void initInterpreter(Interpreter* interpreter) {
|
|||||||
|
|
||||||
initLiteralArray(&interpreter->stack);
|
initLiteralArray(&interpreter->stack);
|
||||||
|
|
||||||
|
interpreter->exports = ALLOCATE(LiteralDictionary, 1);
|
||||||
|
initLiteralDictionary(interpreter->exports);
|
||||||
|
interpreter->exportTypes = ALLOCATE(LiteralDictionary, 1);
|
||||||
|
initLiteralDictionary(interpreter->exportTypes);
|
||||||
|
|
||||||
setInterpreterPrint(interpreter, printWrapper);
|
setInterpreterPrint(interpreter, printWrapper);
|
||||||
setInterpreterAssert(interpreter, assertWrapper);
|
setInterpreterAssert(interpreter, assertWrapper);
|
||||||
setInterpreterError(interpreter, errorWrapper);
|
setInterpreterError(interpreter, errorWrapper);
|
||||||
@@ -115,6 +120,11 @@ void freeInterpreter(Interpreter* interpreter) {
|
|||||||
interpreter->scope = popScope(interpreter->scope);
|
interpreter->scope = popScope(interpreter->scope);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FREE(LiteralDictionary, interpreter->exports);
|
||||||
|
interpreter->exports = NULL;
|
||||||
|
FREE(LiteralDictionary, interpreter->exportTypes);
|
||||||
|
interpreter->exportTypes = NULL;
|
||||||
|
|
||||||
freeLiteralArray(&interpreter->literalCache);
|
freeLiteralArray(&interpreter->literalCache);
|
||||||
freeLiteralArray(&interpreter->stack);
|
freeLiteralArray(&interpreter->stack);
|
||||||
}
|
}
|
||||||
@@ -509,7 +519,7 @@ static bool execVarDecl(Interpreter* interpreter, bool lng) {
|
|||||||
printLiteralCustom(identifier, interpreter->errorOutput);
|
printLiteralCustom(identifier, interpreter->errorOutput);
|
||||||
interpreter->errorOutput("\"\n");
|
interpreter->errorOutput("\"\n");
|
||||||
|
|
||||||
freeLiteral(identifier); //TODO: test this
|
freeLiteral(identifier);
|
||||||
freeLiteral(type);
|
freeLiteral(type);
|
||||||
freeLiteral(val);
|
freeLiteral(val);
|
||||||
|
|
||||||
@@ -1071,6 +1081,8 @@ static bool execFnCall(Interpreter* interpreter) {
|
|||||||
inner.codeStart = -1;
|
inner.codeStart = -1;
|
||||||
inner.panic = false;
|
inner.panic = false;
|
||||||
initLiteralArray(&inner.stack);
|
initLiteralArray(&inner.stack);
|
||||||
|
inner.exports = interpreter->exports;
|
||||||
|
inner.exportTypes = interpreter->exportTypes;
|
||||||
setInterpreterPrint(&inner, interpreter->printOutput);
|
setInterpreterPrint(&inner, interpreter->printOutput);
|
||||||
setInterpreterAssert(&inner, interpreter->assertOutput);
|
setInterpreterAssert(&inner, interpreter->assertOutput);
|
||||||
setInterpreterError(&inner, interpreter->errorOutput);
|
setInterpreterError(&inner, interpreter->errorOutput);
|
||||||
@@ -1097,7 +1109,9 @@ static bool execFnCall(Interpreter* interpreter) {
|
|||||||
//free, and skip out
|
//free, and skip out
|
||||||
freeLiteralArray(&arguments);
|
freeLiteralArray(&arguments);
|
||||||
popScope(inner.scope);
|
popScope(inner.scope);
|
||||||
freeInterpreter(&inner);
|
|
||||||
|
freeLiteralArray(&inner.stack);
|
||||||
|
freeLiteralArray(&inner.literalCache);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -1111,7 +1125,9 @@ static bool execFnCall(Interpreter* interpreter) {
|
|||||||
//free, and skip out
|
//free, and skip out
|
||||||
freeLiteralArray(&arguments);
|
freeLiteralArray(&arguments);
|
||||||
popScope(inner.scope);
|
popScope(inner.scope);
|
||||||
freeInterpreter(&inner);
|
|
||||||
|
freeLiteralArray(&inner.stack);
|
||||||
|
freeLiteralArray(&inner.literalCache);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -1131,7 +1147,10 @@ static bool execFnCall(Interpreter* interpreter) {
|
|||||||
freeLiteral(arg);
|
freeLiteral(arg);
|
||||||
freeLiteralArray(&arguments);
|
freeLiteralArray(&arguments);
|
||||||
popScope(inner.scope);
|
popScope(inner.scope);
|
||||||
freeInterpreter(&inner);
|
|
||||||
|
|
||||||
|
freeLiteralArray(&inner.stack);
|
||||||
|
freeLiteralArray(&inner.literalCache);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -1162,7 +1181,9 @@ static bool execFnCall(Interpreter* interpreter) {
|
|||||||
freeLiteralArray(&rest);
|
freeLiteralArray(&rest);
|
||||||
freeLiteralArray(&arguments);
|
freeLiteralArray(&arguments);
|
||||||
popScope(inner.scope);
|
popScope(inner.scope);
|
||||||
freeInterpreter(&inner);
|
|
||||||
|
freeLiteralArray(&inner.stack);
|
||||||
|
freeLiteralArray(&inner.literalCache);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -1176,7 +1197,9 @@ static bool execFnCall(Interpreter* interpreter) {
|
|||||||
freeLiteral(lit);
|
freeLiteral(lit);
|
||||||
freeLiteralArray(&arguments);
|
freeLiteralArray(&arguments);
|
||||||
popScope(inner.scope);
|
popScope(inner.scope);
|
||||||
freeInterpreter(&inner);
|
|
||||||
|
freeLiteralArray(&inner.stack);
|
||||||
|
freeLiteralArray(&inner.literalCache);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -1227,7 +1250,7 @@ static bool execFnCall(Interpreter* interpreter) {
|
|||||||
freeLiteral(ret);
|
freeLiteral(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
//free
|
//manual free
|
||||||
//BUGFIX: handle scopes of functions, which refer to the parent scope (leaking memory)
|
//BUGFIX: handle scopes of functions, which refer to the parent scope (leaking memory)
|
||||||
while(inner.scope != AS_FUNCTION(func).scope) {
|
while(inner.scope != AS_FUNCTION(func).scope) {
|
||||||
for (int i = 0; i < inner.scope->variables.capacity; i++) {
|
for (int i = 0; i < inner.scope->variables.capacity; i++) {
|
||||||
@@ -1284,6 +1307,81 @@ static bool execFnReturn(Interpreter* interpreter) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool execImport(Interpreter* interpreter) {
|
||||||
|
Literal alias = popLiteralArray(&interpreter->stack);
|
||||||
|
Literal identifier = popLiteralArray(&interpreter->stack);
|
||||||
|
|
||||||
|
Literal lit = getLiteralDictionary(interpreter->exports, identifier);
|
||||||
|
Literal type = getLiteralDictionary(interpreter->exportTypes, identifier);
|
||||||
|
|
||||||
|
//use the alias
|
||||||
|
if (!IS_NULL(alias)) {
|
||||||
|
if (!declareScopeVariable(interpreter->scope, alias, type)) {
|
||||||
|
interpreter->errorOutput("Can't redefine the variable \"");
|
||||||
|
printLiteralCustom(alias, interpreter->errorOutput);
|
||||||
|
interpreter->errorOutput("\"\n");
|
||||||
|
|
||||||
|
freeLiteral(lit);
|
||||||
|
freeLiteral(type);
|
||||||
|
freeLiteral(alias);
|
||||||
|
freeLiteral(identifier);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
setScopeVariable(interpreter->scope, alias, lit, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
//use the original identifier
|
||||||
|
else {
|
||||||
|
if (!declareScopeVariable(interpreter->scope, identifier, type)) {
|
||||||
|
interpreter->errorOutput("Can't redefine the variable \"");
|
||||||
|
printLiteralCustom(identifier, interpreter->errorOutput);
|
||||||
|
interpreter->errorOutput("\"\n");
|
||||||
|
|
||||||
|
freeLiteral(lit);
|
||||||
|
freeLiteral(type);
|
||||||
|
freeLiteral(alias);
|
||||||
|
freeLiteral(identifier);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
setScopeVariable(interpreter->scope, identifier, lit, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
//cleanup
|
||||||
|
freeLiteral(lit);
|
||||||
|
freeLiteral(type);
|
||||||
|
freeLiteral(alias);
|
||||||
|
freeLiteral(identifier);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool execExport(Interpreter* interpreter) {
|
||||||
|
Literal alias = popLiteralArray(&interpreter->stack);
|
||||||
|
Literal identifier = popLiteralArray(&interpreter->stack);
|
||||||
|
|
||||||
|
Literal lit = TO_NULL_LITERAL;
|
||||||
|
|
||||||
|
getScopeVariable(interpreter->scope, identifier, &lit);
|
||||||
|
Literal type = getScopeType(interpreter->scope, identifier);
|
||||||
|
|
||||||
|
if (!IS_NULL(alias)) {
|
||||||
|
setLiteralDictionary(interpreter->exports, alias, lit);
|
||||||
|
setLiteralDictionary(interpreter->exportTypes, alias, type);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
setLiteralDictionary(interpreter->exports, identifier, lit);
|
||||||
|
setLiteralDictionary(interpreter->exportTypes, identifier, type);
|
||||||
|
}
|
||||||
|
|
||||||
|
//cleanup
|
||||||
|
freeLiteral(lit);
|
||||||
|
freeLiteral(type);
|
||||||
|
freeLiteral(alias);
|
||||||
|
freeLiteral(identifier);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
//the heart of toy
|
//the heart of toy
|
||||||
static void execInterpreter(Interpreter* interpreter) {
|
static void execInterpreter(Interpreter* interpreter) {
|
||||||
//set the starting point for the interpreter
|
//set the starting point for the interpreter
|
||||||
@@ -1473,6 +1571,18 @@ static void execInterpreter(Interpreter* interpreter) {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case OP_IMPORT:
|
||||||
|
if (!execImport(interpreter)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_EXPORT:
|
||||||
|
if (!execExport(interpreter)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
case OP_POP_STACK:
|
case OP_POP_STACK:
|
||||||
while (interpreter->stack.count > 0) {
|
while (interpreter->stack.count > 0) {
|
||||||
freeLiteral(popLiteralArray(&interpreter->stack));
|
freeLiteral(popLiteralArray(&interpreter->stack));
|
||||||
|
|||||||
@@ -21,7 +21,8 @@ typedef struct Interpreter {
|
|||||||
LiteralArray stack;
|
LiteralArray stack;
|
||||||
|
|
||||||
//output
|
//output
|
||||||
// LiteralDictionary exports; //TODO: read-write - interface with Toy from C
|
LiteralDictionary* exports; //read-write - interface with Toy from C - this is a pointer, since it works at a script-level
|
||||||
|
LiteralDictionary* exportTypes;
|
||||||
PrintFn printOutput;
|
PrintFn printOutput;
|
||||||
PrintFn assertOutput;
|
PrintFn assertOutput;
|
||||||
PrintFn errorOutput;
|
PrintFn errorOutput;
|
||||||
|
|||||||
@@ -93,6 +93,12 @@ void freeNodeCustom(Node* node, bool freeSelf) {
|
|||||||
case NODE_INCREMENT_POSTFIX:
|
case NODE_INCREMENT_POSTFIX:
|
||||||
freeLiteral(node->increment.identifier);
|
freeLiteral(node->increment.identifier);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case NODE_IMPORT:
|
||||||
|
case NODE_EXPORT:
|
||||||
|
freeLiteral(node->import.identifier);
|
||||||
|
freeLiteral(node->import.alias);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (freeSelf) {
|
if (freeSelf) {
|
||||||
@@ -246,3 +252,13 @@ void emitNodePostfixIncrement(Node** nodeHandle, Literal identifier, int increme
|
|||||||
|
|
||||||
*nodeHandle = tmp;
|
*nodeHandle = tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void emitNodeImport(Node** nodeHandle, NodeType mode, Literal identifier, Literal alias) {
|
||||||
|
Node* tmp = ALLOCATE(Node, 1);
|
||||||
|
|
||||||
|
tmp->type = mode;
|
||||||
|
tmp->import.identifier = copyLiteral(identifier);
|
||||||
|
tmp->import.alias = copyLiteral(alias);
|
||||||
|
|
||||||
|
*nodeHandle = tmp;
|
||||||
|
}
|
||||||
@@ -23,11 +23,13 @@ typedef enum NodeType {
|
|||||||
NODE_PATH_IF, //for control flow
|
NODE_PATH_IF, //for control flow
|
||||||
NODE_PATH_WHILE, //for control flow
|
NODE_PATH_WHILE, //for control flow
|
||||||
NODE_PATH_FOR, //for control flow
|
NODE_PATH_FOR, //for control flow
|
||||||
NODE_PATH_BREAK,
|
NODE_PATH_BREAK, //for control flow
|
||||||
NODE_PATH_CONTINUE,
|
NODE_PATH_CONTINUE, //for control flow
|
||||||
NODE_PATH_RETURN,
|
NODE_PATH_RETURN,
|
||||||
NODE_INCREMENT_PREFIX,
|
NODE_INCREMENT_PREFIX,
|
||||||
NODE_INCREMENT_POSTFIX,
|
NODE_INCREMENT_POSTFIX,
|
||||||
|
NODE_IMPORT,
|
||||||
|
NODE_EXPORT,
|
||||||
} NodeType;
|
} NodeType;
|
||||||
|
|
||||||
typedef struct NodeLiteral {
|
typedef struct NodeLiteral {
|
||||||
@@ -116,6 +118,12 @@ typedef struct NodeIncrement {
|
|||||||
int increment;
|
int increment;
|
||||||
} NodeIncrement;
|
} NodeIncrement;
|
||||||
|
|
||||||
|
typedef struct NodeImport {
|
||||||
|
NodeType type;
|
||||||
|
Literal identifier;
|
||||||
|
Literal alias;
|
||||||
|
} NodeImport;
|
||||||
|
|
||||||
union _node {
|
union _node {
|
||||||
NodeType type;
|
NodeType type;
|
||||||
NodeLiteral atomic;
|
NodeLiteral atomic;
|
||||||
@@ -131,6 +139,7 @@ union _node {
|
|||||||
NodeFnCall fnCall;
|
NodeFnCall fnCall;
|
||||||
NodePath path;
|
NodePath path;
|
||||||
NodeIncrement increment;
|
NodeIncrement increment;
|
||||||
|
NodeImport import;
|
||||||
};
|
};
|
||||||
|
|
||||||
void freeNode(Node* node);
|
void freeNode(Node* node);
|
||||||
@@ -148,3 +157,4 @@ void emitNodeFnCollection(Node** nodeHandle);
|
|||||||
void emitNodePath(Node** nodeHandle, NodeType type, Node* preClause, Node* postClause, Node* condition, Node* thenPath, Node* elsePath);
|
void emitNodePath(Node** nodeHandle, NodeType type, Node* preClause, Node* postClause, Node* condition, Node* thenPath, Node* elsePath);
|
||||||
void emitNodePrefixIncrement(Node** nodeHandle, Literal identifier, int increment);
|
void emitNodePrefixIncrement(Node** nodeHandle, Literal identifier, int increment);
|
||||||
void emitNodePostfixIncrement(Node** nodeHandle, Literal identifier, int increment);
|
void emitNodePostfixIncrement(Node** nodeHandle, Literal identifier, int increment);
|
||||||
|
void emitNodeImport(Node** nodeHandle, NodeType mode, Literal identifier, Literal alias);
|
||||||
@@ -44,6 +44,9 @@ typedef enum Opcode {
|
|||||||
|
|
||||||
OP_TYPE_CAST, //temporarily change a type of an atomic value
|
OP_TYPE_CAST, //temporarily change a type of an atomic value
|
||||||
|
|
||||||
|
OP_IMPORT,
|
||||||
|
OP_EXPORT,
|
||||||
|
|
||||||
//comparion of values
|
//comparion of values
|
||||||
OP_COMPARE_EQUAL,
|
OP_COMPARE_EQUAL,
|
||||||
OP_COMPARE_NOT_EQUAL,
|
OP_COMPARE_NOT_EQUAL,
|
||||||
|
|||||||
@@ -1175,6 +1175,50 @@ static void returnStmt(Parser* parser, Node** nodeHandle) {
|
|||||||
emitNodePath(nodeHandle, NODE_PATH_RETURN, NULL, NULL, NULL, returnValues, NULL);
|
emitNodePath(nodeHandle, NODE_PATH_RETURN, NULL, NULL, NULL, returnValues, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void importStmt(Parser* parser, Node** nodeHandle) {
|
||||||
|
//read the identifier
|
||||||
|
Node* node = NULL;
|
||||||
|
advance(parser);
|
||||||
|
identifier(parser, &node);
|
||||||
|
Literal idn = copyLiteral(node->atomic.literal);
|
||||||
|
freeNode(node);
|
||||||
|
|
||||||
|
Literal alias = TO_NULL_LITERAL;
|
||||||
|
|
||||||
|
if (match(parser, TOKEN_AS)) {
|
||||||
|
advance(parser);
|
||||||
|
identifier(parser, &node);
|
||||||
|
alias = copyLiteral(node->atomic.literal);
|
||||||
|
freeNode(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
emitNodeImport(nodeHandle, NODE_IMPORT, idn, alias);
|
||||||
|
|
||||||
|
consume(parser, TOKEN_SEMICOLON, "Expected ';' at end of import statement");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void exportStmt(Parser* parser, Node** nodeHandle) {
|
||||||
|
//read the identifier
|
||||||
|
Node* node = NULL;
|
||||||
|
advance(parser);
|
||||||
|
identifier(parser, &node);
|
||||||
|
Literal idn = copyLiteral(node->atomic.literal);
|
||||||
|
freeNode(node);
|
||||||
|
|
||||||
|
Literal alias = TO_NULL_LITERAL;
|
||||||
|
|
||||||
|
if (match(parser, TOKEN_AS)) {
|
||||||
|
advance(parser);
|
||||||
|
identifier(parser, &node);
|
||||||
|
alias = copyLiteral(node->atomic.literal);
|
||||||
|
freeNode(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
emitNodeImport(nodeHandle, NODE_EXPORT, idn, alias);
|
||||||
|
|
||||||
|
consume(parser, TOKEN_SEMICOLON, "Expected ';' at end of export statement");
|
||||||
|
}
|
||||||
|
|
||||||
//precedence functions
|
//precedence functions
|
||||||
static void expressionStmt(Parser* parser, Node** nodeHandle) {
|
static void expressionStmt(Parser* parser, Node** nodeHandle) {
|
||||||
//BUGFIX: check for empty statements
|
//BUGFIX: check for empty statements
|
||||||
@@ -1248,6 +1292,18 @@ static void statement(Parser* parser, Node** nodeHandle) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//import
|
||||||
|
if (match(parser, TOKEN_IMPORT)) {
|
||||||
|
importStmt(parser, nodeHandle);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//export
|
||||||
|
if (match(parser, TOKEN_EXPORT)) {
|
||||||
|
exportStmt(parser, nodeHandle);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
//default
|
//default
|
||||||
expressionStmt(parser, nodeHandle);
|
expressionStmt(parser, nodeHandle);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -162,13 +162,14 @@ int main() {
|
|||||||
|
|
||||||
{
|
{
|
||||||
//run each file in ../scripts/test/
|
//run each file in ../scripts/test/
|
||||||
int count = 14;
|
int count = 15;
|
||||||
char* filenames[] = {
|
char* filenames[] = {
|
||||||
"arithmetic.toy",
|
"arithmetic.toy",
|
||||||
"casting.toy",
|
"casting.toy",
|
||||||
"comparisons.toy",
|
"comparisons.toy",
|
||||||
"dot-and-matrix.toy",
|
"dot-and-matrix.toy",
|
||||||
"functions.toy",
|
"functions.toy",
|
||||||
|
"imports-and-exports.toy",
|
||||||
"jumps.toy",
|
"jumps.toy",
|
||||||
"jumps-in-functions.toy",
|
"jumps-in-functions.toy",
|
||||||
"logicals.toy",
|
"logicals.toy",
|
||||||
|
|||||||
Reference in New Issue
Block a user