Skip to content

Commit

Permalink
增加op-expr, 这是我们更加熟悉的表达形式, 它使复杂计算也更加干练
Browse files Browse the repository at this point in the history
  • Loading branch information
A4-Tacks committed Aug 19, 2023
1 parent 416acde commit 1b567c1
Show file tree
Hide file tree
Showing 6 changed files with 379 additions and 23 deletions.
2 changes: 1 addition & 1 deletion 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.10.6"
version = "0.11.0"
edition = "2021"

authors = ["A4-Tacks <[email protected]>"]
Expand Down
1 change: 1 addition & 0 deletions examples/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
> [`print.mdtlbl`](./print.mdtlbl)<br/>
> [`sets.mdtlbl`](./sets.mdtlbl)<br/>
> [`op.mdtlbl`](./op.mdtlbl)<br/>
> [`op_expr.mdtlbl`](./op_expr.mdtlbl)<br/>
> [`control.mdtlbl`](./control.mdtlbl)<br/>
> [`cmps.mdtlbl`](./cmps.mdtlbl)<br/>
> [`insert_sort.mdtlbl`](./insert_sort.mdtlbl)<br/>
Expand Down
58 changes: 58 additions & 0 deletions examples/op_expr.mdtlbl
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
#**
* 这是在0.11.0版本添加的表达式系统, 旨在更加干练的编写复杂运算
* 可以有限的以我们比较常见的表达式形式使用op来进行运算
* 这个语法可以看成在对sets左值为单个时的行为扩展
* 在sets左值为单个Value时, 右值将成为一个op-expr
*
* 以下为各种运算符的优先级与结合性:
* | 符号 | 实际运算(op) | 优先级 | 结合性 |
* | --------- | ------------ | ------ | ------ |
* | `a ** b` | `a ** b` | -1 | RL |
* | `! x` | `x != false` | -2 | R |
* | `- x` | `0 - x` | -2 | R |
* | `~ x` | `~ x` | -2 | R |
* | `a * b` | `a * b` | -3 | LR |
* | `a / b` | `a / b` | -3 | LR |
* | `a % b` | `a % b` | -3 | LR |
* | `a // b` | `a // b` | -3 | LR |
* | `a + b` | `a + b` | -4 | LR |
* | `a - b` | `a - b` | -4 | LR |
* | `a << b` | `a << b` | -5 | LR |
* | `a >> b` | `a >> b` | -5 | LR |
* | `a & b` | `a & b` | -6 | LR |
* | `a ^ b` | `a ^ b` | -7 | LR |
* | `a | b` | `a | b` | -8 | LR |
* | `a == b` | `a == b` | -9 | LR |
* | `a != b` | `a != b` | -9 | LR |
* | `a < b` | `a < b` | -9 | LR |
* | `a > b` | `a > b` | -9 | LR |
* | `a <= b` | `a <= b` | -9 | LR |
* | `a >= b` | `a >= b` | -9 | LR |
* | `a === b` | `a === b` | -9 | LR |
* | `a && b` | `a && b` | -10 | LR |
* | `a || b` | `a + b` | -11 | LR |
*
* 以上表格外, 还有一元与二元函数(其实就是op)
* 它们的优先级与括号平级,
* 二元函数有: `max` `min` `angle` `len` `noise`,
* 一元函数的部分列举有: `log` `rand` ...,
*
* 具体参考op中没有符号的运算
*#

x = 1 + 2 * 3;
y = (1 + 2) * 3;
z = min(a+b, c-d);
#* A >>>
op 'x' '1' + (op $ '2' * '3';);
op 'y' (op $ '1' + '2';) * '3';
op 'z' min (op $ 'a' + 'b';) (op $ 'c' - 'd';);
*#
# 我们可以看出, 优先级生效了, 并且运算被正常解析为DExp树了
# 并且我们并没有遇到最后要经历一遭set的问题, 因为解析时有一个安全标记
# 这个标记将使我们可以正确的将op与set合并.
#
# 当然, 需要注意的是,
# 虽然运算成员是Value, 但依旧不推荐使用`$`符号(返回句柄替换符)
# 因为这并没有什么意义, 且如果在最外层, 那么因为最顶层op与set的合并,
# 这个句柄将会指向set的更外层的DExp.
142 changes: 134 additions & 8 deletions src/syntax.rs
Original file line number Diff line number Diff line change
Expand Up @@ -290,6 +290,14 @@ impl DExp {
lines
}
}

pub fn result(&self) -> &str {
self.result.as_ref()
}

