use crate::{
lexer::{Token, TokenType},
utility::{
res::Res,
debug::Log
}
};
mod grammar;
use grammar::{
GRAMMAR,
Rule,
Item
};
#[derive(Clone)]
pub enum Refined {
Token(Token),
Node(Node)
}
#[derive(Clone)]
pub struct Node {
pub name: String,
pub children: Vec<Refined>
}
pub struct SyntaxTree {
children: Vec<Node>
}
fn print_refined(data: Refined, indent: &str, is_last: bool) {
let marker = if is_last { "└──" } else { "├──" };
print!("{indent}");
print!("{marker}");
match data {
Refined::Token(token) => {
print!("{token}");
println!();
},
Refined::Node(node) => {
print!("{}", node.name);
println!();
if node.children.is_empty() { return }
let indent = format!("{indent}{}", if is_last {" "} else {"│ "});
let mut index = 1;
let last_index = node.children.len();
for child in node.children {
print_refined(child, &indent, index == last_index);
index += 1;
}
},
}
}
impl SyntaxTree {
pub fn pretty_print(&self) {
for node in &self.children {
print_refined(
Refined::Node(node.clone()),
"",
false
)
}
}
}
struct Parser {
tokens: Vec<Token>,
index: usize,
current: Option<Token>
}
impl Parser {
#[inline]
pub fn new(tokens: Vec<Token>) -> Self {
Self {
tokens,
index: 0,
current: None
}
}
fn next(&mut self) {
self.index += 1;
self.current = self.tokens.get(self.index).cloned();
}
#[inline]
fn get_current(&self) -> Option<Token> {
self.current.clone()
}
#[allow(clippy::only_used_in_recursion)]
fn check_item(&self, item: &Item, current: &Token) -> bool {
match item {
Item::Token(tt)
| Item::IgnoredToken(tt)
| Item::OptionalToken(tt) => {
return (tt.varies() && (¤t.data == tt))
|| current.data.teq(tt)
},
Item::OneOf(_, _) => unimplemented!(),
Item::Rule(r)
| Item::MinToManyRule(_, r)
| Item::OptionalRule(r) => {
return self.check_item(
&r.requests[0],
current
)
}
}
}
#[inline]
fn check_rule(&mut self, rule: &Rule) -> bool {
return self.check_item(
&rule.requests[0],
&self.get_current().unwrap()
);
}
fn process_request(&mut self, item: &Item) -> Option<Result<Refined, Log>> {
let current = self.get_current().unwrap();
match item {
Item::Token(tt) => {
if self.check_item(item, ¤t) {
let tok = current;
self.next();
return Some(Ok(
Refined::Token(tok)
));
} else {
panic!("Expected `{tt:?}` got `{:?}`", current.data)
}
},
Item::Rule(r) => {
let result = self.process_rule(r);
match result {
Ok(node) => return Some(Ok(
Refined::Node(node)
)),
Err(log) => return Some(
Err(log)
),
}
},
Item::OptionalToken(_) => {
if self.check_item(item, ¤t) {
let tok = current;
self.next();
return Some(Ok(
Refined::Token(tok)
));
} else {
return None
}
},
Item::OptionalRule(r) => {
if self.check_rule(r) {
let result = self.process_rule(r);
match result {
Ok(node) => return Some(Ok(
Refined::Node(node)
)),
Err(log) => return Some(
Err(log)
),
}
} else {
todo!()
}
},
Item::OneOf(options, error) => {
for option in *options {
if !self.check_item(option, ¤t) { continue }
let proc = self.process_request(option);
if proc.is_none() { continue
} else {
match proc.unwrap() {
Ok(result) => return Some(
Ok(result)
),
Err(log) => return Some(
Err(log)
)
}
}
}
panic!("{error}");
},
Item::IgnoredToken(tt) => {
if self.check_item(item, ¤t) {
self.next();
return None
} else {
panic!("Expected `{tt:?}` got `{:?}`", current.data)
}
},
Item::MinToManyRule(min, r) => {
let mut all = Vec::<Refined>::new();
if self.check_rule(r) {
let result = self.process_rule(r);
match result {
Ok(node) => all.push(Refined::Node(node)),
Err(log) => return Some(
Err(log)
),
}
} else {
if min < &1 { return None }
todo!()
}
let mut index = 1;
'inf: loop {
if self.check_rule(r) {
let result = self.process_rule(r);
match result {
Ok(node) => all.push(Refined::Node(node)),
Err(log) => return Some(
Err(log)
),
}
} else {
if &index >= min { break 'inf }
todo!()
}
index += 1;
}
return Some(Ok(
Refined::Node(Node {
name: r.name.to_owned(),
children: all
})
))
},
}
}
fn process_rule(&mut self, rule: &Rule) -> Result<Node, Log> {
let mut processed = Vec::<Refined>::new();
for request in rule.requests {
let proc = self.process_request(request);
if proc.is_none() { continue
} else {
let unwrap = proc.unwrap();
match unwrap {
Ok(result) => processed.push(result),
Err(log) => return Err(log)
}
}
}
return Ok(Node {
name: rule.name.to_owned(),
children: processed
})
}
pub fn parse(&mut self, filename: String, source: String) -> Res<SyntaxTree> {
let mut res = Res::<SyntaxTree>::new(filename, source);
let mut nodes = Vec::<Node>::new();
self.current = self.tokens.get(self.index).cloned();
while self.current.is_some() {
for rule in GRAMMAR {
if !self.check_rule(rule) { continue }
let result = self.process_rule(rule);
match result {
Ok(node) => nodes.push(node),
Err(log) => { res.fail(log); break }
}
};
if let Some(current) = &self.current {
if current.data == TokenType::Eof { break }
}
}
if !res.has_errors() {
res.success(SyntaxTree {
children: nodes
})
}
return res
}
}
pub fn parse(filename: impl Into<String>, source: impl Into<String>, tokens: &Vec<Token>) -> Res<SyntaxTree> {
if tokens.is_empty() { panic!("No tokens to parse") }
let filename = filename.into();
let source = source.into();
let mut parser = Parser::new(tokens.clone());
return parser.parse(filename, source)
}