Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
sbillig committed Jun 20, 2021
1 parent 678ae28 commit c7803ea
Show file tree
Hide file tree
Showing 11 changed files with 330 additions and 138 deletions.
17 changes: 17 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions compiler/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ maplit = "1.0.2"
once_cell = "1.5.2"
vec1 = "1.8.0"
num-bigint = "0.3.1"
indexmap = "1.6.2"

[dev-dependencies]
evm-runtime = "0.18"
Expand Down
2 changes: 1 addition & 1 deletion compiler/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ pub fn compile(
let json_abis = abi::build(&context, &fe_module)?;

// lower the AST
let lowered_fe_module = lowering::lower(&mut context, fe_module.clone());
let lowered_fe_module = lowering::lower(fe_module.clone());

// analyze the lowered AST
let context =
Expand Down
148 changes: 148 additions & 0 deletions compiler/src/lowering/context.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
use fe_analyzer::context::Context as AnalyzerContext;
use fe_analyzer::namespace::types::Array;
use fe_parser::ast::{GenericArg, TypeDesc};
use indexmap::IndexMap;
use std::hash::{Hash, Hasher};

#[derive(Default)]
pub struct ModuleContext<'a> {
analyzer_context: &'a AnalyzerContext,

/// Tuples that were used inside of a module,
/// and the generated name of the resulting struct.
tuple_structs: IndexMap<TupleTypeDesc, String>,

/// Holds fresh id for [`ModuleContext::make_unique_name`]
fresh_id: u64,
}

impl ModuleContext<'_> {
/// Makes a unique name from the given name, keeping it as readable as possible.
pub fn make_unique_name(&mut self, name: &str) -> String {
let id = self.fresh_id;
self.fresh_id += 1;
format!("${}_{}", name, id)
}

pub fn tuple_struct_name(&mut self, tuple: TypeDesc) -> &str {
let entry = self.tuple_structs.entry(TupleTypeDesc(tuple));
let index = entry.index();
entry.or_insert_with(|| format!("__tuple_{}", index))
}

pub fn iter_tuples(&self) -> impl Iterator<Item = (&TypeDesc, &str)> {
self.tuple_structs
.iter()
.map(|(typ, name)| (&typ.0, name.as_str()))
}
}

// This is contract context, but it's used all over so it has a short name.
pub struct Context<'a, 'b> {
pub module: &'a mut ModuleContext<'b>,
/// List expressions that the contract uses
array_literals: IndexMap<Array, String>,
}

impl Context<'_, '_> {
pub fn array_literal_function(typ: Array) -> String {
let name = list_expr_generator_fn_name(&typ);
self.array_literals.insert(typ);
name
}
}

struct TupleTypeDesc(TypeDesc);

impl PartialEq for TupleTypeDesc {
fn eq(&self, other: &TupleTypeDesc) -> bool {
types_equal(&self.0, &other.0)
}
}
impl Eq for TupleTypeDesc {}

impl Hash for TupleTypeDesc {
fn hash<H: Hasher>(&self, state: &mut H) {
hash_type_desc(&self.0, state)
}
}

fn types_equal(left: &TypeDesc, right: &TypeDesc) -> bool {
use TypeDesc::*;
match (left, right) {
(Unit, Unit) => true,
(Base { base: lname }, Base { base: rname }) => lname == rname,
(
Array {
typ: ltyp,
dimension: ldim,
},
Array {
typ: rtyp,
dimension: rdim,
},
) => ldim == rdim && types_equal(&ltyp.kind, &rtyp.kind),
(Tuple { items: left }, Tuple { items: right }) => {
left.len() == right.len()
&& left
.iter()
.zip(right.iter())
.all(|(lnode, rnode)| types_equal(&lnode.kind, &rnode.kind))
}
(
Generic {
base: lbase,
args: largs,
},
Generic {
base: rbase,
args: rargs,
},
) => {
lbase.kind == rbase.kind
&& largs.kind.len() == rargs.kind.len()
&& largs
.kind
.iter()
.zip(rargs.kind.iter())
.all(|(left, right)| match (left, right) {
(GenericArg::Int(l), GenericArg::Int(r)) => l.kind == r.kind,
(GenericArg::TypeDesc(l), GenericArg::TypeDesc(r)) => &l.kind == &r.kind,
_ => false,
})
}
_ => false,
}
}

fn hash_type_desc(typ: &TypeDesc, state: &mut impl Hasher) {
use TypeDesc::*;
match typ {
Unit => state.write_u8(0),
Base { base } => {
state.write_u8(1);
base.hash(state);
}
Array { typ, dimension } => {
state.write_u8(2);
hash_type_desc(&typ.kind, state);
state.write_usize(*dimension);
}
Tuple { items } => {
state.write_u8(3);
for item in items {
hash_type_desc(&item.kind, state);
}
}
Generic { base, args } => {
state.write_u8(4);
base.kind.hash(state);
for arg in &args.kind {
match arg {
GenericArg::Int(node) => state.write_usize(node.kind),
GenericArg::TypeDesc(node) => hash_type_desc(&node.kind, state),
}
}
}
}
}
19 changes: 8 additions & 11 deletions compiler/src/lowering/mappers/contracts.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
use fe_analyzer::context::Context;
use fe_analyzer::namespace::types::{Array, FixedSize};

