Small improvements ♻

This commit is contained in:
Laurenz 2021-01-26 13:49:04 +01:00
parent ac788f2082
commit 16ac3f3ebc
7 changed files with 55 additions and 51 deletions

View File

@ -270,8 +270,8 @@ impl Spanned<&ExprBinary> {
// Short-circuit boolean operations. // Short-circuit boolean operations.
match (self.v.op.v, &lhs) { match (self.v.op.v, &lhs) {
(BinOp::And, Value::Bool(false)) => return Value::Bool(false), (BinOp::And, Value::Bool(false)) => return lhs,
(BinOp::Or, Value::Bool(true)) => return Value::Bool(true), (BinOp::Or, Value::Bool(true)) => return lhs,
_ => {} _ => {}
} }
@ -310,13 +310,11 @@ impl Spanned<&ExprBinary> {
let lhs = std::mem::replace(slot, Value::None); let lhs = std::mem::replace(slot, Value::None);
*slot = op(lhs, rhs); *slot = op(lhs, rhs);
return Value::None; return Value::None;
} else { } else if ctx.scopes.is_const(id) {
if ctx.scopes.is_const(id) {
ctx.diag(error!(span, "cannot assign to constant")); ctx.diag(error!(span, "cannot assign to constant"));
} else { } else {
ctx.diag(error!(span, "unknown variable")); ctx.diag(error!(span, "unknown variable"));
} }
}
} else { } else {
ctx.diag(error!(span, "cannot assign to this expression")); ctx.diag(error!(span, "cannot assign to this expression"));
} }

View File

