-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmain.rhm
168 lines (143 loc) · 4.81 KB
/
main.rhm
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
#lang rhombus/static
import:
rhombus/meta open
export:
Dyn
maybe_dyn_block
dyn_idx_serial
dyn_append
dyn_with
stat_inspector
rename:
dyn_app as #%call
dyn_idx as #%index
dyn_append_infix as ++
dyn_with_infix as with
meta:
// Function to check if a bit of syntax has been given the `Dyn` annotation
fun has_dyn_dot_provider(stx):
def maybe_key = statinfo_meta.lookup(stx, statinfo_meta.dot_provider_key)
maybe_key && Syntax.to_source_string(maybe_key) == "dyn_dot_provider"
// Syntax class to check has_dyn_dot_provider
syntax_class DynStx
| '$(x :: Term)': match_when: has_dyn_dot_provider(x)
annot.macro 'Dyn':
annot_meta.pack_predicate('fun (x): #true', // anything can flow to Dyn
'(($(statinfo_meta.dot_provider_key), dyn_dot_provider),
($(statinfo_meta.sequence_constructor_key), dyn_seq))')
dot.macro 'dyn_dot_provider $left . $right':
'(block:
use_dynamic
$left) . $right'
expr.macro 'stat_inspector $thing':
'$thing'
expr.macro 'dyn_seq($expr)':
'block:
use_dynamic
$expr'
expr.macro 'maybe_dyn_block $thing:
$block':
if has_dyn_dot_provider(thing)
| 'block:
use_dynamic
$block'
| 'block:
$block'
expr.macro '$func dyn_app ($args, ...)':
~stronger_than: ~other
if has_dyn_dot_provider(func)
| def [temps, ...] = [Syntax.make_temp_id(args), ...]
'block:
def $temps = $args; ...
block:
use_dynamic
$func #%call ($temps, ...)'
| '$func #%call ($args, ...)'
repet.macro '$func dyn_app ($(args :: repet_meta.Parsed), ...)':
~op_stx self
fun
| max([n]): n
| max([n, ns, ...]):
let m = max([ns, ...])
if m > n | m | n
def '($func_orig, $func_name, $func_expr, $func_depth, $func_use_depth, $func_statinfos, $func_is_immed)':
repet_meta.unpack_list(func)
def ['($orig, $name, $expr, $depth, $use_depth, $statinfos, $is_immed)', ...]:
[repet_meta.unpack_list(args), ...]
unless func_depth.unwrap() == 0 && for all (d: [depth.unwrap(), ...]): d == 1 || d == 0
| error("only handle argument repetitions and constants right now")
def (pred, si):
annot_meta.unpack_predicate(match 'List' | '$(p :: annot_meta.Parsed)': p)
def temps_depths = [[Syntax.make_temp_id(expr), expr, depth.unwrap()], ...]
def [[repet_temps, repet_exprs, _d1], ...] = (for List (i: temps_depths): keep_when i[2] == 1; i)
def [[const_temps, const_exprs, _dz], ...] = (for List (i: temps_depths): keep_when i[2] == 0; i)
def [[all_temps, _expr, _depth], ...] = temps_depths
def max_depth = max([depth.unwrap(), ...])
repet_meta.pack_list('($self,
$func_name,
block:
let $const_temps = $const_exprs
...
for PairList:
each:
$repet_temps: $repet_exprs :~ PairList
...
$func_expr dyn_app ($all_temps, ...),
2, // can hardcode I think... we check that the args depth is 1 above
$max_depth,
$si,
#false)')
expr.macro
| '$thing dyn_idx [$idx] $assn_op $rhs_expr':
~stronger_than: ~other
'$thing #%index [$idx] $assn_op $rhs_expr'
| '$thing dyn_idx [$idx]':
if has_dyn_dot_provider(thing)
| 'block:
def tmp = $idx
block:
use_dynamic
$thing #%index [tmp]'
| '$thing #%index [$idx]'
expr.macro
| 'dyn_idx_serial $(thing :: DynStx) [$idx]':
'block:
def tmp = $idx
block:
use_dynamic
$thing #%index [tmp]'
| 'dyn_idx_serial $thing [$idx]':
'$thing #%index [$idx]'
expr.macro '$thing1 dyn_append_infix $thing2':
'dyn_append $thing1 $thing2'
expr.macro
| 'dyn_append $(thing1 :: DynStx) $(thing2 :: DynStx)':
'block:
use_dynamic
$thing1 ++ $thing2'
| 'dyn_append $(thing1 :: DynStx) $thing2': // Warning: out-of-order evaluation?
'block:
def tmp = $thing2
block:
use_dynamic
$thing1 ++ tmp'
| 'dyn_append $thing1 $(thing2 :: DynStx)':
'block:
def tmp = $thing1
block:
use_dynamic
tmp ++ $thing2'
| 'dyn_append $thing1 $thing2':
'$thing1 ++ $thing2'
expr.macro '$thing1 dyn_with_infix ($(var :: Identifier) = $val, ...)':
'dyn_with $thing1 ($var = $val, ...)'
expr.macro
| 'dyn_with $(thing1 :: DynStx) ($(var :: Identifier) = $val, ...)':
def [temps, ...] = [Syntax.make_temp_id(var), ...]
'block:
def $temps = $val; ...
block:
use_dynamic
$thing1 with ($var = $temps, ...)'
| 'dyn_with $thing1 ($(var :: Identifier) = $val, ...)':
'$thing1 with ($var = $val, ...)'