Advertisement
thisismysignup

pico8 repl v34

Dec 14th, 2022
122
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 74.48 KB | None | 0 0
  1. ------------------------
  2. -- Prepare globals
  3. ------------------------
  4.  
  5. local g_ENV, my_ENV, globfuncs = _ENV, {}, {}
  6. for k,v in pairs(_ENV) do
  7.     my_ENV[k] = v
  8.     if (type(v) == "function") globfuncs[k] = true
  9. end
  10.  
  11. local _ENV = my_ENV -- with this, we segregate ourselves from the running code (all global accesses below use _ENV automagically)
  12.  
  13. g_enable_repl, g_last_value = true
  14.  
  15.  
  16. ------------------------
  17. -- Utils
  18. ------------------------
  19.  
  20. -- is ch inside str? (if so, returns index)
  21. function isoneof(ch, str)
  22.     for i=1,#str do
  23.         if (str[i] == ch) return i
  24.     end
  25. end
  26.  
  27. ------------------------
  28. -- Tokenize
  29. ------------------------
  30.  
  31. -- escape sequences in strings (e.g. \n -> new line)
  32. local esc_keys, esc_values = split "a,b,f,n,r,t,v,\\,\",',\n,*,#,-,|,+,^", split "\a,\b,\f,\n,\r,\t,\v,\\,\",',\n,\*,\#,\-,\|,\+,\^"
  33. local escapes = {}
  34. for i=1,#esc_keys do escapes[esc_keys[i]] = esc_values[i] end
  35.  
  36. -- is ch a digit char?
  37. function isdigit(ch)
  38.     return ch and ch >= '0' and ch <= '9'
  39. end
  40. -- is ch a valid identifier char?
  41. function isalnum(ch)
  42.     return ch and (ch >= 'A' and ch <= 'Z' or ch >= 'a' and ch <= 'z' or ch == '_' or ch >= '\x80' or isdigit(ch))
  43. end
  44.  
  45.  
  46. -- extarct string value from quoted string
  47. -- returns value, end index
  48. function dequote(str, i, strlen, quote, fail)
  49.     local rawstr = ''
  50.     while i <= strlen do
  51.         local ch = str[i]
  52.         if (ch == quote) break
  53.         if ch == '\\' then -- handle escape sequences
  54.             i += 1
  55.             local esch = str[i]
  56.             ch = escapes[esch] -- handle normal escapes
  57.             -- hex escape (e.g. \xff)
  58.             if esch == 'x' then
  59.                 esch = tonum('0x'..sub(str,i+1,i+2))
  60.                 if (esch) i += 2 else fail "bad hex escape"
  61.                 ch = chr(esch)
  62.             -- decimal escape (e.g. \014)
  63.             elseif isdigit(esch) then
  64.                 local start = i
  65.                 while isdigit(esch) and i < start + 3 do i += 1; esch = str[i] end
  66.                 i -= 1
  67.                 esch = tonum(sub(str,start,i))
  68.                 if (not esch or esch >= 256) fail "bad decimal escape"
  69.                 ch = chr(esch)
  70.             -- ignore subsequent whitespace
  71.             elseif esch == 'z' then
  72.                 repeat i += 1; esch = str[i] until not isoneof(esch, ' \r\t\f\v\n')
  73.                 if (not esch) fail()
  74.                 ch = ''
  75.                 i -= 1
  76.             elseif not esch then fail() ch='' end
  77.             if (not ch) fail("bad escape: " .. esch) ch=''
  78.         elseif ch == '\n' then
  79.             fail "unterminated string"
  80.             break
  81.         end
  82.         rawstr ..= ch
  83.         i += 1
  84.     end
  85.     if (i > strlen) fail("unterminated string", true)
  86.     return rawstr, i+1
  87. end
  88.  
  89. -- extracts string value from long bracketed string (e.g. [[string]])
  90. -- if comment is true, parse it as a comment - i.e. recursively (pico8-specific)
  91. -- returns value, end index
  92. function delongbracket(str, i, strlen, fail, comment)
  93.     if str[i] == '[' then
  94.         i += 1
  95.         local eq_start = i
  96.         while (str[i] == '=') i += 1
  97.         local start_delim = sub(str,eq_start-1,i)
  98.         local end_delim = ']' .. sub(str,eq_start,i-1) .. ']'
  99.         local j = #end_delim
  100.  
  101.         if str[i] == '[' then
  102.             i += 1
  103.             if (str[i] == '\n') i += 1
  104.             local start, depth = i, 0
  105.             while i <= strlen do
  106.                 local substr = sub(str,i,i+j-1)
  107.                 if comment and substr == start_delim then
  108.                     depth += 1; i += j
  109.                 elseif substr == end_delim then
  110.                     if (depth == 0) return sub(str,start,i-1), i+j
  111.                     depth -= 1; i += j
  112.                 else
  113.                     i += 1
  114.                 end
  115.             end
  116.             fail()
  117.         end
  118.     end
  119.     return nil, i
  120. end
  121.  
  122. -- converts a string into tokens.
  123. --   if strict is set, errors are thrown if invalid, and comments are ignored
  124. -- returns:
  125. --   array of tokens
  126. --   array of the line each token is found at (for if/while shorthand parsing only)
  127. --   array of token start indices
  128. --   array of token end indices
  129. -- A token is:
  130. --   false for invalid
  131. --   true for comment (unless strict)
  132. --   number for numeric literal
  133. --   string for identifier, keyword, or punctuation
  134. --   table for string literal (table contains a single string at position [1])
  135. function tokenize(str, strict)
  136.     local i, line, start = 1, 1
  137.     local tokens, tlines, tstarts, tends, err = {}, {}, {}, {}
  138.  
  139.     local function fail(v, ok)
  140.         if (strict) on_compile_fail(v, start)
  141.         err = v and not ok
  142.     end
  143.  
  144.     -- we support unindexable huge strings up to 64KB (at least as long as pico8 can handle them)
  145.     -- we do this via the below hacks (though it doesn't handle huge tokens over 16KB...)
  146.     local strlen = #str >= 0 and #str or 0x7fff
  147.     while i <= strlen do
  148.         if (i >= 0x4001 and strlen >= 0x7fff) str = sub(str, 0x4001); i -= 0x4000; strlen = #str >= 0 and #str or 0x7fff
  149.        
  150.         start = i
  151.         local ch = str[i]
  152.         local ws, token
  153.         -- whitespace
  154.         if isoneof(ch, ' \r\t\f\v\n') then
  155.             i += 1; ws = true
  156.             if (ch == '\n') line += 1
  157.         -- comment
  158.         elseif isoneof(ch, '-/') and str[i+1] == ch then
  159.             i += 2
  160.             if (ch == '-' and str[i] == '[') token, i = delongbracket(str, i, strlen, fail, true)
  161.             if not token then
  162.                 while (i <= strlen and str[i] != '\n') i += 1
  163.             end
  164.             if (strict) ws = true else add(tokens, true)
  165.         -- number
  166.         elseif isdigit(ch) or (ch == '.' and isdigit(str[i+1])) then
  167.             local digits, dot = "0123456789", true
  168.             -- hex. number (0x...)
  169.             if ch == '0' and isoneof(str[i+1], 'xX') then digits ..= "AaBbCcDdEeFf"; i += 2
  170.             -- binary number (0b...)
  171.             elseif ch == '0' and isoneof(str[i+1], 'bB') then digits = "01"; i += 2
  172.             end
  173.             while true do
  174.                 ch = str[i]
  175.                 if ch == '.' and dot then dot = false
  176.                 elseif not isoneof(ch, digits) then break end
  177.                 i += 1
  178.             end
  179.             token = sub(str,start,i-1)
  180.             if (not tonum(token)) fail "bad number"; token="0"
  181.             add(tokens, tonum(token))
  182.         -- identifier
  183.         elseif isalnum(ch) then
  184.             while isalnum(str[i]) do i += 1 end
  185.             add(tokens, sub(str,start,i-1))
  186.         -- string
  187.         elseif ch == "'" or ch == '"' then
  188.             token, i = dequote(str, i+1, strlen, ch, fail)
  189.             add(tokens, {token})
  190.         -- long-bracket string
  191.         elseif ch == '[' and isoneof(str[i+1], "=[") then
  192.             token, i = delongbracket(str, i, strlen, fail)
  193.             if (not token) fail "invalid long brackets"
  194.             add(tokens, {token})
  195.         -- punctuation
  196.         else
  197.             i += 1
  198.             local ch2,ch3,ch4 = unpack(split(sub(str,i,i+2),""))
  199.             if ch2 == ch and ch3 == ch and isoneof(ch,'.>') then
  200.                 i += 2
  201.                 if (ch4 == "=" and isoneof(ch,'>')) i += 1
  202.             elseif ch2 == ch and ch3 != ch and isoneof(ch,'<>') and isoneof(ch3,'<>') then
  203.                 i += 2
  204.                 if (ch4 == "=") i += 1
  205.             elseif ch2 == ch and isoneof(ch,'.:^<>') then
  206.                 i += 1
  207.                 if (ch3 == "=" and isoneof(ch,'.^<>')) i += 1
  208.             elseif ch2 == '=' and isoneof(ch,'+-*/\\%^&|<>=~!') then i += 1
  209.             elseif isoneof(ch,'+-*/\\%^&|<>=~#(){}[];,?@$.:') then
  210.             else fail("bad char: " .. ch) end
  211.             add(tokens, sub(str,start,i-1))
  212.         end
  213.         if (not ws) add(tlines, line); add(tstarts, start); add(tends, i-1)
  214.         if (err) tokens[#tokens], err = false, false
  215.     end
  216.     return tokens, tlines, tstarts, tends
  217. end
  218.  
  219. ------------------------
  220. -- More Utils
  221. ------------------------
  222.  
  223. -- is obj inside table?
  224. function isin(obj, tab)
  225.     for i=1,#tab do
  226.         if (tab[i] == obj) return i
  227.     end
  228. end
  229.  
  230. -- similar to unpack, except depack(pack(...)) is always ...
  231. function depack(t)
  232.     return unpack(t,1,t.n) -- (unpack defaults to t,1,#t instead)
  233. end
  234.  
  235. -- copy a table
  236. function copy(t)
  237.     local ct = {}
  238.     for k, v in next, t do ct[k] = v end
  239.     return ct
  240. end
  241.  
  242. ------------------------
  243. -- Parse & Eval
  244. ------------------------
  245.  
  246. -- General information:
  247. -- As we parse lua's grammar, we build nodes, which are merely
  248. -- functions that take e (an environment) as the first arg.
  249. -- Parent nodes call their children nodes, thus forming a sort of tree.
  250.  
  251. -- An environment (e) is an array of scope tables
  252. -- the scope table at index 0 contains top-level upvalues like _ENV
  253. -- other scope tables contain locals defined within a local statement (*)
  254. -- Thus, upvalues and locals are accessed the same way
  255.  
  256. -- Expression (expr) parsing returns a (node, setnode, tailcallnode) tuple.
  257. -- node returns the expression's value
  258. -- setnode returns a tuple of the table and key to use for the assignment (**)
  259. -- tailcallnode returns a tuple of the function and args to use for a tail-call
  260. -- setnode and/or tailcallnode are nil if assignment/call is not available
  261.  
  262. -- Note that functions called from within parse_expr instead return a
  263. -- (node, is_prefix, setnode, tailcallnode) tuple, where is_prefix
  264. -- says whether the node can be used as a prefix for calls/etc.
  265.  
  266. -- Statement (stmt) parsing returns a (node, is_end) tuple
  267. -- node returns either:
  268. --   nil to continue execution
  269. --   true to break from loop
  270. --   (0, label object) to goto the label object
  271. --   table to return its depack() from the function
  272. --   function to tail-call it as we return from the function
  273. -- node may also be nil for empty statements
  274. -- is_end is true if the statement must end the block
  275.  
  276. -- (*) We create a table per local statement, instead of per block
  277. --     because by using goto, you can execute a local statement multiple
  278. --     times without leaving a block, each time resulting in a different
  279. --     local (that can be independently captured)
  280.  
  281. -- (**) It would be much simpler for setnode to do the assignment itself,
  282. --      but it would prevent us from mimicking lua's observable left-to-right
  283. --      evaluation behaviour,  where the assignment targets are evaluated
  284. --      before the assignment values.
  285.  
  286. -- On that note, we generally mimic lua's observable left-to-right evaluation
  287. -- behaviour, except that we do true left-to-right evaluation, while lua
  288. -- usually evaluates locals (only!) right before the operation that uses them.
  289. -- This difference can be observed if the local is captured by a closure,
  290. --  e.g: local a=1; print(a + (function() a = 3; return 0 end)())
  291.  
  292. -- anyway:
  293.  
  294. -- identifiers to treat as keywords instead
  295. local keywords = split "and,break,do,else,elseif,end,false,for,function,goto,if,in,local,nil,not,or,repeat,return,then,true,until,while"
  296.  
  297. keyword_map = {}
  298. for kw in all(keywords) do keyword_map[kw] = true end
  299.  
  300. -- is token an assign op (e.g. +=)?
  301. local function is_op_assign(token)
  302.     return type(token) == "string" and token[-1] == '='
  303. end
  304.  
  305. -- tokens that terminate a block
  306. end_tokens = split 'end,else,elseif,until'
  307.  
  308.  
  309.  
  310. -- parses a string, returning a function
  311. -- that receives a global environment (e.g. _ENV) and executes the code
  312. function parse(str )
  313.     -- tokenize the string first
  314.     local tokens, tlines, tstarts = tokenize(str, true)
  315.     -- ti: the token index we're at
  316.     -- e_len: how many environments deep we are
  317.     -- depth: how many blocks deep we are
  318.     local ti, e_len, depth, func_e_len, loop_depth, func_depth = 1, 0, 0 , 0
  319.     local parse_expr, parse_block
  320.     -- gotos: array of functions to evaluate in order to finalize gotos
  321.     -- locals: maps names of locals to the environment array index where
  322.     --         they're defined
  323.     -- labels: maps names of labels to label objects
  324.     --
  325.     -- both locals and labels use a metatable to simulate a sort-of stack
  326.     -- where pushed maps inherit from all previous maps in the stack and
  327.     -- can be easily popped.
  328.     --
  329.     -- endcb: specifies when to stop shorthand parsing
  330.     local gotos, locals, labels, endcb = {}
  331.  
  332.     local function fail(err)
  333.         on_compile_fail(err, tstarts[ti-1] or 1)
  334.     end
  335.  
  336.     -- return a node that returns a constant
  337.     local function const_node(value)
  338.         return function() return value end
  339.     end
  340.     -- return a node that returns the value of a variable
  341.     local function var_node(name)
  342.         local e_i = locals[name]
  343.         if e_i then return function(e) return e[e_i][name] end -- local/upvalue
  344.         else e_i = locals._ENV return function(e) return e[e_i]._ENV[name] end -- global
  345.         end
  346.     end
  347.     -- return a node that returns the values of the vararg arguments
  348.     -- of the current function.
  349.     local function vararg_node()
  350.         local e_i = locals['...']
  351.         if (not e_i or e_i != func_e_len) fail "unexpected '...'"
  352.         return function(e) return depack(e[e_i]["..."]) end
  353.     end
  354.     -- return a setnode that allows assigning to the value of a variable
  355.     local function assign_node(name)
  356.         local e_i = locals[name]
  357.         if e_i then return function(e) return e[e_i], name end -- local/upvalue
  358.         else e_i = locals._ENV return function(e) return e[e_i]._ENV, name end -- global
  359.         end
  360.     end
  361.  
  362.     -- consume the next token, requiring it to be 'expect'
  363.     local function require(expect)
  364.         local token = tokens[ti]; ti += 1
  365.         if (token == expect) return
  366.         if (token == nil) fail()
  367.         fail("expected: " .. expect)
  368.     end
  369.  
  370.     -- consume the next token, requiring it to be an identifier
  371.     -- returns the identifier
  372.     local function require_ident(token)
  373.         if (not token) token = tokens[ti]; ti += 1
  374.         if (token == nil) fail()
  375.         if (type(token) == 'string' and isalnum(token[1]) and not keyword_map[token]) return token
  376.         if (type(token) == 'string') fail("invalid identifier: " .. token)
  377.         fail "identifier expected"
  378.     end
  379.  
  380.     -- if the next token is 'expect', consumes it and returns true
  381.     local function accept(expect)
  382.         if (tokens[ti] == expect) ti += 1; return true
  383.     end
  384.  
  385.     -- return whether we're at the end of a statement
  386.     local function at_stmt_end()
  387.         return isin(tokens[ti], end_tokens) or (endcb and endcb(ti))
  388.     end
  389.  
  390.     -- push a new locals map to the locals 'stack'
  391.     local function push_locals()
  392.         locals = setmetatable({}, {__index=locals})
  393.         e_len += 1
  394.     end
  395.  
  396.     -- pop a locals map from the 'stack'
  397.     local function pop_locals()
  398.         locals = getmetatable(locals).__index
  399.         e_len -= 1
  400.     end
  401.  
  402.     -- evaluate an array of nodes, returning a pack of results
  403.     -- the last node in the array may return an arbitrary number of results,
  404.     -- all of which are packed.
  405.     local function eval_nodes(e, nodes)
  406.         local results = {}
  407.         local n = #nodes
  408.         for i=1,n-1 do
  409.             results[i] = nodes[i](e)
  410.         end
  411.         if n > 0 then
  412.             local values = pack(nodes[n](e))
  413.             if values.n != 1 then
  414.                 for i=1,values.n do
  415.                     results[n + i - 1] = values[i]
  416.                 end
  417.                 n += values.n - 1
  418.             else
  419.                 results[n] = values[1]
  420.             end
  421.         end
  422.         results.n = n
  423.         return results
  424.     end
  425.  
  426.     -- parses a comma-separated list of elements, each parsed via 'parser'
  427.     local function parse_list(parser)
  428.         local list = {}
  429.         add(list, (parser()))
  430.         while accept ',' do
  431.             add(list, (parser()))
  432.         end
  433.         return list
  434.     end
  435.  
  436.     -- parse a call expression
  437.     --   node : call target node
  438.     --   method : method to call for method call expression (e.g. a:b())
  439.     --   arg : single argument node (e.g. for a"b" and a{b})
  440.     -- returns (node, is_prefix (true), setnode (nil), tailcallnode)
  441.     local function parse_call(node, method, arg)
  442.         -- parse the arguments
  443.         local args = {}
  444.         if arg then
  445.             add(args, arg)
  446.         elseif not accept ')' then
  447.             while true do
  448.                 add(args, (parse_expr()))
  449.                 if (accept ')') break
  450.                 require ','
  451.             end
  452.         end
  453.  
  454.         if method then
  455.             return function(e)
  456.                 -- call method
  457.                 local obj = node(e)
  458.                 return obj[method](obj, depack(eval_nodes(e, args)))
  459.             end, true, nil, function(e)
  460.                 -- return ingredients for a method tail-call
  461.                 local obj = node(e)
  462.                 return obj[method], pack(obj, depack(eval_nodes(e, args)))
  463.             end
  464.         else
  465.             return function(e)
  466.                 -- call function
  467.                 return node(e)(depack(eval_nodes(e, args)))
  468.             end, true, nil, function(e)
  469.                 -- return ingredients for a function tail-call
  470.                 return node(e), eval_nodes(e, args)
  471.             end
  472.         end
  473.     end
  474.  
  475.     -- parse a table construction expression (e.g. {1,2,3})
  476.     local function parse_table()
  477.         -- key/value nodes
  478.         local keys, values = {}, {}
  479.         -- splat_i : either #keys if the last item in the table is array-style
  480.         --   (and thus may fill multiple array values), or nil otherwise
  481.         local index, splat_i = 1
  482.         while not accept '}' do
  483.             splat_i = nil
  484.  
  485.             local key, value
  486.             -- e.g. [a]=b
  487.             if accept '[' then
  488.                 key = parse_expr(); require ']'; require '='; value = parse_expr()
  489.             -- e.g. a=b
  490.             elseif tokens[ti+1] == '=' then
  491.                 key = const_node(require_ident()); require '='; value = parse_expr()
  492.             -- e.g. b
  493.             else
  494.                 key = const_node(index); value = parse_expr(); index += 1; splat_i = #keys + 1
  495.             end
  496.  
  497.             add(keys, key); add(values, value)
  498.  
  499.             if (accept '}') break
  500.             if (not accept ';') require ','
  501.         end
  502.  
  503.         return function(e)
  504.             -- constuct table
  505.             -- note: exact behaviour of # may differ from natively created tables
  506.             local table = {}
  507.             for i=1,#keys do
  508.                 if i == splat_i then
  509.                     -- set multiple table elements (e.g. {f()})
  510.                     local key, value = keys[i](e), pack(values[i](e))
  511.                     for j=1,value.n do
  512.                         table[key + j - 1] = value[j]
  513.                     end
  514.                 else
  515.                     -- set table element
  516.                     table[keys[i](e)] = values[i](e)
  517.                 end
  518.             end
  519.             return table
  520.         end
  521.     end
  522.  
  523.     -- parse a function expression or statement
  524.     -- is_stmt : true if statement
  525.     -- is_local: true if local function statement
  526.     local function parse_function(is_stmt, is_local)
  527.        
  528.         -- has_self : function has implicit self arg
  529.         -- setnode : for statements, how to assign the function to a variable
  530.         local name, has_self, setnode
  531.  
  532.         if is_stmt then
  533.             if is_local then
  534.                 -- local function statement
  535.                 push_locals()
  536.                 name = require_ident()
  537.                 locals[name] = e_len
  538.                 setnode = assign_node(name)
  539.                
  540.             else
  541.                 -- function statement
  542.                 name = {require_ident()}
  543.                 -- function name may include multiple .-seprated parts
  544.                 while (accept '.') add(name, require_ident())
  545.                 -- and may include a final :-separated part
  546.                 if (accept ':') add(name, require_ident()); has_self = true
  547.  
  548.                 if #name == 1 then setnode = assign_node(name[1])
  549.                 else
  550.                     local node = var_node(name[1])
  551.                     for i=2,#name-1 do
  552.                         local node_i = node -- capture
  553.                         node = function(e) return node_i(e)[name[i]] end
  554.                     end
  555.                     setnode = function(e) return node(e), name[#name] end
  556.                 end
  557.                
  558.             end
  559.         end
  560.  
  561.         -- parse function params
  562.         local params, vararg = {}
  563.         if (has_self) add(params, 'self')
  564.         require "("
  565.         if not accept ')' then
  566.             while true do
  567.                 if (accept '...') vararg = true; else add(params, require_ident())
  568.                 if (accept ')') break
  569.                 require ','
  570.                 if (vararg) fail "unexpected param after '...'"
  571.             end
  572.         end
  573.  
  574.         -- add function params as locals
  575.         push_locals()
  576.         for param in all(params) do locals[param] = e_len end
  577.         if (vararg) locals['...'] = e_len
  578.  
  579.         -- parse function's body
  580.         local old_gotos, old_depth, old_e_len = gotos, func_depth, func_e_len
  581.         gotos, func_depth, func_e_len = {}, depth + 1, e_len
  582.         local body = parse_block()
  583.         for g in all(gotos) do g() end -- handle gotos
  584.         gotos, func_depth, func_e_len = old_gotos, old_depth, old_e_len
  585.         require 'end'
  586.         pop_locals()
  587.  
  588.         return function(e)
  589.             if (is_local) add(e, {})
  590.  
  591.             -- create the function's environment
  592.             -- note: this is a shallow copy of the environment array,
  593.             --   not of the tables within.
  594.             local func_e = copy(e)
  595.             local expected_e_len = #func_e
  596.  
  597.             -- this is the actual function created
  598.             local func = function(...)
  599.                 local args = pack(...) -- pack args
  600.                
  601.                
  602.  
  603.                 -- normally, when a function exits, its environment
  604.                 -- ends up the same as it started, so it can be reused
  605.                 -- however, if the function didn't exit yet (e.g. recursion)
  606.                 -- we create a copy of the environment to use for this call
  607.                 local my_e = func_e
  608.                 if #my_e != expected_e_len then
  609.                     local new_e = {}
  610.                     for i=0, expected_e_len do new_e[i] = my_e[i] end
  611.                     my_e = new_e
  612.                 end
  613.  
  614.                 -- add scope for params
  615.                 local scope = {}
  616.                 for i=1,#params do scope[params[i]] = args[i] end
  617.  
  618.                 if (vararg) scope['...'] = pack(unpack(args, #params+1, args.n))
  619.  
  620.                 -- evaluate function body
  621.                 add(my_e, scope)
  622.                 local retval = body(my_e)
  623.                 deli(my_e)
  624.  
  625.                
  626.                
  627.                 -- return function result
  628.                 if retval then
  629.                     if (type(retval) == "table") return depack(retval) -- return
  630.                     return retval() -- tailcall
  631.                 end
  632.             end
  633.  
  634.             -- assign or return the function
  635.             if (is_stmt) local d,k = setnode(e); d[k] = func else return func
  636.         end
  637.     end
  638.  
  639.     -- parse a core expression, aka an expression without any suffixes
  640.     -- returns (node, is_prefix, setnode, tailcallnode)
  641.     local function parse_core()
  642.         local token = tokens[ti]; ti += 1
  643.         local arg
  644.         if (token == nil) fail()
  645.         -- nil constant
  646.         if (token == "nil") return const_node()
  647.         -- true constant
  648.         if (token == "true") return const_node(true)
  649.         -- false constant
  650.         if (token == "false") return const_node(false)
  651.         -- number constant
  652.         if (type(token) == "number") return const_node(token)
  653.         -- string constant
  654.         if (type(token) == "table") return const_node(token[1])
  655.         -- table
  656.         if (token == "{") return parse_table()
  657.         -- parentheses (this is NOT an no-op, unlike in most
  658.         --   languages - as it forces the expression to return 1 result)
  659.         if (token == "(") arg = parse_expr(); require ')'; return function(e) return (arg(e)) end, true
  660.         -- unary ops
  661.         if (token == "-") arg = parse_expr(11); return function(e) return -arg(e) end
  662.         if (token == "~") arg = parse_expr(11); return function(e) return ~arg(e) end
  663.         if (token == "not") arg = parse_expr(11); return function(e) return not arg(e) end
  664.         if (token == "#") arg = parse_expr(11); return function(e) return #arg(e) end
  665.         if (token == "@") arg = parse_expr(11); return function(e) return @arg(e) end
  666.         if (token == "%") arg = parse_expr(11); return function(e) return %arg(e) end
  667.         if (token == "$") arg = parse_expr(11); return function(e) return $arg(e) end
  668.         -- function creation
  669.         if (token == 'function') return parse_function()
  670.         -- vararg
  671.         if (token == "...") return vararg_node()
  672.         -- special repl-specific commands
  673.         if (token == "\\") arg = require_ident() return function() return cmd_exec(arg) end, true, function() return cmd_assign(arg) end
  674.         -- identifiers
  675.         if (require_ident(token)) return var_node(token), true, assign_node(token)
  676.         fail("unexpected token: " .. token)
  677.     end
  678.  
  679.     -- parse a binary operation expression
  680.     -- the extra 'v' argument is used only by op-assignment statements
  681.     local function parse_binary_op(token, prec, left, right_expr)
  682.         local right
  683.         if (token == "^" and prec <= 12) right = right_expr(12); return function(e,v) return left(e,v) ^ right(e) end
  684.         if (token == "*" and prec < 10) right = right_expr(10); return function(e,v) return left(e,v) * right(e) end
  685.         if (token == "/" and prec < 10) right = right_expr(10); return function(e,v) return left(e,v) / right(e) end
  686.         if (token == "\\" and prec < 10) right = right_expr(10); return function(e,v) return left(e,v) \ right(e) end
  687.         if (token == "%" and prec < 10) right = right_expr(10); return function(e,v) return left(e,v) % right(e) end
  688.         if (token == "+" and prec < 9) right = right_expr(9); return function(e,v) return left(e,v) + right(e) end
  689.         if (token == "-" and prec < 9) right = right_expr(9); return function(e,v) return left(e,v) - right(e) end
  690.         if (token == ".." and prec <= 8) right = right_expr(8); return function(e,v) return left(e,v) .. right(e) end
  691.         if (token == "<<" and prec < 7) right = right_expr(7); return function(e,v) return left(e,v) << right(e) end
  692.         if (token == ">>" and prec < 7) right = right_expr(7); return function(e,v) return left(e,v) >> right(e) end
  693.         if (token == ">>>" and prec < 7) right = right_expr(7); return function(e,v) return left(e,v) >>> right(e) end
  694.         if (token == "<<>" and prec < 7) right = right_expr(7); return function(e,v) return left(e,v) <<> right(e) end
  695.         if (token == ">><" and prec < 7) right = right_expr(7); return function(e,v) return left(e,v) >>< right(e) end
  696.         if (token == "&" and prec < 6) right = right_expr(6); return function(e,v) return left(e,v) & right(e) end
  697.         if ((token == "^^" or token == "~") and prec < 5) right = right_expr(5); return function(e,v) return left(e,v) ^^ right(e) end
  698.         if (token == "|" and prec < 4) right = right_expr(4); return function(e,v) return left(e,v) | right(e) end
  699.         if (token == "<" and prec < 3) right = right_expr(3); return function(e,v) return left(e,v) < right(e) end
  700.         if (token == ">" and prec < 3) right = right_expr(3); return function(e,v) return left(e,v) > right(e) end
  701.         if (token == "<=" and prec < 3) right = right_expr(3); return function(e,v) return left(e,v) <= right(e) end
  702.         if (token == ">=" and prec < 3) right = right_expr(3); return function(e,v) return left(e,v) >= right(e) end
  703.         if (token == "==" and prec < 3) right = right_expr(3); return function(e,v) return left(e,v) == right(e) end
  704.         if ((token == "~=" or token == "!=") and prec < 3) right = right_expr(3); return function(e,v) return left(e,v) ~= right(e) end
  705.         if (token == "and" and prec < 2) right = right_expr(2); return function(e,v) return left(e,v) and right(e) end
  706.         if (token == "or" and prec < 1) right = right_expr(1); return function(e,v) return left(e,v) or right(e) end
  707.     end
  708.  
  709.     -- given an expression, parses a suffix for this expression, if possible
  710.     -- prec : precedence to not go beyond when parsing
  711.     -- isprefix : true to allow calls/etc. (lua disallows it for certain
  712.     --            expression unless parentheses are used, not sure why)
  713.     -- returns (node, is_prefix, setnode, tailcallnode)
  714.     local function parse_expr_more(prec, left, isprefix)
  715.         local token = tokens[ti]; ti += 1
  716.         local right, arg
  717.         if isprefix then
  718.             -- table index by name
  719.             if (token == '.') right = require_ident(); return function(e) return left(e)[right] end, true, function(e) return left(e), right end
  720.             -- table index
  721.             if (token == '[') right = parse_expr(); require ']'; return function(e) return left(e)[right(e)] end, true, function(e) return left(e), right(e) end
  722.             -- call
  723.             if (token == "(") return parse_call(left)
  724.             -- call with table or string argument
  725.             if (token == "{" or type(token) == "table") ti -= 1; arg = parse_core(); return parse_call(left, nil, arg)
  726.             -- method call
  727.             if token == ":" then
  728.                 right = require_ident();
  729.                 -- ... with table or string argument
  730.                 if (tokens[ti] == "{" or type(tokens[ti]) == "table") arg = parse_core(); return parse_call(left, right, arg)
  731.                 require '('; return parse_call(left, right)
  732.             end
  733.         end
  734.        
  735.         -- binary op
  736.         local node = parse_binary_op(token, prec, left, parse_expr)
  737.         if (not node) ti -= 1
  738.         return node
  739.     end
  740.  
  741.     -- parse an arbitrary expression
  742.     -- prec : precedence to not go beyond when parsing
  743.     -- returns (node, setnode, tailcallnode)
  744.     parse_expr = function(prec)
  745.         local node, isprefix, setnode, callnode = parse_core()
  746.         while true do
  747.             local newnode, newisprefix, newsetnode, newcallnode = parse_expr_more(prec or 0, node, isprefix)
  748.             if (not newnode) break
  749.             node, isprefix, setnode, callnode = newnode, newisprefix, newsetnode, newcallnode
  750.         end
  751.         return node, setnode, callnode
  752.     end
  753.  
  754.     -- parse an assignment expression, returning its setnode
  755.     local function parse_assign_expr()
  756.         local _, assign_expr = parse_expr()
  757.         if (not assign_expr) fail "cannot assign to value"
  758.         return assign_expr
  759.     end
  760.  
  761.     -- parse assignment statement
  762.     local function parse_assign()
  763.         local targets = parse_list(parse_assign_expr)
  764.         require "="
  765.         local sources = parse_list(parse_expr)
  766.  
  767.         if #targets == 1 and #sources == 1 then return function(e)
  768.             -- single assignment (for performance)
  769.             local d,k = targets[1](e); d[k] = sources[1](e)
  770.         end else return function(e)
  771.             -- multiple assignment (e.g. a,b=c,d)
  772.             local dests, keys = {}, {}
  773.             for i=1,#targets do local d,k = targets[i](e); add(dests,d) add(keys,k) end
  774.             local values = eval_nodes(e, sources)
  775.             -- assign from last to first, per observable lua behaviour
  776.             for i=#targets,1,-1 do dests[i][keys[i]] = values[i] end
  777.         end end
  778.     end
  779.  
  780.     -- parse op-assignment statement (e.g. +=)
  781.     -- receives the setnode of the assignment target, and uses it to both get and set the value
  782.     -- (this is to ensure the node is evaluated only once)
  783.     local function parse_op_assign(setnode)
  784.         local token = tokens[ti]; ti += 1
  785.         local op = sub(token,1,-2)
  786.         local node = function(e, v) return v end -- parse_binary_op propagates the value as an extra arg to us
  787.         local op_node = parse_binary_op(op, 0, node, function() return parse_expr() end) -- ignore precedence
  788.         if (not op_node) fail "invalid compound assignment"
  789.         return function(e) local d,k = setnode(e); d[k] = op_node(e, d[k]) end
  790.     end
  791.  
  792.     -- parse local statement
  793.     local function parse_local()
  794.         if accept 'function' then
  795.             -- local function statement
  796.             return parse_function(true, true)
  797.         else
  798.             local targets = parse_list(require_ident)
  799.             local sources = accept '=' and parse_list(parse_expr) or {}
  800.  
  801.             push_locals()
  802.             for i=1,#targets do locals[targets[i]] = e_len end
  803.  
  804.             if #targets == 1 and #sources == 1 then return function(e)
  805.                 -- single local (for performance)
  806.                 add(e, {[targets[1]] = sources[1](e)})
  807.             end else return function(e)
  808.                 -- multiple locals
  809.                 local scope = {}
  810.                 local values = eval_nodes(e, sources)
  811.                 for i=1,#targets do scope[targets[i]] = values[i] end
  812.                 add(e, scope)
  813.             end end
  814.         end
  815.     end
  816.  
  817.     -- start if/while shorthand parsing
  818.     -- allows terminating the parsing of a block at the end of the line
  819.     local function start_shorthand(allowed)
  820.         local line = tlines[ti - 1]
  821.         local prev_endcb = endcb
  822.         endcb = function(i) return line != tlines[i] end
  823.         if (not allowed or endcb(ti)) fail(ti <= #tokens and "unterminated shorthand" or nil)
  824.         return prev_endcb
  825.     end
  826.  
  827.     -- end shorthand parsing, and verify we haven't exceeded the line
  828.     local function end_shorthand(prev_endcb)
  829.         if (endcb(ti-1)) fail("unterminated shorthand")
  830.         endcb = prev_endcb
  831.     end
  832.  
  833.     -- parse an 'if' statement
  834.     local function parse_ifstmt()
  835.         local short = tokens[ti] == '('
  836.         local cond = parse_expr()
  837.         local then_b, else_b
  838.         if accept 'then' then
  839.             -- normal if statement
  840.             then_b, else_b = parse_block()
  841.             if accept 'else' then else_b = parse_block(); require "end" -- else
  842.             elseif accept 'elseif' then else_b = parse_ifstmt() -- elseif
  843.             else require "end" end
  844.         else
  845.             -- shorthand if
  846.             local prev = start_shorthand(short)
  847.             then_b = parse_block()
  848.             if (not endcb(ti) and accept 'else') else_b = parse_block() -- shorhand if/else
  849.             end_shorthand(prev)
  850.         end
  851.  
  852.         return function(e)
  853.             -- execute the if
  854.             if cond(e) then return then_b(e)
  855.             elseif else_b then return else_b(e)
  856.             end
  857.         end
  858.     end
  859.  
  860.     -- parse a loop block, updating loop_depth (for break purposes)
  861.     local function parse_loop_block(...)
  862.         local old_depth = loop_depth
  863.         loop_depth = depth + 1
  864.         local result = parse_block(...)
  865.         loop_depth = old_depth
  866.         return result
  867.     end
  868.  
  869.     -- if retval denotes a break, do not propagate it further
  870.     -- useful when returning from loop blocks
  871.     local function handle_break(retval, label)
  872.         if (retval == true) return -- break
  873.         return retval, label
  874.     end
  875.  
  876.     -- parse a 'while' block
  877.     local function parse_while()
  878.         local short = tokens[ti] == '('
  879.         local cond = parse_expr()
  880.         local body
  881.         if accept 'do' then
  882.             -- normal while statement
  883.             body = parse_loop_block()
  884.             require 'end'
  885.         else
  886.             -- shorthand while statement
  887.             local prev = start_shorthand(short)
  888.             body = parse_loop_block()
  889.             end_shorthand(prev)
  890.         end
  891.  
  892.         return function(e)
  893.             -- execute the while
  894.             while cond(e) do
  895.                 if (stat(1)>=1) yield_execute()
  896.                 local retval, label = body(e)
  897.                 if (retval) return handle_break(retval, label)
  898.             end
  899.         end
  900.     end
  901.  
  902.     -- parse a repeat/until statement
  903.     local function parse_repeat()
  904.         -- note that the until part can reference
  905.         -- locals declared inside the repeat body, thus
  906.         -- we pop the locals/scopes ourselves
  907.         local block_e_len = e_len
  908.         local body = parse_loop_block(true)
  909.         require 'until'
  910.         local cond = parse_expr()
  911.         while (e_len > block_e_len) pop_locals()
  912.  
  913.         return function(e)
  914.             -- execute the repeat/until
  915.             repeat
  916.                 if (stat(1)>=1) yield_execute()
  917.                 local retval, label = body(e)
  918.                 if (not retval) label = cond(e) -- reuse label as the end cond
  919.  
  920.                 while (#e > block_e_len) deli(e) -- pop scopes ourselves
  921.                 if (retval) return handle_break(retval, label)
  922.             until label -- actually the end cond
  923.         end
  924.     end
  925.  
  926.     -- parse a 'for' statement
  927.     local function parse_for()
  928.         if tokens[ti + 1] == '=' then
  929.             -- numeric for statement
  930.             local varb = require_ident()
  931.             require '='
  932.             local min = parse_expr()
  933.             require ','
  934.             local max = parse_expr()
  935.             local step = accept ',' and parse_expr() or const_node(1)
  936.             require 'do'
  937.  
  938.             -- push 'for' local, and parse the body
  939.             push_locals()
  940.             locals[varb] = e_len
  941.             local body = parse_loop_block()
  942.             require 'end'
  943.             pop_locals()
  944.  
  945.             return function(e)
  946.                 -- execute the numeric 'for'
  947.                 for i=min(e),max(e),step(e) do
  948.                     if (stat(1)>=1) yield_execute()
  949.                     add(e, {[varb]=i})
  950.                     local retval, label = body(e)
  951.                     deli(e)
  952.                     if (retval) return handle_break(retval, label)
  953.                 end
  954.             end
  955.         else
  956.             -- generic 'for' block
  957.             local targets = parse_list(require_ident)
  958.             require "in"
  959.             local sources = parse_list(parse_expr)
  960.             require 'do'
  961.  
  962.             -- push 'for' locals, and parse the body
  963.             push_locals()
  964.             for target in all(targets) do locals[target] = e_len end
  965.  
  966.             local body = parse_loop_block()
  967.             require 'end'
  968.             pop_locals()
  969.  
  970.             return function(e)
  971.                 -- execute the generic 'for'
  972.                 -- (must synthesize it ourselves, as a generic for's
  973.                 --  number of vars is fixed)
  974.                 local exps = eval_nodes(e, sources)
  975.                 while true do
  976.                     local scope = {}
  977.  
  978.                     local vars = {exps[1](exps[2], exps[3])}
  979.                     if (vars[1] == nil) break
  980.                     exps[3] = vars[1]
  981.                     for i=1,#targets do scope[targets[i]] = vars[i] end
  982.  
  983.                     if (stat(1)>=1) yield_execute()
  984.                     add(e, scope)
  985.                     local retval, label = body(e)
  986.                     deli(e)
  987.                     if (retval) return handle_break(retval, label)
  988.                 end
  989.             end
  990.         end
  991.     end
  992.  
  993.     -- parse a break statement
  994.     local function parse_break()
  995.         if (not loop_depth or func_depth and loop_depth < func_depth) fail "break outside of loop"
  996.         return function() return true end
  997.     end
  998.  
  999.     -- parse a return statement
  1000.     -- N.B. lua actually allows return (and vararg) in top-level
  1001.     --      this sort-of breaks repuzzle and is confusing/useless in pico,
  1002.     --      so we disallow it.
  1003.     local function parse_return()
  1004.  
  1005.         if tokens[ti] == ';' or at_stmt_end() then
  1006.             -- return no values (represented by us as an empty pack)
  1007.             return function() return pack() end
  1008.         else
  1009.             local node, _, callnode = parse_expr()
  1010.             local nodes = {node}
  1011.             while (accept ',') add(nodes, (parse_expr()))
  1012.  
  1013.             if #nodes == 1 and callnode and func_depth then
  1014.                 -- tail-call (aka jump into other function instead of returning)
  1015.                 return function(e) local func, args = callnode(e);
  1016.                     if (stat(1)>=1) yield_execute()
  1017.                     return function() return func(depack(args)) end
  1018.                 end
  1019.             else
  1020.                 -- normal return
  1021.                 return function(e) return eval_nodes(e, nodes) end
  1022.             end
  1023.         end
  1024.     end
  1025.  
  1026.     -- parse label statement
  1027.     local function parse_label(parent)
  1028.         local label = require_ident()
  1029.         require '::'
  1030.         if (labels[label] and labels[label].depth == depth) fail "label already defined"
  1031.         -- store label object
  1032.         labels[label] = {e_len=e_len, depth=depth, block=parent, i=#parent}
  1033.     end
  1034.  
  1035.     -- parse goto statement
  1036.     local function parse_goto()
  1037.         local label = require_ident()
  1038.         local labels_c, e_len_c, value = labels, e_len -- capture labels
  1039.  
  1040.         -- the label may be defined after the goto, so process the goto
  1041.         -- at function end
  1042.         add(gotos, function ()
  1043.             value = labels_c[label]
  1044.             if (not value) fail "label not found"
  1045.             if (func_depth and value.depth < func_depth) fail "goto outside of function"
  1046.             -- goto cannot enter a scope
  1047.             -- (empty statements at the end of a scope aren't considered a
  1048.             --  part of the scope for this purpose)
  1049.             local goto_e_len = labels_c[value.depth] or e_len_c
  1050.             if (value.e_len > goto_e_len and value.i < #value.block) fail "goto past local"
  1051.         end)
  1052.  
  1053.         return function()
  1054.             if (stat(1)>=1) yield_execute()
  1055.             return 0, value
  1056.         end
  1057.     end
  1058.  
  1059.     -- parse any statement
  1060.     local function parse_stmt(parent)
  1061.         local token = tokens[ti]; ti += 1
  1062.         -- empty semicolon
  1063.         if (token == ';') return
  1064.         -- do-end block
  1065.         if (token == 'do') local node = parse_block(); require 'end'; return node
  1066.         -- if
  1067.         if (token == 'if') return parse_ifstmt()
  1068.         -- while loop
  1069.         if (token == 'while') return parse_while()
  1070.         -- repeat/until loop
  1071.         if (token == 'repeat') return parse_repeat()
  1072.         -- for loop
  1073.         if (token == 'for') return parse_for()
  1074.         -- break
  1075.         if (token == 'break') return parse_break()
  1076.         -- return
  1077.         if (token == 'return') return parse_return(), true
  1078.         -- local
  1079.         if (token == 'local') return parse_local()
  1080.         -- goto
  1081.         if (token == 'goto') return parse_goto()
  1082.         -- label
  1083.         if (token == '::') return parse_label(parent)
  1084.         -- function
  1085.         if (token == 'function' and tokens[ti] != '(') return parse_function(true)
  1086.         -- print shorthand
  1087.         if token == '?' then
  1088.             local print_node, nodes = var_node 'print', parse_list(parse_expr);
  1089.             return function (e) print_node(e)(depack(eval_nodes(e, nodes))) end
  1090.         end
  1091.  
  1092.         -- handle assignments and expressions
  1093.         ti -= 1
  1094.         local start = ti -- allow reparse
  1095.         local node, setnode, callnode = parse_expr()
  1096.  
  1097.         -- assignment
  1098.         if accept ',' or accept '=' then
  1099.             ti = start; return parse_assign()
  1100.         -- op-assignment
  1101.         elseif is_op_assign(tokens[ti]) then
  1102.             return parse_op_assign(setnode)
  1103.         -- repl-specific print of top-level expression
  1104.         elseif depth <= 1 and g_enable_repl then
  1105.             return function (e)
  1106.                 local results = pack(node(e))
  1107.                 if (not (callnode and results.n == 0)) add(g_results, results)
  1108.                 g_last_value = results[1]
  1109.             end
  1110.         -- regular expression statements (must be call)
  1111.         else
  1112.             if (not callnode) fail "statement has no effect"
  1113.             return function(e) node(e) end
  1114.         end
  1115.     end
  1116.  
  1117.     -- parse a block of statements
  1118.     -- keep_locals: true to let the caller exit the block themselves
  1119.     parse_block = function(keep_locals)
  1120.         -- push a new labels map in the labels 'stack'
  1121.         labels = setmetatable({}, {__index=labels})
  1122.         labels[depth] = e_len
  1123.  
  1124.         -- increase depth
  1125.         depth += 1
  1126.         local block_depth = depth
  1127.         local block_e_len = keep_locals and 0x7fff or e_len
  1128.  
  1129.         -- parse block statements
  1130.         local block = {}
  1131.         while ti <= #tokens and not at_stmt_end() do
  1132.             local  stmt, need_end =  parse_stmt(block)
  1133.             if (stmt) add(block, stmt)
  1134.             if (need_end) accept ';'; break
  1135.         end
  1136.  
  1137.         -- pop any locals pushed inside the block
  1138.         while (e_len > block_e_len) pop_locals()
  1139.         depth -= 1
  1140.         labels = getmetatable(labels).__index
  1141.  
  1142.         return function (e)
  1143.             -- execute the block's statements
  1144.             local retval, label
  1145.             local i,n = 1,#block
  1146.             while i <= n do
  1147.                
  1148.                 retval, label = block[i](e)
  1149.                 if retval then
  1150.                     -- handle returns & breaks
  1151.                     if (type(retval) != "number") break
  1152.                     -- handle goto to parent block
  1153.                     if (label.depth != block_depth) break
  1154.                     -- handle goto to this block
  1155.                     i = label.i
  1156.                     while (#e > label.e_len) deli(e)
  1157.                     retval, label = nil
  1158.                 end
  1159.                 i += 1
  1160.             end
  1161.             while (#e > block_e_len) deli(e)
  1162.             return retval, label
  1163.         end
  1164.     end
  1165.    
  1166.     -- create top-level upvalues
  1167.     locals = g_enable_repl and {_ENV=0, _env=0, _=0} or {_ENV=0}
  1168.     locals['...'] = 0
  1169.     -- parse top-level block
  1170.     local root = parse_block()
  1171.     if (ti <= #tokens) fail "unexpected end"
  1172.     -- handle top-level gotos
  1173.     for g in all(gotos) do g() end
  1174.  
  1175.     return function(env, ...)
  1176.         -- create top-level scope
  1177.         local scope = g_enable_repl and {_ENV=env, _env=env, _=g_last_value} or {_ENV=env}
  1178.         scope['...'] = pack(...)
  1179.        
  1180.         -- execute
  1181.                
  1182.         local retval = root{[0]=scope}
  1183.        
  1184.         if (retval) return depack(retval)
  1185.     end
  1186. end
  1187.  
  1188. ------------------------
  1189. -- Output
  1190. ------------------------
  1191.  
  1192. g_show_max_items, g_hex_output, g_precise_output = 10, false, false
  1193.  
  1194.  
  1195. -- reverse mapping of escapes
  1196. local unescapes = {["\0"]="000",["\014"]="014",["\015"]="015"}
  1197. for k, v in pairs(escapes) do
  1198.     if (not isoneof(k, "'\n")) unescapes[v] = k
  1199. end
  1200.  
  1201. -- create quoted string from a string value
  1202. function requote(str)
  1203.     local i = 1
  1204.     while i <= #str do
  1205.         local ch = str[i]
  1206.         local nch = unescapes[ch]
  1207.         if (nch) str = sub(str,1,i-1) .. '\\' .. nch .. sub(str,i+1); i += #nch
  1208.         i += 1
  1209.     end
  1210.     return '"' .. str .. '"'
  1211. end
  1212.  
  1213. -- is 'key' representable as an identifier?
  1214. function is_identifier(key)
  1215.     if (type(key) != 'string') return false
  1216.     if (keyword_map[key]) return false
  1217.     if (#key == 0 or isdigit(key[1])) return false
  1218.     for i=1,#key do
  1219.         if (not isalnum(key[i])) return false
  1220.     end
  1221.     return true
  1222. end
  1223.  
  1224. -- convert value as a string
  1225. -- (more featured than tostr)
  1226. function value_to_str(val, depth)
  1227.     local ty = type(val)
  1228.     -- nil
  1229.     if (ty == 'nil') then
  1230.         return 'nil'
  1231.     -- boolean
  1232.     elseif (ty == 'boolean') then
  1233.         return val and 'true' or 'false'
  1234.     -- number (optionally hex)
  1235.     elseif (ty == 'number') then
  1236.         if (not g_precise_output) return tostr(val, g_hex_output)
  1237.         local str = tostr(val)
  1238.         return tonum(str) == val and str or tostr(val,1)
  1239.     -- string (with quotes)
  1240.     elseif (ty == 'string') then
  1241.         return requote(val)
  1242.     -- table contents
  1243.     elseif (ty == 'table' and not depth) then
  1244.         local res = '{'
  1245.         local i = 0
  1246.         local prev = 0
  1247.         -- avoid pairs, as it uses metamethods
  1248.         for k,v in next, val do
  1249.             if (i == g_show_max_items) res ..= ',<...>' break
  1250.             if (i > 0) res ..= ','
  1251.            
  1252.             local vstr = value_to_str(v,1)
  1253.             if k == prev + 1 then res ..= vstr; prev = k
  1254.             elseif is_identifier(k) then res ..= k .. '=' .. vstr
  1255.             else res ..= '[' .. value_to_str(k,1) ..']=' .. vstr end
  1256.             i += 1
  1257.         end
  1258.        
  1259.         return res .. '}'
  1260.     -- other
  1261.     else
  1262.         return '<' .. tostr(ty) .. '>'
  1263.     end
  1264. end
  1265.  
  1266. -- convert more results into a string
  1267. function results_to_str(str, results)
  1268.     if (results == nil) return str -- no new results
  1269.     if (not str) str = ''
  1270.  
  1271.     local count = min(21,#results)
  1272.     for ir=1, count do
  1273.         if (#str > 0) str ..= '\n'
  1274.  
  1275.         local result = results[ir]
  1276.         if type(result) == 'table' then
  1277.             local line = ''
  1278.             for i=1,result.n do
  1279.                 if (#line > 0) line ..= ', '
  1280.                 line ..= value_to_str(result[i])
  1281.             end
  1282.             str ..= line
  1283.         else
  1284.             str ..= result
  1285.         end
  1286.     end
  1287.  
  1288.     local new_results = {}
  1289.     for i=count+1, #results do new_results[i - count] = results[i] end
  1290.     return str, new_results
  1291. end
  1292.  
  1293. ------------------------
  1294. -- Console output
  1295. ------------------------
  1296.  
  1297. poke(0x5f2d,1) -- enable keyboard
  1298. cls()
  1299.  
  1300. g_prompt = "> " -- currently must be valid token!
  1301. g_input, g_input_lines, g_input_start = "", 1, 0
  1302. g_cursor_pos, g_cursor_time = 1, 20
  1303. --lint: g_str_output, g_error_output
  1304. g_history, g_history_i = {''}, 1
  1305. --lint: g_interrupt, g_notice, g_notice_time
  1306. g_abort = false
  1307. g_num_output_lines, g_line = 0, 1
  1308.  
  1309. g_enable_interrupt, g_enable_autoflip = true, true
  1310. g_pal = split "7,4,3,5,6,8,5,12,14,7,11,5"
  1311.  
  1312. -- override print for better output
  1313. g_ENV.print = function(value, ...)
  1314.     if (pack(...).n != 0 or not g_enable_interrupt) return print(value, ...)
  1315.  
  1316.     add(g_results, tostr(value))
  1317. end
  1318.  
  1319. -- suppress pause (e.g. from p, etc.)
  1320. function unpause()
  1321.     poke(0x5f30,1)
  1322. end
  1323.  
  1324. -- an iterator over pressed keys
  1325. function get_keys()
  1326.     return function()
  1327.         if (stat(30)) return stat(31)
  1328.     end
  1329. end
  1330.  
  1331. -- walk over a string, calling a callback on its chars
  1332. function walk_str(str, cb)
  1333.     local i = 1
  1334.     local x, y = 0, 0
  1335.     if (not str) return i, x, y
  1336.     while i <= #str do
  1337.         local ch = str[i]
  1338.         local spch = ch >= '\x80'
  1339.         if (x >= (spch and 31 or 32)) y += 1; x = 0
  1340.         if (cb) cb(i,ch,x,y)
  1341.  
  1342.         if ch == '\n' then y += 1; x = 0
  1343.         else x += (spch and 2 or 1) end
  1344.         i += 1
  1345.     end
  1346.     return i, x, y
  1347. end
  1348.  
  1349. -- given string and index, return x,y at index
  1350. function str_i2xy(str, ci)
  1351.     local cx, cy = 0, 0
  1352.     local ei, ex, ey = walk_str(str, function(i,ch,x,y)
  1353.         if (ci == i) cx, cy = x, y
  1354.     end)
  1355.     if (ci >= ei) cx, cy = ex, ey
  1356.     if (ex > 0) ey += 1
  1357.     return cx, cy, ey
  1358. end
  1359.  
  1360. -- given string and x,y - return index at x,y
  1361. function str_xy2i(str, cx, cy)
  1362.     local ci = 1
  1363.     local found = false
  1364.     local ei, ex, ey = walk_str(str, function(i,ch,x,y)
  1365.         if (cy == y and cx == x and not found) ci = i; found = true
  1366.         if ((cy < y or cy == y and cx < x) and not found) ci = i - 1; found = true
  1367.     end)
  1368.     if (not found) ci = cy >= ey and ei or ei - 1
  1369.     if (ex > 0) ey += 1
  1370.     return ci, ey
  1371. end
  1372.  
  1373. -- print string at position, using color value or function
  1374. function str_print(str, xpos, ypos, color)
  1375.     if type(color) == "function" then
  1376.         walk_str(str, function(i,ch,x,y)
  1377.             print(ch, xpos + x*4, ypos + y*6, color(i))
  1378.         end)
  1379.     else
  1380.         print(str and "\^rw" .. str, xpos, ypos, color)
  1381.     end
  1382. end
  1383.  
  1384. -- print code, using syntax highlighting
  1385. function str_print_input(input, xpos, ypos)
  1386.     local tokens, _, tstarts, tends = tokenize(input) -- tlines not reliable!
  1387.     local ti = 1
  1388.     str_print(input, xpos, ypos, function(i)
  1389.         while ti <= #tends and tends[ti] < i do ti += 1 end
  1390.  
  1391.         local token
  1392.         if (ti <= #tends and tstarts[ti] <= i) token = tokens[ti]
  1393.  
  1394.         local c = g_pal[5]
  1395.         if token == false then c = g_pal[6] -- error
  1396.         elseif token == true then c = g_pal[7] -- comment
  1397.         elseif type(token) != 'string' or isin(token, {"nil","true","false"}) then c = g_pal[8]
  1398.         elseif keyword_map[token] then c = g_pal[9]
  1399.         elseif not isalnum(token[1]) then c = g_pal[10]
  1400.         elseif globfuncs[token] then c = g_pal[11] end
  1401.  
  1402.         return c
  1403.     end)
  1404. end
  1405.  
  1406. -- draw (messy...)
  1407. function _draw()
  1408.     local old_color = peek(0x5f25)
  1409.     local old_camx, old_camy = peek2(0x5f28), peek2(0x5f2a)
  1410.     camera()
  1411.  
  1412.     local function scroll(count)
  1413.         cursor(0,127)
  1414.         for _=1,count do
  1415.             rectfill(0,g_line*6,127,(g_line+1)*6-1,0)
  1416.             if g_line < 21 then
  1417.                 g_line += 1
  1418.             else
  1419.                 print ""
  1420.             end
  1421.         end
  1422.     end
  1423.  
  1424.     local function unscroll(count, minline)
  1425.         for _=1,count do
  1426.             if (g_line > minline) g_line -= 1
  1427.             rectfill(0,g_line*6,127,(g_line+1)*6-1,0)
  1428.         end
  1429.     end
  1430.  
  1431.     local function draw_cursor(x, y)
  1432.         for i=0,2 do
  1433.             local c = pget(x+i,y+5)
  1434.             pset(x+i,y+5,c==0 and g_pal[12] or 0)
  1435.         end
  1436.     end
  1437.  
  1438.     local function draw_input(cursor)
  1439.         local input = g_prompt .. g_input .. ' '
  1440.         local cx, cy, ilines = str_i2xy(input, #g_prompt + g_cursor_pos) -- ' ' is cursor placeholder
  1441.  
  1442.         if ilines > g_input_lines then
  1443.             scroll(ilines - g_input_lines)
  1444.         elseif ilines < g_input_lines then
  1445.             unscroll(g_input_lines - ilines, ilines)
  1446.         end
  1447.         g_input_lines = ilines
  1448.  
  1449.         g_input_start = mid(g_input_start, 0, max(g_input_lines - 21, 0))
  1450.  
  1451.         ::again::
  1452.         local sy = g_line - g_input_lines + g_input_start
  1453.         if (sy+cy < 0) g_input_start += 1; goto again
  1454.         if (sy+cy >= 21) g_input_start -= 1; goto again
  1455.  
  1456.         local y = sy*6
  1457.         rectfill(0,y,127,y+g_input_lines*6-1,0)
  1458.         if (g_input_lines>21) rectfill(0,126,127,127,0) -- clear partial line
  1459.         str_print_input(input,0,y)
  1460.         print(g_prompt,0,y,g_pal[4])
  1461.  
  1462.         if (g_cursor_time >= 10 and cursor != false and not g_interrupt) draw_cursor(cx*4, y + cy*6)
  1463.     end
  1464.  
  1465.     -- require pressing enter to view more results
  1466.     local function page_interrupt(page_olines)
  1467.         scroll(1)
  1468.         g_line -= 1
  1469.         print("[enter] ('esc' to abort)",0,g_line*6,g_pal[3])
  1470.  
  1471.         while true do
  1472.             flip(); unpause()
  1473.             for key in get_keys() do
  1474.                 if (key == '\x1b') g_abort = true; g_str_output = ''; g_results = {}; return false
  1475.                 if (key == '\r' or key == '\n') g_num_output_lines += page_olines; return true
  1476.             end
  1477.         end
  1478.     end
  1479.  
  1480.     ::again::
  1481.     local ostart, olines
  1482.     if g_results or g_str_output then
  1483.         ostart, olines = str_xy2i(g_str_output, 0, g_num_output_lines)
  1484.         if olines - g_num_output_lines <= 20 and g_results then -- add more output
  1485.             g_str_output, g_results = results_to_str(g_str_output, g_results)
  1486.             ostart, olines = str_xy2i(g_str_output, 0, g_num_output_lines)
  1487.             if (#g_results == 0 and not g_interrupt) g_results = nil
  1488.         end
  1489.     end
  1490.  
  1491.     if (not g_interrupt) camera()
  1492.  
  1493.     if (g_num_output_lines == 0 and not g_interrupt) draw_input(not g_str_output)
  1494.  
  1495.     if g_str_output then
  1496.         local output = sub(g_str_output, ostart)
  1497.         local page_olines = min(olines - g_num_output_lines, 20)
  1498.  
  1499.         scroll(page_olines)
  1500.         str_print(output,0,(g_line - page_olines)*6,g_pal[1])
  1501.  
  1502.         if page_olines < olines - g_num_output_lines then
  1503.             if (page_interrupt(page_olines)) goto again
  1504.         else
  1505.             local _, _, elines = str_i2xy(g_error_output, 0)
  1506.             scroll(elines)
  1507.             str_print(g_error_output,0,(g_line - elines)*6,g_pal[2])
  1508.  
  1509.             if g_interrupt then
  1510.                 g_num_output_lines += page_olines
  1511.             else
  1512.                 g_input, g_input_lines, g_input_start, g_cursor_pos, g_num_output_lines, g_str_output, g_error_output =
  1513.                     '', 0, 0, 1, 0
  1514.                 draw_input()
  1515.             end
  1516.         end
  1517.     end
  1518.  
  1519.     if g_interrupt then
  1520.         scroll(1)
  1521.         g_line -= 1
  1522.         print(g_interrupt,0,g_line*6,g_pal[3])
  1523.     end
  1524.  
  1525.     if g_notice then
  1526.         scroll(1)
  1527.         g_line -= 1
  1528.         print(g_notice,0,g_line*6,g_pal[3])
  1529.         g_notice = nil
  1530.     end
  1531.  
  1532.     if g_notice_time then
  1533.         g_notice_time -= 1
  1534.         if (g_notice_time == 0) g_notice, g_notice_time = ''
  1535.     end
  1536.  
  1537.     g_cursor_time -= 1
  1538.     if (g_cursor_time == 0) g_cursor_time = 20
  1539.  
  1540.     color(old_color)
  1541.     camera(old_camx, old_camy)
  1542.     if (g_line <= 20) cursor(0, g_line * 6)
  1543. end
  1544.  
  1545. ------------------------
  1546. --- Execution loop
  1547. ------------------------
  1548.  
  1549. g_in_execute_yield, g_in_mainloop, g_from_flip = false, false, false
  1550. g_pending_keys = {}
  1551. --lint: g_results, g_error, g_error_idx
  1552.  
  1553. -- report compilation error
  1554. -- an error of nil means code is likely incomplete
  1555. function on_compile_fail(err, idx)
  1556.     g_error, g_error_idx = err, idx
  1557.     assert(false, err)
  1558. end
  1559.  
  1560. -- execute code
  1561. function execute_raw(line, env, ...)
  1562.     return parse(line)(env or g_ENV, ...)
  1563. end
  1564.  
  1565. -- evaluate code
  1566. function eval_raw(expr, env, ...)
  1567.     return execute_raw("return " .. expr, env, ...)
  1568. end
  1569.  
  1570. -- try parse code
  1571. function try_parse(line)
  1572.     local cc = cocreate(parse)
  1573.     ::_::
  1574.     local ok, result = coresume(cc, line)
  1575.     if (ok and not result) goto _ -- this shouldn't happen anymore, but does (pico bug?)
  1576.     if (not ok) result, g_error = g_error, false
  1577.     return ok, result
  1578. end
  1579.  
  1580. function pos_to_str(line, idx)
  1581.     local x, y = str_i2xy(line, idx)
  1582.     return "line " .. y+1 .. " col " .. x+1
  1583. end
  1584.  
  1585. -- execute code
  1586. function execute(line, complete)
  1587.     g_results, g_abort, g_error = {}, false, false
  1588.     g_in_execute_yield, g_in_mainloop, g_from_flip = false, false, false
  1589.  
  1590.     -- create a coroutine to allow the code to yield to us periodically
  1591.     local coro = cocreate(function ()
  1592.         local results = pack(execute_raw(line))
  1593.         if (results.n != 0) add(g_results, results)
  1594.     end)
  1595.     local _ok, error
  1596.     while true do
  1597.         _ok, error = coresume(coro)
  1598.         if (costatus(coro) == 'dead') break
  1599.  
  1600.         -- handle yields (due to yield/flip or periodic)
  1601.         if g_enable_interrupt and not g_in_mainloop then
  1602.             g_interrupt = "running, press 'esc' to abort"
  1603.             _draw(); flip()
  1604.             g_interrupt = nil
  1605.         else
  1606.             if (g_enable_autoflip and not g_in_mainloop and not g_from_flip) flip()
  1607.             if (not g_enable_autoflip and holdframe) holdframe()
  1608.             g_from_flip = false
  1609.         end
  1610.  
  1611.         for key in get_keys() do
  1612.             if key == '\x1b' then g_abort = true
  1613.             else add(g_pending_keys, key) end
  1614.         end
  1615.  
  1616.         -- abort execution if needed
  1617.         if (g_abort) error = 'computation aborted'; break
  1618.     end
  1619.  
  1620.     if g_error == nil then -- code is incomplete
  1621.         if (complete) error = "unexpected end of code" else error, g_results = nil
  1622.     end
  1623.     if (g_error) error, g_error = g_error .. "\nat " .. pos_to_str(line, g_error_idx)
  1624.     g_error_output = error
  1625.     g_pending_keys = {}
  1626.     return not error
  1627. end
  1628.  
  1629. -- called periodically during execution
  1630. yield_execute = function ()
  1631.     -- yield all the way back to us
  1632.     g_in_execute_yield = true
  1633.     yield()
  1634.     g_in_execute_yield = false
  1635. end
  1636.  
  1637. -- override flip to force a yield_execute
  1638. g_ENV.flip = function(...)
  1639.     local results = pack(flip(...))
  1640.     g_from_flip = true
  1641.     yield_execute()
  1642.     return depack(results)
  1643. end
  1644.  
  1645. -- override coresume to handle yield_execute in coroutines
  1646. g_ENV.coresume = function(co, ...)
  1647.     local results = pack(coresume(co, ...))
  1648.     -- propagate yields from yield_execute
  1649.     while g_in_execute_yield do
  1650.         yield()
  1651.         results = pack(coresume(co)) -- and resume
  1652.     end
  1653.     g_error = false -- discard inner compilation errors (via \x)
  1654.     return depack(results)
  1655. end
  1656.  
  1657. -- override stat so we can handle keys ourselves
  1658. g_ENV.stat = function(i, ...)
  1659.     if i == 30 then
  1660.         return #g_pending_keys > 0 or stat(i, ...)
  1661.     elseif i == 31 then
  1662.         if #g_pending_keys > 0 then
  1663.             return deli(g_pending_keys, 1)
  1664.         else
  1665.             local key = stat(i, ...)
  1666.             if (key == '\x1b') g_abort = true
  1667.             return key
  1668.         end
  1669.     else
  1670.         return stat(i, ...)
  1671.     end
  1672. end
  1673.  
  1674. -- simulate a mainloop.
  1675. -- NOTE:
  1676. --   real mainloop disables time/btnp updates, and also can't be recursed into/quit legally.
  1677. --   the below doesn't disable time/btnp updates at all - but that's not important enough for us.
  1678. function do_mainloop(env, continue)
  1679.     if not continue then
  1680.         if (_set_fps) _set_fps(env._update60 and 60 or 30)
  1681.         if (env._init) env._init()
  1682.     end
  1683.     g_in_mainloop = true
  1684.     while env._draw or env._update or env._update60 do
  1685.         -- if (_update_buttons) _update_buttons() -- this breaks btnp in its current form
  1686.         if (holdframe) holdframe()
  1687.         if env._update60 then env._update60() elseif env._update then env._update() end
  1688.         if (env._draw) env._draw()
  1689.         flip()
  1690.         g_from_flip = true
  1691.         yield_execute()
  1692.     end
  1693.     g_in_mainloop = false
  1694. end
  1695.  
  1696. ------------------------
  1697. -- Cart decompression
  1698. ------------------------
  1699.  
  1700. k_old_code_table = "\n 0123456789abcdefghijklmnopqrstuvwxyz!#%(){}[]<>+=/*:;.,~_"
  1701.  
  1702. -- Old code compression scheme - encodes offset+count for repeated code
  1703. function uncompress_code_old(comp)
  1704.     local code, i = "", 9
  1705.     while true do
  1706.         local ch = ord(comp, i); i += 1
  1707.         if ch == 0 then
  1708.             -- any pico8 char
  1709.             local ch2 = comp[i]; i += 1
  1710.             if (ch2 == '\0') break -- end
  1711.             code ..= ch2
  1712.         elseif ch <= 0x3b then
  1713.             -- quick char from table
  1714.             code ..= k_old_code_table[ch]
  1715.         else
  1716.             -- copy previous code
  1717.             local ch2 = ord(comp, i); i += 1
  1718.             local count = (ch2 >> 4) + 2
  1719.             local offset = ((ch - 0x3c) << 4) + (ch2 & 0xf)
  1720.             for _=1,count do
  1721.                 code ..= code[-offset]
  1722.             end
  1723.         end
  1724.     end
  1725.     return code
  1726. end
  1727.  
  1728. -- New code compression scheme - also uses move-to-front (mtf) and bit reading
  1729. function uncompress_code_new(comp)
  1730.     local code, i, shift, mtf = "", 9, 0, {}
  1731.  
  1732.     for idx=0,0xff do mtf[idx] = chr(idx) end
  1733.  
  1734.     local function getbit()
  1735.         local bit = (ord(comp, i) >> shift) & 1
  1736.         shift += 1
  1737.         if (shift == 8) i += 1; shift = 0
  1738.         return bit == 1
  1739.     end
  1740.     local function getbits(n)
  1741.         local value = 0
  1742.         for bit=0,n-1 do -- NOT fast
  1743.             value |= tonum(getbit()) << bit
  1744.         end
  1745.         return value
  1746.     end
  1747.  
  1748.     while true do
  1749.         if getbit() then
  1750.             -- literal char
  1751.             local nbits, idx = 4, 0
  1752.             while (getbit()) idx |= 1 << nbits; nbits += 1
  1753.             idx += getbits(nbits)
  1754.  
  1755.             local ch = mtf[idx]
  1756.             code ..= ch
  1757.  
  1758.             -- update mtf
  1759.             for j=idx,1,-1 do
  1760.                 mtf[j] = mtf[j-1]
  1761.             end
  1762.             mtf[0] = ch
  1763.         else
  1764.             -- copy previous code (usually)
  1765.             local obits = getbit() and (getbit() and 5 or 10) or 15
  1766.             local offset = getbits(obits) + 1
  1767.  
  1768.             if offset == 1 and obits == 15 then
  1769.                 break -- not an official way to recognize end, but works
  1770.             elseif offset == 1 and obits == 10 then
  1771.                 -- raw block
  1772.                 while true do
  1773.                     local ch = getbits(8)
  1774.                     if (ch == 0) break else code ..= chr(ch)
  1775.                 end
  1776.             else
  1777.                 local count = 3
  1778.                 repeat
  1779.                     local part = getbits(3)
  1780.                     count += part
  1781.                 until part != 7
  1782.  
  1783.                 for _=1,count do
  1784.                     -- we assume 0x8000 isn't a valid offset (pico8 doesn't produce it)
  1785.                     code ..= code[-offset]
  1786.                 end
  1787.             end
  1788.         end
  1789.     end
  1790.     return code
  1791. end
  1792.  
  1793. ------------------------
  1794. -- Console input
  1795. ------------------------
  1796.  
  1797. --lint: g_ideal_x, g_key_code
  1798. g_prev_paste = stat(4)
  1799. g_key_time, g_lower = 0, false
  1800.  
  1801. poke(0x5f5c,10,2) -- faster btnp
  1802.  
  1803. -- return if keyboard key is pressed, using btnp-like logic
  1804. function keyp(code)
  1805.     if stat(28,code) then
  1806.         if (code != g_key_code) g_key_code, g_key_time = code, 0
  1807.         return g_key_time == 0 or (g_key_time >= 10 and g_key_time % 2 == 0)
  1808.     elseif g_key_code == code then
  1809.         g_key_code = nil
  1810.     end
  1811. end
  1812.  
  1813. -- update console input
  1814. function _update()
  1815.     local input = false
  1816.  
  1817.     local function go_line(dy)
  1818.         local cx, cy, h = str_i2xy(g_prompt .. g_input, #g_prompt + g_cursor_pos)
  1819.         if (g_ideal_x) cx = g_ideal_x
  1820.         cy += dy
  1821.         if (not (cy >= 0 and cy < h)) return false
  1822.         g_cursor_pos = max(str_xy2i(g_prompt .. g_input, cx, cy) - #g_prompt, 1)
  1823.         g_ideal_x = cx
  1824.         g_cursor_time = 20 -- setting input clears ideal x
  1825.         return true
  1826.     end
  1827.  
  1828.     local function go_edge(dx)
  1829.         local cx, cy = str_i2xy(g_prompt .. g_input, #g_prompt + g_cursor_pos)
  1830.         cx = dx > 0 and 100 or 0
  1831.         g_cursor_pos = max(str_xy2i(g_prompt .. g_input, cx, cy) - #g_prompt, 1)
  1832.         input = true
  1833.     end
  1834.  
  1835.     local function go_history(di)
  1836.         g_history[g_history_i] = g_input
  1837.         g_history_i += di
  1838.         g_input = g_history[g_history_i]
  1839.         if di < 0 then
  1840.             g_cursor_pos = #g_input + 1
  1841.         else
  1842.             g_cursor_pos = max(str_xy2i(g_prompt .. g_input, 32, 0) - #g_prompt, 1) -- end of first line
  1843.             local ch = g_input[g_cursor_pos]
  1844.             if (ch and ch != '\n') g_cursor_pos -= 1
  1845.         end
  1846.         input = true
  1847.     end
  1848.  
  1849.     local function push_history()
  1850.         if #g_input > 0 then
  1851.             if (#g_history > 50) del(g_history, g_history[1])
  1852.             g_history[#g_history] = g_input
  1853.             add(g_history, '')
  1854.             g_history_i = #g_history
  1855.             input = true
  1856.         end
  1857.     end
  1858.  
  1859.     local function delchar(offset)
  1860.         if (g_cursor_pos+offset > 0) then
  1861.             g_input = sub(g_input,1,g_cursor_pos+offset-1) .. sub(g_input,g_cursor_pos+offset+1)
  1862.             g_cursor_pos += offset
  1863.             input = true
  1864.         end
  1865.     end
  1866.  
  1867.     local function inschar(key)
  1868.         g_input = sub(g_input,1,g_cursor_pos-1) .. key .. sub(g_input,g_cursor_pos)
  1869.         g_cursor_pos += #key
  1870.         input = true
  1871.     end
  1872.  
  1873.     local ctrl = stat(28,224) or stat(28,228)
  1874.     local shift = stat(28,225) or stat(28,229)
  1875.  
  1876.     local keycode = -1
  1877.     if keyp(80) then -- left
  1878.         if (g_cursor_pos > 1) g_cursor_pos -= 1; input = true
  1879.     elseif keyp(79) then -- right
  1880.         if (g_cursor_pos <= #g_input) g_cursor_pos += 1; input = true
  1881.     elseif keyp(82) then -- up
  1882.         if ((ctrl or not go_line(-1)) and g_history_i > 1) go_history(-1)
  1883.     elseif keyp(81) then -- down
  1884.         if ((ctrl or not go_line(1)) and g_history_i < #g_history) go_history(1)
  1885.     else
  1886.         local key = stat(31)
  1887.         keycode = ord(key)
  1888.  
  1889.         if key == '\x1b' then -- escape
  1890.             if #g_input == 0 then extcmd "pause"
  1891.             else g_results, g_error_output = {}; push_history() end
  1892.         elseif key == '\r' or key == '\n' then -- enter
  1893.             if shift then
  1894.                 inschar '\n'
  1895.             else
  1896.                 execute(g_input) -- sets g_results/g_error_output
  1897.                 if (not g_results) inschar '\n' else push_history()
  1898.             end
  1899.         elseif ctrl and keyp(40) then -- ctrl+enter
  1900.             execute(g_input, true); push_history()
  1901.         elseif key != '' and keycode >= 0x20 and keycode < 0x9a then -- ignore ctrl-junk
  1902.             if (g_lower and keycode >= 0x80) key = chr(keycode - 63)
  1903.             inschar(key)
  1904.         elseif keycode == 193 then -- ctrl+b
  1905.             inschar '\n'
  1906.         elseif keycode == 192 then -- ctrl+a
  1907.             go_edge(-1)
  1908.         elseif keycode == 196 then -- ctrl+e
  1909.             go_edge(1)
  1910.         elseif keycode == 203 then -- ctrl+l
  1911.             g_lower = not g_lower
  1912.             g_notice, g_notice_time = "shift now selects " .. (g_lower and "punycase" or "symbols"), 40
  1913.         elseif keyp(74) then -- home
  1914.             if (ctrl) g_cursor_pos = 1; input = true else go_edge(-1);
  1915.         elseif keyp(77) then -- end
  1916.             if (ctrl) g_cursor_pos = #g_input + 1; input = true else go_edge(1);        
  1917.         elseif keyp(42) then delchar(-1) -- backspace
  1918.         elseif keyp(76) then delchar(0) -- del
  1919.         end
  1920.     end
  1921.  
  1922.     local paste = stat(4)
  1923.     if (paste != g_prev_paste or keycode == 213) inschar(paste); g_prev_paste = paste -- ctrl+v
  1924.  
  1925.     if keycode == 194 or keycode == 215 then -- ctrl+x/c
  1926.         if g_input != '' and g_input != g_prev_paste then
  1927.             g_prev_paste = g_input; printh(g_input, "@clip");
  1928.             if (keycode == 215) g_input = ''; g_cursor_pos = 1;
  1929.             g_notice = "press again to put in clipboard"
  1930.         else
  1931.             g_notice = ''
  1932.         end
  1933.     end
  1934.  
  1935.     if stat(120) then -- file drop
  1936.         local str, count = ""
  1937.         repeat
  1938.             count = serial(0x800,0x5f80,0x80)
  1939.             str ..= chr(peek(0x5f80,count))
  1940.         until count == 0
  1941.         if (not load_cart(str)) inschar(str)
  1942.     end
  1943.  
  1944.     if (input) g_cursor_time, g_ideal_x = 20
  1945.     g_key_time += 1
  1946.  
  1947.     unpause()
  1948. end
  1949.  
  1950. ------------------------
  1951. -- Main
  1952. ------------------------
  1953.  
  1954. -- my own crummy mainloop, since time() does not seem to update if the regular mainloop goes "rogue" and flips.
  1955. function toplevel_main()
  1956.     while true do
  1957.         if (holdframe) holdframe()
  1958.         _update()
  1959.         _draw()
  1960.         flip()
  1961.     end
  1962. end
  1963.  
  1964. -- Self-test
  1965. -- (so I can more easily see if something got regressed in the future (esp. due to pico8 changes))
  1966.  
  1967. function selftest(i, cb)
  1968.     local ok, error = coresume(cocreate(cb))
  1969.     if not ok then
  1970.         printh("error #" .. i .. ": " .. error)
  1971.         print("error #" .. i .. "\npico8 broke something again,\nthis cart may not work.\npress any button to ignore")
  1972.         while (btnp() == 0) flip()
  1973.         cls()
  1974.     end
  1975. end
  1976.  
  1977. selftest(1, function() assert(pack(eval_raw "(function (...) return ... end)(1,2,nil,nil)" ).n == 4) end)
  1978. selftest(2, function() assert(eval_raw "function() local temp, temp2 = {max(1,3)}, -20;return temp[1] + temp2; end" () == -17) end)
  1979.  
  1980. -------------------------------------------------------
  1981. -- We're running out of tokens!
  1982. -- What to do? Well, we already have an interpreter above,
  1983. -- so we might as well as interpret the rest of our code!
  1984. --
  1985. -- But looking at code inside strings isn't fun, so I'm automatically moving
  1986. -- all the below code (after the count::stop) into the $$BELOW$$ string
  1987. -- when creating the cart.
  1988. -------------------------------------------------------
  1989.  
  1990. _ENV.g_ENV = g_ENV -- make g_ENV a global, so it can be accessed by below code
  1991. execute_raw("$$BELOW$$", _ENV)
  1992. --lint: count::stop
  1993.  
  1994. ------------------------
  1995. -- Special \-commands
  1996. ------------------------
  1997.  
  1998. -- execute a repl-specific command
  1999. function cmd_exec(name)
  2000.     if isin(name, {"i","interrupt"}) then
  2001.         return g_enable_interrupt
  2002.     elseif isin(name, {"f","flip"}) then
  2003.         return g_enable_autoflip
  2004.     elseif isin(name, {"r","repl"}) then
  2005.         return g_enable_repl
  2006.     elseif isin(name, {"mi","max_items"}) then
  2007.         return g_show_max_items
  2008.     elseif isin(name, {"h","hex"}) then
  2009.         return g_hex_output
  2010.     elseif isin(name, {"pr","precise"}) then
  2011.         return g_precise_output
  2012.     elseif isin(name, {"cl","colors"}) then
  2013.         return g_pal
  2014.     elseif isin(name, {"c","code"}) then
  2015.         local code = {[0]=g_input}
  2016.         for i=1,#g_history-1 do code[i] = g_history[#g_history-i] end
  2017.         return code
  2018.     elseif isin(name, {"cm","compile"}) then
  2019.         return function(str) return try_parse(str) end
  2020.     elseif isin(name, {"x","exec"}) then
  2021.         return function(str, env, ...) execute_raw(str, env, ...) end
  2022.     elseif isin(name, {"v","eval"}) then
  2023.         return function(str, env, ...) return eval_raw(str, env, ...) end
  2024.     elseif isin(name, {"p","print"}) then
  2025.         return function(str, ...) g_ENV.print(value_to_str(str), ...) end
  2026.     elseif isin(name, {"ts","tostr"}) then
  2027.         return function(str) return value_to_str(str) end
  2028.     elseif isin(name, {"rst","reset"}) then
  2029.         run() -- full pico8 reset
  2030.     elseif isin(name, {"run"}) then
  2031.         do_mainloop(g_ENV)
  2032.     elseif isin(name, {"cont"}) then
  2033.         do_mainloop(g_ENV, true)
  2034.     else
  2035.         assert(false, "unknown \\-command")
  2036.     end
  2037. end
  2038.  
  2039. -- assign to a repl-specific command
  2040. function cmd_assign(name)
  2041.     local function trueish(t)
  2042.         return (t and t != 0) and true or false
  2043.     end
  2044.  
  2045.     local func
  2046.     if isin(name, {"i","interrupt"}) then
  2047.         func = function(v) g_enable_interrupt = trueish(v) end
  2048.     elseif isin(name, {"f","flip"}) then
  2049.         func = function(v) g_enable_autoflip = trueish(v) end
  2050.     elseif isin(name, {"r","repl"}) then
  2051.         func = function(v) g_enable_repl = trueish(v) end
  2052.     elseif isin(name, {"mi","max_items"}) then
  2053.         func = function(v) g_show_max_items = tonum(v) or -1 end
  2054.     elseif isin(name, {"h","hex"}) then
  2055.         func = function(v) g_hex_output = trueish(v) end
  2056.     elseif isin(name, {"pr","precise"}) then
  2057.         func = function(v) g_precise_output = trueish(v) end
  2058.     elseif isin(name, {"cl","colors"}) then
  2059.         func = function(v) g_pal = v end
  2060.     else
  2061.         assert(false, "unknown \\-command assign")
  2062.     end
  2063.  
  2064.     -- do some trickery to allow calling func upon assignment
  2065.     -- (as we're expected to return the assignment target)
  2066.     local obj = {
  2067.         __newindex=function(t,k,v) func(v) end,
  2068.         __index=function() return cmd_exec(name) end, -- op-assign needs this
  2069.     }
  2070.     return setmetatable(obj, obj), 0
  2071. end
  2072.  
  2073. ------------------------
  2074. -- Misc.
  2075. ------------------------
  2076.  
  2077. function load_cart(str)
  2078.     -- is this a full rom? (I'm assuming nobody will drop exactly-32kb text files here!)
  2079.     local code, full = sub(str, 0x4301)
  2080.     if #code == 0x3d00 then
  2081.         full = true
  2082.         poke(0, ord(str, 1, 0x4300)) -- load rom
  2083.     else
  2084.         code = str -- else, either tiny-rom or plaintext
  2085.     end
  2086.  
  2087.     local header = sub(code, 1, 4)
  2088.     if header == ":c:\0" then
  2089.         code = uncompress_code_old(code)
  2090.     elseif header == "\0pxa" then
  2091.         code = uncompress_code_new(code)
  2092.     elseif full then
  2093.         code = split(code, '\0')[1]
  2094.     else
  2095.         -- either plaintext or a tiny/uncompressed tiny-rom (indistinguishable)
  2096.         return
  2097.     end
  2098.  
  2099.     -- run in ideal execution environment
  2100.     g_enable_interrupt, g_enable_repl = false, false
  2101.     local ok = execute(code, true)
  2102.     g_enable_repl = true
  2103.     if (ok) execute("\\run") -- we need to call do_mainloop from within execute, this is the easiest way
  2104.     return true
  2105. end
  2106.  
  2107. toplevel_main()
  2108.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement