From c50e1b04ea217e7c4ed0a33f2cf4ee5eb900e349 Mon Sep 17 00:00:00 2001 From: A4-Tacks Date: Fri, 24 Jan 2025 18:49:46 +0800 Subject: [PATCH] =?UTF-8?q?=E4=B8=80=E4=BA=9B=E8=AF=AD=E6=B3=95=E6=8A=A5?= =?UTF-8?q?=E9=94=99=E6=97=B6=E5=B0=86=E4=BC=9A=E5=B8=A6=E4=B8=8A=E6=BA=90?= =?UTF-8?q?=E7=A0=81=E4=BD=8D=E7=BD=AE,=20=E6=96=B9=E4=BE=BF=E6=9F=A5?= =?UTF-8?q?=E6=89=BE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Cargo.lock | 10 ++-- Cargo.toml | 2 +- src/main.rs | 9 ++- tools/parser/Cargo.toml | 6 +- tools/parser/src/parser.lalrpop | 28 +++++---- tools/parser/tests/Cargo.toml | 2 +- tools/parser/tests/src/lib.rs | 1 + tools/syntax/Cargo.toml | 2 +- tools/syntax/src/lib.rs | 95 ++++++++++++++++++++++-------- tools/tag_code/Cargo.toml | 2 +- tools/tag_code/src/logic_parser.rs | 12 +++- 11 files changed, 114 insertions(+), 55 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 975c8ca..9dc0a11 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -284,7 +284,7 @@ checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "mindustry_logic_bang_lang" -version = "0.17.18" +version = "0.17.19" dependencies = [ "display_source", "logic_lint", @@ -330,7 +330,7 @@ dependencies = [ [[package]] name = "parser" -version = "0.3.25" +version = "0.3.26" dependencies = [ "lalrpop", "lalrpop-util", @@ -341,7 +341,7 @@ dependencies = [ [[package]] name = "parser-tests" -version = "0.1.44" +version = "0.1.45" dependencies = [ "either", "parser", @@ -530,7 +530,7 @@ dependencies = [ [[package]] name = "syntax" -version = "0.2.48" +version = "0.2.49" dependencies = [ "either", "itermaps", @@ -541,7 +541,7 @@ dependencies = [ [[package]] name = "tag_code" -version = "0.2.3" +version = "0.2.4" dependencies = [ "either", "peg", diff --git a/Cargo.toml b/Cargo.toml index bac6255..45689ac 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "mindustry_logic_bang_lang" -version = "0.17.18" +version = "0.17.19" edition = "2021" authors = ["A4-Tacks "] diff --git a/src/main.rs b/src/main.rs index 1716625..a5175b0 100644 --- a/src/main.rs +++ b/src/main.rs @@ -11,6 +11,7 @@ use std::{ fmt::Display, cell::RefCell, borrow::Cow, + rc::Rc, }; use display_source::{ @@ -442,11 +443,11 @@ fn unwrap_parse_err(result: ParseResult<'_>, src: &str) -> Expand { } struct CompileMetaExtender { - source: String, + source: Rc, display_meta: RefCell, } impl CompileMetaExtender { - fn new(source: String, display_meta: RefCell) -> Self { + fn new(source: Rc, display_meta: RefCell) -> Self { Self { source, display_meta, @@ -471,10 +472,12 @@ impl CompileMetaExtends for CompileMetaExtender { fn compile_ast(ast: Expand, src: String) -> CompileMeta { let mut meta = CompileMeta::new(); + let src = Rc::new(src); meta.set_extender(Box::new(CompileMetaExtender::new( - src, + src.clone(), DisplaySourceMeta::new().into(), ))); + meta.set_source(src); meta.compile_res_self(ast) } diff --git a/tools/parser/Cargo.toml b/tools/parser/Cargo.toml index c900e09..126f465 100644 --- a/tools/parser/Cargo.toml +++ b/tools/parser/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "parser" -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 @@ -11,6 +11,7 @@ lalrpop = "=0.20.0" [dependencies] syntax = { path = "../syntax", version = "*" } var_utils = { path = "../var_utils", version = "*" } +tag_code = { path = "../tag_code", version = "*" } [dependencies.lalrpop-util] version = "=0.20.0" @@ -20,6 +21,3 @@ features = [ "regex", "lexer" ] - -[dev-dependencies] -tag_code = { path = "../tag_code", version = "*" } diff --git a/tools/parser/src/parser.lalrpop b/tools/parser/src/parser.lalrpop index eeb5444..307c375 100644 --- a/tools/parser/src/parser.lalrpop +++ b/tools/parser/src/parser.lalrpop @@ -16,6 +16,7 @@ use ::syntax::{ }, Var, DExp, + Cmper, ValueBind, ValueBindRef, ValueBindRefTarget, @@ -53,6 +54,7 @@ use ::syntax::{ FALSE_VAR, }; use ::var_utils::string_escape; +use tag_code::logic_parser::IdxBox; grammar(meta: &mut Meta); @@ -104,6 +106,9 @@ MakeDExpBody: DExp = { #[inline] Boxed: Box = T => Box::new(<>); +#[inline] +Loc: IdxBox = @L T => IdxBox::new(<>); + CtrlBreakStart: () = () => meta.add_control_break_level(None); CtrlContinueStart: () = () => meta.add_control_continue_level(None); CtrlStart: () = () => meta.add_control_level(None, None); @@ -168,7 +173,7 @@ NonConstRangeValue: Value = { LogicLine::SetResultHandle(value), ].into()).into() }, - "goto" > => Value::Cmper(<>.into()), + > >> => Cmper(l.new_value(v)).into(), ".." => Value::Binder, FEDExp => <>.into(), MFTuple, @@ -381,7 +386,7 @@ QuickTake: LogicLine = "!" LEnd => { }; Match: Match = { - "match" > <("@" )?> > )*>> => { Match::new(args, cases.into_iter() @@ -395,7 +400,7 @@ Match: Match = { .collect() ) }, - "match" "=>" > "=>" <("@" )?> > )> => { Match::new(args, vec![case].into_iter() @@ -419,12 +424,12 @@ MatchPat: MatchPatAtom = { } ConstMatch: ConstMatch = { - "const" "match" > > => { ConstMatch::new(args, cases) }, - "const" "match" "=>" > "=>" => { ConstMatch::new(args, vec![case]) @@ -449,10 +454,10 @@ ConstMatchPatAtom: ConstMatchPatAtom = { sr, ) }, - > > ":")?> )>> => { + > >> ":")?> )>> => { let dexp = DExp::new(meta.unnamed_var(), vec![ LogicLine::from(Match::new( - Args::GLOB_ONLY, + dotake.new_value(Args::GLOB_ONLY), vec![ ( vec![MatchPatAtom::new_unamed(pat, false)].into(), @@ -474,7 +479,7 @@ ConstMatchPatAtom: ConstMatchPatAtom = { )), ].into()); ConstMatchPatAtom::new_guard( - dotake, + dotake.value, name.unwrap_or_default(), dexp.into(), sr, @@ -521,9 +526,10 @@ ArgsRepeatBlock: ArgsRepeat = { } Ok(ArgsRepeat::new(chunk.unwrap_or(1), block)) }, - "@" => { + > => { + let glob = l.new_value(Args::GLOB_ONLY); ArgsRepeat::new(pats.len(), vec![ - ConstMatch::new(Args::GLOB_ONLY, vec![ + ConstMatch::new(glob, vec![ (pats.into(), block), ]).into() ].into()) @@ -1104,7 +1110,7 @@ ControlBody: LogicLine = { Block, } GSwitchCase: GSwitchCase = { - > )?> => GSwitchCase::Normal { skip_extra, ids: ids.unwrap_or_default(), guard }, + > > )?> => GSwitchCase::Normal { skip_extra, ids: ids.map(Option::unwrap_or_default), guard }, > "<" => GSwitchCase::Catch { skip_extra, underflow: true, missed: false, overflow: false, to }, > "!" => GSwitchCase::Catch { skip_extra, underflow: false, missed: true, overflow: false, to }, > ">" => GSwitchCase::Catch { skip_extra, underflow: false, missed: false, overflow: true, to }, diff --git a/tools/parser/tests/Cargo.toml b/tools/parser/tests/Cargo.toml index 6ff0413..69e822e 100644 --- a/tools/parser/tests/Cargo.toml +++ b/tools/parser/tests/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "parser-tests" -version = "0.1.44" +version = "0.1.45" 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 56235bf..ce540a7 100644 --- a/tools/parser/tests/src/lib.rs +++ b/tools/parser/tests/src/lib.rs @@ -5278,6 +5278,7 @@ fn match_test() { assert_eq!( parse!(parser, r#" + # align............. inline@ A B *C { print A B C; } diff --git a/tools/syntax/Cargo.toml b/tools/syntax/Cargo.toml index 638a0cf..98f3e4f 100644 --- a/tools/syntax/Cargo.toml +++ b/tools/syntax/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "syntax" -version = "0.2.48" +version = "0.2.49" 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 6610bfb..c348570 100644 --- a/tools/syntax/src/lib.rs +++ b/tools/syntax/src/lib.rs @@ -14,6 +14,7 @@ use std::{ num::ParseIntError, ops, process::exit, + rc::Rc, }; use builtins::{build_builtins, BuiltinFunc}; @@ -230,7 +231,7 @@ pub enum Value { ValueBindRef(ValueBindRef), /// 一个跳转条件, 未决目标的跳转, 它会被内联 /// 如果它被take, 那么它将引起报错 - Cmper(Box), + Cmper(Cmper), /// 本层应该指向的绑定者, 也就是ValueBind的被绑定的值 Binder, ClosuredValue(ClosuredValue), @@ -307,10 +308,13 @@ impl TakeHandle for Value { meta.get_dexp_expand_binder().cloned() .unwrap_or_else(|| "__".into()) }, - cmp @ Self::Cmper(_) => { + ref cmp @ Self::Cmper(Cmper(ref loc)) => { + let loc = loc.location(&meta.source); err!( - "{}\n最终未被展开的cmper:\n{}", + "{}\n最终未被展开的 Cmper, 位于: {}:{}\n{}", meta.err_info().join("\n"), + loc.0, + loc.1, cmp.display_src(meta), ); exit(6); @@ -510,6 +514,7 @@ impl_enum_froms!(impl From for Value { Var => String; Var => &str; DExp => DExp; + Cmper => Cmper; ValueBind => ValueBind; ClosuredValue => ClosuredValue; BuiltinFunc => BuiltinFunc; @@ -518,11 +523,21 @@ impl_enum_froms!(impl From for Value { impl_enum_try_into!(impl TryInto for Value { Var => Var; DExp => DExp; - Cmper => Box; + Cmper => Cmper; ValueBind => ValueBind; ValueBindRef => ValueBindRef; }); +#[derive(Debug, PartialEq, Clone)] +pub struct Cmper(pub IdxBox>); +impl std::ops::Deref for Cmper { + type Target = IdxBox>; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + /// 一次性的迭代器格式化包装器 struct IterFmtter { iter: Cell>, @@ -1632,7 +1647,7 @@ impl CmpTree { let values = this.get_values_ref_mut().unwrap(); let value = if left { values.1 } else { values.0 }; match value { - V::Cmper(cmper) => { + V::Cmper(Cmper(cmper)) => { // (a < b) != false => a < b // (a < b) == false => !(a < b) let cmper: CmpTree = mem::take(&mut **cmper); @@ -1656,10 +1671,10 @@ impl CmpTree { let cmp = cmper(info.arg1, info.arg2.unwrap()); *self = cmp_rev(cmp.into()) } - Some(ConstData { value: V::Cmper(cmper), .. }) => { + Some(ConstData { value: V::Cmper(Cmper(cmper)), .. }) => { *self = cmp_rev(Self::Expand( name.clone(), - cmper.clone(), + cmper.value.clone(), )) } Some(_) | None => return, @@ -2841,12 +2856,13 @@ impl Compile for ArgsRepeat { #[derive(Debug, PartialEq, Clone)] pub struct Match { - args: Args, + args: IdxBox, cases: Vec<(MatchPat, InlineBlock)>, } impl Compile for Match { fn compile(self, meta: &mut CompileMeta) { - let args = self.args.into_taked_args_handle(meta); + let loc = self.args.new_value(()); + let args = self.args.value.into_taked_args_handle(meta); for (pat, block) in self.cases { if pat.do_pattern(&args, meta) { block.compile(meta); @@ -2854,16 +2870,20 @@ impl Compile for Match { } } if meta.enable_misses_match_log_info { + let (line, column) = loc.location(&meta.source); let args = args.into_iter() .map(|v| v.display_src(meta).into_owned()) .collect::>(); - meta.log_info(format_args!("Misses match, [{}]", args.join(" "))); + meta.log_info(format_args!( + "{line}:{column} Misses match, [{}]", + args.join(" "), + )); meta.log_expand_stack::(); } } } impl Match { - pub fn new(args: Args, cases: Vec<(MatchPat, InlineBlock)>) -> Self { + pub fn new(args: IdxBox, cases: Vec<(MatchPat, InlineBlock)>) -> Self { Self { args, cases } } @@ -3000,11 +3020,11 @@ impl MatchPatAtom { #[derive(Debug, PartialEq, Clone)] pub struct ConstMatch { - args: Args, + args: IdxBox, cases: Vec<(ConstMatchPat, InlineBlock)>, } impl ConstMatch { - pub fn new(args: Args, cases: Vec<(ConstMatchPat, InlineBlock)>) -> Self { + pub fn new(args: IdxBox, cases: Vec<(ConstMatchPat, InlineBlock)>) -> Self { Self { args, cases } } @@ -3018,7 +3038,8 @@ impl ConstMatch { } impl Compile for ConstMatch { fn compile(self, meta: &mut CompileMeta) { - let args = self.args.into_value_args(meta) + let loc = self.args.new_value(()); + let args = self.args.value.into_value_args(meta) .into_iter() .map(|value| { if let Some(var) = value.as_var() { @@ -3041,10 +3062,14 @@ impl Compile for ConstMatch { } } if meta.enable_misses_match_log_info { + let (line, column) = loc.location(&meta.source); let args = args.into_iter() .map(|v| v.display_src(meta).into_owned()) .collect::>(); - meta.log_info(format_args!("Misses match, [{}]", args.join(" "))); + meta.log_info(format_args!( + "{line}:{column} Misses const match, [{}]", + args.join(" "), + )); meta.log_expand_stack::(); } } @@ -3274,7 +3299,7 @@ pub enum GSwitchCase { Normal { skip_extra: bool, /// 如果为空, 那么则继承上一个的编号 - ids: Args, + ids: IdxBox, guard: Option, }, } @@ -3320,35 +3345,41 @@ pub struct GSwitch { impl GSwitch { const MAX_CONST_ID: usize = 750; - fn get_ids(ids: Args, meta: &mut CompileMeta) -> impl Iterator< + fn get_ids(ids: IdxBox, meta: &mut CompileMeta) -> impl Iterator< Item = usize > + '_ { - ids.into_taked_args_handle(meta) + let loc = ids.new_value(()); + let loc = move |meta: &CompileMeta| { + let (line, column) = loc.location(&meta.source); + format!("{line}:{column}") + }; + + ids.value.into_taked_args_handle(meta) .into_iter() .map(Value::ReprVar) - .map(|var| var.try_eval_const_num(meta) + .map(move |var| var.try_eval_const_num(meta) .map(|x| match x.0.round() { n if n < 0. => { meta.log_expand_stack::(); - err!("小于0的gswitch id: {}", n); + err!("{} 小于0的gswitch id: {}", loc(meta), n); exit(4); }, n if n >= GSwitch::MAX_CONST_ID as f64 => { meta.log_expand_stack::(); - err!("过大的gswitch id: {}", n); + err!("{} 过大的gswitch id: {}", loc(meta), n); exit(4); }, n => n as usize, }) .unwrap_or_else(|| { meta.log_expand_stack::(); - err!("gswitch id并不是一个数字"); + err!("{} gswitch id并不是一个数字", loc(meta)); exit(4); })) } fn case_lab_with_cond( - &self, + &self, mut f: impl FnMut(&GSwitchCase) -> bool, meta: &mut CompileMeta, ) -> Option { @@ -3895,6 +3926,7 @@ pub struct CompileMeta { noop_line: String, /// 保证不会是字符串 bind_custom_sep: Option, + source: Rc, } impl Debug for CompileMeta { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { @@ -3923,7 +3955,10 @@ impl Debug for CompileMeta { } impl Default for CompileMeta { fn default() -> Self { - Self::with_tag_codes(ParseLines::new(vec![])) + Self::with_tag_codes( + ParseLines::new(vec![]), + Rc::default(), + ) } } impl CompileMeta { @@ -3933,7 +3968,10 @@ impl CompileMeta { Self::default() } - pub fn with_tag_codes(tag_codes: ParseLines<'static>) -> Self { + pub fn with_tag_codes( + tag_codes: ParseLines<'static>, + source: Rc, + ) -> Self { let mut meta = Self { extender: None, parse_lines: tag_codes, @@ -3952,6 +3990,7 @@ impl CompileMeta { enable_misses_bind_info: false, noop_line: "noop".into(), bind_custom_sep: None, + source, }; let builtin = Var::from(Self::BUILTIN_FUNCS_BINDER); for builtin_func in build_builtins() { @@ -4287,7 +4326,7 @@ impl CompileMeta { } } - /// 对在外部使用`DExpHandle`进行报错 + /// 对在DExp外部使用某些东西进行报错 fn do_out_of_dexp_err(&self, value: &str) -> ! { err!( "{}\n尝试在`DExp`的外部使用{}", @@ -4549,6 +4588,10 @@ impl CompileMeta { self.extender = extender.into(); } + pub fn set_source(&mut self, source: Rc) { + self.source = source; + } + pub fn extender(&self) -> Option<&dyn CompileMetaExtends> { self.extender.as_deref() } diff --git a/tools/tag_code/Cargo.toml b/tools/tag_code/Cargo.toml index 115637d..490ed2b 100644 --- a/tools/tag_code/Cargo.toml +++ b/tools/tag_code/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "tag_code" -version = "0.2.3" +version = "0.2.4" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/tools/tag_code/src/logic_parser.rs b/tools/tag_code/src/logic_parser.rs index 5e60ab6..4503319 100644 --- a/tools/tag_code/src/logic_parser.rs +++ b/tools/tag_code/src/logic_parser.rs @@ -382,14 +382,22 @@ impl IdxBox { /// Get line and column /// - /// - `index >= s.len()` return last char next char location + /// - `index == s.len()` return last char next char location /// /// start line and column is 1 /// /// newline char is LF (`\n` 0x0A), and next line after the newline char, /// e.g `("a\n", 1)` location is `(1, 2)` + /// + /// # Panics + /// - `index > s.len()` return last char next char location + #[track_caller] pub fn location(&self, s: &str) -> (u32, u32) { - if self.index >= s.len() { + assert!(self.index <= s.len(), + "location index out of range ({} > {})", + self.index, + s.len()); + if self.index == s.len() { let nl = s.chars().filter(|&ch| ch == '\n').count(); let ch = s.chars() .rev()