Compare commits

..

1 Commits

Author SHA1 Message Date
Johan B.W. de Vries
c318c780da Start on llvm IR target 2025-05-03 16:54:10 +02:00
88 changed files with 450 additions and 1342 deletions

View File

@ -2,14 +2,14 @@ import os
import sys import sys
def emit(string): def emit(string):
sys.stdout.buffer.write(string.encode('latin_1')) sys.stdout.write(string)
sys.stdout.flush() sys.stdout.flush()
def trace(header, value): def trace(header, value):
if os.environ.get('TRACE'): if os.environ.get('TRACE'):
sys.stderr.write(f'{header}={value!r}\n') sys.stderr.write(f'{header}={value!r}\n')
eof = chr(0xFF) eof = chr(0)
eol = chr(10) eol = chr(10)
quote = chr(34) quote = chr(34)
PEEK = None PEEK = None
@ -39,36 +39,6 @@ def skip():
PEEK = None 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): def emitln(data):
emit(data) emit(data)
emit(eol) emit(eol)
@ -111,15 +81,12 @@ def parseconststring():
emit(quote) emit(quote)
def parseexprvarref(): def parseexprvarref():
varname = lexident() var = lexident()
varid = registerid(varname) emit(var)
emit(varid)
def parseexprcall(): def parseexprcall():
funcname = lexident() funcname = lexident()
__check(mapgetkey, ["FUNCREG", funcname, ""], ["Function", funcname, "does not exist"]) emit(funcname)
funcid = registerid(funcname)
emit(funcid)
emit('(') emit('(')
first = True first = True
@ -142,12 +109,11 @@ def parsestatdeclare(indent):
def parsestatset(indent): def parsestatset(indent):
skipchar(' ') skipchar(' ')
varname = lexident() var = lexident()
varid = registerid(varname)
skipchar(' ') skipchar(' ')
emit(' ' * indent) emit(' ' * indent)
emit(varid) emit(var)
emit(' = ') emit(' = ')
parseconststring() parseconststring()
@ -157,12 +123,11 @@ def parsestatset(indent):
def parsestatcalc(indent): def parsestatcalc(indent):
skipchar(' ') skipchar(' ')
varname = lexident() var = lexident()
varid = registerid(varname)
skipchar(' ') skipchar(' ')
emit(' ' * indent) emit(' ' * indent)
emit(varid) emit(var)
emit(' = ') emit(' = ')
parseexprcall() parseexprcall()
@ -201,21 +166,17 @@ def parsestatreturn(indent):
parseconststring() parseconststring()
else: else:
parseexprvarref() parseexprvarref()
else:
emit('""')
emit(eol) emit(eol)
skipchar(eol) skipchar(eol)
def parsestatcheck(indent): def parsestatcheck(indent):
skipchar(' ') skipchar(' ')
emit(' ' * indent) emit(' ' * indent)
emit('__check(') emit('assert ')
funcname = lexident() func_name = lexident()
funcid = registerid(funcname) emit(func_name)
trace("funcid", funcid) emit('(')
emit(funcid)
emit(', [')
notfirst = False notfirst = False
while True: while True:
@ -236,7 +197,7 @@ def parsestatcheck(indent):
skipchar(':') skipchar(':')
emit('], [') emit('), (')
notfirst = False notfirst = False
while True: while True:
@ -253,21 +214,19 @@ def parsestatcheck(indent):
if eol == peek(): if eol == peek():
break break
notfirst = True notfirst = True
emitln(')')
emitln('])')
def parsestattrace(indent): def parsestattrace(indent):
skipchar(' ') skipchar(' ')
emit(' ' * indent) emit(' ' * indent)
emit('__trace("') emit('trace("')
varname = lexident() var_name = lexident()
varid = registerid(varname)
skipchar(eol) skipchar(eol)
emit(varname) emit(var_name)
emit('", ') emit('", ')
emit(varid) emit(var_name)
emitln(')') emitln(')')
def parsestat(indent): def parsestat(indent):
@ -310,12 +269,8 @@ def parsestat(indent):
parsestattrace(indent) parsestattrace(indent)
return return
__check(mapgetkey, ["FUNCREG", call, ""], ["Function", call, "does not exist"])
callid = registerid(call)
emit(' ' * indent) emit(' ' * indent)
emit(callid) emit(call)
emit('(') emit('(')
first = True first = True
@ -352,22 +307,19 @@ def parseblock(indent):
def parsefunc(): def parsefunc():
funcname = lexident() funcname = lexident()
funcid = registerid(funcname)
mapsetkey("FUNCREG", funcname, "1")
trace('funcname', funcname) trace('funcname', funcname)
emit('def ') emit('def ')
emit(funcid) emit(funcname)
emit('(') emit('(')
first = True first = True
while ' ' == peek(): while ' ' == peek():
skip() skip()
varname = lexident() var = lexident()
varid = registerid(varname)
if not first: if not first:
emit(", ") emit(", ")
emit(varid) emit(var)
first = False first = False
if '/' == peek(): if '/' == peek():
@ -392,26 +344,26 @@ def emitheader():
emitln("import os") emitln("import os")
emitln("import sys") emitln("import sys")
emitln("") emitln("")
emitln("def __eq(a: str, b: str) -> str:") emitln("def eq(a, b):")
emitln(" return '1' if a == b else ''") emitln(" return a == b")
emitln("") emitln("")
emitln("def __lt(a: str, b: str) -> str:") emitln("def lt(a, b):")
emitln(" return '1' if a < b else ''") emitln(" return a[0] < b[0]")
emitln("") emitln("")
emitln("def __add(a: str, b: str) -> str:") emitln("def addstringchar(a, b):")
emitln(" return a + b") emitln(" return a + b[0]")
emitln("") emitln("")
emitln("def __emit(string):") emitln("def emit(string):")
emitln(" sys.stdout.buffer.write(string.encode('latin_1'))") emitln(" sys.stdout.write(string)")
emitln(" sys.stdout.flush()") emitln(" sys.stdout.flush()")
emitln("") emitln("")
emitln("def __trace(header, value):") emitln("def trace(header, value):")
emitln(" if os.environ.get('TRACE'):") emitln(" if os.environ.get('TRACE'):")
emitln(" sys.stderr.write(f'{header}={value!r}\\n')") emitln(" sys.stderr.write(f'{header}={value!r}\\n')")
emitln("") emitln("")
emitln("__EOF = chr(0xFF)") emitln("eof = chr(0)")
emitln("__EOL = chr(10)") emitln("eol = chr(10)")
emitln("__QUOTE = chr(34)") emitln("quote = chr(34)")
emitln("") emitln("")
emitln("STDINCOLNO = 0") emitln("STDINCOLNO = 0")
emitln("STDINLINENO = 1") emitln("STDINLINENO = 1")
@ -419,106 +371,41 @@ def emitheader():
emitln("") emitln("")
emitln("def _readchar():") emitln("def _readchar():")
emitln(" char = sys.stdin.read(1)") emitln(" char = sys.stdin.read(1)")
emitln(" __trace('char', char)") emitln(" trace('char', char)")
emitln(" if not char:") emitln(" if not char:")
emitln(" return __EOF") emitln(" return eof")
emitln(" return char") emitln(" return char")
emitln("") emitln("")
emitln("def __peek():") emitln("def peek():")
emitln(" return STDINPEEK") emitln(" return STDINPEEK")
emitln("") emitln("")
emitln("def __skip():") emitln("def skip():")
emitln(" global STDINCOLNO") emitln(" global STDINCOLNO")
emitln(" global STDINLINENO") emitln(" global STDINLINENO")
emitln(" global STDINPEEK") emitln(" global STDINPEEK")
emitln(" if __EOL == STDINPEEK:") emitln(" if eol == STDINPEEK:")
emitln(" STDINLINENO += 1") emitln(" STDINLINENO += 1")
emitln(" STDINCOLNO = 0") emitln(" STDINCOLNO = 0")
emitln(" STDINCOLNO += 1") emitln(" STDINCOLNO += 1")
emitln(" STDINPEEK = _readchar()") emitln(" STDINPEEK = _readchar()")
emitln("") emitln("")
emitln("def __stdinlineno():") emitln("def stdinlineno():")
emitln(" global STDINLINENO") emitln(" global STDINLINENO")
emitln(" return str(STDINLINENO)") emitln(" return str(STDINLINENO)")
emitln("") emitln("")
emitln("def __stdincolno():") emitln("def stdincolno():")
emitln(" global STDINCOLNO") emitln(" global STDINCOLNO")
emitln(" return str(STDINCOLNO)") emitln(" return str(STDINCOLNO)")
emitln("") 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("") emitln("")
def emitfooter(): def emitfooter():
mainid = registerid("main") emit("if __name__ == '__main__':\n")
emitln("if __name__ == '__main__':") emit(" main()\n")
emit(" ")
emit(mainid)
emitln("()")
def main(): def main():
emitheader() 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: while True:
if eof == peek(): if eof == peek():
break break

