From ac8dda46c91720576a575da1ac69c1d874ba9273 Mon Sep 17 00:00:00 2001 From: A4-Tacks Date: Thu, 19 Oct 2023 18:43:28 +0800 Subject: [PATCH] =?UTF-8?q?=E5=BC=BA=E5=8C=96OpExpr,=20=E4=BD=BF=E5=BE=97?= =?UTF-8?q?=E4=B8=80=E4=B8=AA=E5=80=BC=E5=8F=AF=E4=BB=A5=E4=B8=80=E6=AC=A1?= =?UTF-8?q?=E8=B5=8B=E7=BB=99=E5=A4=9A=E4=B8=AA=E6=8E=A5=E6=94=B6=E8=80=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Cargo.lock | 2 +- Cargo.toml | 2 +- examples/op_expr.mdtlbl | 17 ++++++++++++++ src/syntax/def.lalrpop | 50 +++++++++++++++++++++++------------------ src/syntax/mod.rs | 49 ++++++++++++++++++++++++++++++++++++++++ src/syntax/tests.rs | 14 ++++++++++++ 6 files changed, 110 insertions(+), 24 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 36b6e23..eee135a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -288,7 +288,7 @@ checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" [[package]] name = "mindustry_logic_bang_lang" -version = "0.12.6" +version = "0.12.7" dependencies = [ "display_source", "lalrpop", diff --git a/Cargo.toml b/Cargo.toml index af28986..21b4bb7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "mindustry_logic_bang_lang" -version = "0.12.6" +version = "0.12.7" edition = "2021" authors = ["A4-Tacks "] diff --git a/examples/op_expr.mdtlbl b/examples/op_expr.mdtlbl index 62335dc..dec83a6 100644 --- a/examples/op_expr.mdtlbl +++ b/examples/op_expr.mdtlbl @@ -138,3 +138,20 @@ op 'x' '1' + ( ); *# # 由于前面解释过的原因, 你需要添加括号 + + +# 这是0.12.7版本添加的语法, 可以将一个值一次赋给多个接收者 +# 方法是使用首次赋值的值来为接下来赋值 +# +# 需要注意的是, 求值顺序是: +# 第一个接收者 -> 值 -> 第二个接收者 -> ... -> 第N个接收者 + +a, b, c = 1 + 2 * 3; +#* A >>> +{ + take ___0 = a; + op ___0 1 + (op $ 2 * 3;); + `'set'` b ___0; + `'set'` c ___0; +} +*# diff --git a/src/syntax/def.lalrpop b/src/syntax/def.lalrpop index 150973f..b53571b 100644 --- a/src/syntax/def.lalrpop +++ b/src/syntax/def.lalrpop @@ -17,6 +17,7 @@ use crate::syntax::{ DExp, ValueBind, op_expr_build_op, + op_expr_build_results, OpExprInfo, JumpCmp, CmpTree, @@ -58,12 +59,12 @@ MTuple = Wrap<"(", T, ")">; MList = Wrap<"[", T, "]">; MBlock = Wrap<"{", T, "}">; OpenArgs = ( S)*; // 零至多个有分隔后缀值 -CloseArgs = ( S)* T => { // 一至多个有分隔无后缀值 +CloseArgs: Vec = OpenArgs T => { // 一至多个有分隔无后缀值 let (mut args, tail) = <>; args.push(tail); args }; -OOCArgs = { +OOCArgs: Vec = { OpenArgs, CloseArgs, } @@ -319,30 +320,35 @@ Args2: Vec = { Value Value Value Value Value Value Value Value Value Value Value Value Value Value Value => vec![<>], } -OpExpr: LogicLine = LEnd => { - let (mut results, values) = <>; - results.reverse(); - assert_eq!(results.len(), values.len()); - - let mut lines = Vec::with_capacity(results.len()); - - let ziped = results.into_iter().zip(values); - for (result, value) in ziped { - let line = value.into_logic_line(meta, result); - lines.push(line) - } +OpExpr: LogicLine = { + LEnd => { + let (mut results, value) = <>; + results.reverse(); + op_expr_build_results(meta, results, vec![value]) + }, + LEnd => { + let (mut results, values) = <>; + results.reverse(); + op_expr_build_results(meta, results, values) + }, +} - assert!(! lines.is_empty()); - if lines.len() == 1 { - lines.pop().unwrap() - } else { - Expand(lines).into() - } -}; +// 多个接收者的OpExpr, 例如`a, b, c = 1;` +OpExprMultipleResult: (Vec, OpExprInfo) = { + "=" => { + (vec![result], value) + }, + "," => { + let (mut results, value) = body; + results.push(result); + (results, value) + }, +} // 例如`a, b = 1, 2`返回`([b, a], [1, 2])` OpExprDoMultiple: (Vec, Vec) = { - "=" => (vec![result], vec![value]), + "," "=" "," + => (vec![res2, res1], vec![val1, val2]), "," "," => { let (results, values) = &mut mid; results.push(result); diff --git a/src/syntax/mod.rs b/src/syntax/mod.rs index 8aef82d..a83e205 100644 --- a/src/syntax/mod.rs +++ b/src/syntax/mod.rs @@ -2583,6 +2583,55 @@ where F: FnOnce() -> Op { f().into() } +pub fn op_expr_build_results( + meta: &mut Meta, + mut results: Vec, + mut values: Vec, +) -> LogicLine { + match (results.len(), values.len()) { + e @ ((0, _) | (_, 0)) => unreachable!("len by zero, {e:?}"), + (1, 1) => { + let (result, value) = ( + results.pop().unwrap(), + values.pop().unwrap(), + ); + value.into_logic_line(meta, result) + }, + (len, 1) => { + let mut lines = Vec::with_capacity(len + 1); + let value = values.pop().unwrap(); + let mut results = results.into_iter(); + let first_result_handle = meta.get_tmp_var(); + lines.push(Take( + first_result_handle.clone(), results.next().unwrap() + ).into()); + lines.push(value.into_logic_line( + meta, + first_result_handle.clone().into() + )); + for result in results { + let value + = OpExprInfo::Value(first_result_handle.clone().into()); + lines.push(value.into_logic_line(meta, result.clone())) + } + assert_eq!(lines.len(), len + 1); + Expand(lines).into() + }, + (res_len, val_len) => { + assert_eq!(res_len, val_len); + + let mut lines = Vec::with_capacity(res_len); + let ziped + = results.into_iter().zip(values); + + for (result, value) in ziped { + let line = value.into_logic_line(meta, result); + lines.push(line) + } + Expand(lines).into() + }, + } +} #[cfg(test)] mod tests; diff --git a/src/syntax/tests.rs b/src/syntax/tests.rs index df15c68..bc34efd 100644 --- a/src/syntax/tests.rs +++ b/src/syntax/tests.rs @@ -2221,6 +2221,20 @@ fn op_expr_test() { "#).unwrap(), ); + assert_eq!( + parse!(parser, r#" + a, b, c = 1; + "#).unwrap(), + parse!(parser, r#" + { + take ___0 = a; + ___0 = 1; + b = ___0; + c = ___0; + } + "#).unwrap(), + ); + } #[test]