Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
cburgdorf committed Feb 2, 2021
1 parent f0fe21c commit dc80649
Show file tree
Hide file tree
Showing 21 changed files with 445 additions and 27 deletions.
9 changes: 7 additions & 2 deletions compiler/src/abi/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,11 @@ pub fn module<'a>(module: &'a fe::Module<'a>) -> Result<ModuleAbis, CompileError
{
return Err(CompileError::static_str("duplicate contract definition"));
}
}
},
fe::ModuleStmt::StructDef { name, body} => {
// TODO: We probably need register a type_def for a Tuple here to make the struct
// known as an ABI Type (Structs are serialized as tuples)
},
_ => {}
};

Expand Down Expand Up @@ -157,6 +161,7 @@ fn type_desc<'a>(
type_defs: &'a TypeDefs<'a>,
typ: &'a fe::TypeDesc<'a>,
) -> Result<VarType, CompileError> {
dbg!(&type_defs);
if let fe::TypeDesc::Base { base } = typ {
if let Some(custom_type) = type_defs.get(base) {
return type_desc(type_defs, custom_type);
Expand All @@ -178,7 +183,7 @@ fn type_desc<'a>(
fe::TypeDesc::Base { base: "i8" } => Ok(VarType::Int8),
fe::TypeDesc::Base { base: "bool" } => Ok(VarType::Bool),
fe::TypeDesc::Base { base: "address" } => Ok(VarType::Address),
fe::TypeDesc::Base { base } if &base[..6] == "string" => Ok(VarType::String),
fe::TypeDesc::Base { base } if base.starts_with("string") => Ok(VarType::String),
fe::TypeDesc::Base { base } => {
Err(CompileError::str(format!("unrecognized type: {}", base)))
}
Expand Down
2 changes: 2 additions & 0 deletions compiler/src/abi/elements.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ use std::collections::HashMap;
/// The ABIs for each contract in a Fe module.
pub type ModuleAbis = HashMap<String, Contract>;

// TODO: Add Tuple here

/// All public interfaces of a Fe contract.
#[derive(Debug, PartialEq, Clone)]
pub struct Contract {
Expand Down
24 changes: 24 additions & 0 deletions compiler/src/yul/mappers/declarations.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ pub fn var_decl(
FixedSize::Array(array) => var_decl_array(context, stmt, array.to_owned()),
FixedSize::Tuple(_) => unimplemented!(),
FixedSize::String(_) => unimplemented!(),
FixedSize::Struct(val) => var_decl_struct(context, stmt),
};
}

Expand Down Expand Up @@ -77,6 +78,29 @@ fn var_decl_array(
unreachable!()
}

fn var_decl_struct(
context: &Context,
decl: &Spanned<fe::FuncStmt>,
) -> Result<yul::Statement, CompileError> {
if let fe::FuncStmt::VarDecl {
target,
typ: _,
value,
} = &decl.node
{
let target = names::var_name(expressions::expr_name_str(target)?);

return Ok(if let Some(value) = value {
let value = expressions::expr(context, &value)?;
statement! { let [target] := [value] }
} else {
statement! { let [target] := alloc(0) }
});
}

unreachable!()
}

#[cfg(test)]
mod tests {
use crate::yul::mappers::declarations::var_decl;
Expand Down
40 changes: 39 additions & 1 deletion compiler/src/yul/mappers/expressions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,14 @@ use fe_semantics::builtins;
use fe_semantics::namespace::types::{
FixedSize,
Type,
Struct,
};
use fe_semantics::{
CallType,
Context,
Location,
};
use std::convert::TryFrom;
use std::{convert::TryFrom};
use yultsur::*;

/// Builds a Yul expression from a Fe expression.
Expand Down Expand Up @@ -99,6 +100,10 @@ pub fn expr_call(
.collect::<Result<_, _>>()?;

return match call_type {
// TODO: Should we be calling something like abi_get_method_name(struct_Type)(...yul_args)
CallType::TypeConstructor { typ: Type::Struct(val) } => Ok(
expression! { encode_dummy_tuple([yul_args[0].to_owned()], [yul_args[1].to_owned()])
}),
CallType::TypeConstructor { .. } => Ok(yul_args[0].to_owned()),
CallType::SelfAttribute { func_name } => {
let func_name = names::func_name(func_name);
Expand Down Expand Up @@ -313,13 +318,46 @@ fn expr_attribute(
return match expr_name_str(value)? {
builtins::MSG => expr_attribute_msg(attr),
builtins::SELF => expr_attribute_self(context, exp),
custom_type => {
let x = context.get_expression(&*value).expect("fucked up");
if let Type::Struct(val) = &x.typ {
let values: Vec<String> = val.fields.keys().cloned().collect();
let index = values.iter().position(|r| r == attr.node).unwrap() * 32;
println!("{} is at index {}", attr.node, index);
let custom_type = format!("${}", custom_type);
let x = literal_expression! {(custom_type)};
let offset = literal_expression! {(index)};
return Ok(expression! { add([x], [offset]) })
}
unreachable!();
}
_ => Err(CompileError::static_str("invalid attributes")),
};
}

unreachable!()
}

// fn expr_attribute_custom_type(
// context: &Context,
// exp: &Spanned<fe::Expr>,
// ) -> Result<yul::Expression, CompileError> {
// if let Some(attributes) = context.get_expression(exp) {
// let nonce = if let Location::Storage { nonce: Some(nonce) } = attributes.location {
// nonce
// } else {
// return Err(CompileError::static_str("invalid attributes"));
// };

// return match attributes.typ {
// Type::Map(_) => Ok(literal_expression! { (nonce) }),
// _ => Ok(nonce_to_ptr(nonce)),
// };
// }

// Err(CompileError::static_str("missing attributes"))
// }

fn expr_attribute_msg(attr: &Spanned<&str>) -> Result<yul::Expression, CompileError> {
match attr.node {
builtins::SENDER => Ok(expression! { caller() }),
Expand Down
2 changes: 1 addition & 1 deletion compiler/src/yul/mappers/module.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ pub fn module(context: &Context, module: &fe::Module) -> Result<YulContracts, Co
return Err(CompileError::static_str("duplicate contract def"));
}
}
fe::ModuleStmt::StructDef { .. } => unimplemented!(),
fe::ModuleStmt::StructDef { .. } => { },
fe::ModuleStmt::FromImport { .. } => unimplemented!(),
fe::ModuleStmt::SimpleImport { .. } => unimplemented!(),
}
Expand Down
2 changes: 2 additions & 0 deletions compiler/src/yul/operations/abi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,14 @@ pub fn encode_size<T: AbiEncoding>(types: Vec<T>, vals: Vec<yul::Expression>) ->
for (typ, val) in typed_vals {
match typ.abi_type() {
AbiType::Uint { .. } => static_size += 32,
AbiType::Tuple => unimplemented!("encode_size for tuple"),
AbiType::Array { inner, size } => {
let inner_size = match *inner {
AbiType::Uint {
size: AbiUintSize { padded_size, .. },
} => padded_size,
AbiType::Array { .. } => unimplemented!(),
AbiType::Tuple => unimplemented!("Encode size for tuple in array")
};
match size {
AbiArraySize::Static { size } => {
Expand Down
25 changes: 21 additions & 4 deletions compiler/src/yul/runtime/functions/abi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ fn encode<T: AbiEncoding>(types: Vec<T>) -> yul::Statement {
encode_uint(dyn_offset)
}
AbiType::Uint { .. } => encode_uint(param),
AbiType::Tuple => unimplemented!("encode for Tuple"),
})
.collect::<Vec<_>>();

Expand Down Expand Up @@ -118,6 +119,7 @@ fn decode<T: AbiEncoding>(typ: T, location: AbiDecodeLocation) -> yul::Statement
AbiArraySize::Static { size } => decode_static_array(*inner, size, location),
AbiArraySize::Dynamic => decode_dyn_array(*inner, location),
},
AbiType::Tuple => unimplemented!("decode for Tuple")
};

function_definition! {
Expand Down Expand Up @@ -178,7 +180,8 @@ fn dyn_array_data_size(val: yul::Expression, inner: AbiType) -> yul::Expression
let array_size = expression! { mload([val]) };
let elements_size = expression! { mul([array_size], [inner_padded_size]) };
expression! { add(32, (ceil32([elements_size]))) }
}
},
AbiType::Tuple => unimplemented!(),
}
}

Expand All @@ -195,6 +198,17 @@ fn encode_dyn_array(val: yul::Expression, inner: AbiType) -> yul::Statement {
}
}

// fn encode_dummy_tuple() -> yul::Statement {
// function_definition! {
// function encode_dummy_tuple() -> mptr {
// (mptr := alloc(32))
// (mstore(mptr, 100))
// (let second_ptr := alloc(32))
// (mstore(second_ptr, 500))
// }
// }
// }

fn encode_static_array(val: yul::Expression, inner: AbiType, size: usize) -> yul::Statement {
let array_size = literal_expression! { (size) };
encode_array(val, inner, array_size)
Expand Down Expand Up @@ -233,7 +247,8 @@ fn encode_array(
} else {
statement! { abi_unpack([val], [array_size], [inner_data_size]) }
}
}
},
AbiType::Tuple => unimplemented!("encoding of tuples in arrays")
}
}