View File

@ -36,8 +36,5 @@ lang0py.py: lang0py.lang0 lang0py2.exe
mv $@.tmp $@ mv $@.tmp $@
-diff lang0py2.py lang0py.py -diff lang0py2.py lang0py.py
$(LANG0PY): $(CURDIR)/../0-lang0py/lang0py.py $(CURDIR)/../0-lang0py/lang0py.lang0
cd ../0-lang0py && make lang0py.exe
clean: clean:
rm -f lang0py*.py lang0py*.c lang0py*.o lang0py*.exe rm -f lang0py*.py lang0py*.c lang0py*.o lang0py*.exe

View File

@ -1,14 +1,12 @@
registerid id: skipchar exp:
declare idname declare act
declare newidx declare lineno
declare colno
calc idname mapgetkey "REGISTERID" id "" calc act peek
if idname calc lineno stdinlineno
return idname calc colno stdincolno
/ check eq exp act : "Unexpected character" act "expected" exp "at" lineno colno
skip
calc idname add "id_" id
return idname
/ /
emitln data: emitln data:
@ -16,6 +14,14 @@ emitln data:
emit eol emit eol
/ /
increaseindent indent:
calc indent addstringchar indent " "
calc indent addstringchar indent " "
calc indent addstringchar indent " "
calc indent addstringchar indent " "
return indent
/
lexident: lexident:
declare word declare word
set word "" set word ""
@ -29,28 +35,12 @@ lexident:
if isafterz if isafterz
break break
/ /
calc word add word char calc word addstringchar word char
skip skip
/ /
return word 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: parseconststring:
skipchar quote skipchar quote
emit quote emit quote
@ -73,15 +63,12 @@ parseconststring:
parseexprvarref: parseexprvarref:
calc varname lexident calc varname lexident
calc varid registerid varname emit varname
emit varid
/ /
parseexprcall: parseexprcall:
calc funcname lexident calc funcname lexident
calc funcid registerid funcname emit funcname
check mapgetkey "FUNCREG" funcname "" : "Function" funcname "does not exist"
emit funcid
emit "(" emit "("
set first "1" set first "1"
forever forever
@ -113,18 +100,16 @@ parseexprcall:
parsestatdeclare indent: parsestatdeclare indent:
skipchar " " skipchar " "
calc varname lexident calc var lexident
calc varid registerid varname
skipchar eol skipchar eol
/ /
parsestatset indent: parsestatset indent:
skipchar " " skipchar " "
calc varname lexident calc var lexident
calc varid registerid varname
skipchar " " skipchar " "
emit indent emit indent
emit varid emit var
emit " = " emit " = "
parseconststring parseconststring
emit eol emit eol
@ -133,11 +118,10 @@ parsestatset indent:
parsestatcalc indent: parsestatcalc indent:
skipchar " " skipchar " "
calc varname lexident calc var lexident
calc varid registerid varname
skipchar " " skipchar " "
emit indent emit indent
emit varid emit var
emit " = " emit " = "
parseexprcall parseexprcall
emit eol emit eol
@ -176,7 +160,6 @@ parsestatreturn indent:
emit "return " emit "return "
calc char peek calc char peek
calc isspace eq char " " calc isspace eq char " "
calc isnotspace not isspace
if isspace if isspace
skip skip
calc char peek calc char peek
@ -189,10 +172,6 @@ parsestatreturn indent:
parseexprvarref parseexprvarref
/ /
/ /
if isnotspace
emit quote
emit quote
/
emit eol emit eol
skipchar eol skipchar eol
/ /
@ -207,12 +186,11 @@ parsestatcheck indent:
skipchar " " skipchar " "
emit indent emit indent
emit "__check(" emit "assert "
calc funcname lexident calc funcname lexident
calc funcid registerid funcname emit funcname
emit funcid emit "("
emit ", ["
set notfirst "" set notfirst ""
forever forever
@ -242,8 +220,7 @@ parsestatcheck indent:
skipchar ":" skipchar ":"
emit "], [" emit "), ("
set notfirst "" set notfirst ""
forever forever
@ -272,20 +249,19 @@ parsestatcheck indent:
set notfirst "1" set notfirst "1"
/ /
emitln "])" emitln ")"
/ /
parsestattrace indent: parsestattrace indent:
emit indent emit indent
emit "__trace(" emit "trace("
emit quote emit quote
skipchar " " skipchar " "
calc varname lexident calc varname lexident
calc varid registerid varname
emit varname emit varname
emit quote emit quote
emit ", " emit ", "
emit varid emit varname
emitln ")" emitln ")"
skipchar eol skipchar eol
/ /
@ -338,10 +314,8 @@ parsestat indent:
parsestatcheck indent parsestatcheck indent
return return
/ /
check mapgetkey "FUNCREG" call "" : "Function" call "does not exist"
calc callid registerid call
emit indent emit indent
emit callid emit call
emit "(" emit "("
set first "1" set first "1"
forever forever
@ -406,11 +380,9 @@ parseblock indent:
parsefunc: parsefunc:
calc funcname lexident calc funcname lexident
calc funcid registerid funcname
trace funcname trace funcname
mapsetkey "FUNCREG" funcname "1"
emit "def " emit "def "
emit funcid emit funcname
emit "(" emit "("
set isnotfirst "" set isnotfirst ""
forever forever
@ -421,12 +393,11 @@ parsefunc:
break break
/ /
skip skip
calc varname lexident calc var lexident
calc varid registerid varname
if isnotfirst if isnotfirst
emit ", " emit ", "
/ /
emit varid emit var
set isnotfirst "1" set isnotfirst "1"
/ /
calc char peek calc char peek
@ -450,31 +421,26 @@ emitheader:
emitln "import os" emitln "import os"
emitln "import sys" emitln "import sys"
emitln "" emitln ""
emitln "def __eq(a: str, b: str) -> str:" emitln "def eq(a, b):"
emitln " return '1' if a == b else ''" emitln " return a == b"
emitln "" emitln ""
emitln "def __lt(a: str, b: str) -> str:" emitln "def lt(a, b):"
emitln " return '1' if a < b else ''" emitln " return a[0] < b[0]"
emitln "" emitln ""
emitln "def __not(a: str) -> str:" emitln "def addstringchar(a, b):"
emitln " if a:" emitln " return a + b[0]"
emitln " return ''"
emitln " return '1'"
emitln "" emitln ""
emitln "def __add(a: str, b :str) -> str:" emitln "def emit(string):"
emitln " return a + b" emitln " sys.stdout.write(string)"
emitln ""
emitln "def __emit(string):"
emitln " sys.stdout.buffer.write(string.encode('latin_1'))"
emitln " sys.stdout.flush()" emitln " sys.stdout.flush()"
emitln "" emitln ""
emitln "def __trace(header, value):" emitln "def trace(header, value):"
emitln " if os.environ.get('TRACE'):" emitln " if os.environ.get('TRACE'):"
emitln " sys.stderr.write(f'{header}={value!r}\\n')" emitln " sys.stderr.write(f'{header}={value!r}\\n')"
emitln "" emitln ""
emitln "__EOF = chr(0xFF)" emitln "eof = chr(0)"
emitln "__EOL = chr(10)" emitln "eol = chr(10)"
emitln "__QUOTE = chr(34)" emitln "quote = chr(34)"
emitln "" emitln ""
emitln "STDINCOLNO = 0" emitln "STDINCOLNO = 0"
emitln "STDINLINENO = 1" emitln "STDINLINENO = 1"
@ -482,105 +448,43 @@ emitheader:
emitln "" emitln ""
emitln "def _readchar():" emitln "def _readchar():"
emitln " char = sys.stdin.read(1)" emitln " char = sys.stdin.read(1)"
emitln " __trace('char', char)" emitln " trace('char', char)"
emitln " if not char:" emitln " if not char:"
emitln " return __EOF" emitln " return eof"
emitln " return char" emitln " return char"
emitln "" emitln ""
emitln "def __peek():" emitln "def peek():"
emitln " return STDINPEEK" emitln " return STDINPEEK"
emitln "" emitln ""
emitln "def __skip():" emitln "def skip():"
emitln " global STDINCOLNO" emitln " global STDINCOLNO"
emitln " global STDINLINENO" emitln " global STDINLINENO"
emitln " global STDINPEEK" emitln " global STDINPEEK"
emitln " if __EOL == STDINPEEK:" emitln " if eol == STDINPEEK:"
emitln " STDINLINENO += 1" emitln " STDINLINENO += 1"
emitln " STDINCOLNO = 0" emitln " STDINCOLNO = 0"
emitln " STDINCOLNO += 1" emitln " STDINCOLNO += 1"
emitln " STDINPEEK = _readchar()" emitln " STDINPEEK = _readchar()"
emitln "" emitln ""
emitln "def __stdinlineno():" emitln "def stdinlineno():"
emitln " global STDINLINENO" emitln " global STDINLINENO"
emitln " return str(STDINLINENO)" emitln " return str(STDINLINENO)"
emitln "" emitln ""
emitln "def __stdincolno():" emitln "def stdincolno():"
emitln " global STDINCOLNO" emitln " global STDINCOLNO"
emitln " return str(STDINCOLNO)" emitln " return str(STDINCOLNO)"
emitln "" 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 "" emitln ""
/ /
emitfooter: emitfooter:
declare mainid
calc mainid registerid "main"
emitln "if __name__ == '__main__':" emitln "if __name__ == '__main__':"
emit " " emitln " main()"
emit mainid
emitln "()"
/ /
main: main:
emitheader 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 forever
calc char peek calc char peek
calc iseof eq char eof calc iseof eq char eof

