Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
cburgdorf committed Feb 4, 2021
1 parent 013787a commit b1af6a5
Show file tree
Hide file tree
Showing 18 changed files with 624 additions and 24 deletions.
21 changes: 15 additions & 6 deletions analyzer/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ use crate::namespace::scopes::{
use crate::namespace::types::{
Contract,
FixedSize,
Struct,
Type,
};
use fe_parser::ast as fe;
Expand Down Expand Up @@ -55,6 +56,7 @@ impl Location {
Type::Array(_) => Ok(Location::Memory),
Type::Tuple(_) => Ok(Location::Memory),
Type::String(_) => Ok(Location::Memory),
Type::Struct(_) => Ok(Location::Memory),
Type::Map(_) => Err(SemanticError::cannot_move()),
}
}
Expand All @@ -71,6 +73,8 @@ pub struct ContractAttributes {
pub events: Vec<Event>,
/// Static strings that the contract defines
pub string_literals: HashSet<String>,
/// Structs that have been defined by the user
pub structs: Vec<Struct>,
/// External contracts that may be called from within this contract.
pub external_contracts: Vec<Contract>,
}
Expand Down Expand Up @@ -108,6 +112,14 @@ impl From<Shared<ContractScope>> for ContractAttributes {
}
});

let structs = scope.borrow().get_module_type_defs(|typ| {
if let Type::Struct(val) = typ {
Some(val.to_owned())
} else {
None
}
});

ContractAttributes {
public_functions,
init_function,
Expand All @@ -118,6 +130,7 @@ impl From<Shared<ContractScope>> for ContractAttributes {
.map(|event| event.to_owned())
.collect::<Vec<Event>>(),
string_literals: scope.borrow().string_defs.clone(),
structs,
external_contracts,
}
}
Expand Down Expand Up @@ -248,12 +261,8 @@ impl Context {
}

/// Attribute contextual information to an expression node.
pub fn add_expression(
&mut self,
spanned: &Spanned<fe::Expr>,
attributes: ExpressionAttributes,
) {
self.expressions.insert(spanned.span, attributes);
pub fn add_expression<T: Into<Span>>(&mut self, span: T, attributes: ExpressionAttributes) {
self.expressions.insert(span.into(), attributes);
}

/// Get information that has been attributed to an expression node.
Expand Down
1 change: 1 addition & 0 deletions analyzer/src/namespace/operations.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ pub fn index(value: Type, index: Type) -> Result<Type, SemanticError> {
Type::Tuple(_) => Err(SemanticError::not_subscriptable()),
Type::String(_) => Err(SemanticError::not_subscriptable()),
Type::Contract(_) => Err(SemanticError::not_subscriptable()),
Type::Struct(_) => Err(SemanticError::not_subscriptable()),
}
}

Expand Down
58 changes: 57 additions & 1 deletion analyzer/src/namespace/types.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
use crate::errors::SemanticError;
use fe_parser::ast as fe;
use std::collections::HashMap;
use std::collections::{
BTreeMap,
HashMap,
};
use std::convert::TryFrom;
use std::num::{
IntErrorKind,
Expand Down Expand Up @@ -103,6 +106,7 @@ pub enum Type {
Tuple(Tuple),
String(FeString),
Contract(Contract),
Struct(Struct),
}

#[derive(Clone, Debug, PartialEq, PartialOrd, Ord, Eq)]
Expand All @@ -112,6 +116,7 @@ pub enum FixedSize {
Tuple(Tuple),
String(FeString),
Contract(Contract),
Struct(Struct),
}

#[derive(Clone, Debug, PartialEq, PartialOrd, Ord, Eq)]
Expand Down Expand Up @@ -157,6 +162,12 @@ pub struct Tuple {
pub items: Vec<Base>,
}

#[derive(Clone, Debug, PartialEq, PartialOrd, Ord, Eq)]
pub struct Struct {
pub name: String,
pub fields: BTreeMap<String, Base>,
}

#[derive(Clone, Debug, PartialEq, PartialOrd, Ord, Eq)]
pub struct FeString {
pub max_size: usize,
Expand All @@ -168,6 +179,19 @@ pub struct Contract {
pub functions: Vec<FunctionAttributes>,
}

impl Struct {
pub fn new(name: &str) -> Struct {
Struct {
name: name.to_string(),
fields: BTreeMap::new(),
}
}

pub fn get_field_types(&self) -> Vec<Type> {
self.fields.values().map(|val| val.clone().into()).collect()
}
}

impl TryFrom<&str> for FeString {
type Error = String;

Expand Down Expand Up @@ -258,10 +282,17 @@ impl From<FixedSize> for Type {
FixedSize::Tuple(tuple) => Type::Tuple(tuple),
FixedSize::String(string) => Type::String(string),
FixedSize::Contract(contract) => Type::Contract(contract),
FixedSize::Struct(val) => Type::Struct(val),
}
}
}

impl From<Base> for Type {
fn from(value: Base) -> Self {
Type::Base(value)
}
}

impl FeSized for FixedSize {
fn size(&self) -> usize {
match self {
Expand All @@ -270,6 +301,7 @@ impl FeSized for FixedSize {
FixedSize::Tuple(tuple) => tuple.size(),
FixedSize::String(string) => string.size(),
FixedSize::Contract(contract) => contract.size(),
FixedSize::Struct(val) => val.size(),
}
}
}
Expand Down Expand Up @@ -301,6 +333,7 @@ impl AbiEncoding for FixedSize {
FixedSize::Tuple(tuple) => tuple.abi_name(),
FixedSize::String(string) => string.abi_name(),
FixedSize::Contract(contract) => contract.abi_name(),
FixedSize::Struct(val) => val.abi_name(),
}
}

Expand All @@ -311,6 +344,7 @@ impl AbiEncoding for FixedSize {
FixedSize::Tuple(tuple) => tuple.abi_safe_name(),
FixedSize::String(string) => string.abi_safe_name(),
FixedSize::Contract(contract) => contract.abi_safe_name(),
FixedSize::Struct(val) => val.abi_safe_name(),
}
}

