Files
vulcan/forge_core/src/parser/mod.rs
T

93 lines
3.0 KiB
Rust
Raw Normal View History

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;
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.
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 {
pub(crate) fn parse(src: &str) -> Result<Self, ParseError> {
Self::from_str(src)
}
}