View File

@ -1,14 +1,12 @@
registerid id: skipchar exp:
declare idname declare act
declare newidx declare lineno
declare colno
calc idname mapgetkey "REGISTERID" id "" calc act peek
if idname calc lineno stdinlineno
return idname calc colno stdincolno
/ check eq exp act : "Unexpected character" act "expected" exp "at" lineno colno
skip
calc idname add "id_" id
return idname
/ /
emitln data: emitln data:
@ -16,6 +14,14 @@ emitln data:
emit eol emit eol
/ /
increaseindent indent:
calc indent addstringchar indent " "
calc indent addstringchar indent " "
calc indent addstringchar indent " "
calc indent addstringchar indent " "
return indent
/
lexident: lexident:
declare char declare char
declare isbeforea declare isbeforea
@ -32,28 +38,12 @@ lexident:
if isafterz if isafterz
break break
/ /
calc word add word char calc word addstringchar word char
skip skip
/ /
return word 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: parseconststring:
declare char declare char
declare iseof declare iseof
@ -79,18 +69,16 @@ parseconststring:
/ /
parseexprvarref: parseexprvarref:
declare varid
declare varname declare varname
calc varname lexident calc varname lexident
calc varid registerid varname emit "var_"
emit varid emit varname
return return
/ /
parseexprcall: parseexprcall:
declare char declare char
declare first declare first
declare funcid
declare funcname declare funcname
declare isspace declare isspace
declare isnotspace declare isnotspace
@ -99,9 +87,7 @@ parseexprcall:
declare isquote declare isquote
declare isnotquote declare isnotquote
calc funcname lexident calc funcname lexident
check mapgetkey "FUNCREG" funcname "" : "Function" funcname "does not exist" emit funcname
calc funcid registerid funcname
emit funcid
emit "(" emit "("
set first "1" set first "1"
forever forever
@ -133,14 +119,12 @@ parseexprcall:
/ /
parsestatdeclare indent: parsestatdeclare indent:
declare varid declare var
declare varname
skipchar " " skipchar " "
calc varname lexident calc var lexident
calc varid registerid varname
emit indent emit indent
emit "char * " emit "char * var_"
emit varid emit var
emit ";" emit ";"
emit eol emit eol
skipchar eol skipchar eol
@ -148,14 +132,13 @@ parsestatdeclare indent:
/ /
parsestatset indent: parsestatset indent:
declare varid declare var
declare varname
skipchar " " skipchar " "
calc varname lexident calc var lexident
calc varid registerid varname
skipchar " " skipchar " "
emit indent emit indent
emit varid emit "var_"
emit var
emit " = " emit " = "
parseconststring parseconststring
emit ";" emit ";"
@ -165,14 +148,13 @@ parsestatset indent:
/ /
parsestatcalc indent: parsestatcalc indent:
declare varid declare var
declare varname
skipchar " " skipchar " "
calc varname lexident calc var lexident
calc varid registerid varname
skipchar " " skipchar " "
emit indent emit indent
emit varid emit "var_"
emit var
emit " = " emit " = "
parseexprcall parseexprcall
emit ";" emit ";"
@ -245,8 +227,7 @@ parsestatreturn indent:
/ /
/ /
if isnotspace if isnotspace
emit quote emit "0"
emit quote
/ /
emit ";" emit ";"
emit eol emit eol
@ -256,7 +237,6 @@ parsestatreturn indent:
parsestatcheck indent: parsestatcheck indent:
declare char declare char
declare funcid
declare funcname declare funcname
declare iscolon declare iscolon
declare iseol declare iseol
@ -269,8 +249,7 @@ parsestatcheck indent:
emit "if( 0 == strlen(" emit "if( 0 == strlen("
calc funcname lexident calc funcname lexident
calc funcid registerid funcname emit funcname
emit funcid
emit "(" emit "("
set notfirst "" set notfirst ""
@ -305,7 +284,6 @@ parsestatcheck indent:
emit indent emit indent
emitln "{" emitln "{"
emit indent
emit " fprintf(stderr, " emit " fprintf(stderr, "
emit quote emit quote
emit "%s" emit "%s"
@ -343,14 +321,6 @@ parsestatcheck indent:
/ /
/ /
emit indent
emit " fprintf(stderr, "
emit quote
emit "%s"
emit quote
emit ", __EOL"
emitln ");"
emit indent emit indent
emitln " exit(1);" emitln " exit(1);"
emit indent emit indent
@ -358,18 +328,16 @@ parsestatcheck indent:
/ /
parsestattrace indent: parsestattrace indent:
declare varid
declare varname declare varname
emit indent emit indent
emit "__trace(" emit "trace("
emit quote emit quote
skipchar " " skipchar " "
calc varname lexident calc varname lexident
calc varid registerid varname
emit varname emit varname
emit quote emit quote
emit ", " emit ", var_"
emit varid emit varname
emitln ");" emitln ");"
skipchar eol skipchar eol
return return
@ -377,7 +345,6 @@ parsestattrace indent:
parsestat indent: parsestat indent:
declare call declare call
declare callid
declare char declare char
declare first declare first
declare iscall declare iscall
@ -434,10 +401,8 @@ parsestat indent:
parsestattrace indent parsestattrace indent
return return
/ /
check mapgetkey "FUNCREG" call "" : "Function" call "does not exist"
calc callid registerid call
emit indent emit indent
emit callid emit call
emit "(" emit "("
set first "1" set first "1"
forever forever
@ -451,17 +416,17 @@ parsestat indent:
calc char peek calc char peek
calc isquote eq char quote calc isquote eq char quote
calc isnotquote not isquote calc isnotquote not isquote
calc isfirst eq first "1"
calc isnotfirst not isfirst
if isnotfirst
emit ", "
/
if isquote if isquote
parseconststring parseconststring
/ /
if isnotquote if isnotquote
parseexprvarref parseexprvarref
/ /
calc isfirst eq first "1"
calc isnotfirst not isfirst
if isnotfirst
emit ", "
/
set first "0" set first "0"
/ /
skipchar eol skipchar eol
@ -511,23 +476,17 @@ parseblock indent:
parsefunc: parsefunc:
declare char declare char
declare first declare first
declare funcid
declare funcname declare funcname
declare iseoblock declare iseoblock
declare isfirst declare isfirst
declare ismain
declare isnotmain
declare isspace declare isspace
declare isnotfirst declare isnotfirst
declare isnotspace declare isnotspace
declare varid declare var
declare varname
calc funcname lexident calc funcname lexident
mapsetkey "FUNCREG" funcname "1"
calc funcid registerid funcname
trace funcname trace funcname
emit "char * " emit "char * "
emit funcid emit funcname
emit "(" emit "("
set first "1" set first "1"
forever forever
@ -538,15 +497,14 @@ parsefunc:
break break
/ /
skip skip
calc varname lexident calc var lexident
calc varid registerid varname
calc isfirst eq first "1" calc isfirst eq first "1"
calc isnotfirst not isfirst calc isnotfirst not isfirst
if isnotfirst if isnotfirst
emit ", " emit ", "
/ /
emit "char * " emit "char * var_"
emit varid emit var
set first "0" set first "0"
/ /
calc char peek calc char peek
@ -574,45 +532,45 @@ emitheader:
emitln "#include <string.h>" emitln "#include <string.h>"
emitln "" emitln ""
emitln "" emitln ""
emitln "char __EOF[2] = {0xFF, 0};" emitln "char var_eof[2] = {-1, 0};"
emitln "char __EOL[2] = {10, 0};" emitln "char var_eol[2] = {10, 0};"
emitln "char __QUOTE[2] = {34, 0};" emitln "char var_quote[2] = {34, 0};"
emitln "char __FALSE[1] = {0};" emitln "char var_false[1] = {0};"
emitln "char __TRUE[2] = {'1', 0};" emitln "char var_true[2] = {'1', 0};"
emitln "" emitln ""
emitln "" emitln ""
emitln "char * __eq(char * a, char * b)" emitln "char * eq(char * a, char * b)"
emitln "{" emitln "{"
emitln " return (strcmp(a, b) == 0) ? __TRUE : __FALSE;" emitln " return (strcmp(a, b) == 0) ? var_true : var_false;"
emitln "}" emitln "}"
emitln "" emitln ""
emitln "char * __lt(char * a, char * b)" emitln "char * lt(char * a, char * b)"
emitln "{" emitln "{"
emitln " return (strcmp(a, b) < 0) ? __TRUE : __FALSE;" emitln " return (strcmp(a, b) < 0) ? var_true : var_false;"
emitln "}" emitln "}"
emitln "char * __not(char * a)" emitln "char * not(char * a)"
emitln "{" emitln "{"
emitln " return (0 == strlen(a)) ? __TRUE : __FALSE;" emitln " return (strcmp(a, var_true) != 0) ? var_true : var_false;"
emitln "}" emitln "}"
emitln "" emitln ""
emitln "char * __add(char * lft, char * rgt)" emitln "char * addstringchar(char * str, char * chr)"
emitln "{" emitln "{"
emitln " int lft_len = strlen(lft);" emitln " int str_len = strlen(str);"
emitln " int rgt_len = strlen(rgt);" emitln " assert(strlen(chr) == 1);"
emitln " char * res = malloc((lft_len + rgt_len + 1) * sizeof(char));" emitln " char * res = malloc((str_len + 2) * sizeof(char));"
emitln " strcpy(res, lft);" emitln " strcpy(res, str);"
emitln " strcpy(res + lft_len, rgt);" emitln " res[str_len + 0] = chr[0];"
emitln " res[lft_len + rgt_len] = 0;" emitln " res[str_len + 1] = 0;"
emitln " return res;" emitln " return res;"
emitln "}" emitln "}"
emitln "" emitln ""
emitln "char * __emit(char * str)" emitln "char * emit(char * str)"
emitln "{" emitln "{"
emitln " fputs(str, stdout);" emitln " fputs(str, stdout);"
emitln " return 0;" emitln " return 0;"
emitln "}" emitln "}"
emitln "" emitln ""
emitln "char * __trace(char * var_name, char * var_value)" emitln "char * trace(char * var_name, char * var_value)"
emitln "{" emitln "{"
emit " const char * env_trace = getenv(" emit " const char * env_trace = getenv("
emit quote emit quote
@ -627,7 +585,7 @@ emitheader:
emit quote emit quote
emitln ", stderr);" emitln ", stderr);"
emitln " fputs(var_value, stderr);" emitln " fputs(var_value, stderr);"
emitln " fputs(__EOL, stderr);" emitln " fputs(var_eol, stderr);"
emitln " return 0;" emitln " return 0;"
emitln "}" emitln "}"
emitln "" emitln ""
@ -643,13 +601,13 @@ emitheader:
emitln " return res;" emitln " return res;"
emitln "}" emitln "}"
emitln "" emitln ""
emitln "char * __peek()" emitln "char * peek()"
emitln "{" emitln "{"
emitln " if( !STDINPEEK ) STDINPEEK = _readchar(); // First byte read" emitln " if( !STDINPEEK ) STDINPEEK = _readchar(); // First byte read"
emitln " return STDINPEEK;" emitln " return STDINPEEK;"
emitln "}" emitln "}"
emitln "" emitln ""
emitln "void __skip()" emitln "void skip()"
emitln "{" emitln "{"
emitln " if( !STDINPEEK ) STDINPEEK = _readchar(); // First byte read, not even peek()'d" emitln " if( !STDINPEEK ) STDINPEEK = _readchar(); // First byte read, not even peek()'d"
emitln " if( STDINPEEK[0] == 10 ) {" emitln " if( STDINPEEK[0] == 10 ) {"
@ -660,7 +618,7 @@ emitheader:
emitln " STDINPEEK = _readchar();" emitln " STDINPEEK = _readchar();"
emitln "}" emitln "}"
emitln "" emitln ""
emitln "char * __stdinlineno()" emitln "char * stdinlineno()"
emitln "{" emitln "{"
emitln " char * res = malloc(8*sizeof(char));" emitln " char * res = malloc(8*sizeof(char));"
emit " sprintf(res, " emit " sprintf(res, "
@ -671,7 +629,7 @@ emitheader:
emitln " return res;" emitln " return res;"
emitln "}" emitln "}"
emitln "" emitln ""
emitln "char * __stdincolno()" emitln "char * stdincolno()"
emitln "{" emitln "{"
emitln " char * res = malloc(8*sizeof(char));" emitln " char * res = malloc(8*sizeof(char));"
emit " sprintf(res, " emit " sprintf(res, "
@ -682,137 +640,11 @@ emitheader:
emitln " return res;" emitln " return res;"
emitln "}" emitln "}"
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 return
/ /
emitfooter: emitfooter:
declare mainid emit ""
calc mainid registerid "main"
emitln "int main() {"
emit " "
emit mainid
emitln "();"
emitln " return 0;"
emitln "}"
return return
/ /
@ -821,38 +653,7 @@ main:
declare iseof declare iseof
declare iseol declare iseol
declare isnoteol declare isnoteol
emitheader 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 forever
calc char peek calc char peek
calc iseof eq char eof calc iseof eq char eof

