Lang
include syntax
This file contains a number of modules that are used in common between the Ivy and C++ languages. Some of these modules have parameters that can vary the syntax, for example, by selecting the assignment or equality operator, or whether parentheses are required around the condition in an if/else statement.
The type priority is used to represent the binding strength of
operators, with stronger-binding operators having higher priority.
For example, * has a higher priority that +. Priorities are used
both to resolve ambiguous parses and to elide perenthese when
printing.
instance priority : arith_int
verb type is an enumeration of the built-in symbols in the
language. This is used to avoid comparison of quoted strings
representing the names of these symbols. Each verb also has a
corresponding priority. The verb corresponding to a symbol name is
added as a meta-field to the symbol, in which case the string name
can be empty (the value none is used for non-built-in symbols).
str_to_verbstores the map from string symbol names to verbsverb_to_stris the inverse mapverb_to_priogives the priority of a verb
The verb empty represents the empty tuple, of type unit. Neither
of these is available in the source lanuage, but they are used
internally.
module verb_base = {
object verb = {
type this =
{
none, arrow, plus, times, colon, app, empty, dot, new, numeral, castv,
boolv, truev, falsev, and, or, not, iff, equals, notequals,
lt, leq, gt, geq, minus, div, string, ite, comma, varv, logvar, isav
}
}
function str_to_verb(X:str) : verb
function verb_to_str(X:verb) : str
function verb_to_prio(X:verb) : priority
function verb_to_arity(X:verb) : pos
after init {
verb_to_arity(verb.numeral) := 0;
verb_to_arity(verb.string) := 0;
verb_to_arity(verb.logvar) := 0;
}
str_to_verb. The default is none, which indicates a
program-defined symbol.
action is_logvar_name(name:str) returns (res:bool) = {
if name.value(0).is_capital {
res := true;
var idx := name.begin.next;
while res & idx < name.end {
res := name.value(idx).is_digit
};
idx := idx.next
}
}
action verb_from_name(name:str) returns(vrb:verb) = {
if name.value(0).is_digit {
vrb := verb.numeral
} else if name.value(0) = 34 { # double quote character
vrb := verb.string
} else if is_logvar_name(name) {
vrb := verb.logvar;
} else {
vrb := str_to_verb(name);
}
}
}
module built_in (optok,vrb,opprio,oparity) = {
after init {
str_to_verb(optok) := vrb;
verb_to_str(vrb) := optok;
verb_to_prio(vrb) := opprio;
verb_to_arity(vrb) := oparity;
}
}
module built_in_unary (optok,vrb,opprio) = {
instantiate built_in(optok,vrb,opprio,1)
action make(arg:expr,ann:annot) returns (res:expr) = {
var s:app;
s.func := symbol.makestr(optok,ann);
s.args := s.args.append(arg);
s.ann := ann;
res := s
}
}
module built_in_binary (optok,vrb,opprio) = {
instantiate built_in(optok,vrb,opprio,2)
action make(lhs:expr,rhs:expr,ann:annot) returns (res:expr) = {
var s:app;
s.func := symbol.makestr(optok,ann);
s.args := s.args.append(lhs);
s.args := s.args.append(rhs);
s.ann := ann;
res := s
}
[x1,..,xn] to the expression x1 * ... *xn<code>, where </code>* is a binary operator that associates to the left.
action fold_left(args:vector[expr],ann:annot) returns (res:expr) = {
if args.end > 0 {
res := args.value(0);
var idx := args.begin.next;
while idx < args.end {
res := make(res,args.value(idx),ann);
idx := idx.next;
}
} else {
res := empty.make(ann); # Works for comma and cross product
}
}
x1 * ... * xn to the vector [x1,..,xn],
where * is a binary operator that associates to the left.
action unfold_left(s:expr) returns (args:vector[expr]) = {
var e := s;
var b := e.is_typed(vrb); # workaround
while b {
args := args.append(e.get_arg(1));
e := e.get_arg(0);
b := e.is_typed(vrb);
};
args := args.append(e);
args := args.reverse;
}
}
module built_in_ternary (optok,vrb,opprio) = {
instantiate built_in(optok,vrb,opprio,3)
action make(arg0:expr,arg1:expr,arg2:expr,ann:annot) returns (res:expr) = {
var s:app;
s.func := symbol.makestr(optok,ann);
s.args := s.args.append(arg0);
s.args := s.args.append(arg1);
s.args := s.args.append(arg2);
s.ann := ann;
res := s
}
}
module built_in_const (optok,vrb) = {
instantiate built_in(optok,vrb,0,0)
action make(ann:annot) returns (res:expr) = {
res := symbol.makestr(optok,ann);
}
}
module genbinop(expr,arg) = {
variant this of expr = struct {
lhs : arg,
rhs : arg,
ann : annot
}
action make(x:arg,y:arg,ann:annot) returns (res:expr) = {
var s:this;
s.lhs := x;
s.rhs := y;
s.ann := ann;
res := s;
}
}
import action parse_error(p:pos,tok:str)
module parse_intf(expr,cppstyle) = {
action enc(e:expr) returns (s:str) = {
var p := pretty.make(100,4);
p.cppstyle := cppstyle;
p := e.encode(p,0);
p := p.flush;
s := p.output
}
action dec(s:str) returns (e:expr) = {
var st := pstate.make(s);
(st,e) := expr.parse(st,0);
if ~st.ok | st.tok.end ~= 0 {
call parse_error(st.ann.line,st.tok);
}
}
action encdec(s:str) returns (res:str) = {
var e := dec(s);
res := enc(e)
}
}
module expr_base(cppstyle) = {
ident are use as names. They don't have
annotations, so they can be hashed and compared for equality.
object ident = {
type this
action encode(s:this,b:pretty,prio:priority) returns (b:pretty)
action to_str(s:this) returns (res:str)
action get_namesp(s:this) returns (res:ident)
action get_member(s:this) returns (res:ident)
action get_subscripts(s:this) returns (res:vector[ident])
action prefix(s:this,pref:ident) returns (res:ident) = {
res := s
}
action get_last(s:this) returns (res:strident)
action get_verb(s:this) returns (vrb:verb) = {
vrb := verb.none
}
}
+ and &.
object strident = {
variant this of ident = struct {
val : str,
subscrs : vector[ident]
}
action encode(s:this,b:pretty,prio:priority) returns (b:pretty) = {
b := b.extend(s.val);
if cppstyle {
if s.subscrs.end > 0 {
b := b.extend("< ");
var idx := s.subscrs.begin;
while idx < s.subscrs.end {
if idx > 0 {
b := b.extend(",");
};
b := s.subscrs.value(idx).encode(b,0);
idx := idx.next
};
b := b.extend(" >");
}
} else {
var idx := s.subscrs.begin;
while idx < s.subscrs.end {
b := b.extend("[");
b := s.subscrs.value(idx).encode(b,0);
b := b.extend("]");
idx := idx.next
}
}
}
action make(val:str) returns (res:ident) = {
var s : this;
s.val := val;
res := s
}
action make1(val:str,arg:ident) returns (res:ident) = {
var s : this;
s.val := val;
s.subscrs := s.subscrs.append(arg);
res := s
}
action to_str(s:this) returns (b:str) = {
b := s.val;
if cppstyle {
if s.subscrs.end > 0 {
b := b.extend("< ");
var idx := s.subscrs.begin;
while idx < s.subscrs.end {
if idx > 0 {
b := b.extend(",");
};
b := b.extend(s.subscrs.value(idx).to_str);
idx := idx.next
};
b := b.extend(" >");
}
} else {
var idx := s.subscrs.begin;
while idx < s.subscrs.end {
b := b.extend("[");
b := b.extend(s.subscrs.value(idx).to_str);
b := b.extend("]");
idx := idx.next
}
}
}
action prefix(s:this,pref:ident) returns (res:ident) = {
res := dotident.make(pref,s);
}
action parse(st : pstate) returns(st : pstate, id:strident) = {
if st.ok & st.tok.end ~= 0 {
id.val := st.tok;
st := st.consume;
while st.ok & st.tok = "[" {
st := st.consume;
var mid : strident;
(st,mid) := parse(st);
var sid : ident := mid;
while st.ok & st.tok = "." {
st := st.consume;
(st,mid) := parse(st);
sid := dotident.make(sid,mid)
};
if st.ok & st.tok = "]" {
st := st.consume;
id.subscrs := id.subscrs.append(sid);
} else { st.ok := false }
}
} else { st.ok := false }
}
action get_last(s:this) returns (res:strident) = {
res := s
}
action get_verb(s:this) returns (vrb:verb) = {
vrb := verb_from_name(s.val)
}
}
object numident = {
variant this of ident = struct {
val : pos
}
action encode(s:this,b:pretty,prio:priority) returns (b:pretty) = {
b := b.extend("[");
b := b.extend(s.val.to_str);
b := b.extend("]");
}
action make(val:pos) returns (res:ident) = {
var s : this;
s.val := val;
res := s
}
}
object dotident = {
variant this of ident = struct {
namesp : ident,
member : strident
}
action encode(s:this,b:pretty,prio:priority) returns (b:pretty) = {
b := s.namesp.encode(b,0);
b := b.extend("::" if cppstyle else ".");
b := s.member.encode(b,0)
}
action make(namesp:ident,member:strident) returns (res:ident) = {
var s : this;
s.namesp := namesp;
s.member := member;
res := s
}
action to_str(s:this) returns (res:str) = {
res := s.namesp.to_str;
res := res.extend("::" if cppstyle else ".");
res := res.extend(s.member.to_str);
}
action get_namesp(s:this) returns (res:ident) = {
res := s.namesp;
}
action get_member(s:this) returns (res:ident) = {
res := s.member;
}
action prefix(s:this,pref:ident) returns (res:ident) = {
res := dotident.make(s.namesp.prefix(pref),s.member);
}
action get_last(s:this) returns (res:strident) = {
res := s.member
}
}
object expr = {
type this
action encode(s:this,b:pretty,prio:priority) returns (b:pretty)
instantiate parse_intf(expr,cppstyle)
action get_verb(s:this) returns (vrb:verb) = {
vrb := verb.none;
}
action get_verb_typed(s:this) returns (vrb:verb) = {
if s.is(verb.colon) {
vrb := s.get_arg(0).get_verb;
} else {
vrb := s.get_verb;
}
}
action is(s:this,vrb:verb) returns (res:bool) = {
res := false;
}
action is_typed(s:this,vrb:verb) returns (res:bool) = {
res := false;
}
action get_arg(s:this,p:vector[expr].domain) returns (res:expr)
action get_name(s:this) returns (res:ident)
action app_verb(s:this) returns (res:verb)
action get_ann(s:this) returns (res:annot)
action get_func(s:this) returns (res:expr)
action get_args(s:this) returns (res:vector[expr])
action prefix(s:this,pref:ident) returns (res:expr)
action eq(e1:expr,e2:expr) returns (res:bool) = {
if e1 isa symbol {
if e2 isa symbol {
res := (e1.get_name = e2.get_name);
}
} else if e1 isa app {
if eq(e1.get_func,e2.get_func) {
var args1 := e1.get_args;
var args2 := e2.get_args;
if args1.end = args2.end {
res := true;
var idx := args1.begin;
while res & idx < args1.end {
if ~eq(args1.value(idx),args2.value(idx)) {
res := false;
};
idx := idx.next;
}
}
}
}
}
}
object symbol = {
variant this of expr = struct {
name : ident,
vrb : verb,
ann : annot
}
action make(name:ident,ann:annot) returns (res:expr) = {
var s:symbol;
s.name := name;
s.vrb := verb.none;
s.ann := ann;
res := s
}
action makestr(name:str,ann:annot) returns (res:expr) = {
var s:symbol;
s.name := strident.make(name);
s.vrb := verb_from_name(name);
s.ann := ann;
res := s
}
action makestr1(name:str,arg:ident,ann:annot) returns (res:expr) = {
var s:symbol;
s.name := strident.make1(name,arg);
s.vrb := verb_from_name(name);
s.ann := ann;
res := s
}
action makenum(num:pos,ann:annot) returns (res:expr) = {
var s:symbol;
s.name := numident.make(num);
s.vrb := verb.none;
s.ann := ann;
res := s
}
action encode(s:symbol,b:pretty,prio:priority) returns (b:pretty) = {
b := s.ann.encode(b);
b := s.name.encode(b,0);
}
action parse(st : pstate) returns(st : pstate, res:expr) = {
if st.ok & st.tok.end ~= 0 {
var s : symbol;
s.vrb := verb_from_name(st.tok);
(st,s.ann) := st.get_ann;
var id : strident;
(st,id) := strident.parse(st);
s.name := id;
res := s;
}
else {
st.ok := false;
}
}
action get_verb(s:symbol) returns (res:verb) = {
res := s.vrb;
}
action get_name(s:this) returns (res:ident) = {
res := s.name
}
action get_ann(s:this) returns (res:annot) = {
res := s.ann
}
action prefix(s:this,pref:ident) returns (res:expr) = {
res := symbol.make(s.get_name.prefix(pref),s.get_ann);
}
}
object app = {
variant this of expr = struct {
func : expr,
args : vector[expr],
ann : annot
}
action make(func:expr,args:vector[expr],ann:annot) returns (res:expr) = {
var s:app;
s.func := func;
s.args := args;
s.ann := ann;
res := s
}
action make1(func:expr,arg0:expr,ann:annot) returns (res:expr) = {
var s:app;
s.func := func;
s.args := s.args.append(arg0);
s.ann := ann;
res := s
}
action make2(func:expr,arg0:expr,arg1:expr,ann:annot) returns (res:expr) = {
var s:app;
s.func := func;
s.args := s.args.append(arg0);
s.args := s.args.append(arg1);
s.ann := ann;
res := s
}
action encode(s:this,b:pretty,prio:priority) returns (b:pretty) = {
b := s.ann.encode(b);
var vrb := s.func.get_verb;
if vrb ~= verb.none {
var opprio := verb_to_prio(vrb);
if opprio < prio {
b := b.nest;
b := b.extend("(");
};
if s.args.end = 1 {
b := b.extend(verb_to_str(vrb));
b := b.extend(" ");
b := s.args.value(0).encode(b,opprio);
} else {
b := s.args.value(0).encode(b,opprio);
b := b.extend(" ");
b := b.extend(verb_to_str(vrb));
b := b.extend(" ");
b := s.args.value(1).encode(b,opprio+1);
if vrb = verb.ite {
b := b.extend(" ");
b := b.extend(":" if cppstyle else "else");
b := b.extend(" ");
b := s.args.value(2).encode(b,opprio+1);
}
};
if opprio < prio {
b := b.extend(")");
b := b.unnest
}
} else {
b := b.nest;
b := s.func.encode(b,99);
if s.args.end = 0 {
b := b.extend("()")
} else {
b := expr.tup.encode(s.args,b,0);
};
b := b.unnest;
}
}
action is(s:this,vrb:verb) returns (res:bool) = {
res := s.func.get_verb = vrb;
}
action is_typed(s:this,vrb:verb) returns (res:bool) = {
res := s.is(vrb) | s.func.is(verb.colon) & s.func.get_arg(0).get_verb = vrb
}
action app_verb(s:this) returns (res:verb) = {
res := s.func.get_verb
}
action get_func(s:this) returns (res:expr) = {
res := s.func
}
action get_args(s:this) returns (res:vector[expr]) = {
res := s.args
}
action get_arg(s:this,p:vector[expr].domain) returns (res:expr) = {
res := s.args.value(p)
}
action get_ann(s:this) returns (res:annot) = {
res := s.ann
}
}
object variable = {
variant this of expr = struct {
idx : pos,
ann : annot
}
action make(idx:pos) returns (res:expr) = {
var s:this;
s.idx := idx;
res := s
}
}
object pi = {
variant this of expr = struct {
vars : vector[expr],
body : expr,
ann : annot
}
action make (vars:vector[expr], body:expr,ann:annot) returns (res:expr) = {
var s:this;
s.vars := vars;
s.ann := ann;
res := s;
}
action encode(s:this,b:pretty,prio:priority) returns (b:pretty) = {
b := s.ann.encode(b);
b := b.nest;
b := b.extend("pi");
b := b.extend(" ");
b := expr.tup.encode(s.vars,b,0);
b := b.extend(".");
b := b.extend(" ");
b := s.body.encode(b,0);
b := b.extend(";");
b := b.unnest;
}
}
instance iff : built_in_binary("<->",verb.iff,2)
instance or : built_in_binary("|",verb.or,3)
instance and : built_in_binary("&",verb.and,4)
instance lt : built_in_binary("<",verb.lt,6)
instance leq : built_in_binary("<=",verb.leq,6)
instance gt : built_in_binary(">",verb.gt,6)
instance geq : built_in_binary(">=",verb.geq,6)
instance plus : built_in_binary("+",verb.plus,12)
instance minus : built_in_binary("-",verb.minus,12)
instance times : built_in_binary("*",verb.times,13)
instance div : built_in_binary("/",verb.div,13)
instance empty : built_in_const("()",verb.empty)
instance boolv : built_in_const("bool",verb.boolv)
instance truev : built_in_const("true",verb.truev)
instance falsev : built_in_const("false",verb.falsev)
instance comma : built_in_binary(",",verb.comma,1)
instance dot : built_in_binary(".",verb.dot,100)
instantiate built_in("(",verb.app,99,1)
object expr = { ...
var foo : vector[expr] # workaround
action parse(st : pstate, prio:priority) returns(st : pstate, res:expr) = {
if st.tok = "(" {
st := st.consume;
(st,res) := parse(st,0);
if st.ok & st.tok = ")" {
st := st.consume;
} else {
st.ok := false;
}
} else {
var vrb := str_to_verb(st.tok);
if vrb ~= verb.none & verb_to_arity(vrb) = 1 {
var s : app;
s.func := symbol.makestr(st.tok,s.ann);
st := st.consume;
var arg : expr;
(st,arg) := parse(st,verb_to_prio(vrb));
s.args := s.args.append(arg);
res := s;
} else {
(st,res) := symbol.parse(st);
}
};
var vrb := str_to_verb(st.tok);
while st.ok & vrb ~= verb.none & prio < verb_to_prio(vrb) {
var s : app;
(st,s.ann) := st.get_ann;
if vrb = verb.app {
s.func := res;
(st,s.args) := tup.parse(st,1);
} else {
s.func := symbol.makestr(st.tok,s.ann);
st := st.consume;
s.args := s.args.append(res);
var arg : expr;
(st,arg) := parse(st,verb_to_prio(vrb));
s.args := s.args.append(arg);
if st.ok & vrb = verb.ite {
if st.tok = (":" if cppstyle else "else") {
st := st.consume;
(st,arg) := parse(st,verb_to_prio(vrb));
s.args := s.args.append(arg);
} else { st.ok := false }
}
};
res := s;
vrb := str_to_verb(st.tok);
}
}
instance tup : tuple(expr,"(",")",verb)
}
}
module generic_stmt_encode(stmt_prio) = {
action encode(s:this,b:pretty,prio:priority) returns (b:pretty) = {
b := s.ann.encode(b);
if stmt_prio < prio {
b := b.nest;
b := b.extend("{");
b := b.newline;
};
b := s.encode_int(b,prio);
if stmt_prio < prio {
b := b.unnest;
b := b.newline;
b := b.extend("}");
}
}
}
module stmt_base(expr,asgntok,cppstyle) = {
object stmt = {
type this
action encode(s:this,b:pretty,prio:priority) returns (b:pretty)
instantiate parse_intf(stmt,cppstyle)
action get_expr(s:this) returns (res:expr)
action get_lhs(s:this) returns (res:expr)
action get_rhs(s:this) returns (res:expr)
action get_ann(s:this) returns (res:annot)
}
object asgn = {
instantiate genbinop(stmt,expr)
instantiate generic_stmt_encode(1)
action encode_int(s:this,b:pretty,prio:priority) returns (b:pretty) = {
b := b.nest;
if s.lhs.get_verb ~= verb.empty {
b := s.lhs.encode(b,0);
b := b.extend(" ");
b := b.extend(asgntok);
b := b.extend(" ");
};
b := s.rhs.encode(b,0);
b := b.extend(";");
b := b.unnest;
}
action get_lhs(s:this) returns (res:expr) = {
res := s.lhs;
}
action get_rhs(s:this) returns (res:expr) = {
res := s.rhs;
}
action get_ann(s:this) returns (res:annot) = {
res := s.ann
}
}
object sequence = {
instantiate genbinop(stmt,stmt)
instantiate generic_stmt_encode(0)
action encode_int(s:this,b:pretty,prio:priority) returns (b:pretty) = {
b := s.lhs.encode(b,1);
b := b.newline;
b := s.rhs.encode(b,0);
}
var dummy : vector[stmt] # workaround
[x1,..,xn] to the expression x1 * ... *xn<code>, where </code>* is a binary operator that associates to the right.
action fold_right(args:vector[stmt],ann:annot) returns (res:stmt) = {
if args.end > 0 {
var idx := args.end.prev;
res := args.value(idx);
while idx > 0 {
idx := idx.prev;
res := make(args.value(idx),res,ann);
}
}
}
action get_ann(s:this) returns (res:annot) = {
res := s.ann
}
}
object skipst = {
variant this of stmt = struct {
ann : annot
}
action make (ann:annot) returns (res:stmt) = {
var s:this;
s.ann := ann;
res := s;
}
action encode(s:this,b:pretty,prio:priority) returns (b:pretty) = {
b := s.ann.encode(b);
b := b.extend("{");
b := b.extend("}")
}
action get_ann(s:this) returns (res:annot) = {
res := s.ann
}
}
object ifst = {
variant this of stmt = struct {
cond : expr,
thenst : stmt,
elsest : stmt,
ann : annot
}
instantiate generic_stmt_encode(1)
action make(cond:expr,thenst:stmt,elsest:stmt,ann:annot) returns (res:stmt) = {
var s:this;
s.cond := cond;
s.thenst := elsest;
s.elsest := elsest;
s.ann := ann;
res := s;
}
action encode_int(s:this,b:pretty,prio:priority) returns (b:pretty) = {
b := b.extend("if");
b := b.extend(" ");
if cppstyle {
b := b.extend("(");
};
b := s.cond.encode(b,0);
if cppstyle {
b := b.extend(")");
};
b := b.extend(" ");
b := s.thenst.encode(b,2);
if ~(s.elsest isa skipst) {
b := b.extend(" ");
b := b.extend("else");
b := b.extend(" ");
b := s.elsest.encode(b,2);
};
}
action get_ann(s:this) returns (res:annot) = {
res := s.ann
}
}
object whilest = {
variant this of stmt = struct {
cond : expr,
body : stmt,
ann : annot
}
instantiate generic_stmt_encode(1)
action make(cond:expr,body:stmt,ann:annot) returns (res:stmt) = {
var s:this;
s.cond := cond;
s.body := body;
s.ann := ann;
res := s;
}
action encode_int(s:this,b:pretty,prio:priority) returns (b:pretty) = {
b := b.extend("while");
b := b.extend(" ");
if cppstyle {
b := b.extend("(");
};
b := s.cond.encode(b,0);
if cppstyle {
b := b.extend(")");
};
b := b.extend(" ");
b := s.body.encode(b,2);
}
action get_ann(s:this) returns (res:annot) = {
res := s.ann
}
}
object breakst = {
variant this of stmt = struct {
ann : annot
}
instantiate generic_stmt_encode(1)
action make(ann:annot) returns (res:stmt) = {
var s:this;
s.ann := ann;
res := s;
}
action encode_int(s:this,b:pretty,prio:priority) returns (b:pretty) = {
b := b.extend("break;");
}
action get_ann(s:this) returns (res:annot) = {
res := s.ann
}
}
object stmt = { ...
action parse(st : pstate, prio:priority) returns(st : pstate, res:stmt) = {
while st.tok = ";" {
st := st.consume;
};
if st.tok = "{" {
st := st.consume;
(st,res) := parse(st,0);
if st.ok & st.tok = "}" {
st := st.consume;
} else {
st.ok := false;
}
} else if st.tok = "if" {
st := st.consume;
var s : ifst;
(st,s.ann) := st.get_ann;
(st,s.cond) := expr.parse(st,0);
if st.ok & st.tok = "{" {
(st,s.thenst) := stmt.parse(st,1);
if st.ok & st.tok = "else" {
st := st.consume;
if st.ok & (st.tok = "{" | st.tok = "if") {
(st,s.elsest) := stmt.parse(st,1);
} else {
st.ok := false;
}
} else {
var ann : annot; # missing else doesn't print, so don't annotate
s.elsest := skipst.make(ann)
}
}
else {
st.ok := false;
};
res := s;
} else if st.tok = "while" {
st := st.consume;
var s : whilest;
(st,s.ann) := st.get_ann;
(st,s.cond) := expr.parse(st,0);
if st.ok & st.tok = "{" {
(st,s.body) := stmt.parse(st,1);
}
else {
st.ok := false;
};
res := s;
} else if st.tok = "}" {
var ann : annot;
(st,ann) := st.get_ann;
res := skipst.make(ann);
} else {
(st,res) := stmt.parse_lang_stmt(st,prio);
};
if st.ok & prio = 0 & st.tok.end > 0 & st.tok ~= "}" {
var sq : sequence;
sq.lhs := res;
(st,sq.rhs) := stmt.parse(st,0);
res := sq;
}
}
}
}
module decl_base(expr,stmt) = {
object decl = {
type this
action encode(s:this,b:pretty,prio:priority) returns (b:pretty)
instantiate parse_intf(decl,false)
action get_expr(s:this) returns (res:expr)
action get_ann(s:this) returns (res:annot)
action get_body(s:this) returns (res:stmt)
}
object action_kind = {
type this = {internal,external,imported,exported}
}
is_input and is_output fields tell us whether the argument
is an input, an output or both. Field is_ref means the
argument is passed by reference. Field is_const indicates it
is a const reference.
object prototype_argument = {
type this = struct {
name : expr,
is_input : bool,
inpos : vector[expr].domain,
is_output : bool,
outpos : vector[expr].domain,
is_ref : bool,
is_const : bool
}
}
object prototype = {
type this = struct {
args : vector[prototype_argument],
has_ret : bool,
ret : prototype_argument
}
}
object actdc = {
variant this of decl = struct {
name : expr,
kind : action_kind,
inputs : vector[expr],
outputs : vector[expr],
has_body : bool,
body : stmt,
ann : annot,
has_proto : bool,
proto : prototype
}
action make(name : expr, inputs : vector[expr], outputs : vector[expr], has_body:bool,
body : stmt)
returns (res:decl) =
{
var s:this;
s.name := name;
s.inputs := inputs;
s.outputs := outputs;
s.has_body := has_body;
s.body := body;
res := s;
}
action encode(s:this,b:pretty,prio:priority) returns (b:pretty) = {
b := s.ann.encode(b);
b := b.nest;
if s.kind = action_kind.external {
b := b.extend("extern");
b := b.extend(" ");
} else if s.kind = action_kind.imported {
b := b.extend("import");
b := b.extend(" ");
} else if s.kind = action_kind.exported {
b := b.extend("export");
b := b.extend(" ");
};
b := b.extend("action");
b := b.extend(" ");
b := s.name.encode(b,0);
b := expr.tup.encode(s.inputs,b,prio);
if s.outputs.end > 0 {
b := b.extend(" ");
b := b.extend("returns");
b := expr.tup.encode(s.outputs,b,prio);
};
b := b.unnest;
if s.has_body {
b := b.extend(" ");
b := b.extend("=");
b := b.extend(" ");
b := s.body.encode(b,2);
}
}
action type.member(x:type,...)
action is_member(s:this) returns (res:bool) = {
res := s.name.get_name isa dotident
& s.inputs.end > 0
& s.member_type = s.name.get_name.get_namesp;
}
action member_type(s:this) returns (res:ident) = {
res := s.inputs.value(0).get_arg(1).get_name;
}
action get_body(s:this) returns (res:stmt) = {
res := s.body
}
}
}
module prog_base(cppstyle) = {
object version = {
type this = struct {
nums : vector[pos]
}
action encode(s:this,b:pretty) returns(b:pretty) = {
b := b.extend("#lang ivy");
var idx := s.nums.begin;
while idx < s.nums.end {
if idx > s.nums.begin {
b := b.extend(".")
};
b := b.extend(s.nums.value(idx).to_str);
idx := idx.next
}
}
action parse(st : pstate, prio:priority) returns(st : pstate, res:this) = {
if st.ok & st.tok = "lang" {
st := st.consume;
} else {st.ok := false};
if st.ok & st.tok.segment(0,3) = "ivy" {
st.p := st.p - (st.tok.end - 3); # re-read remainder of token for backward compat
st := st.consume;
};
if st.ok & st.tok.end > 0 & st.tok.value(0).is_digit {
res.nums := res.nums.append(pos.from_str(st.tok));
st := st.consume;
while st.ok & st.tok = "." {
st := st.consume;
if st.tok.end > 0 & st.tok.value(0).is_digit {
res.nums := res.nums.append(pos.from_str(st.tok));
st := st.consume;
} else {st.ok := false;}
}
};
if st.tok.end > 0 {
st.ok := false;
}
}
}
object prog = {
type this = struct {
vers : version,
decls : vector[decl]
}
instantiate parse_intf(this,cppstyle)
action make(decls : vector[decl]) returns (res:prog) =
{
var s:this;
s.decls := decls;
res := s;
}
action encode(s:this,b:pretty,prio:priority) returns (b:pretty) = {
if ~cppstyle {
b := s.vers.encode(b)
};
b := b.newline;
var idx := s.decls.begin;
while idx < s.decls.end {
b := b.newline;
b := s.decls.value(idx).encode(b,0);
idx := idx.next;
};
}
action parse_to(st : pstate, prio:priority, res:prog) returns(st : pstate, res:prog) = {
if ~cppstyle {
if st.ann.comments.end > 0 {
var vst := pstate.make(st.ann.comments.value(0));
(vst,res.vers) := version.parse(vst,0);
st.ok := vst.ok;
st.ann.comments := st.ann.comments.segment(1,st.ann.comments.end)
} else {st.ok := false};
};
while st.ok & st.tok.end > 0 {
var dcl : decl;
(st,dcl) := decl.parse(st,0);
res.decls := res.decls.append(dcl);
}
}
action parse(st : pstate, prio:priority) returns(st : pstate, res:prog) = {
(st,res) := parse_to(st,prio,res);
}
}
}