-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathop_expr.mdtlbl
244 lines (222 loc) · 7.11 KB
/
op_expr.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
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
#**
* 这是在0.11.0版本添加的表达式系统, 旨在更加干练的编写复杂运算
* 可以有限的以我们比较常见的表达式形式使用op来进行运算
* 这个语法可以看成在对sets左值为单个时的行为扩展
* 在sets左值为单个Value时, 右值将成为一个op-expr
*
* 以下为各种运算符的优先级与结合性:
* | 符号 | 实际运算(op) | 优先级 | 结合性 |
* | ---------- | ------------ | ------ | ------ |
* | `++ a` | `++ a` | -1 | - |
* | `-- a` | `-- a` | -1 | - |
* | `a ++` | `a ++` | -1 | - |
* | `a --` | `a --` | -1 | - |
* | `a ** b` | `a ** b` | -2 | RL |
* | `! x` | `x != false` | -3 | R |
* | `- x` | `0 - x` | -3 | R |
* | `~ x` | `~ x` | -3 | R |
* | `a * b` | `a * b` | -4 | LR |
* | `a / b` | `a / b` | -4 | LR |
* | `a % b` | `a % b` | -4 | LR |
* | `a // b` | `a // b` | -4 | LR |
* | `a + b` | `a + b` | -5 | LR |
* | `a - b` | `a - b` | -5 | LR |
* | `a << b` | `a << b` | -6 | LR |
* | `a >> b` | `a >> b` | -6 | LR |
* | `a & b` | `a & b` | -7 | LR |
* | `a ^ b` | `a ^ b` | -8 | LR |
* | `a | b` | `a | b` | -9 | LR |
* | `a < b` | `a < b` | -10 | - |
* | `a > b` | `a > b` | -10 | - |
* | `a <= b` | `a <= b` | -10 | - |
* | `a >= b` | `a >= b` | -10 | - |
* | `a == b` | `a == b` | -11 | - |
* | `a != b` | `a != b` | -11 | - |
* | `a === b` | `a === b` | -11 | - |
* | `a !== b` | `a !== b` | -11 | - |
* | `a && b` | `a && b` | -12 | LR |
* | `a || b` | `a + b` | -13 | LR |
* | `if c?a:b` | ... | -14 | LR |
*
* 结合性的`LR`指左结合 比如`a+b+c`结合为`(a+b)+c`
* 而结合性为`-`指不发生结合, 将需要添加括号
*
* 以上表格外, 还有一元与二元函数(其实就是op)
* 它们的优先级与括号平级,
* 二元函数有: `max` `min` `angle` `len` `noise`,
* 一元函数的部分列举有: `log` `rand` ...,
*
* 具体参考op中没有符号的运算
*
* 对于三元表达式, 也就是`if c?a:b`,
* 它是低优先级的, 所以参与高优先级运算时需要括号括起.
* 就算是`1+if x != y ? x : y`这样的, 也需要写成`1+(if x != y ? x : y)`
* 想要取消这个设计的方案有几个但都极其复杂, 所以就如现在这样.
* 注意, 结果带值而非运算的三元表达式最好写在顶层, 不然可能出现不必要的赋值
*
* 在0.14.21版本中, 添加了一个语法糖, 可以用 `(?x: a+b)` 来表示 `(x: $=a+b;)`
* 而在0.16.19版本中, 增加了简单的`(*a+b)`, 和`(?a+b)`区别在于它直接尝试展开成值
* 这样在例如`++i`的时候可以不用看到不想要的set, `(*++i)`和`(?++i)`
*#
x = 1 + 2 * 3;
y = (1 + 2) * 3;
z = min(a+b, c-d);
#* A >>>
op 'x' '1' + (op $ '2' * '3';);
op 'y' (op $ '1' + '2';) * '3';
op 'z' min (op $ 'a' + 'b';) (op $ 'c' - 'd';);
*#
# 我们可以看出, 优先级生效了, 并且运算被正常解析为DExp树了
# 并且我们并没有遇到最后要经历一遭set的问题, 因为解析时有一个安全标记
# 这个标记将使我们可以正确的将op与set合并.
#
# 当然, 需要注意的是,
# 虽然运算成员是Value, 但依旧不推荐使用`$`符号(返回句柄替换符)
# 因为这并没有什么意义, 且如果在最外层, 那么因为最顶层op与set的合并,
# 这个句柄将会指向set的更外层的DExp.
# 在0.11.2版本起, 我们可以像sets一样, 同时进行多个
a, b, c = x, -y, z+2*3;
#* A >>>
{
`'set'` 'a' 'x';
op 'b' `'0'` - 'y';
op 'c' 'z' + (op $ '2' * '3';);
}
*#
# 可以看到, 就像sets一样, 只不过使用逗号分隔了.
# 对于多个简易运算, 我们不用写在多行或者使用额外一个set来换取写在一行中了
# 当然, 运算之外的例如sensor还是不能这么做,
# 因为op-expr的内联set目前仅为它自己的op服务
#
# 起码我们在数学运算方面的舒适度上来了不是吗
# 三元表达式可以在分支运算赋值上进行简化
x = if a < b ? 2 + 3 : 4;
#* A >>>
{
take '___0' = 'x';
goto :'___0' 'a' < 'b';
`'set'` '___0' '4';
goto :'___1' _;
:'___0'
op '___0' '2' + '3';
:'___1'
}
*#
x = if a < b ? if c < d ? c : d : if e < f ? e : f;
#* A >>>
{
take '___2' = 'x';
goto :'___4' 'a' < 'b';
{
take '___1' = '___2';
goto :'___2' 'e' < 'f';
`'set'` '___1' 'f';
goto :'___3' _;
:'___2'
`'set'` '___1' 'e';
:'___3'
}
goto :'___5' _;
:'___4'
{
take '___0' = '___2';
goto :'___0' 'c' < 'd';
`'set'` '___0' 'd';
goto :'___1' _;
:'___0'
`'set'` '___0' 'c';
:'___1'
}
:'___5'
}
*#
x = 1 + (if y ? y : z);
#* A >>>
op 'x' '1' + (
take '___0' = $;
goto :'___0' 'y' != `'false'`;
`'set'` '___0' 'z';
goto :'___1' _;
:'___0'
`'set'` '___0' 'y';
:'___1'
);
*#
# 由于前面解释过的原因, 你需要添加括号
# 这是0.12.7版本添加的语法, 可以将一个值一次赋给多个接收者
# 方法是使用首次赋值的值来为接下来赋值
#
# 需要注意的是, 求值顺序是:
# 第一个接收者 -> 值 -> 第二个接收者 -> ... -> 第N个接收者
a, b, c = 1 + 2 * 3;
#* A >>>
{
take ___0 = a;
op ___0 1 + (op $ 2 * 3;);
`'set'` b ___0;
`'set'` c ___0;
}
*#
#**
* 在0.14.17版本, 可以对常见的运算使用自运算格式, 这会简化一些代码
* 这些运算包括+-*///%等运算, 同时也支持min和max
*#
x += n*2;
#**
* 在0.16.15版本, 这些顶层自运算可以使用顶层赋值可用的操作了,
* 例如
*#
a, b += c + d;
x, y += w, h;
#* >>>
op add __0 c d
op add a a __0
op add b b __0
op add x x w
op add y y h
*#
#**
* 在0.16.16版本添加了单元自运算, 熟悉的++ --终于登场了
*#
j = i++;
k = ++i;
#* >>>
set j i
op add i i 1
op add i i 1
set k i
*#
# 同时还有一个扩展用法, 因为如`x+i++`这种情况`i++`被展开为值而非行,
# 则可能产生不希望的set, 所以可以使用扩展语法将外层操作挪到内层去
a = x + i++;
#* >>>
set __0 i
op add i i 1
op add a x __0
*#
b = i++(x + _);
#* >>>
op add b x i
op add i i 1
*#
# 可以看到, 使用这种方式使`i++`操作又回到了顶层, 从而被展开成行, 保证了性能
# 这个问题在if else也有类似例子.
# `_`是占位表达式, 它会构建时被替换为外层的`i++`中i被take的句柄
# `i++(...)`中的`(...)`接受正常的op-expr, 然后会将其展开成行,
# 返回句柄视外层的`i++`而定, 如果外层不是展开成行, 那么它会直接赋给`$`
# 还有一个单独的简单用法, 比如
i++; j--;
#* A >>>
{
take ___0 = i;
op ___0 ___0 + `1`;
}
{
take ___1 = j;
op ___1 ___1 - `1`;
}
*#
# 在0.16.22版本为了使take配合op-expr更加简洁, 添加了一个语法糖
take*A, B = x+y, i++;
# 相当于
take A=(*x+y) B=(*i++);