View File

@ -97,7 +97,7 @@ Exits the deepest `forever` loop.
#### func args* #### func args*
Calls the function name `func` with the given arguments. The return value is ignored. Calls the function name `func` with the given arguments. The result, if any, is ignored.
#### if arg #### if arg
@ -109,7 +109,7 @@ Repeats the block until `break` or `return` is called.
#### return var? #### return var?
Returns the given value. If you don't give something to return, the function will return the empty string. Returns the given value. You can not give an argument if your function is never used in `call`.
### Builtins ### Builtins
@ -121,23 +121,11 @@ Calls the given function with the given arguments. If the function's return valu
Writes the name and value of the variable passed to stderr if the TRACE environment variable is set. Writes the name and value of the variable passed to stderr if the TRACE environment variable is set.
### Standard library constants
#### eof
End of file character, zero byte.
#### eol
End of line character.
#### quote
Double quote character.
### Standard library functions ### Standard library functions
#### add a b #### addstringchar a b
`b` is expected to have length 1.
Creates a new string with `b` appended to `a`. Creates a new string with `b` appended to `a`.
@ -149,6 +137,13 @@ Writes the given string to standard output.
Return true if the given strings are the same. Return true if the given strings are the same.
#### intinc a
Available in it2 runtime and onwards.
Interprets string `a` as an integer, increases it by one and returns it (as a string).
If `a` cannot be interpreted as an integer, or has additional bytes, this function returns 1.
#### lt a b #### lt a b
`a` and `b` are expected to have length 1. `a` and `b` are expected to have length 1.
@ -157,12 +152,16 @@ Return true if a would sort before b.
#### mapclear mapname #### mapclear mapname
Available in it2 runtime and onwards.
Maps are global and can be used from any function. Maps are global and can be used from any function.
Clears all values set in the map named `mapname`. Clears all values set in the map named `mapname`.
#### mapgetkey mapname key #### mapgetkey mapname key
Available in it2 runtime and onwards.
Maps are global and can be used from any function. Maps are global and can be used from any function.
Looks up `key` in the map named `mapname` and returns it. Looks up `key` in the map named `mapname` and returns it.
@ -170,14 +169,12 @@ If not found, returns an empty string.
#### mapsetkey mapname key value #### mapsetkey mapname key value
Available in it2 runtime and onwards.
Maps are global and can be used from any function. Maps are global and can be used from any function.
Adds a mapping from `key` to `value` to the map named `mapname`. Adds a mapping from `key` to `value` to the map named `mapname`.
#### not a
Returns "1" if a is empty; otherwise, returns "".
#### peek #### peek
Checks stdin for the next character and returns it. Checks stdin for the next character and returns it.

