Compare commits
10 Commits
bbb1e38649
...
v2
| Author | SHA1 | Date | |
|---|---|---|---|
| 4e31c0c551 | |||
| a00739f580 | |||
| d194bff5fe | |||
| 75cb1dfa86 | |||
| 27d2a21710 | |||
| abba7e0534 | |||
| b312c0d8a3 | |||
| 3e115095d6 | |||
| f2b714baaa | |||
| 92e4a41662 |
Vendored
+1
-1
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"recommendations": [
|
"recommendations": [
|
||||||
"gruntfuggly.todo-tree"
|
"FanaticPythoner.better-todo-tree"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
Vendored
+7
-7
@@ -1,16 +1,16 @@
|
|||||||
{
|
{
|
||||||
"todo-tree.filtering.includeGlobs": [
|
"better-todo-tree.filtering.includeGlobs": [
|
||||||
"**/repl/**",
|
"**/repl/**",
|
||||||
"**/scripts/**",
|
"**/examples/**",
|
||||||
"**/source/**",
|
"**/source/**",
|
||||||
"**/tests/**",
|
"**/tests/**"
|
||||||
"**/tools/**",
|
|
||||||
],
|
],
|
||||||
"todo-tree.filtering.excludeGlobs": [
|
"better-todo-tree.filtering.excludeGlobs": [
|
||||||
"**/obj/**",
|
"**/obj/**",
|
||||||
"**/out/**",
|
"**/out/**",
|
||||||
|
"**/docs/**"
|
||||||
],
|
],
|
||||||
"todo-tree.general.tags": [
|
"better-todo-tree.general.tags": [
|
||||||
"URGENT",
|
"URGENT",
|
||||||
"BUG",
|
"BUG",
|
||||||
"TODO",
|
"TODO",
|
||||||
@@ -19,7 +19,7 @@
|
|||||||
"WONTFIX",
|
"WONTFIX",
|
||||||
"NOTE"
|
"NOTE"
|
||||||
],
|
],
|
||||||
"todo-tree.highlights.customHighlight": {
|
"better-todo-tree.highlights.customHighlight": {
|
||||||
"URGENT": {
|
"URGENT": {
|
||||||
"icon": "alert",
|
"icon": "alert",
|
||||||
"type": "text",
|
"type": "text",
|
||||||
|
|||||||
@@ -33,10 +33,9 @@ fn makeCounter() {
|
|||||||
|
|
||||||
var tally = makeCounter();
|
var tally = makeCounter();
|
||||||
|
|
||||||
while (true) {
|
var result = 0;
|
||||||
var result = tally();
|
while (result = tally()) {
|
||||||
|
print result;
|
||||||
print result; //prints 1 to 10
|
|
||||||
|
|
||||||
if (result >= 10) {
|
if (result >= 10) {
|
||||||
break;
|
break;
|
||||||
|
|||||||
+4
-5
@@ -29,10 +29,9 @@ fn makeCounter() {
|
|||||||
|
|
||||||
var tally = makeCounter();
|
var tally = makeCounter();
|
||||||
|
|
||||||
while (true) {
|
var result = 0;
|
||||||
var result = tally();
|
while (result = tally()) {
|
||||||
|
print result;
|
||||||
print result; //prints 1 to 10
|
|
||||||
|
|
||||||
if (result >= 10) {
|
if (result >= 10) {
|
||||||
break;
|
break;
|
||||||
@@ -44,7 +43,7 @@ while (true) {
|
|||||||
|
|
||||||
This website is a work in progress - for further info, see the official repository: [https://gitea.krgamestudios.com/krgamestudios/Toy](https://gitea.krgamestudios.com/krgamestudios/Toy), or the GitHub mirror: [https://github.com/krgamestudios/Toy](https://github.com/krgamestudios/Toy).
|
This website is a work in progress - for further info, see the official repository: [https://gitea.krgamestudios.com/krgamestudios/Toy](https://gitea.krgamestudios.com/krgamestudios/Toy), or the GitHub mirror: [https://github.com/krgamestudios/Toy](https://github.com/krgamestudios/Toy).
|
||||||
|
|
||||||
An example of Toy in action: [Vampire Toyvivors](https://gitea.krgamestudios.com/krgamestudios/VampireToyvivors) (a simple "game" used for testing, not intended for commercial release).
|
An example of Toy in action: [ToyBox](https://gitea.krgamestudios.com/krgamestudios/ToyBox) - IDK what it is, I'll figure it out on the way.
|
||||||
|
|
||||||
<p align="center">
|
<p align="center">
|
||||||
<image src="img/noai.png" alt="No AI" width="200px" />
|
<image src="img/noai.png" alt="No AI" width="200px" />
|
||||||
|
|||||||
+16
-1
@@ -141,4 +141,19 @@ TOY_API void Toy_inheritVM(Toy_VM* parentVM, Toy_VM* subVM);
|
|||||||
TOY_API unsigned int Toy_runVM(Toy_VM* vm);
|
TOY_API unsigned int Toy_runVM(Toy_VM* vm);
|
||||||
TOY_API void Toy_freeVM(Toy_VM* vm);
|
TOY_API void Toy_freeVM(Toy_VM* vm);
|
||||||
TOY_API Toy_Value Toy_getReturnValueFromVM(Toy_VM* parentVM, Toy_VM* subVM);
|
TOY_API Toy_Value Toy_getReturnValueFromVM(Toy_VM* parentVM, Toy_VM* subVM);
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Standard Library
|
||||||
|
|
||||||
|
The tools in `repl/` includes a standard library, which can be added to the root VM by calling `initStandardLibrary` just before `Toy_runVM`. It provides the following general purpose functions:
|
||||||
|
|
||||||
|
* `min(x, y)`
|
||||||
|
* `max(x, y)`
|
||||||
|
* `floor(x)`
|
||||||
|
* `ceil(x)`
|
||||||
|
* `sqrt(x)`
|
||||||
|
* `range(x)`
|
||||||
|
|
||||||
|
It also offers an example of how to write an API.
|
||||||
|
|
||||||
|
*Note: Range returns a closure intended for use in the `for` keyword, but the that keyword isn't done yet.*
|
||||||
@@ -1,5 +1,3 @@
|
|||||||
//tentatively functional
|
|
||||||
|
|
||||||
//fibonacci sequence
|
//fibonacci sequence
|
||||||
fn fib(n) {
|
fn fib(n) {
|
||||||
if (n < 2) return n;
|
if (n < 2) return n;
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
//the semicolon is super important
|
||||||
|
print "Hello world!";
|
||||||
@@ -1,11 +1,10 @@
|
|||||||
//find the leap years
|
//is 'n' a leap year
|
||||||
fn isLeapYear(n: Int) {
|
fn isLeapYear(n: Int) {
|
||||||
if (n % 400 == 0) return true;
|
if (n % 400 == 0) return true;
|
||||||
if (n % 100 == 0) return false;
|
if (n % 100 == 0) return false;
|
||||||
return n % 4 == 0;
|
return n % 4 == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
//check for string reuse
|
|
||||||
{
|
{
|
||||||
print isLeapYear(1999);
|
print isLeapYear(1999);
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
|
||||||
|
var randi: Int = 69420;
|
||||||
|
fn rand() {
|
||||||
|
//a quick and dirty random number generator
|
||||||
|
return randi = randi * 1664525 + 1013904223;
|
||||||
|
}
|
||||||
|
|
||||||
|
print rand();
|
||||||
|
print rand();
|
||||||
|
print rand();
|
||||||
@@ -8,11 +8,11 @@ fn makeCounter() {
|
|||||||
return increment;
|
return increment;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//'tally' becomes a closure
|
||||||
var tally = makeCounter();
|
var tally = makeCounter();
|
||||||
|
|
||||||
while (true) {
|
var result = 0;
|
||||||
var result = tally();
|
while (result = tally()) {
|
||||||
|
|
||||||
print result;
|
print result;
|
||||||
|
|
||||||
if (result >= 10) {
|
if (result >= 10) {
|
||||||
+4
-30
@@ -1,6 +1,7 @@
|
|||||||
|
#include "bucket_inspector.h"
|
||||||
#include "ast_inspector.h"
|
#include "ast_inspector.h"
|
||||||
#include "bytecode_inspector.h"
|
#include "bytecode_inspector.h"
|
||||||
#include "bucket_inspector.h"
|
#include "stack_inspector.h"
|
||||||
|
|
||||||
#include "toy_console_colors.h"
|
#include "toy_console_colors.h"
|
||||||
|
|
||||||
@@ -9,7 +10,6 @@
|
|||||||
#include "toy_compiler.h"
|
#include "toy_compiler.h"
|
||||||
#include "toy_vm.h"
|
#include "toy_vm.h"
|
||||||
|
|
||||||
//NOTE: for testing
|
|
||||||
#include "standard_library.h"
|
#include "standard_library.h"
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
@@ -247,32 +247,6 @@ CmdLine parseCmdLine(int argc, const char* argv[]) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//debugging
|
//debugging
|
||||||
static void debugStackPrint(Toy_Stack* stack) {
|
|
||||||
//DEBUG: if there's anything on the stack, print it
|
|
||||||
if (stack->count > 0) {
|
|
||||||
Toy_Bucket* stringBucket = Toy_allocateBucket(TOY_BUCKET_IDEAL);
|
|
||||||
|
|
||||||
printf("\n" TOY_CC_NOTICE "Stack Dump" TOY_CC_RESET "\n" TOY_CC_NOTICE "%-20s%-20s" TOY_CC_RESET "\n", "type", "value");
|
|
||||||
for (unsigned int i = 0; i < stack->count; i++) {
|
|
||||||
Toy_Value v = ((Toy_Value*)(stack + 1))[i]; //'stack + 1' is a naughty trick
|
|
||||||
|
|
||||||
//print type
|
|
||||||
printf("%-20s", Toy_getValueTypeAsCString(v.type));
|
|
||||||
|
|
||||||
//print value
|
|
||||||
Toy_String* string = Toy_stringifyValue(&stringBucket, Toy_unwrapValue(v));
|
|
||||||
char* buffer = Toy_getStringRaw(string);
|
|
||||||
printf("%-20s", buffer);
|
|
||||||
free(buffer);
|
|
||||||
Toy_freeString(string);
|
|
||||||
|
|
||||||
printf("\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
Toy_freeBucket(&stringBucket);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void debugScopePrint(Toy_Scope* scope, int depth) {
|
static void debugScopePrint(Toy_Scope* scope, int depth) {
|
||||||
//DEBUG: if there's anything in the scope, print it
|
//DEBUG: if there's anything in the scope, print it
|
||||||
if (scope->count > 0) {
|
if (scope->count > 0) {
|
||||||
@@ -392,7 +366,7 @@ int repl(const char* filepath, bool verbose) {
|
|||||||
|
|
||||||
//print the debug info
|
//print the debug info
|
||||||
if (verbose) {
|
if (verbose) {
|
||||||
debugStackPrint(vm.stack);
|
inspect_stack(vm.stack);
|
||||||
debugScopePrint(vm.scope, 0);
|
debugScopePrint(vm.scope, 0);
|
||||||
|
|
||||||
depthBeforeGC = inspect_bucket(&vm.memoryBucket);
|
depthBeforeGC = inspect_bucket(&vm.memoryBucket);
|
||||||
@@ -516,7 +490,7 @@ int main(int argc, const char* argv[]) {
|
|||||||
|
|
||||||
//print the debug info
|
//print the debug info
|
||||||
if (cmd.verbose) {
|
if (cmd.verbose) {
|
||||||
debugStackPrint(vm.stack);
|
inspect_stack(vm.stack);
|
||||||
debugScopePrint(vm.scope, 0);
|
debugScopePrint(vm.scope, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,39 @@
|
|||||||
|
#include "stack_inspector.h"
|
||||||
|
#include "toy_console_colors.h"
|
||||||
|
#include "toy_string.h"
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
void inspect_stack(Toy_Stack* stack) {
|
||||||
|
printf(TOY_CC_NOTICE "Stack State: %u / %u\n" TOY_CC_RESET, stack->count, stack->capacity);
|
||||||
|
|
||||||
|
if (stack->count == 0) {
|
||||||
|
printf(TOY_CC_NOTICE "\n-- Empty Stack --\n\n" TOY_CC_RESET);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Toy_Bucket* bucket = Toy_allocateBucket(TOY_BUCKET_IDEAL);
|
||||||
|
|
||||||
|
printf(TOY_CC_NOTICE "-- Beginning Stack Dump --\n\n%-10s%-20s%-20s\n\n" TOY_CC_RESET, "Index", "Type", "Value");
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < stack->count; i++) {
|
||||||
|
Toy_Value v = ((Toy_Value*)(stack + 1))[i]; //'stack + 1' is a naughty trick
|
||||||
|
|
||||||
|
//print type
|
||||||
|
printf("%-10u%-20s", i, Toy_getValueTypeAsCString(v.type));
|
||||||
|
|
||||||
|
//print value
|
||||||
|
Toy_String* string = Toy_stringifyValue(&bucket, Toy_unwrapValue(v));
|
||||||
|
char* buffer = Toy_getStringRaw(string); //lazy, but it works
|
||||||
|
printf("%-20s", buffer);
|
||||||
|
free(buffer);
|
||||||
|
Toy_freeString(string);
|
||||||
|
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
printf(TOY_CC_NOTICE "\n-- End Stack Dump --\n\n" TOY_CC_RESET);
|
||||||
|
|
||||||
|
Toy_freeBucket(&bucket);
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "toy_stack.h"
|
||||||
|
|
||||||
|
void inspect_stack(Toy_Stack* stack);
|
||||||
+161
-24
@@ -1,49 +1,185 @@
|
|||||||
#include "standard_library.h"
|
#include "standard_library.h"
|
||||||
#include "toy_console_colors.h"
|
#include "toy_console_colors.h"
|
||||||
|
|
||||||
#include "toy_print.h"
|
|
||||||
#include "toy_scope.h"
|
#include "toy_scope.h"
|
||||||
#include "toy_stack.h"
|
#include "toy_stack.h"
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
typedef struct CallbackPairs {
|
typedef struct CallbackPairs {
|
||||||
const char* name;
|
const char* name;
|
||||||
Toy_nativeCallback callback;
|
Toy_nativeCallback callback;
|
||||||
} CallbackPairs;
|
} CallbackPairs;
|
||||||
|
|
||||||
//example callbacks
|
//example of how to write and use C bindings
|
||||||
static void answer(Toy_VM* vm, Toy_FunctionNative* self) {
|
static void std_min(Toy_VM* vm, Toy_FunctionNative* self) {
|
||||||
(void)vm;
|
|
||||||
(void)self;
|
(void)self;
|
||||||
Toy_print(TOY_CC_DEBUG "This function returns the integer '42' to the calling scope." TOY_CC_RESET);
|
|
||||||
Toy_pushStack(&vm->stack, TOY_VALUE_FROM_INTEGER(42));
|
//return the lesser of two values, or null on error
|
||||||
|
Toy_Value first = Toy_popStack(&vm->stack);
|
||||||
|
Toy_Value second = Toy_popStack(&vm->stack);
|
||||||
|
|
||||||
|
//check types
|
||||||
|
if ((!TOY_VALUE_IS_INTEGER(first) && !TOY_VALUE_IS_FLOAT(first)) || (!TOY_VALUE_IS_INTEGER(second) && !TOY_VALUE_IS_FLOAT(second))) {
|
||||||
|
char buffer[256];
|
||||||
|
snprintf(buffer, 256, "Invalid types '%s' and '%s' found in 'min()'", Toy_getValueTypeAsCString(Toy_unwrapValue(first).type), Toy_getValueTypeAsCString(Toy_unwrapValue(second).type));
|
||||||
|
Toy_error(buffer);
|
||||||
|
|
||||||
|
Toy_freeValue(first);
|
||||||
|
Toy_freeValue(second);
|
||||||
|
Toy_pushStack(&vm->stack, TOY_VALUE_FROM_NULL());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//compare ints, or coerce ints into floats if needed
|
||||||
|
if (TOY_VALUE_IS_INTEGER(first) && TOY_VALUE_IS_INTEGER(second)) {
|
||||||
|
Toy_Value result = TOY_VALUE_FROM_INTEGER(TOY_VALUE_AS_INTEGER(first) < TOY_VALUE_AS_INTEGER(second) ? TOY_VALUE_AS_INTEGER(first) : TOY_VALUE_AS_INTEGER(second));
|
||||||
|
Toy_pushStack(&vm->stack, result);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else if (TOY_VALUE_IS_INTEGER(first) && TOY_VALUE_IS_FLOAT(second)) {
|
||||||
|
first = TOY_VALUE_FROM_FLOAT( (float)TOY_VALUE_AS_INTEGER(first) );
|
||||||
|
}
|
||||||
|
else if (TOY_VALUE_IS_FLOAT(first) && TOY_VALUE_IS_INTEGER(second)) {
|
||||||
|
second = TOY_VALUE_FROM_FLOAT( (float)TOY_VALUE_AS_INTEGER(second) );
|
||||||
|
}
|
||||||
|
|
||||||
|
//finally, do the comparison on floats
|
||||||
|
Toy_Value result = TOY_VALUE_FROM_FLOAT(TOY_VALUE_AS_FLOAT(first) < TOY_VALUE_AS_FLOAT(second) ? TOY_VALUE_AS_FLOAT(first) : TOY_VALUE_AS_FLOAT(second));
|
||||||
|
Toy_pushStack(&vm->stack, result);
|
||||||
|
//NOTE: not freeing scalar values does work, but only in narrow cases
|
||||||
}
|
}
|
||||||
|
|
||||||
static void identity(Toy_VM* vm, Toy_FunctionNative* self) {
|
static void std_max(Toy_VM* vm, Toy_FunctionNative* self) {
|
||||||
//does nothing, but any arguements are left on the stack as results
|
|
||||||
(void)vm;
|
|
||||||
(void)self;
|
(void)self;
|
||||||
|
|
||||||
|
//return the lesser of two values, or null on error
|
||||||
|
Toy_Value first = Toy_popStack(&vm->stack);
|
||||||
|
Toy_Value second = Toy_popStack(&vm->stack);
|
||||||
|
|
||||||
|
//check types
|
||||||
|
if ((!TOY_VALUE_IS_INTEGER(first) && !TOY_VALUE_IS_FLOAT(first)) || (!TOY_VALUE_IS_INTEGER(second) && !TOY_VALUE_IS_FLOAT(second))) {
|
||||||
|
char buffer[256];
|
||||||
|
snprintf(buffer, 256, "Invalid types '%s' and '%s' found in 'max()'", Toy_getValueTypeAsCString(Toy_unwrapValue(first).type), Toy_getValueTypeAsCString(Toy_unwrapValue(second).type));
|
||||||
|
Toy_error(buffer);
|
||||||
|
|
||||||
|
Toy_freeValue(first);
|
||||||
|
Toy_freeValue(second);
|
||||||
|
Toy_pushStack(&vm->stack, TOY_VALUE_FROM_NULL());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//compare ints, or coerce ints into floats if needed
|
||||||
|
if (TOY_VALUE_IS_INTEGER(first) && TOY_VALUE_IS_INTEGER(second)) {
|
||||||
|
Toy_Value result = TOY_VALUE_FROM_INTEGER(TOY_VALUE_AS_INTEGER(first) > TOY_VALUE_AS_INTEGER(second) ? TOY_VALUE_AS_INTEGER(first) : TOY_VALUE_AS_INTEGER(second));
|
||||||
|
Toy_pushStack(&vm->stack, result);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else if (TOY_VALUE_IS_INTEGER(first) && TOY_VALUE_IS_FLOAT(second)) {
|
||||||
|
first = TOY_VALUE_FROM_FLOAT( (float)TOY_VALUE_AS_INTEGER(first) );
|
||||||
|
}
|
||||||
|
else if (TOY_VALUE_IS_FLOAT(first) && TOY_VALUE_IS_INTEGER(second)) {
|
||||||
|
second = TOY_VALUE_FROM_FLOAT( (float)TOY_VALUE_AS_INTEGER(second) );
|
||||||
|
}
|
||||||
|
|
||||||
|
//finally, do the comparison on floats
|
||||||
|
Toy_Value result = TOY_VALUE_FROM_FLOAT(TOY_VALUE_AS_FLOAT(first) > TOY_VALUE_AS_FLOAT(second) ? TOY_VALUE_AS_FLOAT(first) : TOY_VALUE_AS_FLOAT(second));
|
||||||
|
Toy_pushStack(&vm->stack, result);
|
||||||
|
//NOTE: not freeing scalar values does work, but only in narrow cases
|
||||||
}
|
}
|
||||||
|
|
||||||
static void echo(Toy_VM* vm, Toy_FunctionNative* self) {
|
static void std_floor(Toy_VM* vm, Toy_FunctionNative* self) {
|
||||||
(void)self;
|
(void)self;
|
||||||
//pops one argument, and prints it
|
|
||||||
Toy_Value value = Toy_popStack(&vm->stack);
|
Toy_Value value = Toy_popStack(&vm->stack);
|
||||||
Toy_String* string = Toy_stringifyValue(&vm->memoryBucket, value);
|
|
||||||
char* cstr = Toy_getStringRaw(string);
|
|
||||||
|
|
||||||
Toy_print(cstr);
|
if (!TOY_VALUE_IS_INTEGER(value) && !TOY_VALUE_IS_FLOAT(value)) {
|
||||||
|
char buffer[256];
|
||||||
|
snprintf(buffer, 256, "Invalid type '%s' found in 'floor()'", Toy_getValueTypeAsCString(Toy_unwrapValue(value).type));
|
||||||
|
Toy_error(buffer);
|
||||||
|
|
||||||
free(cstr);
|
Toy_freeValue(value);
|
||||||
Toy_freeString(string);
|
Toy_pushStack(&vm->stack, TOY_VALUE_FROM_NULL());
|
||||||
Toy_freeValue(value);
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//this only runs on floats, but converts them to integers
|
||||||
|
if (TOY_VALUE_IS_FLOAT(value)) {
|
||||||
|
double d = (double)TOY_VALUE_AS_FLOAT(value);
|
||||||
|
d = floor(d);
|
||||||
|
value = TOY_VALUE_FROM_INTEGER((int)d);
|
||||||
|
}
|
||||||
|
|
||||||
|
Toy_pushStack(&vm->stack, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void std_ceil(Toy_VM* vm, Toy_FunctionNative* self) {
|
||||||
|
(void)self;
|
||||||
|
|
||||||
|
Toy_Value value = Toy_popStack(&vm->stack);
|
||||||
|
|
||||||
|
if (!TOY_VALUE_IS_INTEGER(value) && !TOY_VALUE_IS_FLOAT(value)) {
|
||||||
|
char buffer[256];
|
||||||
|
snprintf(buffer, 256, "Invalid type '%s' found in 'ceil()'", Toy_getValueTypeAsCString(Toy_unwrapValue(value).type));
|
||||||
|
Toy_error(buffer);
|
||||||
|
|
||||||
|
Toy_freeValue(value);
|
||||||
|
Toy_pushStack(&vm->stack, TOY_VALUE_FROM_NULL());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//this only runs on floats, but converts them to integers
|
||||||
|
if (TOY_VALUE_IS_FLOAT(value)) {
|
||||||
|
double d = (double)TOY_VALUE_AS_FLOAT(value);
|
||||||
|
d = ceil(d);
|
||||||
|
value = TOY_VALUE_FROM_INTEGER((int)d);
|
||||||
|
}
|
||||||
|
|
||||||
|
Toy_pushStack(&vm->stack, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void std_sqrt(Toy_VM* vm, Toy_FunctionNative* self) {
|
||||||
|
(void)self;
|
||||||
|
|
||||||
|
Toy_Value value = Toy_popStack(&vm->stack);
|
||||||
|
|
||||||
|
if (!TOY_VALUE_IS_INTEGER(value) && !TOY_VALUE_IS_FLOAT(value)) {
|
||||||
|
char buffer[256];
|
||||||
|
snprintf(buffer, 256, "Invalid type '%s' found in 'sqrt()'", Toy_getValueTypeAsCString(Toy_unwrapValue(value).type));
|
||||||
|
Toy_error(buffer);
|
||||||
|
|
||||||
|
Toy_freeValue(value);
|
||||||
|
Toy_pushStack(&vm->stack, TOY_VALUE_FROM_NULL());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
double d = 0;
|
||||||
|
|
||||||
|
if (TOY_VALUE_IS_INTEGER(value)) d = (double)TOY_VALUE_AS_INTEGER(value);
|
||||||
|
else if (TOY_VALUE_IS_FLOAT(value)) d = (double)TOY_VALUE_AS_FLOAT(value);
|
||||||
|
|
||||||
|
//only works on non-negative values
|
||||||
|
if (d < 0) {
|
||||||
|
char buffer[256];
|
||||||
|
snprintf(buffer, 256, "Can't get the sqrt of a negative number (found '%g')", d);
|
||||||
|
Toy_error(buffer);
|
||||||
|
|
||||||
|
Toy_freeValue(value);
|
||||||
|
Toy_pushStack(&vm->stack, TOY_VALUE_FROM_NULL());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//do the thing and push the result
|
||||||
|
d = sqrt(d);
|
||||||
|
|
||||||
|
Toy_pushStack(&vm->stack, TOY_VALUE_FROM_FLOAT((float)d));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void next(Toy_VM* vm, Toy_FunctionNative* self) {
|
static void next(Toy_VM* vm, Toy_FunctionNative* self) {
|
||||||
//used by 'range'
|
//used by 'std_range'
|
||||||
if (self->meta2 < self->meta1) {
|
if (self->meta2 < self->meta1) {
|
||||||
Toy_Value result = TOY_VALUE_FROM_INTEGER(self->meta2);
|
Toy_Value result = TOY_VALUE_FROM_INTEGER(self->meta2);
|
||||||
Toy_pushStack(&vm->stack, result);
|
Toy_pushStack(&vm->stack, result);
|
||||||
@@ -54,7 +190,7 @@ static void next(Toy_VM* vm, Toy_FunctionNative* self) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void range(Toy_VM* vm, Toy_FunctionNative* self) {
|
static void std_range(Toy_VM* vm, Toy_FunctionNative* self) {
|
||||||
(void)self;
|
(void)self;
|
||||||
|
|
||||||
//one arg to represent the number of iterations
|
//one arg to represent the number of iterations
|
||||||
@@ -79,12 +215,13 @@ static void range(Toy_VM* vm, Toy_FunctionNative* self) {
|
|||||||
Toy_pushStack(&vm->stack, result);
|
Toy_pushStack(&vm->stack, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
CallbackPairs callbackPairs[] = {
|
CallbackPairs callbackPairs[] = {
|
||||||
{"dbg_answer", answer},
|
{"min", std_min},
|
||||||
{"dbg_identity", identity},
|
{"max", std_max},
|
||||||
{"dbg_echo", echo},
|
{"floor", std_floor},
|
||||||
{"range", range},
|
{"ceil", std_ceil},
|
||||||
|
{"sqrt", std_sqrt},
|
||||||
|
{"range", std_range},
|
||||||
|
|
||||||
{NULL, NULL},
|
{NULL, NULL},
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,16 +0,0 @@
|
|||||||
//calculate the nth fibonacci number, and print it
|
|
||||||
|
|
||||||
var counter: Int = 0;
|
|
||||||
|
|
||||||
var first: Int = 1;
|
|
||||||
var second: Int = 0;
|
|
||||||
|
|
||||||
while (counter < 100_000) {
|
|
||||||
var third: Int = first + second;
|
|
||||||
first = second;
|
|
||||||
second = third;
|
|
||||||
|
|
||||||
print third;
|
|
||||||
|
|
||||||
++counter;
|
|
||||||
}
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
|
|
||||||
fn output(arg) {
|
|
||||||
print arg;
|
|
||||||
}
|
|
||||||
|
|
||||||
var array = ["alpha", "bravo", "charlie"];
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
array.forEach(echo);
|
|
||||||
array.forEach(output);
|
|
||||||
@@ -1,35 +0,0 @@
|
|||||||
//WARN: This is just a scratch pad, don't use it
|
|
||||||
//TODO: table.hasValue or table.getKeyFromValue?
|
|
||||||
|
|
||||||
|
|
||||||
//for (var i in array) print i;
|
|
||||||
//for (var i in table) print i;
|
|
||||||
//for (var i in range(10)) print i;
|
|
||||||
//for (range(10)) print "ha";
|
|
||||||
|
|
||||||
|
|
||||||
//example of a `range`-like function
|
|
||||||
fn range(limit: Int) {
|
|
||||||
var counter: Int = 0;
|
|
||||||
|
|
||||||
fn next() {
|
|
||||||
if (counter >= limit) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
else return counter++;
|
|
||||||
}
|
|
||||||
|
|
||||||
return next;
|
|
||||||
}
|
|
||||||
|
|
||||||
var next = range(10);
|
|
||||||
|
|
||||||
|
|
||||||
fn log(x) {
|
|
||||||
if (x == null) return;
|
|
||||||
print x;
|
|
||||||
}
|
|
||||||
|
|
||||||
while (true) {
|
|
||||||
log(next());
|
|
||||||
}
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
|
|
||||||
|
|
||||||
var table = [
|
|
||||||
"Alpha": 1,
|
|
||||||
"Bravo": 2,
|
|
||||||
"Charlie": 3,
|
|
||||||
"Delta": 4,
|
|
||||||
"Echo": 5,
|
|
||||||
"Foxtrot": 6,
|
|
||||||
"Golf": 7,
|
|
||||||
"Hotel": 8,
|
|
||||||
"India": 9,
|
|
||||||
"Juliett": 10,
|
|
||||||
"Kilo": 11,
|
|
||||||
"Lima": 12,
|
|
||||||
"Mike": 13,
|
|
||||||
];
|
|
||||||
|
|
||||||
for (var i in table) {
|
|
||||||
print i;
|
|
||||||
}
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
var randi: Int = 69420;
|
|
||||||
fn rand() {
|
|
||||||
return randi = randi * 1664525 + 1013904223;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
var a = rand();
|
|
||||||
|
|
||||||
|
|
||||||
+1
-1
@@ -97,7 +97,7 @@ typedef enum Toy_AstFlag {
|
|||||||
//the root AST type
|
//the root AST type
|
||||||
typedef union Toy_Ast Toy_Ast;
|
typedef union Toy_Ast Toy_Ast;
|
||||||
|
|
||||||
typedef struct Toy_AstBlock {
|
typedef struct Toy_AstBlock { //TODO: optimize away single-line blocks in the AST
|
||||||
Toy_AstType type;
|
Toy_AstType type;
|
||||||
bool innerScope;
|
bool innerScope;
|
||||||
Toy_Ast* child; //begin encoding the line
|
Toy_Ast* child; //begin encoding the line
|
||||||
|
|||||||
@@ -37,6 +37,8 @@ Toy_Value Toy_private_handleStringAttributes(Toy_VM* vm, Toy_Value compound, Toy
|
|||||||
free(buffer);
|
free(buffer);
|
||||||
return TOY_VALUE_FROM_STRING(str);
|
return TOY_VALUE_FROM_STRING(str);
|
||||||
}
|
}
|
||||||
|
//TODO: as capitalized
|
||||||
|
//TODO: split?
|
||||||
else {
|
else {
|
||||||
char buffer[256];
|
char buffer[256];
|
||||||
snprintf(buffer, 256, "Unknown attribute '%s' of type '%s'", TOY_VALUE_AS_STRING(attribute)->leaf.data, Toy_getValueTypeAsCString(compound.type));
|
snprintf(buffer, 256, "Unknown attribute '%s' of type '%s'", TOY_VALUE_AS_STRING(attribute)->leaf.data, Toy_getValueTypeAsCString(compound.type));
|
||||||
|
|||||||
@@ -11,13 +11,11 @@
|
|||||||
// [x] array.length
|
// [x] array.length
|
||||||
// [x] array.pushBack(x)
|
// [x] array.pushBack(x)
|
||||||
// [x] array.popBack()
|
// [x] array.popBack()
|
||||||
// [x] array.forEach(fn) // fn(x) -> void
|
|
||||||
// [ ] array.sort(fn) // fn(a,b) -> int
|
// [ ] array.sort(fn) // fn(a,b) -> int
|
||||||
// [x] table.length
|
// [x] table.length
|
||||||
// [x] table.insert(x, y)
|
// [x] table.insert(x, y)
|
||||||
// [x] table.hasKey(x)
|
// [x] table.hasKey(x)
|
||||||
// [x] table.remove(x)
|
// [x] table.remove(x)
|
||||||
// [ ] table.forEach(fn) // fn(x,y) -> void
|
|
||||||
|
|
||||||
Toy_Value Toy_private_handleStringAttributes(Toy_VM* vm, Toy_Value compound, Toy_Value attribute);
|
Toy_Value Toy_private_handleStringAttributes(Toy_VM* vm, Toy_Value compound, Toy_Value attribute);
|
||||||
Toy_Value Toy_private_handleArrayAttributes(Toy_VM* vm, Toy_Value compound, Toy_Value attribute);
|
Toy_Value Toy_private_handleArrayAttributes(Toy_VM* vm, Toy_Value compound, Toy_Value attribute);
|
||||||
|
|||||||
@@ -56,5 +56,3 @@ TOY_API void Toy_collectBucketGarbage(Toy_Bucket** bucketHandle);
|
|||||||
#ifndef TOY_BUCKET_IDEAL
|
#ifndef TOY_BUCKET_IDEAL
|
||||||
#define TOY_BUCKET_IDEAL (TOY_BUCKET_64KB - sizeof(Toy_Bucket))
|
#define TOY_BUCKET_IDEAL (TOY_BUCKET_64KB - sizeof(Toy_Bucket))
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
//TODO: check for leaks when freeBucket is called, for debugging
|
|
||||||
+14
-2
@@ -632,6 +632,12 @@ static unsigned int writeInstructionIfThenElse(Toy_Bytecode** mb, Toy_AstIfThenE
|
|||||||
//cond-branch
|
//cond-branch
|
||||||
writeBytecodeFromAst(mb, ast.condBranch);
|
writeBytecodeFromAst(mb, ast.condBranch);
|
||||||
|
|
||||||
|
//leave the assigned value on the stack when inside a condition
|
||||||
|
if (checkForChainedAssign(ast.condBranch)) {
|
||||||
|
Toy_AstVarAccess access = { .type = TOY_AST_VAR_ACCESS, .child = ast.condBranch->varAssign.target };
|
||||||
|
writeInstructionAccess(mb, access);
|
||||||
|
}
|
||||||
|
|
||||||
//emit the jump word (opcode, type, condition, padding)
|
//emit the jump word (opcode, type, condition, padding)
|
||||||
EMIT_BYTE(mb, code, TOY_OPCODE_JUMP);
|
EMIT_BYTE(mb, code, TOY_OPCODE_JUMP);
|
||||||
EMIT_BYTE(mb, code, TOY_OP_PARAM_JUMP_RELATIVE);
|
EMIT_BYTE(mb, code, TOY_OP_PARAM_JUMP_RELATIVE);
|
||||||
@@ -677,6 +683,12 @@ static unsigned int writeInstructionWhileThen(Toy_Bytecode** mb, Toy_AstWhileThe
|
|||||||
//cond-branch
|
//cond-branch
|
||||||
writeBytecodeFromAst(mb, ast.condBranch);
|
writeBytecodeFromAst(mb, ast.condBranch);
|
||||||
|
|
||||||
|
//leave the assigned value on the stack when inside a condition
|
||||||
|
if (checkForChainedAssign(ast.condBranch)) {
|
||||||
|
Toy_AstVarAccess access = { .type = TOY_AST_VAR_ACCESS, .child = ast.condBranch->varAssign.target };
|
||||||
|
writeInstructionAccess(mb, access);
|
||||||
|
}
|
||||||
|
|
||||||
//emit the jump word (opcode, type, condition, padding)
|
//emit the jump word (opcode, type, condition, padding)
|
||||||
EMIT_BYTE(mb, code, TOY_OPCODE_JUMP);
|
EMIT_BYTE(mb, code, TOY_OPCODE_JUMP);
|
||||||
EMIT_BYTE(mb, code, TOY_OP_PARAM_JUMP_RELATIVE);
|
EMIT_BYTE(mb, code, TOY_OP_PARAM_JUMP_RELATIVE);
|
||||||
@@ -775,7 +787,7 @@ static unsigned int writeInstructionForThen(Toy_Bytecode** mb, Toy_AstForThen as
|
|||||||
|
|
||||||
emitString(mb, ast.condBranch->iterable.left->varDeclare.name);
|
emitString(mb, ast.condBranch->iterable.left->varDeclare.name);
|
||||||
|
|
||||||
//TODO: use a different approach
|
//TODO: use a different approach?
|
||||||
//BUGFIX: shadow the iterable's name
|
//BUGFIX: shadow the iterable's name
|
||||||
EMIT_BYTE(mb, code, TOY_OPCODE_READ);
|
EMIT_BYTE(mb, code, TOY_OPCODE_READ);
|
||||||
EMIT_BYTE(mb, code, TOY_VALUE_NULL);
|
EMIT_BYTE(mb, code, TOY_VALUE_NULL);
|
||||||
@@ -1452,7 +1464,7 @@ static void writeBytecodeBody(Toy_Bytecode* mb, Toy_Ast* ast) {
|
|||||||
writeBytecodeFromAst(&mb, ast);
|
writeBytecodeFromAst(&mb, ast);
|
||||||
|
|
||||||
//append an extra return if needed
|
//append an extra return if needed
|
||||||
if (mb->codeCount <= 4 || mb->code[mb->codeCount - 4] != TOY_OPCODE_RETURN) { //if empty or no return statement
|
if (mb->codeCount < 4 || mb->code[mb->codeCount - 4] != TOY_OPCODE_RETURN) { //if empty or no return statement
|
||||||
EMIT_BYTE(&mb, code, TOY_OPCODE_RETURN); //end terminator
|
EMIT_BYTE(&mb, code, TOY_OPCODE_RETURN); //end terminator
|
||||||
EMIT_BYTE(&mb, code, 0); //4-byte alignment
|
EMIT_BYTE(&mb, code, 0); //4-byte alignment
|
||||||
EMIT_BYTE(&mb, code, 0);
|
EMIT_BYTE(&mb, code, 0);
|
||||||
|
|||||||
+1
-1
@@ -198,7 +198,7 @@ static ParsingTuple parsingRulesetTable[] = {
|
|||||||
//structural operators
|
//structural operators
|
||||||
{PREC_CALL,group,invoke},// TOY_TOKEN_OPERATOR_PAREN_LEFT,
|
{PREC_CALL,group,invoke},// TOY_TOKEN_OPERATOR_PAREN_LEFT,
|
||||||
{PREC_NONE,NULL,NULL},// TOY_TOKEN_OPERATOR_PAREN_RIGHT,
|
{PREC_NONE,NULL,NULL},// TOY_TOKEN_OPERATOR_PAREN_RIGHT,
|
||||||
{PREC_GROUP,compound,aggregate},// TOY_TOKEN_OPERATOR_BRACKET_LEFT,
|
{PREC_CALL,compound,aggregate},// TOY_TOKEN_OPERATOR_BRACKET_LEFT,
|
||||||
{PREC_NONE,compound,aggregate},// TOY_TOKEN_OPERATOR_BRACKET_RIGHT,
|
{PREC_NONE,compound,aggregate},// TOY_TOKEN_OPERATOR_BRACKET_RIGHT,
|
||||||
{PREC_NONE,NULL,NULL},// TOY_TOKEN_OPERATOR_BRACE_LEFT,
|
{PREC_NONE,NULL,NULL},// TOY_TOKEN_OPERATOR_BRACE_LEFT,
|
||||||
{PREC_NONE,NULL,NULL},// TOY_TOKEN_OPERATOR_BRACE_RIGHT,
|
{PREC_NONE,NULL,NULL},// TOY_TOKEN_OPERATOR_BRACE_RIGHT,
|
||||||
|
|||||||
+3
-17
@@ -464,29 +464,15 @@ Toy_String* Toy_stringifyValue(Toy_Bucket** bucketHandle, Toy_Value value) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
case TOY_VALUE_INTEGER: {
|
case TOY_VALUE_INTEGER: {
|
||||||
char buffer[16];
|
char buffer[128];
|
||||||
sprintf(buffer, "%d", value.as.integer);
|
sprintf(buffer, "%d", value.as.integer);
|
||||||
return Toy_createStringLength(bucketHandle, buffer, strlen(buffer));
|
return Toy_createStringLength(bucketHandle, buffer, strlen(buffer));
|
||||||
}
|
}
|
||||||
|
|
||||||
case TOY_VALUE_FLOAT: {
|
case TOY_VALUE_FLOAT: {
|
||||||
//using printf
|
char buffer[128];
|
||||||
char buffer[16];
|
sprintf(buffer, "%g", value.as.number);
|
||||||
sprintf(buffer, "%f", value.as.number);
|
|
||||||
|
|
||||||
//BUGFIX: printf format specificer '%f' will set the precision to 6 decimal places, which means there's trailing zeroes
|
|
||||||
unsigned int length = strlen(buffer);
|
unsigned int length = strlen(buffer);
|
||||||
|
|
||||||
//find the decimal, if it exists
|
|
||||||
unsigned int decimal = 0;
|
|
||||||
while (decimal != length && buffer[decimal] != '.' && buffer[decimal] != ',') decimal++; //'.' and ',' supports more locales
|
|
||||||
|
|
||||||
//locales are hard, sorry!
|
|
||||||
if (decimal != length && buffer[decimal] == ',') buffer[decimal] = '.';
|
|
||||||
|
|
||||||
//wipe the trailing zeros
|
|
||||||
while(decimal != length && buffer[length-1] == '0') buffer[--length] = '\0';
|
|
||||||
|
|
||||||
return Toy_createStringLength(bucketHandle, buffer, length);
|
return Toy_createStringLength(bucketHandle, buffer, length);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+4
-2
@@ -546,7 +546,7 @@ static void processIterate(Toy_VM* vm) {
|
|||||||
processJump(vm);
|
processJump(vm);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//TODO: support closures as a parameter
|
//TODO: support closures in for-loops
|
||||||
else {
|
else {
|
||||||
fprintf(stderr, TOY_CC_ERROR "ERROR: Unknown iterable type '%s' found in for loop, exiting\n" TOY_CC_RESET, Toy_getValueTypeAsCString(Toy_unwrapValue(compound).type));
|
fprintf(stderr, TOY_CC_ERROR "ERROR: Unknown iterable type '%s' found in for loop, exiting\n" TOY_CC_RESET, Toy_getValueTypeAsCString(Toy_unwrapValue(compound).type));
|
||||||
exit(-1);
|
exit(-1);
|
||||||
@@ -826,7 +826,7 @@ static void processAssert(Toy_VM* vm) {
|
|||||||
|
|
||||||
//determine the args
|
//determine the args
|
||||||
if (count == 1) {
|
if (count == 1) {
|
||||||
message = TOY_VALUE_FROM_STRING(Toy_toString(&vm->memoryBucket, "assertion failed")); //TODO: better default error message
|
message = TOY_VALUE_FROM_STRING(Toy_toString(&vm->memoryBucket, "assertion failed")); //TODO: better default assert message
|
||||||
value = Toy_popStack(&vm->stack);
|
value = Toy_popStack(&vm->stack);
|
||||||
}
|
}
|
||||||
else if (count == 2) {
|
else if (count == 2) {
|
||||||
@@ -895,6 +895,8 @@ static void processConcat(Toy_VM* vm) {
|
|||||||
static void processIndex(Toy_VM* vm) {
|
static void processIndex(Toy_VM* vm) {
|
||||||
unsigned char count = READ_BYTE(vm); //value[index, length] ; 1[2, 3]
|
unsigned char count = READ_BYTE(vm); //value[index, length] ; 1[2, 3]
|
||||||
|
|
||||||
|
//TODO: slicing from the end of a string/array, value[0:-1]
|
||||||
|
|
||||||
Toy_Value value = TOY_VALUE_FROM_NULL();
|
Toy_Value value = TOY_VALUE_FROM_NULL();
|
||||||
Toy_Value index = TOY_VALUE_FROM_NULL();
|
Toy_Value index = TOY_VALUE_FROM_NULL();
|
||||||
Toy_Value length = TOY_VALUE_FROM_NULL();
|
Toy_Value length = TOY_VALUE_FROM_NULL();
|
||||||
|
|||||||
@@ -7,5 +7,3 @@ all:
|
|||||||
gdb:
|
gdb:
|
||||||
$(MAKE) -C units -k gdb
|
$(MAKE) -C units -k gdb
|
||||||
$(MAKE) -C scripts -k gdb
|
$(MAKE) -C scripts -k gdb
|
||||||
|
|
||||||
#TODO: valgrind
|
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
//WARN: not yet implemented
|
||||||
@@ -163,5 +163,3 @@ print !false; //true
|
|||||||
var i = 42;
|
var i = 42;
|
||||||
print a;
|
print a;
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO: type casting
|
|
||||||
@@ -0,0 +1,90 @@
|
|||||||
|
//NOTE: Not tested: null (neither true or false), Opaque, Any
|
||||||
|
{
|
||||||
|
//booleans
|
||||||
|
var value: Bool = true;
|
||||||
|
if (value) print "boolean";
|
||||||
|
else assert false, "boolean";
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
var value: Bool = false;
|
||||||
|
if (value) assert false, "boolean";
|
||||||
|
else print "boolean";
|
||||||
|
}
|
||||||
|
|
||||||
|
//integers
|
||||||
|
{
|
||||||
|
var value: Int = 42;
|
||||||
|
if (value) print "integer";
|
||||||
|
else assert false, "integer";
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
var value: Int = 0;
|
||||||
|
if (value) assert false, "integer";
|
||||||
|
else print "integer";
|
||||||
|
}
|
||||||
|
|
||||||
|
//floats
|
||||||
|
{
|
||||||
|
var value: Float = 42.8891;
|
||||||
|
if (value) print "float";
|
||||||
|
else assert false, "float";
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
var value: Float = 0;
|
||||||
|
if (value) assert false, "float";
|
||||||
|
else print "float";
|
||||||
|
}
|
||||||
|
|
||||||
|
//strings
|
||||||
|
{
|
||||||
|
var value: String = "foobar";
|
||||||
|
if (value) print "string";
|
||||||
|
else assert false, "string";
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
var value: String = ""; //empty string is truthy
|
||||||
|
if (value) print "string";
|
||||||
|
else assert false, "string";
|
||||||
|
}
|
||||||
|
|
||||||
|
//arrays
|
||||||
|
{
|
||||||
|
var value: Array = [1,2,3];
|
||||||
|
if (value) print "array";
|
||||||
|
else assert false, "array";
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
var value: Array = []; //empty array is truthy
|
||||||
|
if (value) print "array";
|
||||||
|
else assert false, "array";
|
||||||
|
}
|
||||||
|
|
||||||
|
//table
|
||||||
|
{
|
||||||
|
var value: Table = ["alpha":"bravo"];
|
||||||
|
if (value) print "table";
|
||||||
|
else assert false, "table";
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
var value: Table = [:]; //empty table is truthy
|
||||||
|
if (value) print "table";
|
||||||
|
else assert false, "table";
|
||||||
|
}
|
||||||
|
|
||||||
|
//function
|
||||||
|
{
|
||||||
|
fn identity(x) {
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (identity) print "function";
|
||||||
|
else assert false, "function";
|
||||||
|
}
|
||||||
|
|
||||||
|
//TODO: test library as API, would be cleaner than using asserts
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
//typenames are now capitalized, so ensure they don't overlap with variable names
|
//NOTE: typenames are now capitalized, to ensure they don't overlap with variable names
|
||||||
|
|
||||||
var bool: Bool = true;
|
var bool: Bool = true;
|
||||||
print bool;
|
print bool;
|
||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
//TODO: empty test script
|
//WARN: empty test script
|
||||||
|
|
||||||
//TODO: test iteration on arrays, tables, closures
|
//TODO: test iteration on arrays, tables, closures
|
||||||
|
|
||||||
+1
-1
@@ -17,5 +17,5 @@ print "\tHello\nworld!";
|
|||||||
print "Hello world"[0,5];
|
print "Hello world"[0,5];
|
||||||
|
|
||||||
//print from a substring, after a concat
|
//print from a substring, after a concat
|
||||||
print ("hello" .. "world")[2,6];
|
print ("hello" .. "world")[3,3]; //should print "low"
|
||||||
|
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
|
||||||
|
fn empty() {
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
||||||
|
fn almostEmpty() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn notEmpty() {
|
||||||
|
return 42;
|
||||||
|
}
|
||||||
@@ -20,10 +20,10 @@ endif
|
|||||||
TEST_ROOTDIR=../..
|
TEST_ROOTDIR=../..
|
||||||
TEST_SOURCEDIR=$(TEST_ROOTDIR)/$(TOY_SOURCEDIR)
|
TEST_SOURCEDIR=$(TEST_ROOTDIR)/$(TOY_SOURCEDIR)
|
||||||
TEST_REPLDIR=$(TEST_ROOTDIR)/$(TOY_REPLDIR)
|
TEST_REPLDIR=$(TEST_ROOTDIR)/$(TOY_REPLDIR)
|
||||||
TEST_SCRIPTDIR=.
|
TEST_SCRIPTDIRS=basics values keywords algorithms
|
||||||
|
|
||||||
#file names
|
#file names
|
||||||
TEST_SCRIPTFILES=$(wildcard $(TEST_SCRIPTDIR)/test_*.toy)
|
TEST_SCRIPTFILES=$(foreach dir,$(TEST_SCRIPTDIRS), $(wildcard $(dir)/test_*.toy))
|
||||||
|
|
||||||
#build the source and repl, copy to the local dir, and run
|
#build the source and repl, copy to the local dir, and run
|
||||||
all: source repl copy run
|
all: source repl copy run
|
||||||
|
|||||||
@@ -1,26 +0,0 @@
|
|||||||
//1-D array
|
|
||||||
var arr = [1, 2, 3];
|
|
||||||
arr[1] = 6;
|
|
||||||
|
|
||||||
assert arr == [1, 6, 3], "1-D array failed";
|
|
||||||
|
|
||||||
//we need to go deeper
|
|
||||||
var barr = [
|
|
||||||
[1, 2, 3],
|
|
||||||
[4, 5, 6],
|
|
||||||
[7, 8, 9]
|
|
||||||
];
|
|
||||||
|
|
||||||
barr[1][1] = 99;
|
|
||||||
|
|
||||||
assert barr == [[1, 2, 3],[4,99,6],[7,8,9]], "2-D array failed";
|
|
||||||
|
|
||||||
//test trailing commas
|
|
||||||
var a = [1, 2, 3, ];
|
|
||||||
|
|
||||||
print a;
|
|
||||||
|
|
||||||
//test empty arrays
|
|
||||||
var b = [];
|
|
||||||
|
|
||||||
print b;
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
//TODO: empty test script
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
//closures
|
|
||||||
fn makeCounter() {
|
|
||||||
var counter: Int = 0;
|
|
||||||
|
|
||||||
fn increment() {
|
|
||||||
return ++counter;
|
|
||||||
}
|
|
||||||
|
|
||||||
return increment;
|
|
||||||
}
|
|
||||||
|
|
||||||
var tally = makeCounter();
|
|
||||||
|
|
||||||
while (true) {
|
|
||||||
var result = tally();
|
|
||||||
|
|
||||||
print result;
|
|
||||||
|
|
||||||
if (result >= 10) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
//check functions are first class citizens
|
|
||||||
fn hello() {
|
|
||||||
print "Hello world";
|
|
||||||
}
|
|
||||||
|
|
||||||
fn ident(x) {
|
|
||||||
return x;
|
|
||||||
}
|
|
||||||
|
|
||||||
assert ident(hello) == hello, "First class function check failed";
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
|
|
||||||
|
|
||||||
fn a(x) {
|
|
||||||
assert x == 42;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn b() {
|
|
||||||
return 42;
|
|
||||||
}
|
|
||||||
|
|
||||||
a(b());
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
//TODO: empty test script
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
|
|
||||||
fn empty() { //BUG: there's an extra return in the bytecode
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn full() {
|
|
||||||
return 42;
|
|
||||||
}
|
|
||||||
@@ -1,33 +0,0 @@
|
|||||||
//1-D table
|
|
||||||
var a = ["alpha": 1, "beta": 2, "gamma": 3];
|
|
||||||
a["beta"] = 6;
|
|
||||||
|
|
||||||
print a;
|
|
||||||
assert a == ["alpha": 1, "beta": 6, "gamma": 3], "1-D tables failed";
|
|
||||||
|
|
||||||
//nested
|
|
||||||
var b = [
|
|
||||||
"outer": ["inner": true],
|
|
||||||
"alpha": 1,
|
|
||||||
"beta": 2,
|
|
||||||
"gamma": 3
|
|
||||||
];
|
|
||||||
|
|
||||||
print b;
|
|
||||||
assert b == ["alpha": 1, "beta": 2, "gamma": 3, "outer": ["inner": true]], "nested tables failed";
|
|
||||||
|
|
||||||
//test empty tables
|
|
||||||
var empty = [:];
|
|
||||||
|
|
||||||
print empty;
|
|
||||||
assert empty == [:], "empty tables failed";
|
|
||||||
|
|
||||||
//test trailing commas
|
|
||||||
var trailing = [
|
|
||||||
"alpha":1,
|
|
||||||
"beta":2,
|
|
||||||
"gamma":3,
|
|
||||||
];
|
|
||||||
|
|
||||||
print trailing;
|
|
||||||
assert trailing == ["alpha": 1, "beta": 2, "gamma": 3], "trailing tables failed";
|
|
||||||
@@ -1,80 +0,0 @@
|
|||||||
//booleans
|
|
||||||
{
|
|
||||||
var value: Bool = true;
|
|
||||||
|
|
||||||
if (value) {
|
|
||||||
print "boolean";
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
assert false, "boolean";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
var value: Bool = false;
|
|
||||||
|
|
||||||
if (value) {
|
|
||||||
assert false, "boolean";
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
print "boolean";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//integers
|
|
||||||
{
|
|
||||||
var value: Int = 42;
|
|
||||||
|
|
||||||
if (value) {
|
|
||||||
print "integer";
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
assert false, "integer";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
var value: Int = 0;
|
|
||||||
|
|
||||||
if (value) {
|
|
||||||
assert false, "integer";
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
print "integer";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//floats
|
|
||||||
{
|
|
||||||
var value: Float = 42.8891;
|
|
||||||
|
|
||||||
if (value) {
|
|
||||||
print "float";
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
assert false, "float";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
var value: Float = 0;
|
|
||||||
|
|
||||||
if (value) {
|
|
||||||
assert false, "float";
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
print "float";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//everything else
|
|
||||||
{
|
|
||||||
var value: String = "foobar";
|
|
||||||
|
|
||||||
if (value) {
|
|
||||||
print "string";
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
assert false, "string";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
//1-D array
|
||||||
|
{
|
||||||
|
var array: Array = [1, 2, 3];
|
||||||
|
array[1] = 6;
|
||||||
|
assert array == [1, 6, 3], "1-D array failed";
|
||||||
|
}
|
||||||
|
|
||||||
|
//we need to go deeper
|
||||||
|
{
|
||||||
|
var array = [
|
||||||
|
[1, 2, 3],
|
||||||
|
[4, 5, 6],
|
||||||
|
[7, 8, 9]
|
||||||
|
];
|
||||||
|
|
||||||
|
array[1][1] = 99;
|
||||||
|
|
||||||
|
assert array == [[1, 2, 3],[4,99,6],[7,8,9]], "2-D array failed";
|
||||||
|
}
|
||||||
|
|
||||||
|
//attributes
|
||||||
|
{
|
||||||
|
var array = [0,1,2,3,4,5,6,7,8,9];
|
||||||
|
assert array.length == 10, "Array length attribute failed";
|
||||||
|
|
||||||
|
array.pushBack(10);
|
||||||
|
assert array.length == 11, "Array pushBack attribute failed";
|
||||||
|
|
||||||
|
array.popBack();
|
||||||
|
array.popBack();
|
||||||
|
assert array.popBack() == 8, "Array popBack attribute failed";
|
||||||
|
}
|
||||||
|
|
||||||
|
//sorting algorithm
|
||||||
|
{
|
||||||
|
//WARN: Array sorting algorithm not yet implemented
|
||||||
|
}
|
||||||
|
|
||||||
|
//syntax
|
||||||
|
{
|
||||||
|
var empty = [];
|
||||||
|
assert empty.length == 0, "Empty array failed";
|
||||||
|
|
||||||
|
var trailing = [1, 2, 3, ];
|
||||||
|
assert trailing == [1,2,3], "Trailing comma array failed";
|
||||||
|
}
|
||||||
@@ -0,0 +1,55 @@
|
|||||||
|
//define and invoke a function
|
||||||
|
{
|
||||||
|
|
||||||
|
fn greeting() {
|
||||||
|
return "Hello world";
|
||||||
|
}
|
||||||
|
|
||||||
|
assert greeting() == "Hello world", "Function definition failed";
|
||||||
|
}
|
||||||
|
|
||||||
|
//functions within other function argument lists
|
||||||
|
{
|
||||||
|
fn outer(arg: String) {
|
||||||
|
return arg == "Hello world";
|
||||||
|
}
|
||||||
|
|
||||||
|
fn inner() {
|
||||||
|
return "Hello world";
|
||||||
|
}
|
||||||
|
|
||||||
|
assert outer(inner()), "Functions within argument lists failed";
|
||||||
|
}
|
||||||
|
|
||||||
|
//first class functions
|
||||||
|
{
|
||||||
|
fn hello() {
|
||||||
|
print "Hello world";
|
||||||
|
}
|
||||||
|
|
||||||
|
fn identity(x) {
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert identity(hello) == hello, "First class functions failed";
|
||||||
|
}
|
||||||
|
|
||||||
|
//closures
|
||||||
|
{
|
||||||
|
//closures
|
||||||
|
fn makeCounter() {
|
||||||
|
var counter: Int = 0;
|
||||||
|
fn increment() {
|
||||||
|
return ++counter;
|
||||||
|
}
|
||||||
|
return increment;
|
||||||
|
}
|
||||||
|
|
||||||
|
var tally: Function = makeCounter();
|
||||||
|
|
||||||
|
tally();
|
||||||
|
tally();
|
||||||
|
tally();
|
||||||
|
|
||||||
|
assert tally() == 4, "closures failed";
|
||||||
|
}
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
//declare, define and manipulate strings
|
||||||
|
{
|
||||||
|
var string: String = "Hello World";
|
||||||
|
assert string[5] == " ", "String indexing failed";
|
||||||
|
|
||||||
|
var greeting: String = string[0:5];
|
||||||
|
assert greeting == "Hello", "String slicing failed";
|
||||||
|
|
||||||
|
var parting: String = "Goodbye " .. string[6:5];
|
||||||
|
print parting;
|
||||||
|
assert parting == "Goodbye World", "String concat from an index failed";
|
||||||
|
|
||||||
|
//WARN: Unbounded slice not possible without indexing from the end of a string
|
||||||
|
//var simple: String = parting[5:-1];
|
||||||
|
//assert simple == "bye World", "String unbounded slice failed";
|
||||||
|
}
|
||||||
|
|
||||||
|
//var greeting: String = "Hello World";
|
||||||
|
//var parting: String = "Goodbye " .. greeting[6:5];
|
||||||
|
|
||||||
|
//String attributes
|
||||||
|
{
|
||||||
|
var string: String = "Hello World";
|
||||||
|
assert string.length == 11, "string.length failed";
|
||||||
|
assert string.asUpper == "HELLO WORLD", "string.asUpper failed";
|
||||||
|
assert string.asLower == "hello world", "string.asLower failed";
|
||||||
|
}
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
//1-D table
|
||||||
|
{
|
||||||
|
var table: Table = ["alpha": 1, "beta": 2, "gamma": 3];
|
||||||
|
table["beta"] = 6;
|
||||||
|
assert table == ["alpha": 1, "beta": 6, "gamma": 3], "1-D tables failed";
|
||||||
|
}
|
||||||
|
|
||||||
|
//nested
|
||||||
|
{
|
||||||
|
var table: Table = [
|
||||||
|
"outer": ["inner": true],
|
||||||
|
"alpha": 1,
|
||||||
|
"beta": 2,
|
||||||
|
"gamma": 3
|
||||||
|
];
|
||||||
|
|
||||||
|
assert table == ["alpha": 1, "beta": 2, "gamma": 3, "outer": ["inner": true]], "nested tables failed";
|
||||||
|
}
|
||||||
|
|
||||||
|
//syntax
|
||||||
|
{
|
||||||
|
var empty = [:];
|
||||||
|
assert empty.length == 0, "Empty table failed";
|
||||||
|
|
||||||
|
var trailing = [
|
||||||
|
"alpha":1,
|
||||||
|
"beta":2,
|
||||||
|
"gamma":3,
|
||||||
|
];
|
||||||
|
|
||||||
|
assert trailing == ["alpha": 1, "beta": 2, "gamma": 3], "Trailing comma table failed";
|
||||||
|
}
|
||||||
|
|
||||||
@@ -4,7 +4,7 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
int main(void) {
|
int main(void) {
|
||||||
//TODO: Test not yet implemented
|
//WARN: Test not yet implemented
|
||||||
printf(TOY_CC_WARN "Test not yet implemented: %s\n" TOY_CC_RESET, __FILE__);
|
printf(TOY_CC_WARN "Test not yet implemented: %s\n" TOY_CC_RESET, __FILE__);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -117,7 +117,7 @@ int test_functions_from_bytecodes(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int test_functions_from_callbacks(void) {
|
int test_functions_from_callbacks(void) {
|
||||||
//TODO: Test not yet implemented
|
//WARN: Test not yet implemented
|
||||||
printf(TOY_CC_WARN "WIP test not yet implemented: %s\n" TOY_CC_RESET, __FILE__);
|
printf(TOY_CC_WARN "WIP test not yet implemented: %s\n" TOY_CC_RESET, __FILE__);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -607,9 +607,8 @@ int main(void) {
|
|||||||
total += res;
|
total += res;
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO: references
|
//WARN: Testing references not implemented
|
||||||
//TODO: type coersions
|
//WARN: Testing opaques not implemented
|
||||||
//TODO: opaques?
|
|
||||||
|
|
||||||
return total;
|
return total;
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user