pub fn lines(&self) -> &Expand {
&self.lines
}
}
impl TakeHandle for DExp {
fn take_handle(self, meta: &mut CompileMeta) -> Var {
Expand Down Expand Up @@ -351,6 +359,7 @@ impl DisplaySource for DExp {
meta.push(")");
}
}
impl_derefs!(impl for DExp => (self: self.lines): Expand);

/// 将一个Value与一个Var以特定格式组合起来,
/// 可完成如属性调用的功能
Expand Down Expand Up @@ -442,15 +451,9 @@ impl Meta {
/// 如果只有一个值与被赋值则与之前行为一致
/// 如果值与被赋值数量不匹配则返回错误
/// 如果值与被赋值数量匹配且大于一对就返回Expand中多个set
pub fn build_sets(&self, loc: [Location; 2], mut vars: Vec<Value>, mut values: Vec<Value>)
pub fn build_sets(loc: [Location; 2], mut vars: Vec<Value>, mut values: Vec<Value>)
-> Result<LogicLine, Error> {
fn build_set(var: Value, value: Value) -> LogicLine {
LogicLine::Other(vec![
Value::ReprVar("set".into()),
var,
value,
])
}
let build_set = Self::build_set;
if vars.len() != values.len() {
// 接受与值数量不匹配
return Err((
Expand All @@ -475,6 +478,15 @@ impl Meta {
Ok(Expand(expand).into())
}
}

/// 单纯的构建一个set语句
pub fn build_set(var: Value, value: Value) -> LogicLine {
LogicLine::Other(vec![
Value::ReprVar("set".into()),
var,
value,
])
}
}

pub trait FromMdtArgs
Expand Down Expand Up @@ -1018,6 +1030,50 @@ impl Op {
}
}

pub fn get_result(&self) -> &Value {
macro_rules! build_match {
{
$(
$variant:ident
),* $(,)?
} => {
match self {
$( Self::$variant(res, ..) => res ),*
}
};
}
build_match! {
Add, Sub, Mul, Div, Idiv, Mod, Pow,
Equal, NotEqual, Land, LessThan, LessThanEq, GreaterThan, GreaterThanEq,
StrictEqual, Shl, Shr, Or, And, Xor, Not,
Max, Min, Angle, Len, Noise, Abs, Log,
Log10, Floor, Ceil, Sqrt, Rand, Sin, Cos,
Tan, Asin, Acos, Atan,
}
}

pub fn get_result_mut(&mut self) -> &mut Value {
macro_rules! build_match {
{
$(
$variant:ident
),* $(,)?
} => {
match self {
$( Self::$variant(res, ..) => res ),*
}
};
}
build_match! {
Add, Sub, Mul, Div, Idiv, Mod, Pow,
Equal, NotEqual, Land, LessThan, LessThanEq, GreaterThan, GreaterThanEq,
StrictEqual, Shl, Shr, Or, And, Xor, Not,
Max, Min, Angle, Len, Noise, Abs, Log,
Log10, Floor, Ceil, Sqrt, Rand, Sin, Cos,
Tan, Asin, Acos, Atan,
}
}

pub fn oper_symbol_str(&self) -> &'static str {
macro_rules! build_match {
{
Expand Down Expand Up @@ -1651,6 +1707,14 @@ impl LogicLine {
}
}

pub fn as_op_mut(&mut self) -> Option<&mut Op> {
if let Self::Op(v) = self {
Some(v)
} else {
None
}
}

/// Returns `true` if the logic line is [`Label`].
///
/// [`Label`]: LogicLine::Label
Expand Down Expand Up @@ -2201,6 +2265,14 @@ pub fn mdt_logic_split(s: &str) -> Result<Vec<&str>, usize> {
Ok(res)
}

pub type OpExprInfo = (bool, Value);

pub fn op_expr_do<F>(f: F) -> OpExprInfo
where F: FnOnce() -> Op
{
(true, DExp::new_nores(vec![f().into()].into()).into())
}

#[cfg(test)]
mod tests {
use std::str::FromStr;
Expand Down Expand Up @@ -4322,4 +4394,58 @@ mod tests {
);
}
}

#[test]
fn op_expr_test() {
let parser = ExpandParser::new();

assert_eq!(
parse!(parser, r#"
x = max(1, 2);
y = max(max(1, 2), max(3, max(4, 5)));
"#).unwrap(),
parse!(parser, r#"
op x max 1 2;
op y max (op $ max 1 2;) (op $ max 3 (op $ max 4 5;););
"#).unwrap(),
);

assert_eq!(
parse!(parser, r#"
x = 1+2*3;
y = (1+2)*3;
z = 1+2+3;
"#).unwrap(),
parse!(parser, r#"
op x 1 + (op $ 2 * 3;);
op y (op $ 1 + 2;) * 3;
op z (op $ 1 + 2;) + 3;
"#).unwrap(),
);

assert_eq!(
parse!(parser, r#"
x = 1*max(2, 3);
y = a & b | c & d & e | f;
"#).unwrap(),
parse!(parser, r#"
op x 1 * (op $ max 2 3;);
op y (op $ (op $ a & b;) | (op $ (op $ c & d;) & e;);) | f;
"#).unwrap(),
);

assert_eq!(
parse!(parser, r#"
x = a**b**c; # pow的右结合
y = -x;
z = ~y;
"#).unwrap(),
parse!(parser, r#"
op x a ** (op $ b ** c;);
op y `0` - x;
op z ~y;
"#).unwrap(),
);

}
}
Loading

0 comments on commit 1b567c1

Please sign in to comment.