2
tests/.gitignore vendored
View File

@ -1 +1 @@
/Makefile.mk /*.results

View File

@ -1,36 +1,38 @@
.SUFFIXES: .SUFFIXES:
.PHONY: all clean .PHONY: all clean
.PRECIOUS: build/%.it0.py build/%.it0.c
.DELETE_ON_ERROR: .DELETE_ON_ERROR:
PYVERSION=3.12 PYVERSION=3.12
PYPREFIX=/usr PYPREFIX=/usr
CYTHON=cython3 CYTHON=cython3
CC=gcc CC=gcc
CFLAGS=-ggdb
all: verify-results # builtincheckfalse is separate since it's supposed to crash. It's a test for the test 'framework', if you will.
TESTLIST=$(shell ls *.lang0 | grep -v 'builtincheckfalse' | sed 's/.lang0//')
Makefile.mk: generate-recipes.py $(wildcard test_*/test_*) all: check
python3 generate-recipes.py Makefile.mk it0 it1 it2
include Makefile.mk check: all-it0.results all-it1.results all-it2.results
! grep -v 'Success' $^
all-it0.results: $(addprefix build/,$(addsuffix .it0, $(TESTLIST))) build/builtincheckfalse.it0
-rm -f $@
cat test-input.txt | build/builtincheckfalse.it0 2> /dev/null 2>&1 | grep 'Success'
$(foreach test,$(TESTLIST), echo -n "$(test) " >> $@; cat test-input.txt | ./build/$(test).it0 >> $@ ; echo "" >> $@ ;)
all-it1.results: $(addprefix build/,$(addsuffix .it1, $(TESTLIST))) build/builtincheckfalse.it1
-rm -f $@
cat test-input.txt | build/builtincheckfalse.it1 2> /dev/null 2>&1 | grep 'Success'
$(foreach test,$(TESTLIST), echo -n "$(test) " >> $@; cat test-input.txt | ./build/$(test).it1 >> $@ ; echo "" >> $@ ;)
all-it2.results: $(addprefix build/,$(addsuffix .it2, $(TESTLIST))) build/builtincheckfalse.it2
-rm -f $@
cat test-input.txt | build/builtincheckfalse.it2 2> /dev/null 2>&1 | grep 'Success'
$(foreach test,$(TESTLIST), echo -n "$(test) " >> $@; cat test-input.txt | ./build/$(test).it2 >> $@ ; echo "" >> $@ ;)
clean: clean:
find build -name '*.c' -delete -rm -f *.results build/*.it0* build/*.it1* build/*.it2*
find build -name '*.it0' -delete
find build -name '*.it0.result' -delete
find build -name '*.it0.stderr' -delete
find build -name '*.it0.stdout' -delete
find build -name '*.it1' -delete
find build -name '*.it1.result' -delete
find build -name '*.it1.stderr' -delete
find build -name '*.it1.stdout' -delete
find build -name '*.it2' -delete
find build -name '*.it2.result' -delete
find build -name '*.it2.stderr' -delete
find build -name '*.it2.stdout' -delete
find build -name '*.py' -delete
find build -name '*.tmp' -delete
### ###
# it0 # it0
@ -39,17 +41,17 @@ clean:
$(MAKE) -C ../0-lang0py $(MAKE) -C ../0-lang0py
build/%.it0.py: %.lang0 ../0-lang0py/lang0py.exe build/%.it0.py: %.lang0 ../0-lang0py/lang0py.exe
-cat $< | ../0-lang0py/lang0py.exe > $@.tmp 2> build/$*.it0.cmperr cat $< | ../0-lang0py/lang0py.exe > $@.tmp
mv $@.tmp $@ mv $@.tmp $@
build/%.it0.c: build/%.it0.py build/%.it0.c: build/%.it0.py
$(CYTHON) -3 --embed -o $@ $^ $(CYTHON) -3 --embed -o $@ $^
build/%.it0.o: build/%.it0.c build/%.it0.o: build/%.it0.c
$(CC) $(CFLAGS) -o $@ -c $^ -I$(PYPREFIX)/include/python$(PYVERSION) $(CC) -o $@ -c $^ -I$(PYPREFIX)/include/python$(PYVERSION)
build/%.it0: build/%.it0.o build/%.it0: build/%.it0.o
$(CC) $(CFLAGS) -o $@ $^ -lpython$(PYVERSION) $(CC) -o $@ $^ -lpython$(PYVERSION)
### ###
# it1 # it1
@ -58,17 +60,17 @@ build/%.it0: build/%.it0.o
$(MAKE) -C ../1-lang0py $(MAKE) -C ../1-lang0py
build/%.it1.py: %.lang0 ../1-lang0py/lang0py.exe build/%.it1.py: %.lang0 ../1-lang0py/lang0py.exe
-cat $< | ../1-lang0py/lang0py.exe > $@.tmp 2> build/$*.it1.cmperr cat $< | ../1-lang0py/lang0py.exe > $@.tmp
mv $@.tmp $@ mv $@.tmp $@
build/%.it1.c: build/%.it1.py build/%.it1.c: build/%.it1.py
$(CYTHON) -3 --embed -o $@ $^ $(CYTHON) -3 --embed -o $@ $^
build/%.it1.o: build/%.it1.c build/%.it1.o: build/%.it1.c
$(CC) $(CFLAGS) -o $@ -c $^ -I$(PYPREFIX)/include/python$(PYVERSION) $(CC) -o $@ -c $^ -I$(PYPREFIX)/include/python$(PYVERSION)
build/%.it1: build/%.it1.o build/%.it1: build/%.it1.o
$(CC) $(CFLAGS) -o $@ $^ -lpython$(PYVERSION) $(CC) -o $@ $^ -lpython$(PYVERSION)
### ###
# it2 # it2
@ -77,11 +79,11 @@ build/%.it1: build/%.it1.o
$(MAKE) -C ../2-lang0c $(MAKE) -C ../2-lang0c
build/%.it2.c: %.lang0 ../2-lang0c/lang0c.exe build/%.it2.c: %.lang0 ../2-lang0c/lang0c.exe
-cat $< | ../2-lang0c/lang0c.exe > $@.tmp 2> build/$*.it2.cmperr cat $< | ../2-lang0c/lang0c.exe > $@.tmp
mv $@.tmp $@ mv $@.tmp $@
build/%.it2.o: build/%.it2.c build/%.it2.o: build/%.it2.c
$(CC) $(CFLAGS) -o $@ -c $^ -I$(PYPREFIX)/include/python$(PYVERSION) $(CC) -o $@ -c $^ -I$(PYPREFIX)/include/python$(PYVERSION)
build/%.it2: build/%.it2.o build/%.it2: build/%.it2.o
$(CC) $(CFLAGS) -o $@ $^ -lpython$(PYVERSION) $(CC) -o $@ $^ -lpython$(PYVERSION)

14
tests/build/.gitignore vendored Normal file
View File

@ -0,0 +1,14 @@
/*.it0
/*.it0.c
/*.it0.o
/*.it0.py
/*.it0.py.tmp
/*.it1
/*.it1.c
/*.it1.o
/*.it1.py
/*.it1.py.tmp
/*.it2
/*.it2.c
/*.it2.c.tmp
/*.it2.o

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -0,0 +1,3 @@
main:
check not "1" : "Success"
/

View File

@ -0,0 +1,4 @@
main:
check not "" : "Failure"
emit "Success"
/

View File

@ -1,7 +1,6 @@
main: main:
forever forever
emit "Suc"
break break
/ /
emit "cess" emit "Success"
/ /

8
tests/flowiffalse.lang0 Normal file
View File

@ -0,0 +1,8 @@
main:
declare bool
set bool ""
if bool
return
/
emit "Success"
/

7
tests/flowiftrue.lang0 Normal file
View File

@ -0,0 +1,7 @@
main:
declare bool
set bool "1"
if bool
emit "Success"
/
/

View File

@ -0,0 +1,8 @@
func:
return
/
main:
func
emit "Success"
/

View File

@ -0,0 +1,11 @@
func:
declare result
set result "Success"
return result
/
main:
declare result
calc result func
emit result
/

View File

@ -0,0 +1,9 @@
func:
return "Success"
/
main:
declare result
calc result func
emit result
/

View File

@ -1,122 +0,0 @@
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
self.prerequisites = prerequisites
self.recipe = recipe
def make_lines(self):
return [
self.target + ': ' + ' '.join(self.prerequisites),
] + [
'\t' + line
for line in self.recipe
] + ['']
def get_file_list():
return sorted(glob.glob('test_*/*.lang0'))
def make_rules(file_path, lang0it):
result: list[Rule] = []
stdin = file_path.replace('.lang0', '.stdin')
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_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}')
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 []),
[
'-' + (f'cat {stdin} | ' if os.path.isfile(stdin) else 'echo x | ')
+ f'{program} 1> {act_stdout} 2> {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,
([program_stage0] if os.path.isfile(exp_cmperr) else [act_stdout]) + [
x
for x in exp_list
if os.path.isfile(x)
],
[
'rm -f $@',
] + [
f'-diff {exp_file} {act_file} >> $@'
for exp_file, act_file in zip(exp_list, act_list, strict=True)
if os.path.isfile(exp_file)
] + [
f'-diff /dev/null {act_file} >> $@'
for exp_file, act_file in zip(exp_list, act_list, strict=True)
if not os.path.isfile(exp_file)
]
))
return result
def main(program, write_to, *lang0it):
rule_list_list = [
make_rules(file_path, it)
for file_path in get_file_list()
for it in lang0it
]
result_targets = [
rule.target
for rule_list in rule_list_list
for rule in rule_list
if rule.target.endswith('.result')
]
rule_list_list.append([Rule(
'verify-results',
result_targets,
[
'@echo Finding failed test results...',
'@find $^ -not -empty -print -exec false {} +',
'@echo All tests passed.'
]
)])
data = '\n'.join(
line
for rule_list in rule_list_list
for rule in rule_list
for line in rule.make_lines()
)
with open(write_to, 'wt', encoding='ASCII') as fil:
fil.write(data)
if __name__ == '__main__':
main(*sys.argv)

