2023-08-13 23:55:49 -05:00
|
|
|
use pest::pratt_parser::PrattParser;
|
2023-07-08 19:09:32 -05:00
|
|
|
use pest::Parser;
|
2023-07-02 02:10:06 -05:00
|
|
|
|
2023-11-11 15:59:04 -06:00
|
|
|
use crate::ast::*;
|
|
|
|
|
pub use pairs_ext::*;
|
|
|
|
|
pub use parse_error::ParseError;
|
|
|
|
|
|
|
|
|
|
mod parse_error;
|
|
|
|
|
mod pairs_ext;
|
|
|
|
|
mod ast_nodes;
|
|
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
|
mod test_utils;
|
|
|
|
|
|
2023-07-08 22:31:53 -05:00
|
|
|
#[derive(Parser)]
|
2023-11-09 22:58:26 -06:00
|
|
|
#[grammar = "parser/forge.pest"]
|
2023-07-08 22:31:53 -05:00
|
|
|
struct ForgeParser;
|
|
|
|
|
|
|
|
|
|
lazy_static::lazy_static! {
|
|
|
|
|
static ref PRATT_PARSER: PrattParser<Rule> = {
|
|
|
|
|
use pest::pratt_parser::{Assoc::*, Op};
|
|
|
|
|
use Rule::*;
|
|
|
|
|
|
|
|
|
|
// Precedence is defined lowest to highest
|
|
|
|
|
PrattParser::new()
|
2023-07-08 23:08:22 -05:00
|
|
|
.op(Op::infix(log_or, Left))
|
|
|
|
|
.op(Op::infix(log_and, Left))
|
|
|
|
|
.op(Op::infix(bit_or, Left))
|
|
|
|
|
.op(Op::infix(xor, Left))
|
|
|
|
|
.op(Op::infix(bit_and, Left))
|
|
|
|
|
.op(Op::infix(eq, Left) | Op::infix(ne, Left))
|
|
|
|
|
.op(Op::infix(gt, Left) | Op::infix(ge, Left) | Op::infix(lt, Left) | Op::infix(le, Left))
|
|
|
|
|
.op(Op::infix(lshift, Left) | Op::infix(rshift, Left))
|
2023-07-08 22:31:53 -05:00
|
|
|
.op(Op::infix(add, Left) | Op::infix(sub, Left))
|
|
|
|
|
.op(Op::infix(mul, Left) | Op::infix(div, Left) | Op::infix(modulus, Left))
|
2023-07-08 23:33:30 -05:00
|
|
|
.op(Op::prefix(Rule::prefix))
|
2023-08-05 11:07:09 -05:00
|
|
|
.op(Op::postfix(Rule::arglist))
|
|
|
|
|
.op(Op::postfix(Rule::subscript))
|
2023-07-08 22:31:53 -05:00
|
|
|
};
|
2023-07-02 02:10:06 -05:00
|
|
|
}
|
|
|
|
|
|
2023-11-09 23:23:44 -06:00
|
|
|
/// Make some Pest types a little more ergonomic to refer to, especially outside this file:
|
2023-11-09 22:58:26 -06:00
|
|
|
pub type PestRule = Rule;
|
2023-07-03 01:35:37 -05:00
|
|
|
pub(crate) type Pair<'a> = pest::iterators::Pair<'a, Rule>;
|
|
|
|
|
pub(crate) type Pairs<'i, R = Rule> = pest::iterators::Pairs<'i, R>;
|
2023-07-02 02:10:06 -05:00
|
|
|
|
2023-11-09 23:23:44 -06:00
|
|
|
/// A trait that represents something that can be parsed into an AST node: impl this to turn
|
|
|
|
|
/// a pair into your node, by from_pair-ing child nodes.
|
2023-07-03 23:11:44 -05:00
|
|
|
trait AstNode: Sized {
|
2023-07-03 01:35:37 -05:00
|
|
|
const RULE: Rule;
|
2023-07-03 23:11:44 -05:00
|
|
|
fn from_pair(pair: Pair) -> Self;
|
2023-08-20 01:38:42 -05:00
|
|
|
fn from_pair_located(pair: Pair) -> Located<Self> {
|
|
|
|
|
let loc = pair.line_col();
|
|
|
|
|
Located {
|
|
|
|
|
location: loc.into(),
|
|
|
|
|
ast: Self::from_pair(pair)
|
|
|
|
|
}
|
|
|
|
|
}
|
2023-07-03 23:11:44 -05:00
|
|
|
}
|
|
|
|
|
|
2023-11-09 23:23:44 -06:00
|
|
|
/// A companion trait to AstNode: Parseable things can be parsed from strings, and Parseable
|
|
|
|
|
/// AstNodes have a default way of doing that (using the ForgeParser to make a pair and then
|
|
|
|
|
/// from_pair-ing it
|
2023-07-03 23:11:44 -05:00
|
|
|
trait Parseable: Sized {
|
2023-07-08 22:31:53 -05:00
|
|
|
fn from_str(src: &str) -> Result<Self, ParseError>;
|
2023-07-03 23:11:44 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl<T: AstNode> Parseable for T {
|
2023-07-08 22:31:53 -05:00
|
|
|
fn from_str(src: &str) -> Result<Self, ParseError> {
|
2023-07-03 01:35:37 -05:00
|
|
|
let pair = ForgeParser::parse(Self::RULE, src)
|
|
|
|
|
.map_err(ParseError::from)?
|
|
|
|
|
.next()
|
|
|
|
|
.unwrap();
|
2023-07-03 23:11:44 -05:00
|
|
|
Ok(Self::from_pair(pair))
|
2023-07-03 01:35:37 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-11-09 23:23:44 -06:00
|
|
|
/// Try and parse a program into an AST node. A convenience method (since Program is both
|
|
|
|
|
/// Parseable and an AstNode) but also the outside entry point into this whole module.
|
2023-07-12 00:53:52 -05:00
|
|
|
pub fn parse(src: &str) -> Result<Program, ParseError> {
|
|
|
|
|
Program::from_str(src)
|
|
|
|
|
}
|
|
|
|
|
|
2023-07-03 23:11:44 -05:00
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////
|
2023-07-03 01:35:37 -05:00
|
|
|
|
2023-11-10 15:41:31 -06:00
|
|
|
// todo: can this die? it's only used in compiler tests but needs to be here for visibility reasons
|
2023-11-11 15:59:04 -06:00
|
|
|
#[cfg(test)]
|
2023-08-02 21:56:26 -05:00
|
|
|
impl Expr {
|
2023-07-12 00:53:52 -05:00
|
|
|
pub(crate) fn parse(src: &str) -> Result<Self, ParseError> {
|
|
|
|
|
Self::from_str(src)
|
|
|
|
|
}
|
|
|
|
|
}
|