From 17841954deb272dd9e4da83431bfab0fb2120feb Mon Sep 17 00:00:00 2001 From: "Johan B.W. de Vries" Date: Sun, 2 Feb 2025 15:13:03 +0100 Subject: [PATCH] Added a number of tests Fix: skip() would not work without peek() on iteration 0 or 1. --- 0-lang0py/lang0py.py | 4 ++ 1-lang0py/lang0py.lang0 | 26 ++++++------ README.md | 56 +++++++++++++++++++------- tests/.gitignore | 11 ----- tests/Makefile | 52 ++++++++++++------------ tests/build/.gitignore | 11 +++++ tests/flowbreak.lang0 | 6 +++ tests/flowcall.lang0 | 8 ++++ tests/flowiffalse.lang0 | 8 ++++ tests/flowiftrue.lang0 | 7 ++++ tests/flowreturnnothing.lang0 | 8 ++++ tests/flowreturnvalue.lang0 | 11 +++++ tests/parsingpredeclaredfunction.lang0 | 11 +++++ tests/stdlibaddstringchar.lang0 | 5 +++ tests/{emit.lang0 => stdlibemit.lang0} | 0 tests/stdlibeqfalse.lang0 | 8 ++++ tests/stdlibeqtrue.lang0 | 7 ++++ tests/stdlibltfalse.lang0 | 8 ++++ tests/stdliblttrue.lang0 | 7 ++++ tests/stdlibpeek.lang0 | 9 +++++ tests/stdlibskip.lang0 | 24 +++++++++++ tests/variablescalc.lang0 | 9 +++++ tests/variablesset.lang0 | 5 +++ 23 files changed, 237 insertions(+), 64 deletions(-) create mode 100644 tests/build/.gitignore create mode 100644 tests/flowbreak.lang0 create mode 100644 tests/flowcall.lang0 create mode 100644 tests/flowiffalse.lang0 create mode 100644 tests/flowiftrue.lang0 create mode 100644 tests/flowreturnnothing.lang0 create mode 100644 tests/flowreturnvalue.lang0 create mode 100644 tests/parsingpredeclaredfunction.lang0 create mode 100644 tests/stdlibaddstringchar.lang0 rename tests/{emit.lang0 => stdlibemit.lang0} (100%) create mode 100644 tests/stdlibeqfalse.lang0 create mode 100644 tests/stdlibeqtrue.lang0 create mode 100644 tests/stdlibltfalse.lang0 create mode 100644 tests/stdliblttrue.lang0 create mode 100644 tests/stdlibpeek.lang0 create mode 100644 tests/stdlibskip.lang0 create mode 100644 tests/variablescalc.lang0 create mode 100644 tests/variablesset.lang0 diff --git a/0-lang0py/lang0py.py b/0-lang0py/lang0py.py index a169ddc..f274d6c 100644 --- a/0-lang0py/lang0py.py +++ b/0-lang0py/lang0py.py @@ -27,6 +27,8 @@ def peek(): return PEEK +peek() + def skip(): global LINE global PEEK @@ -316,6 +318,8 @@ def emitheader(): emit(" PEEK = char\n") emit(" return PEEK\n") emit("\n") + emit("peek()\n") + emit("\n") emit("def skip():\n") emit(" global LINE\n") emit(" global PEEK\n") diff --git a/1-lang0py/lang0py.lang0 b/1-lang0py/lang0py.lang0 index bc61e62..c7f8a4e 100644 --- a/1-lang0py/lang0py.lang0 +++ b/1-lang0py/lang0py.lang0 @@ -309,42 +309,42 @@ parsefunc: skipchar eol emit "):\n" emit " pass # ahead declaration\n" - emit "\n" + emit eol return / skipchar ":" skipchar eol emit "):\n" parseblock " " - emit "\n" + emit eol / emitheader: emit "import os\n" emit "import sys\n" - emit "\n" + emit eol emit "def eq(a, b):\n" emit " return a == b\n" - emit "\n" + emit eol emit "def lt(a, b):\n" emit " return a[0] < b[0]\n" - emit "\n" + emit eol emit "def addstringchar(a, b):\n" emit " return a + b[0]\n" - emit "\n" + emit eol emit "def emit(string):\n" emit " sys.stdout.write(string)\n" - emit "\n" + emit eol emit "def trace(header, value):\n" emit " if os.environ.get('TRACE'):\n" emit " sys.stderr.write(f'{header}={value!r}\\n')\n" - emit "\n" + emit eol emit "eof = chr(0)\n" emit "eol = chr(10)\n" emit "quote = chr(34)\n" emit "PEEK = None\n" emit "LINE = 1\n" - emit "\n" + emit eol emit "def peek():\n" emit " global PEEK\n" emit " if PEEK is None:\n" @@ -355,19 +355,21 @@ emitheader: emit " else:\n" emit " PEEK = char\n" emit " return PEEK\n" - emit "\n" + emit eol + emit "peek()\n" + emit eol emit "def skip():\n" emit " global LINE\n" emit " global PEEK\n" emit " if eol == PEEK:\n" emit " LINE += 1\n" emit " PEEK = None\n" - emit "\n" + emit eol emit "def skipchar(char):\n" emit " global LINE\n" emit " assert char == peek(), (LINE, char, peek())\n" emit " skip()\n" - emit "\n" + emit eol / emitfooter: diff --git a/README.md b/README.md index 941cd32..d14e8ea 100644 --- a/README.md +++ b/README.md @@ -49,6 +49,32 @@ Indentation is done using tabs. ### Parsing +#### Pre declaration (functions) + +Functions need to be pre-declared if you intend to use them before you have defined them: + +``` +func result/ + +... + +func result: + return result +/ +``` + +#### Pre declaration (variables) + +Variables will need to be declared before you can use them: + +``` +func: + declare result + set result "Result" + return result +/ +``` + ### Variables #### calc var func args* @@ -69,6 +95,10 @@ Sets var to "const". Exits the deepest `forever` loop. +#### func args* + +Calls the function name `func` with the given arguments. The result, if any, is ignored. + #### if arg Evaluates arg. If found to be true, descends in the block. Otherwise, skips the block @@ -81,27 +111,13 @@ Repeats the block until `break` or `return` is called. Returns the given value. You can not give an argument if your function is never used in `call`. -#### func args* - -Calls the given function with the given arguments. The result, if any, is ignored. - ### Builtins #### trace Writes the name and value of the variable passed to stderr if the TRACE environment variable is set. -#### Standard library functions - -#### eq a b - -Return true if the given strings are the same. - -#### lt a b - -`a` and `b` are expected to have length 1. - -Return true if a would sort before b. +### Standard library functions #### addstringchar a b @@ -113,6 +129,16 @@ Creates a new string with `b` appended to `a`. Writes the given string to standard output. +#### eq a b + +Return true if the given strings are the same. + +#### lt a b + +`a` and `b` are expected to have length 1. + +Return true if a would sort before b. + #### peek Checks stdin for the next character and returns it. diff --git a/tests/.gitignore b/tests/.gitignore index 50044b6..fa47d71 100644 --- a/tests/.gitignore +++ b/tests/.gitignore @@ -1,12 +1 @@ -/*.it0 -/*.it0.c -/*.it0.o -/*.it0.py -/*.it1 -/*.it1.c -/*.it1.o -/*.it1.py -/*.it2 -/*.it2.c -/*.it2.o /*.results diff --git a/tests/Makefile b/tests/Makefile index fb4e7bc..8701ecc 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -8,64 +8,64 @@ CC=gcc TESTLIST=$(shell ls *.lang0 | sed 's/.lang0//') -all: all-it0.results all-it1.results all-it2.results +all: check -all-it0.results: $(addsuffix .it0, $(TESTLIST)) - -rm -f $@ - $(foreach test,$(TESTLIST), echo -n "$(test) " >> $@; ./$(test).it0 >> $@ ; echo "" >> $@) - ! grep -v 'Success' $@ +check: all-it0.results all-it1.results all-it2.results + ! grep -v 'Success' $^ -all-it1.results: $(addsuffix .it1, $(TESTLIST)) +all-it0.results: $(addprefix build/,$(addsuffix .it0, $(TESTLIST))) -rm -f $@ - $(foreach test,$(TESTLIST), echo -n "$(test) " >> $@; ./$(test).it1 >> $@ ; echo "" >> $@) - ! grep -v 'Success' $@ + $(foreach test,$(TESTLIST), echo -n "$(test) " >> $@; echo "Hello" | ./build/$(test).it0 >> $@ ; echo "" >> $@ ;) -all-it2.results: $(addsuffix .it2, $(TESTLIST)) +all-it1.results: $(addprefix build/,$(addsuffix .it1, $(TESTLIST))) -rm -f $@ - $(foreach test,$(TESTLIST), echo -n "$(test) " >> $@; ./$(test).it2 >> $@ ; echo "" >> $@) - ! grep -v 'Success' $@ + $(foreach test,$(TESTLIST), echo -n "$(test) " >> $@; echo "Hello" | ./build/$(test).it1 >> $@ ; echo "" >> $@ ;) + +all-it2.results: $(addprefix build/,$(addsuffix .it2, $(TESTLIST))) + -rm -f $@ + $(foreach test,$(TESTLIST), echo -n "$(test) " >> $@; echo "Hello" | ./build/$(test).it2 >> $@ ; echo "" >> $@ ;) clean: - -rm -f *.result *.it0* *.it1* *.it2* + -rm -f *.results build/*.it0* build/*.it1* build/*.it2* ### # it0 -%.it0.py: %.lang0 ../0-lang0py/lang0py.exe +build/%.it0.py: %.lang0 ../0-lang0py/lang0py.exe cat $< | ../0-lang0py/lang0py.exe > $@ -%.it0.c: %.it0.py +build/%.it0.c: build/%.it0.py $(CYTHON) -3 --embed -o $@ $^ -%.it0.o: %.it0.c - $(CC) -c $^ -I$(PYPREFIX)/include/python$(PYVERSION) +build/%.it0.o: build/%.it0.c + $(CC) -o $@ -c $^ -I$(PYPREFIX)/include/python$(PYVERSION) -%.it0: %.it0.o +build/%.it0: build/%.it0.o $(CC) -o $@ $^ -lpython$(PYVERSION) ### # it1 -%.it1.py: %.lang0 ../1-lang0py/lang0py.exe +build/%.it1.py: %.lang0 ../1-lang0py/lang0py.exe cat $< | ../1-lang0py/lang0py.exe > $@ -%.it1.c: %.it1.py +build/%.it1.c: build/%.it1.py $(CYTHON) -3 --embed -o $@ $^ -%.it1.o: %.it1.c - $(CC) -c $^ -I$(PYPREFIX)/include/python$(PYVERSION) +build/%.it1.o: build/%.it1.c + $(CC) -o $@ -c $^ -I$(PYPREFIX)/include/python$(PYVERSION) -%.it1: %.it1.o +build/%.it1: build/%.it1.o $(CC) -o $@ $^ -lpython$(PYVERSION) ### # it2 -%.it2.c: %.lang0 ../2-lang0c/lang0c.exe +build/%.it2.c: %.lang0 ../2-lang0c/lang0c.exe cat $< | ../2-lang0c/lang0c.exe > $@ -%.it2.o: %.it2.c - $(CC) -c $^ -I$(PYPREFIX)/include/python$(PYVERSION) +build/%.it2.o: build/%.it2.c + $(CC) -o $@ -c $^ -I$(PYPREFIX)/include/python$(PYVERSION) -%.it2: %.it2.o +build/%.it2: build/%.it2.o $(CC) -o $@ $^ -lpython$(PYVERSION) diff --git a/tests/build/.gitignore b/tests/build/.gitignore new file mode 100644 index 0000000..3ee26ee --- /dev/null +++ b/tests/build/.gitignore @@ -0,0 +1,11 @@ +/*.it0 +/*.it0.c +/*.it0.o +/*.it0.py +/*.it1 +/*.it1.c +/*.it1.o +/*.it1.py +/*.it2 +/*.it2.c +/*.it2.o diff --git a/tests/flowbreak.lang0 b/tests/flowbreak.lang0 new file mode 100644 index 0000000..28afb05 --- /dev/null +++ b/tests/flowbreak.lang0 @@ -0,0 +1,6 @@ +main: + forever + break + / + emit "Success" +/ diff --git a/tests/flowcall.lang0 b/tests/flowcall.lang0 new file mode 100644 index 0000000..ec24cf6 --- /dev/null +++ b/tests/flowcall.lang0 @@ -0,0 +1,8 @@ +func: + emit "Success" + return +/ + +main: + func +/ diff --git a/tests/flowiffalse.lang0 b/tests/flowiffalse.lang0 new file mode 100644 index 0000000..c17bf16 --- /dev/null +++ b/tests/flowiffalse.lang0 @@ -0,0 +1,8 @@ +main: + declare bool + set bool "" + if bool + return + / + emit "Success" +/ diff --git a/tests/flowiftrue.lang0 b/tests/flowiftrue.lang0 new file mode 100644 index 0000000..43dc7d5 --- /dev/null +++ b/tests/flowiftrue.lang0 @@ -0,0 +1,7 @@ +main: + declare bool + set bool "1" + if bool + emit "Success" + / +/ diff --git a/tests/flowreturnnothing.lang0 b/tests/flowreturnnothing.lang0 new file mode 100644 index 0000000..d81523f --- /dev/null +++ b/tests/flowreturnnothing.lang0 @@ -0,0 +1,8 @@ +func: + return +/ + +main: + func + emit "Success" +/ diff --git a/tests/flowreturnvalue.lang0 b/tests/flowreturnvalue.lang0 new file mode 100644 index 0000000..4846fe6 --- /dev/null +++ b/tests/flowreturnvalue.lang0 @@ -0,0 +1,11 @@ +func: + declare result + set result "Success" + return result +/ + +main: + declare result + calc result func + emit result +/ diff --git a/tests/parsingpredeclaredfunction.lang0 b/tests/parsingpredeclaredfunction.lang0 new file mode 100644 index 0000000..a794b15 --- /dev/null +++ b/tests/parsingpredeclaredfunction.lang0 @@ -0,0 +1,11 @@ +func result/ + +main: + declare result + calc result func "Success" + emit result +/ + +func result: + return result +/ diff --git a/tests/stdlibaddstringchar.lang0 b/tests/stdlibaddstringchar.lang0 new file mode 100644 index 0000000..5d83c80 --- /dev/null +++ b/tests/stdlibaddstringchar.lang0 @@ -0,0 +1,5 @@ +main: + declare result + calc result addstringchar "Succes" "s" + emit result +/ diff --git a/tests/emit.lang0 b/tests/stdlibemit.lang0 similarity index 100% rename from tests/emit.lang0 rename to tests/stdlibemit.lang0 diff --git a/tests/stdlibeqfalse.lang0 b/tests/stdlibeqfalse.lang0 new file mode 100644 index 0000000..e2e52d3 --- /dev/null +++ b/tests/stdlibeqfalse.lang0 @@ -0,0 +1,8 @@ +main: + declare bool + calc bool eq "1" "2" + if bool + return + / + emit "Success" +/ diff --git a/tests/stdlibeqtrue.lang0 b/tests/stdlibeqtrue.lang0 new file mode 100644 index 0000000..dd44ca0 --- /dev/null +++ b/tests/stdlibeqtrue.lang0 @@ -0,0 +1,7 @@ +main: + declare bool + calc bool eq "1" "1" + if bool + emit "Success" + / +/ diff --git a/tests/stdlibltfalse.lang0 b/tests/stdlibltfalse.lang0 new file mode 100644 index 0000000..0a7ad58 --- /dev/null +++ b/tests/stdlibltfalse.lang0 @@ -0,0 +1,8 @@ +main: + declare bool + calc bool lt "b" "a" + if bool + return + / + emit "Success" +/ diff --git a/tests/stdliblttrue.lang0 b/tests/stdliblttrue.lang0 new file mode 100644 index 0000000..f3f3433 --- /dev/null +++ b/tests/stdliblttrue.lang0 @@ -0,0 +1,7 @@ +main: + declare bool + calc bool lt "a" "b" + if bool + emit "Success" + / +/ diff --git a/tests/stdlibpeek.lang0 b/tests/stdlibpeek.lang0 new file mode 100644 index 0000000..9455c7b --- /dev/null +++ b/tests/stdlibpeek.lang0 @@ -0,0 +1,9 @@ +main: + declare char + declare ish + calc char peek + calc ish eq char "H" + if ish + emit "Success" + / +/ diff --git a/tests/stdlibskip.lang0 b/tests/stdlibskip.lang0 new file mode 100644 index 0000000..1392458 --- /dev/null +++ b/tests/stdlibskip.lang0 @@ -0,0 +1,24 @@ +main: + declare char + declare ish + declare iso + declare notish + declare notiso + skip + calc char peek + calc ish eq char "e" + calc notish not ish + if notish + return + / + skip + skip + skip + calc char peek + calc iso eq char "o" + calc notiso not iso + if notish + return + / + emit "Success" +/ diff --git a/tests/variablescalc.lang0 b/tests/variablescalc.lang0 new file mode 100644 index 0000000..2ff98b2 --- /dev/null +++ b/tests/variablescalc.lang0 @@ -0,0 +1,9 @@ +func result: + return result +/ + +main: + declare result + calc result func "Success" + emit result +/ diff --git a/tests/variablesset.lang0 b/tests/variablesset.lang0 new file mode 100644 index 0000000..2d83af1 --- /dev/null +++ b/tests/variablesset.lang0 @@ -0,0 +1,5 @@ +main: + declare result + set result "Success" + emit result +/