View File

@ -0,0 +1,10 @@
func/
main:
check func : "The function should return 1, even though it is not defined yet"
emit "Success"
/
func:
return "1"
/

View File

@ -0,0 +1,10 @@
func arg/
main:
check func "1" : "The function should return 1, even though it is not defined yet"
emit "Success"
/
func arg:
return arg
/

86
tests/stdinlineno.lang0 Normal file
View File

@ -0,0 +1,86 @@
main:
declare char
declare colno
declare lineno
calc char peek
calc colno stdincolno
calc lineno stdinlineno
check eq char "H" : "Read: H" char
check eq colno "1" : "The column number should not have advanced yet" colno
check eq lineno "1" : "The line number should not have advanced yet" lineno
skip
calc char peek
calc colno stdincolno
calc lineno stdinlineno
check eq char "e" : "Read: e" char
check eq colno "2" : "The column number should have been advanced by 1" colno
check eq lineno "1" : "The line number should not have advanced yet" lineno
skip
calc char peek
calc colno stdincolno
calc lineno stdinlineno
check eq char "l" : "Read: l" char
check eq colno "3" : "The column number should have been advanced by 2" colno
check eq lineno "1" : "The line number should not have advanced yet" lineno
skip
calc char peek
calc colno stdincolno
calc lineno stdinlineno
check eq char "l" : "Read: l" char
check eq colno "4" : "The column number should have been advanced by 3" colno
check eq lineno "1" : "The line number should not have advanced yet" lineno
skip
calc char peek
calc colno stdincolno
calc lineno stdinlineno
check eq char "o" : "Read: o" char
check eq colno "5" : "The column number should have been advanced by 4" colno
check eq lineno "1" : "The line number should not have advanced yet" lineno
skip
calc char peek
calc colno stdincolno
calc lineno stdinlineno
check eq char "!" : "Read: !" char
check eq colno "6" : "The column number should have been advanced by 5" colno
check eq lineno "1" : "The line number should not have advanced yet" lineno
skip
calc char peek
calc colno stdincolno
calc lineno stdinlineno
check eq char eol : "Read: eol" char
check eq colno "7" : "The column number should have been advanced by 6" colno
check eq lineno "1" : "The line number should not have advanced yet" lineno
skip
calc char peek
calc colno stdincolno
calc lineno stdinlineno
check eq char eol : "Read: eol" char
check eq colno "1" : "The column number should have been reset" colno
check eq lineno "2" : "The line number should have advanced by 1" lineno
skip
calc char peek
calc colno stdincolno
calc lineno stdinlineno
check eq char "T" : "Read: T" char
check eq colno "1" : "The column number should have been reset again" colno
check eq lineno "3" : "The line number should have advanced by 2" lineno
skip
calc char peek
calc colno stdincolno
calc lineno stdinlineno
check eq char "h" : "Read: h" char
check eq colno "2" : "The line number should not have been advanced by 1" colno
check eq lineno "3" : "The line number should not have advanced further" lineno
emit "Success"
/

