Skip to content

Commit

Permalink
添加cmp-deps语法, 可以更好的使用条件表达式
Browse files Browse the repository at this point in the history
  • Loading branch information
A4-Tacks committed Nov 24, 2023
1 parent 9d4a1f4 commit e22f9cc
Show file tree
Hide file tree
Showing 7 changed files with 119 additions and 42 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.12.9"
version = "0.12.10"
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 @@ -19,6 +19,7 @@
> [`const.mdtlbl`](./const.mdtlbl)<br/>
> [`inline_block.mdtlbl`](./inline_block.mdtlbl)<br/>
> [`take.mdtlbl`](./take.mdtlbl)<br/>
> [`cmp_deps.mdtlbl`](./cmp_deps.mdtlbl)<br/>
> [`switch_append.mdtlbl`](./switch_append.mdtlbl)<br/>
> [`shell_sort.mdtlbl`](./shell_sort.mdtlbl)<br/>
> [`switch_catch.mdtlbl`](./switch_catch.mdtlbl)<br/>
Expand Down
13 changes: 13 additions & 0 deletions examples/cmp_deps.mdtlbl
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#**
* 这是0.12.0版本加入的语法, 可以在JumpCmp中加入这个比较式的依赖语句
* 它的优先级是溢出的, 大部分情况需要在括号内使用, 其优先级高于`||`
*
* 它为自身左右运算成员构建了一层作用域
*#

const X = ($ = 1 + 2;);

while ({take N = X;} => N > 10 && N < 30) {
noop;
}
# 不用这个语法来解决这个问题的话, 总是不那么美观, 或者只能是看着X被take多次
26 changes: 17 additions & 9 deletions src/syntax/def.lalrpop
Original file line number Diff line number Diff line change
Expand Up @@ -170,29 +170,36 @@ JumpCmpBody: JumpCmp = {
<Value> => JumpCmp::bool(<>),
}

pub JumpCmp: CmpTree = CmpTree1;
// 入口
pub JumpCmp: CmpTree = CmpTree2;
pub JumpCmpOnce: CmpTree = CmpTree1;

// 可空的, 空时为总是的条件
AlwaysJumpCmp: CmpTree = JumpCmp? => <>.unwrap_or(JumpCmp::Always.into());

