Skip to content

Commit 6713bf5

Browse files
committed
添加take时进行对约定的常量便捷的传参与忽略返回值的语法,
这让代码复用不再困难
1 parent a27df78 commit 6713bf5

File tree

5 files changed

+312
-10
lines changed

5 files changed

+312
-10
lines changed

Cargo.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "mindustry_logic_bang_lang"
3-
version = "0.4.3"
3+
version = "0.5.0"
44
edition = "2021"
55

66
authors = ["A4-Tacks <wdsjxhno1001@163.com>"]

examples/take2.mdtlbl

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
#* 此篇使用的是v0.5.0的语法
2+
在这个版本为take语法进行了扩展
3+
这是一个让代码复用更加方便的版本
4+
首先, 允许`take F;`这种写法了, 这将等价于以前的`take __ = F;`
5+
我们不再需要填写一个用不上的常量来符合语法了
6+
7+
然后是一个重要的语法, `take[Value*]`, 你可以在左边take的右侧插入一个方括号
8+
当你没有在里面写值时, 这等同于你不加这个方括号
9+
如果你在里面写了1至若干个值,
10+
那么take将不会被构建为一个Take, 而是一个Expand.
11+
你可以将它理解成一个块, 常量的作用域就是来源于Expand
12+
然后它会将你写在方括号内的`Value`按顺序在这个块内
13+
`const _0 = V1;`
14+
`const _1 = V2;`
15+
`const _2 = V3;`
16+
这种, 将你传入的顺序分配给`_0` `_1` `_2`名字的常量
17+
注意, 这不会进行label收集, 它仅在语法层面的`const`被编写时有效
18+
所以, 如果你想要在内部使用被跳转标签, 请老实的构建一个`const`再传入
19+
然后是take的本身`Take`
20+
接着, 如果你的take返回用常量没有缺省的话,
21+
还会再加一行`ConstLeak`, 将这个你给出的返回常量泄露到外部一层块
22+
因为这种形式的take建立了一个块, 不将其泄露到上一层块我们将无法再获取它
23+
这个`ConstLeak`目前无法被手动编写, 防止滥用、作用域逃逸等不规范使用
24+
*#
25+
26+
27+
const DO = (
28+
# 这是一个用来执行传入的第一个参数的const
29+
print "enter";
30+
take _0;
31+
print "exit";
32+
);
33+
34+
take[(
35+
print "hello";
36+
)] DO;
37+
38+
#* 以上代码会被编译为
39+
print "enter"
40+
print "hello"
41+
print "exit"
42+
*#
43+
# 可以看到, 我们使用take计算了这个`DO`, 然后它被展开
44+
# 但是根据上述介绍, 我们知道, 是先将_0被const到了我们传入的DExp中
45+
# 然后再进行take的
46+
# 所以take展开的内容中间才会正常获取_0得到我们的DExp
47+
48+
49+
const ADD = (
50+
# 这是一个将传入值计算并加1再与之前的自身相乘的DExp
51+
take N = _0; # 这里首先将传入的值计算出来, 避免如果是一个DExp反复计算
52+
op $ N + 1;
53+
op $ $ * N;
54+
);
55+
56+
take[(op $ 3 + 4;)] RES = ADD;
57+
print RES;
58+
#* 以上代码会被编译为
59+
op add __1 3 4
60+
op add __0 __1 1
61+
op mul __0 __0 __1
62+
print __0
63+
*#
64+
# 首先ADD头部的take会先将传入的DExp计算出来
65+
# 然后再使用
66+
# 接着我们的RES被映射到了返回句柄__0, 接下来使用并将其打印了出来
67+
# 我们可以看看如果不使用`take N = _0`并且N换成_0直接使用会怎样
68+
# 以下为代码
69+
const ADD = (
70+
# 这是一个将传入值计算并加1再与之前的自身相乘的DExp
71+
op $ _0 + 1;
72+
op $ $ * _0;
73+
);
74+
75+
take[(op $ 3 + 4;)] RES = ADD;
76+
print RES;
77+
#* 以上代码会被编译为
78+
op add __1 3 4
79+
op add __0 __1 1
80+
op add __2 3 4
81+
op mul __0 __0 __2
82+
print __0
83+
*#
84+
# 我们可以看到, 3 + 4被重复计算了
85+
# 这就是先使用take计算出来的意义
86+
87+
88+
# 多个值的示例
89+
const PRINT2 = (
90+
print _0 _1;
91+
);
92+
take[123 456] PRINT2;
93+
#* 以上代码会被编译为
94+
print 123
95+
print 456
96+
*#
97+
# 多个值传入也是可以的

src/syntax.rs

Lines changed: 192 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -280,6 +280,14 @@ impl Meta {
280280
pub fn pop_label_scope(&mut self) -> Vec<Var> {
281281
self.defined_labels.pop().unwrap()
282282
}
283+
284+
/// 根据一系列构建一系列常量传参
285+
pub fn build_arg_consts(&self, values: Vec<Value>, mut f: impl FnMut(Const)) {
286+
for (i, value) in values.into_iter().enumerate() {
287+
let name = format!("_{}", i);
288+
f(Const(name, value, Vec::with_capacity(0)))
289+
}
290+
}
283291
}
284292