View File

@ -0,0 +1,6 @@
main:
declare result
calc result addstringchar "abc" "d"
check eq result "abcd" : "Adding abc and d should be abcd"
emit "Success"
/

3
tests/stdlibemit.lang0 Normal file
View File

@ -0,0 +1,3 @@
main:
emit "Success"
/

View File

@ -0,0 +1,6 @@
main:
declare bool
calc bool eq "1" "2"
check not bool : "1 should not equal 2"
emit "Success"
/

5
tests/stdlibeqtrue.lang0 Normal file
View File

@ -0,0 +1,5 @@
main:
declare bool
check eq "1" "1" : "1 should equal 1"
emit "Success"
/

View File

@ -0,0 +1,6 @@
main:
declare bool
calc bool lt "b" "a"
check not bool : "a should should sort before b"
emit "Success"
/

5
tests/stdliblttrue.lang0 Normal file
View File

@ -0,0 +1,5 @@
main:
declare bool
check lt "a" "b" : "a should should sort before b"
emit "Success"
/

6
tests/stdlibpeek.lang0 Normal file
View File

@ -0,0 +1,6 @@
main:
declare char
calc char peek
check eq char "H" : "The first byte we're passed is expected to be an 'H'"
emit "Success"
/

12
tests/stdlibskip.lang0 Normal file
View File

