-
Notifications
You must be signed in to change notification settings - Fork 1
/
dexp.mdtlbl
90 lines (84 loc) · 4.02 KB
/
dexp.mdtlbl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
#*
* 这是bang语言中重要的组成部分, `DExp`
* 它是一个特殊的表达式, 在其中可以有多个语句, 然后提供一个句柄来当返回值
* 这个句柄在未手动指定时, 会自动分配一个不重复的值
*
* 我们可以在任何接受Value的语法中使用DExp, 因为DExp是Value的一个变体
* 例如我们熟知的op
* op a b + c; 或者 op add a b c; 或者 op abs a b; 或者 op a abs b; 中
* a和b和c的类型是一个Value, 它们可以是一个值、一个DExp、一个句柄替换符,
* 值: 就像123 "abc" var 这样的字面值或者变量
* DExp: 用圆括号括起来的一组语句,
* 头部可以使用一个Var跟一个冒号也就是值来显式定义返回句柄.
* 其原理是从左到右深度遍历的编译其内语句, 然后编译完毕后再编译调用者,
* 在调用者DExp的位置会被替换为DExp的返回句柄
* 如果没有显式定义返回句柄将会被自动分配一个不重复的值
* 在DExp中, 我们可以在使用Value的地方使用句柄替换符,
* 会被替换为当前层DExp的返回句柄
* 句柄替换符: 符号为(`$`), 可以在使用Value的地方使用(它也是一个Value)
* 会被替换为当前层的句柄, 例如
* `x = (y: y = (z: $ = 2;););`,
* 此处的句柄替换符会被替换为`z`
*
* 需要注意的是, 对于Var这些, 它们的句柄即为它们自己本身
*
* 语法方面的困惑可以查看源码中的`parser.lalrpop`文件
* `...: ... = ... => ...;`这种就是一个类型定义, 而`=>`前面的就是语法定义, 后方的不用管那是逻辑处理
* 例如`pub Foo: FooStruct = "!" <r"\d+"> => { ... };`
* pub是可见性, 不用管
* Foo是语法结构名字
* FooStruct是处理后返回类型, 不用管
* "!"是一个常量符号
* <...>外面这个尖括号没有语法意义, 不用管
* r"\d+"这里的r标识这个字符串为一个正则表达式
* 根据以上规则 我们可以写出 `!123` `! 2495` 会符合这个语法结构
* 当然, 除了正则啊 常量符号里面, 其它间隙都是允许空白符的,
* 例如`! 23`是被允许的
* 再接着`pub Bar: BarStruct = "@" <Foo> "&"`, 此处使用了Foo结构
* 根据前面学的, 我们很容易就可以写出`@ ! 234 &`来被这个语法结构匹配
* 很简单吧? 在此处感谢lalrpop框架
* 再接着`pub Variant: () = { Bar, "_" }`, 这里有两个新知识点
* 等号后面写花括号代表匹配其中一个结构
* 没有`=>`号代表直接使用这个结构的值(没有语法意义,
* 不用管, 当做有个隐藏的 `=> { ... }`就行)
* 至于`Macro<T> = "(" <T> ")"; pub X: Bar = Macro<Bar>;`
* 相当于`pub X: Bar = "(" <Bar> ")";`,
* 直接就是宏展开替换过来
*
* 在0.14.21版本中, 为值添加了无操作的括号, 其使用例子为`(% value )`
* 可以在其中包含任意的Value, 这可以扩展某些操作
* 例如之后会学到的 ValueBind 绑定者可以用这种括号括起来,
* 这样就可以绑定 DExp, ConstedDExp 等语法了
*
* 还有一个小语法糖, 可以用如 `(%res: print 1;%)` 来替代 `(%(res: print 1;))`,
* 其意义完全相同
*#
set x (op a 1 + 2; op $ a + 2;);
#* 会被编译为:
op add a 1 2
op add __0 a 2
set x __0
*#
# 可以看到, 此处__0就是一个自动分配的变量,
# 不用管它的变量名, 只要好好用`$`就行
# 简而言之, 就是可以在 DExp 中放一些逻辑语句,
# 然后使用这个 DExp 时这些语句总是会在使用之前执行,
# 并且如果需要传递值, DExp 中的语句给 $ 赋值就行,
# 表示了当前这一层 DExp 代表的句柄
print "core: ";
print (
ulocate building core false @copper outx outy found $;
print "pos: " outx ", " outy;
);
printflush message1;
# 以下为上述代码编译的结果
#* >>>
print "core: "
ulocate building core false @copper outx outy found __0
print "pos: "
print outx
print ", "
print outy
print __0
printflush message1
*#