285293
/// `jump`可用判断条件枚举
@@ -653,6 +661,7 @@ pub enum LogicLine {
653661
Ignore,
654662
Const(Const),
655663
Take(Take),
664+
ConstLeak(Var),
656665
}
657666
impl Compile for LogicLine {
658667
fn compile(self, meta: &mut CompileMeta) {
@@ -678,6 +687,7 @@ impl Compile for LogicLine {
678687
Self::Ignore => (),
679688
Self::Const(r#const) => r#const.compile(meta),
680689
Self::Take(take) => take.compile(meta),
690+
Self::ConstLeak(r#const) => meta.add_const_value_leak(r#const),
681691
}
682692
}
683693
}
@@ -807,9 +817,11 @@ pub struct CompileMeta {
807817
tag_count: usize,
808818
tag_codes: TagCodes,
809819
tmp_var_count: usize,
810-
/// # 块中宏, 且带有展开次数与内部标记
811-
/// `Vec<HashMap<name, (count, Vec<Label>, Value)>>`
812-
const_var_namespace: Vec<HashMap<Var, (usize, Vec<Var>, Value)>>,
820+
/// 块中常量, 且带有展开次数与内部标记
821+
/// 并且存储了需要泄露的常量
822+
///
823+
/// `Vec<(leaks, HashMap<name, (count, Vec<Label>, Value)>)>`
824+
const_var_namespace: Vec<(Vec<Var>, HashMap<Var, (usize, Vec<Var>, Value)>)>,
813825
/// 每层DExp所使用的句柄, 末尾为当前层
814826
dexp_result_handles: Vec<Var>,
815827
tmp_tag_count: usize,
@@ -905,14 +917,39 @@ impl CompileMeta {
905917

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

911923
/// 退出一个子块, 弹出最顶层命名空间
912924
/// 如果无物可弹说明逻辑出现了问题, 所以内部处理为unwrap
913925
/// 一个enter对应一个exit
914926
pub fn block_exit(&mut self) -> HashMap<Var, (usize, Vec<Var>, Value)> {
915-
self.const_var_namespace.pop().unwrap()
927+
// this is poped block
928+
let (leaks, mut res)
929+
= self.const_var_namespace.pop().unwrap();
930+
931+
// do leak
932+
for leak_const_name in leaks {
933+
let value
934+
= res.remove(&leak_const_name).unwrap();
935+
936+
// insert to prev block
937+
self.const_var_namespace
938+
.last_mut()
939+
.unwrap()
940+
.1
941+
.insert(leak_const_name, value);
942+
}
943+
res
944+
}
945+
946+
/// 添加一个需泄露的const
947+
pub fn add_const_value_leak(&mut self, name: Var) {
948+
self.const_var_namespace
949+
.last_mut()
950+
.unwrap()
951+
.0
952+
.push(name)
916953
}
917954

918955
/// 获取一个常量到值的使用次数与映射与其内部标记的引用,
@@ -921,7 +958,7 @@ impl CompileMeta {
921958
self.const_var_namespace
922959
.iter()
923960
.rev()
924-
.find_map(|namespace| {
961+
.find_map(|(_, namespace)| {
925962
namespace.get(name)
926963
})
927964
}
@@ -933,7 +970,7 @@ impl CompileMeta {
933970
self.const_var_namespace
934971
.iter_mut()
935972
.rev()
936-
.find_map(|namespace| {
973+
.find_map(|(_, namespace)| {
937974
namespace.get_mut(name)
938975
})
939976
}
@@ -961,6 +998,7 @@ impl CompileMeta {
961998
self.const_var_namespace
962999
.last_mut()
9631000
.unwrap()
1001+
.1
9641002
.insert(var, (0, labels, value))
9651003
}
9661004

@@ -1784,4 +1822,151 @@ mod tests {
17841822
let mut tag_codes = meta.compile(ast);
17851823
let _logic_lines = tag_codes.compile().unwrap();
17861824
}
1825+
1826+
#[test]
1827+
fn take_default_result_test() {
1828+
let parser = LogicLineParser::new();
1829+
1830+
let ast = parse!(parser, "take 2;").unwrap();
1831+
assert_eq!(ast, Take("__".into(), "2".into()).into());
1832+
}
1833+
1834+
#[test]
1835+
fn const_value_leak_test() {
1836+
let ast: Expand = vec![
1837+
Expand(vec![
1838+
LogicLine::Other(vec!["print".into(), "N".into()]),
1839+
Const("N".into(), "2".into(), Vec::new()).into(),
1840+
LogicLine::Other(vec!["print".into(), "N".into()]),
1841+
]).into(),
1842+
LogicLine::Other(vec!["print".into(), "N".into()]),
1843+
].into();
1844+
let meta = CompileMeta::new();
1845+
let mut tag_codes = meta.compile(ast);
1846+
let logic_lines = tag_codes.compile().unwrap();
1847+
assert_eq!(logic_lines, vec![
1848+
"print N",
1849+
"print 2",
1850+
"print N",
1851+
]);
1852+
1853+
let ast: Expand = vec![
1854+
Expand(vec![
1855+
LogicLine::Other(vec!["print".into(), "N".into()]),
1856+
Const("N".into(), "2".into(), Vec::new()).into(),
1857+
LogicLine::Other(vec!["print".into(), "N".into()]),
1858+
LogicLine::ConstLeak("N".into()),
1859+
]).into(),
1860+
LogicLine::Other(vec!["print".into(), "N".into()]),
1861+
].into();
1862+
let meta = CompileMeta::new();
1863+
let mut tag_codes = meta.compile(ast);
1864+
let logic_lines = tag_codes.compile().unwrap();
1865+
assert_eq!(logic_lines, vec![
1866+
"print N",
1867+
"print 2",
1868+
"print 2",
1869+
]);
1870+
}
1871+
1872+
#[test]
1873+
fn take_test2() {
1874+
let parser = LogicLineParser::new();
1875+
1876+
let ast = parse!(parser, "take X;").unwrap();
1877+
assert_eq!(ast, Take("__".into(), "X".into()).into());
1878+
1879+
let ast = parse!(parser, "take R = X;").unwrap();
1880+
assert_eq!(ast, Take("R".into(), "X".into()).into());
1881+
1882+
let ast = parse!(parser, "take[] X;").unwrap();
1883+
assert_eq!(ast, Take("__".into(), "X".into()).into());
1884+
1885+
let ast = parse!(parser, "take[] R = X;").unwrap();
1886+
assert_eq!(ast, Take("R".into(), "X".into()).into());
1887+
1888+
let ast = parse!(parser, "take[1 2] R = X;").unwrap();
1889+
assert_eq!(ast, Expand(vec![
1890+
Const::new("_0".into(), "1".into()).into(),
1891+
Const::new("_1".into(), "2".into()).into(),
1892+
Take("R".into(), "X".into()).into(),
1893+
LogicLine::ConstLeak("R".into()),
1894+
]).into());
1895+
1896+
let ast = parse!(parser, "take[1 2] X;").unwrap();
1897+
assert_eq!(ast, Expand(vec![
1898+
Const::new("_0".into(), "1".into()).into(),
1899+
Const::new("_1".into(), "2".into()).into(),
1900+
Take("__".into(), "X".into()).into(),
1901+
]).into());
1902+
}
1903+
1904+
#[test]
1905+
fn take_args_test() {
1906+
let parser = ExpandParser::new();
1907+
1908+
let ast = parse!(parser, r#"
1909+
const M = (
1910+
print _0 _1 _2;
1911+
set $ 3;
1912+
);
1913+
take[1 2 3] M;
1914+
take[4 5 6] R = M;
1915+
print R;
1916+
"#).unwrap();
1917+
let meta = CompileMeta::new();
1918+
let mut tag_codes = meta.compile(ast);
1919+
let logic_lines = tag_codes.compile().unwrap();
1920+
assert_eq!(logic_lines, vec![
1921+
"print 1",
1922+
"print 2",
1923+
"print 3",
1924+
"set __0 3",
1925+
"print 4",
1926+
"print 5",
1927+
"print 6",
1928+
"set __1 3",
1929+
"print __1",
1930+
]);
1931+
1932+
let ast = parse!(parser, r#"
1933+
const DO = (
1934+
print _0 "start";
1935+
take _1;
1936+
print _0 "start*2";
1937+
take _1;
1938+
printflush message1;
1939+
);
1940+
# 这里赋给一个常量再使用, 因为直接使用不会记录label, 无法重复被使用
1941+
# 而DO中, 会使用两次传入的参数1
1942+
const F = (
1943+
i = 0;
1944+
while i < 10 {
1945+
print i;
1946+
op i i + 1;
1947+
}
1948+
);
1949+
take["loop" F] DO;
1950+
"#).unwrap();
1951+
let meta = CompileMeta::new();
1952+
let mut tag_codes = meta.compile(ast);
1953+
let logic_lines = tag_codes.compile().unwrap();
1954+
assert_eq!(logic_lines, vec![
1955+
r#"print "loop""#,
1956+
r#"print "start""#,
1957+
r#"set i 0"#,
1958+
r#"jump 7 greaterThanEq i 10"#,
1959+
r#"print i"#,
1960+
r#"op add i i 1"#,
1961+
r#"jump 4 lessThan i 10"#,
1962+
r#"print "loop""#,
1963+
r#"print "start*2""#,
1964+
r#"set i 0"#,
1965+
r#"jump 14 greaterThanEq i 10"#,
1966+
r#"print i"#,
1967+
r#"op add i i 1"#,
1968+
r#"jump 11 lessThan i 10"#,
1969+
r#"printflush message1"#,
1970+
]);
1971+
}
17871972
}

0 commit comments

Comments
 (0)