@ -0,0 +1,12 @@
main:
declare char
skip
calc char peek
check eq char "e" : "The second byte we're passed is expected to be an 'e'"
skip
skip
skip
calc char peek
check eq char "o" : "The fifth byte we're passed is expected to be an 'o'"
emit "Success"
/

3
tests/test-input.txt Normal file
View File

@ -0,0 +1,3 @@
Hello!
This is an example of standard input.

View File

@ -1 +0,0 @@
ERROR: Check failed successfully

View File

@ -1 +0,0 @@
Still alive

View File

@ -1,8 +0,0 @@
main:
check not "" : "This should not trigger"
emit "Still alive"
emit eol
check not "1" : "Check failed successfully"
emit "This should not be output"
emit eol
/

View File

@ -1 +0,0 @@
Success

View File

@ -1 +0,0 @@
Success

View File

@ -1,2 +0,0 @@
1 is true
A is true

View File

@ -1,18 +0,0 @@
main:
declare bool
set bool ""
if bool
emit "empty string is true"
emit eol
/
set bool "1"
if bool
emit "1 is true"
emit eol
/
set bool "A"
if bool
emit "A is true"
emit eol
/
/

View File

@ -1,3 +0,0 @@
funca Constant
funcb Variable
funcc

View File

@ -1,32 +0,0 @@
funca:
return "Constant"
/
funcb:
declare var
set var "Variable"
return var
/
funcc:
return
/
main:
declare var
calc var funca
emit "funca "
emit var
emit eol
calc var funcb
emit "funcb "
emit var
emit eol
calc var funcc
emit "funcc "
emit var
emit eol
/

View File

@ -1,2 +0,0 @@
Predeclared without argument: 1
Predeclared with argument: 2

View File

@ -1,24 +0,0 @@
funca/
funcb arg/
main:
declare var
calc var funca
emit "Predeclared without argument: "
emit var
emit eol
calc var funcb "2"
emit "Predeclared with argument: "
emit var
emit eol
/
funca:
return "1"
/
funcb arg:
return arg
/

View File

@ -1,8 +0,0 @@
main:
declare assert
declare class
set assert "1"
set class "1"
emit assert
emit class
/

View File

@ -1 +0,0 @@
<EFBFBD>

View File

@ -1,3 +0,0 @@
main:
emit eof
/

View File

@ -1,3 +0,0 @@
main:
emit eol
/

View File

@ -1,3 +0,0 @@
main:
emit quote
/

View File

@ -1,3 +0,0 @@
1 + 2 = 12
10 + 20 = 1020
101 + 202 = 101202

View File

@ -1,29 +0,0 @@
func tst a b:
declare var
calc var add a b
emit a
emit " + "
emit b
emit " = "
emit var
emit eol
/
main:
declare var
calc var add "1" "2"
emit "1 + 2 = "
emit var
emit eol
calc var add "10" "20"
emit "10 + 20 = "
emit var
emit eol
calc var add "101" "202"
emit "101 + 202 = "
emit var
emit eol
/

View File

@ -1 +0,0 @@
Hello, world!

View File

@ -1,4 +0,0 @@
main:
emit "Hello"
emit ", world!"
/

View File

@ -1,4 +0,0 @@
eq A A: 1
eq A B:
eq AA AA: 1
eq AA AB:

View File

@ -1,19 +0,0 @@
main:
declare result
emit "eq A A: "
calc result eq "A" "A"
emit result
emit eol
emit "eq A B: "
calc result eq "A" "B"
emit result
emit eol
emit "eq AA AA: "
calc result eq "AA" "AA"
emit result
emit eol
emit "eq AA AB: "
calc result eq "AA" "AB"
emit result
emit eol
/

View File

@ -1,6 +0,0 @@
lt A A:
lt A B: 1
lt B A:
lt AA AA:
lt AA AB: 1
lt AB AA:

View File

@ -1,27 +0,0 @@
main:
declare result
emit "lt A A: "
calc result lt "A" "A"
emit result
emit eol
emit "lt A B: "
calc result lt "A" "B"
emit result
emit eol
emit "lt B A: "
calc result lt "B" "A"
emit result
emit eol
emit "lt AA AA: "
calc result lt "AA" "AA"
emit result
emit eol
emit "lt AA AB: "
calc result lt "AA" "AB"
emit result
emit eol
emit "lt AB AA: "
calc result lt "AB" "AA"
emit result
emit eol
/

View File

@ -1,14 +0,0 @@
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

View File

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

View File

@ -1,4 +0,0 @@
not == 1
not a ==
not 1 ==
not -1 ==

View File

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

View File

@ -1 +0,0 @@
AAA

View File

@ -1,9 +0,0 @@
main:
declare char
calc char peek
emit char
calc char peek
emit char
calc char peek
emit char
/

View File

@ -1 +0,0 @@
ABC

View File

@ -1 +0,0 @@
ABD

View File

@ -1,12 +0,0 @@
main:
declare char
calc char peek
emit char
skip
calc char peek
emit char
skip
skip
calc char peek
emit char
/

View File

@ -1 +0,0 @@
ABCD

View File

@ -1,4 +0,0 @@
"A" 1
"
" 2
"B" 1

View File

@ -1,35 +0,0 @@
main:
declare char
declare colno
calc char peek
calc colno stdincolno
emit quote
emit char
emit quote
emit " "
emit colno
emit eol
skip
calc char peek
calc colno stdincolno
emit quote
emit char
emit quote
emit " "
emit colno
emit eol
skip
calc char peek
calc colno stdincolno
emit quote
emit char
emit quote
emit " "
emit colno
emit eol
/

View File

@ -1,3 +0,0 @@
A
B
C

View File

@ -1,4 +0,0 @@
"A" 1
"
" 1
"B" 2

View File

@ -1,35 +0,0 @@
main:
declare char
declare lineno
calc char peek
calc lineno stdinlineno
emit quote
emit char
emit quote
emit " "
emit lineno
emit eol
skip
calc char peek
calc lineno stdinlineno
emit quote
emit char
emit quote
emit " "
emit lineno
emit eol
skip
calc char peek
calc lineno stdinlineno
emit quote
emit char
emit quote
emit " "
emit lineno
emit eol
/

View File

@ -1,3 +0,0 @@
A
B
C

View File

@ -1 +0,0 @@
ERROR: Function funca does not exist

View File

@ -1,4 +0,0 @@
main:
declare var
calc var funca "1"
/

View File

@ -1 +0,0 @@
ERROR: Function routine does not exist

View File

@ -1,3 +0,0 @@
main:
routine "1"
/

View File

@ -1 +0,0 @@
Success

View File

@ -1 +0,0 @@
Success