Compare commits

..

56 Commits

Author SHA1 Message Date
Kayne Ruse 85dc24c4a6 Updated bug report template 2023-02-09 17:25:24 +00:00
Kayne Ruse 1804e380a0 tweak 2023-02-09 17:06:51 +00:00
Kayne Ruse 7567f4f3b2 Experimenting with issues 2023-02-09 17:05:20 +00:00
Kayne Ruse e8160eb9df Fixed string indexing with null 2023-02-09 16:46:36 +00:00
Kayne Ruse 276648630e trying to uncluster-bomb the builtin functions 2023-02-09 16:12:42 +00:00
Kayne Ruse e946a5f071 Patched segault in parser 2023-02-09 12:37:18 +00:00
Kayne Ruse 932401c26d Can now correctly parse escaped characters 2023-02-09 08:44:08 +00:00
Kayne Ruse fc67d6a18b Fixed a segfault 2023-02-09 08:24:16 +00:00
Kayne Ruse 60908c8bf3 Added panic state to Toy_Compiler to catch a certain condition 2023-02-09 07:58:55 +00:00
Kayne Ruse b8e3324acb tweak 2023-02-07 18:32:59 +00:00
Kayne Ruse 0fc8183799 Added _reduce 2023-02-06 09:46:20 +00:00
Kayne Ruse 9a6aa8d15e Added _trimBegin() and _trimEnd() 2023-02-06 06:11:17 +00:00
Kayne Ruse 0b9051cab2 Experimenting with numbers 2023-02-06 05:37:41 +00:00
Kayne Ruse 0d7e4db661 Fixed repl bug 2023-02-06 04:47:30 +00:00
Kayne Ruse d5c833b344 I wish I could test on windows 2023-02-06 01:05:44 +00:00
Kayne Ruse c875ae7a0e Added _forEach and _map, added tests for them 2023-02-06 00:51:07 +00:00
Kayne Ruse c0ec5ef28e Tested _concat() with clashing dict keys 2023-02-05 22:46:00 +00:00
Kayne Ruse be91de9535 Fixed a leak 2023-02-05 20:46:55 +00:00
Kayne Ruse 3088c4fe6d Implemented _concat 2023-02-05 20:45:31 +00:00
Kayne Ruse 9bd0cd23e7 Imported an example file for bytecode size testing, see #21 2023-02-05 15:40:17 +00:00
Kayne Ruse 29f8a698b4 Added a mustfail test 2023-02-05 15:19:04 +00:00
Kayne Ruse 41d274177a String concatenation restricted to + and += signs 2023-02-05 15:15:32 +00:00
Kayne Ruse 7ea249f723 Added the about library, resolved #51 2023-02-05 14:43:46 +00:00
Kayne Ruse 3949be3706 Quick potential bugfix 2023-02-05 13:34:39 +00:00
Kayne Ruse 0e932f24cc Added _toString() 2023-02-05 13:29:44 +00:00
Kayne Ruse 60225b733b Added _getKeys() and _getValues() 2023-02-05 12:49:12 +00:00
Kayne Ruse 15f99495a1 Aesthetics 2023-02-05 11:31:17 +00:00
Kayne Ruse 7b26527e95 Nesting index multiplication assignment fixed
This affects all arithmetic types applied to inner-nested compounds.
2023-02-05 06:28:24 +00:00
Kayne Ruse 386201b6e9 Added fib-memo.toy, fixed bugs until it worked 2023-02-04 17:01:58 +00:00
Kayne Ruse 8d278077b1 Added constant folding for strings, tweaked some error messages 2023-02-04 09:50:29 +00:00
Kayne Ruse 57c16d2ede Fixed an obscure memory leak, potential issue with lib_runner on linux 2023-02-04 15:30:46 +11:00
Kayne Ruse 2f1613e306 Caught an error in the compiler 2023-02-04 03:03:56 +00:00
Kayne Ruse 2776c87026 Ambiguous ternary syntax might be an issue 2023-02-04 02:59:10 +00:00
Kayne Ruse 8cc33f5fbb Added to ternary expression tests 2023-02-03 17:22:44 +00:00
Kayne Ruse 90f91a234a r is a bad character to escape 2023-01-31 12:38:42 +00:00
Kayne Ruse fcd1cdf70b Added a few characters that can be escaped 2023-01-31 12:37:18 +00:00
Kayne Ruse e265038547 Tested custom char trims 2023-01-29 08:38:26 +00:00
Kayne Ruse a357e0b0d4 Implemented _trim() 2023-01-29 08:30:31 +00:00
Kayne Ruse 2c5e3c6aa5 Started working on compound library 2023-01-29 07:23:52 +00:00
Kayne Ruse aeda0a0d94 Fixed pointer to int casting 2023-01-28 09:11:38 +00:00
Kayne Ruse ebbcba1b16 Enabled -std=c18 -pedantic, fixed all resulting errors
Thanks @gyrovorbis
2023-01-28 08:54:46 +00:00
Kayne Ruse 4bce10803e Added official support for mingw32 2023-01-28 07:56:11 +00:00
Kayne Ruse daee91904d Trying to test on windows 2023-01-28 06:20:36 +00:00
Kayne Ruse c397384766 Merge remote-tracking branch 'refs/remotes/origin/main' 2023-01-28 06:11:54 +00:00
Kayne Ruse 667efc2feb Removed nonstandard C constructor attribute 2023-01-28 06:06:04 +00:00
Kayne Ruse f4469fc53d Removed file extension guard 2023-01-27 07:03:36 +00:00
Kayne Ruse c86c5800a7 Moved guard 2023-01-27 06:31:13 +00:00
Kayne Ruse e4d843ad3a Type check 2023-01-27 06:16:39 +00:00
Kayne Ruse 6667bce3d7 Finally fixed the buffer
I suppose valgrind, et. al. complaining is a good thing, overall.
2023-01-27 06:01:05 +00:00
Kayne Ruse 50b07da188 Put the clear BEFORE the return 2023-01-27 05:56:23 +00:00
Kayne Ruse 708db75760 Forgot to free this buffer 2023-01-27 05:53:35 +00:00
Kayne Ruse b632ce77ba Moved drive to filepath code into a function 2023-01-27 05:49:14 +00:00
Kayne Ruse b2c3dd894c Added a memusage tool 2023-01-25 15:11:22 +00:00
Kayne Ruse 9b21bfb53b Missed a rename 2023-01-25 13:54:28 +00:00
Kayne Ruse d3adac8a59 Fixed the parser - whoops 2023-01-25 13:17:57 +00:00
Kayne Ruse 5183037a99 Missed the globals 2023-01-25 13:15:16 +00:00
54 changed files with 2851 additions and 613 deletions
+29
View File
@@ -0,0 +1,29 @@
---
name: Bug Report
about: Create a report to help us improve
labels: bug
---
## Describe the bug
A clear and concise description of what the bug is.
## To Reproduce
Steps to reproduce the behaviour:
1. run `git pull` on the repository
2. run `make rebuild` on the code
3. ...
You can include some screenshots here if you'd like!
## Versioning
- OS: [for example MacOS, Windows, iOS, Android]
- Version: [What version of Toy was this running?]
### Additional context
Add any other context about the problem here.
+17
View File
@@ -0,0 +1,17 @@
---
name: Feature Request
about: Suggest an idea
labels: enhancement
---
### Describe the feature youd like
A clear and concise description of what youd like to be able to do with Toy.
### Describe alternatives you've considered
A clear and concise description of any alternative solutions or workarounds you've considered.
### Additional context
Add any other context about the feature request here.
+8 -2
View File
@@ -8,7 +8,6 @@ on:
jobs: jobs:
test-valgrind: test-valgrind:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
@@ -19,10 +18,17 @@ jobs:
run: make test run: make test
test-sanitized: test-sanitized:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
- name: make test (sanitized) - name: make test (sanitized)
run: make test-sanitized run: make test-sanitized
test-mingw32:
runs-on: windows-latest
steps:
- uses: actions/checkout@v3
- name: make test (mingw32)
run: make test
+1 -3
View File
@@ -21,9 +21,7 @@ Special thanks to http://craftinginterpreters.com/ for their fantastic book that
## Building ## Building
For Windows, Linux and MacOS, simply run `make` in the root directory. For Windows(mingw32 & cygwin), Linux and MacOS, simply run `make` in the root directory.
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! Note: MacOS is not officially supported (no machines for testing), but we'll do our best!
+2
View File
@@ -2,6 +2,8 @@
# export CFLAGS+=-O2 -mtune=native -march=native # export CFLAGS+=-O2 -mtune=native -march=native
# export CFLAGS+=-fsanitize=address,undefined # export CFLAGS+=-fsanitize=address,undefined
export CFLAGS+=-std=c18 -pedantic -Werror
export TOY_OUTDIR = out export TOY_OUTDIR = out
all: $(TOY_OUTDIR) repl all: $(TOY_OUTDIR) repl
+162
View File
@@ -0,0 +1,162 @@
#include "lib_about.h"
#include "toy_memory.h"
int Toy_hookAbout(Toy_Interpreter* interpreter, Toy_Literal identifier, Toy_Literal alias) {
//the about keys
Toy_Literal majorKeyLiteral = TOY_TO_STRING_LITERAL(Toy_createRefString("major"));
Toy_Literal minorKeyLiteral = TOY_TO_STRING_LITERAL(Toy_createRefString("minor"));
Toy_Literal patchKeyLiteral = TOY_TO_STRING_LITERAL(Toy_createRefString("patch"));
Toy_Literal buildKeyLiteral = TOY_TO_STRING_LITERAL(Toy_createRefString("build"));
Toy_Literal authorKeyLiteral = TOY_TO_STRING_LITERAL(Toy_createRefString("author"));
//the about identifiers
Toy_Literal majorIdentifierLiteral = TOY_TO_IDENTIFIER_LITERAL(Toy_createRefString("major"));
Toy_Literal minorIdentifierLiteral = TOY_TO_IDENTIFIER_LITERAL(Toy_createRefString("minor"));
Toy_Literal patchIdentifierLiteral = TOY_TO_IDENTIFIER_LITERAL(Toy_createRefString("patch"));
Toy_Literal buildIdentifierLiteral = TOY_TO_IDENTIFIER_LITERAL(Toy_createRefString("build"));
Toy_Literal authorIdentifierLiteral = TOY_TO_IDENTIFIER_LITERAL(Toy_createRefString("author"));
//the about values
Toy_Literal majorLiteral = TOY_TO_INTEGER_LITERAL(TOY_VERSION_MAJOR);
Toy_Literal minorLiteral = TOY_TO_INTEGER_LITERAL(TOY_VERSION_MINOR);
Toy_Literal patchLiteral = TOY_TO_INTEGER_LITERAL(TOY_VERSION_PATCH);
Toy_Literal buildLiteral = TOY_TO_STRING_LITERAL(Toy_createRefString(TOY_VERSION_BUILD));
Toy_Literal authorLiteral = TOY_TO_STRING_LITERAL(Toy_createRefString("Kayne Ruse, KR Game Studios"));
//store as an aliased dictionary
if (!TOY_IS_NULL(alias)) {
//make sure the name isn't taken
if (Toy_isDelcaredScopeVariable(interpreter->scope, alias)) {
interpreter->errorOutput("Can't override an existing variable\n");
Toy_freeLiteral(alias);
Toy_freeLiteral(majorKeyLiteral);
Toy_freeLiteral(minorKeyLiteral);
Toy_freeLiteral(patchKeyLiteral);
Toy_freeLiteral(buildKeyLiteral);
Toy_freeLiteral(authorKeyLiteral);
Toy_freeLiteral(majorIdentifierLiteral);
Toy_freeLiteral(minorIdentifierLiteral);
Toy_freeLiteral(patchIdentifierLiteral);
Toy_freeLiteral(buildIdentifierLiteral);
Toy_freeLiteral(authorIdentifierLiteral);
Toy_freeLiteral(majorLiteral);
Toy_freeLiteral(minorLiteral);
Toy_freeLiteral(patchLiteral);
Toy_freeLiteral(buildLiteral);
Toy_freeLiteral(authorLiteral);
return -1;
}
//create the dictionary to load up with values
Toy_LiteralDictionary* dictionary = TOY_ALLOCATE(Toy_LiteralDictionary, 1);
Toy_initLiteralDictionary(dictionary);
//set each key/value pair
Toy_setLiteralDictionary(dictionary, majorKeyLiteral, majorLiteral);
Toy_setLiteralDictionary(dictionary, minorKeyLiteral, minorLiteral);
Toy_setLiteralDictionary(dictionary, patchKeyLiteral, patchLiteral);
Toy_setLiteralDictionary(dictionary, buildKeyLiteral, buildLiteral);
Toy_setLiteralDictionary(dictionary, authorKeyLiteral, authorLiteral);
//build the type
Toy_Literal type = TOY_TO_TYPE_LITERAL(TOY_LITERAL_DICTIONARY, true);
Toy_Literal strType = TOY_TO_TYPE_LITERAL(TOY_LITERAL_STRING, true);
Toy_Literal anyType = TOY_TO_TYPE_LITERAL(TOY_LITERAL_ANY, true);
TOY_TYPE_PUSH_SUBTYPE(&type, strType);
TOY_TYPE_PUSH_SUBTYPE(&type, anyType);
//set scope
Toy_Literal dict = TOY_TO_DICTIONARY_LITERAL(dictionary);
Toy_declareScopeVariable(interpreter->scope, alias, type);
Toy_setScopeVariable(interpreter->scope, alias, dict, false);
//cleanup
Toy_freeLiteral(dict);
Toy_freeLiteral(type);
}
//store globally
else {
//make sure the names aren't taken
if (Toy_isDelcaredScopeVariable(interpreter->scope, majorKeyLiteral) ||
Toy_isDelcaredScopeVariable(interpreter->scope, minorKeyLiteral) ||
Toy_isDelcaredScopeVariable(interpreter->scope, patchKeyLiteral) ||
Toy_isDelcaredScopeVariable(interpreter->scope, buildKeyLiteral) ||
Toy_isDelcaredScopeVariable(interpreter->scope, authorKeyLiteral)) {
interpreter->errorOutput("Can't override an existing variable\n");
Toy_freeLiteral(alias);
Toy_freeLiteral(majorKeyLiteral);
Toy_freeLiteral(minorKeyLiteral);
Toy_freeLiteral(patchKeyLiteral);
Toy_freeLiteral(buildKeyLiteral);
Toy_freeLiteral(authorKeyLiteral);
Toy_freeLiteral(majorIdentifierLiteral);
Toy_freeLiteral(minorIdentifierLiteral);
Toy_freeLiteral(patchIdentifierLiteral);
Toy_freeLiteral(buildIdentifierLiteral);
Toy_freeLiteral(authorIdentifierLiteral);
Toy_freeLiteral(majorLiteral);
Toy_freeLiteral(minorLiteral);
Toy_freeLiteral(patchLiteral);
Toy_freeLiteral(buildLiteral);
Toy_freeLiteral(authorLiteral);
return -1;
}
Toy_Literal intType = TOY_TO_TYPE_LITERAL(TOY_LITERAL_INTEGER, true);
Toy_Literal strType = TOY_TO_TYPE_LITERAL(TOY_LITERAL_STRING, true);
//major
Toy_declareScopeVariable(interpreter->scope, majorIdentifierLiteral, intType);
Toy_setScopeVariable(interpreter->scope, majorIdentifierLiteral, majorLiteral, false);
//minor
Toy_declareScopeVariable(interpreter->scope, minorIdentifierLiteral, intType);
Toy_setScopeVariable(interpreter->scope, minorIdentifierLiteral, minorLiteral, false);
//patch
Toy_declareScopeVariable(interpreter->scope, patchIdentifierLiteral, intType);
Toy_setScopeVariable(interpreter->scope, patchIdentifierLiteral, patchLiteral, false);
//build
Toy_declareScopeVariable(interpreter->scope, buildIdentifierLiteral, strType);
Toy_setScopeVariable(interpreter->scope, buildIdentifierLiteral, buildLiteral, false);
//author
Toy_declareScopeVariable(interpreter->scope, authorIdentifierLiteral, strType);
Toy_setScopeVariable(interpreter->scope, authorIdentifierLiteral, authorLiteral, false);
Toy_freeLiteral(intType);
Toy_freeLiteral(strType);
}
//cleanup
Toy_freeLiteral(majorKeyLiteral);
Toy_freeLiteral(minorKeyLiteral);
Toy_freeLiteral(patchKeyLiteral);
Toy_freeLiteral(buildKeyLiteral);
Toy_freeLiteral(authorKeyLiteral);
Toy_freeLiteral(majorIdentifierLiteral);
Toy_freeLiteral(minorIdentifierLiteral);
Toy_freeLiteral(patchIdentifierLiteral);
Toy_freeLiteral(buildIdentifierLiteral);
Toy_freeLiteral(authorIdentifierLiteral);
Toy_freeLiteral(majorLiteral);
Toy_freeLiteral(minorLiteral);
Toy_freeLiteral(patchLiteral);
Toy_freeLiteral(buildLiteral);
Toy_freeLiteral(authorLiteral);
return 0;
}
+6
View File
@@ -0,0 +1,6 @@
#pragma once
#include "toy_interpreter.h"
int Toy_hookAbout(Toy_Interpreter* interpreter, Toy_Literal identifier, Toy_Literal alias);
+1003
View File
File diff suppressed because it is too large Load Diff
+6
View File
@@ -0,0 +1,6 @@
#pragma once
#include "toy_interpreter.h"
int Toy_hookCompound(Toy_Interpreter* interpreter, Toy_Literal identifier, Toy_Literal alias);
+95 -62
View File
@@ -24,72 +24,27 @@ static int nativeLoadScript(Toy_Interpreter* interpreter, Toy_LiteralArray* argu
return -1; return -1;
} }
//get the argument //get the file path literal with a handle
Toy_Literal drivePathLiteral = Toy_popLiteralArray(arguments); Toy_Literal drivePathLiteral = Toy_popLiteralArray(arguments);
Toy_RefString* drivePath = Toy_copyRefString(TOY_AS_STRING(drivePathLiteral));
//get the drive and path as a string (can't trust that pesky strtok - custom split) TODO: move this to refstring library Toy_Literal drivePathLiteralIdn = drivePathLiteral;
int driveLength = 0; if (TOY_IS_IDENTIFIER(drivePathLiteral) && Toy_parseIdentifierToValue(interpreter, &drivePathLiteral)) {
while (Toy_toCString(drivePath)[driveLength] != ':') { Toy_freeLiteral(drivePathLiteralIdn);
if (driveLength >= Toy_lengthRefString(drivePath)) { }
interpreter->errorOutput("Incorrect drive path format given to loadScript\n");
Toy_deleteRefString(drivePath); Toy_Literal filePathLiteral = Toy_getFilePathLiteral(interpreter, &drivePathLiteral);
if (TOY_IS_NULL(filePathLiteral)) {
Toy_freeLiteral(filePathLiteral);
Toy_freeLiteral(drivePathLiteral); Toy_freeLiteral(drivePathLiteral);
return -1; return -1;
} }
driveLength++;
}
Toy_RefString* drive = Toy_createRefStringLength(Toy_toCString(drivePath), driveLength);
Toy_RefString* path = Toy_createRefStringLength( &Toy_toCString(drivePath)[driveLength + 1], Toy_lengthRefString(drivePath) - driveLength );
//get the real drive file path
Toy_Literal driveLiteral = TOY_TO_STRING_LITERAL(drive); //NOTE: driveLiteral takes ownership of the refString
Toy_Literal realDriveLiteral = Toy_getLiteralDictionary(Toy_getDriveDictionary(), driveLiteral);
if (!TOY_IS_STRING(realDriveLiteral)) {
interpreter->errorOutput("Incorrect literal type found for drive: ");
Toy_printLiteralCustom(realDriveLiteral, interpreter->errorOutput);
interpreter->errorOutput("\n");
Toy_freeLiteral(realDriveLiteral);
Toy_freeLiteral(driveLiteral);
Toy_deleteRefString(path);
Toy_deleteRefString(drivePath);
Toy_freeLiteral(drivePathLiteral);
return -1;
}
//get the final real file path (concat) TODO: move this concat to refstring library
Toy_RefString* realDrive = Toy_copyRefString(TOY_AS_STRING(realDriveLiteral));
int realLength = Toy_lengthRefString(realDrive) + Toy_lengthRefString(path);
char* filePath = TOY_ALLOCATE(char, realLength + 1); //+1 for null
snprintf(filePath, realLength, "%s%s", Toy_toCString(realDrive), Toy_toCString(path));
//clean up the drivepath stuff
Toy_deleteRefString(realDrive);
Toy_freeLiteral(realDriveLiteral);
Toy_freeLiteral(driveLiteral);
Toy_deleteRefString(path);
Toy_deleteRefString(drivePath);
Toy_freeLiteral(drivePathLiteral); Toy_freeLiteral(drivePathLiteral);
//check for file extensions //use raw types - easier
if (!(filePath[realLength - 5] == '.' && filePath[realLength - 4] == 't' && filePath[realLength - 3] == 'o' && filePath[realLength - 2] == 'y')) { char* filePath = Toy_toCString(TOY_AS_STRING(filePathLiteral));
interpreter->errorOutput("Bad script file extension (expected .toy)\n"); int filePathLength = Toy_lengthRefString(TOY_AS_STRING(filePathLiteral));
TOY_FREE_ARRAY(char, filePath, realLength);
return -1;
}
//check for break-out attempts
for (int i = 0; i < realLength - 1; i++) {
if (filePath[i] == '.' && filePath[i + 1] == '.') {
interpreter->errorOutput("Parent directory access not allowed\n");
TOY_FREE_ARRAY(char, filePath, realLength);
return -1;
}
}
//load and compile the bytecode //load and compile the bytecode
size_t fileSize = 0; size_t fileSize = 0;
@@ -97,6 +52,7 @@ static int nativeLoadScript(Toy_Interpreter* interpreter, Toy_LiteralArray* argu
if (!source) { if (!source) {
interpreter->errorOutput("Failed to load source file\n"); interpreter->errorOutput("Failed to load source file\n");
Toy_freeLiteral(filePathLiteral);
return -1; return -1;
} }
@@ -105,6 +61,7 @@ static int nativeLoadScript(Toy_Interpreter* interpreter, Toy_LiteralArray* argu
if (!bytecode) { if (!bytecode) {
interpreter->errorOutput("Failed to compile source file\n"); interpreter->errorOutput("Failed to compile source file\n");
Toy_freeLiteral(filePathLiteral);
return -1; return -1;
} }
@@ -124,7 +81,8 @@ static int nativeLoadScript(Toy_Interpreter* interpreter, Toy_LiteralArray* argu
Toy_Literal runnerLiteral = TOY_TO_OPAQUE_LITERAL(runner, TOY_OPAQUE_TAG_RUNNER); Toy_Literal runnerLiteral = TOY_TO_OPAQUE_LITERAL(runner, TOY_OPAQUE_TAG_RUNNER);
Toy_pushLiteralArray(&interpreter->stack, runnerLiteral); Toy_pushLiteralArray(&interpreter->stack, runnerLiteral);
TOY_FREE_ARRAY(char, filePath, realLength); //free the drive path
Toy_freeLiteral(filePathLiteral);
return 1; return 1;
} }
@@ -138,6 +96,12 @@ static int nativeLoadScriptBytecode(Toy_Interpreter* interpreter, Toy_LiteralArr
//get the argument //get the argument
Toy_Literal drivePathLiteral = Toy_popLiteralArray(arguments); Toy_Literal drivePathLiteral = Toy_popLiteralArray(arguments);
Toy_Literal drivePathLiteralIdn = drivePathLiteral;
if (TOY_IS_IDENTIFIER(drivePathLiteral) && Toy_parseIdentifierToValue(interpreter, &drivePathLiteral)) {
Toy_freeLiteral(drivePathLiteralIdn);
}
Toy_RefString* drivePath = Toy_copyRefString(TOY_AS_STRING(drivePathLiteral)); Toy_RefString* drivePath = Toy_copyRefString(TOY_AS_STRING(drivePathLiteral));
//get the drive and path as a string (can't trust that pesky strtok - custom split) TODO: move this to refstring library //get the drive and path as a string (can't trust that pesky strtok - custom split) TODO: move this to refstring library
@@ -552,7 +516,7 @@ int Toy_hookRunner(Toy_Interpreter* interpreter, Toy_Literal identifier, Toy_Lit
if (Toy_isDelcaredScopeVariable(interpreter->scope, alias)) { if (Toy_isDelcaredScopeVariable(interpreter->scope, alias)) {
interpreter->errorOutput("Can't override an existing variable\n"); interpreter->errorOutput("Can't override an existing variable\n");
Toy_freeLiteral(alias); Toy_freeLiteral(alias);
return false; return -1;
} }
//create the dictionary to load up with functions //create the dictionary to load up with functions
@@ -562,8 +526,7 @@ int Toy_hookRunner(Toy_Interpreter* interpreter, Toy_Literal identifier, Toy_Lit
//load the dict with functions //load the dict with functions
for (int i = 0; natives[i].name; i++) { for (int i = 0; natives[i].name; i++) {
Toy_Literal name = TOY_TO_STRING_LITERAL(Toy_createRefString(natives[i].name)); Toy_Literal name = TOY_TO_STRING_LITERAL(Toy_createRefString(natives[i].name));
Toy_Literal func = TOY_TO_FUNCTION_LITERAL((void*)natives[i].fn, 0); Toy_Literal func = TOY_TO_FUNCTION_NATIVE_LITERAL(natives[i].fn);
func.type = TOY_LITERAL_FUNCTION_NATIVE;
Toy_setLiteralDictionary(dictionary, name, func); Toy_setLiteralDictionary(dictionary, name, func);
@@ -611,3 +574,73 @@ void Toy_freeDriveDictionary() {
Toy_LiteralDictionary* Toy_getDriveDictionary() { Toy_LiteralDictionary* Toy_getDriveDictionary() {
return &Toy_driveDictionary; return &Toy_driveDictionary;
} }
Toy_Literal Toy_getFilePathLiteral(Toy_Interpreter* interpreter, Toy_Literal* drivePathLiteral) {
//check argument types
if (!TOY_IS_STRING(*drivePathLiteral)) {
interpreter->errorOutput("Incorrect argument type passed to Toy_getFilePathLiteral\n");
return TOY_TO_NULL_LITERAL;
}
Toy_RefString* drivePath = Toy_copyRefString(TOY_AS_STRING(*drivePathLiteral));
//get the drive and path as a string (can't trust that pesky strtok - custom split) TODO: move this to refstring library
int driveLength = 0;
while (Toy_toCString(drivePath)[driveLength] != ':') {
if (driveLength >= Toy_lengthRefString(drivePath)) {
interpreter->errorOutput("Incorrect drive path format given to Toy_getFilePathLiteral\n");
return TOY_TO_NULL_LITERAL;
}
driveLength++;
}
Toy_RefString* drive = Toy_createRefStringLength(Toy_toCString(drivePath), driveLength);
Toy_RefString* path = Toy_createRefStringLength( &Toy_toCString(drivePath)[driveLength + 1], Toy_lengthRefString(drivePath) - driveLength );
//get the real drive file path
Toy_Literal driveLiteral = TOY_TO_STRING_LITERAL(drive); //NOTE: driveLiteral takes ownership of the refString
Toy_Literal realDriveLiteral = Toy_getLiteralDictionary(Toy_getDriveDictionary(), driveLiteral);
if (!TOY_IS_STRING(realDriveLiteral)) {
interpreter->errorOutput("Incorrect literal type found for drive: ");
Toy_printLiteralCustom(realDriveLiteral, interpreter->errorOutput);
interpreter->errorOutput("\n");
Toy_freeLiteral(realDriveLiteral);
Toy_freeLiteral(driveLiteral);
Toy_deleteRefString(path);
Toy_deleteRefString(drivePath);
return TOY_TO_NULL_LITERAL;
}
//get the final real file path (concat) TODO: move this concat to refstring library
Toy_RefString* realDrive = Toy_copyRefString(TOY_AS_STRING(realDriveLiteral));
int realLength = Toy_lengthRefString(realDrive) + Toy_lengthRefString(path);
char* filePath = TOY_ALLOCATE(char, realLength + 1); //+1 for null
snprintf(filePath, realLength, "%s%s", Toy_toCString(realDrive), Toy_toCString(path));
//clean up the drivepath stuff
Toy_deleteRefString(realDrive);
Toy_freeLiteral(realDriveLiteral);
Toy_freeLiteral(driveLiteral);
Toy_deleteRefString(path);
Toy_deleteRefString(drivePath);
//check for break-out attempts
for (int i = 0; i < realLength - 1; i++) {
if (filePath[i] == '.' && filePath[i + 1] == '.') {
interpreter->errorOutput("Parent directory access not allowed\n");
TOY_FREE_ARRAY(char, filePath, realLength + 1);
return TOY_TO_NULL_LITERAL;
}
}
Toy_Literal result = TOY_TO_STRING_LITERAL(Toy_createRefStringLength(filePath, realLength));
TOY_FREE_ARRAY(char, filePath, realLength + 1);
return result;
}
+3
View File
@@ -10,3 +10,6 @@ void Toy_freeDriveDictionary();
Toy_LiteralDictionary* Toy_getDriveDictionary(); Toy_LiteralDictionary* Toy_getDriveDictionary();
#define TOY_OPAQUE_TAG_RUNNER 100 #define TOY_OPAQUE_TAG_RUNNER 100
//file system API - for use with other libs
Toy_Literal Toy_getFilePathLiteral(Toy_Interpreter* interpreter, Toy_Literal* drivePathLiteral);
+2 -3
View File
@@ -49,7 +49,7 @@ int Toy_hookStandard(Toy_Interpreter* interpreter, Toy_Literal identifier, Toy_L
if (Toy_isDelcaredScopeVariable(interpreter->scope, alias)) { if (Toy_isDelcaredScopeVariable(interpreter->scope, alias)) {
interpreter->errorOutput("Can't override an existing variable\n"); interpreter->errorOutput("Can't override an existing variable\n");
Toy_freeLiteral(alias); Toy_freeLiteral(alias);
return false; return -1;
} }
//create the dictionary to load up with functions //create the dictionary to load up with functions
@@ -59,8 +59,7 @@ int Toy_hookStandard(Toy_Interpreter* interpreter, Toy_Literal identifier, Toy_L
//load the dict with functions //load the dict with functions
for (int i = 0; natives[i].name; i++) { for (int i = 0; natives[i].name; i++) {
Toy_Literal name = TOY_TO_STRING_LITERAL(Toy_createRefString(natives[i].name)); Toy_Literal name = TOY_TO_STRING_LITERAL(Toy_createRefString(natives[i].name));
Toy_Literal func = TOY_TO_FUNCTION_LITERAL((void*)natives[i].fn, 0); Toy_Literal func = TOY_TO_FUNCTION_NATIVE_LITERAL(natives[i].fn);
func.type = TOY_LITERAL_FUNCTION_NATIVE;
Toy_setLiteralDictionary(dictionary, name, func); Toy_setLiteralDictionary(dictionary, name, func);
+2 -3
View File
@@ -366,7 +366,7 @@ int Toy_hookTimer(Toy_Interpreter* interpreter, Toy_Literal identifier, Toy_Lite
if (Toy_isDelcaredScopeVariable(interpreter->scope, alias)) { if (Toy_isDelcaredScopeVariable(interpreter->scope, alias)) {
interpreter->errorOutput("Can't override an existing variable\n"); interpreter->errorOutput("Can't override an existing variable\n");
Toy_freeLiteral(alias); Toy_freeLiteral(alias);
return false; return -1;
} }
//create the dictionary to load up with functions //create the dictionary to load up with functions
@@ -376,8 +376,7 @@ int Toy_hookTimer(Toy_Interpreter* interpreter, Toy_Literal identifier, Toy_Lite
//load the dict with functions //load the dict with functions
for (int i = 0; natives[i].name; i++) { for (int i = 0; natives[i].name; i++) {
Toy_Literal name = TOY_TO_STRING_LITERAL(Toy_createRefString(natives[i].name)); Toy_Literal name = TOY_TO_STRING_LITERAL(Toy_createRefString(natives[i].name));
Toy_Literal func = TOY_TO_FUNCTION_LITERAL((void*)natives[i].fn, 0); Toy_Literal func = TOY_TO_FUNCTION_NATIVE_LITERAL(natives[i].fn);
func.type = TOY_LITERAL_FUNCTION_NATIVE;
Toy_setLiteralDictionary(dictionary, name, func); Toy_setLiteralDictionary(dictionary, name, func);
+29 -20
View File
@@ -1,4 +1,6 @@
#include "repl_tools.h" #include "repl_tools.h"
#include "lib_about.h"
#include "lib_compound.h"
#include "lib_standard.h" #include "lib_standard.h"
#include "lib_timer.h" #include "lib_timer.h"
#include "lib_runner.h" #include "lib_runner.h"
@@ -26,6 +28,8 @@ void repl() {
Toy_initInterpreter(&interpreter); Toy_initInterpreter(&interpreter);
//inject the libs //inject the libs
Toy_injectNativeHook(&interpreter, "about", Toy_hookAbout);
Toy_injectNativeHook(&interpreter, "compound", Toy_hookCompound);
Toy_injectNativeHook(&interpreter, "standard", Toy_hookStandard); Toy_injectNativeHook(&interpreter, "standard", Toy_hookStandard);
Toy_injectNativeHook(&interpreter, "timer", Toy_hookTimer); Toy_injectNativeHook(&interpreter, "timer", Toy_hookTimer);
Toy_injectNativeHook(&interpreter, "runner", Toy_hookRunner); Toy_injectNativeHook(&interpreter, "runner", Toy_hookRunner);
@@ -57,7 +61,9 @@ void repl() {
while(node != NULL) { while(node != NULL) {
//pack up and restart //pack up and restart
if (node->type == TOY_AST_NODE_ERROR) { if (node->type == TOY_AST_NODE_ERROR) {
printf(TOY_CC_ERROR "error node detected\n" TOY_CC_RESET); if (Toy_commandLine.verbose) {
printf(TOY_CC_ERROR "Error node detected\n" TOY_CC_RESET);
}
error = true; error = true;
Toy_freeASTNode(node); Toy_freeASTNode(node);
break; break;
@@ -88,7 +94,7 @@ void repl() {
//entry point //entry point
int main(int argc, const char* argv[]) { int main(int argc, const char* argv[]) {
Toy_initCommand(argc, argv); Toy_initCommandLine(argc, argv);
//lib setup (hacky - only really for this program) //lib setup (hacky - only really for this program)
Toy_initDriveDictionary(); Toy_initDriveDictionary();
@@ -101,30 +107,30 @@ int main(int argc, const char* argv[]) {
Toy_freeLiteral(driveLiteral); Toy_freeLiteral(driveLiteral);
Toy_freeLiteral(pathLiteral); Toy_freeLiteral(pathLiteral);
//command specific actions //command line specific actions
if (command.error) { if (Toy_commandLine.error) {
Toy_usageCommand(argc, argv); Toy_usageCommandLine(argc, argv);
return 0; return 0;
} }
if (command.help) { if (Toy_commandLine.help) {
Toy_helpCommand(argc, argv); Toy_helpCommandLine(argc, argv);
return 0; return 0;
} }
if (command.version) { if (Toy_commandLine.version) {
Toy_copyrightCommand(argc, argv); Toy_copyrightCommandLine(argc, argv);
return 0; return 0;
} }
//version //version
if (command.verbose) { if (Toy_commandLine.verbose) {
printf(TOY_CC_NOTICE "Toy Programming Language Version %d.%d.%d\n" TOY_CC_RESET, TOY_VERSION_MAJOR, TOY_VERSION_MINOR, TOY_VERSION_PATCH); printf(TOY_CC_NOTICE "Toy Programming Language Version %d.%d.%d, built '%s'\n" TOY_CC_RESET, TOY_VERSION_MAJOR, TOY_VERSION_MINOR, TOY_VERSION_PATCH, TOY_VERSION_BUILD);
} }
//run source file //run source file
if (command.sourcefile) { if (Toy_commandLine.sourcefile) {
Toy_runSourceFile(command.sourcefile); Toy_runSourceFile(Toy_commandLine.sourcefile);
//lib cleanup //lib cleanup
Toy_freeDriveDictionary(); Toy_freeDriveDictionary();
@@ -133,8 +139,8 @@ int main(int argc, const char* argv[]) {
} }
//run from stdin //run from stdin
if (command.source) { if (Toy_commandLine.source) {
Toy_runSource(command.source); Toy_runSource(Toy_commandLine.source);
//lib cleanup //lib cleanup
Toy_freeDriveDictionary(); Toy_freeDriveDictionary();
@@ -143,20 +149,23 @@ int main(int argc, const char* argv[]) {
} }
//compile source file //compile source file
if (command.compilefile && command.outfile) { if (Toy_commandLine.compilefile && Toy_commandLine.outfile) {
size_t size = 0; size_t size = 0;
char* source = Toy_readFile(command.compilefile, &size); char* source = Toy_readFile(Toy_commandLine.compilefile, &size);
if (!source) {
return 1;
}
unsigned char* tb = Toy_compileString(source, &size); unsigned char* tb = Toy_compileString(source, &size);
if (!tb) { if (!tb) {
return 1; return 1;
} }
Toy_writeFile(command.outfile, tb, size); Toy_writeFile(Toy_commandLine.outfile, tb, size);
return 0; return 0;
} }
//run binary //run binary
if (command.binaryfile) { if (Toy_commandLine.binaryfile) {
Toy_runBinaryFile(command.binaryfile); Toy_runBinaryFile(Toy_commandLine.binaryfile);
//lib cleanup //lib cleanup
Toy_freeDriveDictionary(); Toy_freeDriveDictionary();
+7
View File
@@ -1,4 +1,6 @@
#include "repl_tools.h" #include "repl_tools.h"
#include "lib_about.h"
#include "lib_compound.h"
#include "lib_standard.h" #include "lib_standard.h"
#include "lib_timer.h" #include "lib_timer.h"
#include "lib_runner.h" #include "lib_runner.h"
@@ -110,6 +112,8 @@ void Toy_runBinary(unsigned char* tb, size_t size) {
Toy_initInterpreter(&interpreter); Toy_initInterpreter(&interpreter);
//inject the libs //inject the libs
Toy_injectNativeHook(&interpreter, "about", Toy_hookAbout);
Toy_injectNativeHook(&interpreter, "compound", Toy_hookCompound);
Toy_injectNativeHook(&interpreter, "standard", Toy_hookStandard); Toy_injectNativeHook(&interpreter, "standard", Toy_hookStandard);
Toy_injectNativeHook(&interpreter, "timer", Toy_hookTimer); Toy_injectNativeHook(&interpreter, "timer", Toy_hookTimer);
Toy_injectNativeHook(&interpreter, "runner", Toy_hookRunner); Toy_injectNativeHook(&interpreter, "runner", Toy_hookRunner);
@@ -141,6 +145,9 @@ void Toy_runSource(char* source) {
void Toy_runSourceFile(char* fname) { void Toy_runSourceFile(char* fname) {
size_t size = 0; //not used size_t size = 0; //not used
char* source = Toy_readFile(fname, &size); char* source = Toy_readFile(fname, &size);
if (!source) {
return;
}
Toy_runSource(source); Toy_runSource(source);
free((void*)source); free((void*)source);
} }
+125
View File
@@ -0,0 +1,125 @@
import node;
//constants
var SPEED: int const = 10;
//variables
var parent: opaque = null;
var posX: int = 50;
var posY: int = 50;
var WIDTH: int const = 100;
var HEIGHT: int const = 100;
var xspeed: int = 0;
var yspeed: int = 0;
//accessors - variables are private, functions are public
fn getX(node: opaque) {
return posX;
}
fn getY(node: opaque) {
return posY;
}
//lifecycle functions
fn onInit(node: opaque) {
print "render.toy:onInit() called";
node.loadTexture("sprites:/character.png");
parent = node.getNodeParent();
}
fn onStep(node: opaque) {
posX += xspeed;
posY += yspeed;
}
fn onFree(node: opaque) {
print "render.toy:onFree() called";
node.freeTexture();
}
fn onDraw(node: opaque) {
// print "render.toy:onDraw() called";
var px = parent.callNode("getX");
var py = parent.callNode("getY");
if (px == null) {
px = 0;
}
if (py == null) {
py = 0;
}
node.drawNode(posX + px, posY + py, WIDTH, HEIGHT);
}
//event functions
fn onKeyDown(node: opaque, event: string) {
if (event == "character_up") {
yspeed -= SPEED;
return;
}
if (event == "character_down") {
yspeed += SPEED;
return;
}
if (event == "character_left") {
xspeed -= SPEED;
return;
}
if (event == "character_right") {
xspeed += SPEED;
return;
}
}
fn onKeyUp(node: opaque, event: string) {
if (event == "character_up" && yspeed < 0) {
yspeed = 0;
return;
}
if (event == "character_down" && yspeed > 0) {
yspeed = 0;
return;
}
if (event == "character_left" && xspeed < 0) {
xspeed = 0;
return;
}
if (event == "character_right" && xspeed > 0) {
xspeed = 0;
return;
}
}
fn onMouseMotion(node: opaque, x: int, y: int, xrel: int, yrel: int) {
print "entity.toy:onMouseMotion(" + string x + ", " + string y + ", " + string xrel + ", " + string yrel + ")";
}
fn onMouseButtonDown(node: opaque, x: int, y: int, button: string) {
print "entity.toy:onMouseButtonDown(" + string x + ", " + string y + ", " + button + ")";
//jump to pos
posX = x - WIDTH / 2;
posY = y - HEIGHT / 2;
}
fn onMouseButtonUp(node: opaque, x: int, y: int, button: string) {
print "entity.toy:onMouseButtonUp(" + string x + ", " + string y + ", " + button + ")";
}
fn onMouseWheel(node: opaque, xrel: int, yrel: int) {
print "entity.toy:onMouseWheel(" + string xrel + ", " + string yrel + ")";
}
+21
View File
@@ -0,0 +1,21 @@
//memoize the fib function
var memo: [int : int] = [:];
fn fib(n : int) {
if (n < 2) {
return n;
}
var result = memo[n];
if (result == null) {
result = fib(n-1) + fib(n-2);
memo[n] = result;
}
return result;
}
for (var i = 0; i < 40; i++) {
var res = fib(i);
print string i + ": " + string res;
}
+1 -4
View File
@@ -1,8 +1,5 @@
fn fib(n : int) { fn fib(n : int) {
if (n < 2) { if (n < 2) return n;
return n;
}
return fib(n-1) + fib(n-2); return fib(n-1) + fib(n-2);
} }
+2 -2
View File
@@ -1,5 +1,5 @@
//number of iterations //number of iterations
var SIZE: int const = 100; var SIZE: int const = 260;
//lookup table //lookup table
var lookup = [ var lookup = [
@@ -32,7 +32,7 @@ prev += "*"; //initial
print prev; print prev;
//run //run
for (var iteration = 0; iteration < 100; iteration++) { for (var iteration = 0; iteration < SIZE -1; iteration++) {
//left //left
var output = (lookup[" "][prev[0]][prev[1]]); var output = (lookup[" "][prev[0]][prev[1]]);
+4 -19
View File
@@ -1,21 +1,6 @@
//test basic truth ternaries import compound;
{ var arr: [int] = [1, 2, 3];
assert true ? true : false, "Basic true ternary failed"; fn f(_, v: int): int { return v + 1; }
assert false ? false : true, "Basic false ternary failed"; print arr.map(f);
}
//test nesting
{
fn least(a, b, c) {
return a < b ? a : b < c ? b : c;
}
assert least(1, 2, 3) == 1, "Least 1, 2, 3 failed";
assert least(10, 5, 7) == 5, "Least 10, 5, 7 failed";
assert least(9, 7, 5) == 5, "Least 9, 7, 5 failed";
}
print "All good";
+259 -133
View File
@@ -249,7 +249,7 @@ static Toy_Literal modulo(Toy_Interpreter* interpreter, Toy_Literal lhs, Toy_Lit
return TOY_TO_NULL_LITERAL; return TOY_TO_NULL_LITERAL;
} }
int _index(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) { int Toy_private_index(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
//_index(compound, first, second, third, assignValue, op) //_index(compound, first, second, third, assignValue, op)
Toy_Literal op = Toy_popLiteralArray(arguments); Toy_Literal op = Toy_popLiteralArray(arguments);
Toy_Literal assign = Toy_popLiteralArray(arguments); Toy_Literal assign = Toy_popLiteralArray(arguments);
@@ -258,8 +258,6 @@ int _index(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
Toy_Literal first = Toy_popLiteralArray(arguments); Toy_Literal first = Toy_popLiteralArray(arguments);
Toy_Literal compound = Toy_popLiteralArray(arguments); Toy_Literal compound = Toy_popLiteralArray(arguments);
Toy_Literal value = TOY_TO_NULL_LITERAL;
//dictionary - no slicing //dictionary - no slicing
if (TOY_IS_DICTIONARY(compound)) { if (TOY_IS_DICTIONARY(compound)) {
if (TOY_IS_IDENTIFIER(first)) { if (TOY_IS_IDENTIFIER(first)) {
@@ -280,7 +278,22 @@ int _index(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
Toy_freeLiteral(idn); Toy_freeLiteral(idn);
} }
value = Toy_getLiteralDictionary(TOY_AS_DICTIONARY(compound), first); //second and third are bad args to dictionaries
if (!TOY_IS_NULL(second) || !TOY_IS_NULL(third)) {
interpreter->errorOutput("Index slicing not allowed for dictionaries\n");
Toy_freeLiteral(op);
Toy_freeLiteral(assign);
Toy_freeLiteral(third);
Toy_freeLiteral(second);
Toy_freeLiteral(first);
Toy_freeLiteral(compound);
return -1;
}
//get the value
Toy_Literal value = Toy_getLiteralDictionary(TOY_AS_DICTIONARY(compound), first);
//dictionary //dictionary
if (TOY_IS_NULL(op)) { if (TOY_IS_NULL(op)) {
@@ -330,6 +343,19 @@ int _index(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
Toy_setLiteralDictionary(TOY_AS_DICTIONARY(compound), first, lit); Toy_setLiteralDictionary(TOY_AS_DICTIONARY(compound), first, lit);
Toy_freeLiteral(lit); Toy_freeLiteral(lit);
} }
//leave the dictionary on the stack
Toy_pushLiteralArray(&interpreter->stack, compound);
Toy_freeLiteral(op);
Toy_freeLiteral(assign);
Toy_freeLiteral(third);
Toy_freeLiteral(second);
Toy_freeLiteral(first);
Toy_freeLiteral(compound);
Toy_freeLiteral(value);
return 1;
} }
//array - slicing //array - slicing
@@ -374,8 +400,10 @@ int _index(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
Toy_freeLiteral(idn); Toy_freeLiteral(idn);
} }
//handle each null case //handle each error case
if (TOY_IS_NULL(first) || !TOY_IS_INTEGER(first)) { if (!TOY_IS_INTEGER(first) || TOY_AS_INTEGER(first) < 0 || TOY_AS_INTEGER(first) >= TOY_AS_ARRAY(compound)->count) {
interpreter->errorOutput("Bad first indexing\n");
//something is weird - skip out //something is weird - skip out
Toy_freeLiteral(op); Toy_freeLiteral(op);
Toy_freeLiteral(assign); Toy_freeLiteral(assign);
@@ -383,17 +411,42 @@ int _index(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
Toy_freeLiteral(second); Toy_freeLiteral(second);
Toy_freeLiteral(first); Toy_freeLiteral(first);
Toy_freeLiteral(compound); Toy_freeLiteral(compound);
Toy_freeLiteral(value);
return -1; return -1;
} }
if (TOY_IS_NULL(second)) { //assign only a single character if ((!TOY_IS_NULL(second) && !TOY_IS_INTEGER(second)) || TOY_AS_INTEGER(second) < 0 || TOY_AS_INTEGER(second) >= TOY_AS_ARRAY(compound)->count) {
//get the "first" within the array, then skip out interpreter->errorOutput("Bad second indexing\n");
Toy_freeLiteral(value); //something is weird - skip out
value = Toy_getLiteralArray(TOY_AS_ARRAY(compound), first); Toy_freeLiteral(op);
Toy_pushLiteralArray(&interpreter->stack, value); Toy_freeLiteral(assign);
Toy_freeLiteral(third);
Toy_freeLiteral(second);
Toy_freeLiteral(first);
Toy_freeLiteral(compound);
return -1;
}
if ((!TOY_IS_NULL(third) && !TOY_IS_INTEGER(third)) || TOY_AS_INTEGER(third) == 0) {
interpreter->errorOutput("Bad third indexing\n");
//something is weird - skip out
Toy_freeLiteral(op);
Toy_freeLiteral(assign);
Toy_freeLiteral(third);
Toy_freeLiteral(second);
Toy_freeLiteral(first);
Toy_freeLiteral(compound);
return -1;
}
//simple indexing if second is null
if (TOY_IS_NULL(second)) {
Toy_Literal result = Toy_getLiteralArray(TOY_AS_ARRAY(compound), first);
Toy_pushLiteralArray(&interpreter->stack, result);
Toy_freeLiteral(op); Toy_freeLiteral(op);
Toy_freeLiteral(assign); Toy_freeLiteral(assign);
@@ -401,32 +454,18 @@ int _index(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
Toy_freeLiteral(second); Toy_freeLiteral(second);
Toy_freeLiteral(first); Toy_freeLiteral(first);
Toy_freeLiteral(compound); Toy_freeLiteral(compound);
Toy_freeLiteral(value); Toy_freeLiteral(result);
return 1; return 1;
} }
if (!TOY_IS_INTEGER(second) || (!TOY_IS_NULL(third) && !TOY_IS_INTEGER(third)) || TOY_AS_INTEGER(second) < 0 || TOY_AS_INTEGER(second) > TOY_AS_ARRAY(compound)->count || TOY_AS_INTEGER(third) == 0) {
//something is weird - skip out
Toy_freeLiteral(op);
Toy_freeLiteral(assign);
Toy_freeLiteral(third);
Toy_freeLiteral(second);
Toy_freeLiteral(first);
Toy_freeLiteral(compound);
Toy_freeLiteral(value);
return -1;
}
//start building a new array from the old one //start building a new array from the old one
Toy_LiteralArray* result = TOY_ALLOCATE(Toy_LiteralArray, 1); Toy_LiteralArray* result = TOY_ALLOCATE(Toy_LiteralArray, 1);
Toy_initLiteralArray(result); Toy_initLiteralArray(result);
int min = TOY_AS_INTEGER(third) > 0 ? TOY_AS_INTEGER(first) : TOY_AS_INTEGER(second);
//copy compound into result //copy compound into result
for (int i = min; i >= 0 && i <= TOY_AS_ARRAY(compound)->count && i >= TOY_AS_INTEGER(first) && i <= TOY_AS_INTEGER(second); i += TOY_AS_INTEGER(third)) { if (TOY_AS_INTEGER(third) > 0) {
for (int i = TOY_AS_INTEGER(first); i <= TOY_AS_INTEGER(second); i += TOY_AS_INTEGER(third)) {
Toy_Literal idx = TOY_TO_INTEGER_LITERAL(i); Toy_Literal idx = TOY_TO_INTEGER_LITERAL(i);
Toy_Literal tmp = Toy_getLiteralArray(TOY_AS_ARRAY(compound), idx); Toy_Literal tmp = Toy_getLiteralArray(TOY_AS_ARRAY(compound), idx);
Toy_pushLiteralArray(result, tmp); Toy_pushLiteralArray(result, tmp);
@@ -434,10 +473,33 @@ int _index(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
Toy_freeLiteral(idx); Toy_freeLiteral(idx);
Toy_freeLiteral(tmp); Toy_freeLiteral(tmp);
} }
}
else {
for (int i = TOY_AS_INTEGER(second); i >= TOY_AS_INTEGER(first); i += TOY_AS_INTEGER(third)) {
Toy_Literal idx = TOY_TO_INTEGER_LITERAL(i);
Toy_Literal tmp = Toy_getLiteralArray(TOY_AS_ARRAY(compound), idx);
Toy_pushLiteralArray(result, tmp);
Toy_freeLiteral(idx);
Toy_freeLiteral(tmp);
}
}
//finally, swap out the compound for the result //finally, swap out the compound for the result
Toy_freeLiteral(compound); Toy_freeLiteral(compound);
compound = TOY_TO_ARRAY_LITERAL(result); compound = TOY_TO_ARRAY_LITERAL(result);
//leave the array on the stack
Toy_pushLiteralArray(&interpreter->stack, compound);
Toy_freeLiteral(op);
Toy_freeLiteral(assign);
Toy_freeLiteral(third);
Toy_freeLiteral(second);
Toy_freeLiteral(first);
Toy_freeLiteral(compound);
return 1;
} }
//array slice assignment //array slice assignment
@@ -480,8 +542,10 @@ int _index(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
Toy_freeLiteral(idn); Toy_freeLiteral(idn);
} }
//handle each null case //handle each error case
if (TOY_IS_NULL(first) || !TOY_IS_INTEGER(first)) { if (!TOY_IS_INTEGER(first) || TOY_AS_INTEGER(first) < 0 || TOY_AS_INTEGER(first) >= TOY_AS_ARRAY(compound)->count) {
interpreter->errorOutput("Bad first indexing assignment\n");
//something is weird - skip out //something is weird - skip out
Toy_freeLiteral(op); Toy_freeLiteral(op);
Toy_freeLiteral(assign); Toy_freeLiteral(assign);
@@ -489,51 +553,59 @@ int _index(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
Toy_freeLiteral(second); Toy_freeLiteral(second);
Toy_freeLiteral(first); Toy_freeLiteral(first);
Toy_freeLiteral(compound); Toy_freeLiteral(compound);
Toy_freeLiteral(value);
return -1; return -1;
} }
if ((!TOY_IS_NULL(second) && !TOY_IS_INTEGER(second)) || TOY_AS_INTEGER(second) < 0 || TOY_AS_INTEGER(second) >= TOY_AS_ARRAY(compound)->count) {
interpreter->errorOutput("Bad second indexing assignment\n");
//something is weird - skip out
Toy_freeLiteral(op);
Toy_freeLiteral(assign);
Toy_freeLiteral(third);
Toy_freeLiteral(second);
Toy_freeLiteral(first);
Toy_freeLiteral(compound);
return -1;
}
if ((!TOY_IS_NULL(third) && !TOY_IS_INTEGER(third)) || TOY_AS_INTEGER(third) == 0) {
interpreter->errorOutput("Bad third indexing assignment\n");
//something is weird - skip out
Toy_freeLiteral(op);
Toy_freeLiteral(assign);
Toy_freeLiteral(third);
Toy_freeLiteral(second);
Toy_freeLiteral(first);
Toy_freeLiteral(compound);
return -1;
}
//simple indexing assignment if second is null
if (TOY_IS_NULL(second)) { if (TOY_IS_NULL(second)) {
//set the "first" within the array, then skip out bool ret = -1;
if (!Toy_setLiteralArray(TOY_AS_ARRAY(compound), first, assign)) { if (!Toy_setLiteralArray(TOY_AS_ARRAY(compound), first, assign)) {
interpreter->errorOutput("Index assignment out of bounds\n"); interpreter->errorOutput("Array index out of bounds in assignment");
Toy_freeLiteral(op);
Toy_freeLiteral(assign);
Toy_freeLiteral(third);
Toy_freeLiteral(second);
Toy_freeLiteral(first);
Toy_freeLiteral(compound);
Toy_freeLiteral(value);
return -1; return -1;
} }
else {
Toy_pushLiteralArray(&interpreter->stack, compound); Toy_pushLiteralArray(&interpreter->stack, compound); //leave the array on the stack
ret = 1;
Toy_freeLiteral(op);
Toy_freeLiteral(assign);
Toy_freeLiteral(third);
Toy_freeLiteral(second);
Toy_freeLiteral(first);
Toy_freeLiteral(compound);
Toy_freeLiteral(value);
return 1;
} }
if (!TOY_IS_INTEGER(second) || (!TOY_IS_NULL(third) && !TOY_IS_INTEGER(third)) || TOY_AS_INTEGER(second) < 0 || TOY_AS_INTEGER(second) > TOY_AS_ARRAY(compound)->count || TOY_AS_INTEGER(third) == 0) {
//something is weird - skip out
Toy_freeLiteral(op); Toy_freeLiteral(op);
Toy_freeLiteral(assign); Toy_freeLiteral(assign);
Toy_freeLiteral(third); Toy_freeLiteral(third);
Toy_freeLiteral(second); Toy_freeLiteral(second);
Toy_freeLiteral(first); Toy_freeLiteral(first);
Toy_freeLiteral(compound); Toy_freeLiteral(compound);
Toy_freeLiteral(value);
return -1; return ret;
} }
//start building a new array from the old one //start building a new array from the old one
@@ -611,15 +683,28 @@ int _index(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
//finally, swap out the compound for the result //finally, swap out the compound for the result
Toy_freeLiteral(compound); Toy_freeLiteral(compound);
compound = TOY_TO_ARRAY_LITERAL(result); compound = TOY_TO_ARRAY_LITERAL(result);
//leave the array on the stack
Toy_pushLiteralArray(&interpreter->stack, compound);
Toy_freeLiteral(op);
Toy_freeLiteral(assign);
Toy_freeLiteral(third);
Toy_freeLiteral(second);
Toy_freeLiteral(first);
Toy_freeLiteral(compound);
return 1;
} }
//assignment and other operations
if (TOY_IS_IDENTIFIER(first)) { if (TOY_IS_IDENTIFIER(first)) {
Toy_Literal idn = first; Toy_Literal idn = first;
Toy_parseIdentifierToValue(interpreter, &first); Toy_parseIdentifierToValue(interpreter, &first);
Toy_freeLiteral(idn); Toy_freeLiteral(idn);
} }
value = Toy_getLiteralArray(TOY_AS_ARRAY(compound), first); Toy_Literal value = Toy_getLiteralArray(TOY_AS_ARRAY(compound), first);
if (TOY_IS_STRING(op) && Toy_equalsRefStringCString(TOY_AS_STRING(op), "+=")) { if (TOY_IS_STRING(op) && Toy_equalsRefStringCString(TOY_AS_STRING(op), "+=")) {
Toy_Literal lit = addition(interpreter, value, assign); Toy_Literal lit = addition(interpreter, value, assign);
@@ -650,6 +735,18 @@ int _index(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
Toy_setLiteralArray(TOY_AS_ARRAY(compound), first, lit); Toy_setLiteralArray(TOY_AS_ARRAY(compound), first, lit);
Toy_freeLiteral(lit); Toy_freeLiteral(lit);
} }
//leave the array on the stack
Toy_pushLiteralArray(&interpreter->stack, compound);
Toy_freeLiteral(op);
Toy_freeLiteral(assign);
Toy_freeLiteral(third);
Toy_freeLiteral(second);
Toy_freeLiteral(first);
Toy_freeLiteral(compound);
return 1;
} }
//string - slicing //string - slicing
@@ -674,7 +771,7 @@ int _index(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
if (!TOY_IS_NULL(second)) { if (!TOY_IS_NULL(second)) {
if (TOY_IS_INDEX_BLANK(second)) { if (TOY_IS_INDEX_BLANK(second)) {
Toy_freeLiteral(second); Toy_freeLiteral(second);
second = TOY_TO_INTEGER_LITERAL(compoundLength); second = TOY_TO_INTEGER_LITERAL(compoundLength - 1);
} }
if (TOY_IS_IDENTIFIER(second)) { if (TOY_IS_IDENTIFIER(second)) {
@@ -695,8 +792,10 @@ int _index(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
Toy_freeLiteral(idn); Toy_freeLiteral(idn);
} }
//handle each null case //handle each error case
if (TOY_IS_NULL(first) || !TOY_IS_INTEGER(first)) { if (!TOY_IS_INTEGER(first) || TOY_AS_INTEGER(first) < 0 || TOY_AS_INTEGER(first) >= TOY_AS_STRING(compound)->length) {
interpreter->errorOutput("Bad first indexing in string\n");
//something is weird - skip out //something is weird - skip out
Toy_freeLiteral(op); Toy_freeLiteral(op);
Toy_freeLiteral(assign); Toy_freeLiteral(assign);
@@ -704,22 +803,48 @@ int _index(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
Toy_freeLiteral(second); Toy_freeLiteral(second);
Toy_freeLiteral(first); Toy_freeLiteral(first);
Toy_freeLiteral(compound); Toy_freeLiteral(compound);
Toy_freeLiteral(value);
return -1; return -1;
} }
if (TOY_IS_NULL(second)) { //assign only a single character if ((!TOY_IS_NULL(second) && !TOY_IS_INTEGER(second)) || TOY_AS_INTEGER(second) < 0 || TOY_AS_INTEGER(second) >= TOY_AS_STRING(compound)->length) {
char c = Toy_toCString(TOY_AS_STRING(compound))[TOY_AS_INTEGER(first)]; interpreter->errorOutput("Bad second indexing in string\n");
char buffer[16]; //something is weird - skip out
snprintf(buffer, 16, "%c", c); Toy_freeLiteral(op);
Toy_freeLiteral(assign);
Toy_freeLiteral(third);
Toy_freeLiteral(second);
Toy_freeLiteral(first);
Toy_freeLiteral(compound);
Toy_freeLiteral(value); return -1;
int totalLength = strlen(buffer); }
value = TOY_TO_STRING_LITERAL(Toy_createRefStringLength(buffer, totalLength));
Toy_pushLiteralArray(&interpreter->stack, value); if ((!TOY_IS_NULL(third) && !TOY_IS_INTEGER(third)) || TOY_AS_INTEGER(third) == 0) {
interpreter->errorOutput("Bad third indexing in string\n");
//something is weird - skip out
Toy_freeLiteral(op);
Toy_freeLiteral(assign);
Toy_freeLiteral(third);
Toy_freeLiteral(second);
Toy_freeLiteral(first);
Toy_freeLiteral(compound);
return -1;
}
//simple indexing if second is null
if (TOY_IS_NULL(second)) {
char* cstr = Toy_toCString(TOY_AS_STRING(compound));
char buf[16];
snprintf(buf, 16, "%s", &(cstr[ TOY_AS_INTEGER(first) ]) );
Toy_Literal result = TOY_TO_STRING_LITERAL(Toy_createRefStringLength(buf, 1));
Toy_pushLiteralArray(&interpreter->stack, result);
Toy_freeLiteral(op); Toy_freeLiteral(op);
Toy_freeLiteral(assign); Toy_freeLiteral(assign);
@@ -727,36 +852,27 @@ int _index(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
Toy_freeLiteral(second); Toy_freeLiteral(second);
Toy_freeLiteral(first); Toy_freeLiteral(first);
Toy_freeLiteral(compound); Toy_freeLiteral(compound);
Toy_freeLiteral(value); Toy_freeLiteral(result);
return 1; return 1;
} }
if (!TOY_IS_INTEGER(second) || (!TOY_IS_NULL(third) && !TOY_IS_INTEGER(third)) || TOY_AS_INTEGER(second) < 0 || TOY_AS_INTEGER(second) > compoundLength || TOY_AS_INTEGER(third) == 0) {
//something is weird - skip out
Toy_freeLiteral(op);
Toy_freeLiteral(assign);
Toy_freeLiteral(third);
Toy_freeLiteral(second);
Toy_freeLiteral(first);
Toy_freeLiteral(compound);
Toy_freeLiteral(value);
return -1;
}
//start building a new string from the old one //start building a new string from the old one
char* result = TOY_ALLOCATE(char, TOY_MAX_STRING_LENGTH); char* result = TOY_ALLOCATE(char, TOY_MAX_STRING_LENGTH);
int lower = TOY_AS_INTEGER(third) > 0 ? TOY_AS_INTEGER(first) : TOY_AS_INTEGER(first) -1;
int min = TOY_AS_INTEGER(third) > 0 ? TOY_AS_INTEGER(first) : TOY_AS_INTEGER(second) -1;
int max = TOY_AS_INTEGER(third) > 0 ? TOY_AS_INTEGER(second) + (TOY_AS_INTEGER(second) == compoundLength ? -1 : 0) : TOY_AS_INTEGER(second);
//copy compound into result //copy compound into result
int resultIndex = 0; int resultIndex = 0;
for (int i = min; i >= 0 && i >= lower && i <= max; i += TOY_AS_INTEGER(third)) {
if (TOY_AS_INTEGER(third) > 0) {
for (int i = TOY_AS_INTEGER(first); i <= TOY_AS_INTEGER(second); i += TOY_AS_INTEGER(third)) {
result[ resultIndex++ ] = Toy_toCString(TOY_AS_STRING(compound))[ i ]; result[ resultIndex++ ] = Toy_toCString(TOY_AS_STRING(compound))[ i ];
} }
}
else {
for (int i = TOY_AS_INTEGER(second); i >= TOY_AS_INTEGER(first); i += TOY_AS_INTEGER(third)) {
result[ resultIndex++ ] = Toy_toCString(TOY_AS_STRING(compound))[ i ];
}
}
result[ resultIndex ] = '\0'; result[ resultIndex ] = '\0';
@@ -765,6 +881,18 @@ int _index(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
compound = TOY_TO_STRING_LITERAL(Toy_createRefStringLength(result, resultIndex)); compound = TOY_TO_STRING_LITERAL(Toy_createRefStringLength(result, resultIndex));
TOY_FREE_ARRAY(char, result, TOY_MAX_STRING_LENGTH); TOY_FREE_ARRAY(char, result, TOY_MAX_STRING_LENGTH);
//leave the string on the stack
Toy_pushLiteralArray(&interpreter->stack, compound);
Toy_freeLiteral(op);
Toy_freeLiteral(assign);
Toy_freeLiteral(third);
Toy_freeLiteral(second);
Toy_freeLiteral(first);
Toy_freeLiteral(compound);
return 1;
} }
//string slice assignment //string slice assignment
@@ -787,7 +915,7 @@ int _index(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
if (!TOY_IS_NULL(second)) { if (!TOY_IS_NULL(second)) {
if (TOY_IS_INDEX_BLANK(second)) { if (TOY_IS_INDEX_BLANK(second)) {
Toy_freeLiteral(second); Toy_freeLiteral(second);
second = TOY_TO_INTEGER_LITERAL(compoundLength); second = TOY_TO_INTEGER_LITERAL(compoundLength - 1);
} }
if (TOY_IS_IDENTIFIER(second)) { if (TOY_IS_IDENTIFIER(second)) {
@@ -808,8 +936,10 @@ int _index(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
Toy_freeLiteral(idn); Toy_freeLiteral(idn);
} }
//handle each null case //handle each error case
if (TOY_IS_NULL(first) || !TOY_IS_INTEGER(first)) { if (!TOY_IS_INTEGER(first) || TOY_AS_INTEGER(first) < 0 || TOY_AS_INTEGER(first) >= TOY_AS_STRING(compound)->length) {
interpreter->errorOutput("Bad first indexing in string assignment\n");
//something is weird - skip out //something is weird - skip out
Toy_freeLiteral(op); Toy_freeLiteral(op);
Toy_freeLiteral(assign); Toy_freeLiteral(assign);
@@ -817,14 +947,13 @@ int _index(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
Toy_freeLiteral(second); Toy_freeLiteral(second);
Toy_freeLiteral(first); Toy_freeLiteral(first);
Toy_freeLiteral(compound); Toy_freeLiteral(compound);
Toy_freeLiteral(value);
return -1; return -1;
} }
if (TOY_IS_NULL(second)) { //assign only a single character if ((!TOY_IS_NULL(second) && !TOY_IS_INTEGER(second)) || TOY_AS_INTEGER(second) < 0 || TOY_AS_INTEGER(second) >= TOY_AS_STRING(compound)->length) {
//set the "first" within the array, then skip out interpreter->errorOutput("Bad second indexing in string assignment\n");
if (TOY_AS_STRING(assign)->length != 1) {
//something is weird - skip out //something is weird - skip out
Toy_freeLiteral(op); Toy_freeLiteral(op);
Toy_freeLiteral(assign); Toy_freeLiteral(assign);
@@ -832,29 +961,13 @@ int _index(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
Toy_freeLiteral(second); Toy_freeLiteral(second);
Toy_freeLiteral(first); Toy_freeLiteral(first);
Toy_freeLiteral(compound); Toy_freeLiteral(compound);
Toy_freeLiteral(value);
return -1; return -1;
} }
Toy_Literal copiedCompound = TOY_TO_STRING_LITERAL(Toy_deepCopyRefString(TOY_AS_STRING(compound))); if ((!TOY_IS_NULL(third) && !TOY_IS_INTEGER(third)) || TOY_AS_INTEGER(third) == 0) {
interpreter->errorOutput("Bad third indexing in string assignment\n");
TOY_AS_STRING(copiedCompound)->data[TOY_AS_INTEGER(first)] = Toy_toCString(TOY_AS_STRING(assign))[0];
Toy_pushLiteralArray(&interpreter->stack, copiedCompound);
Toy_freeLiteral(op);
Toy_freeLiteral(assign);
Toy_freeLiteral(third);
Toy_freeLiteral(second);
Toy_freeLiteral(first);
Toy_freeLiteral(compound);
Toy_freeLiteral(value);
return 1;
}
if (!TOY_IS_INTEGER(second) || (!TOY_IS_NULL(third) && !TOY_IS_INTEGER(third)) || TOY_AS_INTEGER(second) < 0 || TOY_AS_INTEGER(second) > compoundLength || TOY_AS_INTEGER(third) == 0) {
//something is weird - skip out //something is weird - skip out
Toy_freeLiteral(op); Toy_freeLiteral(op);
Toy_freeLiteral(assign); Toy_freeLiteral(assign);
@@ -862,7 +975,6 @@ int _index(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
Toy_freeLiteral(second); Toy_freeLiteral(second);
Toy_freeLiteral(first); Toy_freeLiteral(first);
Toy_freeLiteral(compound); Toy_freeLiteral(compound);
Toy_freeLiteral(value);
return -1; return -1;
} }
@@ -911,16 +1023,8 @@ int _index(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
compound = TOY_TO_STRING_LITERAL(Toy_createRefStringLength(result, resultIndex)); compound = TOY_TO_STRING_LITERAL(Toy_createRefStringLength(result, resultIndex));
TOY_FREE_ARRAY(char, result, TOY_MAX_STRING_LENGTH); TOY_FREE_ARRAY(char, result, TOY_MAX_STRING_LENGTH);
}
else if (TOY_IS_STRING(op) && Toy_equalsRefStringCString(TOY_AS_STRING(op), "+=")) { //leave the string on the stack
Toy_Literal tmp = addition(interpreter, compound, assign);
Toy_freeLiteral(compound);
compound = tmp; //don't clear tmp
}
}
//leave the compound on the stack
Toy_pushLiteralArray(&interpreter->stack, compound); Toy_pushLiteralArray(&interpreter->stack, compound);
Toy_freeLiteral(op); Toy_freeLiteral(op);
@@ -929,12 +1033,34 @@ int _index(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
Toy_freeLiteral(second); Toy_freeLiteral(second);
Toy_freeLiteral(first); Toy_freeLiteral(first);
Toy_freeLiteral(compound); Toy_freeLiteral(compound);
Toy_freeLiteral(value);
return 1; return 1;
}
else if (TOY_IS_STRING(op) && Toy_equalsRefStringCString(TOY_AS_STRING(op), "+=")) {
Toy_Literal tmp = addition(interpreter, compound, assign);
Toy_freeLiteral(compound);
compound = tmp; //don't clear tmp
}
//leave the string on the stack
Toy_pushLiteralArray(&interpreter->stack, compound);
Toy_freeLiteral(op);
Toy_freeLiteral(assign);
Toy_freeLiteral(third);
Toy_freeLiteral(second);
Toy_freeLiteral(first);
Toy_freeLiteral(compound);
return 1;
}
return -1;
} }
int _set(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) { int Toy_private_set(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
//if wrong number of arguments, fail //if wrong number of arguments, fail
if (arguments->count != 3) { if (arguments->count != 3) {
interpreter->errorOutput("Incorrect number of arguments to _set\n"); interpreter->errorOutput("Incorrect number of arguments to _set\n");
@@ -1052,7 +1178,7 @@ int _set(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
return 0; return 0;
} }
int _get(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) { int Toy_private_get(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
//if wrong number of arguments, fail //if wrong number of arguments, fail
if (arguments->count != 2) { if (arguments->count != 2) {
interpreter->errorOutput("Incorrect number of arguments to _get"); interpreter->errorOutput("Incorrect number of arguments to _get");
@@ -1123,7 +1249,7 @@ int _get(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
} }
} }
int _push(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) { int Toy_private_push(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
//if wrong number of arguments, fail //if wrong number of arguments, fail
if (arguments->count != 2) { if (arguments->count != 2) {
interpreter->errorOutput("Incorrect number of arguments to _push\n"); interpreter->errorOutput("Incorrect number of arguments to _push\n");
@@ -1186,7 +1312,7 @@ int _push(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
} }
} }
int _pop(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) { int Toy_private_pop(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
//if wrong number of arguments, fail //if wrong number of arguments, fail
if (arguments->count != 1) { if (arguments->count != 1) {
interpreter->errorOutput("Incorrect number of arguments to _pop\n"); interpreter->errorOutput("Incorrect number of arguments to _pop\n");
@@ -1229,7 +1355,7 @@ int _pop(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
} }
} }
int _length(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) { int Toy_private_length(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
//if wrong number of arguments, fail //if wrong number of arguments, fail
if (arguments->count != 1) { if (arguments->count != 1) {
interpreter->errorOutput("Incorrect number of arguments to _length\n"); interpreter->errorOutput("Incorrect number of arguments to _length\n");
@@ -1280,7 +1406,7 @@ int _length(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
return 1; return 1;
} }
int _clear(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) { int Toy_private_clear(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
//if wrong number of arguments, fail //if wrong number of arguments, fail
if (arguments->count != 1) { if (arguments->count != 1) {
interpreter->errorOutput("Incorrect number of arguments to _clear\n"); interpreter->errorOutput("Incorrect number of arguments to _clear\n");
+7 -7
View File
@@ -3,12 +3,12 @@
#include "toy_interpreter.h" #include "toy_interpreter.h"
//the _index function is a historical oddity - it's used whenever a compound is indexed //the _index function is a historical oddity - it's used whenever a compound is indexed
int _index(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments); int Toy_private_index(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments);
//globally available native functions //globally available native functions
int _set(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments); int Toy_private_set(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments);
int _get(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments); int Toy_private_get(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments);
int _push(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments); int Toy_private_push(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments);
int _pop(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments); int Toy_private_pop(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments);
int _length(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments); int Toy_private_length(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments);
int _clear(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments); int Toy_private_clear(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments);
+33 -33
View File
@@ -18,74 +18,74 @@ STATIC_ASSERT(sizeof(unsigned int) == 4);
#ifndef TOY_EXPORT #ifndef TOY_EXPORT
//declare the singleton //declare the singleton
Command command; Toy_CommandLine Toy_commandLine;
void Toy_initCommand(int argc, const char* argv[]) { void Toy_initCommandLine(int argc, const char* argv[]) {
//default values //default values
command.error = false; Toy_commandLine.error = false;
command.help = false; Toy_commandLine.help = false;
command.version = false; Toy_commandLine.version = false;
command.binaryfile = NULL; Toy_commandLine.binaryfile = NULL;
command.sourcefile = NULL; Toy_commandLine.sourcefile = NULL;
command.compilefile = NULL; Toy_commandLine.compilefile = NULL;
command.outfile = "out.tb"; Toy_commandLine.outfile = "out.tb";
command.source = NULL; Toy_commandLine.source = NULL;
command.verbose = false; Toy_commandLine.verbose = false;
for (int i = 1; i < argc; i++) { //start at 1 to skip the program name for (int i = 1; i < argc; i++) { //start at 1 to skip the program name
command.error = true; //error state by default, set to false by successful flags Toy_commandLine.error = true; //error state by default, set to false by successful flags
if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "--help")) { if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "--help")) {
command.help = true; Toy_commandLine.help = true;
command.error = false; Toy_commandLine.error = false;
continue; continue;
} }
if (!strcmp(argv[i], "-v") || !strcmp(argv[i], "--version")) { if (!strcmp(argv[i], "-v") || !strcmp(argv[i], "--version")) {
command.version = true; Toy_commandLine.version = true;
command.error = false; Toy_commandLine.error = false;
continue; continue;
} }
if (!strcmp(argv[i], "-d") || !strcmp(argv[i], "--debug")) { if (!strcmp(argv[i], "-d") || !strcmp(argv[i], "--debug")) {
command.verbose = true; Toy_commandLine.verbose = true;
command.error = false; Toy_commandLine.error = false;
continue; continue;
} }
if ((!strcmp(argv[i], "-f") || !strcmp(argv[i], "--sourcefile")) && i + 1 < argc) { if ((!strcmp(argv[i], "-f") || !strcmp(argv[i], "--sourcefile")) && i + 1 < argc) {
command.sourcefile = (char*)argv[i + 1]; Toy_commandLine.sourcefile = (char*)argv[i + 1];
i++; i++;
command.error = false; Toy_commandLine.error = false;
continue; continue;
} }
if ((!strcmp(argv[i], "-i") || !strcmp(argv[i], "--input")) && i + 1 < argc) { if ((!strcmp(argv[i], "-i") || !strcmp(argv[i], "--input")) && i + 1 < argc) {
command.source = (char*)argv[i + 1]; Toy_commandLine.source = (char*)argv[i + 1];
i++; i++;
command.error = false; Toy_commandLine.error = false;
continue; continue;
} }
if ((!strcmp(argv[i], "-c") || !strcmp(argv[i], "--compile")) && i + 1 < argc) { if ((!strcmp(argv[i], "-c") || !strcmp(argv[i], "--compile")) && i + 1 < argc) {
command.compilefile = (char*)argv[i + 1]; Toy_commandLine.compilefile = (char*)argv[i + 1];
i++; i++;
command.error = false; Toy_commandLine.error = false;
continue; continue;
} }
if ((!strcmp(argv[i], "-o") || !strcmp(argv[i], "--output")) && i + 1 < argc) { if ((!strcmp(argv[i], "-o") || !strcmp(argv[i], "--output")) && i + 1 < argc) {
command.outfile = (char*)argv[i + 1]; Toy_commandLine.outfile = (char*)argv[i + 1];
i++; i++;
command.error = false; Toy_commandLine.error = false;
continue; continue;
} }
//option without a flag + ending in .tb = binary input //option without a flag + ending in .tb = binary input
if (i < argc) { if (i < argc) {
if (strncmp(&(argv[i][strlen(argv[i]) - 3]), ".tb", 3) == 0) { if (strncmp(&(argv[i][strlen(argv[i]) - 3]), ".tb", 3) == 0) {
command.binaryfile = (char*)argv[i]; Toy_commandLine.binaryfile = (char*)argv[i];
command.error = false; Toy_commandLine.error = false;
continue; continue;
} }
} }
@@ -95,12 +95,12 @@ void Toy_initCommand(int argc, const char* argv[]) {
} }
} }
void Toy_usageCommand(int argc, const char* argv[]) { void Toy_usageCommandLine(int argc, const char* argv[]) {
printf("Usage: %s [<file.tb> | -h | -v | [-d][-f file | -i source | -c file [-o outfile]]]\n\n", argv[0]); printf("Usage: %s [<file.tb> | -h | -v | [-d][-f file | -i source | -c file [-o outfile]]]\n\n", argv[0]);
} }
void Toy_helpCommand(int argc, const char* argv[]) { void Toy_helpCommandLine(int argc, const char* argv[]) {
Toy_usageCommand(argc, argv); Toy_usageCommandLine(argc, argv);
printf("<file.tb>\t\t\tBinary input file in tb format, must be version %d.%d.%d.\n\n", TOY_VERSION_MAJOR, TOY_VERSION_MINOR, TOY_VERSION_PATCH); printf("<file.tb>\t\t\tBinary input file in tb format, must be version %d.%d.%d.\n\n", TOY_VERSION_MAJOR, TOY_VERSION_MINOR, TOY_VERSION_PATCH);
printf("-h\t| --help\t\tShow this help then exit.\n\n"); printf("-h\t| --help\t\tShow this help then exit.\n\n");
@@ -112,9 +112,9 @@ void Toy_helpCommand(int argc, const char* argv[]) {
printf("-o\t| --output outfile\tName of the output file built with --compile (default: out.tb).\n\n"); printf("-o\t| --output outfile\tName of the output file built with --compile (default: out.tb).\n\n");
} }
void Toy_copyrightCommand(int argc, const char* argv[]) { void Toy_copyrightCommandLine(int argc, const char* argv[]) {
printf("Toy Programming Language Interpreter Version %d.%d.%d (built on %s)\n\n", TOY_VERSION_MAJOR, TOY_VERSION_MINOR, TOY_VERSION_PATCH, TOY_VERSION_BUILD); printf("Toy Programming Language Interpreter Version %d.%d.%d (built on %s)\n\n", TOY_VERSION_MAJOR, TOY_VERSION_MINOR, TOY_VERSION_PATCH, TOY_VERSION_BUILD);
printf("Copyright (c) 2020-2022 Kayne Ruse, KR Game Studios\n\n"); printf("Copyright (c) 2020-2023 Kayne Ruse, KR Game Studios\n\n");
printf("This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software.\n\n"); printf("This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software.\n\n");
printf("Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions:\n\n"); printf("Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions:\n\n");
printf("1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.\n\n"); printf("1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.\n\n");
+7 -7
View File
@@ -6,7 +6,7 @@
#define TOY_VERSION_MAJOR 0 #define TOY_VERSION_MAJOR 0
#define TOY_VERSION_MINOR 8 #define TOY_VERSION_MINOR 8
#define TOY_VERSION_PATCH 0 #define TOY_VERSION_PATCH 1
#define TOY_VERSION_BUILD __DATE__ " " __TIME__ #define TOY_VERSION_BUILD __DATE__ " " __TIME__
//platform-specific specifications //platform-specific specifications
@@ -33,13 +33,13 @@ typedef struct {
char* outfile; //defaults to out.tb char* outfile; //defaults to out.tb
char* source; char* source;
bool verbose; bool verbose;
} Command; } Toy_CommandLine;
extern Command command; extern Toy_CommandLine Toy_commandLine;
void Toy_initCommand(int argc, const char* argv[]); void Toy_initCommandLine(int argc, const char* argv[]);
void Toy_usageCommand(int argc, const char* argv[]); void Toy_usageCommandLine(int argc, const char* argv[]);
void Toy_helpCommand(int argc, const char* argv[]); void Toy_helpCommandLine(int argc, const char* argv[]);
void Toy_copyrightCommand(int argc, const char* argv[]); void Toy_copyrightCommandLine(int argc, const char* argv[]);
#endif #endif
+63 -9
View File
@@ -15,6 +15,7 @@ void Toy_initCompiler(Toy_Compiler* compiler) {
compiler->bytecode = NULL; compiler->bytecode = NULL;
compiler->capacity = 0; compiler->capacity = 0;
compiler->count = 0; compiler->count = 0;
compiler->panic = false;
} }
//separated out, so it can be recursive //separated out, so it can be recursive
@@ -129,10 +130,11 @@ static int writeNodeCompoundToCache(Toy_Compiler* compiler, Toy_ASTNode* node) {
//push the store to the cache, with instructions about how pack it //push the store to the cache, with instructions about how pack it
Toy_Literal literal = TOY_TO_DICTIONARY_LITERAL(store); Toy_Literal literal = TOY_TO_DICTIONARY_LITERAL(store);
literal.type = TOY_LITERAL_DICTIONARY_INTERMEDIATE; //god damn it literal.type = TOY_LITERAL_DICTIONARY_INTERMEDIATE; //god damn it - nested in a dictionary
index = Toy_pushLiteralArray(&compiler->literalCache, literal); index = Toy_pushLiteralArray(&compiler->literalCache, literal);
Toy_freeLiteral(literal); Toy_freeLiteral(literal);
} }
else if (node->compound.literalType == TOY_LITERAL_ARRAY) { else if (node->compound.literalType == TOY_LITERAL_ARRAY) {
//ensure each literal value is in the cache, individually //ensure each literal value is in the cache, individually
for (int i = 0; i < node->compound.count; i++) { for (int i = 0; i < node->compound.count; i++) {
@@ -160,18 +162,20 @@ static int writeNodeCompoundToCache(Toy_Compiler* compiler, Toy_ASTNode* node) {
break; break;
default: default:
fprintf(stderr, TOY_CC_ERROR "[internal] Unrecognized node type in writeNodeCompoundToCache()" TOY_CC_RESET); fprintf(stderr, TOY_CC_ERROR "[internal] Unrecognized node type in writeNodeCompoundToCache()\n" TOY_CC_RESET);
return -1; return -1;
} }
} }
//push the store to the cache, with instructions about how pack it //push the store to the cache, with instructions about how pack it
Toy_Literal literal = TOY_TO_ARRAY_LITERAL(store); Toy_Literal literal = TOY_TO_ARRAY_LITERAL(store);
literal.type = TOY_LITERAL_ARRAY_INTERMEDIATE; //god damn it - nested in an array
index = Toy_pushLiteralArray(&compiler->literalCache, literal); index = Toy_pushLiteralArray(&compiler->literalCache, literal);
Toy_freeLiteral(literal); Toy_freeLiteral(literal);
} }
else { else {
fprintf(stderr, TOY_CC_ERROR "[internal] Unrecognized compound type in writeNodeCompoundToCache()" TOY_CC_RESET); fprintf(stderr, TOY_CC_ERROR "[internal] Unrecognized compound type in writeNodeCompoundToCache()\n" TOY_CC_RESET);
return -1;
} }
return index; return index;
@@ -311,7 +315,7 @@ static Toy_Opcode Toy_writeCompilerWithJumps(Toy_Compiler* compiler, Toy_ASTNode
//return this if... //return this if...
Toy_Opcode ret = Toy_writeCompilerWithJumps(compiler, node->binary.right, breakAddressesPtr, continueAddressesPtr, jumpOffsets, rootNode); Toy_Opcode ret = Toy_writeCompilerWithJumps(compiler, node->binary.right, breakAddressesPtr, continueAddressesPtr, jumpOffsets, rootNode);
if (node->binary.opcode == TOY_OP_INDEX && rootNode->type == TOY_AST_NODE_BINARY && rootNode->binary.opcode == TOY_OP_VAR_ASSIGN) { //why var assign? if (node->binary.opcode == TOY_OP_INDEX && rootNode->type == TOY_AST_NODE_BINARY && (rootNode->binary.opcode >= TOY_OP_VAR_ASSIGN && rootNode->binary.opcode <= TOY_OP_VAR_MODULO_ASSIGN)) { //range-based check for assignment type
return TOY_OP_INDEX_ASSIGN_INTERMEDIATE; return TOY_OP_INDEX_ASSIGN_INTERMEDIATE;
} }
@@ -332,7 +336,7 @@ static Toy_Opcode Toy_writeCompilerWithJumps(Toy_Compiler* compiler, Toy_ASTNode
break; break;
case TOY_AST_NODE_TERNARY: { case TOY_AST_NODE_TERNARY: {
// TODO // TODO: a ?: b;
//process the condition //process the condition
Toy_Opcode override = Toy_writeCompilerWithJumps(compiler, node->ternary.condition, breakAddressesPtr, continueAddressesPtr, jumpOffsets, rootNode); Toy_Opcode override = Toy_writeCompilerWithJumps(compiler, node->ternary.condition, breakAddressesPtr, continueAddressesPtr, jumpOffsets, rootNode);
@@ -365,7 +369,7 @@ static Toy_Opcode Toy_writeCompilerWithJumps(Toy_Compiler* compiler, Toy_ASTNode
//write the else path //write the else path
Toy_Opcode override2 = Toy_writeCompilerWithJumps(compiler, node->pathIf.elsePath, breakAddressesPtr, continueAddressesPtr, jumpOffsets, rootNode); Toy_Opcode override2 = Toy_writeCompilerWithJumps(compiler, node->pathIf.elsePath, breakAddressesPtr, continueAddressesPtr, jumpOffsets, rootNode);
if (override2 != TOY_OP_EOF) {//compensate for indexing & dot notation being screwy if (override2 != TOY_OP_EOF) {//compensate for indexing & dot notation being screwy
compiler->bytecode[compiler->count++] = (unsigned char)override; //1 byte compiler->bytecode[compiler->count++] = (unsigned char)override2; //1 byte
} }
//update the jumpToEnd to point here //update the jumpToEnd to point here
@@ -401,6 +405,11 @@ static Toy_Opcode Toy_writeCompilerWithJumps(Toy_Compiler* compiler, Toy_ASTNode
case TOY_AST_NODE_COMPOUND: { case TOY_AST_NODE_COMPOUND: {
int index = writeNodeCompoundToCache(compiler, node); int index = writeNodeCompoundToCache(compiler, node);
if (index < 0) {
compiler->panic = true;
return TOY_OP_EOF;
}
//push the node opcode to the bytecode //push the node opcode to the bytecode
if (index >= 256) { if (index >= 256) {
//push a "long" index //push a "long" index
@@ -468,6 +477,11 @@ static Toy_Opcode Toy_writeCompilerWithJumps(Toy_Compiler* compiler, Toy_ASTNode
compiler->bytecode[compiler->count++] = (unsigned char)override; //1 byte compiler->bytecode[compiler->count++] = (unsigned char)override; //1 byte
} }
//adopt the panic state if anything happened
if (fnCompiler->panic) {
compiler->panic = true;
}
//create the function in the literal cache (by storing the compiler object) //create the function in the literal cache (by storing the compiler object)
Toy_Literal fnLiteral = TOY_TO_FUNCTION_LITERAL(fnCompiler, 0); Toy_Literal fnLiteral = TOY_TO_FUNCTION_LITERAL(fnCompiler, 0);
fnLiteral.type = TOY_LITERAL_FUNCTION_INTERMEDIATE; //NOTE: changing type fnLiteral.type = TOY_LITERAL_FUNCTION_INTERMEDIATE; //NOTE: changing type
@@ -505,6 +519,11 @@ static Toy_Opcode Toy_writeCompilerWithJumps(Toy_Compiler* compiler, Toy_ASTNode
//embed these in the bytecode... //embed these in the bytecode...
unsigned short index = (unsigned short)writeNodeCollectionToCache(compiler, node); unsigned short index = (unsigned short)writeNodeCollectionToCache(compiler, node);
if (index == (unsigned short)-1) {
compiler->panic = true;
return TOY_OP_EOF;
}
memcpy(compiler->bytecode + compiler->count, &index, sizeof(index)); memcpy(compiler->bytecode + compiler->count, &index, sizeof(index));
compiler->count += sizeof(unsigned short); compiler->count += sizeof(unsigned short);
} }
@@ -754,7 +773,7 @@ static Toy_Opcode Toy_writeCompilerWithJumps(Toy_Compiler* compiler, Toy_ASTNode
case TOY_AST_NODE_BREAK: { case TOY_AST_NODE_BREAK: {
if (!breakAddressesPtr) { if (!breakAddressesPtr) {
fprintf(stderr, TOY_CC_ERROR "TOY_CC_ERROR: Can't place a break statement here\n" TOY_CC_RESET); fprintf(stderr, TOY_CC_ERROR "[internal] Can't place a break statement here\n" TOY_CC_RESET);
break; break;
} }
@@ -772,7 +791,7 @@ static Toy_Opcode Toy_writeCompilerWithJumps(Toy_Compiler* compiler, Toy_ASTNode
case TOY_AST_NODE_CONTINUE: { case TOY_AST_NODE_CONTINUE: {
if (!continueAddressesPtr) { if (!continueAddressesPtr) {
fprintf(stderr, TOY_CC_ERROR "TOY_CC_ERROR: Can't place a continue statement here\n" TOY_CC_RESET); fprintf(stderr, TOY_CC_ERROR "[internal] Can't place a continue statement here\n" TOY_CC_RESET);
break; break;
} }
@@ -1007,6 +1026,11 @@ static void emitFloat(unsigned char** collationPtr, int* capacityPtr, int* count
//return the result //return the result
static unsigned char* collateCompilerHeaderOpt(Toy_Compiler* compiler, int* size, bool embedHeader) { static unsigned char* collateCompilerHeaderOpt(Toy_Compiler* compiler, int* size, bool embedHeader) {
if (compiler->panic) {
fprintf(stderr, TOY_CC_ERROR "[internal] Can't collate a panicked compiler\n" TOY_CC_RESET);
return NULL;
}
int capacity = TOY_GROW_CAPACITY(0); int capacity = TOY_GROW_CAPACITY(0);
int count = 0; int count = 0;
unsigned char* collation = TOY_ALLOCATE(unsigned char, capacity); unsigned char* collation = TOY_ALLOCATE(unsigned char, capacity);
@@ -1095,7 +1119,22 @@ static unsigned char* collateCompilerHeaderOpt(Toy_Compiler* compiler, int* size
} }
break; break;
case TOY_LITERAL_DICTIONARY_INTERMEDIATE: { case TOY_LITERAL_ARRAY_INTERMEDIATE: {
emitByte(&collation, &capacity, &count, TOY_LITERAL_ARRAY_INTERMEDIATE);
Toy_LiteralArray* ptr = TOY_AS_ARRAY(compiler->literalCache.literals[i]);
//length of the array, as a short
Toy_emitShort(&collation, &capacity, &count, ptr->count);
//each element of the array
for (int i = 0; i < ptr->count; i++) {
Toy_emitShort(&collation, &capacity, &count, (unsigned short)TOY_AS_INTEGER(ptr->literals[i])); //shorts representing the indexes of the values
}
}
break;
case TOY_LITERAL_DICTIONARY: {
emitByte(&collation, &capacity, &count, TOY_LITERAL_DICTIONARY); emitByte(&collation, &capacity, &count, TOY_LITERAL_DICTIONARY);
Toy_LiteralArray* ptr = TOY_AS_ARRAY(compiler->literalCache.literals[i]); //used an array for storage above Toy_LiteralArray* ptr = TOY_AS_ARRAY(compiler->literalCache.literals[i]); //used an array for storage above
@@ -1110,6 +1149,21 @@ static unsigned char* collateCompilerHeaderOpt(Toy_Compiler* compiler, int* size
} }
break; break;
case TOY_LITERAL_DICTIONARY_INTERMEDIATE: {
emitByte(&collation, &capacity, &count, TOY_LITERAL_DICTIONARY_INTERMEDIATE);
Toy_LiteralArray* ptr = TOY_AS_ARRAY(compiler->literalCache.literals[i]); //used an array for storage above
//length of the array, as a short
Toy_emitShort(&collation, &capacity, &count, ptr->count); //count is the array size, NOT the dictionary size
//each element of the array
for (int i = 0; i < ptr->count; i++) {
Toy_emitShort(&collation, &capacity, &count, (unsigned short)TOY_AS_INTEGER(ptr->literals[i])); //shorts representing the indexes of the values
}
}
break;
case TOY_LITERAL_FUNCTION_INTERMEDIATE: { case TOY_LITERAL_FUNCTION_INTERMEDIATE: {
//extract the compiler //extract the compiler
Toy_Literal fn = compiler->literalCache.literals[i]; Toy_Literal fn = compiler->literalCache.literals[i];
+1
View File
@@ -11,6 +11,7 @@ typedef struct Toy_Compiler {
unsigned char* bytecode; unsigned char* bytecode;
int capacity; int capacity;
int count; int count;
bool panic;
} Toy_Compiler; } Toy_Compiler;
TOY_API void Toy_initCompiler(Toy_Compiler* compiler); TOY_API void Toy_initCompiler(Toy_Compiler* compiler);
+214 -203
View File
@@ -42,9 +42,7 @@ bool Toy_injectNativeFn(Toy_Interpreter* interpreter, char* name, Toy_NativeFn f
return false; return false;
} }
Toy_Literal fn = TOY_TO_FUNCTION_LITERAL((void*)func, 0); Toy_Literal fn = TOY_TO_FUNCTION_NATIVE_LITERAL(func);
fn.type = TOY_LITERAL_FUNCTION_NATIVE;
Toy_Literal type = TOY_TO_TYPE_LITERAL(fn.type, true); Toy_Literal type = TOY_TO_TYPE_LITERAL(fn.type, true);
Toy_setLiteralDictionary(&interpreter->scope->variables, identifier, fn); Toy_setLiteralDictionary(&interpreter->scope->variables, identifier, fn);
@@ -72,9 +70,7 @@ bool Toy_injectNativeHook(Toy_Interpreter* interpreter, char* name, Toy_HookFn h
return false; return false;
} }
Toy_Literal fn = TOY_TO_FUNCTION_LITERAL((void*)hook, 0); Toy_Literal fn = TOY_TO_FUNCTION_HOOK_LITERAL(hook);
fn.type = TOY_LITERAL_FUNCTION_NATIVE;
Toy_setLiteralDictionary(interpreter->hooks, identifier, fn); Toy_setLiteralDictionary(interpreter->hooks, identifier, fn);
Toy_freeLiteral(identifier); Toy_freeLiteral(identifier);
@@ -228,19 +224,28 @@ static void consumeShort(Toy_Interpreter* interpreter, unsigned short bytes, uns
static bool execAssert(Toy_Interpreter* interpreter) { static bool execAssert(Toy_Interpreter* interpreter) {
Toy_Literal rhs = Toy_popLiteralArray(&interpreter->stack); Toy_Literal rhs = Toy_popLiteralArray(&interpreter->stack);
Toy_Literal lhs = Toy_popLiteralArray(&interpreter->stack); Toy_Literal lhs = Toy_popLiteralArray(&interpreter->stack);
Toy_parseIdentifierToValue(interpreter, &lhs);
Toy_Literal lhsIdn = lhs;
if (TOY_IS_IDENTIFIER(lhs) && Toy_parseIdentifierToValue(interpreter, &lhs)) {
Toy_freeLiteral(lhsIdn);
}
if (!TOY_IS_STRING(rhs)) { if (!TOY_IS_STRING(rhs)) {
interpreter->errorOutput("The assert keyword needs a string as the second argument, received: "); interpreter->errorOutput("The assert keyword needs a string as the second argument, received: ");
Toy_printLiteralCustom(rhs, interpreter->errorOutput); Toy_printLiteralCustom(rhs, interpreter->errorOutput);
interpreter->errorOutput("\n"); interpreter->errorOutput("\n");
Toy_freeLiteral(rhs);
Toy_freeLiteral(lhs);
return false; return false;
} }
if (TOY_IS_NULL(lhs) || !TOY_IS_TRUTHY(lhs)) { if (TOY_IS_NULL(lhs) || !TOY_IS_TRUTHY(lhs)) {
(*interpreter->assertOutput)(Toy_toCString(TOY_AS_STRING(rhs))); (*interpreter->assertOutput)(Toy_toCString(TOY_AS_STRING(rhs)));
Toy_freeLiteral(rhs);
interpreter->panic = true; interpreter->panic = true;
Toy_freeLiteral(rhs);
Toy_freeLiteral(lhs);
return false; return false;
} }
@@ -254,11 +259,8 @@ static bool execPrint(Toy_Interpreter* interpreter) {
//print what is on top of the stack, then pop it //print what is on top of the stack, then pop it
Toy_Literal lit = Toy_popLiteralArray(&interpreter->stack); Toy_Literal lit = Toy_popLiteralArray(&interpreter->stack);
if (TOY_IS_IDENTIFIER(lit)) {
Toy_Literal idn = lit; Toy_Literal idn = lit;
if (!Toy_parseIdentifierToValue(interpreter, &lit)) { if (TOY_IS_IDENTIFIER(lit) && Toy_parseIdentifierToValue(interpreter, &lit)) {
return false;
}
Toy_freeLiteral(idn); Toy_freeLiteral(idn);
} }
@@ -289,16 +291,12 @@ static bool execPushLiteral(Toy_Interpreter* interpreter, bool lng) {
static bool rawLiteral(Toy_Interpreter* interpreter) { static bool rawLiteral(Toy_Interpreter* interpreter) {
Toy_Literal lit = Toy_popLiteralArray(&interpreter->stack); Toy_Literal lit = Toy_popLiteralArray(&interpreter->stack);
if (TOY_IS_IDENTIFIER(lit)) {
Toy_Literal idn = lit; Toy_Literal idn = lit;
if (!Toy_parseIdentifierToValue(interpreter, &lit)) { if (TOY_IS_IDENTIFIER(lit) && Toy_parseIdentifierToValue(interpreter, &lit)) {
return false;
}
Toy_freeLiteral(idn); Toy_freeLiteral(idn);
} }
Toy_pushLiteralArray(&interpreter->stack, lit); Toy_pushLiteralArray(&interpreter->stack, lit);
Toy_freeLiteral(lit); Toy_freeLiteral(lit);
return true; return true;
@@ -308,11 +306,8 @@ static bool execNegate(Toy_Interpreter* interpreter) {
//negate the top literal on the stack (numbers only) //negate the top literal on the stack (numbers only)
Toy_Literal lit = Toy_popLiteralArray(&interpreter->stack); Toy_Literal lit = Toy_popLiteralArray(&interpreter->stack);
if (TOY_IS_IDENTIFIER(lit)) {
Toy_Literal idn = lit; Toy_Literal idn = lit;
if (!Toy_parseIdentifierToValue(interpreter, &lit)) { if (TOY_IS_IDENTIFIER(lit) && Toy_parseIdentifierToValue(interpreter, &lit)) {
return false;
}
Toy_freeLiteral(idn); Toy_freeLiteral(idn);
} }
@@ -333,7 +328,6 @@ static bool execNegate(Toy_Interpreter* interpreter) {
} }
Toy_pushLiteralArray(&interpreter->stack, lit); Toy_pushLiteralArray(&interpreter->stack, lit);
Toy_freeLiteral(lit); Toy_freeLiteral(lit);
return true; return true;
@@ -343,11 +337,8 @@ static bool execInvert(Toy_Interpreter* interpreter) {
//negate the top literal on the stack (booleans only) //negate the top literal on the stack (booleans only)
Toy_Literal lit = Toy_popLiteralArray(&interpreter->stack); Toy_Literal lit = Toy_popLiteralArray(&interpreter->stack);
if (TOY_IS_IDENTIFIER(lit)) {
Toy_Literal idn = lit; Toy_Literal idn = lit;
if (!Toy_parseIdentifierToValue(interpreter, &lit)) { if (TOY_IS_IDENTIFIER(lit) && Toy_parseIdentifierToValue(interpreter, &lit)) {
return false;
}
Toy_freeLiteral(idn); Toy_freeLiteral(idn);
} }
@@ -365,7 +356,6 @@ static bool execInvert(Toy_Interpreter* interpreter) {
} }
Toy_pushLiteralArray(&interpreter->stack, lit); Toy_pushLiteralArray(&interpreter->stack, lit);
Toy_freeLiteral(lit); Toy_freeLiteral(lit);
return true; return true;
@@ -375,24 +365,22 @@ static bool execArithmetic(Toy_Interpreter* interpreter, Toy_Opcode opcode) {
Toy_Literal rhs = Toy_popLiteralArray(&interpreter->stack); Toy_Literal rhs = Toy_popLiteralArray(&interpreter->stack);
Toy_Literal lhs = Toy_popLiteralArray(&interpreter->stack); Toy_Literal lhs = Toy_popLiteralArray(&interpreter->stack);
if (TOY_IS_IDENTIFIER(rhs)) { Toy_Literal rhsIdn = rhs;
Toy_Literal idn = rhs; if (TOY_IS_IDENTIFIER(rhs) && Toy_parseIdentifierToValue(interpreter, &rhs)) {
Toy_parseIdentifierToValue(interpreter, &rhs); Toy_freeLiteral(rhsIdn);
Toy_freeLiteral(idn);
} }
if (TOY_IS_IDENTIFIER(lhs)) { Toy_Literal lhsIdn = lhs;
Toy_Literal idn = lhs; if (TOY_IS_IDENTIFIER(lhs) && Toy_parseIdentifierToValue(interpreter, &lhs)) {
Toy_parseIdentifierToValue(interpreter, &lhs); Toy_freeLiteral(lhsIdn);
Toy_freeLiteral(idn);
} }
//special case for string concatenation ONLY //special case for string concatenation ONLY
if (TOY_IS_STRING(lhs) && TOY_IS_STRING(rhs)) { if (TOY_IS_STRING(lhs) && TOY_IS_STRING(rhs) && (opcode == TOY_OP_ADDITION || opcode == TOY_OP_VAR_ADDITION_ASSIGN)) {
//check for overflow //check for overflow
int totalLength = TOY_AS_STRING(lhs)->length + TOY_AS_STRING(rhs)->length; int totalLength = TOY_AS_STRING(lhs)->length + TOY_AS_STRING(rhs)->length;
if (totalLength > TOY_MAX_STRING_LENGTH) { if (totalLength > TOY_MAX_STRING_LENGTH) {
interpreter->errorOutput("Can't concatenate these strings (result is too long)\n"); interpreter->errorOutput("Can't concatenate these strings, result is too long (error found in interpreter)\n");
return false; return false;
} }
@@ -440,7 +428,7 @@ static bool execArithmetic(Toy_Interpreter* interpreter, Toy_Opcode opcode) {
case TOY_OP_DIVISION: case TOY_OP_DIVISION:
case TOY_OP_VAR_DIVISION_ASSIGN: case TOY_OP_VAR_DIVISION_ASSIGN:
if (TOY_AS_INTEGER(rhs) == 0) { if (TOY_AS_INTEGER(rhs) == 0) {
interpreter->errorOutput("Can't divide by zero (error found in interpreter)"); interpreter->errorOutput("Can't divide by zero (error found in interpreter)\n");
return false; return false;
} }
Toy_pushLiteralArray(&interpreter->stack, TOY_TO_INTEGER_LITERAL( TOY_AS_INTEGER(lhs) / TOY_AS_INTEGER(rhs) )); Toy_pushLiteralArray(&interpreter->stack, TOY_TO_INTEGER_LITERAL( TOY_AS_INTEGER(lhs) / TOY_AS_INTEGER(rhs) ));
@@ -449,14 +437,14 @@ static bool execArithmetic(Toy_Interpreter* interpreter, Toy_Opcode opcode) {
case TOY_OP_MODULO: case TOY_OP_MODULO:
case TOY_OP_VAR_MODULO_ASSIGN: case TOY_OP_VAR_MODULO_ASSIGN:
if (TOY_AS_INTEGER(rhs) == 0) { if (TOY_AS_INTEGER(rhs) == 0) {
interpreter->errorOutput("Can't modulo by zero (error found in interpreter)"); interpreter->errorOutput("Can't modulo by zero (error found in interpreter)\n");
return false; return false;
} }
Toy_pushLiteralArray(&interpreter->stack, TOY_TO_INTEGER_LITERAL( TOY_AS_INTEGER(lhs) % TOY_AS_INTEGER(rhs) )); Toy_pushLiteralArray(&interpreter->stack, TOY_TO_INTEGER_LITERAL( TOY_AS_INTEGER(lhs) % TOY_AS_INTEGER(rhs) ));
return true; return true;
default: default:
interpreter->errorOutput("[internal] bad opcode argument passed to execArithmetic()"); interpreter->errorOutput("[internal] bad opcode argument passed to execArithmetic()\n");
return false; return false;
} }
} }
@@ -487,14 +475,14 @@ static bool execArithmetic(Toy_Interpreter* interpreter, Toy_Opcode opcode) {
case TOY_OP_DIVISION: case TOY_OP_DIVISION:
case TOY_OP_VAR_DIVISION_ASSIGN: case TOY_OP_VAR_DIVISION_ASSIGN:
if (TOY_AS_FLOAT(rhs) == 0) { if (TOY_AS_FLOAT(rhs) == 0) {
interpreter->errorOutput("Can't divide by zero (error found in interpreter)"); interpreter->errorOutput("Can't divide by zero (error found in interpreter)\n");
return false; return false;
} }
Toy_pushLiteralArray(&interpreter->stack, TOY_TO_FLOAT_LITERAL( TOY_AS_FLOAT(lhs) / TOY_AS_FLOAT(rhs) )); Toy_pushLiteralArray(&interpreter->stack, TOY_TO_FLOAT_LITERAL( TOY_AS_FLOAT(lhs) / TOY_AS_FLOAT(rhs) ));
return true; return true;
default: default:
interpreter->errorOutput("[internal] bad opcode argument passed to execArithmetic()"); interpreter->errorOutput("[internal] bad opcode argument passed to execArithmetic()\n");
return false; return false;
} }
} }
@@ -514,10 +502,9 @@ static bool execArithmetic(Toy_Interpreter* interpreter, Toy_Opcode opcode) {
static Toy_Literal parseTypeToValue(Toy_Interpreter* interpreter, Toy_Literal type) { static Toy_Literal parseTypeToValue(Toy_Interpreter* interpreter, Toy_Literal type) {
//if an identifier is embedded in the type, figure out what it iss //if an identifier is embedded in the type, figure out what it iss
if (TOY_IS_IDENTIFIER(type)) { Toy_Literal typeIdn = type;
Toy_Literal idn = type; if (TOY_IS_IDENTIFIER(type) && Toy_parseIdentifierToValue(interpreter, &type)) {
Toy_parseIdentifierToValue(interpreter, &type); Toy_freeLiteral(typeIdn);
Toy_freeLiteral(idn);
} }
//if this is an array or dictionary, continue to the subtypes //if this is an array or dictionary, continue to the subtypes
@@ -555,10 +542,9 @@ static bool execVarDecl(Toy_Interpreter* interpreter, bool lng) {
Toy_Literal identifier = interpreter->literalCache.literals[identifierIndex]; Toy_Literal identifier = interpreter->literalCache.literals[identifierIndex];
Toy_Literal type = Toy_copyLiteral(interpreter->literalCache.literals[typeIndex]); Toy_Literal type = Toy_copyLiteral(interpreter->literalCache.literals[typeIndex]);
if (TOY_IS_IDENTIFIER(type)) { Toy_Literal typeIdn = type;
Toy_Literal orig = type; if (TOY_IS_IDENTIFIER(type) && Toy_parseIdentifierToValue(interpreter, &type)) {
Toy_parseIdentifierToValue(interpreter, &type); Toy_freeLiteral(typeIdn);
Toy_freeLiteral(orig);
} }
//BUGFIX: because identifiers are getting embedded in type definitions //BUGFIX: because identifiers are getting embedded in type definitions
@@ -573,10 +559,9 @@ static bool execVarDecl(Toy_Interpreter* interpreter, bool lng) {
Toy_Literal val = Toy_popLiteralArray(&interpreter->stack); Toy_Literal val = Toy_popLiteralArray(&interpreter->stack);
if (TOY_IS_IDENTIFIER(val)) { Toy_Literal valIdn = val;
Toy_Literal idn = val; if (TOY_IS_IDENTIFIER(val) && Toy_parseIdentifierToValue(interpreter, &val)) {
Toy_parseIdentifierToValue(interpreter, &val); Toy_freeLiteral(valIdn);
Toy_freeLiteral(idn);
} }
if (TOY_IS_ARRAY(val) || TOY_IS_DICTIONARY(val)) { if (TOY_IS_ARRAY(val) || TOY_IS_DICTIONARY(val)) {
@@ -654,10 +639,9 @@ static bool execVarAssign(Toy_Interpreter* interpreter) {
Toy_Literal rhs = Toy_popLiteralArray(&interpreter->stack); Toy_Literal rhs = Toy_popLiteralArray(&interpreter->stack);
Toy_Literal lhs = Toy_popLiteralArray(&interpreter->stack); Toy_Literal lhs = Toy_popLiteralArray(&interpreter->stack);
if (TOY_IS_IDENTIFIER(rhs)) { Toy_Literal rhsIdn = rhs;
Toy_Literal idn = rhs; if (TOY_IS_IDENTIFIER(rhs) && Toy_parseIdentifierToValue(interpreter, &rhs)) {
Toy_parseIdentifierToValue(interpreter, &rhs); Toy_freeLiteral(rhsIdn);
Toy_freeLiteral(idn);
} }
if (TOY_IS_ARRAY(rhs) || TOY_IS_DICTIONARY(rhs)) { if (TOY_IS_ARRAY(rhs) || TOY_IS_DICTIONARY(rhs)) {
@@ -724,12 +708,9 @@ static bool execValCast(Toy_Interpreter* interpreter) {
Toy_Literal value = Toy_popLiteralArray(&interpreter->stack); Toy_Literal value = Toy_popLiteralArray(&interpreter->stack);
Toy_Literal type = Toy_popLiteralArray(&interpreter->stack); Toy_Literal type = Toy_popLiteralArray(&interpreter->stack);
if (TOY_IS_IDENTIFIER(value)) { Toy_Literal valueIdn = value;
Toy_Literal idn = value; if (TOY_IS_IDENTIFIER(value) && Toy_parseIdentifierToValue(interpreter, &value)) {
if (!Toy_parseIdentifierToValue(interpreter, &value)) { Toy_freeLiteral(valueIdn);
return false;
}
Toy_freeLiteral(idn);
} }
Toy_Literal result = TOY_TO_NULL_LITERAL; Toy_Literal result = TOY_TO_NULL_LITERAL;
@@ -841,7 +822,7 @@ static bool execTypeOf(Toy_Interpreter* interpreter) {
type = Toy_getScopeType(interpreter->scope, rhs); type = Toy_getScopeType(interpreter->scope, rhs);
} }
else { else {
type = TOY_TO_TYPE_LITERAL(rhs.type, false); type = TOY_TO_TYPE_LITERAL(rhs.type, false); //see issue #53
} }
Toy_pushLiteralArray(&interpreter->stack, type); Toy_pushLiteralArray(&interpreter->stack, type);
@@ -856,16 +837,14 @@ static bool execCompareEqual(Toy_Interpreter* interpreter, bool invert) {
Toy_Literal rhs = Toy_popLiteralArray(&interpreter->stack); Toy_Literal rhs = Toy_popLiteralArray(&interpreter->stack);
Toy_Literal lhs = Toy_popLiteralArray(&interpreter->stack); Toy_Literal lhs = Toy_popLiteralArray(&interpreter->stack);
if (TOY_IS_IDENTIFIER(rhs)) { Toy_Literal rhsIdn = rhs;
Toy_Literal idn = rhs; if (TOY_IS_IDENTIFIER(rhs) && Toy_parseIdentifierToValue(interpreter, &rhs)) {
Toy_parseIdentifierToValue(interpreter, &rhs); Toy_freeLiteral(rhsIdn);
Toy_freeLiteral(idn);
} }
if (TOY_IS_IDENTIFIER(lhs)) { Toy_Literal lhsIdn = lhs;
Toy_Literal idn = lhs; if (TOY_IS_IDENTIFIER(lhs) && Toy_parseIdentifierToValue(interpreter, &lhs)) {
Toy_parseIdentifierToValue(interpreter, &lhs); Toy_freeLiteral(lhsIdn);
Toy_freeLiteral(idn);
} }
bool result = Toy_literalsAreEqual(lhs, rhs); bool result = Toy_literalsAreEqual(lhs, rhs);
@@ -886,16 +865,14 @@ static bool execCompareLess(Toy_Interpreter* interpreter, bool invert) {
Toy_Literal rhs = Toy_popLiteralArray(&interpreter->stack); Toy_Literal rhs = Toy_popLiteralArray(&interpreter->stack);
Toy_Literal lhs = Toy_popLiteralArray(&interpreter->stack); Toy_Literal lhs = Toy_popLiteralArray(&interpreter->stack);
if (TOY_IS_IDENTIFIER(rhs)) { Toy_Literal rhsIdn = rhs;
Toy_Literal idn = rhs; if (TOY_IS_IDENTIFIER(rhs) && Toy_parseIdentifierToValue(interpreter, &rhs)) {
Toy_parseIdentifierToValue(interpreter, &rhs); Toy_freeLiteral(rhsIdn);
Toy_freeLiteral(idn);
} }
if (TOY_IS_IDENTIFIER(lhs)) { Toy_Literal lhsIdn = lhs;
Toy_Literal idn = lhs; if (TOY_IS_IDENTIFIER(lhs) && Toy_parseIdentifierToValue(interpreter, &lhs)) {
Toy_parseIdentifierToValue(interpreter, &lhs); Toy_freeLiteral(lhsIdn);
Toy_freeLiteral(idn);
} }
//not a number, return falure //not a number, return falure
@@ -948,16 +925,14 @@ static bool execCompareLessEqual(Toy_Interpreter* interpreter, bool invert) {
Toy_Literal rhs = Toy_popLiteralArray(&interpreter->stack); Toy_Literal rhs = Toy_popLiteralArray(&interpreter->stack);
Toy_Literal lhs = Toy_popLiteralArray(&interpreter->stack); Toy_Literal lhs = Toy_popLiteralArray(&interpreter->stack);
if (TOY_IS_IDENTIFIER(rhs)) { Toy_Literal rhsIdn = rhs;
Toy_Literal idn = rhs; if (TOY_IS_IDENTIFIER(rhs) && Toy_parseIdentifierToValue(interpreter, &rhs)) {
Toy_parseIdentifierToValue(interpreter, &rhs); Toy_freeLiteral(rhsIdn);
Toy_freeLiteral(idn);
} }
if (TOY_IS_IDENTIFIER(lhs)) { Toy_Literal lhsIdn = lhs;
Toy_Literal idn = lhs; if (TOY_IS_IDENTIFIER(lhs) && Toy_parseIdentifierToValue(interpreter, &lhs)) {
Toy_parseIdentifierToValue(interpreter, &lhs); Toy_freeLiteral(lhsIdn);
Toy_freeLiteral(idn);
} }
//not a number, return falure //not a number, return falure
@@ -1011,16 +986,14 @@ static bool execAnd(Toy_Interpreter* interpreter) {
Toy_Literal rhs = Toy_popLiteralArray(&interpreter->stack); Toy_Literal rhs = Toy_popLiteralArray(&interpreter->stack);
Toy_Literal lhs = Toy_popLiteralArray(&interpreter->stack); Toy_Literal lhs = Toy_popLiteralArray(&interpreter->stack);
if (TOY_IS_IDENTIFIER(rhs)) { Toy_Literal rhsIdn = rhs;
Toy_Literal idn = rhs; if (TOY_IS_IDENTIFIER(rhs) && Toy_parseIdentifierToValue(interpreter, &rhs)) {
Toy_parseIdentifierToValue(interpreter, &rhs); Toy_freeLiteral(rhsIdn);
Toy_freeLiteral(idn);
} }
if (TOY_IS_IDENTIFIER(lhs)) { Toy_Literal lhsIdn = lhs;
Toy_Literal idn = lhs; if (TOY_IS_IDENTIFIER(lhs) && Toy_parseIdentifierToValue(interpreter, &lhs)) {
Toy_parseIdentifierToValue(interpreter, &lhs); Toy_freeLiteral(lhsIdn);
Toy_freeLiteral(idn);
} }
if (TOY_IS_TRUTHY(lhs) && TOY_IS_TRUTHY(rhs)) { if (TOY_IS_TRUTHY(lhs) && TOY_IS_TRUTHY(rhs)) {
@@ -1040,16 +1013,14 @@ static bool execOr(Toy_Interpreter* interpreter) {
Toy_Literal rhs = Toy_popLiteralArray(&interpreter->stack); Toy_Literal rhs = Toy_popLiteralArray(&interpreter->stack);
Toy_Literal lhs = Toy_popLiteralArray(&interpreter->stack); Toy_Literal lhs = Toy_popLiteralArray(&interpreter->stack);
if (TOY_IS_IDENTIFIER(rhs)) { Toy_Literal rhsIdn = rhs;
Toy_Literal idn = rhs; if (TOY_IS_IDENTIFIER(rhs) && Toy_parseIdentifierToValue(interpreter, &rhs)) {
Toy_parseIdentifierToValue(interpreter, &rhs); Toy_freeLiteral(rhsIdn);
Toy_freeLiteral(idn);
} }
if (TOY_IS_IDENTIFIER(lhs)) { Toy_Literal lhsIdn = lhs;
Toy_Literal idn = lhs; if (TOY_IS_IDENTIFIER(lhs) && Toy_parseIdentifierToValue(interpreter, &lhs)) {
Toy_parseIdentifierToValue(interpreter, &lhs); Toy_freeLiteral(lhsIdn);
Toy_freeLiteral(idn);
} }
if (TOY_IS_TRUTHY(lhs) || TOY_IS_TRUTHY(rhs)) { if (TOY_IS_TRUTHY(lhs) || TOY_IS_TRUTHY(rhs)) {
@@ -1090,16 +1061,14 @@ static bool execFalseJump(Toy_Interpreter* interpreter) {
//actually jump //actually jump
Toy_Literal lit = Toy_popLiteralArray(&interpreter->stack); Toy_Literal lit = Toy_popLiteralArray(&interpreter->stack);
bool freeLit = false; Toy_Literal litIdn = lit;
if (TOY_IS_IDENTIFIER(lit)) { if (TOY_IS_IDENTIFIER(lit) && Toy_parseIdentifierToValue(interpreter, &lit)) {
Toy_Literal idn = lit; Toy_freeLiteral(litIdn);
Toy_parseIdentifierToValue(interpreter, &lit);
Toy_freeLiteral(idn);
freeLit = true;
} }
if (TOY_IS_NULL(lit)) { if (TOY_IS_NULL(lit)) {
interpreter->errorOutput("Null detected in comparison\n"); interpreter->errorOutput("Null detected in comparison\n");
Toy_freeLiteral(lit);
return false; return false;
} }
@@ -1107,9 +1076,7 @@ static bool execFalseJump(Toy_Interpreter* interpreter) {
interpreter->count = target + interpreter->codeStart; interpreter->count = target + interpreter->codeStart;
} }
if (freeLit) {
Toy_freeLiteral(lit); Toy_freeLiteral(lit);
}
return true; return true;
} }
@@ -1156,6 +1123,14 @@ static bool execFnCall(Toy_Interpreter* interpreter, bool looseFirstArgument) {
//let's screw with the fn name, too //let's screw with the fn name, too
if (looseFirstArgument) { if (looseFirstArgument) {
if (!TOY_IS_IDENTIFIER(identifier)) {
interpreter->errorOutput("Bad literal passed as a function identifier\n");
Toy_freeLiteral(identifier);
Toy_freeLiteral(stackSize);
Toy_freeLiteralArray(&arguments);
return false;
}
int length = TOY_AS_IDENTIFIER(identifier)->length + 1; int length = TOY_AS_IDENTIFIER(identifier)->length + 1;
char buffer[TOY_MAX_STRING_LENGTH]; char buffer[TOY_MAX_STRING_LENGTH];
snprintf(buffer, TOY_MAX_STRING_LENGTH, "_%s", Toy_toCString(TOY_AS_IDENTIFIER(identifier))); //prepend an underscore snprintf(buffer, TOY_MAX_STRING_LENGTH, "_%s", Toy_toCString(TOY_AS_IDENTIFIER(identifier))); //prepend an underscore
@@ -1168,6 +1143,7 @@ static bool execFnCall(Toy_Interpreter* interpreter, bool looseFirstArgument) {
if (!Toy_parseIdentifierToValue(interpreter, &func)) { if (!Toy_parseIdentifierToValue(interpreter, &func)) {
Toy_freeLiteralArray(&arguments); Toy_freeLiteralArray(&arguments);
Toy_freeLiteral(stackSize);
Toy_freeLiteral(identifier); Toy_freeLiteral(identifier);
return false; return false;
} }
@@ -1187,9 +1163,10 @@ static bool execFnCall(Toy_Interpreter* interpreter, bool looseFirstArgument) {
Toy_freeLiteralArray(&arguments); Toy_freeLiteralArray(&arguments);
//call the native function //call the native function
((Toy_NativeFn) TOY_AS_FUNCTION(func).bytecode )(interpreter, &correct); TOY_AS_FUNCTION_NATIVE(func)(interpreter, &correct);
Toy_freeLiteralArray(&correct); Toy_freeLiteralArray(&correct);
Toy_freeLiteral(stackSize);
Toy_freeLiteral(identifier); Toy_freeLiteral(identifier);
return true; return true;
} }
@@ -1200,6 +1177,7 @@ static bool execFnCall(Toy_Interpreter* interpreter, bool looseFirstArgument) {
interpreter->errorOutput("\n"); interpreter->errorOutput("\n");
Toy_freeLiteral(identifier); Toy_freeLiteral(identifier);
Toy_freeLiteral(stackSize);
Toy_freeLiteralArray(&arguments); Toy_freeLiteralArray(&arguments);
return false; return false;
} }
@@ -1214,12 +1192,57 @@ static bool execFnCall(Toy_Interpreter* interpreter, bool looseFirstArgument) {
Toy_freeLiteralArray(&arguments); Toy_freeLiteralArray(&arguments);
Toy_freeLiteral(func); Toy_freeLiteral(func);
Toy_freeLiteral(stackSize);
Toy_freeLiteral(identifier); Toy_freeLiteral(identifier);
return ret; return ret;
} }
bool Toy_callLiteralFn(Toy_Interpreter* interpreter, Toy_Literal func, Toy_LiteralArray* arguments, Toy_LiteralArray* returns) { bool Toy_callLiteralFn(Toy_Interpreter* interpreter, Toy_Literal func, Toy_LiteralArray* arguments, Toy_LiteralArray* returns) {
//check for side-loaded native functions
if (TOY_IS_FUNCTION_NATIVE(func)) {
//reverse the order to the correct order
Toy_LiteralArray correct;
Toy_initLiteralArray(&correct);
while(arguments->count) {
Toy_Literal lit = Toy_popLiteralArray(arguments);
Toy_pushLiteralArray(&correct, lit);
Toy_freeLiteral(lit);
}
//call the native function
int returnsCount = TOY_AS_FUNCTION_NATIVE(func)(interpreter, &correct);
if (returnsCount < 0) {
interpreter->errorOutput("Unknown error from native function\n");
Toy_freeLiteralArray(&correct);
return false;
}
//get the results
Toy_LiteralArray returnsFromInner;
Toy_initLiteralArray(&returnsFromInner);
for (int i = 0; i < (returnsCount || 1); i++) {
Toy_Literal lit = Toy_popLiteralArray(&interpreter->stack);
Toy_pushLiteralArray(&returnsFromInner, lit); //NOTE: also reverses the order
Toy_freeLiteral(lit);
}
//flip them around and pass to returns
while (returnsFromInner.count > 0) {
Toy_Literal lit = Toy_popLiteralArray(&returnsFromInner);
Toy_pushLiteralArray(returns, lit);
Toy_freeLiteral(lit);
}
Toy_freeLiteralArray(&returnsFromInner);
Toy_freeLiteralArray(&correct);
return true;
}
//normal Toy function
if (!TOY_IS_FUNCTION(func)) { if (!TOY_IS_FUNCTION(func)) {
interpreter->errorOutput("Function required in Toy_callLiteralFn()\n"); interpreter->errorOutput("Function required in Toy_callLiteralFn()\n");
return false; return false;
@@ -1286,10 +1309,9 @@ bool Toy_callLiteralFn(Toy_Interpreter* interpreter, Toy_Literal func, Toy_Liter
Toy_Literal arg = Toy_popLiteralArray(arguments); Toy_Literal arg = Toy_popLiteralArray(arguments);
if (TOY_IS_IDENTIFIER(arg)) { Toy_Literal argIdn = arg;
Toy_Literal idn = arg; if (TOY_IS_IDENTIFIER(arg) && Toy_parseIdentifierToValue(interpreter, &arg)) {
Toy_parseIdentifierToValue(interpreter, &arg); Toy_freeLiteral(argIdn);
Toy_freeLiteral(idn);
} }
if (!Toy_setScopeVariable(inner.scope, paramArray->literals[i], arg, false)) { if (!Toy_setScopeVariable(inner.scope, paramArray->literals[i], arg, false)) {
@@ -1450,10 +1472,10 @@ static bool execFnReturn(Toy_Interpreter* interpreter) {
//get the values of everything on the stack //get the values of everything on the stack
while (interpreter->stack.count > 0) { while (interpreter->stack.count > 0) {
Toy_Literal lit = Toy_popLiteralArray(&interpreter->stack); Toy_Literal lit = Toy_popLiteralArray(&interpreter->stack);
if (TOY_IS_IDENTIFIER(lit)) {
Toy_Literal idn = lit; Toy_Literal litIdn = lit;
Toy_parseIdentifierToValue(interpreter, &lit); if (TOY_IS_IDENTIFIER(lit) && Toy_parseIdentifierToValue(interpreter, &lit)) {
Toy_freeLiteral(idn); Toy_freeLiteral(litIdn);
} }
if (TOY_IS_ARRAY(lit) || TOY_IS_DICTIONARY(lit)) { if (TOY_IS_ARRAY(lit) || TOY_IS_DICTIONARY(lit)) {
@@ -1494,8 +1516,8 @@ static bool execImport(Toy_Interpreter* interpreter) {
Toy_Literal func = Toy_getLiteralDictionary(interpreter->hooks, identifier); Toy_Literal func = Toy_getLiteralDictionary(interpreter->hooks, identifier);
if (!TOY_IS_FUNCTION_NATIVE(func)) { if (!TOY_IS_FUNCTION_HOOK(func)) {
interpreter->errorOutput("Expected native function for a hook: "); interpreter->errorOutput("Expected hook function, found: ");
Toy_printLiteralCustom(identifier, interpreter->errorOutput); Toy_printLiteralCustom(identifier, interpreter->errorOutput);
interpreter->errorOutput("\"\n"); interpreter->errorOutput("\"\n");
@@ -1505,9 +1527,7 @@ static bool execImport(Toy_Interpreter* interpreter) {
return false; return false;
} }
Toy_HookFn fn = (Toy_HookFn)TOY_AS_FUNCTION(func).bytecode; TOY_AS_FUNCTION_HOOK(func)(interpreter, identifier, alias);
fn(interpreter, identifier, alias);
Toy_freeLiteral(func); Toy_freeLiteral(func);
Toy_freeLiteral(alias); Toy_freeLiteral(alias);
@@ -1523,31 +1543,26 @@ static bool execIndex(Toy_Interpreter* interpreter, bool assignIntermediate) {
Toy_Literal first = Toy_popLiteralArray(&interpreter->stack); Toy_Literal first = Toy_popLiteralArray(&interpreter->stack);
Toy_Literal compound = Toy_popLiteralArray(&interpreter->stack); Toy_Literal compound = Toy_popLiteralArray(&interpreter->stack);
Toy_Literal idn = compound; Toy_Literal compoundIdn = compound;
bool freeIdn = false; bool freeIdn = false;
if (TOY_IS_IDENTIFIER(compound) && Toy_parseIdentifierToValue(interpreter, &compound)) {
if (TOY_IS_IDENTIFIER(compound)) {
freeIdn = true; freeIdn = true;
if (!Toy_parseIdentifierToValue(interpreter, &compound)) {
Toy_freeLiteral(third);
Toy_freeLiteral(second);
Toy_freeLiteral(first);
Toy_freeLiteral(compound);
//freeLiteral(idn); //since compound is freed, idn is still pointing there
return false;
}
} }
if (!TOY_IS_ARRAY(compound) && !TOY_IS_DICTIONARY(compound) && !TOY_IS_STRING(compound)) { if (!TOY_IS_ARRAY(compound) && !TOY_IS_DICTIONARY(compound) && !TOY_IS_STRING(compound)) {
interpreter->errorOutput("Unknown compound found in indexing notation: "); interpreter->errorOutput("Unknown compound found in indexing notation: ");
Toy_printLiteralCustom(compound, interpreter->errorOutput); Toy_printLiteralCustom(compound, interpreter->errorOutput);
interpreter->errorOutput("\n");
Toy_freeLiteral(third); Toy_freeLiteral(third);
Toy_freeLiteral(second); Toy_freeLiteral(second);
Toy_freeLiteral(first); Toy_freeLiteral(first);
Toy_freeLiteral(compound); Toy_freeLiteral(compound);
if (freeIdn) { if (freeIdn) {
Toy_freeLiteral(idn); Toy_freeLiteral(compoundIdn);
} }
return false; return false;
} }
@@ -1564,8 +1579,8 @@ static bool execIndex(Toy_Interpreter* interpreter, bool assignIntermediate) {
//leave the idn and compound on the stack //leave the idn and compound on the stack
if (assignIntermediate) { if (assignIntermediate) {
if (TOY_IS_IDENTIFIER(idn)) { if (TOY_IS_IDENTIFIER(compoundIdn)) {
Toy_pushLiteralArray(&interpreter->stack, idn); Toy_pushLiteralArray(&interpreter->stack, compoundIdn);
} }
Toy_pushLiteralArray(&interpreter->stack, compound); Toy_pushLiteralArray(&interpreter->stack, compound);
Toy_pushLiteralArray(&interpreter->stack, first); Toy_pushLiteralArray(&interpreter->stack, first);
@@ -1574,9 +1589,9 @@ static bool execIndex(Toy_Interpreter* interpreter, bool assignIntermediate) {
} }
//call the _index function //call the _index function
if (_index(interpreter, &arguments) < 0) { if (Toy_private_index(interpreter, &arguments) < 0) {
interpreter->errorOutput("Something went wrong while indexing: "); interpreter->errorOutput("Something went wrong while indexing (simple index): ");
Toy_printLiteralCustom(idn, interpreter->errorOutput); Toy_printLiteralCustom(compoundIdn, interpreter->errorOutput);
interpreter->errorOutput("\n"); interpreter->errorOutput("\n");
//clean up //clean up
@@ -1585,7 +1600,7 @@ static bool execIndex(Toy_Interpreter* interpreter, bool assignIntermediate) {
Toy_freeLiteral(first); Toy_freeLiteral(first);
Toy_freeLiteral(compound); Toy_freeLiteral(compound);
if (freeIdn) { if (freeIdn) {
Toy_freeLiteral(idn); Toy_freeLiteral(compoundIdn);
} }
Toy_freeLiteralArray(&arguments); Toy_freeLiteralArray(&arguments);
return false; return false;
@@ -1597,7 +1612,7 @@ static bool execIndex(Toy_Interpreter* interpreter, bool assignIntermediate) {
Toy_freeLiteral(first); Toy_freeLiteral(first);
Toy_freeLiteral(compound); Toy_freeLiteral(compound);
if (freeIdn) { if (freeIdn) {
Toy_freeLiteral(idn); Toy_freeLiteral(compoundIdn);
} }
Toy_freeLiteralArray(&arguments); Toy_freeLiteralArray(&arguments);
@@ -1613,20 +1628,15 @@ static bool execIndexAssign(Toy_Interpreter* interpreter) {
Toy_Literal first = Toy_popLiteralArray(&interpreter->stack); Toy_Literal first = Toy_popLiteralArray(&interpreter->stack);
Toy_Literal compound = Toy_popLiteralArray(&interpreter->stack); Toy_Literal compound = Toy_popLiteralArray(&interpreter->stack);
Toy_Literal idn = compound; Toy_Literal assignIdn = assign;
bool freeIdn = false; if (TOY_IS_IDENTIFIER(assign) && Toy_parseIdentifierToValue(interpreter, &assign)) {
Toy_freeLiteral(assignIdn);
if (TOY_IS_IDENTIFIER(compound)) {
freeIdn = true;
if (!Toy_parseIdentifierToValue(interpreter, &compound)) {
Toy_freeLiteral(assign);
Toy_freeLiteral(third);
Toy_freeLiteral(second);
Toy_freeLiteral(first);
Toy_freeLiteral(compound);
Toy_freeLiteral(idn);
return false;
} }
Toy_Literal compoundIdn = compound;
bool freeIdn = false;
if (TOY_IS_IDENTIFIER(compound) && Toy_parseIdentifierToValue(interpreter, &compound)) {
freeIdn = true;
} }
if (!TOY_IS_ARRAY(compound) && !TOY_IS_DICTIONARY(compound) && !TOY_IS_STRING(compound)) { if (!TOY_IS_ARRAY(compound) && !TOY_IS_DICTIONARY(compound) && !TOY_IS_STRING(compound)) {
@@ -1637,7 +1647,7 @@ static bool execIndexAssign(Toy_Interpreter* interpreter) {
Toy_freeLiteral(first); Toy_freeLiteral(first);
Toy_freeLiteral(compound); Toy_freeLiteral(compound);
if (freeIdn) { if (freeIdn) {
Toy_freeLiteral(idn); Toy_freeLiteral(compoundIdn);
} }
return false; return false;
} }
@@ -1673,7 +1683,7 @@ static bool execIndexAssign(Toy_Interpreter* interpreter) {
Toy_freeLiteral(first); Toy_freeLiteral(first);
Toy_freeLiteral(compound); Toy_freeLiteral(compound);
if (freeIdn) { if (freeIdn) {
Toy_freeLiteral(idn); Toy_freeLiteral(compoundIdn);
} }
return false; return false;
} }
@@ -1693,7 +1703,7 @@ static bool execIndexAssign(Toy_Interpreter* interpreter) {
Toy_pushLiteralArray(&arguments, op); //it expects an assignment "opcode" Toy_pushLiteralArray(&arguments, op); //it expects an assignment "opcode"
//call the _index function //call the _index function
if (_index(interpreter, &arguments) < 0) { if (Toy_private_index(interpreter, &arguments) < 0) {
//clean up //clean up
Toy_freeLiteral(assign); Toy_freeLiteral(assign);
Toy_freeLiteral(third); Toy_freeLiteral(third);
@@ -1701,7 +1711,7 @@ static bool execIndexAssign(Toy_Interpreter* interpreter) {
Toy_freeLiteral(first); Toy_freeLiteral(first);
Toy_freeLiteral(compound); Toy_freeLiteral(compound);
if (freeIdn) { if (freeIdn) {
Toy_freeLiteral(idn); Toy_freeLiteral(compoundIdn);
} }
Toy_freeLiteral(op); Toy_freeLiteral(op);
Toy_freeLiteralArray(&arguments); Toy_freeLiteralArray(&arguments);
@@ -1712,11 +1722,11 @@ static bool execIndexAssign(Toy_Interpreter* interpreter) {
//save the result (assume top of the interpreter stack is the new compound value) //save the result (assume top of the interpreter stack is the new compound value)
Toy_Literal result = Toy_popLiteralArray(&interpreter->stack); Toy_Literal result = Toy_popLiteralArray(&interpreter->stack);
//if idn is NOT an identifier, assign backwards while there are things on the stack (inner-compound assignment, BIG assumptions here) //deep
if (!TOY_IS_IDENTIFIER(idn)) { if (!freeIdn) {
while (interpreter->stack.count > 1) { while (interpreter->stack.count > 1) {
//read the new values //read the new values
Toy_freeLiteral(idn); Toy_freeLiteral(compound);
Toy_freeLiteral(third); Toy_freeLiteral(third);
Toy_freeLiteral(second); Toy_freeLiteral(second);
Toy_freeLiteral(first); Toy_freeLiteral(first);
@@ -1724,26 +1734,27 @@ static bool execIndexAssign(Toy_Interpreter* interpreter) {
Toy_initLiteralArray(&arguments); Toy_initLiteralArray(&arguments);
Toy_freeLiteral(op); Toy_freeLiteral(op);
//reuse these like an idiot
third = Toy_popLiteralArray(&interpreter->stack); third = Toy_popLiteralArray(&interpreter->stack);
second = Toy_popLiteralArray(&interpreter->stack); second = Toy_popLiteralArray(&interpreter->stack);
first = Toy_popLiteralArray(&interpreter->stack); first = Toy_popLiteralArray(&interpreter->stack);
idn = Toy_popLiteralArray(&interpreter->stack); compound = Toy_popLiteralArray(&interpreter->stack);
char* opStr = "="; //shadow, but force assignment char* opStr = "="; //shadow, but force assignment
int opLength = strlen(opStr); int opLength = strlen(opStr);
op = TOY_TO_STRING_LITERAL(Toy_createRefStringLength(opStr, opLength)); //TODO: static reference optimisation? op = TOY_TO_STRING_LITERAL(Toy_createRefStringLength(opStr, opLength)); //TODO: static reference optimisation?
//assign to the idn / compound - with _index //assign to the idn / compound - with _index
Toy_pushLiteralArray(&arguments, idn); Toy_pushLiteralArray(&arguments, compound); //
Toy_pushLiteralArray(&arguments, first); Toy_pushLiteralArray(&arguments, first);
Toy_pushLiteralArray(&arguments, second); Toy_pushLiteralArray(&arguments, second);
Toy_pushLiteralArray(&arguments, third); Toy_pushLiteralArray(&arguments, third);
Toy_pushLiteralArray(&arguments, result); Toy_pushLiteralArray(&arguments, result);
Toy_pushLiteralArray(&arguments, op); Toy_pushLiteralArray(&arguments, op);
if (_index(interpreter, &arguments) < 0) { if (Toy_private_index(interpreter, &arguments) < 0) {
interpreter->errorOutput("Something went wrong while indexing: "); interpreter->errorOutput("Something went wrong while indexing (index assign): ");
Toy_printLiteralCustom(idn, interpreter->errorOutput); Toy_printLiteralCustom(compound, interpreter->errorOutput);
interpreter->errorOutput("\n"); interpreter->errorOutput("\n");
//clean up //clean up
@@ -1751,13 +1762,11 @@ static bool execIndexAssign(Toy_Interpreter* interpreter) {
Toy_freeLiteral(third); Toy_freeLiteral(third);
Toy_freeLiteral(second); Toy_freeLiteral(second);
Toy_freeLiteral(first); Toy_freeLiteral(first);
Toy_freeLiteral(compound);
if (freeIdn) { if (freeIdn) {
Toy_freeLiteral(idn); Toy_freeLiteral(compoundIdn);
} }
Toy_freeLiteral(op); Toy_freeLiteral(op);
Toy_freeLiteralArray(&arguments); Toy_freeLiteralArray(&arguments);
Toy_freeLiteral(result);
return false; return false;
} }
@@ -1765,14 +1774,15 @@ static bool execIndexAssign(Toy_Interpreter* interpreter) {
result = Toy_popLiteralArray(&interpreter->stack); result = Toy_popLiteralArray(&interpreter->stack);
} }
Toy_freeLiteral(idn); Toy_freeLiteral(compound);
idn = Toy_popLiteralArray(&interpreter->stack); compound = Toy_popLiteralArray(&interpreter->stack);
compound = idn; compoundIdn = compound;
freeIdn = false;
} }
if (TOY_IS_IDENTIFIER(idn) && !Toy_setScopeVariable(interpreter->scope, idn, result, true)) { if (TOY_IS_IDENTIFIER(compoundIdn) && !Toy_setScopeVariable(interpreter->scope, compoundIdn, result, true)) {
interpreter->errorOutput("Incorrect type assigned to compound member "); interpreter->errorOutput("Incorrect type assigned to compound member ");
Toy_printLiteralCustom(idn, interpreter->errorOutput); Toy_printLiteralCustom(compoundIdn, interpreter->errorOutput);
interpreter->errorOutput("\n"); interpreter->errorOutput("\n");
//clean up //clean up
@@ -1782,7 +1792,7 @@ static bool execIndexAssign(Toy_Interpreter* interpreter) {
Toy_freeLiteral(first); Toy_freeLiteral(first);
Toy_freeLiteral(compound); Toy_freeLiteral(compound);
if (freeIdn) { if (freeIdn) {
Toy_freeLiteral(idn); Toy_freeLiteral(compoundIdn);
} }
Toy_freeLiteral(op); Toy_freeLiteral(op);
Toy_freeLiteralArray(&arguments); Toy_freeLiteralArray(&arguments);
@@ -1797,7 +1807,7 @@ static bool execIndexAssign(Toy_Interpreter* interpreter) {
Toy_freeLiteral(first); Toy_freeLiteral(first);
Toy_freeLiteral(compound); Toy_freeLiteral(compound);
if (freeIdn) { if (freeIdn) {
Toy_freeLiteral(idn); Toy_freeLiteral(compoundIdn);
} }
Toy_freeLiteral(op); Toy_freeLiteral(op);
Toy_freeLiteralArray(&arguments); Toy_freeLiteralArray(&arguments);
@@ -2001,7 +2011,6 @@ static void execInterpreter(Toy_Interpreter* interpreter) {
} }
break; break;
case TOY_OP_FN_RETURN: case TOY_OP_FN_RETURN:
if (!execFnReturn(interpreter)) { if (!execFnReturn(interpreter)) {
return; return;
@@ -2052,7 +2061,7 @@ static void readInterpreterSections(Toy_Interpreter* interpreter) {
const unsigned short literalCount = readShort(interpreter->bytecode, &interpreter->count); const unsigned short literalCount = readShort(interpreter->bytecode, &interpreter->count);
#ifndef TOY_EXPORT #ifndef TOY_EXPORT
if (command.verbose) { if (Toy_commandLine.verbose) {
printf(TOY_CC_NOTICE "Reading %d literals\n" TOY_CC_RESET, literalCount); printf(TOY_CC_NOTICE "Reading %d literals\n" TOY_CC_RESET, literalCount);
} }
#endif #endif
@@ -2066,7 +2075,7 @@ static void readInterpreterSections(Toy_Interpreter* interpreter) {
Toy_pushLiteralArray(&interpreter->literalCache, TOY_TO_NULL_LITERAL); Toy_pushLiteralArray(&interpreter->literalCache, TOY_TO_NULL_LITERAL);
#ifndef TOY_EXPORT #ifndef TOY_EXPORT
if (command.verbose) { if (Toy_commandLine.verbose) {
printf("(null)\n"); printf("(null)\n");
} }
#endif #endif
@@ -2080,7 +2089,7 @@ static void readInterpreterSections(Toy_Interpreter* interpreter) {
Toy_freeLiteral(literal); Toy_freeLiteral(literal);
#ifndef TOY_EXPORT #ifndef TOY_EXPORT
if (command.verbose) { if (Toy_commandLine.verbose) {
printf("(boolean %s)\n", b ? "true" : "false"); printf("(boolean %s)\n", b ? "true" : "false");
} }
#endif #endif
@@ -2094,7 +2103,7 @@ static void readInterpreterSections(Toy_Interpreter* interpreter) {
Toy_freeLiteral(literal); Toy_freeLiteral(literal);
#ifndef TOY_EXPORT #ifndef TOY_EXPORT
if (command.verbose) { if (Toy_commandLine.verbose) {
printf("(integer %d)\n", d); printf("(integer %d)\n", d);
} }
#endif #endif
@@ -2108,7 +2117,7 @@ static void readInterpreterSections(Toy_Interpreter* interpreter) {
Toy_freeLiteral(literal); Toy_freeLiteral(literal);
#ifndef TOY_EXPORT #ifndef TOY_EXPORT
if (command.verbose) { if (Toy_commandLine.verbose) {
printf("(float %f)\n", f); printf("(float %f)\n", f);
} }
#endif #endif
@@ -2123,13 +2132,14 @@ static void readInterpreterSections(Toy_Interpreter* interpreter) {
Toy_freeLiteral(literal); Toy_freeLiteral(literal);
#ifndef TOY_EXPORT #ifndef TOY_EXPORT
if (command.verbose) { if (Toy_commandLine.verbose) {
printf("(string \"%s\")\n", s); printf("(string \"%s\")\n", s);
} }
#endif #endif
} }
break; break;
case TOY_LITERAL_ARRAY_INTERMEDIATE:
case TOY_LITERAL_ARRAY: { case TOY_LITERAL_ARRAY: {
Toy_LiteralArray* array = TOY_ALLOCATE(Toy_LiteralArray, 1); Toy_LiteralArray* array = TOY_ALLOCATE(Toy_LiteralArray, 1);
Toy_initLiteralArray(array); Toy_initLiteralArray(array);
@@ -2143,7 +2153,7 @@ static void readInterpreterSections(Toy_Interpreter* interpreter) {
} }
#ifndef TOY_EXPORT #ifndef TOY_EXPORT
if (command.verbose) { if (Toy_commandLine.verbose) {
printf("(array "); printf("(array ");
Toy_Literal literal = TOY_TO_ARRAY_LITERAL(array); Toy_Literal literal = TOY_TO_ARRAY_LITERAL(array);
Toy_printLiteral(literal); Toy_printLiteral(literal);
@@ -2160,6 +2170,7 @@ static void readInterpreterSections(Toy_Interpreter* interpreter) {
} }
break; break;
case TOY_LITERAL_DICTIONARY_INTERMEDIATE:
case TOY_LITERAL_DICTIONARY: { case TOY_LITERAL_DICTIONARY: {
Toy_LiteralDictionary* dictionary = TOY_ALLOCATE(Toy_LiteralDictionary, 1); Toy_LiteralDictionary* dictionary = TOY_ALLOCATE(Toy_LiteralDictionary, 1);
Toy_initLiteralDictionary(dictionary); Toy_initLiteralDictionary(dictionary);
@@ -2174,7 +2185,7 @@ static void readInterpreterSections(Toy_Interpreter* interpreter) {
} }
#ifndef TOY_EXPORT #ifndef TOY_EXPORT
if (command.verbose) { if (Toy_commandLine.verbose) {
printf("(dictionary "); printf("(dictionary ");
Toy_Literal literal = TOY_TO_DICTIONARY_LITERAL(dictionary); Toy_Literal literal = TOY_TO_DICTIONARY_LITERAL(dictionary);
Toy_printLiteral(literal); Toy_printLiteral(literal);
@@ -2203,7 +2214,7 @@ static void readInterpreterSections(Toy_Interpreter* interpreter) {
Toy_pushLiteralArray(&interpreter->literalCache, literal); Toy_pushLiteralArray(&interpreter->literalCache, literal);
#ifndef TOY_EXPORT #ifndef TOY_EXPORT
if (command.verbose) { if (Toy_commandLine.verbose) {
printf("(function)\n"); printf("(function)\n");
} }
#endif #endif
@@ -2219,7 +2230,7 @@ static void readInterpreterSections(Toy_Interpreter* interpreter) {
Toy_pushLiteralArray(&interpreter->literalCache, identifier); Toy_pushLiteralArray(&interpreter->literalCache, identifier);
#ifndef TOY_EXPORT #ifndef TOY_EXPORT
if (command.verbose) { if (Toy_commandLine.verbose) {
printf("(identifier %s (hash: %x))\n", Toy_toCString(TOY_AS_IDENTIFIER(identifier)), identifier.as.identifier.hash); printf("(identifier %s (hash: %x))\n", Toy_toCString(TOY_AS_IDENTIFIER(identifier)), identifier.as.identifier.hash);
} }
#endif #endif
@@ -2239,7 +2250,7 @@ static void readInterpreterSections(Toy_Interpreter* interpreter) {
Toy_pushLiteralArray(&interpreter->literalCache, typeLiteral); Toy_pushLiteralArray(&interpreter->literalCache, typeLiteral);
#ifndef TOY_EXPORT #ifndef TOY_EXPORT
if (command.verbose) { if (Toy_commandLine.verbose) {
printf("(type "); printf("(type ");
Toy_printLiteral(typeLiteral); Toy_printLiteral(typeLiteral);
printf(")\n"); printf(")\n");
@@ -2274,7 +2285,7 @@ static void readInterpreterSections(Toy_Interpreter* interpreter) {
Toy_pushLiteralArray(&interpreter->literalCache, typeLiteral); //copied Toy_pushLiteralArray(&interpreter->literalCache, typeLiteral); //copied
#ifndef TOY_EXPORT #ifndef TOY_EXPORT
if (command.verbose) { if (Toy_commandLine.verbose) {
printf("(type "); printf("(type ");
Toy_printLiteral(typeLiteral); Toy_printLiteral(typeLiteral);
printf(")\n"); printf(")\n");
@@ -2290,7 +2301,7 @@ static void readInterpreterSections(Toy_Interpreter* interpreter) {
Toy_pushLiteralArray(&interpreter->literalCache, TOY_TO_INDEX_BLANK_LITERAL); Toy_pushLiteralArray(&interpreter->literalCache, TOY_TO_INDEX_BLANK_LITERAL);
#ifndef TOY_EXPORT #ifndef TOY_EXPORT
if (command.verbose) { if (Toy_commandLine.verbose) {
printf("(blank)\n"); printf("(blank)\n");
} }
#endif #endif
@@ -2388,7 +2399,7 @@ void Toy_runInterpreter(Toy_Interpreter* interpreter, unsigned char* bytecode, i
const char* build = readString(interpreter->bytecode, &interpreter->count); const char* build = readString(interpreter->bytecode, &interpreter->count);
#ifndef TOY_EXPORT #ifndef TOY_EXPORT
if (command.verbose) { if (Toy_commandLine.verbose) {
if (strncmp(build, TOY_VERSION_BUILD, strlen(TOY_VERSION_BUILD))) { if (strncmp(build, TOY_VERSION_BUILD, strlen(TOY_VERSION_BUILD))) {
printf(TOY_CC_WARN "Warning: interpreter/bytecode build mismatch\n" TOY_CC_RESET); printf(TOY_CC_WARN "Warning: interpreter/bytecode build mismatch\n" TOY_CC_RESET);
} }
@@ -2402,7 +2413,7 @@ void Toy_runInterpreter(Toy_Interpreter* interpreter, unsigned char* bytecode, i
//code section //code section
#ifndef TOY_EXPORT #ifndef TOY_EXPORT
if (command.verbose) { if (Toy_commandLine.verbose) {
printf(TOY_CC_NOTICE "executing bytecode\n" TOY_CC_RESET); printf(TOY_CC_NOTICE "executing bytecode\n" TOY_CC_RESET);
} }
#endif #endif
@@ -2434,12 +2445,12 @@ void Toy_resetInterpreter(Toy_Interpreter* interpreter) {
interpreter->scope = Toy_pushScope(NULL); interpreter->scope = Toy_pushScope(NULL);
//globally available functions //globally available functions
Toy_injectNativeFn(interpreter, "_set", _set); Toy_injectNativeFn(interpreter, "_set", Toy_private_set);
Toy_injectNativeFn(interpreter, "_get", _get); Toy_injectNativeFn(interpreter, "_get", Toy_private_get);
Toy_injectNativeFn(interpreter, "_push", _push); Toy_injectNativeFn(interpreter, "_push", Toy_private_push);
Toy_injectNativeFn(interpreter, "_pop", _pop); Toy_injectNativeFn(interpreter, "_pop", Toy_private_pop);
Toy_injectNativeFn(interpreter, "_length", _length); Toy_injectNativeFn(interpreter, "_length", Toy_private_length);
Toy_injectNativeFn(interpreter, "_clear", _clear); Toy_injectNativeFn(interpreter, "_clear", Toy_private_clear);
} }
void Toy_freeInterpreter(Toy_Interpreter* interpreter) { void Toy_freeInterpreter(Toy_Interpreter* interpreter) {
-3
View File
@@ -34,10 +34,7 @@ typedef struct Toy_Interpreter {
} Toy_Interpreter; } Toy_Interpreter;
//native API //native API
typedef int (*Toy_NativeFn)(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments);
TOY_API bool Toy_injectNativeFn(Toy_Interpreter* interpreter, char* name, Toy_NativeFn func); TOY_API bool Toy_injectNativeFn(Toy_Interpreter* interpreter, char* name, Toy_NativeFn func);
typedef int (*Toy_HookFn)(Toy_Interpreter* interpreter, Toy_Literal identifier, Toy_Literal alias);
TOY_API bool Toy_injectNativeHook(Toy_Interpreter* interpreter, char* name, Toy_HookFn hook); TOY_API bool Toy_injectNativeHook(Toy_Interpreter* interpreter, char* name, Toy_HookFn hook);
TOY_API bool Toy_callLiteralFn(Toy_Interpreter* interpreter, Toy_Literal func, Toy_LiteralArray* arguments, Toy_LiteralArray* returns); TOY_API bool Toy_callLiteralFn(Toy_Interpreter* interpreter, Toy_Literal func, Toy_LiteralArray* arguments, Toy_LiteralArray* returns);
+36 -11
View File
@@ -110,7 +110,7 @@ static Toy_Token makeErrorToken(Toy_Lexer* lexer, char* msg) {
token.line = lexer->line; token.line = lexer->line;
#ifndef TOY_EXPORT #ifndef TOY_EXPORT
if (command.verbose) { if (Toy_commandLine.verbose) {
printf("err:"); printf("err:");
Toy_printToken(&token); Toy_printToken(&token);
} }
@@ -129,7 +129,7 @@ static Toy_Token makeToken(Toy_Lexer* lexer, Toy_TokenType type) {
#ifndef TOY_EXPORT #ifndef TOY_EXPORT
//BUG #10: this shows TOKEN_EOF twice due to the overarching structure of the program - can't be fixed //BUG #10: this shows TOKEN_EOF twice due to the overarching structure of the program - can't be fixed
if (command.verbose) { if (Toy_commandLine.verbose) {
printf("tok:"); printf("tok:");
Toy_printToken(&token); Toy_printToken(&token);
} }
@@ -141,12 +141,12 @@ static Toy_Token makeToken(Toy_Lexer* lexer, Toy_TokenType type) {
static Toy_Token makeIntegerOrFloat(Toy_Lexer* lexer) { static Toy_Token makeIntegerOrFloat(Toy_Lexer* lexer) {
Toy_TokenType type = TOY_TOKEN_LITERAL_INTEGER; //what am I making? Toy_TokenType type = TOY_TOKEN_LITERAL_INTEGER; //what am I making?
while(isDigit(lexer)) advance(lexer); while(isDigit(lexer) || peek(lexer) == '_') advance(lexer);
if (peek(lexer) == '.' && (peekNext(lexer) >= '0' && peekNext(lexer) <= '9')) { //BUGFIX: peekNext == digit if (peek(lexer) == '.' && (peekNext(lexer) >= '0' && peekNext(lexer) <= '9')) { //BUGFIX: peekNext == digit
type = TOY_TOKEN_LITERAL_FLOAT; type = TOY_TOKEN_LITERAL_FLOAT;
advance(lexer); advance(lexer);
while(isDigit(lexer)) advance(lexer); while(isDigit(lexer) || peek(lexer) == '_') advance(lexer);
} }
Toy_Token token; Toy_Token token;
@@ -157,7 +157,7 @@ static Toy_Token makeIntegerOrFloat(Toy_Lexer* lexer) {
token.line = lexer->line; token.line = lexer->line;
#ifndef TOY_EXPORT #ifndef TOY_EXPORT
if (command.verbose) { if (Toy_commandLine.verbose) {
if (type == TOY_TOKEN_LITERAL_INTEGER) { if (type == TOY_TOKEN_LITERAL_INTEGER) {
printf("int:"); printf("int:");
} else { } else {
@@ -170,12 +170,37 @@ static Toy_Token makeIntegerOrFloat(Toy_Lexer* lexer) {
return token; return token;
} }
static bool isEscapableCharacter(char c) {
switch (c) {
case 'n':
case 't':
case '\\':
case '"':
return true;
default:
return false;
}
}
static Toy_Token makeString(Toy_Lexer* lexer, char terminator) { static Toy_Token makeString(Toy_Lexer* lexer, char terminator) {
while (!isAtEnd(lexer) && peek(lexer) != terminator) { while (!isAtEnd(lexer)) {
advance(lexer); //stop if you've hit the terminator
if (peek(lexer) == terminator) {
advance(lexer); //eat terminator
break;
} }
advance(lexer); //eat terminator //skip escaped control characters
if (peek(lexer) == '\\' && isEscapableCharacter(peekNext(lexer))) {
advance(lexer);
advance(lexer);
continue;
}
//otherwise
advance(lexer);
}
if (isAtEnd(lexer)) { if (isAtEnd(lexer)) {
return makeErrorToken(lexer, "Unterminated string"); return makeErrorToken(lexer, "Unterminated string");
@@ -189,7 +214,7 @@ static Toy_Token makeString(Toy_Lexer* lexer, char terminator) {
token.line = lexer->line; token.line = lexer->line;
#ifndef TOY_EXPORT #ifndef TOY_EXPORT
if (command.verbose) { if (Toy_commandLine.verbose) {
printf("str:"); printf("str:");
Toy_printToken(&token); Toy_printToken(&token);
} }
@@ -216,7 +241,7 @@ static Toy_Token makeKeywordOrIdentifier(Toy_Lexer* lexer) {
token.line = lexer->line; token.line = lexer->line;
#ifndef TOY_EXPORT #ifndef TOY_EXPORT
if (command.verbose) { if (Toy_commandLine.verbose) {
printf("kwd:"); printf("kwd:");
Toy_printToken(&token); Toy_printToken(&token);
} }
@@ -235,7 +260,7 @@ static Toy_Token makeKeywordOrIdentifier(Toy_Lexer* lexer) {
token.line = lexer->line; token.line = lexer->line;
#ifndef TOY_EXPORT #ifndef TOY_EXPORT
if (command.verbose) { if (Toy_commandLine.verbose) {
printf("idf:"); printf("idf:");
Toy_printToken(&token); Toy_printToken(&token);
} }
+22 -1
View File
@@ -42,7 +42,7 @@ void Toy_freeLiteral(Toy_Literal literal) {
} }
//compounds //compounds
if (TOY_IS_ARRAY(literal) || literal.type == TOY_LITERAL_DICTIONARY_INTERMEDIATE || literal.type == TOY_LITERAL_TYPE_INTERMEDIATE) { if (TOY_IS_ARRAY(literal) || literal.type == TOY_LITERAL_ARRAY_INTERMEDIATE || literal.type == TOY_LITERAL_DICTIONARY_INTERMEDIATE || literal.type == TOY_LITERAL_TYPE_INTERMEDIATE) {
Toy_freeLiteralArray(TOY_AS_ARRAY(literal)); Toy_freeLiteralArray(TOY_AS_ARRAY(literal));
TOY_FREE(Toy_LiteralArray, TOY_AS_ARRAY(literal)); TOY_FREE(Toy_LiteralArray, TOY_AS_ARRAY(literal));
return; return;
@@ -172,6 +172,22 @@ Toy_Literal Toy_copyLiteral(Toy_Literal original) {
return original; //literally a shallow copy return original; //literally a shallow copy
} }
case TOY_LITERAL_ARRAY_INTERMEDIATE: {
Toy_LiteralArray* array = TOY_ALLOCATE(Toy_LiteralArray, 1);
Toy_initLiteralArray(array);
//copy each element
for (int i = 0; i < TOY_AS_ARRAY(original)->count; i++) {
Toy_Literal literal = Toy_copyLiteral(TOY_AS_ARRAY(original)->literals[i]);
Toy_pushLiteralArray(array, literal);
Toy_freeLiteral(literal);
}
Toy_Literal ret = TOY_TO_ARRAY_LITERAL(array);
ret.type = TOY_LITERAL_ARRAY_INTERMEDIATE;
return ret;
}
case TOY_LITERAL_DICTIONARY_INTERMEDIATE: { case TOY_LITERAL_DICTIONARY_INTERMEDIATE: {
Toy_LiteralArray* array = TOY_ALLOCATE(Toy_LiteralArray, 1); Toy_LiteralArray* array = TOY_ALLOCATE(Toy_LiteralArray, 1);
Toy_initLiteralArray(array); Toy_initLiteralArray(array);
@@ -206,6 +222,7 @@ Toy_Literal Toy_copyLiteral(Toy_Literal original) {
case TOY_LITERAL_FUNCTION_INTERMEDIATE: //caries a compiler case TOY_LITERAL_FUNCTION_INTERMEDIATE: //caries a compiler
case TOY_LITERAL_FUNCTION_NATIVE: case TOY_LITERAL_FUNCTION_NATIVE:
case TOY_LITERAL_FUNCTION_HOOK:
case TOY_LITERAL_INDEX_BLANK: case TOY_LITERAL_INDEX_BLANK:
//no copying possible //no copying possible
return original; return original;
@@ -249,6 +266,7 @@ bool Toy_literalsAreEqual(Toy_Literal lhs, Toy_Literal rhs) {
return Toy_equalsRefString(TOY_AS_STRING(lhs), TOY_AS_STRING(rhs)); return Toy_equalsRefString(TOY_AS_STRING(lhs), TOY_AS_STRING(rhs));
case TOY_LITERAL_ARRAY: case TOY_LITERAL_ARRAY:
case TOY_LITERAL_ARRAY_INTERMEDIATE:
case TOY_LITERAL_DICTIONARY_INTERMEDIATE: //BUGFIX case TOY_LITERAL_DICTIONARY_INTERMEDIATE: //BUGFIX
case TOY_LITERAL_TYPE_INTERMEDIATE: //BUGFIX: used for storing types as an array case TOY_LITERAL_TYPE_INTERMEDIATE: //BUGFIX: used for storing types as an array
//mismatched sizes //mismatched sizes
@@ -287,6 +305,7 @@ bool Toy_literalsAreEqual(Toy_Literal lhs, Toy_Literal rhs) {
case TOY_LITERAL_FUNCTION: case TOY_LITERAL_FUNCTION:
case TOY_LITERAL_FUNCTION_NATIVE: case TOY_LITERAL_FUNCTION_NATIVE:
case TOY_LITERAL_FUNCTION_HOOK:
return false; //functions are never equal return false; //functions are never equal
break; break;
@@ -384,6 +403,7 @@ int Toy_hashLiteral(Toy_Literal lit) {
case TOY_LITERAL_FUNCTION: case TOY_LITERAL_FUNCTION:
case TOY_LITERAL_FUNCTION_NATIVE: case TOY_LITERAL_FUNCTION_NATIVE:
case TOY_LITERAL_FUNCTION_HOOK:
return 0; //can't hash these return 0; //can't hash these
case TOY_LITERAL_IDENTIFIER: case TOY_LITERAL_IDENTIFIER:
@@ -570,6 +590,7 @@ void Toy_printLiteralCustom(Toy_Literal literal, void (printFn)(const char*)) {
case TOY_LITERAL_FUNCTION: case TOY_LITERAL_FUNCTION:
case TOY_LITERAL_FUNCTION_NATIVE: case TOY_LITERAL_FUNCTION_NATIVE:
case TOY_LITERAL_FUNCTION_HOOK:
printFn("(function)"); printFn("(function)");
break; break;
+19 -3
View File
@@ -4,6 +4,13 @@
#include "toy_refstring.h" #include "toy_refstring.h"
//forward delcare stuff
struct Toy_Literal;
struct Toy_Interpreter;
struct Toy_LiteralArray;
typedef int (*Toy_NativeFn)(struct Toy_Interpreter* interpreter, struct Toy_LiteralArray* arguments);
typedef int (*Toy_HookFn)(struct Toy_Interpreter* interpreter, struct Toy_Literal identifier, struct Toy_Literal alias);
#include <string.h> #include <string.h>
typedef enum { typedef enum {
@@ -22,14 +29,16 @@ typedef enum {
//these are meta-level types - not for general use //these are meta-level types - not for general use
TOY_LITERAL_TYPE_INTERMEDIATE, //used to process types in the compiler only TOY_LITERAL_TYPE_INTERMEDIATE, //used to process types in the compiler only
TOY_LITERAL_ARRAY_INTERMEDIATE, //used to process arrays in the compiler only
TOY_LITERAL_DICTIONARY_INTERMEDIATE, //used to process dictionaries in the compiler only TOY_LITERAL_DICTIONARY_INTERMEDIATE, //used to process dictionaries in the compiler only
TOY_LITERAL_FUNCTION_INTERMEDIATE, //used to process functions in the compiler only TOY_LITERAL_FUNCTION_INTERMEDIATE, //used to process functions in the compiler only
TOY_LITERAL_FUNCTION_ARG_REST, //used to process function rest parameters only TOY_LITERAL_FUNCTION_ARG_REST, //used to process function rest parameters only
TOY_LITERAL_FUNCTION_NATIVE, //for handling native functions only TOY_LITERAL_FUNCTION_NATIVE, //for handling native functions only
TOY_LITERAL_FUNCTION_HOOK, //for handling hook functions within literals only
TOY_LITERAL_INDEX_BLANK, //for blank indexing i.e. arr[:] TOY_LITERAL_INDEX_BLANK, //for blank indexing i.e. arr[:]
} Toy_LiteralType; } Toy_LiteralType;
typedef struct { typedef struct Toy_Literal {
Toy_LiteralType type; Toy_LiteralType type;
union { union {
bool boolean; bool boolean;
@@ -45,6 +54,8 @@ typedef struct {
struct { struct {
void* bytecode; void* bytecode;
Toy_NativeFn native; //already a pointer
Toy_HookFn hook; //already a pointer
void* scope; void* scope;
int length; int length;
} function; } function;
@@ -55,7 +66,7 @@ typedef struct {
} identifier; } identifier;
struct { struct {
Toy_LiteralType typeOf; //no longer a mask Toy_LiteralType typeOf;
bool constant; bool constant;
void* subtypes; //for nested types caused by compounds void* subtypes; //for nested types caused by compounds
int capacity; int capacity;
@@ -64,7 +75,7 @@ typedef struct {
struct { struct {
void* ptr; void* ptr;
int tag; //TODO: remove tags? int tag;
} opaque; } opaque;
} as; } as;
} Toy_Literal; } Toy_Literal;
@@ -78,6 +89,7 @@ typedef struct {
#define TOY_IS_DICTIONARY(value) ((value).type == TOY_LITERAL_DICTIONARY) #define TOY_IS_DICTIONARY(value) ((value).type == TOY_LITERAL_DICTIONARY)
#define TOY_IS_FUNCTION(value) ((value).type == TOY_LITERAL_FUNCTION) #define TOY_IS_FUNCTION(value) ((value).type == TOY_LITERAL_FUNCTION)
#define TOY_IS_FUNCTION_NATIVE(value) ((value).type == TOY_LITERAL_FUNCTION_NATIVE) #define TOY_IS_FUNCTION_NATIVE(value) ((value).type == TOY_LITERAL_FUNCTION_NATIVE)
#define TOY_IS_FUNCTION_HOOK(value) ((value).type == TOY_LITERAL_FUNCTION_HOOK)
#define TOY_IS_IDENTIFIER(value) ((value).type == TOY_LITERAL_IDENTIFIER) #define TOY_IS_IDENTIFIER(value) ((value).type == TOY_LITERAL_IDENTIFIER)
#define TOY_IS_TYPE(value) ((value).type == TOY_LITERAL_TYPE) #define TOY_IS_TYPE(value) ((value).type == TOY_LITERAL_TYPE)
#define TOY_IS_OPAQUE(value) ((value).type == TOY_LITERAL_OPAQUE) #define TOY_IS_OPAQUE(value) ((value).type == TOY_LITERAL_OPAQUE)
@@ -89,6 +101,8 @@ typedef struct {
#define TOY_AS_ARRAY(value) ((Toy_LiteralArray*)((value).as.array)) #define TOY_AS_ARRAY(value) ((Toy_LiteralArray*)((value).as.array))
#define TOY_AS_DICTIONARY(value) ((Toy_LiteralDictionary*)((value).as.dictionary)) #define TOY_AS_DICTIONARY(value) ((Toy_LiteralDictionary*)((value).as.dictionary))
#define TOY_AS_FUNCTION(value) ((value).as.function) #define TOY_AS_FUNCTION(value) ((value).as.function)
#define TOY_AS_FUNCTION_NATIVE(value) ((value).as.function.native)
#define TOY_AS_FUNCTION_HOOK(value) ((value).as.function.hook)
#define TOY_AS_IDENTIFIER(value) ((value).as.identifier.ptr) #define TOY_AS_IDENTIFIER(value) ((value).as.identifier.ptr)
#define TOY_AS_TYPE(value) ((value).as.type) #define TOY_AS_TYPE(value) ((value).as.type)
#define TOY_AS_OPAQUE(value) ((value).as.opaque.ptr) #define TOY_AS_OPAQUE(value) ((value).as.opaque.ptr)
@@ -101,6 +115,8 @@ typedef struct {
#define TOY_TO_ARRAY_LITERAL(value) ((Toy_Literal){TOY_LITERAL_ARRAY, { .array = value }}) #define TOY_TO_ARRAY_LITERAL(value) ((Toy_Literal){TOY_LITERAL_ARRAY, { .array = value }})
#define TOY_TO_DICTIONARY_LITERAL(value) ((Toy_Literal){TOY_LITERAL_DICTIONARY, { .dictionary = value }}) #define TOY_TO_DICTIONARY_LITERAL(value) ((Toy_Literal){TOY_LITERAL_DICTIONARY, { .dictionary = value }})
#define TOY_TO_FUNCTION_LITERAL(value, l) ((Toy_Literal){TOY_LITERAL_FUNCTION, { .function.bytecode = value, .function.scope = NULL, .function.length = l }}) #define TOY_TO_FUNCTION_LITERAL(value, l) ((Toy_Literal){TOY_LITERAL_FUNCTION, { .function.bytecode = value, .function.scope = NULL, .function.length = l }})
#define TOY_TO_FUNCTION_NATIVE_LITERAL(value) ((Toy_Literal){TOY_LITERAL_FUNCTION_NATIVE, { .function.native = value, .function.scope = NULL, .function.length = 0 }})
#define TOY_TO_FUNCTION_HOOK_LITERAL(value) ((Toy_Literal){TOY_LITERAL_FUNCTION_HOOK, { .function.hook = value, .function.scope = NULL, .function.length = 0 }})
#define TOY_TO_IDENTIFIER_LITERAL(value) Toy_private_toIdentifierLiteral(value) #define TOY_TO_IDENTIFIER_LITERAL(value) Toy_private_toIdentifierLiteral(value)
#define TOY_TO_TYPE_LITERAL(value, c) ((Toy_Literal){ TOY_LITERAL_TYPE, { .type.typeOf = value, .type.constant = c, .type.subtypes = NULL, .type.capacity = 0, .type.count = 0 }}) #define TOY_TO_TYPE_LITERAL(value, c) ((Toy_Literal){ TOY_LITERAL_TYPE, { .type.typeOf = value, .type.constant = c, .type.subtypes = NULL, .type.capacity = 0, .type.count = 0 }})
#define TOY_TO_OPAQUE_LITERAL(value, t) ((Toy_Literal){ TOY_LITERAL_OPAQUE, { .opaque.ptr = value, .opaque.tag = t }}) #define TOY_TO_OPAQUE_LITERAL(value, t) ((Toy_Literal){ TOY_LITERAL_OPAQUE, { .opaque.ptr = value, .opaque.tag = t }})
+3 -8
View File
@@ -7,7 +7,7 @@
#include <stdlib.h> #include <stdlib.h>
//default allocator //default allocator
static void* defaultMemoryAllocator(void* pointer, size_t oldSize, size_t newSize) { void* Toy_private_defaultMemoryAllocator(void* pointer, size_t oldSize, size_t newSize) {
if (newSize == 0 && oldSize == 0) { if (newSize == 0 && oldSize == 0) {
//causes issues, so just skip out with a NO-OP //causes issues, so just skip out with a NO-OP
return NULL; return NULL;
@@ -22,7 +22,7 @@ static void* defaultMemoryAllocator(void* pointer, size_t oldSize, size_t newSiz
void* mem = realloc(pointer, newSize); void* mem = realloc(pointer, newSize);
if (mem == NULL) { if (mem == NULL) {
fprintf(stderr, TOY_CC_ERROR "[internal] Memory allocation error (requested %d for %ld, replacing %d)\n" TOY_CC_RESET, (int)newSize, (long int)pointer, (int)oldSize); fprintf(stderr, TOY_CC_ERROR "[internal] Memory allocation error (requested %d, replacing %d)\n" TOY_CC_RESET, (int)newSize, (int)oldSize);
exit(-1); exit(-1);
} }
@@ -30,12 +30,7 @@ static void* defaultMemoryAllocator(void* pointer, size_t oldSize, size_t newSiz
} }
//static variables //static variables
static Toy_MemoryAllocatorFn allocator; static Toy_MemoryAllocatorFn allocator = Toy_private_defaultMemoryAllocator;
//preload
static void __attribute__((constructor)) preloadMemoryAllocator() {
Toy_setMemoryAllocator(defaultMemoryAllocator);
}
//exposed API //exposed API
void* Toy_reallocate(void* pointer, size_t oldSize, size_t newSize) { void* Toy_reallocate(void* pointer, size_t oldSize, size_t newSize) {
+80 -13
View File
@@ -58,8 +58,8 @@ static void consume(Toy_Parser* parser, Toy_TokenType tokenType, const char* msg
static void synchronize(Toy_Parser* parser) { static void synchronize(Toy_Parser* parser) {
#ifndef TOY_EXPORT #ifndef TOY_EXPORT
if (command.verbose) { if (Toy_commandLine.verbose) {
fprintf(stderr, TOY_CC_ERROR "synchronizing\n" TOY_CC_RESET); fprintf(stderr, TOY_CC_ERROR "Synchronizing input\n" TOY_CC_RESET);
} }
#endif #endif
@@ -112,6 +112,7 @@ typedef struct {
PrecedenceRule precedence; PrecedenceRule precedence;
} ParseRule; } ParseRule;
//no static!
ParseRule parseRules[]; ParseRule parseRules[];
//forward declarations //forward declarations
@@ -260,17 +261,48 @@ static Toy_Opcode string(Toy_Parser* parser, Toy_ASTNode** nodeHandle) {
//handle strings //handle strings
switch(parser->previous.type) { switch(parser->previous.type) {
case TOY_TOKEN_LITERAL_STRING: { case TOY_TOKEN_LITERAL_STRING: {
int length = parser->previous.length; //unescape valid escaped characters
int strLength = 0;
char* buffer = TOY_ALLOCATE(char, parser->previous.length);
//for safety for (int i = 0; i < parser->previous.length; i++) {
if (length > TOY_MAX_STRING_LENGTH) { if (parser->previous.lexeme[i] != '\\') { //copy normally
length = TOY_MAX_STRING_LENGTH; buffer[strLength++] = parser->previous.lexeme[i];
char buffer[256]; continue;
snprintf(buffer, 256, TOY_CC_ERROR "Strings can only be a maximum of %d characters long" TOY_CC_RESET, TOY_MAX_STRING_LENGTH);
error(parser, parser->previous, buffer);
} }
Toy_Literal literal = TOY_TO_STRING_LITERAL(Toy_createRefStringLength(parser->previous.lexeme, length)); //unescape based on the character
switch(parser->previous.lexeme[++i]) {
case 'n':
buffer[strLength++] = '\n';
break;
case 't':
buffer[strLength++] = '\t';
break;
case '\\':
buffer[strLength++] = '\\';
break;
case '"':
buffer[strLength++] = '"';
break;
default: {
char msg[256];
snprintf(msg, 256, TOY_CC_ERROR "Unrecognized escape character %c in string" TOY_CC_RESET, parser->previous.lexeme[++i]);
error(parser, parser->previous, msg);
}
}
}
//for length safety
if (strLength > TOY_MAX_STRING_LENGTH) {
strLength = TOY_MAX_STRING_LENGTH;
char msg[256];
snprintf(msg, 256, TOY_CC_ERROR "Strings can only be a maximum of %d characters long" TOY_CC_RESET, TOY_MAX_STRING_LENGTH);
error(parser, parser->previous, msg);
}
Toy_Literal literal = TOY_TO_STRING_LITERAL(Toy_createRefStringLength(buffer, strLength));
TOY_FREE_ARRAY(char, buffer, parser->previous.length);
Toy_emitASTNodeLiteral(nodeHandle, literal); Toy_emitASTNodeLiteral(nodeHandle, literal);
Toy_freeLiteral(literal); Toy_freeLiteral(literal);
return TOY_OP_EOF; return TOY_OP_EOF;
@@ -476,6 +508,22 @@ static Toy_Opcode unary(Toy_Parser* parser, Toy_ASTNode** nodeHandle) {
return TOY_OP_EOF; return TOY_OP_EOF;
} }
static char* removeChar(char* lexeme, int length, char c) {
int resPos = 0;
char* result = TOY_ALLOCATE(char, length + 1);
for (int i = 0; i < length; i++) {
if (lexeme[i] == c) {
continue;
}
result[resPos++] = lexeme[i];
}
result[resPos] = '\0';
return result;
}
static Toy_Opcode atomic(Toy_Parser* parser, Toy_ASTNode** nodeHandle) { static Toy_Opcode atomic(Toy_Parser* parser, Toy_ASTNode** nodeHandle) {
switch(parser->previous.type) { switch(parser->previous.type) {
case TOY_TOKEN_NULL: case TOY_TOKEN_NULL:
@@ -492,14 +540,18 @@ static Toy_Opcode atomic(Toy_Parser* parser, Toy_ASTNode** nodeHandle) {
case TOY_TOKEN_LITERAL_INTEGER: { case TOY_TOKEN_LITERAL_INTEGER: {
int value = 0; int value = 0;
sscanf(parser->previous.lexeme, "%d", &value); char* lexeme = removeChar(parser->previous.lexeme, parser->previous.length, '_');
sscanf(lexeme, "%d", &value);
TOY_FREE_ARRAY(char, lexeme, parser->previous.length + 1);
Toy_emitASTNodeLiteral(nodeHandle, TOY_TO_INTEGER_LITERAL(value)); Toy_emitASTNodeLiteral(nodeHandle, TOY_TO_INTEGER_LITERAL(value));
return TOY_OP_EOF; return TOY_OP_EOF;
} }
case TOY_TOKEN_LITERAL_FLOAT: { case TOY_TOKEN_LITERAL_FLOAT: {
float value = 0; float value = 0;
sscanf(parser->previous.lexeme, "%f", &value); char* lexeme = removeChar(parser->previous.lexeme, parser->previous.length, '_');
sscanf(lexeme, "%f", &value);
TOY_FREE_ARRAY(char, lexeme, parser->previous.length + 1);
Toy_emitASTNodeLiteral(nodeHandle, TOY_TO_FLOAT_LITERAL(value)); Toy_emitASTNodeLiteral(nodeHandle, TOY_TO_FLOAT_LITERAL(value));
return TOY_OP_EOF; return TOY_OP_EOF;
} }
@@ -950,6 +1002,21 @@ static bool calcStaticBinaryArithmetic(Toy_Parser* parser, Toy_ASTNode** nodeHan
Toy_Literal rhs = (*nodeHandle)->binary.right->atomic.literal; Toy_Literal rhs = (*nodeHandle)->binary.right->atomic.literal;
Toy_Literal result = TOY_TO_NULL_LITERAL; Toy_Literal result = TOY_TO_NULL_LITERAL;
//special case for string concatenation ONLY
if (TOY_IS_STRING(lhs) && TOY_IS_STRING(rhs) && (*nodeHandle)->binary.opcode == TOY_OP_ADDITION) {
//check for overflow
int totalLength = TOY_AS_STRING(lhs)->length + TOY_AS_STRING(rhs)->length;
if (totalLength > TOY_MAX_STRING_LENGTH) {
error(parser, parser->previous, "Can't concatenate these strings, result is too long (error found in constant folding)\n");
return false;
}
//concat the strings
char buffer[TOY_MAX_STRING_LENGTH];
snprintf(buffer, TOY_MAX_STRING_LENGTH, "%s%s", Toy_toCString(TOY_AS_STRING(lhs)), Toy_toCString(TOY_AS_STRING(rhs)));
result = TOY_TO_STRING_LITERAL(Toy_createRefStringLength(buffer, totalLength));
}
//type coersion //type coersion
if (TOY_IS_FLOAT(lhs) && TOY_IS_INTEGER(rhs)) { if (TOY_IS_FLOAT(lhs) && TOY_IS_INTEGER(rhs)) {
rhs = TOY_TO_FLOAT_LITERAL(TOY_AS_INTEGER(rhs)); rhs = TOY_TO_FLOAT_LITERAL(TOY_AS_INTEGER(rhs));
@@ -1153,7 +1220,7 @@ static void parsePrecedence(Toy_Parser* parser, Toy_ASTNode** nodeHandle, Preced
Toy_emitASTNodeBinary(nodeHandle, rhsNode, opcode); Toy_emitASTNodeBinary(nodeHandle, rhsNode, opcode);
//optimise away the constants //optimise away the constants
if (!calcStaticBinaryArithmetic(parser, nodeHandle)) { if (!parser->panic && !calcStaticBinaryArithmetic(parser, nodeHandle)) {
return; return;
} }
} }
+4 -3
View File
@@ -11,7 +11,8 @@ STATIC_ASSERT(sizeof(int) == 4);
STATIC_ASSERT(sizeof(char) == 1); STATIC_ASSERT(sizeof(char) == 1);
//memory allocation //memory allocation
static Toy_RefStringAllocatorFn allocate; extern void* Toy_private_defaultMemoryAllocator(void* pointer, size_t oldSize, size_t newSize);
static Toy_RefStringAllocatorFn allocate = Toy_private_defaultMemoryAllocator;
void Toy_setRefStringAllocatorFn(Toy_RefStringAllocatorFn allocator) { void Toy_setRefStringAllocatorFn(Toy_RefStringAllocatorFn allocator) {
allocate = allocator; allocate = allocator;
@@ -19,7 +20,7 @@ void Toy_setRefStringAllocatorFn(Toy_RefStringAllocatorFn allocator) {
//API //API
Toy_RefString* Toy_createRefString(char* cstring) { Toy_RefString* Toy_createRefString(char* cstring) {
int length = strnlen(cstring, 4096); int length = strlen(cstring);
return Toy_createRefStringLength(cstring, length); return Toy_createRefStringLength(cstring, length);
} }
@@ -86,7 +87,7 @@ bool Toy_equalsRefString(Toy_RefString* lhs, Toy_RefString* rhs) {
bool Toy_equalsRefStringCString(Toy_RefString* lhs, char* cstring) { bool Toy_equalsRefStringCString(Toy_RefString* lhs, char* cstring) {
//get the rhs length //get the rhs length
int length = strnlen(cstring, 4096); int length = strlen(cstring);
//different length //different length
if (lhs->length != length) { if (lhs->length != length) {
+11
View File
@@ -28,4 +28,15 @@ a %= 8;
assert a == 4, "%= failed"; assert a == 4, "%= failed";
//strings as special cases
var s = "foo";
assert s + "bar" == "foobar", "string addition failed";
assert s == "foo", "string addition failed (was too sticky)";
s += "bar";
assert s == "foobar", "string addition failed (wasn't sticky enough)";
print "All good"; print "All good";
+10
View File
@@ -72,6 +72,16 @@
} }
//test nested indexing multipliciation assignment
{
var a = [[1, 2, 3], [4, 5, 6], [7, 8, 9]];
a[1][1] *= 10;
assert a == [[1, 2, 3], [4, 50, 6], [7, 8, 9]], "nested indexing multipliciation assignment failed";
}
//test combine example //test combine example
{ {
fn combine(a, b, c) { fn combine(a, b, c) {
+3 -5
View File
@@ -30,13 +30,11 @@
//test nested indexing //test nested indexing
{ {
var d = ["foo": ["bar": 0]]; var d = ["foo" : ["bar" : ["bazz" : ["fizz" : 5]]]];
d["foo"]["bar"] = 42; d["foo"]["bar"]["bazz"]["fizz"] = 66;
print d; assert d == ["foo": ["bar": ["bazz": ["fizz": 66]]]], "nested indexing failed";
assert d == ["foo": ["bar": 42]], "nested indexing failed";
} }
+4 -4
View File
@@ -18,7 +18,7 @@ assert greeting == "goodnight world", "basic replacement failed";
//test backwards string //test backwards string
assert greeting[::-1] == "dlrow thgindoog", "backwards string failed"; assert greeting[::-1] == "dlrow thgindoog", "backwards string failed";
assert greeting[11:15:-1] == "dlrow", "backwards indexed string failed"; assert greeting[10:14:-1] == "dlrow", "backwards indexed string failed";
//test string weird manipulation //test string weird manipulation
@@ -26,12 +26,12 @@ var numbers = "0123456789";
numbers[::-2] = "abc"; numbers[::-2] = "abc";
assert numbers == "01234c6b8a", "string weird manipulation failed"; assert numbers == "0123c5b7a9", "string weird manipulation failed";
//test indexing with variables //test indexing with variables
var first = 11; var first = 10;
var second = 15; var second = 14;
var third = -1; var third = -1;
assert greeting[first:second:third] == "dlrow", "indexing with variables failed"; assert greeting[first:second:third] == "dlrow", "indexing with variables failed";
+7
View File
@@ -0,0 +1,7 @@
import about as about;
import about;
assert author == "Kayne Ruse, KR Game Studios", "Author failed";
print "All good";
+189
View File
@@ -0,0 +1,189 @@
import compound;
//test concat
{
//test array concat
{
var a = [1, 2, 3];
var b = [4, 5, 6];
var c = a.concat(b).concat(b);
assert c == [1, 2, 3, 4, 5, 6, 4, 5, 6], "array.concat() failed";
}
//test dictionary concat
{
var a = ["one" : 1, "two": 2, "three": 3];
var b = ["four" : 4, "five": 5, "six": 6];
var c = a.concat(b);
assert c.length() == 6, "dictionary.concat().length() failed";
assert c == ["one" : 1, "two": 2, "three": 3, "four" : 4, "five": 5, "six": 6], "dictionary.concat() comparison failed";
}
//test dictionary concat with clashing keys
{
var a = ["one" : 1, "two": 2, "three": 3, "random": 1];
var b = ["four" : 4, "five": 5, "six": 6, "random": 2];
var c = a.concat(b);
assert c["random"] == 1, "dictionary.concat() clashing keys failed";
}
//test string concat
{
var a = "foo";
var b = "bar";
var c = a.concat(b);
assert c == "foobar", "string.concat() failed";
}
}
//test forEach
{
var counter = 0;
fn p(k, v) {
counter++;
print string k + ": " + string v;
}
var a = ["a", "b"];
var d = ["foo": 1, "bar": 2, "bazz": 3, "fizz": 4];
a.forEach(p);
assert counter == 2, "forEach ran an unusual number of times";
counter = 0;
d.forEach(p);
assert counter == 4, "forEach ran an unusual number of times";
}
//test getKeys
{
var d = ["foo": 1, "bar": 2];
var a = d.getKeys();
assert a.length() == 2, "_getKeys() length failed";
//NOTE: dependant on hash algorithm
assert a == ["bar", "foo"], "_getKeys() result failed";
}
//test getValues
{
var d = ["foo": 1, "bar": 2];
var a = d.getValues();
assert a.length() == 2, "_getValues() length failed";
//NOTE: dependant on hash algorithm
assert a == [2, 1], "_getValues() result failed";
}
//test map
{
//test map with toy functions
{
fn increment(k, v) {
return v + 1;
}
var a = [1, 2, 3];
var d = ["four": 4, "five": 5, "six": 6];
assert a.map(increment).map(increment).map(increment) == [4,5,6], "array.map() failed";
assert d.map(increment).map(increment).map(increment) == [8,9,7], "dictionary.map() failed";
}
//test map with native functions
{
//TODO: write some native functions for use with map
}
}
//test reduce
{
var a = [1, 2, 3, 4];
var d = ["one": 1, "two": 2, "three": 3, "four": 4];
fn f(acc, k, v) {
return acc + v;
}
assert a.reduce(0, f) == 10, "array.reduce() failed";
assert d.reduce(0, f) == 10, "dictionary.reduce() failed";
}
//test toLower
{
assert "Hello World".toLower() == "hello world", "_toLower() failed";
}
//test toString
{
var a = [[1, 2, 3], [4, 5, 6], [7, 8, 9]];
var s = a.toString();
assert s == "[[1,2,3],[4,5,6],[7,8,9]]", "array._toString() failed";
}
//test toUpper
{
assert "Hello World".toUpper() == "HELLO WORLD", "_toUpper() failed";
}
//test trim defaults
{
{
//test a bunch
fn test(s, pass) {
var result = s.trim();
assert result == pass, "_trim(" + result + ") failed";
}
test("hello world", "hello world");
test(" hello world", "hello world");
test("hello world ", "hello world");
test(" hello world ", "hello world");
test(" hello world", "hello world");
test("hello world ", "hello world");
test(" hello world ", "hello world");
test(" hello world", "hello world");
test("hello world ", "hello world");
test(" hello world ", "hello world");
//one for goot luck
assert " hello world ".trim() == "hello world", "hello world.trim() failed";
}
//test trim custom values
{
var chars = "heliod";
assert "hello world".trim(chars) == " wor", "custom _trim() failed";
}
//test trimBegin() & trimEnd()
assert " foo ".trimBegin() == "foo ", "string.trimBegin() failed";
assert " foo ".trimEnd() == " foo", "string.trimBegin() failed";
}
print "All good";
+40
View File
@@ -0,0 +1,40 @@
//test this logic for memory leaks
{
import compound;
import timer;
fn start(k, v) {
return startTimer();
}
fn check(k, v) {
var l = v.stopTimer();
print l.timerToString();
l.destroyTimer();
return v;
}
fn destroy(k, v) {
v.destroyTimer();
}
var arr = [1];
arr
.map(start)
.map(check)
.map(check)
.map(check)
.map(check)
.map(check)
.map(check)
.map(check)
.map(check)
.map(check)
.map(check)
.map(destroy)
;
}
print "All good";
@@ -0,0 +1 @@
print "foo" + + "bar";
@@ -0,0 +1,2 @@
1.type();
@@ -2,6 +2,3 @@
var t = astype [int]; var t = astype [int];
var arr: t = [1, 2, 3.14]; var arr: t = [1, 2, 3.14];
} }
print "All good";
@@ -2,6 +2,3 @@
var t = astype [string:int]; var t = astype [string:int];
var dict: t = ["one": 1, "two": 2, 3:4]; var dict: t = ["one": 1, "two": 2, 3:4];
} }
print "All good";
@@ -2,6 +2,3 @@
var t = astype [string:int]; var t = astype [string:int];
var dict: t = ["one": 1, "two": 2, "pi": 3.14]; var dict: t = ["one": 1, "two": 2, "pi": 3.14];
} }
print "All good";
@@ -2,6 +2,3 @@
var a: [int] = [1, 2, 3]; var a: [int] = [1, 2, 3];
print a[a]; print a[a];
} }
print "All good";
+3
View File
@@ -0,0 +1,3 @@
{
var s = "foo" - "bar";
}
+17 -1
View File
@@ -4,7 +4,6 @@
assert false ? false : true, "Basic false ternary failed"; assert false ? false : true, "Basic false ternary failed";
} }
//test nesting //test nesting
{ {
fn least(a, b, c) { fn least(a, b, c) {
@@ -16,6 +15,23 @@
assert least(9, 7, 5) == 5, "Least 9, 7, 5 failed"; assert least(9, 7, 5) == 5, "Least 9, 7, 5 failed";
} }
//test division prevention
{
var x = 0;
assert (x ? 0 : 1 / x) == 0, "Division by zero prevention failed";
}
//test ambiguous syntax
{
var aa = 1;
var bbb = 2;
var cccc = 3;
var ddddd = 4;
var eeeeee = 5;
assert (aa ? bbb ? cccc : ddddd : eeeeee) == 3, "Ambiguous syntax failed";
}
print "All good"; print "All good";
+61 -2
View File
@@ -13,9 +13,11 @@
#include "../repl/repl_tools.h" #include "../repl/repl_tools.h"
#include "../repl/lib_about.h"
#include "../repl/lib_compound.h"
#include "../repl/lib_runner.h"
#include "../repl/lib_standard.h" #include "../repl/lib_standard.h"
#include "../repl/lib_timer.h" #include "../repl/lib_timer.h"
#include "../repl/lib_runner.h"
//supress the print output //supress the print output
static void noPrintFn(const char* output) { static void noPrintFn(const char* output) {
@@ -51,6 +53,26 @@ void runBinaryWithLibrary(unsigned char* tb, size_t size, char* library, Toy_Hoo
Toy_freeInterpreter(&interpreter); Toy_freeInterpreter(&interpreter);
} }
void runBinaryQuietly(unsigned char* tb, size_t size) {
Toy_Interpreter interpreter;
Toy_initInterpreter(&interpreter);
//NOTE: supress print output for testing
Toy_setInterpreterPrint(&interpreter, noPrintFn);
Toy_setInterpreterAssert(&interpreter, assertWrapper);
Toy_setInterpreterError(&interpreter, errorWrapper);
//inject the libs
Toy_injectNativeHook(&interpreter, "about", Toy_hookAbout);
Toy_injectNativeHook(&interpreter, "compound", Toy_hookCompound);
Toy_injectNativeHook(&interpreter, "standard", Toy_hookStandard);
Toy_injectNativeHook(&interpreter, "timer", Toy_hookTimer);
Toy_injectNativeHook(&interpreter, "runner", Toy_hookRunner);
Toy_runInterpreter(&interpreter, tb, size);
Toy_freeInterpreter(&interpreter);
}
typedef struct Payload { typedef struct Payload {
char* fname; char* fname;
char* libname; char* libname;
@@ -73,9 +95,11 @@ int main() {
//run each file in test/scripts //run each file in test/scripts
Payload payloads[] = { Payload payloads[] = {
{"interactions.toy", "standard", Toy_hookStandard}, //interactions needs standard {"interactions.toy", "standard", Toy_hookStandard}, //interactions needs standard
{"about.toy", "about", Toy_hookAbout},
{"compound.toy", "compound", Toy_hookCompound},
{"runner.toy", "runner", Toy_hookRunner},
{"standard.toy", "standard", Toy_hookStandard}, {"standard.toy", "standard", Toy_hookStandard},
{"timer.toy", "timer", Toy_hookTimer}, {"timer.toy", "timer", Toy_hookTimer},
{"runner.toy", "runner", Toy_hookRunner},
{NULL, NULL, NULL} {NULL, NULL, NULL}
}; };
@@ -107,6 +131,41 @@ int main() {
} }
} }
{
//run whatever, testing stuff together to check for memory leaks
char* whatever[] = {
"random-stuff.toy",
NULL
};
for (int i = 0; whatever[i]; i++) {
printf("Running %s\n", whatever[i]);
char fname[128];
snprintf(fname, 128, "scripts/lib/%s", whatever[i]);
//compile the source
size_t size = 0;
char* source = Toy_readFile(fname, &size);
if (!source) {
printf(TOY_CC_ERROR "Failed to load file: %s\n" TOY_CC_RESET, fname);
failedAsserts++;
continue;
}
unsigned char* tb = Toy_compileString(source, &size);
free((void*)source);
if (!tb) {
printf(TOY_CC_ERROR "Failed to compile file: %s\n" TOY_CC_RESET, fname);
failedAsserts++;
continue;
}
runBinaryQuietly(tb, size);
}
}
//lib cleanup //lib cleanup
Toy_freeDriveDictionary(); Toy_freeDriveDictionary();
+3
View File
@@ -96,10 +96,13 @@ int main() {
//run each file in tests/scripts/ //run each file in tests/scripts/
char* filenames[] = { char* filenames[] = {
"access-parent-directory.toy", "access-parent-directory.toy",
"arithmetic-without-operand.toy",
"bad-function-identifier.toy",
"declare-types-array.toy", "declare-types-array.toy",
"declare-types-dictionary-key.toy", "declare-types-dictionary-key.toy",
"declare-types-dictionary-value.toy", "declare-types-dictionary-value.toy",
"index-arrays-non-integer.toy", "index-arrays-non-integer.toy",
"string-concat.toy",
"unary-inverted-nothing.toy", "unary-inverted-nothing.toy",
"unary-negative-nothing.toy", "unary-negative-nothing.toy",
NULL NULL
+80 -4
View File
@@ -36,17 +36,17 @@ int main() {
//inspect the node //inspect the node
if (node == NULL) { if (node == NULL) {
fprintf(stderr, TOY_CC_ERROR "ERROR: ASTNode is null" TOY_CC_RESET); fprintf(stderr, TOY_CC_ERROR "ERROR: ASTNode is null\n" TOY_CC_RESET);
return -1; return -1;
} }
if (node->type != TOY_AST_NODE_UNARY || node->unary.opcode != TOY_OP_PRINT) { if (node->type != TOY_AST_NODE_UNARY || node->unary.opcode != TOY_OP_PRINT) {
fprintf(stderr, TOY_CC_ERROR "ERROR: ASTNode is not a unary print instruction" TOY_CC_RESET); fprintf(stderr, TOY_CC_ERROR "ERROR: ASTNode is not a unary print instruction\n" TOY_CC_RESET);
return -1; return -1;
} }
if (node->unary.child->type != TOY_AST_NODE_LITERAL || !TOY_IS_NULL(node->unary.child->atomic.literal)) { if (node->unary.child->type != TOY_AST_NODE_LITERAL || !TOY_IS_NULL(node->unary.child->atomic.literal)) {
fprintf(stderr, TOY_CC_ERROR "ERROR: ASTNode to be printed is not a null literal" TOY_CC_RESET); fprintf(stderr, TOY_CC_ERROR "ERROR: ASTNode to be printed is not a null literal\n" TOY_CC_RESET);
return -1; return -1;
} }
@@ -70,7 +70,7 @@ int main() {
while (node != NULL) { while (node != NULL) {
if (node->type == TOY_AST_NODE_ERROR) { if (node->type == TOY_AST_NODE_ERROR) {
fprintf(stderr, TOY_CC_ERROR "ERROR: Error node detected" TOY_CC_RESET); fprintf(stderr, TOY_CC_ERROR "ERROR: Error node detected\n" TOY_CC_RESET);
return -1; return -1;
} }
@@ -83,6 +83,82 @@ int main() {
free((void*)source); free((void*)source);
} }
{
//test parsing of escaped characters
char* source = "print \"\\\"\";"; //NOTE: this string goes through two layers of escaping
//test parsing
Toy_Lexer lexer;
Toy_Parser parser;
Toy_initLexer(&lexer, source);
Toy_initParser(&parser, &lexer);
Toy_ASTNode* node = Toy_scanParser(&parser);
//inspect the node
if (node == NULL) {
fprintf(stderr, TOY_CC_ERROR "ERROR: ASTNode is null\n" TOY_CC_RESET);
return -1;
}
if (node->type != TOY_AST_NODE_UNARY || node->unary.opcode != TOY_OP_PRINT) {
fprintf(stderr, TOY_CC_ERROR "ERROR: ASTNode is not a unary print instruction\n" TOY_CC_RESET);
return -1;
}
if (node->unary.child->type != TOY_AST_NODE_LITERAL || !TOY_IS_STRING(node->unary.child->atomic.literal)) {
fprintf(stderr, TOY_CC_ERROR "ERROR: ASTNode to be printed is not a string literal\n" TOY_CC_RESET);
return -1;
}
if (!Toy_equalsRefStringCString(TOY_AS_STRING(node->unary.child->atomic.literal), "\"")) {
fprintf(stderr, TOY_CC_ERROR "ERROR: ASTNode to be printed is not an escaped character, found: %s\n" TOY_CC_RESET, Toy_toCString(TOY_AS_STRING(node->unary.child->atomic.literal)));
return -1;
}
//cleanup
Toy_freeASTNode(node);
Toy_freeParser(&parser);
}
{
//test parsing of underscored numbers
char* source = "print 1_000_000;";
//test parsing
Toy_Lexer lexer;
Toy_Parser parser;
Toy_initLexer(&lexer, source);
Toy_initParser(&parser, &lexer);
Toy_ASTNode* node = Toy_scanParser(&parser);
//inspect the node
if (node == NULL) {
fprintf(stderr, TOY_CC_ERROR "ERROR: ASTNode is null\n" TOY_CC_RESET);
return -1;
}
if (node->type != TOY_AST_NODE_UNARY || node->unary.opcode != TOY_OP_PRINT) {
fprintf(stderr, TOY_CC_ERROR "ERROR: ASTNode is not a unary print instruction\n" TOY_CC_RESET);
return -1;
}
if (node->unary.child->type != TOY_AST_NODE_LITERAL || !TOY_IS_INTEGER(node->unary.child->atomic.literal)) {
fprintf(stderr, TOY_CC_ERROR "ERROR: ASTNode to be printed is not a string literal\n" TOY_CC_RESET);
return -1;
}
if (TOY_AS_INTEGER(node->unary.child->atomic.literal) != 1000000) {
fprintf(stderr, TOY_CC_ERROR "ERROR: ASTNode to be printed is not the correct value, found: %d\n" TOY_CC_RESET, TOY_AS_INTEGER(node->unary.child->atomic.literal));
return -1;
}
//cleanup
Toy_freeASTNode(node);
Toy_freeParser(&parser);
}
printf(TOY_CC_NOTICE "All good\n" TOY_CC_RESET); printf(TOY_CC_NOTICE "All good\n" TOY_CC_RESET);
return 0; return 0;
} }
+72
View File
@@ -0,0 +1,72 @@
#include "repl_tools.h"
#include "toy_memory.h"
#include "toy_console_colors.h"
#include "lib_runner.h"
#include <stdio.h>
#include <stdlib.h>
//tracker allocator
int currentMemoryUsed = 0;
int maxMemoryUsed = 0;
int memoryAllocCalls = 0;
static void* trackerAllocator(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;
}
memoryAllocCalls++;
//track the changes
currentMemoryUsed = currentMemoryUsed - oldSize + newSize;
maxMemoryUsed = currentMemoryUsed > maxMemoryUsed ? currentMemoryUsed : maxMemoryUsed;
if (newSize == 0) {
free(pointer);
return NULL;
}
void* mem = realloc(pointer, newSize);
if (mem == NULL) {
fprintf(stderr, TOY_CC_ERROR "[internal] Memory allocation error (requested %d, replacing %d)\n" TOY_CC_RESET, (int)newSize, (int)oldSize);
exit(-1);
}
return mem;
}
int main(int argc, char* argv[]) {
if (argc <= 1) {
return -1;
}
//setup for runner
Toy_initDriveDictionary();
Toy_Literal driveLiteral = TOY_TO_STRING_LITERAL(Toy_createRefString("scripts"));
Toy_Literal pathLiteral = TOY_TO_STRING_LITERAL(Toy_createRefString("scripts"));
Toy_setLiteralDictionary(Toy_getDriveDictionary(), driveLiteral, pathLiteral);
Toy_freeLiteral(driveLiteral);
Toy_freeLiteral(pathLiteral);
Toy_setMemoryAllocator(trackerAllocator);
//run memory tests
for (int fileCounter = 1; fileCounter < argc; fileCounter++) {
Toy_runSourceFile(argv[fileCounter]);
}
//lib cleanup
Toy_freeDriveDictionary();
//report output
printf("Memory report: %d max bytes, %d calls\n", maxMemoryUsed, memoryAllocCalls);
return 0;
}
+42
View File
@@ -0,0 +1,42 @@
CC=gcc
TOY_OUTDIR=out
IDIR+=. ../../source
CFLAGS+=$(addprefix -I,$(IDIR)) -g -Wall -W -Wno-unused-parameter -Wno-unused-function -Wno-unused-variable
LIBS+=-ltoy
ODIR = obj
SRC = $(wildcard *.c)
OBJ = $(addprefix $(ODIR)/,$(SRC:.c=.o))
OUTNAME=toy
OUT=../../$(TOY_OUTDIR)/memusage
all:
cp $(shell find ../../repl/repl_tools*) .
cp $(shell find ../../repl/lib*) .
$(MAKE) build
build: $(OBJ)
echo $(OBJ)
ifeq ($(shell uname),Darwin)
cp $(PWD)/$(TOY_OUTDIR)/lib$(OUTNAME).dylib /usr/local/lib/
$(CC) -DTOY_IMPORT $(CFLAGS) -o $(OUT) $(OBJ) $(LIBS)
else
$(CC) -DTOY_IMPORT $(CFLAGS) -o $(OUT) $(OBJ) -Wl,-rpath,. -L$(realpath $(shell pwd)/../../$(TOY_OUTDIR)) $(LIBS)
endif
$(OBJ): | $(ODIR)
$(ODIR):
mkdir $(ODIR)
$(ODIR)/%.o: %.c
$(CC) -c -o $@ $< $(CFLAGS)
.PHONY: clean
clean:
$(RM) -r $(ODIR)
$(RM) $(shell find ./repl_tools*)
$(RM) $(shell find ./lib*)