Script tests re-added, all tests can run under gdb

Also fixed a minor bug with printing, and removed the ability to
configure the parser.

Added and updated QUICKSTART.md as a quick way to get people started.

There's some broken scripts under 'scripts/' that require functions to
work properly.
This commit is contained in:
2026-04-10 15:28:56 +10:00
parent 211744535e
commit 547229e150
26 changed files with 916 additions and 48 deletions

View File

@@ -1,9 +1,11 @@
#bridge file
export CFLAGS+=-DTOY_CC_ENABLED
all:
$(MAKE) -C units -k
$(MAKE) -C scripts -k
gdb:
$(MAKE) -C units -k gdb
$(MAKE) -C scripts -k gdb
#TODO: valgrind

2
tests/scripts/gdb_init Normal file
View File

@@ -0,0 +1,2 @@
set breakpoint pending on

52
tests/scripts/makefile Normal file
View File

@@ -0,0 +1,52 @@
#compiler settings
CC=gcc
CFLAGS+=-std=c17 -g -Wall -Werror -Wextra -Wpedantic -Wformat=2 -Wno-newline-eof
LIBS+=-lm
LDFLAGS+=
ifeq ($(shell uname),Linux)
LDFLAGS=-Wl,--gc-sections
else ifeq ($(shell uname),NetBSD)
LDFLAGS=-Wl,--gc-sections
else ifeq ($(OS),Windows_NT)
LDFLAGS=-Wl,--gc-sections
else ifeq ($(shell uname),Darwin)
LDFLAGS=-Wl,-dead_strip
else
@echo "LDFLAGS set failed - what platform is this?"
endif
#directories
TEST_ROOTDIR=../..
TEST_SOURCEDIR=$(TEST_ROOTDIR)/$(TOY_SOURCEDIR)
TEST_REPLDIR=$(TEST_ROOTDIR)/$(TOY_REPLDIR)
TEST_SCRIPTDIR=.
#file names
TEST_SCRIPTFILES=$(wildcard $(TEST_SCRIPTDIR)/test_*.toy)
#build the source and repl, copy to the local dir, and run
all: source repl copy run
#compile the source and repl first
source:
$(MAKE) -C $(TEST_SOURCEDIR)
repl: source
$(MAKE) -C $(TEST_REPLDIR)
copy:
cp -r $(TEST_ROOTDIR)/$(TOY_OUTDIR) .
run: $(TEST_SCRIPTFILES:.toy=.toy-run)
%.toy-run: %.toy
find -name repl* -type f -exec {} -f ../$< --verbose \;
#using gdb
gdb: source repl copy run-gdb
run-gdb: $(TEST_SCRIPTFILES:.toy=.toy-run-gdb)
%.toy-run-gdb: %.toy
gdb $(TEST_OUTDIR)/$(TEST_REPLNAME) -ix gdb_init -ex=run --batch --return-child-result --args "out/repl.out" "-f" "../$<" "--verbose"

View File

@@ -0,0 +1,26 @@
//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;

View File

@@ -0,0 +1,9 @@
//these are allowed
/* EMPTY */;
if (true) { }
if (true) pass;
//these are not allowed
// if (true) /* EMPTY */;

View File

@@ -0,0 +1,13 @@
//NOTE: these tests are all passing - failing tests can be found under the 'mustfails' directory
//basic assert statement
assert true;
//assert on a string (tests for it's truthiness)
assert "Hello world";
//assert on a condition
assert 1 < 2;
//assert with an optional message
assert true, "Assertion message";

View File

@@ -0,0 +1,65 @@
//literals
if (true) {
print "Success 1";
}
else {
print "Failure 1";
}
//false literals
if (false) {
print "Failure 2";
}
else {
print "Success 2";
}
//conditionals
if (1 < 2) {
print "Success 3";
}
if (1 > 2) {
print "Failure 3";
}
//variables
var a = 42;
if (a) {
print "Success 4";
}
else {
print "Failure 4";
}
if (a == 42) {
print "Success 5";
}
else {
print "Failure 5";
}
//concatenated strings
if ("foo" .. "bar" == "foobar") {
print "Success 6";
}
else {
print "Failure 6";
}
if ("foobar" == "foo" .. "bar") {
print "Success 7";
}
else {
print "Failure 7";
}
if ("fizz" .. "le" == "fi" .. "zzle") {
print "Success 8";
}
else {
print "Failure 8";
}

