Ivylang
include lang
include hash
object ivy = {
instantiate verb_base
instantiate expr_base(false)
instantiate stmt_base(expr,":=",false)
instantiate decl_base(expr,stmt)
instance ident_set : hash_map(ident,bool)
The binary : operator is used to represent a type
judgement.
instance colon : built_in_binary(":",verb.colon,50)
instance arrow : built_in_binary("->",verb.arrow,2)
instance castop : built_in_unary("cast",verb.castv,49)
=, ~= and ~ verbs are spelled differently in Ivy and C++
instance equals : built_in_binary("=",verb.equals,5)
instance notequals : built_in_binary("~=",verb.notequals,5)
instance not : built_in_unary("~",verb.not,15)
x if c else y.
instance ite : built_in_ternary("if",verb.ite,2)
instance varv : built_in_unary("var",verb.varv,2)
isa operator
instance isaop : built_in_binary("isa",verb.isav,5)
The object varst represents the var statement.
object varst = {
variant this of stmt = struct {
name : expr,
ann : annot
}
action make (name:expr,ann:annot) returns (res:stmt) = {
var s:this;
s.name := name;
s.ann := ann;
res := s;
}
instantiate generic_stmt_encode(1)
action encode_int(s:this,b:pretty,prio:priority) returns (b:pretty) = {
b := s.ann.encode(b);
b := b.nest;
b := b.extend("var");
b := b.extend(" ");
b := s.name.encode(b,0);
b := b.extend(";");
b := b.unnest;
}
action get_expr(s:this) returns (res:expr) = {
res := s.name;
}
}
object stmt = { ...
action parse_lang_stmt(st : pstate, prio:priority) returns(st : pstate, res:stmt) = {
var s : asgn;
(st,s.ann) := st.get_ann;
if st.tok = "call" {
st := st.consume;
};
(st,s.lhs) := expr.parse(st,0);
if st.ok & st.tok = ":=" {
st := st.consume;
(st,s.rhs) := expr.parse(st,0);
if st.ok & st.tok = ";" {
st := st.consume;
} else {
st.ok := st.tok = "}"; # allow to omit final semicolon
};
res := s;
} else if st.ok & (st.tok = ";" | st.tok = "}") {
if st.tok = ";" {
st := st.consume;
};
if s.lhs.is(verb.varv) {
var vst : varst;
vst.ann := s.ann;
vst.name := s.lhs.get_arg(0);
res := vst;
} else {
s.rhs := s.lhs;
s.lhs := empty.make(s.ann.strip); # just an expression -- assign to ()
res := s;
}
} else {
st.ok := false;
};
}
}
object groupdc = {
variant this of decl = struct {
decls : vector[decl],
ann : annot
}
action make(decls : vector[decl]) returns (res:decl) =
{
var s:this;
s.decls := decls;
res := s;
}
action encode(s:this,b:pretty,prio:priority) returns (b:pretty) = {
b := b.nest;
b := b.extend("{");
var idx := s.decls.begin;
while idx < s.decls.end {
b := b.newline;
b := s.decls.value(idx).encode(b,0);
idx := idx.next;
};
b := b.unnest;
b := b.newline;
b := b.extend("}");
}
}
object typespec = {
type this
action parse(st : pstate, prio:priority) returns(st : pstate, res:this) = {
if st.tok = "struct" {
var s : structspec;
(st,s.ann) := st.get_ann;
st := st.consume;
(st,s.destructors) := curly_tup.parse(st,1);
res := s;
} else {
var s : enumspec;
(st,s.ann) := st.get_ann;
(st,s.constructors) := curly_tup.parse(st,1);
res := s;
}
}
action encode(s:this,b:pretty,prio:priority) returns (b:pretty)
action get_elems(s:this) returns (res:vector[expr])
}
instance curly_tup : tuple(expr,"{","}",verb)
object enumspec = {
variant this of typespec = struct {
constructors : vector[expr],
ann : annot
}
action encode(s:this,b:pretty,prio:priority) returns (b:pretty) = {
b := b.nest;
b := curly_tup.encode(s.constructors,b,prio);
b := b.unnest;
}
action get_elems(s:this) returns (res:vector[expr]) = {
res := s.constructors
}
}
object structspec = {
variant this of typespec = struct {
destructors : vector[expr],
ann : annot
}
action encode(s:this,b:pretty,prio:priority) returns (b:pretty) = {
b := b.nest;
b := b.extend("struct");
b := b.extend(" ");
b := curly_tup.encode(s.destructors,b,prio);
b := b.unnest;
}
action get_elems(s:this) returns (res:vector[expr]) = {
res := s.destructors
}
}
object typedc = {
variant this of decl = struct {
sort : expr,
has_super : bool,
super : expr,
has_spec : bool,
spec : typespec,
ann : annot
}
action make(sort:expr) returns (res:decl) =
{
var s:this;
s.sort := sort;
res := s;
}
action encode(s:this,b:pretty,prio:priority) returns (b:pretty) = {
b := s.ann.encode(b);
b := b.nest;
b := b.extend("variant" if s.has_super else "type");
b := b.extend(" ");
b := s.sort.encode(b,0);
if s.has_super {
b := b.extend(" ");
b := b.extend("of");
b := b.extend(" ");
b := s.super.encode(b,0);
};
if s.has_spec {
b := b.extend(" ");
b := b.extend("=");
b := b.extend(" ");
b := s.spec.encode(b,0);
};
b := b.unnest;
b := b.newline;
}
}
object vardc = {
variant this of decl = struct {
typing : expr,
is_destructor : bool,
has_def : bool,
def : expr,
ann : annot
}
action make(typing:expr,is_destructor:bool,ann:annot) returns (res:decl) =
{
var s:this;
s.typing := typing;
s.is_destructor := is_destructor;
s.ann := ann;
res := s;
}
action encode(s:this,b:pretty,prio:priority) returns (b:pretty) = {
b := b.nest;
b := b.extend("destructor" if s.is_destructor
else ("function" if s.has_def else "var"));
b := b.extend(" ");
b := s.typing.encode(b,0);
b := b.unnest;
if s.has_def {
b := b.extend(" ");
b := b.extend("=");
b := b.extend(" ");
b := s.def.encode(b,0);
};
b := b.newline;
}
}
object header = {
variant this of decl = struct {
filename : str,
ann : annot
}
action make(filename:str) returns (res:decl) =
{
var s:this;
s.filename := filename;
res := s;
}
action encode(s:this,b:pretty,prio:priority) returns (b:pretty) = {
b := b.nest;
b := b.extend("header");
b := b.extend(" ");
b := b.extend(s.filename);
b := b.unnest;
b := b.newline;
}
}
object interpdc = {
variant this of decl = struct {
itype : expr,
ctype : expr,
ann : annot
}
action make(itype : expr, ctype : expr, ann : annot) returns (res:decl) =
{
var s:this;
s.itype := itype;
s.ctype := ctype;
res := s;
}
action encode(s:this,b:pretty,prio:priority) returns (b:pretty) = {
b := b.nest;
b := b.extend("interpret");
b := b.extend(" ");
b := s.itype.encode(b,0);
b := b.extend(" ");
b := b.extend("->");
b := b.extend(" ");
b := s.ctype.encode(b,0);
b := b.unnest;
b := b.newline;
}
}
object includedc = {
variant this of decl = struct {
file : expr,
ann : annot
}
action make(file:expr,ann:annot) returns (res:decl) =
{
var s:this;
s.ann := ann;
s.file := file;
res := s;
}
action encode(s:this,b:pretty,prio:priority) returns (b:pretty) = {
b := b.nest;
b := b.extend("include");
b := b.extend(" ");
b := s.file.encode(b,0);
b := b.unnest;
b := b.newline;
}
action get_expr(s:this) returns (res:expr) = {
res := s.file
}
action get_ann(s:this) returns (res:annot) = {
res := s.ann
}
}
object moduledc = {
variant this of decl = struct {
name : expr,
prms : vector[expr],
body : decl,
ann : annot
}
action make(name : expr, prms : vector[expr], body : decl) returns (res:decl) =
{
var s:this;
s.name := name;
s.prms := prms;
s.body := body;
res := s;
}
action encode(s:this,b:pretty,prio:priority) returns (b:pretty) = {
b := b.nest;
b := b.extend("module");
b := b.extend(" ");
b := s.name.encode(b,0);
if s.prms.end > 0 {
b := expr.tup.encode(s.prms,b,0)
};
b := b.unnest;
b := b.extend(" ");
b := b.extend("=");
b := b.extend(" ");
b := s.body.encode(b,2);
}
}
object instantiatedc = {
variant this of decl = struct {
name : expr,
prms : vector[expr],
ann : annot
}
action make(name : expr, prms : vector[expr], ann:annot) returns (res:decl) =
{
var s:this;
s.name := name;
s.prms := prms;
s.ann := ann;
res := s;
}
action encode(s:this,b:pretty,prio:priority) returns (b:pretty) = {
b := b.nest;
b := b.extend("instantiate");
b := b.extend(" ");
b := s.name.encode(b,0);
if s.prms.end > 0 {
b := expr.tup.encode(s.prms,b,0)
};
b := b.unnest;
b := b.newline
}
}
object objectdc = {
variant this of decl = struct {
name : expr,
body : decl,
ann : annot
}
action make(name : expr, body : decl, ann:annot) returns (res:decl) =
{
var s:this;
s.name := name;
s.body := body;
s.ann := ann;
res := s;
}
action encode(s:this,b:pretty,prio:priority) returns (b:pretty) = {
b := b.nest;
b := b.extend("object");
b := b.extend(" ");
b := s.name.encode(b,0);
b := b.unnest;
b := b.extend(" ");
b := b.extend("=");
b := b.extend(" ");
b := s.body.encode(b,0);
}
}
instance x : y(p1...pn) is a shorthand for
object x : { instantiate y(p1...pn) }.
The declaration autoinstance x[p1][p2] : y(p1...pn) causes an instance
x[p1][p2] of y(p1...pn) to be generated for each identifier x[p1][p2] that occurs
undefined in the program, for any values of p1...pn. The module y is instantiated
just before the declaration triggering the instantiation.
object instancedc = {
variant this of decl = struct {
objname : expr,
modname : expr,
prms : vector[expr],
is_auto : bool,
ann : annot
}
action make(objname : expr, modname : expr, prms : vector[expr]) returns (res:decl) =
{
var s:this;
s.objname := objname;
s.modname := modname;
s.prms := prms;
res := s;
}
action encode(s:this,b:pretty,prio:priority) returns (b:pretty) = {
b := b.nest;
b := b.extend("autoinstance" if s.is_auto else "instance");
b := b.extend(" ");
b := s.objname.encode(b,0);
b := b.extend(" ");
b := b.extend(":");
b := b.extend(" ");
b := s.modname.encode(b,0);
if s.prms.end > 0 {
b := expr.tup.encode(s.prms,b,0)
};
b := b.unnest;
b := b.newline
}
}
init declaration contains initialization code
object initdc = {
variant this of decl = struct {
body : stmt,
ann : annot
}
action encode(s:this,b:pretty,prio:priority) returns (b:pretty) = {
b := b.extend("init");
b := b.extend(" ");
b := s.body.encode(b,1);
b := b.newline
}
action get_body(s:this) returns (res:stmt) = {
res := s.body
}
}
action parse_action(st : pstate, prio:priority, kind:action_kind)
returns (st : pstate, res:decl) =
{
if st.tok = "action" {
st := st.consume;
var s : actdc;
s.kind := kind;
(st,s.ann) := st.get_ann;
(st,s.name) := expr.parse(st,99);
if st.ok & st.tok = "(" {
(st,s.inputs) := expr.tup.parse(st,1); # 1 = prio of ","
};
if st.ok & st.tok = "returns" {
st := st.consume;
(st,s.outputs) := expr.tup.parse(st,1);
};
if st.ok & st.tok = "=" {
st := st.consume;
s.has_body := true;
if st.tok = "{" {
(st,s.body) := stmt.parse(st,1);
} else {st.ok := false}
};
res := s
} else {
st.ok := false;
}
}
object decl = { ...
action parse(st : pstate, prio:priority) returns(st : pstate, res:decl) = {
if st.tok = "{" {
st := st.consume;
var s : groupdc;
(st,s.ann) := st.get_ann;
if st.tok = "..." {
st := st.consume # for now, ignore "..."
};
(st,s.decls) := parse_list(st,0);
if st.tok = "}" {
st := st.consume;
} else {st.ok := false};
res := s
}
else if st.tok = "action" {
(st,res) := parse_action(st,prio,action_kind.internal)
} else if st.tok = "type" {
st := st.consume;
var s : typedc;
(st,s.ann) := st.get_ann;
(st,s.sort) := expr.parse(st,verb_to_prio(verb.equals));
if st.ok & st.tok = "=" {
st := st.consume;
s.has_spec := true;
(st,s.spec) := typespec.parse(st,0);
};
res := s
} else if st.tok = "var" | st.tok = "destructor" | st.tok = "function" {
var s : vardc;
s.is_destructor := (st.tok = "destructor");
st := st.consume;
(st,s.ann) := st.get_ann;
(st,s.typing) := expr.parse(st,verb_to_prio(verb.equals));
if st.ok & st.tok = "=" {
st := st.consume;
s.has_def := true;
(st,s.def) := expr.parse(st,0);
};
res := s
} else if st.tok = "header" {
var s : header;
(st,s.ann) := st.get_ann;
st := st.consume;
if st.ok & st.tok.end > 0 & st.tok.value(0) = 34 { # double quote
s.filename := st.tok;
st := st.consume;
} else { st.ok := false };
res := s
} else if st.tok = "interpret" {
var s : interpdc;
(st,s.ann) := st.get_ann;
st := st.consume;
if st.ok & st.tok.end > 0 { # double quote
(st,s.itype) := expr.parse(st,verb_to_prio(verb.arrow));
if st.ok & st.tok = "->" {
st := st.consume;
(st,s.ctype) := expr.parse(st,0);
} else { st.ok := false };
} else { st.ok := false };
res := s
} else if st.tok = "include" {
var s : includedc;
(st,s.ann) := st.get_ann;
st := st.consume;
(st,s.file) := expr.parse(st,0);
res := s
} else if st.tok = "module" {
var s : moduledc;
(st,s.ann) := st.get_ann;
st := st.consume;
(st,s.name) := expr.parse(st,99); # allow dot operator, not application
if st.ok & st.tok = "(" {
(st,s.prms) := expr.tup.parse(st,1);
};
if st.ok & st.tok = "=" {
st := st.consume;
(st,s.body) := decl.parse(st,0);
} else { st.ok := false };
res := s;
} else if st.tok = "instantiate" {
var s : instantiatedc;
(st,s.ann) := st.get_ann;
st := st.consume;
(st,s.name) := expr.parse(st,99);
if st.ok & st.tok = "(" {
(st,s.prms) := expr.tup.parse(st,1);
};
res := s
} else if st.tok = "object" {
var s : objectdc;
(st,s.ann) := st.get_ann;
st := st.consume;
(st,s.name) := expr.parse(st,99);
if st.ok & st.tok = "=" {
st := st.consume;
};
if st.ok & st.tok = "{" {
(st,s.body) := decl.parse(st,0);
};
res := s
} else if st.tok = "instance" | st.tok = "autoinstance" {
var s : instancedc;
s.is_auto := (st.tok = "autoinstance");
(st,s.ann) := st.get_ann;
st := st.consume;
(st,s.objname) := expr.parse(st,99);
if st.ok & st.tok = ":" {
st := st.consume;
};
if st.ok {
(st,s.modname) := expr.parse(st,99)
};
if st.ok & st.tok = "(" {
(st,s.prms) := expr.tup.parse(st,1);
};
res := s
} else if st.tok = "variant" {
st := st.consume;
var s : typedc;
s.has_super := true;
(st,s.ann) := st.get_ann;
(st,s.sort) := expr.parse(st,0);
if st.ok & st.tok = "of" {
st := st.consume
} else {st.ok := false};
(st,s.super) := expr.parse(st,verb_to_prio(verb.equals));
if st.ok & st.tok = "=" {
st := st.consume;
s.has_spec := true;
(st,s.spec) := typespec.parse(st,0);
};
res := s
} else if st.tok = "extern" {
st := st.consume;
(st,res) := parse_action(st,prio,action_kind.external);
} else if st.tok = "import" {
st := st.consume;
(st,res) := parse_action(st,prio,action_kind.imported);
} else if st.tok = "export" {
st := st.consume;
(st,res) := parse_action(st,prio,action_kind.exported);
} else if st.tok = "init" {
var s : initdc;
(st,s.ann) := st.get_ann;
st := st.consume;
if st.tok = "{" {
(st,s.body) := stmt.parse(st,1);
} else {st.ok := false};
res := s;
} else if st.tok = "after" {
var s : initdc;
(st,s.ann) := st.get_ann;
st := st.consume;
if st.tok = "init" {
st := st.consume;
} else {st.ok := false};
if st.ok & st.tok = "{" {
(st,s.body) := stmt.parse(st,1);
} else {st.ok := false};
res := s;
} else {st.ok := false}
}
action parse_list(st : pstate, prio:priority) returns(st : pstate, res:vector[decl]) = {
while st.ok & st.tok.end > 0 & st.tok ~= "}" {
var s : decl;
(st,s) := parse(st,0);
res := res.append(s);
}
}
}
instantiate prog_base(false)
}