diff --git a/src/parser.rs b/src/parser.rs index 875fcc0..84cf349 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -1,4 +1,5 @@ pub mod error; +pub mod expression; mod literals; pub mod module; pub mod proc; @@ -23,6 +24,7 @@ pub type IErr = GreedyError; // custom IResult type for VerboseError pub type IResult> = nom::IResult; +pub use crate::parser::expression::{expression, Call, Expression, Operation}; pub use crate::parser::module::{module, Module, ModuleItem, PortDirection}; use crate::parser::tokens::{token, TokenKind as tk, TokenSpan}; @@ -76,35 +78,14 @@ pub struct Assign<'a> { pub expr: Expression<'a>, } -#[derive(Debug, Clone)] -pub enum Operation<'a> { - And { - a: Expression<'a>, - b: Expression<'a>, - }, - Or { - a: Expression<'a>, - b: Expression<'a>, - }, - Xor { - a: Expression<'a>, - b: Expression<'a>, - }, - Not(Expression<'a>), -} - -#[derive(Debug, Clone)] -pub struct Call<'a> { - pub name: Span<'a>, - pub args: Vec>, -} - -#[derive(Debug, Clone)] -pub enum Expression<'a> { - Ident(&'a str), - Literal(u64), - Call(Box>), - Operation(Box>), +fn assign_statement(input: TokenSpan) -> IResult { + map( + separated_pair(token(tk::Ident), token(tk::EqAssign), expression), + |(lhs, expr)| Assign { + lhs: (*lhs.span().fragment()), + expr, + }, + )(input) } // TODO: reallow assignments @@ -122,74 +103,6 @@ fn declaration(i: TokenSpan) -> IResult { )(i) } -fn operation(input: TokenSpan) -> IResult { - // temporarily given up on before I learn the shunting yard algorithm - alt(( - map( - separated_pair(expression_nonrecurse, token(tk::BitAnd), expression), - |(a, b)| Operation::And { a, b }, - ), - map( - separated_pair(expression_nonrecurse, token(tk::BitOr), expression), - |(a, b)| Operation::Or { a, b }, - ), - map( - separated_pair(expression_nonrecurse, token(tk::BitXor), expression), - |(a, b)| Operation::Xor { a, b }, - ), - map(preceded(token(tk::BitNot), expression), Operation::Not), - ))(input) -} - -fn call_item(input: TokenSpan) -> IResult { - map( - tuple(( - token(tk::Ident), - delimited( - token(tk::LParen), - separated_list0(token(tk::Comma), expression), - token(tk::RParen), - ), - )), - |(name, args)| Call { - name: name.span(), - args, - }, - )(input) -} - -/// parser combinators can not parse left-recursive grammars. To work around this, we split -/// expressions into a recursive and non-recursive portion. -/// Parsers reachable from this point must call expression_nonrecurse instead -fn expression(input: TokenSpan) -> IResult { - alt(( - map(operation, |op| Expression::Operation(Box::new(op))), - expression_nonrecurse, - ))(input) -} - -/// the portion of the expression grammar that can be parsed without left recursion -fn expression_nonrecurse(input: TokenSpan) -> IResult { - alt(( - map(token(tk::Number), |_| Expression::Literal(42)), - map(call_item, |call| Expression::Call(Box::new(call))), - map(token(tk::Ident), |ident| { - Expression::Ident(*ident.span().fragment()) - }), - delimited(token(tk::LParen), expression, token(tk::RParen)), - ))(input) -} - -fn assign_statement(input: TokenSpan) -> IResult { - map( - separated_pair(token(tk::Ident), token(tk::EqAssign), expression), - |(lhs, expr)| Assign { - lhs: (*lhs.span().fragment()), - expr, - }, - )(input) -} - pub fn parse(input: TokenSpan) -> IResult { module(input) } diff --git a/src/parser/expression.rs b/src/parser/expression.rs new file mode 100644 index 0000000..14de774 --- /dev/null +++ b/src/parser/expression.rs @@ -0,0 +1,97 @@ +use super::tokens::{token, TokenKind as tk, TokenSpan}; +use super::{IResult, Span}; +use nom::{ + branch::alt, + combinator::map, + multi::separated_list0, + sequence::{delimited, preceded, separated_pair, tuple}, +}; + +#[derive(Debug, Clone)] +pub enum Operation<'a> { + And { + a: Expression<'a>, + b: Expression<'a>, + }, + Or { + a: Expression<'a>, + b: Expression<'a>, + }, + Xor { + a: Expression<'a>, + b: Expression<'a>, + }, + Not(Expression<'a>), +} + +pub fn operation(input: TokenSpan) -> IResult { + // temporarily given up on before I learn the shunting yard algorithm + alt(( + map( + separated_pair(expression_nonrecurse, token(tk::BitAnd), expression), + |(a, b)| Operation::And { a, b }, + ), + map( + separated_pair(expression_nonrecurse, token(tk::BitOr), expression), + |(a, b)| Operation::Or { a, b }, + ), + map( + separated_pair(expression_nonrecurse, token(tk::BitXor), expression), + |(a, b)| Operation::Xor { a, b }, + ), + map(preceded(token(tk::BitNot), expression), Operation::Not), + ))(input) +} + +#[derive(Debug, Clone)] +pub struct Call<'a> { + pub name: Span<'a>, + pub args: Vec>, +} + +pub fn call_item(input: TokenSpan) -> IResult { + map( + tuple(( + token(tk::Ident), + delimited( + token(tk::LParen), + separated_list0(token(tk::Comma), expression), + token(tk::RParen), + ), + )), + |(name, args)| Call { + name: name.span(), + args, + }, + )(input) +} + +#[derive(Debug, Clone)] +pub enum Expression<'a> { + Ident(&'a str), + Literal(u64), + Call(Box>), + Operation(Box>), +} + +/// parser combinators can not parse left-recursive grammars. To work around this, we split +/// expressions into a recursive and non-recursive portion. +/// Parsers reachable from this point must call expression_nonrecurse instead +pub fn expression(input: TokenSpan) -> IResult { + alt(( + map(operation, |op| Expression::Operation(Box::new(op))), + expression_nonrecurse, + ))(input) +} + +/// the portion of the expression grammar that can be parsed without left recursion +fn expression_nonrecurse(input: TokenSpan) -> IResult { + alt(( + map(token(tk::Number), |_| Expression::Literal(42)), + map(call_item, |call| Expression::Call(Box::new(call))), + map(token(tk::Ident), |ident| { + Expression::Ident(*ident.span().fragment()) + }), + delimited(token(tk::LParen), expression, token(tk::RParen)), + ))(input) +}