use json;
use tree_sitter;
use tree_sitter_applesoft;
use crate::lang;
use crate::lang::Visit;
use super::minify_guards;
use crate::DYNERR;
pub struct Minifier
{
line: String,
minified_line: String,
minified_program: String,
var_guards: json::JsonValue
}
impl lang::Visit for Minifier
{
fn visit(&mut self,curs:&tree_sitter::TreeCursor) -> lang::WalkerChoice
{
let node_str: String = lang::node_text(curs.node(),&self.line);
if curs.node().kind().starts_with("name_") {
let txt = node_str.replace(" ","");
if txt.len()>3 && (curs.node().kind()=="name_str" || curs.node().kind()=="name_int") {
self.minified_line += &txt[0..2];
self.minified_line += &txt[txt.len()-1..txt.len()];
} else if txt.len()>2 && curs.node().kind()!="name_str" && curs.node().kind()!="name_int" {
if !self.needs_guard(&txt,curs) {
self.minified_line += &txt[0..2];
} else {
if txt.len() > 4 {
self.minified_line += "(";
self.minified_line += &txt[0..2];
self.minified_line += ")";
} else {
self.minified_line += &txt;
}
}
} else {
self.minified_line += &txt;
}
return lang::WalkerChoice::GotoSibling;
}
if curs.node().kind()=="statement" {
if let Some(tok) = curs.node().named_child(0) {
if tok.kind()=="tok_rem" {
if let Some(prev) = curs.node().prev_named_sibling() {
if prev.kind()=="statement" {
return lang::WalkerChoice::GotoSibling;
}
}
self.minified_line += "REM";
return lang::WalkerChoice::GotoSibling;
}
if tok.kind()=="tok_data" || tok.kind()=="tok_amp" {
self.minified_line += &node_str;
return lang::WalkerChoice::GotoSibling;
}
}
}
if curs.node().kind()=="str" {
let mut curr = curs.node();
while curr.kind()!="line" {
if curr.next_sibling()!=None {
self.minified_line += node_str.trim_start();
return lang::WalkerChoice::GotoSibling;
}
if curr.parent()==None {
break;
};
curr = curr.parent().unwrap();
}
if node_str.ends_with("\"") && node_str.len()>1 {
self.minified_line += &node_str[0..node_str.len()-1].trim_start();
} else {
self.minified_line += node_str.trim_start();
}
return lang::WalkerChoice::GotoSibling;
}
if !curs.node().is_named() && node_str==":" {
if let Some(next) = curs.node().next_sibling() {
if !next.is_named() && lang::node_text(next, &self.line)==":" {
return lang::WalkerChoice::GotoSibling; }
} else {
return lang::WalkerChoice::GotoSibling; }
}
if curs.node().named_child_count()==0 {
self.minified_line += &node_str.replace(" ","");
if curs.node().kind()=="tok_at" {
self.minified_line += " ";
}
return lang::WalkerChoice::GotoSibling;
}
return lang::WalkerChoice::GotoChild;
}
}
impl Minifier
{
pub fn new() -> Self
{
Self {
line: String::new(),
minified_line: String::new(),
minified_program: String::new(),
var_guards: json::parse(minify_guards::VAR_GUARDS_JSON).expect("json error")
}
}
fn needs_guard(&self,clean_str: &str,curs: &tree_sitter::TreeCursor) -> bool {
let short_str = clean_str[0..2].to_lowercase();
let cannot_follow = &self.var_guards[short_str];
if let Some(mut parent) = curs.node().parent() {
while parent.next_named_sibling()==None {
if parent.parent()==None {
return false;
}
parent = parent.parent().unwrap();
}
let next = parent.next_named_sibling().unwrap();
return cannot_follow.contains(next.kind());
}
return false;
}
pub fn minify(&mut self,program: &str) -> Result<String,DYNERR> {
self.minified_program = String::new();
let mut parser = tree_sitter::Parser::new();
parser.set_language(tree_sitter_applesoft::language()).expect("error loading applesoft grammar");
for line in program.lines() {
if line.len()==0 {
continue;
}
self.minified_line = String::from(line) + "\n";
for _rep in 0..10 {
self.line = self.minified_line.clone();
self.minified_line = String::new();
let tree = parser.parse(&self.line,None).expect("Error parsing file");
self.walk(&tree);
self.minified_line.push('\n');
if self.minified_line==self.line {
break;
}
}
self.minified_program += &self.minified_line;
}
Ok(self.minified_program.clone())
}
}