Skip to content

Commit

Permalink
Allow prefixes in any call path. (FuelLabs#472)
Browse files Browse the repository at this point in the history
* Test case and parsing.

* Better test case.

* First pass as structs.

* CallPath keeps track of if its an absolute path or not.

* Update license.

* Better test case.

* Implement for enums.

* Fix bug created during merge with master.

* Better test case.

* Fix clippy error.

* Implement for functions.

* Fix merge mistake.

* Fix bug.

* Fix cargo suggestion.

* Remove part of test case due to OOM error.

* Turn silent mode back on.

* Clippy suggestions.

* Pin lib version (FuelLabs#689)

Depends on FuelLabs#683

* Add clippy allow.

* Clippy suggestions.

* Clippy suggestions.

* Clippy suggestions.

* PR review feedback.

* Add verbose back.

* Add unintended test.

* Update test case.

Co-authored-by: John Adler <[email protected]>
Co-authored-by: John Adler <[email protected]>
  • Loading branch information
3 people authored Feb 23, 2022
1 parent 24bb7aa commit 24c879c
Show file tree
Hide file tree
Showing 36 changed files with 429 additions and 233 deletions.
3 changes: 1 addition & 2 deletions sway-core/src/asm_generation/expression/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -361,8 +361,7 @@ pub(crate) fn convert_expression_to_asm(
}
// ABI casts are purely compile-time constructs and generate no corresponding bytecode
TypedExpressionVariant::AbiCast { .. } => ok(vec![], warnings, errors),
a => {
println!("unimplemented: {:?}", a);
_ => {
errors.push(CompileError::Unimplemented(
"ASM generation has not yet been implemented for this.",
exp.span.clone(),
Expand Down
6 changes: 4 additions & 2 deletions sway-core/src/control_flow_analysis/dead_code_analysis.rs
Original file line number Diff line number Diff line change
Expand Up @@ -491,8 +491,9 @@ fn connect_trait_declaration(
) {
graph.namespace.add_trait(
CallPath {
suffix: decl.name.clone(),
prefixes: vec![],
suffix: decl.name.clone(),
is_absolute: false,
},
entry_node,
);
Expand All @@ -506,8 +507,9 @@ fn connect_abi_declaration(
) {
graph.namespace.add_trait(
CallPath {
suffix: decl.name.clone(),
prefixes: vec![],
suffix: decl.name.clone(),
is_absolute: false,
},
entry_node,
);
Expand Down
3 changes: 3 additions & 0 deletions sway-core/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -390,6 +390,8 @@ pub enum CompileError {
span: Span,
err: pest::error::Error<Rule>,
},
#[error("Error parsing input: {err:?}")]
ParseError { span: Span, err: String },
#[error(
"Invalid top-level item: {0:?}. A program should consist of a contract, script, or \
predicate at the top level."
Expand Down Expand Up @@ -929,6 +931,7 @@ impl CompileError {
Unimplemented(_, span) => span,
TypeError(err) => err.internal_span(),
ParseFailure { span, .. } => span,
ParseError { span, .. } => span,
InvalidTopLevelItem(_, span) => span,
Internal(_, span) => span,
InternalOwned(_, span) => span,
Expand Down
48 changes: 45 additions & 3 deletions sway-core/src/parse_tree/call_path.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,17 @@ use pest::iterators::Pair;
pub struct CallPath {
pub prefixes: Vec<Ident>,
pub suffix: Ident,
// If `is_absolute` is true, then this call path is an absolute path from
// the project root namespace. If not, then it is relative to the current namespace.
pub(crate) is_absolute: bool,
}

impl std::convert::From<Ident> for CallPath {
fn from(other: Ident) -> Self {
CallPath {
prefixes: vec![],
suffix: other,
is_absolute: false,
}
}
}
Expand Down Expand Up @@ -66,10 +70,31 @@ impl CallPath {
pair: Pair<Rule>,
config: Option<&BuildConfig>,
) -> CompileResult<CallPath> {
assert!(pair.as_rule() == Rule::call_path || pair.as_rule() == Rule::call_path_);
let mut warnings = vec![];
let mut errors = vec![];
let span = Span {
span: pair.as_span(),
path: config.map(|c| c.path()),
};
if !(pair.as_rule() == Rule::call_path || pair.as_rule() == Rule::call_path_) {
errors.push(CompileError::ParseError {
span,
err: "expected call path here".to_string(),
});
return err(warnings, errors);
}
let mut pairs_buf = vec![];
for pair in pair.into_inner() {
let stmt = pair.into_inner().next().unwrap();
let is_absolute = stmt.as_rule() == Rule::absolute_call_path
|| stmt.as_rule() == Rule::absolute_call_path_;
let stmt = stmt.into_inner();
let it = if is_absolute {
stmt.skip(1)
} else {
stmt.skip(0)
};
for pair in it {
if pair.as_rule() != Rule::path_separator {
pairs_buf.push(check!(
ident::parse_from_pair(pair, config),
Expand All @@ -83,7 +108,24 @@ impl CallPath {
let suffix = pairs_buf.pop().unwrap();
let prefixes = pairs_buf;

// TODO eventually we want to be able to call methods with colon-delineated syntax
ok(CallPath { prefixes, suffix }, warnings, errors)
ok(
CallPath {
prefixes,
suffix,
is_absolute,
},
warnings,
errors,
)
}

pub(crate) fn friendly_name(&self) -> String {
let mut buf = String::new();
for prefix in self.prefixes.iter() {
buf.push_str(prefix.as_str());
buf.push_str("::");
}
buf.push_str(self.suffix.as_str());
buf
}
}
1 change: 0 additions & 1 deletion sway-core/src/parse_tree/declaration/impl_trait.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,6 @@ impl ImplTrait {
let impl_keyword = iter.next().unwrap();
assert_eq!(impl_keyword.as_str(), "impl");
let trait_name = iter.next().unwrap();
assert_eq!(trait_name.as_rule(), Rule::trait_name);
let trait_name = check!(
CallPath::parse_from_pair(trait_name, config),
return err(warnings, errors),
Expand Down
1 change: 1 addition & 0 deletions sway-core/src/parse_tree/declaration/struct.rs
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ impl StructDeclaration {
span: name.as_span(),
path,
};

let name = check!(
ident::parse_from_pair(name, config),
return err(warnings, errors),
Expand Down
1 change: 0 additions & 1 deletion sway-core/src/parse_tree/expression/method_name.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ pub enum MethodName {
call_path: CallPath,
// if this is `None`, then use the first argument to determine the type
type_name: Option<TypeInfo>,
is_absolute: bool,
},
/// Represents a method lookup that does not contain any types in the path
FromModule { method_name: Ident },
Expand Down
84 changes: 53 additions & 31 deletions sway-core/src/parse_tree/expression/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ pub enum Expression {
span: Span,
},
StructExpression {
struct_name: Ident,
struct_name: CallPath,
fields: Vec<StructExpressionField>,
span: Span,
},
Expand Down Expand Up @@ -224,9 +224,9 @@ impl Expression {
span: span.clone(),
}
.to_var_name(),
is_absolute: true,
},
type_name: None,
is_absolute: true,
},
arguments,
span,
Expand All @@ -242,9 +242,9 @@ impl Expression {
Ident::new_with_override("ops", span.clone()),
],
suffix: op.to_var_name(),
is_absolute: true,
},
type_name: None,
is_absolute: true,
},
arguments,
span,
Expand Down Expand Up @@ -401,17 +401,13 @@ impl Expression {
};
let mut func_app_parts = expr.into_inner();
let first_part = func_app_parts.next().unwrap();
assert!(first_part.as_rule() == Rule::ident);
let suffix = check!(
ident::parse_from_pair(first_part, config),
assert!(first_part.as_rule() == Rule::call_path);
let name = check!(
CallPath::parse_from_pair(first_part, config),
return err(warnings, errors),
warnings,
errors
);
let name = CallPath {
prefixes: vec![],
suffix,
};
let (arguments, type_args) = {
let maybe_type_args = func_app_parts.next().unwrap();
match maybe_type_args.as_rule() {
Expand Down Expand Up @@ -538,7 +534,7 @@ impl Expression {
let mut expr_iter = expr.into_inner();
let struct_name = expr_iter.next().unwrap();
let struct_name = check!(
ident::parse_from_pair(struct_name, config),
CallPath::parse_from_pair(struct_name, config),
return err(warnings, errors),
warnings,
errors
Expand Down Expand Up @@ -751,16 +747,16 @@ impl Expression {
}
}
Rule::fully_qualified_method => {
let mut path_parts_buf = vec![];
let mut call_path = None;
let mut type_name = None;
let mut method_name = None;
let mut arguments = None;
for pair in pair.into_inner() {
match pair.as_rule() {
Rule::path_separator => (),
Rule::path_ident => {
path_parts_buf.push(check!(
ident::parse_from_pair(pair, config),
Rule::call_path => {
call_path = Some(check!(
CallPath::parse_from_pair(pair, config),
continue,
warnings,
errors
Expand Down Expand Up @@ -788,22 +784,48 @@ impl Expression {
errors
);

// parse the method name into a call path
let method_name = MethodName::FromType {
call_path: CallPath {
prefixes: path_parts_buf,
suffix: check!(
ident::parse_from_pair(
method_name.expect("guaranteed by grammar"),
config
),
return err(warnings, errors),
warnings,
errors
),
},
type_name: Some(type_name),
is_absolute: false,
let method_name = match call_path {
Some(call_path) => {
let mut call_path_buf = call_path.prefixes;
call_path_buf.push(call_path.suffix);

// parse the method name into a call path
MethodName::FromType {
call_path: CallPath {
prefixes: call_path_buf,
suffix: check!(
ident::parse_from_pair(
method_name.expect("guaranteed by grammar"),
config
),
return err(warnings, errors),
warnings,
errors
),
is_absolute: call_path.is_absolute, //is_absolute: false,
},
type_name: Some(type_name),
}
}
None => {
// parse the method name into a call path
MethodName::FromType {
call_path: CallPath {
prefixes: vec![],
suffix: check!(
ident::parse_from_pair(
method_name.expect("guaranteed by grammar"),
config
),
return err(warnings, errors),
warnings,
errors
),
is_absolute: false, //is_absolute: false,
},
type_name: Some(type_name),
}
}
};

let mut arguments_buf = vec![];
Expand Down
1 change: 1 addition & 0 deletions sway-core/src/parse_tree/expression/unary_op.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ impl UnaryOp {
Ident::new_with_override("ops", op_span.clone()),
],
suffix: Ident::new_with_override(self.to_var_name(), op_span),
is_absolute: false,
},
arguments: vec![arg],
span,
Expand Down
Loading

0 comments on commit 24c879c

Please sign in to comment.