USER_GUIDE
a brief primer, which will hopefully be developed further, as time allows.
subject to change as rep_lang
develops!
rep_lang
parses programs (text / strings of characters) into an Abstract Syntax Tree (AST).
internally, this is referred to as Expr
, short for expression.
Expr
s can be interpreted to Value
s.
an example here would be that the string (+ 1 2)
parses to an Expr
of "the addition operator applied to the literal 1 and the literal 2".
that Expr
can the be interpreted to the Value
of 3
.
ideally, the internals of the language will not need to be inspected by users, because the abstractions won't "leak".
however, Expr
and Value
are relatively "public" and there values may be stored outside of the interpreter (which is somewhat uncommon - for a language to expose internal datastructures - but seems necessary for some of our goals related to Holochain interoperation).
note: unfortunately, I can't give a full specification of the concrete syntax and then generate the parser from that, for various reasons. so what is written here is subject to diverge from the implementation of the parser. this is current as of 2021-11-12.
e ::= (lam [x ...] e) ;; lambda, with 1+ arguments
| (let ([x e] ...) e) ;; let binding
| (if e e e) ;; if (first `e` must have type Bool, and the second
;; & third must have the same type)
| (e e ...) ;; application expression
| (fix e) ;; fixpoint operator on `e`
| var ;; variable reference
| prim
| lit
primop ::= +
| -
| *
| /
| ==
| null
| pair
| fst
| snd
| cons
| nil
| head
| tail
var ::= sequence of chars matching `^[a-zA-Z_][a-zA-Z0-9_\-]*$`
lit ::= sequence of chars matching `^-?[0-9]+$`
| bool
bool ::= true
| false
looking at e
above, we see (on the right side of the ::=
and below it) a number of variants.
some of those variants contain e
s, which implies that we choose variants of e
and fill them in there, ad infinitum.
with primop
, by contrast, we see no such recursive occurrences - only a finite number of "flat" variants.
the best way to get a felt sense for rep_lang
is to use rli
(rep_lang
interactive/interpreter).
here is an example transcript:
# from the repo root
~/projects/rep_lang » cd rep_lang_runtime
~/projects/rep_lang/rep_lang_runtime » cargo run -q --bin rli
__
________ ____ / /___ _____ ____ _
/ ___/ _ \/ __ \ / / __ `/ __ \/ __ `/
/ / / __/ /_/ / / / /_/ / / / / /_/ /
/_/ \___/ .___/____/_/\__,_/_/ /_/\__, /
/_/ /_____/ /____/
welcome 🙂
any expression or definiton will be parsed, typechecked, and evaluated.
quit with `ctrl-d`.
> 1
ast: Lit(LInt(1))
(: 1
Int
)
> true
ast: Lit(LBool(true))
(: true
Bool
)
> (+ 1 2)
ast: App(App(Prim(Add), Lit(LInt(1))), Lit(LInt(2)))
(: 3
Int
)
> ((lam [x] (+ x 1)) 9)
ast: App(Lam(Name("x"), App(App(Prim(Add), Var(Name("x"))), Lit(LInt(1)))), Lit(LInt(9)))
(: 10
Int
)
> (if (== 1 2) 3 4)
ast: If(App(App(Prim(Eql), Lit(LInt(1))), Lit(LInt(2))), Lit(LInt(3)), Lit(LInt(4)))
(: 4
Int
)
> (let ([x 1] [y 2]) (* x y))
ast: Let(Name("x"), Lit(LInt(1)), Let(Name("y"), Lit(LInt(2)), App(App(Prim(Mul), Var(Name("x"))), Var(Name("y")))))
(: 2
Int
)
> (cons 1 nil)
ast: App(App(Prim(Cons), Lit(LInt(1))), Prim(Nil))
(: (cons 1 nil)
(List Int)
)
> (null nil)
ast: App(Prim(Null), Prim(Nil))
(: true
Bool
)
> (pair 7 false)
ast: App(App(Prim(Pair), Lit(LInt(7))), Lit(LBool(false)))
(: (7, false)
(Int, Bool)
)
> (snd (pair 7 false))
ast: App(Prim(Snd), App(App(Prim(Pair), Lit(LInt(7))), Lit(LBool(false))))
(: false
Bool
)
> (head (cons 7 (cons 8 nil)))
ast: App(Prim(Head), App(App(Prim(Cons), Lit(LInt(7))), App(App(Prim(Cons), Lit(LInt(8))), Prim(Nil))))
(: 7
Int
)
>
bye!