Make meticulous changes to pratt parser
This commit is contained in:
parent
9ea203f419
commit
2ae75dcdd0
@ -228,7 +228,10 @@ impl Lexer {
|
|||||||
} else {
|
} else {
|
||||||
self.position += 1;
|
self.position += 1;
|
||||||
|
|
||||||
return Err(LexError::UnexpectedCharacter(c));
|
return Err(LexError::UnexpectedCharacter {
|
||||||
|
character: c,
|
||||||
|
position: self.position,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
';' => {
|
';' => {
|
||||||
@ -244,13 +247,19 @@ impl Lexer {
|
|||||||
} else {
|
} else {
|
||||||
self.position += 1;
|
self.position += 1;
|
||||||
|
|
||||||
return Err(LexError::UnexpectedCharacter(c));
|
return Err(LexError::UnexpectedCharacter {
|
||||||
|
character: c,
|
||||||
|
position: self.position,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
self.position += 1;
|
self.position += 1;
|
||||||
|
|
||||||
return Err(LexError::UnexpectedCharacter(c));
|
return Err(LexError::UnexpectedCharacter {
|
||||||
|
character: c,
|
||||||
|
position: self.position,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -433,13 +442,21 @@ impl Default for Lexer {
|
|||||||
|
|
||||||
#[derive(Debug, PartialEq, Clone)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
pub enum LexError {
|
pub enum LexError {
|
||||||
UnexpectedCharacter(char),
|
UnexpectedCharacter { character: char, position: usize },
|
||||||
|
}
|
||||||
|
|
||||||
|
impl LexError {
|
||||||
|
pub fn position(&self) -> Span {
|
||||||
|
match self {
|
||||||
|
Self::UnexpectedCharacter { position, .. } => (*position, *position),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Error for LexError {
|
impl Error for LexError {
|
||||||
fn source(&self) -> Option<&(dyn Error + 'static)> {
|
fn source(&self) -> Option<&(dyn Error + 'static)> {
|
||||||
match self {
|
match self {
|
||||||
Self::UnexpectedCharacter(_) => None,
|
Self::UnexpectedCharacter { .. } => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -447,7 +464,7 @@ impl Error for LexError {
|
|||||||
impl Display for LexError {
|
impl Display for LexError {
|
||||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
Self::UnexpectedCharacter(character) => {
|
Self::UnexpectedCharacter { character, .. } => {
|
||||||
write!(f, "Unexpected character: '{}'", character)
|
write!(f, "Unexpected character: '{}'", character)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -23,7 +23,7 @@ pub use identifier::Identifier;
|
|||||||
pub use lex::{lex, LexError, Lexer};
|
pub use lex::{lex, LexError, Lexer};
|
||||||
pub use parse::{parse, ParseError, Parser};
|
pub use parse::{parse, ParseError, Parser};
|
||||||
pub use r#type::Type;
|
pub use r#type::Type;
|
||||||
pub use token::Token;
|
pub use token::{Token, TokenOwned};
|
||||||
pub use value::{Value, ValueError};
|
pub use value::{Value, ValueError};
|
||||||
pub use vm::{run, Vm, VmError};
|
pub use vm::{run, Vm, VmError};
|
||||||
|
|
||||||
|
@ -12,8 +12,8 @@ use std::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
abstract_tree::BinaryOperator, built_in_function::BuiltInFunction, token::TokenOwned,
|
AbstractSyntaxTree, BinaryOperator, BuiltInFunction, Identifier, LexError, Lexer, Node, Span,
|
||||||
AbstractSyntaxTree, Identifier, LexError, Lexer, Node, Span, Statement, Token, Value,
|
Statement, Token, TokenOwned, Value,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Parses the input into an abstract syntax tree.
|
/// Parses the input into an abstract syntax tree.
|
||||||
@ -121,44 +121,32 @@ impl<'src> Parser<'src> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse(&mut self) -> Result<Node<Statement>, ParseError> {
|
|
||||||
self.parse_node(0)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn current(&self) -> &(Token, Span) {
|
pub fn current(&self) -> &(Token, Span) {
|
||||||
&self.current
|
&self.current
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn parse(&mut self) -> Result<Node<Statement>, ParseError> {
|
||||||
|
self.parse_statement(0)
|
||||||
|
}
|
||||||
|
|
||||||
fn next_token(&mut self) -> Result<(), ParseError> {
|
fn next_token(&mut self) -> Result<(), ParseError> {
|
||||||
let next = self.lexer.next_token(self.source);
|
self.current = self.lexer.next_token(self.source)?;
|
||||||
|
|
||||||
self.current = match next {
|
|
||||||
Ok((token, position)) => (token, position),
|
|
||||||
Err(lex_error) => {
|
|
||||||
let position = {
|
|
||||||
self.next_token()?;
|
|
||||||
|
|
||||||
self.current.1
|
|
||||||
};
|
|
||||||
|
|
||||||
return Err(ParseError::LexError {
|
|
||||||
error: lex_error,
|
|
||||||
position,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_node(&mut self, precedence: u8) -> Result<Node<Statement>, ParseError> {
|
fn parse_statement(&mut self, precedence: u8) -> Result<Node<Statement>, ParseError> {
|
||||||
let left = self.parse_primary()?;
|
let mut left = self.parse_primary()?;
|
||||||
|
|
||||||
if precedence < self.current_precedence() {
|
while precedence < self.current.0.precedence() {
|
||||||
self.parse_infix(left)
|
if self.current.0.is_postfix() {
|
||||||
} else {
|
left = self.parse_postfix(left)?;
|
||||||
Ok(left)
|
} else {
|
||||||
|
left = self.parse_infix(left)?;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Ok(left)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_primary(&mut self) -> Result<Node<Statement>, ParseError> {
|
fn parse_primary(&mut self) -> Result<Node<Statement>, ParseError> {
|
||||||
@ -241,7 +229,7 @@ impl<'src> Parser<'src> {
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
let next_node = self.parse_node(0)?;
|
let next_node = self.parse_statement(0)?;
|
||||||
|
|
||||||
// If the next node is an assignment, this might be a map
|
// If the next node is an assignment, this might be a map
|
||||||
if let Statement::BinaryOperation {
|
if let Statement::BinaryOperation {
|
||||||
@ -264,20 +252,20 @@ impl<'src> Parser<'src> {
|
|||||||
if let Statement::Map(map_properties) =
|
if let Statement::Map(map_properties) =
|
||||||
statement.get_or_insert_with(|| Statement::Map(Vec::new()))
|
statement.get_or_insert_with(|| Statement::Map(Vec::new()))
|
||||||
{
|
{
|
||||||
// Ignore commas after properties
|
|
||||||
if let Token::Comma = self.current.0 {
|
|
||||||
self.next_token()?;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add the new property to the map
|
// Add the new property to the map
|
||||||
map_properties.push((*left, *right));
|
map_properties.push((*left, *right));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Ignore commas after properties
|
||||||
|
if let Token::Comma = self.current.0 {
|
||||||
|
self.next_token()?;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// Otherwise, the new statement is a block
|
// Otherwise, the new statement is a block
|
||||||
} else if let Statement::Block(statements) =
|
} else if let Statement::Block(statements) =
|
||||||
statement.get_or_insert_with(|| Statement::Block(Vec::new()))
|
statement.get_or_insert_with(|| Statement::Block(Vec::new()))
|
||||||
{
|
{
|
||||||
// Add the assignment statement to the block
|
// Add the statement to the block
|
||||||
statements.push(next_node);
|
statements.push(next_node);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -285,7 +273,7 @@ impl<'src> Parser<'src> {
|
|||||||
(Token::LeftParenthesis, left_position) => {
|
(Token::LeftParenthesis, left_position) => {
|
||||||
self.next_token()?;
|
self.next_token()?;
|
||||||
|
|
||||||
let node = self.parse_node(0)?;
|
let node = self.parse_statement(0)?;
|
||||||
|
|
||||||
if let (Token::RightParenthesis, right_position) = self.current {
|
if let (Token::RightParenthesis, right_position) = self.current {
|
||||||
self.next_token()?;
|
self.next_token()?;
|
||||||
@ -320,7 +308,7 @@ impl<'src> Parser<'src> {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Ok(instruction) = self.parse_node(0) {
|
if let Ok(instruction) = self.parse_statement(0) {
|
||||||
nodes.push(instruction);
|
nodes.push(instruction);
|
||||||
} else {
|
} else {
|
||||||
return Err(ParseError::ExpectedToken {
|
return Err(ParseError::ExpectedToken {
|
||||||
@ -369,7 +357,7 @@ impl<'src> Parser<'src> {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Ok(node) = self.parse_node(0) {
|
if let Ok(node) = self.parse_statement(0) {
|
||||||
if let Some(ref mut arguments) = value_arguments {
|
if let Some(ref mut arguments) = value_arguments {
|
||||||
arguments.push(node);
|
arguments.push(node);
|
||||||
} else {
|
} else {
|
||||||
@ -403,59 +391,51 @@ impl<'src> Parser<'src> {
|
|||||||
fn parse_infix(&mut self, left: Node<Statement>) -> Result<Node<Statement>, ParseError> {
|
fn parse_infix(&mut self, left: Node<Statement>) -> Result<Node<Statement>, ParseError> {
|
||||||
let left_start = left.position.0;
|
let left_start = left.position.0;
|
||||||
|
|
||||||
// Postfix operations
|
if let Token::Dot = &self.current.0 {
|
||||||
if let Token::Semicolon = &self.current.0 {
|
|
||||||
self.next_token()?;
|
self.next_token()?;
|
||||||
|
|
||||||
let right_end = self.current.1 .1;
|
let right = self.parse_statement(Token::Dot.precedence() + 1)?;
|
||||||
|
let right_end = right.position.1;
|
||||||
|
|
||||||
return Ok(Node::new(
|
return Ok(Node::new(
|
||||||
Statement::Nil(Box::new(left)),
|
Statement::PropertyAccess(Box::new(left), Box::new(right)),
|
||||||
(left_start, right_end),
|
(left_start, right_end),
|
||||||
));
|
));
|
||||||
};
|
}
|
||||||
|
|
||||||
// Infix operations
|
let binary_operator = match &self.current.0 {
|
||||||
let binary_operator = match &self.current {
|
Token::DoubleAmpersand => Node::new(BinaryOperator::And, self.current.1),
|
||||||
(Token::Dot, _) => {
|
Token::DoubleEqual => Node::new(BinaryOperator::Equal, self.current.1),
|
||||||
self.next_token()?;
|
Token::DoublePipe => Node::new(BinaryOperator::Or, self.current.1),
|
||||||
|
Token::Equal => Node::new(BinaryOperator::Assign, self.current.1),
|
||||||
let right = self.parse_node(0)?;
|
Token::Greater => Node::new(BinaryOperator::Greater, self.current.1),
|
||||||
let right_end = right.position.1;
|
Token::GreaterEqual => Node::new(BinaryOperator::GreaterOrEqual, self.current.1),
|
||||||
|
Token::Less => Node::new(BinaryOperator::Less, self.current.1),
|
||||||
return Ok(Node::new(
|
Token::LessEqual => Node::new(BinaryOperator::LessOrEqual, self.current.1),
|
||||||
Statement::PropertyAccess(Box::new(left), Box::new(right)),
|
Token::Minus => Node::new(BinaryOperator::Subtract, self.current.1),
|
||||||
(left_start, right_end),
|
Token::Plus => Node::new(BinaryOperator::Add, self.current.1),
|
||||||
));
|
Token::PlusEqual => Node::new(BinaryOperator::AddAssign, self.current.1),
|
||||||
}
|
Token::Star => Node::new(BinaryOperator::Multiply, self.current.1),
|
||||||
(Token::DoubleAmpersand, _) => Node::new(BinaryOperator::And, self.current.1),
|
Token::Slash => Node::new(BinaryOperator::Divide, self.current.1),
|
||||||
(Token::DoubleEqual, _) => Node::new(BinaryOperator::Equal, self.current.1),
|
Token::Percent => Node::new(BinaryOperator::Modulo, self.current.1),
|
||||||
(Token::DoublePipe, _) => Node::new(BinaryOperator::Or, self.current.1),
|
|
||||||
(Token::Equal, _) => Node::new(BinaryOperator::Assign, self.current.1),
|
|
||||||
(Token::Greater, _) => Node::new(BinaryOperator::Greater, self.current.1),
|
|
||||||
(Token::GreaterEqual, _) => Node::new(BinaryOperator::GreaterOrEqual, self.current.1),
|
|
||||||
(Token::Less, _) => Node::new(BinaryOperator::Less, self.current.1),
|
|
||||||
(Token::LessEqual, _) => Node::new(BinaryOperator::LessOrEqual, self.current.1),
|
|
||||||
(Token::Minus, _) => Node::new(BinaryOperator::Subtract, self.current.1),
|
|
||||||
(Token::Plus, _) => Node::new(BinaryOperator::Add, self.current.1),
|
|
||||||
(Token::PlusEqual, _) => Node::new(BinaryOperator::AddAssign, self.current.1),
|
|
||||||
(Token::Star, _) => Node::new(BinaryOperator::Multiply, self.current.1),
|
|
||||||
(Token::Slash, _) => Node::new(BinaryOperator::Divide, self.current.1),
|
|
||||||
(Token::Percent, _) => Node::new(BinaryOperator::Modulo, self.current.1),
|
|
||||||
_ => {
|
_ => {
|
||||||
self.next_token()?;
|
|
||||||
|
|
||||||
return Err(ParseError::UnexpectedToken {
|
return Err(ParseError::UnexpectedToken {
|
||||||
actual: self.current.0.to_owned(),
|
actual: self.current.0.to_owned(),
|
||||||
position: self.current.1,
|
position: self.current.1,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
let operator_precedence = self.current.0.precedence()
|
||||||
|
- if self.current.0.is_right_associative() {
|
||||||
|
1
|
||||||
|
} else {
|
||||||
|
0
|
||||||
|
};
|
||||||
|
|
||||||
self.next_token()?;
|
self.next_token()?;
|
||||||
|
|
||||||
let left_start = left.position.0;
|
let left_start = left.position.0;
|
||||||
let right = self.parse_node(0)?;
|
let right = self.parse_statement(operator_precedence)?;
|
||||||
let right_end = right.position.1;
|
let right_end = right.position.1;
|
||||||
|
|
||||||
Ok(Node::new(
|
Ok(Node::new(
|
||||||
@ -468,33 +448,21 @@ impl<'src> Parser<'src> {
|
|||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn current_precedence(&self) -> u8 {
|
fn parse_postfix(&mut self, left: Node<Statement>) -> Result<Node<Statement>, ParseError> {
|
||||||
match self.current.0 {
|
if let Token::Semicolon = &self.current.0 {
|
||||||
Token::Semicolon => 10,
|
self.next_token()?;
|
||||||
Token::Equal | Token::PlusEqual => 8,
|
|
||||||
Token::DoubleEqual => 7,
|
let left_start = left.position.0;
|
||||||
Token::DoubleAmpersand | Token::DoublePipe => 6,
|
let operator_end = self.current.1 .1;
|
||||||
Token::Greater | Token::GreaterEqual | Token::Less | Token::LessEqual => 5,
|
|
||||||
Token::Dot => 4,
|
Ok(Node::new(
|
||||||
Token::Percent => 3,
|
Statement::Nil(Box::new(left)),
|
||||||
Token::Star => 2,
|
(left_start, operator_end),
|
||||||
Token::Slash => 2,
|
))
|
||||||
Token::Plus => 1,
|
} else {
|
||||||
Token::Minus => 1,
|
Ok(left)
|
||||||
_ => 0,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn peek_token(&mut self) -> Token {
|
|
||||||
self.lexer
|
|
||||||
.peek_token(self.source)
|
|
||||||
.map(|(token, _)| token)
|
|
||||||
.unwrap_or(Token::Eof)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn next_is_postfix(&mut self) -> bool {
|
|
||||||
matches!(self.peek_token(), Token::Semicolon)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Clone)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
@ -503,10 +471,7 @@ pub enum ParseError {
|
|||||||
error: ParseBoolError,
|
error: ParseBoolError,
|
||||||
position: Span,
|
position: Span,
|
||||||
},
|
},
|
||||||
LexError {
|
LexError(LexError),
|
||||||
error: LexError,
|
|
||||||
position: Span,
|
|
||||||
},
|
|
||||||
ExpectedIdentifier {
|
ExpectedIdentifier {
|
||||||
actual: TokenOwned,
|
actual: TokenOwned,
|
||||||
position: Span,
|
position: Span,
|
||||||
@ -530,6 +495,12 @@ pub enum ParseError {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<LexError> for ParseError {
|
||||||
|
fn from(v: LexError) -> Self {
|
||||||
|
Self::LexError(v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl ParseError {
|
impl ParseError {
|
||||||
pub fn position(&self) -> Span {
|
pub fn position(&self) -> Span {
|
||||||
match self {
|
match self {
|
||||||
@ -538,7 +509,7 @@ impl ParseError {
|
|||||||
ParseError::ExpectedToken { position, .. } => *position,
|
ParseError::ExpectedToken { position, .. } => *position,
|
||||||
ParseError::FloatError { position, .. } => *position,
|
ParseError::FloatError { position, .. } => *position,
|
||||||
ParseError::IntegerError { position, .. } => *position,
|
ParseError::IntegerError { position, .. } => *position,
|
||||||
ParseError::LexError { position, .. } => *position,
|
ParseError::LexError(error) => error.position(),
|
||||||
ParseError::UnexpectedToken { position, .. } => *position,
|
ParseError::UnexpectedToken { position, .. } => *position,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -547,7 +518,7 @@ impl ParseError {
|
|||||||
impl Error for ParseError {
|
impl Error for ParseError {
|
||||||
fn source(&self) -> Option<&(dyn Error + 'static)> {
|
fn source(&self) -> Option<&(dyn Error + 'static)> {
|
||||||
match self {
|
match self {
|
||||||
Self::LexError { error, .. } => Some(error),
|
Self::LexError(error) => Some(error),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -565,7 +536,7 @@ impl Display for ParseError {
|
|||||||
} => write!(f, "Expected token {expected}, found {actual}"),
|
} => write!(f, "Expected token {expected}, found {actual}"),
|
||||||
Self::FloatError { error, .. } => write!(f, "{}", error),
|
Self::FloatError { error, .. } => write!(f, "{}", error),
|
||||||
Self::IntegerError { error, .. } => write!(f, "{}", error),
|
Self::IntegerError { error, .. } => write!(f, "{}", error),
|
||||||
Self::LexError { error, .. } => write!(f, "{}", error),
|
Self::LexError(error) => write!(f, "{}", error),
|
||||||
Self::UnexpectedToken { actual, .. } => write!(f, "Unexpected token {actual}"),
|
Self::UnexpectedToken { actual, .. } => write!(f, "Unexpected token {actual}"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -127,6 +127,40 @@ impl<'src> Token<'src> {
|
|||||||
Token::WriteLine => "write_line",
|
Token::WriteLine => "write_line",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn is_eof(&self) -> bool {
|
||||||
|
matches!(self, Token::Eof)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn precedence(&self) -> u8 {
|
||||||
|
match self {
|
||||||
|
Token::Equal | Token::PlusEqual => 8,
|
||||||
|
Token::Semicolon => 7,
|
||||||
|
Token::DoubleAmpersand | Token::DoublePipe => 6,
|
||||||
|
Token::Greater
|
||||||
|
| Token::GreaterEqual
|
||||||
|
| Token::Less
|
||||||
|
| Token::LessEqual
|
||||||
|
| Token::DoubleEqual => 5,
|
||||||
|
Token::Dot => 4,
|
||||||
|
Token::Percent => 3,
|
||||||
|
Token::Star | Token::Slash => 2,
|
||||||
|
Token::Plus | Token::Minus => 1,
|
||||||
|
_ => 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_left_associative(&self) -> bool {
|
||||||
|
!self.is_right_associative()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_right_associative(&self) -> bool {
|
||||||
|
matches!(self, Token::Semicolon)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_postfix(&self) -> bool {
|
||||||
|
matches!(self, Token::Semicolon)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'src> Display for Token<'src> {
|
impl<'src> Display for Token<'src> {
|
||||||
|
Loading…
Reference in New Issue
Block a user