From 05a53e96b9cb2060e0838e613c4441d765580b08 Mon Sep 17 00:00:00 2001 From: A4-Tacks Date: Wed, 22 Jan 2025 14:12:17 +0800 Subject: [PATCH] =?UTF-8?q?=E7=BB=99match=E4=B9=9F=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=E8=AE=BE=E7=BD=AE=E8=BF=94=E5=9B=9E=E5=8F=A5=E6=9F=84=E7=9A=84?= =?UTF-8?q?=E6=94=AF=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 移除不应该的数字常量评估中Binder的错误实现 - 给标签类错误添加建议使用编译选项的提示 --- Cargo.lock | 10 +-- Cargo.toml | 2 +- examples/learn.md | 4 +- src/main.rs | 2 +- tools/display_source/Cargo.toml | 2 +- tools/display_source/src/impls.rs | 46 +++++++++++++ tools/parser/Cargo.toml | 2 +- tools/parser/src/parser.lalrpop | 9 +-- tools/parser/tests/Cargo.toml | 2 +- tools/parser/tests/src/lib.rs | 104 ++++++++++++++++++++++++++++++ tools/syntax/Cargo.toml | 2 +- tools/syntax/src/lib.rs | 56 ++++++++++------ 12 files changed, 206 insertions(+), 35 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index eeedc72..8621465 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -88,7 +88,7 @@ dependencies = [ [[package]] name = "display_source" -version = "0.3.25" +version = "0.3.26" dependencies = [ "parser", "syntax", @@ -284,7 +284,7 @@ checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "mindustry_logic_bang_lang" -version = "0.17.15" +version = "0.17.16" dependencies = [ "display_source", "logic_lint", @@ -330,7 +330,7 @@ dependencies = [ [[package]] name = "parser" -version = "0.3.24" +version = "0.3.25" dependencies = [ "lalrpop", "lalrpop-util", @@ -341,7 +341,7 @@ dependencies = [ [[package]] name = "parser-tests" -version = "0.1.41" +version = "0.1.42" dependencies = [ "either", "parser", @@ -530,7 +530,7 @@ dependencies = [ [[package]] name = "syntax" -version = "0.2.45" +version = "0.2.46" dependencies = [ "either", "itermaps", diff --git a/Cargo.toml b/Cargo.toml index d911473..dcaac47 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "mindustry_logic_bang_lang" -version = "0.17.15" +version = "0.17.16" edition = "2021" authors = ["A4-Tacks "] diff --git a/examples/learn.md b/examples/learn.md index 646e104..d291163 100644 --- a/examples/learn.md +++ b/examples/learn.md @@ -1150,6 +1150,9 @@ op add c a b 其中`A:`部分可省略 - `@`: 在这个位置匹配任意个数的值, 并将匹配到的值进行`# setArgs`, 每个分支只能存在一个`@` +- 其它匹配前面加上`$`可以方便的将这个匹配到的值进行 setres + +match 里面由零至多个匹配后面跟上一个花括号组成, 称作一个分支, 可以有多个分支 而除了普通 match, 还存在一种 const-match, 区别是 match 会将所有参数进行求值后拿其句柄进行匹配, @@ -1159,7 +1162,6 @@ op add c a b 而 const-match 还多出一些可用的匹配: - 其它匹配前面加上`*`则使用 take 而不是 const 这个值到要绑定到的常量 -- 其它匹配前面加上`$`可以方便的将这个匹配到的值进行 setres - 在方括号匹配里面方括号头部加上`*`则尝试先将待匹配的值进行求值后匹配其句柄 - 在方括号匹配里面方括号头部加上`?`则方括号内输入 op-expr, 来通过返回0还是1来确定是否匹配 diff --git a/src/main.rs b/src/main.rs index 3ede930..1716625 100644 --- a/src/main.rs +++ b/src/main.rs @@ -187,7 +187,7 @@ fn logic_to_tagcode<'a>(lines: ParseLines<'a>, src: &str) -> TagCodes { Err(e) => { let (line, column) = e.location(src); let prefix = format!("ParseTagCode {line}:{column}"); - err!("{prefix} {e}"); + err!("{prefix} {e}\n或许你可以使用`Li`选项编译来详细查看"); exit(10) }, }; diff --git a/tools/display_source/Cargo.toml b/tools/display_source/Cargo.toml index 44f208c..7c84c0b 100644 --- a/tools/display_source/Cargo.toml +++ b/tools/display_source/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "display_source" -version = "0.3.25" +version = "0.3.26" 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 8d02d8d..ef66690 100644 --- a/tools/display_source/src/impls.rs +++ b/tools/display_source/src/impls.rs @@ -569,6 +569,9 @@ impl DisplaySource for MatchPatAtom { fn display_source(&self, meta: &mut DisplaySourceMeta) { let show_name = !self.name().is_empty(); let show_list = !self.pattern().is_empty(); + if self.set_res() { + meta.push("$"); + } if show_name { meta.push(self.name()); if show_list { meta.push(":") } @@ -578,6 +581,9 @@ impl DisplaySource for MatchPatAtom { meta.display_source_iter_by_space(self.pattern()); meta.push("]"); } + if !show_name && !show_list { + meta.push("_"); + } } } impl DisplaySource for MatchPat { @@ -1066,6 +1072,46 @@ fn display_source_test() { .display_source_and_get(&mut meta), "match {}" ); + assert_eq!( + parse!(line_parser, r#" + match { $X {} } + "#) + .unwrap() + .display_source_and_get(&mut meta), + "match {\n $X {}\n}" + ); + assert_eq!( + parse!(line_parser, r#" + match { $X:[1] {} } + "#) + .unwrap() + .display_source_and_get(&mut meta), + "match {\n $X:[1] {}\n}" + ); + assert_eq!( + parse!(line_parser, r#" + match { $[1 2] {} } + "#) + .unwrap() + .display_source_and_get(&mut meta), + "match {\n $[1 2] {}\n}" + ); + assert_eq!( + parse!(line_parser, r#" + match { _ {} } + "#) + .unwrap() + .display_source_and_get(&mut meta), + "match {\n _ {}\n}" + ); + assert_eq!( + parse!(line_parser, r#" + match { $_ {} } + "#) + .unwrap() + .display_source_and_get(&mut meta), + "match {\n $_ {}\n}" + ); assert_eq!( parse!(line_parser, r#" foo 'match'; diff --git a/tools/parser/Cargo.toml b/tools/parser/Cargo.toml index b6dc4c3..c900e09 100644 --- a/tools/parser/Cargo.toml +++ b/tools/parser/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "parser" -version = "0.3.24" +version = "0.3.25" 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 096d8de..eeb5444 100644 --- a/tools/parser/src/parser.lalrpop +++ b/tools/parser/src/parser.lalrpop @@ -412,9 +412,10 @@ Match: Match = { } MatchPat: MatchPatAtom = { - MList => MatchPatAtom::new_unamed(<>), - Var => MatchPatAtom::new(<>, vec![]), - ":" > => MatchPatAtom::new(name, pat), + > > => MatchPatAtom::new_unamed(pat, sr), + > "_" => MatchPatAtom::new_unamed(vec![], sr), + > => MatchPatAtom::new(v, vec![], sr), + > ":" > => MatchPatAtom::new(name, pat, sr), } ConstMatch: ConstMatch = { @@ -454,7 +455,7 @@ ConstMatchPatAtom: ConstMatchPatAtom = { Args::GLOB_ONLY, vec![ ( - vec![MatchPatAtom::new_unamed(pat)].into(), + vec![MatchPatAtom::new_unamed(pat, false)].into(), vec![ LogicLine::SetResultHandle( Value::ReprVar("1".into()) diff --git a/tools/parser/tests/Cargo.toml b/tools/parser/tests/Cargo.toml index 2935853..a92d027 100644 --- a/tools/parser/tests/Cargo.toml +++ b/tools/parser/tests/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "parser-tests" -version = "0.1.41" +version = "0.1.42" 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 99001dd..c6f8ce6 100644 --- a/tools/parser/tests/src/lib.rs +++ b/tools/parser/tests/src/lib.rs @@ -5294,6 +5294,110 @@ fn match_test() { "print 2", ], ); + + assert_eq!( + CompileMeta::new().compile(parse!(parser, r#" + const Foo = (match @ { + { print 0; } + _ { print 1; } + _ _ { print 2; } + }); + take Foo[] Foo[3] Foo[3 3]; + "#).unwrap()).compile().unwrap(), + vec![ + "print 0", + "print 1", + "print 2", + ], + ); + + assert_eq!( + CompileMeta::new().compile(parse!(parser, r#" + const Foo = (match @ { + $_ { print 1; } + }); + print Foo[6]; + "#).unwrap()).compile().unwrap(), + vec![ + "print 1", + "print 6", + ], + ); + + assert_eq!( + CompileMeta::new().compile(parse!(parser, r#" + const Foo = (match @ { + $X { print 8 X 8; } + }); + print Foo[6]; + "#).unwrap()).compile().unwrap(), + vec![ + "print 8", + "print 6", + "print 8", + "print 6", + ], + ); + + assert_eq!( + CompileMeta::new().compile(parse!(parser, r#" + const Foo = (match @ { + $X $Y { print 8 X 8; } + }); + print Foo[6 9]; + "#).unwrap()).compile().unwrap(), + vec![ + "print 8", + "print 6", + "print 8", + "print 9", + ], + ); + + assert_eq!( + CompileMeta::new().compile(parse!(parser, r#" + const Foo = (match @ { + X $Y { print 8 X 8; } + }); + print Foo[6 9]; + "#).unwrap()).compile().unwrap(), + vec![ + "print 8", + "print 6", + "print 8", + "print 9", + ], + ); + + assert_eq!( + CompileMeta::new().compile(parse!(parser, r#" + const Foo = (match @ { + $X Y { print 8 X 8; } + }); + print Foo[6 9]; + "#).unwrap()).compile().unwrap(), + vec![ + "print 8", + "print 6", + "print 8", + "print 6", + ], + ); + + assert_eq!( + CompileMeta::new().compile(parse!(parser, r#" + const Foo = (match @ { + X Y { print 8 X 8; } + }); + print Foo[6 9]; + "#).unwrap()).compile().unwrap(), + vec![ + "print 8", + "print 6", + "print 8", + "print __2", + ], + ); } #[test] diff --git a/tools/syntax/Cargo.toml b/tools/syntax/Cargo.toml index 64309da..0cba38d 100644 --- a/tools/syntax/Cargo.toml +++ b/tools/syntax/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "syntax" -version = "0.2.45" +version = "0.2.46" 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 2f62297..944c332 100644 --- a/tools/syntax/src/lib.rs +++ b/tools/syntax/src/lib.rs @@ -492,7 +492,8 @@ impl Value { _ => None, } }, - Value::Binder => num(meta.get_dexp_expand_binder()?, true), + // NOTE: 故意的不实现, 可能并没有正确的绑定者环境 + Value::Binder => None, // NOTE: 故意的不实现, 常量求值应该'简单' Value::ValueBind(..) => None, Value::ValueBindRef(..) => None, @@ -2889,36 +2890,46 @@ impl MatchPat { /// 进行匹配, 如果成功则直接将量绑定 pub fn do_pattern(self, args: &[Var], meta: &mut CompileMeta) -> bool { fn to_vars(args: Vec, meta: &mut CompileMeta) - -> Vec<(Var, Vec)> { + -> Vec<(Var, Vec, bool)> { args.into_iter() - .map(|arg| ( - arg.name, - arg.pattern.into_iter() + .map(|arg| { + let collect = arg.pattern.into_iter() .map(|pat| pat.take_handle(meta)) - .collect() - )) + .collect(); + ( + arg.name, + collect, + arg.set_res, + ) + }) .collect() } - fn cmp(pats: &[(Var, Vec)], args: &[Var]) -> bool { + fn cmp(pats: &[(Var, Vec, bool)], args: &[Var]) -> bool { pats.iter() - .map(|(_, x)| &x[..]) + .map(|(_, x, _)| &x[..]) .zip(args) .all(|(pat, var)| { pat.is_empty() || pat.iter().any(|x| x == var) }) } - fn binds(name: Var, value: &Var, meta: &mut CompileMeta) { + fn binds(name: Var, value: &Var, set_res: bool, meta: &mut CompileMeta) { if !name.is_empty() { meta.add_const_value(Const(name.into(), value.clone().into(), vec![])); } + if set_res { + LogicLine::SetResultHandle(Value::ReprVar(value.clone())).compile(meta); + } } match self { Self::Normal(iargs) if iargs.len() == args.len() => { - let pats: Vec<(Var, Vec)> = to_vars(iargs, meta); + let pats = to_vars(iargs, meta); cmp(&pats, args).then(|| { - for ((name, _), arg) in pats.into_iter().zip(args) { - binds(name, arg, meta) + for ((name, _, set_res), arg) in + pats.into_iter() + .zip(args) + { + binds(name, arg, set_res, meta) } }).is_some() }, @@ -2934,8 +2945,10 @@ impl MatchPat { prefix.into_iter().zip(args), suffix.into_iter().zip(&args[tl..]), ); - for ((name, _), arg) in a.chain(b) { - binds(name, arg, meta) + for ((name, _, set_res), arg) in + a.chain(b) + { + binds(name, arg, set_res, meta) } let extracted = extracted.iter() .map_into() @@ -2957,14 +2970,15 @@ impl From> for MatchPat { pub struct MatchPatAtom { name: Var, pattern: Vec, + set_res: bool, } impl MatchPatAtom { - pub fn new(name: Var, pattern: Vec) -> Self { - Self { name, pattern } + pub fn new(name: Var, pattern: Vec, set_res: bool) -> Self { + Self { name, pattern, set_res } } - pub fn new_unamed(pattern: Vec) -> Self { - Self::new("".into(), pattern) + pub fn new_unamed(pattern: Vec, set_res: bool) -> Self { + Self::new("".into(), pattern, set_res) } pub fn name(&self) -> &str { @@ -2974,6 +2988,10 @@ impl MatchPatAtom { pub fn pattern(&self) -> &[Value] { self.pattern.as_ref() } + + pub fn set_res(&self) -> bool { + self.set_res + } } #[derive(Debug, PartialEq, Clone)]