Skip to content

Commit

Permalink
添加了control-block, 可以简单的控制break和continue的目标了
Browse files Browse the repository at this point in the history
  • Loading branch information
A4-Tacks committed Nov 10, 2023
1 parent 70530f2 commit cf45c5c
Show file tree
Hide file tree
Showing 7 changed files with 286 additions and 7 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.7"
version = "0.12.8"
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 @@ -12,6 +12,7 @@
> [`op_expr.mdtlbl`](./op_expr.mdtlbl)<br/>
> [`control.mdtlbl`](./control.mdtlbl)<br/>
> [`control_plus.mdtlbl`](./control_plus.mdtlbl)<br/>
> [`control_block.mdtlbl`](./control_block.mdtlbl)<br/>
> [`cmps.mdtlbl`](./cmps.mdtlbl)<br/>
> [`insert_sort.mdtlbl`](./insert_sort.mdtlbl)<br/>
> [`switch.mdtlbl`](./switch.mdtlbl)<br/>
Expand Down
31 changes: 31 additions & 0 deletions examples/control_block.mdtlbl
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
#**
* 这是0.12.8加入的功能, 可以自定义break和continue的跳出点.
* 语法为(("break" | "continue") "!"?)+ Block
* 其中编写break就是表示捕获break至块末尾,
* 编写continue就是表示捕获continue至块末尾.
*
* 当break或者continue后方加上了叹号时, 将反转其跳转点,
* 例如`break! { ... }`内部使用break会跳转到块首部,
* 也就是应该continue跳转到的位置.
*#

i = 0;
while i < 10 {
continue! {
getlink block i;
continue !(sensor $ block @enabled;);
}
op i i + 1;
}
#* >>>
set i 0
jump 0 greaterThanEq i 10
getlink block i
sensor __0 block @enabled
jump 5 equal __0 false
op add i i 1
jump 2 lessThan i 10
*#
# 可以看到, 控制块中的continue被导向了i自加处,
# 这样就可以在循环等结构中简单的定义break和continue的导向处了
# 合理使用可以增加一些可读性等
36 changes: 36 additions & 0 deletions src/syntax/def.lalrpop
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,12 @@ OOCArgs<T, S>: Vec<T> = {
}
Span<T> = @L T @R;

CtrlBreakStart: () = () => meta.add_control_break_level(None);
CtrlContinueStart: () = () => meta.add_control_continue_level(None);
CtrlStart: () = () => meta.add_control_level(None, None);

CtrlBreakStop: Option<Var> = () => meta.pop_control_break_level();
CtrlContinueStop: Option<Var> = () => meta.pop_control_continue_level();
CtrlStop: (Option<Var>, Option<Var>) = () => meta.pop_control_level();

