Compare commits

..

41 Commits

Author SHA1 Message Date
Kayne Ruse c1625c53f4 Patched a bug in deepCopyRefString() 2022-11-26 21:33:46 +00:00
Kayne Ruse fb55f42d0e Tweaked where strlen() is called 2022-11-26 15:53:07 +00:00
Kayne Ruse e4ef35092f Merge pull request #43 from Ratstail91/dev
refstring implementation to handle strings and identifiers
2022-11-26 21:43:35 +11:00
Kayne Ruse cfafba589b All tests passing, repl builds successfully 2022-11-26 09:53:59 +00:00
Kayne Ruse f6367fa89d Updated interpreter 2022-11-26 09:43:19 +00:00
Kayne Ruse d199209772 Updated compiler 2022-11-26 06:58:38 +00:00
Kayne Ruse 4cf5c6a5bf Updated parser 2022-11-26 01:59:37 +00:00
Kayne Ruse 30c3a890ee Adjusted how AST Nodes are generated 2022-11-25 12:29:35 +00:00
Kayne Ruse 130ac980fe Enabled lexer tests 2022-11-23 13:02:43 +00:00
Kayne Ruse 923cf70c06 Minimal build of the refstrings in the literal structure 2022-11-23 12:52:49 +00:00
Kayne Ruse c7465e1204 Added API macro 2022-11-19 08:33:08 +00:00
Kayne Ruse 4518b59417 Added custom allocator support 2022-11-19 08:18:45 +00:00
Kayne Ruse 0b57f7efe7 Added release build targets, because bored 2022-11-16 22:05:47 +00:00
Kayne Ruse 7bf18a744c Tweaked bounds check 2022-11-12 11:39:32 +00:00
Kayne Ruse fa20763c07 Corrected negative timers 2022-11-12 11:30:24 +00:00
Kayne Ruse 774f3d9e83 Corrected error messages in the timer lib 2022-11-12 10:07:54 +00:00
Kayne Ruse 2d18ff4ba3 Fixed some printf formats in the tests 2022-11-12 03:26:14 +00:00
Kayne Ruse 30b068fcdb Fixed timer issues, tests should pass
Reduced test duration by a factor of 11,000. Don't ask.

