From 670532059a6595edf5994ab789e18eb6ae996ff3 Mon Sep 17 00:00:00 2001 From: "Johan B.W. de Vries" Date: Sun, 2 Feb 2025 15:43:37 +0100 Subject: [PATCH] Feat: Adds mapclear, mapgetkey, mapsetkey Feat: Error on undefined function Fix: All ids are now prefix to prevent native var clashes. This was already done on it2, but now also in it0 and it1. Redid it2 to match. Fix: generate-recipes would not complain on missing exp. Fix: Adds documentation and test for not Chore: __check helper function for ease of use in it0, it1. Chore: some reordering to match more between iterations. --- 0-lang0py/lang0py.py | 195 ++++++++--- 1-lang0py/Makefile | 3 + 1-lang0py/lang0py.lang0 | 198 ++++++++--- 2-lang0c/lang0c.lang0 | 324 ++++++++++++++---- README.md | 23 ++ tests/Makefile | 19 +- tests/build/test_builtins/.gitignore | 3 + tests/build/test_flow_control/.gitignore | 3 + tests/build/test_parsing/.gitignore | 3 + tests/build/test_stdlib_constants/.gitignore | 3 + tests/build/test_stdlib_functions/.gitignore | 3 + tests/build/test_validation/.gitignore | 26 ++ tests/build/test_variables/.gitignore | 3 + tests/generate-recipes.py | 32 +- .../test_target_reserved_names.exp.stdout | 1 + .../test_target_reserved_names.lang0 | 8 + .../test_stdlib_functions/test_map.exp.stdout | 14 + tests/test_stdlib_functions/test_map.lang0 | 36 ++ .../test_stdlib_functions/test_not.exp.stdout | 4 + tests/test_stdlib_functions/test_not.lang0 | 16 + .../test_undefined_call.exp.cmperr | 1 + .../test_validation/test_undefined_call.lang0 | 4 + .../test_undefined_function.exp.cmperr | 1 + .../test_undefined_function.lang0 | 3 + 24 files changed, 736 insertions(+), 190 deletions(-) create mode 100644 tests/build/test_validation/.gitignore create mode 100644 tests/test_parsing/test_target_reserved_names.exp.stdout create mode 100644 tests/test_parsing/test_target_reserved_names.lang0 create mode 100644 tests/test_stdlib_functions/test_map.exp.stdout create mode 100644 tests/test_stdlib_functions/test_map.lang0 create mode 100644 tests/test_stdlib_functions/test_not.exp.stdout create mode 100644 tests/test_stdlib_functions/test_not.lang0 create mode 100644 tests/test_validation/test_undefined_call.exp.cmperr create mode 100644 tests/test_validation/test_undefined_call.lang0 create mode 100644 tests/test_validation/test_undefined_function.exp.cmperr create mode 100644 tests/test_validation/test_undefined_function.lang0 diff --git a/0-lang0py/lang0py.py b/0-lang0py/lang0py.py index 295898b..f4c5a99 100644 --- a/0-lang0py/lang0py.py +++ b/0-lang0py/lang0py.py @@ -39,6 +39,36 @@ def skip(): PEEK = None +def __check(func, args: list[str], msg: list[str]) -> None: + result = func(*args) + if result: + return + + sys.stderr.write('ERROR: ' + ' '.join(msg) + '\n') + sys.stderr.flush() + exit(1) + +MAPSTORE = {} + +def mapclear(mapname: str) -> str: + MAPSTORE.pop(mapname) + return "" + +def mapgetkey(mapname: str, key: str, default: str) -> str: + return MAPSTORE.get(mapname, {}).get(key, default) + +def mapsetkey(mapname: str, key: str, value: str) -> str: + MAPSTORE.setdefault(mapname, {}) + MAPSTORE[mapname][key] = value + return "" + +def registerid(id: str) -> str: + idname = mapgetkey("REGISTERID", id, "") + if idname: + return idname + idname = "id_" + id + return idname + def emitln(data): emit(data) emit(eol) @@ -81,12 +111,15 @@ def parseconststring(): emit(quote) def parseexprvarref(): - var = lexident() - emit(var) + varname = lexident() + varid = registerid(varname) + emit(varid) def parseexprcall(): funcname = lexident() - emit(funcname) + __check(mapgetkey, ["FUNCREG", funcname, ""], ["Function", funcname, "does not exist"]) + funcid = registerid(funcname) + emit(funcid) emit('(') first = True @@ -109,11 +142,12 @@ def parsestatdeclare(indent): def parsestatset(indent): skipchar(' ') - var = lexident() + varname = lexident() + varid = registerid(varname) skipchar(' ') emit(' ' * indent) - emit(var) + emit(varid) emit(' = ') parseconststring() @@ -123,11 +157,12 @@ def parsestatset(indent): def parsestatcalc(indent): skipchar(' ') - var = lexident() + varname = lexident() + varid = registerid(varname) skipchar(' ') emit(' ' * indent) - emit(var) + emit(varid) emit(' = ') parseexprcall() @@ -174,11 +209,13 @@ def parsestatreturn(indent): def parsestatcheck(indent): skipchar(' ') emit(' ' * indent) - emit('if not ') + emit('__check(') - func_name = lexident() - emit(func_name) - emit('(') + funcname = lexident() + funcid = registerid(funcname) + trace("funcid", funcid) + emit(funcid) + emit(', [') notfirst = False while True: @@ -199,9 +236,7 @@ def parsestatcheck(indent): skipchar(':') - emitln('):') - emit(' ' * (indent + 1)) - emit('sys.stderr.write(\' \'.join(["ERROR:", ') + emit('], [') notfirst = False while True: @@ -218,23 +253,21 @@ def parsestatcheck(indent): if eol == peek(): break notfirst = True - emitln(']))') - emit(' ' * (indent + 1)) - emitln('sys.stderr.write(eol)') - emit(' ' * (indent + 1)) - emitln('sys.exit(1)') + + emitln('])') def parsestattrace(indent): skipchar(' ') emit(' ' * indent) - emit('trace("') + emit('__trace("') - var_name = lexident() + varname = lexident() + varid = registerid(varname) skipchar(eol) - emit(var_name) + emit(varname) emit('", ') - emit(var_name) + emit(varid) emitln(')') def parsestat(indent): @@ -277,8 +310,12 @@ def parsestat(indent): parsestattrace(indent) return + __check(mapgetkey, ["FUNCREG", call, ""], ["Function", call, "does not exist"]) + + callid = registerid(call) + emit(' ' * indent) - emit(call) + emit(callid) emit('(') first = True @@ -315,19 +352,22 @@ def parseblock(indent): def parsefunc(): funcname = lexident() + funcid = registerid(funcname) + mapsetkey("FUNCREG", funcname, "1") trace('funcname', funcname) emit('def ') - emit(funcname) + emit(funcid) emit('(') first = True while ' ' == peek(): skip() - var = lexident() + varname = lexident() + varid = registerid(varname) if not first: emit(", ") - emit(var) + emit(varid) first = False if '/' == peek(): @@ -352,26 +392,26 @@ def emitheader(): emitln("import os") emitln("import sys") emitln("") - emitln("def eq(a: str, b: str) -> str:") + emitln("def __eq(a: str, b: str) -> str:") emitln(" return '1' if a == b else ''") emitln("") - emitln("def lt(a: str, b: str) -> str:") + emitln("def __lt(a: str, b: str) -> str:") emitln(" return '1' if a < b else ''") emitln("") - emitln("def add(a: str, b: str) -> str:") + emitln("def __add(a: str, b: str) -> str:") emitln(" return a + b") emitln("") - emitln("def emit(string):") + emitln("def __emit(string):") emitln(" sys.stdout.buffer.write(string.encode('latin_1'))") emitln(" sys.stdout.flush()") emitln("") - emitln("def trace(header, value):") + emitln("def __trace(header, value):") emitln(" if os.environ.get('TRACE'):") emitln(" sys.stderr.write(f'{header}={value!r}\\n')") emitln("") - emitln("eof = chr(0xFF)") - emitln("eol = chr(10)") - emitln("quote = chr(34)") + emitln("__EOF = chr(0xFF)") + emitln("__EOL = chr(10)") + emitln("__QUOTE = chr(34)") emitln("") emitln("STDINCOLNO = 0") emitln("STDINLINENO = 1") @@ -379,41 +419,106 @@ def emitheader(): emitln("") emitln("def _readchar():") emitln(" char = sys.stdin.read(1)") - emitln(" trace('char', char)") + emitln(" __trace('char', char)") emitln(" if not char:") - emitln(" return eof") + emitln(" return __EOF") emitln(" return char") emitln("") - emitln("def peek():") + emitln("def __peek():") emitln(" return STDINPEEK") emitln("") - emitln("def skip():") + emitln("def __skip():") emitln(" global STDINCOLNO") emitln(" global STDINLINENO") emitln(" global STDINPEEK") - emitln(" if eol == STDINPEEK:") + emitln(" if __EOL == STDINPEEK:") emitln(" STDINLINENO += 1") emitln(" STDINCOLNO = 0") emitln(" STDINCOLNO += 1") emitln(" STDINPEEK = _readchar()") emitln("") - emitln("def stdinlineno():") + emitln("def __stdinlineno():") emitln(" global STDINLINENO") emitln(" return str(STDINLINENO)") emitln("") - emitln("def stdincolno():") + emitln("def __stdincolno():") emitln(" global STDINCOLNO") emitln(" return str(STDINCOLNO)") emitln("") - emitln("skip()") + emitln("__skip()") + emitln("") + emitln("MAPSTORE = {}") + emitln("") + emitln("def __mapclear(mapname: str) -> str:") + emitln(" MAPSTORE.pop(mapname)") + emitln(" return ''") + emitln("") + emitln("def __mapgetkey(mapname: str, key: str, default: str) -> str:") + emitln(" return MAPSTORE.get(mapname, {}).get(key, default)") + emitln("") + emitln("def __mapsetkey(mapname: str, key: str, value: str) -> str:") + emitln(" MAPSTORE.setdefault(mapname, {})") + emitln(" MAPSTORE[mapname][key] = value") + emitln(" return ''") + emitln("") + emitln("def __not(a: str) -> str:") + emitln(" if a:") + emitln(" return ''") + emitln(" return '1'") + emitln("") + emitln("def __check(func, args: list[str], msg: list[str]) -> None:") + emitln(" result = func(*args)") + emitln(" if result:") + emitln(" return") + emitln("") + emitln(" sys.stderr.write('ERROR: ' + ' '.join(msg) + '\\n')") + emitln(" sys.stderr.flush()") + emitln(" exit(1)") + emitln("") + emitln("# ### END OF RUNTIME ### #") emitln("") def emitfooter(): - emit("if __name__ == '__main__':\n") - emit(" main()\n") + mainid = registerid("main") + emitln("if __name__ == '__main__':") + emit(" ") + emit(mainid) + emitln("()") def main(): emitheader() + + # Standard library constants + mapsetkey("REGISTERID", "eof", "__EOF") + mapsetkey("REGISTERID", "eol", "__EOL") + mapsetkey("REGISTERID", "quote", "__QUOTE") + + # Standard library functions + mapsetkey("FUNCREG", "add", "1") + mapsetkey("REGISTERID", "add", "__add") + mapsetkey("FUNCREG", "emit", "1") + mapsetkey("REGISTERID", "emit", "__emit") + mapsetkey("FUNCREG", "eq", "1") + mapsetkey("REGISTERID", "eq", "__eq") + mapsetkey("FUNCREG", "lt", "1") + mapsetkey("REGISTERID", "lt", "__lt") + mapsetkey("FUNCREG", "not", "1") + mapsetkey("REGISTERID", "not", "__not") + mapsetkey("FUNCREG", "mapclear", "1") + mapsetkey("REGISTERID", "mapclear", "__mapclear") + mapsetkey("FUNCREG", "mapgetkey", "1") + mapsetkey("REGISTERID", "mapgetkey", "__mapgetkey") + mapsetkey("FUNCREG", "mapsetkey", "1") + mapsetkey("REGISTERID", "mapsetkey", "__mapsetkey") + mapsetkey("FUNCREG", "peek", "1") + mapsetkey("REGISTERID", "peek", "__peek") + mapsetkey("FUNCREG", "skip", "1") + mapsetkey("REGISTERID", "skip", "__skip") + mapsetkey("FUNCREG", "stdincolno", "1") + mapsetkey("REGISTERID", "stdincolno", "__stdincolno") + mapsetkey("FUNCREG", "stdinlineno", "1") + mapsetkey("REGISTERID", "stdinlineno", "__stdinlineno") + while True: if eof == peek(): break diff --git a/1-lang0py/Makefile b/1-lang0py/Makefile index ad189bd..e96fdf5 100644 --- a/1-lang0py/Makefile +++ b/1-lang0py/Makefile @@ -36,5 +36,8 @@ lang0py.py: lang0py.lang0 lang0py2.exe mv $@.tmp $@ -diff lang0py2.py lang0py.py +$(LANG0PY): $(CURDIR)/../0-lang0py/lang0py.py $(CURDIR)/../0-lang0py/lang0py.lang0 + cd ../0-lang0py && make lang0py.exe + clean: rm -f lang0py*.py lang0py*.c lang0py*.o lang0py*.exe diff --git a/1-lang0py/lang0py.lang0 b/1-lang0py/lang0py.lang0 index abfa2f9..0a207e4 100644 --- a/1-lang0py/lang0py.lang0 +++ b/1-lang0py/lang0py.lang0 @@ -1,12 +1,14 @@ -skipchar exp: - declare act - declare lineno - declare colno - calc act peek - calc lineno stdinlineno - calc colno stdincolno - check eq exp act : "Unexpected character" act "expected" exp "at" lineno colno - skip +registerid id: + declare idname + declare newidx + + calc idname mapgetkey "REGISTERID" id "" + if idname + return idname + / + + calc idname add "id_" id + return idname / emitln data: @@ -14,11 +16,6 @@ emitln data: emit eol / -increaseindent indent: - calc indent add indent " " - return indent -/ - lexident: declare word set word "" @@ -38,6 +35,22 @@ lexident: return word / +skipchar exp: + declare act + declare lineno + declare colno + calc act peek + calc lineno stdinlineno + calc colno stdincolno + check eq exp act : "Unexpected character" act "expected" exp "at" lineno colno + skip +/ + +increaseindent indent: + calc indent add indent " " + return indent +/ + parseconststring: skipchar quote emit quote @@ -60,12 +73,15 @@ parseconststring: parseexprvarref: calc varname lexident - emit varname + calc varid registerid varname + emit varid / parseexprcall: calc funcname lexident - emit funcname + calc funcid registerid funcname + check mapgetkey "FUNCREG" funcname "" : "Function" funcname "does not exist" + emit funcid emit "(" set first "1" forever @@ -97,16 +113,18 @@ parseexprcall: parsestatdeclare indent: skipchar " " - calc var lexident + calc varname lexident + calc varid registerid varname skipchar eol / parsestatset indent: skipchar " " - calc var lexident + calc varname lexident + calc varid registerid varname skipchar " " emit indent - emit var + emit varid emit " = " parseconststring emit eol @@ -115,10 +133,11 @@ parsestatset indent: parsestatcalc indent: skipchar " " - calc var lexident + calc varname lexident + calc varid registerid varname skipchar " " emit indent - emit var + emit varid emit " = " parseexprcall emit eol @@ -188,11 +207,12 @@ parsestatcheck indent: skipchar " " emit indent - emit "if not " + emit "__check(" calc funcname lexident - emit funcname - emit "(" + calc funcid registerid funcname + emit funcid + emit ", [" set notfirst "" forever @@ -222,10 +242,7 @@ parsestatcheck indent: skipchar ":" - emitln "):" - calc indent increaseindent indent - emit indent - emit "sys.stderr.write(' '.join(['ERROR:', " + emit "], [" set notfirst "" @@ -255,23 +272,20 @@ parsestatcheck indent: set notfirst "1" / - emitln "]))" - emit indent - emitln "sys.stderr.write(eol)" - emit indent - emitln "sys.exit(1)" + emitln "])" / parsestattrace indent: emit indent - emit "trace(" + emit "__trace(" emit quote skipchar " " calc varname lexident + calc varid registerid varname emit varname emit quote emit ", " - emit varname + emit varid emitln ")" skipchar eol / @@ -324,8 +338,10 @@ parsestat indent: parsestatcheck indent return / + check mapgetkey "FUNCREG" call "" : "Function" call "does not exist" + calc callid registerid call emit indent - emit call + emit callid emit "(" set first "1" forever @@ -390,9 +406,11 @@ parseblock indent: parsefunc: calc funcname lexident + calc funcid registerid funcname trace funcname + mapsetkey "FUNCREG" funcname "1" emit "def " - emit funcname + emit funcid emit "(" set isnotfirst "" forever @@ -403,11 +421,12 @@ parsefunc: break / skip - calc var lexident + calc varname lexident + calc varid registerid varname if isnotfirst emit ", " / - emit var + emit varid set isnotfirst "1" / calc char peek @@ -431,26 +450,31 @@ emitheader: emitln "import os" emitln "import sys" emitln "" - emitln "def eq(a: str, b: str) -> str:" + emitln "def __eq(a: str, b: str) -> str:" emitln " return '1' if a == b else ''" emitln "" - emitln "def lt(a: str, b: str) -> str:" + emitln "def __lt(a: str, b: str) -> str:" emitln " return '1' if a < b else ''" emitln "" - emitln "def add(a: str, b :str) -> str:" + emitln "def __not(a: str) -> str:" + emitln " if a:" + emitln " return ''" + emitln " return '1'" + emitln "" + emitln "def __add(a: str, b :str) -> str:" emitln " return a + b" emitln "" - emitln "def emit(string):" + emitln "def __emit(string):" emitln " sys.stdout.buffer.write(string.encode('latin_1'))" emitln " sys.stdout.flush()" emitln "" - emitln "def trace(header, value):" + emitln "def __trace(header, value):" emitln " if os.environ.get('TRACE'):" emitln " sys.stderr.write(f'{header}={value!r}\\n')" emitln "" - emitln "eof = chr(0xFF)" - emitln "eol = chr(10)" - emitln "quote = chr(34)" + emitln "__EOF = chr(0xFF)" + emitln "__EOL = chr(10)" + emitln "__QUOTE = chr(34)" emitln "" emitln "STDINCOLNO = 0" emitln "STDINLINENO = 1" @@ -458,43 +482,105 @@ emitheader: emitln "" emitln "def _readchar():" emitln " char = sys.stdin.read(1)" - emitln " trace('char', char)" + emitln " __trace('char', char)" emitln " if not char:" - emitln " return eof" + emitln " return __EOF" emitln " return char" emitln "" - emitln "def peek():" + emitln "def __peek():" emitln " return STDINPEEK" emitln "" - emitln "def skip():" + emitln "def __skip():" emitln " global STDINCOLNO" emitln " global STDINLINENO" emitln " global STDINPEEK" - emitln " if eol == STDINPEEK:" + emitln " if __EOL == STDINPEEK:" emitln " STDINLINENO += 1" emitln " STDINCOLNO = 0" emitln " STDINCOLNO += 1" emitln " STDINPEEK = _readchar()" emitln "" - emitln "def stdinlineno():" + emitln "def __stdinlineno():" emitln " global STDINLINENO" emitln " return str(STDINLINENO)" emitln "" - emitln "def stdincolno():" + emitln "def __stdincolno():" emitln " global STDINCOLNO" emitln " return str(STDINCOLNO)" emitln "" - emitln "skip()" + emitln "__skip()" + emitln "" + emitln "" + emitln "MAPSTORE = {}" + emitln "" + emitln "def __mapclear(mapname: str) -> str:" + emitln " MAPSTORE.pop(mapname)" + emitln " return ''" + emitln "" + emitln "def __mapgetkey(mapname: str, key: str, default: str) -> str:" + emitln " return MAPSTORE.get(mapname, {}).get(key, default)" + emitln "" + emitln "def __mapsetkey(mapname: str, key: str, value: str) -> str:" + emitln " MAPSTORE.setdefault(mapname, {})" + emitln " MAPSTORE[mapname][key] = value" + emitln " return ''" + emitln "" + emitln "def __check(func, args: list[str], msg: list[str]) -> None:" + emitln " result = func(*args)" + emitln " if result:" + emitln " return" + emitln "" + emitln " sys.stderr.write('ERROR: ' + ' '.join(msg) + '\\n')" + emitln " sys.stderr.flush()" + emitln " exit(1)" + emitln "" + emitln "# ### END OF RUNTIME ### #" emitln "" / emitfooter: + declare mainid + calc mainid registerid "main" + emitln "if __name__ == '__main__':" - emitln " main()" + emit " " + emit mainid + emitln "()" / main: emitheader + + mapsetkey "REGISTERID" "eof" "__EOF" + mapsetkey "REGISTERID" "eol" "__EOL" + mapsetkey "REGISTERID" "quote" "__QUOTE" + + mapsetkey "FUNCREG" "add" "1" + mapsetkey "REGISTERID" "add" "__add" + mapsetkey "FUNCREG" "emit" "1" + mapsetkey "REGISTERID" "emit" "__emit" + mapsetkey "FUNCREG" "eq" "1" + mapsetkey "REGISTERID" "eq" "__eq" + mapsetkey "FUNCREG" "lt" "1" + mapsetkey "REGISTERID" "lt" "__lt" + mapsetkey "FUNCREG" "not" "1" + mapsetkey "REGISTERID" "not" "__not" + mapsetkey "FUNCREG" "mapclear" "1" + mapsetkey "REGISTERID" "mapclear" "__mapclear" + mapsetkey "FUNCREG" "mapgetkey" "1" + mapsetkey "REGISTERID" "mapgetkey" "__mapgetkey" + mapsetkey "FUNCREG" "mapsetkey" "1" + mapsetkey "REGISTERID" "mapsetkey" "__mapsetkey" + mapsetkey "FUNCREG" "peek" "1" + mapsetkey "REGISTERID" "peek" "__peek" + mapsetkey "FUNCREG" "skip" "1" + mapsetkey "REGISTERID" "skip" "__skip" + mapsetkey "FUNCREG" "stdincolno" "1" + mapsetkey "REGISTERID" "stdincolno" "__stdincolno" + mapsetkey "FUNCREG" "stdinlineno" "1" + mapsetkey "REGISTERID" "stdinlineno" "__stdinlineno" + + forever calc char peek calc iseof eq char eof diff --git a/2-lang0c/lang0c.lang0 b/2-lang0c/lang0c.lang0 index 96066cd..edb1aaa 100644 --- a/2-lang0c/lang0c.lang0 +++ b/2-lang0c/lang0c.lang0 @@ -1,12 +1,14 @@ -skipchar exp: - declare act - declare lineno - declare colno - calc act peek - calc lineno stdinlineno - calc colno stdincolno - check eq exp act : "Unexpected character" act "expected" exp "at" lineno colno - skip +registerid id: + declare idname + declare newidx + + calc idname mapgetkey "REGISTERID" id "" + if idname + return idname + / + + calc idname add "id_" id + return idname / emitln data: @@ -14,11 +16,6 @@ emitln data: emit eol / -increaseindent indent: - calc indent add indent " " - return indent -/ - lexident: declare char declare isbeforea @@ -41,6 +38,22 @@ lexident: return word / +skipchar exp: + declare act + declare lineno + declare colno + calc act peek + calc lineno stdinlineno + calc colno stdincolno + check eq exp act : "Unexpected character" act "expected" exp "at" lineno colno + skip +/ + +increaseindent indent: + calc indent add indent " " + return indent +/ + parseconststring: declare char declare iseof @@ -66,16 +79,18 @@ parseconststring: / parseexprvarref: + declare varid declare varname calc varname lexident - emit "var_" - emit varname + calc varid registerid varname + emit varid return / parseexprcall: declare char declare first + declare funcid declare funcname declare isspace declare isnotspace @@ -84,7 +99,9 @@ parseexprcall: declare isquote declare isnotquote calc funcname lexident - emit funcname + check mapgetkey "FUNCREG" funcname "" : "Function" funcname "does not exist" + calc funcid registerid funcname + emit funcid emit "(" set first "1" forever @@ -116,12 +133,14 @@ parseexprcall: / parsestatdeclare indent: - declare var + declare varid + declare varname skipchar " " - calc var lexident + calc varname lexident + calc varid registerid varname emit indent - emit "char * var_" - emit var + emit "char * " + emit varid emit ";" emit eol skipchar eol @@ -129,13 +148,14 @@ parsestatdeclare indent: / parsestatset indent: - declare var + declare varid + declare varname skipchar " " - calc var lexident + calc varname lexident + calc varid registerid varname skipchar " " emit indent - emit "var_" - emit var + emit varid emit " = " parseconststring emit ";" @@ -145,13 +165,14 @@ parsestatset indent: / parsestatcalc indent: - declare var + declare varid + declare varname skipchar " " - calc var lexident + calc varname lexident + calc varid registerid varname skipchar " " emit indent - emit "var_" - emit var + emit varid emit " = " parseexprcall emit ";" @@ -235,6 +256,7 @@ parsestatreturn indent: parsestatcheck indent: declare char + declare funcid declare funcname declare iscolon declare iseol @@ -247,7 +269,8 @@ parsestatcheck indent: emit "if( 0 == strlen(" calc funcname lexident - emit funcname + calc funcid registerid funcname + emit funcid emit "(" set notfirst "" @@ -325,7 +348,7 @@ parsestatcheck indent: emit quote emit "%s" emit quote - emit ", var_eol" + emit ", __EOL" emitln ");" emit indent @@ -335,16 +358,18 @@ parsestatcheck indent: / parsestattrace indent: + declare varid declare varname emit indent - emit "trace(" + emit "__trace(" emit quote skipchar " " calc varname lexident + calc varid registerid varname emit varname emit quote - emit ", var_" - emit varname + emit ", " + emit varid emitln ");" skipchar eol return @@ -352,6 +377,7 @@ parsestattrace indent: parsestat indent: declare call + declare callid declare char declare first declare iscall @@ -408,8 +434,10 @@ parsestat indent: parsestattrace indent return / + check mapgetkey "FUNCREG" call "" : "Function" call "does not exist" + calc callid registerid call emit indent - emit call + emit callid emit "(" set first "1" forever @@ -423,17 +451,17 @@ parsestat indent: calc char peek calc isquote eq char quote calc isnotquote not isquote + calc isfirst eq first "1" + calc isnotfirst not isfirst + if isnotfirst + emit ", " + / if isquote parseconststring / if isnotquote parseexprvarref / - calc isfirst eq first "1" - calc isnotfirst not isfirst - if isnotfirst - emit ", " - / set first "0" / skipchar eol @@ -483,6 +511,7 @@ parseblock indent: parsefunc: declare char declare first + declare funcid declare funcname declare iseoblock declare isfirst @@ -491,18 +520,14 @@ parsefunc: declare isspace declare isnotfirst declare isnotspace - declare var + declare varid + declare varname calc funcname lexident - calc ismain eq funcname "main" - calc isnotmain not ismain + mapsetkey "FUNCREG" funcname "1" + calc funcid registerid funcname trace funcname emit "char * " - if ismain - emit "__main" - / - if isnotmain - emit funcname - / + emit funcid emit "(" set first "1" forever @@ -513,14 +538,15 @@ parsefunc: break / skip - calc var lexident + calc varname lexident + calc varid registerid varname calc isfirst eq first "1" calc isnotfirst not isfirst if isnotfirst emit ", " / - emit "char * var_" - emit var + emit "char * " + emit varid set first "0" / calc char peek @@ -548,28 +574,28 @@ emitheader: emitln "#include " emitln "" emitln "" - emitln "char var_eof[2] = {0xFF, 0};" - emitln "char var_eol[2] = {10, 0};" - emitln "char var_quote[2] = {34, 0};" - emitln "char var_false[1] = {0};" - emitln "char var_true[2] = {'1', 0};" + emitln "char __EOF[2] = {0xFF, 0};" + emitln "char __EOL[2] = {10, 0};" + emitln "char __QUOTE[2] = {34, 0};" + emitln "char __FALSE[1] = {0};" + emitln "char __TRUE[2] = {'1', 0};" emitln "" emitln "" - emitln "char * eq(char * a, char * b)" + emitln "char * __eq(char * a, char * b)" emitln "{" - emitln " return (strcmp(a, b) == 0) ? var_true : var_false;" + emitln " return (strcmp(a, b) == 0) ? __TRUE : __FALSE;" emitln "}" emitln "" - emitln "char * lt(char * a, char * b)" + emitln "char * __lt(char * a, char * b)" emitln "{" - emitln " return (strcmp(a, b) < 0) ? var_true : var_false;" + emitln " return (strcmp(a, b) < 0) ? __TRUE : __FALSE;" emitln "}" - emitln "char * not(char * a)" + emitln "char * __not(char * a)" emitln "{" - emitln " return (strcmp(a, var_true) != 0) ? var_true : var_false;" + emitln " return (0 == strlen(a)) ? __TRUE : __FALSE;" emitln "}" emitln "" - emitln "char * add(char * lft, char * rgt)" + emitln "char * __add(char * lft, char * rgt)" emitln "{" emitln " int lft_len = strlen(lft);" emitln " int rgt_len = strlen(rgt);" @@ -580,13 +606,13 @@ emitheader: emitln " return res;" emitln "}" emitln "" - emitln "char * emit(char * str)" + emitln "char * __emit(char * str)" emitln "{" emitln " fputs(str, stdout);" emitln " return 0;" emitln "}" emitln "" - emitln "char * trace(char * var_name, char * var_value)" + emitln "char * __trace(char * var_name, char * var_value)" emitln "{" emit " const char * env_trace = getenv(" emit quote @@ -601,7 +627,7 @@ emitheader: emit quote emitln ", stderr);" emitln " fputs(var_value, stderr);" - emitln " fputs(var_eol, stderr);" + emitln " fputs(__EOL, stderr);" emitln " return 0;" emitln "}" emitln "" @@ -617,13 +643,13 @@ emitheader: emitln " return res;" emitln "}" emitln "" - emitln "char * peek()" + emitln "char * __peek()" emitln "{" emitln " if( !STDINPEEK ) STDINPEEK = _readchar(); // First byte read" emitln " return STDINPEEK;" emitln "}" emitln "" - emitln "void skip()" + emitln "void __skip()" emitln "{" emitln " if( !STDINPEEK ) STDINPEEK = _readchar(); // First byte read, not even peek()'d" emitln " if( STDINPEEK[0] == 10 ) {" @@ -634,7 +660,7 @@ emitheader: emitln " STDINPEEK = _readchar();" emitln "}" emitln "" - emitln "char * stdinlineno()" + emitln "char * __stdinlineno()" emitln "{" emitln " char * res = malloc(8*sizeof(char));" emit " sprintf(res, " @@ -645,7 +671,7 @@ emitheader: emitln " return res;" emitln "}" emitln "" - emitln "char * stdincolno()" + emitln "char * __stdincolno()" emitln "{" emitln " char * res = malloc(8*sizeof(char));" emit " sprintf(res, " @@ -656,12 +682,135 @@ emitheader: emitln " return res;" emitln "}" emitln "" + emitln "struct KEYVALUE" + emitln "{" + emitln " char * key;" + emitln " char * value;" + emitln " struct KEYVALUE * nextkeyvalue;" + emitln "};" + emitln "" + emitln "struct MAP" + emitln "{" + emitln " char * mapname;" + emitln " struct KEYVALUE * firstkeyvalue;" + emitln " struct MAP * nextmap;" + emitln "};" + emitln "" + emitln "struct MAP * MAPSTORE = 0;" + emitln "" + emitln "struct MAP * __map_get(char * mapname, int create)" + emitln "{" + emitln " struct MAP *prevmap, *map;" + emitln "" + emitln " prevmap = 0;" + emitln " map = MAPSTORE;" + emitln " while( map ) {" + emitln " if( strcmp(mapname, map->mapname) == 0) break;" + emitln " prevmap = map;" + emitln " map = map->nextmap;" + emitln " }" + emitln "" + emitln " if( map ) {" + emitln " return map;" + emitln " }" + emitln "" + emitln " if( !create ) {" + emitln " return 0;" + emitln " }" + emitln "" + emitln " map = malloc(sizeof(struct MAP));" + emitln " map->mapname = mapname;" + emitln " map->firstkeyvalue = 0;" + emitln " map->nextmap = 0;" + emitln " if( prevmap == 0) {" + emitln " MAPSTORE = map;" + emitln " } else {" + emitln " prevmap->nextmap = map;" + emitln " }" + emitln "" + emitln " return map;" + emitln "}" + emitln "" + emitln "struct KEYVALUE * __map_keyvalue_get(struct MAP * map, char * key, int create)" + emitln "{" + emitln " struct KEYVALUE *prevkeyvalue, *keyvalue;" + emitln "" + emitln " prevkeyvalue = 0;" + emitln " keyvalue = map->firstkeyvalue;" + emitln " while( keyvalue ) {" + emitln " if( strcmp(key, keyvalue->key) == 0) break;" + emitln " prevkeyvalue = keyvalue;" + emitln " keyvalue = keyvalue->nextkeyvalue;" + emitln " }" + emitln "" + emitln " if( keyvalue ) {" + emitln " return keyvalue;" + emitln " }" + emitln "" + emitln " if( !create ) {" + emitln " return 0;" + emitln " }" + emitln "" + emitln " keyvalue = malloc(sizeof(struct KEYVALUE));" + emitln " keyvalue->key = key;" + emitln " keyvalue->nextkeyvalue = 0;" + emitln " if( prevkeyvalue == 0) {" + emitln " map->firstkeyvalue = keyvalue;" + emitln " } else {" + emitln " prevkeyvalue->nextkeyvalue = keyvalue;" + emitln " }" + emitln "" + emitln " return keyvalue;" + emitln "}" + emitln "" + emitln "char * __mapclear(char * mapname)" + emitln "{" + emitln " struct MAP * map = __map_get(mapname, 0);" + emitln " if( map ) {" + emitln " map->firstkeyvalue = 0;" + emitln " }" + emitln "" + emit " return " + emit quote + emit quote + emitln ";" + emitln "}" + emitln "" + emitln "char * __mapgetkey(char * mapname, char * key, char * def)" + emitln "{" + emitln " struct MAP * map = __map_get(mapname, 0);" + emitln " if( !map ) return def;" + emitln "" + emitln " struct KEYVALUE *keyvalue = __map_keyvalue_get(map, key, 0);" + emitln " if( !keyvalue ) return def;" + emitln "" + emitln " return keyvalue->value;" + emitln "}" + emitln "" + emitln "char * __mapsetkey(char * mapname, char * key, char * value)" + emitln "{" + emitln " struct MAP *map = __map_get(mapname, 1);" + emitln " struct KEYVALUE *keyvalue = __map_keyvalue_get(map, key, 1);" + emitln " keyvalue->value = value;" + emit " return " + emit quote + emit quote + emitln ";" + emitln "}" + emitln "" + emitln "// ### END OF RUNTIME ### //" + emitln "" return / emitfooter: + declare mainid + calc mainid registerid "main" + emitln "int main() {" - emitln " __main();" + emit " " + emit mainid + emitln "();" emitln " return 0;" emitln "}" return @@ -672,7 +821,38 @@ main: declare iseof declare iseol declare isnoteol + emitheader + + mapsetkey "REGISTERID" "eof" "__EOF" + mapsetkey "REGISTERID" "eol" "__EOL" + mapsetkey "REGISTERID" "quote" "__QUOTE" + + mapsetkey "FUNCREG" "add" "1" + mapsetkey "REGISTERID" "add" "__add" + mapsetkey "FUNCREG" "emit" "1" + mapsetkey "REGISTERID" "emit" "__emit" + mapsetkey "FUNCREG" "eq" "1" + mapsetkey "REGISTERID" "eq" "__eq" + mapsetkey "FUNCREG" "lt" "1" + mapsetkey "REGISTERID" "lt" "__lt" + mapsetkey "FUNCREG" "not" "1" + mapsetkey "REGISTERID" "not" "__not" + mapsetkey "FUNCREG" "mapclear" "1" + mapsetkey "REGISTERID" "mapclear" "__mapclear" + mapsetkey "FUNCREG" "mapgetkey" "1" + mapsetkey "REGISTERID" "mapgetkey" "__mapgetkey" + mapsetkey "FUNCREG" "mapsetkey" "1" + mapsetkey "REGISTERID" "mapsetkey" "__mapsetkey" + mapsetkey "FUNCREG" "peek" "1" + mapsetkey "REGISTERID" "peek" "__peek" + mapsetkey "FUNCREG" "skip" "1" + mapsetkey "REGISTERID" "skip" "__skip" + mapsetkey "FUNCREG" "stdincolno" "1" + mapsetkey "REGISTERID" "stdincolno" "__stdincolno" + mapsetkey "FUNCREG" "stdinlineno" "1" + mapsetkey "REGISTERID" "stdinlineno" "__stdinlineno" + forever calc char peek calc iseof eq char eof diff --git a/README.md b/README.md index 1ddb987..24a3656 100644 --- a/README.md +++ b/README.md @@ -155,6 +155,29 @@ Return true if the given strings are the same. Return true if a would sort before b. +#### mapclear mapname + +Maps are global and can be used from any function. + +Clears all values set in the map named `mapname`. + +#### mapgetkey mapname key + +Maps are global and can be used from any function. + +Looks up `key` in the map named `mapname` and returns it. +If not found, returns an empty string. + +#### mapsetkey mapname key value + +Maps are global and can be used from any function. + +Adds a mapping from `key` to `value` to the map named `mapname`. + +#### not a + +Returns "1" if a is empty; otherwise, returns "". + #### peek Checks stdin for the next character and returns it. diff --git a/tests/Makefile b/tests/Makefile index d2eee94..15be89e 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -6,6 +6,7 @@ PYVERSION=3.12 PYPREFIX=/usr CYTHON=cython3 CC=gcc +CFLAGS=-ggdb all: verify-results @@ -38,17 +39,17 @@ clean: $(MAKE) -C ../0-lang0py build/%.it0.py: %.lang0 ../0-lang0py/lang0py.exe - cat $< | ../0-lang0py/lang0py.exe > $@.tmp + -cat $< | ../0-lang0py/lang0py.exe > $@.tmp 2> build/$*.it0.cmperr mv $@.tmp $@ build/%.it0.c: build/%.it0.py $(CYTHON) -3 --embed -o $@ $^ build/%.it0.o: build/%.it0.c - $(CC) -o $@ -c $^ -I$(PYPREFIX)/include/python$(PYVERSION) + $(CC) $(CFLAGS) -o $@ -c $^ -I$(PYPREFIX)/include/python$(PYVERSION) build/%.it0: build/%.it0.o - $(CC) -o $@ $^ -lpython$(PYVERSION) + $(CC) $(CFLAGS) -o $@ $^ -lpython$(PYVERSION) ### # it1 @@ -57,17 +58,17 @@ build/%.it0: build/%.it0.o $(MAKE) -C ../1-lang0py build/%.it1.py: %.lang0 ../1-lang0py/lang0py.exe - cat $< | ../1-lang0py/lang0py.exe > $@.tmp + -cat $< | ../1-lang0py/lang0py.exe > $@.tmp 2> build/$*.it1.cmperr mv $@.tmp $@ build/%.it1.c: build/%.it1.py $(CYTHON) -3 --embed -o $@ $^ build/%.it1.o: build/%.it1.c - $(CC) -o $@ -c $^ -I$(PYPREFIX)/include/python$(PYVERSION) + $(CC) $(CFLAGS) -o $@ -c $^ -I$(PYPREFIX)/include/python$(PYVERSION) build/%.it1: build/%.it1.o - $(CC) -o $@ $^ -lpython$(PYVERSION) + $(CC) $(CFLAGS) -o $@ $^ -lpython$(PYVERSION) ### # it2 @@ -76,11 +77,11 @@ build/%.it1: build/%.it1.o $(MAKE) -C ../2-lang0c build/%.it2.c: %.lang0 ../2-lang0c/lang0c.exe - cat $< | ../2-lang0c/lang0c.exe > $@.tmp + -cat $< | ../2-lang0c/lang0c.exe > $@.tmp 2> build/$*.it2.cmperr mv $@.tmp $@ build/%.it2.o: build/%.it2.c - $(CC) -o $@ -c $^ -I$(PYPREFIX)/include/python$(PYVERSION) + $(CC) $(CFLAGS) -o $@ -c $^ -I$(PYPREFIX)/include/python$(PYVERSION) build/%.it2: build/%.it2.o - $(CC) -o $@ $^ -lpython$(PYVERSION) + $(CC) $(CFLAGS) -o $@ $^ -lpython$(PYVERSION) diff --git a/tests/build/test_builtins/.gitignore b/tests/build/test_builtins/.gitignore index 12ad130..74aeb99 100644 --- a/tests/build/test_builtins/.gitignore +++ b/tests/build/test_builtins/.gitignore @@ -1,5 +1,6 @@ /*.it0 /*.it0.c +/*.it0.cmperr /*.it0.o /*.it0.py /*.it0.py.tmp @@ -8,6 +9,7 @@ /*.it0.stdout /*.it1 /*.it1.c +/*.it1.cmperr /*.it1.o /*.it1.py /*.it1.py.tmp @@ -16,6 +18,7 @@ /*.it1.stdout /*.it2 /*.it2.c +/*.it2.cmperr /*.it2.c.tmp /*.it2.o /*.it2.result diff --git a/tests/build/test_flow_control/.gitignore b/tests/build/test_flow_control/.gitignore index 12ad130..74aeb99 100644 --- a/tests/build/test_flow_control/.gitignore +++ b/tests/build/test_flow_control/.gitignore @@ -1,5 +1,6 @@ /*.it0 /*.it0.c +/*.it0.cmperr /*.it0.o /*.it0.py /*.it0.py.tmp @@ -8,6 +9,7 @@ /*.it0.stdout /*.it1 /*.it1.c +/*.it1.cmperr /*.it1.o /*.it1.py /*.it1.py.tmp @@ -16,6 +18,7 @@ /*.it1.stdout /*.it2 /*.it2.c +/*.it2.cmperr /*.it2.c.tmp /*.it2.o /*.it2.result diff --git a/tests/build/test_parsing/.gitignore b/tests/build/test_parsing/.gitignore index 12ad130..74aeb99 100644 --- a/tests/build/test_parsing/.gitignore +++ b/tests/build/test_parsing/.gitignore @@ -1,5 +1,6 @@ /*.it0 /*.it0.c +/*.it0.cmperr /*.it0.o /*.it0.py /*.it0.py.tmp @@ -8,6 +9,7 @@ /*.it0.stdout /*.it1 /*.it1.c +/*.it1.cmperr /*.it1.o /*.it1.py /*.it1.py.tmp @@ -16,6 +18,7 @@ /*.it1.stdout /*.it2 /*.it2.c +/*.it2.cmperr /*.it2.c.tmp /*.it2.o /*.it2.result diff --git a/tests/build/test_stdlib_constants/.gitignore b/tests/build/test_stdlib_constants/.gitignore index 12ad130..74aeb99 100644 --- a/tests/build/test_stdlib_constants/.gitignore +++ b/tests/build/test_stdlib_constants/.gitignore @@ -1,5 +1,6 @@ /*.it0 /*.it0.c +/*.it0.cmperr /*.it0.o /*.it0.py /*.it0.py.tmp @@ -8,6 +9,7 @@ /*.it0.stdout /*.it1 /*.it1.c +/*.it1.cmperr /*.it1.o /*.it1.py /*.it1.py.tmp @@ -16,6 +18,7 @@ /*.it1.stdout /*.it2 /*.it2.c +/*.it2.cmperr /*.it2.c.tmp /*.it2.o /*.it2.result diff --git a/tests/build/test_stdlib_functions/.gitignore b/tests/build/test_stdlib_functions/.gitignore index 12ad130..74aeb99 100644 --- a/tests/build/test_stdlib_functions/.gitignore +++ b/tests/build/test_stdlib_functions/.gitignore @@ -1,5 +1,6 @@ /*.it0 /*.it0.c +/*.it0.cmperr /*.it0.o /*.it0.py /*.it0.py.tmp @@ -8,6 +9,7 @@ /*.it0.stdout /*.it1 /*.it1.c +/*.it1.cmperr /*.it1.o /*.it1.py /*.it1.py.tmp @@ -16,6 +18,7 @@ /*.it1.stdout /*.it2 /*.it2.c +/*.it2.cmperr /*.it2.c.tmp /*.it2.o /*.it2.result diff --git a/tests/build/test_validation/.gitignore b/tests/build/test_validation/.gitignore new file mode 100644 index 0000000..74aeb99 --- /dev/null +++ b/tests/build/test_validation/.gitignore @@ -0,0 +1,26 @@ +/*.it0 +/*.it0.c +/*.it0.cmperr +/*.it0.o +/*.it0.py +/*.it0.py.tmp +/*.it0.result +/*.it0.stderr +/*.it0.stdout +/*.it1 +/*.it1.c +/*.it1.cmperr +/*.it1.o +/*.it1.py +/*.it1.py.tmp +/*.it1.result +/*.it1.stderr +/*.it1.stdout +/*.it2 +/*.it2.c +/*.it2.cmperr +/*.it2.c.tmp +/*.it2.o +/*.it2.result +/*.it2.stderr +/*.it2.stdout diff --git a/tests/build/test_variables/.gitignore b/tests/build/test_variables/.gitignore index 12ad130..74aeb99 100644 --- a/tests/build/test_variables/.gitignore +++ b/tests/build/test_variables/.gitignore @@ -1,5 +1,6 @@ /*.it0 /*.it0.c +/*.it0.cmperr /*.it0.o /*.it0.py /*.it0.py.tmp @@ -8,6 +9,7 @@ /*.it0.stdout /*.it1 /*.it1.c +/*.it1.cmperr /*.it1.o /*.it1.py /*.it1.py.tmp @@ -16,6 +18,7 @@ /*.it1.stdout /*.it2 /*.it2.c +/*.it2.cmperr /*.it2.c.tmp /*.it2.o /*.it2.result diff --git a/tests/generate-recipes.py b/tests/generate-recipes.py index 16e511a..164185f 100644 --- a/tests/generate-recipes.py +++ b/tests/generate-recipes.py @@ -2,6 +2,12 @@ import glob import os import sys +STAGE0_MAP = { + 'it0': '.py', + 'it1': '.py', + 'it2': '.c', +} + class Rule: def __init__(self, target: str, prerequisites: list[str], recipe: list[str]) -> None: self.target = target @@ -23,15 +29,25 @@ def make_rules(file_path, lang0it): result: list[Rule] = [] stdin = file_path.replace('.lang0', '.stdin') - exp_stdout = file_path.replace('.lang0', '.exp.stdout') + exp_cmperr = file_path.replace('.lang0', '.exp.cmperr') exp_stderr = file_path.replace('.lang0', '.exp.stderr') + exp_stdout = file_path.replace('.lang0', '.exp.stdout') + + act_cmperr = 'build/' + file_path.replace('.lang0', f'.{lang0it}.cmperr') - act_result = 'build/' + file_path.replace('.lang0', f'.{lang0it}.result') act_stderr = 'build/' + file_path.replace('.lang0', f'.{lang0it}.stderr') act_stdout = 'build/' + file_path.replace('.lang0', f'.{lang0it}.stdout') + + act_result = 'build/' + file_path.replace('.lang0', f'.{lang0it}.result') program = 'build/' + file_path.replace('.lang0', f'.{lang0it}') - if os.path.isfile(exp_stdout) or os.path.isfile(exp_stderr): + program_stage0 = program + STAGE0_MAP[lang0it] + + if os.path.isfile(exp_cmperr): + # No need to try to run the program + exp_list = [exp_cmperr] + act_list = [act_cmperr] + elif os.path.isfile(exp_stdout) or os.path.isfile(exp_stderr): result.append(Rule( act_stdout, [program] + ([stdin] if os.path.isfile(stdin) else []), @@ -41,12 +57,14 @@ def make_rules(file_path, lang0it): ] )) - exp_list = [exp_stdout, exp_stderr] - act_list = [act_stdout, act_stderr] + exp_list = [exp_stdout, exp_stderr] + act_list = [act_stdout, act_stderr] + else: + assert False, f'Missing expectations for {file_path}' result.append(Rule( act_result, - [act_stdout] + [ + ([program_stage0] if os.path.isfile(exp_cmperr) else [act_stdout]) + [ x for x in exp_list if os.path.isfile(x) @@ -64,8 +82,6 @@ def make_rules(file_path, lang0it): ] )) - assert result[-1].prerequisites, f'Missing expectations for {file_path}' - return result def main(program, write_to, *lang0it): diff --git a/tests/test_parsing/test_target_reserved_names.exp.stdout b/tests/test_parsing/test_target_reserved_names.exp.stdout new file mode 100644 index 0000000..9d60796 --- /dev/null +++ b/tests/test_parsing/test_target_reserved_names.exp.stdout @@ -0,0 +1 @@ +11 \ No newline at end of file diff --git a/tests/test_parsing/test_target_reserved_names.lang0 b/tests/test_parsing/test_target_reserved_names.lang0 new file mode 100644 index 0000000..7029417 --- /dev/null +++ b/tests/test_parsing/test_target_reserved_names.lang0 @@ -0,0 +1,8 @@ +main: + declare assert + declare class + set assert "1" + set class "1" + emit assert + emit class +/ diff --git a/tests/test_stdlib_functions/test_map.exp.stdout b/tests/test_stdlib_functions/test_map.exp.stdout new file mode 100644 index 0000000..345cea8 --- /dev/null +++ b/tests/test_stdlib_functions/test_map.exp.stdout @@ -0,0 +1,14 @@ +TESTMAP.abc0: def +OTHERMAP.abc0: def +TESTMAP.abc0: blue +TESTMAP.abc1: green +TESTMAP.abc2: def +OTHERMAP.abc0: blue +OTHERMAP.abc1: green +OTHERMAP.abc2: def +TESTMAP.abc0: def +TESTMAP.abc1: def +TESTMAP.abc2: def +OTHERMAP.abc0: blue +OTHERMAP.abc1: green +OTHERMAP.abc2: def diff --git a/tests/test_stdlib_functions/test_map.lang0 b/tests/test_stdlib_functions/test_map.lang0 new file mode 100644 index 0000000..ccb0e46 --- /dev/null +++ b/tests/test_stdlib_functions/test_map.lang0 @@ -0,0 +1,36 @@ +print mapname key: + declare value + calc value mapgetkey mapname key "def" + emit mapname + emit "." + emit key + emit ": " + emit value + emit eol +/ + +main: + print "TESTMAP" "abc0" + print "OTHERMAP" "abc0" + + mapsetkey "TESTMAP" "abc0" "blue" + mapsetkey "TESTMAP" "abc1" "green" + mapsetkey "OTHERMAP" "abc0" "blue" + mapsetkey "OTHERMAP" "abc1" "green" + + print "TESTMAP" "abc0" + print "TESTMAP" "abc1" + print "TESTMAP" "abc2" + print "OTHERMAP" "abc0" + print "OTHERMAP" "abc1" + print "OTHERMAP" "abc2" + + mapclear "TESTMAP" + + print "TESTMAP" "abc0" + print "TESTMAP" "abc1" + print "TESTMAP" "abc2" + print "OTHERMAP" "abc0" + print "OTHERMAP" "abc1" + print "OTHERMAP" "abc2" +/ diff --git a/tests/test_stdlib_functions/test_not.exp.stdout b/tests/test_stdlib_functions/test_not.exp.stdout new file mode 100644 index 0000000..8fdf547 --- /dev/null +++ b/tests/test_stdlib_functions/test_not.exp.stdout @@ -0,0 +1,4 @@ +not == 1 +not a == +not 1 == +not -1 == diff --git a/tests/test_stdlib_functions/test_not.lang0 b/tests/test_stdlib_functions/test_not.lang0 new file mode 100644 index 0000000..cff4dad --- /dev/null +++ b/tests/test_stdlib_functions/test_not.lang0 @@ -0,0 +1,16 @@ +test a: + declare var + calc var not a + emit "not " + emit a + emit " == " + emit var + emit eol +/ + +main: + test "" + test "a" + test "1" + test "-1" +/ diff --git a/tests/test_validation/test_undefined_call.exp.cmperr b/tests/test_validation/test_undefined_call.exp.cmperr new file mode 100644 index 0000000..fc0f546 --- /dev/null +++ b/tests/test_validation/test_undefined_call.exp.cmperr @@ -0,0 +1 @@ +ERROR: Function funca does not exist diff --git a/tests/test_validation/test_undefined_call.lang0 b/tests/test_validation/test_undefined_call.lang0 new file mode 100644 index 0000000..42622b6 --- /dev/null +++ b/tests/test_validation/test_undefined_call.lang0 @@ -0,0 +1,4 @@ +main: + declare var + calc var funca "1" +/ diff --git a/tests/test_validation/test_undefined_function.exp.cmperr b/tests/test_validation/test_undefined_function.exp.cmperr new file mode 100644 index 0000000..3f8f388 --- /dev/null +++ b/tests/test_validation/test_undefined_function.exp.cmperr @@ -0,0 +1 @@ +ERROR: Function routine does not exist diff --git a/tests/test_validation/test_undefined_function.lang0 b/tests/test_validation/test_undefined_function.lang0 new file mode 100644 index 0000000..480e7c7 --- /dev/null +++ b/tests/test_validation/test_undefined_function.lang0 @@ -0,0 +1,3 @@ +main: + routine "1" +/