mirror of
https://github.com/Noratrieb/dilaria.git
synced 2026-01-16 10:25:02 +01:00
binary op
This commit is contained in:
parent
8f99a1d630
commit
e13f3e35c2
2 changed files with 120 additions and 16 deletions
|
|
@ -61,7 +61,7 @@
|
||||||
|
|
||||||
<factor> ::= <unary> { ( "*" | "/" | "%" ) <unary> }
|
<factor> ::= <unary> { ( "*" | "/" | "%" ) <unary> }
|
||||||
|
|
||||||
<unary> ::= ( "not" | "-" ) <primary>
|
<unary> ::= { ( "not" | "-" ) } <primary>
|
||||||
|
|
||||||
<primary> ::= <NUMBER>
|
<primary> ::= <NUMBER>
|
||||||
| <STRING>
|
| <STRING>
|
||||||
|
|
|
||||||
134
src/parse.rs
134
src/parse.rs
|
|
@ -92,29 +92,78 @@ impl<'code> Parser<'code> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn factor(&mut self) -> ParseResult<'code, Expr> {
|
fn factor(&mut self) -> ParseResult<'code, Expr> {
|
||||||
todo!()
|
let lhs = self.unary()?;
|
||||||
|
match self.peek() {
|
||||||
|
Some(Token {
|
||||||
|
kind: TokenType::Asterisk,
|
||||||
|
..
|
||||||
|
}) => {
|
||||||
|
let _ = self.next();
|
||||||
|
let rhs = self.unary()?;
|
||||||
|
Ok(Expr::BinaryOp(Box::new(BinaryOp {
|
||||||
|
span: lhs.span().extend(rhs.span()),
|
||||||
|
lhs,
|
||||||
|
rhs,
|
||||||
|
kind: BinaryOpKind::Mul,
|
||||||
|
})))
|
||||||
|
}
|
||||||
|
Some(Token {
|
||||||
|
kind: TokenType::Slash,
|
||||||
|
..
|
||||||
|
}) => {
|
||||||
|
let _ = self.next();
|
||||||
|
let rhs = self.unary()?;
|
||||||
|
Ok(Expr::BinaryOp(Box::new(BinaryOp {
|
||||||
|
span: lhs.span().extend(rhs.span()),
|
||||||
|
lhs,
|
||||||
|
rhs,
|
||||||
|
kind: BinaryOpKind::Div,
|
||||||
|
})))
|
||||||
|
}
|
||||||
|
Some(Token {
|
||||||
|
kind: TokenType::Percent,
|
||||||
|
..
|
||||||
|
}) => {
|
||||||
|
let _ = self.next();
|
||||||
|
let rhs = self.unary()?;
|
||||||
|
Ok(Expr::BinaryOp(Box::new(BinaryOp {
|
||||||
|
span: lhs.span().extend(rhs.span()),
|
||||||
|
lhs,
|
||||||
|
rhs,
|
||||||
|
kind: BinaryOpKind::Mod,
|
||||||
|
})))
|
||||||
|
}
|
||||||
|
_ => Ok(lhs),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn unary(&mut self) -> ParseResult<'code, Expr> {
|
fn unary(&mut self) -> ParseResult<'code, Expr> {
|
||||||
let next = self.next().ok_or(ParseErr::EOF)?;
|
match self.peek() {
|
||||||
match next.kind {
|
Some(Token {
|
||||||
TokenType::Not => {
|
kind: TokenType::Not,
|
||||||
|
..
|
||||||
|
}) => {
|
||||||
|
let unary_op_span = self.next().unwrap().span;
|
||||||
let expr = self.expression()?;
|
let expr = self.expression()?;
|
||||||
Ok(Expr::UnaryOp(Box::new(UnaryOp {
|
Ok(Expr::UnaryOp(Box::new(UnaryOp {
|
||||||
span: next.span,
|
span: unary_op_span.extend(expr.span()),
|
||||||
expr,
|
expr,
|
||||||
kind: UnaryOpKind::Not,
|
kind: UnaryOpKind::Not,
|
||||||
})))
|
})))
|
||||||
}
|
}
|
||||||
TokenType::Minus => {
|
Some(Token {
|
||||||
|
kind: TokenType::Minus,
|
||||||
|
..
|
||||||
|
}) => {
|
||||||
|
let unary_op_span = self.next().unwrap().span;
|
||||||
let expr = self.expression()?;
|
let expr = self.expression()?;
|
||||||
Ok(Expr::UnaryOp(Box::new(UnaryOp {
|
Ok(Expr::UnaryOp(Box::new(UnaryOp {
|
||||||
span: next.span,
|
span: unary_op_span.extend(expr.span()),
|
||||||
expr,
|
expr,
|
||||||
kind: UnaryOpKind::Neg,
|
kind: UnaryOpKind::Neg,
|
||||||
})))
|
})))
|
||||||
}
|
}
|
||||||
_ => todo!(),
|
_ => self.primary(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -160,10 +209,12 @@ impl<'code> Parser<'code> {
|
||||||
|
|
||||||
// helpers
|
// helpers
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
fn next(&mut self) -> Option<Token<'code>> {
|
fn next(&mut self) -> Option<Token<'code>> {
|
||||||
self.tokens.next()
|
self.tokens.next()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
fn peek(&mut self) -> Option<&Token<'code>> {
|
fn peek(&mut self) -> Option<&Token<'code>> {
|
||||||
self.tokens.peek()
|
self.tokens.peek()
|
||||||
}
|
}
|
||||||
|
|
@ -206,6 +257,13 @@ mod test {
|
||||||
use crate::lex::{Token, TokenType};
|
use crate::lex::{Token, TokenType};
|
||||||
use crate::parse::Parser;
|
use crate::parse::Parser;
|
||||||
|
|
||||||
|
mod prelude {
|
||||||
|
pub(super) use super::{parser, token};
|
||||||
|
pub(super) use crate::ast::{Expr, Literal};
|
||||||
|
pub(super) use crate::errors::Span;
|
||||||
|
pub(super) use crate::lex::{Token, TokenType};
|
||||||
|
}
|
||||||
|
|
||||||
fn token(kind: TokenType) -> Token {
|
fn token(kind: TokenType) -> Token {
|
||||||
Token {
|
Token {
|
||||||
span: crate::errors::Span::dummy(),
|
span: crate::errors::Span::dummy(),
|
||||||
|
|
@ -219,17 +277,63 @@ mod test {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mod factor {
|
||||||
|
use super::prelude::*;
|
||||||
|
use crate::ast::{BinaryOp, BinaryOpKind};
|
||||||
|
|
||||||
|
fn parse_factor<'a, T: Into<Vec<Token<'a>>>>(tokens: T) -> Expr {
|
||||||
|
let mut parser = parser(tokens);
|
||||||
|
parser.factor().unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_literal_factor(token_type: TokenType, expected_op_kind: BinaryOpKind) {
|
||||||
|
let tokens = [TokenType::Number(10.0), token_type, TokenType::Number(4.0)].map(token);
|
||||||
|
let factor = parse_factor(tokens);
|
||||||
|
assert_eq!(
|
||||||
|
Expr::BinaryOp(Box::new(BinaryOp {
|
||||||
|
span: Span::dummy(),
|
||||||
|
lhs: Expr::Literal(Literal::Number(10.0, Span::dummy())),
|
||||||
|
rhs: Expr::Literal(Literal::Number(4.0, Span::dummy())),
|
||||||
|
kind: expected_op_kind
|
||||||
|
})),
|
||||||
|
factor
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn multiply() {
|
||||||
|
test_literal_factor(TokenType::Asterisk, BinaryOpKind::Mul);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn divide() {
|
||||||
|
test_literal_factor(TokenType::Slash, BinaryOpKind::Div);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn modulo() {
|
||||||
|
test_literal_factor(TokenType::Percent, BinaryOpKind::Mod);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
mod unary {
|
mod unary {
|
||||||
use super::{parser, token};
|
use super::prelude::*;
|
||||||
use crate::ast::{Expr, Literal};
|
|
||||||
use crate::lex::{Token, TokenType};
|
fn parse_unary<'a, T: Into<Vec<Token<'a>>>>(tokens: T) -> Expr {
|
||||||
|
let mut parser = parser(tokens);
|
||||||
|
parser.primary().unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn number_literal() {
|
||||||
|
let tokens = [TokenType::Number(10.0)].map(token);
|
||||||
|
let unary = parse_unary(tokens);
|
||||||
|
assert_eq!(Expr::Literal(Literal::Number(10.0, Span::dummy())), unary);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mod primary {
|
mod primary {
|
||||||
use super::{parser, token};
|
use super::prelude::*;
|
||||||
use crate::ast::{Expr, Literal};
|
|
||||||
use crate::errors::Span;
|
|
||||||
use crate::lex::{Token, TokenType};
|
|
||||||
|
|
||||||
fn parse_primary<'a, T: Into<Vec<Token<'a>>>>(tokens: T) -> Expr {
|
fn parse_primary<'a, T: Into<Vec<Token<'a>>>>(tokens: T) -> Expr {
|
||||||
let mut parser = parser(tokens);
|
let mut parser = parser(tokens);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue