Compare commits
26 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 3498baad9b | |||
| 0649a141dd | |||
| 65e5905011 | |||
| bf64275aa9 | |||
| 08b400debf | |||
| 9ad2a6cf2e | |||
| 8009f410a4 | |||
| 584fb115b6 | |||
| 70698a4a1a | |||
| eb26d23363 | |||
| c1625c53f4 | |||
| fb55f42d0e | |||
| e4ef35092f | |||
| cfafba589b | |||
| f6367fa89d | |||
| d199209772 | |||
| 4cf5c6a5bf | |||
| 30c3a890ee | |||
| 130ac980fe | |||
| 923cf70c06 | |||
| c7465e1204 | |||
| 4518b59417 | |||
| 0b57f7efe7 | |||
| 7bf18a744c | |||
| fa20763c07 | |||
| 774f3d9e83 |
@@ -0,0 +1,5 @@
|
|||||||
|
# These are supported funding model platforms
|
||||||
|
|
||||||
|
patreon: krgamestudios
|
||||||
|
ko_fi: krgamestudios
|
||||||
|
custom: ["https://www.paypal.com/donate/?hosted_button_id=73Q82T2ZHV8AA"]
|
||||||
@@ -2,7 +2,7 @@ name: Comprehensive Tests
|
|||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches: [ "main" ]
|
branches: [ "main", "dev" ]
|
||||||
pull_request:
|
pull_request:
|
||||||
branches: [ "main" ]
|
branches: [ "main" ]
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
# License
|
# License
|
||||||
|
|
||||||
Copyright (c) 2020-2022 Kayne Ruse, KR Game Studios
|
Copyright (c) 2020-2023 Kayne Ruse, KR Game Studios
|
||||||
|
|
||||||
This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software.
|
This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software.
|
||||||
|
|
||||||
|
|||||||
@@ -1,51 +0,0 @@
|
|||||||
DONE: rework type system
|
|
||||||
DONE: var decl with a type, but no value
|
|
||||||
DONE: type casting
|
|
||||||
DONE: remove optimization option
|
|
||||||
DONE: conditionals
|
|
||||||
DONE: if-then-else
|
|
||||||
DONE: chained if-then-else
|
|
||||||
DONE: optional block around a path if it's only one statement
|
|
||||||
DONE: while-then
|
|
||||||
DONE: for-then
|
|
||||||
DONE: break and continue statements
|
|
||||||
DONE: truthiness rethink
|
|
||||||
DONE: string concat with the + operator
|
|
||||||
DONE: increment & decrement operators
|
|
||||||
DONE: store compound types in variables
|
|
||||||
DONE: += -= *= /= %= operators
|
|
||||||
DONE: && and || operators
|
|
||||||
DONE: functions are invoked by calling their names
|
|
||||||
DONE: function arguments can have specified types
|
|
||||||
DONE: function returns can have specified types
|
|
||||||
DONE: closures are explicitly supported
|
|
||||||
DONE: functions are first-class citizens
|
|
||||||
DONE: functions take a set number of parameters
|
|
||||||
DONE: functions last argument can be a rest parameter
|
|
||||||
DONE: assert needs to kill the whole script, not just functions
|
|
||||||
DONE: native functions
|
|
||||||
DONE: global functions _get, _set, _push, _pop, _length, clear available
|
|
||||||
DONE: change comma to colon in dictionary definition
|
|
||||||
DONE: Address circular references
|
|
||||||
DONE: are compounds shallow or deep copies? Deep copies
|
|
||||||
DONE: third output stream, for lexer/parser/compiler/interpreter errors
|
|
||||||
DONE: Assertion-based test scripts
|
|
||||||
DONE: Import/export keywords
|
|
||||||
DONE: A way to check the type of a variable (typeOf keyword)
|
|
||||||
DONE: slice and dot notation around the builtin _index and _dot functions
|
|
||||||
DONE: maximum recursion/function depth
|
|
||||||
DONE: better sugar for _push, _pop, _length
|
|
||||||
DONE: nested compound assignment bug
|
|
||||||
DONE: hooks on the external libraries, triggered on import
|
|
||||||
|
|
||||||
|
|
||||||
TODO: standard library
|
|
||||||
TODO: external script runner library
|
|
||||||
TODO: document how it all works
|
|
||||||
TODO: packaging for release?
|
|
||||||
TODO: test embedding in a game
|
|
||||||
|
|
||||||
NOPE: a = b = c = 1;
|
|
||||||
NOPE: functions return a set number of values
|
|
||||||
NOPE: ternary operator?
|
|
||||||
NOPE: Nullish types?
|
|
||||||
@@ -5,18 +5,33 @@ export TOY_OUTDIR = out
|
|||||||
|
|
||||||
all: $(TOY_OUTDIR) repl
|
all: $(TOY_OUTDIR) repl
|
||||||
|
|
||||||
|
#repl builds
|
||||||
repl: $(TOY_OUTDIR) library
|
repl: $(TOY_OUTDIR) library
|
||||||
$(MAKE) -C repl
|
$(MAKE) -C repl
|
||||||
|
|
||||||
repl-static: $(TOY_OUTDIR) static
|
repl-static: $(TOY_OUTDIR) static
|
||||||
$(MAKE) -C repl
|
$(MAKE) -C repl
|
||||||
|
|
||||||
|
repl-release: clean $(TOY_OUTDIR) library-release
|
||||||
|
$(MAKE) -C repl release
|
||||||
|
|
||||||
|
repl-static-release: clean $(TOY_OUTDIR) static-release
|
||||||
|
$(MAKE) -C repl release
|
||||||
|
|
||||||
|
#lib builds
|
||||||
library: $(TOY_OUTDIR)
|
library: $(TOY_OUTDIR)
|
||||||
$(MAKE) -j8 -C source library
|
$(MAKE) -j8 -C source library
|
||||||
|
|
||||||
static: $(TOY_OUTDIR)
|
static: $(TOY_OUTDIR)
|
||||||
$(MAKE) -j8 -C source static
|
$(MAKE) -j8 -C source static
|
||||||
|
|
||||||
|
library-release: $(TOY_OUTDIR)
|
||||||
|
$(MAKE) -j8 -C source library-release
|
||||||
|
|
||||||
|
static-release: $(TOY_OUTDIR)
|
||||||
|
$(MAKE) -j8 -C source static-release
|
||||||
|
|
||||||
|
#utils
|
||||||
test: clean $(TOY_OUTDIR)
|
test: clean $(TOY_OUTDIR)
|
||||||
$(MAKE) -C test
|
$(MAKE) -C test
|
||||||
|
|
||||||
|
|||||||
+3
-2
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#include "memory.h"
|
#include "memory.h"
|
||||||
|
|
||||||
|
#include <time.h>
|
||||||
#include <sys/time.h>
|
#include <sys/time.h>
|
||||||
|
|
||||||
static int nativeClock(Interpreter* interpreter, LiteralArray* arguments) {
|
static int nativeClock(Interpreter* interpreter, LiteralArray* arguments) {
|
||||||
@@ -18,7 +19,7 @@ static int nativeClock(Interpreter* interpreter, LiteralArray* arguments) {
|
|||||||
|
|
||||||
//push to the stack
|
//push to the stack
|
||||||
int len = strlen(timestr) - 1; //-1 for the newline
|
int len = strlen(timestr) - 1; //-1 for the newline
|
||||||
Literal timeLiteral = TO_STRING_LITERAL(copyString(timestr, len), len);
|
Literal timeLiteral = TO_STRING_LITERAL(createRefStringLength(timestr, len));
|
||||||
|
|
||||||
//push to the stack
|
//push to the stack
|
||||||
pushLiteralArray(&interpreter->stack, timeLiteral);
|
pushLiteralArray(&interpreter->stack, timeLiteral);
|
||||||
@@ -57,7 +58,7 @@ int hookStandard(Interpreter* interpreter, Literal identifier, Literal alias) {
|
|||||||
|
|
||||||
//load the dict with functions
|
//load the dict with functions
|
||||||
for (int i = 0; natives[i].name; i++) {
|
for (int i = 0; natives[i].name; i++) {
|
||||||
Literal name = TO_STRING_LITERAL(copyString(natives[i].name, strlen(natives[i].name)), strlen(natives[i].name));
|
Literal name = TO_STRING_LITERAL(createRefString(natives[i].name));
|
||||||
Literal func = TO_FUNCTION_LITERAL((void*)natives[i].fn, 0);
|
Literal func = TO_FUNCTION_LITERAL((void*)natives[i].fn, 0);
|
||||||
func.type = LITERAL_FUNCTION_NATIVE;
|
func.type = LITERAL_FUNCTION_NATIVE;
|
||||||
|
|
||||||
|
|||||||
+59
-14
@@ -1,25 +1,48 @@
|
|||||||
#include "lib_timer.h"
|
#include "lib_timer.h"
|
||||||
|
|
||||||
#include "toy_common.h"
|
|
||||||
#include "memory.h"
|
#include "memory.h"
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <sys/time.h>
|
||||||
|
|
||||||
|
//GOD DAMN IT: https://stackoverflow.com/questions/15846762/timeval-subtract-explanation
|
||||||
|
int timeval_subtract(struct timeval *result, struct timeval *x, struct timeval *y) {
|
||||||
|
//normallize
|
||||||
|
if (x->tv_usec > 999999) {
|
||||||
|
x->tv_sec += x->tv_usec / 1000000;
|
||||||
|
x->tv_usec %= 1000000;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (y->tv_usec > 999999) {
|
||||||
|
y->tv_sec += y->tv_usec / 1000000;
|
||||||
|
y->tv_usec %= 1000000;
|
||||||
|
}
|
||||||
|
|
||||||
|
//calc
|
||||||
|
result->tv_sec = x->tv_sec - y->tv_sec;
|
||||||
|
|
||||||
|
if ((result->tv_usec = x->tv_usec - y->tv_usec) < 0) {
|
||||||
|
if (result->tv_sec != 0) { //only works far from 0
|
||||||
|
result->tv_usec += 1000000;
|
||||||
|
result->tv_sec--; // borrow
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result->tv_sec < 0 || (result->tv_sec == 0 && result->tv_usec < 0);
|
||||||
|
}
|
||||||
|
|
||||||
//god damn it
|
//god damn it
|
||||||
static struct timeval* diff(struct timeval* lhs, struct timeval* rhs) {
|
static struct timeval* diff(struct timeval* lhs, struct timeval* rhs) {
|
||||||
struct timeval* d = ALLOCATE(struct timeval, 1);
|
struct timeval* d = ALLOCATE(struct timeval, 1);
|
||||||
|
|
||||||
d->tv_sec = rhs->tv_sec - lhs->tv_sec;
|
//I gave up, copied from SO
|
||||||
d->tv_usec = rhs->tv_usec - lhs->tv_usec;
|
timeval_subtract(d, rhs, lhs);
|
||||||
|
|
||||||
if (d->tv_usec < 0) {
|
|
||||||
d->tv_sec--;
|
|
||||||
d->tv_usec += 1000 * 1000;
|
|
||||||
}
|
|
||||||
|
|
||||||
return d;
|
return d;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//callbacks
|
||||||
static int nativeStartTimer(Interpreter* interpreter, LiteralArray* arguments) {
|
static int nativeStartTimer(Interpreter* interpreter, LiteralArray* arguments) {
|
||||||
//no arguments
|
//no arguments
|
||||||
if (arguments->count != 0) {
|
if (arguments->count != 0) {
|
||||||
@@ -60,6 +83,7 @@ static int nativeStopTimer(Interpreter* interpreter, LiteralArray* arguments) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!IS_OPAQUE(timeLiteral)) {
|
if (!IS_OPAQUE(timeLiteral)) {
|
||||||
|
interpreter->errorOutput("Incorrect argument type passed to _stopTimer\n");
|
||||||
freeLiteral(timeLiteral);
|
freeLiteral(timeLiteral);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@@ -100,6 +124,14 @@ static int nativeCreateTimer(Interpreter* interpreter, LiteralArray* arguments)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!IS_INTEGER(secondLiteral) || !IS_INTEGER(microsecondLiteral)) {
|
if (!IS_INTEGER(secondLiteral) || !IS_INTEGER(microsecondLiteral)) {
|
||||||
|
interpreter->errorOutput("Incorrect argument type passed to createTimer\n");
|
||||||
|
freeLiteral(secondLiteral);
|
||||||
|
freeLiteral(microsecondLiteral);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (AS_INTEGER(microsecondLiteral) <= -1000 * 1000 || AS_INTEGER(microsecondLiteral) >= 1000 * 1000 || (AS_INTEGER(secondLiteral) != 0 && AS_INTEGER(microsecondLiteral) < 0) ) {
|
||||||
|
interpreter->errorOutput("Microseconds out of range in createTimer\n");
|
||||||
freeLiteral(secondLiteral);
|
freeLiteral(secondLiteral);
|
||||||
freeLiteral(microsecondLiteral);
|
freeLiteral(microsecondLiteral);
|
||||||
return -1;
|
return -1;
|
||||||
@@ -124,7 +156,7 @@ static int nativeCreateTimer(Interpreter* interpreter, LiteralArray* arguments)
|
|||||||
static int nativeGetTimerSeconds(Interpreter* interpreter, LiteralArray* arguments) {
|
static int nativeGetTimerSeconds(Interpreter* interpreter, LiteralArray* arguments) {
|
||||||
//no arguments
|
//no arguments
|
||||||
if (arguments->count != 1) {
|
if (arguments->count != 1) {
|
||||||
interpreter->errorOutput("Incorrect number of arguments to getTimerSeconds\n");
|
interpreter->errorOutput("Incorrect number of arguments to _getTimerSeconds\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -137,6 +169,7 @@ static int nativeGetTimerSeconds(Interpreter* interpreter, LiteralArray* argumen
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!IS_OPAQUE(timeLiteral)) {
|
if (!IS_OPAQUE(timeLiteral)) {
|
||||||
|
interpreter->errorOutput("Incorrect argument type passed to _getTimerSeconds\n");
|
||||||
freeLiteral(timeLiteral);
|
freeLiteral(timeLiteral);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@@ -157,7 +190,7 @@ static int nativeGetTimerSeconds(Interpreter* interpreter, LiteralArray* argumen
|
|||||||
static int nativeGetTimerMicroseconds(Interpreter* interpreter, LiteralArray* arguments) {
|
static int nativeGetTimerMicroseconds(Interpreter* interpreter, LiteralArray* arguments) {
|
||||||
//no arguments
|
//no arguments
|
||||||
if (arguments->count != 1) {
|
if (arguments->count != 1) {
|
||||||
interpreter->errorOutput("Incorrect number of arguments to getTimerSeconds\n");
|
interpreter->errorOutput("Incorrect number of arguments to _getTimerMicroseconds\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -170,6 +203,7 @@ static int nativeGetTimerMicroseconds(Interpreter* interpreter, LiteralArray* ar
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!IS_OPAQUE(timeLiteral)) {
|
if (!IS_OPAQUE(timeLiteral)) {
|
||||||
|
interpreter->errorOutput("Incorrect argument type passed to _getTimerMicroseconds\n");
|
||||||
freeLiteral(timeLiteral);
|
freeLiteral(timeLiteral);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@@ -190,7 +224,7 @@ static int nativeGetTimerMicroseconds(Interpreter* interpreter, LiteralArray* ar
|
|||||||
static int nativeCompareTimer(Interpreter* interpreter, LiteralArray* arguments) {
|
static int nativeCompareTimer(Interpreter* interpreter, LiteralArray* arguments) {
|
||||||
//no arguments
|
//no arguments
|
||||||
if (arguments->count != 2) {
|
if (arguments->count != 2) {
|
||||||
interpreter->errorOutput("Incorrect number of arguments to _stopTimer\n");
|
interpreter->errorOutput("Incorrect number of arguments to _compareTimer\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -209,6 +243,7 @@ static int nativeCompareTimer(Interpreter* interpreter, LiteralArray* arguments)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!IS_OPAQUE(lhsLiteral) || !IS_OPAQUE(rhsLiteral)) {
|
if (!IS_OPAQUE(lhsLiteral) || !IS_OPAQUE(rhsLiteral)) {
|
||||||
|
interpreter->errorOutput("Incorrect argument type passed to _compareTimer\n");
|
||||||
freeLiteral(lhsLiteral);
|
freeLiteral(lhsLiteral);
|
||||||
freeLiteral(rhsLiteral);
|
freeLiteral(rhsLiteral);
|
||||||
return -1;
|
return -1;
|
||||||
@@ -246,6 +281,7 @@ static int nativeTimerToString(Interpreter* interpreter, LiteralArray* arguments
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!IS_OPAQUE(timeLiteral)) {
|
if (!IS_OPAQUE(timeLiteral)) {
|
||||||
|
interpreter->errorOutput("Incorrect argument type passed to _timerToString\n");
|
||||||
freeLiteral(timeLiteral);
|
freeLiteral(timeLiteral);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@@ -253,9 +289,17 @@ static int nativeTimerToString(Interpreter* interpreter, LiteralArray* arguments
|
|||||||
struct timeval* timer = AS_OPAQUE(timeLiteral);
|
struct timeval* timer = AS_OPAQUE(timeLiteral);
|
||||||
|
|
||||||
//create the string literal
|
//create the string literal
|
||||||
|
Literal resultLiteral = TO_NULL_LITERAL;
|
||||||
|
if (timer->tv_sec == 0 && timer->tv_usec < 0) { //special case, for when the negative sign is encoded in the usec
|
||||||
|
char buffer[128];
|
||||||
|
snprintf(buffer, 128, "-%ld.%06ld", timer->tv_sec, -timer->tv_usec);
|
||||||
|
resultLiteral = TO_STRING_LITERAL(createRefStringLength(buffer, strlen(buffer)));
|
||||||
|
}
|
||||||
|
else { //normal case
|
||||||
char buffer[128];
|
char buffer[128];
|
||||||
snprintf(buffer, 128, "%ld.%06ld", timer->tv_sec, timer->tv_usec);
|
snprintf(buffer, 128, "%ld.%06ld", timer->tv_sec, timer->tv_usec);
|
||||||
Literal resultLiteral = TO_STRING_LITERAL( copyString(buffer, strlen(buffer)), strlen(buffer));
|
resultLiteral = TO_STRING_LITERAL(createRefStringLength(buffer, strlen(buffer)));
|
||||||
|
}
|
||||||
|
|
||||||
pushLiteralArray(&interpreter->stack, resultLiteral);
|
pushLiteralArray(&interpreter->stack, resultLiteral);
|
||||||
|
|
||||||
@@ -269,7 +313,7 @@ static int nativeTimerToString(Interpreter* interpreter, LiteralArray* arguments
|
|||||||
static int nativeDestroyTimer(Interpreter* interpreter, LiteralArray* arguments) {
|
static int nativeDestroyTimer(Interpreter* interpreter, LiteralArray* arguments) {
|
||||||
//no arguments
|
//no arguments
|
||||||
if (arguments->count != 1) {
|
if (arguments->count != 1) {
|
||||||
interpreter->errorOutput("Incorrect number of arguments to _desroyTimer\n");
|
interpreter->errorOutput("Incorrect number of arguments to _destroyTimer\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -282,6 +326,7 @@ static int nativeDestroyTimer(Interpreter* interpreter, LiteralArray* arguments)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!IS_OPAQUE(timeLiteral)) {
|
if (!IS_OPAQUE(timeLiteral)) {
|
||||||
|
interpreter->errorOutput("Incorrect argument type passed to _destroyTimer\n");
|
||||||
freeLiteral(timeLiteral);
|
freeLiteral(timeLiteral);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@@ -330,7 +375,7 @@ int hookTimer(Interpreter* interpreter, Literal identifier, Literal alias) {
|
|||||||
|
|
||||||
//load the dict with functions
|
//load the dict with functions
|
||||||
for (int i = 0; natives[i].name; i++) {
|
for (int i = 0; natives[i].name; i++) {
|
||||||
Literal name = TO_STRING_LITERAL(copyString(natives[i].name, strlen(natives[i].name)), strlen(natives[i].name));
|
Literal name = TO_STRING_LITERAL(createRefString(natives[i].name));
|
||||||
Literal func = TO_FUNCTION_LITERAL((void*)natives[i].fn, 0);
|
Literal func = TO_FUNCTION_LITERAL((void*)natives[i].fn, 0);
|
||||||
func.type = LITERAL_FUNCTION_NATIVE;
|
func.type = LITERAL_FUNCTION_NATIVE;
|
||||||
|
|
||||||
|
|||||||
@@ -18,6 +18,9 @@ else
|
|||||||
$(CC) -DTOY_IMPORT $(CFLAGS) -o $(OUT) $(OBJ) -Wl,-rpath,. -L$(realpath $(shell pwd)/../$(TOY_OUTDIR)) $(LIBS)
|
$(CC) -DTOY_IMPORT $(CFLAGS) -o $(OUT) $(OBJ) -Wl,-rpath,. -L$(realpath $(shell pwd)/../$(TOY_OUTDIR)) $(LIBS)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
release: all
|
||||||
|
strip $(OUT)
|
||||||
|
|
||||||
$(OBJ): | $(ODIR)
|
$(OBJ): | $(ODIR)
|
||||||
|
|
||||||
$(ODIR):
|
$(ODIR):
|
||||||
|
|||||||
+4
-4
@@ -50,15 +50,15 @@ void repl() {
|
|||||||
ASTNode* node = scanParser(&parser);
|
ASTNode* node = scanParser(&parser);
|
||||||
while(node != NULL) {
|
while(node != NULL) {
|
||||||
//pack up and restart
|
//pack up and restart
|
||||||
if (node->type == AST_NODEERROR) {
|
if (node->type == AST_NODE_ERROR) {
|
||||||
printf(ERROR "error node detected\n" RESET);
|
printf(ERROR "error node detected\n" RESET);
|
||||||
error = true;
|
error = true;
|
||||||
freeNode(node);
|
freeASTNode(node);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
writeCompiler(&compiler, node);
|
writeCompiler(&compiler, node);
|
||||||
freeNode(node);
|
freeASTNode(node);
|
||||||
node = scanParser(&parser);
|
node = scanParser(&parser);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -100,7 +100,7 @@ int main(int argc, const char* argv[]) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO: remove this when the interpreter meets the specification
|
//version
|
||||||
if (command.verbose) {
|
if (command.verbose) {
|
||||||
printf(NOTICE "Toy Programming Language Version %d.%d.%d\n" RESET, TOY_VERSION_MAJOR, TOY_VERSION_MINOR, TOY_VERSION_PATCH);
|
printf(NOTICE "Toy Programming Language Version %d.%d.%d\n" RESET, TOY_VERSION_MAJOR, TOY_VERSION_MINOR, TOY_VERSION_PATCH);
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-3
@@ -78,16 +78,16 @@ unsigned char* compileString(char* source, size_t* size) {
|
|||||||
ASTNode* node = scanParser(&parser);
|
ASTNode* node = scanParser(&parser);
|
||||||
while(node != NULL) {
|
while(node != NULL) {
|
||||||
//pack up and leave
|
//pack up and leave
|
||||||
if (node->type == AST_NODEERROR) {
|
if (node->type == AST_NODE_ERROR) {
|
||||||
printf(ERROR "error node detected\n" RESET);
|
printf(ERROR "error node detected\n" RESET);
|
||||||
freeNode(node);
|
freeASTNode(node);
|
||||||
freeCompiler(&compiler);
|
freeCompiler(&compiler);
|
||||||
freeParser(&parser);
|
freeParser(&parser);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
writeCompiler(&compiler, node);
|
writeCompiler(&compiler, node);
|
||||||
freeNode(node);
|
freeASTNode(node);
|
||||||
node = scanParser(&parser);
|
node = scanParser(&parser);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+40
-57
@@ -1,66 +1,49 @@
|
|||||||
var size: int const = 100;
|
//number of iterations
|
||||||
|
var SIZE: int const = 100;
|
||||||
|
|
||||||
var prev = [];
|
//lookup table
|
||||||
for (var i = 0; i < size; i++) {
|
var lookup = [
|
||||||
prev.push(false);
|
"*": [
|
||||||
|
"*": [
|
||||||
|
"*": " ",
|
||||||
|
" ": "*"
|
||||||
|
],
|
||||||
|
" ": [
|
||||||
|
"*": "*",
|
||||||
|
" ": " "
|
||||||
|
]
|
||||||
|
], " ": [
|
||||||
|
"*": [
|
||||||
|
"*": "*",
|
||||||
|
" ": "*"
|
||||||
|
],
|
||||||
|
" ": [
|
||||||
|
"*": "*",
|
||||||
|
" ": " "
|
||||||
|
]
|
||||||
|
]];
|
||||||
|
|
||||||
|
//initial line to build from
|
||||||
|
var prev: string = "";
|
||||||
|
for (var i = 0; i < SIZE -1; i++) {
|
||||||
|
prev += " ";
|
||||||
}
|
}
|
||||||
|
prev += "*"; //initial
|
||||||
|
print prev;
|
||||||
|
|
||||||
prev.set(size - 1, true);
|
//run
|
||||||
|
|
||||||
|
|
||||||
fn calc(p, i) {
|
|
||||||
if (p[i-1] && p[i] && p[i+1]) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (p[i-1] && p[i] && !p[i+1]) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (p[i-1] && !p[i] && p[i+1]) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (p[i-1] && !p[i] && !p[i+1]) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!p[i-1] && p[i] && p[i+1]) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!p[i-1] && p[i] && !p[i+1]) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!p[i-1] && !p[i] && p[i+1]) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!p[i-1] && !p[i] && !p[i+1]) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
for (var iteration = 0; iteration < 100; iteration++) {
|
for (var iteration = 0; iteration < 100; iteration++) {
|
||||||
var line = [false];
|
//left
|
||||||
for (var i = 1; i < size-1; i++) {
|
var output = (lookup[" "][prev[0]][prev[1]]);
|
||||||
line.push(calc(prev, i));
|
|
||||||
}
|
|
||||||
line.push(false);
|
|
||||||
|
|
||||||
var output = "";
|
//middle
|
||||||
for (var i = 0; i < line.length(); i++) {
|
for (var i = 1; i < SIZE-1; i++) {
|
||||||
if (line[i]) {
|
output += (lookup[prev[i-1]][prev[i]][prev[i+1]]);
|
||||||
output += "*";
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
output += " ";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//right
|
||||||
|
output += (lookup[prev[SIZE-2]][prev[SIZE-1]][" "]);
|
||||||
|
|
||||||
print output;
|
print output;
|
||||||
prev = line;
|
prev = output;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,10 @@
|
|||||||
|
|
||||||
|
{
|
||||||
|
var t = astype [int];
|
||||||
|
var arr: t = [1, 2, 3.14];
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
var t = astype [string:int];
|
||||||
|
var dict: t = ["one": 1, "two": 2, "pi": 3.14];
|
||||||
|
}
|
||||||
|
|||||||
+187
-113
@@ -5,107 +5,130 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
void freeNodeCustom(ASTNode* node, bool freeSelf) {
|
void freeASTNodeCustom(ASTNode* node, bool freeSelf) {
|
||||||
//don't free a NULL node
|
//don't free a NULL node
|
||||||
if (node == NULL) {
|
if (node == NULL) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch(node->type) {
|
switch(node->type) {
|
||||||
case AST_NODEERROR:
|
case AST_NODE_ERROR:
|
||||||
//NO-OP
|
//NO-OP
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case AST_NODELITERAL:
|
case AST_NODE_LITERAL:
|
||||||
freeLiteral(node->atomic.literal);
|
freeLiteral(node->atomic.literal);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case AST_NODEUNARY:
|
case AST_NODE_UNARY:
|
||||||
freeNode(node->unary.child);
|
freeASTNode(node->unary.child);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case AST_NODEBINARY:
|
case AST_NODE_BINARY:
|
||||||
freeNode(node->binary.left);
|
freeASTNode(node->binary.left);
|
||||||
freeNode(node->binary.right);
|
freeASTNode(node->binary.right);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case AST_NODEGROUPING:
|
case AST_NODE_GROUPING:
|
||||||
freeNode(node->grouping.child);
|
freeASTNode(node->grouping.child);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case AST_NODEBLOCK:
|
case AST_NODE_BLOCK:
|
||||||
for (int i = 0; i < node->block.count; i++) {
|
for (int i = 0; i < node->block.count; i++) {
|
||||||
freeNodeCustom(node->block.nodes + i, false);
|
freeASTNodeCustom(node->block.nodes + i, false);
|
||||||
}
|
}
|
||||||
FREE_ARRAY(ASTNode, node->block.nodes, node->block.capacity);
|
FREE_ARRAY(ASTNode, node->block.nodes, node->block.capacity);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case AST_NODECOMPOUND:
|
case AST_NODE_COMPOUND:
|
||||||
for (int i = 0; i < node->compound.count; i++) {
|
for (int i = 0; i < node->compound.count; i++) {
|
||||||
freeNodeCustom(node->compound.nodes + i, false);
|
freeASTNodeCustom(node->compound.nodes + i, false);
|
||||||
}
|
}
|
||||||
FREE_ARRAY(ASTNode, node->compound.nodes, node->compound.capacity);
|
FREE_ARRAY(ASTNode, node->compound.nodes, node->compound.capacity);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case AST_NODEPAIR:
|
case AST_NODE_PAIR:
|
||||||
freeNode(node->pair.left);
|
freeASTNode(node->pair.left);
|
||||||
freeNode(node->pair.right);
|
freeASTNode(node->pair.right);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case AST_NODEVAR_DECL:
|
case AST_NODE_INDEX:
|
||||||
|
freeASTNode(node->index.first);
|
||||||
|
freeASTNode(node->index.second);
|
||||||
|
freeASTNode(node->index.third);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case AST_NODE_VAR_DECL:
|
||||||
freeLiteral(node->varDecl.identifier);
|
freeLiteral(node->varDecl.identifier);
|
||||||
freeLiteral(node->varDecl.typeLiteral);
|
freeLiteral(node->varDecl.typeLiteral);
|
||||||
freeNode(node->varDecl.expression);
|
freeASTNode(node->varDecl.expression);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case AST_NODEFN_DECL:
|
case AST_NODE_FN_COLLECTION:
|
||||||
freeLiteral(node->fnDecl.identifier);
|
|
||||||
freeNode(node->fnDecl.arguments);
|
|
||||||
freeNode(node->fnDecl.returns);
|
|
||||||
freeNode(node->fnDecl.block);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case AST_NODEFN_COLLECTION:
|
|
||||||
for (int i = 0; i < node->fnCollection.count; i++) {
|
for (int i = 0; i < node->fnCollection.count; i++) {
|
||||||
freeNodeCustom(node->fnCollection.nodes + i, false);
|
freeASTNodeCustom(node->fnCollection.nodes + i, false);
|
||||||
}
|
}
|
||||||
FREE_ARRAY(ASTNode, node->fnCollection.nodes, node->fnCollection.capacity);
|
FREE_ARRAY(ASTNode, node->fnCollection.nodes, node->fnCollection.capacity);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case AST_NODEFN_CALL:
|
case AST_NODE_FN_DECL:
|
||||||
freeNode(node->fnCall.arguments);
|
freeLiteral(node->fnDecl.identifier);
|
||||||
|
freeASTNode(node->fnDecl.arguments);
|
||||||
|
freeASTNode(node->fnDecl.returns);
|
||||||
|
freeASTNode(node->fnDecl.block);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case AST_NODEPATH_IF:
|
case AST_NODE_FN_CALL:
|
||||||
case AST_NODEPATH_WHILE:
|
freeASTNode(node->fnCall.arguments);
|
||||||
case AST_NODEPATH_FOR:
|
|
||||||
case AST_NODEPATH_BREAK:
|
|
||||||
case AST_NODEPATH_CONTINUE:
|
|
||||||
case AST_NODEPATH_RETURN:
|
|
||||||
freeNode(node->path.preClause);
|
|
||||||
freeNode(node->path.postClause);
|
|
||||||
freeNode(node->path.condition);
|
|
||||||
freeNode(node->path.thenPath);
|
|
||||||
freeNode(node->path.elsePath);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case AST_NODEINCREMENT_PREFIX:
|
case AST_NODE_FN_RETURN:
|
||||||
case AST_NODEINCREMENT_POSTFIX:
|
freeASTNode(node->returns.returns);
|
||||||
freeLiteral(node->increment.identifier);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case AST_NODEIMPORT:
|
case AST_NODE_IF:
|
||||||
case AST_NODEEXPORT:
|
freeASTNode(node->pathIf.condition);
|
||||||
|
freeASTNode(node->pathIf.thenPath);
|
||||||
|
freeASTNode(node->pathIf.elsePath);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case AST_NODE_WHILE:
|
||||||
|
freeASTNode(node->pathWhile.condition);
|
||||||
|
freeASTNode(node->pathWhile.thenPath);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case AST_NODE_FOR:
|
||||||
|
freeASTNode(node->pathFor.preClause);
|
||||||
|
freeASTNode(node->pathFor.postClause);
|
||||||
|
freeASTNode(node->pathFor.condition);
|
||||||
|
freeASTNode(node->pathFor.thenPath);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case AST_NODE_BREAK:
|
||||||
|
//NO-OP
|
||||||
|
break;
|
||||||
|
|
||||||
|
case AST_NODE_CONTINUE:
|
||||||
|
//NO-OP
|
||||||
|
break;
|
||||||
|
|
||||||
|
case AST_NODE_PREFIX_INCREMENT:
|
||||||
|
freeLiteral(node->prefixIncrement.identifier);
|
||||||
|
break;
|
||||||
|
case AST_NODE_PREFIX_DECREMENT:
|
||||||
|
freeLiteral(node->prefixDecrement.identifier);
|
||||||
|
break;
|
||||||
|
case AST_NODE_POSTFIX_INCREMENT:
|
||||||
|
freeLiteral(node->postfixIncrement.identifier);
|
||||||
|
break;
|
||||||
|
case AST_NODE_POSTFIX_DECREMENT:
|
||||||
|
freeLiteral(node->postfixDecrement.identifier);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case AST_NODE_IMPORT:
|
||||||
freeLiteral(node->import.identifier);
|
freeLiteral(node->import.identifier);
|
||||||
freeLiteral(node->import.alias);
|
freeLiteral(node->import.alias);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case AST_NODEINDEX:
|
|
||||||
case AST_NODEDOT:
|
|
||||||
freeNode(node->index.first);
|
|
||||||
freeNode(node->index.second);
|
|
||||||
freeNode(node->index.third);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (freeSelf) {
|
if (freeSelf) {
|
||||||
@@ -113,15 +136,16 @@ void freeNodeCustom(ASTNode* node, bool freeSelf) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void freeNode(ASTNode* node) {
|
void freeASTNode(ASTNode* node) {
|
||||||
freeNodeCustom(node, true);
|
freeASTNodeCustom(node, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//various emitters
|
||||||
void emitASTNodeLiteral(ASTNode** nodeHandle, Literal literal) {
|
void emitASTNodeLiteral(ASTNode** nodeHandle, Literal literal) {
|
||||||
//allocate a new node
|
//allocate a new node
|
||||||
*nodeHandle = ALLOCATE(ASTNode, 1);
|
*nodeHandle = ALLOCATE(ASTNode, 1);
|
||||||
|
|
||||||
(*nodeHandle)->type = AST_NODELITERAL;
|
(*nodeHandle)->type = AST_NODE_LITERAL;
|
||||||
(*nodeHandle)->atomic.literal = copyLiteral(literal);
|
(*nodeHandle)->atomic.literal = copyLiteral(literal);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -129,7 +153,7 @@ void emitASTNodeUnary(ASTNode** nodeHandle, Opcode opcode, ASTNode* child) {
|
|||||||
//allocate a new node
|
//allocate a new node
|
||||||
*nodeHandle = ALLOCATE(ASTNode, 1);
|
*nodeHandle = ALLOCATE(ASTNode, 1);
|
||||||
|
|
||||||
(*nodeHandle)->type = AST_NODEUNARY;
|
(*nodeHandle)->type = AST_NODE_UNARY;
|
||||||
(*nodeHandle)->unary.opcode = opcode;
|
(*nodeHandle)->unary.opcode = opcode;
|
||||||
(*nodeHandle)->unary.child = child;
|
(*nodeHandle)->unary.child = child;
|
||||||
}
|
}
|
||||||
@@ -137,7 +161,7 @@ void emitASTNodeUnary(ASTNode** nodeHandle, Opcode opcode, ASTNode* child) {
|
|||||||
void emitASTNodeBinary(ASTNode** nodeHandle, ASTNode* rhs, Opcode opcode) {
|
void emitASTNodeBinary(ASTNode** nodeHandle, ASTNode* rhs, Opcode opcode) {
|
||||||
ASTNode* tmp = ALLOCATE(ASTNode, 1);
|
ASTNode* tmp = ALLOCATE(ASTNode, 1);
|
||||||
|
|
||||||
tmp->type = AST_NODEBINARY;
|
tmp->type = AST_NODE_BINARY;
|
||||||
tmp->binary.opcode = opcode;
|
tmp->binary.opcode = opcode;
|
||||||
tmp->binary.left = *nodeHandle;
|
tmp->binary.left = *nodeHandle;
|
||||||
tmp->binary.right = rhs;
|
tmp->binary.right = rhs;
|
||||||
@@ -148,7 +172,7 @@ void emitASTNodeBinary(ASTNode** nodeHandle, ASTNode* rhs, Opcode opcode) {
|
|||||||
void emitASTNodeGrouping(ASTNode** nodeHandle) {
|
void emitASTNodeGrouping(ASTNode** nodeHandle) {
|
||||||
ASTNode* tmp = ALLOCATE(ASTNode, 1);
|
ASTNode* tmp = ALLOCATE(ASTNode, 1);
|
||||||
|
|
||||||
tmp->type = AST_NODEGROUPING;
|
tmp->type = AST_NODE_GROUPING;
|
||||||
tmp->grouping.child = *nodeHandle;
|
tmp->grouping.child = *nodeHandle;
|
||||||
|
|
||||||
*nodeHandle = tmp;
|
*nodeHandle = tmp;
|
||||||
@@ -157,8 +181,8 @@ void emitASTNodeGrouping(ASTNode** nodeHandle) {
|
|||||||
void emitASTNodeBlock(ASTNode** nodeHandle) {
|
void emitASTNodeBlock(ASTNode** nodeHandle) {
|
||||||
ASTNode* tmp = ALLOCATE(ASTNode, 1);
|
ASTNode* tmp = ALLOCATE(ASTNode, 1);
|
||||||
|
|
||||||
tmp->type = AST_NODEBLOCK;
|
tmp->type = AST_NODE_BLOCK;
|
||||||
tmp->block.nodes = NULL;
|
tmp->block.nodes = NULL; //NOTE: appended by the parser
|
||||||
tmp->block.capacity = 0;
|
tmp->block.capacity = 0;
|
||||||
tmp->block.count = 0;
|
tmp->block.count = 0;
|
||||||
|
|
||||||
@@ -168,7 +192,7 @@ void emitASTNodeBlock(ASTNode** nodeHandle) {
|
|||||||
void emitASTNodeCompound(ASTNode** nodeHandle, LiteralType literalType) {
|
void emitASTNodeCompound(ASTNode** nodeHandle, LiteralType literalType) {
|
||||||
ASTNode* tmp = ALLOCATE(ASTNode, 1);
|
ASTNode* tmp = ALLOCATE(ASTNode, 1);
|
||||||
|
|
||||||
tmp->type = AST_NODECOMPOUND;
|
tmp->type = AST_NODE_COMPOUND;
|
||||||
tmp->compound.literalType = literalType;
|
tmp->compound.literalType = literalType;
|
||||||
tmp->compound.nodes = NULL;
|
tmp->compound.nodes = NULL;
|
||||||
tmp->compound.capacity = 0;
|
tmp->compound.capacity = 0;
|
||||||
@@ -178,16 +202,27 @@ void emitASTNodeCompound(ASTNode** nodeHandle, LiteralType literalType) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void setASTNodePair(ASTNode* node, ASTNode* left, ASTNode* right) {
|
void setASTNodePair(ASTNode* node, ASTNode* left, ASTNode* right) {
|
||||||
//assume the node has already been allocated
|
//set - assume the node has already been allocated
|
||||||
node->type = AST_NODEPAIR;
|
node->type = AST_NODE_PAIR;
|
||||||
node->pair.left = left;
|
node->pair.left = left;
|
||||||
node->pair.right = right;
|
node->pair.right = right;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void emitASTNodeIndex(ASTNode** nodeHandle, ASTNode* first, ASTNode* second, ASTNode* third) {
|
||||||
|
ASTNode* tmp = ALLOCATE(ASTNode, 1);
|
||||||
|
|
||||||
|
tmp->type = AST_NODE_INDEX;
|
||||||
|
tmp->index.first = first;
|
||||||
|
tmp->index.second = second;
|
||||||
|
tmp->index.third = third;
|
||||||
|
|
||||||
|
*nodeHandle = tmp;
|
||||||
|
}
|
||||||
|
|
||||||
void emitASTNodeVarDecl(ASTNode** nodeHandle, Literal identifier, Literal typeLiteral, ASTNode* expression) {
|
void emitASTNodeVarDecl(ASTNode** nodeHandle, Literal identifier, Literal typeLiteral, ASTNode* expression) {
|
||||||
ASTNode* tmp = ALLOCATE(ASTNode, 1);
|
ASTNode* tmp = ALLOCATE(ASTNode, 1);
|
||||||
|
|
||||||
tmp->type = AST_NODEVAR_DECL;
|
tmp->type = AST_NODE_VAR_DECL;
|
||||||
tmp->varDecl.identifier = identifier;
|
tmp->varDecl.identifier = identifier;
|
||||||
tmp->varDecl.typeLiteral = typeLiteral;
|
tmp->varDecl.typeLiteral = typeLiteral;
|
||||||
tmp->varDecl.expression = expression;
|
tmp->varDecl.expression = expression;
|
||||||
@@ -195,10 +230,21 @@ void emitASTNodeVarDecl(ASTNode** nodeHandle, Literal identifier, Literal typeLi
|
|||||||
*nodeHandle = tmp;
|
*nodeHandle = tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void emitASTNodeFnCollection(ASTNode** nodeHandle) { //a collection of nodes, intended for use with functions
|
||||||
|
ASTNode* tmp = ALLOCATE(ASTNode, 1);
|
||||||
|
|
||||||
|
tmp->type = AST_NODE_FN_COLLECTION;
|
||||||
|
tmp->fnCollection.nodes = NULL;
|
||||||
|
tmp->fnCollection.capacity = 0;
|
||||||
|
tmp->fnCollection.count = 0;
|
||||||
|
|
||||||
|
*nodeHandle = tmp;
|
||||||
|
}
|
||||||
|
|
||||||
void emitASTNodeFnDecl(ASTNode** nodeHandle, Literal identifier, ASTNode* arguments, ASTNode* returns, ASTNode* block) {
|
void emitASTNodeFnDecl(ASTNode** nodeHandle, Literal identifier, ASTNode* arguments, ASTNode* returns, ASTNode* block) {
|
||||||
ASTNode* tmp = ALLOCATE(ASTNode, 1);
|
ASTNode* tmp = ALLOCATE(ASTNode, 1);
|
||||||
|
|
||||||
tmp->type = AST_NODEFN_DECL;
|
tmp->type = AST_NODE_FN_DECL;
|
||||||
tmp->fnDecl.identifier = identifier;
|
tmp->fnDecl.identifier = identifier;
|
||||||
tmp->fnDecl.arguments = arguments;
|
tmp->fnDecl.arguments = arguments;
|
||||||
tmp->fnDecl.returns = returns;
|
tmp->fnDecl.returns = returns;
|
||||||
@@ -207,88 +253,116 @@ void emitASTNodeFnDecl(ASTNode** nodeHandle, Literal identifier, ASTNode* argume
|
|||||||
*nodeHandle = tmp;
|
*nodeHandle = tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
void emitASTFnCall(ASTNode** nodeHandle, ASTNode* arguments, int argumentCount) {
|
void emitASTNodeFnCall(ASTNode** nodeHandle, ASTNode* arguments) {
|
||||||
ASTNode* tmp = ALLOCATE(ASTNode, 1);
|
ASTNode* tmp = ALLOCATE(ASTNode, 1);
|
||||||
|
|
||||||
tmp->type = AST_NODEFN_CALL;
|
tmp->type = AST_NODE_FN_CALL;
|
||||||
tmp->fnCall.arguments = arguments;
|
tmp->fnCall.arguments = arguments;
|
||||||
tmp->fnCall.argumentCount = argumentCount;
|
tmp->fnCall.argumentCount = arguments->fnCollection.count;
|
||||||
|
|
||||||
*nodeHandle = tmp;
|
*nodeHandle = tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
void emitASTNodeFnCollection(ASTNode** nodeHandle) { //a collection of nodes, intended for use with functions
|
void emitASTNodeFnReturn(ASTNode** nodeHandle, ASTNode* returns) {
|
||||||
ASTNode* tmp = ALLOCATE(ASTNode, 1);
|
ASTNode* tmp = ALLOCATE(ASTNode, 1);
|
||||||
|
|
||||||
tmp->type = AST_NODEFN_COLLECTION;
|
tmp->type = AST_NODE_FN_RETURN;
|
||||||
tmp->fnCollection.nodes = NULL;
|
tmp->returns.returns = returns;
|
||||||
tmp->fnCollection.capacity = 0;
|
|
||||||
tmp->fnCollection.count = 0;
|
|
||||||
|
|
||||||
*nodeHandle = tmp;
|
*nodeHandle = tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
void emitASTNodePath(ASTNode** nodeHandle, ASTNodeType type, ASTNode* preClause, ASTNode* postClause, ASTNode* condition, ASTNode* thenPath, ASTNode* elsePath) {
|
void emitASTNodeIf(ASTNode** nodeHandle, ASTNode* condition, ASTNode* thenPath, ASTNode* elsePath) {
|
||||||
ASTNode* tmp = ALLOCATE(ASTNode, 1);
|
ASTNode* tmp = ALLOCATE(ASTNode, 1);
|
||||||
|
|
||||||
tmp->type = type;
|
tmp->type = AST_NODE_IF;
|
||||||
tmp->path.preClause = preClause;
|
tmp->pathIf.condition = condition;
|
||||||
tmp->path.postClause = postClause;
|
tmp->pathIf.thenPath = thenPath;
|
||||||
tmp->path.condition = condition;
|
tmp->pathIf.elsePath = elsePath;
|
||||||
tmp->path.thenPath = thenPath;
|
|
||||||
tmp->path.elsePath = elsePath;
|
|
||||||
|
|
||||||
*nodeHandle = tmp;
|
*nodeHandle = tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
void emitASTNodePrefixIncrement(ASTNode** nodeHandle, Literal identifier, int increment) {
|
void emitASTNodeWhile(ASTNode** nodeHandle, ASTNode* condition, ASTNode* thenPath) {
|
||||||
ASTNode* tmp = ALLOCATE(ASTNode, 1);
|
ASTNode* tmp = ALLOCATE(ASTNode, 1);
|
||||||
|
|
||||||
tmp->type = AST_NODEINCREMENT_PREFIX;
|
tmp->type = AST_NODE_WHILE;
|
||||||
tmp->increment.identifier = copyLiteral(identifier);
|
tmp->pathWhile.condition = condition;
|
||||||
tmp->increment.increment = increment;
|
tmp->pathWhile.thenPath = thenPath;
|
||||||
|
|
||||||
*nodeHandle = tmp;
|
*nodeHandle = tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
void emitASTNodePostfixIncrement(ASTNode** nodeHandle, Literal identifier, int increment) {
|
void emitASTNodeFor(ASTNode** nodeHandle, ASTNode* preClause, ASTNode* condition, ASTNode* postClause, ASTNode* thenPath) {
|
||||||
ASTNode* tmp = ALLOCATE(ASTNode, 1);
|
ASTNode* tmp = ALLOCATE(ASTNode, 1);
|
||||||
|
|
||||||
tmp->type = AST_NODEINCREMENT_POSTFIX;
|
tmp->type = AST_NODE_FOR;
|
||||||
tmp->increment.identifier = copyLiteral(identifier);
|
tmp->pathFor.preClause = preClause;
|
||||||
tmp->increment.increment = increment;
|
tmp->pathFor.condition = condition;
|
||||||
|
tmp->pathFor.postClause = postClause;
|
||||||
|
tmp->pathFor.thenPath = thenPath;
|
||||||
|
|
||||||
*nodeHandle = tmp;
|
*nodeHandle = tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
void emitASTNodeImport(ASTNode** nodeHandle, ASTNodeType mode, Literal identifier, Literal alias) {
|
void emitASTNodeBreak(ASTNode** nodeHandle) {
|
||||||
ASTNode* tmp = ALLOCATE(ASTNode, 1);
|
ASTNode* tmp = ALLOCATE(ASTNode, 1);
|
||||||
|
|
||||||
tmp->type = mode;
|
tmp->type = AST_NODE_BREAK;
|
||||||
|
|
||||||
|
*nodeHandle = tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
void emitASTNodeContinue(ASTNode** nodeHandle) {
|
||||||
|
ASTNode* tmp = ALLOCATE(ASTNode, 1);
|
||||||
|
|
||||||
|
tmp->type = AST_NODE_CONTINUE;
|
||||||
|
|
||||||
|
*nodeHandle = tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
void emitASTNodePrefixIncrement(ASTNode** nodeHandle, Literal identifier) {
|
||||||
|
ASTNode* tmp = ALLOCATE(ASTNode, 1);
|
||||||
|
|
||||||
|
tmp->type = AST_NODE_PREFIX_INCREMENT;
|
||||||
|
tmp->prefixIncrement.identifier = copyLiteral(identifier);
|
||||||
|
|
||||||
|
*nodeHandle = tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
void emitASTNodePrefixDecrement(ASTNode** nodeHandle, Literal identifier) {
|
||||||
|
ASTNode* tmp = ALLOCATE(ASTNode, 1);
|
||||||
|
|
||||||
|
tmp->type = AST_NODE_PREFIX_DECREMENT;
|
||||||
|
tmp->prefixDecrement.identifier = copyLiteral(identifier);
|
||||||
|
|
||||||
|
*nodeHandle = tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
void emitASTNodePostfixIncrement(ASTNode** nodeHandle, Literal identifier) {
|
||||||
|
ASTNode* tmp = ALLOCATE(ASTNode, 1);
|
||||||
|
|
||||||
|
tmp->type = AST_NODE_POSTFIX_INCREMENT;
|
||||||
|
tmp->postfixIncrement.identifier = copyLiteral(identifier);
|
||||||
|
|
||||||
|
*nodeHandle = tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
void emitASTNodePostfixDecrement(ASTNode** nodeHandle, Literal identifier) {
|
||||||
|
ASTNode* tmp = ALLOCATE(ASTNode, 1);
|
||||||
|
|
||||||
|
tmp->type = AST_NODE_POSTFIX_DECREMENT;
|
||||||
|
tmp->postfixDecrement.identifier = copyLiteral(identifier);
|
||||||
|
|
||||||
|
*nodeHandle = tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
void emitASTNodeImport(ASTNode** nodeHandle, Literal identifier, Literal alias) {
|
||||||
|
ASTNode* tmp = ALLOCATE(ASTNode, 1);
|
||||||
|
|
||||||
|
tmp->type = AST_NODE_IMPORT;
|
||||||
tmp->import.identifier = copyLiteral(identifier);
|
tmp->import.identifier = copyLiteral(identifier);
|
||||||
tmp->import.alias = copyLiteral(alias);
|
tmp->import.alias = copyLiteral(alias);
|
||||||
|
|
||||||
*nodeHandle = tmp;
|
*nodeHandle = tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
void emitASTNodeIndex(ASTNode** nodeHandle, ASTNode* first, ASTNode* second, ASTNode* third) {
|
|
||||||
ASTNode* tmp = ALLOCATE(ASTNode, 1);
|
|
||||||
|
|
||||||
tmp->type = AST_NODEINDEX;
|
|
||||||
tmp->index.first = first;
|
|
||||||
tmp->index.second = second;
|
|
||||||
tmp->index.third = third;
|
|
||||||
|
|
||||||
*nodeHandle = tmp;
|
|
||||||
}
|
|
||||||
|
|
||||||
void emitASTNodeDot(ASTNode** nodeHandle, ASTNode* first) {
|
|
||||||
ASTNode* tmp = ALLOCATE(ASTNode, 1);
|
|
||||||
|
|
||||||
tmp->type = AST_NODEDOT;
|
|
||||||
tmp->index.first = first;
|
|
||||||
tmp->index.second = NULL;
|
|
||||||
tmp->index.third = NULL;
|
|
||||||
|
|
||||||
*nodeHandle = tmp;
|
|
||||||
}
|
|
||||||
|
|||||||
+153
-71
@@ -9,43 +9,52 @@
|
|||||||
typedef union _node ASTNode;
|
typedef union _node ASTNode;
|
||||||
|
|
||||||
typedef enum ASTNodeType {
|
typedef enum ASTNodeType {
|
||||||
AST_NODEERROR,
|
AST_NODE_ERROR,
|
||||||
AST_NODELITERAL, //a simple value
|
AST_NODE_LITERAL, //a simple value
|
||||||
AST_NODEUNARY, //one child + opcode
|
AST_NODE_UNARY, //one child + opcode
|
||||||
AST_NODEBINARY, //two children, left and right + opcode
|
AST_NODE_BINARY, //two children, left and right + opcode
|
||||||
AST_NODEGROUPING, //one child
|
AST_NODE_GROUPING, //one child
|
||||||
AST_NODEBLOCK, //contains a sub-node array
|
AST_NODE_BLOCK, //contains a sub-node array
|
||||||
AST_NODECOMPOUND, //contains a sub-node array
|
AST_NODE_COMPOUND, //contains a sub-node array
|
||||||
AST_NODEPAIR, //contains a left and right
|
AST_NODE_PAIR, //contains a left and right
|
||||||
AST_NODEVAR_DECL, //contains identifier literal, typenode, expression definition
|
AST_NODE_INDEX, //index a variable
|
||||||
AST_NODEFN_DECL, //containd identifier literal, arguments node, returns node, block node
|
AST_NODE_VAR_DECL, //contains identifier literal, typenode, expression definition
|
||||||
AST_NODEFN_COLLECTION, //parts of a function
|
AST_NODE_FN_DECL, //containd identifier literal, arguments node, returns node, block node
|
||||||
AST_NODEFN_CALL,
|
AST_NODE_FN_COLLECTION, //parts of a function
|
||||||
AST_NODEPATH_IF, //for control flow
|
AST_NODE_FN_CALL, //call a function
|
||||||
AST_NODEPATH_WHILE, //for control flow
|
AST_NODE_FN_RETURN, //for control flow
|
||||||
AST_NODEPATH_FOR, //for control flow
|
AST_NODE_IF, //for control flow
|
||||||
AST_NODEPATH_BREAK, //for control flow
|
AST_NODE_WHILE, //for control flow
|
||||||
AST_NODEPATH_CONTINUE, //for control flow
|
AST_NODE_FOR, //for control flow
|
||||||
AST_NODEPATH_RETURN,
|
AST_NODE_BREAK, //for control flow
|
||||||
AST_NODEINCREMENT_PREFIX,
|
AST_NODE_CONTINUE, //for control flow
|
||||||
AST_NODEINCREMENT_POSTFIX,
|
AST_NODE_PREFIX_INCREMENT, //increment a variable
|
||||||
AST_NODEIMPORT,
|
AST_NODE_POSTFIX_INCREMENT, //increment a variable
|
||||||
AST_NODEEXPORT,
|
AST_NODE_PREFIX_DECREMENT, //decrement a variable
|
||||||
AST_NODEINDEX,
|
AST_NODE_POSTFIX_DECREMENT, //decrement a variable
|
||||||
AST_NODEDOT,
|
AST_NODE_IMPORT, //import a library
|
||||||
} ASTNodeType;
|
} ASTNodeType;
|
||||||
|
|
||||||
|
//literals
|
||||||
|
void emitASTNodeLiteral(ASTNode** nodeHandle, Literal literal);
|
||||||
|
|
||||||
typedef struct NodeLiteral {
|
typedef struct NodeLiteral {
|
||||||
ASTNodeType type;
|
ASTNodeType type;
|
||||||
Literal literal;
|
Literal literal;
|
||||||
} NodeLiteral;
|
} NodeLiteral;
|
||||||
|
|
||||||
|
//unary operator
|
||||||
|
void emitASTNodeUnary(ASTNode** nodeHandle, Opcode opcode, ASTNode* child);
|
||||||
|
|
||||||
typedef struct NodeUnary {
|
typedef struct NodeUnary {
|
||||||
ASTNodeType type;
|
ASTNodeType type;
|
||||||
Opcode opcode;
|
Opcode opcode;
|
||||||
ASTNode* child;
|
ASTNode* child;
|
||||||
} NodeUnary;
|
} NodeUnary;
|
||||||
|
|
||||||
|
//binary operator
|
||||||
|
void emitASTNodeBinary(ASTNode** nodeHandle, ASTNode* rhs, Opcode opcode); //handled node becomes lhs
|
||||||
|
|
||||||
typedef struct NodeBinary {
|
typedef struct NodeBinary {
|
||||||
ASTNodeType type;
|
ASTNodeType type;
|
||||||
Opcode opcode;
|
Opcode opcode;
|
||||||
@@ -53,11 +62,17 @@ typedef struct NodeBinary {
|
|||||||
ASTNode* right;
|
ASTNode* right;
|
||||||
} NodeBinary;
|
} NodeBinary;
|
||||||
|
|
||||||
|
//grouping of other AST nodes
|
||||||
|
void emitASTNodeGrouping(ASTNode** nodeHandle);
|
||||||
|
|
||||||
typedef struct NodeGrouping {
|
typedef struct NodeGrouping {
|
||||||
ASTNodeType type;
|
ASTNodeType type;
|
||||||
ASTNode* child;
|
ASTNode* child;
|
||||||
} NodeGrouping;
|
} NodeGrouping;
|
||||||
|
|
||||||
|
//block of statement nodes
|
||||||
|
void emitASTNodeBlock(ASTNode** nodeHandle);
|
||||||
|
|
||||||
typedef struct NodeBlock {
|
typedef struct NodeBlock {
|
||||||
ASTNodeType type;
|
ASTNodeType type;
|
||||||
ASTNode* nodes;
|
ASTNode* nodes;
|
||||||
@@ -65,6 +80,9 @@ typedef struct NodeBlock {
|
|||||||
int count;
|
int count;
|
||||||
} NodeBlock;
|
} NodeBlock;
|
||||||
|
|
||||||
|
//compound literals (array, dictionary)
|
||||||
|
void emitASTNodeCompound(ASTNode** nodeHandle, LiteralType literalType);
|
||||||
|
|
||||||
typedef struct NodeCompound {
|
typedef struct NodeCompound {
|
||||||
ASTNodeType type;
|
ASTNodeType type;
|
||||||
LiteralType literalType;
|
LiteralType literalType;
|
||||||
@@ -73,12 +91,26 @@ typedef struct NodeCompound {
|
|||||||
int count;
|
int count;
|
||||||
} NodeCompound;
|
} NodeCompound;
|
||||||
|
|
||||||
|
void setASTNodePair(ASTNode* node, ASTNode* left, ASTNode* right); //NOTE: this is a set function, not an emit function
|
||||||
|
|
||||||
typedef struct NodePair {
|
typedef struct NodePair {
|
||||||
ASTNodeType type;
|
ASTNodeType type;
|
||||||
ASTNode* left;
|
ASTNode* left;
|
||||||
ASTNode* right;
|
ASTNode* right;
|
||||||
} NodePair;
|
} NodePair;
|
||||||
|
|
||||||
|
void emitASTNodeIndex(ASTNode** nodeHandle, ASTNode* first, ASTNode* second, ASTNode* third);
|
||||||
|
|
||||||
|
typedef struct NodeIndex {
|
||||||
|
ASTNodeType type;
|
||||||
|
ASTNode* first;
|
||||||
|
ASTNode* second;
|
||||||
|
ASTNode* third;
|
||||||
|
} NodeIndex;
|
||||||
|
|
||||||
|
//variable declaration
|
||||||
|
void emitASTNodeVarDecl(ASTNode** nodeHandle, Literal identifier, Literal type, ASTNode* expression);
|
||||||
|
|
||||||
typedef struct NodeVarDecl {
|
typedef struct NodeVarDecl {
|
||||||
ASTNodeType type;
|
ASTNodeType type;
|
||||||
Literal identifier;
|
Literal identifier;
|
||||||
@@ -86,6 +118,19 @@ typedef struct NodeVarDecl {
|
|||||||
ASTNode* expression;
|
ASTNode* expression;
|
||||||
} NodeVarDecl;
|
} NodeVarDecl;
|
||||||
|
|
||||||
|
//NOTE: fnCollection is used by fnDecl, fnCall and fnReturn
|
||||||
|
void emitASTNodeFnCollection(ASTNode** nodeHandle);
|
||||||
|
|
||||||
|
typedef struct NodeFnCollection {
|
||||||
|
ASTNodeType type;
|
||||||
|
ASTNode* nodes;
|
||||||
|
int capacity;
|
||||||
|
int count;
|
||||||
|
} NodeFnCollection;
|
||||||
|
|
||||||
|
//function declaration
|
||||||
|
void emitASTNodeFnDecl(ASTNode** nodeHandle, Literal identifier, ASTNode* arguments, ASTNode* returns, ASTNode* block);
|
||||||
|
|
||||||
typedef struct NodeFnDecl {
|
typedef struct NodeFnDecl {
|
||||||
ASTNodeType type;
|
ASTNodeType type;
|
||||||
Literal identifier;
|
Literal identifier;
|
||||||
@@ -94,33 +139,87 @@ typedef struct NodeFnDecl {
|
|||||||
ASTNode* block;
|
ASTNode* block;
|
||||||
} NodeFnDecl;
|
} NodeFnDecl;
|
||||||
|
|
||||||
typedef struct NodeFnCollection {
|
//function call
|
||||||
ASTNodeType type;
|
void emitASTNodeFnCall(ASTNode** nodeHandle, ASTNode* arguments);
|
||||||
ASTNode* nodes;
|
|
||||||
int capacity;
|
|
||||||
int count;
|
|
||||||
} NodeFnCollection;
|
|
||||||
|
|
||||||
typedef struct NodeFnCall {
|
typedef struct NodeFnCall {
|
||||||
ASTNodeType type;
|
ASTNodeType type;
|
||||||
ASTNode* arguments;
|
ASTNode* arguments;
|
||||||
int argumentCount;
|
int argumentCount; //NOTE: leave this, so it can be hacked by dottify()
|
||||||
} NodeFnCall;
|
} NodeFnCall;
|
||||||
|
|
||||||
typedef struct NodePath {
|
//function return
|
||||||
|
void emitASTNodeFnReturn(ASTNode** nodeHandle, ASTNode* returns);
|
||||||
|
|
||||||
|
typedef struct NodeFnReturn {
|
||||||
|
ASTNodeType type;
|
||||||
|
ASTNode* returns;
|
||||||
|
} NodeFnReturn;
|
||||||
|
|
||||||
|
//control flow path - if-else, while, for, break, continue, return
|
||||||
|
void emitASTNodeIf(ASTNode** nodeHandle, ASTNode* condition, ASTNode* thenPath, ASTNode* elsePath);
|
||||||
|
void emitASTNodeWhile(ASTNode** nodeHandle, ASTNode* condition, ASTNode* thenPath);
|
||||||
|
void emitASTNodeFor(ASTNode** nodeHandle, ASTNode* preClause, ASTNode* condition, ASTNode* postClause, ASTNode* thenPath);
|
||||||
|
void emitASTNodeBreak(ASTNode** nodeHandle);
|
||||||
|
void emitASTNodeContinue(ASTNode** nodeHandle);
|
||||||
|
|
||||||
|
typedef struct NodeIf {
|
||||||
ASTNodeType type;
|
ASTNodeType type;
|
||||||
ASTNode* preClause;
|
|
||||||
ASTNode* postClause;
|
|
||||||
ASTNode* condition;
|
ASTNode* condition;
|
||||||
ASTNode* thenPath;
|
ASTNode* thenPath;
|
||||||
ASTNode* elsePath;
|
ASTNode* elsePath;
|
||||||
} NodePath;
|
} NodeIf;
|
||||||
|
|
||||||
typedef struct NodeIncrement {
|
typedef struct NodeWhile {
|
||||||
|
ASTNodeType type;
|
||||||
|
ASTNode* condition;
|
||||||
|
ASTNode* thenPath;
|
||||||
|
} NodeWhile;
|
||||||
|
|
||||||
|
typedef struct NodeFor {
|
||||||
|
ASTNodeType type;
|
||||||
|
ASTNode* preClause;
|
||||||
|
ASTNode* condition;
|
||||||
|
ASTNode* postClause;
|
||||||
|
ASTNode* thenPath;
|
||||||
|
} NodeFor;
|
||||||
|
|
||||||
|
typedef struct NodeBreak {
|
||||||
|
ASTNodeType type;
|
||||||
|
} NodeBreak;
|
||||||
|
|
||||||
|
typedef struct NodeContinue {
|
||||||
|
ASTNodeType type;
|
||||||
|
} NodeContinue;
|
||||||
|
|
||||||
|
//pre-post increment/decrement
|
||||||
|
void emitASTNodePrefixIncrement(ASTNode** nodeHandle, Literal identifier);
|
||||||
|
void emitASTNodePrefixDecrement(ASTNode** nodeHandle, Literal identifier);
|
||||||
|
void emitASTNodePostfixIncrement(ASTNode** nodeHandle, Literal identifier);
|
||||||
|
void emitASTNodePostfixDecrement(ASTNode** nodeHandle, Literal identifier);
|
||||||
|
|
||||||
|
typedef struct NodePrefixIncrement {
|
||||||
ASTNodeType type;
|
ASTNodeType type;
|
||||||
Literal identifier;
|
Literal identifier;
|
||||||
int increment;
|
} NodePrefixIncrement;
|
||||||
} NodeIncrement;
|
|
||||||
|
typedef struct NodePrefixDecrement {
|
||||||
|
ASTNodeType type;
|
||||||
|
Literal identifier;
|
||||||
|
} NodePrefixDecrement;
|
||||||
|
|
||||||
|
typedef struct NodePostfixIncrement {
|
||||||
|
ASTNodeType type;
|
||||||
|
Literal identifier;
|
||||||
|
} NodePostfixIncrement;
|
||||||
|
|
||||||
|
typedef struct NodePostfixDecrement {
|
||||||
|
ASTNodeType type;
|
||||||
|
Literal identifier;
|
||||||
|
} NodePostfixDecrement;
|
||||||
|
|
||||||
|
//import a library
|
||||||
|
void emitASTNodeImport(ASTNode** nodeHandle, Literal identifier, Literal alias);
|
||||||
|
|
||||||
typedef struct NodeImport {
|
typedef struct NodeImport {
|
||||||
ASTNodeType type;
|
ASTNodeType type;
|
||||||
@@ -128,13 +227,6 @@ typedef struct NodeImport {
|
|||||||
Literal alias;
|
Literal alias;
|
||||||
} NodeImport;
|
} NodeImport;
|
||||||
|
|
||||||
typedef struct NodeIndex {
|
|
||||||
ASTNodeType type;
|
|
||||||
ASTNode* first;
|
|
||||||
ASTNode* second;
|
|
||||||
ASTNode* third;
|
|
||||||
} NodeIndex;
|
|
||||||
|
|
||||||
union _node {
|
union _node {
|
||||||
ASTNodeType type;
|
ASTNodeType type;
|
||||||
NodeLiteral atomic;
|
NodeLiteral atomic;
|
||||||
@@ -144,32 +236,22 @@ union _node {
|
|||||||
NodeBlock block;
|
NodeBlock block;
|
||||||
NodeCompound compound;
|
NodeCompound compound;
|
||||||
NodePair pair;
|
NodePair pair;
|
||||||
NodeVarDecl varDecl;
|
|
||||||
NodeFnDecl fnDecl;
|
|
||||||
NodeFnCollection fnCollection;
|
|
||||||
NodeFnCall fnCall;
|
|
||||||
NodePath path;
|
|
||||||
NodeIncrement increment;
|
|
||||||
NodeImport import;
|
|
||||||
NodeIndex index;
|
NodeIndex index;
|
||||||
|
NodeVarDecl varDecl;
|
||||||
|
NodeFnCollection fnCollection;
|
||||||
|
NodeFnDecl fnDecl;
|
||||||
|
NodeFnCall fnCall;
|
||||||
|
NodeFnReturn returns;
|
||||||
|
NodeIf pathIf;
|
||||||
|
NodeWhile pathWhile;
|
||||||
|
NodeFor pathFor;
|
||||||
|
NodeBreak pathBreak;
|
||||||
|
NodeContinue pathContinue;
|
||||||
|
NodePrefixIncrement prefixIncrement;
|
||||||
|
NodePrefixDecrement prefixDecrement;
|
||||||
|
NodePostfixIncrement postfixIncrement;
|
||||||
|
NodePostfixDecrement postfixDecrement;
|
||||||
|
NodeImport import;
|
||||||
};
|
};
|
||||||
|
|
||||||
TOY_API void freeNode(ASTNode* node);
|
TOY_API void freeASTNode(ASTNode* node);
|
||||||
|
|
||||||
void emitASTNodeLiteral(ASTNode** nodeHandle, Literal literal);
|
|
||||||
void emitASTNodeUnary(ASTNode** nodeHandle, Opcode opcode, ASTNode* child);
|
|
||||||
void emitASTNodeBinary(ASTNode** nodeHandle, ASTNode* rhs, Opcode opcode); //handled node becomes lhs
|
|
||||||
void emitASTNodeGrouping(ASTNode** nodeHandle);
|
|
||||||
void emitASTNodeBlock(ASTNode** nodeHandle);
|
|
||||||
void emitASTNodeCompound(ASTNode** nodeHandle, LiteralType literalType);
|
|
||||||
void setASTNodePair(ASTNode* node, ASTNode* left, ASTNode* right);
|
|
||||||
void emitASTNodeVarDecl(ASTNode** nodeHandle, Literal identifier, Literal type, ASTNode* expression);
|
|
||||||
void emitASTNodeFnDecl(ASTNode** nodeHandle, Literal identifier, ASTNode* arguments, ASTNode* returns, ASTNode* block);
|
|
||||||
void emitASTFnCall(ASTNode** nodeHandle, ASTNode* arguments, int argumentCount);
|
|
||||||
void emitASTNodeFnCollection(ASTNode** nodeHandle);
|
|
||||||
void emitASTNodePath(ASTNode** nodeHandle, ASTNodeType type, ASTNode* preClause, ASTNode* postClause, ASTNode* condition, ASTNode* thenPath, ASTNode* elsePath);
|
|
||||||
void emitASTNodePrefixIncrement(ASTNode** nodeHandle, Literal identifier, int increment);
|
|
||||||
void emitASTNodePostfixIncrement(ASTNode** nodeHandle, Literal identifier, int increment);
|
|
||||||
void emitASTNodeImport(ASTNode** nodeHandle, ASTNodeType mode, Literal identifier, Literal alias);
|
|
||||||
void emitASTNodeIndex(ASTNode** nodeHandle, ASTNode* first, ASTNode* second, ASTNode* third);
|
|
||||||
void emitASTNodeDot(ASTNode** nodeHandle, ASTNode* first);
|
|
||||||
|
|||||||
+39
-36
@@ -10,7 +10,7 @@ static Literal addition(Interpreter* interpreter, Literal lhs, Literal rhs) {
|
|||||||
//special case for string concatenation ONLY
|
//special case for string concatenation ONLY
|
||||||
if (IS_STRING(lhs) && IS_STRING(rhs)) {
|
if (IS_STRING(lhs) && IS_STRING(rhs)) {
|
||||||
//check for overflow
|
//check for overflow
|
||||||
int totalLength = strlen(AS_STRING(lhs)) + strlen(AS_STRING(rhs));
|
int totalLength = AS_STRING(lhs)->length + AS_STRING(rhs)->length;
|
||||||
if (totalLength > MAX_STRING_LENGTH) {
|
if (totalLength > MAX_STRING_LENGTH) {
|
||||||
interpreter->errorOutput("Can't concatenate these strings (result is too long)\n");
|
interpreter->errorOutput("Can't concatenate these strings (result is too long)\n");
|
||||||
return TO_NULL_LITERAL;
|
return TO_NULL_LITERAL;
|
||||||
@@ -18,8 +18,9 @@ static Literal addition(Interpreter* interpreter, Literal lhs, Literal rhs) {
|
|||||||
|
|
||||||
//concat the strings
|
//concat the strings
|
||||||
char buffer[MAX_STRING_LENGTH];
|
char buffer[MAX_STRING_LENGTH];
|
||||||
snprintf(buffer, MAX_STRING_LENGTH, "%s%s", AS_STRING(lhs), AS_STRING(rhs));
|
snprintf(buffer, MAX_STRING_LENGTH, "%s%s", toCString(AS_STRING(lhs)), toCString(AS_STRING(rhs)));
|
||||||
Literal literal = TO_STRING_LITERAL(copyString(buffer, totalLength), totalLength);
|
Literal literal = TO_STRING_LITERAL(createRefStringLength(buffer, totalLength));
|
||||||
|
|
||||||
freeLiteral(lhs);
|
freeLiteral(lhs);
|
||||||
freeLiteral(rhs);
|
freeLiteral(rhs);
|
||||||
|
|
||||||
@@ -296,35 +297,35 @@ int _index(Interpreter* interpreter, LiteralArray* arguments) {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (!strcmp( AS_STRING(op), "=")) {
|
else if (equalsRefStringCString(AS_STRING(op), "=")) {
|
||||||
setLiteralDictionary(AS_DICTIONARY(compound), first, assign);
|
setLiteralDictionary(AS_DICTIONARY(compound), first, assign);
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (!strcmp( AS_STRING(op), "+=")) {
|
else if (equalsRefStringCString(AS_STRING(op), "+=")) {
|
||||||
Literal lit = addition(interpreter, value, assign);
|
Literal lit = addition(interpreter, value, assign);
|
||||||
setLiteralDictionary(AS_DICTIONARY(compound), first, lit);
|
setLiteralDictionary(AS_DICTIONARY(compound), first, lit);
|
||||||
freeLiteral(lit);
|
freeLiteral(lit);
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (!strcmp( AS_STRING(op), "-=")) {
|
else if (equalsRefStringCString(AS_STRING(op), "-=")) {
|
||||||
Literal lit = subtraction(interpreter, value, assign);
|
Literal lit = subtraction(interpreter, value, assign);
|
||||||
setLiteralDictionary(AS_DICTIONARY(compound), first, lit);
|
setLiteralDictionary(AS_DICTIONARY(compound), first, lit);
|
||||||
freeLiteral(lit);
|
freeLiteral(lit);
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (!strcmp( AS_STRING(op), "*=")) {
|
else if (equalsRefStringCString(AS_STRING(op), "*=")) {
|
||||||
Literal lit = multiplication(interpreter, value, assign);
|
Literal lit = multiplication(interpreter, value, assign);
|
||||||
setLiteralDictionary(AS_DICTIONARY(compound), first, lit);
|
setLiteralDictionary(AS_DICTIONARY(compound), first, lit);
|
||||||
freeLiteral(lit);
|
freeLiteral(lit);
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (!strcmp( AS_STRING(op), "/=")) {
|
else if (equalsRefStringCString(AS_STRING(op), "/=")) {
|
||||||
Literal lit = division(interpreter, value, assign);
|
Literal lit = division(interpreter, value, assign);
|
||||||
setLiteralDictionary(AS_DICTIONARY(compound), first, lit);
|
setLiteralDictionary(AS_DICTIONARY(compound), first, lit);
|
||||||
freeLiteral(lit);
|
freeLiteral(lit);
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (!strcmp( AS_STRING(op), "%=")) {
|
else if (equalsRefStringCString(AS_STRING(op), "%=")) {
|
||||||
Literal lit = modulo(interpreter, value, assign);
|
Literal lit = modulo(interpreter, value, assign);
|
||||||
setLiteralDictionary(AS_DICTIONARY(compound), first, lit);
|
setLiteralDictionary(AS_DICTIONARY(compound), first, lit);
|
||||||
freeLiteral(lit);
|
freeLiteral(lit);
|
||||||
@@ -440,7 +441,7 @@ int _index(Interpreter* interpreter, LiteralArray* arguments) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//array slice assignment
|
//array slice assignment
|
||||||
if (IS_STRING(op) && !strcmp( AS_STRING(op), "=")) {
|
if (IS_STRING(op) && equalsRefStringCString(AS_STRING(op), "=")) {
|
||||||
//parse out the booleans & their defaults
|
//parse out the booleans & their defaults
|
||||||
if (!IS_NULL(first)) {
|
if (!IS_NULL(first)) {
|
||||||
if (IS_BOOLEAN(first)) {
|
if (IS_BOOLEAN(first)) {
|
||||||
@@ -620,31 +621,31 @@ int _index(Interpreter* interpreter, LiteralArray* arguments) {
|
|||||||
|
|
||||||
value = getLiteralArray(AS_ARRAY(compound), first);
|
value = getLiteralArray(AS_ARRAY(compound), first);
|
||||||
|
|
||||||
if (IS_STRING(op) && !strcmp( AS_STRING(op), "+=")) {
|
if (IS_STRING(op) && equalsRefStringCString(AS_STRING(op), "+=")) {
|
||||||
Literal lit = addition(interpreter, value, assign);
|
Literal lit = addition(interpreter, value, assign);
|
||||||
setLiteralArray(AS_ARRAY(compound), first, lit);
|
setLiteralArray(AS_ARRAY(compound), first, lit);
|
||||||
freeLiteral(lit);
|
freeLiteral(lit);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IS_STRING(op) && !strcmp( AS_STRING(op), "-=")) {
|
if (IS_STRING(op) && equalsRefStringCString(AS_STRING(op), "-=")) {
|
||||||
Literal lit = subtraction(interpreter, value, assign);
|
Literal lit = subtraction(interpreter, value, assign);
|
||||||
setLiteralArray(AS_ARRAY(compound), first, lit);
|
setLiteralArray(AS_ARRAY(compound), first, lit);
|
||||||
freeLiteral(lit);
|
freeLiteral(lit);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IS_STRING(op) && !strcmp( AS_STRING(op), "*=")) {
|
if (IS_STRING(op) && equalsRefStringCString(AS_STRING(op), "*=")) {
|
||||||
Literal lit = multiplication(interpreter, value, assign);
|
Literal lit = multiplication(interpreter, value, assign);
|
||||||
setLiteralArray(AS_ARRAY(compound), first, lit);
|
setLiteralArray(AS_ARRAY(compound), first, lit);
|
||||||
freeLiteral(lit);
|
freeLiteral(lit);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IS_STRING(op) && !strcmp( AS_STRING(op), "/=")) {
|
if (IS_STRING(op) && equalsRefStringCString(AS_STRING(op), "/=")) {
|
||||||
Literal lit = division(interpreter, value, assign);
|
Literal lit = division(interpreter, value, assign);
|
||||||
setLiteralArray(AS_ARRAY(compound), first, lit);
|
setLiteralArray(AS_ARRAY(compound), first, lit);
|
||||||
freeLiteral(lit);
|
freeLiteral(lit);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IS_STRING(op) && !strcmp( AS_STRING(op), "%=")) {
|
if (IS_STRING(op) && equalsRefStringCString(AS_STRING(op), "%=")) {
|
||||||
Literal lit = modulo(interpreter, value, assign);
|
Literal lit = modulo(interpreter, value, assign);
|
||||||
setLiteralArray(AS_ARRAY(compound), first, lit);
|
setLiteralArray(AS_ARRAY(compound), first, lit);
|
||||||
freeLiteral(lit);
|
freeLiteral(lit);
|
||||||
@@ -669,7 +670,7 @@ int _index(Interpreter* interpreter, LiteralArray* arguments) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int compoundLength = strlen(AS_STRING(compound));
|
int compoundLength = AS_STRING(compound)->length;
|
||||||
if (!IS_NULL(second)) {
|
if (!IS_NULL(second)) {
|
||||||
if (IS_BOOLEAN(second)) {
|
if (IS_BOOLEAN(second)) {
|
||||||
freeLiteral(second);
|
freeLiteral(second);
|
||||||
@@ -709,14 +710,14 @@ int _index(Interpreter* interpreter, LiteralArray* arguments) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (IS_NULL(second)) { //assign only a single character
|
if (IS_NULL(second)) { //assign only a single character
|
||||||
char c = AS_STRING(compound)[AS_INTEGER(first)];
|
char c = toCString(AS_STRING(compound))[AS_INTEGER(first)];
|
||||||
|
|
||||||
char buffer[16];
|
char buffer[16];
|
||||||
snprintf(buffer, 16, "%c", c);
|
snprintf(buffer, 16, "%c", c);
|
||||||
|
|
||||||
freeLiteral(value);
|
freeLiteral(value);
|
||||||
int totalLength = strlen(buffer);
|
int totalLength = strlen(buffer);
|
||||||
value = TO_STRING_LITERAL(copyString(buffer, totalLength), totalLength);
|
value = TO_STRING_LITERAL(createRefStringLength(buffer, totalLength));
|
||||||
|
|
||||||
pushLiteralArray(&interpreter->stack, value);
|
pushLiteralArray(&interpreter->stack, value);
|
||||||
|
|
||||||
@@ -754,20 +755,20 @@ int _index(Interpreter* interpreter, LiteralArray* arguments) {
|
|||||||
//copy compound into result
|
//copy compound into result
|
||||||
int resultIndex = 0;
|
int resultIndex = 0;
|
||||||
for (int i = min; i >= 0 && i >= lower && i <= max; i += AS_INTEGER(third)) {
|
for (int i = min; i >= 0 && i >= lower && i <= max; i += AS_INTEGER(third)) {
|
||||||
result[ resultIndex++ ] = AS_STRING(compound)[ i ];
|
result[ resultIndex++ ] = toCString(AS_STRING(compound))[ i ];
|
||||||
}
|
}
|
||||||
|
|
||||||
result[ resultIndex ] = '\0';
|
result[ resultIndex ] = '\0';
|
||||||
|
|
||||||
//finally, swap out the compound for the result
|
//finally, swap out the compound for the result
|
||||||
freeLiteral(compound);
|
freeLiteral(compound);
|
||||||
compound = TO_STRING_LITERAL(copyString(result, resultIndex), resultIndex);
|
compound = TO_STRING_LITERAL(createRefStringLength(result, resultIndex));
|
||||||
|
|
||||||
FREE_ARRAY(char, result, MAX_STRING_LENGTH);
|
FREE_ARRAY(char, result, MAX_STRING_LENGTH);
|
||||||
}
|
}
|
||||||
|
|
||||||
//string slice assignment
|
//string slice assignment
|
||||||
else if (IS_STRING(op) && !strcmp( AS_STRING(op), "=")) {
|
else if (IS_STRING(op) && equalsRefStringCString(AS_STRING(op), "=")) {
|
||||||
//parse out the booleans & their defaults
|
//parse out the booleans & their defaults
|
||||||
if (!IS_NULL(first)) {
|
if (!IS_NULL(first)) {
|
||||||
if (IS_BOOLEAN(first)) {
|
if (IS_BOOLEAN(first)) {
|
||||||
@@ -782,7 +783,7 @@ int _index(Interpreter* interpreter, LiteralArray* arguments) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int compoundLength = strlen(AS_STRING(compound));
|
int compoundLength = AS_STRING(compound)->length;
|
||||||
if (!IS_NULL(second)) {
|
if (!IS_NULL(second)) {
|
||||||
if (IS_BOOLEAN(second)) {
|
if (IS_BOOLEAN(second)) {
|
||||||
freeLiteral(second);
|
freeLiteral(second);
|
||||||
@@ -823,7 +824,7 @@ int _index(Interpreter* interpreter, LiteralArray* arguments) {
|
|||||||
|
|
||||||
if (IS_NULL(second)) { //assign only a single character
|
if (IS_NULL(second)) { //assign only a single character
|
||||||
//set the "first" within the array, then skip out
|
//set the "first" within the array, then skip out
|
||||||
if (strlen( AS_STRING(assign) ) != 1) {
|
if (AS_STRING(assign)->length != 1) {
|
||||||
//something is weird - skip out
|
//something is weird - skip out
|
||||||
freeLiteral(op);
|
freeLiteral(op);
|
||||||
freeLiteral(assign);
|
freeLiteral(assign);
|
||||||
@@ -836,9 +837,11 @@ int _index(Interpreter* interpreter, LiteralArray* arguments) {
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
AS_STRING(compound)[AS_INTEGER(first)] = AS_STRING(assign)[0];
|
Literal copiedCompound = TO_STRING_LITERAL(deepCopyRefString(AS_STRING(compound)));
|
||||||
|
|
||||||
pushLiteralArray(&interpreter->stack, compound);
|
AS_STRING(copiedCompound)->data[AS_INTEGER(first)] = toCString(AS_STRING(assign))[0];
|
||||||
|
|
||||||
|
pushLiteralArray(&interpreter->stack, copiedCompound);
|
||||||
|
|
||||||
freeLiteral(op);
|
freeLiteral(op);
|
||||||
freeLiteral(assign);
|
freeLiteral(assign);
|
||||||
@@ -871,18 +874,18 @@ int _index(Interpreter* interpreter, LiteralArray* arguments) {
|
|||||||
int resultIndex = 0;
|
int resultIndex = 0;
|
||||||
if (AS_INTEGER(third) == 1 || AS_INTEGER(third) == -1) {
|
if (AS_INTEGER(third) == 1 || AS_INTEGER(third) == -1) {
|
||||||
for (int i = 0; i < AS_INTEGER(first); i++) {
|
for (int i = 0; i < AS_INTEGER(first); i++) {
|
||||||
result[ resultIndex++ ] = AS_STRING(compound)[ i ];
|
result[ resultIndex++ ] = toCString(AS_STRING(compound))[ i ];
|
||||||
}
|
}
|
||||||
|
|
||||||
int assignLength = strlen(AS_STRING(assign));
|
int assignLength = AS_STRING(assign)->length;
|
||||||
int min = AS_INTEGER(third) > 0 ? 0 : assignLength - 1;
|
int min = AS_INTEGER(third) > 0 ? 0 : assignLength - 1;
|
||||||
|
|
||||||
for (int i = min; i >= 0 && i < assignLength; i += AS_INTEGER(third)) {
|
for (int i = min; i >= 0 && i < assignLength; i += AS_INTEGER(third)) {
|
||||||
result[ resultIndex++ ] = AS_STRING(assign)[ i ];
|
result[ resultIndex++ ] = toCString(AS_STRING(assign))[ i ];
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = AS_INTEGER(second) + 1; i < compoundLength; i++) {
|
for (int i = AS_INTEGER(second) + 1; i < compoundLength; i++) {
|
||||||
result[ resultIndex++ ] = AS_STRING(compound)[ i ];
|
result[ resultIndex++ ] = toCString(AS_STRING(compound))[ i ];
|
||||||
}
|
}
|
||||||
|
|
||||||
result[ resultIndex ] = '\0';
|
result[ resultIndex ] = '\0';
|
||||||
@@ -891,26 +894,26 @@ int _index(Interpreter* interpreter, LiteralArray* arguments) {
|
|||||||
//else override elements of the array instead
|
//else override elements of the array instead
|
||||||
else {
|
else {
|
||||||
//copy compound to result
|
//copy compound to result
|
||||||
snprintf(result, MAX_STRING_LENGTH, "%s", AS_STRING(compound));
|
snprintf(result, MAX_STRING_LENGTH, "%s", toCString(AS_STRING(compound)));
|
||||||
|
|
||||||
int assignLength = strlen(AS_STRING(assign));
|
int assignLength = AS_STRING(assign)->length;
|
||||||
int min = AS_INTEGER(third) > 0 ? AS_INTEGER(first) : AS_INTEGER(second) - 1;
|
int min = AS_INTEGER(third) > 0 ? AS_INTEGER(first) : AS_INTEGER(second) - 1;
|
||||||
|
|
||||||
int assignIndex = 0;
|
int assignIndex = 0;
|
||||||
for (int i = min; i >= AS_INTEGER(first) && i <= AS_INTEGER(second) && assignIndex < assignLength; i += AS_INTEGER(third)) {
|
for (int i = min; i >= AS_INTEGER(first) && i <= AS_INTEGER(second) && assignIndex < assignLength; i += AS_INTEGER(third)) {
|
||||||
result[ i ] = AS_STRING(assign)[ assignIndex++ ];
|
result[ i ] = toCString(AS_STRING(assign))[ assignIndex++ ];
|
||||||
}
|
}
|
||||||
resultIndex = strlen(result);
|
resultIndex = strlen(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
//finally, swap out the compound for the result
|
//finally, swap out the compound for the result
|
||||||
freeLiteral(compound);
|
freeLiteral(compound);
|
||||||
compound = TO_STRING_LITERAL(copyString(result, resultIndex), resultIndex);
|
compound = TO_STRING_LITERAL(createRefStringLength(result, resultIndex));
|
||||||
|
|
||||||
FREE_ARRAY(char, result, MAX_STRING_LENGTH);
|
FREE_ARRAY(char, result, MAX_STRING_LENGTH);
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (IS_STRING(op) && !strcmp( AS_STRING(op), "+=")) {
|
else if (IS_STRING(op) && equalsRefStringCString(AS_STRING(op), "+=")) {
|
||||||
Literal tmp = addition(interpreter, compound, assign);
|
Literal tmp = addition(interpreter, compound, assign);
|
||||||
freeLiteral(compound);
|
freeLiteral(compound);
|
||||||
compound = tmp; //don't clear tmp
|
compound = tmp; //don't clear tmp
|
||||||
@@ -1229,7 +1232,7 @@ int _pop(Interpreter* interpreter, LiteralArray* arguments) {
|
|||||||
int _length(Interpreter* interpreter, LiteralArray* arguments) {
|
int _length(Interpreter* interpreter, LiteralArray* arguments) {
|
||||||
//if wrong number of arguments, fail
|
//if wrong number of arguments, fail
|
||||||
if (arguments->count != 1) {
|
if (arguments->count != 1) {
|
||||||
interpreter->errorOutput("Incorrect number of arguments to _get\n");
|
interpreter->errorOutput("Incorrect number of arguments to _length\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1257,7 +1260,7 @@ int _length(Interpreter* interpreter, LiteralArray* arguments) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
case LITERAL_STRING: {
|
case LITERAL_STRING: {
|
||||||
Literal lit = TO_INTEGER_LITERAL( strlen(AS_STRING(obj)) );
|
Literal lit = TO_INTEGER_LITERAL( AS_STRING(obj)->length );
|
||||||
pushLiteralArray(&interpreter->stack, lit);
|
pushLiteralArray(&interpreter->stack, lit);
|
||||||
freeLiteral(lit);
|
freeLiteral(lit);
|
||||||
break;
|
break;
|
||||||
|
|||||||
+112
-99
@@ -18,7 +18,7 @@ void initCompiler(Compiler* compiler) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//separated out, so it can be recursive
|
//separated out, so it can be recursive
|
||||||
static int writeLiteralTypeToCacheOpt(LiteralArray* literalCache, Literal literal, bool skipDuplicationOptimisation) {
|
static int writeLiteralTypeToCache(LiteralArray* literalCache, Literal literal) {
|
||||||
bool shouldFree = false;
|
bool shouldFree = false;
|
||||||
|
|
||||||
//if it's a compound type, recurse and store the results
|
//if it's a compound type, recurse and store the results
|
||||||
@@ -32,7 +32,7 @@ static int writeLiteralTypeToCacheOpt(LiteralArray* literalCache, Literal litera
|
|||||||
|
|
||||||
for (int i = 0; i < AS_TYPE(literal).count; i++) {
|
for (int i = 0; i < AS_TYPE(literal).count; i++) {
|
||||||
//write the values to the cache, and the indexes to the store
|
//write the values to the cache, and the indexes to the store
|
||||||
int subIndex = writeLiteralTypeToCacheOpt(literalCache, ((Literal*)(AS_TYPE(literal).subtypes))[i], false);
|
int subIndex = writeLiteralTypeToCache(literalCache, ((Literal*)(AS_TYPE(literal).subtypes))[i]);
|
||||||
|
|
||||||
Literal lit = TO_INTEGER_LITERAL(subIndex);
|
Literal lit = TO_INTEGER_LITERAL(subIndex);
|
||||||
pushLiteralArray(store, lit);
|
pushLiteralArray(store, lit);
|
||||||
@@ -45,8 +45,7 @@ static int writeLiteralTypeToCacheOpt(LiteralArray* literalCache, Literal litera
|
|||||||
literal.type = LITERAL_TYPE_INTERMEDIATE; //NOTE: tweaking the type usually isn't a good idea
|
literal.type = LITERAL_TYPE_INTERMEDIATE; //NOTE: tweaking the type usually isn't a good idea
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!skipDuplicationOptimisation) {
|
//optimisation: check if exactly this literal array exists
|
||||||
//BUGFIX: check if exactly this literal array exists
|
|
||||||
int index = findLiteralIndex(literalCache, literal);
|
int index = findLiteralIndex(literalCache, literal);
|
||||||
if (index < 0) {
|
if (index < 0) {
|
||||||
index = pushLiteralArray(literalCache, literal);
|
index = pushLiteralArray(literalCache, literal);
|
||||||
@@ -56,18 +55,6 @@ static int writeLiteralTypeToCacheOpt(LiteralArray* literalCache, Literal litera
|
|||||||
freeLiteral(literal);
|
freeLiteral(literal);
|
||||||
}
|
}
|
||||||
return index;
|
return index;
|
||||||
}
|
|
||||||
else {
|
|
||||||
int index = pushLiteralArray(literalCache, literal);
|
|
||||||
if (shouldFree) {
|
|
||||||
freeLiteral(literal);
|
|
||||||
}
|
|
||||||
return index;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static int writeLiteralTypeToCache(LiteralArray* literalCache, Literal literal) {
|
|
||||||
return writeLiteralTypeToCacheOpt(literalCache, literal, false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int writeNodeCompoundToCache(Compiler* compiler, ASTNode* node) {
|
static int writeNodeCompoundToCache(Compiler* compiler, ASTNode* node) {
|
||||||
@@ -83,7 +70,7 @@ static int writeNodeCompoundToCache(Compiler* compiler, ASTNode* node) {
|
|||||||
for (int i = 0; i < node->compound.count; i++) {
|
for (int i = 0; i < node->compound.count; i++) {
|
||||||
//keys
|
//keys
|
||||||
switch(node->compound.nodes[i].pair.left->type) {
|
switch(node->compound.nodes[i].pair.left->type) {
|
||||||
case AST_NODELITERAL: {
|
case AST_NODE_LITERAL: {
|
||||||
//keys are literals
|
//keys are literals
|
||||||
int key = findLiteralIndex(&compiler->literalCache, node->compound.nodes[i].pair.left->atomic.literal);
|
int key = findLiteralIndex(&compiler->literalCache, node->compound.nodes[i].pair.left->atomic.literal);
|
||||||
if (key < 0) {
|
if (key < 0) {
|
||||||
@@ -96,7 +83,7 @@ static int writeNodeCompoundToCache(Compiler* compiler, ASTNode* node) {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case AST_NODECOMPOUND: {
|
case AST_NODE_COMPOUND: {
|
||||||
int key = writeNodeCompoundToCache(compiler, node->compound.nodes[i].pair.left);
|
int key = writeNodeCompoundToCache(compiler, node->compound.nodes[i].pair.left);
|
||||||
|
|
||||||
Literal literal = TO_INTEGER_LITERAL(key);
|
Literal literal = TO_INTEGER_LITERAL(key);
|
||||||
@@ -112,7 +99,7 @@ static int writeNodeCompoundToCache(Compiler* compiler, ASTNode* node) {
|
|||||||
|
|
||||||
//values
|
//values
|
||||||
switch(node->compound.nodes[i].pair.right->type) {
|
switch(node->compound.nodes[i].pair.right->type) {
|
||||||
case AST_NODELITERAL: {
|
case AST_NODE_LITERAL: {
|
||||||
//values are literals
|
//values are literals
|
||||||
int val = findLiteralIndex(&compiler->literalCache, node->compound.nodes[i].pair.right->atomic.literal);
|
int val = findLiteralIndex(&compiler->literalCache, node->compound.nodes[i].pair.right->atomic.literal);
|
||||||
if (val < 0) {
|
if (val < 0) {
|
||||||
@@ -125,7 +112,7 @@ static int writeNodeCompoundToCache(Compiler* compiler, ASTNode* node) {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case AST_NODECOMPOUND: {
|
case AST_NODE_COMPOUND: {
|
||||||
int val = writeNodeCompoundToCache(compiler, node->compound.nodes[i].pair.right);
|
int val = writeNodeCompoundToCache(compiler, node->compound.nodes[i].pair.right);
|
||||||
|
|
||||||
Literal literal = TO_INTEGER_LITERAL(val);
|
Literal literal = TO_INTEGER_LITERAL(val);
|
||||||
@@ -150,7 +137,7 @@ static int writeNodeCompoundToCache(Compiler* compiler, ASTNode* node) {
|
|||||||
//ensure each literal value is in the cache, individually
|
//ensure each literal value is in the cache, individually
|
||||||
for (int i = 0; i < node->compound.count; i++) {
|
for (int i = 0; i < node->compound.count; i++) {
|
||||||
switch(node->compound.nodes[i].type) {
|
switch(node->compound.nodes[i].type) {
|
||||||
case AST_NODELITERAL: {
|
case AST_NODE_LITERAL: {
|
||||||
//values
|
//values
|
||||||
int val = findLiteralIndex(&compiler->literalCache, node->compound.nodes[i].atomic.literal);
|
int val = findLiteralIndex(&compiler->literalCache, node->compound.nodes[i].atomic.literal);
|
||||||
if (val < 0) {
|
if (val < 0) {
|
||||||
@@ -163,7 +150,7 @@ static int writeNodeCompoundToCache(Compiler* compiler, ASTNode* node) {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case AST_NODECOMPOUND: {
|
case AST_NODE_COMPOUND: {
|
||||||
int val = writeNodeCompoundToCache(compiler, &node->compound.nodes[i]);
|
int val = writeNodeCompoundToCache(compiler, &node->compound.nodes[i]);
|
||||||
|
|
||||||
Literal literal = TO_INTEGER_LITERAL(val);
|
Literal literal = TO_INTEGER_LITERAL(val);
|
||||||
@@ -197,10 +184,10 @@ static int writeNodeCollectionToCache(Compiler* compiler, ASTNode* node) {
|
|||||||
//ensure each literal value is in the cache, individually
|
//ensure each literal value is in the cache, individually
|
||||||
for (int i = 0; i < node->fnCollection.count; i++) {
|
for (int i = 0; i < node->fnCollection.count; i++) {
|
||||||
switch(node->fnCollection.nodes[i].type) {
|
switch(node->fnCollection.nodes[i].type) {
|
||||||
case AST_NODEVAR_DECL: {
|
case AST_NODE_VAR_DECL: {
|
||||||
//write each piece of the declaration to the cache
|
//write each piece of the declaration to the cache
|
||||||
int identifierIndex = pushLiteralArray(&compiler->literalCache, node->fnCollection.nodes[i].varDecl.identifier); //store without duplication optimisation
|
int identifierIndex = pushLiteralArray(&compiler->literalCache, node->fnCollection.nodes[i].varDecl.identifier); //store without duplication optimisation
|
||||||
int typeIndex = writeLiteralTypeToCacheOpt(&compiler->literalCache, node->fnCollection.nodes[i].varDecl.typeLiteral, false);
|
int typeIndex = writeLiteralTypeToCache(&compiler->literalCache, node->fnCollection.nodes[i].varDecl.typeLiteral);
|
||||||
|
|
||||||
Literal identifierLiteral = TO_INTEGER_LITERAL(identifierIndex);
|
Literal identifierLiteral = TO_INTEGER_LITERAL(identifierIndex);
|
||||||
pushLiteralArray(store, identifierLiteral);
|
pushLiteralArray(store, identifierLiteral);
|
||||||
@@ -212,9 +199,9 @@ static int writeNodeCollectionToCache(Compiler* compiler, ASTNode* node) {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case AST_NODELITERAL: {
|
case AST_NODE_LITERAL: {
|
||||||
//write each piece of the declaration to the cache
|
//write each piece of the declaration to the cache
|
||||||
int typeIndex = writeLiteralTypeToCacheOpt(&compiler->literalCache, node->fnCollection.nodes[i].atomic.literal, false);
|
int typeIndex = writeLiteralTypeToCache(&compiler->literalCache, node->fnCollection.nodes[i].atomic.literal);
|
||||||
|
|
||||||
Literal typeLiteral = TO_INTEGER_LITERAL(typeIndex);
|
Literal typeLiteral = TO_INTEGER_LITERAL(typeIndex);
|
||||||
pushLiteralArray(store, typeLiteral);
|
pushLiteralArray(store, typeLiteral);
|
||||||
@@ -267,8 +254,8 @@ static int writeLiteralToCompiler(Compiler* compiler, Literal literal) {
|
|||||||
return index;
|
return index;
|
||||||
}
|
}
|
||||||
|
|
||||||
//NOTE: jumpOfsets are included, because function arg and return indexes are embedded in the code body i.e. need to include thier sizes in the jump
|
//NOTE: jumpOfsets are included, because function arg and return indexes are embedded in the code body i.e. need to include their sizes in the jump
|
||||||
//NODE: rootNode should NOT include groupings and blocks
|
//NOTE: rootNode should NOT include groupings and blocks
|
||||||
static Opcode writeCompilerWithJumps(Compiler* compiler, ASTNode* node, void* breakAddressesPtr, void* continueAddressesPtr, int jumpOffsets, ASTNode* rootNode) {
|
static Opcode writeCompilerWithJumps(Compiler* compiler, ASTNode* node, void* breakAddressesPtr, void* continueAddressesPtr, int jumpOffsets, ASTNode* rootNode) {
|
||||||
//grow if the bytecode space is too small
|
//grow if the bytecode space is too small
|
||||||
if (compiler->count + 32 > compiler->capacity) {
|
if (compiler->count + 32 > compiler->capacity) {
|
||||||
@@ -280,18 +267,18 @@ static Opcode writeCompilerWithJumps(Compiler* compiler, ASTNode* node, void* br
|
|||||||
|
|
||||||
//determine node type
|
//determine node type
|
||||||
switch(node->type) {
|
switch(node->type) {
|
||||||
case AST_NODEERROR: {
|
case AST_NODE_ERROR: {
|
||||||
fprintf(stderr, ERROR "[internal] AST_NODEERROR encountered in writeCompilerWithJumps()\n" RESET);
|
fprintf(stderr, ERROR "[internal] AST_NODEERROR encountered in writeCompilerWithJumps()\n" RESET);
|
||||||
compiler->bytecode[compiler->count++] = OP_EOF; //1 byte
|
compiler->bytecode[compiler->count++] = OP_EOF; //1 byte
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case AST_NODELITERAL: {
|
case AST_NODE_LITERAL: {
|
||||||
writeLiteralToCompiler(compiler, node->atomic.literal);
|
writeLiteralToCompiler(compiler, node->atomic.literal);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case AST_NODEUNARY: {
|
case AST_NODE_UNARY: {
|
||||||
//pass to the child node, then embed the unary command (print, negate, etc.)
|
//pass to the child node, then embed the unary command (print, negate, etc.)
|
||||||
Opcode override = writeCompilerWithJumps(compiler, node->unary.child, breakAddressesPtr, continueAddressesPtr, jumpOffsets, rootNode);
|
Opcode override = writeCompilerWithJumps(compiler, node->unary.child, breakAddressesPtr, continueAddressesPtr, jumpOffsets, rootNode);
|
||||||
|
|
||||||
@@ -304,7 +291,7 @@ static Opcode writeCompilerWithJumps(Compiler* compiler, ASTNode* node, void* br
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
//all infixes come here
|
//all infixes come here
|
||||||
case AST_NODEBINARY: {
|
case AST_NODE_BINARY: {
|
||||||
//pass to the child nodes, then embed the binary command (math, etc.)
|
//pass to the child nodes, then embed the binary command (math, etc.)
|
||||||
Opcode override = writeCompilerWithJumps(compiler, node->binary.left, breakAddressesPtr, continueAddressesPtr, jumpOffsets, rootNode);
|
Opcode override = writeCompilerWithJumps(compiler, node->binary.left, breakAddressesPtr, continueAddressesPtr, jumpOffsets, rootNode);
|
||||||
|
|
||||||
@@ -324,7 +311,7 @@ static Opcode writeCompilerWithJumps(Compiler* compiler, ASTNode* node, void* br
|
|||||||
//return this if...
|
//return this if...
|
||||||
Opcode ret = writeCompilerWithJumps(compiler, node->binary.right, breakAddressesPtr, continueAddressesPtr, jumpOffsets, rootNode);
|
Opcode ret = writeCompilerWithJumps(compiler, node->binary.right, breakAddressesPtr, continueAddressesPtr, jumpOffsets, rootNode);
|
||||||
|
|
||||||
if (node->binary.opcode == OP_INDEX && rootNode->type == AST_NODEBINARY && rootNode->binary.opcode == OP_VAR_ASSIGN) { //why var assign?
|
if (node->binary.opcode == OP_INDEX && rootNode->type == AST_NODE_BINARY && rootNode->binary.opcode == OP_VAR_ASSIGN) { //why var assign?
|
||||||
return OP_INDEX_ASSIGN_INTERMEDIATE;
|
return OP_INDEX_ASSIGN_INTERMEDIATE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -344,7 +331,7 @@ static Opcode writeCompilerWithJumps(Compiler* compiler, ASTNode* node, void* br
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case AST_NODEGROUPING: {
|
case AST_NODE_GROUPING: {
|
||||||
compiler->bytecode[compiler->count++] = (unsigned char)OP_GROUPING_BEGIN; //1 byte
|
compiler->bytecode[compiler->count++] = (unsigned char)OP_GROUPING_BEGIN; //1 byte
|
||||||
Opcode override = writeCompilerWithJumps(compiler, node->grouping.child, breakAddressesPtr, continueAddressesPtr, jumpOffsets, node->grouping.child);
|
Opcode override = writeCompilerWithJumps(compiler, node->grouping.child, breakAddressesPtr, continueAddressesPtr, jumpOffsets, node->grouping.child);
|
||||||
if (override != OP_EOF) {//compensate for indexing & dot notation being screwy
|
if (override != OP_EOF) {//compensate for indexing & dot notation being screwy
|
||||||
@@ -354,7 +341,7 @@ static Opcode writeCompilerWithJumps(Compiler* compiler, ASTNode* node, void* br
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case AST_NODEBLOCK: {
|
case AST_NODE_BLOCK: {
|
||||||
compiler->bytecode[compiler->count++] = (unsigned char)OP_SCOPE_BEGIN; //1 byte
|
compiler->bytecode[compiler->count++] = (unsigned char)OP_SCOPE_BEGIN; //1 byte
|
||||||
|
|
||||||
for (int i = 0; i < node->block.count; i++) {
|
for (int i = 0; i < node->block.count; i++) {
|
||||||
@@ -368,7 +355,7 @@ static Opcode writeCompilerWithJumps(Compiler* compiler, ASTNode* node, void* br
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case AST_NODECOMPOUND: {
|
case AST_NODE_COMPOUND: {
|
||||||
int index = writeNodeCompoundToCache(compiler, node);
|
int index = writeNodeCompoundToCache(compiler, node);
|
||||||
|
|
||||||
//push the node opcode to the bytecode
|
//push the node opcode to the bytecode
|
||||||
@@ -387,12 +374,12 @@ static Opcode writeCompilerWithJumps(Compiler* compiler, ASTNode* node, void* br
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case AST_NODEPAIR:
|
case AST_NODE_PAIR:
|
||||||
fprintf(stderr, ERROR "[internal] AST_NODEPAIR encountered in writeCompilerWithJumps()\n" RESET);
|
fprintf(stderr, ERROR "[internal] AST_NODEPAIR encountered in writeCompilerWithJumps()\n" RESET);
|
||||||
compiler->bytecode[compiler->count++] = OP_EOF; //1 byte
|
compiler->bytecode[compiler->count++] = OP_EOF; //1 byte
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case AST_NODEVAR_DECL: {
|
case AST_NODE_VAR_DECL: {
|
||||||
//first, embed the expression (leaves it on the stack)
|
//first, embed the expression (leaves it on the stack)
|
||||||
Opcode override = writeCompilerWithJumps(compiler, node->varDecl.expression, breakAddressesPtr, continueAddressesPtr, jumpOffsets, rootNode);
|
Opcode override = writeCompilerWithJumps(compiler, node->varDecl.expression, breakAddressesPtr, continueAddressesPtr, jumpOffsets, rootNode);
|
||||||
if (override != OP_EOF) {//compensate for indexing & dot notation being screwy
|
if (override != OP_EOF) {//compensate for indexing & dot notation being screwy
|
||||||
@@ -427,7 +414,7 @@ static Opcode writeCompilerWithJumps(Compiler* compiler, ASTNode* node, void* br
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case AST_NODEFN_DECL: {
|
case AST_NODE_FN_DECL: {
|
||||||
//run a compiler over the function
|
//run a compiler over the function
|
||||||
Compiler* fnCompiler = ALLOCATE(Compiler, 1);
|
Compiler* fnCompiler = ALLOCATE(Compiler, 1);
|
||||||
initCompiler(fnCompiler);
|
initCompiler(fnCompiler);
|
||||||
@@ -471,7 +458,7 @@ static Opcode writeCompilerWithJumps(Compiler* compiler, ASTNode* node, void* br
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case AST_NODEFN_COLLECTION: {
|
case AST_NODE_FN_COLLECTION: {
|
||||||
//embed these in the bytecode...
|
//embed these in the bytecode...
|
||||||
int index = writeNodeCollectionToCache(compiler, node);
|
int index = writeNodeCollectionToCache(compiler, node);
|
||||||
|
|
||||||
@@ -480,12 +467,12 @@ static Opcode writeCompilerWithJumps(Compiler* compiler, ASTNode* node, void* br
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case AST_NODEFN_CALL: {
|
case AST_NODE_FN_CALL: {
|
||||||
//NOTE: assume the function definition/name is above us
|
//NOTE: assume the function definition/name is above us
|
||||||
|
|
||||||
for (int i = 0; i < node->fnCall.arguments->fnCollection.count; i++) { //reverse order, to count from the beginning in the interpreter
|
for (int i = 0; i < node->fnCall.arguments->fnCollection.count; i++) { //reverse order, to count from the beginning in the interpreter
|
||||||
//sub-calls
|
//sub-calls
|
||||||
if (node->fnCall.arguments->fnCollection.nodes[i].type != AST_NODELITERAL) {
|
if (node->fnCall.arguments->fnCollection.nodes[i].type != AST_NODE_LITERAL) {
|
||||||
Opcode override = writeCompilerWithJumps(compiler, &node->fnCall.arguments->fnCollection.nodes[i], breakAddressesPtr, continueAddressesPtr, jumpOffsets, rootNode);
|
Opcode override = writeCompilerWithJumps(compiler, &node->fnCall.arguments->fnCollection.nodes[i], breakAddressesPtr, continueAddressesPtr, jumpOffsets, rootNode);
|
||||||
if (override != OP_EOF) {//compensate for indexing & dot notation being screwy
|
if (override != OP_EOF) {//compensate for indexing & dot notation being screwy
|
||||||
compiler->bytecode[compiler->count++] = (unsigned char)override; //1 byte
|
compiler->bytecode[compiler->count++] = (unsigned char)override; //1 byte
|
||||||
@@ -540,9 +527,9 @@ static Opcode writeCompilerWithJumps(Compiler* compiler, ASTNode* node, void* br
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case AST_NODEPATH_IF: {
|
case AST_NODE_IF: {
|
||||||
//process the condition
|
//process the condition
|
||||||
Opcode override = writeCompilerWithJumps(compiler, node->path.condition, breakAddressesPtr, continueAddressesPtr, jumpOffsets, rootNode);
|
Opcode override = writeCompilerWithJumps(compiler, node->pathIf.condition, breakAddressesPtr, continueAddressesPtr, jumpOffsets, rootNode);
|
||||||
if (override != OP_EOF) {//compensate for indexing & dot notation being screwy
|
if (override != OP_EOF) {//compensate for indexing & dot notation being screwy
|
||||||
compiler->bytecode[compiler->count++] = (unsigned char)override; //1 byte
|
compiler->bytecode[compiler->count++] = (unsigned char)override; //1 byte
|
||||||
}
|
}
|
||||||
@@ -553,14 +540,14 @@ static Opcode writeCompilerWithJumps(Compiler* compiler, ASTNode* node, void* br
|
|||||||
compiler->count += sizeof(unsigned short); //2 bytes
|
compiler->count += sizeof(unsigned short); //2 bytes
|
||||||
|
|
||||||
//write the then path
|
//write the then path
|
||||||
override = writeCompilerWithJumps(compiler, node->path.thenPath, breakAddressesPtr, continueAddressesPtr, jumpOffsets, rootNode);
|
override = writeCompilerWithJumps(compiler, node->pathIf.thenPath, breakAddressesPtr, continueAddressesPtr, jumpOffsets, rootNode);
|
||||||
if (override != OP_EOF) {//compensate for indexing & dot notation being screwy
|
if (override != OP_EOF) {//compensate for indexing & dot notation being screwy
|
||||||
compiler->bytecode[compiler->count++] = (unsigned char)override; //1 byte
|
compiler->bytecode[compiler->count++] = (unsigned char)override; //1 byte
|
||||||
}
|
}
|
||||||
|
|
||||||
int jumpToEnd = 0;
|
int jumpToEnd = 0;
|
||||||
|
|
||||||
if (node->path.elsePath) {
|
if (node->pathIf.elsePath) {
|
||||||
//insert jump to end
|
//insert jump to end
|
||||||
compiler->bytecode[compiler->count++] = OP_JUMP; //1 byte
|
compiler->bytecode[compiler->count++] = OP_JUMP; //1 byte
|
||||||
jumpToEnd = compiler->count;
|
jumpToEnd = compiler->count;
|
||||||
@@ -570,9 +557,9 @@ static Opcode writeCompilerWithJumps(Compiler* compiler, ASTNode* node, void* br
|
|||||||
//update the jumpToElse to point here
|
//update the jumpToElse to point here
|
||||||
AS_USHORT(compiler->bytecode[jumpToElse]) = compiler->count + jumpOffsets; //2 bytes
|
AS_USHORT(compiler->bytecode[jumpToElse]) = compiler->count + jumpOffsets; //2 bytes
|
||||||
|
|
||||||
if (node->path.elsePath) {
|
if (node->pathIf.elsePath) {
|
||||||
//if there's an else path, write it and
|
//if there's an else path, write it and
|
||||||
Opcode override = writeCompilerWithJumps(compiler, node->path.elsePath, breakAddressesPtr, continueAddressesPtr, jumpOffsets, rootNode);
|
Opcode override = writeCompilerWithJumps(compiler, node->pathIf.elsePath, breakAddressesPtr, continueAddressesPtr, jumpOffsets, rootNode);
|
||||||
if (override != OP_EOF) {//compensate for indexing & dot notation being screwy
|
if (override != OP_EOF) {//compensate for indexing & dot notation being screwy
|
||||||
compiler->bytecode[compiler->count++] = (unsigned char)override; //1 byte
|
compiler->bytecode[compiler->count++] = (unsigned char)override; //1 byte
|
||||||
}
|
}
|
||||||
@@ -583,7 +570,7 @@ static Opcode writeCompilerWithJumps(Compiler* compiler, ASTNode* node, void* br
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case AST_NODEPATH_WHILE: {
|
case AST_NODE_WHILE: {
|
||||||
//for breaks and continues
|
//for breaks and continues
|
||||||
LiteralArray breakAddresses;
|
LiteralArray breakAddresses;
|
||||||
LiteralArray continueAddresses;
|
LiteralArray continueAddresses;
|
||||||
@@ -595,7 +582,7 @@ static Opcode writeCompilerWithJumps(Compiler* compiler, ASTNode* node, void* br
|
|||||||
unsigned short jumpToStart = compiler->count;
|
unsigned short jumpToStart = compiler->count;
|
||||||
|
|
||||||
//process the condition
|
//process the condition
|
||||||
Opcode override = writeCompilerWithJumps(compiler, node->path.condition, &breakAddresses, &continueAddresses, jumpOffsets, rootNode);
|
Opcode override = writeCompilerWithJumps(compiler, node->pathWhile.condition, &breakAddresses, &continueAddresses, jumpOffsets, rootNode);
|
||||||
if (override != OP_EOF) {//compensate for indexing & dot notation being screwy
|
if (override != OP_EOF) {//compensate for indexing & dot notation being screwy
|
||||||
compiler->bytecode[compiler->count++] = (unsigned char)override; //1 byte
|
compiler->bytecode[compiler->count++] = (unsigned char)override; //1 byte
|
||||||
}
|
}
|
||||||
@@ -606,7 +593,7 @@ static Opcode writeCompilerWithJumps(Compiler* compiler, ASTNode* node, void* br
|
|||||||
compiler->count += sizeof(unsigned short); //2 bytes
|
compiler->count += sizeof(unsigned short); //2 bytes
|
||||||
|
|
||||||
//write the body
|
//write the body
|
||||||
override = writeCompilerWithJumps(compiler, node->path.thenPath, &breakAddresses, &continueAddresses, jumpOffsets, rootNode);
|
override = writeCompilerWithJumps(compiler, node->pathWhile.thenPath, &breakAddresses, &continueAddresses, jumpOffsets, rootNode);
|
||||||
if (override != OP_EOF) {//compensate for indexing & dot notation being screwy
|
if (override != OP_EOF) {//compensate for indexing & dot notation being screwy
|
||||||
compiler->bytecode[compiler->count++] = (unsigned char)override; //1 byte
|
compiler->bytecode[compiler->count++] = (unsigned char)override; //1 byte
|
||||||
}
|
}
|
||||||
@@ -639,7 +626,7 @@ static Opcode writeCompilerWithJumps(Compiler* compiler, ASTNode* node, void* br
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case AST_NODEPATH_FOR: {
|
case AST_NODE_FOR: {
|
||||||
//for breaks and continues
|
//for breaks and continues
|
||||||
LiteralArray breakAddresses;
|
LiteralArray breakAddresses;
|
||||||
LiteralArray continueAddresses;
|
LiteralArray continueAddresses;
|
||||||
@@ -650,14 +637,14 @@ static Opcode writeCompilerWithJumps(Compiler* compiler, ASTNode* node, void* br
|
|||||||
compiler->bytecode[compiler->count++] = OP_SCOPE_BEGIN; //1 byte
|
compiler->bytecode[compiler->count++] = OP_SCOPE_BEGIN; //1 byte
|
||||||
|
|
||||||
//initial setup
|
//initial setup
|
||||||
Opcode override = writeCompilerWithJumps(compiler, node->path.preClause, &breakAddresses, &continueAddresses, jumpOffsets, rootNode);
|
Opcode override = writeCompilerWithJumps(compiler, node->pathFor.preClause, &breakAddresses, &continueAddresses, jumpOffsets, rootNode);
|
||||||
if (override != OP_EOF) {//compensate for indexing & dot notation being screwy
|
if (override != OP_EOF) {//compensate for indexing & dot notation being screwy
|
||||||
compiler->bytecode[compiler->count++] = (unsigned char)override; //1 byte
|
compiler->bytecode[compiler->count++] = (unsigned char)override; //1 byte
|
||||||
}
|
}
|
||||||
|
|
||||||
//conditional
|
//conditional
|
||||||
unsigned short jumpToStart = compiler->count;
|
unsigned short jumpToStart = compiler->count;
|
||||||
override = writeCompilerWithJumps(compiler, node->path.condition, &breakAddresses, &continueAddresses, jumpOffsets, rootNode);
|
override = writeCompilerWithJumps(compiler, node->pathFor.condition, &breakAddresses, &continueAddresses, jumpOffsets, rootNode);
|
||||||
if (override != OP_EOF) {//compensate for indexing & dot notation being screwy
|
if (override != OP_EOF) {//compensate for indexing & dot notation being screwy
|
||||||
compiler->bytecode[compiler->count++] = (unsigned char)override; //1 byte
|
compiler->bytecode[compiler->count++] = (unsigned char)override; //1 byte
|
||||||
}
|
}
|
||||||
@@ -669,7 +656,7 @@ static Opcode writeCompilerWithJumps(Compiler* compiler, ASTNode* node, void* br
|
|||||||
|
|
||||||
//write the body
|
//write the body
|
||||||
compiler->bytecode[compiler->count++] = OP_SCOPE_BEGIN; //1 byte
|
compiler->bytecode[compiler->count++] = OP_SCOPE_BEGIN; //1 byte
|
||||||
override = writeCompilerWithJumps(compiler, node->path.thenPath, &breakAddresses, &continueAddresses, jumpOffsets, rootNode);
|
override = writeCompilerWithJumps(compiler, node->pathFor.thenPath, &breakAddresses, &continueAddresses, jumpOffsets, rootNode);
|
||||||
if (override != OP_EOF) {//compensate for indexing & dot notation being screwy
|
if (override != OP_EOF) {//compensate for indexing & dot notation being screwy
|
||||||
compiler->bytecode[compiler->count++] = (unsigned char)override; //1 byte
|
compiler->bytecode[compiler->count++] = (unsigned char)override; //1 byte
|
||||||
}
|
}
|
||||||
@@ -679,7 +666,7 @@ static Opcode writeCompilerWithJumps(Compiler* compiler, ASTNode* node, void* br
|
|||||||
int jumpToIncrement = compiler->count;
|
int jumpToIncrement = compiler->count;
|
||||||
|
|
||||||
//evaluate third clause, restart
|
//evaluate third clause, restart
|
||||||
override = writeCompilerWithJumps(compiler, node->path.postClause, &breakAddresses, &continueAddresses, jumpOffsets, rootNode);
|
override = writeCompilerWithJumps(compiler, node->pathFor.postClause, &breakAddresses, &continueAddresses, jumpOffsets, rootNode);
|
||||||
if (override != OP_EOF) {//compensate for indexing & dot notation being screwy
|
if (override != OP_EOF) {//compensate for indexing & dot notation being screwy
|
||||||
compiler->bytecode[compiler->count++] = (unsigned char)override; //1 byte
|
compiler->bytecode[compiler->count++] = (unsigned char)override; //1 byte
|
||||||
}
|
}
|
||||||
@@ -712,7 +699,7 @@ static Opcode writeCompilerWithJumps(Compiler* compiler, ASTNode* node, void* br
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case AST_NODEPATH_BREAK: {
|
case AST_NODE_BREAK: {
|
||||||
if (!breakAddressesPtr) {
|
if (!breakAddressesPtr) {
|
||||||
fprintf(stderr, ERROR "ERROR: Can't place a break statement here\n" RESET);
|
fprintf(stderr, ERROR "ERROR: Can't place a break statement here\n" RESET);
|
||||||
break;
|
break;
|
||||||
@@ -730,7 +717,7 @@ static Opcode writeCompilerWithJumps(Compiler* compiler, ASTNode* node, void* br
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case AST_NODEPATH_CONTINUE: {
|
case AST_NODE_CONTINUE: {
|
||||||
if (!continueAddressesPtr) {
|
if (!continueAddressesPtr) {
|
||||||
fprintf(stderr, ERROR "ERROR: Can't place a continue statement here\n" RESET);
|
fprintf(stderr, ERROR "ERROR: Can't place a continue statement here\n" RESET);
|
||||||
break;
|
break;
|
||||||
@@ -748,10 +735,10 @@ static Opcode writeCompilerWithJumps(Compiler* compiler, ASTNode* node, void* br
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case AST_NODEPATH_RETURN: {
|
case AST_NODE_FN_RETURN: {
|
||||||
//read each returned literal onto the stack, and return the number of values to return
|
//read each returned literal onto the stack, and return the number of values to return
|
||||||
for (int i = 0; i < node->path.thenPath->fnCollection.count; i++) {
|
for (int i = 0; i < node->returns.returns->fnCollection.count; i++) {
|
||||||
Opcode override = writeCompilerWithJumps(compiler, &node->path.thenPath->fnCollection.nodes[i], breakAddressesPtr, continueAddressesPtr, jumpOffsets, rootNode);
|
Opcode override = writeCompilerWithJumps(compiler, &node->returns.returns->fnCollection.nodes[i], breakAddressesPtr, continueAddressesPtr, jumpOffsets, rootNode);
|
||||||
if (override != OP_EOF) {//compensate for indexing & dot notation being screwy
|
if (override != OP_EOF) {//compensate for indexing & dot notation being screwy
|
||||||
compiler->bytecode[compiler->count++] = (unsigned char)override; //1 byte
|
compiler->bytecode[compiler->count++] = (unsigned char)override; //1 byte
|
||||||
}
|
}
|
||||||
@@ -760,18 +747,18 @@ static Opcode writeCompilerWithJumps(Compiler* compiler, ASTNode* node, void* br
|
|||||||
//push the return, with the number of literals
|
//push the return, with the number of literals
|
||||||
compiler->bytecode[compiler->count++] = OP_FN_RETURN; //1 byte
|
compiler->bytecode[compiler->count++] = OP_FN_RETURN; //1 byte
|
||||||
|
|
||||||
*((unsigned short*)(compiler->bytecode + compiler->count)) = (unsigned short)(node->path.thenPath->fnCollection.count); //2 bytes
|
*((unsigned short*)(compiler->bytecode + compiler->count)) = (unsigned short)(node->returns.returns->fnCollection.count); //2 bytes
|
||||||
compiler->count += sizeof(unsigned short);
|
compiler->count += sizeof(unsigned short);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case AST_NODEINCREMENT_PREFIX: {
|
case AST_NODE_PREFIX_INCREMENT: {
|
||||||
//push the literal to the stack (twice)
|
//push the literal to the stack (twice: add + assign)
|
||||||
writeLiteralToCompiler(compiler, node->increment.identifier);
|
writeLiteralToCompiler(compiler, node->prefixIncrement.identifier);
|
||||||
writeLiteralToCompiler(compiler, node->increment.identifier);
|
writeLiteralToCompiler(compiler, node->prefixIncrement.identifier);
|
||||||
|
|
||||||
//push the increment / decrement
|
//push the increment / decrement
|
||||||
Literal increment = TO_INTEGER_LITERAL(node->increment.increment);
|
Literal increment = TO_INTEGER_LITERAL(1);
|
||||||
writeLiteralToCompiler(compiler, increment);
|
writeLiteralToCompiler(compiler, increment);
|
||||||
|
|
||||||
//push the add opcode
|
//push the add opcode
|
||||||
@@ -781,22 +768,43 @@ static Opcode writeCompilerWithJumps(Compiler* compiler, ASTNode* node, void* br
|
|||||||
compiler->bytecode[compiler->count++] = (unsigned char)OP_VAR_ASSIGN; //1 byte
|
compiler->bytecode[compiler->count++] = (unsigned char)OP_VAR_ASSIGN; //1 byte
|
||||||
|
|
||||||
//leave the result on the stack
|
//leave the result on the stack
|
||||||
writeLiteralToCompiler(compiler, node->increment.identifier);
|
writeLiteralToCompiler(compiler, node->prefixIncrement.identifier);
|
||||||
compiler->bytecode[compiler->count++] = (unsigned char)OP_LITERAL_RAW; //1 byte
|
compiler->bytecode[compiler->count++] = (unsigned char)OP_LITERAL_RAW; //1 byte
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case AST_NODEINCREMENT_POSTFIX: {
|
case AST_NODE_PREFIX_DECREMENT: {
|
||||||
//push the identifier's VALUE to the stack
|
//push the literal to the stack (twice: add + assign)
|
||||||
writeLiteralToCompiler(compiler, node->increment.identifier);
|
writeLiteralToCompiler(compiler, node->prefixDecrement.identifier);
|
||||||
compiler->bytecode[compiler->count++] = (unsigned char)OP_LITERAL_RAW; //1 byte
|
writeLiteralToCompiler(compiler, node->prefixDecrement.identifier);
|
||||||
|
|
||||||
//push the identifier (twice)
|
|
||||||
writeLiteralToCompiler(compiler, node->increment.identifier);
|
|
||||||
writeLiteralToCompiler(compiler, node->increment.identifier);
|
|
||||||
|
|
||||||
//push the increment / decrement
|
//push the increment / decrement
|
||||||
Literal increment = TO_INTEGER_LITERAL(node->increment.increment);
|
Literal increment = TO_INTEGER_LITERAL(1);
|
||||||
|
writeLiteralToCompiler(compiler, increment);
|
||||||
|
|
||||||
|
//push the subtract opcode
|
||||||
|
compiler->bytecode[compiler->count++] = (unsigned char)OP_SUBTRACTION; //1 byte
|
||||||
|
|
||||||
|
//push the assign
|
||||||
|
compiler->bytecode[compiler->count++] = (unsigned char)OP_VAR_ASSIGN; //1 byte
|
||||||
|
|
||||||
|
//leave the result on the stack
|
||||||
|
writeLiteralToCompiler(compiler, node->prefixDecrement.identifier);
|
||||||
|
compiler->bytecode[compiler->count++] = (unsigned char)OP_LITERAL_RAW; //1 byte
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case AST_NODE_POSTFIX_INCREMENT: {
|
||||||
|
//push the identifier's VALUE to the stack
|
||||||
|
writeLiteralToCompiler(compiler, node->postfixIncrement.identifier);
|
||||||
|
compiler->bytecode[compiler->count++] = (unsigned char)OP_LITERAL_RAW; //1 byte
|
||||||
|
|
||||||
|
//push the identifier (twice: add + assign)
|
||||||
|
writeLiteralToCompiler(compiler, node->postfixIncrement.identifier);
|
||||||
|
writeLiteralToCompiler(compiler, node->postfixIncrement.identifier);
|
||||||
|
|
||||||
|
//push the increment / decrement
|
||||||
|
Literal increment = TO_INTEGER_LITERAL(1);
|
||||||
writeLiteralToCompiler(compiler, increment);
|
writeLiteralToCompiler(compiler, increment);
|
||||||
|
|
||||||
//push the add opcode
|
//push the add opcode
|
||||||
@@ -807,7 +815,28 @@ static Opcode writeCompilerWithJumps(Compiler* compiler, ASTNode* node, void* br
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case AST_NODEIMPORT: {
|
case AST_NODE_POSTFIX_DECREMENT: {
|
||||||
|
//push the identifier's VALUE to the stack
|
||||||
|
writeLiteralToCompiler(compiler, node->postfixDecrement.identifier);
|
||||||
|
compiler->bytecode[compiler->count++] = (unsigned char)OP_LITERAL_RAW; //1 byte
|
||||||
|
|
||||||
|
//push the identifier (twice: add + assign)
|
||||||
|
writeLiteralToCompiler(compiler, node->postfixDecrement.identifier);
|
||||||
|
writeLiteralToCompiler(compiler, node->postfixDecrement.identifier);
|
||||||
|
|
||||||
|
//push the increment / decrement
|
||||||
|
Literal increment = TO_INTEGER_LITERAL(1);
|
||||||
|
writeLiteralToCompiler(compiler, increment);
|
||||||
|
|
||||||
|
//push the subtract opcode
|
||||||
|
compiler->bytecode[compiler->count++] = (unsigned char)OP_SUBTRACTION; //1 byte
|
||||||
|
|
||||||
|
//push the assign
|
||||||
|
compiler->bytecode[compiler->count++] = (unsigned char)OP_VAR_ASSIGN; //1 byte
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case AST_NODE_IMPORT: {
|
||||||
//push the identifier, and the alias
|
//push the identifier, and the alias
|
||||||
writeLiteralToCompiler(compiler, node->import.identifier);
|
writeLiteralToCompiler(compiler, node->import.identifier);
|
||||||
writeLiteralToCompiler(compiler, node->import.alias);
|
writeLiteralToCompiler(compiler, node->import.alias);
|
||||||
@@ -817,17 +846,7 @@ static Opcode writeCompilerWithJumps(Compiler* compiler, ASTNode* node, void* br
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case AST_NODEEXPORT: {
|
case AST_NODE_INDEX: {
|
||||||
//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;
|
|
||||||
|
|
||||||
case AST_NODEINDEX: {
|
|
||||||
//pass to the child nodes, then embed the opcode
|
//pass to the child nodes, then embed the opcode
|
||||||
|
|
||||||
//first
|
//first
|
||||||
@@ -868,12 +887,6 @@ static Opcode writeCompilerWithJumps(Compiler* compiler, ASTNode* node, void* br
|
|||||||
return OP_INDEX_ASSIGN; //override binary's instruction IF it is assign
|
return OP_INDEX_ASSIGN; //override binary's instruction IF it is assign
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case AST_NODEDOT: {
|
|
||||||
fprintf(stderr, ERROR "[internal] AST_NODEDOT encountered in writeCompilerWithJumps()\n" RESET);
|
|
||||||
compiler->bytecode[compiler->count++] = OP_EOF; //1 byte
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return OP_EOF;
|
return OP_EOF;
|
||||||
@@ -1006,8 +1019,8 @@ static unsigned char* collateCompilerHeaderOpt(Compiler* compiler, int* size, bo
|
|||||||
|
|
||||||
Literal str = compiler->literalCache.literals[i];
|
Literal str = compiler->literalCache.literals[i];
|
||||||
|
|
||||||
for (int c = 0; c < (int)strlen(AS_STRING(str)); c++) {
|
for (int c = 0; c < AS_STRING(str)->length; c++) {
|
||||||
emitByte(&collation, &capacity, &count, AS_STRING(str)[c]);
|
emitByte(&collation, &capacity, &count, toCString(AS_STRING(str))[c]);
|
||||||
}
|
}
|
||||||
|
|
||||||
emitByte(&collation, &capacity, &count, '\0'); //terminate the string
|
emitByte(&collation, &capacity, &count, '\0'); //terminate the string
|
||||||
@@ -1078,8 +1091,8 @@ static unsigned char* collateCompilerHeaderOpt(Compiler* compiler, int* size, bo
|
|||||||
|
|
||||||
Literal identifier = compiler->literalCache.literals[i];
|
Literal identifier = compiler->literalCache.literals[i];
|
||||||
|
|
||||||
for (int c = 0; c < (int)strlen(AS_IDENTIFIER(identifier)); c++) {
|
for (int c = 0; c < AS_IDENTIFIER(identifier)->length; c++) {
|
||||||
emitByte(&collation, &capacity, &count, AS_IDENTIFIER(identifier)[c]);
|
emitByte(&collation, &capacity, &count, toCString(AS_IDENTIFIER(identifier))[c]);
|
||||||
}
|
}
|
||||||
|
|
||||||
emitByte(&collation, &capacity, &count, '\0'); //terminate the string
|
emitByte(&collation, &capacity, &count, '\0'); //terminate the string
|
||||||
|
|||||||
+39
-131
@@ -34,7 +34,7 @@ bool injectNativeFn(Interpreter* interpreter, char* name, NativeFn func) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int identifierLength = strlen(name);
|
int identifierLength = strlen(name);
|
||||||
Literal identifier = TO_IDENTIFIER_LITERAL(copyString(name, identifierLength), identifierLength);
|
Literal identifier = TO_IDENTIFIER_LITERAL(createRefStringLength(name, identifierLength));
|
||||||
|
|
||||||
//make sure the name isn't taken
|
//make sure the name isn't taken
|
||||||
if (existsLiteralDictionary(&interpreter->scope->variables, identifier)) {
|
if (existsLiteralDictionary(&interpreter->scope->variables, identifier)) {
|
||||||
@@ -64,7 +64,7 @@ bool injectNativeHook(Interpreter* interpreter, char* name, HookFn hook) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int identifierLength = strlen(name);
|
int identifierLength = strlen(name);
|
||||||
Literal identifier = TO_IDENTIFIER_LITERAL(copyString(name, identifierLength), identifierLength);
|
Literal identifier = TO_IDENTIFIER_LITERAL(createRefStringLength(name, identifierLength));
|
||||||
|
|
||||||
//make sure the name isn't taken
|
//make sure the name isn't taken
|
||||||
if (existsLiteralDictionary(interpreter->hooks, identifier)) {
|
if (existsLiteralDictionary(interpreter->hooks, identifier)) {
|
||||||
@@ -235,7 +235,7 @@ static bool execAssert(Interpreter* interpreter) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (IS_NULL(lhs) || !IS_TRUTHY(lhs)) {
|
if (IS_NULL(lhs) || !IS_TRUTHY(lhs)) {
|
||||||
(*interpreter->assertOutput)(AS_STRING(rhs));
|
(*interpreter->assertOutput)(toCString(AS_STRING(rhs)));
|
||||||
freeLiteral(rhs);
|
freeLiteral(rhs);
|
||||||
interpreter->panic = true;
|
interpreter->panic = true;
|
||||||
return false;
|
return false;
|
||||||
@@ -320,7 +320,7 @@ static bool execNegate(Interpreter* interpreter) {
|
|||||||
lit = TO_FLOAT_LITERAL(-AS_FLOAT(lit));
|
lit = TO_FLOAT_LITERAL(-AS_FLOAT(lit));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
interpreter->errorOutput("[internal] The interpreter can't negate that literal: ");
|
interpreter->errorOutput("Can't negate that literal: ");
|
||||||
printLiteralCustom(lit, interpreter->errorOutput);
|
printLiteralCustom(lit, interpreter->errorOutput);
|
||||||
interpreter->errorOutput("\n");
|
interpreter->errorOutput("\n");
|
||||||
|
|
||||||
@@ -352,7 +352,7 @@ static bool execInvert(Interpreter* interpreter) {
|
|||||||
lit = TO_BOOLEAN_LITERAL(!AS_BOOLEAN(lit));
|
lit = TO_BOOLEAN_LITERAL(!AS_BOOLEAN(lit));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
interpreter->errorOutput("[internal] The interpreter can't invert that literal: ");
|
interpreter->errorOutput("Can't invert that literal: ");
|
||||||
printLiteralCustom(lit, interpreter->errorOutput);
|
printLiteralCustom(lit, interpreter->errorOutput);
|
||||||
interpreter->errorOutput("\n");
|
interpreter->errorOutput("\n");
|
||||||
|
|
||||||
@@ -387,7 +387,7 @@ static bool execArithmetic(Interpreter* interpreter, Opcode opcode) {
|
|||||||
//special case for string concatenation ONLY
|
//special case for string concatenation ONLY
|
||||||
if (IS_STRING(lhs) && IS_STRING(rhs)) {
|
if (IS_STRING(lhs) && IS_STRING(rhs)) {
|
||||||
//check for overflow
|
//check for overflow
|
||||||
int totalLength = strlen(AS_STRING(lhs)) + strlen(AS_STRING(rhs));
|
int totalLength = AS_STRING(lhs)->length + AS_STRING(rhs)->length;
|
||||||
if (totalLength > MAX_STRING_LENGTH) {
|
if (totalLength > MAX_STRING_LENGTH) {
|
||||||
interpreter->errorOutput("Can't concatenate these strings (result is too long)\n");
|
interpreter->errorOutput("Can't concatenate these strings (result is too long)\n");
|
||||||
return false;
|
return false;
|
||||||
@@ -395,9 +395,11 @@ static bool execArithmetic(Interpreter* interpreter, Opcode opcode) {
|
|||||||
|
|
||||||
//concat the strings
|
//concat the strings
|
||||||
char buffer[MAX_STRING_LENGTH];
|
char buffer[MAX_STRING_LENGTH];
|
||||||
snprintf(buffer, MAX_STRING_LENGTH, "%s%s", AS_STRING(lhs), AS_STRING(rhs));
|
snprintf(buffer, MAX_STRING_LENGTH, "%s%s", toCString(AS_STRING(lhs)), toCString(AS_STRING(rhs)));
|
||||||
Literal literal = TO_STRING_LITERAL( copyString(buffer, totalLength), totalLength);
|
Literal literal = TO_STRING_LITERAL(createRefStringLength(buffer, totalLength));
|
||||||
pushLiteralArray(&interpreter->stack, literal);
|
pushLiteralArray(&interpreter->stack, literal);
|
||||||
|
|
||||||
|
//cleanup
|
||||||
freeLiteral(literal);
|
freeLiteral(literal);
|
||||||
freeLiteral(lhs);
|
freeLiteral(lhs);
|
||||||
freeLiteral(rhs);
|
freeLiteral(rhs);
|
||||||
@@ -751,7 +753,7 @@ static bool execValCast(Interpreter* interpreter) {
|
|||||||
|
|
||||||
if (IS_STRING(value)) {
|
if (IS_STRING(value)) {
|
||||||
int val = 0;
|
int val = 0;
|
||||||
sscanf(AS_STRING(value), "%d", &val);
|
sscanf(toCString(AS_STRING(value)), "%d", &val);
|
||||||
result = TO_INTEGER_LITERAL(val);
|
result = TO_INTEGER_LITERAL(val);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -771,7 +773,7 @@ static bool execValCast(Interpreter* interpreter) {
|
|||||||
|
|
||||||
if (IS_STRING(value)) {
|
if (IS_STRING(value)) {
|
||||||
float val = 0;
|
float val = 0;
|
||||||
sscanf(AS_STRING(value), "%f", &val);
|
sscanf(toCString(AS_STRING(value)), "%f", &val);
|
||||||
result = TO_FLOAT_LITERAL(val);
|
result = TO_FLOAT_LITERAL(val);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -781,21 +783,21 @@ static bool execValCast(Interpreter* interpreter) {
|
|||||||
char* str = AS_BOOLEAN(value) ? "true" : "false";
|
char* str = AS_BOOLEAN(value) ? "true" : "false";
|
||||||
|
|
||||||
int length = strlen(str);
|
int length = strlen(str);
|
||||||
result = TO_STRING_LITERAL(copyString(str, length), length);
|
result = TO_STRING_LITERAL(createRefStringLength(str, length)); //TODO: static reference optimisation?
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IS_INTEGER(value)) {
|
if (IS_INTEGER(value)) {
|
||||||
char buffer[128];
|
char buffer[128];
|
||||||
snprintf(buffer, 128, "%d", AS_INTEGER(value));
|
snprintf(buffer, 128, "%d", AS_INTEGER(value));
|
||||||
int length = strlen(buffer);
|
int length = strlen(buffer);
|
||||||
result = TO_STRING_LITERAL(copyString(buffer, length), length);
|
result = TO_STRING_LITERAL(createRefStringLength(buffer, length));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IS_FLOAT(value)) {
|
if (IS_FLOAT(value)) {
|
||||||
char buffer[128];
|
char buffer[128];
|
||||||
snprintf(buffer, 128, "%g", AS_FLOAT(value));
|
snprintf(buffer, 128, "%g", AS_FLOAT(value));
|
||||||
int length = strlen(buffer);
|
int length = strlen(buffer);
|
||||||
result = TO_STRING_LITERAL(copyString(buffer, length), length);
|
result = TO_STRING_LITERAL(createRefStringLength(buffer, length));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IS_STRING(value)) {
|
if (IS_STRING(value)) {
|
||||||
@@ -1143,12 +1145,12 @@ static bool execFnCall(Interpreter* interpreter, bool looseFirstArgument) {
|
|||||||
|
|
||||||
//let's screw with the fn name, too
|
//let's screw with the fn name, too
|
||||||
if (looseFirstArgument) {
|
if (looseFirstArgument) {
|
||||||
int length = strlen(AS_IDENTIFIER(identifier)) + 1;
|
int length = AS_IDENTIFIER(identifier)->length + 1;
|
||||||
char buffer[MAX_STRING_LENGTH];
|
char buffer[MAX_STRING_LENGTH];
|
||||||
snprintf(buffer, MAX_STRING_LENGTH, "_%s", AS_IDENTIFIER(identifier)); //prepend an underscore
|
snprintf(buffer, MAX_STRING_LENGTH, "_%s", toCString(AS_IDENTIFIER(identifier))); //prepend an underscore
|
||||||
|
|
||||||
freeLiteral(identifier);
|
freeLiteral(identifier);
|
||||||
identifier = TO_IDENTIFIER_LITERAL(copyString(buffer, length), length);
|
identifier = TO_IDENTIFIER_LITERAL(createRefStringLength(buffer, length));
|
||||||
}
|
}
|
||||||
|
|
||||||
Literal func = identifier;
|
Literal func = identifier;
|
||||||
@@ -1219,14 +1221,12 @@ bool callLiteralFn(Interpreter* interpreter, Literal func, LiteralArray* argumen
|
|||||||
initLiteralArray(&inner.literalCache);
|
initLiteralArray(&inner.literalCache);
|
||||||
inner.scope = pushScope(func.as.function.scope);
|
inner.scope = pushScope(func.as.function.scope);
|
||||||
inner.bytecode = AS_FUNCTION(func).bytecode;
|
inner.bytecode = AS_FUNCTION(func).bytecode;
|
||||||
inner.length = func.as.function.length;
|
inner.length = AS_FUNCTION(func).length;
|
||||||
inner.count = 0;
|
inner.count = 0;
|
||||||
inner.codeStart = -1;
|
inner.codeStart = -1;
|
||||||
inner.depth = interpreter->depth + 1;
|
inner.depth = interpreter->depth + 1;
|
||||||
inner.panic = false;
|
inner.panic = false;
|
||||||
initLiteralArray(&inner.stack);
|
initLiteralArray(&inner.stack);
|
||||||
inner.exports = interpreter->exports;
|
|
||||||
inner.exportTypes = interpreter->exportTypes;
|
|
||||||
inner.hooks = interpreter->hooks;
|
inner.hooks = interpreter->hooks;
|
||||||
setInterpreterPrint(&inner, interpreter->printOutput);
|
setInterpreterPrint(&inner, interpreter->printOutput);
|
||||||
setInterpreterAssert(&inner, interpreter->assertOutput);
|
setInterpreterAssert(&inner, interpreter->assertOutput);
|
||||||
@@ -1414,7 +1414,7 @@ bool callLiteralFn(Interpreter* interpreter, Literal func, LiteralArray* argumen
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool callFn(Interpreter* interpreter, char* name, LiteralArray* arguments, LiteralArray* returns) {
|
bool callFn(Interpreter* interpreter, char* name, LiteralArray* arguments, LiteralArray* returns) {
|
||||||
Literal key = TO_IDENTIFIER_LITERAL(copyString(name, strlen(name)), strlen(name));
|
Literal key = TO_IDENTIFIER_LITERAL(createRefStringLength(name, strlen(name)));
|
||||||
Literal val = TO_NULL_LITERAL;
|
Literal val = TO_NULL_LITERAL;
|
||||||
|
|
||||||
if (!isDelcaredScopeVariable(interpreter->scope, key)) {
|
if (!isDelcaredScopeVariable(interpreter->scope, key)) {
|
||||||
@@ -1471,7 +1471,16 @@ static bool execImport(Interpreter* interpreter) {
|
|||||||
Literal identifier = popLiteralArray(&interpreter->stack);
|
Literal identifier = popLiteralArray(&interpreter->stack);
|
||||||
|
|
||||||
//access the hooks
|
//access the hooks
|
||||||
if (existsLiteralDictionary(interpreter->hooks, identifier)) {
|
if (!existsLiteralDictionary(interpreter->hooks, identifier)) {
|
||||||
|
interpreter->errorOutput("Unknown library name in import statement: ");
|
||||||
|
printLiteralCustom(identifier, interpreter->errorOutput);
|
||||||
|
interpreter->errorOutput("\"\n");
|
||||||
|
|
||||||
|
freeLiteral(alias);
|
||||||
|
freeLiteral(identifier);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
Literal func = getLiteralDictionary(interpreter->hooks, identifier);
|
Literal func = getLiteralDictionary(interpreter->hooks, identifier);
|
||||||
|
|
||||||
if (!IS_FUNCTION_NATIVE(func)) {
|
if (!IS_FUNCTION_NATIVE(func)) {
|
||||||
@@ -1493,77 +1502,6 @@ static bool execImport(Interpreter* interpreter) {
|
|||||||
freeLiteral(alias);
|
freeLiteral(alias);
|
||||||
freeLiteral(identifier);
|
freeLiteral(identifier);
|
||||||
return true;
|
return true;
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool execIndex(Interpreter* interpreter, bool assignIntermediate) {
|
static bool execIndex(Interpreter* interpreter, bool assignIntermediate) {
|
||||||
@@ -1590,7 +1528,8 @@ static bool execIndex(Interpreter* interpreter, bool assignIntermediate) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!IS_ARRAY(compound) && !IS_DICTIONARY(compound) && !IS_STRING(compound)) {
|
if (!IS_ARRAY(compound) && !IS_DICTIONARY(compound) && !IS_STRING(compound)) {
|
||||||
interpreter->errorOutput("Unknown compound found in indexing notation\n");
|
interpreter->errorOutput("Unknown compound found in indexing notation: ");
|
||||||
|
printLiteralCustom(compound, interpreter->errorOutput);
|
||||||
freeLiteral(third);
|
freeLiteral(third);
|
||||||
freeLiteral(second);
|
freeLiteral(second);
|
||||||
freeLiteral(first);
|
freeLiteral(first);
|
||||||
@@ -1605,7 +1544,7 @@ static bool execIndex(Interpreter* interpreter, bool assignIntermediate) {
|
|||||||
Literal func = TO_NULL_LITERAL;
|
Literal func = TO_NULL_LITERAL;
|
||||||
char* keyStr = "_index";
|
char* keyStr = "_index";
|
||||||
int keyStrLength = strlen(keyStr);
|
int keyStrLength = strlen(keyStr);
|
||||||
Literal key = TO_IDENTIFIER_LITERAL(copyString(keyStr, keyStrLength), keyStrLength);
|
Literal key = TO_IDENTIFIER_LITERAL(createRefStringLength(keyStr, keyStrLength));
|
||||||
|
|
||||||
if (!getScopeVariable(interpreter->scope, key, &func) || !IS_FUNCTION_NATIVE(func)) {
|
if (!getScopeVariable(interpreter->scope, key, &func) || !IS_FUNCTION_NATIVE(func)) {
|
||||||
interpreter->errorOutput("couldn't get the _index function\n");
|
interpreter->errorOutput("couldn't get the _index function\n");
|
||||||
@@ -1704,7 +1643,7 @@ static bool execIndexAssign(Interpreter* interpreter) {
|
|||||||
Literal func = TO_NULL_LITERAL;
|
Literal func = TO_NULL_LITERAL;
|
||||||
char* keyStr = "_index";
|
char* keyStr = "_index";
|
||||||
int keyStrLength = strlen(keyStr);
|
int keyStrLength = strlen(keyStr);
|
||||||
Literal key = TO_IDENTIFIER_LITERAL(copyString(keyStr, keyStrLength), keyStrLength);
|
Literal key = TO_IDENTIFIER_LITERAL(createRefStringLength(keyStr, keyStrLength));
|
||||||
|
|
||||||
if (!getScopeVariable(interpreter->scope, key, &func) || !IS_FUNCTION_NATIVE(func)) {
|
if (!getScopeVariable(interpreter->scope, key, &func) || !IS_FUNCTION_NATIVE(func)) {
|
||||||
interpreter->errorOutput("couldn't get the _index function\n");
|
interpreter->errorOutput("couldn't get the _index function\n");
|
||||||
@@ -1760,7 +1699,7 @@ static bool execIndexAssign(Interpreter* interpreter) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int opLength = strlen(opStr);
|
int opLength = strlen(opStr);
|
||||||
Literal op = TO_STRING_LITERAL(copyString(opStr, opLength), opLength);
|
Literal op = TO_STRING_LITERAL(createRefStringLength(opStr, opLength)); //TODO: static reference optimisation?
|
||||||
|
|
||||||
//build the argument list
|
//build the argument list
|
||||||
LiteralArray arguments;
|
LiteralArray arguments;
|
||||||
@@ -1815,7 +1754,7 @@ static bool execIndexAssign(Interpreter* interpreter) {
|
|||||||
|
|
||||||
char* opStr = "="; //shadow, but force assignment
|
char* opStr = "="; //shadow, but force assignment
|
||||||
int opLength = strlen(opStr);
|
int opLength = strlen(opStr);
|
||||||
op = TO_STRING_LITERAL(copyString(opStr, opLength), opLength);
|
op = TO_STRING_LITERAL(createRefStringLength(opStr, opLength)); //TODO: static reference optimisation?
|
||||||
|
|
||||||
//assign to the idn / compound - with _index
|
//assign to the idn / compound - with _index
|
||||||
pushLiteralArray(&arguments, idn);
|
pushLiteralArray(&arguments, idn);
|
||||||
@@ -2084,12 +2023,6 @@ static void execInterpreter(Interpreter* interpreter) {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case OP_EXPORT:
|
|
||||||
if (!execExport(interpreter)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case OP_INDEX:
|
case OP_INDEX:
|
||||||
if (!execIndex(interpreter, false)) {
|
if (!execIndex(interpreter, false)) {
|
||||||
return;
|
return;
|
||||||
@@ -2194,7 +2127,7 @@ static void readInterpreterSections(Interpreter* interpreter) {
|
|||||||
case LITERAL_STRING: {
|
case LITERAL_STRING: {
|
||||||
char* s = readString(interpreter->bytecode, &interpreter->count);
|
char* s = readString(interpreter->bytecode, &interpreter->count);
|
||||||
int length = strlen(s);
|
int length = strlen(s);
|
||||||
Literal literal = TO_STRING_LITERAL( copyString(s, length), length);
|
Literal literal = TO_STRING_LITERAL(createRefStringLength(s, length));
|
||||||
pushLiteralArray(&interpreter->literalCache, literal);
|
pushLiteralArray(&interpreter->literalCache, literal);
|
||||||
freeLiteral(literal);
|
freeLiteral(literal);
|
||||||
|
|
||||||
@@ -2290,13 +2223,13 @@ static void readInterpreterSections(Interpreter* interpreter) {
|
|||||||
char* str = readString(interpreter->bytecode, &interpreter->count);
|
char* str = readString(interpreter->bytecode, &interpreter->count);
|
||||||
|
|
||||||
int length = strlen(str);
|
int length = strlen(str);
|
||||||
Literal identifier = TO_IDENTIFIER_LITERAL(copyString(str, length), length);
|
Literal identifier = TO_IDENTIFIER_LITERAL(createRefStringLength(str, length));
|
||||||
|
|
||||||
pushLiteralArray(&interpreter->literalCache, identifier);
|
pushLiteralArray(&interpreter->literalCache, identifier);
|
||||||
|
|
||||||
#ifndef TOY_EXPORT
|
#ifndef TOY_EXPORT
|
||||||
if (command.verbose) {
|
if (command.verbose) {
|
||||||
printf("(identifier %s (hash: %x))\n", AS_IDENTIFIER(identifier), identifier.as.identifier.hash);
|
printf("(identifier %s (hash: %x))\n", toCString(AS_IDENTIFIER(identifier)), identifier.as.identifier.hash);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -2398,11 +2331,6 @@ static void readInterpreterSections(Interpreter* interpreter) {
|
|||||||
|
|
||||||
//exposed functions
|
//exposed functions
|
||||||
void initInterpreter(Interpreter* interpreter) {
|
void initInterpreter(Interpreter* interpreter) {
|
||||||
//NOTE: separate initialization for exports
|
|
||||||
interpreter->exports = ALLOCATE(LiteralDictionary, 1);
|
|
||||||
initLiteralDictionary(interpreter->exports);
|
|
||||||
interpreter->exportTypes = ALLOCATE(LiteralDictionary, 1);
|
|
||||||
initLiteralDictionary(interpreter->exportTypes);
|
|
||||||
interpreter->hooks = ALLOCATE(LiteralDictionary, 1);
|
interpreter->hooks = ALLOCATE(LiteralDictionary, 1);
|
||||||
initLiteralDictionary(interpreter->hooks);
|
initLiteralDictionary(interpreter->hooks);
|
||||||
|
|
||||||
@@ -2517,26 +2445,6 @@ void freeInterpreter(Interpreter* interpreter) {
|
|||||||
interpreter->scope = popScope(interpreter->scope);
|
interpreter->scope = popScope(interpreter->scope);
|
||||||
}
|
}
|
||||||
|
|
||||||
//BUGFIX: handle scopes/types in the exports
|
|
||||||
for (int i = 0; i < interpreter->exports->capacity; i++) {
|
|
||||||
if (IS_FUNCTION(interpreter->exports->entries[i].key)) {
|
|
||||||
popScope(AS_FUNCTION(interpreter->exports->entries[i].key).scope);
|
|
||||||
AS_FUNCTION(interpreter->exports->entries[i].key).scope = NULL;
|
|
||||||
}
|
|
||||||
if (IS_FUNCTION(interpreter->exports->entries[i].value)) {
|
|
||||||
popScope(AS_FUNCTION(interpreter->exports->entries[i].value).scope);
|
|
||||||
AS_FUNCTION(interpreter->exports->entries[i].value).scope = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
freeLiteralDictionary(interpreter->exports);
|
|
||||||
FREE(LiteralDictionary, interpreter->exports);
|
|
||||||
interpreter->exports = NULL;
|
|
||||||
|
|
||||||
freeLiteralDictionary(interpreter->exportTypes);
|
|
||||||
FREE(LiteralDictionary, interpreter->exportTypes);
|
|
||||||
interpreter->exportTypes = NULL;
|
|
||||||
|
|
||||||
freeLiteralDictionary(interpreter->hooks);
|
freeLiteralDictionary(interpreter->hooks);
|
||||||
FREE(LiteralDictionary, interpreter->hooks);
|
FREE(LiteralDictionary, interpreter->hooks);
|
||||||
interpreter->hooks = NULL;
|
interpreter->hooks = NULL;
|
||||||
|
|||||||
@@ -21,8 +21,7 @@ typedef struct Interpreter {
|
|||||||
Scope* scope;
|
Scope* scope;
|
||||||
LiteralArray stack;
|
LiteralArray stack;
|
||||||
|
|
||||||
LiteralDictionary* exports; //read-write - interface with Toy from C - this is a pointer, since it works at a script-level
|
//Library APIs
|
||||||
LiteralDictionary* exportTypes;
|
|
||||||
LiteralDictionary* hooks;
|
LiteralDictionary* hooks;
|
||||||
|
|
||||||
//debug outputs
|
//debug outputs
|
||||||
|
|||||||
+35
-37
@@ -21,7 +21,7 @@ static unsigned int hashString(const char* string, int length) {
|
|||||||
return hash;
|
return hash;
|
||||||
}
|
}
|
||||||
|
|
||||||
static unsigned int hash(unsigned int x) {
|
static unsigned int hashUInt(unsigned int x) {
|
||||||
x = ((x >> 16) ^ x) * 0x45d9f3b;
|
x = ((x >> 16) ^ x) * 0x45d9f3b;
|
||||||
x = ((x >> 16) ^ x) * 0x45d9f3b;
|
x = ((x >> 16) ^ x) * 0x45d9f3b;
|
||||||
x = (x >> 16) ^ x;
|
x = (x >> 16) ^ x;
|
||||||
@@ -30,11 +30,18 @@ static unsigned int hash(unsigned int x) {
|
|||||||
|
|
||||||
//exposed functions
|
//exposed functions
|
||||||
void freeLiteral(Literal literal) {
|
void freeLiteral(Literal literal) {
|
||||||
|
//refstrings
|
||||||
if (IS_STRING(literal)) {
|
if (IS_STRING(literal)) {
|
||||||
FREE_ARRAY(char, AS_STRING(literal), literal.as.string.length + 1);
|
deleteRefString(AS_STRING(literal));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (IS_IDENTIFIER(literal)) {
|
||||||
|
deleteRefString(AS_IDENTIFIER(literal));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//compounds
|
||||||
if (IS_ARRAY(literal) || literal.type == LITERAL_DICTIONARY_INTERMEDIATE || literal.type == LITERAL_TYPE_INTERMEDIATE) {
|
if (IS_ARRAY(literal) || literal.type == LITERAL_DICTIONARY_INTERMEDIATE || literal.type == LITERAL_TYPE_INTERMEDIATE) {
|
||||||
freeLiteralArray(AS_ARRAY(literal));
|
freeLiteralArray(AS_ARRAY(literal));
|
||||||
FREE(LiteralArray, AS_ARRAY(literal));
|
FREE(LiteralArray, AS_ARRAY(literal));
|
||||||
@@ -47,17 +54,13 @@ void freeLiteral(Literal literal) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//complex literals
|
||||||
if (IS_FUNCTION(literal)) {
|
if (IS_FUNCTION(literal)) {
|
||||||
popScope(AS_FUNCTION(literal).scope);
|
popScope(AS_FUNCTION(literal).scope);
|
||||||
AS_FUNCTION(literal).scope = NULL;
|
AS_FUNCTION(literal).scope = NULL;
|
||||||
FREE_ARRAY(unsigned char, AS_FUNCTION(literal).bytecode, AS_FUNCTION(literal).length);
|
FREE_ARRAY(unsigned char, AS_FUNCTION(literal).bytecode, AS_FUNCTION(literal).length);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IS_IDENTIFIER(literal)) {
|
|
||||||
FREE_ARRAY(char, AS_IDENTIFIER(literal), literal.as.identifier.length + 1);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (IS_TYPE(literal)) {
|
if (IS_TYPE(literal)) {
|
||||||
for (int i = 0; i < AS_TYPE(literal).count; i++) {
|
for (int i = 0; i < AS_TYPE(literal).count; i++) {
|
||||||
freeLiteral(((Literal*)(AS_TYPE(literal).subtypes))[i]);
|
freeLiteral(((Literal*)(AS_TYPE(literal).subtypes))[i]);
|
||||||
@@ -80,12 +83,12 @@ bool _isTruthy(Literal x) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
Literal _toStringLiteral(char* str, int length) {
|
Literal _toStringLiteral(RefString* ptr) {
|
||||||
return ((Literal){LITERAL_STRING, { .string.ptr = (char*)str, .string.length = length }});
|
return ((Literal){LITERAL_STRING, { .string.ptr = ptr }});
|
||||||
}
|
}
|
||||||
|
|
||||||
Literal _toIdentifierLiteral(char* str, int length) {
|
Literal _toIdentifierLiteral(RefString* ptr) {
|
||||||
return ((Literal){LITERAL_IDENTIFIER,{ .identifier.ptr = (char*)str, .identifier.length = length, .identifier.hash = hashString(str, length) }});
|
return ((Literal){LITERAL_IDENTIFIER,{ .identifier.ptr = ptr, .identifier.hash = hashString(toCString(ptr), lengthRefString(ptr)) }});
|
||||||
}
|
}
|
||||||
|
|
||||||
Literal* _typePushSubtype(Literal* lit, Literal subtype) {
|
Literal* _typePushSubtype(Literal* lit, Literal subtype) {
|
||||||
@@ -112,7 +115,7 @@ Literal copyLiteral(Literal original) {
|
|||||||
return original;
|
return original;
|
||||||
|
|
||||||
case LITERAL_STRING: {
|
case LITERAL_STRING: {
|
||||||
return TO_STRING_LITERAL(copyString(AS_STRING(original), original.as.string.length), original.as.string.length);
|
return TO_STRING_LITERAL(copyRefString(AS_STRING(original)));
|
||||||
}
|
}
|
||||||
|
|
||||||
case LITERAL_ARRAY: {
|
case LITERAL_ARRAY: {
|
||||||
@@ -152,7 +155,7 @@ Literal copyLiteral(Literal original) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
case LITERAL_IDENTIFIER: {
|
case LITERAL_IDENTIFIER: {
|
||||||
return TO_IDENTIFIER_LITERAL(copyString(AS_IDENTIFIER(original), original.as.identifier.length), original.as.identifier.length);
|
return TO_IDENTIFIER_LITERAL(copyRefString(AS_IDENTIFIER(original)));
|
||||||
}
|
}
|
||||||
|
|
||||||
case LITERAL_TYPE: {
|
case LITERAL_TYPE: {
|
||||||
@@ -212,14 +215,6 @@ Literal copyLiteral(Literal original) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
char* copyString(char* original, int length) {
|
|
||||||
//make a local copy of the char array
|
|
||||||
char* buffer = ALLOCATE(char, length + 1);
|
|
||||||
strncpy(buffer, original, length);
|
|
||||||
buffer[length] = '\0';
|
|
||||||
return buffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool literalsAreEqual(Literal lhs, Literal rhs) {
|
bool literalsAreEqual(Literal lhs, Literal rhs) {
|
||||||
//utility for other things
|
//utility for other things
|
||||||
if (lhs.type != rhs.type) {
|
if (lhs.type != rhs.type) {
|
||||||
@@ -250,10 +245,7 @@ bool literalsAreEqual(Literal lhs, Literal rhs) {
|
|||||||
return AS_FLOAT(lhs) == AS_FLOAT(rhs);
|
return AS_FLOAT(lhs) == AS_FLOAT(rhs);
|
||||||
|
|
||||||
case LITERAL_STRING:
|
case LITERAL_STRING:
|
||||||
if (lhs.as.string.length != rhs.as.string.length) {
|
return equalsRefString(AS_STRING(lhs), AS_STRING(rhs));
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return !strncmp(AS_STRING(lhs), AS_STRING(rhs), lhs.as.string.length);
|
|
||||||
|
|
||||||
case LITERAL_ARRAY:
|
case LITERAL_ARRAY:
|
||||||
case LITERAL_DICTIONARY_INTERMEDIATE: //BUGFIX
|
case LITERAL_DICTIONARY_INTERMEDIATE: //BUGFIX
|
||||||
@@ -299,11 +291,11 @@ bool literalsAreEqual(Literal lhs, Literal rhs) {
|
|||||||
|
|
||||||
case LITERAL_IDENTIFIER:
|
case LITERAL_IDENTIFIER:
|
||||||
//check shortcuts
|
//check shortcuts
|
||||||
if (HASH_I(lhs) != HASH_I(rhs) && lhs.as.identifier.length != rhs.as.identifier.length) {
|
if (HASH_I(lhs) != HASH_I(rhs)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return !strncmp(AS_IDENTIFIER(lhs), AS_IDENTIFIER(rhs), lhs.as.identifier.length);
|
return equalsRefString(AS_IDENTIFIER(lhs), AS_IDENTIFIER(rhs));
|
||||||
|
|
||||||
case LITERAL_TYPE:
|
case LITERAL_TYPE:
|
||||||
//check types
|
//check types
|
||||||
@@ -359,20 +351,20 @@ int hashLiteral(Literal lit) {
|
|||||||
return AS_BOOLEAN(lit) ? 1 : 0;
|
return AS_BOOLEAN(lit) ? 1 : 0;
|
||||||
|
|
||||||
case LITERAL_INTEGER:
|
case LITERAL_INTEGER:
|
||||||
return hash((unsigned int)AS_INTEGER(lit));
|
return hashUInt((unsigned int)AS_INTEGER(lit));
|
||||||
|
|
||||||
case LITERAL_FLOAT:
|
case LITERAL_FLOAT:
|
||||||
return hash(*(unsigned int*)(&AS_FLOAT(lit)));
|
return hashUInt(*(unsigned int*)(&AS_FLOAT(lit)));
|
||||||
|
|
||||||
case LITERAL_STRING:
|
case LITERAL_STRING:
|
||||||
return hashString(AS_STRING(lit), strlen(AS_STRING(lit)));
|
return hashString(toCString(AS_STRING(lit)), lengthRefString(AS_STRING(lit)));
|
||||||
|
|
||||||
case LITERAL_ARRAY: {
|
case LITERAL_ARRAY: {
|
||||||
unsigned int res = 0;
|
unsigned int res = 0;
|
||||||
for (int i = 0; i < AS_ARRAY(lit)->count; i++) {
|
for (int i = 0; i < AS_ARRAY(lit)->count; i++) {
|
||||||
res += hashLiteral(AS_ARRAY(lit)->literals[i]);
|
res += hashLiteral(AS_ARRAY(lit)->literals[i]);
|
||||||
}
|
}
|
||||||
return hash(res);
|
return hashUInt(res);
|
||||||
}
|
}
|
||||||
|
|
||||||
case LITERAL_DICTIONARY: {
|
case LITERAL_DICTIONARY: {
|
||||||
@@ -383,12 +375,12 @@ int hashLiteral(Literal lit) {
|
|||||||
res += hashLiteral(AS_DICTIONARY(lit)->entries[i].value);
|
res += hashLiteral(AS_DICTIONARY(lit)->entries[i].value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return hash(res);
|
return hashUInt(res);
|
||||||
}
|
}
|
||||||
|
|
||||||
case LITERAL_FUNCTION:
|
case LITERAL_FUNCTION:
|
||||||
case LITERAL_FUNCTION_NATIVE:
|
case LITERAL_FUNCTION_NATIVE:
|
||||||
return 0; //TODO: find a way to hash these properly
|
return 0; //can't hash these
|
||||||
|
|
||||||
case LITERAL_IDENTIFIER:
|
case LITERAL_IDENTIFIER:
|
||||||
return HASH_I(lit); //pre-computed
|
return HASH_I(lit); //pre-computed
|
||||||
@@ -456,7 +448,14 @@ void printLiteralCustom(Literal literal, void (printFn)(const char*)) {
|
|||||||
|
|
||||||
case LITERAL_FLOAT: {
|
case LITERAL_FLOAT: {
|
||||||
char buffer[256];
|
char buffer[256];
|
||||||
|
|
||||||
|
if (AS_FLOAT(literal) - (int)AS_FLOAT(literal)) {
|
||||||
snprintf(buffer, 256, "%g", AS_FLOAT(literal));
|
snprintf(buffer, 256, "%g", AS_FLOAT(literal));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
snprintf(buffer, 256, "%.1f", AS_FLOAT(literal));
|
||||||
|
}
|
||||||
|
|
||||||
printFn(buffer);
|
printFn(buffer);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -464,10 +463,10 @@ void printLiteralCustom(Literal literal, void (printFn)(const char*)) {
|
|||||||
case LITERAL_STRING: {
|
case LITERAL_STRING: {
|
||||||
char buffer[MAX_STRING_LENGTH];
|
char buffer[MAX_STRING_LENGTH];
|
||||||
if (!quotes) {
|
if (!quotes) {
|
||||||
snprintf(buffer, MAX_STRING_LENGTH, "%.*s", (int)strlen(AS_STRING(literal)), AS_STRING(literal));
|
snprintf(buffer, MAX_STRING_LENGTH, "%.*s", lengthRefString(AS_STRING(literal)), toCString(AS_STRING(literal)));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
snprintf(buffer, MAX_STRING_LENGTH, "%c%.*s%c", quotes, (int)strlen(AS_STRING(literal)), AS_STRING(literal), quotes);
|
snprintf(buffer, MAX_STRING_LENGTH, "%c%.*s%c", quotes, lengthRefString(AS_STRING(literal)), toCString(AS_STRING(literal)), quotes);
|
||||||
}
|
}
|
||||||
printFn(buffer);
|
printFn(buffer);
|
||||||
}
|
}
|
||||||
@@ -565,7 +564,6 @@ void printLiteralCustom(Literal literal, void (printFn)(const char*)) {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
//TODO: functions
|
|
||||||
case LITERAL_FUNCTION:
|
case LITERAL_FUNCTION:
|
||||||
case LITERAL_FUNCTION_NATIVE:
|
case LITERAL_FUNCTION_NATIVE:
|
||||||
printFn("(function)");
|
printFn("(function)");
|
||||||
@@ -573,7 +571,7 @@ void printLiteralCustom(Literal literal, void (printFn)(const char*)) {
|
|||||||
|
|
||||||
case LITERAL_IDENTIFIER: {
|
case LITERAL_IDENTIFIER: {
|
||||||
char buffer[256];
|
char buffer[256];
|
||||||
snprintf(buffer, 256, "%.*s", (int)strlen( AS_IDENTIFIER(literal) ), AS_IDENTIFIER(literal));
|
snprintf(buffer, 256, "%.*s", lengthRefString(AS_IDENTIFIER(literal)), toCString(AS_IDENTIFIER(literal)));
|
||||||
printFn(buffer);
|
printFn(buffer);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|||||||
+10
-10
@@ -2,6 +2,8 @@
|
|||||||
|
|
||||||
#include "toy_common.h"
|
#include "toy_common.h"
|
||||||
|
|
||||||
|
#include "refstring.h"
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
@@ -33,8 +35,8 @@ typedef struct {
|
|||||||
int integer;
|
int integer;
|
||||||
float number;
|
float number;
|
||||||
struct {
|
struct {
|
||||||
char* ptr;
|
RefString* ptr;
|
||||||
int length;
|
//string hash?
|
||||||
} string;
|
} string;
|
||||||
|
|
||||||
void* array;
|
void* array;
|
||||||
@@ -47,8 +49,7 @@ typedef struct {
|
|||||||
} function;
|
} function;
|
||||||
|
|
||||||
struct { //for variable names
|
struct { //for variable names
|
||||||
char* ptr;
|
RefString* ptr;
|
||||||
int length;
|
|
||||||
int hash;
|
int hash;
|
||||||
} identifier;
|
} identifier;
|
||||||
|
|
||||||
@@ -62,7 +63,7 @@ typedef struct {
|
|||||||
|
|
||||||
struct {
|
struct {
|
||||||
void* ptr;
|
void* ptr;
|
||||||
int tag;
|
int tag; //TODO: remove tags?
|
||||||
} opaque;
|
} opaque;
|
||||||
} as;
|
} as;
|
||||||
} Literal;
|
} Literal;
|
||||||
@@ -95,11 +96,11 @@ typedef struct {
|
|||||||
#define TO_BOOLEAN_LITERAL(value) ((Literal){LITERAL_BOOLEAN, { .boolean = value }})
|
#define TO_BOOLEAN_LITERAL(value) ((Literal){LITERAL_BOOLEAN, { .boolean = value }})
|
||||||
#define TO_INTEGER_LITERAL(value) ((Literal){LITERAL_INTEGER, { .integer = value }})
|
#define TO_INTEGER_LITERAL(value) ((Literal){LITERAL_INTEGER, { .integer = value }})
|
||||||
#define TO_FLOAT_LITERAL(value) ((Literal){LITERAL_FLOAT, { .number = value }})
|
#define TO_FLOAT_LITERAL(value) ((Literal){LITERAL_FLOAT, { .number = value }})
|
||||||
#define TO_STRING_LITERAL(value, l) _toStringLiteral(value, l)
|
#define TO_STRING_LITERAL(value) _toStringLiteral(value)
|
||||||
#define TO_ARRAY_LITERAL(value) ((Literal){LITERAL_ARRAY, { .array = value }})
|
#define TO_ARRAY_LITERAL(value) ((Literal){LITERAL_ARRAY, { .array = value }})
|
||||||
#define TO_DICTIONARY_LITERAL(value) ((Literal){LITERAL_DICTIONARY, { .dictionary = value }})
|
#define TO_DICTIONARY_LITERAL(value) ((Literal){LITERAL_DICTIONARY, { .dictionary = value }})
|
||||||
#define TO_FUNCTION_LITERAL(value, l) ((Literal){LITERAL_FUNCTION, { .function.bytecode = value, .function.scope = NULL, .function.length = l }})
|
#define TO_FUNCTION_LITERAL(value, l) ((Literal){LITERAL_FUNCTION, { .function.bytecode = value, .function.scope = NULL, .function.length = l }})
|
||||||
#define TO_IDENTIFIER_LITERAL(value, l) _toIdentifierLiteral(value, l)
|
#define TO_IDENTIFIER_LITERAL(value) _toIdentifierLiteral(value)
|
||||||
#define TO_TYPE_LITERAL(value, c) ((Literal){ LITERAL_TYPE, { .type.typeOf = value, .type.constant = c, .type.subtypes = NULL, .type.capacity = 0, .type.count = 0 }})
|
#define TO_TYPE_LITERAL(value, c) ((Literal){ LITERAL_TYPE, { .type.typeOf = value, .type.constant = c, .type.subtypes = NULL, .type.capacity = 0, .type.count = 0 }})
|
||||||
#define TO_OPAQUE_LITERAL(value, t) ((Literal){ LITERAL_OPAQUE, { .opaque.ptr = value, .opaque.tag = t }})
|
#define TO_OPAQUE_LITERAL(value, t) ((Literal){ LITERAL_OPAQUE, { .opaque.ptr = value, .opaque.tag = t }})
|
||||||
|
|
||||||
@@ -114,13 +115,12 @@ TOY_API void freeLiteral(Literal literal);
|
|||||||
|
|
||||||
//BUGFIX: macros are not functions
|
//BUGFIX: macros are not functions
|
||||||
TOY_API bool _isTruthy(Literal x);
|
TOY_API bool _isTruthy(Literal x);
|
||||||
TOY_API Literal _toStringLiteral(char* str, int length);
|
TOY_API Literal _toStringLiteral(RefString* ptr);
|
||||||
TOY_API Literal _toIdentifierLiteral(char* str, int length);
|
TOY_API Literal _toIdentifierLiteral(RefString* ptr);
|
||||||
TOY_API Literal* _typePushSubtype(Literal* lit, Literal subtype);
|
TOY_API Literal* _typePushSubtype(Literal* lit, Literal subtype);
|
||||||
|
|
||||||
//utils
|
//utils
|
||||||
TOY_API Literal copyLiteral(Literal original);
|
TOY_API Literal copyLiteral(Literal original);
|
||||||
TOY_API char* copyString(char* original, int length);
|
|
||||||
TOY_API bool literalsAreEqual(Literal lhs, Literal rhs);
|
TOY_API bool literalsAreEqual(Literal lhs, Literal rhs);
|
||||||
TOY_API int hashLiteral(Literal lit);
|
TOY_API int hashLiteral(Literal lit);
|
||||||
|
|
||||||
|
|||||||
@@ -77,8 +77,6 @@ bool setLiteralArray(LiteralArray* array, Literal index, Literal value) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO: implicit push when referencing one-past-the-end?
|
|
||||||
|
|
||||||
freeLiteral(array->literals[idx]);
|
freeLiteral(array->literals[idx]);
|
||||||
array->literals[idx] = copyLiteral(value);
|
array->literals[idx] = copyLiteral(value);
|
||||||
|
|
||||||
|
|||||||
@@ -34,6 +34,12 @@ library: $(OBJ)
|
|||||||
static: $(OBJ)
|
static: $(OBJ)
|
||||||
ar crs ../$(TOY_OUTDIR)/lib$(OUTNAME).a $(OBJ)
|
ar crs ../$(TOY_OUTDIR)/lib$(OUTNAME).a $(OBJ)
|
||||||
|
|
||||||
|
library-release: $(OBJ) library
|
||||||
|
strip $(OUT)
|
||||||
|
|
||||||
|
static-release: $(OBJ) static
|
||||||
|
strip -d ../$(TOY_OUTDIR)/lib$(OUTNAME).a
|
||||||
|
|
||||||
$(OBJ): | $(ODIR)
|
$(OBJ): | $(ODIR)
|
||||||
|
|
||||||
$(ODIR):
|
$(ODIR):
|
||||||
|
|||||||
+31
-2
@@ -1,11 +1,13 @@
|
|||||||
#include "memory.h"
|
#include "memory.h"
|
||||||
|
#include "refstring.h"
|
||||||
|
|
||||||
#include "console_colors.h"
|
#include "console_colors.h"
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
void* reallocate(void* pointer, size_t oldSize, size_t newSize) {
|
//default allocator
|
||||||
|
void* defaultMemoryAllocator(void* pointer, size_t oldSize, size_t newSize) {
|
||||||
if (newSize == 0 && oldSize == 0) {
|
if (newSize == 0 && oldSize == 0) {
|
||||||
//causes issues, so just skip out with a NO-OP
|
//causes issues, so just skip out with a NO-OP
|
||||||
return NULL;
|
return NULL;
|
||||||
@@ -20,10 +22,37 @@ void* reallocate(void* pointer, size_t oldSize, size_t newSize) {
|
|||||||
void* mem = realloc(pointer, newSize);
|
void* mem = realloc(pointer, newSize);
|
||||||
|
|
||||||
if (mem == NULL) {
|
if (mem == NULL) {
|
||||||
fprintf(stderr, ERROR "[internal]Memory allocation error (requested %d for %ld, replacing %d)\n" ERROR, (int)newSize, (long int)pointer, (int)oldSize);
|
fprintf(stderr, ERROR "[internal] Memory allocation error (requested %d for %ld, replacing %d)\n" RESET, (int)newSize, (long int)pointer, (int)oldSize);
|
||||||
exit(-1);
|
exit(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
return mem;
|
return mem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//static variables
|
||||||
|
static MemoryAllocatorFn allocator;
|
||||||
|
|
||||||
|
//preload
|
||||||
|
static void __attribute__((constructor)) preloadMemoryAllocator() {
|
||||||
|
setMemoryAllocator(defaultMemoryAllocator);
|
||||||
|
}
|
||||||
|
|
||||||
|
//exposed API
|
||||||
|
void* reallocate(void* pointer, size_t oldSize, size_t newSize) {
|
||||||
|
return allocator(pointer, oldSize, newSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setMemoryAllocator(MemoryAllocatorFn fn) {
|
||||||
|
if (fn == NULL) {
|
||||||
|
fprintf(stderr, ERROR "[internal] Memory allocator error (can't be null)\n" RESET);
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fn == reallocate) {
|
||||||
|
fprintf(stderr, ERROR "[internal] Memory allocator error (can't loop the reallocate function)\n" RESET);
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
allocator = fn;
|
||||||
|
setRefStringAllocatorFn(fn);
|
||||||
|
}
|
||||||
|
|||||||
@@ -10,5 +10,9 @@
|
|||||||
#define SHRINK_ARRAY(type, pointer, oldCount, count) (type*)reallocate((type*)pointer, sizeof(type) * (oldCount), sizeof(type) * (count))
|
#define SHRINK_ARRAY(type, pointer, oldCount, count) (type*)reallocate((type*)pointer, sizeof(type) * (oldCount), sizeof(type) * (count))
|
||||||
#define FREE_ARRAY(type, pointer, oldCount) reallocate((type*)pointer, sizeof(type) * (oldCount), 0)
|
#define FREE_ARRAY(type, pointer, oldCount) reallocate((type*)pointer, sizeof(type) * (oldCount), 0)
|
||||||
|
|
||||||
|
//implementation details
|
||||||
void* reallocate(void* pointer, size_t oldSize, size_t newSize);
|
void* reallocate(void* pointer, size_t oldSize, size_t newSize);
|
||||||
|
|
||||||
|
//assign the memory allocator
|
||||||
|
typedef void* (*MemoryAllocatorFn)(void* pointer, size_t oldSize, size_t newSize);
|
||||||
|
TOY_API void setMemoryAllocator(MemoryAllocatorFn);
|
||||||
|
|||||||
+1
-1
@@ -46,7 +46,7 @@ typedef enum Opcode {
|
|||||||
OP_TYPE_OF, //get the type of a variable
|
OP_TYPE_OF, //get the type of a variable
|
||||||
|
|
||||||
OP_IMPORT,
|
OP_IMPORT,
|
||||||
OP_EXPORT,
|
OP_EXPORT_removed,
|
||||||
|
|
||||||
//for indexing
|
//for indexing
|
||||||
OP_INDEX,
|
OP_INDEX,
|
||||||
|
|||||||
+88
-135
@@ -119,6 +119,7 @@ static void declaration(Parser* parser, ASTNode** nodeHandle);
|
|||||||
static void parsePrecedence(Parser* parser, ASTNode** nodeHandle, PrecedenceRule rule);
|
static void parsePrecedence(Parser* parser, ASTNode** nodeHandle, PrecedenceRule rule);
|
||||||
static Literal readTypeToLiteral(Parser* parser);
|
static Literal readTypeToLiteral(Parser* parser);
|
||||||
|
|
||||||
|
//TODO: resolve the messy order of these
|
||||||
//the expression rules
|
//the expression rules
|
||||||
static Opcode asType(Parser* parser, ASTNode** nodeHandle) {
|
static Opcode asType(Parser* parser, ASTNode** nodeHandle) {
|
||||||
Literal literal = readTypeToLiteral(parser);
|
Literal literal = readTypeToLiteral(parser);
|
||||||
@@ -182,14 +183,14 @@ static Opcode compound(Parser* parser, ASTNode** nodeHandle) {
|
|||||||
parsePrecedence(parser, &right, PREC_PRIMARY);
|
parsePrecedence(parser, &right, PREC_PRIMARY);
|
||||||
|
|
||||||
if (!right) { //error
|
if (!right) { //error
|
||||||
freeNode(left);
|
freeASTNode(left);
|
||||||
return OP_EOF;
|
return OP_EOF;
|
||||||
}
|
}
|
||||||
|
|
||||||
//check we ARE defining a dictionary
|
//check we ARE defining a dictionary
|
||||||
if (array) {
|
if (array) {
|
||||||
error(parser, parser->previous, "Incorrect detection between array and dictionary");
|
error(parser, parser->previous, "Incorrect detection between array and dictionary");
|
||||||
freeNode(array);
|
freeASTNode(array);
|
||||||
return OP_EOF;
|
return OP_EOF;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -214,7 +215,7 @@ static Opcode compound(Parser* parser, ASTNode** nodeHandle) {
|
|||||||
//check we ARE defining an array
|
//check we ARE defining an array
|
||||||
if (dictionary) {
|
if (dictionary) {
|
||||||
error(parser, parser->current, "Incorrect detection between array and dictionary");
|
error(parser, parser->current, "Incorrect detection between array and dictionary");
|
||||||
freeNode(dictionary);
|
freeASTNode(dictionary);
|
||||||
return OP_EOF;
|
return OP_EOF;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -269,7 +270,7 @@ static Opcode string(Parser* parser, ASTNode** nodeHandle) {
|
|||||||
error(parser, parser->previous, buffer);
|
error(parser, parser->previous, buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
Literal literal = TO_STRING_LITERAL(copyString(parser->previous.lexeme, length), length);
|
Literal literal = TO_STRING_LITERAL(createRefStringLength(parser->previous.lexeme, length));
|
||||||
emitASTNodeLiteral(nodeHandle, literal);
|
emitASTNodeLiteral(nodeHandle, literal);
|
||||||
freeLiteral(literal);
|
freeLiteral(literal);
|
||||||
return OP_EOF;
|
return OP_EOF;
|
||||||
@@ -417,8 +418,8 @@ static Opcode unary(Parser* parser, ASTNode** nodeHandle) {
|
|||||||
//temp handle to potentially negate values
|
//temp handle to potentially negate values
|
||||||
parsePrecedence(parser, &tmpNode, PREC_TERNARY); //can be a literal
|
parsePrecedence(parser, &tmpNode, PREC_TERNARY); //can be a literal
|
||||||
|
|
||||||
//check for negative literals (optimisation)
|
//optimisation: check for negative literals
|
||||||
if (tmpNode->type == AST_NODELITERAL && (IS_INTEGER(tmpNode->atomic.literal) || IS_FLOAT(tmpNode->atomic.literal))) {
|
if (tmpNode->type == AST_NODE_LITERAL && (IS_INTEGER(tmpNode->atomic.literal) || IS_FLOAT(tmpNode->atomic.literal))) {
|
||||||
//negate directly, if int or float
|
//negate directly, if int or float
|
||||||
Literal lit = tmpNode->atomic.literal;
|
Literal lit = tmpNode->atomic.literal;
|
||||||
|
|
||||||
@@ -437,22 +438,22 @@ static Opcode unary(Parser* parser, ASTNode** nodeHandle) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//check for negated boolean errors
|
//check for negated boolean errors
|
||||||
if (tmpNode->type == AST_NODELITERAL && IS_BOOLEAN(tmpNode->atomic.literal)) {
|
if (tmpNode->type == AST_NODE_LITERAL && IS_BOOLEAN(tmpNode->atomic.literal)) {
|
||||||
error(parser, parser->previous, "Negative booleans are not allowed");
|
error(parser, parser->previous, "Negative booleans are not allowed");
|
||||||
return OP_EOF;
|
return OP_EOF;
|
||||||
}
|
}
|
||||||
|
|
||||||
//actually emit the negation
|
//actually emit the negation node
|
||||||
emitASTNodeUnary(nodeHandle, OP_NEGATE, tmpNode);
|
emitASTNodeUnary(nodeHandle, OP_NEGATE, tmpNode);
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (parser->previous.type == TOKEN_NOT) {
|
else if (parser->previous.type == TOKEN_NOT) {
|
||||||
//temp handle to potentially negate values
|
//temp handle to potentially negate values
|
||||||
parsePrecedence(parser, &tmpNode, PREC_CALL); //can be a literal
|
parsePrecedence(parser, &tmpNode, PREC_CALL); //can be a literal, grouping, fn call, etc.
|
||||||
|
|
||||||
//check for inverted booleans
|
//check for inverted booleans
|
||||||
if (tmpNode->type == AST_NODELITERAL && IS_BOOLEAN(tmpNode->atomic.literal)) {
|
if (tmpNode->type == AST_NODE_LITERAL && IS_BOOLEAN(tmpNode->atomic.literal)) {
|
||||||
//negate directly, if int or float
|
//negate directly, if boolean
|
||||||
Literal lit = tmpNode->atomic.literal;
|
Literal lit = tmpNode->atomic.literal;
|
||||||
|
|
||||||
lit = TO_BOOLEAN_LITERAL(!AS_BOOLEAN(lit));
|
lit = TO_BOOLEAN_LITERAL(!AS_BOOLEAN(lit));
|
||||||
@@ -463,12 +464,6 @@ static Opcode unary(Parser* parser, ASTNode** nodeHandle) {
|
|||||||
return OP_EOF;
|
return OP_EOF;
|
||||||
}
|
}
|
||||||
|
|
||||||
//check for inverted number errors
|
|
||||||
if (tmpNode->type == AST_NODELITERAL && (IS_INTEGER(tmpNode->atomic.literal) || IS_FLOAT(tmpNode->atomic.literal))) {
|
|
||||||
error(parser, parser->previous, "Inverted numbers are not allowed");
|
|
||||||
return OP_EOF;
|
|
||||||
}
|
|
||||||
|
|
||||||
//actually emit the negation
|
//actually emit the negation
|
||||||
emitASTNodeUnary(nodeHandle, OP_INVERT, tmpNode);
|
emitASTNodeUnary(nodeHandle, OP_INVERT, tmpNode);
|
||||||
}
|
}
|
||||||
@@ -543,12 +538,9 @@ static Opcode identifier(Parser* parser, ASTNode** nodeHandle) {
|
|||||||
error(parser, parser->previous, "Identifiers can only be a maximum of 256 characters long");
|
error(parser, parser->previous, "Identifiers can only be a maximum of 256 characters long");
|
||||||
}
|
}
|
||||||
|
|
||||||
char* cpy = copyString(identifierToken.lexeme, length);
|
Literal identifier = TO_IDENTIFIER_LITERAL(createRefStringLength(identifierToken.lexeme, length));
|
||||||
Literal identifier = _toIdentifierLiteral(cpy, length); //BUGFIX: use this instead of the macro
|
|
||||||
|
|
||||||
emitASTNodeLiteral(nodeHandle, identifier);
|
emitASTNodeLiteral(nodeHandle, identifier);
|
||||||
|
freeLiteral(identifier);
|
||||||
freeLiteral(identifier); //don't leave it hanging
|
|
||||||
|
|
||||||
return OP_EOF;
|
return OP_EOF;
|
||||||
}
|
}
|
||||||
@@ -594,6 +586,7 @@ static Opcode castingPrefix(Parser* parser, ASTNode** nodeHandle) {
|
|||||||
static Opcode castingInfix(Parser* parser, ASTNode** nodeHandle) {
|
static Opcode castingInfix(Parser* parser, ASTNode** nodeHandle) {
|
||||||
advance(parser);
|
advance(parser);
|
||||||
|
|
||||||
|
//NOTE: using the precedence rules here
|
||||||
switch(parser->previous.type) {
|
switch(parser->previous.type) {
|
||||||
case TOKEN_IDENTIFIER:
|
case TOKEN_IDENTIFIER:
|
||||||
identifier(parser, nodeHandle);
|
identifier(parser, nodeHandle);
|
||||||
@@ -624,28 +617,29 @@ static Opcode castingInfix(Parser* parser, ASTNode** nodeHandle) {
|
|||||||
return OP_TYPE_CAST;
|
return OP_TYPE_CAST;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//TODO: fix these screwy names
|
||||||
static Opcode incrementPrefix(Parser* parser, ASTNode** nodeHandle) {
|
static Opcode incrementPrefix(Parser* parser, ASTNode** nodeHandle) {
|
||||||
advance(parser);
|
advance(parser);
|
||||||
|
|
||||||
ASTNode* node = NULL;
|
ASTNode* tmpNode = NULL;
|
||||||
identifier(parser, &node);
|
identifier(parser, &tmpNode);
|
||||||
|
|
||||||
emitASTNodePrefixIncrement(nodeHandle, node->atomic.literal, 1);
|
emitASTNodePrefixIncrement(nodeHandle, tmpNode->atomic.literal);
|
||||||
|
|
||||||
freeNode(node);
|
freeASTNode(tmpNode);
|
||||||
|
|
||||||
return OP_EOF;
|
return OP_EOF;
|
||||||
}
|
}
|
||||||
|
|
||||||
static Opcode incrementInfix(Parser* parser, ASTNode** nodeHandle) {
|
static Opcode incrementInfix(Parser* parser, ASTNode** nodeHandle) {
|
||||||
ASTNode* node = NULL;
|
ASTNode* tmpNode = NULL;
|
||||||
identifier(parser, &node);
|
identifier(parser, &tmpNode);
|
||||||
|
|
||||||
advance(parser);
|
advance(parser);
|
||||||
|
|
||||||
emitASTNodePostfixIncrement(nodeHandle, node->atomic.literal, 1);
|
emitASTNodePostfixIncrement(nodeHandle, tmpNode->atomic.literal);
|
||||||
|
|
||||||
freeNode(node);
|
freeASTNode(tmpNode);
|
||||||
|
|
||||||
return OP_EOF;
|
return OP_EOF;
|
||||||
}
|
}
|
||||||
@@ -653,25 +647,25 @@ static Opcode incrementInfix(Parser* parser, ASTNode** nodeHandle) {
|
|||||||
static Opcode decrementPrefix(Parser* parser, ASTNode** nodeHandle) {
|
static Opcode decrementPrefix(Parser* parser, ASTNode** nodeHandle) {
|
||||||
advance(parser);
|
advance(parser);
|
||||||
|
|
||||||
ASTNode* node = NULL;
|
ASTNode* tmpNode = NULL;
|
||||||
identifier(parser, &node); //weird
|
identifier(parser, &tmpNode); //weird
|
||||||
|
|
||||||
emitASTNodePrefixIncrement(nodeHandle, node->atomic.literal, -1);
|
emitASTNodePrefixDecrement(nodeHandle, tmpNode->atomic.literal);
|
||||||
|
|
||||||
freeNode(node);
|
freeASTNode(tmpNode);
|
||||||
|
|
||||||
return OP_EOF;
|
return OP_EOF;
|
||||||
}
|
}
|
||||||
|
|
||||||
static Opcode decrementInfix(Parser* parser, ASTNode** nodeHandle) {
|
static Opcode decrementInfix(Parser* parser, ASTNode** nodeHandle) {
|
||||||
ASTNode* node = NULL;
|
ASTNode* tmpNode = NULL;
|
||||||
identifier(parser, &node);
|
identifier(parser, &tmpNode);
|
||||||
|
|
||||||
advance(parser);
|
advance(parser);
|
||||||
|
|
||||||
emitASTNodePostfixIncrement(nodeHandle, node->atomic.literal, -1);
|
emitASTNodePostfixDecrement(nodeHandle, tmpNode->atomic.literal);
|
||||||
|
|
||||||
freeNode(node);
|
freeASTNode(tmpNode);
|
||||||
|
|
||||||
return OP_EOF;
|
return OP_EOF;
|
||||||
}
|
}
|
||||||
@@ -698,17 +692,17 @@ static Opcode fnCall(Parser* parser, ASTNode** nodeHandle) {
|
|||||||
arguments->fnCollection.nodes = GROW_ARRAY(ASTNode, arguments->fnCollection.nodes, oldCapacity, arguments->fnCollection.capacity);
|
arguments->fnCollection.nodes = GROW_ARRAY(ASTNode, arguments->fnCollection.nodes, oldCapacity, arguments->fnCollection.capacity);
|
||||||
}
|
}
|
||||||
|
|
||||||
ASTNode* node = NULL;
|
ASTNode* tmpNode = NULL;
|
||||||
parsePrecedence(parser, &node, PREC_TERNARY);
|
parsePrecedence(parser, &tmpNode, PREC_TERNARY);
|
||||||
arguments->fnCollection.nodes[arguments->fnCollection.count++] = *node;
|
arguments->fnCollection.nodes[arguments->fnCollection.count++] = *tmpNode;
|
||||||
FREE(ASTNode, node);
|
FREE(ASTNode, tmpNode); //simply free the tmpNode, so you don't free the children
|
||||||
} while(match(parser, TOKEN_COMMA));
|
} while(match(parser, TOKEN_COMMA));
|
||||||
|
|
||||||
consume(parser, TOKEN_PAREN_RIGHT, "Expected ')' at end of argument list");
|
consume(parser, TOKEN_PAREN_RIGHT, "Expected ')' at end of argument list");
|
||||||
}
|
}
|
||||||
|
|
||||||
//emit the call
|
//emit the call
|
||||||
emitASTFnCall(nodeHandle, arguments, arguments->fnCollection.count);
|
emitASTNodeFnCall(nodeHandle, arguments);
|
||||||
|
|
||||||
return OP_FN_CALL;
|
return OP_FN_CALL;
|
||||||
}
|
}
|
||||||
@@ -722,7 +716,7 @@ static Opcode fnCall(Parser* parser, ASTNode** nodeHandle) {
|
|||||||
return OP_EOF;
|
return OP_EOF;
|
||||||
}
|
}
|
||||||
|
|
||||||
static Opcode indexAccess(Parser* parser, ASTNode** nodeHandle) {
|
static Opcode indexAccess(Parser* parser, ASTNode** nodeHandle) { //TODO: fix indexing signalling
|
||||||
advance(parser);
|
advance(parser);
|
||||||
|
|
||||||
//val[first : second : third]
|
//val[first : second : third]
|
||||||
@@ -740,7 +734,7 @@ static Opcode indexAccess(Parser* parser, ASTNode** nodeHandle) {
|
|||||||
|
|
||||||
//eat the first
|
//eat the first
|
||||||
if (!match(parser, TOKEN_COLON)) {
|
if (!match(parser, TOKEN_COLON)) {
|
||||||
freeNode(first);
|
freeASTNode(first);
|
||||||
parsePrecedence(parser, &first, PREC_TERNARY);
|
parsePrecedence(parser, &first, PREC_TERNARY);
|
||||||
match(parser, TOKEN_COLON);
|
match(parser, TOKEN_COLON);
|
||||||
readFirst = true;
|
readFirst = true;
|
||||||
@@ -749,11 +743,11 @@ static Opcode indexAccess(Parser* parser, ASTNode** nodeHandle) {
|
|||||||
if (match(parser, TOKEN_BRACKET_RIGHT)) {
|
if (match(parser, TOKEN_BRACKET_RIGHT)) {
|
||||||
|
|
||||||
if (readFirst) {
|
if (readFirst) {
|
||||||
freeNode(second);
|
freeASTNode(second);
|
||||||
second = NULL;
|
second = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
freeNode(third);
|
freeASTNode(third);
|
||||||
third = NULL;
|
third = NULL;
|
||||||
|
|
||||||
emitASTNodeIndex(nodeHandle, first, second, third);
|
emitASTNodeIndex(nodeHandle, first, second, third);
|
||||||
@@ -762,20 +756,20 @@ static Opcode indexAccess(Parser* parser, ASTNode** nodeHandle) {
|
|||||||
|
|
||||||
//eat the second
|
//eat the second
|
||||||
if (!match(parser, TOKEN_COLON)) {
|
if (!match(parser, TOKEN_COLON)) {
|
||||||
freeNode(second);
|
freeASTNode(second);
|
||||||
parsePrecedence(parser, &second, PREC_TERNARY);
|
parsePrecedence(parser, &second, PREC_TERNARY);
|
||||||
match(parser, TOKEN_COLON);
|
match(parser, TOKEN_COLON);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (match(parser, TOKEN_BRACKET_RIGHT)) {
|
if (match(parser, TOKEN_BRACKET_RIGHT)) {
|
||||||
freeNode(third);
|
freeASTNode(third);
|
||||||
third = NULL;
|
third = NULL;
|
||||||
emitASTNodeIndex(nodeHandle, first, second, third);
|
emitASTNodeIndex(nodeHandle, first, second, third);
|
||||||
return OP_INDEX;
|
return OP_INDEX;
|
||||||
}
|
}
|
||||||
|
|
||||||
//eat the third
|
//eat the third
|
||||||
freeNode(third);
|
freeASTNode(third);
|
||||||
parsePrecedence(parser, &third, PREC_TERNARY);
|
parsePrecedence(parser, &third, PREC_TERNARY);
|
||||||
emitASTNodeIndex(nodeHandle, first, second, third);
|
emitASTNodeIndex(nodeHandle, first, second, third);
|
||||||
|
|
||||||
@@ -787,16 +781,15 @@ static Opcode indexAccess(Parser* parser, ASTNode** nodeHandle) {
|
|||||||
static Opcode dot(Parser* parser, ASTNode** nodeHandle) {
|
static Opcode dot(Parser* parser, ASTNode** nodeHandle) {
|
||||||
advance(parser); //for the dot
|
advance(parser); //for the dot
|
||||||
|
|
||||||
ASTNode* node = NULL;
|
ASTNode* tmpNode = NULL;
|
||||||
|
parsePrecedence(parser, &tmpNode, PREC_CALL);
|
||||||
|
|
||||||
parsePrecedence(parser, &node, PREC_CALL);
|
if (tmpNode == NULL || tmpNode->binary.right == NULL) {
|
||||||
|
|
||||||
if (node == NULL || node->binary.right == NULL) {
|
|
||||||
error(parser, parser->previous, "Expected function call after dot operator");
|
error(parser, parser->previous, "Expected function call after dot operator");
|
||||||
return OP_EOF;
|
return OP_EOF;
|
||||||
}
|
}
|
||||||
|
|
||||||
(*nodeHandle) = node;
|
(*nodeHandle) = tmpNode;
|
||||||
return OP_DOT; //signal that the function name and arguments are in the wrong order
|
return OP_DOT; //signal that the function name and arguments are in the wrong order
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -895,7 +888,7 @@ ParseRule* getRule(TokenType type) {
|
|||||||
return &parseRules[type];
|
return &parseRules[type];
|
||||||
}
|
}
|
||||||
|
|
||||||
//constant folding
|
//optimisation: constant folding
|
||||||
static bool calcStaticBinaryArithmetic(Parser* parser, ASTNode** nodeHandle) {
|
static bool calcStaticBinaryArithmetic(Parser* parser, ASTNode** nodeHandle) {
|
||||||
switch((*nodeHandle)->binary.opcode) {
|
switch((*nodeHandle)->binary.opcode) {
|
||||||
case OP_ADDITION:
|
case OP_ADDITION:
|
||||||
@@ -916,16 +909,16 @@ static bool calcStaticBinaryArithmetic(Parser* parser, ASTNode** nodeHandle) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//recurse to the left and right
|
//recurse to the left and right
|
||||||
if ((*nodeHandle)->binary.left->type == AST_NODEBINARY) {
|
if ((*nodeHandle)->binary.left->type == AST_NODE_BINARY) {
|
||||||
calcStaticBinaryArithmetic(parser, &(*nodeHandle)->binary.left);
|
calcStaticBinaryArithmetic(parser, &(*nodeHandle)->binary.left);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((*nodeHandle)->binary.right->type == AST_NODEBINARY) {
|
if ((*nodeHandle)->binary.right->type == AST_NODE_BINARY) {
|
||||||
calcStaticBinaryArithmetic(parser, &(*nodeHandle)->binary.right);
|
calcStaticBinaryArithmetic(parser, &(*nodeHandle)->binary.right);
|
||||||
}
|
}
|
||||||
|
|
||||||
//make sure left and right are both literals
|
//make sure left and right are both literals
|
||||||
if (!((*nodeHandle)->binary.left->type == AST_NODELITERAL && (*nodeHandle)->binary.right->type == AST_NODELITERAL)) {
|
if (!((*nodeHandle)->binary.left->type == AST_NODE_LITERAL && (*nodeHandle)->binary.right->type == AST_NODE_LITERAL)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1068,18 +1061,18 @@ static bool calcStaticBinaryArithmetic(Parser* parser, ASTNode** nodeHandle) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//optimize by converting this node into a literal node
|
//optimize by converting this node into a literal node
|
||||||
freeNode((*nodeHandle)->binary.left);
|
freeASTNode((*nodeHandle)->binary.left);
|
||||||
freeNode((*nodeHandle)->binary.right);
|
freeASTNode((*nodeHandle)->binary.right);
|
||||||
|
|
||||||
(*nodeHandle)->type = AST_NODELITERAL;
|
(*nodeHandle)->type = AST_NODE_LITERAL;
|
||||||
(*nodeHandle)->atomic.literal = result;
|
(*nodeHandle)->atomic.literal = result;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void dottify(Parser* parser, ASTNode** nodeHandle) {
|
static void dottify(Parser* parser, ASTNode** nodeHandle) { //TODO: remove dot from the compiler entirely
|
||||||
//only if this is chained from a higher binary "fn_call"
|
//only if this is chained from a higher binary "fn call"
|
||||||
if ((*nodeHandle)->type == AST_NODEBINARY) {
|
if ((*nodeHandle)->type == AST_NODE_BINARY) {
|
||||||
if ((*nodeHandle)->binary.opcode == OP_FN_CALL) {
|
if ((*nodeHandle)->binary.opcode == OP_FN_CALL) {
|
||||||
(*nodeHandle)->binary.opcode = OP_DOT;
|
(*nodeHandle)->binary.opcode = OP_DOT;
|
||||||
(*nodeHandle)->binary.right->fnCall.argumentCount++;
|
(*nodeHandle)->binary.right->fnCall.argumentCount++;
|
||||||
@@ -1117,7 +1110,7 @@ static void parsePrecedence(Parser* parser, ASTNode** nodeHandle, PrecedenceRule
|
|||||||
const Opcode opcode = infixRule(parser, &rhsNode); //NOTE: infix rule must advance the parser
|
const Opcode opcode = infixRule(parser, &rhsNode); //NOTE: infix rule must advance the parser
|
||||||
|
|
||||||
if (opcode == OP_EOF) {
|
if (opcode == OP_EOF) {
|
||||||
freeNode(*nodeHandle);
|
freeASTNode(*nodeHandle);
|
||||||
*nodeHandle = rhsNode;
|
*nodeHandle = rhsNode;
|
||||||
return; //we're done here
|
return; //we're done here
|
||||||
}
|
}
|
||||||
@@ -1129,6 +1122,7 @@ static void parsePrecedence(Parser* parser, ASTNode** nodeHandle, PrecedenceRule
|
|||||||
|
|
||||||
emitASTNodeBinary(nodeHandle, rhsNode, opcode);
|
emitASTNodeBinary(nodeHandle, rhsNode, opcode);
|
||||||
|
|
||||||
|
//optimise away the constants
|
||||||
if (!calcStaticBinaryArithmetic(parser, nodeHandle)) {
|
if (!calcStaticBinaryArithmetic(parser, nodeHandle)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -1160,19 +1154,19 @@ static void blockStmt(Parser* parser, ASTNode** nodeHandle) {
|
|||||||
(*nodeHandle)->block.nodes = GROW_ARRAY(ASTNode, (*nodeHandle)->block.nodes, oldCapacity, (*nodeHandle)->block.capacity);
|
(*nodeHandle)->block.nodes = GROW_ARRAY(ASTNode, (*nodeHandle)->block.nodes, oldCapacity, (*nodeHandle)->block.capacity);
|
||||||
}
|
}
|
||||||
|
|
||||||
ASTNode* node = NULL;
|
ASTNode* tmpNode = NULL;
|
||||||
|
|
||||||
//process the grammar rule for this line
|
//process the grammar rule for this line
|
||||||
declaration(parser, &node);
|
declaration(parser, &tmpNode);
|
||||||
|
|
||||||
// Ground floor: perfumery / Stationery and leather goods / Wigs and haberdashery / Kitchenware and food / Going up!
|
// Ground floor: perfumery / Stationery and leather goods / Wigs and haberdashery / Kitchenware and food / Going up!
|
||||||
if (parser->panic) {
|
if (parser->panic) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//BUGFIX: statements no longer require an existing node
|
//BUGFIX: statements no longer require the existing node
|
||||||
((*nodeHandle)->block.nodes[(*nodeHandle)->block.count++]) = *node;
|
((*nodeHandle)->block.nodes[(*nodeHandle)->block.count++]) = *tmpNode;
|
||||||
FREE(ASTNode, node); //simply free the tmp node
|
FREE(ASTNode, tmpNode); //simply free the tmpNode, so you don't free the children
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1188,7 +1182,7 @@ static void printStmt(Parser* parser, ASTNode** nodeHandle) {
|
|||||||
static void assertStmt(Parser* parser, ASTNode** nodeHandle) {
|
static void assertStmt(Parser* parser, ASTNode** nodeHandle) {
|
||||||
//set the node info
|
//set the node info
|
||||||
(*nodeHandle) = ALLOCATE(ASTNode, 1); //special case, because I'm lazy
|
(*nodeHandle) = ALLOCATE(ASTNode, 1); //special case, because I'm lazy
|
||||||
(*nodeHandle)->type = AST_NODEBINARY;
|
(*nodeHandle)->type = AST_NODE_BINARY;
|
||||||
(*nodeHandle)->binary.opcode = OP_ASSERT;
|
(*nodeHandle)->binary.opcode = OP_ASSERT;
|
||||||
|
|
||||||
parsePrecedence(parser, &((*nodeHandle)->binary.left), PREC_TERNARY);
|
parsePrecedence(parser, &((*nodeHandle)->binary.left), PREC_TERNARY);
|
||||||
@@ -1216,7 +1210,7 @@ static void ifStmt(Parser* parser, ASTNode** nodeHandle) {
|
|||||||
declaration(parser, &elsePath);
|
declaration(parser, &elsePath);
|
||||||
}
|
}
|
||||||
|
|
||||||
emitASTNodePath(nodeHandle, AST_NODEPATH_IF, NULL, NULL, condition, thenPath, elsePath);
|
emitASTNodeIf(nodeHandle, condition, thenPath, elsePath);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void whileStmt(Parser* parser, ASTNode** nodeHandle) {
|
static void whileStmt(Parser* parser, ASTNode** nodeHandle) {
|
||||||
@@ -1231,40 +1225,40 @@ static void whileStmt(Parser* parser, ASTNode** nodeHandle) {
|
|||||||
consume(parser, TOKEN_PAREN_RIGHT, "Expected ')' at end of while clause");
|
consume(parser, TOKEN_PAREN_RIGHT, "Expected ')' at end of while clause");
|
||||||
declaration(parser, &thenPath);
|
declaration(parser, &thenPath);
|
||||||
|
|
||||||
emitASTNodePath(nodeHandle, AST_NODEPATH_WHILE, NULL, NULL, condition, thenPath, NULL);
|
emitASTNodeWhile(nodeHandle, condition, thenPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void forStmt(Parser* parser, ASTNode** nodeHandle) {
|
static void forStmt(Parser* parser, ASTNode** nodeHandle) {
|
||||||
ASTNode* preClause = NULL;
|
ASTNode* preClause = NULL;
|
||||||
ASTNode* postClause = NULL;
|
|
||||||
ASTNode* condition = NULL;
|
ASTNode* condition = NULL;
|
||||||
|
ASTNode* postClause = NULL;
|
||||||
ASTNode* thenPath = NULL;
|
ASTNode* thenPath = NULL;
|
||||||
|
|
||||||
//read the clauses
|
//read the clauses
|
||||||
consume(parser, TOKEN_PAREN_LEFT, "Expected '(' at beginning of for clause");
|
consume(parser, TOKEN_PAREN_LEFT, "Expected '(' at beginning of for clause");
|
||||||
declaration(parser, &preClause);
|
|
||||||
|
declaration(parser, &preClause); //allow defining variables in the pre-clause
|
||||||
|
|
||||||
parsePrecedence(parser, &condition, PREC_TERNARY);
|
parsePrecedence(parser, &condition, PREC_TERNARY);
|
||||||
|
|
||||||
consume(parser, TOKEN_SEMICOLON, "Expected ';' after condition of for clause");
|
consume(parser, TOKEN_SEMICOLON, "Expected ';' after condition of for clause");
|
||||||
parsePrecedence(parser, &postClause, PREC_ASSIGNMENT);
|
|
||||||
|
|
||||||
|
parsePrecedence(parser, &postClause, PREC_ASSIGNMENT);
|
||||||
consume(parser, TOKEN_PAREN_RIGHT, "Expected ')' at end of for clause");
|
consume(parser, TOKEN_PAREN_RIGHT, "Expected ')' at end of for clause");
|
||||||
|
|
||||||
//read the path
|
//read the path
|
||||||
declaration(parser, &thenPath);
|
declaration(parser, &thenPath);
|
||||||
|
|
||||||
emitASTNodePath(nodeHandle, AST_NODEPATH_FOR, preClause, postClause, condition, thenPath, NULL);
|
emitASTNodeFor(nodeHandle, preClause, condition, postClause, thenPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void breakStmt(Parser* parser, ASTNode** nodeHandle) {
|
static void breakStmt(Parser* parser, ASTNode** nodeHandle) {
|
||||||
emitASTNodePath(nodeHandle, AST_NODEPATH_BREAK, NULL, NULL, NULL, NULL, NULL);
|
emitASTNodeBreak(nodeHandle);
|
||||||
|
|
||||||
consume(parser, TOKEN_SEMICOLON, "Expected ';' at end of break statement");
|
consume(parser, TOKEN_SEMICOLON, "Expected ';' at end of break statement");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void continueStmt(Parser* parser, ASTNode** nodeHandle) {
|
static void continueStmt(Parser* parser, ASTNode** nodeHandle) {
|
||||||
emitASTNodePath(nodeHandle, AST_NODEPATH_CONTINUE, NULL, NULL, NULL, NULL, NULL);
|
emitASTNodeContinue(nodeHandle);
|
||||||
|
|
||||||
consume(parser, TOKEN_SEMICOLON, "Expected ';' at end of continue statement");
|
consume(parser, TOKEN_SEMICOLON, "Expected ';' at end of continue statement");
|
||||||
}
|
}
|
||||||
@@ -1287,13 +1281,13 @@ static void returnStmt(Parser* parser, ASTNode** nodeHandle) {
|
|||||||
parsePrecedence(parser, &node, PREC_TERNARY);
|
parsePrecedence(parser, &node, PREC_TERNARY);
|
||||||
|
|
||||||
returnValues->fnCollection.nodes[returnValues->fnCollection.count++] = *node;
|
returnValues->fnCollection.nodes[returnValues->fnCollection.count++] = *node;
|
||||||
FREE(ASTNode, node);
|
FREE(ASTNode, node); //free manually
|
||||||
} while(match(parser, TOKEN_COMMA));
|
} while(match(parser, TOKEN_COMMA));
|
||||||
|
|
||||||
consume(parser, TOKEN_SEMICOLON, "Expected ';' at end of return statement");
|
consume(parser, TOKEN_SEMICOLON, "Expected ';' at end of return statement");
|
||||||
}
|
}
|
||||||
|
|
||||||
emitASTNodePath(nodeHandle, AST_NODEPATH_RETURN, NULL, NULL, NULL, returnValues, NULL);
|
emitASTNodeFnReturn(nodeHandle, returnValues);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void importStmt(Parser* parser, ASTNode** nodeHandle) {
|
static void importStmt(Parser* parser, ASTNode** nodeHandle) {
|
||||||
@@ -1307,50 +1301,21 @@ static void importStmt(Parser* parser, ASTNode** nodeHandle) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Literal idn = copyLiteral(node->atomic.literal);
|
Literal idn = copyLiteral(node->atomic.literal);
|
||||||
freeNode(node);
|
freeASTNode(node);
|
||||||
|
|
||||||
Literal alias = TO_NULL_LITERAL;
|
Literal alias = TO_NULL_LITERAL;
|
||||||
|
|
||||||
if (match(parser, TOKEN_AS)) {
|
if (match(parser, TOKEN_AS)) {
|
||||||
advance(parser);
|
|
||||||
identifier(parser, &node);
|
|
||||||
alias = copyLiteral(node->atomic.literal);
|
|
||||||
freeNode(node);
|
|
||||||
}
|
|
||||||
|
|
||||||
emitASTNodeImport(nodeHandle, AST_NODEIMPORT, idn, alias);
|
|
||||||
|
|
||||||
consume(parser, TOKEN_SEMICOLON, "Expected ';' at end of import statement");
|
|
||||||
|
|
||||||
freeLiteral(idn);
|
|
||||||
freeLiteral(alias);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void exportStmt(Parser* parser, ASTNode** nodeHandle) {
|
|
||||||
//read the identifier
|
|
||||||
ASTNode* node = NULL;
|
ASTNode* node = NULL;
|
||||||
advance(parser);
|
advance(parser);
|
||||||
identifier(parser, &node);
|
identifier(parser, &node);
|
||||||
|
|
||||||
if (node == NULL) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
alias = copyLiteral(node->atomic.literal);
|
||||||
freeNode(node);
|
freeASTNode(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
emitASTNodeImport(nodeHandle, AST_NODEEXPORT, idn, alias);
|
emitASTNodeImport(nodeHandle, idn, alias);
|
||||||
|
|
||||||
consume(parser, TOKEN_SEMICOLON, "Expected ';' at end of export statement");
|
consume(parser, TOKEN_SEMICOLON, "Expected ';' at end of import statement");
|
||||||
|
|
||||||
freeLiteral(idn);
|
freeLiteral(idn);
|
||||||
freeLiteral(alias);
|
freeLiteral(alias);
|
||||||
@@ -1435,12 +1400,6 @@ static void statement(Parser* parser, ASTNode** nodeHandle) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//export
|
|
||||||
if (match(parser, TOKEN_EXPORT)) {
|
|
||||||
exportStmt(parser, nodeHandle);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
//default
|
//default
|
||||||
expressionStmt(parser, nodeHandle);
|
expressionStmt(parser, nodeHandle);
|
||||||
}
|
}
|
||||||
@@ -1516,8 +1475,7 @@ static Literal readTypeToLiteral(Parser* parser) {
|
|||||||
length = 256;
|
length = 256;
|
||||||
error(parser, parser->previous, "Identifiers can only be a maximum of 256 characters long");
|
error(parser, parser->previous, "Identifiers can only be a maximum of 256 characters long");
|
||||||
}
|
}
|
||||||
char* cpy = copyString(identifierToken.lexeme, length);
|
literal = TO_IDENTIFIER_LITERAL(createRefStringLength(identifierToken.lexeme, length));
|
||||||
literal = _toIdentifierLiteral(cpy, strlen(cpy)); //BUGFIX: use this instead of the macro
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -1552,8 +1510,7 @@ static void varDecl(Parser* parser, ASTNode** nodeHandle) {
|
|||||||
error(parser, parser->previous, "Identifiers can only be a maximum of 256 characters long");
|
error(parser, parser->previous, "Identifiers can only be a maximum of 256 characters long");
|
||||||
}
|
}
|
||||||
|
|
||||||
char* cpy = copyString(identifierToken.lexeme, length);
|
Literal identifier = TO_IDENTIFIER_LITERAL(createRefStringLength(identifierToken.lexeme, length));
|
||||||
Literal identifier = _toIdentifierLiteral(cpy, strlen(cpy)); //BUGFIX: use this instead of the macro
|
|
||||||
|
|
||||||
//read the type, if present
|
//read the type, if present
|
||||||
Literal typeLiteral;
|
Literal typeLiteral;
|
||||||
@@ -1596,8 +1553,7 @@ static void fnDecl(Parser* parser, ASTNode** nodeHandle) {
|
|||||||
error(parser, parser->previous, "Identifiers can only be a maximum of 256 characters long");
|
error(parser, parser->previous, "Identifiers can only be a maximum of 256 characters long");
|
||||||
}
|
}
|
||||||
|
|
||||||
char* cpy = copyString(identifierToken.lexeme, length);
|
Literal identifier = TO_IDENTIFIER_LITERAL(createRefStringLength(identifierToken.lexeme, length));
|
||||||
Literal identifier = _toIdentifierLiteral(cpy, strlen(cpy)); //BUGFIX: use this instead of the macro
|
|
||||||
|
|
||||||
//read the parameters and arity
|
//read the parameters and arity
|
||||||
consume(parser, TOKEN_PAREN_LEFT, "Expected '(' after function identifier");
|
consume(parser, TOKEN_PAREN_LEFT, "Expected '(' after function identifier");
|
||||||
@@ -1623,8 +1579,7 @@ static void fnDecl(Parser* parser, ASTNode** nodeHandle) {
|
|||||||
error(parser, parser->previous, "Identifiers can only be a maximum of 256 characters long");
|
error(parser, parser->previous, "Identifiers can only be a maximum of 256 characters long");
|
||||||
}
|
}
|
||||||
|
|
||||||
char* cpy = copyString(argIdentifierToken.lexeme, length);
|
Literal argIdentifier = TO_IDENTIFIER_LITERAL(createRefStringLength(argIdentifierToken.lexeme, length));
|
||||||
Literal argIdentifier = _toIdentifierLiteral(cpy, strlen(cpy)); //BUGFIX: use this instead of the macro
|
|
||||||
|
|
||||||
//set the type (array of any types)
|
//set the type (array of any types)
|
||||||
Literal argTypeLiteral = TO_TYPE_LITERAL(LITERAL_FUNCTION_ARG_REST, false);
|
Literal argTypeLiteral = TO_TYPE_LITERAL(LITERAL_FUNCTION_ARG_REST, false);
|
||||||
@@ -1659,9 +1614,7 @@ static void fnDecl(Parser* parser, ASTNode** nodeHandle) {
|
|||||||
error(parser, parser->previous, "Identifiers can only be a maximum of 256 characters long");
|
error(parser, parser->previous, "Identifiers can only be a maximum of 256 characters long");
|
||||||
}
|
}
|
||||||
|
|
||||||
char* cpy = copyString(argIdentifierToken.lexeme, length);
|
Literal argIdentifier = TO_IDENTIFIER_LITERAL(createRefStringLength(argIdentifierToken.lexeme, length));
|
||||||
|
|
||||||
Literal argIdentifier = _toIdentifierLiteral(cpy, strlen(cpy)); //BUGFIX: use this instead of the macro
|
|
||||||
|
|
||||||
//read optional type of the identifier
|
//read optional type of the identifier
|
||||||
Literal argTypeLiteral;
|
Literal argTypeLiteral;
|
||||||
@@ -1773,9 +1726,9 @@ ASTNode* scanParser(Parser* parser) {
|
|||||||
if (parser->panic) {
|
if (parser->panic) {
|
||||||
synchronize(parser);
|
synchronize(parser);
|
||||||
//return an error node for this iteration
|
//return an error node for this iteration
|
||||||
freeNode(node);
|
freeASTNode(node);
|
||||||
node = ALLOCATE(ASTNode, 1);
|
node = ALLOCATE(ASTNode, 1);
|
||||||
node->type = AST_NODEERROR;
|
node->type = AST_NODE_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
return node;
|
return node;
|
||||||
|
|||||||
@@ -0,0 +1,100 @@
|
|||||||
|
#include "refstring.h"
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
//test variable sizes based on platform (safety)
|
||||||
|
#define STATIC_ASSERT(test_for_true) static_assert((test_for_true), "(" #test_for_true ") failed")
|
||||||
|
|
||||||
|
STATIC_ASSERT(sizeof(RefString) == 12);
|
||||||
|
STATIC_ASSERT(sizeof(int) == 4);
|
||||||
|
STATIC_ASSERT(sizeof(char) == 1);
|
||||||
|
|
||||||
|
//memory allocation
|
||||||
|
static RefStringAllocatorFn allocate;
|
||||||
|
|
||||||
|
void setRefStringAllocatorFn(RefStringAllocatorFn allocator) {
|
||||||
|
allocate = allocator;
|
||||||
|
}
|
||||||
|
|
||||||
|
//API
|
||||||
|
RefString* createRefString(char* cstring) {
|
||||||
|
int length = strlen(cstring);
|
||||||
|
|
||||||
|
return createRefStringLength(cstring, length);
|
||||||
|
}
|
||||||
|
|
||||||
|
RefString* createRefStringLength(char* cstring, int length) {
|
||||||
|
//allocate the memory area (including metadata space)
|
||||||
|
RefString* refString = (RefString*)allocate(NULL, 0, sizeof(int) * 2 + sizeof(char) * length + 1);
|
||||||
|
|
||||||
|
//set the data
|
||||||
|
refString->refcount = 1;
|
||||||
|
refString->length = length;
|
||||||
|
strncpy(refString->data, cstring, refString->length);
|
||||||
|
|
||||||
|
refString->data[refString->length] = '\0'; //string terminator
|
||||||
|
|
||||||
|
return refString;
|
||||||
|
}
|
||||||
|
|
||||||
|
void deleteRefString(RefString* refString) {
|
||||||
|
if (refString->refcount > 0) {
|
||||||
|
//decrement, then check
|
||||||
|
refString->refcount--;
|
||||||
|
if (refString->refcount <= 0) {
|
||||||
|
allocate(refString, sizeof(int) * 2 + sizeof(char) * refString->length + 1, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int countRefString(RefString* refString) {
|
||||||
|
return refString->refcount;
|
||||||
|
}
|
||||||
|
|
||||||
|
int lengthRefString(RefString* refString) {
|
||||||
|
return refString->length;
|
||||||
|
}
|
||||||
|
|
||||||
|
RefString* copyRefString(RefString* refString) {
|
||||||
|
//Cheaty McCheater Face
|
||||||
|
refString->refcount++;
|
||||||
|
return refString;
|
||||||
|
}
|
||||||
|
|
||||||
|
RefString* deepCopyRefString(RefString* refString) {
|
||||||
|
//create a new string, with a new refcount
|
||||||
|
return createRefStringLength(refString->data, refString->length);
|
||||||
|
}
|
||||||
|
|
||||||
|
char* toCString(RefString* refString) {
|
||||||
|
return refString->data;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool equalsRefString(RefString* lhs, RefString* rhs) {
|
||||||
|
//same pointer
|
||||||
|
if (lhs == rhs) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
//different length
|
||||||
|
if (lhs->length != rhs->length) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
//same string
|
||||||
|
return strncmp(lhs->data, rhs->data, lhs->length) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool equalsRefStringCString(RefString* lhs, char* cstring) {
|
||||||
|
//get the rhs length
|
||||||
|
int length = strlen(cstring);
|
||||||
|
|
||||||
|
//different length
|
||||||
|
if (lhs->length != length) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
//same string
|
||||||
|
return strncmp(lhs->data, cstring, lhs->length) == 0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
//memory allocation hook
|
||||||
|
typedef void* (*RefStringAllocatorFn)(void* pointer, size_t oldSize, size_t newSize);
|
||||||
|
void setRefStringAllocatorFn(RefStringAllocatorFn);
|
||||||
|
|
||||||
|
//the RefString structure
|
||||||
|
typedef struct RefString {
|
||||||
|
int refcount;
|
||||||
|
int length;
|
||||||
|
char data[1];
|
||||||
|
} RefString;
|
||||||
|
|
||||||
|
//API
|
||||||
|
RefString* createRefString(char* cstring);
|
||||||
|
RefString* createRefStringLength(char* cstring, int length);
|
||||||
|
void deleteRefString(RefString* refString);
|
||||||
|
int countRefString(RefString* refString);
|
||||||
|
int lengthRefString(RefString* refString);
|
||||||
|
RefString* copyRefString(RefString* refString);
|
||||||
|
RefString* deepCopyRefString(RefString* refString);
|
||||||
|
char* toCString(RefString* refString);
|
||||||
|
bool equalsRefString(RefString* lhs, RefString* rhs);
|
||||||
|
bool equalsRefStringCString(RefString* lhs, char* cstring);
|
||||||
+19
-2
@@ -70,8 +70,14 @@ static bool checkType(Literal typeLiteral, Literal original, Literal value, bool
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
//if null, assume it's a new entry
|
//if null, assume it's a new array variable that needs checking
|
||||||
if (IS_NULL(original)) {
|
if (IS_NULL(original)) {
|
||||||
|
for (int i = 0; i < AS_ARRAY(value)->count; i++) {
|
||||||
|
if (!checkType( ((Literal*)(AS_TYPE(typeLiteral).subtypes))[0], TO_NULL_LITERAL, AS_ARRAY(value)->literals[i], constCheck)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -97,8 +103,19 @@ static bool checkType(Literal typeLiteral, Literal original, Literal value, bool
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
//if null, assume it's a new entry to a parent
|
//if null, assume it's a new dictionary variable that needs checking
|
||||||
if (IS_NULL(original)) {
|
if (IS_NULL(original)) {
|
||||||
|
for (int i = 0; i < AS_DICTIONARY(value)->capacity; i++) {
|
||||||
|
//check the type of key and value
|
||||||
|
if (!checkType(((Literal*)(AS_TYPE(typeLiteral).subtypes))[0], TO_NULL_LITERAL, AS_DICTIONARY(value)->entries[i].key, constCheck)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!checkType(((Literal*)(AS_TYPE(typeLiteral).subtypes))[1], TO_NULL_LITERAL, AS_DICTIONARY(value)->entries[i].value, constCheck)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+3
-9
@@ -5,25 +5,19 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
#define TOY_VERSION_MAJOR 0
|
#define TOY_VERSION_MAJOR 0
|
||||||
#define TOY_VERSION_MINOR 6
|
#define TOY_VERSION_MINOR 7
|
||||||
#define TOY_VERSION_PATCH 1
|
#define TOY_VERSION_PATCH 0
|
||||||
#define TOY_VERSION_BUILD __DATE__ " " __TIME__
|
#define TOY_VERSION_BUILD __DATE__ " " __TIME__
|
||||||
|
|
||||||
//platform exports/imports
|
//platform-specific specifications
|
||||||
#if defined(__linux__)
|
#if defined(__linux__)
|
||||||
#define TOY_API extern
|
#define TOY_API extern
|
||||||
#include <time.h>
|
|
||||||
#include <sys/time.h>
|
|
||||||
|
|
||||||
#elif defined(_WIN32) || defined(WIN32)
|
#elif defined(_WIN32) || defined(WIN32)
|
||||||
#define TOY_API
|
#define TOY_API
|
||||||
#include <time.h>
|
|
||||||
#include <sys/time.h>
|
|
||||||
|
|
||||||
#else
|
#else
|
||||||
#define TOY_API
|
#define TOY_API
|
||||||
#include <time.h>
|
|
||||||
#include <sys/time.h>
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
+1
-2
@@ -3,10 +3,9 @@ CC=gcc
|
|||||||
IDIR +=. ../source ../repl
|
IDIR +=. ../source ../repl
|
||||||
CFLAGS +=$(addprefix -I,$(IDIR)) -g -Wall -W -Wno-unused-parameter -Wno-unused-function -Wno-unused-variable
|
CFLAGS +=$(addprefix -I,$(IDIR)) -g -Wall -W -Wno-unused-parameter -Wno-unused-function -Wno-unused-variable
|
||||||
LIBS +=
|
LIBS +=
|
||||||
|
|
||||||
ODIR = obj
|
ODIR = obj
|
||||||
TARGETS = $(wildcard ../source/*.c) $(wildcard ../repl/lib_*.c)
|
TARGETS = $(wildcard ../source/*.c) $(wildcard ../repl/lib_*.c)
|
||||||
TESTS = $(wildcard *.c)
|
TESTS = $(wildcard test_*.c)
|
||||||
OBJ = $(addprefix $(ODIR)/,$(TARGETS:../source/%.c=%.o)) $(addprefix $(ODIR)/,$(TESTS:.c=.o))
|
OBJ = $(addprefix $(ODIR)/,$(TARGETS:../source/%.c=%.o)) $(addprefix $(ODIR)/,$(TESTS:.c=.o))
|
||||||
|
|
||||||
.PRECIOUS: $(TESTS:%.c=../$(TOY_OUTDIR)/%.exe)
|
.PRECIOUS: $(TESTS:%.c=../$(TOY_OUTDIR)/%.exe)
|
||||||
|
|||||||
@@ -1,52 +0,0 @@
|
|||||||
//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";
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//test that variables retain their types with the typeof keyword
|
|
||||||
{
|
|
||||||
var t: type = int;
|
|
||||||
|
|
||||||
export t;
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
import t;
|
|
||||||
|
|
||||||
assert typeof t == type, "type retention failed";
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
print "All good";
|
|
||||||
@@ -56,5 +56,37 @@
|
|||||||
timer.destroyTimer();
|
timer.destroyTimer();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
//test positive and negative values of timers
|
||||||
|
import timer;
|
||||||
|
|
||||||
|
var a = createTimer(1, 0);
|
||||||
|
var b = createTimer(2, 0);
|
||||||
|
|
||||||
|
var acmp = a.compareTimer(b);
|
||||||
|
var bcmp = b.compareTimer(a);
|
||||||
|
|
||||||
|
var c = createTimer(0, 1);
|
||||||
|
var d = createTimer(0, 2);
|
||||||
|
|
||||||
|
var ccmp = c.compareTimer(d);
|
||||||
|
var dcmp = d.compareTimer(c);
|
||||||
|
|
||||||
|
assert acmp.timerToString() == "1.000000", "positive and negative tests failed (acmp)";
|
||||||
|
assert bcmp.timerToString() == "-1.000000", "positive and negative tests failed (bcmp)";
|
||||||
|
assert ccmp.timerToString() == "0.000001", "positive and negative tests failed (ccmp)";
|
||||||
|
assert dcmp.timerToString() == "-0.000001", "positive and negative tests failed (dcmp)";
|
||||||
|
|
||||||
|
a.destroyTimer();
|
||||||
|
b.destroyTimer();
|
||||||
|
c.destroyTimer();
|
||||||
|
d.destroyTimer();
|
||||||
|
acmp.destroyTimer();
|
||||||
|
bcmp.destroyTimer();
|
||||||
|
ccmp.destroyTimer();
|
||||||
|
dcmp.destroyTimer();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
print "All good";
|
print "All good";
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
var t = astype [int];
|
||||||
|
var arr: t = [1, 2, 3.14];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
print "All good";
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
var t = astype [string:int];
|
||||||
|
var dict: t = ["one": 1, "two": 2, 3:4];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
print "All good";
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
var t = astype [string:int];
|
||||||
|
var dict: t = ["one": 1, "two": 2, "pi": 3.14];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
print "All good";
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
//test exports
|
|
||||||
var field: int = 42;
|
|
||||||
|
|
||||||
fn function() {
|
|
||||||
return 69;
|
|
||||||
}
|
|
||||||
|
|
||||||
export field;
|
|
||||||
export function;
|
|
||||||
|
|
||||||
print "All good";
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
//test imports
|
|
||||||
import field;
|
|
||||||
//import function;
|
|
||||||
|
|
||||||
//assert field == 42, "import field failed";
|
|
||||||
|
|
||||||
//assert function() == 69, "import function failed";
|
|
||||||
|
|
||||||
print "All good";
|
|
||||||
|
|
||||||
+66
-7
@@ -4,20 +4,79 @@
|
|||||||
#include "console_colors.h"
|
#include "console_colors.h"
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
//lazy
|
||||||
|
#define ASSERT(test_for_true) if (!(test_for_true)) {\
|
||||||
|
fprintf(stderr, ERROR "assert failed: %s\n" RESET, #test_for_true); \
|
||||||
|
exit(-1); \
|
||||||
|
}
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
|
//test literals
|
||||||
{
|
{
|
||||||
//test literals
|
//test literals
|
||||||
char* str = "foobar";
|
char* str = "foobar";
|
||||||
|
Literal literal = TO_STRING_LITERAL(createRefString(str));
|
||||||
|
|
||||||
Literal literal = TO_STRING_LITERAL(copyString(str, strlen(str)), strlen(str));
|
//generate the node
|
||||||
|
ASTNode* node = NULL;
|
||||||
ASTNode* node;
|
|
||||||
emitASTNodeLiteral(&node, literal);
|
emitASTNodeLiteral(&node, literal);
|
||||||
|
|
||||||
|
//check node type
|
||||||
|
ASSERT(node->type == AST_NODE_LITERAL);
|
||||||
|
|
||||||
|
//cleanup
|
||||||
freeLiteral(literal);
|
freeLiteral(literal);
|
||||||
freeNode(node);
|
freeASTNode(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//test unary
|
||||||
|
{
|
||||||
|
//generate the child node
|
||||||
|
char* str = "foobar";
|
||||||
|
Literal literal = TO_STRING_LITERAL(createRefString(str));
|
||||||
|
ASTNode* childNode = NULL;
|
||||||
|
emitASTNodeLiteral(&childNode, literal);
|
||||||
|
|
||||||
|
//generate the unary node
|
||||||
|
ASTNode* unary = NULL;
|
||||||
|
emitASTNodeUnary(&unary, OP_PRINT, childNode);
|
||||||
|
|
||||||
|
//check node type
|
||||||
|
ASSERT(unary->type == AST_NODE_UNARY);
|
||||||
|
|
||||||
|
//cleanup
|
||||||
|
freeLiteral(literal);
|
||||||
|
freeASTNode(unary);
|
||||||
|
}
|
||||||
|
|
||||||
|
//test binary
|
||||||
|
{
|
||||||
|
//generate the child node
|
||||||
|
char* str = "foobar";
|
||||||
|
Literal literal = TO_STRING_LITERAL(createRefString(str));
|
||||||
|
ASTNode* nodeHandle = NULL;
|
||||||
|
emitASTNodeLiteral(&nodeHandle, literal);
|
||||||
|
|
||||||
|
ASTNode* rhsChildNode = NULL;
|
||||||
|
emitASTNodeLiteral(&rhsChildNode, literal);
|
||||||
|
|
||||||
|
//generate the unary node
|
||||||
|
emitASTNodeBinary(&nodeHandle, rhsChildNode, OP_PRINT);
|
||||||
|
|
||||||
|
//check node type
|
||||||
|
ASSERT(nodeHandle->type == AST_NODE_BINARY);
|
||||||
|
ASSERT(nodeHandle->binary.opcode == OP_PRINT);
|
||||||
|
|
||||||
|
//cleanup
|
||||||
|
freeLiteral(literal);
|
||||||
|
freeASTNode(nodeHandle);
|
||||||
|
}
|
||||||
|
|
||||||
|
//TODO: more tests for other AST node types
|
||||||
|
|
||||||
|
//test compounds
|
||||||
{
|
{
|
||||||
//test compound (dictionary)
|
//test compound (dictionary)
|
||||||
char* idn = "foobar";
|
char* idn = "foobar";
|
||||||
@@ -27,8 +86,8 @@ int main() {
|
|||||||
ASTNode* left;
|
ASTNode* left;
|
||||||
ASTNode* right;
|
ASTNode* right;
|
||||||
|
|
||||||
Literal identifier = TO_IDENTIFIER_LITERAL(copyString(idn, strlen(idn)), strlen(idn));
|
Literal identifier = TO_IDENTIFIER_LITERAL(createRefString(idn));
|
||||||
Literal string = TO_STRING_LITERAL(copyString(str, strlen(str)), strlen(str));
|
Literal string = TO_STRING_LITERAL(createRefString(str));
|
||||||
|
|
||||||
emitASTNodeCompound(&dictionary, LITERAL_DICTIONARY);
|
emitASTNodeCompound(&dictionary, LITERAL_DICTIONARY);
|
||||||
emitASTNodeLiteral(&left, identifier);
|
emitASTNodeLiteral(&left, identifier);
|
||||||
@@ -46,7 +105,7 @@ int main() {
|
|||||||
setASTNodePair(&dictionary->compound.nodes[dictionary->compound.count++], left, right);
|
setASTNodePair(&dictionary->compound.nodes[dictionary->compound.count++], left, right);
|
||||||
|
|
||||||
//the real test
|
//the real test
|
||||||
freeNode(dictionary);
|
freeASTNode(dictionary);
|
||||||
freeLiteral(identifier);
|
freeLiteral(identifier);
|
||||||
freeLiteral(string);
|
freeLiteral(string);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -64,16 +64,16 @@ unsigned char* compileString(char* source, size_t* size) {
|
|||||||
ASTNode* node = scanParser(&parser);
|
ASTNode* node = scanParser(&parser);
|
||||||
while(node != NULL) {
|
while(node != NULL) {
|
||||||
//pack up and leave
|
//pack up and leave
|
||||||
if (node->type == AST_NODEERROR) {
|
if (node->type == AST_NODE_ERROR) {
|
||||||
printf(ERROR "error node detected\n" RESET);
|
printf(ERROR "error node detected\n" RESET);
|
||||||
freeNode(node);
|
freeASTNode(node);
|
||||||
freeCompiler(&compiler);
|
freeCompiler(&compiler);
|
||||||
freeParser(&parser);
|
freeParser(&parser);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
writeCompiler(&compiler, node);
|
writeCompiler(&compiler, node);
|
||||||
freeNode(node);
|
freeASTNode(node);
|
||||||
node = scanParser(&parser);
|
node = scanParser(&parser);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -76,7 +76,7 @@ int main() {
|
|||||||
|
|
||||||
//cleanup
|
//cleanup
|
||||||
FREE_ARRAY(unsigned char, bytecode, size);
|
FREE_ARRAY(unsigned char, bytecode, size);
|
||||||
freeNode(node);
|
freeASTNode(node);
|
||||||
freeParser(&parser);
|
freeParser(&parser);
|
||||||
freeCompiler(&compiler);
|
freeCompiler(&compiler);
|
||||||
}
|
}
|
||||||
@@ -97,14 +97,14 @@ int main() {
|
|||||||
|
|
||||||
ASTNode* node = scanParser(&parser);
|
ASTNode* node = scanParser(&parser);
|
||||||
while (node != NULL) {
|
while (node != NULL) {
|
||||||
if (node->type == AST_NODEERROR) {
|
if (node->type == AST_NODE_ERROR) {
|
||||||
fprintf(stderr, ERROR "ERROR: Error node found" RESET);
|
fprintf(stderr, ERROR "ERROR: Error node found" RESET);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
//write
|
//write
|
||||||
writeCompiler(&compiler, node);
|
writeCompiler(&compiler, node);
|
||||||
freeNode(node);
|
freeASTNode(node);
|
||||||
|
|
||||||
node = scanParser(&parser);
|
node = scanParser(&parser);
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-37
@@ -75,16 +75,16 @@ unsigned char* compileString(char* source, size_t* size) {
|
|||||||
ASTNode* node = scanParser(&parser);
|
ASTNode* node = scanParser(&parser);
|
||||||
while(node != NULL) {
|
while(node != NULL) {
|
||||||
//pack up and leave
|
//pack up and leave
|
||||||
if (node->type == AST_NODEERROR) {
|
if (node->type == AST_NODE_ERROR) {
|
||||||
printf(ERROR "error node detected\n" RESET);
|
printf(ERROR "error node detected\n" RESET);
|
||||||
freeNode(node);
|
freeASTNode(node);
|
||||||
freeCompiler(&compiler);
|
freeCompiler(&compiler);
|
||||||
freeParser(&parser);
|
freeParser(&parser);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
writeCompiler(&compiler, node);
|
writeCompiler(&compiler, node);
|
||||||
freeNode(node);
|
freeASTNode(node);
|
||||||
node = scanParser(&parser);
|
node = scanParser(&parser);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -168,7 +168,7 @@ int main() {
|
|||||||
runInterpreter(&interpreter, bytecode, size);
|
runInterpreter(&interpreter, bytecode, size);
|
||||||
|
|
||||||
//cleanup
|
//cleanup
|
||||||
freeNode(node);
|
freeASTNode(node);
|
||||||
freeParser(&parser);
|
freeParser(&parser);
|
||||||
freeCompiler(&compiler);
|
freeCompiler(&compiler);
|
||||||
freeInterpreter(&interpreter);
|
freeInterpreter(&interpreter);
|
||||||
@@ -186,7 +186,6 @@ int main() {
|
|||||||
"dot-chaining.toy",
|
"dot-chaining.toy",
|
||||||
"dottify-bugfix.toy",
|
"dottify-bugfix.toy",
|
||||||
"functions.toy",
|
"functions.toy",
|
||||||
"imports-and-exports.toy",
|
|
||||||
"index-arrays.toy",
|
"index-arrays.toy",
|
||||||
"index-dictionaries.toy",
|
"index-dictionaries.toy",
|
||||||
"index-strings.toy",
|
"index-strings.toy",
|
||||||
@@ -212,38 +211,6 @@ int main() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
|
||||||
//read source
|
|
||||||
size_t dummy;
|
|
||||||
size_t exportSize, importSize;
|
|
||||||
char* exportSource = readFile("scripts/separate-exports.toy", &dummy);
|
|
||||||
char* importSource = readFile("scripts/separate-imports.toy", &dummy);
|
|
||||||
|
|
||||||
//compile
|
|
||||||
unsigned char* exportBinary = compileString(exportSource, &exportSize);
|
|
||||||
unsigned char* importBinary = compileString(importSource, &importSize);
|
|
||||||
|
|
||||||
//run the interpreter over both binaries
|
|
||||||
Interpreter interpreter;
|
|
||||||
initInterpreter(&interpreter);
|
|
||||||
|
|
||||||
//NOTE: supress print output for testing
|
|
||||||
setInterpreterPrint(&interpreter, noPrintFn);
|
|
||||||
setInterpreterAssert(&interpreter, noAssertFn);
|
|
||||||
|
|
||||||
runInterpreter(&interpreter, exportBinary, exportSize); //automatically frees the binary data
|
|
||||||
|
|
||||||
resetInterpreter(&interpreter);
|
|
||||||
|
|
||||||
runInterpreter(&interpreter, importBinary, importSize); //automatically frees the binary data
|
|
||||||
|
|
||||||
freeInterpreter(&interpreter);
|
|
||||||
|
|
||||||
//cleanup
|
|
||||||
free((void*)exportSource);
|
|
||||||
free((void*)importSource);
|
|
||||||
}
|
|
||||||
|
|
||||||
//1, to allow for the assertion test
|
//1, to allow for the assertion test
|
||||||
if (ignoredAssertions > 1) {
|
if (ignoredAssertions > 1) {
|
||||||
fprintf(stderr, ERROR "Assertions hidden: %d\n", ignoredAssertions);
|
fprintf(stderr, ERROR "Assertions hidden: %d\n", ignoredAssertions);
|
||||||
|
|||||||
@@ -79,16 +79,16 @@ unsigned char* compileString(char* source, size_t* size) {
|
|||||||
ASTNode* node = scanParser(&parser);
|
ASTNode* node = scanParser(&parser);
|
||||||
while(node != NULL) {
|
while(node != NULL) {
|
||||||
//pack up and leave
|
//pack up and leave
|
||||||
if (node->type == AST_NODEERROR) {
|
if (node->type == AST_NODE_ERROR) {
|
||||||
printf(ERROR "error node detected\n" RESET);
|
printf(ERROR "error node detected\n" RESET);
|
||||||
freeNode(node);
|
freeASTNode(node);
|
||||||
freeCompiler(&compiler);
|
freeCompiler(&compiler);
|
||||||
freeParser(&parser);
|
freeParser(&parser);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
writeCompiler(&compiler, node);
|
writeCompiler(&compiler, node);
|
||||||
freeNode(node);
|
freeASTNode(node);
|
||||||
node = scanParser(&parser);
|
node = scanParser(&parser);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+4
-8
@@ -29,22 +29,18 @@ int main() {
|
|||||||
|
|
||||||
{
|
{
|
||||||
//test string literals
|
//test string literals
|
||||||
char* buffer = ALLOCATE(char, 128);
|
char* buffer = "Hello world";
|
||||||
|
|
||||||
snprintf(buffer, 128, "Hello world");
|
Literal literal = TO_STRING_LITERAL(createRefString(buffer));
|
||||||
|
|
||||||
Literal literal = TO_STRING_LITERAL(buffer, 128);
|
|
||||||
|
|
||||||
freeLiteral(literal);
|
freeLiteral(literal);
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
//test identifier literals
|
//test identifier literals
|
||||||
char* buffer = ALLOCATE(char, 128);
|
char buffer[] = "Hello world";
|
||||||
|
|
||||||
snprintf(buffer, 128, "foobar");
|
Literal literal = TO_IDENTIFIER_LITERAL(createRefString(buffer));
|
||||||
|
|
||||||
Literal literal = TO_IDENTIFIER_LITERAL(buffer, 128);
|
|
||||||
|
|
||||||
freeLiteral(literal);
|
freeLiteral(literal);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -46,10 +46,10 @@ int main() {
|
|||||||
char* str_raw = "hello world";
|
char* str_raw = "hello world";
|
||||||
char* idn_raw = "foobar";
|
char* idn_raw = "foobar";
|
||||||
|
|
||||||
Literal string = TO_STRING_LITERAL(copyString(str_raw, strlen(str_raw)), strlen(str_raw));
|
Literal string = TO_STRING_LITERAL(createRefString(str_raw));
|
||||||
Literal identifier = TO_IDENTIFIER_LITERAL(copyString(idn_raw, strlen(idn_raw)), strlen(idn_raw));
|
Literal identifier = TO_IDENTIFIER_LITERAL(createRefString(idn_raw));
|
||||||
|
|
||||||
//[string, string]
|
//[string : string]
|
||||||
Literal type = TO_TYPE_LITERAL(LITERAL_DICTIONARY, false);
|
Literal type = TO_TYPE_LITERAL(LITERAL_DICTIONARY, false);
|
||||||
TYPE_PUSH_SUBTYPE(&type, TO_TYPE_LITERAL(LITERAL_STRING, false));
|
TYPE_PUSH_SUBTYPE(&type, TO_TYPE_LITERAL(LITERAL_STRING, false));
|
||||||
TYPE_PUSH_SUBTYPE(&type, TO_TYPE_LITERAL(LITERAL_STRING, false));
|
TYPE_PUSH_SUBTYPE(&type, TO_TYPE_LITERAL(LITERAL_STRING, false));
|
||||||
|
|||||||
@@ -18,8 +18,8 @@ int main() {
|
|||||||
char* idn_raw = "foobar";
|
char* idn_raw = "foobar";
|
||||||
char* str_raw = "hello world";
|
char* str_raw = "hello world";
|
||||||
|
|
||||||
Literal identifier = TO_IDENTIFIER_LITERAL(copyString(idn_raw, strlen(idn_raw)), strlen(idn_raw));
|
Literal identifier = TO_IDENTIFIER_LITERAL(createRefString(idn_raw));
|
||||||
Literal string = TO_STRING_LITERAL(copyString(str_raw, strlen(str_raw)), strlen(str_raw));
|
Literal string = TO_STRING_LITERAL(createRefString(str_raw));
|
||||||
|
|
||||||
LiteralDictionary dictionary;
|
LiteralDictionary dictionary;
|
||||||
initLiteralDictionary(&dictionary);
|
initLiteralDictionary(&dictionary);
|
||||||
|
|||||||
+47
-5
@@ -3,32 +3,74 @@
|
|||||||
#include "console_colors.h"
|
#include "console_colors.h"
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
int main() {
|
//the test allocator
|
||||||
|
static int callCount = 0;
|
||||||
|
|
||||||
|
void* allocator(void* pointer, size_t oldSize, size_t newSize) {
|
||||||
|
callCount++;
|
||||||
|
|
||||||
|
if (newSize == 0 && oldSize == 0) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (newSize == 0) {
|
||||||
|
free(pointer);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void* mem = realloc(pointer, newSize);
|
||||||
|
|
||||||
|
if (mem == NULL) {
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return mem;
|
||||||
|
}
|
||||||
|
|
||||||
|
void testMemoryAllocation() {
|
||||||
{
|
{
|
||||||
//test single pointer
|
//test single pointer
|
||||||
int* integer = ALLOCATE(int, 1);
|
int* integer = ALLOCATE(int, 1);
|
||||||
|
|
||||||
FREE(int, integer);
|
FREE(int, integer);
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
//test single pointer
|
//test single pointer array
|
||||||
int* array = ALLOCATE(int, 10);
|
int* array = ALLOCATE(int, 10);
|
||||||
|
|
||||||
|
array[1] = 42; //access the given memory
|
||||||
|
|
||||||
FREE_ARRAY(int, array, 10);
|
FREE_ARRAY(int, array, 10);
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
//test single pointer
|
//test multiple pointer arrays
|
||||||
int* array1 = ALLOCATE(int, 10);
|
int* array1 = ALLOCATE(int, 10);
|
||||||
int* array2 = ALLOCATE(int, 10);
|
int* array2 = ALLOCATE(int, 10);
|
||||||
|
|
||||||
|
array1[1] = 42; //access the given memory
|
||||||
|
array2[1] = 42; //access the given memory
|
||||||
|
|
||||||
FREE_ARRAY(int, array1, 10);
|
FREE_ARRAY(int, array1, 10);
|
||||||
FREE_ARRAY(int, array2, 10);
|
FREE_ARRAY(int, array2, 10);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
//test the default allocator
|
||||||
|
testMemoryAllocation();
|
||||||
|
|
||||||
|
//test the custom allocator
|
||||||
|
setMemoryAllocator(allocator);
|
||||||
|
testMemoryAllocation();
|
||||||
|
|
||||||
|
if (callCount != 8) {
|
||||||
|
fprintf(stderr, ERROR "Unexpected call count for custom allocator; was called %d times" RESET, callCount);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
printf(NOTICE "All good\n" RESET);
|
printf(NOTICE "All good\n" RESET);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,160 @@
|
|||||||
|
#include "lexer.h"
|
||||||
|
#include "parser.h"
|
||||||
|
#include "compiler.h"
|
||||||
|
#include "interpreter.h"
|
||||||
|
|
||||||
|
#include "console_colors.h"
|
||||||
|
|
||||||
|
#include "memory.h"
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
//suppress the print output
|
||||||
|
static void noPrintFn(const char* output) {
|
||||||
|
//NO OP
|
||||||
|
}
|
||||||
|
|
||||||
|
int errorsTriggered = 0;
|
||||||
|
static void noErrorFn(const char* output) {
|
||||||
|
errorsTriggered++;
|
||||||
|
}
|
||||||
|
|
||||||
|
//compilation functions
|
||||||
|
char* readFile(char* path, size_t* fileSize) {
|
||||||
|
FILE* file = fopen(path, "rb");
|
||||||
|
|
||||||
|
if (file == NULL) {
|
||||||
|
fprintf(stderr, ERROR "Could not open file \"%s\"\n" RESET, path);
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
fseek(file, 0L, SEEK_END);
|
||||||
|
*fileSize = ftell(file);
|
||||||
|
rewind(file);
|
||||||
|
|
||||||
|
char* buffer = (char*)malloc(*fileSize + 1);
|
||||||
|
|
||||||
|
if (buffer == NULL) {
|
||||||
|
fprintf(stderr, ERROR "Not enough memory to read \"%s\"\n" RESET, path);
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t bytesRead = fread(buffer, sizeof(char), *fileSize, file);
|
||||||
|
|
||||||
|
buffer[*fileSize] = '\0'; //NOTE: fread doesn't append this
|
||||||
|
|
||||||
|
if (bytesRead < *fileSize) {
|
||||||
|
fprintf(stderr, ERROR "Could not read file \"%s\"\n" RESET, path);
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(file);
|
||||||
|
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned char* compileString(char* source, size_t* size) {
|
||||||
|
Lexer lexer;
|
||||||
|
Parser parser;
|
||||||
|
Compiler compiler;
|
||||||
|
|
||||||
|
initLexer(&lexer, source);
|
||||||
|
initParser(&parser, &lexer);
|
||||||
|
initCompiler(&compiler);
|
||||||
|
|
||||||
|
//run the parser until the end of the source
|
||||||
|
ASTNode* node = scanParser(&parser);
|
||||||
|
while(node != NULL) {
|
||||||
|
//pack up and leave
|
||||||
|
if (node->type == AST_NODE_ERROR) {
|
||||||
|
printf(ERROR "error node detected\n" RESET);
|
||||||
|
freeASTNode(node);
|
||||||
|
freeCompiler(&compiler);
|
||||||
|
freeParser(&parser);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
writeCompiler(&compiler, node);
|
||||||
|
freeASTNode(node);
|
||||||
|
node = scanParser(&parser);
|
||||||
|
}
|
||||||
|
|
||||||
|
//get the bytecode dump
|
||||||
|
unsigned char* tb = collateCompiler(&compiler, (int*)(size));
|
||||||
|
|
||||||
|
//cleanup
|
||||||
|
freeCompiler(&compiler);
|
||||||
|
freeParser(&parser);
|
||||||
|
//no lexer to clean up
|
||||||
|
|
||||||
|
//finally
|
||||||
|
return tb;
|
||||||
|
}
|
||||||
|
|
||||||
|
void runBinary(unsigned char* tb, size_t size) {
|
||||||
|
Interpreter interpreter;
|
||||||
|
initInterpreter(&interpreter);
|
||||||
|
|
||||||
|
//NOTE: suppress print output for testing
|
||||||
|
setInterpreterPrint(&interpreter, noPrintFn);
|
||||||
|
setInterpreterError(&interpreter, noErrorFn);
|
||||||
|
|
||||||
|
runInterpreter(&interpreter, tb, size);
|
||||||
|
freeInterpreter(&interpreter);
|
||||||
|
}
|
||||||
|
|
||||||
|
void runSource(char* source) {
|
||||||
|
size_t size = 0;
|
||||||
|
unsigned char* tb = compileString(source, &size);
|
||||||
|
if (!tb) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
runBinary(tb, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
void runSourceFile(char* fname) {
|
||||||
|
size_t size = 0; //not used
|
||||||
|
char* source = readFile(fname, &size);
|
||||||
|
runSource(source);
|
||||||
|
free((void*)source);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
bool success = true;
|
||||||
|
|
||||||
|
{
|
||||||
|
//run each file in tests/scripts/
|
||||||
|
char* filenames[] = {
|
||||||
|
"declare-types-array.toy",
|
||||||
|
"declare-types-dictionary-key.toy",
|
||||||
|
"declare-types-dictionary-value.toy",
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
|
||||||
|
for (int i = 0; filenames[i]; i++) {
|
||||||
|
printf("Running (must fail) %s\n", filenames[i]);
|
||||||
|
|
||||||
|
char buffer[128];
|
||||||
|
snprintf(buffer, 128, "scripts/mustfail/%s", filenames[i]);
|
||||||
|
|
||||||
|
runSourceFile(buffer);
|
||||||
|
|
||||||
|
if (errorsTriggered == 0) {
|
||||||
|
printf(ERROR "Expected error did not occur in %s\n" RESET, filenames[i]);
|
||||||
|
success = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
errorsTriggered = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!success) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf(NOTICE "All good\n" RESET);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
@@ -62,16 +62,16 @@ unsigned char* compileString(char* source, size_t* size) {
|
|||||||
ASTNode* node = scanParser(&parser);
|
ASTNode* node = scanParser(&parser);
|
||||||
while(node != NULL) {
|
while(node != NULL) {
|
||||||
//pack up and leave
|
//pack up and leave
|
||||||
if (node->type == AST_NODEERROR) {
|
if (node->type == AST_NODE_ERROR) {
|
||||||
printf(ERROR "error node detected\n" RESET);
|
printf(ERROR "error node detected\n" RESET);
|
||||||
freeNode(node);
|
freeASTNode(node);
|
||||||
freeCompiler(&compiler);
|
freeCompiler(&compiler);
|
||||||
freeParser(&parser);
|
freeParser(&parser);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
writeCompiler(&compiler, node);
|
writeCompiler(&compiler, node);
|
||||||
freeNode(node);
|
freeASTNode(node);
|
||||||
node = scanParser(&parser);
|
node = scanParser(&parser);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+8
-7
@@ -72,18 +72,18 @@ int main() {
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (node->type != AST_NODEUNARY || node->unary.opcode != OP_PRINT) {
|
if (node->type != AST_NODE_UNARY || node->unary.opcode != OP_PRINT) {
|
||||||
fprintf(stderr, ERROR "ERROR: ASTNode is not a print instruction" RESET);
|
fprintf(stderr, ERROR "ERROR: ASTNode is not a unary print instruction" RESET);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (node->unary.child->type != AST_NODELITERAL || !IS_NULL(node->unary.child->atomic.literal)) {
|
if (node->unary.child->type != AST_NODE_LITERAL || !IS_NULL(node->unary.child->atomic.literal)) {
|
||||||
fprintf(stderr, ERROR "ERROR: ASTNode to be printed is not a null value" RESET);
|
fprintf(stderr, ERROR "ERROR: ASTNode to be printed is not a null literal" RESET);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
//cleanup
|
//cleanup
|
||||||
freeNode(node);
|
freeASTNode(node);
|
||||||
freeParser(&parser);
|
freeParser(&parser);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -101,12 +101,12 @@ int main() {
|
|||||||
ASTNode* node = scanParser(&parser);
|
ASTNode* node = scanParser(&parser);
|
||||||
|
|
||||||
while (node != NULL) {
|
while (node != NULL) {
|
||||||
if (node->type == AST_NODEERROR) {
|
if (node->type == AST_NODE_ERROR) {
|
||||||
fprintf(stderr, ERROR "ERROR: Error node detected" RESET);
|
fprintf(stderr, ERROR "ERROR: Error node detected" RESET);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
freeNode(node);
|
freeASTNode(node);
|
||||||
node = scanParser(&parser);
|
node = scanParser(&parser);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -114,6 +114,7 @@ int main() {
|
|||||||
freeParser(&parser);
|
freeParser(&parser);
|
||||||
free((void*)source);
|
free((void*)source);
|
||||||
}
|
}
|
||||||
|
|
||||||
printf(NOTICE "All good\n" RESET);
|
printf(NOTICE "All good\n" RESET);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-2
@@ -16,7 +16,7 @@ int main() {
|
|||||||
//prerequisites
|
//prerequisites
|
||||||
char* idn_raw = "foobar";
|
char* idn_raw = "foobar";
|
||||||
|
|
||||||
Literal identifier = TO_IDENTIFIER_LITERAL(copyString(idn_raw, strlen(idn_raw)), strlen(idn_raw));
|
Literal identifier = TO_IDENTIFIER_LITERAL(createRefString(idn_raw));
|
||||||
Literal value = TO_INTEGER_LITERAL(42);
|
Literal value = TO_INTEGER_LITERAL(42);
|
||||||
Literal type = TO_TYPE_LITERAL(value.type, false);
|
Literal type = TO_TYPE_LITERAL(value.type, false);
|
||||||
|
|
||||||
@@ -46,7 +46,7 @@ int main() {
|
|||||||
//prerequisites
|
//prerequisites
|
||||||
char* idn_raw = "foobar";
|
char* idn_raw = "foobar";
|
||||||
|
|
||||||
Literal identifier = TO_IDENTIFIER_LITERAL(copyString(idn_raw, strlen(idn_raw)), strlen(idn_raw));
|
Literal identifier = TO_IDENTIFIER_LITERAL(createRefString(idn_raw));
|
||||||
Literal type = TO_TYPE_LITERAL(LITERAL_INTEGER, false);
|
Literal type = TO_TYPE_LITERAL(LITERAL_INTEGER, false);
|
||||||
|
|
||||||
//test declarations & assignments
|
//test declarations & assignments
|
||||||
|
|||||||
Reference in New Issue
Block a user