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.
This commit is contained in:
Johan B.W. de Vries 2025-02-02 15:43:37 +01:00
parent 6055cddab2
commit 670532059a
24 changed files with 736 additions and 190 deletions

View File

@ -39,6 +39,36 @@ 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)
@ -81,12 +111,15 @@ def parseconststring():
emit(quote) emit(quote)
def parseexprvarref(): def parseexprvarref():
var = lexident() varname = lexident()
emit(var) varid = registerid(varname)
emit(varid)
def parseexprcall(): def parseexprcall():
funcname = lexident() funcname = lexident()
emit(funcname) __check(mapgetkey, ["FUNCREG", funcname, ""], ["Function", funcname, "does not exist"])
funcid = registerid(funcname)
emit(funcid)
emit('(') emit('(')
first = True first = True
@ -109,11 +142,12 @@ def parsestatdeclare(indent):
def parsestatset(indent): def parsestatset(indent):
skipchar(' ') skipchar(' ')
var = lexident() varname = lexident()
varid = registerid(varname)
skipchar(' ') skipchar(' ')
emit(' ' * indent) emit(' ' * indent)
emit(var) emit(varid)
emit(' = ') emit(' = ')
parseconststring() parseconststring()
@ -123,11 +157,12 @@ def parsestatset(indent):
def parsestatcalc(indent): def parsestatcalc(indent):
skipchar(' ') skipchar(' ')
var = lexident() varname = lexident()
varid = registerid(varname)
skipchar(' ') skipchar(' ')
emit(' ' * indent) emit(' ' * indent)
emit(var) emit(varid)
emit(' = ') emit(' = ')
parseexprcall() parseexprcall()
@ -174,11 +209,13 @@ def parsestatreturn(indent):
def parsestatcheck(indent): def parsestatcheck(indent):
skipchar(' ') skipchar(' ')
emit(' ' * indent) emit(' ' * indent)
emit('if not ') emit('__check(')
func_name = lexident() funcname = lexident()
emit(func_name) funcid = registerid(funcname)
emit('(') trace("funcid", funcid)
emit(funcid)
emit(', [')
notfirst = False notfirst = False
while True: while True:
@ -199,9 +236,7 @@ def parsestatcheck(indent):
skipchar(':') skipchar(':')
emitln('):') emit('], [')
emit(' ' * (indent + 1))
emit('sys.stderr.write(\' \'.join(["ERROR:", ')
notfirst = False notfirst = False
while True: while True:
@ -218,23 +253,21 @@ def parsestatcheck(indent):
if eol == peek(): if eol == peek():
break break
notfirst = True notfirst = True
emitln(']))')
emit(' ' * (indent + 1)) emitln('])')
emitln('sys.stderr.write(eol)')
emit(' ' * (indent + 1))
emitln('sys.exit(1)')
def parsestattrace(indent): def parsestattrace(indent):
skipchar(' ') skipchar(' ')
emit(' ' * indent) emit(' ' * indent)
emit('trace("') emit('__trace("')
var_name = lexident() varname = lexident()
varid = registerid(varname)
skipchar(eol) skipchar(eol)
emit(var_name) emit(varname)
emit('", ') emit('", ')
emit(var_name) emit(varid)
emitln(')') emitln(')')
def parsestat(indent): def parsestat(indent):
@ -277,8 +310,12 @@ 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(call) emit(callid)
emit('(') emit('(')
first = True first = True
@ -315,19 +352,22 @@ 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(funcname) emit(funcid)
emit('(') emit('(')
first = True first = True
while ' ' == peek(): while ' ' == peek():
skip() skip()
var = lexident() varname = lexident()
varid = registerid(varname)
if not first: if not first:
emit(", ") emit(", ")
emit(var) emit(varid)
first = False first = False
if '/' == peek(): if '/' == peek():
@ -352,26 +392,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: str, b: str) -> str:")
emitln(" return '1' if a == b else ''") emitln(" return '1' if a == b else ''")
emitln("") 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(" return '1' if a < b else ''")
emitln("") emitln("")
emitln("def add(a: str, b: str) -> str:") emitln("def __add(a: str, b: str) -> str:")
emitln(" return a + b") emitln(" return a + b")
emitln("") emitln("")
emitln("def emit(string):") emitln("def __emit(string):")
emitln(" sys.stdout.buffer.write(string.encode('latin_1'))") 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(0xFF)")
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")
@ -379,41 +419,106 @@ 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():
emit("if __name__ == '__main__':\n") mainid = registerid("main")
emit(" main()\n") emitln("if __name__ == '__main__':")
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,5 +36,8 @@ 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,12 +1,14 @@
skipchar exp: registerid id:
declare act declare idname
declare lineno declare newidx
declare colno
calc act peek calc idname mapgetkey "REGISTERID" id ""
calc lineno stdinlineno if idname
calc colno stdincolno return idname
check eq exp act : "Unexpected character" act "expected" exp "at" lineno colno /
skip
calc idname add "id_" id
return idname
/ /
emitln data: emitln data:
@ -14,11 +16,6 @@ emitln data:
emit eol emit eol
/ /
increaseindent indent:
calc indent add indent " "
return indent
/
lexident: lexident:
declare word declare word
set word "" set word ""
@ -38,6 +35,22 @@ lexident:
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
@ -60,12 +73,15 @@ parseconststring:
parseexprvarref: parseexprvarref:
calc varname lexident calc varname lexident
emit varname calc varid registerid varname
emit varid
/ /
parseexprcall: parseexprcall:
calc funcname lexident calc funcname lexident
emit funcname calc funcid registerid funcname
check mapgetkey "FUNCREG" funcname "" : "Function" funcname "does not exist"
emit funcid
emit "(" emit "("
set first "1" set first "1"
forever forever
@ -97,16 +113,18 @@ parseexprcall:
parsestatdeclare indent: parsestatdeclare indent:
skipchar " " skipchar " "
calc var lexident calc varname lexident
calc varid registerid varname
skipchar eol skipchar eol
/ /
parsestatset indent: parsestatset indent:
skipchar " " skipchar " "
calc var lexident calc varname lexident
calc varid registerid varname
skipchar " " skipchar " "
emit indent emit indent
emit var emit varid
emit " = " emit " = "
parseconststring parseconststring
emit eol emit eol
@ -115,10 +133,11 @@ parsestatset indent:
parsestatcalc indent: parsestatcalc indent:
skipchar " " skipchar " "
calc var lexident calc varname lexident
calc varid registerid varname
skipchar " " skipchar " "
emit indent emit indent
emit var emit varid
emit " = " emit " = "
parseexprcall parseexprcall
emit eol emit eol
@ -188,11 +207,12 @@ parsestatcheck indent:
skipchar " " skipchar " "
emit indent emit indent
emit "if not " emit "__check("
calc funcname lexident calc funcname lexident
emit funcname calc funcid registerid funcname
emit "(" emit funcid
emit ", ["
set notfirst "" set notfirst ""
forever forever
@ -222,10 +242,7 @@ parsestatcheck indent:
skipchar ":" skipchar ":"
emitln "):" emit "], ["
calc indent increaseindent indent
emit indent
emit "sys.stderr.write(' '.join(['ERROR:', "
set notfirst "" set notfirst ""
@ -255,23 +272,20 @@ parsestatcheck indent:
set notfirst "1" set notfirst "1"
/ /
emitln "]))" emitln "])"
emit indent
emitln "sys.stderr.write(eol)"
emit indent
emitln "sys.exit(1)"
/ /
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 varname emit varid
emitln ")" emitln ")"
skipchar eol skipchar eol
/ /
@ -324,8 +338,10 @@ 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 call emit callid
emit "(" emit "("
set first "1" set first "1"
forever forever
@ -390,9 +406,11 @@ 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 funcname emit funcid
emit "(" emit "("
set isnotfirst "" set isnotfirst ""
forever forever
@ -403,11 +421,12 @@ parsefunc:
break break
/ /
skip skip
calc var lexident calc varname lexident
calc varid registerid varname
if isnotfirst if isnotfirst
emit ", " emit ", "
/ /
emit var emit varid
set isnotfirst "1" set isnotfirst "1"
/ /
calc char peek calc char peek
@ -431,26 +450,31 @@ 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: str, b: str) -> str:"
emitln " return '1' if a == b else ''" emitln " return '1' if a == b else ''"
emitln "" 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 " return '1' if a < b else ''"
emitln "" 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 " return a + b"
emitln "" emitln ""
emitln "def emit(string):" emitln "def __emit(string):"
emitln " sys.stdout.buffer.write(string.encode('latin_1'))" 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(0xFF)"
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"
@ -458,43 +482,105 @@ 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__':"
emitln " main()" emit " "
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,12 +1,14 @@
skipchar exp: registerid id:
declare act declare idname
declare lineno declare newidx
declare colno
calc act peek calc idname mapgetkey "REGISTERID" id ""
calc lineno stdinlineno if idname
calc colno stdincolno return idname
check eq exp act : "Unexpected character" act "expected" exp "at" lineno colno /
skip
calc idname add "id_" id
return idname
/ /
emitln data: emitln data:
@ -14,11 +16,6 @@ emitln data:
emit eol emit eol
/ /
increaseindent indent:
calc indent add indent " "
return indent
/
lexident: lexident:
declare char declare char
declare isbeforea declare isbeforea
@ -41,6 +38,22 @@ lexident:
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
@ -66,16 +79,18 @@ parseconststring:
/ /
parseexprvarref: parseexprvarref:
declare varid
declare varname declare varname
calc varname lexident calc varname lexident
emit "var_" calc varid registerid varname
emit varname emit varid
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
@ -84,7 +99,9 @@ parseexprcall:
declare isquote declare isquote
declare isnotquote declare isnotquote
calc funcname lexident calc funcname lexident
emit funcname check mapgetkey "FUNCREG" funcname "" : "Function" funcname "does not exist"
calc funcid registerid funcname
emit funcid
emit "(" emit "("
set first "1" set first "1"
forever forever
@ -116,12 +133,14 @@ parseexprcall:
/ /
parsestatdeclare indent: parsestatdeclare indent:
declare var declare varid
declare varname
skipchar " " skipchar " "
calc var lexident calc varname lexident
calc varid registerid varname
emit indent emit indent
emit "char * var_" emit "char * "
emit var emit varid
emit ";" emit ";"
emit eol emit eol
skipchar eol skipchar eol
@ -129,13 +148,14 @@ parsestatdeclare indent:
/ /
parsestatset indent: parsestatset indent:
declare var declare varid
declare varname
skipchar " " skipchar " "
calc var lexident calc varname lexident
calc varid registerid varname
skipchar " " skipchar " "
emit indent emit indent
emit "var_" emit varid
emit var
emit " = " emit " = "
parseconststring parseconststring
emit ";" emit ";"
@ -145,13 +165,14 @@ parsestatset indent:
/ /
parsestatcalc indent: parsestatcalc indent:
declare var declare varid
declare varname
skipchar " " skipchar " "
calc var lexident calc varname lexident
calc varid registerid varname
skipchar " " skipchar " "
emit indent emit indent
emit "var_" emit varid
emit var
emit " = " emit " = "
parseexprcall parseexprcall
emit ";" emit ";"
@ -235,6 +256,7 @@ parsestatreturn indent:
parsestatcheck indent: parsestatcheck indent:
declare char declare char
declare funcid
declare funcname declare funcname
declare iscolon declare iscolon
declare iseol declare iseol
@ -247,7 +269,8 @@ parsestatcheck indent:
emit "if( 0 == strlen(" emit "if( 0 == strlen("
calc funcname lexident calc funcname lexident
emit funcname calc funcid registerid funcname
emit funcid
emit "(" emit "("
set notfirst "" set notfirst ""
@ -325,7 +348,7 @@ parsestatcheck indent:
emit quote emit quote
emit "%s" emit "%s"
emit quote emit quote
emit ", var_eol" emit ", __EOL"
emitln ");" emitln ");"
emit indent emit indent
@ -335,16 +358,18 @@ 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 ", var_" emit ", "
emit varname emit varid
emitln ");" emitln ");"
skipchar eol skipchar eol
return return
@ -352,6 +377,7 @@ parsestattrace indent:
parsestat indent: parsestat indent:
declare call declare call
declare callid
declare char declare char
declare first declare first
declare iscall declare iscall
@ -408,8 +434,10 @@ 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 call emit callid
emit "(" emit "("
set first "1" set first "1"
forever forever
@ -423,17 +451,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
@ -483,6 +511,7 @@ 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
@ -491,18 +520,14 @@ parsefunc:
declare isspace declare isspace
declare isnotfirst declare isnotfirst
declare isnotspace declare isnotspace
declare var declare varid
declare varname
calc funcname lexident calc funcname lexident
calc ismain eq funcname "main" mapsetkey "FUNCREG" funcname "1"
calc isnotmain not ismain calc funcid registerid funcname
trace funcname trace funcname
emit "char * " emit "char * "
if ismain emit funcid
emit "__main"
/
if isnotmain
emit funcname
/
emit "(" emit "("
set first "1" set first "1"
forever forever
@ -513,14 +538,15 @@ parsefunc:
break break
/ /
skip skip
calc var lexident calc varname 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 * var_" emit "char * "
emit var emit varid
set first "0" set first "0"
/ /
calc char peek calc char peek
@ -548,28 +574,28 @@ emitheader:
emitln "#include <string.h>" emitln "#include <string.h>"
emitln "" emitln ""
emitln "" emitln ""
emitln "char var_eof[2] = {0xFF, 0};" emitln "char __EOF[2] = {0xFF, 0};"
emitln "char var_eol[2] = {10, 0};" emitln "char __EOL[2] = {10, 0};"
emitln "char var_quote[2] = {34, 0};" emitln "char __QUOTE[2] = {34, 0};"
emitln "char var_false[1] = {0};" emitln "char __FALSE[1] = {0};"
emitln "char var_true[2] = {'1', 0};" emitln "char __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) ? var_true : var_false;" emitln " return (strcmp(a, b) == 0) ? __TRUE : __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) ? var_true : var_false;" emitln " return (strcmp(a, b) < 0) ? __TRUE : __FALSE;"
emitln "}" emitln "}"
emitln "char * not(char * a)" emitln "char * __not(char * a)"
emitln "{" emitln "{"
emitln " return (strcmp(a, var_true) != 0) ? var_true : var_false;" emitln " return (0 == strlen(a)) ? __TRUE : __FALSE;"
emitln "}" emitln "}"
emitln "" emitln ""
emitln "char * add(char * lft, char * rgt)" emitln "char * __add(char * lft, char * rgt)"
emitln "{" emitln "{"
emitln " int lft_len = strlen(lft);" emitln " int lft_len = strlen(lft);"
emitln " int rgt_len = strlen(rgt);" emitln " int rgt_len = strlen(rgt);"
@ -580,13 +606,13 @@ emitheader:
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
@ -601,7 +627,7 @@ emitheader:
emit quote emit quote
emitln ", stderr);" emitln ", stderr);"
emitln " fputs(var_value, stderr);" emitln " fputs(var_value, stderr);"
emitln " fputs(var_eol, stderr);" emitln " fputs(__EOL, stderr);"
emitln " return 0;" emitln " return 0;"
emitln "}" emitln "}"
emitln "" emitln ""
@ -617,13 +643,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 ) {"
@ -634,7 +660,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, "
@ -645,7 +671,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, "
@ -656,12 +682,135 @@ 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
calc mainid registerid "main"
emitln "int main() {" emitln "int main() {"
emitln " __main();" emit " "
emit mainid
emitln "();"
emitln " return 0;" emitln " return 0;"
emitln "}" emitln "}"
return return
@ -672,7 +821,38 @@ 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

@ -155,6 +155,29 @@ Return true if the given strings are the same.
Return true if a would sort before b. 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 #### peek
Checks stdin for the next character and returns it. Checks stdin for the next character and returns it.

View File

@ -6,6 +6,7 @@ PYVERSION=3.12
PYPREFIX=/usr PYPREFIX=/usr
CYTHON=cython3 CYTHON=cython3
CC=gcc CC=gcc
CFLAGS=-ggdb
all: verify-results all: verify-results
@ -38,17 +39,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 -cat $< | ../0-lang0py/lang0py.exe > $@.tmp 2> build/$*.it0.cmperr
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) -o $@ -c $^ -I$(PYPREFIX)/include/python$(PYVERSION) $(CC) $(CFLAGS) -o $@ -c $^ -I$(PYPREFIX)/include/python$(PYVERSION)
build/%.it0: build/%.it0.o build/%.it0: build/%.it0.o
$(CC) -o $@ $^ -lpython$(PYVERSION) $(CC) $(CFLAGS) -o $@ $^ -lpython$(PYVERSION)
### ###
# it1 # it1
@ -57,17 +58,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 -cat $< | ../1-lang0py/lang0py.exe > $@.tmp 2> build/$*.it1.cmperr
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) -o $@ -c $^ -I$(PYPREFIX)/include/python$(PYVERSION) $(CC) $(CFLAGS) -o $@ -c $^ -I$(PYPREFIX)/include/python$(PYVERSION)
build/%.it1: build/%.it1.o build/%.it1: build/%.it1.o
$(CC) -o $@ $^ -lpython$(PYVERSION) $(CC) $(CFLAGS) -o $@ $^ -lpython$(PYVERSION)
### ###
# it2 # it2
@ -76,11 +77,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 -cat $< | ../2-lang0c/lang0c.exe > $@.tmp 2> build/$*.it2.cmperr
mv $@.tmp $@ mv $@.tmp $@
build/%.it2.o: build/%.it2.c 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 build/%.it2: build/%.it2.o
$(CC) -o $@ $^ -lpython$(PYVERSION) $(CC) $(CFLAGS) -o $@ $^ -lpython$(PYVERSION)

