summaryrefslogtreecommitdiff
path: root/src/parse/mod.rs
diff options
context:
space:
mode:
authorLaurenz <laurmaedje@gmail.com>2021-02-17 23:07:28 +0100
committerLaurenz <laurmaedje@gmail.com>2021-02-18 15:06:00 +0100
commit84cdc85ca7494368e7ce2039fcef06ac2d3bd2ed (patch)
tree4820cfbd853fd3e98953f3a23aa398f29761ab53 /src/parse/mod.rs
parente143fd36efaabfcfb42823fe5f7a25dd6de4a960 (diff)
Refresh parser 🌊
Diffstat (limited to 'src/parse/mod.rs')
-rw-r--r--src/parse/mod.rs231
1 files changed, 93 insertions, 138 deletions
diff --git a/src/parse/mod.rs b/src/parse/mod.rs
index e9cf2a60..1d3b8be7 100644
--- a/src/parse/mod.rs
+++ b/src/parse/mod.rs
@@ -70,8 +70,8 @@ fn node(p: &mut Parser, at_start: &mut bool) -> Option<Node> {
Token::Raw(t) => raw(p, t),
Token::UnicodeEscape(t) => Node::Text(unicode_escape(p, t)),
- // Keywords.
- Token::Let | Token::If | Token::For => {
+ // Hashtag + keyword / identifier.
+ Token::Ident(_) | Token::Let | Token::If | Token::For => {
*at_start = false;
let stmt = token == Token::Let;
let group = if stmt { Group::Stmt } else { Group::Expr };
@@ -100,12 +100,6 @@ fn node(p: &mut Parser, at_start: &mut bool) -> Option<Node> {
return Some(Node::Expr(template(p)));
}
- // Bracket function.
- Token::HashBracket => {
- *at_start = false;
- return Some(Node::Expr(bracket_call(p)?));
- }
-
// Comments.
Token::LineComment(_) | Token::BlockComment(_) => {
p.eat();
@@ -125,7 +119,7 @@ fn node(p: &mut Parser, at_start: &mut bool) -> Option<Node> {
/// Parse a heading.
fn heading(p: &mut Parser) -> Node {
let start = p.start();
- p.assert(&[Token::Eq]);
+ p.assert(Token::Eq);
// Count depth.
let mut level: usize = 0;
@@ -174,108 +168,6 @@ fn unicode_escape(p: &mut Parser, token: TokenUnicodeEscape) -> String {
text
}
-/// Parse a bracketed function call.
-fn bracket_call(p: &mut Parser) -> Option<Expr> {
- p.start_group(Group::Bracket, TokenMode::Code);
-
- // One header is guaranteed, but there may be more (through chaining).
- let mut outer = vec![];
- let mut inner = bracket_subheader(p);
- while p.eat_if(Token::Pipe) {
- if let Some(new) = bracket_subheader(p) {
- outer.extend(inner);
- inner = Some(new);
- }
- }
-
- p.end_group();
-
- let body = match p.peek() {
- Some(Token::LeftBracket) => Some(bracket_body(p)),
- _ => None,
- };
-
- let mut inner = inner?;
- if let Some(body) = body {
- inner.span.expand(body.span());
- inner.args.items.push(ExprArg::Pos(body));
- }
-
- while let Some(mut top) = outer.pop() {
- top.args.items.push(ExprArg::Pos(Expr::Call(inner)));
- inner = top;
- }
-
- Some(Expr::Call(inner))
-}
-
-/// Parse one subheader of a bracketed function call.
-fn bracket_subheader(p: &mut Parser) -> Option<ExprCall> {
- p.start_group(Group::Subheader, TokenMode::Code);
- let name = ident(p);
- let args = args(p);
- let span = p.end_group();
- Some(ExprCall {
- span,
- callee: Box::new(Expr::Ident(name?)),
- args,
- })
-}
-
-/// Parse the body of a bracketed function call.
-fn bracket_body(p: &mut Parser) -> Expr {
- p.start_group(Group::Bracket, TokenMode::Markup);
- let tree = Rc::new(tree(p));
- let span = p.end_group();
- Expr::Template(ExprTemplate { span, tree })
-}
-
-/// Parse an expression.
-fn expr(p: &mut Parser) -> Option<Expr> {
- expr_with(p, 0)
-}
-
-/// Parse an expression with operators having at least the minimum precedence.
-fn expr_with(p: &mut Parser, min_prec: usize) -> Option<Expr> {
- let start = p.start();
- let mut lhs = match p.eat_map(UnOp::from_token) {
- Some(op) => {
- let prec = op.precedence();
- let expr = Box::new(expr_with(p, prec)?);
- Expr::Unary(ExprUnary { span: p.span_from(start), op, expr })
- }
- None => primary(p)?,
- };
-
- loop {
- let op = match p.peek().and_then(BinOp::from_token) {
- Some(binop) => binop,
- None => break,
- };
-
- let mut prec = op.precedence();
- if prec < min_prec {
- break;
- }
-
- p.eat();
- match op.associativity() {
- Associativity::Left => prec += 1,
- Associativity::Right => {}
- }
-
- let rhs = match expr_with(p, prec) {
- Some(rhs) => Box::new(rhs),
- None => break,
- };
-
- let span = lhs.span().join(rhs.span());
- lhs = Expr::Binary(ExprBinary { span, lhs: Box::new(lhs), op, rhs });
- }
-
- Some(lhs)
-}
-
/// Parse a primary expression.
fn primary(p: &mut Parser) -> Option<Expr> {
if let Some(expr) = literal(p) {
@@ -289,10 +181,10 @@ fn primary(p: &mut Parser) -> Option<Expr> {
span: p.eat_span(),
string: string.into(),
};
- if p.peek() == Some(Token::LeftParen) {
- Some(paren_call(p, ident))
- } else {
- Some(Expr::Ident(ident))
+
+ match p.peek_direct() {
+ Some(Token::LeftParen) | Some(Token::LeftBracket) => Some(call(p, ident)),
+ _ => Some(Expr::Ident(ident)),
}
}
@@ -304,7 +196,6 @@ fn primary(p: &mut Parser) -> Option<Expr> {
// Structures.
Some(Token::LeftBrace) => block(p, true),
Some(Token::LeftBracket) => Some(template(p)),
- Some(Token::HashBracket) => bracket_call(p),
Some(Token::LeftParen) => Some(parenthesized(p)),
// Nothing.
@@ -327,7 +218,12 @@ fn literal(p: &mut Parser) -> Option<Expr> {
Token::Angle(val, unit) => LitKind::Angle(val, unit),
Token::Percent(p) => LitKind::Percent(p),
Token::Color(color) => LitKind::Color(color),
- Token::Str(token) => LitKind::Str(string(p, token)),
+ Token::Str(token) => LitKind::Str({
+ if !token.terminated {
+ p.expected_at("quote", p.peek_span().end);
+ }
+ resolve::resolve_string(token.string)
+ }),
_ => return None,
};
Some(Expr::Lit(Lit { span: p.eat_span(), kind }))
@@ -360,30 +256,83 @@ fn block(p: &mut Parser, scopes: bool) -> Option<Expr> {
Some(Expr::Block(ExprBlock { span, exprs, scoping: scopes }))
}
-/// Parse a parenthesized function call.
-fn paren_call(p: &mut Parser, name: Ident) -> Expr {
- p.start_group(Group::Paren, TokenMode::Code);
- let args = args(p);
- p.end_group();
+/// Parse an expression.
+fn expr(p: &mut Parser) -> Option<Expr> {
+ expr_with(p, 0)
+}
+
+/// Parse an expression with operators having at least the minimum precedence.
+fn expr_with(p: &mut Parser, min_prec: usize) -> Option<Expr> {
+ let start = p.start();
+ let mut lhs = match p.eat_map(UnOp::from_token) {
+ Some(op) => {
+ let prec = op.precedence();
+ let expr = Box::new(expr_with(p, prec)?);
+ Expr::Unary(ExprUnary { span: p.span(start), op, expr })
+ }
+ None => primary(p)?,
+ };
+
+ loop {
+ let op = match p.peek().and_then(BinOp::from_token) {
+ Some(binop) => binop,
+ None => break,
+ };
+
+ let mut prec = op.precedence();
+ if prec < min_prec {
+ break;
+ }
+
+ p.eat();
+ match op.associativity() {
+ Associativity::Left => prec += 1,
+ Associativity::Right => {}
+ }
+
+ let rhs = match expr_with(p, prec) {
+ Some(rhs) => Box::new(rhs),
+ None => break,
+ };
+
+ let span = lhs.span().join(rhs.span());
+ lhs = Expr::Binary(ExprBinary { span, lhs: Box::new(lhs), op, rhs });
+ }
+
+ Some(lhs)
+}
+
+/// Parse a function call.
+fn call(p: &mut Parser, name: Ident) -> Expr {
+ let mut args = match p.peek_direct() {
+ Some(Token::LeftParen) => {
+ p.start_group(Group::Paren, TokenMode::Code);
+ let args = args(p);
+ p.end_group();
+ args
+ }
+ _ => ExprArgs {
+ span: Span::at(name.span.end),
+ items: vec![],
+ },
+ };
+
+ if p.peek_direct() == Some(Token::LeftBracket) {
+ let body = template(p);
+ args.items.push(ExprArg::Pos(body));
+ }
+
Expr::Call(ExprCall {
- span: p.span_from(name.span.start),
+ span: p.span(name.span.start),
callee: Box::new(Expr::Ident(name)),
args,
})
}
-/// Parse a string.
-fn string(p: &mut Parser, token: TokenStr) -> String {
- if !token.terminated {
- p.expected_at("quote", p.peek_span().end);
- }
- resolve::resolve_string(token.string)
-}
-
/// Parse a let expression.
fn expr_let(p: &mut Parser) -> Option<Expr> {
let start = p.start();
- p.assert(&[Token::Let]);
+ p.assert(Token::Let);
let mut expr_let = None;
if let Some(binding) = ident(p) {
@@ -393,7 +342,7 @@ fn expr_let(p: &mut Parser) -> Option<Expr> {
}
expr_let = Some(Expr::Let(ExprLet {
- span: p.span_from(start),
+ span: p.span(start),
binding,
init: init.map(Box::new),
}))
@@ -405,18 +354,24 @@ fn expr_let(p: &mut Parser) -> Option<Expr> {
/// Parse an if expresion.
fn expr_if(p: &mut Parser) -> Option<Expr> {
let start = p.start();
- p.assert(&[Token::If]);
+ p.assert(Token::If);
let mut expr_if = None;
if let Some(condition) = expr(p) {
if let Some(if_body) = body(p) {
let mut else_body = None;
- if p.eat_if(Token::Else) {
+
+ // We are in code mode but still want to react to `#else` if the
+ // outer mode is markup.
+ if match p.outer_mode() {
+ TokenMode::Markup => p.eat_if(Token::Invalid("#else")),
+ TokenMode::Code => p.eat_if(Token::Else),
+ } {
else_body = body(p);
}
expr_if = Some(Expr::If(ExprIf {
- span: p.span_from(start),
+ span: p.span(start),
condition: Box::new(condition),
if_body: Box::new(if_body),
else_body: else_body.map(Box::new),
@@ -430,7 +385,7 @@ fn expr_if(p: &mut Parser) -> Option<Expr> {
/// Parse a for expression.
fn expr_for(p: &mut Parser) -> Option<Expr> {
let start = p.start();
- p.assert(&[Token::For]);
+ p.assert(Token::For);
let mut expr_for = None;
if let Some(pattern) = for_pattern(p) {
@@ -438,7 +393,7 @@ fn expr_for(p: &mut Parser) -> Option<Expr> {
if let Some(iter) = expr(p) {
if let Some(body) = body(p) {
expr_for = Some(Expr::For(ExprFor {
- span: p.span_from(start),
+ span: p.span(start),
pattern,
iter: Box::new(iter),
body: Box::new(body),