diff --git a/README.md b/README.md index 082b392..7d4c590 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,18 @@ An experiment in combining [Fennel](https://fennel-lang.org) and [Terra](https:/ ## Rationale Idk, seemed cool +## Goals and Non-Goals +At its core are a few a largely non-opinionated macros that directly expose the functionality +that is only available through Terra's custom syntax. Terra code is not necessarily meant to +read like Fennel or have the same semantics. Early returns are fine, all variables are mutable, +break and continue and imperative loops are the norm. + +Ideally it would be possible to build a much cleaner set of macros on top of these base macros. +But the goal isn't to design a nice low-level language, it's to expose a powerful compilation +target. It's assumed that if you want to take advantage of Terra, it's probably because you +want to do horrible code-generation tricks. Hosting it inside Fennel simply makes it more +comfortable to do so. + ## Usage At the top of your file, include the following: ```fennel @@ -177,17 +189,27 @@ it consistently mean "create a quote" everywhere. Not sure.) #### var ```fennel -(var name initial-value) ; compiles to: var name = initial-value -(var name type initial-value) ; compiles to: var name : type = initial-value +(var name initial-value) ; compiles to: var name = initial-value +(var name type initial-value) ; compiles to: var name : type = initial-value +(var (name1 name2) val1 val2) ; compiles to: var name1, name2 = val1, val2 +(var {name1 type1 name2 type2} val1 val2) ; compiles to: var name1 : type1, name2 : type2 = val1, val2 +(var {undefined type}) ; compiles to: var undefined : type ``` Define a local variable named `var`, and set its initial value to `initial-value`. You can -manually specify a `type`, or you can let terra infer it from `initial-value`. There is no -syntax for _not_ initalizing the variable on declaration. +manually specify a `type`, or you can let terra infer it from `initial-value`. Both forms +require `initial-value` to be provided. + +You can define multiple type-inferred variables at once with the `(name1 name2)` syntax, and +multiple explicitly-typed variables with the `{name1 type1 name2 type2}` syntax. Both of those +forms accept any number of initial values. If no values are provided, the variables are left +uninitialized. If one value is passed, Terra will treat it as a tuple destructuring. Otherwise +you should probably pass the same number of values as names. #### assignment ```fennel (set varname value) ; compiles to: varname = value (set struct.field value) ; compiles to: struct.field = value +(set (field1 field2) tuple) ; compiles to: field1, field2 = tuple (tset struct (getfield) value) ; compiles to: struct.[getfield()] = value ``` diff --git a/terra.fnl b/terra.fnl index 5dabe26..5d614b0 100644 --- a/terra.fnl +++ b/terra.fnl @@ -180,7 +180,15 @@ (fn type-constructors.raw-escape [[text] scope] text) (fn forms.var [defn scope] + (fn rvaluelist [initvals] + (if (> (length initvals) 0) + (.. " = " (commasep initvals #(comp.expr $1 scope))) + "")) (case defn + (where [names & initvals] (list? names)) + (.. "var " (commasep names #(scope:addlocal $1)) (rvaluelist initvals)) + (where [nametyps & initvals] (kv-table? nametyps)) + (.. "var " (kvcommasep nametyps #(.. (scope:addlocal $1) " : " (comp.type $2 scope))) (rvaluelist initvals)) [name typ initval] (.. "var " (scope:addlocal name) " : " (comp.type typ scope) " = " (comp.expr initval scope)) [name initval] (.. "var " (scope:addlocal name) " = " (comp.expr initval scope)))) @@ -214,7 +222,8 @@ (def-infix :not= "~=") (fn forms.not [[expr] scope] (.. "not (" (comp.expr expr scope) ")")) (fn forms.set [[left right] scope] - (.. (comp.expr left scope) " = (" (comp.expr right scope) ")")) + (if (list? left) (.. (commasep left #(comp.expr $1 scope)) " = (" (comp.expr right scope) ")") + (.. (comp.expr left scope) " = (" (comp.expr right scope) ")"))) (fn forms.tset [args scope] (let [iright (length args) right (. args iright)]