Escaping assignment, more docs, fix not

This commit is contained in:
Jeremy Penner 2023-12-03 17:12:09 -05:00
parent 128224a97a
commit 8e6a04536a
3 changed files with 112 additions and 32 deletions

View file

@ -44,12 +44,11 @@ Unlike Fennel, we do not implement implicit return semantics, and early returns
Sorry Phil.
### 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.
```fennel
(fn inc [x] (q (+ x 1))) ; compiles to: function(x) `(x + 1) end
```
### Type syntax
@ -125,7 +124,7 @@ a function call, but there is a shortened form using `$` to match the tuple inst
#### Escaping
Arbitrary Fennel expressions can be evaluated in a type-compilation context using Fennel's `,` prefix,
which is normally used by macros. If you need to re-enter a type-compilation context after escaping,
you'll need to nest a call to `ttype`. (I'm considering using ` `` ` for this purpose, but I might have
you'll need to nest a call to `ttype`. (I'm considering using `` ` `` for this purpose, but I might have
it consistently mean "create a quote" everywhere. Not sure.)
```fennel
@ -136,22 +135,98 @@ it consistently mean "create a quote" everywhere. Not sure.)
### Terra syntax
#### Pointers and arrays
Dereferencing a pointer or accessing an element in an array uses the same syntax as defining a pointer
or array type - the Fennel sequence literal. To take a reference to a value, you can use the `&` form.
```fennel
(def [ptr [int]] (return [ptr])) ; compiles to: terra (ptr : &int) return @ptr end
(def [arr [int 8]] (return [arr 5])) ; compiles to: terra (arr : int[8]) return arr[5] end
(def [nested [[int]]] (return [nested 0 3])) ; compiles to: terra (nested : &&int) return nested[0][3] end
(def [ptr [int] : [int]] (return (& [ptr 1]))) ; compiles to: terra (ptr : &int): &int return &ptr[1] end
```
#### var
```fennel
(var name initial-value) ; compiles to: var name = initial-value
(var name initial-value) ; compiles to: var name = initial-value
(var name type initial-value) ; compiles to: var name : type = initial-value
```
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.
#### Pointers and arrays
Dereferencing a pointer or accessing an element in an array uses the same syntax as defining a pointer
or array type - the Fennel sequence literal. To take a reference to a value, you can use the `&` form.
#### assignment
```fennel
(set varname value) ; compiles to: varname = value
(set struct.field value) ; compiles to: struct.field = value
(tset struct (getfield) value) ; compiles to: struct.[getfield()] = value
```
#### field access
```fennel
struct.field ; compiles to: struct.field
(struct.func) ; compiles to: struct.func()
(obj:method) ; compiles to: obj:method()
(. struct (getfield)) ; compiles to: struct.[getfield()]
(: obj (getmethod)) ; compiles to: struct:[getmethod()]()
```
#### cast
```fennel
(cast type expr)
```
Cast an expression `expr` to the type `type`.
```fennel
(def [ptr [int]] (return [ptr])) ; compiles to: terra (ptr : &int) return @ptr end
(def [arr [int 8]] (return [arr 5])) ; compiles to: terra (arr : int[8]) return arr[5] end
(def [nested [[int]]] (return [nested 0 3])) ; compiles to: terra (nested : &&int) return nested[0][3] end
(def [])
```
(cast [int] voidptr) ; compiles to: ([&int]voidptr)
(cast [int8] (C.malloc (* (sizeof int8) 16))) ; compiles to: ([&int8]C.malloc(sizeof(int8) * 16))
```
#### tuple literal
`$` can be used to create a tuple.
```fennel
($ 5 2.5 :hello) ; compiles to: { 5, 2.5, "hello" }
(var pair ($ int int) ($ 5 10)) ; compiles to: var pair : { int, int } = { 5, 10 }
```
#### struct literal
A fennel key-value table literal is interpreted as an anonymous struct literal.
If you "call" a struct type with a struct literal, it will coerce it to the given
type.
```fennel
(local Complex (ttype {real float imag float}))
; compiles to:
; local Complex = struct { real : float, imag : float }
(def [: Complex] (return (Complex { real 5 imag 1 })))
; compiles to:
; terra (): Complex
; return Complex({ real = 5, imag = 1 })
; end
```
#### Primitive operators
| Fennel | Terra | Meaning |
| ------------ | ------------ | ----------------------------------- |
| `(+ x y)` | `x + y` | add x and y |
| `(- x y)` | `x - y` | subtract y from x |
| `(/ x y)` | `x / y` | divide x by y |
| `(* x y)` | `x * y` | multiply x and y |
| `(% x y)` | `x % y` | x modulo y |
| `(< x y)` | `x < y` | x is less than y |
| `(<= x y)` | `x <= y` | x is less than or equal to y |
| `(= x y)` | `x == y` | x is equal to y |
| `(not= x y)` | `x ~= y` | x is not equal to y |
| `(> x y)` | `x > y` | x is greater than y |
| `(>= x y)` | `x >= y` | x is greater than or equal to y |
| `(and x y)` | `x and y` | x AND y (boolean or bitwise) |
| `(or x y)` | `x or y` | x OR y (boolean or bitwise) |
| `(not x)` | `not x` | NOT x (boolean or bitwise) |
| `(^ x y)` | `x ^ y` | x XOR y (bitwise) |
| `(<< x y)` | `x << y` | arithmetic shift x left by y bits |
| `(>> x y)` | `x >> y` | arithmetic shift x right by y bits |
#### Fennel escaping