use crate::lowering::context::Context;
use crate::lowering::mappers::{functions, types};
use crate::lowering::names;
use crate::lowering::utils::ZeroSpanNode;
use fe_analyzer::namespace::types::{Array, FixedSize};
use fe_parser::ast as fe;
use fe_parser::node::Node;

Expand All @@ -20,15 +19,13 @@ pub fn contract_def(context: &mut Context, stmt: Node<fe::Contract>) -> Node<fe:
})
.collect();

let attributes = context.get_contract(stmt.id).expect("missing attributes");

let func_defs_from_list_expr = attributes
.list_expressions
.iter()
.map(|expr| fe::ContractStmt::Function(list_expr_to_fn_def(expr).into_node()))
.collect::<Vec<fe::ContractStmt>>();
// let func_defs_from_list_expr = context
// .list_expressions
// .iter()
// .map(|expr| fe::ContractStmt::Function(list_expr_to_fn_def(expr).into_node()))
// .collect::<Vec<fe::ContractStmt>>();

let lowered_body = [lowered_body, func_defs_from_list_expr].concat();
// let lowered_body = [lowered_body, func_defs_from_list_expr].concat();

let lowered_fields = fields
.into_iter()
Expand Down
134 changes: 68 additions & 66 deletions compiler/src/lowering/mappers/expressions.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use crate::lowering::context::Context;
use crate::lowering::names::{list_expr_generator_fn_name, tuple_struct_name};
use crate::lowering::utils::ZeroSpanNode;
use fe_analyzer::builtins::Object;
use fe_analyzer::context::Context;
use fe_analyzer::namespace::types::Type;
use fe_parser::ast as fe;
use fe_parser::node::Node;
Expand Down Expand Up @@ -102,72 +102,74 @@ pub fn call_args(
}

fn expr_tuple(context: &mut Context, exp: Node<fe::Expr>) -> fe::Expr {
let attributes = context.get_expression(&exp).expect("missing attributes");

if let Type::Tuple(tuple) = &attributes.typ {
let name = tuple_struct_name(tuple);

if let fe::Expr::Tuple { elts } = exp.kind {
// map the tuple args to named args
let args = Node::new(
elts.into_iter()
.enumerate()
.map(|(index, elt)| {
Node::new(
fe::CallArg {
label: Some(Node::new(format!("item{}", index), elt.span)),
value: elt.clone(),
},
elt.span,
)
})
.collect(),
exp.span,
);

// create type constructor call for the lowered tuple
return fe::Expr::Call {
func: Box::new(Node::new(name, exp.span)),
generic_args: None,
args,
};
}
}

unreachable!()
todo!()
// let attributes = context.get_expression(&exp).expect("missing attributes");

// if let Type::Tuple(tuple) = &attributes.typ {
// let name = tuple_struct_name(tuple);

// if let fe::Expr::Tuple { elts } = exp.kind {
// // map the tuple args to named args
// let args = Node::new(
// elts.into_iter()
// .enumerate()
// .map(|(index, elt)| {
// Node::new(
// fe::CallArg {
// label: Some(Node::new(format!("item{}", index), elt.span)),
// value: elt.clone(),
// },
// elt.span,
// )
// })
// .collect(),
// exp.span,
// );

// // create type constructor call for the lowered tuple
// return fe::Expr::Call {
// func: Box::new(Node::new(name, exp.span)),
// generic_args: None,
// args,
// };
// }
// }

// unreachable!()
}

fn expr_list(context: &mut Context, exp: Node<fe::Expr>) -> fe::Expr {
let attributes = context.get_expression(&exp).expect("missing attributes");

if let Type::Array(array) = &attributes.typ {
let fn_name = list_expr_generator_fn_name(array);

if let fe::Expr::List { elts } = exp.kind {
let args = elts
.into_iter()
.map(|list_val| {
fe::CallArg {
label: None,
value: list_val,
}
.into_node()
})
.collect::<Vec<_>>()
.into_node();

// Turn List Expression into a function call
return fe::Expr::Call {
func: fe::Expr::Attribute {
value: fe::Expr::Name(Object::Self_.to_string()).into_boxed_node(),
attr: fn_name.into_node(),
}
.into_boxed_node(),
generic_args: None,
args,
};
}
}

unreachable!()
todo!()
// let attributes = context.get_expression(&exp).expect("missing attributes");

// if let Type::Array(array) = &attributes.typ {
// let fn_name = list_expr_generator_fn_name(array);

// if let fe::Expr::List { elts } = exp.kind {
// let args = elts
// .into_iter()
// .map(|list_val| {
// fe::CallArg {
// label: None,
// value: list_val,
// }
// .into_node()
// })
// .collect::<Vec<_>>()
// .into_node();

// // Turn List Expression into a function call
// return fe::Expr::Call {
// func: fe::Expr::Attribute {
// value: fe::Expr::Name(Object::Self_.to_string()).into_boxed_node(),
// attr: fn_name.into_node(),
// }
// .into_boxed_node(),
// generic_args: None,
// args,
// };
// }
// }

// unreachable!()
}
Loading

0 comments on commit c7803ea

Please sign in to comment.