lang0/1-lang0py/lang0py.lang0
Johan B.W. de Vries 670532059a 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.
2025-05-04 18:06:04 +02:00

603 lines
10 KiB
Plaintext

registerid id:
declare idname
declare newidx
calc idname mapgetkey "REGISTERID" id ""
if idname
return idname
/
calc idname add "id_" id
return idname
/
emitln data:
emit data
emit eol
/
lexident:
declare word
set word ""
forever
calc char peek
calc isbeforea lt char "a"
if isbeforea
break
/
calc isafterz lt "z" char
if isafterz
break
/
calc word add word char
skip
/
return word
/
skipchar exp:
declare act
declare lineno
declare colno
calc act peek
calc lineno stdinlineno
calc colno stdincolno
check eq exp act : "Unexpected character" act "expected" exp "at" lineno colno
skip
/
increaseindent indent:
calc indent add indent " "
return indent
/
parseconststring:
skipchar quote
emit quote
forever
calc char peek
calc iseof eq char eof
if iseof
break
/
calc isquote eq char quote
if isquote
break
/
emit char
skip
/
skipchar quote
emit quote
/
parseexprvarref:
calc varname lexident
calc varid registerid varname
emit varid
/
parseexprcall:
calc funcname lexident
calc funcid registerid funcname
check mapgetkey "FUNCREG" funcname "" : "Function" funcname "does not exist"
emit funcid
emit "("
set first "1"
forever
calc char peek
calc isspace eq char " "
calc isnotspace not isspace
if isnotspace
break
/
skip
calc isfirst eq first "1"
calc isnotfirst not isfirst
if isnotfirst
emit ", "
/
calc char peek
calc isquote eq char quote
calc isnotquote not isquote
if isquote
parseconststring
/
if isnotquote
parseexprvarref
/
set first "0"
/
emit ")"
/
parsestatdeclare indent:
skipchar " "
calc varname lexident
calc varid registerid varname
skipchar eol
/
parsestatset indent:
skipchar " "
calc varname lexident
calc varid registerid varname
skipchar " "
emit indent
emit varid
emit " = "
parseconststring
emit eol
skipchar eol
/
parsestatcalc indent:
skipchar " "
calc varname lexident
calc varid registerid varname
skipchar " "
emit indent
emit varid
emit " = "
parseexprcall
emit eol
skipchar eol
/
parseblock indent/
parsestatif indent:
skipchar " "
emit indent
emit "if "
parseexprvarref
emitln ":"
skipchar eol
calc indent increaseindent indent
parseblock indent
/
parsestatforever indent:
emit indent
emitln "while True:"
skipchar eol
calc indent increaseindent indent
parseblock indent
/
parsestatbreak indent:
emit indent
emitln "break"
skipchar eol
/
parsestatreturn indent:
emit indent
emit "return "
calc char peek
calc isspace eq char " "
calc isnotspace not isspace
if isspace
skip
calc char peek
calc isquote eq char quote
calc isnotquote not isquote
if isquote
parseconststring
/
if isnotquote
parseexprvarref
/
/
if isnotspace
emit quote
emit quote
/
emit eol
skipchar eol
/
parsestatcheck indent:
declare char
declare funcname
declare iscolon
declare isnotquote
declare isquote
declare notfirst
skipchar " "
emit indent
emit "__check("
calc funcname lexident
calc funcid registerid funcname
emit funcid
emit ", ["
set notfirst ""
forever
skipchar " "
calc char peek
calc iscolon eq char ":"
if iscolon
break
/
if notfirst
emit ", "
/
calc char peek
calc isquote eq char quote
calc isnotquote not isquote
if isquote
parseconststring
/
if isnotquote
parseexprvarref
/
set notfirst "1"
/
skipchar ":"
emit "], ["
set notfirst ""
forever
skipchar " "
if notfirst
emit ", "
/
calc char peek
calc isquote eq char quote
calc isnotquote not isquote
if isquote
parseconststring
/
if isnotquote
parseexprvarref
/
calc char peek
calc iseol eq char eol
if iseol
break
/
set notfirst "1"
/
emitln "])"
/
parsestattrace indent:
emit indent
emit "__trace("
emit quote
skipchar " "
calc varname lexident
calc varid registerid varname
emit varname
emit quote
emit ", "
emit varid
emitln ")"
skipchar eol
/
parsestat indent:
calc call lexident
trace call
calc isset eq call "declare"
if isset
parsestatdeclare indent
return
/
calc isset eq call "set"
if isset
parsestatset indent
return
/
calc iscalc eq call "calc"
if iscalc
parsestatcalc indent
return
/
calc isif eq call "if"
if isif
parsestatif indent
return
/
calc isforever eq call "forever"
if isforever
parsestatforever indent
return
/
calc isbreak eq call "break"
if isbreak
parsestatbreak indent
return
/
calc isreturn eq call "return"
if isreturn
parsestatreturn indent
return
/
calc istrace eq call "trace"
if istrace
parsestattrace indent
return
/
calc ischeck eq call "check"
if ischeck
parsestatcheck indent
return
/
check mapgetkey "FUNCREG" call "" : "Function" call "does not exist"
calc callid registerid call
emit indent
emit callid
emit "("
set first "1"
forever
calc char peek
calc isspace eq char " "
calc isnotspace not isspace
if isnotspace
break
/
skip
calc isfirst eq first "1"
calc isnotfirst not isfirst
if isnotfirst
emit ", "
/
calc char peek
calc isquote eq char quote
calc isnotquote not isquote
if isquote
parseconststring
/
if isnotquote
parseexprvarref
/
set first "0"
/
skipchar eol
emitln ")"
/
parseblock indent:
forever
forever
calc char peek
calc iseol eq char eol
calc isnoteol not iseol
if isnoteol
break
/
skip
/
set copy " "
forever
calc isdone eq copy indent
if isdone
break
/
skipchar "\t"
calc copy increaseindent copy
/
calc char peek
calc iseoblock eq char "/"
if iseoblock
skip
skipchar eol
break
/
skipchar "\t"
parsestat indent
/
/
parsefunc:
calc funcname lexident
calc funcid registerid funcname
trace funcname
mapsetkey "FUNCREG" funcname "1"
emit "def "
emit funcid
emit "("
set isnotfirst ""
forever
calc char peek
calc isspace eq char " "
calc isnotspace not isspace
if isnotspace
break
/
skip
calc varname lexident
calc varid registerid varname
if isnotfirst
emit ", "
/
emit varid
set isnotfirst "1"
/
calc char peek
calc iseoblock eq char "/"
if iseoblock
skipchar "/"
skipchar eol
emitln "):"
emitln " pass # ahead declaration"
emit eol
return
/
skipchar ":"
skipchar eol
emitln "):"
parseblock " "
emit eol
/
emitheader:
emitln "import os"
emitln "import sys"
emitln ""
emitln "def __eq(a: str, b: str) -> str:"
emitln " return '1' if a == b else ''"
emitln ""
emitln "def __lt(a: str, b: str) -> str:"
emitln " return '1' if a < b else ''"
emitln ""
emitln "def __not(a: str) -> str:"
emitln " if a:"
emitln " return ''"
emitln " return '1'"
emitln ""
emitln "def __add(a: str, b :str) -> str:"
emitln " return a + b"
emitln ""
emitln "def __emit(string):"
emitln " sys.stdout.buffer.write(string.encode('latin_1'))"
emitln " sys.stdout.flush()"
emitln ""
emitln "def __trace(header, value):"
emitln " if os.environ.get('TRACE'):"
emitln " sys.stderr.write(f'{header}={value!r}\\n')"
emitln ""
emitln "__EOF = chr(0xFF)"
emitln "__EOL = chr(10)"
emitln "__QUOTE = chr(34)"
emitln ""
emitln "STDINCOLNO = 0"
emitln "STDINLINENO = 1"
emitln "STDINPEEK = None"
emitln ""
emitln "def _readchar():"
emitln " char = sys.stdin.read(1)"
emitln " __trace('char', char)"
emitln " if not char:"
emitln " return __EOF"
emitln " return char"
emitln ""
emitln "def __peek():"
emitln " return STDINPEEK"
emitln ""
emitln "def __skip():"
emitln " global STDINCOLNO"
emitln " global STDINLINENO"
emitln " global STDINPEEK"
emitln " if __EOL == STDINPEEK:"
emitln " STDINLINENO += 1"
emitln " STDINCOLNO = 0"
emitln " STDINCOLNO += 1"
emitln " STDINPEEK = _readchar()"
emitln ""
emitln "def __stdinlineno():"
emitln " global STDINLINENO"
emitln " return str(STDINLINENO)"
emitln ""
emitln "def __stdincolno():"
emitln " global STDINCOLNO"
emitln " return str(STDINCOLNO)"
emitln ""
emitln "__skip()"
emitln ""
emitln ""
emitln "MAPSTORE = {}"
emitln ""
emitln "def __mapclear(mapname: str) -> str:"
emitln " MAPSTORE.pop(mapname)"
emitln " return ''"
emitln ""
emitln "def __mapgetkey(mapname: str, key: str, default: str) -> str:"
emitln " return MAPSTORE.get(mapname, {}).get(key, default)"
emitln ""
emitln "def __mapsetkey(mapname: str, key: str, value: str) -> str:"
emitln " MAPSTORE.setdefault(mapname, {})"
emitln " MAPSTORE[mapname][key] = value"
emitln " return ''"
emitln ""
emitln "def __check(func, args: list[str], msg: list[str]) -> None:"
emitln " result = func(*args)"
emitln " if result:"
emitln " return"
emitln ""
emitln " sys.stderr.write('ERROR: ' + ' '.join(msg) + '\\n')"
emitln " sys.stderr.flush()"
emitln " exit(1)"
emitln ""
emitln "# ### END OF RUNTIME ### #"
emitln ""
/
emitfooter:
declare mainid
calc mainid registerid "main"
emitln "if __name__ == '__main__':"
emit " "
emit mainid
emitln "()"
/
main:
emitheader
mapsetkey "REGISTERID" "eof" "__EOF"
mapsetkey "REGISTERID" "eol" "__EOL"
mapsetkey "REGISTERID" "quote" "__QUOTE"
mapsetkey "FUNCREG" "add" "1"
mapsetkey "REGISTERID" "add" "__add"
mapsetkey "FUNCREG" "emit" "1"
mapsetkey "REGISTERID" "emit" "__emit"
mapsetkey "FUNCREG" "eq" "1"
mapsetkey "REGISTERID" "eq" "__eq"
mapsetkey "FUNCREG" "lt" "1"
mapsetkey "REGISTERID" "lt" "__lt"
mapsetkey "FUNCREG" "not" "1"
mapsetkey "REGISTERID" "not" "__not"
mapsetkey "FUNCREG" "mapclear" "1"
mapsetkey "REGISTERID" "mapclear" "__mapclear"
mapsetkey "FUNCREG" "mapgetkey" "1"
mapsetkey "REGISTERID" "mapgetkey" "__mapgetkey"
mapsetkey "FUNCREG" "mapsetkey" "1"
mapsetkey "REGISTERID" "mapsetkey" "__mapsetkey"
mapsetkey "FUNCREG" "peek" "1"
mapsetkey "REGISTERID" "peek" "__peek"
mapsetkey "FUNCREG" "skip" "1"
mapsetkey "REGISTERID" "skip" "__skip"
mapsetkey "FUNCREG" "stdincolno" "1"
mapsetkey "REGISTERID" "stdincolno" "__stdincolno"
mapsetkey "FUNCREG" "stdinlineno" "1"
mapsetkey "REGISTERID" "stdinlineno" "__stdinlineno"
forever
calc char peek
calc iseof eq char eof
if iseof
break
/
forever
calc char peek
calc iseol eq char eol
calc isnoteol not iseol
if isnoteol
break
/
skip
/
parsefunc
/
emitfooter
/