Compare commits

..

3 Commits

Author SHA1 Message Date
Kayne Ruse 4e31c0c551 Tweaked docs README 2026-05-31 20:05:46 +10:00
Kayne Ruse a00739f580 Moved 'debugStackPrint' to 'stack_inspector.c' 2026-05-30 20:32:22 +10:00
Kayne Ruse d194bff5fe Revised tests 2026-05-30 10:53:21 +10:00
40 changed files with 315 additions and 229 deletions
+1 -1
View File
@@ -43,7 +43,7 @@ while (result = tally()) {
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">
<image src="img/noai.png" alt="No AI" width="200px" />
+4 -29
View File
@@ -1,6 +1,7 @@
#include "bucket_inspector.h"
#include "ast_inspector.h"
#include "bytecode_inspector.h"
#include "bucket_inspector.h"
#include "stack_inspector.h"
#include "toy_console_colors.h"
@@ -246,32 +247,6 @@ CmdLine parseCmdLine(int argc, const char* argv[]) {
}
//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) {
//DEBUG: if there's anything in the scope, print it
if (scope->count > 0) {
@@ -391,7 +366,7 @@ int repl(const char* filepath, bool verbose) {
//print the debug info
if (verbose) {
debugStackPrint(vm.stack);
inspect_stack(vm.stack);
debugScopePrint(vm.scope, 0);
depthBeforeGC = inspect_bucket(&vm.memoryBucket);
@@ -515,7 +490,7 @@ int main(int argc, const char* argv[]) {
//print the debug info
if (cmd.verbose) {
debugStackPrint(vm.stack);
inspect_stack(vm.stack);
debugScopePrint(vm.scope, 0);
}
+39
View File
@@ -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);
}
+5
View File
@@ -0,0 +1,5 @@
#pragma once
#include "toy_stack.h"
void inspect_stack(Toy_Stack* stack);
+2
View File
@@ -37,6 +37,8 @@ Toy_Value Toy_private_handleStringAttributes(Toy_VM* vm, Toy_Value compound, Toy
free(buffer);
return TOY_VALUE_FROM_STRING(str);
}
//TODO: as capitalized
//TODO: split?
else {
char buffer[256];
snprintf(buffer, 256, "Unknown attribute '%s' of type '%s'", TOY_VALUE_AS_STRING(attribute)->leaf.data, Toy_getValueTypeAsCString(compound.type));
-2
View File
@@ -11,13 +11,11 @@
// [x] array.length
// [x] array.pushBack(x)
// [x] array.popBack()
// [x] array.forEach(fn) // fn(x) -> void
// [ ] array.sort(fn) // fn(a,b) -> int
// [x] table.length
// [x] table.insert(x, y)
// [x] table.hasKey(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_handleArrayAttributes(Toy_VM* vm, Toy_Value compound, Toy_Value attribute);
+1 -1
View File
@@ -198,7 +198,7 @@ static ParsingTuple parsingRulesetTable[] = {
//structural operators
{PREC_CALL,group,invoke},// TOY_TOKEN_OPERATOR_PAREN_LEFT,
{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,NULL,NULL},// TOY_TOKEN_OPERATOR_BRACE_LEFT,
{PREC_NONE,NULL,NULL},// TOY_TOKEN_OPERATOR_BRACE_RIGHT,
+2
View File
@@ -895,6 +895,8 @@ static void processConcat(Toy_VM* vm) {
static void processIndex(Toy_VM* vm) {
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 index = TOY_VALUE_FROM_NULL();
Toy_Value length = TOY_VALUE_FROM_NULL();
@@ -0,0 +1 @@
//WARN: not yet implemented
@@ -163,5 +163,3 @@ print !false; //true
var i = 42;
print a;
}
//TODO: type casting
+90
View File
@@ -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;
print bool;
@@ -1,4 +1,4 @@
//URGENT: empty test script
//WARN: empty test script
//TODO: test iteration on arrays, tables, closures
@@ -17,5 +17,5 @@ print "\tHello\nworld!";
print "Hello world"[0,5];
//print from a substring, after a concat
print ("hello" .. "world")[2,6];
print ("hello" .. "world")[3,3]; //should print "low"
+2 -2
View File
@@ -20,10 +20,10 @@ endif
TEST_ROOTDIR=../..
TEST_SOURCEDIR=$(TEST_ROOTDIR)/$(TOY_SOURCEDIR)
TEST_REPLDIR=$(TEST_ROOTDIR)/$(TOY_REPLDIR)
TEST_SCRIPTDIR=.
TEST_SCRIPTDIRS=basics values keywords algorithms
#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
all: source repl copy run
-26
View File
@@ -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
View File
@@ -1 +0,0 @@
//URGENT: empty test script
-22
View File
@@ -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
View File
@@ -1 +0,0 @@
//URGENT: empty test script
-33
View File
@@ -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";
-80
View File
@@ -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";
}
}
+46
View File
@@ -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";
}
+55
View File
@@ -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";
}
+27
View File
@@ -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";
}
+33
View File
@@ -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";
}
+1 -1
View File
@@ -4,7 +4,7 @@
#include <string.h>
int main(void) {
//URGENT: Test not yet implemented
//WARN: Test not yet implemented
printf(TOY_CC_WARN "Test not yet implemented: %s\n" TOY_CC_RESET, __FILE__);
return 0;
}
+1 -1
View File
@@ -117,7 +117,7 @@ int test_functions_from_bytecodes(void) {
}
int test_functions_from_callbacks(void) {
//URGENT: Test not yet implemented
//WARN: Test not yet implemented
printf(TOY_CC_WARN "WIP test not yet implemented: %s\n" TOY_CC_RESET, __FILE__);
return 0;
}
+2 -3
View File
@@ -607,9 +607,8 @@ int main(void) {
total += res;
}
//TODO: references?
//TODO: type coersions?
//TODO: opaques?
//WARN: Testing references not implemented
//WARN: Testing opaques not implemented
return total;
}