mirror of
https://github.com/Noratrieb/dilaria.git
synced 2026-01-16 18:35:02 +01:00
better errors
This commit is contained in:
parent
c6e5a5d686
commit
67e6dfccc2
4 changed files with 152 additions and 43 deletions
|
|
@ -66,7 +66,8 @@
|
||||||
|
|
||||||
<unary> ::= { ( "not" | "-" ) } <primary>
|
<unary> ::= { ( "not" | "-" ) } <primary>
|
||||||
|
|
||||||
<primary> ::= <NUMBER>
|
<primary> ::= <IDENT>
|
||||||
|
| <NUMBER>
|
||||||
| <STRING>
|
| <STRING>
|
||||||
| <object-literal>
|
| <object-literal>
|
||||||
| <array-literal>
|
| <array-literal>
|
||||||
|
|
|
||||||
|
|
@ -76,6 +76,7 @@ pub struct Break {
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub enum Expr {
|
pub enum Expr {
|
||||||
|
Ident(Symbol, Span),
|
||||||
Literal(Literal),
|
Literal(Literal),
|
||||||
UnaryOp(Box<UnaryOp>),
|
UnaryOp(Box<UnaryOp>),
|
||||||
BinaryOp(Box<BinaryOp>),
|
BinaryOp(Box<BinaryOp>),
|
||||||
|
|
@ -87,6 +88,7 @@ impl Expr {
|
||||||
Expr::Literal(lit) => lit.span(),
|
Expr::Literal(lit) => lit.span(),
|
||||||
Expr::UnaryOp(unary) => unary.span,
|
Expr::UnaryOp(unary) => unary.span,
|
||||||
Expr::BinaryOp(binary) => binary.span,
|
Expr::BinaryOp(binary) => binary.span,
|
||||||
|
Expr::Ident(_, span) => *span,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
188
src/parse.rs
188
src/parse.rs
|
|
@ -181,8 +181,16 @@ impl<'code> Parser<'code> {
|
||||||
TokenType::Null => Ok(Expr::Literal(Literal::Null(next.span))),
|
TokenType::Null => Ok(Expr::Literal(Literal::Null(next.span))),
|
||||||
TokenType::BraceO => self.object_literal(next.span),
|
TokenType::BraceO => self.object_literal(next.span),
|
||||||
TokenType::BracketO => self.array_literal(next.span),
|
TokenType::BracketO => self.array_literal(next.span),
|
||||||
TokenType::ParenO => todo!(),
|
TokenType::ParenO => {
|
||||||
_ => todo!(),
|
let expr = self.expression()?;
|
||||||
|
let _ = self.expect(TokenType::ParenC)?;
|
||||||
|
Ok(expr)
|
||||||
|
}
|
||||||
|
TokenType::Ident(name) => {
|
||||||
|
let name_owned = name.to_owned();
|
||||||
|
Ok(Expr::Ident(name_owned, next.span))
|
||||||
|
}
|
||||||
|
_ => Err(ParseErr::InvalidTokenPrimary(next)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -193,7 +201,12 @@ impl<'code> Parser<'code> {
|
||||||
|
|
||||||
fn array_literal(&mut self, open_span: Span) -> ParseResult<'code, Expr> {
|
fn array_literal(&mut self, open_span: Span) -> ParseResult<'code, Expr> {
|
||||||
let mut elements = Vec::new();
|
let mut elements = Vec::new();
|
||||||
while self.peek().ok_or(ParseErr::EOF("array literal"))?.kind != TokenType::BracketC {
|
while self
|
||||||
|
.peek()
|
||||||
|
.ok_or(ParseErr::EOFExpecting(TokenType::BracketC))?
|
||||||
|
.kind
|
||||||
|
!= TokenType::BracketC
|
||||||
|
{
|
||||||
let expr = self.expression()?;
|
let expr = self.expression()?;
|
||||||
elements.push(expr);
|
elements.push(expr);
|
||||||
self.expect(TokenType::Comma)?;
|
self.expect(TokenType::Comma)?;
|
||||||
|
|
@ -222,32 +235,60 @@ impl<'code> Parser<'code> {
|
||||||
if token.kind == kind {
|
if token.kind == kind {
|
||||||
Ok(token)
|
Ok(token)
|
||||||
} else {
|
} else {
|
||||||
Err(ParseErr::MismatchedKind { expected: kind })
|
Err(ParseErr::MismatchedKind {
|
||||||
|
expected: kind,
|
||||||
|
actual: token,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Err(ParseErr::ExpectedToken(kind))
|
Err(ParseErr::EOFExpecting(kind))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum ParseErr<'code> {
|
pub enum ParseErr<'code> {
|
||||||
MismatchedKind { expected: TokenType<'code> },
|
MismatchedKind {
|
||||||
ExpectedToken(TokenType<'code>),
|
expected: TokenType<'code>,
|
||||||
|
actual: Token<'code>,
|
||||||
|
},
|
||||||
|
InvalidTokenPrimary(Token<'code>),
|
||||||
|
EOFExpecting(TokenType<'code>),
|
||||||
EOF(&'static str),
|
EOF(&'static str),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CompilerError for ParseErr<'_> {
|
impl CompilerError for ParseErr<'_> {
|
||||||
fn span(&self) -> Span {
|
fn span(&self) -> Span {
|
||||||
todo!()
|
match self {
|
||||||
|
ParseErr::MismatchedKind {
|
||||||
|
actual: Token { span, .. },
|
||||||
|
..
|
||||||
|
} => *span,
|
||||||
|
ParseErr::InvalidTokenPrimary(Token { span, .. }) => *span,
|
||||||
|
ParseErr::EOFExpecting(_) => Span::dummy(),
|
||||||
|
ParseErr::EOF(_) => Span::dummy(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn message(&self) -> String {
|
fn message(&self) -> String {
|
||||||
todo!()
|
match self {
|
||||||
|
ParseErr::MismatchedKind { expected, actual } => {
|
||||||
|
format!("expected: {:?}, received: {:?}", expected, actual.kind)
|
||||||
|
}
|
||||||
|
ParseErr::InvalidTokenPrimary(token) => {
|
||||||
|
format!("invalid token in expression: {:?}", token.kind)
|
||||||
|
}
|
||||||
|
ParseErr::EOFExpecting(token) => {
|
||||||
|
format!("reached EOF searching for: {:?}", token)
|
||||||
|
}
|
||||||
|
ParseErr::EOF(message) => {
|
||||||
|
format!("reached EOF while parsing: {}", message)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn note(&self) -> Option<String> {
|
fn note(&self) -> Option<String> {
|
||||||
todo!()
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -266,7 +307,7 @@ mod test {
|
||||||
|
|
||||||
fn token(kind: TokenType) -> Token {
|
fn token(kind: TokenType) -> Token {
|
||||||
Token {
|
Token {
|
||||||
span: crate::errors::Span::dummy(),
|
span: Span::dummy(),
|
||||||
kind,
|
kind,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -305,6 +346,7 @@ mod test {
|
||||||
|
|
||||||
mod expr {
|
mod expr {
|
||||||
use super::prelude::*;
|
use super::prelude::*;
|
||||||
|
use crate::ast::{UnaryOp, UnaryOpKind};
|
||||||
use TokenType::*;
|
use TokenType::*;
|
||||||
|
|
||||||
fn parse_expr(tokens: Vec<Token>) -> Expr {
|
fn parse_expr(tokens: Vec<Token>) -> Expr {
|
||||||
|
|
@ -312,6 +354,11 @@ mod test {
|
||||||
parser.expression().unwrap()
|
parser.expression().unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn number_literal() {
|
||||||
|
test_number_literal(parse_expr);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn add_multiply() {
|
fn add_multiply() {
|
||||||
let tokens = [Number(10.0), Plus, Number(20.0), Asterisk, Number(100.0)]
|
let tokens = [Number(10.0), Plus, Number(20.0), Asterisk, Number(100.0)]
|
||||||
|
|
@ -334,6 +381,58 @@ mod test {
|
||||||
expr
|
expr
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn equal_unary() {
|
||||||
|
let tokens = [Number(10.0), EqualEqual, Minus, Number(10.0)]
|
||||||
|
.map(token)
|
||||||
|
.into();
|
||||||
|
let expr = parse_expr(tokens);
|
||||||
|
assert_eq!(
|
||||||
|
Expr::BinaryOp(Box::new(BinaryOp {
|
||||||
|
span: Span::dummy(),
|
||||||
|
lhs: Expr::Literal(Literal::Number(10.0, Span::dummy())),
|
||||||
|
rhs: Expr::UnaryOp(Box::new(UnaryOp {
|
||||||
|
span: Span::dummy(),
|
||||||
|
expr: Expr::Literal(Literal::Number(10.0, Span::dummy())),
|
||||||
|
kind: UnaryOpKind::Neg
|
||||||
|
})),
|
||||||
|
kind: BinaryOpKind::Equal
|
||||||
|
})),
|
||||||
|
expr
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn parentheses_mul_add() {
|
||||||
|
let tokens = [
|
||||||
|
Number(10.0),
|
||||||
|
Asterisk,
|
||||||
|
ParenO,
|
||||||
|
Number(20.0),
|
||||||
|
Plus,
|
||||||
|
Number(30.0),
|
||||||
|
ParenC,
|
||||||
|
]
|
||||||
|
.map(token)
|
||||||
|
.into();
|
||||||
|
let expr = parse_expr(tokens);
|
||||||
|
assert_eq!(
|
||||||
|
Expr::BinaryOp(Box::new(BinaryOp {
|
||||||
|
span: Span::dummy(),
|
||||||
|
lhs: Expr::Literal(Literal::Number(10.0, Span::dummy())),
|
||||||
|
rhs: Expr::BinaryOp(Box::new(BinaryOp {
|
||||||
|
span: Span::dummy(),
|
||||||
|
lhs: Expr::Literal(Literal::Number(20.0, Span::dummy())),
|
||||||
|
rhs: Expr::Literal(Literal::Number(30.0, Span::dummy())),
|
||||||
|
|
||||||
|
kind: BinaryOpKind::Add
|
||||||
|
})),
|
||||||
|
kind: BinaryOpKind::Mul
|
||||||
|
})),
|
||||||
|
expr
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mod logical_or {
|
mod logical_or {
|
||||||
|
|
@ -495,6 +594,7 @@ mod test {
|
||||||
|
|
||||||
mod unary {
|
mod unary {
|
||||||
use super::prelude::*;
|
use super::prelude::*;
|
||||||
|
use crate::ast::{UnaryOp, UnaryOpKind};
|
||||||
|
|
||||||
fn parse_unary(tokens: Vec<Token>) -> Expr {
|
fn parse_unary(tokens: Vec<Token>) -> Expr {
|
||||||
let mut parser = parser(tokens);
|
let mut parser = parser(tokens);
|
||||||
|
|
@ -508,36 +608,35 @@ mod test {
|
||||||
|
|
||||||
// needs expr support
|
// needs expr support
|
||||||
|
|
||||||
//
|
#[test]
|
||||||
// #[test]
|
fn not() {
|
||||||
// fn not() {
|
let tokens = [TokenType::Not, TokenType::True].map(token).into();
|
||||||
// let tokens = [TokenType::Not, TokenType::True].map(token).into();
|
let unary = parse_unary(tokens);
|
||||||
// let unary = parse_unary(tokens);
|
assert_eq!(
|
||||||
// assert_eq!(
|
Expr::UnaryOp(Box::new(UnaryOp {
|
||||||
// Expr::UnaryOp(Box::new(UnaryOp {
|
span: Span::dummy(),
|
||||||
// span: Span::dummy(),
|
expr: Expr::Literal(Literal::Boolean(true, Span::dummy())),
|
||||||
// expr: Expr::Literal(Literal::Boolean(true, Span::dummy())),
|
kind: UnaryOpKind::Not
|
||||||
// kind: UnaryOpKind::Not
|
})),
|
||||||
// })),
|
unary
|
||||||
// unary
|
);
|
||||||
// );
|
}
|
||||||
// }
|
|
||||||
//
|
#[test]
|
||||||
// #[test]
|
fn neg() {
|
||||||
// fn neg() {
|
let tokens = [TokenType::Minus, TokenType::Number(10.0)]
|
||||||
// let tokens = [TokenType::Minus, TokenType::Number(10.0)]
|
.map(token)
|
||||||
// .map(token)
|
.into();
|
||||||
// .into();
|
let unary = parse_unary(tokens);
|
||||||
// let unary = parse_unary(tokens);
|
assert_eq!(
|
||||||
// assert_eq!(
|
Expr::UnaryOp(Box::new(UnaryOp {
|
||||||
// Expr::UnaryOp(Box::new(UnaryOp {
|
span: Span::dummy(),
|
||||||
// span: Span::dummy(),
|
expr: Expr::Literal(Literal::Number(10.0, Span::dummy())),
|
||||||
// expr: Expr::Literal(Literal::Number(10.0, Span::dummy())),
|
kind: UnaryOpKind::Neg
|
||||||
// kind: UnaryOpKind::Neg
|
})),
|
||||||
// })),
|
unary
|
||||||
// unary
|
);
|
||||||
// );
|
}
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
mod primary {
|
mod primary {
|
||||||
|
|
@ -548,6 +647,13 @@ mod test {
|
||||||
parser.primary().unwrap()
|
parser.primary().unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn ident() {
|
||||||
|
let tokens = [TokenType::Ident("tokens")].map(token).into();
|
||||||
|
let literal = parse_primary(tokens);
|
||||||
|
assert_eq!(Expr::Ident("tokens".to_string(), Span::dummy()), literal);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn string() {
|
fn string() {
|
||||||
let tokens = [TokenType::Number(10.0)].map(token).into();
|
let tokens = [TokenType::Number(10.0)].map(token).into();
|
||||||
|
|
|
||||||
2
test.sl
2
test.sl
|
|
@ -1 +1 @@
|
||||||
1 + 2 * 10;
|
(1 + 5 and 5) / 2;
|
||||||
Loading…
Add table
Add a link
Reference in a new issue