diff --git a/Cargo.lock b/Cargo.lock index 846050e..e602ddc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -292,7 +292,7 @@ checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" [[package]] name = "mindustry_logic_bang_lang" -version = "0.14.12" +version = "0.14.13" dependencies = [ "display_source", "parser", @@ -525,7 +525,7 @@ dependencies = [ [[package]] name = "syntax" -version = "0.2.9" +version = "0.2.10" dependencies = [ "tag_code", "utils", diff --git a/Cargo.toml b/Cargo.toml index 12a2c19..b3d0106 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "mindustry_logic_bang_lang" -version = "0.14.12" +version = "0.14.13" edition = "2021" authors = ["A4-Tacks "] diff --git a/examples/builtin_functions.mdtlbl b/examples/builtin_functions.mdtlbl index d1ab999..cb03848 100644 --- a/examples/builtin_functions.mdtlbl +++ b/examples/builtin_functions.mdtlbl @@ -22,6 +22,9 @@ * * `SliceArgs[start end]`: 将参数切分, 但不take * * `ArgsHandle[idx]`: 拿到指定下标的参数的const句柄, 配合Const内置函数转移其值 * * `MetaDebug[]`: 以调试形式输出编译时元数据 +* * `MaxExpandDepth[]`: 获取最大展开层数限制 +* * `SetMaxExpandDepth[depth]`: 设置最大展开层数限制 +* * `ExpandStack[]`: 调试输出当前展开栈情况 *# print Builtin.Type[x]; diff --git a/tools/syntax/Cargo.toml b/tools/syntax/Cargo.toml index 144519d..b11ed2e 100644 --- a/tools/syntax/Cargo.toml +++ b/tools/syntax/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "syntax" -version = "0.2.9" +version = "0.2.10" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/tools/syntax/src/builtins.rs b/tools/syntax/src/builtins.rs index b759070..f02700b 100644 --- a/tools/syntax/src/builtins.rs +++ b/tools/syntax/src/builtins.rs @@ -305,5 +305,27 @@ pub fn build_builtins() -> Vec { meta.log_info(msg); Ok("__".into()) } + + fn max_expand_depth:MaxExpandDepth(meta) [] { + Ok(meta.const_expand_max_depth().to_string()) + } + + fn set_max_expand_depth:SetMaxExpandDepth(meta) [d:depth] { + check_type!("var" Value::Var(depth) = depth.value() => { + let depth: usize = match depth.parse() { + Ok(n) => n, + Err(e) => { + return Err((2, e.to_string())) + }, + }; + meta.set_const_expand_max_depth(depth); + Ok("__".into()) + }) + } + + fn expand_stack:ExpandStack(meta) [] { + meta.log_expand_stack(); + Ok("__".into()) + } } } diff --git a/tools/syntax/src/lib.rs b/tools/syntax/src/lib.rs index b2608c9..1822f7e 100644 --- a/tools/syntax/src/lib.rs +++ b/tools/syntax/src/lib.rs @@ -2692,6 +2692,8 @@ pub struct CompileMeta { /// 一个标签从尾部上寻, 寻到就返回找到的, 没找到就返回原本的 /// 所以它支持在宏A内部展开的宏B跳转到宏A内部的标记 const_expand_tag_name_map: Vec>, + const_expand_names: Vec, + const_expand_max_depth: usize, value_binds: HashMap<(Var, Var), Var>, /// 值绑定全局常量表, 只有值绑定在使用它 value_bind_global_consts: HashMap, @@ -2746,6 +2748,8 @@ impl CompileMeta { dexp_expand_binders: Vec::new(), tmp_tag_count: Counter::new(Self::tmp_tag_getter), const_expand_tag_name_map: Vec::new(), + const_expand_names: Vec::new(), + const_expand_max_depth: 500, value_binds: HashMap::new(), value_bind_global_consts: HashMap::new(), last_builtin_exit_code: 0, @@ -3057,6 +3061,19 @@ impl CompileMeta { /// 如果不是一个宏则直接返回None, 也不会进入无需清理 pub fn const_expand_enter(&mut self, name: &Var) -> Option { let label_count = self.get_const_value(name)?.labels().len(); + if self.const_expand_names.len() >= self.const_expand_max_depth { + self.log_err(format!( + "Stack Expand:\n{}", + self.debug_expand_stack() + .collect::>() + .join(", "), + )); + err!( + "Maximum recursion depth exceeded ({})", + self.const_expand_max_depth, + ); + exit(6) + } let mut tmp_tags = Vec::with_capacity(label_count); tmp_tags.extend(repeat_with(|| self.get_tmp_tag()) .take(label_count)); @@ -3077,11 +3094,14 @@ impl CompileMeta { let res = value.clone(); self.dexp_expand_binders.push(binder.clone()); self.const_expand_tag_name_map.push(labels_map); + self.const_expand_names.push(name.clone()); res.into() } - pub fn const_expand_exit(&mut self) -> (HashMap, Option) { + pub fn const_expand_exit(&mut self) + -> (Var, HashMap, Option) { ( + self.const_expand_names.pop().unwrap(), self.const_expand_tag_name_map.pop().unwrap(), self.dexp_expand_binders.pop().unwrap(), ) @@ -3190,6 +3210,22 @@ impl CompileMeta { .trim_end().replace('\n', "\n ")) } + pub fn debug_expand_stack(&self) -> impl Iterator + '_ { + self.const_expand_names().iter() + .zip(&self.dexp_expand_binders) + .map(|x| match x { + (name, Some(binder)) => format!("{name} ..{binder}"), + (name, None) => name.into(), + }) + } + + pub fn log_expand_stack(&mut self) { + let names = self.debug_expand_stack() + .collect::>() + .join("\n"); + self.log_info(format!("Expand Stack:\n{names}")) + } + pub fn last_builtin_exit_code(&self) -> u8 { self.last_builtin_exit_code } @@ -3197,6 +3233,18 @@ impl CompileMeta { pub fn set_last_builtin_exit_code(&mut self, new_code: u8) -> u8 { replace(&mut self.last_builtin_exit_code, new_code) } + + pub fn const_expand_names(&self) -> &[String] { + self.const_expand_names.as_ref() + } + + pub fn const_expand_max_depth(&self) -> usize { + self.const_expand_max_depth + } + + pub fn set_const_expand_max_depth(&mut self, const_expand_max_depth: usize) { + self.const_expand_max_depth = const_expand_max_depth; + } } pub fn line_first_add(lines: &mut Vec, insert: &str) {