View File

@@ -0,0 +1,46 @@
//literals
if (true)
print "Success 1";
else
print "Failure 1";
//false literals
if (false)
print "Failure 2";
else
print "Success 2";
//conditionals
if (1 < 2)
print "Success 3";
if (1 > 2)
print "Failure 3";
//variables
var a = 42;
if (a)
print "Success 4";
else
print "Failure 4";
if (a == 42)
print "Success 5";
else
print "Failure 5";
//concatenated strings
if ("foo" .. "bar" == "foobar")
print "Success 6";
else
print "Failure 6";
if ("foobar" == "foo" .. "bar")
print "Success 7";
else
print "Failure 7";
if ("fizz" .. "le" == "fi" .. "zzle")
print "Success 8";
else
print "Failure 8";

View File

@@ -0,0 +1,21 @@
//basic print statement
print 42;
//print compount expressions
print 3 * 5;
//print a string
print "Hello world!";
//print a concatenated string
print "Hello" .. "world!";
//print with escaped characters
print "\tHello\nworld!";
//print from a substring string
print "Hello world"[0,5];
//print from a substring, after a concat
print ("hello" .. "world")[2,6];

View File

@@ -0,0 +1,132 @@
//make sure it works with multiple repititions
//-------------------------
//test break
while (true) {
break;
assert false, "break failed";
}
//test continue
var flag1: bool = true;
while (flag1) {
flag1 = false;
continue;
assert false, "continue failed";
}
//-------------------------
//test break
while (true) {
break;
assert false, "break failed";
}
//test continue
var flag2: bool = true;
while (flag2) {
flag2 = false;
continue;
assert false, "continue failed";
}
//-------------------------
//test break
while (true) {
break;
assert false, "break failed";
}
//test continue
var flag3: bool = true;
while (flag3) {
flag3 = false;
continue;
assert false, "continue failed";
}
//-------------------------
{
//test break
while (true) {
break;
assert false, "break failed";
}
//test continue
var flag4: bool = true;
while (flag4) {
flag4 = false;
continue;
assert false, "continue failed";
}
}
//-------------------------
{
//test break
while (true) {
{
break;
}
assert false, "break failed";
}
//test continue
var flag5: bool = true;
while (flag5) {
flag5 = false;
{
continue;
}
assert false, "continue failed";
}
}
//-------------------------
{
//iteration
var iteration = 0;
while(iteration < 10) {
print iteration;
iteration += 1;
}
}
{
//if and while work together
var count = 1;
while (count <= 10) {
if (count % 2 == 0) {
print "even";
}
else {
print "odd";
}
count += 1;
}
}
//-------------------------
{
//make sure break and continue point to the correct locations
var loops = 0;
while (true) {
if (++loops < 15532) {
continue;
}
break;
}
assert loops == 15532, "Yuki loop failed (break + continue)";
}

View File

@@ -0,0 +1,17 @@
//shadowing
var answer = 42;
print answer; //42
{
var answer = 7;
print answer; //7
}
print answer; //42
//rebinding
var question = 42;
print question; //42
{
var question = question;
print question; //42
}
print question; //42

View File

@@ -0,0 +1,33 @@
//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";

View File

@@ -0,0 +1,80 @@
//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";
}
}

View File

