"static", more docs, indenting, fix set
This commit is contained in:
parent
95d279e45e
commit
128224a97a
115
README.md
115
README.md
|
@ -7,11 +7,11 @@ Idk, seemed cool
|
|||
## Usage
|
||||
At the top of your file, include the following:
|
||||
```fennel
|
||||
(import-macros {: def : q : ttype} :terra)
|
||||
(import-macros {: def : q : ttype : static} :terra)
|
||||
```
|
||||
The `def` macro defines a new terra function. The `q` macro defines a quoted terra expression.
|
||||
The `ttype` macro allows you to specify terra type definitions that can't be expressed with
|
||||
regular lua syntax.
|
||||
regular lua syntax. The `static` macro allows you to define "global" terra variables.
|
||||
|
||||
Notably, all of these macros return values, and none of them define new variables, local or global.
|
||||
I could maybe be persuaded to make `def` work like `fn` and optionally define a local, but for now,
|
||||
|
@ -29,6 +29,12 @@ Simple example:
|
|||
```fennel
|
||||
(local add (def [x int y int : int]
|
||||
(return (+ x y))))
|
||||
|
||||
; compiles to:
|
||||
; local add = terra(x : int, y : int) : {int}
|
||||
; return (x + y)
|
||||
; end
|
||||
|
||||
(add 1 2) ; returns 3
|
||||
```
|
||||
|
||||
|
@ -38,19 +44,114 @@ 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.
|
||||
|
||||
### syntax within `def` and `q` forms
|
||||
```fennel
|
||||
(fn inc [x] (q (+ x 1))) ; compiles to: function(x) `(x + 1) end
|
||||
|
||||
```
|
||||
|
||||
### Type syntax
|
||||
In Terra, types are Lua values and can be constructed from regular Lua code, outside of
|
||||
`terra` or `quote` blocks. (There are certain places inside these blocks where types can
|
||||
be constructed as well.) However, because Terra significantly extends the syntax of Lua to
|
||||
allow for convenient type construction, Garden also must provide a mini-language to support
|
||||
it.
|
||||
|
||||
Inside `terra` or `quote` blocks, whenever you have a form that requires a type to be passed
|
||||
to it, the compiler will automatically enter a type-compiling context. Outside of these blocks,
|
||||
the `ttype` macro can be used.
|
||||
|
||||
#### Pointers and arrays
|
||||
Pointers to types and arrays of types use the Fennel "sequence table" syntax. Alternatively,
|
||||
the `&` operator can be used.
|
||||
```fennel
|
||||
(local intptr (ttype [int])) ; compiles to: &int
|
||||
(local intptr2 (ttype (& int))) ; also compiles to: &int
|
||||
(local intarray (ttype [int 16])) ; compiles to: int[16]
|
||||
```
|
||||
|
||||
#### Structs
|
||||
Structs are defined using the Fennel "key-value table" syntax. For each row in the table,
|
||||
the keys are Fennel symbols representing the name of the field, and the values are type
|
||||
expressions. If, instead of a symbol, the compiler finds the string `:union`, the value
|
||||
is expected to be another "key-value table" containing the same structure. Struct definitons
|
||||
can be nested.
|
||||
|
||||
Note that the field names must be valid Lua symbols; no name-mangling is done. Might be
|
||||
worth doing that at some point; it seems likely that I will be annoyed if we don't
|
||||
auto-convert `-` to `_` at least.
|
||||
|
||||
```fennel
|
||||
(var name initial-value)
|
||||
(var name type initial-value)
|
||||
(local Variant (ttype {tag int
|
||||
:union {number float
|
||||
string [int8]
|
||||
complex {real float imag float}}}))
|
||||
; compiles to:
|
||||
; local Variant = struct {
|
||||
; tag : int,
|
||||
; union {
|
||||
; number : float,
|
||||
; string : &int8,
|
||||
; complex : struct {
|
||||
; real : float,
|
||||
; imag : float
|
||||
; }
|
||||
; }
|
||||
; }
|
||||
```
|
||||
|
||||
#### Function pointers
|
||||
Function pointer types are defined with the `->` form, which accepts two arguments - a sequence
|
||||
of types representing the input parameter types, and a sequence of types representing the return
|
||||
value. Actually this kind of sucks, I think we should use the same syntax as `def`. I'll probably
|
||||
change this. But this is how it works right now:
|
||||
|
||||
```fennel
|
||||
(local callback (ttype (-> [[int] int] [int]))) ; compiles to: local callback = { &int, int } -> { int }
|
||||
```
|
||||
|
||||
#### Tuples
|
||||
Tuple types are defined in Terra with a generic Lua function call to `tuple` that takes a variable
|
||||
number of types as parameters. This is supported directly, like any type declaration consisting of
|
||||
a function call, but there is a shortened form using `$` to match the tuple instantiation syntax.
|
||||
|
||||
```fennel
|
||||
(ttype (tuple int [int])) ; compiles to: tuple(int, &int)
|
||||
(ttype ($ int [int])) ; compiles to: tuple(int, &int)
|
||||
```
|
||||
|
||||
#### 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
|
||||
it consistently mean "create a quote" everywhere. Not sure.)
|
||||
|
||||
```fennel
|
||||
(ttype ($ [int] (fn-accepting-type [int]) ,(fn-accepting-seq [5]) (fn-accepting-seq-of-types ,[(ttype [int])])))
|
||||
; compiles to:
|
||||
; tuple(&int, fn_accepting_type(&int), fn_accepting_seq({ 5 }), fn_accepting_seq_of_types({ &int }))
|
||||
```
|
||||
|
||||
### Terra syntax
|
||||
|
||||
#### var
|
||||
```fennel
|
||||
(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.
|
||||
|
||||
```fennel
|
||||
#### 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 [])
|
||||
```
|
22
go.fnl
22
go.fnl
|
@ -1,15 +1,23 @@
|
|||
(local fennel (require :fennel))
|
||||
(import-macros {: terra : unterra : untype : def : q : ttype} :terra)
|
||||
(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 N 5)
|
||||
(fn inc [x] (q (+ ,x 1)))
|
||||
(print (unterra
|
||||
(def [x int]
|
||||
(return ,(inc `x)))))
|
||||
(set N (+ N x))
|
||||
(return N))))
|
||||
|
||||
(print
|
||||
(def [x int]
|
||||
(return ,(inc `x))))
|
||||
(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))
|
||||
|
|
44
terra.fnl
44
terra.fnl
|
@ -12,6 +12,15 @@
|
|||
(fn kvcommasep [tbl f ?sep]
|
||||
(commasep (. (getmetatable tbl) :keys) #(f $1 (. tbl $1)) ?sep))
|
||||
|
||||
(fn indent [str scope]
|
||||
(.. (string.rep " " scope.indent) str))
|
||||
|
||||
(fn block [pre stmts post scope f]
|
||||
(set scope.indent (+ scope.indent 2))
|
||||
(local block (commasep stmts #(indent (f $1) scope) "\n"))
|
||||
(set scope.indent (- scope.indent 2))
|
||||
(.. pre "\n" block "\n" (indent post scope)))
|
||||
|
||||
(local extract {})
|
||||
(fn extract.quotes-in-table [into tbl inputs locals]
|
||||
(collect [k v (pairs tbl) &into into] k (extract.quotes v inputs locals)))
|
||||
|
@ -40,8 +49,14 @@
|
|||
{:locals {}
|
||||
:env {}
|
||||
:input []
|
||||
:indent 0
|
||||
:push (fn [self] (set self.locals (setmetatable {} {:__index self.locals})))
|
||||
:pop (fn [self] (set self.locals (. (getmetatable self.locals) :__index)))
|
||||
:with (fn [self f]
|
||||
(self:push)
|
||||
(local result (f))
|
||||
(self:pop)
|
||||
result)
|
||||
:expr (fn [self expr]
|
||||
(if (and (sym? expr) (not (multi-sym? expr))) (self:env-ref expr)
|
||||
(= (type expr) :number) (tostring expr)
|
||||
|
@ -150,10 +165,7 @@
|
|||
[name initval] (.. "var " (scope:addlocal name) " = " (comp.expr initval scope))))
|
||||
|
||||
(fn forms.do [stmts scope]
|
||||
(scope:push)
|
||||
(local lines (icollect [_ stmt (ipairs stmts)] (comp.expr stmt scope)))
|
||||
(scope:pop)
|
||||
(table.concat lines "\n"))
|
||||
(scope:with #(block :do stmts :end scope #(comp.expr $1 scope))))
|
||||
|
||||
(fn find-ival [tbl pred]
|
||||
(var ival nil)
|
||||
|
@ -162,17 +174,14 @@
|
|||
ival)
|
||||
|
||||
(fn forms.def [[arglist & stmts] scope]
|
||||
(scope:push)
|
||||
(let [iarg-return-sep (find-ival arglist #(and (sym? $1) (= (tostring $1) ":")))
|
||||
(scope:with #(let [iarg-return-sep (find-ival arglist #(and (sym? $1) (= (tostring $1) ":")))
|
||||
argpairs (fcollect [i 1 (length arglist) 2 &until (= i iarg-return-sep)]
|
||||
{:name (. arglist i) :type (. arglist (+ i 1))})
|
||||
rettyps (when iarg-return-sep (icollect [i typ (ipairs arglist)] (when (> i iarg-return-sep) typ)))
|
||||
rettyp (if rettyps (.. ": { " (commasep rettyps #(comp.type $1 scope)) " }") "")
|
||||
argdefs (commasep argpairs #(.. (scope:addlocal $1.name) " : " (comp.type $1.type scope)))
|
||||
fulldef (.. "terra (" argdefs ")" rettyp "\n" (forms.do stmts scope) "\nend")]
|
||||
(scope:pop)
|
||||
fulldef))
|
||||
(fn forms.predef [fntyp scope] (.. ))
|
||||
argdefs (commasep argpairs #(.. (scope:addlocal $1.name) " : " (comp.type $1.type scope)))]
|
||||
(block (.. "terra (" argdefs ")" rettyp) stmts :end scope #(comp.expr $1 scope)))))
|
||||
|
||||
(fn forms.return [[expr] scope] (.. "return " (comp.expr expr scope)))
|
||||
(fn forms.cast [[typ expr] scope]
|
||||
(.. "([" (comp.type typ scope)"](" (comp.expr expr scope) "))"))
|
||||
|
@ -188,11 +197,16 @@
|
|||
(def-infix op op))
|
||||
(def-infix := :==)
|
||||
(def-infix :not= "~=")
|
||||
(def-infix :set :=)
|
||||
|
||||
(fn forms.set [[left right] scope]
|
||||
(.. (comp.expr left scope) " = (" (comp.expr right scope) ")"))
|
||||
|
||||
(fn comp.quote [stmts scope]
|
||||
(if (= (length stmts) 1) (.. "`(" (comp.expr (. stmts 1) scope) ")")
|
||||
(.. "quote\n" (commasep stmts #(comp.expr $1 scope) "\n") "\nend")))
|
||||
(.. "quote\n" (commasep stmts #(comp.expr $1 scope)) "\nend")))
|
||||
|
||||
(fn comp.global [[typ initial-val] scope]
|
||||
(.. "global(" (comp.type typ scope) "," (comp.expr initial-val scope) ")"))
|
||||
|
||||
(fn build [expr compiler]
|
||||
(let [scope (new-scope)
|
||||
|
@ -209,7 +223,9 @@
|
|||
|
||||
(fn def [...] (terra `(,(sym :def) ,...)))
|
||||
(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 ...))))
|
||||
|
||||
{: terra : ttype : def : q : unterra : untype}
|
||||
{: terra : ttype : def : q : static : unterra : untype}
|
Loading…
Reference in a new issue