Cpplang
include lang
This file implements a small subset of the syntax of C++ that is used by the Ivy to C++ translator.
object cpp = {
instantiate verb_base
instantiate expr_base(true)
instantiate stmt_base(expr,"=",true)
instance new : built_in_unary("new",verb.new,100)
instance arrow : built_in_binary("->",verb.arrow,100)
= 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)
c ? x : y.
instance ite : built_in_ternary("?",verb.ite,2)
object app = { ...
action make0(func:expr,ann:annot) returns (res:expr) = {
var s:app;
s.func := func;
s.ann := ann;
res := s
}
}
object simpletype = {
type this = struct {
_type : expr,
name : expr,
is_const : bool,
is_ref : bool,
is_rvalue : bool,
is_borrow : bool
}
instance tup : tuple(simpletype,"(",")",verb)
action encode(s:this,b:pretty,prio:priority) returns (b:pretty) = {
if s.is_const {
b := b.extend("const");
b := b.extend(" ");
};
b := s._type.encode(b,0);
b := b.extend(" ");
if s.is_ref {
b := b.extend("&");
};
if s.is_rvalue {
b := b.extend("&");
};
b := s.name.encode(b,99);
}
action parse(st : pstate, prio:priority) returns(st : pstate, res:simpletype) = {
(st,res._type) := symbol.parse(st);
if st.ok {
(st,res.name) := symbol.parse(st);
}
}
}
object functype = {
type this = struct {
base : simpletype,
args : vector[simpletype],
is_const : bool,
has_initializer : bool,
initializer : expr
}
action encode(s:this,b:pretty,prio:priority) returns (b:pretty) = {
b := s.base.encode(b,0);
b := b.extend(" ");
if s.args.end > 0 {
b := simpletype.tup.encode(s.args,b,0);
} else {
b := b.extend("()");
};
if s.is_const {
b := b.extend(" ");
b := b.extend("const");
};
if s.has_initializer {
b := b.extend(" ");
b := b.extend(":");
b := b.extend(" ");
b := s.initializer.encode(b,0);
}
}
action parse(st : pstate, base : simpletype, prio:priority) returns(st : pstate, res:functype) = {
res.base := base;
if st.ok {
(st,res.args) := simpletype.tup.parse(st,1);
};
if st.ok & st.tok = "const" {
res.is_const := true;
st := st.consume;
};
if st.ok & st.tok = ":" {
res.has_initializer := true;
(st,res.initializer) := expr.parse(st,0);
}
}
}
object varst = {
variant this of stmt = struct {
vtype : simpletype,
has_initval : bool,
initval : expr,
ann : annot
}
instantiate generic_stmt_encode(1)
action make(_type:expr, name:expr, ann:annot) returns (res:stmt) = {
var s : this;
s.vtype._type := _type;
s.vtype.name := name;
s.ann := ann;
res := s;
}
action encode_int(s:this,b:pretty,prio:priority) returns (b:pretty) = {
b := b.nest;
b := s.vtype.encode(b,prio);
if s.has_initval {
b := b.extend(" ");
b := b.extend("=");
b := b.extend(" ");
b := s.initval.encode(b,0);
}
b := b.extend(";");
b := b.unnest;
}
}
object retst = {
variant this of stmt = struct {
val : expr,
ann : annot
}
instantiate generic_stmt_encode(1)
action make(val:expr, ann:annot) returns (res:stmt) = {
var s : this;
s.val := val;
s.ann := ann;
res := s;
}
action encode_int(s:this,b:pretty,prio:priority) returns (b:pretty) = {
b := b.nest;
b := b.extend("return");
b := b.extend(" ");
b := s.val.encode(b,prio);
b := b.extend(";");
b := b.unnest;
}
}
object stmt = { ...
action parse_lang_stmt(st : pstate, prio:priority) returns(st : pstate, res:stmt) = {
var lhs : expr;
var ann : annot;
(st,ann) := st.get_ann;
(st,lhs) := expr.parse(st,3);
if st.ok & st.tok = "=" {
st := st.consume;
var s : asgn;
s.lhs := lhs;
s.ann := ann;
(st,s.rhs) := expr.parse(st,0);
res := s;
}
else {
var name : expr;
(st,name) := symbol.parse(st);
if st.ok {
var s : varst;
s.ann := ann;
s.vtype._type := lhs;
s.vtype.name := name;
res := s;
}
};
if st.ok & st.tok = ";" {
st := st.consume;
} else {
st.ok := false; # cannot omit final semicolon in C++
}
}
}
object decl = {
type this
action encode(s:this,b:pretty,prio:priority) returns (b:pretty)
instantiate parse_intf(decl,true)
action get_ann(d:this) returns (res:annot)
action get_name(d:this) returns (res:expr)
action get_type(d:this) returns (res:expr)
}
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("#include ");
b := b.extend(s.filename);
b := b.unnest;
b := b.newline;
}
action get_ann(d:this) returns (res:annot) = {
res := d.ann
}
}
object typedecl = {
variant this of decl = struct {
ttype : simpletype,
ann : annot
}
action encode(s:this,b:pretty,prio:priority) returns (b:pretty) = {
b := s.ann.encode(b);
b := b.nest;
b := b.extend("typedef");
b := b.extend(" ");
b := s.ttype.encode(b,0);
b := b.extend(";");
b := b.unnest;
b := b.newline;
}
action get_ann(d:this) returns (res:annot) = {
res := d.ann
}
}
instance curly_tup : tuple(expr,"{","}",verb)
object enumdecl = {
variant this of decl = struct {
name : expr,
elems : vector[expr],
ann : annot
}
action encode(s:this,b:pretty,prio:priority) returns (b:pretty) = {
b := s.ann.encode(b);
b := b.nest;
b := b.extend("enum");
b := b.extend(" ");
b := s.name.encode(b,0);
b := b.extend(" ");
b := curly_tup.encode(s.elems,b,0);
b := b.extend(";");
b := b.unnest;
b := b.newline;
}
action get_ann(d:this) returns (res:annot) = {
res := d.ann
}
}
object vardecl = {
variant this of decl = struct {
vtype : simpletype,
has_initval : bool,
initval : expr,
ann : annot
}
action encode(s:this,b:pretty,prio:priority) returns (b:pretty) = {
b := s.ann.encode(b);
b := b.nest;
b := s.vtype.encode(b,0);
if s.has_initval {
b := b.extend(" ");
b := b.extend("=");
b := b.extend(" ");
b := s.initval.encode(b,0);
}
b := b.extend(";");
b := b.unnest;
b := b.newline;
}
action get_ann(d:this) returns (res:annot) = {
res := d.ann
}
action get_name(d:this) returns (res:expr) = {
res := d.vtype.name;
}
action get_type(d:this) returns (res:expr) = {
res := d.vtype._type;
}
}
object funcdecl = {
variant this of decl = struct {
ftype : functype,
has_body : bool,
body : stmt,
is_static : bool,
is_virtual : bool,
is_default : bool,
ann : annot
}
action encode(s:this,b:pretty,prio:priority) returns (b:pretty) = {
b := s.ann.encode(b);
b := b.nest;
if s.is_static {
b := b.extend("static");
b := b.extend(" ");
};
if s.is_virtual {
b := b.extend("virtual");
b := b.extend(" ");
};
b := s.ftype.encode(b,0);
if s.has_body {
b := b.unnest;
b := b.extend(" ");
b := s.body.encode(b,2);
}
else {
if s.is_default {
b := b.extend(" ");
b := b.extend("=");
b := b.extend(" ");
b := b.extend("default");
}
b := b.extend(";");
b := b.unnest;
b := b.newline;
}
}
action get_ann(d:this) returns (res:annot) = {
res := d.ann
}
}
object structdecl = {
variant this of decl = struct {
name : expr,
has_super : bool,
super : expr,
has_members : bool,
members : vector[decl],
ann : annot
}
action encode(s:this,b:pretty,prio:priority) returns (b:pretty) = {
b := s.ann.encode(b);
b := b.nest;
b := b.extend("struct");
b := b.extend(" ");
b := s.name.encode(b,0);
if s.has_super {
b := b.extend(" ");
b := b.extend(":");
b := b.extend(" ");
b := s.super.encode(b,0);
};
if s.has_members {
b := b.unnest;
b := b.newline;
b := b.extend("{");
b := b.nest;
var idx := s.members.begin;
while idx < s.members.end {
b := b.newline;
b := s.members.value(idx).encode(b,0);
idx := idx.next;
};
b := b.unnest;
b := b.newline;
b := b.extend("}");
b := b.extend(";");
} else {
b := b.extend(";");
b := b.unnest;
};
b := b.newline;
}
action get_ann(d:this) returns (res:annot) = {
res := d.ann
}
}
object namespacedecl = {
variant this of decl = struct {
name : expr,
members : vector[decl],
ann : annot
}
action encode(s:this,b:pretty,prio:priority) returns (b:pretty) = {
b := s.ann.encode(b);
b := b.nest;
b := b.extend("namespace");
b := b.extend(" ");
b := s.name.encode(b,0);
b := b.unnest;
b := b.newline;
b := b.extend("{");
b := b.nest;
var idx := s.members.begin;
while idx < s.members.end {
b := b.newline;
b := s.members.value(idx).encode(b,0);
idx := idx.next;
};
b := b.unnest;
b := b.newline;
b := b.extend("}");
b := b.newline;
}
action get_ann(d:this) returns (res:annot) = {
res := d.ann
}
}
object groupdc = {
variant this of decl = struct {
decls : vector[decl],
ann : annot
}
action encode(s:this,b:pretty,prio:priority) returns (b:pretty) = {
var idx := s.decls.begin;
while idx < s.decls.end {
b := b.newline;
if idx > 0 {
b := b.newline; # empty line between decls
}
b := s.decls.value(idx).encode(b,0);
idx := idx.next;
};
}
}
object decl = { ...
action parse(st : pstate, prio:priority) returns(st : pstate, res:decl) = {
var ann : annot;
(st,ann) := st.get_ann;
if st.tok = "typedef" {
st := st.consume;
var t : typedecl;
(st,t.ttype) := simpletype.parse(st,0);
t.ann := ann;
if st.ok & st.tok = ";" {
st := st.consume;
} else {
st.ok := false;
};
res := t;
} else if st.tok = "enum" {
st := st.consume;
var t : enumdecl;
(st,t.name) := symbol.parse(st);
(st,t.elems) := curly_tup.parse(st,1);
t.ann := ann;
if st.ok & st.tok = ";" {
st := st.consume;
} else {
st.ok := false;
};
res := t;
} else if st.tok = "struct" {
st := st.consume;
var t : structdecl;
(st,t.name) := symbol.parse(st);
t.ann := ann;
if st.ok & st.tok = ":" {
st := st.consume;
t.has_super := true;
(st,t.super) := symbol.parse(st);
};
if st.ok & st.tok = "{" {
st := st.consume;
(st,t.members) := parse_list(st,0);
if st.ok & st.tok = "}" {
st := st.consume;
} else {
st.ok := false
}
};
if st.ok & st.tok = ";" {
st := st.consume;
} else {
st.ok := false;
};
res := t;
} else if st.tok = "namespace" {
st := st.consume;
var t : namespacedecl;
(st,t.name) := symbol.parse(st);
t.ann := ann;
if st.ok & st.tok = "{" {
st := st.consume;
(st,t.members) := parse_list(st,0);
if st.ok & st.tok = "}" {
st := st.consume;
} else {
st.ok := false
}
};
res := t;
} else if st.tok = "#" {
var s : header;
st := st.consume;
if st.ok & st.tok = "include" {
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 }
} else { st.ok := false }
} else {
var t : simpletype;
var is_static : bool;
if st.ok & st.tok = "static" {
is_static := true;
st := st.consume
};
(st,t) := simpletype.parse(st,prio);
if st.ok & st.tok = "(" {
var s : funcdecl;
s.ann := ann;
s.is_static := is_static;
(st,s.ftype) := functype.parse(st,t,prio);
if st.ok & st.tok = ";" {
st := st.consume;
} else if st.ok & st.tok = "{" {
s.has_body := true;
(st,s.body) := stmt.parse(st,0);
} else {
st.ok := false;
};
res := s;
} else {
if st.ok & st.tok = ";" {
st := st.consume;
var s : vardecl;
s.vtype := t;
s.ann := ann;
res := s;
} else {
st.ok := false;
}
}
}
}
var foo : vector[decl] # workaround
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(true)
action namedtype(name:ident,ann : annot) returns(res:expr) = {
var s : symbol;
s.name := name;
s.ann := ann.strip;
res := s;
}
action inttype(ann : annot) returns(res:expr) = {
res := namedtype(strident.make("int"),ann);
}
action voidtype(ann : annot) returns(res:expr) = {
res := namedtype(strident.make("void"),ann);
}
}