pub TopLevel: Expand = CtrlStart <mut lines:Expand> <ctrl:CtrlStop> => {
Expand Down Expand Up @@ -594,6 +599,35 @@ SwitchCatchFlag: SwitchCatch = {
MTuple<JumpCmp> => SwitchCatch::UserDefine(<>),
}

ControlBlock: Expand = {
"break" <bang:"!"?>
CtrlBreakStart <lines:Or<ControlBlock, BlockExpand>> <ctrl:CtrlBreakStop>
=> {
let mut res = Vec::with_capacity(2);
if bang.is_none() {
res.push(lines.into());
meta.push_some_label_to(&mut res, ctrl);
} else {
meta.push_some_label_to(&mut res, ctrl);
res.push(lines.into());
}
res.into()
},
"continue" <bang:"!"?>
CtrlContinueStart <lines:Or<ControlBlock, BlockExpand>> <ctrl:CtrlContinueStop>
=> {
let mut res = Vec::with_capacity(2);
if bang.is_none() {
meta.push_some_label_to(&mut res, ctrl);
res.push(lines.into());
} else {
res.push(lines.into());
meta.push_some_label_to(&mut res, ctrl);
}
res.into()
},
}

pub Control: LogicLine = {
"goto" <Label> <AlwaysJumpCmp> LEnd => {
Goto(<>).into()
Expand All @@ -607,6 +641,8 @@ pub Control: LogicLine = {
Goto(meta.get_continue().clone(), <>).into()
},

ControlBlock => <>.into(),

"skip" <cmp:JumpCmp> <body:LogicLine> => {
let lab = meta.get_tag();
Expand(vec![
Expand Down
27 changes: 22 additions & 5 deletions src/syntax/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -509,24 +509,41 @@ impl Meta {
self.defined_labels.pop().unwrap()
}

pub fn add_control_break_level(&mut self, r#break: Option<Var>) {
self.break_labels.push(r#break);
}

pub fn add_control_continue_level(&mut self, r#continue: Option<Var>) {
self.continue_labels.push(r#continue);
}

/// 添加一层用于`break`和`continue`的未使用控制层
///
/// 需要在结构结束时将其销毁
pub fn add_control_level(
&mut self, r#break: Option<Var>,
&mut self,
r#break: Option<Var>,
r#continue: Option<Var>,
) {
self.break_labels.push(r#break);
self.continue_labels.push(r#continue);
self.add_control_break_level(r#break);
self.add_control_continue_level(r#continue);
}

pub fn pop_control_break_level(&mut self) -> Option<Var> {
self.break_labels.pop().unwrap()
}

pub fn pop_control_continue_level(&mut self) -> Option<Var> {
self.continue_labels.pop().unwrap()
}

/// 将`break`和`continue`的标签返回
///
/// 如果未使用那么返回的会为空
pub fn pop_control_level(&mut self) -> (Option<Var>, Option<Var>) {
(
self.break_labels.pop().unwrap(),
self.continue_labels.pop().unwrap(),
self.pop_control_break_level(),
self.pop_control_continue_level(),
)
}

Expand Down
194 changes: 194 additions & 0 deletions src/syntax/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3097,3 +3097,197 @@ fn optional_jumpcmp_test() {
);

}

#[test]
fn control_block_test() {
let parser = TopLevelParser::new();

assert_eq!(
CompileMeta::new().compile(parse!(parser, r#"
a;
break {
b;
break;
c;
}
d;
break;
"#).unwrap()).compile().unwrap(),
[
"a",
"b",
"jump 4 always 0 0",
"c",
"d",
"jump 0 always 0 0",
]
);

assert_eq!(
CompileMeta::new().compile(parse!(parser, r#"
a;
break! {
b;
break;
c;
}
d;
break;
"#).unwrap()).compile().unwrap(),
[
"a",
"b",
"jump 1 always 0 0",
"c",
"d",
"jump 0 always 0 0",
]
);

assert_eq!(
CompileMeta::new().compile(parse!(parser, r#"
a;
continue {
b;
continue;
c;
}
d;
continue;
"#).unwrap()).compile().unwrap(),
[
"a",
"b",
"jump 1 always 0 0",
"c",
"d",
"jump 0 always 0 0",
]
);

assert_eq!(
CompileMeta::new().compile(parse!(parser, r#"
a;
continue! {
b;
continue;
c;
}
d;
continue;
"#).unwrap()).compile().unwrap(),
[
"a",
"b",
"jump 4 always 0 0",
"c",
"d",
"jump 0 always 0 0",
]
);

assert_eq!(
CompileMeta::new().compile(parse!(parser, r#"
a;
continue {
b;
break;
c;
}
d;
continue;
"#).unwrap()).compile().unwrap(),
[
"a",
"b",
"jump 0 always 0 0",
"c",
"d",
"jump 0 always 0 0",
]
);

assert_eq!(
CompileMeta::new().compile(parse!(parser, r#"
a;
break {
b;
continue;
c;
}
d;
break;
"#).unwrap()).compile().unwrap(),
[
"a",
"b",
"jump 0 always 0 0",
"c",
"d",
"jump 0 always 0 0",
]
);

assert_eq!(
CompileMeta::new().compile(parse!(parser, r#"
a;
break continue {
b;
continue;
break;
c;
}
d;
"#).unwrap()).compile().unwrap(),
[
"a",
"b",
"jump 1 always 0 0",
"jump 5 always 0 0",
"c",
"d",
]
);

assert_eq!(
CompileMeta::new().compile(parse!(parser, r#"
a;
continue break {
b;
continue;
break;
c;
}
d;
"#).unwrap()).compile().unwrap(),
[
"a",
"b",
"jump 1 always 0 0",
"jump 5 always 0 0",
"c",
"d",
]
);

assert_eq!(
CompileMeta::new().compile(parse!(parser, r#"
a;
continue! break! {
b;
break;
continue;
c;
}
d;
"#).unwrap()).compile().unwrap(),
[
"a",
"b",
"jump 1 always 0 0",
"jump 5 always 0 0",
"c",
"d",
]
);
}

0 comments on commit cf45c5c

Please sign in to comment.