use std::collections::{HashMap, HashSet};
use std::ops::Not;
use log::debug;
use crate::ast::CommandParam::Keywords;
use crate::ast::TemplateAst::{ItemBranch, ItemCommand};
use crate::ast::{Branch, CommandParam, TemplateAst};
use crate::compile::ast_stack::TmplAstStack;
use crate::err::TemplateError::GenericError;
use crate::err::TmplResult;
use crate::utils::str::is_expr;
#[derive(Debug)]
pub enum ParamSyntax {
Keywords(String),
Assignment,
Expression,
StaticValue,
}
#[derive(Debug)]
pub struct CommandSyntax {
key: String,
syntax: HashMap<String, Vec<ParamSyntax>>,
}
impl CommandSyntax {
pub fn build(&self, src: &str) -> TmplResult<Branch> {
if src.starts_with(&self.key).not() {
return Err(GenericError(format!(
"源码与操作符不匹配:{:?} != {:?}",
src, self
)));
}
for (key, param_syntax_arr) in &self.syntax {
let mut result: Vec<CommandParam> = vec![];
let mut src = src.trim();
for param_syntax in param_syntax_arr {
match param_syntax {
ParamSyntax::Keywords(key) => {
if src.starts_with(&format!("{} ", key)) {
src = &src[key.len() + 1..];
result.push(Keywords)
} else {
continue;
}
}
ParamSyntax::Assignment => {
if let Some(end) = src.find("=") {
let param = &src[..end].trim();
let params = if param.starts_with("(") && param.ends_with(")") {
param.split(",").collect::<Vec<&str>>()
} else {
vec![*param]
};
if let Some(inv_expr) = params.iter().find(|e| is_expr(**e).not()) {
debug!("变量 {:?} 格式错误!", inv_expr);
continue;
}
result.push(CommandParam::Assignment(
params.iter().map(|e| e.to_string()).collect(),
))
} else {
continue;
}
}
ParamSyntax::Expression => {}
ParamSyntax::StaticValue => {}
}
}
return Ok(Branch::new(&key.as_str(), result));
}
return Err(GenericError(format!(
"表达式 {} 未找到匹配的解析规则!",
src
)));
}
pub fn new(tag: &str, syntax: Vec<(&str, Vec<ParamSyntax>)>) -> Self {
CommandSyntax {
key: tag.to_string(),
syntax: syntax
.into_iter()
.map(|(k, v)| (k.to_string(), v))
.collect(),
}
}
pub fn to_stage(self, bind: Vec<StageConstraint>) -> ChildStageSyntax {
ChildStageSyntax::new(self, bind)
}
pub fn new_empty_param(tag: &str) -> Self {
Self::new(tag, vec![])
}
}
#[derive(Debug)]
pub struct ChildStageSyntax {
tag: CommandSyntax,
bind: HashSet<StageConstraint>,
}
impl ChildStageSyntax {
pub fn new(tag: CommandSyntax, bind: Vec<StageConstraint>) -> Self {
ChildStageSyntax {
tag,
bind: bind.into_iter().collect(),
}
}
pub fn new_no_bind(tag: CommandSyntax) -> Self {
Self::new(tag, vec![])
}
}
#[derive(Debug, Eq, PartialOrd, PartialEq, Hash)]
pub enum StageConstraint {
SINGLE,
}
#[derive(Debug)]
pub struct BranchSyntax {
pub start: CommandSyntax,
pub child_state: Vec<ChildStageSyntax>,
pub end: CommandSyntax,
}
impl BranchSyntax {
pub fn new(start: CommandSyntax, child: Vec<ChildStageSyntax>, end: CommandSyntax) -> Self {
BranchSyntax {
start,
child_state: child,
end,
}
}
pub fn get_matched_type(&self, tag: &str) -> Option<&ChildStageSyntax> {
self.child_state
.iter()
.find(|e| tag.starts_with(&e.tag.key))
}
}
#[derive(Debug)]
pub struct BranchSyntaxWrapper {
pub syntax: BranchSyntax,
pub scopes: Vec<String>,
pub auto_loop: bool,
}
#[derive(Debug)]
pub struct CommandSyntaxWrapper {
pub syntax: CommandSyntax,
pub scope: Vec<String>,
}
#[derive(Debug)]
pub enum OperatorSyntax {
Branch(BranchSyntaxWrapper),
Command(CommandSyntaxWrapper),
}
impl OperatorSyntax {
pub fn new_branch(block: BranchSyntax, scope: Vec<&str>, loop_branch: bool) -> Self {
OperatorSyntax::Branch(BranchSyntaxWrapper {
syntax: block,
scopes: scope.iter().map(|e| e.to_string()).collect(),
auto_loop: loop_branch,
})
}
pub fn new_command(tag: CommandSyntax, scope: Vec<&str>) -> Self {
OperatorSyntax::Command(CommandSyntaxWrapper {
syntax: tag,
scope: scope.iter().map(|e| e.to_string()).collect(),
})
}
pub fn get_start_tag(&self) -> &str {
match self {
OperatorSyntax::Branch(item) => &item.syntax.start.key,
OperatorSyntax::Command(item) => &item.syntax.key,
}
}
pub fn get_scope(&self) -> &Vec<String> {
match self {
OperatorSyntax::Branch(item) => &item.scopes,
OperatorSyntax::Command(item) => &item.scope,
}
}
pub fn check_scope(&self, stack: &TmplAstStack) -> TmplResult<()> {
stack
.check_scope(self.get_scope())
.map_err(|e| GenericError(format!("解析{:?} 失败,{}", self, e)))
}
pub fn build_ast(&self, start: &str) -> TmplResult<TemplateAst> {
Ok(match self {
OperatorSyntax::Branch(b) => ItemBranch(
b.syntax.start.key.to_string(),
vec![b.syntax.start.build(start)?],
b.auto_loop,
),
OperatorSyntax::Command(c) => {
ItemCommand(c.syntax.key.to_string(), c.syntax.build(start)?.params)
}
})
}
}