@@ -0,0 +1,160 @@
//declare a variable with an initial value
var answer = 42;
//declare a variable without an initial value
var empty;
//assign a previously existing variable
answer = 6 * 9;
//access a variable
answer = answer + 1;
//compound assignments
answer += 5;
answer -= 5;
answer *= 9;
answer /= 2;
answer %= 10;
//equality checks
print 1 == 1; //true
print 1 != 1; //false
//comparison checks
print 1 < 2; //true
print "foo" > "bar"; //true
print 1 < 2; //true
print 1 > 2; //false
print 2 <= 2; //true
print 2 >= 2; //true
print 1 <= 2; //true
print 1 >= 2; //false
//logical checks
print true && true; //true
print true && false; //false
print false && true; //false
print false && false; //false
print true || true; //true
print true || false; //true
print false || true; //true
print false || false; //false
print !true; //false
print !false; //true
//logical AND short-circuits and chained assignments
{
var a = 1;
var b = 2;
var c = a + 1 && b + 2;
assert a == 1, "short circuit 1.1";
assert b == 2, "short circuit 1.2";
assert c == 4, "short circuit 1.3";
}
{
var a = 1;
var b = 2;
var c = a = (a + 1) && b + 2;
assert a == 4, "short circuit 2.1";
assert b == 2, "short circuit 2.2";
assert c == 4, "short circuit 2.3";
}
{
var a = 1;
var b = 2;
var c = a = a + 1 && b + 2;
assert a == 4, "short circuit 3.1";
assert b == 2, "short circuit 3.2";
assert c == 4, "short circuit 3.3";
}
//logical OR short-circuits and chained assignments
{
var a = 1;
var b = 2;
var c = a + 1 || b + 2;
assert a == 1, "short circuit 4.1";
assert b == 2, "short circuit 4.2";
assert c == 2, "short circuit 4.3";
}
{
var a = 1;
var b = 2;
var c = a = (a + 1) || b + 2;
assert a == 2, "short circuit 5.1";
assert b == 2, "short circuit 5.2";
assert c == 2, "short circuit 5.3";
}
{
var a = 1;
var b = 2;
var c = a = a + 1 || b + 2;
assert a == 2, "short circuit 6.1";
assert b == 2, "short circuit 6.2";
assert c == 2, "short circuit 6.3";
}
//types
{
var a: int;
var b: int = 42;
a = 69;
b = 8891;
print a;
print b;
}
//constants
{
var c: int const = 42;
print c;
}
//indexing
{
var s = "Hello" .. "world!";
print s[3, 3];
}
//increment & decrement (prefix)
{
var a = 42;
assert a == 42, "prefix increment & decrement 1.1";
assert ++a == 43, "prefix increment & decrement 1.2";
assert a == 43, "prefix increment & decrement 1.3";
assert --a == 42, "prefix increment & decrement 1.4";
assert a == 42, "prefix increment & decrement 1.5";
}
//increment & decrement (postfix)
{
var a = 42;
assert a == 42, "postfix increment & decrement 1.1";
assert a++ == 42, "postfix increment & decrement 1.2";
assert a == 43, "postfix increment & decrement 1.3";
assert a-- == 43, "postfix increment & decrement 1.4";
assert a == 42, "postfix increment & decrement 1.5";
print a;
}
//TODO: type casting

View File

