tuple destructuring

This commit is contained in:
Jeremy Penner 2023-12-06 22:47:47 -05:00
parent f86b7ba60b
commit 6b5035c111
2 changed files with 36 additions and 5 deletions

View file

@ -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
@ -179,15 +191,25 @@ it consistently mean "create a quote" everywhere. Not sure.)
```fennel
(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
```

View file

@ -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)]