View File

@ -1,5 +1,6 @@
/*.it0 /*.it0
/*.it0.c /*.it0.c
/*.it0.cmperr
/*.it0.o /*.it0.o
/*.it0.py /*.it0.py
/*.it0.py.tmp /*.it0.py.tmp
@ -8,6 +9,7 @@
/*.it0.stdout /*.it0.stdout
/*.it1 /*.it1
/*.it1.c /*.it1.c
/*.it1.cmperr
/*.it1.o /*.it1.o
/*.it1.py /*.it1.py
/*.it1.py.tmp /*.it1.py.tmp
@ -16,6 +18,7 @@
/*.it1.stdout /*.it1.stdout
/*.it2 /*.it2
/*.it2.c /*.it2.c
/*.it2.cmperr
/*.it2.c.tmp /*.it2.c.tmp
/*.it2.o /*.it2.o
/*.it2.result /*.it2.result

View File

@ -1,5 +1,6 @@
/*.it0 /*.it0
/*.it0.c /*.it0.c
/*.it0.cmperr
/*.it0.o /*.it0.o
/*.it0.py /*.it0.py
/*.it0.py.tmp /*.it0.py.tmp
@ -8,6 +9,7 @@
/*.it0.stdout /*.it0.stdout
/*.it1 /*.it1
/*.it1.c /*.it1.c
/*.it1.cmperr
/*.it1.o /*.it1.o
/*.it1.py /*.it1.py
/*.it1.py.tmp /*.it1.py.tmp
@ -16,6 +18,7 @@
/*.it1.stdout /*.it1.stdout
/*.it2 /*.it2
/*.it2.c /*.it2.c
/*.it2.cmperr
/*.it2.c.tmp /*.it2.c.tmp
/*.it2.o /*.it2.o
/*.it2.result /*.it2.result

View File

@ -1,5 +1,6 @@
/*.it0 /*.it0
/*.it0.c /*.it0.c
/*.it0.cmperr
/*.it0.o /*.it0.o
/*.it0.py /*.it0.py
/*.it0.py.tmp /*.it0.py.tmp
@ -8,6 +9,7 @@
/*.it0.stdout /*.it0.stdout
/*.it1 /*.it1
/*.it1.c /*.it1.c
/*.it1.cmperr
/*.it1.o /*.it1.o
/*.it1.py /*.it1.py
/*.it1.py.tmp /*.it1.py.tmp
@ -16,6 +18,7 @@
/*.it1.stdout /*.it1.stdout
/*.it2 /*.it2
/*.it2.c /*.it2.c
/*.it2.cmperr
/*.it2.c.tmp /*.it2.c.tmp
/*.it2.o /*.it2.o
/*.it2.result /*.it2.result

View File

@ -1,5 +1,6 @@
/*.it0 /*.it0
/*.it0.c /*.it0.c
/*.it0.cmperr
/*.it0.o /*.it0.o
/*.it0.py /*.it0.py
/*.it0.py.tmp /*.it0.py.tmp
@ -8,6 +9,7 @@
/*.it0.stdout /*.it0.stdout
/*.it1 /*.it1
/*.it1.c /*.it1.c
/*.it1.cmperr
/*.it1.o /*.it1.o
/*.it1.py /*.it1.py
/*.it1.py.tmp /*.it1.py.tmp
@ -16,6 +18,7 @@
/*.it1.stdout /*.it1.stdout
/*.it2 /*.it2
/*.it2.c /*.it2.c
/*.it2.cmperr
/*.it2.c.tmp /*.it2.c.tmp
/*.it2.o /*.it2.o
/*.it2.result /*.it2.result

View File

@ -1,5 +1,6 @@
/*.it0 /*.it0
/*.it0.c /*.it0.c
/*.it0.cmperr
/*.it0.o /*.it0.o
/*.it0.py /*.it0.py
/*.it0.py.tmp /*.it0.py.tmp
@ -8,6 +9,7 @@
/*.it0.stdout /*.it0.stdout
/*.it1 /*.it1
/*.it1.c /*.it1.c
/*.it1.cmperr
/*.it1.o /*.it1.o
/*.it1.py /*.it1.py
/*.it1.py.tmp /*.it1.py.tmp
@ -16,6 +18,7 @@
/*.it1.stdout /*.it1.stdout
/*.it2 /*.it2
/*.it2.c /*.it2.c
/*.it2.cmperr
/*.it2.c.tmp /*.it2.c.tmp
/*.it2.o /*.it2.o
/*.it2.result /*.it2.result

26
tests/build/test_validation/.gitignore vendored Normal file
View File

@ -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

View File

@ -1,5 +1,6 @@
/*.it0 /*.it0
/*.it0.c /*.it0.c
/*.it0.cmperr
/*.it0.o /*.it0.o
/*.it0.py /*.it0.py
/*.it0.py.tmp /*.it0.py.tmp
@ -8,6 +9,7 @@
/*.it0.stdout /*.it0.stdout
/*.it1 /*.it1
/*.it1.c /*.it1.c
/*.it1.cmperr
/*.it1.o /*.it1.o
/*.it1.py /*.it1.py
/*.it1.py.tmp /*.it1.py.tmp
@ -16,6 +18,7 @@
/*.it1.stdout /*.it1.stdout
/*.it2 /*.it2
/*.it2.c /*.it2.c
/*.it2.cmperr
/*.it2.c.tmp /*.it2.c.tmp
/*.it2.o /*.it2.o
/*.it2.result /*.it2.result

View File

@ -2,6 +2,12 @@ import glob
import os import os
import sys import sys
STAGE0_MAP = {
'it0': '.py',
'it1': '.py',
'it2': '.c',
}
class Rule: class Rule:
def __init__(self, target: str, prerequisites: list[str], recipe: list[str]) -> None: def __init__(self, target: str, prerequisites: list[str], recipe: list[str]) -> None:
self.target = target self.target = target
@ -23,15 +29,25 @@ def make_rules(file_path, lang0it):
result: list[Rule] = [] result: list[Rule] = []
stdin = file_path.replace('.lang0', '.stdin') 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_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_stderr = 'build/' + file_path.replace('.lang0', f'.{lang0it}.stderr')
act_stdout = 'build/' + file_path.replace('.lang0', f'.{lang0it}.stdout') 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 = '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( result.append(Rule(
act_stdout, act_stdout,
[program] + ([stdin] if os.path.isfile(stdin) else []), [program] + ([stdin] if os.path.isfile(stdin) else []),
@ -43,10 +59,12 @@ def make_rules(file_path, lang0it):
exp_list = [exp_stdout, exp_stderr] exp_list = [exp_stdout, exp_stderr]
act_list = [act_stdout, act_stderr] act_list = [act_stdout, act_stderr]
else:
assert False, f'Missing expectations for {file_path}'
result.append(Rule( result.append(Rule(
act_result, act_result,
[act_stdout] + [ ([program_stage0] if os.path.isfile(exp_cmperr) else [act_stdout]) + [
x x
for x in exp_list for x in exp_list
if os.path.isfile(x) 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 return result
def main(program, write_to, *lang0it): def main(program, write_to, *lang0it):

View File

@ -0,0 +1 @@
11

View File

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

View File

@ -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

View File

@ -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"
/

View File

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

View File

@ -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"
/

View File

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

View File

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

View File

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

View File

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