From 9d0560e5c02aff07dc17153218dea2a7fb3e2bca Mon Sep 17 00:00:00 2001 From: A4-Tacks Date: Tue, 2 Jan 2024 12:32:27 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E7=BB=91=E5=AE=9A=E8=80=85?= =?UTF-8?q?=E5=BC=95=E7=94=A8=E5=8F=8A=E8=AF=AD=E6=B3=95,=20=E4=BF=AE?= =?UTF-8?q?=E5=A4=8D=E4=B8=80=E4=B8=AAbug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 修复对被const的值绑定结果进行take的bug --- Cargo.lock | 10 +- Cargo.toml | 2 +- examples/README.md | 1 + examples/dexp_binder.mdtlbl | 38 ++++++ examples/match.mdtlbl | 31 +++++ tools/display_source/Cargo.toml | 2 +- tools/display_source/src/impls.rs | 1 + tools/parser/Cargo.toml | 2 +- tools/parser/src/parser.lalrpop | 5 +- tools/parser/tests/Cargo.toml | 2 +- tools/parser/tests/src/lib.rs | 204 ++++++++++++++++++++++++++++++ tools/syntax/Cargo.toml | 2 +- tools/syntax/src/lib.rs | 107 ++++++++++------ 13 files changed, 353 insertions(+), 54 deletions(-) create mode 100644 examples/dexp_binder.mdtlbl diff --git a/Cargo.lock b/Cargo.lock index 4761a1a..4e77d2f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -100,7 +100,7 @@ dependencies = [ [[package]] name = "display_source" -version = "0.3.5" +version = "0.3.6" dependencies = [ "parser", "syntax", @@ -292,7 +292,7 @@ checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" [[package]] name = "mindustry_logic_bang_lang" -version = "0.14.3" +version = "0.14.4" dependencies = [ "display_source", "parser", @@ -337,7 +337,7 @@ dependencies = [ [[package]] name = "parser" -version = "0.2.0" +version = "0.2.1" dependencies = [ "lalrpop", "lalrpop-util", @@ -348,7 +348,7 @@ dependencies = [ [[package]] name = "parser-tests" -version = "0.1.1" +version = "0.1.2" dependencies = [ "parser", "syntax", @@ -525,7 +525,7 @@ dependencies = [ [[package]] name = "syntax" -version = "0.2.0" +version = "0.2.1" dependencies = [ "tag_code", "utils", diff --git a/Cargo.toml b/Cargo.toml index 467a82b..d5604b3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "mindustry_logic_bang_lang" -version = "0.14.3" +version = "0.14.4" edition = "2021" authors = ["A4-Tacks "] diff --git a/examples/README.md b/examples/README.md index 74e3abf..e7d0213 100644 --- a/examples/README.md +++ b/examples/README.md @@ -31,6 +31,7 @@ > [`consted_dexp.mdtlbl`](./consted_dexp.mdtlbl)
> [`quick_dexp_take.mdtlbl`](./quick_dexp_take.mdtlbl)
> [`value_bind.mdtlbl`](./value_bind.mdtlbl)
+> [`dexp_binder.mdtlbl`](./dexp_binder.mdtlbl)
> [`caller.mdtlbl`](./caller.mdtlbl)
> [`match.mdtlbl`](./match.mdtlbl)
diff --git a/examples/dexp_binder.mdtlbl b/examples/dexp_binder.mdtlbl new file mode 100644 index 0000000..b0774c6 --- /dev/null +++ b/examples/dexp_binder.mdtlbl @@ -0,0 +1,38 @@ +#** +* 这是0.14.4所添加的新语法, 将会尝试给每个const记录其绑定者, +* 然后可以通过`..`来引用 +* +* 正如ValueBind那章所说, 不要轻易给容易混淆的非匿名量绑定 +* +* 这有什么用呢? 这可以模拟'类型方法' '类型成员'等 +*# + +# 以下一个二维向量的例子 +const Vec2 = ( + take $.X=_0 $.Y=_1; + const $.Add = ( + take Rhs = _0; + take ...X=...X ...Y=...Y; # take + # 为了'简单'的常量求值, 需要先take变成支持的格式 + take X=...X Y=...Y; + take RX=Rhs.X RY=Rhs.Y; + # 需要绑定, 不然只是局部作用域并不是全局作用域 + take ...X = ($ = X + RX;); + take ...Y = ($ = Y + RY;); + ); + const $.Print = ( + print ...X","...Y; + ); +); + +take V1 = Vec2[2 3]; +take V2 = Vec2[3 4]; +take V1.Add[V2]; +take V1.Print; +printflush message1; +#* +print 5 +print "," +print 7 +printflush message1 +*# diff --git a/examples/match.mdtlbl b/examples/match.mdtlbl index 05a83d6..a2389dd 100644 --- a/examples/match.mdtlbl +++ b/examples/match.mdtlbl @@ -18,6 +18,8 @@ * 可以使用重复块, 它将在一个内联块中重复给定块, 并且每次重复迭代指定个参数, * 此数字未指定则为1, 它不能为0, 它是构建期被指定的 * +* 需要注意的是, 在这里`Foo`和`Foo[]`有了区别, `Foo`并不会传进空的参数表 +* * match语句 * === * 改语句由参数输入, 并在之后的块中编写多个分支. @@ -283,3 +285,32 @@ print b print "no." print d *# + + +# 坑点排除, 空参数 +const Foo = ( + match @ { + { + print "empty"; + } + @ { + take N = 0; + inline@{ + take N = ($ = N+1;); + } + print N; + } + } +); +match a b c { @ {} } +print "a"; +take Foo; +print "b"; +take Foo[]; +#* +print "a" +print 3 +print "b" +print "empty" +*# +# 在这里, `Foo`和`Foo[]`的作用已经不同了 diff --git a/tools/display_source/Cargo.toml b/tools/display_source/Cargo.toml index 6a165d9..14b8ecc 100644 --- a/tools/display_source/Cargo.toml +++ b/tools/display_source/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "display_source" -version = "0.3.5" +version = "0.3.6" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/tools/display_source/src/impls.rs b/tools/display_source/src/impls.rs index b9b6f34..6c968e6 100644 --- a/tools/display_source/src/impls.rs +++ b/tools/display_source/src/impls.rs @@ -21,6 +21,7 @@ impl DisplaySource for Value { meta.push("`"); }, Self::ResultHandle => meta.push("$"), + Self::Binder => meta.push(".."), Self::DExp(dexp) => dexp.display_source(meta), Self::ValueBind(value_attr) => value_attr.display_source(meta), Self::Cmper(cmp) => { diff --git a/tools/parser/Cargo.toml b/tools/parser/Cargo.toml index f7278d6..39147a8 100644 --- a/tools/parser/Cargo.toml +++ b/tools/parser/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "parser" -version = "0.2.0" +version = "0.2.1" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/tools/parser/src/parser.lalrpop b/tools/parser/src/parser.lalrpop index 07b0f05..cc6fa31 100644 --- a/tools/parser/src/parser.lalrpop +++ b/tools/parser/src/parser.lalrpop @@ -126,15 +126,16 @@ NonDExpValue: Value = { => v.into(), "`" "`" => ReprVar(<>), // 原始值 "$" => ResultHandle, - > => { + > => { // QuickDExpTake DExp::new("__".into(), vec![ LogicLine::SetArgs(args.unwrap_or_default()), - LogicLine::SetResultHandle(name.into()), + LogicLine::SetResultHandle(name), ].into()).into() }, ValueBind => <>.into(), "goto" > => Value::Cmper(<>.into()), + ".." => Value::Binder, } pub Value: Value = { diff --git a/tools/parser/tests/Cargo.toml b/tools/parser/tests/Cargo.toml index a7ce235..2130253 100644 --- a/tools/parser/tests/Cargo.toml +++ b/tools/parser/tests/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "parser-tests" -version = "0.1.1" +version = "0.1.2" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/tools/parser/tests/src/lib.rs b/tools/parser/tests/src/lib.rs index 003682c..eee96e3 100644 --- a/tools/parser/tests/src/lib.rs +++ b/tools/parser/tests/src/lib.rs @@ -3760,6 +3760,39 @@ fn const_expr_eval_test() { "#).unwrap()).compile().unwrap(), ); + assert_eq!( + CompileMeta::new().compile(parse!(parser, r#" + const N=($ = -3 // 2;); + const N1=($ = -N;); + print N1; + "#).unwrap()).compile().unwrap(), + CompileMeta::new().compile(parse!(parser, r#" + print 2; + "#).unwrap()).compile().unwrap(), + ); + + assert_eq!( + CompileMeta::new().compile(parse!(parser, r#" + const N=($ = -3 // 2;); + take N1=($ = -N;); + print N1; + "#).unwrap()).compile().unwrap(), + CompileMeta::new().compile(parse!(parser, r#" + print 2; + "#).unwrap()).compile().unwrap(), + ); + + assert_eq!( + CompileMeta::new().compile(parse!(parser, r#" + const N=($ = -3 // 2;); + take N=($ = -N;); + print N; + "#).unwrap()).compile().unwrap(), + CompileMeta::new().compile(parse!(parser, r#" + print 2; + "#).unwrap()).compile().unwrap(), + ); + assert_eq!( CompileMeta::new().compile(parse!(parser, r#" print ($ = -2 - 3;); @@ -4282,3 +4315,174 @@ fn value_bind_of_constkey_test() { ], ); } + +#[test] +fn dexp_expand_binder_test() { + let parser = TopLevelParser::new(); + + assert_eq!( + CompileMeta::new().compile(parse!(parser, r#" + print ..; + "#).unwrap()).compile().unwrap(), + vec![ + "print __", + ], + ); + + assert_eq!( + CompileMeta::new().compile(parse!(parser, r#" + const X.Y = ( + print ..; + ); + take X.Y; + "#).unwrap()).compile().unwrap(), + vec![ + "print X", + ], + ); + + assert_eq!( + CompileMeta::new().compile(parse!(parser, r#" + const X.Y = ( + const Foo = ( + print ..; + ); + take Foo; + ); + take X.Y; + "#).unwrap()).compile().unwrap(), + vec![ + "print X", + ], + ); + + assert_eq!( + CompileMeta::new().compile(parse!(parser, r#" + const X.Y = ( + const Foo.Bar = ( + print ..; + ); + take Foo.Bar; + ); + take X.Y; + "#).unwrap()).compile().unwrap(), + vec![ + "print Foo", + ], + ); + + assert_eq!( + CompileMeta::new().compile(parse!(parser, r#" + const X.Y = ( + const Foo.Bar = ( + print ..; + ); + const F = Foo.Bar; + take F; + ); + take X.Y; + "#).unwrap()).compile().unwrap(), + vec![ + "print Foo", + ], + ); + + assert_eq!( + CompileMeta::new().compile(parse!(parser, r#" + const Box = ( + $.val = _0; + const $.Add = ( + ...val = ...val + _0.val; + ); + ); + take N = Box[2]; + take N1 = Box[3]; + take N.Add[N1]; + print ..; + "#).unwrap()).compile().unwrap(), + vec![ + "set __1 2", + "set __4 3", + "op add __1 __1 __4", + "print __", + ], + ); + + assert_eq!( + CompileMeta::new().compile(parse!(parser, r#" + const Box = ( + $.val = _0; + const $.Add = ( + const Self = ..; + Self.val = Self.val + _0.val; + ); + ); + take N = Box[2]; + take N1 = Box[3]; + take N.Add[N1]; + "#).unwrap()).compile().unwrap(), + vec![ + "set __1 2", + "set __4 3", + "op add __1 __1 __4", + ], + ); + + assert_eq!( + CompileMeta::new().compile(parse!(parser, r#" + const Box = ( + $.val = _0; + const $.Add = ( + take Self = ..; + Self.val = Self.val + _0.val; + ); + ); + take N = Box[2]; + take N1 = Box[3]; + take N.Add[N1]; + "#).unwrap()).compile().unwrap(), + vec![ + "set __1 2", + "set __4 3", + "op add __1 __1 __4", + ], + ); + + assert_eq!( + CompileMeta::new().compile(parse!(parser, r#" + take a.B = 1; + take a.B = 2; + print a.B; + "#).unwrap()).compile().unwrap(), + vec![ + "print 2", + ], + ); + + assert_eq!( + CompileMeta::new().compile(parse!(parser, r#" + take a.N = 1; + take b.N = 2; + # 故意不实现的常量求值 + take X = ($ = a.N + b.N;); + print X; + "#).unwrap()).compile().unwrap(), + vec![ + "op add __2 1 2", + "print __2", + ], + ); + + assert_eq!( + CompileMeta::new().compile(parse!(parser, r#" + take a.N = 1; + take b.N = 2; + take A=a.N B=b.N; + take X = ($ = A + B;); + print X; + "#).unwrap()).compile().unwrap(), + vec![ + "print 3", + ], + ); +} diff --git a/tools/syntax/Cargo.toml b/tools/syntax/Cargo.toml index edce1a8..191d5df 100644 --- a/tools/syntax/Cargo.toml +++ b/tools/syntax/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "syntax" -version = "0.2.0" +version = "0.2.1" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/tools/syntax/src/lib.rs b/tools/syntax/src/lib.rs index 92f83b8..6f19748 100644 --- a/tools/syntax/src/lib.rs +++ b/tools/syntax/src/lib.rs @@ -1,5 +1,4 @@ use std::{ - ops::Deref, num::ParseIntError, collections::{HashMap, HashSet}, iter::{ @@ -163,6 +162,8 @@ pub enum Value { /// 一个跳转条件, 未决目标的跳转, 它会被内联 /// 如果它被take, 那么它将引起报错 Cmper(Box), + /// 本层应该指向的绑定者, 也就是ValueBind的被绑定的值 + Binder, } impl TakeHandle for Value { fn take_handle(self, meta: &mut CompileMeta) -> Var { @@ -184,6 +185,10 @@ impl TakeHandle for Value { Self::ResultHandle => meta.dexp_handle().clone(), Self::ReprVar(var) => var, Self::ValueBind(val_bind) => val_bind.take_handle(meta), + Self::Binder => { + meta.get_dexp_expand_binder().cloned() + .unwrap_or_else(|| "__".into()) + }, Self::Cmper(cmp) => { err!( "{}\n最终未被展开的cmper, {:#?}", @@ -367,23 +372,12 @@ impl Value { _ => None, } }, - _ => None, - } - } -} -impl Deref for Value { - type Target = str; - - fn deref(&self) -> &Self::Target { - match self { - Self::Var(ref s) | Self::ReprVar(ref s) => s, - Self::DExp(DExp { result, .. }) => result, - Self::ResultHandle => - panic!("未进行AST编译, 而DExp的返回句柄是进行AST编译时已知"), - Self::ValueBind(..) => - panic!("未进行AST编译, 而ValueAttr的返回句柄是进行AST编译时已知"), - Self::Cmper(..) => - panic!("未进行AST编译, 而Cmper不可被使用"), + Value::Binder => num(meta.get_dexp_expand_binder()?, true), + // NOTE: 故意的不实现, 常量求值应该'简单' + Value::ValueBind(ValueBind(..)) => None, + // NOTE: 这不能实现, 否则可能牵扯一些不希望的作用域问题 + Value::ResultHandle => None, + Value::DExp(_) | Value::Cmper(_) => None, } } } @@ -462,9 +456,9 @@ impl TakeHandle for DExp { result = value.as_var().unwrap().clone() } assert!(! result.is_empty()); - meta.push_dexp_handle((result, dexp_res_is_alloced)); + meta.push_dexp_handle(result); lines.compile(meta); - let (result, _) = meta.pop_dexp_handle(); + let result = meta.pop_dexp_handle(); result } } @@ -480,8 +474,7 @@ impl TakeHandle for ValueBind { assert!(! Value::is_string(&self.1)); let binded = meta.get_value_binded(handle, self.1).clone(); - // 进行常量表查询, 虽然是匿名量但是还是要有这个行为嘛 - // 虽然之前没有 + // 进行常量表查询 binded.take_handle(meta) } } @@ -1083,6 +1076,8 @@ impl CmpTree { => Some(&**s), | V::ResultHandle => Some(&**meta.dexp_handle()), + | V::Binder + => Some(meta.get_dexp_expand_binder().map(|s| &**s).unwrap_or("__")), | V::ValueBind(_) | V::Cmper(_) => None, @@ -2327,7 +2322,7 @@ impl Compile for LogicLine { }, Self::SetResultHandle(value) => { let new_dexp_handle = value.take_handle(meta); - meta.set_dexp_handle((new_dexp_handle, false)); + meta.set_dexp_handle(new_dexp_handle); }, Self::SetArgs(args) => { let expand_args = args.into_args(meta); @@ -2535,16 +2530,22 @@ pub trait Compile { pub struct ConstData { value: Value, labels: Vec, + binder: Option, } impl ConstData { pub fn new(value: Value, labels: Vec) -> Self { - Self { value, labels } + Self { value, labels, binder: None } } pub fn new_nolabel(value: Value) -> Self { Self::new(value, vec![]) } + pub fn set_binder(mut self, binder: Var) -> Self { + self.binder = binder.into(); + self + } + pub fn value(&self) -> &Value { &self.value } @@ -2552,6 +2553,14 @@ impl ConstData { pub fn labels(&self) -> &[String] { self.labels.as_ref() } + + pub fn binder(&self) -> Option<&String> { + self.binder.as_ref() + } + + pub fn binder_mut(&mut self) -> &mut Option { + &mut self.binder + } } /// 每层Expand的环境 @@ -2597,7 +2606,8 @@ pub struct CompileMeta { expand_env: Vec, env_args: Vec>>, /// 每层DExp所使用的句柄, 末尾为当前层, 同时有一个是否为自动分配名称的标志 - dexp_result_handles: Vec<(Var, bool)>, + dexp_result_handles: Vec, + dexp_expand_binders: Vec>, tmp_tag_count: Counter Var>, /// 每层const展开的标签 /// 一个标签从尾部上寻, 寻到就返回找到的, 没找到就返回原本的 @@ -2649,6 +2659,7 @@ impl CompileMeta { expand_env: Vec::new(), env_args: Vec::new(), dexp_result_handles: Vec::new(), + dexp_expand_binders: Vec::new(), tmp_tag_count: Counter::new(Self::tmp_tag_getter), const_expand_tag_name_map: Vec::new(), value_binds: HashMap::new(), @@ -2687,6 +2698,7 @@ impl CompileMeta { 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) @@ -2819,7 +2831,7 @@ impl CompileMeta { -> Option { if let Some(var_1) = value.as_var() { // 如果const的映射目标值是一个var - if let Some(ConstData { value: v1, labels: l1 }) + if let Some(ConstData { value: v1, labels: l1, .. }) = self.get_const_value(var_1).cloned() { // 且它是一个常量, 则将它直接克隆过来. // 防止直接映射到另一常量, @@ -2846,7 +2858,7 @@ impl CompileMeta { value => value, }; - match &var { + match var { ConstKey::Var(_) => { let var = var.take_handle(self); @@ -2856,10 +2868,15 @@ impl CompileMeta { .consts .insert(var, ConstData::new(value, labels)) }, - ConstKey::ValueBind(_) => { - let var = var.take_handle(self); + ConstKey::ValueBind(ValueBind(binder, name)) => { + assert!(! Value::is_string(&name)); + let binder_handle = binder.take_handle(self); + let data = ConstData::new(value, labels) + .set_binder(binder_handle.clone()); + let binded = self.get_value_binded( + binder_handle, name).clone(); self.value_bind_global_consts - .insert(var, ConstData::new(value, labels)) + .insert(binded, data) }, } } @@ -2877,12 +2894,12 @@ impl CompileMeta { } /// 新增一层DExp, 并且传入它使用的返回句柄 - pub fn push_dexp_handle(&mut self, handle: (Var, bool)) { + pub fn push_dexp_handle(&mut self, handle: Var) { self.dexp_result_handles.push(handle) } /// 如果弹无可弹, 说明逻辑出现了问题 - pub fn pop_dexp_handle(&mut self) -> (Var, bool) { + pub fn pop_dexp_handle(&mut self) -> Var { self.dexp_result_handles.pop().unwrap() } @@ -2906,7 +2923,7 @@ impl CompileMeta { /// 尝试获取当前DExp返回句柄, 没有DExp的话返回空 pub fn try_get_dexp_handle(&self) -> Option<&Var> { - self.dexp_result_handles.last().map(|(var, _)| var) + self.dexp_result_handles.last() } /// 获取当前DExp返回句柄 @@ -2916,14 +2933,9 @@ impl CompileMeta { || self.do_out_of_dexp_err("`DExpHandle` (`$`)")) } - /// 获取该DExp是否为自动分配的 - pub fn try_get_dexp_is_alloced(&self) -> Option { - self.dexp_result_handles.last().map(|&(_, x)| x) - } - /// 将当前DExp返回句柄替换为新的 /// 并将旧的句柄返回 - pub fn set_dexp_handle(&mut self, new_dexp_handle: (Var, bool)) -> (Var, bool) { + pub fn set_dexp_handle(&mut self, new_dexp_handle: Var) -> Var { if let Some(ref_) = self.dexp_result_handles.last_mut() { replace(ref_, new_dexp_handle) } else { @@ -2958,7 +2970,7 @@ impl CompileMeta { tmp_tags.extend(repeat_with(|| self.get_tmp_tag()) .take(label_count)); - let ConstData { value, labels } + let ConstData { value, labels, binder } = self.get_const_value(name).unwrap(); let mut labels_map = HashMap::with_capacity(labels.len()); for (tmp_tag, label) in zip(tmp_tags, labels.iter().cloned()) { @@ -2972,12 +2984,23 @@ impl CompileMeta { }); } let res = value.clone(); + self.dexp_expand_binders.push(binder.clone()); self.const_expand_tag_name_map.push(labels_map); res.into() } - pub fn const_expand_exit(&mut self) -> HashMap { - self.const_expand_tag_name_map.pop().unwrap() + pub fn const_expand_exit(&mut self) -> (HashMap, Option) { + ( + self.const_expand_tag_name_map.pop().unwrap(), + self.dexp_expand_binders.pop().unwrap(), + ) + } + + pub fn get_dexp_expand_binder(&self) -> Option<&Var> { + self.dexp_expand_binders.iter() + .map(Option::as_ref) + .filter_map(identity) + .next_back() } pub fn err_info(&self) -> Vec {