31
go.fnl
View file

@ -1,23 +1,18 @@
(local fennel (require :fennel))
(import-macros {: def : q : ttype : static : unterra : untype} :terra)
(local N (static int 5))
(print N)
(fn inc [x]
(print "calling inc" x)
(q (+ ,x 1)))
(local Complex (ttype {real float imag float}))
(print (unterra
(def [x int]
(set N (+ N x))
(return N))))
(def [: Complex] (return (Complex { real 5 imag 1 })))
))
(print (unterra
(def [c Complex r float] (tset c :real r))
))
(local thing (def [: Complex] (return (Complex { real 5 imag 1 }))))
(local get-real (def [val Complex] (return (. val :real))))
(local set-real (def [c [Complex] r float] (tset c :real r)))
(local addN (def [x int]
(set N (+ N x))
(return N)))
(print addN)
(print (N:get) (addN 3) (N:get))
; (local inc (def [x [int]] (return [x N])))
; (print (inc 5))
(let [result (thing)]
(print result result.real result.imag (get-real result))
(set-real result 10)
(print (get-real result)))

View file

@ -193,13 +193,23 @@
(fn def-infix [fnlop luaop]
(tset forms fnlop (fn [[left right] scope]
(.. "(" (comp.expr left scope) " " luaop " " (comp.expr right scope) ")"))))
(each [_ op (ipairs [:+ :- :* :/ :% :< :<= :> :>= :and :or :not :^ :<< :>>])]
(each [_ op (ipairs [:+ :- :* :/ :% :< :<= :> :>= :and :or :^ :<< :>>])]
(def-infix op op))
(def-infix := :==)
(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) ")"))
(fn forms.tset [args scope]
(let [iright (length args)
right (. args iright)]
(tset args iright nil)
(.. ((. forms ".") args scope) " = (" (comp.expr right scope) ")")))
(tset forms "." (fn [[struct & fields] scope]
(.. (comp.expr struct scope) (commasep fields #(.. ".[" (scope:expr $1) "]") ""))))
(tset forms ":" (fn [[obj field & args] scope]
(.. (comp.expr obj scope) ":[" (scope:expr field) "](" (commasep args #(comp.expr $1 scope)) ")")))
(fn comp.quote [stmts scope]
(if (= (length stmts) 1) (.. "`(" (comp.expr (. stmts 1) scope) ")")