Expand Down Expand Up @@ -281,7 +296,8 @@ fn decode_dyn_array(inner: AbiType, location: AbiDecodeLocation) -> yul::Express
} else {
unimplemented!("packing of dynamically sized arrays")
}
}
},
AbiType::Tuple => unimplemented!("Decoding of tuples in arrays")
}
}

Expand Down Expand Up @@ -327,7 +343,8 @@ fn decode_static_array(
}
}
}
}
},
AbiType::Tuple => unimplemented!("Decoding of tuples in arrays")
}
}

Expand Down
11 changes: 11 additions & 0 deletions compiler/src/yul/runtime/functions/data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,17 @@ pub fn ccopym() -> yul::Statement {
}
}

pub fn encode_dummy_tuple() -> yul::Statement {
function_definition! {
function encode_dummy_tuple(val_1, val_2) -> mptr {
(mptr := alloc(32))
(mstore(mptr, val_1))
(let second_ptr := alloc(32))
(mstore(second_ptr, val_2))
}
}
}

/// Load a static string from data into a newly allocated segment of memory.
pub fn load_data_string() -> yul::Statement {
function_definition! {
Expand Down
1 change: 1 addition & 0 deletions compiler/src/yul/runtime/functions/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ pub fn std() -> Vec<yul::Statement> {
data::free(),
data::ccopym(),
data::load_data_string(),
data::encode_dummy_tuple(),
data::mcopys(),
data::scopym(),
data::mcopym(),
Expand Down
2 changes: 1 addition & 1 deletion compiler/src/yul/runtime/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,12 +70,12 @@ pub fn build_with_abi_dispatcher(
context: &Context,
contract: &Spanned<fe::ModuleStmt>,
) -> Vec<yul::Statement> {

if let Some(attributes) = context.get_contract(contract) {
let mut runtime = build(context, contract);
runtime.push(abi_dispatcher::dispatcher(
attributes.public_functions.to_owned(),
));

return runtime;
}

Expand Down
2 changes: 2 additions & 0 deletions compiler/src/yul/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,12 @@ pub fn abi_head_offsets<T: AbiEncoding>(types: &[T]) -> (Vec<usize>, usize) {
AbiType::Uint {
size: AbiUintSize { padded_size, .. },
} => ceil_32(padded_size * size),
AbiType::Tuple => unimplemented!(),
},
AbiType::Uint {
size: AbiUintSize { padded_size, .. },
} => padded_size,
AbiType::Tuple => unimplemented!(),
};
}

Expand Down
1 change: 1 addition & 0 deletions compiler/tests/evm_contracts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -910,6 +910,7 @@ fn sized_vals_in_sto() {
fn structs() {
with_executor(&|mut executor| {
let harness = deploy_contract(&mut executor, "structs.fe", "Foo", vec![]);
harness.test_function(&mut executor, "bar", vec![], Some(uint_token(500)));
});
}

Expand Down
10 changes: 8 additions & 2 deletions compiler/tests/fixtures/structs.fe
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,12 @@ struct House:
price: u256
size: u256

contract Foo:

contract City:
pub house: House
pub def bar() -> u256:
# Consider requiring KW syntax to instantiate structs
building: House = House(300, 500)
assert building.size == 500
assert building.price == 300
return building.size

Loading

0 comments on commit dc80649

Please sign in to comment.