diff --git a/Cargo.lock b/Cargo.lock index b53b530..51d0350 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -100,7 +100,7 @@ dependencies = [ [[package]] name = "display_source" -version = "0.3.22" +version = "0.3.23" dependencies = [ "parser", "syntax", @@ -301,7 +301,7 @@ checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" [[package]] name = "mindustry_logic_bang_lang" -version = "0.16.20" +version = "0.16.21" dependencies = [ "display_source", "logic_lint", @@ -347,7 +347,7 @@ dependencies = [ [[package]] name = "parser" -version = "0.3.18" +version = "0.3.19" dependencies = [ "lalrpop", "lalrpop-util", @@ -358,7 +358,7 @@ dependencies = [ [[package]] name = "parser-tests" -version = "0.1.32" +version = "0.1.33" dependencies = [ "parser", "syntax", diff --git a/Cargo.toml b/Cargo.toml index a2007b0..9e33593 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "mindustry_logic_bang_lang" -version = "0.16.20" +version = "0.16.21" edition = "2021" authors = ["A4-Tacks "] diff --git a/examples/const_match.mdtlbl b/examples/const_match.mdtlbl index a4551a2..f44ab4d 100644 --- a/examples/const_match.mdtlbl +++ b/examples/const_match.mdtlbl @@ -50,3 +50,24 @@ take For[0 10 ( take For[0 10 2 ( print "b: "_0; )]; + + +# 在0.16.21版本, 增加了快捷的类似setres的表示方法, +# 使用上类似匹配成功后对匹配到的额外编译一次setres +const Read = (const match @ { + $*Res Addr { + read Res cell1 Addr; + } +}); +# 产生的结果类似如下 +const Read = (const match @ { + *Res Addr { + setres Res; + read Res cell1 Addr; + } +}); + +# 注意, 在捕获之后take的话, 除非真的需要, +# 否则尽量避免编写如 `$Res`, 也就是未添加`*`的情况 +# 不然按以上的展开示例, 会在setres和之后使用时产生对原始值多次take, +# 这通常不是预期的 diff --git a/tools/display_source/Cargo.toml b/tools/display_source/Cargo.toml index 063c904..1053428 100644 --- a/tools/display_source/Cargo.toml +++ b/tools/display_source/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "display_source" -version = "0.3.22" +version = "0.3.23" 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 2bbaf92..1ddb5d9 100644 --- a/tools/display_source/src/impls.rs +++ b/tools/display_source/src/impls.rs @@ -637,6 +637,9 @@ impl DisplaySource for ConstMatchPatAtom { .map(|pats| !pats.is_empty()) .unwrap_or_default() || self.pattern().is_right(); + if self.set_res() { + meta.push("$") + } if self.do_take() { meta.push("*") } @@ -1131,6 +1134,11 @@ fn display_source_test() { X @ Y {} @ Z {} @ {} + $_ {} + $M {} + $*M {} + $M:[2] {} + $[2] {} } "#) .unwrap() @@ -1141,6 +1149,11 @@ fn display_source_test() { \x20 X @ Y {}\n\ \x20 @ Z {}\n\ \x20 @ {}\n\ + \x20 $_ {}\n\ + \x20 $M {}\n\ + \x20 $*M {}\n\ + \x20 $M:[2] {}\n\ + \x20 $[2] {}\n\ }\ " ); diff --git a/tools/parser/Cargo.toml b/tools/parser/Cargo.toml index bde475f..31b6601 100644 --- a/tools/parser/Cargo.toml +++ b/tools/parser/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "parser" -version = "0.3.18" +version = "0.3.19" 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 b9cee93..95920f2 100644 --- a/tools/parser/src/parser.lalrpop +++ b/tools/parser/src/parser.lalrpop @@ -405,50 +405,56 @@ ConstMatchPat: ConstMatchPat = { } ConstMatchPatAtom: ConstMatchPatAtom = { - > ":")?> > => { - ConstMatchPatAtom::new(dotake, name.unwrap_or_default(), pat) + > > ":")?> > => { + ConstMatchPatAtom::new(dotake, name.unwrap_or_default(), pat, sr) }, - > ":")?> )>> => { + > > ":")?> )>> => { ConstMatchPatAtom::new_guard( dotake, name.unwrap_or_default(), pat.into_value(meta), + sr, ) }, - > ":")?> )>> => { + > > ":")?> )>> => { + let dexp = DExp::new(meta.unnamed_var(), vec![ + LogicLine::from(Match::new( + Args::GLOB_ONLY, + vec![ + ( + vec![MatchPatAtom::new_unamed(pat)].into(), + vec![ + LogicLine::SetResultHandle( + Value::ReprVar("1".into()) + ), + ].into(), + ), + ( + vec![MatchPatAtom::default()].into(), + vec![ + LogicLine::SetResultHandle( + Value::ReprVar("0".into()) + ), + ].into(), + ), + ] + )), + ].into()); ConstMatchPatAtom::new_guard( dotake, name.unwrap_or_default(), - DExp::new(meta.unnamed_var(), vec![ - LogicLine::from(Match::new( - Args::GLOB_ONLY, - vec![ - ( - vec![MatchPatAtom::new_unamed(pat)].into(), - vec![ - LogicLine::SetResultHandle( - Value::ReprVar("1".into()) - ), - ].into(), - ), - ( - vec![MatchPatAtom::default()].into(), - vec![ - LogicLine::SetResultHandle( - Value::ReprVar("0".into()) - ), - ].into(), - ), - ] - )), - ].into()).into() + dexp.into(), + sr, ) }, - > => { - ConstMatchPatAtom::new(dotake, name, vec![]) + > > => { + ConstMatchPatAtom::new(dotake, name, vec![], sr) + }, + "$" "_" => { + ConstMatchPatAtom::new(false, Default::default(), vec![], true) }, > "_" => { - ConstMatchPatAtom::new(dotake, Default::default(), vec![]) + ConstMatchPatAtom::new(dotake, Default::default(), vec![], false) }, } diff --git a/tools/parser/tests/Cargo.toml b/tools/parser/tests/Cargo.toml index a21b73a..d48d9b7 100644 --- a/tools/parser/tests/Cargo.toml +++ b/tools/parser/tests/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "parser-tests" -version = "0.1.32" +version = "0.1.33" 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 3d67035..01f47c2 100644 --- a/tools/parser/tests/src/lib.rs +++ b/tools/parser/tests/src/lib.rs @@ -5441,6 +5441,124 @@ fn const_match_test() { "print yes", ], ); + + assert_eq!( + CompileMeta::new().compile(parse!(parser, r#" + foo (const match (h: print taked;) { + $_ { + print body; + } + }); + "#).unwrap()).compile().unwrap(), + vec![ + "print taked", + "print body", + "foo h", + ], + ); + + assert_eq!( + CompileMeta::new().compile(parse!(parser, r#" + foo (const match (h: print taked;) { + $*M { + print body M; + } + }); + "#).unwrap()).compile().unwrap(), + vec![ + "print taked", + "print body", + "print h", + "foo h", + ], + ); + + assert_eq!( + CompileMeta::new().compile(parse!(parser, r#" + foo (const match (h: print taked;) { + $*M { + setres M; + print body M; + } + }); + "#).unwrap()).compile().unwrap(), + vec![ + "print taked", + "print body", + "print h", + "foo h", + ], + ); + + assert_eq!( + CompileMeta::new().compile(parse!(parser, r#" + foo (const match (h: print taked;) { + $*M:[h] { + print body M; + } + }); + "#).unwrap()).compile().unwrap(), + vec![ + "foo __0", + ], + ); + + assert_eq!( + CompileMeta::new().compile(parse!(parser, r#" + foo (const match (h: print taked;) { + $*M:[*h] { + setres M; + print body M; + } + }); + "#).unwrap()).compile().unwrap(), + vec![ + "print taked", + "print taked", + "print body", + "print h", + "foo h", + ], + ); + + assert_eq!( + CompileMeta::new().compile(parse!(parser, r#" + foo (const match (h: print taked;) { + $M:[*h] { + setres M; + print body M; + } + }); + "#).unwrap()).compile().unwrap(), + vec![ + "print taked", + "print taked", + "print taked", + "print body", + "print taked", + "print h", + "foo h", + ], + ); + + assert_eq!( + CompileMeta::new().compile(parse!(parser, r#" + foo (const match (h: print taked;) { + $M { + setres M; + print body M; + } + }); + "#).unwrap()).compile().unwrap(), + vec![ + "print taked", + "print taked", + "print body", + "print taked", + "print h", + "foo h", + ], + ); } #[test] diff --git a/tools/syntax/src/lib.rs b/tools/syntax/src/lib.rs index 0dad4a7..f01773b 100644 --- a/tools/syntax/src/lib.rs +++ b/tools/syntax/src/lib.rs @@ -3106,33 +3106,48 @@ impl ConstMatchPat { iter: impl IntoIterator, meta: &mut CompileMeta, handles: &'a [Var], - ) -> Option> { + ) -> Option> { iter.into_iter() .zip(handles) .map(|(pat, handle)| { pat.pat(meta, handle) - .map(|(do_take, name)| (do_take, name, handle)) + .map(|(do_take, set_res, name)| ( + do_take, + set_res, + name, + handle, + )) }) .collect() } fn make( - (do_take, name, handle): (bool, Var, &Var), + (do_take, set_res, name, handle): ( + bool, + bool, + Var, + &Var + ), meta: &mut CompileMeta, ) { - if do_take { - Take( - name.is_empty() - .then(|| "__".into()) - .unwrap_or(name) - .into(), - handle.into(), - ).compile(meta); - } else if !name.is_empty() { - Const( - name.into(), - handle.clone().into(), - vec![], - ).compile(meta); + let target = name + .is_empty() + .then(|| { + if do_take { + Take((&name).into(), handle.into()).compile(meta); + } + handle + }) + .unwrap_or_else(|| { + let key = (&name).into(); + if do_take { + Take(key, handle.into()).compile(meta); + } else { + Const(key, handle.into(), vec![]).compile(meta); + } + &name + }); + if set_res { + LogicLine::SetResultHandle(target.into()).compile(meta); } } @@ -3186,39 +3201,52 @@ pub struct ConstMatchPatAtom { do_take: bool, name: Var, pattern: Either, Value>, + set_res: bool, } impl ConstMatchPatAtom { - pub fn new(do_take: bool, name: Var, pattern: Vec) -> Self { + pub fn new( + do_take: bool, + name: Var, + pattern: Vec, + set_res: bool, + ) -> Self { Self { do_take, name, pattern: Either::Left(pattern), + set_res, } } - pub fn new_guard(do_take: bool, name: Var, pattern: Value) -> Self { + pub fn new_guard( + do_take: bool, + name: Var, + pattern: Value, + set_res: bool, + ) -> Self { Self { do_take, name, pattern: Either::Right(pattern), + set_res, } } - pub fn new_unamed(do_take: bool, pattern: Vec) -> Self { - Self::new(do_take, "".into(), pattern) - } - - pub fn new_unamed_guard(do_take: bool, pattern: Value) -> Self { - Self::new_guard(do_take, "".into(), pattern) - } - /// 尝试和某个句柄匹配, 返回是否take和需要给到的量 + /// + /// result: (do_take, set_res, name) pub fn pat( self, meta: &mut CompileMeta, handle: &Var, - ) -> Option<(bool, Var)> { - match self.pattern { + ) -> Option<(bool, bool, Var)> { + let Self { + do_take, + name, + pattern, + set_res, + } = self; + match pattern { Either::Left(pats) => { pats.is_empty() || { let var = meta.get_const_value(handle) @@ -3240,7 +3268,7 @@ impl ConstMatchPatAtom { }); res }, - }.then_some((self.do_take, self.name)) + }.then_some((do_take, set_res, name)) } pub fn do_take(&self) -> bool { @@ -3254,6 +3282,10 @@ impl ConstMatchPatAtom { pub fn pattern(&self) -> &Either, Value> { &self.pattern } + + pub fn set_res(&self) -> bool { + self.set_res + } } #[derive(Debug, PartialEq, Clone)]