Compare commits
28 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 7bf18a744c | |||
| fa20763c07 | |||
| 774f3d9e83 | |||
| 2d18ff4ba3 | |||
| 30b068fcdb | |||
| 3d8ce4e7d8 | |||
| e0ab4106fa | |||
| 2c143a8be5 | |||
| 0aa6e4063b | |||
| ec39f099ca | |||
| 4dcc05e796 | |||
| 2af95ec82e | |||
| bbdb521333 | |||
| 56987bc96a | |||
| 8498864dde | |||
| 14710dec90 | |||
| d14177dbca | |||
| 42580bbe2a | |||
| 0c8e036de8 | |||
| a55338d8e3 | |||
| 5d240f85a6 | |||
| cceefa6375 | |||
| 632ed7c089 | |||
| c1528f5501 | |||
| 6c5d952c44 | |||
| 208ad9d615 | |||
| 876aad853c | |||
| 1baa65cc95 |
@@ -0,0 +1,19 @@
|
||||
name: Comprehensive Tests
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ "main" ]
|
||||
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
|
||||
@@ -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
|
||||
|
||||
```
|
||||
|
||||
@@ -12,10 +12,10 @@ repl-static: $(TOY_OUTDIR) static
|
||||
$(MAKE) -C repl
|
||||
|
||||
library: $(TOY_OUTDIR)
|
||||
$(MAKE) -C source library
|
||||
$(MAKE) -j8 -C source library
|
||||
|
||||
static: $(TOY_OUTDIR)
|
||||
$(MAKE) -C source static
|
||||
$(MAKE) -j8 -C source static
|
||||
|
||||
test: clean $(TOY_OUTDIR)
|
||||
$(MAKE) -C test
|
||||
@@ -23,6 +23,10 @@ test: clean $(TOY_OUTDIR)
|
||||
$(TOY_OUTDIR):
|
||||
mkdir $(TOY_OUTDIR)
|
||||
|
||||
#utils
|
||||
install-tools:
|
||||
cp -rf tools/toylang.vscode-highlighting ~/.vscode/extensions
|
||||
|
||||
.PHONY: clean
|
||||
|
||||
clean:
|
||||
|
||||
+1
-1
@@ -2,7 +2,7 @@
|
||||
|
||||
#include "memory.h"
|
||||
|
||||
#include <time.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
static int nativeClock(Interpreter* interpreter, LiteralArray* arguments) {
|
||||
//no arguments
|
||||
|
||||
@@ -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, µsecondLiteral)) {
|
||||
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( copyString(buffer, strlen(buffer)), strlen(buffer));
|
||||
}
|
||||
else { //normal case
|
||||
char buffer[128];
|
||||
snprintf(buffer, 128, "%ld.%06ld", timer->tv_sec, timer->tv_usec);
|
||||
resultLiteral = TO_STRING_LITERAL( copyString(buffer, strlen(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(copyString(natives[i].name, strlen(natives[i].name)), strlen(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;
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "interpreter.h"
|
||||
|
||||
int hookTimer(Interpreter* interpreter, Literal identifier, Literal alias);
|
||||
|
||||
@@ -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("> ");
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#include "repl_tools.h"
|
||||
#include "lib_standard.h"
|
||||
#include "lib_timer.h"
|
||||
|
||||
#include "console_colors.h"
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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();
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
|
||||
|
||||
fn panic() {
|
||||
assert false, "This should only be seen once";
|
||||
}
|
||||
|
||||
panic();
|
||||
panic();
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "common.h"
|
||||
#include "toy_common.h"
|
||||
#include "literal.h"
|
||||
#include "opcodes.h"
|
||||
#include "token_types.h"
|
||||
|
||||
+1
-1
@@ -891,7 +891,7 @@ 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", AS_STRING(compound));
|
||||
|
||||
int assignLength = strlen(AS_STRING(assign));
|
||||
int min = AS_INTEGER(third) > 0 ? AS_INTEGER(first) : AS_INTEGER(second) - 1;
|
||||
|
||||
+1
-1
@@ -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
|
||||
}
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "common.h"
|
||||
#include "toy_common.h"
|
||||
#include "opcodes.h"
|
||||
#include "ast_node.h"
|
||||
#include "literal_array.h"
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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,6 +1,6 @@
|
||||
#include "keyword_types.h"
|
||||
|
||||
#include "common.h"
|
||||
#include "toy_common.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
|
||||
+1
-1
@@ -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
|
||||
|
||||
+1
-1
@@ -15,7 +15,7 @@ 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;
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "common.h"
|
||||
#include "toy_common.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "common.h"
|
||||
#include "toy_common.h"
|
||||
|
||||
#include "literal.h"
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "common.h"
|
||||
#include "toy_common.h"
|
||||
|
||||
#include "literal.h"
|
||||
|
||||
|
||||
+1
-1
@@ -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)
|
||||
|
||||
+1
-8
@@ -1,7 +1,5 @@
|
||||
#include "parser.h"
|
||||
|
||||
#include "common.h"
|
||||
|
||||
#include "memory.h"
|
||||
#include "literal.h"
|
||||
#include "opcodes.h"
|
||||
@@ -798,12 +796,6 @@ static Opcode dot(Parser* parser, ASTNode** nodeHandle) {
|
||||
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;
|
||||
return OP_DOT; //signal that the function name and arguments are in the wrong order
|
||||
}
|
||||
@@ -1090,6 +1082,7 @@ static void dottify(Parser* parser, ASTNode** nodeHandle) {
|
||||
if ((*nodeHandle)->type == AST_NODEBINARY) {
|
||||
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);
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "common.h"
|
||||
#include "toy_common.h"
|
||||
#include "lexer.h"
|
||||
#include "ast_node.h"
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#include "common.h"
|
||||
#include "toy_common.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
@@ -6,14 +6,25 @@
|
||||
|
||||
#define TOY_VERSION_MAJOR 0
|
||||
#define TOY_VERSION_MINOR 6
|
||||
#define TOY_VERSION_PATCH 0
|
||||
#define TOY_VERSION_PATCH 2
|
||||
#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
|
||||
@@ -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";
|
||||
@@ -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";
|
||||
@@ -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";
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
|
||||
|
||||
fn panic() {
|
||||
assert false, "!ignore panicking within a function";
|
||||
}
|
||||
|
||||
panic();
|
||||
panic();
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
+28
-5
@@ -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");
|
||||
@@ -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,8 +160,9 @@ 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);
|
||||
@@ -161,14 +175,16 @@ int main() {
|
||||
}
|
||||
|
||||
{
|
||||
//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;
|
||||
}
|
||||
|
||||
+52
-29
@@ -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");
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
+1
-1
@@ -90,7 +90,7 @@ int main() {
|
||||
{
|
||||
//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;
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
Reference in New Issue
Block a user