Also, something funny is going on with the time headers, so I
stuck them into source/toy_common.h, I'll figure it out later.
2022-11-12 04:45:35 +11:00
Kayne Ruse 3d8ce4e7d8 Trying to fix time and platforms 2022-11-11 17:31:45 +00:00
Kayne Ruse e0ab4106fa Implemented the timer library 2022-11-11 17:18:07 +00:00
Kayne Ruse 2c143a8be5 Moved tests from scripts/ to test/scripts/ 2022-11-11 14:51:47 +00:00
Kayne Ruse 0aa6e4063b Spotted a scope issue in the test 2022-11-08 20:22:20 +00:00
Kayne Ruse ec39f099ca Wrote failing TDD test for timer library, not enabled 2022-11-08 19:40:21 +00:00
Kayne Ruse 4dcc05e796 Corrected fnv1 hash algorithm 2022-11-08 19:36:54 +00:00
Kayne Ruse 2af95ec82e Tweak 2022-11-08 02:55:02 +00:00
Kayne Ruse bbdb521333 Merge remote-tracking branch 'refs/remotes/origin/main' 2022-11-08 02:53:07 +00:00
Kayne Ruse 56987bc96a Tweaked colors for types 2022-11-08 02:52:18 +00:00
Kayne Ruse 8498864dde Resolved a name clash with the engine 2022-11-07 16:38:39 +00:00
Kayne Ruse 14710dec90 Tweaked README.md 2022-11-07 10:12:15 +00:00
Kayne Ruse d14177dbca Made it easier to install syntax highlighting 2022-11-07 10:02:37 +00:00
Kayne Ruse 42580bbe2a Update toy.tmLanguage.json
Forgot opaque type
2022-11-07 20:47:37 +11:00
Kayne Ruse 0c8e036de8 Added vscode syntax highlighting under /tools 2022-11-07 09:44:26 +00:00
Kayne Ruse a55338d8e3 Tweaked README.md 2022-11-06 04:15:33 +00:00
Kayne Ruse 5d240f85a6 BUGFIX: chained calls not being dottified 2022-11-04 11:13:40 +01:00
Kayne Ruse cceefa6375 Resolved #38 2022-11-03 16:25:29 +01:00
Kayne Ruse 632ed7c089 The tests did not like that 2022-11-03 22:59:25 +11:00
Kayne Ruse c1528f5501 Parallelized compilation 2022-11-03 12:54:41 +01:00
Kayne Ruse 6c5d952c44 Tests are ok for now 2022-10-20 00:00:13 +01:00
Kayne Ruse 208ad9d615 Experimenting 2022-10-20 09:45:28 +11:00
Kayne Ruse 876aad853c Creating the CI file 2022-10-20 09:42:52 +11:00
Kayne Ruse 1baa65cc95 Removed annoying assertion test messages from test output 2022-10-19 23:34:15 +01:00
86 changed files with 1879 additions and 696 deletions
+19
View File
@@ -0,0 +1,19 @@
name: Comprehensive Tests
on:
push:
branches: [ "main", "dev" ]
pull_request:
branches: [ "main" ]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: install valgrind
run: sudo apt install valgrind
- name: make test
run: make test
+7 -1
View File
@@ -2,7 +2,7 @@
<image src="toylogo.png" />
</p>
# Toy 0.6.0
# Toy
This is the Toy programming language interpreter, written in C.
@@ -27,6 +27,12 @@ Note: For Linux, you may need to `cd` into the `out` directory before running.
Note: MacOS is not officially supported (no machines for testing), but we'll do our best!
## Tools
Run `make install-tools` to install a number of tools, including:
* VSCode syntax highlighting
## Syntax
```
-51
View File
@@ -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?
+21 -2
View File
@@ -5,24 +5,43 @@ export TOY_OUTDIR = out
all: $(TOY_OUTDIR) repl
#repl builds
repl: $(TOY_OUTDIR) library
$(MAKE) -C repl
repl-static: $(TOY_OUTDIR) static
$(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)
$(MAKE) -C source library
$(MAKE) -j8 -C source library
static: $(TOY_OUTDIR)
$(MAKE) -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)
$(MAKE) -C test
$(TOY_OUTDIR):
mkdir $(TOY_OUTDIR)
#utils
install-tools:
cp -rf tools/toylang.vscode-highlighting ~/.vscode/extensions
.PHONY: clean
clean:
+3 -3
View File
@@ -2,7 +2,7 @@
#include "memory.h"
#include <time.h>
#include <sys/time.h>
static int nativeClock(Interpreter* interpreter, LiteralArray* arguments) {
//no arguments
@@ -18,7 +18,7 @@ static int nativeClock(Interpreter* interpreter, LiteralArray* arguments) {
//push to the stack
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
pushLiteralArray(&interpreter->stack, timeLiteral);
@@ -57,7 +57,7 @@ int hookStandard(Interpreter* interpreter, Literal identifier, Literal alias) {
//load the dict with functions
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);
func.type = LITERAL_FUNCTION_NATIVE;
+411
View File
@@ -0,0 +1,411 @@
#include "lib_timer.h"
#include "toy_common.h"
#include "memory.h"
#include <stdio.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
static struct timeval* diff(struct timeval* lhs, struct timeval* rhs) {
struct timeval* d = ALLOCATE(struct timeval, 1);
//I gave up, copied from SO
timeval_subtract(d, rhs, lhs);
return d;
}
//callbacks
static int nativeStartTimer(Interpreter* interpreter, LiteralArray* arguments) {
//no arguments
if (arguments->count != 0) {
interpreter->errorOutput("Incorrect number of arguments to startTimer\n");
return -1;
}
//get the timeinfo from C
struct timeval* timeinfo = ALLOCATE(struct timeval, 1);
gettimeofday(timeinfo, NULL);
//wrap in an opaque literal for Toy
Literal timeLiteral = TO_OPAQUE_LITERAL(timeinfo, -1);
pushLiteralArray(&interpreter->stack, timeLiteral);
freeLiteral(timeLiteral);
return 1;
}
static int nativeStopTimer(Interpreter* interpreter, LiteralArray* arguments) {
//no arguments
if (arguments->count != 1) {
interpreter->errorOutput("Incorrect number of arguments to _stopTimer\n");
return -1;
}
//get the timeinfo from C
struct timeval timerStop;
gettimeofday(&timerStop, NULL);
//unwrap the opaque literal
Literal timeLiteral = popLiteralArray(arguments);
Literal timeLiteralIdn = timeLiteral;
if (IS_IDENTIFIER(timeLiteral) && parseIdentifierToValue(interpreter, &timeLiteral)) {
freeLiteral(timeLiteralIdn);
}
if (!IS_OPAQUE(timeLiteral)) {
interpreter->errorOutput("Incorrect argument type passed to _stopTimer\n");
freeLiteral(timeLiteral);
return -1;
}
struct timeval* timerStart = AS_OPAQUE(timeLiteral);
//determine the difference, and wrap it
struct timeval* d = diff(timerStart, &timerStop);
Literal diffLiteral = TO_OPAQUE_LITERAL(d, -1);
pushLiteralArray(&interpreter->stack, diffLiteral);
//cleanup
freeLiteral(timeLiteral);
freeLiteral(diffLiteral);
return 1;
}
static int nativeCreateTimer(Interpreter* interpreter, LiteralArray* arguments) {
//no arguments
if (arguments->count != 2) {
interpreter->errorOutput("Incorrect number of arguments to createTimer\n");
return -1;
}
//get the args
Literal microsecondLiteral = popLiteralArray(arguments);
Literal secondLiteral = popLiteralArray(arguments);
Literal secondLiteralIdn = secondLiteral;
if (IS_IDENTIFIER(secondLiteral) && parseIdentifierToValue(interpreter, &secondLiteral)) {
freeLiteral(secondLiteralIdn);
}
Literal microsecondLiteralIdn = microsecondLiteral;
if (IS_IDENTIFIER(microsecondLiteral) && parseIdentifierToValue(interpreter, &microsecondLiteral)) {
freeLiteral(microsecondLiteralIdn);
}
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(microsecondLiteral);
return -1;
}
//get the timeinfo from toy
struct timeval* timeinfo = ALLOCATE(struct timeval, 1);
timeinfo->tv_sec = AS_INTEGER(secondLiteral);
timeinfo->tv_usec = AS_INTEGER(microsecondLiteral);
//wrap in an opaque literal for Toy
Literal timeLiteral = TO_OPAQUE_LITERAL(timeinfo, -1);
pushLiteralArray(&interpreter->stack, timeLiteral);
freeLiteral(timeLiteral);
freeLiteral(secondLiteral);
freeLiteral(microsecondLiteral);
return 1;
}
static int nativeGetTimerSeconds(Interpreter* interpreter, LiteralArray* arguments) {
//no arguments
if (arguments->count != 1) {
interpreter->errorOutput("Incorrect number of arguments to _getTimerSeconds\n");
return -1;
}
//unwrap the opaque literal
Literal timeLiteral = popLiteralArray(arguments);
Literal timeLiteralIdn = timeLiteral;
if (IS_IDENTIFIER(timeLiteral) && parseIdentifierToValue(interpreter, &timeLiteral)) {
freeLiteral(timeLiteralIdn);
}
if (!IS_OPAQUE(timeLiteral)) {
interpreter->errorOutput("Incorrect argument type passed to _getTimerSeconds\n");
freeLiteral(timeLiteral);
return -1;
}
struct timeval* timer = AS_OPAQUE(timeLiteral);
//create the result literal
Literal result = TO_INTEGER_LITERAL(timer->tv_sec);
pushLiteralArray(&interpreter->stack, result);
//cleanup
freeLiteral(timeLiteral);
freeLiteral(result);
return 1;
}
static int nativeGetTimerMicroseconds(Interpreter* interpreter, LiteralArray* arguments) {
//no arguments
if (arguments->count != 1) {
interpreter->errorOutput("Incorrect number of arguments to _getTimerMicroseconds\n");
return -1;
}
//unwrap the opaque literal
Literal timeLiteral = popLiteralArray(arguments);
Literal timeLiteralIdn = timeLiteral;
if (IS_IDENTIFIER(timeLiteral) && parseIdentifierToValue(interpreter, &timeLiteral)) {
freeLiteral(timeLiteralIdn);
}
if (!IS_OPAQUE(timeLiteral)) {
interpreter->errorOutput("Incorrect argument type passed to _getTimerMicroseconds\n");
freeLiteral(timeLiteral);
return -1;
}
struct timeval* timer = AS_OPAQUE(timeLiteral);
//create the result literal
Literal result = TO_INTEGER_LITERAL(timer->tv_usec);
pushLiteralArray(&interpreter->stack, result);
//cleanup
freeLiteral(timeLiteral);
freeLiteral(result);
return 1;
}
static int nativeCompareTimer(Interpreter* interpreter, LiteralArray* arguments) {
//no arguments
if (arguments->count != 2) {
interpreter->errorOutput("Incorrect number of arguments to _compareTimer\n");
return -1;
}
//unwrap the opaque literals
Literal rhsLiteral = popLiteralArray(arguments);
Literal lhsLiteral = popLiteralArray(arguments);
Literal lhsLiteralIdn = lhsLiteral;
if (IS_IDENTIFIER(lhsLiteral) && parseIdentifierToValue(interpreter, &lhsLiteral)) {
freeLiteral(lhsLiteralIdn);
}
Literal rhsLiteralIdn = rhsLiteral;
if (IS_IDENTIFIER(rhsLiteral) && parseIdentifierToValue(interpreter, &rhsLiteral)) {
freeLiteral(rhsLiteralIdn);
}
if (!IS_OPAQUE(lhsLiteral) || !IS_OPAQUE(rhsLiteral)) {
interpreter->errorOutput("Incorrect argument type passed to _compareTimer\n");
freeLiteral(lhsLiteral);
freeLiteral(rhsLiteral);
return -1;
}
struct timeval* lhsTimer = AS_OPAQUE(lhsLiteral);
struct timeval* rhsTimer = AS_OPAQUE(rhsLiteral);
//determine the difference, and wrap it
struct timeval* d = diff(lhsTimer, rhsTimer);
Literal diffLiteral = TO_OPAQUE_LITERAL(d, -1);
pushLiteralArray(&interpreter->stack, diffLiteral);
//cleanup
freeLiteral(lhsLiteral);
freeLiteral(rhsLiteral);
freeLiteral(diffLiteral);
return 1;
}
static int nativeTimerToString(Interpreter* interpreter, LiteralArray* arguments) {
//no arguments
if (arguments->count != 1) {
interpreter->errorOutput("Incorrect number of arguments to _timerToString\n");
return -1;
}
//unwrap in an opaque literal
Literal timeLiteral = popLiteralArray(arguments);
Literal timeLiteralIdn = timeLiteral;
if (IS_IDENTIFIER(timeLiteral) && parseIdentifierToValue(interpreter, &timeLiteral)) {
freeLiteral(timeLiteralIdn);
}
if (!IS_OPAQUE(timeLiteral)) {
interpreter->errorOutput("Incorrect argument type passed to _timerToString\n");
freeLiteral(timeLiteral);
return -1;
}
struct timeval* timer = AS_OPAQUE(timeLiteral);
//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];
snprintf(buffer, 128, "%ld.%06ld", timer->tv_sec, timer->tv_usec);
resultLiteral = TO_STRING_LITERAL(createRefStringLength(buffer, strlen(buffer)));
}
pushLiteralArray(&interpreter->stack, resultLiteral);
//cleanup
freeLiteral(timeLiteral);
freeLiteral(resultLiteral);
return 1;
}
static int nativeDestroyTimer(Interpreter* interpreter, LiteralArray* arguments) {
//no arguments
if (arguments->count != 1) {
interpreter->errorOutput("Incorrect number of arguments to _destroyTimer\n");
return -1;
}
//unwrap in an opaque literal
Literal timeLiteral = popLiteralArray(arguments);
Literal timeLiteralIdn = timeLiteral;
if (IS_IDENTIFIER(timeLiteral) && parseIdentifierToValue(interpreter, &timeLiteral)) {
freeLiteral(timeLiteralIdn);
}
if (!IS_OPAQUE(timeLiteral)) {
interpreter->errorOutput("Incorrect argument type passed to _destroyTimer\n");
freeLiteral(timeLiteral);
return -1;
}
struct timeval* timer = AS_OPAQUE(timeLiteral);
FREE(struct timeval, timer);
freeLiteral(timeLiteral);
return 0;
}
//call the hook
typedef struct Natives {
char* name;
NativeFn fn;
} Natives;
int hookTimer(Interpreter* interpreter, Literal identifier, Literal alias) {
//build the natives list
Natives natives[] = {
{"startTimer", nativeStartTimer},
{"_stopTimer", nativeStopTimer},
{"createTimer", nativeCreateTimer},
{"_getTimerSeconds", nativeGetTimerSeconds},
{"_getTimerMicroseconds", nativeGetTimerMicroseconds},
{"_compareTimer", nativeCompareTimer},
{"_timerToString", nativeTimerToString},
{"_destroyTimer", nativeDestroyTimer},
{NULL, NULL}
};
//store the library in an aliased dictionary
if (!IS_NULL(alias)) {
//make sure the name isn't taken
if (isDelcaredScopeVariable(interpreter->scope, alias)) {
interpreter->errorOutput("Can't override an existing variable\n");
freeLiteral(alias);
return false;
}
//create the dictionary to load up with functions
LiteralDictionary* dictionary = ALLOCATE(LiteralDictionary, 1);
initLiteralDictionary(dictionary);
//load the dict with functions
for (int i = 0; natives[i].name; i++) {
Literal name = TO_STRING_LITERAL(createRefString(natives[i].name));
Literal func = TO_FUNCTION_LITERAL((void*)natives[i].fn, 0);
func.type = LITERAL_FUNCTION_NATIVE;
setLiteralDictionary(dictionary, name, func);
freeLiteral(name);
freeLiteral(func);
}
//build the type
Literal type = TO_TYPE_LITERAL(LITERAL_DICTIONARY, true);
Literal strType = TO_TYPE_LITERAL(LITERAL_STRING, true);
Literal fnType = TO_TYPE_LITERAL(LITERAL_FUNCTION_NATIVE, true);
TYPE_PUSH_SUBTYPE(&type, strType);
TYPE_PUSH_SUBTYPE(&type, fnType);
//set scope
Literal dict = TO_DICTIONARY_LITERAL(dictionary);
declareScopeVariable(interpreter->scope, alias, type);
setScopeVariable(interpreter->scope, alias, dict, false);
//cleanup
freeLiteral(dict);
freeLiteral(type);
return 0;
}
//default
for (int i = 0; natives[i].name; i++) {
injectNativeFn(interpreter, natives[i].name, natives[i].fn);
}
return 0;
}
+6
View File
@@ -0,0 +1,6 @@
#pragma once
#include "interpreter.h"
int hookTimer(Interpreter* interpreter, Literal identifier, Literal alias);
+3
View File
@@ -18,6 +18,9 @@ else
$(CC) -DTOY_IMPORT $(CFLAGS) -o $(OUT) $(OBJ) -Wl,-rpath,. -L$(realpath $(shell pwd)/../$(TOY_OUTDIR)) $(LIBS)
endif
release: all
strip $(OUT)
$(OBJ): | $(ODIR)
$(ODIR):
+5 -3
View File
@@ -1,5 +1,6 @@
#include "repl_tools.h"
#include "lib_standard.h"
#include "lib_timer.h"
#include "console_colors.h"
@@ -25,6 +26,7 @@ void repl() {
//inject the libs
injectNativeHook(&interpreter, "standard", hookStandard);
injectNativeHook(&interpreter, "timer", hookTimer);
for(;;) {
printf("> ");
@@ -48,15 +50,15 @@ void repl() {
ASTNode* node = scanParser(&parser);
while(node != NULL) {
//pack up and restart
if (node->type == AST_NODEERROR) {
if (node->type == AST_NODE_ERROR) {
printf(ERROR "error node detected\n" RESET);
error = true;
freeNode(node);
freeASTNode(node);
break;
}
writeCompiler(&compiler, node);
freeNode(node);
freeASTNode(node);
node = scanParser(&parser);
}
+5 -3
View File
@@ -1,5 +1,6 @@
#include "repl_tools.h"
#include "lib_standard.h"
#include "lib_timer.h"
#include "console_colors.h"
@@ -77,16 +78,16 @@ unsigned char* compileString(char* source, size_t* size) {
ASTNode* node = scanParser(&parser);
while(node != NULL) {
//pack up and leave
if (node->type == AST_NODEERROR) {
if (node->type == AST_NODE_ERROR) {
printf(ERROR "error node detected\n" RESET);
freeNode(node);
freeASTNode(node);
freeCompiler(&compiler);
freeParser(&parser);
return NULL;
}
writeCompiler(&compiler, node);
freeNode(node);
freeASTNode(node);
node = scanParser(&parser);
}
@@ -108,6 +109,7 @@ void runBinary(unsigned char* tb, size_t size) {
//inject the libs
injectNativeHook(&interpreter, "standard", hookStandard);
injectNativeHook(&interpreter, "timer", hookTimer);
runInterpreter(&interpreter, tb, size);
freeInterpreter(&interpreter);
+1 -1
View File
@@ -1,6 +1,6 @@
#pragma once
#include "common.h"
#include "toy_common.h"
char* readFile(char* path, size_t* fileSize);
void writeFile(char* path, unsigned char* bytes, size_t size);
+2 -2
View File
@@ -6,7 +6,7 @@ fn fib(n : int) {
return fib(n-1) + fib(n-2);
}
for (var i = 0; i < 40; i++) {
for (var i = 0; i < 20; i++) {
var res = fib(i);
print (string)i + ": " + (string)res;
print string i + ": " + string res;
}
+9 -52
View File
@@ -1,56 +1,13 @@
import timer;
var a = createTimer(1, 0);
var b = createTimer(2, 0);
fn _b(self) {
print "running _b";
print self;
return self;
}
print a.compareTimer(b).timerToString();
print b.compareTimer(a).timerToString();
fn _c(self) {
print "running _c";
print self;
return self;
}
var c = createTimer(0, 1);
var d = createTimer(0, 2);
fn _d(self) {
print "running _d";
print self;
return self;
}
fn _e(self) {
print "running _e";
print self;
return self;
}
fn _f(self) {
print "running _f";
print self;
return self;
}
fn b() {
print "running b";
}
fn c() {
print "running c";
}
fn d() {
print "running d";
}
fn e() {
print "running e";
}
fn f() {
print "running f";
}
var a = 42;
print a.b().c().d().e().f();
print c.compareTimer(d).timerToString();
print d.compareTimer(c).timerToString();
-8
View File
@@ -1,8 +0,0 @@
fn panic() {
assert false, "This should only be seen once";
}
panic();
panic();
+194 -105
View File
@@ -5,106 +5,134 @@
#include <stdio.h>
#include <stdlib.h>
void freeNodeCustom(ASTNode* node, bool freeSelf) {
void freeASTNodeCustom(ASTNode* node, bool freeSelf) {
//don't free a NULL node
if (node == NULL) {
return;
}
switch(node->type) {
case AST_NODEERROR:
case AST_NODE_ERROR:
//NO-OP
break;
case AST_NODELITERAL:
case AST_NODE_LITERAL:
freeLiteral(node->atomic.literal);
break;
case AST_NODEUNARY:
freeNode(node->unary.child);
case AST_NODE_UNARY:
freeASTNode(node->unary.child);
break;
case AST_NODEBINARY:
freeNode(node->binary.left);
freeNode(node->binary.right);
case AST_NODE_BINARY:
freeASTNode(node->binary.left);
freeASTNode(node->binary.right);
break;
case AST_NODEGROUPING:
freeNode(node->grouping.child);
case AST_NODE_GROUPING:
freeASTNode(node->grouping.child);
break;
case AST_NODEBLOCK:
case AST_NODE_BLOCK:
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);
break;
case AST_NODECOMPOUND:
case AST_NODE_COMPOUND:
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);
break;
case AST_NODEPAIR:
freeNode(node->pair.left);
freeNode(node->pair.right);
case AST_NODE_PAIR:
freeASTNode(node->pair.left);
freeASTNode(node->pair.right);
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.typeLiteral);
freeNode(node->varDecl.expression);
freeASTNode(node->varDecl.expression);
break;
case AST_NODEFN_DECL:
freeLiteral(node->fnDecl.identifier);
freeNode(node->fnDecl.arguments);
freeNode(node->fnDecl.returns);
freeNode(node->fnDecl.block);
break;
case AST_NODEFN_COLLECTION:
case AST_NODE_FN_COLLECTION:
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);
break;
case AST_NODEFN_CALL:
freeNode(node->fnCall.arguments);
case AST_NODE_FN_DECL:
freeLiteral(node->fnDecl.identifier);
freeASTNode(node->fnDecl.arguments);
freeASTNode(node->fnDecl.returns);
freeASTNode(node->fnDecl.block);
break;
case AST_NODEPATH_IF:
case AST_NODEPATH_WHILE:
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);
case AST_NODE_FN_CALL:
freeASTNode(node->fnCall.arguments);
break;
case AST_NODEINCREMENT_PREFIX:
case AST_NODEINCREMENT_POSTFIX:
freeLiteral(node->increment.identifier);
case AST_NODE_FN_RETURN:
freeASTNode(node->returns.returns);
break;
case AST_NODEIMPORT:
case AST_NODEEXPORT:
case AST_NODE_IF:
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.alias);
break;
case AST_NODEINDEX:
case AST_NODEDOT:
freeNode(node->index.first);
freeNode(node->index.second);
freeNode(node->index.third);
case AST_NODE_EXPORT:
freeLiteral(node->export.identifier);
freeLiteral(node->export.alias);
break;
}
@@ -113,15 +141,16 @@ void freeNodeCustom(ASTNode* node, bool freeSelf) {
}
}
void freeNode(ASTNode* node) {
freeNodeCustom(node, true);
void freeASTNode(ASTNode* node) {
freeASTNodeCustom(node, true);
}
//various emitters
void emitASTNodeLiteral(ASTNode** nodeHandle, Literal literal) {
//allocate a new node
*nodeHandle = ALLOCATE(ASTNode, 1);
(*nodeHandle)->type = AST_NODELITERAL;
(*nodeHandle)->type = AST_NODE_LITERAL;
(*nodeHandle)->atomic.literal = copyLiteral(literal);
}
@@ -129,7 +158,7 @@ void emitASTNodeUnary(ASTNode** nodeHandle, Opcode opcode, ASTNode* child) {
//allocate a new node
*nodeHandle = ALLOCATE(ASTNode, 1);
(*nodeHandle)->type = AST_NODEUNARY;
(*nodeHandle)->type = AST_NODE_UNARY;
(*nodeHandle)->unary.opcode = opcode;
(*nodeHandle)->unary.child = child;
}
@@ -137,7 +166,7 @@ void emitASTNodeUnary(ASTNode** nodeHandle, Opcode opcode, ASTNode* child) {
void emitASTNodeBinary(ASTNode** nodeHandle, ASTNode* rhs, Opcode opcode) {
ASTNode* tmp = ALLOCATE(ASTNode, 1);
tmp->type = AST_NODEBINARY;
tmp->type = AST_NODE_BINARY;
tmp->binary.opcode = opcode;
tmp->binary.left = *nodeHandle;
tmp->binary.right = rhs;
@@ -148,7 +177,7 @@ void emitASTNodeBinary(ASTNode** nodeHandle, ASTNode* rhs, Opcode opcode) {
void emitASTNodeGrouping(ASTNode** nodeHandle) {
ASTNode* tmp = ALLOCATE(ASTNode, 1);
tmp->type = AST_NODEGROUPING;
tmp->type = AST_NODE_GROUPING;
tmp->grouping.child = *nodeHandle;
*nodeHandle = tmp;
@@ -157,8 +186,8 @@ void emitASTNodeGrouping(ASTNode** nodeHandle) {
void emitASTNodeBlock(ASTNode** nodeHandle) {
ASTNode* tmp = ALLOCATE(ASTNode, 1);
tmp->type = AST_NODEBLOCK;
tmp->block.nodes = NULL;
tmp->type = AST_NODE_BLOCK;
tmp->block.nodes = NULL; //NOTE: appended by the parser
tmp->block.capacity = 0;
tmp->block.count = 0;
@@ -168,7 +197,7 @@ void emitASTNodeBlock(ASTNode** nodeHandle) {
void emitASTNodeCompound(ASTNode** nodeHandle, LiteralType literalType) {
ASTNode* tmp = ALLOCATE(ASTNode, 1);
tmp->type = AST_NODECOMPOUND;
tmp->type = AST_NODE_COMPOUND;
tmp->compound.literalType = literalType;
tmp->compound.nodes = NULL;
tmp->compound.capacity = 0;
@@ -178,16 +207,27 @@ void emitASTNodeCompound(ASTNode** nodeHandle, LiteralType literalType) {
}
void setASTNodePair(ASTNode* node, ASTNode* left, ASTNode* right) {
//assume the node has already been allocated
node->type = AST_NODEPAIR;
//set - assume the node has already been allocated
node->type = AST_NODE_PAIR;
node->pair.left = left;
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) {
ASTNode* tmp = ALLOCATE(ASTNode, 1);
tmp->type = AST_NODEVAR_DECL;
tmp->type = AST_NODE_VAR_DECL;
tmp->varDecl.identifier = identifier;
tmp->varDecl.typeLiteral = typeLiteral;
tmp->varDecl.expression = expression;
@@ -195,10 +235,21 @@ void emitASTNodeVarDecl(ASTNode** nodeHandle, Literal identifier, Literal typeLi
*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) {
ASTNode* tmp = ALLOCATE(ASTNode, 1);
tmp->type = AST_NODEFN_DECL;
tmp->type = AST_NODE_FN_DECL;
tmp->fnDecl.identifier = identifier;
tmp->fnDecl.arguments = arguments;
tmp->fnDecl.returns = returns;
@@ -207,88 +258,126 @@ void emitASTNodeFnDecl(ASTNode** nodeHandle, Literal identifier, ASTNode* argume
*nodeHandle = tmp;
}
void emitASTFnCall(ASTNode** nodeHandle, ASTNode* arguments, int argumentCount) {
void emitASTNodeFnCall(ASTNode** nodeHandle, ASTNode* arguments) {
ASTNode* tmp = ALLOCATE(ASTNode, 1);
tmp->type = AST_NODEFN_CALL;
tmp->type = AST_NODE_FN_CALL;
tmp->fnCall.arguments = arguments;
tmp->fnCall.argumentCount = argumentCount;
tmp->fnCall.argumentCount = arguments->fnCollection.count;
*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);
tmp->type = AST_NODEFN_COLLECTION;
tmp->fnCollection.nodes = NULL;
tmp->fnCollection.capacity = 0;
tmp->fnCollection.count = 0;
tmp->type = AST_NODE_FN_RETURN;
tmp->returns.returns = returns;
*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);
tmp->type = type;
tmp->path.preClause = preClause;
tmp->path.postClause = postClause;
tmp->path.condition = condition;
tmp->path.thenPath = thenPath;
tmp->path.elsePath = elsePath;
tmp->type = AST_NODE_IF;
tmp->pathIf.condition = condition;
tmp->pathIf.thenPath = thenPath;
tmp->pathIf.elsePath = elsePath;
*nodeHandle = tmp;
}
void emitASTNodePrefixIncrement(ASTNode** nodeHandle, Literal identifier, int increment) {
void emitASTNodeWhile(ASTNode** nodeHandle, ASTNode* condition, ASTNode* thenPath) {
ASTNode* tmp = ALLOCATE(ASTNode, 1);
tmp->type = AST_NODEINCREMENT_PREFIX;
tmp->increment.identifier = copyLiteral(identifier);
tmp->increment.increment = increment;
tmp->type = AST_NODE_WHILE;
tmp->pathWhile.condition = condition;
tmp->pathWhile.thenPath = thenPath;
*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);
tmp->type = AST_NODEINCREMENT_POSTFIX;
tmp->increment.identifier = copyLiteral(identifier);
tmp->increment.increment = increment;
tmp->type = AST_NODE_FOR;
tmp->pathFor.preClause = preClause;
tmp->pathFor.condition = condition;
tmp->pathFor.postClause = postClause;
tmp->pathFor.thenPath = thenPath;
*nodeHandle = tmp;
}
void emitASTNodeImport(ASTNode** nodeHandle, ASTNodeType mode, Literal identifier, Literal alias) {
void emitASTNodeBreak(ASTNode** nodeHandle) {
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.alias = copyLiteral(alias);
*nodeHandle = tmp;
}
void emitASTNodeIndex(ASTNode** nodeHandle, ASTNode* first, ASTNode* second, ASTNode* third) {
void emitASTNodeExport(ASTNode** nodeHandle, Literal identifier, Literal alias) {
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;
tmp->type = AST_NODE_EXPORT;
tmp->export.identifier = copyLiteral(identifier);
tmp->export.alias = copyLiteral(alias);
*nodeHandle = tmp;
}
+161 -70
View File
@@ -1,6 +1,6 @@
#pragma once
#include "common.h"
#include "toy_common.h"
#include "literal.h"
#include "opcodes.h"
#include "token_types.h"
@@ -9,43 +9,53 @@
typedef union _node ASTNode;
typedef enum ASTNodeType {
AST_NODEERROR,
AST_NODELITERAL, //a simple value
AST_NODEUNARY, //one child + opcode
AST_NODEBINARY, //two children, left and right + opcode
AST_NODEGROUPING, //one child
AST_NODEBLOCK, //contains a sub-node array
AST_NODECOMPOUND, //contains a sub-node array
AST_NODEPAIR, //contains a left and right
AST_NODEVAR_DECL, //contains identifier literal, typenode, expression definition
AST_NODEFN_DECL, //containd identifier literal, arguments node, returns node, block node
AST_NODEFN_COLLECTION, //parts of a function
AST_NODEFN_CALL,
AST_NODEPATH_IF, //for control flow
AST_NODEPATH_WHILE, //for control flow
AST_NODEPATH_FOR, //for control flow
AST_NODEPATH_BREAK, //for control flow
AST_NODEPATH_CONTINUE, //for control flow
AST_NODEPATH_RETURN,
AST_NODEINCREMENT_PREFIX,
AST_NODEINCREMENT_POSTFIX,
AST_NODEIMPORT,
AST_NODEEXPORT,
AST_NODEINDEX,
AST_NODEDOT,
AST_NODE_ERROR,
AST_NODE_LITERAL, //a simple value
AST_NODE_UNARY, //one child + opcode
AST_NODE_BINARY, //two children, left and right + opcode
AST_NODE_GROUPING, //one child
AST_NODE_BLOCK, //contains a sub-node array
AST_NODE_COMPOUND, //contains a sub-node array
AST_NODE_PAIR, //contains a left and right
AST_NODE_INDEX, //index a variable
AST_NODE_VAR_DECL, //contains identifier literal, typenode, expression definition
AST_NODE_FN_DECL, //containd identifier literal, arguments node, returns node, block node
AST_NODE_FN_COLLECTION, //parts of a function
AST_NODE_FN_CALL, //call a function
AST_NODE_FN_RETURN, //for control flow
AST_NODE_IF, //for control flow
AST_NODE_WHILE, //for control flow
AST_NODE_FOR, //for control flow
AST_NODE_BREAK, //for control flow
AST_NODE_CONTINUE, //for control flow
AST_NODE_PREFIX_INCREMENT, //increment a variable
AST_NODE_POSTFIX_INCREMENT, //increment a variable
AST_NODE_PREFIX_DECREMENT, //decrement a variable
AST_NODE_POSTFIX_DECREMENT, //decrement a variable
AST_NODE_IMPORT, //import a variable
AST_NODE_EXPORT, //export a variable
} ASTNodeType;
//literals
void emitASTNodeLiteral(ASTNode** nodeHandle, Literal literal);
typedef struct NodeLiteral {
ASTNodeType type;
Literal literal;
} NodeLiteral;
//unary operator
void emitASTNodeUnary(ASTNode** nodeHandle, Opcode opcode, ASTNode* child);
typedef struct NodeUnary {
ASTNodeType type;
Opcode opcode;
ASTNode* child;
} NodeUnary;
//binary operator
void emitASTNodeBinary(ASTNode** nodeHandle, ASTNode* rhs, Opcode opcode); //handled node becomes lhs
typedef struct NodeBinary {
ASTNodeType type;
Opcode opcode;
@@ -53,11 +63,17 @@ typedef struct NodeBinary {
ASTNode* right;
} NodeBinary;
//grouping of other AST nodes
void emitASTNodeGrouping(ASTNode** nodeHandle);
typedef struct NodeGrouping {
ASTNodeType type;
ASTNode* child;
} NodeGrouping;
//block of statement nodes
void emitASTNodeBlock(ASTNode** nodeHandle);
typedef struct NodeBlock {
ASTNodeType type;
ASTNode* nodes;
@@ -65,6 +81,9 @@ typedef struct NodeBlock {
int count;
} NodeBlock;
//compound literals (array, dictionary)
void emitASTNodeCompound(ASTNode** nodeHandle, LiteralType literalType);
typedef struct NodeCompound {
ASTNodeType type;
LiteralType literalType;
@@ -73,12 +92,26 @@ typedef struct NodeCompound {
int count;
} NodeCompound;
void setASTNodePair(ASTNode* node, ASTNode* left, ASTNode* right); //NOTE: this is a set function, not an emit function
typedef struct NodePair {
ASTNodeType type;
ASTNode* left;
ASTNode* right;
} 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 {
ASTNodeType type;
Literal identifier;
@@ -86,6 +119,19 @@ typedef struct NodeVarDecl {
ASTNode* expression;
} 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 {
ASTNodeType type;
Literal identifier;
@@ -94,33 +140,88 @@ typedef struct NodeFnDecl {
ASTNode* block;
} NodeFnDecl;
typedef struct NodeFnCollection {
ASTNodeType type;
ASTNode* nodes;
int capacity;
int count;
} NodeFnCollection;
//function call
void emitASTNodeFnCall(ASTNode** nodeHandle, ASTNode* arguments);
typedef struct NodeFnCall {
ASTNodeType type;
ASTNode* arguments;
int argumentCount;
int argumentCount; //NOTE: leave this, so it can be hacked by dottify()
} 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;
ASTNode* preClause;
ASTNode* postClause;
ASTNode* condition;
ASTNode* thenPath;
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;
Literal identifier;
int increment;
} NodeIncrement;
} NodePrefixIncrement;
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/export a variable
void emitASTNodeImport(ASTNode** nodeHandle, Literal identifier, Literal alias);
void emitASTNodeExport(ASTNode** nodeHandle, Literal identifier, Literal alias);
typedef struct NodeImport {
ASTNodeType type;
@@ -128,12 +229,11 @@ typedef struct NodeImport {
Literal alias;
} NodeImport;
typedef struct NodeIndex {
typedef struct NodeExport {
ASTNodeType type;
ASTNode* first;
ASTNode* second;
ASTNode* third;
} NodeIndex;
Literal identifier;
Literal alias;
} NodeExport;
union _node {
ASTNodeType type;
@@ -144,32 +244,23 @@ union _node {
NodeBlock block;
NodeCompound compound;
NodePair pair;
NodeVarDecl varDecl;
NodeFnDecl fnDecl;
NodeFnCollection fnCollection;
NodeFnCall fnCall;
NodePath path;
NodeIncrement increment;
NodeImport import;
NodeIndex index;
NodeVarDecl varDecl;
NodeFnCollection fnCollection;
NodeFnDecl fnDecl;
NodeFnCall fnCall;
NodeFnReturn returns;
NodeIf pathIf; //TODO: rename these to ifStmt?
NodeWhile pathWhile;
NodeFor pathFor;
NodeBreak pathBreak;
NodeContinue pathContinue;
NodePrefixIncrement prefixIncrement;
NodePrefixDecrement prefixDecrement;
NodePostfixIncrement postfixIncrement;
NodePostfixDecrement postfixDecrement;
NodeImport import;
NodeExport export;
};
TOY_API void freeNode(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);
TOY_API void freeASTNode(ASTNode* node);
+39 -36
View File
@@ -10,7 +10,7 @@ static Literal addition(Interpreter* interpreter, Literal lhs, Literal rhs) {
//special case for string concatenation ONLY
if (IS_STRING(lhs) && IS_STRING(rhs)) {
//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) {
interpreter->errorOutput("Can't concatenate these strings (result is too long)\n");
return TO_NULL_LITERAL;
@@ -18,8 +18,9 @@ static Literal addition(Interpreter* interpreter, Literal lhs, Literal rhs) {
//concat the strings
char buffer[MAX_STRING_LENGTH];
snprintf(buffer, MAX_STRING_LENGTH, "%s%s", AS_STRING(lhs), AS_STRING(rhs));
Literal literal = TO_STRING_LITERAL(copyString(buffer, totalLength), totalLength);
snprintf(buffer, MAX_STRING_LENGTH, "%s%s", toCString(AS_STRING(lhs)), toCString(AS_STRING(rhs)));
Literal literal = TO_STRING_LITERAL(createRefStringLength(buffer, totalLength));
freeLiteral(lhs);
freeLiteral(rhs);
@@ -296,35 +297,35 @@ int _index(Interpreter* interpreter, LiteralArray* arguments) {
return 1;
}
else if (!strcmp( AS_STRING(op), "=")) {
else if (equalsRefStringCString(AS_STRING(op), "=")) {
setLiteralDictionary(AS_DICTIONARY(compound), first, assign);
}
else if (!strcmp( AS_STRING(op), "+=")) {
else if (equalsRefStringCString(AS_STRING(op), "+=")) {
Literal lit = addition(interpreter, value, assign);
setLiteralDictionary(AS_DICTIONARY(compound), first, lit);
freeLiteral(lit);
}
else if (!strcmp( AS_STRING(op), "-=")) {
else if (equalsRefStringCString(AS_STRING(op), "-=")) {
Literal lit = subtraction(interpreter, value, assign);
setLiteralDictionary(AS_DICTIONARY(compound), first, lit);
freeLiteral(lit);
}
else if (!strcmp( AS_STRING(op), "*=")) {
else if (equalsRefStringCString(AS_STRING(op), "*=")) {
Literal lit = multiplication(interpreter, value, assign);
setLiteralDictionary(AS_DICTIONARY(compound), first, lit);
freeLiteral(lit);
}
else if (!strcmp( AS_STRING(op), "/=")) {
else if (equalsRefStringCString(AS_STRING(op), "/=")) {
Literal lit = division(interpreter, value, assign);
setLiteralDictionary(AS_DICTIONARY(compound), first, lit);
freeLiteral(lit);
}
else if (!strcmp( AS_STRING(op), "%=")) {
else if (equalsRefStringCString(AS_STRING(op), "%=")) {
Literal lit = modulo(interpreter, value, assign);
setLiteralDictionary(AS_DICTIONARY(compound), first, lit);
freeLiteral(lit);
@@ -440,7 +441,7 @@ int _index(Interpreter* interpreter, LiteralArray* arguments) {
}
//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
if (!IS_NULL(first)) {
if (IS_BOOLEAN(first)) {
@@ -620,31 +621,31 @@ int _index(Interpreter* interpreter, LiteralArray* arguments) {
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);
setLiteralArray(AS_ARRAY(compound), first, 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);
setLiteralArray(AS_ARRAY(compound), first, 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);
setLiteralArray(AS_ARRAY(compound), first, 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);
setLiteralArray(AS_ARRAY(compound), first, 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);
setLiteralArray(AS_ARRAY(compound), first, 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_BOOLEAN(second)) {
freeLiteral(second);
@@ -709,14 +710,14 @@ int _index(Interpreter* interpreter, LiteralArray* arguments) {
}
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];
snprintf(buffer, 16, "%c", c);
freeLiteral(value);
int totalLength = strlen(buffer);
value = TO_STRING_LITERAL(copyString(buffer, totalLength), totalLength);
value = TO_STRING_LITERAL(createRefStringLength(buffer, totalLength));
pushLiteralArray(&interpreter->stack, value);
@@ -754,20 +755,20 @@ int _index(Interpreter* interpreter, LiteralArray* arguments) {
//copy compound into result
int resultIndex = 0;
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';
//finally, swap out the compound for the result
freeLiteral(compound);
compound = TO_STRING_LITERAL(copyString(result, resultIndex), resultIndex);
compound = TO_STRING_LITERAL(createRefStringLength(result, resultIndex));
FREE_ARRAY(char, result, MAX_STRING_LENGTH);
}
//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
if (!IS_NULL(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_BOOLEAN(second)) {
freeLiteral(second);
@@ -823,7 +824,7 @@ int _index(Interpreter* interpreter, LiteralArray* arguments) {
if (IS_NULL(second)) { //assign only a single character
//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
freeLiteral(op);
freeLiteral(assign);
@@ -836,9 +837,11 @@ int _index(Interpreter* interpreter, LiteralArray* arguments) {
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(assign);
@@ -871,18 +874,18 @@ int _index(Interpreter* interpreter, LiteralArray* arguments) {
int resultIndex = 0;
if (AS_INTEGER(third) == 1 || AS_INTEGER(third) == -1) {
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;
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++) {
result[ resultIndex++ ] = AS_STRING(compound)[ i ];
result[ resultIndex++ ] = toCString(AS_STRING(compound))[ i ];
}
result[ resultIndex ] = '\0';
@@ -891,26 +894,26 @@ int _index(Interpreter* interpreter, LiteralArray* arguments) {
//else override elements of the array instead
else {
//copy compound to result
snprintf(result, MAX_STRING_LENGTH, 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 assignIndex = 0;
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);
}
//finally, swap out the compound for the result
freeLiteral(compound);
compound = TO_STRING_LITERAL(copyString(result, resultIndex), resultIndex);
compound = TO_STRING_LITERAL(createRefStringLength(result, resultIndex));
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);
freeLiteral(compound);
compound = tmp; //don't clear tmp
@@ -1229,7 +1232,7 @@ int _pop(Interpreter* interpreter, LiteralArray* arguments) {
int _length(Interpreter* interpreter, LiteralArray* arguments) {
//if wrong number of arguments, fail
if (arguments->count != 1) {
interpreter->errorOutput("Incorrect number of arguments to _get\n");
interpreter->errorOutput("Incorrect number of arguments to _length\n");
return -1;
}
@@ -1257,7 +1260,7 @@ int _length(Interpreter* interpreter, LiteralArray* arguments) {
}
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);
freeLiteral(lit);
break;
+109 -73
View File
@@ -83,7 +83,7 @@ static int writeNodeCompoundToCache(Compiler* compiler, ASTNode* node) {
for (int i = 0; i < node->compound.count; i++) {
//keys
switch(node->compound.nodes[i].pair.left->type) {
case AST_NODELITERAL: {
case AST_NODE_LITERAL: {
//keys are literals
int key = findLiteralIndex(&compiler->literalCache, node->compound.nodes[i].pair.left->atomic.literal);
if (key < 0) {
@@ -96,7 +96,7 @@ static int writeNodeCompoundToCache(Compiler* compiler, ASTNode* node) {
}
break;
case AST_NODECOMPOUND: {
case AST_NODE_COMPOUND: {
int key = writeNodeCompoundToCache(compiler, node->compound.nodes[i].pair.left);
Literal literal = TO_INTEGER_LITERAL(key);
@@ -112,7 +112,7 @@ static int writeNodeCompoundToCache(Compiler* compiler, ASTNode* node) {
//values
switch(node->compound.nodes[i].pair.right->type) {
case AST_NODELITERAL: {
case AST_NODE_LITERAL: {
//values are literals
int val = findLiteralIndex(&compiler->literalCache, node->compound.nodes[i].pair.right->atomic.literal);
if (val < 0) {
@@ -125,7 +125,7 @@ static int writeNodeCompoundToCache(Compiler* compiler, ASTNode* node) {
}
break;
case AST_NODECOMPOUND: {
case AST_NODE_COMPOUND: {
int val = writeNodeCompoundToCache(compiler, node->compound.nodes[i].pair.right);
Literal literal = TO_INTEGER_LITERAL(val);
@@ -150,7 +150,7 @@ static int writeNodeCompoundToCache(Compiler* compiler, ASTNode* node) {
//ensure each literal value is in the cache, individually
for (int i = 0; i < node->compound.count; i++) {
switch(node->compound.nodes[i].type) {
case AST_NODELITERAL: {
case AST_NODE_LITERAL: {
//values
int val = findLiteralIndex(&compiler->literalCache, node->compound.nodes[i].atomic.literal);
if (val < 0) {
@@ -163,7 +163,7 @@ static int writeNodeCompoundToCache(Compiler* compiler, ASTNode* node) {
}
break;
case AST_NODECOMPOUND: {
case AST_NODE_COMPOUND: {
int val = writeNodeCompoundToCache(compiler, &node->compound.nodes[i]);
Literal literal = TO_INTEGER_LITERAL(val);
@@ -197,7 +197,7 @@ static int writeNodeCollectionToCache(Compiler* compiler, ASTNode* node) {
//ensure each literal value is in the cache, individually
for (int i = 0; i < node->fnCollection.count; i++) {
switch(node->fnCollection.nodes[i].type) {
case AST_NODEVAR_DECL: {
case AST_NODE_VAR_DECL: {
//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 typeIndex = writeLiteralTypeToCacheOpt(&compiler->literalCache, node->fnCollection.nodes[i].varDecl.typeLiteral, false);
@@ -212,7 +212,7 @@ static int writeNodeCollectionToCache(Compiler* compiler, ASTNode* node) {
}
break;
case AST_NODELITERAL: {
case AST_NODE_LITERAL: {
//write each piece of the declaration to the cache
int typeIndex = writeLiteralTypeToCacheOpt(&compiler->literalCache, node->fnCollection.nodes[i].atomic.literal, false);
@@ -267,8 +267,8 @@ static int writeLiteralToCompiler(Compiler* compiler, Literal literal) {
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
//NODE: rootNode should NOT include groupings and blocks
//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
//NOTE: rootNode should NOT include groupings and blocks
static Opcode writeCompilerWithJumps(Compiler* compiler, ASTNode* node, void* breakAddressesPtr, void* continueAddressesPtr, int jumpOffsets, ASTNode* rootNode) {
//grow if the bytecode space is too small
if (compiler->count + 32 > compiler->capacity) {
@@ -280,18 +280,18 @@ static Opcode writeCompilerWithJumps(Compiler* compiler, ASTNode* node, void* br
//determine node type
switch(node->type) {
case AST_NODEERROR: {
case AST_NODE_ERROR: {
fprintf(stderr, ERROR "[internal] AST_NODEERROR encountered in writeCompilerWithJumps()\n" RESET);
compiler->bytecode[compiler->count++] = OP_EOF; //1 byte
}
break;
case AST_NODELITERAL: {
case AST_NODE_LITERAL: {
writeLiteralToCompiler(compiler, node->atomic.literal);
}
break;
case AST_NODEUNARY: {
case AST_NODE_UNARY: {
//pass to the child node, then embed the unary command (print, negate, etc.)
Opcode override = writeCompilerWithJumps(compiler, node->unary.child, breakAddressesPtr, continueAddressesPtr, jumpOffsets, rootNode);
@@ -304,7 +304,7 @@ static Opcode writeCompilerWithJumps(Compiler* compiler, ASTNode* node, void* br
break;
//all infixes come here
case AST_NODEBINARY: {
case AST_NODE_BINARY: {
//pass to the child nodes, then embed the binary command (math, etc.)
Opcode override = writeCompilerWithJumps(compiler, node->binary.left, breakAddressesPtr, continueAddressesPtr, jumpOffsets, rootNode);
@@ -324,7 +324,7 @@ static Opcode writeCompilerWithJumps(Compiler* compiler, ASTNode* node, void* br
//return this if...
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;
}
@@ -333,7 +333,7 @@ static Opcode writeCompilerWithJumps(Compiler* compiler, ASTNode* node, void* br
return node->binary.opcode;
}
if (ret != OP_EOF && (node->binary.opcode == OP_AND || node->binary.opcode == OP_OR || (node->binary.opcode >= OP_COMPARE_EQUAL && node->binary.opcode <= OP_INVERT))) {
if (ret != OP_EOF && (node->binary.opcode == OP_VAR_ASSIGN || node->binary.opcode == OP_AND || node->binary.opcode == OP_OR || (node->binary.opcode >= OP_COMPARE_EQUAL && node->binary.opcode <= OP_INVERT))) {
compiler->bytecode[compiler->count++] = (unsigned char)ret; //1 byte
ret = OP_EOF; //untangle in this case
}
@@ -344,7 +344,7 @@ static Opcode writeCompilerWithJumps(Compiler* compiler, ASTNode* node, void* br
}
break;
case AST_NODEGROUPING: {
case AST_NODE_GROUPING: {
compiler->bytecode[compiler->count++] = (unsigned char)OP_GROUPING_BEGIN; //1 byte
Opcode override = writeCompilerWithJumps(compiler, node->grouping.child, breakAddressesPtr, continueAddressesPtr, jumpOffsets, node->grouping.child);
if (override != OP_EOF) {//compensate for indexing & dot notation being screwy
@@ -354,7 +354,7 @@ static Opcode writeCompilerWithJumps(Compiler* compiler, ASTNode* node, void* br
}
break;
case AST_NODEBLOCK: {
case AST_NODE_BLOCK: {
compiler->bytecode[compiler->count++] = (unsigned char)OP_SCOPE_BEGIN; //1 byte
for (int i = 0; i < node->block.count; i++) {
@@ -368,7 +368,7 @@ static Opcode writeCompilerWithJumps(Compiler* compiler, ASTNode* node, void* br
}
break;
case AST_NODECOMPOUND: {
case AST_NODE_COMPOUND: {
int index = writeNodeCompoundToCache(compiler, node);
//push the node opcode to the bytecode
@@ -387,12 +387,12 @@ static Opcode writeCompilerWithJumps(Compiler* compiler, ASTNode* node, void* br
}
break;
case AST_NODEPAIR:
case AST_NODE_PAIR:
fprintf(stderr, ERROR "[internal] AST_NODEPAIR encountered in writeCompilerWithJumps()\n" RESET);
compiler->bytecode[compiler->count++] = OP_EOF; //1 byte
break;
case AST_NODEVAR_DECL: {
case AST_NODE_VAR_DECL: {
//first, embed the expression (leaves it on the stack)
Opcode override = writeCompilerWithJumps(compiler, node->varDecl.expression, breakAddressesPtr, continueAddressesPtr, jumpOffsets, rootNode);
if (override != OP_EOF) {//compensate for indexing & dot notation being screwy
@@ -427,7 +427,7 @@ static Opcode writeCompilerWithJumps(Compiler* compiler, ASTNode* node, void* br
}
break;
case AST_NODEFN_DECL: {
case AST_NODE_FN_DECL: {
//run a compiler over the function
Compiler* fnCompiler = ALLOCATE(Compiler, 1);
initCompiler(fnCompiler);
@@ -471,7 +471,7 @@ static Opcode writeCompilerWithJumps(Compiler* compiler, ASTNode* node, void* br
}
break;
case AST_NODEFN_COLLECTION: {
case AST_NODE_FN_COLLECTION: {
//embed these in the bytecode...
int index = writeNodeCollectionToCache(compiler, node);
@@ -480,12 +480,12 @@ static Opcode writeCompilerWithJumps(Compiler* compiler, ASTNode* node, void* br
}
break;
case AST_NODEFN_CALL: {
case AST_NODE_FN_CALL: {
//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
//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);
if (override != OP_EOF) {//compensate for indexing & dot notation being screwy
compiler->bytecode[compiler->count++] = (unsigned char)override; //1 byte
@@ -540,9 +540,9 @@ static Opcode writeCompilerWithJumps(Compiler* compiler, ASTNode* node, void* br
}
break;
case AST_NODEPATH_IF: {
case AST_NODE_IF: {
//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
compiler->bytecode[compiler->count++] = (unsigned char)override; //1 byte
}
@@ -553,14 +553,14 @@ static Opcode writeCompilerWithJumps(Compiler* compiler, ASTNode* node, void* br
compiler->count += sizeof(unsigned short); //2 bytes
//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
compiler->bytecode[compiler->count++] = (unsigned char)override; //1 byte
}
int jumpToEnd = 0;
if (node->path.elsePath) {
if (node->pathIf.elsePath) {
//insert jump to end
compiler->bytecode[compiler->count++] = OP_JUMP; //1 byte
jumpToEnd = compiler->count;
@@ -570,9 +570,9 @@ static Opcode writeCompilerWithJumps(Compiler* compiler, ASTNode* node, void* br
//update the jumpToElse to point here
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
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
compiler->bytecode[compiler->count++] = (unsigned char)override; //1 byte
}
@@ -583,7 +583,7 @@ static Opcode writeCompilerWithJumps(Compiler* compiler, ASTNode* node, void* br
}
break;
case AST_NODEPATH_WHILE: {
case AST_NODE_WHILE: {
//for breaks and continues
LiteralArray breakAddresses;
LiteralArray continueAddresses;
@@ -595,7 +595,7 @@ static Opcode writeCompilerWithJumps(Compiler* compiler, ASTNode* node, void* br
unsigned short jumpToStart = compiler->count;
//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
compiler->bytecode[compiler->count++] = (unsigned char)override; //1 byte
}
@@ -606,7 +606,7 @@ static Opcode writeCompilerWithJumps(Compiler* compiler, ASTNode* node, void* br
compiler->count += sizeof(unsigned short); //2 bytes
//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
compiler->bytecode[compiler->count++] = (unsigned char)override; //1 byte
}
@@ -639,7 +639,7 @@ static Opcode writeCompilerWithJumps(Compiler* compiler, ASTNode* node, void* br
}
break;
case AST_NODEPATH_FOR: {
case AST_NODE_FOR: {
//for breaks and continues
LiteralArray breakAddresses;
LiteralArray continueAddresses;
@@ -650,14 +650,14 @@ static Opcode writeCompilerWithJumps(Compiler* compiler, ASTNode* node, void* br
compiler->bytecode[compiler->count++] = OP_SCOPE_BEGIN; //1 byte
//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
compiler->bytecode[compiler->count++] = (unsigned char)override; //1 byte
}
//conditional
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
compiler->bytecode[compiler->count++] = (unsigned char)override; //1 byte
}
@@ -669,7 +669,7 @@ static Opcode writeCompilerWithJumps(Compiler* compiler, ASTNode* node, void* br
//write the body
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
compiler->bytecode[compiler->count++] = (unsigned char)override; //1 byte
}
@@ -679,7 +679,7 @@ static Opcode writeCompilerWithJumps(Compiler* compiler, ASTNode* node, void* br
int jumpToIncrement = compiler->count;
//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
compiler->bytecode[compiler->count++] = (unsigned char)override; //1 byte
}
@@ -712,7 +712,7 @@ static Opcode writeCompilerWithJumps(Compiler* compiler, ASTNode* node, void* br
}
break;
case AST_NODEPATH_BREAK: {
case AST_NODE_BREAK: {
if (!breakAddressesPtr) {
fprintf(stderr, ERROR "ERROR: Can't place a break statement here\n" RESET);
break;
@@ -730,7 +730,7 @@ static Opcode writeCompilerWithJumps(Compiler* compiler, ASTNode* node, void* br
}
break;
case AST_NODEPATH_CONTINUE: {
case AST_NODE_CONTINUE: {
if (!continueAddressesPtr) {
fprintf(stderr, ERROR "ERROR: Can't place a continue statement here\n" RESET);
break;
@@ -748,10 +748,10 @@ static Opcode writeCompilerWithJumps(Compiler* compiler, ASTNode* node, void* br
}
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
for (int i = 0; i < node->path.thenPath->fnCollection.count; i++) {
Opcode override = writeCompilerWithJumps(compiler, &node->path.thenPath->fnCollection.nodes[i], breakAddressesPtr, continueAddressesPtr, jumpOffsets, rootNode);
for (int i = 0; i < node->returns.returns->fnCollection.count; i++) {
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
compiler->bytecode[compiler->count++] = (unsigned char)override; //1 byte
}
@@ -760,18 +760,18 @@ static Opcode writeCompilerWithJumps(Compiler* compiler, ASTNode* node, void* br
//push the return, with the number of literals
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);
}
break;
case AST_NODEINCREMENT_PREFIX: {
//push the literal to the stack (twice)
writeLiteralToCompiler(compiler, node->increment.identifier);
writeLiteralToCompiler(compiler, node->increment.identifier);
case AST_NODE_PREFIX_INCREMENT: {
//push the literal to the stack (twice: add + assign)
writeLiteralToCompiler(compiler, node->prefixIncrement.identifier);
writeLiteralToCompiler(compiler, node->prefixIncrement.identifier);
//push the increment / decrement
Literal increment = TO_INTEGER_LITERAL(node->increment.increment);
Literal increment = TO_INTEGER_LITERAL(1);
writeLiteralToCompiler(compiler, increment);
//push the add opcode
@@ -781,22 +781,43 @@ static Opcode writeCompilerWithJumps(Compiler* compiler, ASTNode* node, void* br
compiler->bytecode[compiler->count++] = (unsigned char)OP_VAR_ASSIGN; //1 byte
//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
}
break;
case AST_NODEINCREMENT_POSTFIX: {
//push the identifier's VALUE to the stack
writeLiteralToCompiler(compiler, node->increment.identifier);
compiler->bytecode[compiler->count++] = (unsigned char)OP_LITERAL_RAW; //1 byte
//push the identifier (twice)
writeLiteralToCompiler(compiler, node->increment.identifier);
writeLiteralToCompiler(compiler, node->increment.identifier);
case AST_NODE_PREFIX_DECREMENT: {
//push the literal to the stack (twice: add + assign)
writeLiteralToCompiler(compiler, node->prefixDecrement.identifier);
writeLiteralToCompiler(compiler, node->prefixDecrement.identifier);
//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);
//push the add opcode
@@ -807,7 +828,28 @@ static Opcode writeCompilerWithJumps(Compiler* compiler, ASTNode* node, void* br
}
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
writeLiteralToCompiler(compiler, node->import.identifier);
writeLiteralToCompiler(compiler, node->import.alias);
@@ -817,7 +859,7 @@ static Opcode writeCompilerWithJumps(Compiler* compiler, ASTNode* node, void* br
}
break;
case AST_NODEEXPORT: {
case AST_NODE_EXPORT: {
//push the identifier, and the alias
writeLiteralToCompiler(compiler, node->import.identifier);
writeLiteralToCompiler(compiler, node->import.alias);
@@ -827,7 +869,7 @@ static Opcode writeCompilerWithJumps(Compiler* compiler, ASTNode* node, void* br
}
break;
case AST_NODEINDEX: {
case AST_NODE_INDEX: {
//pass to the child nodes, then embed the opcode
//first
@@ -868,12 +910,6 @@ static Opcode writeCompilerWithJumps(Compiler* compiler, ASTNode* node, void* br
return OP_INDEX_ASSIGN; //override binary's instruction IF it is assign
}
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;
@@ -1006,8 +1042,8 @@ static unsigned char* collateCompilerHeaderOpt(Compiler* compiler, int* size, bo
Literal str = compiler->literalCache.literals[i];
for (int c = 0; c < (int)strlen(AS_STRING(str)); c++) {
emitByte(&collation, &capacity, &count, AS_STRING(str)[c]);
for (int c = 0; c < AS_STRING(str)->length; c++) {
emitByte(&collation, &capacity, &count, toCString(AS_STRING(str))[c]);
}
emitByte(&collation, &capacity, &count, '\0'); //terminate the string
@@ -1078,8 +1114,8 @@ static unsigned char* collateCompilerHeaderOpt(Compiler* compiler, int* size, bo
Literal identifier = compiler->literalCache.literals[i];
for (int c = 0; c < (int)strlen(AS_IDENTIFIER(identifier)); c++) {
emitByte(&collation, &capacity, &count, AS_IDENTIFIER(identifier)[c]);
for (int c = 0; c < AS_IDENTIFIER(identifier)->length; c++) {
emitByte(&collation, &capacity, &count, toCString(AS_IDENTIFIER(identifier))[c]);
}
emitByte(&collation, &capacity, &count, '\0'); //terminate the string
+1 -1
View File
@@ -1,6 +1,6 @@
#pragma once
#include "common.h"
#include "toy_common.h"
#include "opcodes.h"
#include "ast_node.h"
#include "literal_array.h"
+28 -26
View File
@@ -1,7 +1,7 @@
#include "interpreter.h"
#include "console_colors.h"
#include "common.h"
#include "toy_common.h"
#include "memory.h"
#include "keyword_types.h"
#include "opcodes.h"
@@ -34,7 +34,7 @@ bool injectNativeFn(Interpreter* interpreter, char* name, NativeFn func) {
}
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
if (existsLiteralDictionary(&interpreter->scope->variables, identifier)) {
@@ -64,7 +64,7 @@ bool injectNativeHook(Interpreter* interpreter, char* name, HookFn hook) {
}
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
if (existsLiteralDictionary(interpreter->hooks, identifier)) {
@@ -235,7 +235,7 @@ static bool execAssert(Interpreter* interpreter) {
}
if (IS_NULL(lhs) || !IS_TRUTHY(lhs)) {
(*interpreter->assertOutput)(AS_STRING(rhs));
(*interpreter->assertOutput)(toCString(AS_STRING(rhs)));
freeLiteral(rhs);
interpreter->panic = true;
return false;
@@ -320,7 +320,7 @@ static bool execNegate(Interpreter* interpreter) {
lit = TO_FLOAT_LITERAL(-AS_FLOAT(lit));
}
else {
interpreter->errorOutput("[internal] The interpreter can't negate that literal: ");
interpreter->errorOutput("Can't negate that literal: ");
printLiteralCustom(lit, interpreter->errorOutput);
interpreter->errorOutput("\n");
@@ -352,7 +352,7 @@ static bool execInvert(Interpreter* interpreter) {
lit = TO_BOOLEAN_LITERAL(!AS_BOOLEAN(lit));
}
else {
interpreter->errorOutput("[internal] The interpreter can't invert that literal: ");
interpreter->errorOutput("Can't invert that literal: ");
printLiteralCustom(lit, interpreter->errorOutput);
interpreter->errorOutput("\n");
@@ -387,7 +387,7 @@ static bool execArithmetic(Interpreter* interpreter, Opcode opcode) {
//special case for string concatenation ONLY
if (IS_STRING(lhs) && IS_STRING(rhs)) {
//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) {
interpreter->errorOutput("Can't concatenate these strings (result is too long)\n");
return false;
@@ -395,9 +395,11 @@ static bool execArithmetic(Interpreter* interpreter, Opcode opcode) {
//concat the strings
char buffer[MAX_STRING_LENGTH];
snprintf(buffer, MAX_STRING_LENGTH, "%s%s", AS_STRING(lhs), AS_STRING(rhs));
Literal literal = TO_STRING_LITERAL( copyString(buffer, totalLength), totalLength);
snprintf(buffer, MAX_STRING_LENGTH, "%s%s", toCString(AS_STRING(lhs)), toCString(AS_STRING(rhs)));
Literal literal = TO_STRING_LITERAL(createRefStringLength(buffer, totalLength));
pushLiteralArray(&interpreter->stack, literal);
//cleanup
freeLiteral(literal);
freeLiteral(lhs);
freeLiteral(rhs);
@@ -751,7 +753,7 @@ static bool execValCast(Interpreter* interpreter) {
if (IS_STRING(value)) {
int val = 0;
sscanf(AS_STRING(value), "%d", &val);
sscanf(toCString(AS_STRING(value)), "%d", &val);
result = TO_INTEGER_LITERAL(val);
}
break;
@@ -771,7 +773,7 @@ static bool execValCast(Interpreter* interpreter) {
if (IS_STRING(value)) {
float val = 0;
sscanf(AS_STRING(value), "%f", &val);
sscanf(toCString(AS_STRING(value)), "%f", &val);
result = TO_FLOAT_LITERAL(val);
}
break;
@@ -781,21 +783,21 @@ static bool execValCast(Interpreter* interpreter) {
char* str = AS_BOOLEAN(value) ? "true" : "false";
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)) {
char buffer[128];
snprintf(buffer, 128, "%d", AS_INTEGER(value));
int length = strlen(buffer);
result = TO_STRING_LITERAL(copyString(buffer, length), length);
result = TO_STRING_LITERAL(createRefStringLength(buffer, length));
}
if (IS_FLOAT(value)) {
char buffer[128];
snprintf(buffer, 128, "%g", AS_FLOAT(value));
int length = strlen(buffer);
result = TO_STRING_LITERAL(copyString(buffer, length), length);
result = TO_STRING_LITERAL(createRefStringLength(buffer, length));
}
if (IS_STRING(value)) {
@@ -1143,12 +1145,12 @@ static bool execFnCall(Interpreter* interpreter, bool looseFirstArgument) {
//let's screw with the fn name, too
if (looseFirstArgument) {
int length = strlen(AS_IDENTIFIER(identifier)) + 1;
int length = AS_IDENTIFIER(identifier)->length + 1;
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);
identifier = TO_IDENTIFIER_LITERAL(copyString(buffer, length), length);
identifier = TO_IDENTIFIER_LITERAL(createRefStringLength(buffer, length));
}
Literal func = identifier;
@@ -1219,7 +1221,7 @@ bool callLiteralFn(Interpreter* interpreter, Literal func, LiteralArray* argumen
initLiteralArray(&inner.literalCache);
inner.scope = pushScope(func.as.function.scope);
inner.bytecode = AS_FUNCTION(func).bytecode;
inner.length = func.as.function.length;
inner.length = AS_FUNCTION(func).length;
inner.count = 0;
inner.codeStart = -1;
inner.depth = interpreter->depth + 1;
@@ -1414,7 +1416,7 @@ bool callLiteralFn(Interpreter* interpreter, Literal func, LiteralArray* argumen
}
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;
if (!isDelcaredScopeVariable(interpreter->scope, key)) {
@@ -1605,7 +1607,7 @@ static bool execIndex(Interpreter* interpreter, bool assignIntermediate) {
Literal func = TO_NULL_LITERAL;
char* keyStr = "_index";
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)) {
interpreter->errorOutput("couldn't get the _index function\n");
@@ -1704,7 +1706,7 @@ static bool execIndexAssign(Interpreter* interpreter) {
Literal func = TO_NULL_LITERAL;
char* keyStr = "_index";
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)) {
interpreter->errorOutput("couldn't get the _index function\n");
@@ -1760,7 +1762,7 @@ static bool execIndexAssign(Interpreter* interpreter) {
}
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
LiteralArray arguments;
@@ -1815,7 +1817,7 @@ static bool execIndexAssign(Interpreter* interpreter) {
char* opStr = "="; //shadow, but force assignment
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
pushLiteralArray(&arguments, idn);
@@ -2194,7 +2196,7 @@ static void readInterpreterSections(Interpreter* interpreter) {
case LITERAL_STRING: {
char* s = readString(interpreter->bytecode, &interpreter->count);
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);
freeLiteral(literal);
@@ -2290,13 +2292,13 @@ static void readInterpreterSections(Interpreter* interpreter) {
char* str = readString(interpreter->bytecode, &interpreter->count);
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);
#ifndef TOY_EXPORT
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
+1 -1
View File
@@ -1,6 +1,6 @@
#pragma once
#include "common.h"
#include "toy_common.h"
#include "literal.h"
#include "literal_array.h"
#include "literal_dictionary.h"
+1 -1
View File
@@ -1,6 +1,6 @@
#include "keyword_types.h"
#include "common.h"
#include "toy_common.h"
#include <string.h>
+1 -1
View File
@@ -1,6 +1,6 @@
#pragma once
#include "common.h"
#include "toy_common.h"
#include "token_types.h"
//lexers are bound to a string of code, and return a single token every time scan is called
+28 -36
View File
@@ -15,13 +15,13 @@ static unsigned int hashString(const char* string, int length) {
for (int i = 0; i < length; i++) {
hash *= string[i];
hash *= 16777619;
hash ^= 16777619;
}
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;
@@ -30,11 +30,18 @@ static unsigned int hash(unsigned int x) {
//exposed functions
void freeLiteral(Literal literal) {
//refstrings
if (IS_STRING(literal)) {
FREE_ARRAY(char, AS_STRING(literal), literal.as.string.length + 1);
deleteRefString(AS_STRING(literal));
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) {
freeLiteralArray(AS_ARRAY(literal));
FREE(LiteralArray, AS_ARRAY(literal));
@@ -47,17 +54,13 @@ void freeLiteral(Literal literal) {
return;
}
//complex literals
if (IS_FUNCTION(literal)) {
popScope(AS_FUNCTION(literal).scope);
AS_FUNCTION(literal).scope = NULL;
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)) {
for (int i = 0; i < AS_TYPE(literal).count; i++) {
freeLiteral(((Literal*)(AS_TYPE(literal).subtypes))[i]);
@@ -80,12 +83,12 @@ bool _isTruthy(Literal x) {
return true;
}
Literal _toStringLiteral(char* str, int length) {
return ((Literal){LITERAL_STRING, { .string.ptr = (char*)str, .string.length = length }});
Literal _toStringLiteral(RefString* ptr) {
return ((Literal){LITERAL_STRING, { .string.ptr = ptr }});
}
Literal _toIdentifierLiteral(char* str, int length) {
return ((Literal){LITERAL_IDENTIFIER,{ .identifier.ptr = (char*)str, .identifier.length = length, .identifier.hash = hashString(str, length) }});
Literal _toIdentifierLiteral(RefString* ptr) {
return ((Literal){LITERAL_IDENTIFIER,{ .identifier.ptr = ptr, .identifier.hash = hashString(toCString(ptr), lengthRefString(ptr)) }});
}
Literal* _typePushSubtype(Literal* lit, Literal subtype) {
@@ -112,7 +115,7 @@ Literal copyLiteral(Literal original) {
return original;
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: {
@@ -152,7 +155,7 @@ Literal copyLiteral(Literal original) {
}
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: {
@@ -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) {
//utility for other things
if (lhs.type != rhs.type) {
@@ -250,10 +245,7 @@ bool literalsAreEqual(Literal lhs, Literal rhs) {
return AS_FLOAT(lhs) == AS_FLOAT(rhs);
case LITERAL_STRING:
if (lhs.as.string.length != rhs.as.string.length) {
return false;
}
return !strncmp(AS_STRING(lhs), AS_STRING(rhs), lhs.as.string.length);
return equalsRefString(AS_STRING(lhs), AS_STRING(rhs));
case LITERAL_ARRAY:
case LITERAL_DICTIONARY_INTERMEDIATE: //BUGFIX
@@ -299,11 +291,11 @@ bool literalsAreEqual(Literal lhs, Literal rhs) {
case LITERAL_IDENTIFIER:
//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 !strncmp(AS_IDENTIFIER(lhs), AS_IDENTIFIER(rhs), lhs.as.identifier.length);
return equalsRefString(AS_IDENTIFIER(lhs), AS_IDENTIFIER(rhs));
case LITERAL_TYPE:
//check types
@@ -359,20 +351,20 @@ int hashLiteral(Literal lit) {
return AS_BOOLEAN(lit) ? 1 : 0;
case LITERAL_INTEGER:
return hash((unsigned int)AS_INTEGER(lit));
return hashUInt((unsigned int)AS_INTEGER(lit));
case LITERAL_FLOAT:
return hash(*(unsigned int*)(&AS_FLOAT(lit)));
return hashUInt(*(unsigned int*)(&AS_FLOAT(lit)));
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: {
unsigned int res = 0;
for (int i = 0; i < AS_ARRAY(lit)->count; i++) {
res += hashLiteral(AS_ARRAY(lit)->literals[i]);
}
return hash(res);
return hashUInt(res);
}
case LITERAL_DICTIONARY: {
@@ -383,7 +375,7 @@ int hashLiteral(Literal lit) {
res += hashLiteral(AS_DICTIONARY(lit)->entries[i].value);
}
}
return hash(res);
return hashUInt(res);
}
case LITERAL_FUNCTION:
@@ -464,10 +456,10 @@ void printLiteralCustom(Literal literal, void (printFn)(const char*)) {
case LITERAL_STRING: {
char buffer[MAX_STRING_LENGTH];
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 {
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);
}
@@ -573,7 +565,7 @@ void printLiteralCustom(Literal literal, void (printFn)(const char*)) {
case LITERAL_IDENTIFIER: {
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);
}
break;
+11 -11
View File
@@ -1,6 +1,8 @@
#pragma once
#include "common.h"
#include "toy_common.h"
#include "refstring.h"
#include <string.h>
@@ -33,8 +35,8 @@ typedef struct {
int integer;
float number;
struct {
char* ptr;
int length;
RefString* ptr;
//string hash?
} string;
void* array;
@@ -47,8 +49,7 @@ typedef struct {
} function;
struct { //for variable names
char* ptr;
int length;
RefString* ptr;
int hash;
} identifier;
@@ -62,7 +63,7 @@ typedef struct {
struct {
void* ptr;
int tag;
int tag; //TODO: remove tags?
} opaque;
} as;
} Literal;
@@ -95,11 +96,11 @@ typedef struct {
#define TO_BOOLEAN_LITERAL(value) ((Literal){LITERAL_BOOLEAN, { .boolean = value }})
#define TO_INTEGER_LITERAL(value) ((Literal){LITERAL_INTEGER, { .integer = 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_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_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_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
TOY_API bool _isTruthy(Literal x);
TOY_API Literal _toStringLiteral(char* str, int length);
TOY_API Literal _toIdentifierLiteral(char* str, int length);
TOY_API Literal _toStringLiteral(RefString* ptr);
TOY_API Literal _toIdentifierLiteral(RefString* ptr);
TOY_API Literal* _typePushSubtype(Literal* lit, Literal subtype);
//utils
TOY_API Literal copyLiteral(Literal original);
TOY_API char* copyString(char* original, int length);
TOY_API bool literalsAreEqual(Literal lhs, Literal rhs);
TOY_API int hashLiteral(Literal lit);
+1 -1
View File
@@ -1,6 +1,6 @@
#pragma once
#include "common.h"
#include "toy_common.h"
#include "literal.h"
+1 -1
View File
@@ -1,6 +1,6 @@
#pragma once
#include "common.h"
#include "toy_common.h"
#include "literal.h"
+6
View File
@@ -34,6 +34,12 @@ library: $(OBJ)
static: $(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)
$(ODIR):
+31 -2
View File
@@ -1,11 +1,13 @@
#include "memory.h"
#include "refstring.h"
#include "console_colors.h"
#include <stdio.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) {
//causes issues, so just skip out with a NO-OP
return NULL;
@@ -20,10 +22,37 @@ void* reallocate(void* pointer, size_t oldSize, size_t newSize) {
void* mem = realloc(pointer, newSize);
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);
}
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);
}
+5 -1
View File
@@ -1,6 +1,6 @@
#pragma once
#include "common.h"
#include "toy_common.h"
#define ALLOCATE(type, count) ((type*)reallocate(NULL, 0, sizeof(type) * (count)))
#define FREE(type, pointer) reallocate(pointer, sizeof(type), 0)
@@ -10,5 +10,9 @@
#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)
//implementation details
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);
+92 -109
View File
@@ -1,7 +1,5 @@
#include "parser.h"
#include "common.h"
#include "memory.h"
#include "literal.h"
#include "opcodes.h"
@@ -121,6 +119,7 @@ static void declaration(Parser* parser, ASTNode** nodeHandle);
static void parsePrecedence(Parser* parser, ASTNode** nodeHandle, PrecedenceRule rule);
static Literal readTypeToLiteral(Parser* parser);
//TODO: resolve the messy order of these
//the expression rules
static Opcode asType(Parser* parser, ASTNode** nodeHandle) {
Literal literal = readTypeToLiteral(parser);
@@ -184,14 +183,14 @@ static Opcode compound(Parser* parser, ASTNode** nodeHandle) {
parsePrecedence(parser, &right, PREC_PRIMARY);
if (!right) { //error
freeNode(left);
freeASTNode(left);
return OP_EOF;
}
//check we ARE defining a dictionary
if (array) {
error(parser, parser->previous, "Incorrect detection between array and dictionary");
freeNode(array);
freeASTNode(array);
return OP_EOF;
}
@@ -216,7 +215,7 @@ static Opcode compound(Parser* parser, ASTNode** nodeHandle) {
//check we ARE defining an array
if (dictionary) {
error(parser, parser->current, "Incorrect detection between array and dictionary");
freeNode(dictionary);
freeASTNode(dictionary);
return OP_EOF;
}
@@ -271,7 +270,7 @@ static Opcode string(Parser* parser, ASTNode** nodeHandle) {
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);
freeLiteral(literal);
return OP_EOF;
@@ -420,7 +419,7 @@ static Opcode unary(Parser* parser, ASTNode** nodeHandle) {
parsePrecedence(parser, &tmpNode, PREC_TERNARY); //can be a literal
//check for negative literals (optimisation)
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
Literal lit = tmpNode->atomic.literal;
@@ -439,22 +438,22 @@ static Opcode unary(Parser* parser, ASTNode** nodeHandle) {
}
//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");
return OP_EOF;
}
//actually emit the negation
//actually emit the negation node
emitASTNodeUnary(nodeHandle, OP_NEGATE, tmpNode);
}
else if (parser->previous.type == TOKEN_NOT) {
//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
if (tmpNode->type == AST_NODELITERAL && IS_BOOLEAN(tmpNode->atomic.literal)) {
//negate directly, if int or float
if (tmpNode->type == AST_NODE_LITERAL && IS_BOOLEAN(tmpNode->atomic.literal)) {
//negate directly, if boolean
Literal lit = tmpNode->atomic.literal;
lit = TO_BOOLEAN_LITERAL(!AS_BOOLEAN(lit));
@@ -465,12 +464,6 @@ static Opcode unary(Parser* parser, ASTNode** nodeHandle) {
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
emitASTNodeUnary(nodeHandle, OP_INVERT, tmpNode);
}
@@ -545,12 +538,9 @@ static Opcode identifier(Parser* parser, ASTNode** nodeHandle) {
error(parser, parser->previous, "Identifiers can only be a maximum of 256 characters long");
}
char* cpy = copyString(identifierToken.lexeme, length);
Literal identifier = _toIdentifierLiteral(cpy, length); //BUGFIX: use this instead of the macro
Literal identifier = TO_IDENTIFIER_LITERAL(createRefStringLength(identifierToken.lexeme, length));
emitASTNodeLiteral(nodeHandle, identifier);
freeLiteral(identifier); //don't leave it hanging
freeLiteral(identifier);
return OP_EOF;
}
@@ -596,6 +586,7 @@ static Opcode castingPrefix(Parser* parser, ASTNode** nodeHandle) {
static Opcode castingInfix(Parser* parser, ASTNode** nodeHandle) {
advance(parser);
//NOTE: using the precedence rules here
switch(parser->previous.type) {
case TOKEN_IDENTIFIER:
identifier(parser, nodeHandle);
@@ -626,28 +617,29 @@ static Opcode castingInfix(Parser* parser, ASTNode** nodeHandle) {
return OP_TYPE_CAST;
}
//TODO: fix these screwy names
static Opcode incrementPrefix(Parser* parser, ASTNode** nodeHandle) {
advance(parser);
ASTNode* node = NULL;
identifier(parser, &node);
ASTNode* tmpNode = NULL;
identifier(parser, &tmpNode);
emitASTNodePrefixIncrement(nodeHandle, node->atomic.literal, 1);
emitASTNodePrefixIncrement(nodeHandle, tmpNode->atomic.literal);
freeNode(node);
freeASTNode(tmpNode);
return OP_EOF;
}
static Opcode incrementInfix(Parser* parser, ASTNode** nodeHandle) {
ASTNode* node = NULL;
identifier(parser, &node);
ASTNode* tmpNode = NULL;
identifier(parser, &tmpNode);
advance(parser);
emitASTNodePostfixIncrement(nodeHandle, node->atomic.literal, 1);
emitASTNodePostfixIncrement(nodeHandle, tmpNode->atomic.literal);
freeNode(node);
freeASTNode(tmpNode);
return OP_EOF;
}
@@ -655,25 +647,25 @@ static Opcode incrementInfix(Parser* parser, ASTNode** nodeHandle) {
static Opcode decrementPrefix(Parser* parser, ASTNode** nodeHandle) {
advance(parser);
ASTNode* node = NULL;
identifier(parser, &node); //weird
ASTNode* tmpNode = NULL;
identifier(parser, &tmpNode); //weird
emitASTNodePrefixIncrement(nodeHandle, node->atomic.literal, -1);
emitASTNodePrefixDecrement(nodeHandle, tmpNode->atomic.literal);
freeNode(node);
freeASTNode(tmpNode);
return OP_EOF;
}
static Opcode decrementInfix(Parser* parser, ASTNode** nodeHandle) {
ASTNode* node = NULL;
identifier(parser, &node);
ASTNode* tmpNode = NULL;
identifier(parser, &tmpNode);
advance(parser);
emitASTNodePostfixIncrement(nodeHandle, node->atomic.literal, -1);
emitASTNodePostfixDecrement(nodeHandle, tmpNode->atomic.literal);
freeNode(node);
freeASTNode(tmpNode);
return OP_EOF;
}
@@ -700,17 +692,17 @@ static Opcode fnCall(Parser* parser, ASTNode** nodeHandle) {
arguments->fnCollection.nodes = GROW_ARRAY(ASTNode, arguments->fnCollection.nodes, oldCapacity, arguments->fnCollection.capacity);
}
ASTNode* node = NULL;
parsePrecedence(parser, &node, PREC_TERNARY);
arguments->fnCollection.nodes[arguments->fnCollection.count++] = *node;
FREE(ASTNode, node);
ASTNode* tmpNode = NULL;
parsePrecedence(parser, &tmpNode, PREC_TERNARY);
arguments->fnCollection.nodes[arguments->fnCollection.count++] = *tmpNode;
FREE(ASTNode, tmpNode); //simply free the tmpNode, so you don't free the children
} while(match(parser, TOKEN_COMMA));
consume(parser, TOKEN_PAREN_RIGHT, "Expected ')' at end of argument list");
}
//emit the call
emitASTFnCall(nodeHandle, arguments, arguments->fnCollection.count);
emitASTNodeFnCall(nodeHandle, arguments);
return OP_FN_CALL;
}
@@ -724,7 +716,7 @@ static Opcode fnCall(Parser* parser, ASTNode** nodeHandle) {
return OP_EOF;
}
static Opcode indexAccess(Parser* parser, ASTNode** nodeHandle) {
static Opcode indexAccess(Parser* parser, ASTNode** nodeHandle) { //TODO: fix indexing signalling
advance(parser);
//val[first : second : third]
@@ -742,7 +734,7 @@ static Opcode indexAccess(Parser* parser, ASTNode** nodeHandle) {
//eat the first
if (!match(parser, TOKEN_COLON)) {
freeNode(first);
freeASTNode(first);
parsePrecedence(parser, &first, PREC_TERNARY);
match(parser, TOKEN_COLON);
readFirst = true;
@@ -751,11 +743,11 @@ static Opcode indexAccess(Parser* parser, ASTNode** nodeHandle) {
if (match(parser, TOKEN_BRACKET_RIGHT)) {
if (readFirst) {
freeNode(second);
freeASTNode(second);
second = NULL;
}
freeNode(third);
freeASTNode(third);
third = NULL;
emitASTNodeIndex(nodeHandle, first, second, third);
@@ -764,20 +756,20 @@ static Opcode indexAccess(Parser* parser, ASTNode** nodeHandle) {
//eat the second
if (!match(parser, TOKEN_COLON)) {
freeNode(second);
freeASTNode(second);
parsePrecedence(parser, &second, PREC_TERNARY);
match(parser, TOKEN_COLON);
}
if (match(parser, TOKEN_BRACKET_RIGHT)) {
freeNode(third);
freeASTNode(third);
third = NULL;
emitASTNodeIndex(nodeHandle, first, second, third);
return OP_INDEX;
}
//eat the third
freeNode(third);
freeASTNode(third);
parsePrecedence(parser, &third, PREC_TERNARY);
emitASTNodeIndex(nodeHandle, first, second, third);
@@ -789,22 +781,15 @@ static Opcode indexAccess(Parser* parser, ASTNode** nodeHandle) {
static Opcode dot(Parser* parser, ASTNode** nodeHandle) {
advance(parser); //for the dot
ASTNode* node = NULL;
ASTNode* tmpNode = NULL;
parsePrecedence(parser, &tmpNode, PREC_CALL);
parsePrecedence(parser, &node, PREC_CALL);
if (node == NULL || node->binary.right == NULL) {
if (tmpNode == NULL || tmpNode->binary.right == NULL) {
error(parser, parser->previous, "Expected function call after dot operator");
return OP_EOF;
}
//hijack the function call, and hack in an extra parameter
if (node->binary.opcode == OP_FN_CALL) {
node->binary.right->fnCall.argumentCount++;
node->binary.opcode = OP_DOT;
}
(*nodeHandle) = node;
(*nodeHandle) = tmpNode;
return OP_DOT; //signal that the function name and arguments are in the wrong order
}
@@ -903,7 +888,7 @@ ParseRule* getRule(TokenType type) {
return &parseRules[type];
}
//constant folding
//constant folding (optimisation)
static bool calcStaticBinaryArithmetic(Parser* parser, ASTNode** nodeHandle) {
switch((*nodeHandle)->binary.opcode) {
case OP_ADDITION:
@@ -924,16 +909,16 @@ static bool calcStaticBinaryArithmetic(Parser* parser, ASTNode** nodeHandle) {
}
//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);
}
if ((*nodeHandle)->binary.right->type == AST_NODEBINARY) {
if ((*nodeHandle)->binary.right->type == AST_NODE_BINARY) {
calcStaticBinaryArithmetic(parser, &(*nodeHandle)->binary.right);
}
//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;
}
@@ -1076,20 +1061,21 @@ static bool calcStaticBinaryArithmetic(Parser* parser, ASTNode** nodeHandle) {
}
//optimize by converting this node into a literal node
freeNode((*nodeHandle)->binary.left);
freeNode((*nodeHandle)->binary.right);
freeASTNode((*nodeHandle)->binary.left);
freeASTNode((*nodeHandle)->binary.right);
(*nodeHandle)->type = AST_NODELITERAL;
(*nodeHandle)->type = AST_NODE_LITERAL;
(*nodeHandle)->atomic.literal = result;
return true;
}
static void dottify(Parser* parser, ASTNode** nodeHandle) {
//only if this is chained from a higher binary "fn_call"
if ((*nodeHandle)->type == AST_NODEBINARY) {
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"
if ((*nodeHandle)->type == AST_NODE_BINARY) {
if ((*nodeHandle)->binary.opcode == OP_FN_CALL) {
(*nodeHandle)->binary.opcode = OP_DOT;
(*nodeHandle)->binary.right->fnCall.argumentCount++;
}
dottify(parser, &(*nodeHandle)->binary.left);
dottify(parser, &(*nodeHandle)->binary.right);
@@ -1124,7 +1110,7 @@ static void parsePrecedence(Parser* parser, ASTNode** nodeHandle, PrecedenceRule
const Opcode opcode = infixRule(parser, &rhsNode); //NOTE: infix rule must advance the parser
if (opcode == OP_EOF) {
freeNode(*nodeHandle);
freeASTNode(*nodeHandle);
*nodeHandle = rhsNode;
return; //we're done here
}
@@ -1136,6 +1122,7 @@ static void parsePrecedence(Parser* parser, ASTNode** nodeHandle, PrecedenceRule
emitASTNodeBinary(nodeHandle, rhsNode, opcode);
//optimise away the constants
if (!calcStaticBinaryArithmetic(parser, nodeHandle)) {
return;
}
@@ -1167,19 +1154,19 @@ static void blockStmt(Parser* parser, ASTNode** nodeHandle) {
(*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
declaration(parser, &node);
declaration(parser, &tmpNode);
// Ground floor: perfumery / Stationery and leather goods / Wigs and haberdashery / Kitchenware and food / Going up!
if (parser->panic) {
return;
}
//BUGFIX: statements no longer require an existing node
((*nodeHandle)->block.nodes[(*nodeHandle)->block.count++]) = *node;
FREE(ASTNode, node); //simply free the tmp node
//BUGFIX: statements no longer require the existing node
((*nodeHandle)->block.nodes[(*nodeHandle)->block.count++]) = *tmpNode;
FREE(ASTNode, tmpNode); //simply free the tmpNode, so you don't free the children
}
}
@@ -1195,7 +1182,7 @@ static void printStmt(Parser* parser, ASTNode** nodeHandle) {
static void assertStmt(Parser* parser, ASTNode** nodeHandle) {
//set the node info
(*nodeHandle) = ALLOCATE(ASTNode, 1); //special case, because I'm lazy
(*nodeHandle)->type = AST_NODEBINARY;
(*nodeHandle)->type = AST_NODE_BINARY;
(*nodeHandle)->binary.opcode = OP_ASSERT;
parsePrecedence(parser, &((*nodeHandle)->binary.left), PREC_TERNARY);
@@ -1223,7 +1210,7 @@ static void ifStmt(Parser* parser, ASTNode** nodeHandle) {
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) {
@@ -1238,40 +1225,40 @@ static void whileStmt(Parser* parser, ASTNode** nodeHandle) {
consume(parser, TOKEN_PAREN_RIGHT, "Expected ')' at end of while clause");
declaration(parser, &thenPath);
emitASTNodePath(nodeHandle, AST_NODEPATH_WHILE, NULL, NULL, condition, thenPath, NULL);
emitASTNodeWhile(nodeHandle, condition, thenPath);
}
static void forStmt(Parser* parser, ASTNode** nodeHandle) {
ASTNode* preClause = NULL;
ASTNode* postClause = NULL;
ASTNode* condition = NULL;
ASTNode* postClause = NULL;
ASTNode* thenPath = NULL;
//read the clauses
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);
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");
//read the path
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) {
emitASTNodePath(nodeHandle, AST_NODEPATH_BREAK, NULL, NULL, NULL, NULL, NULL);
emitASTNodeBreak(nodeHandle);
consume(parser, TOKEN_SEMICOLON, "Expected ';' at end of break statement");
}
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");
}
@@ -1294,13 +1281,13 @@ static void returnStmt(Parser* parser, ASTNode** nodeHandle) {
parsePrecedence(parser, &node, PREC_TERNARY);
returnValues->fnCollection.nodes[returnValues->fnCollection.count++] = *node;
FREE(ASTNode, node);
FREE(ASTNode, node); //free manually
} while(match(parser, TOKEN_COMMA));
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) {
@@ -1314,18 +1301,19 @@ static void importStmt(Parser* parser, ASTNode** nodeHandle) {
}
Literal idn = copyLiteral(node->atomic.literal);
freeNode(node);
freeASTNode(node);
Literal alias = TO_NULL_LITERAL;
if (match(parser, TOKEN_AS)) {
ASTNode* node = NULL;
advance(parser);
identifier(parser, &node);
alias = copyLiteral(node->atomic.literal);
freeNode(node);
freeASTNode(node);
}
emitASTNodeImport(nodeHandle, AST_NODEIMPORT, idn, alias);
emitASTNodeImport(nodeHandle, idn, alias);
consume(parser, TOKEN_SEMICOLON, "Expected ';' at end of import statement");
@@ -1344,18 +1332,19 @@ static void exportStmt(Parser* parser, ASTNode** nodeHandle) {
}
Literal idn = copyLiteral(node->atomic.literal);
freeNode(node);
freeASTNode(node);
Literal alias = TO_NULL_LITERAL;
if (match(parser, TOKEN_AS)) {
ASTNode* node;
advance(parser);
identifier(parser, &node);
alias = copyLiteral(node->atomic.literal);
freeNode(node);
freeASTNode(node);
}
emitASTNodeImport(nodeHandle, AST_NODEEXPORT, idn, alias);
emitASTNodeExport(nodeHandle, idn, alias);
consume(parser, TOKEN_SEMICOLON, "Expected ';' at end of export statement");
@@ -1523,8 +1512,7 @@ static Literal readTypeToLiteral(Parser* parser) {
length = 256;
error(parser, parser->previous, "Identifiers can only be a maximum of 256 characters long");
}
char* cpy = copyString(identifierToken.lexeme, length);
literal = _toIdentifierLiteral(cpy, strlen(cpy)); //BUGFIX: use this instead of the macro
literal = TO_IDENTIFIER_LITERAL(createRefStringLength(identifierToken.lexeme, length));
}
break;
@@ -1559,8 +1547,7 @@ static void varDecl(Parser* parser, ASTNode** nodeHandle) {
error(parser, parser->previous, "Identifiers can only be a maximum of 256 characters long");
}
char* cpy = copyString(identifierToken.lexeme, length);
Literal identifier = _toIdentifierLiteral(cpy, strlen(cpy)); //BUGFIX: use this instead of the macro
Literal identifier = TO_IDENTIFIER_LITERAL(createRefStringLength(identifierToken.lexeme, length));
//read the type, if present
Literal typeLiteral;
@@ -1603,8 +1590,7 @@ static void fnDecl(Parser* parser, ASTNode** nodeHandle) {
error(parser, parser->previous, "Identifiers can only be a maximum of 256 characters long");
}
char* cpy = copyString(identifierToken.lexeme, length);
Literal identifier = _toIdentifierLiteral(cpy, strlen(cpy)); //BUGFIX: use this instead of the macro
Literal identifier = TO_IDENTIFIER_LITERAL(createRefStringLength(identifierToken.lexeme, length));
//read the parameters and arity
consume(parser, TOKEN_PAREN_LEFT, "Expected '(' after function identifier");
@@ -1630,8 +1616,7 @@ static void fnDecl(Parser* parser, ASTNode** nodeHandle) {
error(parser, parser->previous, "Identifiers can only be a maximum of 256 characters long");
}
char* cpy = copyString(argIdentifierToken.lexeme, length);
Literal argIdentifier = _toIdentifierLiteral(cpy, strlen(cpy)); //BUGFIX: use this instead of the macro
Literal argIdentifier = TO_IDENTIFIER_LITERAL(createRefStringLength(argIdentifierToken.lexeme, length));
//set the type (array of any types)
Literal argTypeLiteral = TO_TYPE_LITERAL(LITERAL_FUNCTION_ARG_REST, false);
@@ -1666,9 +1651,7 @@ static void fnDecl(Parser* parser, ASTNode** nodeHandle) {
error(parser, parser->previous, "Identifiers can only be a maximum of 256 characters long");
}
char* cpy = copyString(argIdentifierToken.lexeme, length);
Literal argIdentifier = _toIdentifierLiteral(cpy, strlen(cpy)); //BUGFIX: use this instead of the macro
Literal argIdentifier = TO_IDENTIFIER_LITERAL(createRefStringLength(argIdentifierToken.lexeme, length));
//read optional type of the identifier
Literal argTypeLiteral;
@@ -1780,9 +1763,9 @@ ASTNode* scanParser(Parser* parser) {
if (parser->panic) {
synchronize(parser);
//return an error node for this iteration
freeNode(node);
freeASTNode(node);
node = ALLOCATE(ASTNode, 1);
node->type = AST_NODEERROR;
node->type = AST_NODE_ERROR;
}
return node;
+1 -1
View File
@@ -1,6 +1,6 @@
#pragma once
#include "common.h"
#include "toy_common.h"
#include "lexer.h"
#include "ast_node.h"
+100
View File
@@ -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;
}
+27
View File
@@ -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);
+1 -1
View File
@@ -1,4 +1,4 @@
#include "common.h"
#include "toy_common.h"
#include <stdio.h>
#include <string.h>
+12 -1
View File
@@ -6,14 +6,25 @@
#define TOY_VERSION_MAJOR 0
#define TOY_VERSION_MINOR 6
#define TOY_VERSION_PATCH 0
#define TOY_VERSION_PATCH 4
#define TOY_VERSION_BUILD __DATE__ " " __TIME__
//platform exports/imports
#if defined(__linux__)
#define TOY_API extern
#include <time.h>
#include <sys/time.h>
#elif defined(_WIN32) || defined(WIN32)
#define TOY_API
#include <time.h>
#include <sys/time.h>
#else
#define TOY_API
#include <time.h>
#include <sys/time.h>
#endif
#ifndef TOY_EXPORT
+1 -2
View File
@@ -3,10 +3,9 @@ CC=gcc
IDIR +=. ../source ../repl
CFLAGS +=$(addprefix -I,$(IDIR)) -g -Wall -W -Wno-unused-parameter -Wno-unused-function -Wno-unused-variable
LIBS +=
ODIR = obj
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))
.PRECIOUS: $(TESTS:%.c=../$(TOY_OUTDIR)/%.exe)
+20
View File
@@ -0,0 +1,20 @@
/*
NOTES: For some reason, this code results in the error:
Undeclared variable "inner"
It only occurs under these very specific conditions.
It appears to be a compiler issue, see issue #38 for more info.
*/
fn _getValue(self) {
return self;
}
var cache;
cache = 42.getValue(); //assignment, rather than declaration, allows the bug
print "All good";
+9
View File
@@ -0,0 +1,9 @@
fn _add(self, inc) {
return self + inc;
}
assert 1.add(2).add(3).add(4) == 10, "dottify bugfix failed";
print "All good";
+92
View File
@@ -0,0 +1,92 @@
//test the timer library
{
//create a timer, run it for a short period
import timer;
var timerA: opaque = startTimer();
for (var i: int = 0; i < 1000 * 1; i++);
var diffA: opaque = timerA.stopTimer();
//create another timer, run it for a longer period
var timerB: opaque = startTimer();
for (var i: int = 0; i < 1000 * 10; i++);
var diffB: opaque = timerB.stopTimer();
//check to ensure that the second timer took longer than the first
//WARNING: this has the small possibility of failing due to external factors
var difference: opaque = diffA.compareTimer(diffB);
assert difference.getTimerSeconds() >= 0, "compareTimer() (seconds) failed";
if (difference.getTimerSeconds() == 0) {
assert difference.getTimerMicroseconds() >= 0, "compareTimer() (microseconds) failed";
}
//all timers must be destroyed after use
timerA.destroyTimer();
timerB.destroyTimer();
diffA.destroyTimer();
diffB.destroyTimer();
difference.destroyTimer();
}
{
//create a timer, manipulate it's values
import timer;
//set the timer values manually
var timer: opaque = createTimer(42, 8891);
//check the timer values
assert timer.getTimerSeconds() == 42, "getTimerSeconds() failed";
assert timer.getTimerMicroseconds() == 8891, "getTimerMicroseconds() failed";
//all timers must be destroyed after use
timer.destroyTimer();
}
{
//set a timer to check string representation
import timer;
var timer: opaque = createTimer(42, 999);
assert timer.timerToString() == "42.000999", "timerToString() failed";
//all timers must be destroyed after use
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";
+8
View File
@@ -0,0 +1,8 @@
fn panic() {
assert false, "!ignore panicking within a function";
}
panic();
panic();
+66 -7
View File
@@ -4,20 +4,79 @@
#include "console_colors.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() {
//test literals
{
//test literals
char* str = "foobar";
Literal literal = TO_STRING_LITERAL(createRefString(str));
Literal literal = TO_STRING_LITERAL(copyString(str, strlen(str)), strlen(str));
ASTNode* node;
//generate the node
ASTNode* node = NULL;
emitASTNodeLiteral(&node, literal);
//check node type
ASSERT(node->type == AST_NODE_LITERAL);
//cleanup
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)
char* idn = "foobar";
@@ -27,8 +86,8 @@ int main() {
ASTNode* left;
ASTNode* right;
Literal identifier = TO_IDENTIFIER_LITERAL(copyString(idn, strlen(idn)), strlen(idn));
Literal string = TO_STRING_LITERAL(copyString(str, strlen(str)), strlen(str));
Literal identifier = TO_IDENTIFIER_LITERAL(createRefString(idn));
Literal string = TO_STRING_LITERAL(createRefString(str));
emitASTNodeCompound(&dictionary, LITERAL_DICTIONARY);
emitASTNodeLiteral(&left, identifier);
@@ -46,7 +105,7 @@ int main() {
setASTNodePair(&dictionary->compound.nodes[dictionary->compound.count++], left, right);
//the real test
freeNode(dictionary);
freeASTNode(dictionary);
freeLiteral(identifier);
freeLiteral(string);
}
+7 -5
View File
@@ -64,16 +64,16 @@ unsigned char* compileString(char* source, size_t* size) {
ASTNode* node = scanParser(&parser);
while(node != NULL) {
//pack up and leave
if (node->type == AST_NODEERROR) {
if (node->type == AST_NODE_ERROR) {
printf(ERROR "error node detected\n" RESET);
freeNode(node);
freeASTNode(node);
freeCompiler(&compiler);
freeParser(&parser);
return NULL;
}
writeCompiler(&compiler, node);
freeNode(node);
freeASTNode(node);
node = scanParser(&parser);
}
@@ -90,14 +90,14 @@ unsigned char* compileString(char* source, size_t* size) {
}
void error(char* msg) {
printf(msg);
printf("%s", msg);
exit(-1);
}
int main() {
{
size_t size = 0;
char* source = readFile("../scripts//test/call-from-host.toy", &size);
char* source = readFile("scripts/call-from-host.toy", &size);
unsigned char* tb = compileString(source, &size);
free((void*)source);
@@ -281,6 +281,8 @@ int main() {
{
interpreter.printOutput("Testing assertion failure");
setInterpreterAssert(&interpreter, noPrintFn);
LiteralArray arguments;
initLiteralArray(&arguments);
LiteralArray returns;
+4 -4
View File
@@ -76,7 +76,7 @@ int main() {
//cleanup
FREE_ARRAY(unsigned char, bytecode, size);
freeNode(node);
freeASTNode(node);
freeParser(&parser);
freeCompiler(&compiler);
}
@@ -84,7 +84,7 @@ int main() {
{
//source
size_t sourceLength = 0;
char* source = readFile("sample_code.toy", &sourceLength);
char* source = readFile("scripts/sample_code.toy", &sourceLength);
//test basic compilation & collation
Lexer lexer;
@@ -97,14 +97,14 @@ int main() {
ASTNode* node = scanParser(&parser);
while (node != NULL) {
if (node->type == AST_NODEERROR) {
if (node->type == AST_NODE_ERROR) {
fprintf(stderr, ERROR "ERROR: Error node found" RESET);
return -1;
}
//write
writeCompiler(&compiler, node);
freeNode(node);
freeASTNode(node);
node = scanParser(&parser);
}
+32 -9
View File
@@ -16,6 +16,18 @@ static void noPrintFn(const char* output) {
//NO OP
}
int ignoredAssertions = 0;
static void noAssertFn(const char* output) {
if (strncmp(output, "!ignore", 7) == 0) {
ignoredAssertions++;
}
else {
fprintf(stderr, ERROR "Assertion failure: ");
fprintf(stderr, "%s", output);
fprintf(stderr, "\n" RESET); //default new line
}
}
//compilation functions
char* readFile(char* path, size_t* fileSize) {
FILE* file = fopen(path, "rb");
@@ -63,16 +75,16 @@ unsigned char* compileString(char* source, size_t* size) {
ASTNode* node = scanParser(&parser);
while(node != NULL) {
//pack up and leave
if (node->type == AST_NODEERROR) {
if (node->type == AST_NODE_ERROR) {
printf(ERROR "error node detected\n" RESET);
freeNode(node);
freeASTNode(node);
freeCompiler(&compiler);
freeParser(&parser);
return NULL;
}
writeCompiler(&compiler, node);
freeNode(node);
freeASTNode(node);
node = scanParser(&parser);
}
@@ -94,6 +106,7 @@ void runBinary(unsigned char* tb, size_t size) {
//NOTE: suppress print output for testing
setInterpreterPrint(&interpreter, noPrintFn);
setInterpreterAssert(&interpreter, noAssertFn);
runInterpreter(&interpreter, tb, size);
freeInterpreter(&interpreter);
@@ -147,28 +160,31 @@ int main() {
int size = 0;
unsigned char* bytecode = collateCompiler(&compiler, &size);
//NOTE: supress print output for testing
//NOTE: suppress print output for testing
setInterpreterPrint(&interpreter, noPrintFn);
setInterpreterAssert(&interpreter, noAssertFn);
//run
runInterpreter(&interpreter, bytecode, size);
//cleanup
freeNode(node);
freeASTNode(node);
freeParser(&parser);
freeCompiler(&compiler);
freeInterpreter(&interpreter);
}
{
//run each file in ../scripts/test/
//run each file in tests/scripts/
char* filenames[] = {
"arithmetic.toy",
"casting.toy",
"coercions.toy",
"comparisons.toy",
"dot-and-matrix.toy",
"dot-assignments-bugfix.toy",
"dot-chaining.toy",
"dottify-bugfix.toy",
"functions.toy",
"imports-and-exports.toy",
"index-arrays.toy",
@@ -190,7 +206,7 @@ int main() {
printf("Running %s\n", filenames[i]);
char buffer[128];
snprintf(buffer, 128, "../scripts/test/%s", filenames[i]);
snprintf(buffer, 128, "scripts/%s", filenames[i]);
runSourceFile(buffer);
}
@@ -200,8 +216,8 @@ int main() {
//read source
size_t dummy;
size_t exportSize, importSize;
char* exportSource = readFile("../scripts/test/separate-exports.toy", &dummy);
char* importSource = readFile("../scripts/test/separate-imports.toy", &dummy);
char* exportSource = readFile("scripts/separate-exports.toy", &dummy);
char* importSource = readFile("scripts/separate-imports.toy", &dummy);
//compile
unsigned char* exportBinary = compileString(exportSource, &exportSize);
@@ -213,6 +229,7 @@ int main() {
//NOTE: supress print output for testing
setInterpreterPrint(&interpreter, noPrintFn);
setInterpreterAssert(&interpreter, noAssertFn);
runInterpreter(&interpreter, exportBinary, exportSize); //automatically frees the binary data
@@ -227,6 +244,12 @@ int main() {
free((void*)importSource);
}
//1, to allow for the assertion test
if (ignoredAssertions > 1) {
fprintf(stderr, ERROR "Assertions hidden: %d\n", ignoredAssertions);
return -1;
}
printf(NOTICE "All good\n" RESET);
return 0;
}
+55 -32
View File
@@ -12,12 +12,26 @@
#include <string.h>
#include "../repl/lib_standard.h"
#include "../repl/lib_timer.h"
//supress the print output
static void noPrintFn(const char* output) {
//NO OP
}
static int failedAsserts = 0;
static void assertWrapper(const char* output) {
failedAsserts++;
fprintf(stderr, ERROR "Assertion failure: ");
fprintf(stderr, "%s", output);
fprintf(stderr, "\n" RESET); //default new line
}
static void errorWrapper(const char* output) {
failedAsserts++;
fprintf(stderr, ERROR "%s" RESET, output);
}
//compilation functions
char* readFile(char* path, size_t* fileSize) {
FILE* file = fopen(path, "rb");
@@ -65,16 +79,16 @@ unsigned char* compileString(char* source, size_t* size) {
ASTNode* node = scanParser(&parser);
while(node != NULL) {
//pack up and leave
if (node->type == AST_NODEERROR) {
if (node->type == AST_NODE_ERROR) {
printf(ERROR "error node detected\n" RESET);
freeNode(node);
freeASTNode(node);
freeCompiler(&compiler);
freeParser(&parser);
return NULL;
}
writeCompiler(&compiler, node);
freeNode(node);
freeASTNode(node);
node = scanParser(&parser);
}
@@ -90,56 +104,65 @@ unsigned char* compileString(char* source, size_t* size) {
return tb;
}
void runBinary(unsigned char* tb, size_t size) {
void runBinaryWithLibrary(unsigned char* tb, size_t size, char* library, HookFn hook) {
Interpreter interpreter;
initInterpreter(&interpreter);
//NOTE: supress print output for testing
setInterpreterPrint(&interpreter, noPrintFn);
setInterpreterAssert(&interpreter, assertWrapper);
setInterpreterError(&interpreter, errorWrapper);
//inject the standard libraries into this interpreter
injectNativeHook(&interpreter, "standard", hookStandard);
injectNativeHook(&interpreter, library, hook);
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);
}
typedef struct Payload {
char* fname;
char* libname;
HookFn hook;
} Payload;
int main() {
{
//run each file in ../scripts/test/
char* filenames[] = {
"interactions.toy",
"standard.toy",
NULL
//run each file in test/scripts
Payload payloads[] = {
{"interactions.toy", "standard", hookStandard}, //interactions needs standard
{"standard.toy", "standard", hookStandard},
{"timer.toy", "timer", hookTimer},
{NULL, NULL, NULL}
};
for (int i = 0; filenames[i]; i++) {
printf("Running %s\n", filenames[i]);
for (int i = 0; payloads[i].fname; i++) {
printf("Running %s\n", payloads[i].fname);
char buffer[128];
snprintf(buffer, 128, "../scripts/test/lib/%s", filenames[i]);
char fname[128];
snprintf(fname, 128, "scripts/lib/%s", payloads[i].fname);
runSourceFile(buffer);
//compile the source
size_t size = 0;
char* source = readFile(fname, &size);
unsigned char* tb = compileString(source, &size);
free((void*)source);
if (!tb) {
printf(ERROR "Failed to compile file: %s" RESET, fname);
}
runBinaryWithLibrary(tb, size, payloads[i].libname, payloads[i].hook);
}
}
printf(NOTICE "All good\n" RESET);
return 0;
if (!failedAsserts) {
printf(NOTICE "All good\n" RESET);
}
else {
printf(WARN "Problems detected in libraries\n" RESET);
}
return failedAsserts;
}
+4 -8
View File
@@ -29,22 +29,18 @@ int main() {
{
//test string literals
char* buffer = ALLOCATE(char, 128);
char* buffer = "Hello world";
snprintf(buffer, 128, "Hello world");
Literal literal = TO_STRING_LITERAL(buffer, 128);
Literal literal = TO_STRING_LITERAL(createRefString(buffer));
freeLiteral(literal);
}
{
//test identifier literals
char* buffer = ALLOCATE(char, 128);
char buffer[] = "Hello world";
snprintf(buffer, 128, "foobar");
Literal literal = TO_IDENTIFIER_LITERAL(buffer, 128);
Literal literal = TO_IDENTIFIER_LITERAL(createRefString(buffer));
freeLiteral(literal);
}
+3 -3
View File
@@ -46,10 +46,10 @@ int main() {
char* str_raw = "hello world";
char* idn_raw = "foobar";
Literal string = TO_STRING_LITERAL(copyString(str_raw, strlen(str_raw)), strlen(str_raw));
Literal identifier = TO_IDENTIFIER_LITERAL(copyString(idn_raw, strlen(idn_raw)), strlen(idn_raw));
Literal string = TO_STRING_LITERAL(createRefString(str_raw));
Literal identifier = TO_IDENTIFIER_LITERAL(createRefString(idn_raw));
//[string, string]
//[string : string]
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));
+2 -2
View File
@@ -18,8 +18,8 @@ int main() {
char* idn_raw = "foobar";
char* str_raw = "hello world";
Literal identifier = TO_IDENTIFIER_LITERAL(copyString(idn_raw, strlen(idn_raw)), strlen(idn_raw));
Literal string = TO_STRING_LITERAL(copyString(str_raw, strlen(str_raw)), strlen(str_raw));
Literal identifier = TO_IDENTIFIER_LITERAL(createRefString(idn_raw));
Literal string = TO_STRING_LITERAL(createRefString(str_raw));
LiteralDictionary dictionary;
initLiteralDictionary(&dictionary);
+47 -5
View File
@@ -3,32 +3,74 @@
#include "console_colors.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
int* integer = ALLOCATE(int, 1);
FREE(int, integer);
}
{
//test single pointer
//test single pointer array
int* array = ALLOCATE(int, 10);
array[1] = 42; //access the given memory
FREE_ARRAY(int, array, 10);
}
{
//test single pointer
//test multiple pointer arrays
int* array1 = 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, 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);
return 0;
}
+5 -5
View File
@@ -62,16 +62,16 @@ unsigned char* compileString(char* source, size_t* size) {
ASTNode* node = scanParser(&parser);
while(node != NULL) {
//pack up and leave
if (node->type == AST_NODEERROR) {
if (node->type == AST_NODE_ERROR) {
printf(ERROR "error node detected\n" RESET);
freeNode(node);
freeASTNode(node);
freeCompiler(&compiler);
freeParser(&parser);
return NULL;
}
writeCompiler(&compiler, node);
freeNode(node);
freeASTNode(node);
node = scanParser(&parser);
}
@@ -88,7 +88,7 @@ unsigned char* compileString(char* source, size_t* size) {
}
void error(char* msg) {
printf(msg);
printf("%s", msg);
exit(-1);
}
@@ -138,7 +138,7 @@ static int consume(Interpreter* interpreter, LiteralArray* arguments) {
int main() {
{
size_t size = 0;
char* source = readFile("../scripts/test/opaque-data-type.toy", &size);
char* source = readFile("scripts/opaque-data-type.toy", &size);
unsigned char* tb = compileString(source, &size);
free((void*)source);
+9 -8
View File
@@ -72,25 +72,25 @@ int main() {
return -1;
}
if (node->type != AST_NODEUNARY || node->unary.opcode != OP_PRINT) {
fprintf(stderr, ERROR "ERROR: ASTNode is not a print instruction" RESET);
if (node->type != AST_NODE_UNARY || node->unary.opcode != OP_PRINT) {
fprintf(stderr, ERROR "ERROR: ASTNode is not a unary print instruction" RESET);
return -1;
}
if (node->unary.child->type != AST_NODELITERAL || !IS_NULL(node->unary.child->atomic.literal)) {
fprintf(stderr, ERROR "ERROR: ASTNode to be printed is not a null value" RESET);
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 literal" RESET);
return -1;
}
//cleanup
freeNode(node);
freeASTNode(node);
freeParser(&parser);
}
{
//get the source file
size_t size = 0;
char* source = readFile("sample_code.toy", &size);
char* source = readFile("scripts/sample_code.toy", &size);
//test parsing a chunk of junk (valgrind will find leaks)
Lexer lexer;
@@ -101,12 +101,12 @@ int main() {
ASTNode* node = scanParser(&parser);
while (node != NULL) {
if (node->type == AST_NODEERROR) {
if (node->type == AST_NODE_ERROR) {
fprintf(stderr, ERROR "ERROR: Error node detected" RESET);
return -1;
}
freeNode(node);
freeASTNode(node);
node = scanParser(&parser);
}
@@ -114,6 +114,7 @@ int main() {
freeParser(&parser);
free((void*)source);
}
printf(NOTICE "All good\n" RESET);
return 0;
}
+2 -2
View File
@@ -16,7 +16,7 @@ int main() {
//prerequisites
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 type = TO_TYPE_LITERAL(value.type, false);
@@ -46,7 +46,7 @@ int main() {
//prerequisites
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);
//test declarations & assignments
+17
View File
@@ -0,0 +1,17 @@
// A launch configuration that launches the extension inside a new window
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
{
"version": "0.2.0",
"configurations": [
{
"name": "Extension",
"type": "extensionHost",
"request": "launch",
"args": [
"--extensionDevelopmentPath=${workspaceFolder}"
]
}
]
}
@@ -0,0 +1,4 @@
.vscode/**
.vscode-test/**
.gitignore
vsc-extension-quickstart.md
@@ -0,0 +1,2 @@
# Change Log
@@ -0,0 +1,8 @@
# Toy VSCode Highlighting
This is included in the core repo under `/tools`, and is supposed to make your time writing Toy code easier.
## Installing
Just copy the whole folder into the extensions folder for VSCode, or run `make install-tools` in the root directory of Toy.
@@ -0,0 +1,28 @@
{
"comments": {
// symbol used for single line comment. Remove this entry if your language does not support line comments
"lineComment": "//",
// symbols used for start and end a block comment. Remove this entry if your language does not support block comments
"blockComment": [ "/*", "*/" ]
},
// symbols used as brackets
"brackets": [
["{", "}"],
["[", "]"],
["(", ")"]
],
// symbols that are auto closed when typing
"autoClosingPairs": [
["{", "}"],
["[", "]"],
["(", ")"],
["\"", "\""],
],
// symbols that can be used to surround a selection
"surroundingPairs": [
["{", "}"],
["[", "]"],
["(", ")"],
["\"", "\""],
]
}
@@ -0,0 +1,26 @@
{
"name": "toy-syntax-highlighting",
"displayName": "Toy Syntax Highlighting",
"description": "Syntax highligher for a toy programming language",
"author": "Kayne Ruse",
"version": "0.0.1",
"engines": {
"vscode": "^1.73.0"
},
"categories": [
"Programming Languages"
],
"contributes": {
"languages": [{
"id": "toy",
"aliases": ["Toy", "toy"],
"extensions": [".toy"],
"configuration": "./language-configuration.json"
}],
"grammars": [{
"language": "toy",
"scopeName": "source.toy",
"path": "./syntaxes/toy.tmLanguage.json"
}]
}
}
@@ -0,0 +1,85 @@
{
"$schema": "https://raw.githubusercontent.com/martinring/tmlanguage/master/tmlanguage.json",
"name": "Toy",
"patterns": [
{
"include": "#comments"
},
{
"include": "#keywords"
},
{
"include": "#strings"
},
{
"include": "#numbers"
},
{
"include": "#booleans"
},
{
"include": "#null"
},
{
"include": "#reserved"
}
],
"repository": {
"comments": {
"patterns": [{
"name": "comment.line.toy",
"begin": "\/\/",
"end": "\\n"
},
{
"name": "comment.block.toy",
"begin": "/\\*",
"end": "\\*/"
}]
},
"keywords": {
"patterns": [{
"name": "keyword.control.toy",
"match": "\\b(if|else|while|for|return|break|continue)\\b"
},
{
"name": "entity.name.type.toy",
"match": "\\b(any|bool|const|float|int|opaque|string|type)\\b"
},
{
"name": "keyword.other.toy",
"match": "\\b(as|astype|assert|export|fn|import|print|typeof|var)\\b"
}]
},
"strings": {
"name": "string.quoted.double.toy",
"begin": "\"",
"end": "\""
},
"numbers": {
"patterns": [{
"match": "[-]?[0-9]+(.[0-9]+)?",
"name": "constant.numeric.toy"
}]
},
"booleans": {
"patterns": [{
"match": "\\b(true|false)\\b",
"name": "constant.numeric.toy"
}]
},
"null": {
"patterns": [{
"match": "\\b(null)\\b",
"name": "constant.numeric.toy"
}]
},
"reserved": {
"patterns": [{
"name": "keyword.reserved.toy",
"match": "\\b(class|do|foreach|in|of)\\b"
}]
}
},
"scopeName": "source.toy"
}