Ivy2
include ivylang
include hash
object ivy = { ...
instance ident_to_exprs : hash_rel(ident,expr)
object subtypes = {
type this = struct {
subtypes_of : ident_to_exprs,
supertype_of : symeval
}
action is_subtype(s:this,sub:expr,super:expr) returns (res:bool) = {
if sub isa symbol {
var name := sub.get_name;
if s.supertype_of.mem(name) {
res := s.supertype_of.value(name).get_name = super.get_name
}
}
}
}
object prog = { ...
action get_subtypes(p:this) returns (s:subtypes) = {
var idx := p.decls.begin;
while idx < p.decls.end {
s := p.decls.value(idx).build_subtypes(s);
idx := idx.next
}
}
}
object decl = { ...
action build_subtypes(s:decl,st:subtypes) returns (st:subtypes)
}
object typedc = { ...
action build_subtypes(s:this,st:subtypes) returns (st:subtypes) = {
if s.has_super {
st.subtypes_of := st.subtypes_of.add(s.super.get_name,s.sort);
st.supertype_of := st.supertype_of.set(s.sort.get_name,s.super);
}
}
}
curried is set.
object global_types = {
type this = struct {
type_of : symeval,
is_action : ident_set,
curried : bool
}
}
object prog = { ...
action get_global_types(p:this, curried : bool) returns (s:global_types) = {
s.curried := curried;
var idx := p.decls.begin;
while idx < p.decls.end {
s := p.decls.value(idx).build_global_types(s);
idx := idx.next
}
}
}
object decl = { ...
action build_global_types(s:decl,st:global_types) returns (st:global_types)
}
(1) x:t (2) f(x1:t1,...,xn:tn) : t (3) (f : (t1...tn->t)(...) : u (4) (f : (t1...tn->t)(...)
action is_typing_complete(typing:expr) returns (res:bool) = {
if typing.is(verb.colon) {
var lhs := typing.get_arg(0);
if lhs isa symbol {
res := true;
} else if lhs isa app {
if lhs.get_func.is(verb.colon) {
res := true;
} else {
res := true;
var args := lhs.get_args;
var idx := args.begin;
while idx < args.end {
if ~args.value(idx).is(verb.colon) {
res := false;
};
idx := idx.next
}
}
}
} else {
if typing isa app {
if typing.get_func.is(verb.colon) {
res := true
}
}
}
}
object vardc = { ...
action build_global_types(s:this,st:global_types) returns (st:global_types) = {
if is_typing_complete(s.typing) {
var typing := canon_typing(s.typing);
var thing := typing.enc;
var ty := typing.get_arg(1);
if s.is_destructor & st.curried {
ty := ty.curry;
};
st.type_of := st.type_of.set(typing.get_arg(0).get_name,ty);
}
}
}
action get_formal_type(typings : vector[expr],ann:annot) returns (res:expr) = {
if typings.end = 0 {
res := empty.make(ann);
} else {
var tys : vector[expr];
var idx := typings.begin;
while idx < typings.end {
var ty := typings.value(idx).get_arg(1);
tys := tys.append(ty);
idx := idx.next
};
res := times.fold_left(tys,ann);
}
}
object typedc = { ...
action build_global_types(s:this,st:global_types) returns (st:global_types) = {
if s.has_spec {
if s.spec isa enumspec {
var foobar : decl := s;
var conss := s.spec.get_elems;
var idx := conss.begin;
while idx < conss.end {
st.type_of := st.type_of.set(conss.value(idx).get_name,s.sort);
idx := idx.next
}
}
}
}
}
object actdc = { ...
action build_global_types(s:this,st:global_types) returns (st:global_types) = {
var ty := get_formal_type(s.outputs,s.ann);
if s.inputs.end > 0 {
var inpty := get_formal_type(s.inputs,s.ann);
ty := arrow.make(inpty,ty,s.ann)
};
if s.is_member & st.curried {
ty := ty.curry;
};
st.type_of := st.type_of.set(s.name.get_name,ty);
st.is_action := st.is_action.set(s.name.get_name,true);
}
}
object prototype = { ...
action any_non_const_ref(s:this) returns(res:bool) = {
var idx := s.args.begin;
while ~res & idx < s.args.end {
var arg := s.args.value(idx);
res := arg.is_ref & ~arg.is_const;
idx := idx.next
}
}
}
instance param_map : hash_map(ident,vector[expr].domain)
action param_set(ps:vector[expr]) returns (res:param_map) = {
var idx := ps.begin;
while idx < ps.end {
res := res.set(ps.value(idx).get_arg(0).get_name,idx);
idx := idx.next
}
}
object actdc = { ...
action get_proto(s:actdc) returns (res:prototype) = {
if s.has_proto {
res := s.proto
} else {
var inps := param_set(s.inputs);
var outs := param_set(s.outputs);
var idx := s.inputs.begin;
while idx < s.inputs.end {
var arg : prototype_argument;
arg.name := s.inputs.value(idx);
var id := arg.name.get_arg(0).get_name;
arg.is_input := true;
arg.inpos := idx;
arg.is_output := outs.mem(id);
if arg.is_output {
arg.outpos := outs.value(id)
} else {
arg.is_const := true;
};
arg.is_ref := true;
res.args := res.args.append(arg);
idx := idx.next
};
if s.outputs.end = 1 & ~inps.mem(s.outputs.value(0).get_arg(0).get_name) {
res.has_ret := true;
res.ret.name := s.outputs.value(0);
res.ret.is_output := true;
res.ret.outpos := 0;
} else {
idx := 0;
while idx < s.outputs.end {
var arg : prototype_argument;
arg.name := s.outputs.value(idx);
var id := arg.name.get_arg(0).get_name;
if ~inps.mem(id) {
arg.is_output := true;
arg.outpos := idx;
arg.is_ref := true;
res.args := res.args.append(arg);
};
idx := idx.next
}
}
}
}
}
Curry a function type, that is, translate type t1 * ... tn -> s to
type t1 -> (t2 * ... * tn -> s).
object expr = { ...
action curry(ty:expr) returns (res:expr) = {
var dom := times.unfold_left(ty.get_arg(0));
var dom2 := dom.segment(1,dom.end);
var rng := ty.get_arg(1);
var ty2 :=
rng if dom2.end = 0
else arrow.make(times.fold_left(dom2,ty.get_arg(0).get_ann),rng,ty.get_ann);
res := arrow.make(dom.value(0),ty2,ty.get_ann.strip)
}
}
f : t -> (... -> u) to t.f : (t * ... -> u).
action uncurry_func(func:expr) returns (res:expr) = {
var ty := func.get_arg(1).get_arg(0);
var fid := func.get_arg(0).get_name.prefix(ty.get_name);
var sym := symbol.make(fid,func.get_ann);
res := colon.make(sym,func.get_arg(1).uncurry,func.get_ann);
}
ty = (t * ... -> u), return t.
action get_dom0(ty:expr) returns (res:expr) = {
res := ty.get_arg(0);
var b := res.is(verb.times);
while b {
res := res.get_arg(0);
b := res.is(verb.times);
};
}
func has the form
t.f : (t * ...) -> u.
action func_is_member(func:expr) returns (res:bool) = {
var ty := func.get_arg(1);
if ty.is(verb.arrow) {
var fid := func.get_arg(0).get_name;
if fid isa dotident {
var dom := get_dom0(ty);
res := (fid.get_namesp = dom.get_name);
}
}
}
- (x:t).f returns t.f(x)
- (x:t).f(a1...an) returns t.f(x,a1...an)
- (f:...)(a1...an) returns f(a1...an)
This action analyzes an app, returning the type-decorated function and the argument vector. This assumes that the app is already type-decorated.
action get_app(s:expr) returns (func:expr, args:vector[expr]) = {
if s.is(verb.dot) {
var lhs := s.get_arg(0);
var ty := lhs.get_type;
func := uncurry_func(s.get_arg(1));
args := args.append(lhs);
} else {
func := s.get_func;
if func.is(verb.dot) {
var tmp := func; # workaround
(func,args) := get_app(tmp);
};
args := args.extend(s.get_args);
}
}
action canon_app(s:expr) returns (s:expr) = {
if s.is(verb.dot) {
var args : vector[expr];
(s,args) := get_app(s);
if args.end > 0 {
s := app.make(s,args,s.get_ann)
}
}
}
}
module push_pop_map(domain,range) = {
instance map_t : hash_map(domain,range)
instance vec_t : array(pos,domain)
type this = struct {
map : map_t,
del : vec_t,
stack : vector[pos]
}
action set(s:this,id:domain,v:range) returns(s:this) = {
if ~s.map.mem(id) {
s.del := s.del.append(id);
};
s.map := s.map.set(id,v)
}
action mem(s:this, id:domain) returns (res:bool) = {
res := s.map.mem(id)
}
action push(s:this) returns(s:this) = {
s.stack := s.stack.append(s.del.end);
}
action pop(s:this) returns(s:this) = {
var begin := s.stack.back;
s.stack := s.stack.pop_back;
while s.del.end > begin {
var x := s.del.back;
s.del := s.del.pop_back;
s.map := s.map.remove(x);
}
}
}
object ivy = { ...
instance push_pop_ident_set : push_pop_map(ident,bool)
object local_tracker = {
type this = struct {
map : push_pop_ident_set
}
action push(s:this) returns (s:this) = {
s.map := s.map.push;
}
action add_var(s:this,typing:expr) returns (s:this) = {
var v := typing.get_arg(0) if typing.is(verb.colon) else typing;
s.map := s.map.set(v.get_name,true);
}
action push_vars(s:this,typings:vector[expr]) returns (s:this) = {
s.map := s.map.push;
var idx := typings.begin;
while idx < typings.end {
var typing := typings.value(idx);
var v := typing.get_arg(0) if typing.is(verb.colon) else typing;
s.map := s.map.set(v.get_name,true);
idx := idx.next
}
}
action push_stmt(s:this,stm:stmt) returns (s:this) = {
s.map := s.map.push;
if stm isa varst {
s := s.add_var(stm.get_expr);
}
}
action pop(s:this) returns (s:this) = {
s.map := s.map.push
}
action mem(s:this,id:ident) returns (res:bool) = {
res := s.map.mem(id);
}
}
}