Skip to content

Commit

Permalink
[language][compiler][ir_to_bytecode] Function Calls are now Expressions
Browse files Browse the repository at this point in the history
Converting function calls into expressions.

Advantage:
- can be used to express programs with unbalanced stack expressions.
- expressions now also represent a vector of simple expressions.

Limitations:
- Any command of an expression (other than function calls) must be parenthesized.
  • Loading branch information
Gauri-Agarwal authored and calibra-opensource committed Jul 16, 2019
1 parent ffd112a commit ec4bbfa
Show file tree
Hide file tree
Showing 23 changed files with 691 additions and 161 deletions.
205 changes: 113 additions & 92 deletions language/compiler/ir_to_bytecode/src/compiler.rs

Large diffs are not rendered by default.

63 changes: 34 additions & 29 deletions language/compiler/ir_to_bytecode/syntax/src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -315,26 +315,21 @@ pub type FunctionCall_ = Spanned<FunctionCall>;
/// Enum for Move commands
#[derive(Debug, Clone, PartialEq)]
pub enum Cmd {
/// `x_1, ..., x_j = call`
Call {
return_bindings: Vec<Var_>,
call: FunctionCall_,
actuals: Vec<Exp_>,
},
/// `x = e`
Assign(Var_, Exp_),
Assign(Vec<Var_>, Exp_),
/// `n { f_1: x_1, ... , f_j: x_j } = e`
Unpack(StructName, Fields<Var_>, Exp_),
/// `*e_1 = e_2`
Mutate(Exp_, Exp_),
/// `abort e`
Abort(Option<Exp_>),
/// `return e_1, ... , e_j`
Return(Vec<Exp_>),
Return(Exp_),
/// `break`
Break,
/// `continue`
Continue,
Exp(Exp_),
}
/// The type of a command with its location
pub type Cmd_ = Spanned<Cmd>;
Expand Down Expand Up @@ -495,9 +490,13 @@ pub enum Exp {
Copy(Var_),
/// `&x` or `&mut x`
BorrowLocal(bool, Var_),
/// `f(e)` or `f(e_1, e_2, ..., e_j)`
FunctionCall(FunctionCall, Box<Exp_>),
/// (e_1, e_2, e_3, ..., e_j)
ExprList(Vec<Exp_>),
}

/// The type for a `Exp` and it's location
/// The type for a `Exp` and its location
pub type Exp_ = Spanned<Exp>;

