Skip to content

Commit

Permalink
给重复块的重复次数添加参与常量系统的能力
Browse files Browse the repository at this point in the history
  • Loading branch information
A4-Tacks committed Jan 27, 2025
1 parent a3ab2f4 commit 088e674
Show file tree
Hide file tree
Showing 13 changed files with 151 additions and 25 deletions.
13 changes: 7 additions & 6 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.17.19"
version = "0.17.20"
edition = "2021"

authors = ["A4-Tacks <[email protected]>"]
Expand Down
21 changes: 21 additions & 0 deletions examples/learn.md
Original file line number Diff line number Diff line change
Expand Up @@ -1264,6 +1264,27 @@ print 1

通常重复块也配合着 match 一起使用, 来取出参数内容, 或者仅关心参数足够时的情况

> [!TIP]
> 重复块的重复次数类似 gswitch, 也可以参与常量系统, 但是需要额外标注才能使用
```
const C = 2;
match 1 2 3 4 5 6 7 { @ {} }
inline*C@{
foo @;
}
```
编译为
```
foo 1 2
foo 3 4
foo 5 6
foo 7
```

> [!NOTE]
> 重复块从常量系统中获取的重复次数是使用常量评估而不是求值进行的,
> 所以对于一些值你可能需要先求值再给重复块使用

常用语法糖
===============================================================================
Expand Down
14 changes: 14 additions & 0 deletions examples/match.mdtlbl
Original file line number Diff line number Diff line change
Expand Up @@ -397,3 +397,17 @@ match @ {
}
}
# 在只有一个分支时可以减少一层括号, 用于快速接收参数等情况非常舒适


# 在0.17.20版本为重复块添加了从常量系统中获取重复次数的能力
# 需要注意的是, 它获取的方式是使用编译期计算完成的,
# 所以有时你需要先take再给重复块使用
match a b c { @ {} }
const C = 2;
inline*C@ {
foo @;
}
#* >>>
foo a b
foo c
*#
8 changes: 4 additions & 4 deletions syntax/vim/syntax/mdtlbl.vim
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,11 @@ syn case match
syn keyword mdtlblKeyword
\ while gwhile do skip if elif else switch gswitch break continue
\ const setres select match
\ inline
\ op noop print
syn keyword mdtlblKeyword goto nextgroup=mdtlblIdentLabelRest
syn keyword mdtlblKeyword case nextgroup=mdtlblStar skipwhite
syn keyword mdtlblKeyword take nextgroup=mdtlblStar skipwhite
syn keyword mdtlblKeyword goto nextgroup=mdtlblIdentLabelRest
syn keyword mdtlblKeyword case nextgroup=mdtlblStar skipwhite
syn keyword mdtlblKeyword take nextgroup=mdtlblStar skipwhite
syn keyword mdtlblKeyword inline nextgroup=mdtlblStar skipwhite
syn match mdtlblStar /\*/ contained

syn keyword mdtlblOpFunKeyword
Expand Down
1 change: 1 addition & 0 deletions tools/display_source/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
either = "1.10.0"
syntax = { path = "../syntax", version = "*" }

[dev-dependencies]
Expand Down
13 changes: 11 additions & 2 deletions tools/display_source/src/impls.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use syntax::*;
use crate::{DisplaySource, DisplaySourceMeta};
use either::{self, Left, Right};

