Core S-Expression Syntax
The concrete syntax of Juvix once we Hit Core, namely the Named version (HR)
This document is bound to change once a syntax redesign will happen. This will be greatly minimized
For this page we give examples of the syntax rather than a hard bnf unlike what is found in the syntax page
basic
input
let foo x
| x == 2 = 3 + 4 + x
| else = x + 2
output
(:defun foo (x)
(:cond
((:infix == x 2) (:infix + 3 (:infix + 4 x)))
(else (:infix + x 2))))
basic
input
sig foo : int -> int -> int
output
(:defsig foo (:infix -> int (:infix -> int int)))
usage
input
sig foo 0 : int -> int -> int
output
(:defsig foo (:usage 0 (:infix -> int (:infix -> int int))))
This form is a bit odd, ideally it'd mimic the Types version like
(:defsig (foo :usage 0) (:infix -> int (:infix -> int int)))
However for now I think it's fine⦠Though this is a place for improvement for the future
record
input
type foo x y z =
{ y-axis : y
, x-axis : x
, z-axis 1 : z }
output
(type foo (x y z)
(:record-d
(y-axis (:primitve Builtin.Omega) y)
(x-axis (:primitve Builtin.Omega) x)
(z-axis 1 z)))
first sum
input
type foo x y z =
| Foo {y-axis : y, x-axis : x, z-axis : z}
| Bar (var1 : x) (var2 : y)
| Car : hd : x -> cdr : foo y -> foo x y z
output
(type foo (x y z)
(Foo (:record-d (y-axis (:primitve Builtin.Omega) y)
(x-axis (:primitve Builtin.Omega) x)
(z-axis (:primitve Builtin.Omega) z)))
(Bar (:paren (:infix : var1 x))
(:paren (:infix : var2 y)))
(Car (:arrow
(:infix : hd
(:infix -> x
(:infix : cdr
(:infix -> (foo y) (foo x y z))))))))
Signature
input
type foo x y z : typ -> typ -> typ = Foo a b c
output
(type (foo :type (:infix -> typ (:infix -> typ typ))) (x y z)
(Foo a b c))
basic
input
declare infixl foo 3
output
(declare infixl foo 3)
basic
input
mod foo =
let bar = 3
type zar = Boo
end
output
(:defmodule foo ()
(:defun bar () 3)
(type zar () (Boo)))
guards
input
mod foo x
| x == 3 =
let foo = 3
let bar = 5
| else =
let foo = 5
end
output
(:defmodule foo (x)
(:cond ((:infix == x 3)
(:defun foo () 3)
(:defun bar () 5))
(else
(:defun foo () 5))))
basic
input
let foo y =
let fi = 3 in
fi
output
(:defun foo (y)
(let fi () 3
fi))
arguments
input
let foo y =
let fi x = 3 + x in
fi y
output
(:defun foo (y)
(let fi (x) (:infix + 3 x)
(fi y)))
basic
input
let foo =
mod Bar =
let bar = 3
type zar = Boo
end in
Bar.bar
output
(:defun foo ()
(:let-mod Bar ()
((:defun bar () 3)
(type zar () (Boo)))
Bar.bar))
basic
input
let foo = (1,2,3)
output
(:defun foo () (:tuple 1 2 3))
basic
input
let foo = [1,2,3,4]
output
(:defun foo () (:list 1 2 3 4))
basic
input
let foo = {a, b = 2}
output
(:defun foo () (:record (a) (b 2)))
basic
input
let foo xs =
a <- xs;
more-comp;
pure a
output
(:defun foo (xs)
(:do (%<- a xs)
more-comp
(pure a)))
basic
input
let foo y =
\x -> x + y
output
(:defun foo (y)
(:lambda (x) (:infix + x y)))
basic
input
let foo y =
open Prelude in
x + y
output
(:defun foo (y)
(:open-in Prelude
(:infix + x y)))
basic
input
let foo y = (y + 3) * 9
output
(:defun foo (y)
(:infix * (:paren (:infix + y 3)) 9))
basic
input
let foo y = 3 * begin y + y end
output
(:defun foo (y)
(:infix * 3 (:progn (:infix + y y))))
basic
input
let add = %Michelson.add
output
(:defun add ()
(:primitive Michelson.add))
basic
input
let foo = declare infixl (+) 3 in 3
output
(:defun foo ()
(:declaim (infixl + 3) 3))
basic
input
let add x =
if | x == 3 = 1
| x == 4 = 5
| else = 0
output
(:defun add (x)
(:cond ((:infix == x 3) 1)
((:infix == x 4) 5)
(else 0)))
basic
input
let foo =
case x of
| (A (B {a, b})) -> a + b
| A (B c) (C d) -> c + d
output
(:defun foo ()
(case x
((A (B (:record (a) (b)))) (:infix + a b))
((A (B c) (C d)) (:infix + c d))))
Overall the goal of the S-expression incantation is twofold 1.
An unambiguous syntax that is faithful to the original ML syntax
This is a necessity to have limited strife between the ML syntax. and the work we need to do on the generic IR-syntax layer.
Unambiguous in this case implies bijection, as we have to convert between the two forms.
A fully realized syntax that is readable and looks as if it were a standalone language.
This is needed so inspection of the output is obvious. Further this will empower ease of reasoning over the syntax without too many surprises.
Overall a few forms in this representation are quite verbose and thus harder to read than they should be, see
(:arrow
(:infix : hd
(:infix -> x
(:infix : cdr
(:infix -> (foo y) (foo x y z))))))
;; should be
[ hd : x -> cdr : (foo y) -> (foo x y z) ]
(:record
y-axis y
x-axis x
z-axis z)
;; should be
{y-axis y
x-axis x
z-axis z}
This is due to lacking reader macros at this level. Overall this can be largely improved in the future for better inspection (we thus will offer another level of inspection that can do away with the infix view!)
The syntax is heavily inspired from Common Lisp (CL). There are of course a plethora of changes, however some key concepts have survived through this transition.
Namely for adding extra property based information in declarations we got for an alist concept
(type (foo :type (:infix -> typ (:infix -> typ typ))) (x y z)
(Foo a b c))
which is taken directly from CL's defstruct
construct.
Even naming conventions like defun
are lifted directly from Common
Lisp.
With that said, many forms (namely the lets) lack an extra set of parenthesis when in comparison to CL and the Schemer language.
(let fi (x) (:infix + 3 x)
(fi y))
(let fi () 3
fi)
This is due to us fully abusing the fact that we must represent non let blocks currently along with having a single expression each name is bound to.
There are likely inconsistencies between some of the forms. These should be removed as soon as possible. I have tried my best on this front, but likely some forms are inconsistent.
Currently we have a minor point of alists on the name itself to describe extra properties
(type (foo :type (:infix -> typ (:infix -> typ typ))) (x y z)
(Foo a b c))
This is great and we'll be adding it to Modules, however we currently do an odd transformation in regards to signatures
(:defsig foo (:usage 0 (:infix -> int (:infix -> int int))))
;; should be
(:defsig (foo :usage 0) (:infix -> int (:infix -> int int)))
This likely should be changed
The Whimsical spell like nature of sexpressions are heavily derived from SICP and the general imagery of other literature such as the dragon book.
The concrete syntax of Juvix once we Hit Core, namely the Named version (HR)