From 2966a7ba6b7b18a815c2f28d1045b5deba1dc978 Mon Sep 17 00:00:00 2001 From: A4-Tacks Date: Tue, 17 Oct 2023 20:28:55 +0800 Subject: [PATCH] =?UTF-8?q?=E4=B8=BAValueBind=E7=9A=84=E7=94=9F=E6=88=90?= =?UTF-8?q?=E5=8F=A5=E6=9F=84=E7=94=B1=E7=BB=84=E5=90=88=E6=A0=BC=E6=94=B9?= =?UTF-8?q?=E4=B8=BA=E5=8C=BF=E5=90=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Cargo.lock | 7 ++++- Cargo.toml | 3 +- examples/value_bind.mdtlbl | 18 +++++------ src/syntax/mod.rs | 54 +++++++++++++++++++++------------ src/syntax/tests.rs | 8 +++-- tools/utils/.gitignore | 1 + tools/utils/Cargo.lock | 7 +++++ tools/utils/Cargo.toml | 8 +++++ tools/utils/src/counter.rs | 62 ++++++++++++++++++++++++++++++++++++++ tools/utils/src/lib.rs | 3 ++ 10 files changed, 137 insertions(+), 34 deletions(-) create mode 100644 tools/utils/.gitignore create mode 100644 tools/utils/Cargo.lock create mode 100644 tools/utils/Cargo.toml create mode 100644 tools/utils/src/counter.rs create mode 100644 tools/utils/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index 160e381..73176d6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -288,12 +288,13 @@ checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" [[package]] name = "mindustry_logic_bang_lang" -version = "0.12.4" +version = "0.12.5" dependencies = [ "display_source", "lalrpop", "lalrpop-util", "tag_code", + "utils", "var_utils", ] @@ -556,6 +557,10 @@ version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" +[[package]] +name = "utils" +version = "0.1.1" + [[package]] name = "var_utils" version = "0.2.0" diff --git a/Cargo.toml b/Cargo.toml index d7a09b4..5bd3216 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "mindustry_logic_bang_lang" -version = "0.12.4" +version = "0.12.5" edition = "2021" authors = ["A4-Tacks "] @@ -18,6 +18,7 @@ lalrpop = "0.20.0" tag_code = { path = "./tools/tag_code", version = "*" } display_source = { path = "./tools/display_source", version = "*" } var_utils = { path = "./tools/var_utils", version = "*"} +utils = { path = "./tools/utils", version = "*" } [dependencies.lalrpop-util] version = "0.20.0" diff --git a/examples/value_bind.mdtlbl b/examples/value_bind.mdtlbl index 76981ad..6896311 100644 --- a/examples/value_bind.mdtlbl +++ b/examples/value_bind.mdtlbl @@ -17,9 +17,9 @@ take["jack" 18] Human = Human_new; print Human Human.age; #* >>> set __0 "jack" -set ____0__bind__age 18 +set __1 18 print __0 -print ____0__bind__age +print __1 *# # 可以看到, 我们将额外的age绑定到了我们的Human # 这可以用来组织一些复杂结构 @@ -46,13 +46,13 @@ take[Num1 Num2] Num3 = Complex_add; print Num3 "," Num3.i; #* >>> set __0 3 -set ____0__bind__i 5 -set __1 2 -set ____1__bind__i 8 -op add __2 __0 __1 -op add ____2__bind__i ____0__bind__i ____1__bind__i -print __2 +set __1 5 +set __2 2 +set __3 8 +op add __4 __0 __2 +op add __5 __1 __3 +print __4 print "," -print ____2__bind__i +print __5 *# # 可以看到, 这可以使我们方便的组织数据 diff --git a/src/syntax/mod.rs b/src/syntax/mod.rs index 7b714e7..d728977 100644 --- a/src/syntax/mod.rs +++ b/src/syntax/mod.rs @@ -22,6 +22,7 @@ use display_source::{ DisplaySourceMeta, }; pub use crate::tag_code::mdt_logic_split; +use utils::counter::Counter; macro_rules! impl_enum_froms { @@ -430,16 +431,11 @@ impl TakeHandle for ValueBind { // 以`__{}__bind__{}`的形式组合 let handle = self.0.take_handle(meta); assert!(! Value::is_string(&self.1)); - if Value::is_string(&handle) { - err!( - "{}\nValueBind过程中, 左值句柄为字符串, ({}.{})", - meta.err_info().join("\n"), - Value::replace_ident(&handle), - Value::replace_ident(&self.1), - ); - exit(6) - } - format!("__{}__bind__{}", handle, self.1) + let binded + = meta.get_value_binded(handle, self.1).clone(); + // 进行常量表查询, 虽然是匿名量但是还是要有这个行为嘛 + // 虽然之前没有 + binded.take_handle(meta) } } impl DisplaySource for ValueBind { @@ -2131,7 +2127,7 @@ pub struct CompileMeta { tags_map: HashMap, tag_count: usize, tag_codes: TagCodes, - tmp_var_count: usize, + tmp_var_count: Counter Var>, /// 块中常量, 且带有展开次数与内部标记 /// 并且存储了需要泄露的常量 /// @@ -2139,11 +2135,12 @@ pub struct CompileMeta { const_var_namespace: Vec<(Vec, HashMap, Value)>)>, /// 每层DExp所使用的句柄, 末尾为当前层 dexp_result_handles: Vec, - tmp_tag_count: usize, + tmp_tag_count: Counter Var>, /// 每层const展开的标签 /// 一个标签从尾部上寻, 寻到就返回找到的, 没找到就返回原本的 /// 所以它支持在宏A内部展开的宏B跳转到宏A内部的标记 const_expand_tag_name_map: Vec>, + value_binds: HashMap<(Var, Var), Var>, } impl Default for CompileMeta { fn default() -> Self { @@ -2160,11 +2157,12 @@ impl CompileMeta { tags_map: HashMap::new(), tag_count: 0, tag_codes, - tmp_var_count: 0, + tmp_var_count: Counter::new(Self::tmp_var_getter), const_var_namespace: Vec::new(), dexp_result_handles: Vec::new(), - tmp_tag_count: 0, + tmp_tag_count: Counter::new(Self::tmp_tag_getter), const_expand_tag_name_map: Vec::new(), + value_binds: HashMap::new(), } } @@ -2178,17 +2176,33 @@ impl CompileMeta { }) } + fn tmp_tag_getter(id: &mut usize) -> Var { + let old = *id; + *id += 1; + format!("__{old}") + } + /// 获取一个临时的`tag` pub fn get_tmp_tag(&mut self) -> Var { - let id = self.tmp_tag_count; - self.tmp_tag_count += 1; - format!("__{}", id) + self.tmp_tag_count.get() + } + + fn tmp_var_getter(id: &mut usize) -> Var { + let old = *id; + *id += 1; + format!("__{old}") } pub fn get_tmp_var(&mut self) -> Var { - let id = self.tmp_var_count; - self.tmp_var_count += 1; - format!("__{}", id) + self.tmp_var_count.get() + } + + pub fn get_value_binded(&mut self, value: Var, bind: Var) -> &Var { + let key = (value, bind); + self.value_binds.entry(key) + .or_insert_with(|| { + self.tmp_var_count.get() + }) } /// 向已生成代码`push` diff --git a/src/syntax/tests.rs b/src/syntax/tests.rs index 8b9b7d1..df15c68 100644 --- a/src/syntax/tests.rs +++ b/src/syntax/tests.rs @@ -2069,16 +2069,18 @@ fn value_bind_test() { "#).unwrap()).compile().unwrap(); assert_eq!(logic_lines, vec![ "set jack \"jack\"", - "set __jack__bind__age 18", + "set __0 18", "print jack", - "print __jack__bind__age", + "print __0", ]); let logic_lines = CompileMeta::new().compile(parse!(parser, r#" print a.b.c; + print a.b; "#).unwrap()).compile().unwrap(); assert_eq!(logic_lines, vec![ - "print ____a__bind__b__bind__c", + "print __1", + "print __0", ]); } diff --git a/tools/utils/.gitignore b/tools/utils/.gitignore new file mode 100644 index 0000000..ea8c4bf --- /dev/null +++ b/tools/utils/.gitignore @@ -0,0 +1 @@ +/target diff --git a/tools/utils/Cargo.lock b/tools/utils/Cargo.lock new file mode 100644 index 0000000..1014ef1 --- /dev/null +++ b/tools/utils/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "utils" +version = "0.1.0" diff --git a/tools/utils/Cargo.toml b/tools/utils/Cargo.toml new file mode 100644 index 0000000..091e37d --- /dev/null +++ b/tools/utils/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "utils" +version = "0.1.1" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] diff --git a/tools/utils/src/counter.rs b/tools/utils/src/counter.rs new file mode 100644 index 0000000..dd53586 --- /dev/null +++ b/tools/utils/src/counter.rs @@ -0,0 +1,62 @@ +/// 一个负责获取结果并自增的结构 +/// # Examples +/// ``` +/// # use utils::counter::Counter; +/// let mut counter: Counter<_> = Counter::new(|n| { +/// let old = *n; +/// *n += 1; +/// format!("__{old}") +/// }); +/// assert_eq!(counter.get(), "__0"); +/// assert_eq!(counter.get(), "__1"); +/// assert_eq!(counter.get(), "__2"); +/// assert_eq!(counter.get(), "__3"); +/// ``` +#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)] +pub struct Counter +{ + counter: T, + getter: F, +} + +impl Counter +where F: FnMut(&mut T) -> R +{ + pub fn with_counter(f: F, counter: T) -> Self { + Self { + counter, + getter: f + } + } + + pub fn get(&mut self) -> R { + (self.getter)(&mut self.counter) + } +} + +impl Counter +where F: FnMut(&mut T) -> R, + T: Default +{ + pub fn new(f: F) -> Self { + Self::with_counter(f, Default::default()) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test() { + let mut counter: Counter<_> = Counter::new(|n| { + let old = *n; + *n += 1; + format!("__{old}") + }); + assert_eq!(counter.get(), "__0"); + assert_eq!(counter.get(), "__1"); + assert_eq!(counter.get(), "__2"); + assert_eq!(counter.get(), "__3"); + } +} diff --git a/tools/utils/src/lib.rs b/tools/utils/src/lib.rs new file mode 100644 index 0000000..d1f37d4 --- /dev/null +++ b/tools/utils/src/lib.rs @@ -0,0 +1,3 @@ +//! 一系列通用工具 + +pub mod counter;