fn inline_labs_and_binder<T>(
labs: &[T],
Expand Down Expand Up @@ -552,8 +553,16 @@ impl DisplaySource for Args {
impl DisplaySource for ArgsRepeat {
fn display_source(&self, meta: &mut DisplaySourceMeta) {
meta.push("inline");
meta.add_space();
meta.push(&self.count().to_string());
match self.count() {
Left(n) => {
meta.add_space();
meta.push_fmt(n);
},
Right(value) => {
meta.push("*");
value.display_source(meta);
},
}
meta.push("@");
meta.push("{");
if !self.block().is_empty() {
Expand Down
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.26"
version = "0.3.27"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
Expand Down
3 changes: 3 additions & 0 deletions tools/parser/src/parser.lalrpop
Original file line number Diff line number Diff line change
Expand Up @@ -526,6 +526,9 @@ ArgsRepeatBlock: ArgsRepeat = {
}
Ok(ArgsRepeat::new(chunk.unwrap_or(1), block))
},
"*" <value:Loc<NonConstRangeValue>> "@" <block:NoPrefixInlineBlock> => {
ArgsRepeat::new_valued(value, block)
},
<l:Loc<"@">> <pats:ConstMatchPatAtom+> <block:NoPrefixInlineBlock> => {
let glob = l.new_value(Args::GLOB_ONLY);
ArgsRepeat::new(pats.len(), vec![
Expand Down
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.45"
version = "0.1.46"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
Expand Down
41 changes: 41 additions & 0 deletions tools/parser/tests/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4786,6 +4786,47 @@ fn match_test() {
],
);

assert_eq!(
CompileMeta::new().compile(parse!(parser, r#"
const C = 1;
match a b c { @{} }
inline*C@{
foo @;
}
print end;
print @;
"#).unwrap()).compile().unwrap(),
vec![
"foo a",
"foo b",
"foo c",
"print end",
"print a",
"print b",
"print c",
],
);

assert_eq!(
CompileMeta::new().compile(parse!(parser, r#"
const C = 2;
match a b c { @{} }
inline*C@{
foo @;
}
print end;
print @;
"#).unwrap()).compile().unwrap(),
vec![
"foo a b",
"foo c",
"print end",
"print a",
"print b",
"print c",
],
);

assert_eq!(
CompileMeta::new().compile(parse!(parser, r#"
match a b c { __ @{} }
Expand Down
4 changes: 2 additions & 2 deletions tools/syntax/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "syntax"
version = "0.2.49"
version = "0.2.50"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
Expand All @@ -10,4 +10,4 @@ tag_code = { path = "../tag_code", version = "*" }
var_utils = { path = "../var_utils", version = "*"}
utils = { path = "../utils", version = "*" }
either = "1.10.0"
itermaps = "0.2.8"
itermaps = "0.3.1"
52 changes: 44 additions & 8 deletions tools/syntax/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ use std::{

use builtins::{build_builtins, BuiltinFunc};
use either::Either;
use itermaps::{fields, MapExt, Unpack};
use itermaps::{fields, short_funcs::copy, MapExt, Unpack};
use tag_code::{
args,
logic_parser::{Args as LArgs, IdxBox, ParseLine, ParseLines},
Expand Down Expand Up @@ -2811,20 +2811,21 @@ impl_enum_froms!(impl From for Args {
/// 拿取指定个参数, 并重复块中代码
#[derive(Debug, PartialEq, Clone)]
pub struct ArgsRepeat {
count: usize,
count: Either<usize, IdxBox<Value>>,
block: InlineBlock,
}
impl ArgsRepeat {
pub fn new(count: usize, block: InlineBlock) -> Self {
Self { count, block }
assert_ne!(count, 0);
Self { count: Either::Left(count), block }
}

pub fn count(&self) -> usize {
self.count
pub fn new_valued(count: IdxBox<Value>, block: InlineBlock) -> Self {
Self { count: Either::Right(count), block }
}

pub fn count_mut(&mut self) -> &mut usize {
&mut self.count
pub fn count(&self) -> Either<usize, &IdxBox<Value>> {
self.count.as_ref().map_left(copy)
}

pub fn block(&self) -> &InlineBlock {
Expand All @@ -2837,8 +2838,43 @@ impl ArgsRepeat {
}
impl Compile for ArgsRepeat {
fn compile(self, meta: &mut CompileMeta) {
let count = match self.count {
Either::Left(count) => count,
Either::Right(value) => {
let Some((n, _)) = value.try_eval_const_num(meta) else {
let (line, col) = value.location(&meta.source);
err!(
"{}\n重复块次数不是数字, 位于: {}:{}\n{}",
meta.err_info().join("\n"),
line, col,
value.display_src(meta),
);
exit(6)
};
let n = n.round();
if n <= 0.0 || !n.is_finite() {
let (line, col) = value.location(&meta.source);
err!(
"{}\n重复块次数必须大于0 ({}), 位于: {}:{}",
meta.err_info().join("\n"),
n, line, col,
);
exit(6)
}
if n > 512.0 {
let (line, col) = value.location(&meta.source);
err!(
"{}\n重复块次数过大 ({}), 位于: {}:{}",
meta.err_info().join("\n"),
n, line, col,
);
exit(6)
}
n as usize
},
};
let chunks: Vec<Vec<Value>> = meta.get_env_args()
.chunks(self.count)
.chunks(count)
.map(|chunks| chunks.iter()
.cloned()
.map(Into::into)
Expand Down

0 comments on commit 088e674

Please sign in to comment.