diff options
| author | Martin Haug <mhaug@live.de> | 2021-05-29 12:25:10 +0200 |
|---|---|---|
| committer | Laurenz <laurmaedje@gmail.com> | 2021-05-31 22:33:40 +0200 |
| commit | 9f77f09aacd1fb0fd6138a6d16ed2755f6bfae3f (patch) | |
| tree | eba4a1609f178b3f2e6838ca9ee3c013e420621f /src/parse | |
| parent | 0bfee5b7772338fd39bbf708d3e31ea7bcec859b (diff) | |
Parse import and include expressions
Co-Authored-By: Laurenz <laurmaedje@gmail.com>
Diffstat (limited to 'src/parse')
| -rw-r--r-- | src/parse/mod.rs | 76 | ||||
| -rw-r--r-- | src/parse/parser.rs | 6 | ||||
| -rw-r--r-- | src/parse/tokens.rs | 6 |
3 files changed, 69 insertions, 19 deletions
diff --git a/src/parse/mod.rs b/src/parse/mod.rs index b4727fe9..9104b924 100644 --- a/src/parse/mod.rs +++ b/src/parse/mod.rs @@ -74,9 +74,15 @@ fn node(p: &mut Parser, at_start: &mut bool) -> Option<Node> { Token::UnicodeEscape(t) => Node::Text(unicode_escape(p, t)), // Hashtag + keyword / identifier. - Token::Ident(_) | Token::Let | Token::If | Token::While | Token::For => { + Token::Ident(_) + | Token::Let + | Token::If + | Token::While + | Token::For + | Token::Import + | Token::Include => { *at_start = false; - let stmt = token == Token::Let; + let stmt = token == Token::Let || token == Token::Import; let group = if stmt { Group::Stmt } else { Group::Expr }; p.start_group(group, TokenMode::Code); @@ -279,6 +285,8 @@ fn primary(p: &mut Parser, atomic: bool) -> Option<Expr> { Some(Token::If) => expr_if(p), Some(Token::While) => expr_while(p), Some(Token::For) => expr_for(p), + Some(Token::Import) => expr_import(p), + Some(Token::Include) => expr_include(p), // Nothing. _ => { @@ -331,7 +339,7 @@ fn parenthesized(p: &mut Parser) -> Option<Expr> { // Arrow means this is a closure's parameter list. if p.eat_if(Token::Arrow) { - let params = params(p, items); + let params = idents(p, items); let body = expr(p)?; return Some(Expr::Closure(ClosureExpr { span: span.join(body.span()), @@ -429,9 +437,9 @@ fn dict(p: &mut Parser, items: Vec<CallArg>, span: Span) -> Expr { Expr::Dict(DictExpr { span, items: items.collect() }) } -/// Convert a collection into a parameter list, producing errors for anything -/// other than identifiers. -fn params(p: &mut Parser, items: Vec<CallArg>) -> Vec<Ident> { +/// Convert a collection into a list of identifiers, producing errors for +/// anything other than identifiers. +fn idents(p: &mut Parser, items: Vec<CallArg>) -> Vec<Ident> { let items = items.into_iter().filter_map(|item| match item { CallArg::Pos(Expr::Ident(id)) => Some(id), _ => { @@ -511,24 +519,24 @@ fn expr_let(p: &mut Parser) -> Option<Expr> { let mut expr_let = None; if let Some(binding) = ident(p) { // If a parenthesis follows, this is a function definition. - let mut parameters = None; + let mut params = None; if p.peek_direct() == Some(Token::LeftParen) { p.start_group(Group::Paren, TokenMode::Code); let items = collection(p).0; - parameters = Some(params(p, items)); + params = Some(idents(p, items)); p.end_group(); } let mut init = None; if p.eat_if(Token::Eq) { init = expr(p); - } else if parameters.is_some() { + } else if params.is_some() { // Function definitions must have a body. p.expected_at("body", p.end()); } // Rewrite into a closure expression if it's a function definition. - if let Some(params) = parameters { + if let Some(params) = params { let body = init?; init = Some(Expr::Closure(ClosureExpr { span: binding.span.join(body.span()), @@ -548,6 +556,54 @@ fn expr_let(p: &mut Parser) -> Option<Expr> { expr_let } +/// Parse an import expression. +fn expr_import(p: &mut Parser) -> Option<Expr> { + let start = p.start(); + p.assert(Token::Import); + + let mut expr_import = None; + if let Some(path) = expr(p) { + if p.expect(Token::Using) { + let imports = if p.eat_if(Token::Star) { + // This is the wildcard scenario. + Imports::Wildcard + } else { + // This is the list of identifier scenario. + p.start_group(Group::Expr, TokenMode::Code); + let items = collection(p).0; + if items.is_empty() { + p.expected_at("import items", p.end()); + } + + let idents = idents(p, items); + p.end_group(); + Imports::Idents(idents) + }; + + expr_import = Some(Expr::Import(ImportExpr { + span: p.span(start), + imports, + path: Box::new(path), + })); + } + } + + expr_import +} + +/// Parse an include expression. +fn expr_include(p: &mut Parser) -> Option<Expr> { + let start = p.start(); + p.assert(Token::Include); + + expr(p).map(|path| { + Expr::Include(IncludeExpr { + span: p.span(start), + path: Box::new(path), + }) + }) +} + /// Parse an if expresion. fn expr_if(p: &mut Parser) -> Option<Expr> { let start = p.start(); diff --git a/src/parse/parser.rs b/src/parse/parser.rs index 729d0a8d..6269ad73 100644 --- a/src/parse/parser.rs +++ b/src/parse/parser.rs @@ -46,9 +46,6 @@ pub enum Group { Bracket, /// A curly-braced group: `{...}`. Brace, - /// A group ended by a chained subheader or a closing bracket: - /// `... >>`, `...]`. - Subheader, /// A group ended by a semicolon or a line break: `;`, `\n`. Stmt, /// A group for a single expression, ended by a line break. @@ -129,7 +126,6 @@ impl<'s> Parser<'s> { Group::Paren => self.assert(Token::LeftParen), Group::Bracket => self.assert(Token::LeftBracket), Group::Brace => self.assert(Token::LeftBrace), - Group::Subheader => {} Group::Stmt => {} Group::Expr => {} } @@ -152,7 +148,6 @@ impl<'s> Parser<'s> { Group::Paren => Some((Token::RightParen, true)), Group::Bracket => Some((Token::RightBracket, true)), Group::Brace => Some((Token::RightBrace, true)), - Group::Subheader => None, Group::Stmt => Some((Token::Semicolon, false)), Group::Expr => None, } { @@ -365,7 +360,6 @@ impl<'s> Parser<'s> { Token::RightBracket => self.inside(Group::Bracket), Token::RightBrace => self.inside(Group::Brace), Token::Semicolon => self.inside(Group::Stmt), - Token::Pipe => self.inside(Group::Subheader), Token::Space(n) => n >= 1 && self.stop_at_newline(), _ => false, } { diff --git a/src/parse/tokens.rs b/src/parse/tokens.rs index a57db93b..62d2e68e 100644 --- a/src/parse/tokens.rs +++ b/src/parse/tokens.rs @@ -124,7 +124,6 @@ impl<'s> Iterator for Tokens<'s> { ',' => Token::Comma, ';' => Token::Semicolon, ':' => Token::Colon, - '|' => Token::Pipe, '+' => Token::Plus, '-' => Token::Hyph, '*' => Token::Star, @@ -456,6 +455,9 @@ fn keyword(id: &str) -> Option<Token<'static>> { "break" => Token::Break, "continue" => Token::Continue, "return" => Token::Return, + "import" => Token::Import, + "include" => Token::Include, + "using" => Token::Using, _ => return None, }) } @@ -617,7 +619,6 @@ mod tests { t!(Code: "," => Comma); t!(Code: ";" => Semicolon); t!(Code: ":" => Colon); - t!(Code: "|" => Pipe); t!(Code: "+" => Plus); t!(Code: "-" => Hyph); t!(Code[" a1"]: "*" => Star); @@ -637,7 +638,6 @@ mod tests { t!(Code: "=>" => Arrow); // Test combinations. - t!(Code: "|=>" => Pipe, Arrow); t!(Code: "<=>" => LtEq, Gt); t!(Code[" a/"]: "..." => Dots, Invalid(".")); |
