Skip to content

Commit

Permalink
Merge pull request #425 from Y-Nak/generic-args
Browse files Browse the repository at this point in the history
Allow generic arguments in `Expr::Call`
  • Loading branch information
g-r-a-n-t committed May 27, 2021
2 parents d529b61 + 300a233 commit 1760025
Show file tree
Hide file tree
Showing 40 changed files with 392 additions and 281 deletions.
7 changes: 7 additions & 0 deletions Cargo.lock

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

28 changes: 9 additions & 19 deletions analyzer/src/namespace/types.rs
Expand Up @@ -251,20 +251,6 @@ impl Struct {
}
}

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

fn try_from(value: &str) -> Result<Self, Self::Error> {
if !value.starts_with("string") {
return Err("Value must start with 'string'".to_string());
}

let max_size = value[6..].parse::<u32>().map_err(|err| err.to_string())? as usize;

Ok(FeString { max_size })
}
}

impl Integer {
/// Returns `true` if the integer is signed, otherwise `false`
pub fn is_signed(&self) -> bool {
Expand Down Expand Up @@ -874,11 +860,7 @@ pub fn type_desc(defs: &BTreeMap<String, Type>, typ: &fe::TypeDesc) -> Result<Ty
"bytes" => Ok(Type::Base(Base::Byte)),
"address" => Ok(Type::Base(Base::Address)),
base => {
if base.starts_with("string") {
Ok(Type::String(
TryFrom::try_from(base).map_err(|_| SemanticError::type_error())?,
))
} else if let Some(typ) = defs.get(base) {
if let Some(typ) = defs.get(base) {
Ok(typ.clone())
} else {
Err(SemanticError::undefined_value())
Expand Down Expand Up @@ -907,6 +889,14 @@ pub fn type_desc(defs: &BTreeMap<String, Type>, typ: &fe::TypeDesc) -> Result<Ty
context: vec![],
}),
}
} else if base.kind == "String" {
match &args[..] {
[Node {
kind: fe::GenericArg::Int(len),
..
}] => Ok(Type::String(FeString { max_size: *len })),
_ => Err(SemanticError::type_error()),
}
} else {
Err(SemanticError::undefined_value())
}
Expand Down
58 changes: 34 additions & 24 deletions analyzer/src/traversal/expressions.rs
Expand Up @@ -18,7 +18,6 @@ use fe_common::numeric;
use fe_parser::ast as fe;
use fe_parser::node::Node;
use num_bigint::BigInt;
use std::convert::TryFrom;
use std::rc::Rc;
use std::str::FromStr;
use vec1::Vec1;
Expand Down Expand Up @@ -482,8 +481,13 @@ fn expr_call(
context: Shared<Context>,
exp: &Node<fe::Expr>,
) -> Result<ExpressionAttributes, SemanticError> {
if let fe::Expr::Call { func, args } = &exp.kind {
return match expr_call_type(Rc::clone(&scope), Rc::clone(&context), func)? {
if let fe::Expr::Call {
func,
generic_args,
args,
} = &exp.kind
{
return match expr_call_type(Rc::clone(&scope), Rc::clone(&context), func, &generic_args)? {
CallType::BuiltinFunction { func } => {
expr_call_builtin_function(scope, context, func, args)
}
Expand Down Expand Up @@ -830,9 +834,10 @@ fn expr_call_type(
scope: Shared<BlockScope>,
context: Shared<Context>,
func: &Node<fe::Expr>,
generic_args: &[Node<fe::GenericArg>],
) -> Result<CallType, SemanticError> {
let call_type = match &func.kind {
fe::Expr::Name(name) => expr_name_call_type(scope, Rc::clone(&context), name),
fe::Expr::Name(name) => expr_name_call_type(scope, Rc::clone(&context), name, generic_args),
fe::Expr::Attribute { .. } => expr_attribute_call_type(scope, Rc::clone(&context), func),
_ => Err(SemanticError::not_callable()),
}?;
Expand All @@ -845,56 +850,61 @@ fn expr_name_call_type(
scope: Shared<BlockScope>,
_context: Shared<Context>,
name: &str,
generic_args: &[Node<fe::GenericArg>],
) -> Result<CallType, SemanticError> {
match name {
"keccak256" => Ok(CallType::BuiltinFunction {
match (name, generic_args) {
("keccak256", _) => Ok(CallType::BuiltinFunction {
func: GlobalMethod::Keccak256,
}),
"address" => Ok(CallType::TypeConstructor {
("address", _) => Ok(CallType::TypeConstructor {
typ: Type::Base(Base::Address),
}),
"u256" => Ok(CallType::TypeConstructor {
("u256", _) => Ok(CallType::TypeConstructor {
typ: Type::Base(Base::Numeric(Integer::U256)),
}),
"u128" => Ok(CallType::TypeConstructor {
("u128", _) => Ok(CallType::TypeConstructor {
typ: Type::Base(Base::Numeric(Integer::U128)),
}),
"u64" => Ok(CallType::TypeConstructor {
("u64", _) => Ok(CallType::TypeConstructor {
typ: Type::Base(Base::Numeric(Integer::U64)),
}),
"u32" => Ok(CallType::TypeConstructor {
("u32", _) => Ok(CallType::TypeConstructor {
typ: Type::Base(Base::Numeric(Integer::U32)),
}),
"u16" => Ok(CallType::TypeConstructor {
("u16", _) => Ok(CallType::TypeConstructor {
typ: Type::Base(Base::Numeric(Integer::U16)),
}),
"u8" => Ok(CallType::TypeConstructor {
("u8", _) => Ok(CallType::TypeConstructor {
typ: Type::Base(Base::Numeric(Integer::U8)),
}),
"i256" => Ok(CallType::TypeConstructor {
("i256", _) => Ok(CallType::TypeConstructor {
typ: Type::Base(Base::Numeric(Integer::I256)),
}),
"i128" => Ok(CallType::TypeConstructor {
("i128", _) => Ok(CallType::TypeConstructor {
typ: Type::Base(Base::Numeric(Integer::I128)),
}),
"i64" => Ok(CallType::TypeConstructor {
("i64", _) => Ok(CallType::TypeConstructor {
typ: Type::Base(Base::Numeric(Integer::I64)),
}),
"i32" => Ok(CallType::TypeConstructor {
("i32", _) => Ok(CallType::TypeConstructor {
typ: Type::Base(Base::Numeric(Integer::I32)),
}),
"i16" => Ok(CallType::TypeConstructor {
("i16", _) => Ok(CallType::TypeConstructor {
typ: Type::Base(Base::Numeric(Integer::I16)),
}),
"i8" => Ok(CallType::TypeConstructor {
("i8", _) => Ok(CallType::TypeConstructor {
typ: Type::Base(Base::Numeric(Integer::I8)),
}),
value if value.starts_with("string") => Ok(CallType::TypeConstructor {
typ: Type::String(
TryFrom::try_from(value).map_err(|_| SemanticError::undefined_value())?,
),
(
"String",
[Node {
kind: fe::GenericArg::Int(len),
..
}],
) => Ok(CallType::TypeConstructor {
typ: Type::String(FeString { max_size: *len }),
}),
value => {
(value, _) => {
if let Some(typ) = scope.borrow().get_module_type_def(value) {
Ok(CallType::TypeConstructor { typ })
} else {
Expand Down
10 changes: 5 additions & 5 deletions analyzer/tests/fixtures/demos/erc20_token.fe
Expand Up @@ -4,8 +4,8 @@ contract ERC20:

_total_supply: u256

_name: string100
_symbol: string100
_name: String<100>
_symbol: String<100>
_decimals: u8

event Approval:
Expand All @@ -18,16 +18,16 @@ contract ERC20:
idx to: address
value: u256

pub def __init__(name: string100, symbol: string100):
pub def __init__(name: String<100>, symbol: String<100>):
self._name = name
self._symbol = symbol
self._decimals = u8(18)
self._mint(msg.sender, 1000000000000000000000000)

pub def name() -> string100:
pub def name() -> String<100>:
return self._name.to_mem()

pub def symbol() -> string100:
pub def symbol() -> String<100>:
return self._symbol.to_mem()

pub def decimals() -> u8:
Expand Down
2 changes: 1 addition & 1 deletion analyzer/tests/fixtures/features/assert.fe
Expand Up @@ -5,5 +5,5 @@ contract Foo:
pub def revert_with_static_string(baz: u256):
assert baz > 5, "Must be greater than five"

pub def revert_with(baz: u256, reason: string1000):
pub def revert_with(baz: u256, reason: String<1000>):
assert baz > 5, reason
6 changes: 3 additions & 3 deletions analyzer/tests/fixtures/features/external_contract.fe
Expand Up @@ -2,9 +2,9 @@ contract Foo:
event MyEvent:
my_num: u256
my_addrs: address[5]
my_string: string11
my_string: String<11>

pub def emit_event(my_num: u256, my_addrs: address[5], my_string: string11):
pub def emit_event(my_num: u256, my_addrs: address[5], my_string: String<11>):
emit MyEvent(my_num, my_addrs, my_string)

pub def build_array(a: u256, b: u256) -> u256[3]:
Expand All @@ -19,7 +19,7 @@ contract FooProxy:
foo_address: address,
my_num: u256,
my_addrs: address[5],
my_string: string11
my_string: String<11>
):
foo: Foo = Foo(foo_address)
foo.emit_event(my_num, my_addrs, my_string)
Expand Down
8 changes: 4 additions & 4 deletions analyzer/tests/fixtures/features/sized_vals_in_sto.fe
@@ -1,12 +1,12 @@
contract Foo:
num: u256
nums: u256[42]
str: string26
str: String<26>

event MyEvent:
num: u256
nums: u256[42]
str: string26
str: String<26>

pub def write_num(x: u256):
self.num = x
Expand All @@ -20,10 +20,10 @@ contract Foo:
pub def read_nums() -> u256[42]:
return self.nums.to_mem()

pub def write_str(x: string26):
pub def write_str(x: String<26>):
self.str = x

pub def read_str() -> string26:
pub def read_str() -> String<26>:
return self.str.to_mem()

pub def emit_event():
Expand Down
22 changes: 11 additions & 11 deletions analyzer/tests/fixtures/features/strings.fe
@@ -1,21 +1,21 @@
contract Foo:
event MyEvent:
s2: string26
s2: String<26>
u: u256
s1: string42
s3: string100
s1: String<42>
s3: String<100>
a: address
s4: string13
s5: string100
s4: String<13>
s5: String<100>

pub def __init__(s1: string42, a: address, s2: string26, u: u256, s3: string100):
emit MyEvent(s2, u, s1, s3, a, "static string", string100("foo"))
pub def __init__(s1: String<42>, a: address, s2: String<26>, u: u256, s3: String<100>):
emit MyEvent(s2, u, s1, s3, a, "static string", String<100>("foo"))

pub def bar(s1: string100, s2: string100) -> string100:
pub def bar(s1: String<100>, s2: String<100>) -> String<100>:
return s2

pub def return_static_string() -> string43:
pub def return_static_string() -> String<43>:
return "The quick brown fox jumps over the lazy dog"

pub def return_casted_static_string() -> string100:
return string100("foo")
pub def return_casted_static_string() -> String<100>:
return String<100>("foo")
8 changes: 4 additions & 4 deletions analyzer/tests/fixtures/stress/abi_encoding_stress.fe
Expand Up @@ -7,15 +7,15 @@ struct MyStruct:
contract Foo:
my_addrs: address[5]
my_u128: u128
my_string: string10
my_string: String<10>
my_u8s: u8[255]
my_bool: bool
my_bytes: bytes[100]

event MyEvent:
my_addrs: address[5]
my_u128: u128
my_string: string10
my_string: String<10>
my_u8s: u8[255]
my_bool: bool
my_bytes: bytes[100]
Expand All @@ -32,10 +32,10 @@ contract Foo:
pub def get_my_u128() -> u128:
return self.my_u128

pub def set_my_string(my_string: string10):
pub def set_my_string(my_string: String<10>):
self.my_string = my_string

pub def get_my_string() -> string10:
pub def get_my_string() -> String<10>:
return self.my_string.to_mem()

pub def set_my_u8s(my_u8s: u8[255]):
Expand Down
12 changes: 6 additions & 6 deletions analyzer/tests/fixtures/stress/data_copying_stress.fe
@@ -1,6 +1,6 @@
contract Foo:
my_string: string42
my_other_string: string42
my_string: String<42>
my_other_string: String<42>

my_u256: u256
my_other_u256: u256
Expand All @@ -10,12 +10,12 @@ contract Foo:
my_addrs: address[3]

event MyEvent:
my_string: string42
my_string: String<42>
my_u256: u256

pub def set_my_vals(
my_string: string42,
my_other_string: string42,
my_string: String<42>,
my_other_string: String<42>,
my_u256: u256,
my_other_u256: u256
):
Expand Down Expand Up @@ -70,7 +70,7 @@ contract Foo:
self.my_u256.to_mem()
)

def emit_my_event_internal(some_string: string42, some_u256: u256):
def emit_my_event_internal(some_string: String<42>, some_u256: u256):
emit MyEvent(some_string, some_u256)

pub def set_my_addrs(my_addrs: address[3]):
Expand Down

0 comments on commit 1760025

Please sign in to comment.