Expand All @@ -321,6 +355,7 @@ impl AbiEncoding for FixedSize {
FixedSize::Tuple(tuple) => tuple.abi_type(),
FixedSize::String(string) => string.abi_type(),
FixedSize::Contract(contract) => contract.abi_type(),
FixedSize::Struct(val) => val.abi_type(),
}
}
}
Expand Down Expand Up @@ -348,6 +383,7 @@ impl TryFrom<Type> for FixedSize {
Type::Base(base) => Ok(FixedSize::Base(base)),
Type::Tuple(tuple) => Ok(FixedSize::Tuple(tuple)),
Type::String(string) => Ok(FixedSize::String(string)),
Type::Struct(val) => Ok(FixedSize::Struct(val)),
Type::Map(_) => Err(SemanticError::type_error()),
Type::Contract(contract) => Ok(FixedSize::Contract(contract)),
}
Expand Down Expand Up @@ -543,6 +579,26 @@ impl FeSized for Tuple {
}
}

impl FeSized for Struct {
fn size(&self) -> usize {
self.fields.values().map(|val| val.size()).sum()
}
}

impl AbiEncoding for Struct {
fn abi_name(&self) -> String {
unimplemented!();
}

fn abi_safe_name(&self) -> String {
unimplemented!();
}

fn abi_type(&self) -> AbiType {
unimplemented!();
}
}