pub CmpTree1: CmpTree = {
<a:CmpTree1> "||" <b:CmpTree2> => CmpTree::Or(Box::new(a.into()), b.into()),
CmpTree1: CmpTree = {
<deps:MBlock<LogicLine*>> "=>" <cmp:CmpTree1> => CmpTree::Deps(deps.into(), cmp.into()),
CmpTree2,
}

pub CmpTree2: CmpTree = {
<a:CmpTree2> "&&" <b:CmpTree3> => CmpTree::And(Box::new(a.into()), b.into()),
CmpTree2: CmpTree = {
<a:CmpTree2> "||" <b:CmpTree3> => CmpTree::Or(Box::new(a.into()), b.into()),
CmpTree3,
}

pub CmpTree3: CmpTree = {
Or<"lnot", "!"> <CmpTree3> => <>.reverse(),
CmpTree3: CmpTree = {
<a:CmpTree3> "&&" <b:CmpTree4> => CmpTree::And(Box::new(a.into()), b.into()),
CmpTree4,
}

CmpTree4: CmpTree = {
Or<"lnot", "!"> <CmpTree4> => <>.reverse(),
CmpTree,
}

pub CmpTree: CmpTree = {
JumpCmpBody => <>.into(),
MTuple<JumpCmp>,
MTuple<JumpCmpOnce>,
}

pub Op: Op = {
Expand Down Expand Up @@ -256,7 +263,8 @@ pub Op: Op = {

Label: String = ":" <Var>;

pub Expand: Expand = LogicLine* => Expand(<>);
#[inline]
Expand: Expand = LogicLine+? => Expand(<>.unwrap_or_default());
pub LogicLine: LogicLine = {
Control,
BuiltinCommand,
Expand Down
102 changes: 72 additions & 30 deletions src/syntax/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -991,6 +991,8 @@ impl_enum_froms!(impl From for LogicLineFromTagError {
/// 例如: `a < b && c < d || e == f`
#[derive(Debug, PartialEq, Clone)]
pub enum CmpTree {
/// 整棵条件树的依赖
Deps(InlineBlock, Box<Self>),
And(Box<Self>, Box<Self>),
Or(Box<Self>, Box<Self>),
Atom(JumpCmp),
Expand All @@ -1007,6 +1009,8 @@ impl CmpTree {
/// 3. `(!a || !b) && !c`
pub fn reverse(self) -> Self {
match self {
Self::Deps(deps, cmp)
=> Self::Deps(deps, cmp.reverse().into()),
Self::Or(a, b)
=> Self::And(a.reverse().into(), b.reverse().into()),
Self::And(a, b)
Expand All @@ -1024,6 +1028,12 @@ impl CmpTree {
let do_tag_expanded = meta.get_in_const_label(do_tag);

match self {
Deps(deps, cmp) => {
meta.with_block(|meta| {
deps.compile(meta);
cmp.build(meta, do_tag_expanded);
});
},
Or(a, b) => {
a.build(meta, do_tag_expanded.clone());
b.build(meta, do_tag_expanded);
Expand Down Expand Up @@ -1090,6 +1100,24 @@ impl DisplaySource for CmpTree {
fn display_source(&self, meta: &mut DisplaySourceMeta) {
match self {
Self::Atom(cmp) => cmp.display_source(meta),
Self::Deps(deps, cmp) => {
meta.push("(");
meta.push("{");
if let [line] = &deps[..] {
line.display_source(meta)
} else {
meta.do_block(|meta| {
meta.add_lf();
deps.display_source(meta)
})
}
meta.push("}");
meta.add_space();
meta.push("=>");
meta.add_space();
cmp.display_source(meta);
meta.push(")");
},
Self::Or(a, b) => {
meta.push("(");
a.display_source(meta);
Expand Down Expand Up @@ -1539,11 +1567,11 @@ impl Default for Expand {
}
impl Compile for Expand {
fn compile(self, meta: &mut CompileMeta) {
meta.block_enter();
for line in self.0 {
line.compile(meta)
}
meta.block_exit(); // 如果要获取丢弃块中的常量映射从此处
meta.with_block(|this| {
for line in self.0 {
line.compile(this)
}
});
}
}
impl From<Vec<LogicLine>> for Expand {
Expand Down Expand Up @@ -1593,6 +1621,11 @@ impl Compile for InlineBlock {
}
}
}
impl From<Vec<LogicLine>> for InlineBlock {
fn from(value: Vec<LogicLine>) -> Self {
Self(value)
}
}
impl_derefs!(impl for InlineBlock => (self: self.0): Vec<LogicLine>);

/// 用于`switch`的`select`结构
Expand Down Expand Up @@ -2286,32 +2319,41 @@ impl CompileMeta {
&self.tags_map
}

/// 进入一个子块, 创建一个新的子命名空间
pub fn block_enter(&mut self) {
self.const_var_namespace.push((Vec::new(), HashMap::new()))
}

/// 退出一个子块, 弹出最顶层命名空间
/// 如果无物可弹说明逻辑出现了问题, 所以内部处理为unwrap
/// 一个enter对应一个exit
pub fn block_exit(&mut self) -> HashMap<Var, (Vec<Var>, Value)> {
// this is poped block
let (leaks, mut res)
= self.const_var_namespace.pop().unwrap();

// do leak
for leak_const_name in leaks {
let value
= res.remove(&leak_const_name).unwrap();

// insert to prev block
self.const_var_namespace
.last_mut()
.unwrap()
.1
.insert(leak_const_name, value);
/// 进入一个拥有子命名空间的子块
/// 返回该子块结束后的命名空间
pub fn with_block(&mut self,
f: impl FnOnce(&mut Self),
) -> HashMap<Var, (Vec<Var>, Value)> {
/// 进入一个子块, 创建一个新的子命名空间
fn block_enter(this: &mut CompileMeta) {
this.const_var_namespace.push((Vec::new(), HashMap::new()))
}
/// 退出一个子块, 弹出最顶层命名空间
/// 如果无物可弹说明逻辑出现了问题, 所以内部处理为unwrap
/// 一个enter对应一个exit
fn block_exit(this: &mut CompileMeta) -> HashMap<Var, (Vec<Var>, Value)> {
// this is poped block
let (leaks, mut res)
= this.const_var_namespace.pop().unwrap();

// do leak
for leak_const_name in leaks {
let value
= res.remove(&leak_const_name).unwrap();

// insert to prev block
this.const_var_namespace
.last_mut()
.unwrap()
.1
.insert(leak_const_name, value);
}
res
}
res

block_enter(self);
f(self);
block_exit(self)
}

/// 添加一个需泄露的const
Expand Down
15 changes: 14 additions & 1 deletion src/syntax/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1916,6 +1916,7 @@ fn switch_catch_test() {
#[test]
fn display_source_test() {
let line_parser = LogicLineParser::new();
let jumpcmp_parser = JumpCmpParser::new();

let mut meta = Default::default();
assert_eq!(
Expand All @@ -1933,7 +1934,7 @@ fn display_source_test() {
"a > 1"
);
assert_eq!(
parse!(JumpCmpParser::new(), "a < b && c < d && e < f")
parse!(jumpcmp_parser, "a < b && c < d && e < f")
.unwrap()
.display_source_and_get(&mut meta),
"((a < b && c < d) && e < f)"
Expand Down Expand Up @@ -2004,6 +2005,18 @@ fn display_source_test() {
.display_source_and_get(&mut meta),
"'take' 'set' 'print' 'const' 'take' 'op';"
);
assert_eq!(
parse!(jumpcmp_parser, "({take X = N;} => X > 10 && X < 50)")
.unwrap()
.display_source_and_get(&mut meta),
"({take X = N;} => (X > 10 && X < 50))"
);
assert_eq!(
parse!(jumpcmp_parser, "({take X = A; take Y = B;} => X > 10 && Y > 20 && X < Y)")
.unwrap()
.display_source_and_get(&mut meta),
"({\n take X = A;\n take Y = B;\n} => ((X > 10 && Y > 20) && X < Y))"
);
}

#[test]
Expand Down

0 comments on commit e22f9cc

Please sign in to comment.