Skip to content

Commit b903329

Browse files
committed
修改常量编译时行为, 避免了一些坑.
如果依赖这些坑的代码请做迁移或者逻辑重构
1 parent 71fc477 commit b903329

File tree

4 files changed

+190
-35
lines changed

4 files changed

+190
-35
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.5.2"
3+
version = "0.6.0"
44
edition = "2021"
55

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

examples/const.mdtlbl

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,3 +75,48 @@ print __0
7575

7676
# 可以看到, 我们使用const与DExp可以完成内联函数这样的操作,
7777
# 这会使代码复用性与组织性上升
78+
79+
80+
81+
# 在0.6.0版本改变了const的作用方式
82+
const A = 1;
83+
const B = A;
84+
const A = 2;
85+
print B;
86+
87+
#* 以上代码会被编译为
88+
print 1
89+
*#
90+
# 如果在之前的版本它会被编译为`print 2`, 这显然不是我们所预期的
91+
# 在之前是普通的const, 然后在使用时进行递归追值
92+
# 而现在版本则是在const时如果是const就把值拿过来, 如果不是则与以前行为相同
93+
# 然后使用时只进行一次追值
94+
# 这样可以避免我们定义常量为另一个常量后再去追值时, 另一个常量已被覆盖或者遮蔽
95+
96+
97+
# 我们可以完成如传入一个函数的操作
98+
const DoOp = (
99+
const Func = _0;
100+
const a = _1;
101+
const b = _2;
102+
take[a b] RES = Func;
103+
$ = RES;
104+
);
105+
106+
const Add = (
107+
op $ _0 + _1;
108+
);
109+
110+
take[Add 1 2] RES = DoOp;
111+
print RES;
112+
113+
#* 以上代码会被编译为
114+
op add __1 1 2
115+
set __0 __1
116+
print __0
117+
*#
118+
# 我们可以看到, 我们传入的Add成功起效, 这可以提供更高的代码复用与抽象
119+
# 但是, 我们还可以看到, 我们经过了一次无操作赋值, 这是`$ = RES`带来的
120+
# 我们需要进行一个set将值返回出去, 目前还没有解决方法, 后续或许有办法
121+
# 例如将返回句柄映射到RES而不是我们去对返回句柄赋值RES
122+
# 但现在还没有被解决

src/syntax.rs

