flesh out quoting

This commit is contained in:
Jeremy Penner 2023-12-04 22:47:59 -05:00
parent 7560aac500
commit f86b7ba60b
3 changed files with 57 additions and 29 deletions

View file

@ -66,10 +66,28 @@ Sorry Phil.
### q ### q
Defines a terra quotation, compiling down to the `` ` `` operator if given one argument, and Defines a terra quotation, compiling down to the `` ` `` operator if given one argument, and
`quote` / `end` if given more than one. `quote` / `in` / `end` if given more than one. The resulting quote can always be used as an
expression that returns a value; if `q` is passed more than one argument, the last form is
used as the `in` block. To force no value to be returned, you can pass `($)` as the last
argument, which corresponds to the empty tuple. Note that quotes inherently creates a new
temporary scope, so variables created in a quote will go out of scope by the end of the
quote.
```fennel ```fennel
(fn inc [x] (q (+ x 1))) ; compiles to: function(x) `(x + 1) end (fn inc [x] (q (+ x 1))) ; compiles to: function(x) return `(x + 1) end
(fn do-thing [f x]
(q (var z (+ ,x 1))
(f z)
($)))
; compiles to:
; function(f, x)
; return quote
; var z = [x] + 1
; f(z)
; in
; {}
; end
; end
``` ```
### Type syntax ### Type syntax

31
go.fnl
View file

@ -1,15 +1,20 @@
(local fennel (require :fennel)) (local fennel (require :fennel))
(import-macros {: def : q : ttype : static : unterra : untype} :terra) (import-macros {: def : q : ttype : static : printform} :terra)
(local iseven (def [uint32 : bool])) (print "define do-thing")
(local isodd (def [n uint32 : bool] (fn do-thing [f x]
(if (= n 0) (printform
(return true) (q (var z (+ x 1))
(return (iseven (- n 1)))))) (f z)
(iseven:adddefinition (def [n uint32 : bool] ($)))
(if (= n 0) )
(return false)
(return (isodd (- n 1)))))) (print "define thing-doer")
(print iseven) (local thing-doer (def [x int] (return)))
(print (iseven 5) (isodd 5)) ; (print thing-doer)
(print (iseven 6) (isodd 6)) ; (printform
(def []
(var z 10)
,(do-thing thing-doer `z))
; )
nil

View file

@ -15,11 +15,15 @@
(fn indent [str scope] (fn indent [str scope]
(.. (string.rep " " scope.indent) str)) (.. (string.rep " " scope.indent) str))
(fn block [pre stmts post scope f] (fn indented [f scope ?f-will-indent]
(set scope.indent (+ scope.indent 2)) (set scope.indent (+ scope.indent 2))
(local block (commasep stmts #(indent (f $1) scope) "\n")) (local result (if ?f-will-indent (f) (indent (f) scope)))
(set scope.indent (- scope.indent 2)) (set scope.indent (- scope.indent 2))
(.. pre "\n" block "\n" (indent post scope))) result)
(fn block [pre stmts post scope f]
(let [block (indented #(commasep stmts #(indent (f $1) scope) "\n") scope true)]
(.. pre "\n" block "\n" (indent post scope))))
(local extract {}) (local extract {})
(fn extract.quotes-in-table [into tbl inputs locals] (fn extract.quotes-in-table [into tbl inputs locals]
@ -224,23 +228,25 @@
(fn forms.if [params scope] (fn forms.if [params scope]
(let [has-else? (= (% (length params) 2) 1) (let [has-else? (= (% (length params) 2) 1)
ilast (if has-else? (length params) (- (length params) 1)) ielse (when has-else? (length params))
ielse (when has-else? ilast)
clauses (fcollect [i 1 (length params) 2] clauses (fcollect [i 1 (length params) 2]
(if (= i ielse) (if (= i ielse)
{:pre (indent :else scope) {:pre (indent :else scope)
:post :end
:clause (. params i)} :clause (. params i)}
{:pre (.. (if (= i 1) :if (indent :elseif scope)) " " (comp.expr (. params i) scope) " then") {:pre (.. (if (= i 1) :if (indent :elseif scope)) " " (comp.expr (. params i) scope) " then")
:post (if (= i ilast) :end "")
:clause (. params (+ i 1))})) :clause (. params (+ i 1))}))
blocks (icollect [_ clause (ipairs clauses)] blocks (icollect [_ clause (ipairs clauses)]
(scope:with #(block clause.pre [clause.clause] clause.post scope #(comp.expr $1 scope))))] (scope:with #(.. clause.pre "\n" (indented #(comp.expr clause.clause scope) scope))))]
(table.concat blocks "\n"))) (.. (table.concat blocks "\n") "\n" (indent :end scope))))
(fn comp.quote [stmts scope] (fn comp.quote [stmts scope]
(if (= (length stmts) 1) (.. "`(" (comp.expr (. stmts 1) scope) ")") (if (= (length stmts) 0) (error "nothing to quote")
(.. "quote\n" (commasep stmts #(comp.expr $1 scope)) "\nend"))) (= (length stmts) 1) (.. "`(" (comp.expr (. stmts 1) scope) ")")
(let [last-expr (. stmts (length stmts))]
(tset stmts (length stmts) nil)
(.. (block :quote stmts :in scope #(comp.expr $1 scope)) "\n"
(indented #(comp.expr last-expr scope) scope) "\n"
(indent :end scope)))))
(fn comp.global [[typ initial-val] scope] (fn comp.global [[typ initial-val] scope]
(.. "global(" (comp.type typ scope) "," (comp.expr initial-val scope) ")")) (.. "global(" (comp.type typ scope) "," (comp.expr initial-val scope) ")"))
@ -262,7 +268,6 @@
(fn q [...] (build [...] comp.quote)) (fn q [...] (build [...] comp.quote))
(fn static [typ initial-value] (build [typ initial-value] comp.global)) (fn static [typ initial-value] (build [typ initial-value] comp.global))
(fn unterra [...] (view (macroexpand (terra ...)))) (fn printform [form] `(do (print ,(view (macroexpand form))) ,form))
(fn untype [...] (view (macroexpand (ttype ...))))
{: terra : ttype : def : q : static : unterra : untype} {: terra : ttype : def : q : static : printform}