use super::*;
use crate::error::Error;
use crate::reader::Reader;
use crate::value::{Dict, RefValue};
use log;
use std::cell::RefCell;
use std::rc::Rc;
use std::thread_local;
thread_local! {
static PARSER: Rc<RefCell<Program>> = {
{
let parser_program = {
#[cfg(feature = "use_cbor_parser")]
{
log::info!("Using pre-compiled parser: _tokay.cbor");
serde_cbor::from_slice(include_bytes!("_tokay.cbor")).unwrap()
}
#[cfg(not(feature = "use_cbor_parser"))]
{
let mut compiler = Compiler::new();
compiler.debug = 0;
log::info!("Using ast-based parser: _tokay.rs");
compiler
.compile_from_ast(&include!("_tokay.rs"), Some("parser".to_string()))
.expect("Tokay grammar cannot be compiled!")
.expect("Tokay grammar contains no main?")
}
};
Rc::new(RefCell::new(parser_program))
}
}
}
pub struct Parser(Rc<RefCell<Program>>);
impl Parser {
pub fn new() -> Self {
Self(PARSER.with(|parser| parser.clone()))
}
pub fn parse(&self, mut reader: Reader) -> Result<RefValue, Error> {
let program = self.0.borrow();
let mut thread = Thread::new(&*program, vec![&mut reader]);
if let Ok(level) = std::env::var("TOKAY_PARSER_DEBUG") {
thread.debug = level.parse::<u8>().unwrap_or_default();
} else {
thread.debug = 0;
}
match thread.run() {
Ok(Some(ast)) => {
if ast.borrow().object::<Dict>().is_some() {
Ok(ast)
} else {
Err(Error::new(None, "Parse error".to_string()))
}
}
Ok(None) => Ok(crate::value!(void)),
Err(error) => Err(error),
}
}
}
#[test]
fn parser_eol() {
for eol in ["\n", "\r", "\r\n", ";"] {
let tok = format!("a = 1{}a + 2", eol);
println!("EOL test {:?}", tok);
assert_eq!(crate::eval(&tok, "", None), Ok(crate::value!(3)));
}
}