Skip to content

Commit

Permalink
给op-expr的自运算也支持多对单和多对多操作
Browse files Browse the repository at this point in the history
  • Loading branch information
A4-Tacks committed Jul 5, 2024
1 parent 8f37053 commit 1742536
Show file tree
Hide file tree
Showing 9 changed files with 123 additions and 43 deletions.
8 changes: 4 additions & 4 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "mindustry_logic_bang_lang"
version = "0.16.14"
version = "0.16.15"
edition = "2021"

authors = ["A4-Tacks <[email protected]>"]
Expand Down
19 changes: 18 additions & 1 deletion examples/op_expr.mdtlbl
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,8 @@
* 对于三元表达式, 也就是`if c?a:b`,
* 它是低优先级的, 所以参与高优先级运算时需要括号括起.
* 就算是`1+if x != y ? x : y`这样的, 也需要写成`1+(if x != y ? x : y)`
* 想要取消这个设计的方案有几个但都极其复杂, 所以就如现在这样
* 想要取消这个设计的方案有几个但都极其复杂, 所以就如现在这样.
* 注意, 结果带值而非运算的三元表达式最好写在顶层, 不然可能出现不必要的赋值
*
* 在0.14.21版本中, 添加了一个语法糖, 可以用 `(?x: a+b)` 来表示 `(x: $=a+b;)`
*#
Expand Down Expand Up @@ -166,3 +167,19 @@ a, b, c = 1 + 2 * 3;
* 在0.14.17版本, 可以对常见的运算使用自运算格式, 这会简化一些代码
*#
x += n*2;


#**
* 在0.16.15版本, 这些自运算可以使用顶层赋值可用的操作了,
* 例如
*#
a, b += c + d;
x, y += w, h;

#* >>>
op add __0 c d
op add a a __0
op add b b __0
op add x x w
op add y y h
*#
2 changes: 1 addition & 1 deletion tools/parser/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "parser"
version = "0.3.14"
version = "0.3.15"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
Expand Down
72 changes: 41 additions & 31 deletions tools/parser/src/parser.lalrpop
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// this is a lalrpop file

