diff --git a/Cargo.lock b/Cargo.lock index 3188669..55aff58 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -307,7 +307,7 @@ checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" [[package]] name = "mindustry_logic_bang_lang" -version = "0.17.3" +version = "0.17.4" dependencies = [ "display_source", "logic_lint", @@ -353,7 +353,7 @@ dependencies = [ [[package]] name = "parser" -version = "0.3.20" +version = "0.3.21" dependencies = [ "lalrpop", "lalrpop-util", @@ -569,7 +569,7 @@ dependencies = [ [[package]] name = "syntax" -version = "0.2.40" +version = "0.2.41" dependencies = [ "either", "itermaps", diff --git a/Cargo.toml b/Cargo.toml index f1d6346..7ac785a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "mindustry_logic_bang_lang" -version = "0.17.3" +version = "0.17.4" edition = "2021" authors = ["A4-Tacks "] diff --git a/examples/op_expr.mdtlbl b/examples/op_expr.mdtlbl index e8f4bf1..37cd42c 100644 --- a/examples/op_expr.mdtlbl +++ b/examples/op_expr.mdtlbl @@ -171,6 +171,7 @@ a, b, c = 1 + 2 * 3; #** * 在0.14.17版本, 可以对常见的运算使用自运算格式, 这会简化一些代码 +* 这些运算包括+-*///%等运算, 同时也支持min和max *# x += n*2; diff --git a/tools/parser/Cargo.toml b/tools/parser/Cargo.toml index eafbb54..6fd7f3d 100644 --- a/tools/parser/Cargo.toml +++ b/tools/parser/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "parser" -version = "0.3.20" +version = "0.3.21" 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 22779e1..4a2a1ed 100644 --- a/tools/parser/src/parser.lalrpop +++ b/tools/parser/src/parser.lalrpop @@ -23,7 +23,8 @@ use ::syntax::{ ClosuredValueMethod, op_expr_build_op, op_expr_build_results, - op_expr_tools::top_assign_oper, + op_expr_tools::TOP_ASSIGN_OPER, + make_assign_oper, OpExprInfo, OpExprAOperFun, JumpCmp, @@ -596,20 +597,22 @@ OpExprDExp: DExp = METuple>; OpExprToValue: Value = MTuple<("*" )>; OpExprAssignOper: OpExprAOperFun = { - "+=" => { |meta, res, v| { let tres = meta.get_tmp_var(); Expand(vec![Take(tres.clone().into(), res).into(), Op::Add (tres.clone().into(), tres.into(), v.into_value(meta)).into()]).into() } }, - "-=" => { |meta, res, v| { let tres = meta.get_tmp_var(); Expand(vec![Take(tres.clone().into(), res).into(), Op::Sub (tres.clone().into(), tres.into(), v.into_value(meta)).into()]).into() } }, - "*=" => { |meta, res, v| { let tres = meta.get_tmp_var(); Expand(vec![Take(tres.clone().into(), res).into(), Op::Mul (tres.clone().into(), tres.into(), v.into_value(meta)).into()]).into() } }, - "/=" => { |meta, res, v| { let tres = meta.get_tmp_var(); Expand(vec![Take(tres.clone().into(), res).into(), Op::Div (tres.clone().into(), tres.into(), v.into_value(meta)).into()]).into() } }, - "//=" => { |meta, res, v| { let tres = meta.get_tmp_var(); Expand(vec![Take(tres.clone().into(), res).into(), Op::Idiv(tres.clone().into(), tres.into(), v.into_value(meta)).into()]).into() } }, - "%=" => { |meta, res, v| { let tres = meta.get_tmp_var(); Expand(vec![Take(tres.clone().into(), res).into(), Op::Mod (tres.clone().into(), tres.into(), v.into_value(meta)).into()]).into() } }, - "**=" => { |meta, res, v| { let tres = meta.get_tmp_var(); Expand(vec![Take(tres.clone().into(), res).into(), Op::Pow (tres.clone().into(), tres.into(), v.into_value(meta)).into()]).into() } }, - "&&=" => { |meta, res, v| { let tres = meta.get_tmp_var(); Expand(vec![Take(tres.clone().into(), res).into(), Op::Land(tres.clone().into(), tres.into(), v.into_value(meta)).into()]).into() } }, - "<<=" => { |meta, res, v| { let tres = meta.get_tmp_var(); Expand(vec![Take(tres.clone().into(), res).into(), Op::Shl (tres.clone().into(), tres.into(), v.into_value(meta)).into()]).into() } }, - ">>=" => { |meta, res, v| { let tres = meta.get_tmp_var(); Expand(vec![Take(tres.clone().into(), res).into(), Op::Shr (tres.clone().into(), tres.into(), v.into_value(meta)).into()]).into() } }, - "|=" => { |meta, res, v| { let tres = meta.get_tmp_var(); Expand(vec![Take(tres.clone().into(), res).into(), Op::Or (tres.clone().into(), tres.into(), v.into_value(meta)).into()]).into() } }, - "&=" => { |meta, res, v| { let tres = meta.get_tmp_var(); Expand(vec![Take(tres.clone().into(), res).into(), Op::And (tres.clone().into(), tres.into(), v.into_value(meta)).into()]).into() } }, - "^=" => { |meta, res, v| { let tres = meta.get_tmp_var(); Expand(vec![Take(tres.clone().into(), res).into(), Op::Xor (tres.clone().into(), tres.into(), v.into_value(meta)).into()]).into() } }, - "=" => { top_assign_oper }, + "+=" => { make_assign_oper!(Op::Add ) }, + "-=" => { make_assign_oper!(Op::Sub ) }, + "*=" => { make_assign_oper!(Op::Mul ) }, + "/=" => { make_assign_oper!(Op::Div ) }, + "//=" => { make_assign_oper!(Op::Idiv ) }, + "%=" => { make_assign_oper!(Op::Mod ) }, + "**=" => { make_assign_oper!(Op::Pow ) }, + "&&=" => { make_assign_oper!(Op::Land ) }, + "<<=" => { make_assign_oper!(Op::Shl ) }, + ">>=" => { make_assign_oper!(Op::Shr ) }, + "|=" => { make_assign_oper!(Op::Or ) }, + "&=" => { make_assign_oper!(Op::And ) }, + "^=" => { make_assign_oper!(Op::Xor ) }, + "max" "=" => { make_assign_oper!(Op::Max ) }, + "min" "=" => { make_assign_oper!(Op::Min ) }, + "=" => { TOP_ASSIGN_OPER }, } // 多个接收者的OpExpr, 例如`a, b, c = 1;` diff --git a/tools/parser/tests/src/lib.rs b/tools/parser/tests/src/lib.rs index 4abb995..75d941b 100644 --- a/tools/parser/tests/src/lib.rs +++ b/tools/parser/tests/src/lib.rs @@ -2538,6 +2538,55 @@ fn op_expr_test() { "#).unwrap(), ); + assert_eq!( + parse!(parser, r#" + a, b min= 2, 3; + "#).unwrap(), + parse!(parser, r#" + { + a min= 2; + b min= 3; + } + "#).unwrap(), + ); + + assert_eq!( + parse!(parser, r#" + a, b max= 2, 3; + "#).unwrap(), + parse!(parser, r#" + { + a max= 2; + b max= 3; + } + "#).unwrap(), + ); + + assert_eq!( + parse!(parser, r#" + x min= 2; + "#).unwrap(), + parse!(parser, r#" + { + take ___0 = x; + op ___0 min ___0 2; + } + "#).unwrap(), + ); + + assert_eq!( + parse!(parser, r#" + a, b min= 2; + "#).unwrap(), + parse!(parser, r#" + { + take ___0 = 2; + {take ___1 = a; op ___1 min ___1 ___0;} + {take ___2 = b; op ___2 min ___2 ___0;} + } + "#).unwrap(), + ); + assert_eq!( parse!(parser, r#" x = ++i; diff --git a/tools/syntax/Cargo.toml b/tools/syntax/Cargo.toml index 95d2fa3..3a04854 100644 --- a/tools/syntax/Cargo.toml +++ b/tools/syntax/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "syntax" -version = "0.2.40" +version = "0.2.41" 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 717c288..c6950bb 100644 --- a/tools/syntax/src/lib.rs +++ b/tools/syntax/src/lib.rs @@ -4656,7 +4656,7 @@ pub fn op_expr_build_results( f(meta, result, value) }, (len, 1) - if f as *const () == op_expr_tools::top_assign_oper as *const () => { + if f as *const () == op_expr_tools::TOP_ASSIGN_OPER as *const () => { let mut lines = Vec::with_capacity(len + 1); let value = values.pop().unwrap(); let mut results = results.into_iter(); @@ -4704,8 +4704,28 @@ pub fn op_expr_build_results( } } +#[macro_export] +macro_rules! make_assign_oper { + ($oper:path) => { + |meta, res, v| { + let tres = meta.get_tmp_var(); + $crate::Expand(::std::vec![ + $crate::Take(tres.clone().into(), res).into(), + $oper( + tres.clone().into(), + tres.into(), + v.into_value(meta), + ).into(), + ]).into() + } + }; +} + pub mod op_expr_tools { - use super::{Meta, Value, OpExprInfo, LogicLine}; + use super::{LogicLine, Meta, OpExprInfo, Value}; + + pub const TOP_ASSIGN_OPER: fn(&mut Meta, Value, OpExprInfo) -> LogicLine + = top_assign_oper; pub fn top_assign_oper( meta: &mut Meta,