@@ -19,30 +19,30 @@ endif
#directories
TEST_ROOTDIR=../..
TEST_SOURCEDIR=$(TEST_ROOTDIR)/$(TOY_SOURCEDIR)
TEST_CASESDIR=.
TEST_UNITSDIR=.
TEST_OUTDIR=out
TEST_OBJDIR=obj
#file names
TEST_SOURCEFILES=$(wildcard $(TEST_SOURCEDIR)/*.c)
TEST_CASESFILES=$(wildcard $(TEST_CASESDIR)/test_*.c)
TEST_UNITSFILES=$(wildcard $(TEST_UNITSDIR)/test_*.c)
#build the object files, compile the test cases, and run
all: build-source build-cases build-link build-run
#build the object files, compile the tess, and run
all: build-source build-units build-link build-run
#targets for each step
.PHONY: build-source
build-source: $(TEST_OUTDIR) $(TEST_OBJDIR) $(addprefix $(TEST_OBJDIR)/,$(notdir $(TEST_SOURCEFILES:.c=.o)))
.PHONY: build-cases
build-cases: $(TEST_OUTDIR) $(TEST_OBJDIR) $(addprefix $(TEST_OBJDIR)/,$(notdir $(TEST_CASESFILES:.c=.o)))
.PHONY: build-units
build-units: $(TEST_OUTDIR) $(TEST_OBJDIR) $(addprefix $(TEST_OBJDIR)/,$(notdir $(TEST_UNITSFILES:.c=.o)))
.PHONY: build-link
build-link: $(TEST_OUTDIR) $(TEST_OBJDIR) $(addprefix $(TEST_OUTDIR)/,$(notdir $(TEST_CASESFILES:%.c=%.exe)))
build-link: $(TEST_OUTDIR) $(TEST_OBJDIR) $(addprefix $(TEST_OUTDIR)/,$(notdir $(TEST_UNITSFILES:%.c=%.exe)))
.PHONY: build-run
build-run: $(addprefix $(TEST_OUTDIR)/,$(notdir $(TEST_CASESFILES:%.c=%.exe))) $(addprefix $(TEST_OUTDIR)/,$(notdir $(TEST_CASESFILES:%.c=%.run)))
build-run: $(addprefix $(TEST_OUTDIR)/,$(notdir $(TEST_UNITSFILES:%.c=%.exe))) $(addprefix $(TEST_OUTDIR)/,$(notdir $(TEST_UNITSFILES:%.c=%.run)))
#util targets
$(TEST_OUTDIR):
@@ -55,8 +55,8 @@ $(TEST_OBJDIR):
$(TEST_OBJDIR)/%.o: $(TEST_SOURCEDIR)/%.c
$(CC) -c -o $@ $< $(addprefix -I,$(TEST_SOURCEDIR)) $(CFLAGS) -fdata-sections -ffunction-sections
$(TEST_OBJDIR)/%.o: $(TEST_CASESDIR)/%.c
$(CC) -c -o $@ $< $(addprefix -I,$(TEST_SOURCEDIR) $(TEST_CASESDIR)) $(CFLAGS) -fdata-sections -ffunction-sections
$(TEST_OBJDIR)/%.o: $(TEST_UNITSDIR)/%.c
$(CC) -c -o $@ $< $(addprefix -I,$(TEST_SOURCEDIR) $(TEST_UNITSDIR)) $(CFLAGS) -fdata-sections -ffunction-sections
$(TEST_OUTDIR)/%.exe: $(TEST_OBJDIR)/%.o
@$(CC) -o $@ $< $(addprefix $(TEST_OBJDIR)/,$(notdir $(TEST_SOURCEFILES:.c=.o))) $(CFLAGS) $(LIBS) $(LDFLAGS)
@@ -66,20 +66,20 @@ $(TEST_OUTDIR)/%.run: $(TEST_OUTDIR)/%.exe
$<
#debugging targets
gdb: build-source build-cases build-link build-run-gdb
gdb: build-source build-units build-link build-run-gdb
.PHONY: build-run-gdb
build-run-gdb: $(addprefix $(TEST_OUTDIR)/,$(notdir $(TEST_CASESFILES:%.c=%.exe))) $(addprefix $(TEST_OUTDIR)/,$(notdir $(TEST_CASESFILES:%.c=%.run-gdb)))
build-run-gdb: $(addprefix $(TEST_OUTDIR)/,$(notdir $(TEST_UNITSFILES:%.c=%.exe))) $(addprefix $(TEST_OUTDIR)/,$(notdir $(TEST_UNITSFILES:%.c=%.run-gdb)))
.PRECIOUS: $(TEST_OUTDIR)/%.run-gdb
$(TEST_OUTDIR)/%.run-gdb: $(TEST_OUTDIR)/%.exe
gdb $< -ix gdb_init -ex=run --batch --return-child-result --args "$<"
#valgrind targets
valgrind: build-source build-cases build-link build-run-valgrind
valgrind: build-source build-units build-link build-run-valgrind
.PHONY: build-run-valgrind
build-run-valgrind: $(addprefix $(TEST_OUTDIR)/,$(notdir $(TEST_CASESFILES:%.c=%.exe))) $(addprefix $(TEST_OUTDIR)/,$(notdir $(TEST_CASESFILES:%.c=%.run-valgrind)))
build-run-valgrind: $(addprefix $(TEST_OUTDIR)/,$(notdir $(TEST_UNITSFILES:%.c=%.exe))) $(addprefix $(TEST_OUTDIR)/,$(notdir $(TEST_UNITSFILES:%.c=%.run-valgrind)))
.PRECIOUS: $(TEST_OUTDIR)/%.run-valgrind
$(TEST_OUTDIR)/%.run-valgrind: $(TEST_OUTDIR)/%.exe