summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLaurenz <laurmaedje@gmail.com>2021-01-26 13:49:04 +0100
committerLaurenz <laurmaedje@gmail.com>2021-01-26 13:49:04 +0100
commit16ac3f3ebc49c5a6e3f61d8546f2f187b191c346 (patch)
tree7b66f108f23c64614a507e2815f706ceb72df157
parentac788f2082711161ec8208eede04d9a2bae02241 (diff)
Small improvements ♻
-rw-r--r--src/eval/mod.rs12
-rw-r--r--src/parse/mod.rs40
-rw-r--r--src/parse/tokens.rs5
-rw-r--r--src/syntax/token.rs37
-rw-r--r--tests/lang/typ/if.typ4
-rw-r--r--tests/lang/typ/let.typ6
-rw-r--r--tests/typeset.rs2
7 files changed, 55 insertions, 51 deletions
diff --git a/src/eval/mod.rs b/src/eval/mod.rs
index c604f2d0..8563520e 100644
--- a/src/eval/mod.rs
+++ b/src/eval/mod.rs
@@ -270,8 +270,8 @@ impl Spanned<&ExprBinary> {
// Short-circuit boolean operations.
match (self.v.op.v, &lhs) {
- (BinOp::And, Value::Bool(false)) => return Value::Bool(false),
- (BinOp::Or, Value::Bool(true)) => return Value::Bool(true),
+ (BinOp::And, Value::Bool(false)) => return lhs,
+ (BinOp::Or, Value::Bool(true)) => return lhs,
_ => {}
}
@@ -310,12 +310,10 @@ impl Spanned<&ExprBinary> {
let lhs = std::mem::replace(slot, Value::None);
*slot = op(lhs, rhs);
return Value::None;
+ } else if ctx.scopes.is_const(id) {
+ ctx.diag(error!(span, "cannot assign to constant"));
} else {
- if ctx.scopes.is_const(id) {
- ctx.diag(error!(span, "cannot assign to constant"));
- } else {
- ctx.diag(error!(span, "unknown variable"));
- }
+ ctx.diag(error!(span, "unknown variable"));
}
} else {
ctx.diag(error!(span, "cannot assign to this expression"));
diff --git a/src/parse/mod.rs b/src/parse/mod.rs
index 00512c3f..9fe8e62e 100644
--- a/src/parse/mod.rs
+++ b/src/parse/mod.rs
@@ -380,42 +380,50 @@ fn stmt_let(p: &mut Parser) -> Option<Expr> {
p.start_group(Group::Stmt, TokenMode::Code);
p.eat_assert(Token::Let);
- let pat = p.span_if(ident);
- let mut rhs = None;
-
- if pat.is_some() {
- if p.eat_if(Token::Eq) {
- rhs = p.span_if(expr);
+ let pat = match p.span_if(ident) {
+ Some(pat) => pat,
+ None => {
+ p.expected("identifier");
+ p.end_group();
+ return None;
}
+ };
- if !p.eof() {
- p.expected_at("semicolon or line break", p.last_end());
- }
- } else {
- p.expected("identifier");
+ let rhs = if p.eat_if(Token::Eq) { p.span_if(expr) } else { None };
+
+ if !p.eof() {
+ p.expected_at("semicolon or line break", p.last_end());
}
p.end_group();
- Some(Expr::Let(ExprLet { pat: pat?, expr: rhs.map(Box::new) }))
+ Some(Expr::Let(ExprLet { pat, expr: rhs.map(Box::new) }))
}
/// Parse an if expresion.
fn expr_if(p: &mut Parser) -> Option<Expr> {
p.start_group(Group::Expr, TokenMode::Code);
p.eat_assert(Token::If);
- let condition = p.span_if(expr);
+
+ let condition = match p.span_if(expr) {
+ Some(condition) => Box::new(condition),
+ None => {
+ p.end_group();
+ return None;
+ }
+ };
+
p.end_group();
- let condition = Box::new(condition?);
let if_body = Box::new(control_body(p)?);
- let end = p.last_end();
+
+ let start = p.last_end();
p.skip_white();
let else_body = if p.eat_if(Token::Else) {
control_body(p).map(Box::new)
} else {
- p.jump(end);
+ p.jump(start);
None
};
diff --git a/src/parse/tokens.rs b/src/parse/tokens.rs
index 312e941b..f5e5baaf 100644
--- a/src/parse/tokens.rs
+++ b/src/parse/tokens.rs
@@ -127,7 +127,6 @@ impl<'s> Iterator for Tokens<'s> {
'=' => Token::Eq,
'<' => Token::Lt,
'>' => Token::Gt,
- '?' => Token::Question,
// Identifiers.
c if is_id_start(c) => self.ident(start),
@@ -206,7 +205,6 @@ impl<'s> Tokens<'s> {
"#if" => Token::If,
"#else" => Token::Else,
"#for" => Token::For,
- "#in" => Token::In,
"#while" => Token::While,
"#break" => Token::Break,
"#continue" => Token::Continue,
@@ -612,7 +610,6 @@ mod tests {
t!(Code: "-=" => HyphEq);
t!(Code: "*=" => StarEq);
t!(Code: "/=" => SlashEq);
- t!(Code: "?" => Question);
t!(Code: ".." => Dots);
t!(Code: "=>" => Arrow);
@@ -636,7 +633,6 @@ mod tests {
("if", If),
("else", Else),
("for", For),
- ("in", In),
("while", While),
("break", Break),
("continue", Continue),
@@ -654,6 +650,7 @@ mod tests {
("not", Not),
("and", And),
("or", Or),
+ ("in", In),
("none", Token::None),
("false", Bool(false)),
("true", Bool(true)),
diff --git a/src/syntax/token.rs b/src/syntax/token.rs
index 43415198..432b4dc5 100644
--- a/src/syntax/token.rs
+++ b/src/syntax/token.rs
@@ -61,8 +61,6 @@ pub enum Token<'s> {
StarEq,
/// A slash followed by an equals sign: `/=`.
SlashEq,
- /// A question mark: `?`.
- Question,
/// Two dots: `..`.
Dots,
/// An equals sign followed by a greater-than sign: `=>`.
@@ -212,30 +210,29 @@ impl<'s> Token<'s> {
Self::Eq => "assignment operator",
Self::EqEq => "equality operator",
Self::BangEq => "inequality operator",
- Self::Lt => "less than operator",
- Self::LtEq => "less than or equal operator",
- Self::Gt => "greater than operator",
- Self::GtEq => "greater than or equal operator",
+ Self::Lt => "less-than operator",
+ Self::LtEq => "less-than or equal operator",
+ Self::Gt => "greater-than operator",
+ Self::GtEq => "greater-than or equal operator",
Self::PlusEq => "add-assign operator",
Self::HyphEq => "subtract-assign operator",
Self::StarEq => "multiply-assign operator",
Self::SlashEq => "divide-assign operator",
- Self::Question => "question mark",
Self::Dots => "dots",
Self::Arrow => "arrow",
- Self::Not => "not operator",
- Self::And => "and operator",
- Self::Or => "or operator",
- Self::Let => "let keyword",
- Self::If => "if keyword",
- Self::Else => "else keyword",
- Self::For => "for keyword",
- Self::In => "in keyword",
- Self::While => "while keyword",
- Self::Break => "break keyword",
- Self::Continue => "continue keyword",
- Self::Return => "return keyword",
- Self::None => "none",
+ Self::Not => "operator `not`",
+ Self::And => "operator `and`",
+ Self::Or => "operator `or`",
+ Self::Let => "keyword `let`",
+ Self::If => "keyword `if`",
+ Self::Else => "keyword `else`",
+ Self::For => "keyword `for`",
+ Self::In => "keyword `in`",
+ Self::While => "keyword `while`",
+ Self::Break => "keyword `break`",
+ Self::Continue => "keyword `continue`",
+ Self::Return => "keyword `return`",
+ Self::None => "`none`",
Self::Space(_) => "space",
Self::Text(_) => "text",
Self::Raw(_) => "raw block",
diff --git a/tests/lang/typ/if.typ b/tests/lang/typ/if.typ
index 5f4c986a..f7de7716 100644
--- a/tests/lang/typ/if.typ
+++ b/tests/lang/typ/if.typ
@@ -18,7 +18,7 @@
"Fi" + "ve"
}
-// Spacing is somewhat delicated. We only want to have spacing in the output if
+// Spacing is somewhat delicate. We only want to have spacing in the output if
// there was whitespace before/after the full if-else statement. In particular,
// spacing after a simple if should be retained, but spacing between the first
// body and the else should be ignored.
@@ -53,7 +53,7 @@ a#if true {}
a#if true [b] #else c
// Lone else.
-// Error: 2:1-2:6 unexpected else keyword
+// Error: 2:1-2:6 unexpected keyword `else`
// Error: 1:8-1:8 expected function name
#else []
diff --git a/tests/lang/typ/let.typ b/tests/lang/typ/let.typ
index 7e9246bb..b3eadeaa 100644
--- a/tests/lang/typ/let.typ
+++ b/tests/lang/typ/let.typ
@@ -28,11 +28,15 @@
// Error: 1:6-1:7 expected identifier, found integer
#let 1 = 2
-// Terminated by end of line before binding name.
+// Missing binding name.
// Error: 1:5-1:5 expected identifier
#let
x = 5
+// Missing right-hand side.
+// Error: 1:9-1:9 expected expression
+#let a =
+
// No name at all.
// Error: 1:11-1:11 expected identifier
The Fi#let;rst
diff --git a/tests/typeset.rs b/tests/typeset.rs
index dbcb6517..620e11a6 100644
--- a/tests/typeset.rs
+++ b/tests/typeset.rs
@@ -254,7 +254,7 @@ fn parse_metadata(src: &str, map: &LineMap) -> (bool, SpanVec<Diag>) {
let pos = |s: &mut Scanner| -> Pos {
let (delta, _, column) = (num(s), s.eat_assert(':'), num(s));
let line = i as u32 + 1 + delta;
- map.pos(Location { line, column }).unwrap()
+ map.pos(Location::new(line, column)).unwrap()
};
let mut s = Scanner::new(rest);