//**************************************************************************************************
Expand Down Expand Up @@ -786,12 +785,12 @@ impl FunctionCall {
impl Cmd {
/// Creates a command that returns no values
pub fn return_empty() -> Self {
Cmd::Return(vec![])
Cmd::Return(Spanned::no_loc(Exp::ExprList(vec![])))
}

/// Creates a command that returns a single value
pub fn return_(op: Exp_) -> Self {
Cmd::Return(vec![op])
Cmd::Return(op)
}
}

Expand Down Expand Up @@ -917,6 +916,15 @@ impl Exp {
pub fn move_(v: Var_) -> Exp_ {
Spanned::no_loc(Exp::Move(v))
}

/// Creates a new function call `Exp` with no location information
pub fn function_call(f: FunctionCall, e: Exp_) -> Exp_ {
Spanned::no_loc(Exp::FunctionCall(f, Box::new(e)))
}

pub fn expr_list(exps: Vec<Exp_>) -> Exp_ {
Spanned::no_loc(Exp::ExprList(exps))
}
}

//**************************************************************************************************
Expand Down Expand Up @@ -1174,25 +1182,13 @@ impl fmt::Display for FunctionCall {
impl fmt::Display for Cmd {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Cmd::Call {
return_bindings,
call,
actuals,
} => {
let args = intersperse(actuals, ", ");
if return_bindings.is_empty() {
write!(f, "{}({});", call, args)
Cmd::Assign(var_list, e) => {
if var_list.is_empty() {
write!(f, "{};", e)
} else {
write!(
f,
"let {} = {}({});",
intersperse(return_bindings, ", "),
call,
args
)
write!(f, "{} = ({});", intersperse(var_list, ", "), e)
}
}
Cmd::Assign(v, e) => write!(f, "{} = {};", v, e,),
Cmd::Unpack(n, bindings, e) => write!(
f,
"{} {{ {} }} = {}",
Expand All @@ -1208,9 +1204,10 @@ impl fmt::Display for Cmd {
Cmd::Mutate(e, o) => write!(f, "*({}) = {};", e, o),
Cmd::Abort(None) => write!(f, "abort;"),
Cmd::Abort(Some(err)) => write!(f, "abort {};", err),
Cmd::Return(exps) => write!(f, "return {};", intersperse(exps, ", ")),
Cmd::Return(exps) => write!(f, "return {};", exps),
Cmd::Break => write!(f, "break;"),
Cmd::Continue => write!(f, "continue;"),
Cmd::Exp(e) => write!(f, "({});", e),
}
}
}
Expand Down Expand Up @@ -1342,7 +1339,7 @@ impl fmt::Display for Exp {
n,
s.iter().fold(String::new(), |acc, (field, op)| format!(
"{} {} : {},",
acc, field, op
acc, field, op,
))
),
Exp::Borrow {
Expand All @@ -1361,6 +1358,14 @@ impl fmt::Display for Exp {
Exp::BorrowLocal(is_mutable, v) => {
write!(f, "&{}{}", if *is_mutable { "mut " } else { "" }, v)
}
Exp::FunctionCall(func, e) => write!(f, "{}({})", func, e),
Exp::ExprList(exps) => {
if exps.is_empty() {
write!(f, "()")
} else {
write!(f, "({})", intersperse(exps, ", "))
}
}
}
}
}
94 changes: 54 additions & 40 deletions language/compiler/ir_to_bytecode/syntax/src/syntax.lalrpop
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ grammar();

U64: u64 = <s:r"[0-9]+"> => u64::from_str(s).unwrap();
Name: String = <s:r"[a-zA-Z$_][a-zA-Z0-9$_]*"> => s.to_string();
DotName: String = <s:r"[a-zA-Z$_][a-zA-Z0-9$_]*\.[a-zA-Z$_][a-zA-Z0-9$_]*"> => s.to_string();

ByteArray: ByteArray = {
<s:r#"b"[0-9a-fA-F]*""#> => {
ByteArray::new(hex::decode(&s[2..s.len()-1]).unwrap_or_else(|_| panic!("The string {:?} is not a valid hex-encoded byte array", s)))
Expand Down Expand Up @@ -88,7 +90,6 @@ Tier<Op, NextTier>: Exp = {
};

BinopExp = Tier<CmpOp, OrExp>;

BinopExp_ = Sp<BinopExp>;

CmpOp: BinOp = {
Expand Down Expand Up @@ -145,23 +146,45 @@ FactorOp: BinOp = {
"%" => BinOp::Mod,
}

QualifiedFunctionName : FunctionCall = {
<f: Builtin> => FunctionCall::Builtin(f),
<module_dot_name: DotName> => {
let v: Vec<&str> = module_dot_name.split(".").collect();
assert!(v.len() == 2, 42);
FunctionCall::ModuleFunctionCall{
module: ModuleName::new(v[0].to_string()),
name: FunctionName::new(v[1].to_string()),
}
}
}

UnaryExp : Exp = {
"!" <e: Sp<<UnaryExp>>> => Exp::UnaryExp(UnaryOp::Not, Box::new(e)),
"*" <e: Sp<<UnaryExp>>> => Exp::Dereference(Box::new(e)),
"&mut " <e: Sp<<UnaryExp>>> "." <f: Field> => {
"!" <e: Sp<UnaryExp>> => Exp::UnaryExp(UnaryOp::Not, Box::new(e)),
"*" <e: Sp<UnaryExp>> => Exp::Dereference(Box::new(e)),
"&mut " <e: Sp<UnaryExp>> "." <f: Field> => {
Exp::Borrow{ is_mutable: true, exp: Box::new(e), field: f }
},
"&" <e: Sp<<UnaryExp>>> "." <f: Field> => {
"&" <e: Sp<UnaryExp>> "." <f: Field> => {
Exp::Borrow{ is_mutable: false, exp: Box::new(e), field: f }
},
Term
CallOrTerm,
}

Call: Exp = {
<f: QualifiedFunctionName> <exp: Sp<CallOrTerm>> => Exp::FunctionCall(f, Box::new(exp)),
}

CallOrTerm: Exp = {
<f: QualifiedFunctionName> <exp: Sp<CallOrTerm>> => Exp::FunctionCall(f, Box::new(exp)),
Term,
}

FieldExp: (Field, Exp_) = {
<f: Field> ":" <e: Sp<Exp>> => (f, e)
}

Term : Exp = {
Term: Exp = {

"move(" <v: Sp<Var>> ")" => Exp::Move(v),
"copy(" <v: Sp<Var>> ")" => Exp::Copy(v),
"&mut " <v: Sp<Var>> => Exp::BorrowLocal(true, v),
Expand All @@ -172,15 +195,21 @@ Term : Exp = {
StructName::new(n),
fs.into_iter().collect::<BTreeMap<Field, Exp_>>()
),
"(" <Exp> ")" => <>,
"(" <exps: Comma<Sp<Exp>>> ")" => Exp::ExprList(exps),
}

StructName: StructName = {
<n: Name> => StructName::new(n),
}

StructType : StructType = {
<m: ModuleName> "." <n: StructName> => StructType::new(m, n),
<module_dot_struct: DotName> => {
let v: Vec<&str> = module_dot_struct.split(".").collect();
assert!(v.len() == 2, 42);
let m: ModuleName = ModuleName::new(v[0].to_string());
let n: StructName = StructName::new(v[1].to_string());
StructType::new(m,n)
}
}


Expand All @@ -206,17 +235,8 @@ Builtin: Builtin = {
"freeze" => Builtin::Freeze,
}

FunctionCallBody : FunctionCall = {
<f: Builtin> => FunctionCall::Builtin(f),
<module: ModuleName> "." <n: Name> =>
FunctionCall::ModuleFunctionCall{
module,
name: FunctionName::new(n),
},
}

ReturnBindings: Vec<Var_> = {
<l:Sp<Var>> <v: ("," <Sp<Var>>)+> => {
<l:Sp<Var>> <v: ("," <Sp<Var>>)*> => {
let mut v = v;
v.reverse();
v.push(l);
Expand All @@ -231,35 +251,20 @@ FieldBindings: (Field, Var_) = {
}

pub Cmd : Cmd = {
<v: Sp<Var>> "=" <e: Sp<Exp>> => Cmd::Assign(v, e),
<bindings: ReturnBindings> "=" <e: Sp<Exp>> => Cmd::Assign(bindings, e),
"*" <e: Sp<Exp>> "=" <op: Sp<Exp>> => Cmd::Mutate(e, op),
<binding: Sp<Var>> "=" <f: Sp<FunctionCallBody>> "(" <s: Comma<Sp<Exp>>> ")" =>
Cmd::Call {
return_bindings: vec![binding],
call: f,
actuals: s,
},
<bindings: ReturnBindings> "=" <f: Sp<FunctionCallBody>> "(" <s: Comma<Sp<Exp>>> ")" =>
Cmd::Call {
return_bindings: bindings,
call: f,
actuals: s,
},
<f: Sp<FunctionCallBody>> "(" <s: Comma<Sp<Exp>>> ")" => Cmd::Call {
return_bindings: vec![],
call: f,
actuals: s,
},
<n: StructName> "{" <bindings: Comma<FieldBindings>> "}" "=" <e: Sp<Exp>> =>
Cmd::Unpack(
n,
bindings.into_iter().collect(),
e,
),
"abort" <err: Sp<Exp>?> => Cmd::Abort(err),
"return" <v: Comma<Sp<Exp>>> => Cmd::Return(v),
"return" <v: Comma<Sp<Exp>>> => Cmd::Return(Spanned::no_loc(Exp::ExprList(v))),
"continue" => Cmd::Continue,
"break" => Cmd::Break,
<Sp<Call>> => Cmd::Exp(<>),
"(" <Comma<Sp<Exp>>> ")" => Cmd::Exp(Spanned::no_loc(Exp::ExprList(<>))),
}

Cmd_ : Cmd_ = {
Expand Down Expand Up @@ -461,7 +466,7 @@ pub Program : Program = {
let return_stmt = Statement::CommandStatement(
Spanned {
span: Span::default(),
value: Cmd::Return(vec![])
value: Cmd::Return(Spanned::no_loc(Exp::ExprList(vec![]))),
}
);
let main =
Expand Down Expand Up @@ -510,8 +515,17 @@ QualifiedModuleIdent: QualifiedModuleIdent = {
}

ModuleIdent: ModuleIdent = {
"Transaction" "." <m: ModuleName> => ModuleIdent::Transaction(m),
<q: QualifiedModuleIdent> => ModuleIdent::Qualified(q),
<transaction_dot_module: DotName> => {
let v: Vec<&str> = transaction_dot_module.split(".").collect();
assert!(v.len() == 2, 42);
let ident: String = v[0].to_string();
if ident != "Transaction" {
panic!("Ident = {} which is not Transaction", ident);
}
let m: ModuleName = ModuleName::new(v[1].to_string());
ModuleIdent::Transaction(m)
},
}

ImportAlias: ModuleName = {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
module M {
public foo(u: u64): u64 * u64 * u64 {
let twice: u64;
let quadruple: u64;
twice = 2 * copy(u);
quadruple = 4 * copy(u);
return move(u), move(twice), move(quadruple);
}

public bar(): u64 {
return 2;
}
}

//! new-transaction
import {{default}}.M;

main() {
let x: u64;
let y: u64;
let z: u64;
x, y, z = M.foo(5) + M.bar();
assert(move(x) == 5, 42);
assert(move(y) == 10, 42);
assert(move(z) == 22, 42);
return;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
main() {
let x: u64;
let y: u64;
let z: u64;
let z_var: u64;

x, y = (4, 5);
z = (6);
z_var = 6;

assert(move(x) == 4, 42);
assert(move(y) == 5, 42);
assert(move(z) == 6, 42);
assert(move(z_var) == 6, 42);
return;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
module A {
public ones_tens(f: u64): u64 * u64 {
let k: u64;
let m: u64;
k = copy(f) % 10;
m = (move(f) % 100) - copy(k);
return move(k), move(m);
}
}

//! new-transaction
import {{default}}.A;

main() {
let x: u64;
let y: u64;
let z: u64;
x = 143;
y, z = A.ones_tens(move(x));
assert(move(y) == 3, 42);
assert(move(z) == 40, 42);
return;
}
Loading

0 comments on commit ec4bbfa

Please sign in to comment.