impl AbiEncoding for Tuple {
fn abi_name(&self) -> String {
unimplemented!();
Expand Down
88 changes: 80 additions & 8 deletions analyzer/src/traversal/expressions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ use crate::namespace::types::{
FeString,
FixedSize,
Integer,
Struct,
Type,
U256,
};
Expand Down Expand Up @@ -45,7 +46,7 @@ pub fn expr(
fe::Expr::Num(_) => expr_num(exp),
fe::Expr::Bool(_) => expr_bool(exp),
fe::Expr::Subscript { .. } => expr_subscript(scope, Rc::clone(&context), exp),
fe::Expr::Attribute { .. } => expr_attribute(scope, exp),
fe::Expr::Attribute { .. } => expr_attribute(scope, Rc::clone(&context), exp),
fe::Expr::Ternary { .. } => expr_ternary(scope, Rc::clone(&context), exp),
fe::Expr::BoolOperation { .. } => unimplemented!(),
fe::Expr::BinOperation { .. } => expr_bin_operation(scope, Rc::clone(&context), exp),
Expand Down Expand Up @@ -138,7 +139,6 @@ pub fn expr_name_str<'a>(exp: &Spanned<fe::Expr<'a>>) -> Result<&'a str, Semanti
if let fe::Expr::Name(name) = exp.node {
return Ok(name);
}

unreachable!()
}

Expand Down Expand Up @@ -198,6 +198,10 @@ fn expr_name(
Location::Memory,
)),
Some(FixedSize::Tuple(_)) => unimplemented!(),
Some(FixedSize::Struct(val)) => Ok(ExpressionAttributes::new(
Type::Struct(val),
Location::Memory,
)),
None => Err(SemanticError::undefined_value()),
};
}
Expand Down Expand Up @@ -275,6 +279,7 @@ fn expr_subscript(

fn expr_attribute(
scope: Shared<BlockScope>,
context: Shared<Context>,
exp: &Spanned<fe::Expr>,
) -> Result<ExpressionAttributes, SemanticError> {
if let fe::Expr::Attribute { value, attr } = &exp.node {
Expand All @@ -286,10 +291,18 @@ fn expr_attribute(
TxField,
};

let object_name = expr_name_str(value)?;

// Before we try to match any pre-defined objects, try matching as a
// custom type
if let Some(FixedSize::Struct(_)) = scope.borrow().variable_def(object_name.to_string()) {
return expr_attribute_custom_type(Rc::clone(&scope), context, value, attr);
}

let val = |t| Ok(ExpressionAttributes::new(Type::Base(t), Location::Value));
let err = || Err(SemanticError::undefined_value());

return match Object::from_str(expr_name_str(value)?) {
return match Object::from_str(object_name) {
Ok(Object::Self_) => expr_attribute_self(scope, attr),

Ok(Object::Block) => match BlockField::from_str(attr.node) {
Expand Down Expand Up @@ -322,6 +335,36 @@ fn expr_attribute(
unreachable!()
}

fn expr_attribute_custom_type(
scope: Shared<BlockScope>,
context: Shared<Context>,
value: &Spanned<fe::Expr>,
attr: &Spanned<&str>,
) -> Result<ExpressionAttributes, SemanticError> {
let val_str = expr_name_str(value)?;
let custom_type = scope
.borrow()
.variable_def(val_str.to_string())
.ok_or_else(SemanticError::undefined_value)?;
context.borrow_mut().add_expression(
value,
ExpressionAttributes::new(custom_type.clone().into(), Location::Memory),
);
match custom_type {
FixedSize::Struct(val) => {
let field = val
.fields
.get(attr.node)
.ok_or_else(SemanticError::undefined_value)?;
Ok(ExpressionAttributes::new(
Type::Base(field.clone()),
Location::Memory,
))
}
_ => Err(SemanticError::undefined_value()),
}
}

fn expr_attribute_self(
scope: Shared<BlockScope>,
attr: &Spanned<&str>,
Expand Down Expand Up @@ -431,12 +474,34 @@ fn expr_call(
unreachable!()
}

fn expr_call_struct_constructor(
scope: Shared<BlockScope>,
context: Shared<Context>,
typ: Struct,
args: &Spanned<Vec<Spanned<fe::CallArg>>>,
) -> Result<ExpressionAttributes, SemanticError> {
let argument_attributes = expr_call_args(Rc::clone(&scope), Rc::clone(&context), args)?;

if typ.get_field_types() != expression_attributes_to_types(argument_attributes) {
return Err(SemanticError::type_error());
}

Ok(ExpressionAttributes::new(
Type::Struct(typ),
Location::Memory,
))
}

fn expr_call_type_constructor(
scope: Shared<BlockScope>,
context: Shared<Context>,
typ: Type,
args: &Spanned<Vec<Spanned<fe::CallArg>>>,
) -> Result<ExpressionAttributes, SemanticError> {
if let Type::Struct(val) = typ {
return expr_call_struct_constructor(scope, context, val, args);
}

if args.node.len() != 1 {
return Err(SemanticError::wrong_number_of_params());
}
Expand Down Expand Up @@ -507,6 +572,17 @@ fn validate_str_literal_fits_type(
Err(SemanticError::type_error())
}

fn expr_call_args(
scope: Shared<BlockScope>,
context: Shared<Context>,
args: &Spanned<Vec<Spanned<fe::CallArg>>>,
) -> Result<Vec<ExpressionAttributes>, SemanticError> {
args.node
.iter()
.map(|arg| call_arg(Rc::clone(&scope), Rc::clone(&context), arg))
.collect::<Result<Vec<_>, _>>()
}

fn expr_call_self_attribute(
scope: Shared<BlockScope>,
context: Shared<Context>,
Expand All @@ -524,11 +600,7 @@ fn expr_call_self_attribute(
.borrow()
.function_def(func_name)
{
let argument_attributes = args
.node
.iter()
.map(|arg| call_arg(Rc::clone(&scope), Rc::clone(&context), arg))
.collect::<Result<Vec<_>, _>>()?;
let argument_attributes = expr_call_args(Rc::clone(&scope), Rc::clone(&context), args)?;

if param_types.len() != argument_attributes.len() {
return Err(SemanticError::wrong_number_of_params());
Expand Down
1 change: 1 addition & 0 deletions analyzer/src/traversal/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,5 @@ mod declarations;
mod expressions;
mod functions;
pub mod module;
mod structs;
mod types;
Loading

0 comments on commit b1af6a5

Please sign in to comment.