Lines changed: 143 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,13 @@ impl Value {
102102
Self::Var(var) => {
103103
if let Some(value) = meta.const_expand_enter(&var) {
104104
// 是一个常量
105-
let res = value.take(meta);
105+
let res = if let Value::Var(var) = value {
106+
// 只进行单步常量追溯
107+
// 因为常量定义时已经完成了原有的多步
108+
var
109+
} else {
110+
value.take(meta)
111+
};
106112
meta.const_expand_exit();
107113
res
108114
} else {
@@ -113,8 +119,8 @@ impl Value {
113119
if result.is_empty() {
114120
result = meta.get_tmp_var(); /* init tmp_var */
115121
} else if let
116-
Some((_, _, value))
117-
= meta.get_const_value_and_add(&result) {
122+
Some((_, value))
123+
= meta.get_const_value(&result) {
118124
// 对返回句柄使用常量值的处理
119125
if let Some(dexp) = value.as_dexp() {
120126
err!(
@@ -860,8 +866,8 @@ pub struct CompileMeta {
860866
/// 块中常量, 且带有展开次数与内部标记
861867
/// 并且存储了需要泄露的常量
862868
///
863-
/// `Vec<(leaks, HashMap<name, (count, Vec<Label>, Value)>)>`
864-
const_var_namespace: Vec<(Vec<Var>, HashMap<Var, (usize, Vec<Var>, Value)>)>,
869+
/// `Vec<(leaks, HashMap<name, (Vec<Label>, Value)>)>`
870+
const_var_namespace: Vec<(Vec<Var>, HashMap<Var, (Vec<Var>, Value)>)>,
865871
/// 每层DExp所使用的句柄, 末尾为当前层
866872
dexp_result_handles: Vec<Var>,
867873
tmp_tag_count: usize,
@@ -963,7 +969,7 @@ impl CompileMeta {
963969
/// 退出一个子块, 弹出最顶层命名空间
964970
/// 如果无物可弹说明逻辑出现了问题, 所以内部处理为unwrap
965971
/// 一个enter对应一个exit
966-
pub fn block_exit(&mut self) -> HashMap<Var, (usize, Vec<Var>, Value)> {
972+
pub fn block_exit(&mut self) -> HashMap<Var, (Vec<Var>, Value)> {
967973
// this is poped block
968974
let (leaks, mut res)
969975
= self.const_var_namespace.pop().unwrap();
@@ -994,7 +1000,7 @@ impl CompileMeta {
9941000

9951001
/// 获取一个常量到值的使用次数与映射与其内部标记的引用,
9961002
/// 从当前作用域往顶层作用域一层层找, 都没找到就返回空
997-
pub fn get_const_value(&self, name: &Var) -> Option<&(usize, Vec<Var>, Value)> {
1003+
pub fn get_const_value(&self, name: &Var) -> Option<&(Vec<Var>, Value)> {
9981004
self.const_var_namespace
9991005
.iter()
10001006
.rev()
@@ -1006,7 +1012,7 @@ impl CompileMeta {
10061012
/// 获取一个常量到值的使用次数与映射与其内部标记的可变引用,
10071013
/// 从当前作用域往顶层作用域一层层找, 都没找到就返回空
10081014
pub fn get_const_value_mut(&mut self, name: &Var)
1009-
-> Option<&mut (usize, Vec<Var>, Value)> {
1015+
-> Option<&mut (Vec<Var>, Value)> {
10101016
self.const_var_namespace
10111017
.iter_mut()
10121018
.rev()
@@ -1015,31 +1021,29 @@ impl CompileMeta {
10151021
})
10161022
}
10171023

1018-
/// 调用[`Self::get_const_value_mut_and_add`]
1019-
/// 并将返回结果转换为不可变引用
1020-
pub fn get_const_value_and_add(&mut self, name: &Var)
1021-
-> Option<&(usize, Vec<Var>, Value)> {
1022-
self.get_const_value_mut_and_add(name)
1023-
.map(|x| &*x)
1024-
}
1025-
1026-
/// 调用[`Self::get_const_value_mut`], 但是非空情况会给使用计数加一
1027-
pub fn get_const_value_mut_and_add(&mut self, name: &Var)
1028-
-> Option<&mut (usize, Vec<Var>, Value)> {
1029-
self.get_const_value_mut(name).map(|x| {
1030-
x.0 += 1;
1031-
x
1032-
})
1033-
}
1034-
10351024
/// 新增一个常量到值的映射, 如果当前作用域已有此映射则返回旧的值并插入新值
1036-
pub fn add_const_value(&mut self, Const(var, value, labels): Const)
1037-
-> Option<(usize, Vec<Var>, Value)> {
1025+
pub fn add_const_value(&mut self, Const(var, mut value, mut labels): Const)
1026+
-> Option<(Vec<Var>, Value)> {
1027+
// TODO
1028+
// 去掉调用次数 (*)
1029+
// 将定义常量映射到常量改为直接把常量对应的值拿过来
1030+
// 防止`const A = 1;const B = A;const A = 2;print B;`输出2
1031+
// 这还需考虑const注册标签
1032+
if let Some(var_1) = value.as_var() {
1033+
// 如果const的映射目标值是一个var
1034+
if let Some((labels_1, value_1))
1035+
= self.get_const_value(var_1).cloned() {
1036+
// 且它是一个常量, 则将它直接克隆过来.
1037+
// 防止直接映射到另一常量,
1038+
// 但是另一常量被覆盖导致这在覆盖之前映射的常量结果也发生改变
1039+
(labels, value) = (labels_1, value_1)
1040+
}
1041+
}
10381042
self.const_var_namespace
10391043
.last_mut()
10401044
.unwrap()
10411045
.1
1042-
.insert(var, (0, labels, value))
1046+
.insert(var, (labels, value))
10431047
}
10441048

10451049
/// 新增一层DExp, 并且传入它使用的返回句柄
@@ -1096,20 +1100,19 @@ impl CompileMeta {
10961100
/// 这个函数会直接调用获取函数将标记映射完毕, 然后返回其值
10971101
/// 如果不是一个宏则直接返回None, 也不会进入无需清理
10981102
pub fn const_expand_enter(&mut self, name: &Var) -> Option<Value> {
1099-
let label_count = self.get_const_value(name)?.1.len();
1103+
let label_count = self.get_const_value(name)?.0.len();
11001104
let mut tmp_tags = Vec::with_capacity(label_count);
11011105
tmp_tags.extend(repeat_with(|| self.get_tmp_tag())
11021106
.take(label_count));
11031107

1104-
let (count, labels, value)
1105-
= self.get_const_value_and_add(name).unwrap();
1108+
let (labels, value)
1109+
= self.get_const_value(name).unwrap();
11061110
let mut labels_map = HashMap::with_capacity(labels.len());
11071111
for (tmp_tag, label) in zip(tmp_tags, labels.iter().cloned()) {
11081112
let maped_label = format!(
1109-
"{}_const_{}_{}_{}",
1113+
"{}_const_{}_{}",
11101114
tmp_tag,
11111115
&name,
1112-
count,
11131116
&label
11141117
);
11151118
labels_map.insert(label, maped_label);
@@ -2060,4 +2063,111 @@ mod tests {
20602063
= 1 2;
20612064
"#).is_err());
20622065
}
2066+
2067+
#[test]
2068+
fn const_value_clone_test() {
2069+
let parser = ExpandParser::new();
2070+
2071+
let logic_lines = CompileMeta::new().compile(parse!(parser, r#"
2072+
const A = 1;
2073+
const B = A;
2074+
const A = 2;
2075+
print A B;
2076+
"#).unwrap()).compile().unwrap();
2077+
assert_eq!(logic_lines, vec![
2078+
"print 2",
2079+
"print 1",
2080+
]);
2081+
2082+
let logic_lines = CompileMeta::new().compile(parse!(parser, r#"
2083+
const A = 1;
2084+
const B = A;
2085+
const A = 2;
2086+
const C = B;
2087+
const B = 3;
2088+
const B = B;
2089+
print A B C;
2090+
"#).unwrap()).compile().unwrap();
2091+
assert_eq!(logic_lines, vec![
2092+
"print 2",
2093+
"print 3",
2094+
"print 1",
2095+
]);
2096+
2097+
let logic_lines = CompileMeta::new().compile(parse!(parser, r#"
2098+
const A = B;
2099+
const B = 2;
2100+
print A;
2101+
"#).unwrap()).compile().unwrap();
2102+
assert_eq!(logic_lines, vec![
2103+
"print B",
2104+
]);
2105+
2106+
let logic_lines = CompileMeta::new().compile(parse!(parser, r#"
2107+
const A = B;
2108+
const B = 2;
2109+
const A = A;
2110+
print A;
2111+
"#).unwrap()).compile().unwrap();
2112+
assert_eq!(logic_lines, vec![
2113+
"print B",
2114+
]);
2115+
2116+
let logic_lines = CompileMeta::new().compile(parse!(parser, r#"
2117+
const A = B;
2118+
const B = 2;
2119+
{
2120+
const A = A;
2121+
print A;
2122+
}
2123+
"#).unwrap()).compile().unwrap();
2124+
assert_eq!(logic_lines, vec![
2125+
"print B",
2126+
]);
2127+
2128+
let logic_lines = CompileMeta::new().compile(parse!(parser, r#"
2129+
const A = B;
2130+
{
2131+
const B = 2;
2132+
const A = A;
2133+
print A;
2134+
}
2135+
"#).unwrap()).compile().unwrap();
2136+
assert_eq!(logic_lines, vec![
2137+
"print B",
2138+
]);
2139+
2140+
let logic_lines = CompileMeta::new().compile(parse!(parser, r#"
2141+
const A = B;
2142+
{
2143+
const B = 2;
2144+
print A;
2145+
}
2146+
"#).unwrap()).compile().unwrap();
2147+
assert_eq!(logic_lines, vec![
2148+
"print B",
2149+
]);
2150+
2151+
let logic_lines = CompileMeta::new().compile(parse!(parser, r#"
2152+
const A = B;
2153+
const B = C;
2154+
const C = A;
2155+
print C;
2156+
"#).unwrap()).compile().unwrap();
2157+
assert_eq!(logic_lines, vec![
2158+
"print B",
2159+
]);
2160+
2161+
let logic_lines = CompileMeta::new().compile(parse!(parser, r#"
2162+
const A = C;
2163+
const C = 2;
2164+
const B = A;
2165+
const A = 3;
2166+
const C = B;
2167+
print C;
2168+
"#).unwrap()).compile().unwrap();
2169+
assert_eq!(logic_lines, vec![
2170+
"print C",
2171+
]);
2172+
}
20632173
}

0 commit comments

Comments
 (0)