Skip to content

Commit

Permalink
Support for self.address and bool operations
Browse files Browse the repository at this point in the history
  • Loading branch information
g-r-a-n-t committed Feb 26, 2021
1 parent f978266 commit fbac494
Show file tree
Hide file tree
Showing 11 changed files with 144 additions and 3 deletions.
6 changes: 6 additions & 0 deletions analyzer/src/builtins.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,3 +66,9 @@ pub enum TxField {
GasPrice,
Origin,
}

#[derive(Debug, PartialEq, EnumString)]
#[strum(serialize_all = "snake_case")]
pub enum SelfField {
Address,
}
38 changes: 37 additions & 1 deletion analyzer/src/traversal/expressions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ pub fn expr(
fe::Expr::Subscript { .. } => expr_subscript(scope, Rc::clone(&context), 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::BoolOperation { .. } => expr_bool_operation(scope, Rc::clone(&context), exp),
fe::Expr::BinOperation { .. } => expr_bin_operation(scope, Rc::clone(&context), exp),
fe::Expr::UnaryOperation { .. } => expr_unary_operation(scope, Rc::clone(&context), exp),
fe::Expr::CompOperation { .. } => expr_comp_operation(scope, Rc::clone(&context), exp),
Expand Down Expand Up @@ -358,6 +358,16 @@ fn expr_attribute_self(
scope: Shared<BlockScope>,
attr: &Spanned<&str>,
) -> Result<ExpressionAttributes, SemanticError> {
match builtins::SelfField::from_str(attr.node) {
Ok(builtins::SelfField::Address) => {
return Ok(ExpressionAttributes::new(
Type::Base(Base::Address),
Location::Value,
))
}
Err(_) => {}
}

match scope.borrow().contract_field_def(attr.node) {
Some(field) => Ok(ExpressionAttributes::new(
field.typ,
Expand Down Expand Up @@ -997,6 +1007,32 @@ fn expr_ternary(
unreachable!()
}

fn expr_bool_operation(
scope: Shared<BlockScope>,
context: Shared<Context>,
exp: &Spanned<fe::Expr>,
) -> Result<ExpressionAttributes, SemanticError> {
if let fe::Expr::BoolOperation {
left,
right,
..
} = &exp.node
{
let left_attributes = value_expr(Rc::clone(&scope), Rc::clone(&context), left)?;
let right_attributes = value_expr(Rc::clone(&scope), Rc::clone(&context), right)?;

let bool_ = Type::Base(Base::Bool);

return if left_attributes.typ == bool_ && right_attributes.typ == bool_ {
Ok(ExpressionAttributes::new(bool_, Location::Value))
} else {
Err(SemanticError::type_error())
};
}

unreachable!()
}

#[cfg(test)]
mod tests {
use crate::namespace::scopes::{
Expand Down
32 changes: 31 additions & 1 deletion compiler/src/yul/mappers/expressions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ use fe_parser::span::Spanned;
use std::convert::TryFrom;
use std::str::FromStr;
use yultsur::*;
use fe_parser::ast::BoolOperator;

/// Builds a Yul expression from a Fe expression.
pub fn expr(context: &Context, exp: &Spanned<fe::Expr>) -> Result<yul::Expression, CompileError> {
Expand All @@ -47,7 +48,7 @@ pub fn expr(context: &Context, exp: &Spanned<fe::Expr>) -> Result<yul::Expressio
fe::Expr::Subscript { .. } => expr_subscript(context, exp),
fe::Expr::Attribute { .. } => expr_attribute(context, exp),
fe::Expr::Ternary { .. } => expr_ternary(context, exp),
fe::Expr::BoolOperation { .. } => unimplemented!(),
fe::Expr::BoolOperation { .. } => expr_bool_operation(context, exp),
fe::Expr::BinOperation { .. } => expr_bin_operation(context, exp),
fe::Expr::UnaryOperation { .. } => expr_unary_operation(context, exp),
fe::Expr::CompOperation { .. } => expr_comp_operation(context, exp),
Expand Down Expand Up @@ -457,6 +458,13 @@ fn expr_attribute_self(
context: &Context,
exp: &Spanned<fe::Expr>,
) -> Result<yul::Expression, CompileError> {
if let fe::Expr::Attribute { attr, .. } = &exp.node {
match builtins::SelfField::from_str(attr.node) {
Ok(builtins::SelfField::Address) => return Ok(expression! { address() }),
Err(_) => {}
}
}

if let Some(attributes) = context.get_expression(exp) {
let nonce = if let Location::Storage { nonce: Some(nonce) } = attributes.location {
nonce
Expand Down Expand Up @@ -502,6 +510,28 @@ fn expr_ternary(
unreachable!()
}

fn expr_bool_operation(
context: &Context,
exp: &Spanned<fe::Expr>,
) -> Result<yul::Expression, CompileError> {
if let fe::Expr::BoolOperation {
left,
op,
right,
} = &exp.node
{
let yul_left = expr(context, left)?;
let yul_right = expr(context, right)?;

return match op.node {
BoolOperator::And => Ok(expression! {and([yul_left], [yul_right])}),
BoolOperator::Or => Ok(expression! {or([yul_left], [yul_right])})
};
}

unreachable!()
}

#[cfg(test)]
mod tests {
use crate::yul::mappers::expressions::{
Expand Down
4 changes: 3 additions & 1 deletion compiler/tests/compile_errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,9 @@ use std::fs;
"NumericCapacityMismatch"
),
case("external_call_type_error.fe", "TypeError"),
case("external_call_wrong_number_of_params.fe", "WrongNumberOfParams")
case("external_call_wrong_number_of_params.fe", "WrongNumberOfParams"),
case("non_bool_and.fe", "TypeError"),
case("non_bool_or.fe", "TypeError"),
)]
fn test_compile_errors(fixture_file: &str, expected_error: &str) {
let src = fs::read_to_string(format!("tests/fixtures/compile_errors/{}", fixture_file))
Expand Down
23 changes: 23 additions & 0 deletions compiler/tests/evm_contracts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,16 @@ fn test_assert() {
case("return_gte_i256.fe", &[int_token(-1), int_token(-2)], bool_token(true)),
case("return_gte_i256.fe", &[int_token(-1), int_token(-1)], bool_token(true)),
case("return_gte_i256.fe", &[int_token(-2), int_token(-1)], bool_token(false)),
// `and` bool operation
case("return_bool_op_and.fe", &[bool_token(true), bool_token(true)], bool_token(true)),
case("return_bool_op_and.fe", &[bool_token(true), bool_token(false)], bool_token(false)),
case("return_bool_op_and.fe", &[bool_token(false), bool_token(true)], bool_token(false)),
case("return_bool_op_and.fe", &[bool_token(false), bool_token(false)], bool_token(false)),
// `or` bool operation
case("return_bool_op_or.fe", &[bool_token(true), bool_token(true)], bool_token(true)),
case("return_bool_op_or.fe", &[bool_token(true), bool_token(false)], bool_token(true)),
case("return_bool_op_or.fe", &[bool_token(false), bool_token(true)], bool_token(true)),
case("return_bool_op_or.fe", &[bool_token(false), bool_token(false)], bool_token(false)),
)]
fn test_method_return(fixture_file: &str, input: &[ethabi::Token], expected: ethabi::Token) {
with_executor(&|mut executor| {
Expand Down Expand Up @@ -1215,3 +1225,16 @@ fn can_deploy_fixture(fixture_file: &str, contract_name: &str) {
deploy_contract(&mut executor, fixture_file, contract_name, &[]);
})
}

#[test]
fn self_address() {
with_executor(&|mut executor| {
let harness = deploy_contract(&mut executor, "self_address.fe", "Foo", &[]);
harness.test_function(
&mut executor,
"my_address",
&[],
Some(&ethabi::Token::Address(harness.address)),
);
});
}
3 changes: 3 additions & 0 deletions compiler/tests/fixtures/compile_errors/non_bool_and.fe
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
contract Foo:
pub def bar(x: bool, y: u256) -> bool:
return x and y
3 changes: 3 additions & 0 deletions compiler/tests/fixtures/compile_errors/non_bool_or.fe
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
contract Foo:
pub def bar(x: bool, y: u256) -> bool:
return y or x
3 changes: 3 additions & 0 deletions compiler/tests/fixtures/return_bool_op_and.fe
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
contract Foo:
pub def bar(x: bool, y: bool) -> bool:
return x and y
3 changes: 3 additions & 0 deletions compiler/tests/fixtures/return_bool_op_or.fe
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
contract Foo:
pub def bar(x: bool, y: bool) -> bool:
return x or y
3 changes: 3 additions & 0 deletions compiler/tests/fixtures/self_address.fe
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
contract Foo:
pub def my_address() -> address:
return self.address
29 changes: 29 additions & 0 deletions newsfragments/270.feature.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
Support for the boolean operations `and` and `or`.

Examples:

```
contract Foo:
pub def bar(x: bool, y: bool) -> bool:
return x and y
```

```
contract Foo:
pub def bar(x: bool, y: bool) -> bool:
return x or y
```

Support for `self.address`.

This expression returns the address of the current contract.

Example:

```
contract Foo:
pub def bar() -> address:
return self.address
```


0 comments on commit fbac494

Please sign in to comment.