Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
cburgdorf committed May 2, 2022
1 parent a9dcf95 commit 1ccbdc9
Show file tree
Hide file tree
Showing 11 changed files with 334 additions and 13 deletions.
2 changes: 2 additions & 0 deletions crates/lowering/src/mappers/functions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ pub fn func_def(context: &mut ModuleContext, function: FunctionId) -> Node<fe::F
unsafe_,
name,
args,
generic_params,
return_type: return_type_node,
body,
} = &node.kind;
Expand Down Expand Up @@ -113,6 +114,7 @@ pub fn func_def(context: &mut ModuleContext, function: FunctionId) -> Node<fe::F
unsafe_: *unsafe_,
name: name.clone(),
args,
generic_params: generic_params.clone(),
return_type: Some(lowered_return_type),
body: lowered_body,
};
Expand Down
1 change: 1 addition & 0 deletions crates/lowering/src/mappers/module.rs
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,7 @@ fn list_expr_to_fn_def(array: &Array) -> ast::Function {
unsafe_: None,
name: names::list_expr_generator_fn_name(array).into_node(),
args,
generic_params: Vec::new().into_node(),
return_type,
body: [vec![var_decl], assignments, vec![return_stmt]].concat(),
}
Expand Down
19 changes: 19 additions & 0 deletions crates/parser/src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,24 @@ impl Spanned for GenericArg {
}
}

#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Hash, Clone)]
pub enum GenericParameter {
Unbounded(Node<SmolStr>),
Bounded {
name: Node<SmolStr>,
bound: Node<SmolStr>,
},
}

impl Spanned for GenericParameter {
fn span(&self) -> Span {
match self {
GenericParameter::Unbounded(node) => node.span,
GenericParameter::Bounded { name, bound } => name.span + bound.span,
}
}
}

/// struct or contract field, with optional 'pub' and 'const' qualifiers
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Hash, Clone)]
pub struct Field {
Expand Down Expand Up @@ -160,6 +178,7 @@ pub struct Function {
pub pub_: Option<Span>,
pub unsafe_: Option<Span>,
pub name: Node<SmolStr>,
pub generic_params: Node<Vec<GenericParameter>>,
pub args: Vec<Node<FunctionArg>>,
pub return_type: Option<Node<TypeDesc>>,
pub body: Vec<Node<FuncStmt>>,
Expand Down
97 changes: 93 additions & 4 deletions crates/parser/src/grammar/functions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@ use super::expressions::{parse_call_args, parse_expr};
use super::types::parse_type_desc;

use crate::ast::{
BinOperator, Expr, FuncStmt, Function, FunctionArg, RegularFunctionArg, VarDeclTarget,
BinOperator, Expr, FuncStmt, Function, FunctionArg, GenericParameter, RegularFunctionArg,
VarDeclTarget,
};
use crate::lexer::TokenKind;
use crate::node::{Node, Span};
use crate::{Label, ParseFailed, ParseResult, Parser};
use crate::{Label, ParseFailed, ParseResult, Parser, TokenKind};

/// Parse a function definition. The optional `pub` qualifier must be parsed by
/// the caller, and passed in. Next token must be `unsafe` or `fn`.
Expand All @@ -28,7 +28,14 @@ pub fn parse_fn_def(par: &mut Parser, mut pub_qual: Option<Span>) -> ParseResult
}
let fn_tok = par.expect(TokenKind::Fn, "failed to parse function definition")?;
let name = par.expect(TokenKind::Name, "failed to parse function definition")?;
let mut span = fn_tok.span + unsafe_qual + pub_qual + name.span;

let generic_params = if par.peek() == Some(TokenKind::Lt) {
parse_generic_params(par)?
} else {
Node::new(vec![], name.span)
};

let mut span = fn_tok.span + unsafe_qual + pub_qual + name.span + generic_params.span;

let args = match par.peek_or_err()? {
TokenKind::ParenOpen => {
Expand Down Expand Up @@ -87,13 +94,95 @@ pub fn parse_fn_def(par: &mut Parser, mut pub_qual: Option<Span>) -> ParseResult
unsafe_: unsafe_qual,
name: name.into(),
args,
generic_params,
return_type,
body,
},
span,
))
}

pub fn parse_generic_param(par: &mut Parser) -> ParseResult<GenericParameter> {
use TokenKind::*;

let name = par.assert(Name);
match par.optional(Colon) {
Some(_) => {
let bound = par.assert(Name);
return Ok(GenericParameter::Bounded {
name: Node::new(name.text.into(), name.span),
bound: Node::new(bound.text.into(), bound.span),
});
}
None => {
return Ok(GenericParameter::Unbounded(Node::new(
name.text.into(),
name.span,
)))
}
}
}