@ -380,42 +380,50 @@ fn stmt_let(p: &mut Parser) -> Option<Expr> {
p.start_group(Group::Stmt, TokenMode::Code); p.start_group(Group::Stmt, TokenMode::Code);
p.eat_assert(Token::Let); p.eat_assert(Token::Let);
let pat = p.span_if(ident); let pat = match p.span_if(ident) {
let mut rhs = None; Some(pat) => pat,
None => {
if pat.is_some() { p.expected("identifier");
if p.eat_if(Token::Eq) { p.end_group();
rhs = p.span_if(expr); return None;
} }
};
let rhs = if p.eat_if(Token::Eq) { p.span_if(expr) } else { None };
if !p.eof() { if !p.eof() {
p.expected_at("semicolon or line break", p.last_end()); p.expected_at("semicolon or line break", p.last_end());
} }
} else {
p.expected("identifier");
}
p.end_group(); 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. /// Parse an if expresion.
fn expr_if(p: &mut Parser) -> Option<Expr> { fn expr_if(p: &mut Parser) -> Option<Expr> {
p.start_group(Group::Expr, TokenMode::Code); p.start_group(Group::Expr, TokenMode::Code);
p.eat_assert(Token::If); 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(); p.end_group();
let condition = Box::new(condition?);
let if_body = Box::new(control_body(p)?); let if_body = Box::new(control_body(p)?);
let end = p.last_end();
let start = p.last_end();
p.skip_white(); p.skip_white();
let else_body = if p.eat_if(Token::Else) { let else_body = if p.eat_if(Token::Else) {
control_body(p).map(Box::new) control_body(p).map(Box::new)
} else { } else {
p.jump(end); p.jump(start);
None None
}; };

View File

@ -127,7 +127,6 @@ impl<'s> Iterator for Tokens<'s> {
'=' => Token::Eq, '=' => Token::Eq,
'<' => Token::Lt, '<' => Token::Lt,
'>' => Token::Gt, '>' => Token::Gt,
'?' => Token::Question,
// Identifiers. // Identifiers.
c if is_id_start(c) => self.ident(start), c if is_id_start(c) => self.ident(start),
@ -206,7 +205,6 @@ impl<'s> Tokens<'s> {
"#if" => Token::If, "#if" => Token::If,
"#else" => Token::Else, "#else" => Token::Else,
"#for" => Token::For, "#for" => Token::For,
"#in" => Token::In,
"#while" => Token::While, "#while" => Token::While,
"#break" => Token::Break, "#break" => Token::Break,
"#continue" => Token::Continue, "#continue" => Token::Continue,
@ -612,7 +610,6 @@ mod tests {
t!(Code: "-=" => HyphEq); t!(Code: "-=" => HyphEq);
t!(Code: "*=" => StarEq); t!(Code: "*=" => StarEq);
t!(Code: "/=" => SlashEq); t!(Code: "/=" => SlashEq);
t!(Code: "?" => Question);
t!(Code: ".." => Dots); t!(Code: ".." => Dots);
t!(Code: "=>" => Arrow); t!(Code: "=>" => Arrow);
@ -636,7 +633,6 @@ mod tests {
("if", If), ("if", If),
("else", Else), ("else", Else),
("for", For), ("for", For),
("in", In),
("while", While), ("while", While),
("break", Break), ("break", Break),
("continue", Continue), ("continue", Continue),
@ -654,6 +650,7 @@ mod tests {
("not", Not), ("not", Not),
("and", And), ("and", And),
("or", Or), ("or", Or),
("in", In),
("none", Token::None), ("none", Token::None),
("false", Bool(false)), ("false", Bool(false)),
("true", Bool(true)), ("true", Bool(true)),

View File

@ -61,8 +61,6 @@ pub enum Token<'s> {
StarEq, StarEq,
/// A slash followed by an equals sign: `/=`. /// A slash followed by an equals sign: `/=`.
SlashEq, SlashEq,
/// A question mark: `?`.
Question,
/// Two dots: `..`. /// Two dots: `..`.
Dots, Dots,
/// An equals sign followed by a greater-than sign: `=>`. /// An equals sign followed by a greater-than sign: `=>`.
@ -212,30 +210,29 @@ impl<'s> Token<'s> {
Self::Eq => "assignment operator", Self::Eq => "assignment operator",
Self::EqEq => "equality operator", Self::EqEq => "equality operator",
Self::BangEq => "inequality operator", Self::BangEq => "inequality operator",
Self::Lt => "less than operator", Self::Lt => "less-than operator",
Self::LtEq => "less than or equal operator", Self::LtEq => "less-than or equal operator",
Self::Gt => "greater than operator", Self::Gt => "greater-than operator",
Self::GtEq => "greater than or equal operator", Self::GtEq => "greater-than or equal operator",
Self::PlusEq => "add-assign operator", Self::PlusEq => "add-assign operator",
Self::HyphEq => "subtract-assign operator", Self::HyphEq => "subtract-assign operator",
Self::StarEq => "multiply-assign operator", Self::StarEq => "multiply-assign operator",
Self::SlashEq => "divide-assign operator", Self::SlashEq => "divide-assign operator",
Self::Question => "question mark",
Self::Dots => "dots", Self::Dots => "dots",
Self::Arrow => "arrow", Self::Arrow => "arrow",
Self::Not => "not operator", Self::Not => "operator `not`",
Self::And => "and operator", Self::And => "operator `and`",
Self::Or => "or operator", Self::Or => "operator `or`",
Self::Let => "let keyword", Self::Let => "keyword `let`",
Self::If => "if keyword", Self::If => "keyword `if`",
Self::Else => "else keyword", Self::Else => "keyword `else`",
Self::For => "for keyword", Self::For => "keyword `for`",
Self::In => "in keyword", Self::In => "keyword `in`",
Self::While => "while keyword", Self::While => "keyword `while`",
Self::Break => "break keyword", Self::Break => "keyword `break`",
Self::Continue => "continue keyword", Self::Continue => "keyword `continue`",
Self::Return => "return keyword", Self::Return => "keyword `return`",
Self::None => "none", Self::None => "`none`",
Self::Space(_) => "space", Self::Space(_) => "space",
Self::Text(_) => "text", Self::Text(_) => "text",
Self::Raw(_) => "raw block", Self::Raw(_) => "raw block",

View File

@ -18,7 +18,7 @@
"Fi" + "ve" "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, // 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 // spacing after a simple if should be retained, but spacing between the first
// body and the else should be ignored. // body and the else should be ignored.
@ -53,7 +53,7 @@ a#if true {}
a#if true [b] #else c a#if true [b] #else c
// Lone else. // 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 // Error: 1:8-1:8 expected function name
#else [] #else []

View File

@ -28,11 +28,15 @@
// Error: 1:6-1:7 expected identifier, found integer // Error: 1:6-1:7 expected identifier, found integer
#let 1 = 2 #let 1 = 2
// Terminated by end of line before binding name. // Missing binding name.
// Error: 1:5-1:5 expected identifier // Error: 1:5-1:5 expected identifier
#let #let
x = 5 x = 5
// Missing right-hand side.
// Error: 1:9-1:9 expected expression
#let a =
// No name at all. // No name at all.
// Error: 1:11-1:11 expected identifier // Error: 1:11-1:11 expected identifier
The Fi#let;rst The Fi#let;rst

View File

@ -254,7 +254,7 @@ fn parse_metadata(src: &str, map: &LineMap) -> (bool, SpanVec<Diag>) {
let pos = |s: &mut Scanner| -> Pos { let pos = |s: &mut Scanner| -> Pos {
let (delta, _, column) = (num(s), s.eat_assert(':'), num(s)); let (delta, _, column) = (num(s), s.eat_assert(':'), num(s));
let line = i as u32 + 1 + delta; 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); let mut s = Scanner::new(rest);