use peg;
use crate::node;
peg::parser!
(
pub grammar custom_language() for str
{
pub rule parse() -> Vec<node::Node>
= value : sentences()
rule sentences() -> Vec<node::Node>
= sentence() ** end_of_line()
rule sentence() -> node::Node
= print() / if() / for() / let() / _ { node::Node::Nop }
rule print() -> node::Node
= "print" _ "\"" value : $([^ '"']*) "\""
{ node::Node::PrintString(value.to_string()) }
/ "print" _ value : calc()
{ node::Node::Print(Box::new(value)) }
rule if() -> node::Node = "if" _ value : if_cond() { value }
rule if_cond() -> node::Node
= if_elif() / if_else() / if_true_only()
rule if_elif() -> node::Node
= condition_node : calc() true_node_vector : block() lf() "elif" _ false_node_vector : if_cond()
{ node::Node::if_(condition_node, true_node_vector, vec![false_node_vector]) }
rule if_else() -> node::Node
= condition_node : calc() true_node_vector : block() lf() "else" _ false_node_vector : block()
{ node::Node::if_(condition_node, true_node_vector, false_node_vector) }
rule if_true_only() -> node::Node
= condition_node : calc() true_node_vector : block()
{ node::Node::if_(condition_node, true_node_vector, vec![]) }
rule block() -> Vec<node::Node>
= "{" _ value : sentences() _ "}" _ { value }
rule for() -> node::Node
= "for" _ variable_name : word() _ "=" _ start : number() _ "to" _ end : number() _ body : block()
{ node::Node::For(variable_name, start, end, Box::new(body)) }
rule let() -> node::Node
= variable_name : word() _ "=" _ value : calc()
{ node::Node::SetVariable(variable_name, Box::new(value))}
rule calc() -> node::Node = comp()
rule comp() -> node::Node
= left : expr() "==" _ right : comp() { node::Node::expression('=', left, right) }
/ left : expr() "!=" _ right : comp() { node::Node::expression('!', left, right) }
/ left : expr() ">" _ right : comp() { node::Node::expression('>', left, right) }
/ left : expr() ">=" _ right : comp() { node::Node::expression('g', left, right) }
/ left : expr() "<" _ right : comp() { node::Node::expression('<', left, right) }
/ left : expr() "<=" _ right : comp() { node::Node::expression('l', left, right) }
/ expr()
rule expr() -> node::Node
= left : term() "+" _ right : calc() { node::Node::expression('+', left, right) }
/ left : term() "-" _ right : calc() { node::Node::expression('-', left, right) }
/ term()
rule term() -> node::Node
= left : val() "*" _ right : term() { node::Node::expression('*', left, right) }
/ left : val() "/" _ right : term() { node::Node::expression('/', left, right) }
/ left : val() "%" _ right : term() { node::Node::expression('%', left, right) }
/ val()
rule val() -> node::Node
= "(" _ value : calc() _ ")" _ { value }
/ value : number() _ { node::Node::Number(value) }
/ value : word() _ { node::Node::GetVariable(value) }
rule number() -> i64
= value : $(['0'..='9']+) { value.parse().unwrap() }
rule word() -> String
= value : $(['a'..='z'|'A'..='Z'|'_']+ ['0'..='9']*)
{ String::from(value) }
rule end_of_line() = [';' | '\n']+ _ // 문장 나누기
rule lf() = _ ['\n']* _ // 줄바꿈
rule _ = [' ' | '\t']* // 공백문자
}
);