Recover agent-loop progress: lua/prolog/forth/erlang/haskell phases 1-2
Salvaged from worktree-agent-* branches killed during sx-tree MCP outage: - lua: tokenizer + parser + phase-2 transpile (~157 tests) - prolog: tokenizer + parser + unification (72 tests, plan update lost to WIP) - forth: phase-1 reader/interpreter + phase-2 colon/VARIABLE (134 tests) - erlang: tokenizer + parser (114 tests) - haskell: tokenizer + parse tests (43 tests) Cherry-picked file contents only, not branch history, to avoid pulling in unrelated ocaml-vm merge commits that were in those branches' bases.
This commit is contained in:
802
lib/lua/parser.sx
Normal file
802
lib/lua/parser.sx
Normal file
@@ -0,0 +1,802 @@
|
||||
(define lua-tok-type (fn (t) (if (= t nil) "eof" (get t :type))))
|
||||
|
||||
(define lua-tok-value (fn (t) (if (= t nil) nil (get t :value))))
|
||||
|
||||
(define
|
||||
lua-binop-prec
|
||||
(fn
|
||||
(op)
|
||||
(cond
|
||||
((= op "or") 1)
|
||||
((= op "and") 2)
|
||||
((= op "<") 3)
|
||||
((= op ">") 3)
|
||||
((= op "<=") 3)
|
||||
((= op ">=") 3)
|
||||
((= op "==") 3)
|
||||
((= op "~=") 3)
|
||||
((= op "..") 5)
|
||||
((= op "+") 6)
|
||||
((= op "-") 6)
|
||||
((= op "*") 7)
|
||||
((= op "/") 7)
|
||||
((= op "%") 7)
|
||||
((= op "^") 10)
|
||||
(else 0))))
|
||||
|
||||
(define lua-binop-right? (fn (op) (or (= op "..") (= op "^"))))
|
||||
|
||||
(define
|
||||
lua-parse
|
||||
(fn
|
||||
(src)
|
||||
(let
|
||||
((tokens (lua-tokenize src)) (idx 0) (tok-len 0))
|
||||
(begin
|
||||
(set! tok-len (len tokens))
|
||||
(define peek-tok (fn () (nth tokens idx)))
|
||||
(define
|
||||
peek-tok-at
|
||||
(fn (n) (if (< (+ idx n) tok-len) (nth tokens (+ idx n)) nil)))
|
||||
(define advance-tok! (fn () (set! idx (+ idx 1))))
|
||||
(define
|
||||
check-tok?
|
||||
(fn
|
||||
(type value)
|
||||
(let
|
||||
((t (peek-tok)))
|
||||
(and
|
||||
(= (lua-tok-type t) type)
|
||||
(or (= value nil) (= (lua-tok-value t) value))))))
|
||||
(define
|
||||
consume!
|
||||
(fn
|
||||
(type value)
|
||||
(if
|
||||
(check-tok? type value)
|
||||
(let ((t (peek-tok))) (begin (advance-tok!) t))
|
||||
(error
|
||||
(str
|
||||
"lua-parse: expected "
|
||||
type
|
||||
" "
|
||||
value
|
||||
" got "
|
||||
(lua-tok-type (peek-tok))
|
||||
" "
|
||||
(lua-tok-value (peek-tok)))))))
|
||||
(define at-keyword? (fn (kw) (check-tok? "keyword" kw)))
|
||||
(define at-op? (fn (op) (check-tok? "op" op)))
|
||||
(define
|
||||
at-binop?
|
||||
(fn
|
||||
()
|
||||
(let
|
||||
((t (peek-tok)))
|
||||
(cond
|
||||
((and (= (lua-tok-type t) "keyword") (or (= (lua-tok-value t) "and") (= (lua-tok-value t) "or")))
|
||||
true)
|
||||
((and (= (lua-tok-type t) "op") (> (lua-binop-prec (lua-tok-value t)) 0))
|
||||
true)
|
||||
(else false)))))
|
||||
(define parse-expr nil)
|
||||
(define parse-block nil)
|
||||
(define parse-prefixexp nil)
|
||||
(define parse-table-ctor nil)
|
||||
(define parse-unary nil)
|
||||
(define parse-args nil)
|
||||
(define parse-funcbody nil)
|
||||
(set!
|
||||
parse-args
|
||||
(fn
|
||||
()
|
||||
(cond
|
||||
((at-op? "(")
|
||||
(begin
|
||||
(advance-tok!)
|
||||
(if
|
||||
(at-op? ")")
|
||||
(begin (advance-tok!) (list))
|
||||
(let
|
||||
((args (list (parse-expr))))
|
||||
(begin
|
||||
(define
|
||||
more
|
||||
(fn
|
||||
()
|
||||
(when
|
||||
(at-op? ",")
|
||||
(begin
|
||||
(advance-tok!)
|
||||
(append! args (parse-expr))
|
||||
(more)))))
|
||||
(more)
|
||||
(consume! "op" ")")
|
||||
args)))))
|
||||
((at-op? "{") (list (parse-table-ctor)))
|
||||
((check-tok? "string" nil)
|
||||
(let
|
||||
((t (peek-tok)))
|
||||
(begin
|
||||
(advance-tok!)
|
||||
(list (list (quote lua-str) (lua-tok-value t))))))
|
||||
(else (error "lua-parse: expected args")))))
|
||||
(set!
|
||||
parse-funcbody
|
||||
(fn
|
||||
()
|
||||
(begin
|
||||
(consume! "op" "(")
|
||||
(let
|
||||
((params (list)) (is-vararg false))
|
||||
(begin
|
||||
(when
|
||||
(not (at-op? ")"))
|
||||
(begin
|
||||
(cond
|
||||
((at-op? "...")
|
||||
(begin (advance-tok!) (set! is-vararg true)))
|
||||
(else
|
||||
(let
|
||||
((t (peek-tok)))
|
||||
(begin
|
||||
(when
|
||||
(not (= (lua-tok-type t) "ident"))
|
||||
(error "lua-parse: expected name in params"))
|
||||
(append! params (lua-tok-value t))
|
||||
(advance-tok!)))))
|
||||
(define
|
||||
more-params
|
||||
(fn
|
||||
()
|
||||
(when
|
||||
(and (at-op? ",") (not is-vararg))
|
||||
(begin
|
||||
(advance-tok!)
|
||||
(cond
|
||||
((at-op? "...")
|
||||
(begin
|
||||
(advance-tok!)
|
||||
(set! is-vararg true)))
|
||||
(else
|
||||
(let
|
||||
((t (peek-tok)))
|
||||
(begin
|
||||
(when
|
||||
(not (= (lua-tok-type t) "ident"))
|
||||
(error "lua-parse: expected name"))
|
||||
(append! params (lua-tok-value t))
|
||||
(advance-tok!)))))
|
||||
(more-params)))))
|
||||
(more-params)))
|
||||
(consume! "op" ")")
|
||||
(let
|
||||
((body (parse-block)))
|
||||
(begin
|
||||
(consume! "keyword" "end")
|
||||
(list (quote lua-function) params is-vararg body))))))))
|
||||
(define
|
||||
parse-primary
|
||||
(fn
|
||||
()
|
||||
(let
|
||||
((t (peek-tok)))
|
||||
(cond
|
||||
((= (lua-tok-type t) "number")
|
||||
(begin
|
||||
(advance-tok!)
|
||||
(list (quote lua-num) (lua-tok-value t))))
|
||||
((= (lua-tok-type t) "string")
|
||||
(begin
|
||||
(advance-tok!)
|
||||
(list (quote lua-str) (lua-tok-value t))))
|
||||
((and (= (lua-tok-type t) "keyword") (= (lua-tok-value t) "nil"))
|
||||
(begin (advance-tok!) (list (quote lua-nil))))
|
||||
((and (= (lua-tok-type t) "keyword") (= (lua-tok-value t) "true"))
|
||||
(begin (advance-tok!) (list (quote lua-true))))
|
||||
((and (= (lua-tok-type t) "keyword") (= (lua-tok-value t) "false"))
|
||||
(begin (advance-tok!) (list (quote lua-false))))
|
||||
((and (= (lua-tok-type t) "op") (= (lua-tok-value t) "..."))
|
||||
(begin (advance-tok!) (list (quote lua-vararg))))
|
||||
((and (= (lua-tok-type t) "keyword") (= (lua-tok-value t) "function"))
|
||||
(begin (advance-tok!) (parse-funcbody)))
|
||||
((and (= (lua-tok-type t) "op") (= (lua-tok-value t) "{"))
|
||||
(parse-table-ctor))
|
||||
((or (= (lua-tok-type t) "ident") (and (= (lua-tok-type t) "op") (= (lua-tok-value t) "(")))
|
||||
(parse-prefixexp))
|
||||
(else
|
||||
(error
|
||||
(str
|
||||
"lua-parse: unexpected "
|
||||
(lua-tok-type t)
|
||||
" "
|
||||
(lua-tok-value t))))))))
|
||||
(set!
|
||||
parse-unary
|
||||
(fn
|
||||
()
|
||||
(cond
|
||||
((at-op? "-")
|
||||
(begin
|
||||
(advance-tok!)
|
||||
(list (quote lua-unop) "-" (parse-unary))))
|
||||
((at-op? "#")
|
||||
(begin
|
||||
(advance-tok!)
|
||||
(list (quote lua-unop) "#" (parse-unary))))
|
||||
((at-keyword? "not")
|
||||
(begin
|
||||
(advance-tok!)
|
||||
(list (quote lua-unop) "not" (parse-unary))))
|
||||
(else (parse-primary)))))
|
||||
(define
|
||||
parse-binop-rhs
|
||||
(fn
|
||||
(min-prec lhs)
|
||||
(begin
|
||||
(define
|
||||
loop
|
||||
(fn
|
||||
(lhs-acc)
|
||||
(if
|
||||
(at-binop?)
|
||||
(let
|
||||
((op (lua-tok-value (peek-tok))))
|
||||
(let
|
||||
((prec (lua-binop-prec op)))
|
||||
(if
|
||||
(< prec min-prec)
|
||||
lhs-acc
|
||||
(begin
|
||||
(advance-tok!)
|
||||
(let
|
||||
((rhs (parse-unary)))
|
||||
(let
|
||||
((next-min (if (lua-binop-right? op) prec (+ prec 1))))
|
||||
(let
|
||||
((rhs2 (parse-binop-rhs next-min rhs)))
|
||||
(loop
|
||||
(list (quote lua-binop) op lhs-acc rhs2)))))))))
|
||||
lhs-acc)))
|
||||
(loop lhs)))))
|
||||
(set!
|
||||
parse-expr
|
||||
(fn () (let ((lhs (parse-unary))) (parse-binop-rhs 1 lhs))))
|
||||
(set!
|
||||
parse-prefixexp
|
||||
(fn
|
||||
()
|
||||
(let
|
||||
((base nil))
|
||||
(begin
|
||||
(cond
|
||||
((check-tok? "ident" nil)
|
||||
(let
|
||||
((t (peek-tok)))
|
||||
(begin
|
||||
(advance-tok!)
|
||||
(set! base (list (quote lua-name) (lua-tok-value t))))))
|
||||
((at-op? "(")
|
||||
(begin
|
||||
(advance-tok!)
|
||||
(set! base (parse-expr))
|
||||
(consume! "op" ")")))
|
||||
(else (error "lua-parse: expected prefixexp")))
|
||||
(define
|
||||
more
|
||||
(fn
|
||||
()
|
||||
(cond
|
||||
((at-op? ".")
|
||||
(begin
|
||||
(advance-tok!)
|
||||
(let
|
||||
((t (peek-tok)))
|
||||
(begin
|
||||
(when
|
||||
(not (= (lua-tok-type t) "ident"))
|
||||
(error "lua-parse: expected name after ."))
|
||||
(set!
|
||||
base
|
||||
(list (quote lua-field) base (lua-tok-value t)))
|
||||
(advance-tok!)
|
||||
(more)))))
|
||||
((at-op? "[")
|
||||
(begin
|
||||
(advance-tok!)
|
||||
(let
|
||||
((e (parse-expr)))
|
||||
(begin
|
||||
(consume! "op" "]")
|
||||
(set! base (list (quote lua-index) base e))
|
||||
(more)))))
|
||||
((at-op? ":")
|
||||
(begin
|
||||
(advance-tok!)
|
||||
(let
|
||||
((t (peek-tok)))
|
||||
(begin
|
||||
(when
|
||||
(not (= (lua-tok-type t) "ident"))
|
||||
(error "lua-parse: expected name after :"))
|
||||
(let
|
||||
((name (lua-tok-value t)))
|
||||
(begin
|
||||
(advance-tok!)
|
||||
(let
|
||||
((args (parse-args)))
|
||||
(begin
|
||||
(set!
|
||||
base
|
||||
(list
|
||||
(quote lua-method-call)
|
||||
base
|
||||
name
|
||||
args))
|
||||
(more)))))))))
|
||||
((or (at-op? "(") (at-op? "{") (check-tok? "string" nil))
|
||||
(let
|
||||
((args (parse-args)))
|
||||
(begin
|
||||
(set! base (list (quote lua-call) base args))
|
||||
(more))))
|
||||
(else nil))))
|
||||
(more)
|
||||
base))))
|
||||
(set!
|
||||
parse-table-ctor
|
||||
(fn
|
||||
()
|
||||
(begin
|
||||
(consume! "op" "{")
|
||||
(let
|
||||
((fields (list)))
|
||||
(begin
|
||||
(define
|
||||
parse-field
|
||||
(fn
|
||||
()
|
||||
(cond
|
||||
((at-op? "[")
|
||||
(begin
|
||||
(advance-tok!)
|
||||
(let
|
||||
((k (parse-expr)))
|
||||
(begin
|
||||
(consume! "op" "]")
|
||||
(consume! "op" "=")
|
||||
(let
|
||||
((v (parse-expr)))
|
||||
(append! fields (list (quote lua-kv) k v)))))))
|
||||
((and (check-tok? "ident" nil) (let ((nxt (peek-tok-at 1))) (and (not (= nxt nil)) (= (lua-tok-type nxt) "op") (= (lua-tok-value nxt) "="))))
|
||||
(let
|
||||
((t (peek-tok)))
|
||||
(begin
|
||||
(advance-tok!)
|
||||
(advance-tok!)
|
||||
(let
|
||||
((v (parse-expr)))
|
||||
(append!
|
||||
fields
|
||||
(list
|
||||
(quote lua-kv)
|
||||
(list (quote lua-str) (lua-tok-value t))
|
||||
v))))))
|
||||
(else
|
||||
(let
|
||||
((v (parse-expr)))
|
||||
(append! fields (list (quote lua-pos) v)))))))
|
||||
(when
|
||||
(not (at-op? "}"))
|
||||
(begin
|
||||
(parse-field)
|
||||
(define
|
||||
more-fields
|
||||
(fn
|
||||
()
|
||||
(when
|
||||
(and
|
||||
(or (at-op? ",") (at-op? ";"))
|
||||
(not (at-op? "}")))
|
||||
(begin
|
||||
(advance-tok!)
|
||||
(when
|
||||
(not (at-op? "}"))
|
||||
(begin (parse-field) (more-fields)))))))
|
||||
(more-fields)))
|
||||
(consume! "op" "}")
|
||||
(cons (quote lua-table) fields))))))
|
||||
(define
|
||||
parse-explist
|
||||
(fn
|
||||
()
|
||||
(let
|
||||
((exps (list (parse-expr))))
|
||||
(begin
|
||||
(define
|
||||
more
|
||||
(fn
|
||||
()
|
||||
(when
|
||||
(at-op? ",")
|
||||
(begin
|
||||
(advance-tok!)
|
||||
(append! exps (parse-expr))
|
||||
(more)))))
|
||||
(more)
|
||||
exps))))
|
||||
(define
|
||||
parse-namelist
|
||||
(fn
|
||||
()
|
||||
(let
|
||||
((names (list)))
|
||||
(begin
|
||||
(let
|
||||
((t (peek-tok)))
|
||||
(begin
|
||||
(when
|
||||
(not (= (lua-tok-type t) "ident"))
|
||||
(error "lua-parse: expected name"))
|
||||
(append! names (lua-tok-value t))
|
||||
(advance-tok!)))
|
||||
(define
|
||||
more
|
||||
(fn
|
||||
()
|
||||
(when
|
||||
(at-op? ",")
|
||||
(begin
|
||||
(advance-tok!)
|
||||
(let
|
||||
((t (peek-tok)))
|
||||
(begin
|
||||
(when
|
||||
(not (= (lua-tok-type t) "ident"))
|
||||
(error "lua-parse: expected name"))
|
||||
(append! names (lua-tok-value t))
|
||||
(advance-tok!)))
|
||||
(more)))))
|
||||
(more)
|
||||
names))))
|
||||
(define
|
||||
parse-if
|
||||
(fn
|
||||
()
|
||||
(begin
|
||||
(consume! "keyword" "if")
|
||||
(let
|
||||
((cnd (parse-expr)))
|
||||
(begin
|
||||
(consume! "keyword" "then")
|
||||
(let
|
||||
((then-body (parse-block))
|
||||
(elseifs (list))
|
||||
(else-body nil))
|
||||
(begin
|
||||
(define
|
||||
elseif-loop
|
||||
(fn
|
||||
()
|
||||
(when
|
||||
(at-keyword? "elseif")
|
||||
(begin
|
||||
(advance-tok!)
|
||||
(let
|
||||
((c (parse-expr)))
|
||||
(begin
|
||||
(consume! "keyword" "then")
|
||||
(let
|
||||
((b (parse-block)))
|
||||
(begin
|
||||
(append! elseifs (list c b))
|
||||
(elseif-loop)))))))))
|
||||
(elseif-loop)
|
||||
(when
|
||||
(at-keyword? "else")
|
||||
(begin (advance-tok!) (set! else-body (parse-block))))
|
||||
(consume! "keyword" "end")
|
||||
(list (quote lua-if) cnd then-body elseifs else-body))))))))
|
||||
(define
|
||||
parse-while
|
||||
(fn
|
||||
()
|
||||
(begin
|
||||
(consume! "keyword" "while")
|
||||
(let
|
||||
((cnd (parse-expr)))
|
||||
(begin
|
||||
(consume! "keyword" "do")
|
||||
(let
|
||||
((body (parse-block)))
|
||||
(begin
|
||||
(consume! "keyword" "end")
|
||||
(list (quote lua-while) cnd body))))))))
|
||||
(define
|
||||
parse-repeat
|
||||
(fn
|
||||
()
|
||||
(begin
|
||||
(consume! "keyword" "repeat")
|
||||
(let
|
||||
((body (parse-block)))
|
||||
(begin
|
||||
(consume! "keyword" "until")
|
||||
(let
|
||||
((cnd (parse-expr)))
|
||||
(list (quote lua-repeat) body cnd)))))))
|
||||
(define
|
||||
parse-do
|
||||
(fn
|
||||
()
|
||||
(begin
|
||||
(consume! "keyword" "do")
|
||||
(let
|
||||
((body (parse-block)))
|
||||
(begin (consume! "keyword" "end") (list (quote lua-do) body))))))
|
||||
(define
|
||||
parse-for
|
||||
(fn
|
||||
()
|
||||
(begin
|
||||
(consume! "keyword" "for")
|
||||
(let
|
||||
((t (peek-tok)))
|
||||
(begin
|
||||
(when
|
||||
(not (= (lua-tok-type t) "ident"))
|
||||
(error "lua-parse: expected name in for"))
|
||||
(let
|
||||
((name (lua-tok-value t)))
|
||||
(begin
|
||||
(advance-tok!)
|
||||
(when
|
||||
(not (at-op? "="))
|
||||
(error "lua-parse: only numeric for supported"))
|
||||
(consume! "op" "=")
|
||||
(let
|
||||
((start (parse-expr)))
|
||||
(begin
|
||||
(consume! "op" ",")
|
||||
(let
|
||||
((stop (parse-expr)) (step nil))
|
||||
(begin
|
||||
(when
|
||||
(at-op? ",")
|
||||
(begin
|
||||
(advance-tok!)
|
||||
(set! step (parse-expr))))
|
||||
(consume! "keyword" "do")
|
||||
(let
|
||||
((body (parse-block)))
|
||||
(begin
|
||||
(consume! "keyword" "end")
|
||||
(list
|
||||
(quote lua-for-num)
|
||||
name
|
||||
start
|
||||
stop
|
||||
step
|
||||
body))))))))))))))
|
||||
(define
|
||||
parse-funcname
|
||||
(fn
|
||||
()
|
||||
(let
|
||||
((t (peek-tok)))
|
||||
(begin
|
||||
(when
|
||||
(not (= (lua-tok-type t) "ident"))
|
||||
(error "lua-parse: expected name after function"))
|
||||
(let
|
||||
((base (list (quote lua-name) (lua-tok-value t))))
|
||||
(begin
|
||||
(advance-tok!)
|
||||
(define
|
||||
dots
|
||||
(fn
|
||||
()
|
||||
(when
|
||||
(at-op? ".")
|
||||
(begin
|
||||
(advance-tok!)
|
||||
(let
|
||||
((tt (peek-tok)))
|
||||
(begin
|
||||
(when
|
||||
(not (= (lua-tok-type tt) "ident"))
|
||||
(error "lua-parse: expected name after ."))
|
||||
(set!
|
||||
base
|
||||
(list
|
||||
(quote lua-field)
|
||||
base
|
||||
(lua-tok-value tt)))
|
||||
(advance-tok!)
|
||||
(dots)))))))
|
||||
(dots)
|
||||
(let
|
||||
((is-method false) (method-name nil))
|
||||
(begin
|
||||
(when
|
||||
(at-op? ":")
|
||||
(begin
|
||||
(advance-tok!)
|
||||
(let
|
||||
((tt (peek-tok)))
|
||||
(begin
|
||||
(when
|
||||
(not (= (lua-tok-type tt) "ident"))
|
||||
(error "lua-parse: expected name after :"))
|
||||
(set! is-method true)
|
||||
(set! method-name (lua-tok-value tt))
|
||||
(advance-tok!)))))
|
||||
(list base is-method method-name)))))))))
|
||||
(define
|
||||
parse-function-decl
|
||||
(fn
|
||||
()
|
||||
(begin
|
||||
(consume! "keyword" "function")
|
||||
(let
|
||||
((parts (parse-funcname)))
|
||||
(let
|
||||
((base (nth parts 0))
|
||||
(is-method (nth parts 1))
|
||||
(m-name (nth parts 2)))
|
||||
(let
|
||||
((func (parse-funcbody)))
|
||||
(if
|
||||
is-method
|
||||
(let
|
||||
((target (list (quote lua-field) base m-name))
|
||||
(new-params (cons "self" (nth func 1))))
|
||||
(list
|
||||
(quote lua-function-decl)
|
||||
target
|
||||
(list
|
||||
(quote lua-function)
|
||||
new-params
|
||||
(nth func 2)
|
||||
(nth func 3))))
|
||||
(list (quote lua-function-decl) base func))))))))
|
||||
(define
|
||||
parse-local
|
||||
(fn
|
||||
()
|
||||
(begin
|
||||
(consume! "keyword" "local")
|
||||
(cond
|
||||
((at-keyword? "function")
|
||||
(begin
|
||||
(advance-tok!)
|
||||
(let
|
||||
((t (peek-tok)))
|
||||
(begin
|
||||
(when
|
||||
(not (= (lua-tok-type t) "ident"))
|
||||
(error "lua-parse: expected name after local fn"))
|
||||
(let
|
||||
((name (lua-tok-value t)))
|
||||
(begin
|
||||
(advance-tok!)
|
||||
(let
|
||||
((func (parse-funcbody)))
|
||||
(list (quote lua-local-function) name func))))))))
|
||||
(else
|
||||
(let
|
||||
((names (parse-namelist)) (exps (list)))
|
||||
(begin
|
||||
(when
|
||||
(at-op? "=")
|
||||
(begin (advance-tok!) (set! exps (parse-explist))))
|
||||
(list (quote lua-local) names exps))))))))
|
||||
(define
|
||||
parse-return
|
||||
(fn
|
||||
()
|
||||
(begin
|
||||
(consume! "keyword" "return")
|
||||
(let
|
||||
((exps (list)))
|
||||
(begin
|
||||
(when
|
||||
(not
|
||||
(or
|
||||
(at-keyword? "end")
|
||||
(at-keyword? "else")
|
||||
(at-keyword? "elseif")
|
||||
(at-keyword? "until")
|
||||
(check-tok? "eof" nil)
|
||||
(at-op? ";")))
|
||||
(set! exps (parse-explist)))
|
||||
(list (quote lua-return) exps))))))
|
||||
(define
|
||||
parse-assign-or-call
|
||||
(fn
|
||||
()
|
||||
(let
|
||||
((pexpr (parse-prefixexp)))
|
||||
(cond
|
||||
((or (at-op? "=") (at-op? ","))
|
||||
(let
|
||||
((lhs (list pexpr)))
|
||||
(begin
|
||||
(define
|
||||
more
|
||||
(fn
|
||||
()
|
||||
(when
|
||||
(at-op? ",")
|
||||
(begin
|
||||
(advance-tok!)
|
||||
(append! lhs (parse-prefixexp))
|
||||
(more)))))
|
||||
(more)
|
||||
(consume! "op" "=")
|
||||
(let
|
||||
((rhs (parse-explist)))
|
||||
(list (quote lua-assign) lhs rhs)))))
|
||||
((or (= (first pexpr) (quote lua-call)) (= (first pexpr) (quote lua-method-call)))
|
||||
(list (quote lua-call-stmt) pexpr))
|
||||
(else (error "lua-parse: expected '=' or call"))))))
|
||||
(define
|
||||
parse-stmt
|
||||
(fn
|
||||
()
|
||||
(cond
|
||||
((at-op? ";") (begin (advance-tok!) nil))
|
||||
((at-keyword? "if") (parse-if))
|
||||
((at-keyword? "while") (parse-while))
|
||||
((at-keyword? "repeat") (parse-repeat))
|
||||
((at-keyword? "do") (parse-do))
|
||||
((at-keyword? "for") (parse-for))
|
||||
((at-keyword? "function") (parse-function-decl))
|
||||
((at-keyword? "local") (parse-local))
|
||||
((at-keyword? "return") (parse-return))
|
||||
((at-keyword? "break")
|
||||
(begin (advance-tok!) (list (quote lua-break))))
|
||||
(else (parse-assign-or-call)))))
|
||||
(define
|
||||
block-end?
|
||||
(fn
|
||||
()
|
||||
(or
|
||||
(at-keyword? "end")
|
||||
(at-keyword? "else")
|
||||
(at-keyword? "elseif")
|
||||
(at-keyword? "until")
|
||||
(check-tok? "eof" nil))))
|
||||
(set!
|
||||
parse-block
|
||||
(fn
|
||||
()
|
||||
(let
|
||||
((stmts (list)))
|
||||
(begin
|
||||
(define
|
||||
loop
|
||||
(fn
|
||||
()
|
||||
(when
|
||||
(not (block-end?))
|
||||
(let
|
||||
((s (parse-stmt)))
|
||||
(begin
|
||||
(when (not (= s nil)) (append! stmts s))
|
||||
(cond
|
||||
((and (not (= s nil)) (= (first s) (quote lua-return)))
|
||||
nil)
|
||||
(else (loop))))))))
|
||||
(loop)
|
||||
(cons (quote lua-block) stmts)))))
|
||||
(parse-block))))
|
||||
|
||||
|
||||
(define
|
||||
lua-parse-expr
|
||||
(fn
|
||||
(src)
|
||||
(let
|
||||
((tree (lua-parse (str "return " src))))
|
||||
(let ((ret (nth tree 1))) (first (nth ret 1))))))
|
||||
171
lib/lua/runtime.sx
Normal file
171
lib/lua/runtime.sx
Normal file
@@ -0,0 +1,171 @@
|
||||
(define lua-truthy? (fn (v) (and (not (= v nil)) (not (= v false)))))
|
||||
|
||||
(define
|
||||
lua-to-number
|
||||
(fn
|
||||
(v)
|
||||
(cond
|
||||
((= (type-of v) "number") v)
|
||||
((= (type-of v) "string")
|
||||
(let ((n (parse-number v))) (if (= n nil) nil n)))
|
||||
(else nil))))
|
||||
|
||||
(define
|
||||
lua-to-string
|
||||
(fn
|
||||
(v)
|
||||
(cond
|
||||
((= v nil) "nil")
|
||||
((= v true) "true")
|
||||
((= v false) "false")
|
||||
((= (type-of v) "number") (str v))
|
||||
((= (type-of v) "string") v)
|
||||
(else (str v)))))
|
||||
|
||||
(define
|
||||
lua-num-op
|
||||
(fn
|
||||
(op a b)
|
||||
(let
|
||||
((na (lua-to-number a)) (nb (lua-to-number b)))
|
||||
(begin
|
||||
(when
|
||||
(or (= na nil) (= nb nil))
|
||||
(error (str "lua: arith on non-number: " a " " op " " b)))
|
||||
(cond
|
||||
((= op "+") (+ na nb))
|
||||
((= op "-") (- na nb))
|
||||
((= op "*") (* na nb))
|
||||
((= op "/") (/ na nb))
|
||||
((= op "%") (- na (* nb (floor (/ na nb)))))
|
||||
((= op "^") (pow na nb))
|
||||
(else (error (str "lua: unknown arith op " op))))))))
|
||||
|
||||
(define lua-add (fn (a b) (lua-num-op "+" a b)))
|
||||
|
||||
(define lua-sub (fn (a b) (lua-num-op "-" a b)))
|
||||
|
||||
(define lua-mul (fn (a b) (lua-num-op "*" a b)))
|
||||
|
||||
(define lua-div (fn (a b) (lua-num-op "/" a b)))
|
||||
|
||||
(define lua-mod (fn (a b) (lua-num-op "%" a b)))
|
||||
|
||||
(define lua-pow (fn (a b) (lua-num-op "^" a b)))
|
||||
|
||||
(define
|
||||
lua-neg
|
||||
(fn
|
||||
(a)
|
||||
(let
|
||||
((na (lua-to-number a)))
|
||||
(begin
|
||||
(when (= na nil) (error (str "lua: neg on non-number: " a)))
|
||||
(- 0 na)))))
|
||||
|
||||
(define
|
||||
lua-concat-coerce
|
||||
(fn
|
||||
(v)
|
||||
(cond
|
||||
((= (type-of v) "string") v)
|
||||
((= (type-of v) "number") (str v))
|
||||
(else (error (str "lua: cannot concat " v))))))
|
||||
|
||||
(define
|
||||
lua-concat
|
||||
(fn
|
||||
(a b)
|
||||
(let
|
||||
((sa (lua-concat-coerce a)) (sb (lua-concat-coerce b)))
|
||||
(str sa sb))))
|
||||
|
||||
(define
|
||||
lua-eq
|
||||
(fn
|
||||
(a b)
|
||||
(cond
|
||||
((and (= a nil) (= b nil)) true)
|
||||
((or (= a nil) (= b nil)) false)
|
||||
((and (= (type-of a) (type-of b)) (= a b)) true)
|
||||
(else false))))
|
||||
|
||||
(define lua-neq (fn (a b) (not (lua-eq a b))))
|
||||
|
||||
(define
|
||||
lua-lt
|
||||
(fn
|
||||
(a b)
|
||||
(cond
|
||||
((and (= (type-of a) "number") (= (type-of b) "number")) (< a b))
|
||||
((and (= (type-of a) "string") (= (type-of b) "string")) (< a b))
|
||||
(else (error "lua: attempt to compare incompatible types")))))
|
||||
|
||||
(define lua-le (fn (a b) (or (lua-lt a b) (lua-eq a b))))
|
||||
|
||||
(define lua-gt (fn (a b) (lua-lt b a)))
|
||||
|
||||
(define lua-ge (fn (a b) (lua-le b a)))
|
||||
|
||||
(define
|
||||
lua-len
|
||||
(fn
|
||||
(a)
|
||||
(cond
|
||||
((= (type-of a) "string") (len a))
|
||||
((= (type-of a) "list") (len a))
|
||||
((= (type-of a) "dict")
|
||||
(let
|
||||
((n 0))
|
||||
(begin
|
||||
(define
|
||||
count-loop
|
||||
(fn
|
||||
(i)
|
||||
(if
|
||||
(has? a (str i))
|
||||
(begin (set! n i) (count-loop (+ i 1)))
|
||||
n)))
|
||||
(count-loop 1))))
|
||||
(else (error (str "lua: len on non-len type: " (type-of a)))))))
|
||||
|
||||
(define
|
||||
lua-for-continue?
|
||||
(fn (i stop step) (if (> step 0) (<= i stop) (>= i stop))))
|
||||
|
||||
(define
|
||||
lua-make-table
|
||||
(fn
|
||||
(&rest fields)
|
||||
(let
|
||||
((t {}) (array-idx 1))
|
||||
(begin
|
||||
(define
|
||||
process
|
||||
(fn
|
||||
(fs)
|
||||
(when
|
||||
(> (len fs) 0)
|
||||
(begin
|
||||
(let
|
||||
((f (first fs)))
|
||||
(cond
|
||||
((= (first f) "pos")
|
||||
(begin
|
||||
(set! t (assoc t (str array-idx) (nth f 1)))
|
||||
(set! array-idx (+ array-idx 1))))
|
||||
((= (first f) "kv")
|
||||
(let
|
||||
((k (nth f 1)) (v (nth f 2)))
|
||||
(set! t (assoc t (str k) v))))))
|
||||
(process (rest fs))))))
|
||||
(process fields)
|
||||
t))))
|
||||
|
||||
(define
|
||||
lua-get
|
||||
(fn
|
||||
(t k)
|
||||
(if (= t nil) nil (let ((v (get t (str k)))) (if (= v nil) nil v)))))
|
||||
|
||||
(define lua-set! (fn (t k v) (assoc t (str k) v)))
|
||||
645
lib/lua/test.sh
Executable file
645
lib/lua/test.sh
Executable file
@@ -0,0 +1,645 @@
|
||||
#!/usr/bin/env bash
|
||||
# Fast Lua-on-SX test runner — epoch protocol direct to sx_server.exe.
|
||||
# Mirrors lib/js/test.sh.
|
||||
#
|
||||
# Usage:
|
||||
# bash lib/lua/test.sh # run all tests
|
||||
# bash lib/lua/test.sh -v # verbose
|
||||
|
||||
set -uo pipefail
|
||||
cd "$(git rev-parse --show-toplevel)"
|
||||
|
||||
SX_SERVER="${SX_SERVER:-hosts/ocaml/_build/default/bin/sx_server.exe}"
|
||||
if [ ! -x "$SX_SERVER" ]; then
|
||||
# fallback to main repo binary when running from a worktree without _build
|
||||
SX_SERVER="/root/rose-ash/hosts/ocaml/_build/default/bin/sx_server.exe"
|
||||
fi
|
||||
if [ ! -x "$SX_SERVER" ]; then
|
||||
echo "ERROR: sx_server.exe not found. Run: cd hosts/ocaml && dune build"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
VERBOSE="${1:-}"
|
||||
PASS=0
|
||||
FAIL=0
|
||||
ERRORS=""
|
||||
TMPFILE=$(mktemp)
|
||||
trap "rm -f $TMPFILE" EXIT
|
||||
|
||||
cat > "$TMPFILE" << 'EPOCHS'
|
||||
(epoch 1)
|
||||
(load "lib/lua/tokenizer.sx")
|
||||
(epoch 2)
|
||||
(load "lib/lua/parser.sx")
|
||||
(epoch 3)
|
||||
(load "lib/lua/runtime.sx")
|
||||
(epoch 4)
|
||||
(load "lib/lua/transpile.sx")
|
||||
|
||||
;; ── Phase 1: tokenizer ──────────────────────────────────────────
|
||||
(epoch 100)
|
||||
(eval "(len (lua-tokenize \"\"))")
|
||||
(epoch 101)
|
||||
(eval "(get (nth (lua-tokenize \"\") 0) :type)")
|
||||
|
||||
;; Numbers
|
||||
(epoch 110)
|
||||
(eval "(get (nth (lua-tokenize \"42\") 0) :type)")
|
||||
(epoch 111)
|
||||
(eval "(get (nth (lua-tokenize \"42\") 0) :value)")
|
||||
(epoch 112)
|
||||
(eval "(get (nth (lua-tokenize \"3.14\") 0) :value)")
|
||||
(epoch 113)
|
||||
(eval "(get (nth (lua-tokenize \"0xff\") 0) :value)")
|
||||
(epoch 114)
|
||||
(eval "(get (nth (lua-tokenize \"1e3\") 0) :value)")
|
||||
(epoch 115)
|
||||
(eval "(get (nth (lua-tokenize \"1.5e-2\") 0) :value)")
|
||||
(epoch 116)
|
||||
(eval "(get (nth (lua-tokenize \".5\") 0) :value)")
|
||||
|
||||
;; Identifiers and keywords
|
||||
(epoch 120)
|
||||
(eval "(get (nth (lua-tokenize \"foo\") 0) :type)")
|
||||
(epoch 121)
|
||||
(eval "(get (nth (lua-tokenize \"foo\") 0) :value)")
|
||||
(epoch 122)
|
||||
(eval "(get (nth (lua-tokenize \"_bar1\") 0) :value)")
|
||||
(epoch 123)
|
||||
(eval "(get (nth (lua-tokenize \"local\") 0) :type)")
|
||||
(epoch 124)
|
||||
(eval "(get (nth (lua-tokenize \"function\") 0) :value)")
|
||||
(epoch 125)
|
||||
(eval "(get (nth (lua-tokenize \"nil\") 0) :type)")
|
||||
(epoch 126)
|
||||
(eval "(get (nth (lua-tokenize \"true\") 0) :value)")
|
||||
(epoch 127)
|
||||
(eval "(get (nth (lua-tokenize \"false\") 0) :type)")
|
||||
|
||||
;; Short strings
|
||||
(epoch 130)
|
||||
(eval "(get (nth (lua-tokenize \"\\\"hi\\\"\") 0) :type)")
|
||||
(epoch 131)
|
||||
(eval "(get (nth (lua-tokenize \"\\\"hi\\\"\") 0) :value)")
|
||||
(epoch 132)
|
||||
(eval "(get (nth (lua-tokenize \"'ab'\") 0) :value)")
|
||||
(epoch 133)
|
||||
(eval "(get (nth (lua-tokenize \"\\\"a\\\\nb\\\"\") 0) :value)")
|
||||
|
||||
;; Long strings
|
||||
(epoch 140)
|
||||
(eval "(get (nth (lua-tokenize \"[[hello]]\") 0) :type)")
|
||||
(epoch 141)
|
||||
(eval "(get (nth (lua-tokenize \"[[hello]]\") 0) :value)")
|
||||
(epoch 142)
|
||||
(eval "(get (nth (lua-tokenize \"[==[level 2]==]\") 0) :value)")
|
||||
|
||||
;; Operators (multi-char)
|
||||
(epoch 150)
|
||||
(eval "(get (nth (lua-tokenize \"==\") 0) :value)")
|
||||
(epoch 151)
|
||||
(eval "(get (nth (lua-tokenize \"~=\") 0) :value)")
|
||||
(epoch 152)
|
||||
(eval "(get (nth (lua-tokenize \"<=\") 0) :value)")
|
||||
(epoch 153)
|
||||
(eval "(get (nth (lua-tokenize \">=\") 0) :value)")
|
||||
(epoch 154)
|
||||
(eval "(get (nth (lua-tokenize \"..\") 0) :value)")
|
||||
(epoch 155)
|
||||
(eval "(get (nth (lua-tokenize \"...\") 0) :value)")
|
||||
(epoch 156)
|
||||
(eval "(get (nth (lua-tokenize \"::\") 0) :value)")
|
||||
|
||||
;; Single-char operators / punctuation
|
||||
(epoch 160)
|
||||
(eval "(get (nth (lua-tokenize \"+\") 0) :value)")
|
||||
(epoch 161)
|
||||
(eval "(get (nth (lua-tokenize \"-\") 0) :value)")
|
||||
(epoch 162)
|
||||
(eval "(get (nth (lua-tokenize \"*\") 0) :value)")
|
||||
(epoch 163)
|
||||
(eval "(get (nth (lua-tokenize \"/\") 0) :value)")
|
||||
(epoch 164)
|
||||
(eval "(get (nth (lua-tokenize \"%\") 0) :value)")
|
||||
(epoch 165)
|
||||
(eval "(get (nth (lua-tokenize \"^\") 0) :value)")
|
||||
(epoch 166)
|
||||
(eval "(get (nth (lua-tokenize \"#\") 0) :value)")
|
||||
(epoch 167)
|
||||
(eval "(get (nth (lua-tokenize \"(\") 0) :value)")
|
||||
(epoch 168)
|
||||
(eval "(get (nth (lua-tokenize \"{\") 0) :value)")
|
||||
(epoch 169)
|
||||
(eval "(get (nth (lua-tokenize \";\") 0) :value)")
|
||||
|
||||
;; Comments are stripped
|
||||
(epoch 170)
|
||||
(eval "(len (lua-tokenize \"-- comment\\n\"))")
|
||||
(epoch 171)
|
||||
(eval "(len (lua-tokenize \"-- comment\\n1\"))")
|
||||
(epoch 172)
|
||||
(eval "(get (nth (lua-tokenize \"-- c\\n42\") 0) :value)")
|
||||
(epoch 173)
|
||||
(eval "(len (lua-tokenize \"--[[ block ]] 1\"))")
|
||||
(epoch 174)
|
||||
(eval "(get (nth (lua-tokenize \"--[[ c ]] 42\") 0) :value)")
|
||||
(epoch 175)
|
||||
(eval "(get (nth (lua-tokenize \"--[==[ x ]==] 7\") 0) :value)")
|
||||
|
||||
;; Compound expressions
|
||||
(epoch 180)
|
||||
(eval "(len (lua-tokenize \"local x = 1\"))")
|
||||
(epoch 181)
|
||||
(eval "(get (nth (lua-tokenize \"local x = 1\") 0) :type)")
|
||||
(epoch 182)
|
||||
(eval "(get (nth (lua-tokenize \"local x = 1\") 0) :value)")
|
||||
(epoch 183)
|
||||
(eval "(get (nth (lua-tokenize \"local x = 1\") 1) :type)")
|
||||
(epoch 184)
|
||||
(eval "(get (nth (lua-tokenize \"local x = 1\") 2) :value)")
|
||||
(epoch 185)
|
||||
(eval "(get (nth (lua-tokenize \"local x = 1\") 3) :value)")
|
||||
|
||||
(epoch 190)
|
||||
(eval "(len (lua-tokenize \"a.b:c()\"))")
|
||||
(epoch 191)
|
||||
(eval "(get (nth (lua-tokenize \"a.b:c()\") 1) :value)")
|
||||
(epoch 192)
|
||||
(eval "(get (nth (lua-tokenize \"a.b:c()\") 3) :value)")
|
||||
|
||||
;; ── Phase 1.parse: parser ────────────────────────────────────
|
||||
;; Literals
|
||||
(epoch 200)
|
||||
(eval "(lua-parse-expr \"42\")")
|
||||
(epoch 201)
|
||||
(eval "(lua-parse-expr \"3.14\")")
|
||||
(epoch 202)
|
||||
(eval "(lua-parse-expr \"\\\"hi\\\"\")")
|
||||
(epoch 203)
|
||||
(eval "(lua-parse-expr \"true\")")
|
||||
(epoch 204)
|
||||
(eval "(lua-parse-expr \"false\")")
|
||||
(epoch 205)
|
||||
(eval "(lua-parse-expr \"nil\")")
|
||||
(epoch 206)
|
||||
(eval "(lua-parse-expr \"foo\")")
|
||||
(epoch 207)
|
||||
(eval "(lua-parse-expr \"...\")")
|
||||
|
||||
;; Binops with precedence
|
||||
(epoch 210)
|
||||
(eval "(lua-parse-expr \"1+2\")")
|
||||
(epoch 211)
|
||||
(eval "(lua-parse-expr \"a+b*c\")")
|
||||
(epoch 212)
|
||||
(eval "(lua-parse-expr \"a*b+c\")")
|
||||
(epoch 213)
|
||||
(eval "(lua-parse-expr \"a and b or c\")")
|
||||
(epoch 214)
|
||||
(eval "(lua-parse-expr \"a==b\")")
|
||||
(epoch 215)
|
||||
(eval "(lua-parse-expr \"a..b..c\")")
|
||||
(epoch 216)
|
||||
(eval "(lua-parse-expr \"a^b^c\")")
|
||||
(epoch 217)
|
||||
(eval "(lua-parse-expr \"(a+b)*c\")")
|
||||
|
||||
;; Unary
|
||||
(epoch 220)
|
||||
(eval "(lua-parse-expr \"-x\")")
|
||||
(epoch 221)
|
||||
(eval "(lua-parse-expr \"not x\")")
|
||||
(epoch 222)
|
||||
(eval "(lua-parse-expr \"#a\")")
|
||||
|
||||
;; Member/index/call
|
||||
(epoch 230)
|
||||
(eval "(lua-parse-expr \"a.b\")")
|
||||
(epoch 231)
|
||||
(eval "(lua-parse-expr \"a.b.c\")")
|
||||
(epoch 232)
|
||||
(eval "(lua-parse-expr \"a[0]\")")
|
||||
(epoch 233)
|
||||
(eval "(lua-parse-expr \"f()\")")
|
||||
(epoch 234)
|
||||
(eval "(lua-parse-expr \"f(1,2)\")")
|
||||
(epoch 235)
|
||||
(eval "(lua-parse-expr \"a:b()\")")
|
||||
|
||||
;; Table constructors
|
||||
(epoch 240)
|
||||
(eval "(lua-parse-expr \"{1,2,3}\")")
|
||||
(epoch 241)
|
||||
(eval "(lua-parse-expr \"{x=1,y=2}\")")
|
||||
(epoch 242)
|
||||
(eval "(lua-parse-expr \"{[1+1]=\\\"a\\\"}\")")
|
||||
(epoch 243)
|
||||
(eval "(lua-parse-expr \"{}\")")
|
||||
|
||||
;; Anonymous function
|
||||
(epoch 250)
|
||||
(eval "(lua-parse-expr \"function() return 1 end\")")
|
||||
(epoch 251)
|
||||
(eval "(lua-parse-expr \"function(a,b) return a+b end\")")
|
||||
(epoch 252)
|
||||
(eval "(lua-parse-expr \"function(...) return 1 end\")")
|
||||
|
||||
;; Statements
|
||||
(epoch 260)
|
||||
(eval "(lua-parse \"local x = 1\")")
|
||||
(epoch 261)
|
||||
(eval "(lua-parse \"local a, b = 1, 2\")")
|
||||
(epoch 262)
|
||||
(eval "(lua-parse \"x = 1\")")
|
||||
(epoch 263)
|
||||
(eval "(lua-parse \"a, b = 1, 2\")")
|
||||
(epoch 264)
|
||||
(eval "(lua-parse \"if x then y = 1 end\")")
|
||||
(epoch 265)
|
||||
(eval "(lua-parse \"if x then y = 1 else y = 2 end\")")
|
||||
(epoch 266)
|
||||
(eval "(lua-parse \"if x then y = 1 elseif z then y = 2 else y = 3 end\")")
|
||||
(epoch 267)
|
||||
(eval "(lua-parse \"while x < 10 do x = x + 1 end\")")
|
||||
(epoch 268)
|
||||
(eval "(lua-parse \"repeat x = x + 1 until x > 10\")")
|
||||
(epoch 269)
|
||||
(eval "(lua-parse \"for i = 1, 10 do x = i end\")")
|
||||
(epoch 270)
|
||||
(eval "(lua-parse \"for i = 1, 10, 2 do x = i end\")")
|
||||
(epoch 271)
|
||||
(eval "(lua-parse \"do local x = 1 end\")")
|
||||
(epoch 272)
|
||||
(eval "(lua-parse \"break\")")
|
||||
(epoch 273)
|
||||
(eval "(lua-parse \"return 42\")")
|
||||
(epoch 274)
|
||||
(eval "(lua-parse \"return 1, 2\")")
|
||||
(epoch 275)
|
||||
(eval "(lua-parse \"return\")")
|
||||
|
||||
;; Function declarations
|
||||
(epoch 280)
|
||||
(eval "(lua-parse \"function f() return 1 end\")")
|
||||
(epoch 281)
|
||||
(eval "(lua-parse \"local function f(x) return x * 2 end\")")
|
||||
(epoch 282)
|
||||
(eval "(lua-parse \"function t.m(x) return x end\")")
|
||||
(epoch 283)
|
||||
(eval "(lua-parse \"function t:m(x) return self end\")")
|
||||
|
||||
;; Calls as statements
|
||||
(epoch 290)
|
||||
(eval "(lua-parse \"print(42)\")")
|
||||
(epoch 291)
|
||||
(eval "(lua-parse \"a:b()\")")
|
||||
(epoch 292)
|
||||
(eval "(lua-parse \"t.f()\")")
|
||||
|
||||
;; Multi-statement chunks
|
||||
(epoch 300)
|
||||
(eval "(len (lua-parse \"local x = 1 x = x + 1 return x\"))")
|
||||
|
||||
;; ── Phase 2: transpile + eval ─────────────────────────────────
|
||||
;; Literals via return
|
||||
(epoch 400)
|
||||
(eval "(lua-eval-ast \"return 1\")")
|
||||
(epoch 401)
|
||||
(eval "(lua-eval-ast \"return true\")")
|
||||
(epoch 402)
|
||||
(eval "(lua-eval-ast \"return false\")")
|
||||
(epoch 403)
|
||||
(eval "(lua-eval-ast \"return nil\")")
|
||||
(epoch 404)
|
||||
(eval "(lua-eval-ast \"return \\\"hi\\\"\")")
|
||||
|
||||
;; Arithmetic
|
||||
(epoch 410)
|
||||
(eval "(lua-eval-ast \"return 1 + 2\")")
|
||||
(epoch 411)
|
||||
(eval "(lua-eval-ast \"return 10 - 3\")")
|
||||
(epoch 412)
|
||||
(eval "(lua-eval-ast \"return 4 * 5\")")
|
||||
(epoch 413)
|
||||
(eval "(lua-eval-ast \"return 10 / 4\")")
|
||||
(epoch 414)
|
||||
(eval "(lua-eval-ast \"return 10 % 3\")")
|
||||
(epoch 415)
|
||||
(eval "(lua-eval-ast \"return 2 ^ 10\")")
|
||||
(epoch 416)
|
||||
(eval "(lua-eval-ast \"return (1 + 2) * 3\")")
|
||||
(epoch 417)
|
||||
(eval "(lua-eval-ast \"return 1 + 2 * 3\")")
|
||||
(epoch 418)
|
||||
(eval "(lua-eval-ast \"return -5 + 10\")")
|
||||
|
||||
;; String
|
||||
(epoch 420)
|
||||
(eval "(lua-eval-ast \"return \\\"a\\\" .. \\\"b\\\"\")")
|
||||
(epoch 421)
|
||||
(eval "(lua-eval-ast \"return \\\"count: \\\" .. 42\")")
|
||||
|
||||
;; Comparison
|
||||
(epoch 430)
|
||||
(eval "(lua-eval-ast \"return 1 < 2\")")
|
||||
(epoch 431)
|
||||
(eval "(lua-eval-ast \"return 3 > 2\")")
|
||||
(epoch 432)
|
||||
(eval "(lua-eval-ast \"return 2 == 2\")")
|
||||
(epoch 433)
|
||||
(eval "(lua-eval-ast \"return 1 ~= 2\")")
|
||||
(epoch 434)
|
||||
(eval "(lua-eval-ast \"return 1 <= 1\")")
|
||||
(epoch 435)
|
||||
(eval "(lua-eval-ast \"return 3 >= 2\")")
|
||||
|
||||
;; Logical (short-circuit, return value)
|
||||
(epoch 440)
|
||||
(eval "(lua-eval-ast \"return true and 42\")")
|
||||
(epoch 441)
|
||||
(eval "(lua-eval-ast \"return false or 99\")")
|
||||
(epoch 442)
|
||||
(eval "(lua-eval-ast \"return nil or 7\")")
|
||||
(epoch 443)
|
||||
(eval "(lua-eval-ast \"return 1 and 2\")")
|
||||
(epoch 444)
|
||||
(eval "(lua-eval-ast \"return false and 999\")")
|
||||
(epoch 445)
|
||||
(eval "(lua-eval-ast \"return not true\")")
|
||||
(epoch 446)
|
||||
(eval "(lua-eval-ast \"return not nil\")")
|
||||
(epoch 447)
|
||||
(eval "(lua-eval-ast \"return not 0\")")
|
||||
|
||||
;; Truthy
|
||||
(epoch 450)
|
||||
(eval "(lua-truthy? 0)")
|
||||
(epoch 451)
|
||||
(eval "(lua-truthy? nil)")
|
||||
(epoch 452)
|
||||
(eval "(lua-truthy? false)")
|
||||
(epoch 453)
|
||||
(eval "(lua-truthy? \"\")")
|
||||
|
||||
;; Control flow
|
||||
(epoch 460)
|
||||
(eval "(lua-eval-ast \"if true then return 1 else return 2 end\")")
|
||||
(epoch 461)
|
||||
(eval "(lua-eval-ast \"if 1 > 2 then return 100 else return 200 end\")")
|
||||
(epoch 462)
|
||||
(eval "(lua-eval-ast \"local x = 1 if x > 0 then x = x * 10 elseif x < 0 then x = 999 else x = 42 end return x\")")
|
||||
|
||||
;; Local and assignment
|
||||
(epoch 470)
|
||||
(eval "(lua-eval-ast \"local x = 5 return x * 2\")")
|
||||
(epoch 471)
|
||||
(eval "(lua-eval-ast \"local x = 0 x = x + 1 x = x + 1 return x\")")
|
||||
(epoch 472)
|
||||
(eval "(lua-eval-ast \"local a, b = 1, 2 return a + b\")")
|
||||
|
||||
;; Loops
|
||||
(epoch 480)
|
||||
(eval "(lua-eval-ast \"local sum = 0 for i = 1, 5 do sum = sum + i end return sum\")")
|
||||
(epoch 481)
|
||||
(eval "(lua-eval-ast \"local n = 0 for i = 10, 1, -1 do n = n + 1 end return n\")")
|
||||
(epoch 482)
|
||||
(eval "(lua-eval-ast \"local i = 0 while i < 5 do i = i + 1 end return i\")")
|
||||
(epoch 483)
|
||||
(eval "(lua-eval-ast \"local i = 0 repeat i = i + 1 until i >= 3 return i\")")
|
||||
(epoch 484)
|
||||
(eval "(lua-eval-ast \"local s = 0 for i = 1, 100 do s = s + i end return s\")")
|
||||
|
||||
EPOCHS
|
||||
|
||||
OUTPUT=$(timeout 60 "$SX_SERVER" < "$TMPFILE" 2>/dev/null)
|
||||
|
||||
check() {
|
||||
local epoch="$1" desc="$2" expected="$3"
|
||||
local actual
|
||||
actual=$(echo "$OUTPUT" | grep -A1 "^(ok-len $epoch " | tail -1)
|
||||
if [ -z "$actual" ]; then
|
||||
actual=$(echo "$OUTPUT" | grep "^(ok $epoch " || true)
|
||||
fi
|
||||
if [ -z "$actual" ]; then
|
||||
actual=$(echo "$OUTPUT" | grep "^(error $epoch " || true)
|
||||
fi
|
||||
if [ -z "$actual" ]; then
|
||||
actual="<no output for epoch $epoch>"
|
||||
fi
|
||||
|
||||
if echo "$actual" | grep -qF -- "$expected"; then
|
||||
PASS=$((PASS + 1))
|
||||
[ "$VERBOSE" = "-v" ] && echo " ok $desc"
|
||||
else
|
||||
FAIL=$((FAIL + 1))
|
||||
ERRORS+=" FAIL $desc (epoch $epoch)
|
||||
expected: $expected
|
||||
actual: $actual
|
||||
"
|
||||
fi
|
||||
}
|
||||
|
||||
# ── Empty / EOF ────────────────────────────────────────────────
|
||||
check 100 "empty tokens length" '1'
|
||||
check 101 "empty first token is eof" '"eof"'
|
||||
|
||||
# ── Numbers ────────────────────────────────────────────────────
|
||||
check 110 "int token type" '"number"'
|
||||
check 111 "int value" '42'
|
||||
check 112 "float value" '3.14'
|
||||
check 113 "hex value" '255'
|
||||
check 114 "exponent" '1000'
|
||||
check 115 "neg exponent" '0.015'
|
||||
check 116 "leading-dot" '0.5'
|
||||
|
||||
# ── Identifiers / keywords ─────────────────────────────────────
|
||||
check 120 "ident type" '"ident"'
|
||||
check 121 "ident value" '"foo"'
|
||||
check 122 "underscore ident" '"_bar1"'
|
||||
check 123 "local is keyword" '"keyword"'
|
||||
check 124 "function keyword" '"function"'
|
||||
check 125 "nil is keyword" '"keyword"'
|
||||
check 126 "true value" '"true"'
|
||||
check 127 "false type" '"keyword"'
|
||||
|
||||
# ── Strings ────────────────────────────────────────────────────
|
||||
check 130 "string type" '"string"'
|
||||
check 131 "string value" '"hi"'
|
||||
check 132 "single-quote string" '"ab"'
|
||||
check 133 "escape sequence" '"a'
|
||||
check 140 "long string type" '"string"'
|
||||
check 141 "long string value" '"hello"'
|
||||
check 142 "level-2 long string" '"level 2"'
|
||||
|
||||
# ── Operators ──────────────────────────────────────────────────
|
||||
check 150 "==" '"=="'
|
||||
check 151 "~=" '"~="'
|
||||
check 152 "<=" '"<="'
|
||||
check 153 ">=" '">="'
|
||||
check 154 ".." '".."'
|
||||
check 155 "..." '"..."'
|
||||
check 156 "::" '"::"'
|
||||
|
||||
check 160 "+" '"+"'
|
||||
check 161 "-" '"-"'
|
||||
check 162 "*" '"*"'
|
||||
check 163 "/" '"/"'
|
||||
check 164 "%" '"%"'
|
||||
check 165 "^" '"^"'
|
||||
check 166 "#" '"#"'
|
||||
check 167 "(" '"("'
|
||||
check 168 "{" '"{"'
|
||||
check 169 ";" '";"'
|
||||
|
||||
# ── Comments ───────────────────────────────────────────────────
|
||||
check 170 "line comment only → eof" '1'
|
||||
check 171 "line comment + num" '2'
|
||||
check 172 "num after line comment" '42'
|
||||
check 173 "block comment → eof" '2'
|
||||
check 174 "num after block comment" '42'
|
||||
check 175 "num after level-2 block comment" '7'
|
||||
|
||||
# ── Compound ───────────────────────────────────────────────────
|
||||
check 180 "local x = 1 token count" '5'
|
||||
check 181 "local is keyword" '"keyword"'
|
||||
check 182 "local value" '"local"'
|
||||
check 183 "x is ident" '"ident"'
|
||||
check 184 "= value" '"="'
|
||||
check 185 "1 value" '1'
|
||||
|
||||
check 190 "a.b:c() token count" '8'
|
||||
check 191 "dot after ident" '"."'
|
||||
check 192 "colon after ident" '":"'
|
||||
|
||||
# ── Phase 1.parse: parser ────────────────────────────────────
|
||||
check 200 "parse int" '(lua-num 42)'
|
||||
check 201 "parse float" '(lua-num 3.14)'
|
||||
check 202 "parse string" '(lua-str "hi")'
|
||||
check 203 "parse true" '(lua-true)'
|
||||
check 204 "parse false" '(lua-false)'
|
||||
check 205 "parse nil" '(lua-nil)'
|
||||
check 206 "parse ident" '(lua-name "foo")'
|
||||
check 207 "parse vararg" '(lua-vararg)'
|
||||
|
||||
check 210 "parse 1+2" '(lua-binop "+" (lua-num 1) (lua-num 2))'
|
||||
check 211 "parse a+b*c prec" '(lua-binop "+" (lua-name "a") (lua-binop "*"'
|
||||
check 212 "parse a*b+c prec" '(lua-binop "+" (lua-binop "*"'
|
||||
check 213 "parse and/or prec" '(lua-binop "or" (lua-binop "and"'
|
||||
check 214 "parse ==" '(lua-binop "==" (lua-name "a") (lua-name "b"))'
|
||||
check 215 "parse .. right-assoc" '(lua-binop ".." (lua-name "a") (lua-binop ".."'
|
||||
check 216 "parse ^ right-assoc" '(lua-binop "^" (lua-name "a") (lua-binop "^"'
|
||||
check 217 "parse paren override" '(lua-binop "*" (lua-binop "+"'
|
||||
|
||||
check 220 "parse -x" '(lua-unop "-" (lua-name "x"))'
|
||||
check 221 "parse not x" '(lua-unop "not" (lua-name "x"))'
|
||||
check 222 "parse #a" '(lua-unop "#" (lua-name "a"))'
|
||||
|
||||
check 230 "parse a.b" '(lua-field (lua-name "a") "b")'
|
||||
check 231 "parse a.b.c" '(lua-field (lua-field (lua-name "a") "b") "c")'
|
||||
check 232 "parse a[0]" '(lua-index (lua-name "a") (lua-num 0))'
|
||||
check 233 "parse f()" '(lua-call (lua-name "f") ())'
|
||||
check 234 "parse f(1,2)" '(lua-call (lua-name "f") ((lua-num 1) (lua-num 2)))'
|
||||
check 235 "parse a:b()" '(lua-method-call (lua-name "a") "b" ())'
|
||||
|
||||
check 240 "parse {1,2,3}" '(lua-table (lua-pos (lua-num 1)) (lua-pos (lua-num 2))'
|
||||
check 241 "parse {x=1,y=2}" '(lua-table (lua-kv (lua-str "x") (lua-num 1))'
|
||||
check 242 "parse {[k]=v}" '(lua-table (lua-kv (lua-binop "+"'
|
||||
check 243 "parse empty table" '(lua-table)'
|
||||
|
||||
check 250 "parse function() 1 end" '(lua-function () false'
|
||||
check 251 "parse function(a,b)" '(lua-function ("a" "b") false'
|
||||
check 252 "parse function(...)" '(lua-function () true'
|
||||
|
||||
check 260 "parse local x = 1" '(lua-block (lua-local ("x") ((lua-num 1))))'
|
||||
check 261 "parse local a,b = 1,2" '(lua-block (lua-local ("a" "b") ((lua-num 1) (lua-num 2))))'
|
||||
check 262 "parse x = 1" '(lua-assign ((lua-name "x")) ((lua-num 1)))'
|
||||
check 263 "parse a,b = 1,2" '(lua-assign ((lua-name "a") (lua-name "b"))'
|
||||
check 264 "parse if then end" '(lua-if (lua-name "x")'
|
||||
check 265 "parse if-else" '(lua-if (lua-name "x") (lua-block (lua-assign ((lua-name "y")) ((lua-num 1)))) () (lua-block'
|
||||
check 266 "parse if-elseif-else" '(((lua-name "z") (lua-block (lua-assign ((lua-name "y")) ((lua-num 2))))))'
|
||||
check 267 "parse while" '(lua-while (lua-binop "<"'
|
||||
check 268 "parse repeat" '(lua-repeat'
|
||||
check 269 "parse for num" '(lua-for-num "i" (lua-num 1) (lua-num 10) nil'
|
||||
check 270 "parse for num step" '(lua-for-num "i" (lua-num 1) (lua-num 10) (lua-num 2)'
|
||||
check 271 "parse do block" '(lua-do (lua-block (lua-local ("x") ((lua-num 1))))'
|
||||
check 272 "parse break" '(lua-break)'
|
||||
check 273 "parse return" '(lua-return ((lua-num 42)))'
|
||||
check 274 "parse return 1,2" '(lua-return ((lua-num 1) (lua-num 2)))'
|
||||
check 275 "parse bare return" '(lua-return ())'
|
||||
|
||||
check 280 "parse function decl" '(lua-function-decl (lua-name "f")'
|
||||
check 281 "parse local function" '(lua-local-function "f" (lua-function ("x") false'
|
||||
check 282 "parse function t.m" '(lua-function-decl (lua-field (lua-name "t") "m")'
|
||||
check 283 "parse method t:m" 'self'
|
||||
|
||||
check 290 "parse call stmt" '(lua-call-stmt (lua-call (lua-name "print")'
|
||||
check 291 "parse method call stmt" '(lua-call-stmt (lua-method-call'
|
||||
check 292 "parse chained call stmt" '(lua-call-stmt (lua-call (lua-field'
|
||||
|
||||
check 300 "parse multi-statement" '4'
|
||||
|
||||
# ── Phase 2: transpile + eval ────────────────────────────────
|
||||
check 400 "eval return 1" '1'
|
||||
check 401 "eval return true" 'true'
|
||||
check 402 "eval return false" 'false'
|
||||
check 403 "eval return nil" 'nil'
|
||||
check 404 "eval return string" '"hi"'
|
||||
|
||||
check 410 "eval 1+2" '3'
|
||||
check 411 "eval 10-3" '7'
|
||||
check 412 "eval 4*5" '20'
|
||||
check 413 "eval 10/4" '2.5'
|
||||
check 414 "eval 10%3" '1'
|
||||
check 415 "eval 2^10" '1024'
|
||||
check 416 "eval (1+2)*3" '9'
|
||||
check 417 "eval 1+2*3 prec" '7'
|
||||
check 418 "eval -5+10" '5'
|
||||
|
||||
check 420 "eval \"a\"..\"b\"" '"ab"'
|
||||
check 421 "eval str..num" '"count: 42"'
|
||||
|
||||
check 430 "eval 1<2" 'true'
|
||||
check 431 "eval 3>2" 'true'
|
||||
check 432 "eval 2==2" 'true'
|
||||
check 433 "eval 1~=2" 'true'
|
||||
check 434 "eval 1<=1" 'true'
|
||||
check 435 "eval 3>=2" 'true'
|
||||
|
||||
check 440 "eval true and 42" '42'
|
||||
check 441 "eval false or 99" '99'
|
||||
check 442 "eval nil or 7" '7'
|
||||
check 443 "eval 1 and 2" '2'
|
||||
check 444 "eval false and 999" 'false'
|
||||
check 445 "eval not true" 'false'
|
||||
check 446 "eval not nil" 'true'
|
||||
check 447 "eval not 0" 'false'
|
||||
|
||||
check 450 "truthy 0 (Lua truthy!)" 'true'
|
||||
check 451 "truthy nil" 'false'
|
||||
check 452 "truthy false" 'false'
|
||||
check 453 "truthy empty string" 'true'
|
||||
|
||||
check 460 "if true then 1 else 2" '1'
|
||||
check 461 "if 1>2 then 100 else 200" '200'
|
||||
check 462 "if-elseif-else branching" '10'
|
||||
|
||||
check 470 "local x=5; x*2" '10'
|
||||
check 471 "mutate x" '2'
|
||||
check 472 "local a,b = 1,2; a+b" '3'
|
||||
|
||||
check 480 "for 1..5 sum" '15'
|
||||
check 481 "for 10..1 step -1 count" '10'
|
||||
check 482 "while i<5 count" '5'
|
||||
check 483 "repeat until i>=3" '3'
|
||||
check 484 "for 1..100 sum" '5050'
|
||||
|
||||
TOTAL=$((PASS + FAIL))
|
||||
if [ $FAIL -eq 0 ]; then
|
||||
echo "ok $PASS/$TOTAL Lua-on-SX tests passed"
|
||||
else
|
||||
echo "FAIL $PASS/$TOTAL passed, $FAIL failed:"
|
||||
echo ""
|
||||
echo "$ERRORS"
|
||||
fi
|
||||
|
||||
[ $FAIL -eq 0 ]
|
||||
30
lib/lua/tests/eval.sx
Normal file
30
lib/lua/tests/eval.sx
Normal file
@@ -0,0 +1,30 @@
|
||||
(define
|
||||
lua-eval-tests
|
||||
(list
|
||||
(list "arith-add" "return 1 + 2" 3)
|
||||
(list "arith-sub" "return 10 - 3" 7)
|
||||
(list "arith-mul" "return 4 * 5" 20)
|
||||
(list "arith-prec" "return 1 + 2 * 3" 7)
|
||||
(list "arith-paren" "return (1 + 2) * 3" 9)
|
||||
(list "unary-neg" "return -5 + 10" 5)
|
||||
(list "lt" "return 1 < 2" true)
|
||||
(list "eq" "return 2 == 2" true)
|
||||
(list "neq" "return 1 ~= 2" true)
|
||||
(list "and-value" "return true and 42" 42)
|
||||
(list "or-value" "return false or 99" 99)
|
||||
(list "or-nil" "return nil or 7" 7)
|
||||
(list "and-short" "return false and 999" false)
|
||||
(list "not-true" "return not true" false)
|
||||
(list "not-zero" "return not 0" false)
|
||||
(list "local" "local x = 5 return x * 2" 10)
|
||||
(list "local-mutate" "local x=0 x=x+1 x=x+1 return x" 2)
|
||||
(list "local-multi" "local a,b = 1,2 return a + b" 3)
|
||||
(list "for-sum" "local sum=0 for i=1,5 do sum=sum+i end return sum" 15)
|
||||
(list "for-neg-step" "local n=0 for i=10,1,-1 do n=n+1 end return n" 10)
|
||||
(list "while" "local i=0 while i<5 do i=i+1 end return i" 5)
|
||||
(list "repeat" "local i=0 repeat i=i+1 until i>=3 return i" 3)
|
||||
(list "for-big" "local s=0 for i=1,100 do s=s+i end return s" 5050)
|
||||
(list
|
||||
"nested-for"
|
||||
"local s=0 for i=1,3 do for j=1,3 do s=s+1 end end return s"
|
||||
9)))
|
||||
32
lib/lua/tests/parse.sx
Normal file
32
lib/lua/tests/parse.sx
Normal file
@@ -0,0 +1,32 @@
|
||||
(define
|
||||
lua-parse-tests
|
||||
(list
|
||||
(list "empty" "" (list (quote lua-block)))
|
||||
(list
|
||||
"int literal"
|
||||
"return 42"
|
||||
(list
|
||||
(quote lua-block)
|
||||
(list (quote lua-return) (list (list (quote lua-num) 42)))))
|
||||
(list
|
||||
"local"
|
||||
"local x = 1"
|
||||
(list
|
||||
(quote lua-block)
|
||||
(list
|
||||
(quote lua-local)
|
||||
(list "x")
|
||||
(list (list (quote lua-num) 1)))))
|
||||
(list
|
||||
"binop"
|
||||
"return 1 + 2"
|
||||
(list
|
||||
(quote lua-block)
|
||||
(list
|
||||
(quote lua-return)
|
||||
(list
|
||||
(list
|
||||
(quote lua-binop)
|
||||
"+"
|
||||
(list (quote lua-num) 1)
|
||||
(list (quote lua-num) 2))))))))
|
||||
353
lib/lua/tokenizer.sx
Normal file
353
lib/lua/tokenizer.sx
Normal file
@@ -0,0 +1,353 @@
|
||||
(define lua-make-token (fn (type value pos) {:pos pos :value value :type type}))
|
||||
|
||||
(define lua-digit? (fn (c) (and (not (= c nil)) (>= c "0") (<= c "9"))))
|
||||
|
||||
(define
|
||||
lua-hex-digit?
|
||||
(fn
|
||||
(c)
|
||||
(and
|
||||
(not (= c nil))
|
||||
(or
|
||||
(lua-digit? c)
|
||||
(and (>= c "a") (<= c "f"))
|
||||
(and (>= c "A") (<= c "F"))))))
|
||||
|
||||
(define
|
||||
lua-letter?
|
||||
(fn
|
||||
(c)
|
||||
(and
|
||||
(not (= c nil))
|
||||
(or (and (>= c "a") (<= c "z")) (and (>= c "A") (<= c "Z"))))))
|
||||
|
||||
(define lua-ident-start? (fn (c) (or (lua-letter? c) (= c "_"))))
|
||||
|
||||
(define lua-ident-char? (fn (c) (or (lua-ident-start? c) (lua-digit? c))))
|
||||
|
||||
(define lua-ws? (fn (c) (or (= c " ") (= c "\t") (= c "\n") (= c "\r"))))
|
||||
|
||||
(define
|
||||
lua-keywords
|
||||
(list
|
||||
"and"
|
||||
"break"
|
||||
"do"
|
||||
"else"
|
||||
"elseif"
|
||||
"end"
|
||||
"false"
|
||||
"for"
|
||||
"function"
|
||||
"goto"
|
||||
"if"
|
||||
"in"
|
||||
"local"
|
||||
"nil"
|
||||
"not"
|
||||
"or"
|
||||
"repeat"
|
||||
"return"
|
||||
"then"
|
||||
"true"
|
||||
"until"
|
||||
"while"))
|
||||
|
||||
(define lua-keyword? (fn (word) (contains? lua-keywords word)))
|
||||
|
||||
(define
|
||||
lua-tokenize
|
||||
(fn
|
||||
(src)
|
||||
(let
|
||||
((tokens (list)) (pos 0) (src-len (len src)))
|
||||
(define
|
||||
lua-peek
|
||||
(fn
|
||||
(offset)
|
||||
(if (< (+ pos offset) src-len) (nth src (+ pos offset)) nil)))
|
||||
(define cur (fn () (lua-peek 0)))
|
||||
(define advance! (fn (n) (set! pos (+ pos n))))
|
||||
(define
|
||||
push!
|
||||
(fn
|
||||
(type value start)
|
||||
(append! tokens (lua-make-token type value start))))
|
||||
(define
|
||||
match-long-open
|
||||
(fn
|
||||
()
|
||||
(if
|
||||
(= (cur) "[")
|
||||
(let
|
||||
((p (+ pos 1)) (level 0))
|
||||
(begin
|
||||
(define
|
||||
count-eq
|
||||
(fn
|
||||
()
|
||||
(when
|
||||
(and (< p src-len) (= (nth src p) "="))
|
||||
(begin
|
||||
(set! level (+ level 1))
|
||||
(set! p (+ p 1))
|
||||
(count-eq)))))
|
||||
(count-eq)
|
||||
(if (and (< p src-len) (= (nth src p) "[")) level -1)))
|
||||
-1)))
|
||||
(define
|
||||
read-long-body
|
||||
(fn
|
||||
(level)
|
||||
(let
|
||||
((start pos) (result nil))
|
||||
(begin
|
||||
(define
|
||||
scan
|
||||
(fn
|
||||
()
|
||||
(cond
|
||||
((>= pos src-len) (set! result (slice src start pos)))
|
||||
((= (cur) "]")
|
||||
(let
|
||||
((p (+ pos 1)) (eq-count 0))
|
||||
(begin
|
||||
(define
|
||||
count-eq
|
||||
(fn
|
||||
()
|
||||
(when
|
||||
(and (< p src-len) (= (nth src p) "="))
|
||||
(begin
|
||||
(set! eq-count (+ eq-count 1))
|
||||
(set! p (+ p 1))
|
||||
(count-eq)))))
|
||||
(count-eq)
|
||||
(if
|
||||
(and
|
||||
(= eq-count level)
|
||||
(< p src-len)
|
||||
(= (nth src p) "]"))
|
||||
(begin
|
||||
(set! result (slice src start pos))
|
||||
(set! pos (+ p 1)))
|
||||
(begin (advance! 1) (scan))))))
|
||||
(else (begin (advance! 1) (scan))))))
|
||||
(scan)
|
||||
result))))
|
||||
(define
|
||||
skip-line-comment!
|
||||
(fn
|
||||
()
|
||||
(when
|
||||
(and (< pos src-len) (not (= (cur) "\n")))
|
||||
(begin (advance! 1) (skip-line-comment!)))))
|
||||
(define
|
||||
skip-ws!
|
||||
(fn
|
||||
()
|
||||
(cond
|
||||
((>= pos src-len) nil)
|
||||
((lua-ws? (cur)) (begin (advance! 1) (skip-ws!)))
|
||||
((and (= (cur) "-") (< (+ pos 1) src-len) (= (lua-peek 1) "-"))
|
||||
(begin
|
||||
(advance! 2)
|
||||
(let
|
||||
((lvl (match-long-open)))
|
||||
(cond
|
||||
((>= lvl 0)
|
||||
(begin
|
||||
(advance! (+ 2 lvl))
|
||||
(read-long-body lvl)
|
||||
(skip-ws!)))
|
||||
(else (begin (skip-line-comment!) (skip-ws!)))))))
|
||||
(else nil))))
|
||||
(define
|
||||
read-ident
|
||||
(fn
|
||||
(start)
|
||||
(begin
|
||||
(when
|
||||
(and (< pos src-len) (lua-ident-char? (cur)))
|
||||
(begin (advance! 1) (read-ident start)))
|
||||
(slice src start pos))))
|
||||
(define
|
||||
read-decimal-digits!
|
||||
(fn
|
||||
()
|
||||
(when
|
||||
(and (< pos src-len) (lua-digit? (cur)))
|
||||
(begin (advance! 1) (read-decimal-digits!)))))
|
||||
(define
|
||||
read-hex-digits!
|
||||
(fn
|
||||
()
|
||||
(when
|
||||
(and (< pos src-len) (lua-hex-digit? (cur)))
|
||||
(begin (advance! 1) (read-hex-digits!)))))
|
||||
(define
|
||||
read-exp-part!
|
||||
(fn
|
||||
()
|
||||
(when
|
||||
(and (< pos src-len) (or (= (cur) "e") (= (cur) "E")))
|
||||
(let
|
||||
((p1 (lua-peek 1)))
|
||||
(when
|
||||
(or
|
||||
(and (not (= p1 nil)) (lua-digit? p1))
|
||||
(and
|
||||
(or (= p1 "+") (= p1 "-"))
|
||||
(< (+ pos 2) src-len)
|
||||
(lua-digit? (lua-peek 2))))
|
||||
(begin
|
||||
(advance! 1)
|
||||
(when
|
||||
(and
|
||||
(< pos src-len)
|
||||
(or (= (cur) "+") (= (cur) "-")))
|
||||
(advance! 1))
|
||||
(read-decimal-digits!)))))))
|
||||
(define
|
||||
read-number
|
||||
(fn
|
||||
(start)
|
||||
(cond
|
||||
((and (= (cur) "0") (< (+ pos 1) src-len) (or (= (lua-peek 1) "x") (= (lua-peek 1) "X")))
|
||||
(begin
|
||||
(advance! 2)
|
||||
(read-hex-digits!)
|
||||
(let
|
||||
((raw (slice src (+ start 2) pos)))
|
||||
(parse-number (str "0x" raw)))))
|
||||
(else
|
||||
(begin
|
||||
(read-decimal-digits!)
|
||||
(when
|
||||
(and
|
||||
(< pos src-len)
|
||||
(= (cur) ".")
|
||||
(< (+ pos 1) src-len)
|
||||
(lua-digit? (lua-peek 1)))
|
||||
(begin (advance! 1) (read-decimal-digits!)))
|
||||
(read-exp-part!)
|
||||
(parse-number (slice src start pos)))))))
|
||||
(define
|
||||
read-string
|
||||
(fn
|
||||
(quote-char)
|
||||
(let
|
||||
((chars (list)))
|
||||
(begin
|
||||
(advance! 1)
|
||||
(define
|
||||
loop
|
||||
(fn
|
||||
()
|
||||
(cond
|
||||
((>= pos src-len) nil)
|
||||
((= (cur) "\\")
|
||||
(begin
|
||||
(advance! 1)
|
||||
(when
|
||||
(< pos src-len)
|
||||
(let
|
||||
((ch (cur)))
|
||||
(begin
|
||||
(cond
|
||||
((= ch "n") (append! chars "\n"))
|
||||
((= ch "t") (append! chars "\t"))
|
||||
((= ch "r") (append! chars "\r"))
|
||||
((= ch "\\") (append! chars "\\"))
|
||||
((= ch "'") (append! chars "'"))
|
||||
((= ch "\"") (append! chars "\""))
|
||||
(else (append! chars ch)))
|
||||
(advance! 1))))
|
||||
(loop)))
|
||||
((= (cur) quote-char) (advance! 1))
|
||||
(else
|
||||
(begin (append! chars (cur)) (advance! 1) (loop))))))
|
||||
(loop)
|
||||
(join "" chars)))))
|
||||
(define
|
||||
try-punct
|
||||
(fn
|
||||
(start)
|
||||
(let
|
||||
((c (cur)) (c1 (lua-peek 1)) (c2 (lua-peek 2)))
|
||||
(cond
|
||||
((and (= c ".") (= c1 ".") (= c2 "."))
|
||||
(begin (advance! 3) (push! "op" "..." start) true))
|
||||
((and (= c ".") (= c1 "."))
|
||||
(begin (advance! 2) (push! "op" ".." start) true))
|
||||
((and (= c "=") (= c1 "="))
|
||||
(begin (advance! 2) (push! "op" "==" start) true))
|
||||
((and (= c "~") (= c1 "="))
|
||||
(begin (advance! 2) (push! "op" "~=" start) true))
|
||||
((and (= c "<") (= c1 "="))
|
||||
(begin (advance! 2) (push! "op" "<=" start) true))
|
||||
((and (= c ">") (= c1 "="))
|
||||
(begin (advance! 2) (push! "op" ">=" start) true))
|
||||
((and (= c ":") (= c1 ":"))
|
||||
(begin (advance! 2) (push! "op" "::" start) true))
|
||||
((or (= c "+") (= c "-") (= c "*") (= c "/") (= c "%") (= c "^") (= c "#") (= c "<") (= c ">") (= c "=") (= c "(") (= c ")") (= c "{") (= c "}") (= c "[") (= c "]") (= c ";") (= c ":") (= c ",") (= c "."))
|
||||
(begin (advance! 1) (push! "op" c start) true))
|
||||
(else false)))))
|
||||
(define
|
||||
step
|
||||
(fn
|
||||
()
|
||||
(begin
|
||||
(skip-ws!)
|
||||
(when
|
||||
(< pos src-len)
|
||||
(let
|
||||
((start pos) (c (cur)))
|
||||
(cond
|
||||
((lua-ident-start? c)
|
||||
(let
|
||||
((word (read-ident start)))
|
||||
(begin
|
||||
(if
|
||||
(lua-keyword? word)
|
||||
(push! "keyword" word start)
|
||||
(push! "ident" word start))
|
||||
(step))))
|
||||
((lua-digit? c)
|
||||
(let
|
||||
((v (read-number start)))
|
||||
(begin (push! "number" v start) (step))))
|
||||
((and (= c ".") (< (+ pos 1) src-len) (lua-digit? (lua-peek 1)))
|
||||
(begin
|
||||
(advance! 1)
|
||||
(read-decimal-digits!)
|
||||
(read-exp-part!)
|
||||
(push!
|
||||
"number"
|
||||
(parse-number (slice src start pos))
|
||||
start)
|
||||
(step)))
|
||||
((or (= c "\"") (= c "'"))
|
||||
(let
|
||||
((s (read-string c)))
|
||||
(begin (push! "string" s start) (step))))
|
||||
((= c "[")
|
||||
(let
|
||||
((lvl (match-long-open)))
|
||||
(cond
|
||||
((>= lvl 0)
|
||||
(begin
|
||||
(advance! (+ 2 lvl))
|
||||
(when (= (cur) "\n") (advance! 1))
|
||||
(let
|
||||
((s (read-long-body lvl)))
|
||||
(begin (push! "string" s start) (step)))))
|
||||
(else
|
||||
(begin (advance! 1) (push! "op" "[" start) (step))))))
|
||||
((try-punct start) (step))
|
||||
(else
|
||||
(error
|
||||
(str "lua-tokenize: unexpected char " c " at " pos)))))))))
|
||||
(step)
|
||||
(push! "eof" nil pos)
|
||||
tokens)))
|
||||
436
lib/lua/transpile.sx
Normal file
436
lib/lua/transpile.sx
Normal file
@@ -0,0 +1,436 @@
|
||||
(define
|
||||
lua-tx
|
||||
(fn
|
||||
(node)
|
||||
(cond
|
||||
((= node nil) nil)
|
||||
((not (= (type-of node) "list")) node)
|
||||
(else (lua-tx-dispatch (first node) node)))))
|
||||
|
||||
(define
|
||||
lua-tx-dispatch
|
||||
(fn
|
||||
(tag node)
|
||||
(cond
|
||||
((= tag (quote lua-num)) (nth node 1))
|
||||
((= tag (quote lua-str)) (nth node 1))
|
||||
((= tag (quote lua-nil)) nil)
|
||||
((= tag (quote lua-true)) true)
|
||||
((= tag (quote lua-false)) false)
|
||||
((= tag (quote lua-name)) (make-symbol (nth node 1)))
|
||||
((= tag (quote lua-vararg))
|
||||
(error "lua-transpile: ... not yet supported"))
|
||||
((= tag (quote lua-binop)) (lua-tx-binop node))
|
||||
((= tag (quote lua-unop)) (lua-tx-unop node))
|
||||
((= tag (quote lua-call)) (lua-tx-call node))
|
||||
((= tag (quote lua-method-call)) (lua-tx-method-call node))
|
||||
((= tag (quote lua-field)) (lua-tx-field node))
|
||||
((= tag (quote lua-index)) (lua-tx-index node))
|
||||
((= tag (quote lua-table)) (lua-tx-table node))
|
||||
((= tag (quote lua-function)) (lua-tx-function node))
|
||||
((= tag (quote lua-block)) (lua-tx-block node))
|
||||
((= tag (quote lua-local)) (lua-tx-local node))
|
||||
((= tag (quote lua-assign)) (lua-tx-assign node))
|
||||
((= tag (quote lua-if)) (lua-tx-if node))
|
||||
((= tag (quote lua-while)) (lua-tx-while node))
|
||||
((= tag (quote lua-repeat)) (lua-tx-repeat node))
|
||||
((= tag (quote lua-for-num)) (lua-tx-for-num node))
|
||||
((= tag (quote lua-do)) (lua-tx-do node))
|
||||
((= tag (quote lua-break)) (quote lua-break-marker))
|
||||
((= tag (quote lua-return)) (lua-tx-return node))
|
||||
((= tag (quote lua-call-stmt)) (lua-tx (nth node 1)))
|
||||
((= tag (quote lua-local-function)) (lua-tx-local-function node))
|
||||
((= tag (quote lua-function-decl)) (lua-tx-function-decl node))
|
||||
(else (error (str "lua-transpile: unknown node " tag))))))
|
||||
|
||||
(define
|
||||
lua-tx-binop
|
||||
(fn
|
||||
(node)
|
||||
(let
|
||||
((op (nth node 1))
|
||||
(a (lua-tx (nth node 2)))
|
||||
(b (lua-tx (nth node 3))))
|
||||
(cond
|
||||
((= op "+") (list (make-symbol "lua-add") a b))
|
||||
((= op "-") (list (make-symbol "lua-sub") a b))
|
||||
((= op "*") (list (make-symbol "lua-mul") a b))
|
||||
((= op "/") (list (make-symbol "lua-div") a b))
|
||||
((= op "%") (list (make-symbol "lua-mod") a b))
|
||||
((= op "^") (list (make-symbol "lua-pow") a b))
|
||||
((= op "..") (list (make-symbol "lua-concat") a b))
|
||||
((= op "==") (list (make-symbol "lua-eq") a b))
|
||||
((= op "~=") (list (make-symbol "lua-neq") a b))
|
||||
((= op "<") (list (make-symbol "lua-lt") a b))
|
||||
((= op "<=") (list (make-symbol "lua-le") a b))
|
||||
((= op ">") (list (make-symbol "lua-gt") a b))
|
||||
((= op ">=") (list (make-symbol "lua-ge") a b))
|
||||
((= op "and")
|
||||
(list
|
||||
(make-symbol "let")
|
||||
(list (list (make-symbol "_la") a))
|
||||
(list
|
||||
(make-symbol "if")
|
||||
(list (make-symbol "lua-truthy?") (make-symbol "_la"))
|
||||
b
|
||||
(make-symbol "_la"))))
|
||||
((= op "or")
|
||||
(list
|
||||
(make-symbol "let")
|
||||
(list (list (make-symbol "_la") a))
|
||||
(list
|
||||
(make-symbol "if")
|
||||
(list (make-symbol "lua-truthy?") (make-symbol "_la"))
|
||||
(make-symbol "_la")
|
||||
b)))
|
||||
(else (error (str "lua-transpile: unknown binop " op)))))))
|
||||
|
||||
(define
|
||||
lua-tx-unop
|
||||
(fn
|
||||
(node)
|
||||
(let
|
||||
((op (nth node 1)) (e (lua-tx (nth node 2))))
|
||||
(cond
|
||||
((= op "-") (list (make-symbol "lua-neg") e))
|
||||
((= op "not")
|
||||
(list (make-symbol "not") (list (make-symbol "lua-truthy?") e)))
|
||||
((= op "#") (list (make-symbol "lua-len") e))
|
||||
(else (error (str "lua-transpile: unknown unop " op)))))))
|
||||
|
||||
(define
|
||||
lua-tx-call
|
||||
(fn
|
||||
(node)
|
||||
(let
|
||||
((fn-ast (nth node 1)) (args (nth node 2)))
|
||||
(cons (lua-tx fn-ast) (map lua-tx args)))))
|
||||
|
||||
(define
|
||||
lua-tx-method-call
|
||||
(fn
|
||||
(node)
|
||||
(let
|
||||
((obj (lua-tx (nth node 1)))
|
||||
(name (nth node 2))
|
||||
(args (nth node 3)))
|
||||
(cons
|
||||
(list (make-symbol "lua-get") obj name)
|
||||
(cons obj (map lua-tx args))))))
|
||||
|
||||
(define
|
||||
lua-tx-field
|
||||
(fn
|
||||
(node)
|
||||
(list (make-symbol "lua-get") (lua-tx (nth node 1)) (nth node 2))))
|
||||
|
||||
(define
|
||||
lua-tx-index
|
||||
(fn
|
||||
(node)
|
||||
(list
|
||||
(make-symbol "lua-get")
|
||||
(lua-tx (nth node 1))
|
||||
(lua-tx (nth node 2)))))
|
||||
|
||||
(define
|
||||
lua-tx-table
|
||||
(fn
|
||||
(node)
|
||||
(let
|
||||
((fields (rest node)))
|
||||
(cons (make-symbol "lua-make-table") (map lua-tx-table-field fields)))))
|
||||
|
||||
(define
|
||||
lua-tx-table-field
|
||||
(fn
|
||||
(f)
|
||||
(cond
|
||||
((= (first f) (quote lua-pos))
|
||||
(list (make-symbol "list") "pos" (lua-tx (nth f 1))))
|
||||
((= (first f) (quote lua-kv))
|
||||
(list
|
||||
(make-symbol "list")
|
||||
"kv"
|
||||
(lua-tx (nth f 1))
|
||||
(lua-tx (nth f 2))))
|
||||
(else (error "lua-transpile: unknown table field")))))
|
||||
|
||||
(define
|
||||
lua-tx-function
|
||||
(fn
|
||||
(node)
|
||||
(let
|
||||
((params (nth node 1))
|
||||
(is-vararg (nth node 2))
|
||||
(body (nth node 3)))
|
||||
(let
|
||||
((sym-params (map make-symbol params)))
|
||||
(list (make-symbol "fn") sym-params (lua-tx body))))))
|
||||
|
||||
(define
|
||||
lua-tx-block
|
||||
(fn
|
||||
(node)
|
||||
(let
|
||||
((stmts (rest node)))
|
||||
(cond
|
||||
((= (len stmts) 0) nil)
|
||||
((= (len stmts) 1) (lua-tx (first stmts)))
|
||||
(else (cons (make-symbol "begin") (map lua-tx stmts)))))))
|
||||
|
||||
(define
|
||||
lua-tx-local
|
||||
(fn
|
||||
(node)
|
||||
(let
|
||||
((names (nth node 1)) (exps (nth node 2)))
|
||||
(cond
|
||||
((= (len names) 1)
|
||||
(list
|
||||
(make-symbol "define")
|
||||
(make-symbol (first names))
|
||||
(if (> (len exps) 0) (lua-tx (first exps)) nil)))
|
||||
(else
|
||||
(cons (make-symbol "begin") (lua-tx-local-pairs names exps 0)))))))
|
||||
|
||||
(define
|
||||
lua-tx-local-pairs
|
||||
(fn
|
||||
(names exps i)
|
||||
(if
|
||||
(>= i (len names))
|
||||
(list)
|
||||
(cons
|
||||
(list
|
||||
(make-symbol "define")
|
||||
(make-symbol (nth names i))
|
||||
(if (< i (len exps)) (lua-tx (nth exps i)) nil))
|
||||
(lua-tx-local-pairs names exps (+ i 1))))))
|
||||
|
||||
(define
|
||||
lua-tx-assign
|
||||
(fn
|
||||
(node)
|
||||
(let
|
||||
((lhss (nth node 1)) (rhss (nth node 2)))
|
||||
(cond
|
||||
((= (len lhss) 1)
|
||||
(lua-tx-single-assign (first lhss) (lua-tx (first rhss))))
|
||||
(else
|
||||
(cons (make-symbol "begin") (lua-tx-assign-pairs lhss rhss 0)))))))
|
||||
|
||||
(define
|
||||
lua-tx-assign-pairs
|
||||
(fn
|
||||
(lhss rhss i)
|
||||
(if
|
||||
(>= i (len lhss))
|
||||
(list)
|
||||
(cons
|
||||
(lua-tx-single-assign
|
||||
(nth lhss i)
|
||||
(if (< i (len rhss)) (lua-tx (nth rhss i)) nil))
|
||||
(lua-tx-assign-pairs lhss rhss (+ i 1))))))
|
||||
|
||||
(define
|
||||
lua-tx-single-assign
|
||||
(fn
|
||||
(lhs rhs)
|
||||
(cond
|
||||
((= (first lhs) (quote lua-name))
|
||||
(list (make-symbol "set!") (make-symbol (nth lhs 1)) rhs))
|
||||
((= (first lhs) (quote lua-field))
|
||||
(list
|
||||
(make-symbol "lua-set!")
|
||||
(lua-tx (nth lhs 1))
|
||||
(nth lhs 2)
|
||||
rhs))
|
||||
((= (first lhs) (quote lua-index))
|
||||
(list
|
||||
(make-symbol "lua-set!")
|
||||
(lua-tx (nth lhs 1))
|
||||
(lua-tx (nth lhs 2))
|
||||
rhs))
|
||||
(else (error "lua-transpile: bad assignment target")))))
|
||||
|
||||
(define
|
||||
lua-tx-if
|
||||
(fn
|
||||
(node)
|
||||
(let
|
||||
((cnd (lua-tx (nth node 1)))
|
||||
(then-body (lua-tx (nth node 2)))
|
||||
(elseifs (nth node 3))
|
||||
(else-body (nth node 4)))
|
||||
(if
|
||||
(and (= (len elseifs) 0) (= else-body nil))
|
||||
(list
|
||||
(make-symbol "when")
|
||||
(list (make-symbol "lua-truthy?") cnd)
|
||||
then-body)
|
||||
(lua-tx-if-cond cnd then-body elseifs else-body)))))
|
||||
|
||||
(define
|
||||
lua-tx-if-cond
|
||||
(fn
|
||||
(cnd then-body elseifs else-body)
|
||||
(let
|
||||
((clauses (cons (list (list (make-symbol "lua-truthy?") cnd) then-body) (map lua-tx-elseif elseifs))))
|
||||
(cons
|
||||
(make-symbol "cond")
|
||||
(if
|
||||
(= else-body nil)
|
||||
clauses
|
||||
(append
|
||||
clauses
|
||||
(list (list (make-symbol "else") (lua-tx else-body)))))))))
|
||||
|
||||
(define
|
||||
lua-tx-elseif
|
||||
(fn
|
||||
(pair)
|
||||
(list
|
||||
(list (make-symbol "lua-truthy?") (lua-tx (first pair)))
|
||||
(lua-tx (nth pair 1)))))
|
||||
|
||||
(define
|
||||
lua-tx-while
|
||||
(fn
|
||||
(node)
|
||||
(let
|
||||
((cnd (lua-tx (nth node 1))) (body (lua-tx (nth node 2))))
|
||||
(list
|
||||
(make-symbol "let")
|
||||
(list)
|
||||
(list
|
||||
(make-symbol "define")
|
||||
(make-symbol "_while_loop")
|
||||
(list
|
||||
(make-symbol "fn")
|
||||
(list)
|
||||
(list
|
||||
(make-symbol "when")
|
||||
(list (make-symbol "lua-truthy?") cnd)
|
||||
(list
|
||||
(make-symbol "begin")
|
||||
body
|
||||
(list (make-symbol "_while_loop"))))))
|
||||
(list (make-symbol "_while_loop"))))))
|
||||
|
||||
(define
|
||||
lua-tx-repeat
|
||||
(fn
|
||||
(node)
|
||||
(let
|
||||
((body (lua-tx (nth node 1))) (cnd (lua-tx (nth node 2))))
|
||||
(list
|
||||
(make-symbol "let")
|
||||
(list)
|
||||
(list
|
||||
(make-symbol "define")
|
||||
(make-symbol "_repeat_loop")
|
||||
(list
|
||||
(make-symbol "fn")
|
||||
(list)
|
||||
(list
|
||||
(make-symbol "begin")
|
||||
body
|
||||
(list
|
||||
(make-symbol "when")
|
||||
(list
|
||||
(make-symbol "not")
|
||||
(list (make-symbol "lua-truthy?") cnd))
|
||||
(list (make-symbol "_repeat_loop"))))))
|
||||
(list (make-symbol "_repeat_loop"))))))
|
||||
|
||||
(define
|
||||
lua-tx-for-num
|
||||
(fn
|
||||
(node)
|
||||
(let
|
||||
((name (nth node 1))
|
||||
(start (lua-tx (nth node 2)))
|
||||
(stop (lua-tx (nth node 3)))
|
||||
(step-ast (nth node 4))
|
||||
(body (lua-tx (nth node 5))))
|
||||
(let
|
||||
((step (if (= step-ast nil) 1 (lua-tx step-ast))))
|
||||
(list
|
||||
(make-symbol "let")
|
||||
(list
|
||||
(list (make-symbol "_for_stop") stop)
|
||||
(list (make-symbol "_for_step") step))
|
||||
(list (make-symbol "define") (make-symbol name) start)
|
||||
(list
|
||||
(make-symbol "define")
|
||||
(make-symbol "_for_loop")
|
||||
(list
|
||||
(make-symbol "fn")
|
||||
(list)
|
||||
(list
|
||||
(make-symbol "when")
|
||||
(list
|
||||
(make-symbol "lua-for-continue?")
|
||||
(make-symbol name)
|
||||
(make-symbol "_for_stop")
|
||||
(make-symbol "_for_step"))
|
||||
(list
|
||||
(make-symbol "begin")
|
||||
body
|
||||
(list
|
||||
(make-symbol "set!")
|
||||
(make-symbol name)
|
||||
(list
|
||||
(make-symbol "+")
|
||||
(make-symbol name)
|
||||
(make-symbol "_for_step")))
|
||||
(list (make-symbol "_for_loop"))))))
|
||||
(list (make-symbol "_for_loop")))))))
|
||||
|
||||
(define lua-tx-do (fn (node) (lua-tx (nth node 1))))
|
||||
|
||||
(define
|
||||
lua-tx-return
|
||||
(fn
|
||||
(node)
|
||||
(let
|
||||
((exps (nth node 1)))
|
||||
(cond
|
||||
((= (len exps) 0) nil)
|
||||
((= (len exps) 1) (lua-tx (first exps)))
|
||||
(else (cons (make-symbol "list") (map lua-tx exps)))))))
|
||||
|
||||
(define
|
||||
lua-tx-local-function
|
||||
(fn
|
||||
(node)
|
||||
(let
|
||||
((name (nth node 1)) (func (nth node 2)))
|
||||
(list (make-symbol "define") (make-symbol name) (lua-tx func)))))
|
||||
|
||||
(define
|
||||
lua-tx-function-decl
|
||||
(fn
|
||||
(node)
|
||||
(let
|
||||
((target (nth node 1)) (func (nth node 2)))
|
||||
(cond
|
||||
((= (first target) (quote lua-name))
|
||||
(list
|
||||
(make-symbol "define")
|
||||
(make-symbol (nth target 1))
|
||||
(lua-tx func)))
|
||||
((= (first target) (quote lua-field))
|
||||
(list
|
||||
(make-symbol "lua-set!")
|
||||
(lua-tx (nth target 1))
|
||||
(nth target 2)
|
||||
(lua-tx func)))
|
||||
(else (error "lua-transpile: bad function decl target"))))))
|
||||
|
||||
(define lua-transpile (fn (src) (lua-tx (lua-parse src))))
|
||||
|
||||
(define
|
||||
lua-eval-ast
|
||||
(fn (src) (let ((sx (lua-transpile src))) (eval-expr sx))))
|
||||
Reference in New Issue
Block a user