#![deny(missing_docs)]
mod event;
pub(crate) mod grammar;
mod marker;
mod parser;
mod sink;
use rowan::GreenNode;
pub struct ParseResult {
pub green: GreenNode,
pub errors: Vec<compactp_diagnostics::Diagnostic>,
}
pub struct ParseOptions {
pub recover: bool,
pub max_errors: usize,
pub max_depth: u32,
}
impl Default for ParseOptions {
fn default() -> Self {
Self {
recover: true,
max_errors: 256,
max_depth: 256,
}
}
}
pub fn parse(source: &str) -> ParseResult {
parse_with(source, ParseOptions::default())
}
pub fn parse_with(source: &str, opts: ParseOptions) -> ParseResult {
let tokens = compactp_lexer::lex(source);
let mut p = parser::Parser::new(tokens.clone());
p.set_options(&opts);
grammar::source_file(&mut p);
let events = p.events;
let (green, errors) = sink::Sink::new(events, tokens).finish();
ParseResult { green, errors }
}
#[cfg(test)]
mod tests {
use super::*;
use compactp_syntax::{SyntaxKind::*, SyntaxNode};
#[test]
fn parse_empty_input() {
let result = parse("");
let root = SyntaxNode::new_root(result.green);
assert_eq!(root.kind(), SOURCE_FILE);
assert!(result.errors.is_empty());
}
#[test]
fn parse_single_ident() {
let result = parse("x");
let root = SyntaxNode::new_root(result.green);
assert_eq!(root.kind(), SOURCE_FILE);
assert_eq!(root.text().to_string(), "x");
assert!(
!result.errors.is_empty(),
"expected a parse error for bare identifier"
);
assert!(!result.errors[0].message.is_empty());
}
#[test]
fn parse_whitespace_preserved() {
let result = parse(" \n ");
let root = SyntaxNode::new_root(result.green);
assert_eq!(root.kind(), SOURCE_FILE);
let text: String = root.text().to_string();
assert_eq!(text, " \n ");
}
#[test]
fn parse_lossless_roundtrip() {
let source = "circuit foo() { return 42; }";
let result = parse(source);
let root = SyntaxNode::new_root(result.green);
assert_eq!(root.text().to_string(), source);
}
}