/// Parse an angle-bracket-wrapped list of generic arguments (eg. the part wrapped in angle brackets
/// of `fn foo<T: SomeTrait>(some_arg: u256) -> bool`).
/// # Panics
/// Panics if the first token isn't `<`.
pub fn parse_generic_params(par: &mut Parser) -> ParseResult<Node<Vec<GenericParameter>>> {
use TokenKind::*;
let mut span = par.assert(Lt).span;

let mut args = vec![];

let expect_end = |par: &mut Parser| {
// If there's no comma, the next token must be `>`
match par.peek_or_err()? {
Gt => Ok(par.next()?.span),
_ => {
let tok = par.next()?;
par.unexpected_token_error(
tok.span,
"Unexpected token while parsing generic arg list",
vec![],
);
Err(ParseFailed)
}
}
};



loop {
match par.peek_or_err()? {
Gt => {
span += par.next()?.span;
break;
}
Name => {
let typ = parse_generic_param(par)?;
args.push(typ);
if par.peek() == Some(Comma) {
par.next()?;
} else {
span += expect_end(par)?;
break;
}
}

// Invalid generic argument.
_ => {
let tok = par.next()?;
par.unexpected_token_error(
tok.span,
"failed to parse generic type argument list",
vec![],
);
return Err(ParseFailed);
}
}
}
Ok(Node::new(args, span))
}

fn parse_fn_param_list(par: &mut Parser) -> ParseResult<Node<Vec<Node<FunctionArg>>>> {
let mut span = par.assert(TokenKind::ParenOpen).span;
let mut params = vec![];
Expand Down
6 changes: 1 addition & 5 deletions crates/parser/src/grammar/traits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,7 @@ use crate::{ParseFailed, ParseResult, Parser, TokenKind};
/// Parse a trait definition.
/// # Panics
/// Panics if the next token isn't `trait`.
pub fn parse_trait_def(
par: &mut Parser,
trait_pub_qual: Option<Span>,
) -> ParseResult<Node<Trait>> {
pub fn parse_trait_def(par: &mut Parser, trait_pub_qual: Option<Span>) -> ParseResult<Node<Trait>> {
let trait_tok = par.assert(TokenKind::Trait);

// trait Event:
Expand All @@ -26,7 +23,6 @@ pub fn parse_trait_def(
par.enter_block(header_span, "trait definition")?;

loop {

match par.peek() {
Some(TokenKind::Pass) => {
parse_single_word_stmt(par)?;
Expand Down
2 changes: 2 additions & 0 deletions crates/parser/tests/cases/parse_ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,8 @@ test_parse! { type_tuple, types::parse_type_desc, "(u8, u16, address, Map<u8, u8
test_parse! { type_unit, types::parse_type_desc, "()" }

test_parse! { fn_def, try_parse_module, "fn transfer(from sender: address, to recip: address, _ val: u64) -> bool:\n false"}

test_parse! { fn_def_generic, try_parse_module, "fn transfer<T, R: Event>(from sender: address, to recip: address, _ val: u64) -> bool:\n false"}
test_parse! { fn_def_pub, try_parse_module, "pub fn foo21(x: bool, y: address,) -> bool:\n x"}
test_parse! { fn_def_unsafe, try_parse_module, "unsafe fn foo21(x: bool, y: address,) -> bool:\n x"}
test_parse! { fn_def_pub_unsafe, try_parse_module, "pub unsafe fn foo21(x: bool, y: address,) -> bool:\n x"}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
source: crates/parser/tests/cases/parse_ast.rs
expression: "ast_string(stringify!(fn_def), try_parse_module,\n \"fn transfer(from sender: address, to recip: address, _ val: u64) -> bool:\\n false\")"
expression: "ast_string(stringify!(fn_def), try_parse_module,\n \"fn transfer(from sender: address, to recip: address, _ val: u64) -> bool:\\n false\")"

---
Node(
Expand All @@ -17,6 +17,13 @@ Node(
end: 11,
),
),
generic_params: Node(
kind: [],
span: Span(
start: 3,
end: 11,
),
),
args: [
Node(
kind: Regular(RegularFunctionArg(
Expand Down
Loading

0 comments on commit 1ccbdc9

Please sign in to comment.