diff --git a/README.md b/README.md index 07d5825..082b392 100644 --- a/README.md +++ b/README.md @@ -66,10 +66,28 @@ Sorry Phil. ### q 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 -(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 diff --git a/go.fnl b/go.fnl index 43dc9f0..efcd62a 100644 --- a/go.fnl +++ b/go.fnl @@ -1,15 +1,20 @@ (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])) -(local isodd (def [n uint32 : bool] - (if (= n 0) - (return true) - (return (iseven (- n 1)))))) -(iseven:adddefinition (def [n uint32 : bool] - (if (= n 0) - (return false) - (return (isodd (- n 1)))))) -(print iseven) -(print (iseven 5) (isodd 5)) -(print (iseven 6) (isodd 6)) +(print "define do-thing") +(fn do-thing [f x] +(printform + (q (var z (+ x 1)) + (f z) + ($))) +) + +(print "define thing-doer") +(local thing-doer (def [x int] (return))) +; (print thing-doer) +; (printform +(def [] + (var z 10) + ,(do-thing thing-doer `z)) +; ) +nil \ No newline at end of file diff --git a/terra.fnl b/terra.fnl index ce20130..5dabe26 100644 --- a/terra.fnl +++ b/terra.fnl @@ -15,11 +15,15 @@ (fn indent [str scope] (.. (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)) - (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)) - (.. 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 {}) (fn extract.quotes-in-table [into tbl inputs locals] @@ -224,23 +228,25 @@ (fn forms.if [params scope] (let [has-else? (= (% (length params) 2) 1) - ilast (if has-else? (length params) (- (length params) 1)) - ielse (when has-else? ilast) + ielse (when has-else? (length params)) clauses (fcollect [i 1 (length params) 2] (if (= i ielse) {:pre (indent :else scope) - :post :end :clause (. params i)} {:pre (.. (if (= i 1) :if (indent :elseif scope)) " " (comp.expr (. params i) scope) " then") - :post (if (= i ilast) :end "") :clause (. params (+ i 1))})) blocks (icollect [_ clause (ipairs clauses)] - (scope:with #(block clause.pre [clause.clause] clause.post scope #(comp.expr $1 scope))))] - (table.concat blocks "\n"))) + (scope:with #(.. clause.pre "\n" (indented #(comp.expr clause.clause scope) scope))))] + (.. (table.concat blocks "\n") "\n" (indent :end scope)))) (fn comp.quote [stmts scope] - (if (= (length stmts) 1) (.. "`(" (comp.expr (. stmts 1) scope) ")") - (.. "quote\n" (commasep stmts #(comp.expr $1 scope)) "\nend"))) + (if (= (length stmts) 0) (error "nothing to quote") + (= (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] (.. "global(" (comp.type typ scope) "," (comp.expr initial-val scope) ")")) @@ -262,7 +268,6 @@ (fn q [...] (build [...] comp.quote)) (fn static [typ initial-value] (build [typ initial-value] comp.global)) -(fn unterra [...] (view (macroexpand (terra ...)))) -(fn untype [...] (view (macroexpand (ttype ...)))) +(fn printform [form] `(do (print ,(view (macroexpand form))) ,form)) -{: terra : ttype : def : q : static : unterra : untype} \ No newline at end of file +{: terra : ttype : def : q : static : printform} \ No newline at end of file