#![allow(unused_braces)]
#![allow(clippy::just_underscores_and_digits)]
#![allow(clippy::needless_lifetimes)]
#![allow(clippy::deprecated_cfg_attr)]
Expand All @@ -22,7 +23,9 @@ use ::syntax::{
ClosuredValueMethod,
op_expr_build_op,
op_expr_build_results,
op_expr_tools::top_assign_oper,
OpExprInfo,
OpExprAOperFun,
JumpCmp,
CmpTree,
Goto,
Expand Down Expand Up @@ -547,58 +550,64 @@ Args2: Vec<Value> = {

OpExpr: LogicLine = {
<OpExprMultipleResult> LEnd => {
let (mut results, value) = <>;
let (mut results, value, oper) = <>;
results.reverse();
op_expr_build_results(meta, results, vec![value])
op_expr_build_results(meta, results, vec![value], oper)
},
<OpExprDoMultiple> LEnd => {
let (mut results, values) = <>;
let (mut results, values, oper) = <>;
results.reverse();
op_expr_build_results(meta, results, values)
op_expr_build_results(meta, results, values, oper)
},
<IOpExpr> LEnd => <>.into(),
}
#[inline]
OpExprBodySetR: Expand = OpExprBody => {
let line = op_expr_build_results(meta, vec![ResultHandle], vec![<>]);
let line = op_expr_build_results(
meta,
vec![ResultHandle], vec![<>],
|meta, res, v| v.into_logic_line(meta, res),
);
vec![line].into()
};
OpExprDExp: DExp = METuple<MakeDExpBody<OpExprBodySetR>>;

IOpExpr: Expand = {
<v:Value> "+=" <r:OpExprBody> => { let tmp = meta.get_tmp_var(); vec![Take(tmp.clone().into(), v).into(), Op::Add (tmp.clone().into(), tmp.into(), r.into_value(meta)).into()].into() },
<v:Value> "-=" <r:OpExprBody> => { let tmp = meta.get_tmp_var(); vec![Take(tmp.clone().into(), v).into(), Op::Sub (tmp.clone().into(), tmp.into(), r.into_value(meta)).into()].into() },
<v:Value> "*=" <r:OpExprBody> => { let tmp = meta.get_tmp_var(); vec![Take(tmp.clone().into(), v).into(), Op::Mul (tmp.clone().into(), tmp.into(), r.into_value(meta)).into()].into() },
<v:Value> "/=" <r:OpExprBody> => { let tmp = meta.get_tmp_var(); vec![Take(tmp.clone().into(), v).into(), Op::Div (tmp.clone().into(), tmp.into(), r.into_value(meta)).into()].into() },
<v:Value> "//=" <r:OpExprBody> => { let tmp = meta.get_tmp_var(); vec![Take(tmp.clone().into(), v).into(), Op::Idiv(tmp.clone().into(), tmp.into(), r.into_value(meta)).into()].into() },
<v:Value> "%=" <r:OpExprBody> => { let tmp = meta.get_tmp_var(); vec![Take(tmp.clone().into(), v).into(), Op::Mod (tmp.clone().into(), tmp.into(), r.into_value(meta)).into()].into() },
<v:Value> "**=" <r:OpExprBody> => { let tmp = meta.get_tmp_var(); vec![Take(tmp.clone().into(), v).into(), Op::Pow (tmp.clone().into(), tmp.into(), r.into_value(meta)).into()].into() },
<v:Value> "&&=" <r:OpExprBody> => { let tmp = meta.get_tmp_var(); vec![Take(tmp.clone().into(), v).into(), Op::Land(tmp.clone().into(), tmp.into(), r.into_value(meta)).into()].into() },
<v:Value> "<<=" <r:OpExprBody> => { let tmp = meta.get_tmp_var(); vec![Take(tmp.clone().into(), v).into(), Op::Shl (tmp.clone().into(), tmp.into(), r.into_value(meta)).into()].into() },
<v:Value> ">>=" <r:OpExprBody> => { let tmp = meta.get_tmp_var(); vec![Take(tmp.clone().into(), v).into(), Op::Shr (tmp.clone().into(), tmp.into(), r.into_value(meta)).into()].into() },
<v:Value> "|=" <r:OpExprBody> => { let tmp = meta.get_tmp_var(); vec![Take(tmp.clone().into(), v).into(), Op::Or (tmp.clone().into(), tmp.into(), r.into_value(meta)).into()].into() },
<v:Value> "&=" <r:OpExprBody> => { let tmp = meta.get_tmp_var(); vec![Take(tmp.clone().into(), v).into(), Op::And (tmp.clone().into(), tmp.into(), r.into_value(meta)).into()].into() },
<v:Value> "^=" <r:OpExprBody> => { let tmp = meta.get_tmp_var(); vec![Take(tmp.clone().into(), v).into(), Op::Xor (tmp.clone().into(), tmp.into(), r.into_value(meta)).into()].into() },
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 },
}

// 多个接收者的OpExpr, 例如`a, b, c = 1;`
OpExprMultipleResult: (Vec<Value>, OpExprInfo) = {
<result:Value> "=" <value:OpExprBody> => {
(vec![result], value)
OpExprMultipleResult: (Vec<Value>, OpExprInfo, OpExprAOperFun) = {
<result:Value> <oper:OpExprAssignOper> <value:OpExprBody> => {
(vec![result], value, oper)
},
<result:Value> "," <body:OpExprMultipleResult> => {
let (mut results, value) = body;
results.push(result);
(results, value)
<result:Value> "," <mut body:OpExprMultipleResult> => {
body.0.push(result);
body
},
}

// 例如`a, b = 1, 2`返回`([b, a], [1, 2])`
OpExprDoMultiple: (Vec<Value>, Vec<OpExprInfo>) = {
<res1:Value> "," <res2:Value> "=" <val1:OpExprBody> "," <val2:OpExprBody>
=> (vec![res2, res1], vec![val1, val2]),
OpExprDoMultiple: (Vec<Value>, Vec<OpExprInfo>, OpExprAOperFun) = {
<res1:Value> "," <res2:Value>
<oper:OpExprAssignOper>
<val1:OpExprBody> "," <val2:OpExprBody>
=> (vec![res2, res1], vec![val1, val2], oper),

<result:Value> "," <mut mid:OpExprDoMultiple> "," <value:OpExprBody> => {
let (results, values) = &mut mid;
let (results, values, _) = &mut mid;
results.push(result);
values.push(value);
mid
Expand Down Expand Up @@ -1296,3 +1305,4 @@ ControlWithOptionalEnd: LogicLine = {
Expand(res).into()
},
}
// vim:nowrap
2 changes: 1 addition & 1 deletion tools/parser/tests/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "parser-tests"
version = "0.1.28"
version = "0.1.29"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
Expand Down
25 changes: 25 additions & 0 deletions tools/parser/tests/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2496,6 +2496,31 @@ fn op_expr_test() {
take Foo = (m: $ = a+b;);
"#).unwrap(),
);

assert_eq!(
parse!(parser, r#"
a, b += 2;
"#).unwrap(),
parse!(parser, r#"
{
take ___0 = 2;
{take ___1 = a; ___1 = ___1 + ___0;}
{take ___2 = b; ___2 = ___2 + ___0;}
}
"#).unwrap(),
);

assert_eq!(
parse!(parser, r#"
a, b += 2, 3;
"#).unwrap(),
parse!(parser, r#"
{
a += 2;
b += 3;
}
"#).unwrap(),
);
}

#[test]
Expand Down
2 changes: 1 addition & 1 deletion tools/syntax/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "syntax"
version = "0.2.33"
version = "0.2.34"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
Expand Down
34 changes: 31 additions & 3 deletions tools/syntax/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4635,9 +4635,12 @@ impl OpExprInfo {
}
impl_enum_froms!(impl From for OpExprInfo {
Value => Value;
Value => Var;
Op => Op;
});

pub type OpExprAOperFun = fn(&mut Meta, Value, OpExprInfo) -> LogicLine;

/// 构建一个op运算
pub fn op_expr_build_op<F>(f: F) -> OpExprInfo
where F: FnOnce() -> Op
Expand All @@ -4648,6 +4651,7 @@ pub fn op_expr_build_results(
meta: &mut Meta,
mut results: Vec<Value>,
mut values: Vec<OpExprInfo>,
f: OpExprAOperFun,
) -> LogicLine {
match (results.len(), values.len()) {
e @ ((0, _) | (_, 0)) => unreachable!("len by zero, {e:?}"),
Expand All @@ -4656,9 +4660,9 @@ pub fn op_expr_build_results(
results.pop().unwrap(),
values.pop().unwrap(),
);
value.into_logic_line(meta, result)
f(meta, result, value)
},
(len, 1) => {
(len, 1) if f == op_expr_tools::top_assign_oper => {
let mut lines = Vec::with_capacity(len + 1);
let value = values.pop().unwrap();
let mut results = results.into_iter();
Expand All @@ -4678,6 +4682,18 @@ pub fn op_expr_build_results(
assert_eq!(lines.len(), len + 1);
Expand(lines).into()
},
(len, 1) => {
let mut lines = Vec::with_capacity(len + 1);
let value = values.pop().unwrap()
.into_value(meta);
let tmp = meta.get_tmp_var();
lines.push(Take(tmp.clone().into(), value).into());
for result in results {
let line = f(meta, result, tmp.clone().into());
lines.push(line);
}
Expand(lines).into()
},
(res_len, val_len) => {
assert_eq!(res_len, val_len);

Expand All @@ -4686,10 +4702,22 @@ pub fn op_expr_build_results(
= results.into_iter().zip(values);

for (result, value) in ziped {
let line = value.into_logic_line(meta, result);
let line = f(meta, result, value);
lines.push(line)
}
Expand(lines).into()
},
}
}

pub mod op_expr_tools {
use super::{Meta, Value, OpExprInfo, LogicLine};

pub fn top_assign_oper(
meta: &mut Meta,
res: Value,
value: OpExprInfo,
) -> LogicLine {
value.into_logic_line(meta, res)
}
}

0 comments on commit 1742536

Please sign in to comment.