pub mod ast;
pub mod complete;
pub mod emit;
pub mod highlight;
pub mod lint;
pub mod parser;
pub mod render;
pub mod resolve;
#[cfg(feature = "reedline")]
pub mod complete_reedline;
#[cfg(test)]
mod shape_tests;
pub const GRAMMAR: &str = include_str!("nibli_kr.pest");
use nibli_types::ast::{AstBuffer, ParseResult};
use nibli_types::error::{NibliError, SyntaxDetail};
fn to_nibli(e: parser::ParseError) -> NibliError {
NibliError::Syntax(SyntaxDetail {
message: e.message,
line: e.line,
column: e.column,
})
}
pub fn parse_checked(text: &str) -> Result<AstBuffer, NibliError> {
let statements = parser::parse_statements(text).map_err(to_nibli)?;
emit::emit(text, &statements).map_err(to_nibli)
}
pub fn parse_text(text: &str) -> ParseResult {
let (statements, parse_errors) = parser::parse_text_with_errors(text);
let (buffer, emit_errors) = emit::emit_recovering(text, &statements);
let errors = parse_errors
.into_iter()
.chain(emit_errors)
.map(|e| nibli_types::ast::ParseError {
message: e.message,
line: e.line,
column: e.column,
})
.collect();
ParseResult { buffer, errors }
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn parse_text_recovers_per_statement_with_rollback() {
let r = parse_text("dog(Rex). zzq(me). goes(me, some market).");
assert_eq!(r.errors.len(), 1, "{:?}", r.errors);
assert!(
r.errors[0].message.contains("unknown predicate"),
"{:?}",
r.errors
);
assert_eq!(r.buffer.roots.len(), 2, "two survivors");
let rendered = render::render(&r.buffer).unwrap();
assert!(rendered.contains("dog(Rex)"), "{rendered}");
assert!(rendered.contains("goes(me, some market)"), "{rendered}");
assert!(!rendered.contains("zzq"), "{rendered}");
nibli_semantics::compile_from_ast(r.buffer).unwrap();
}
#[test]
fn parse_text_resets_walk_state_after_a_failed_statement() {
let r = parse_text("every dog where zzq(it, you) $d: big($d). big(it).");
assert_eq!(r.errors.len(), 2, "{:?}", r.errors);
assert!(
r.errors[0].message.contains("unknown predicate"),
"{:?}",
r.errors
);
assert!(
r.errors[1].message.contains("where/also clause body"),
"{:?}",
r.errors
);
assert!(r.buffer.roots.is_empty(), "no survivors");
assert!(r.buffer.sentences.is_empty(), "rollback left nodes behind");
}
}