aboutsummaryrefslogtreecommitdiff
path: root/src/c.bqn
blob: 018e032ba5b2397caff0ef55ea3f29bf6011ac9a (plain)
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
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
funcmod1mod2  •args
lf@+1013
charSetcgl(  ¨)
  func                  # Function
  mod1                  # 1-modifier
  mod2                  # 2-modifier
  "⋄,"lf               # Separator
  ":;?"                 # Header punctuation
  "⇐←↩"                 # Gets
  "(){}⟨⟩"              # Bracket
  "‿"                   # Ligature
  "·"                   # nOthing
  # Use last character in case of UTF-16 (like dzaima/BQN)
  ¯1˘11"𝕊𝕏𝕎𝔽𝔾𝕤𝕩𝕨𝕣𝕗𝕘"# Input
  ".¯π∞"                # Numeric
  '0'+↕10               # Digit
  "_"˜"aA"+na26    # Alphabetic
  "•"(¯1"𝕨")" "@+9  # Whitespace (or special name prefix in UTF-16)
  "#'""@"               # Preprocessed characters

bFb1b2bSbHbGbBbLbObXbNbDbAbWbP¨˜(0»+`)cgl
M1(0≤∧>)-   # ∊ for an init,length pair 𝕩 as above
sepbS
pred2+⊑bH
bIbX+⋈-5bR8+⊑bX
Pl("s"/˜1<≠)   # Pluralize
_tmpl{𝕗{𝕎𝕩}¨<𝕩} # Template
# Convert characters to numbers, mostly the same as tokens
CharCodecharSet{
  ErrUnknownChars!"Unknown character"Pl,": ",_tmpl
  Chk  ⊢⊣ErrUnknownChars(≠/⊣)(𝕗)
  (! "Character set conflict: "gf/˜0)(´) 1(↓=-)gf(g𝕗)𝕗
   Chk g˜1-˜1gf⍋⊢
}
swap_undoCharCode∊mod1/"˜⁼"

vd1+vibN  # Start of identifier numbering (plus dot)
charRole4˜∾⥊¨˜(≠↑cgl˙)1,2,3,¯1,¯1,¯3,¯10,¯2,0,¬/56 # For first vd chars
T`×  ITT  I1T(1+↕)T
PN1(∾/∾˜)(∨/⊣)  # Partitioned-none: partitions where 𝕨<𝕩 is never 1

# Source to ⟨tokens, roles, number of identifiers, literals⟩
# Identifiers then literal tokens are numbered starting at vi
Tokenize{Systemvars𝕨
  # Resolve comments and strings
  c𝕩='#'s/00«sm𝕩='''⋄d←/dm←𝕩='"'
  g←⍋q←∾⟨  s⋄¯1↓d⋄/c⟩ ⋄q↩g⊏q                # Open indices
  e← g⊏∾⟨2+s⋄ 1↓d⋄-⟜»∘⊏⟜(0∾+`c)⊸//(𝕩∊lf)∾1⟩ # Matching close indices
  Se←{(⊏˜𝕨)Se 1¨⌾((𝕩/𝕨)⊸⊏)𝕩}⍟(0=¯1⊑⊢)       # Mark reachable openings
  St←(≠𝕩)↑·/⁼((≠↑∾⟜≠Se 1∾0¨)q⍋e)⊸/          # All indices → reached mask
  a←St q⋄b←St e⋄f←1≠`ab←a∨b                 # Open/close masks; filter
  {!⟨⊑/𝕩,"Unclosed quote"⟩}⍟(∨´)(sm∨dm)∧b<f

  # Extract character and string literals
  u←f∧𝕩='@'⋄ci←/u∨»a∧sm
  chr←(⊏⟜𝕩-('@'-@)×⊏⟜u)ci                   # Characters (indices ci)
  f>↩qe←dm∧«a∧↩dm                           # Quote Escape ""
  str←𝕩⊔˜1-˜(si←a>»qe)(⊣+`⊸×○(∾⟜1)<)≠`dm∧ab # Strings (indices /si)

  # Extract words: identifiers and numbers
  ie←/f⋄is←ie≠⊸↑/1»f                        # Token start and end
  is-↩is(-×⊏⟜c)ie                           # Comment → ending newline only
  t←CharCode ie⊏𝕩
  nd←(t=⊑bN)>«t M bD⋄rr←t=bR                # Namespace dot; 𝕣
  w←»⊸<l←rr∨nd<t M bN(⊣⋈-˜)○⊑bW             # Word chars l, start w
  us←t=¯1++´bA⋄sy←t=⊑bW                     # Underscore, system dot
  {!⟨/us∧w+`⊸⊏0∾𝕩,"Words can't only have underscores"⟩}⍟(∨´)w(/<1(⊢/«)(∨/⊣))l>us
  wk←(¬w/rr)×na⌊∘÷˜(⊑bA)-˜w/t               # Kind of word from first char
  t-↩na×l∧t≥na+⊑bA                          # Case-insensitive
  {!⟨𝕩/is,"System dot with no name"⟩}⍟(∨´)sy>«l
  w≠↩»⊸∨sy                                  # Start system word at dot
  wi←0<wt←(2×wk≥0)(×⟜¬+⊢)w/sy               # Type: 0 number, 1 system, 2 identifier
  i←l>n←l∧(+`w)⊏0∾¬wi                       # Identifier/Number masks
  num←is ReadNums○(((0∾us)<∨⟜«0∾n)/0⊸∾) t×l # Numbers
  ir←(us/˜«⊸<i)(⊢+∧⟜(2⊸=))wi/wk             # Identifier role
  if←(»⌈`)⊸<ig←(i>us)×+`w>n                 # Identifier groups and first character
  fr←(1=wi/wt)<if/rr                        # Identifier is 𝕣-based
  w↩if∨n∧w0←w⋄ws←1=0⊸<⊸/wt/˜↩¬w/rr          # Don't produce an identifier for 𝕣
  {!𝕩/is,"𝕣 can't be used with other word characters"}(´)(i>us)(rr≠∨if<)ig0fr
  {!is˜𝕩/𝕨,"Numbers can't start with underscores"}(´)(ws<(bA)>⊏t)/rr<if
  ig1-˜0∾+`׬fr
  idvars(ws2)igtcharSet            # ⟨Identifiers, system values⟩

  # Deduplicate literals and identifiers; other cleanup
  ki(wt⊏/w>rr)(ci∾/si)⊏+`»f             # Indices in t
  kidnumchrstrk(⊢>¯1»⌈`)/¨˜j¨k     # IDs j into uniques k
  kSystem(1)k                           # System value lookup
  wf¬lt M bWis/˜wfw0ie/˜wf∨>«l      # Index management for...
  t(wwf)/(vars↓∾j++`vd»kk¨k)(ki)t  # Add IDs; remove words/whitespace
  t-t(M×-)bS                             # Separators are equivalent
  p`1¨sb¯11↓/1(∾≠∾˜)t=sep               # Separator group boundaries (excludes leading and trailing)
  sksb/˜p>∨«(MbH(35+⊑bB)˜p+)(sb-p)t # Keep the first of each group that's not just inside a bracket
  t{is/˜𝕨ie/˜𝕨𝕨/𝕩}˜1¨(sk)tsep      # Remove the rest
  im(t=bR)t M vd⋈+´2kk                   # Identifier (or 𝕣) mask
  rir(im/)(vdt)charRole0              # Role
  t+(bX)((⊢M⋈5)×5+3+)t                # Case-insensitive special names
  t-vi(<+10×=)t                            # Shift . to bX and variables back one
  t,r,k,is,ie
}

# 𝕩 is a list of tokens that contains the numeric literals, each
# preceded by 0. Return the numbers.
ReadNums{
  _err_{(!/𝔾⋈𝔽)(´)}
  EChars"Letter"Pl," """,charSet,""" not allowed in numbers"_tmpl
  ednpi=𝕩¨((bA)+-´"ea")∾+´bN       # Masks for e.¯π∞
  EChars(/𝕩)_err_𝕨 (𝕩=bR)∨¬e𝕩<⊑bA
  sdcez0=𝕩m¬nc
  "Negative sign in the middle of a number"_err_𝕨 nc
  "Portion of a number is empty"_err_𝕨 (1«s)ns
  "Ill-formed decimal or exponent use"_err_(s/𝕎) ¬(0=∨»<)s/𝕩
  "π and ∞ must occur alone"_err_𝕨 (pi)>1(»∧(p∧«e)∨«)zne
  f(17≥¬(⊢-T)+`)g(«≤(d<𝕩≠⊑bD)>I1T¬)m # No leading 0s; max 17 digits
  l(¯1π1∾↕10)˜(¬d)/f×𝕩-1+⊑bN            # Digit lookup, with ∞ as 1 to avoid ∞×0
  v(>«0l)/0(0≤××10+)`l                # Numeric values—mantissas and exponents
  v×1¯1˜(r>»m)n                      # Negate if ¯
  vmc/z                                    # Mask of mantissas in l
  dpvm/f(--»-(<×⊢)(I1T«d)-)(/>«)g    # Decimal position
  t10⋆|eedp-˜vmv׬vm                    # Power of 10
  t÷˜((0>ee)/)t×((0<ee)/)vm/v×(r/i)1 # Correct ∞ then ×10⋆ee
}


Parse  {rvniedef𝕨nvvn
  ErrMismatchedBrackets{
    Lcs  (0<≠)0, ¯1  0¨ {𝕩⌈⌈`𝕨𝕩}˝ =
    _mis_  {"Missing "𝕗" "charSet˜𝕘+⊢/˜⊣=⊒}
    Msg  >"opening"_mis_ 0, "closing"_mis_ 1˜
    ! 𝕨 (Lcs<⌊)Msg,"Malformed bracket nesting" 𝕩
  }
  _err_{(!((ie˙)1˜/𝔾)⋈𝔽)(´=)}

  # Bracket and ligature validation and handling
  # Open brackets have role ¯1 and closed ones have role 0
  "Empty program" ! 0<≠𝕩
  gpd+`p(¯1-2×r)×𝕩 M bBgbgr=¯1       # Paren (actually any bracket type) depth and grade
  (gp)(>0/ErrMismatchedBrackets1-˜<0/)gxg𝕩
  "Swapped open and closed brackets" ! 0(g)pd
  "Parentheses can't contain separators"_err_(gb/G) ((bB)pred=∨sep=)gbxgb/gx
  "Predicates can't be placed inside lists"_err_((sep≠GBX)/gb/G) ((4+⊑bB)pred=)sep/gbx
  {"Empty statement or expression"_err_(𝕩/0∾G) (4+⊑bB)𝕩/0gx}1«1gb
  dl«dcr=4                              # Dot left
  r-(𝕩=⊑bG)>ec«dc<0r+p                   # Role ¯4 for exports: ⊑bG is ⇐
  "Invalid assignment or stranding use"_err_(↕≠) ((¯4<∧≤¯2)r)>(ec𝕩=2+⊑bG)∧»dc<0r
  "Can't use export statement as predicate"_err_(↕≠) (»¯4=r)𝕩=pred
  "Dot must be followed by a name"_err_(↕≠) dc𝕩 M vinv
  sr»(((⍋⊏dl)g))sl«r=¯2ns¬slsr # Strand right and left; not stranded
  cp𝕩=1+⊑bB                                # Closed paren
  nr(IT¬cp)(𝕩=2+⊑bI)+2×𝕩=⊑bO              # Nothingness role: 1 for 𝕨, 2 for ·
  nx0  nei↕≠nr  _nerr{𝕗 _err_ nei 2=nx𝕩}
  g˜gsdlsldl                          # Avoid reordering strands and dots in rev
  rp»(g)↕≠r                           # Position of previous, for roles
  # Permutation to reverse each expression: *more* complicated than it looks
  rev⍋+`¯1(¯1g)(⊣⍋⊏⊏˜⍋¬⊏˜)⍋+`+1gsdlr=¯1
  gffd+`brrevp×𝕩M2+⊑bB,2             # Order by brace depth fd to de-nest blocks
  rev˜gffd˜gfbr˜gf
  𝕩˜revdc˜revi˜reve˜rev

  # Compute parsing ordering gr≡g⊏rev
  g⍋+`pbr-˜revpg˜g⊏«dcgrgrev    # Order by non-brace bracket depth, then dots
  sll1+2÷˜0(<-/>)grsr-sll/g𝕩=5+⊑bB    # Strand length; list starts
  bbr>0c/br<0                            # Block Begin (mask) and Close (index), in matching order
  bp/b,c¨0(<≍(</g)>)gp               # Bracket pairs
  g˜gsgrslgrgrevgig              # Send strand prefixes *‿ to the end

  # Headers
  hh𝕩=⊑bHcs𝕩=1+⊑bHqm𝕩=pred             # Case header : and separator ; and predicate ?
  "Punctuation : ; ? not allowed outside blocks"_err_(↕≠) (`b)<hhcsqm
  fi+`cbbcsHcb¬PN⊢                    # Body index fi; which bodies Have a property
  cq(H qm)chH hh                         # ch: body has : header ; cq: or ? predicate
  cf1∾¬cocb/cscm0∾∨«co                 # cf: body is first; cm: body is one of multiple
  "Header-less bodies must come last"_err_(/CB) 1(-↓<co∧↓)cq
  "At most two header-less bodies allowed"_err_(/CB) »co>¯1cq
  cc(⍋⍋«co)c∾/cs                          # Case close
  hi/hfhh˜IT((g))cbhh              # Header component indices
  un0=usswap_undo(⊣-⊐)hi𝕩
  "Invalid Undo header syntax"_err_(HI) un<(»≥∨(1»un)2=)us
  utunushi/˜0=us                       # Undo type: 0 normal, 1 ⁼, 2 ˜⁼
  hr(ns×⊏r)rev˜hi                      # Header component roles
  hl2=hn(1»+«)hc¯1=hr                   # hl: is label, hc: is :
  "Only one header per body allowed"_err_(hc/HI) (1+hc/hi)hf
  ho(»∨·«(hr=3)∧⊢)hl<hy2hr               # Header operands
  "Missing operand in header"_err_(HI) (uthr=3)hohchy
  hm¬hohaho<(0=hr)1=hn                  # Mask for main name; header arguments
  "Invalid header structure"_err_(hm/HI) 1»=hm/hc
  hk3|1-˜(+`bInv)hthi𝕩׬revsr         # Kind: 0 special, 1 name, 2 compound
  hmahm>hlahl(0=hr)1hkhr+hlahl>hla # Lone non-name subject is 𝕩 with 𝕊 omitted
  hv(hla+ha×1hc)+(ho×43=hr)+hma×3×1-˜2hr # Special name for position
  "Incorrect special name"_err_(HI) (0=hk)hthv+⊑bI
  hk׬hchl0=hr                           # Treat subject labels like special names
  hm>hchr/˜hmhx(1»hc)/ha               # Header-derived role hr and immediacy ¬hx
  ut--»ut×ho                              # Shift ⁼ from right operand to main name
  "Invalid Undo header syntax"_err_(HI) hmut
  "Header left argument without right"_err_(HI) ha>hc+`hx0
  "Header operation must be a plain name"_err_(HI) hma>hk2
  ut/˜hmhx1=hr
  "Header with ⁼ must take arguments"_err_(hm/HI) hxut
  cwhhchlha×1+he0hk                   # Body 𝕨 for just headers
  "Header with ˜⁼ must have left argument"_err_(HI) (0=cwh)ut22=ut
  cw(cwh2×ut2)(ch/)1+-«(»cq)<1(⊢<«)cf  # Body 𝕨: 0 no, 1 allowed, 2 required
  hl/˜hmhu(¬he)(hi)hf                 # hu: mask of header special names
  hjgi˜he/hihd2=he/hk                   # hj: header assignments; hd: which ones destructure

  # Block properties
  ss0356(⊢+(0<hk)×hv-)(hi)𝕩-⊑bI    # Special name
  ss+(revr=3)𝕩=3+⊑bI                     # Treat _𝕣_ as 3, like 𝕘
  HS(¯1+`cf)b¬PN=sssp/hu<𝕩 M bI       # Has-special (𝕤𝕩𝕨/𝕣𝕗/𝕘); indices of specials
  fxHS 1fr(fx0<)+ft2(⊣⌈2×⊢)HS 3     # Body immediacy ¬fx, type ft, role fr
  "Block header type conflict"_err_(ch/0∾/CB) (hr<ch/fr)hl<hx<ch/fx
  ft1-˜frhr(ch/)frfxhx(ch/)fx
  "Special name outside of any block"_err_(/{(0=fi)𝕩 M bI}𝕩) 0<⊑fr
  "Unreachable body"_err_(/CB) 1(»(¬hl)(ch/)cq)<cm>fx
  fsc(ft023)+3×fx                       # Special name count
  hv-(»+`hc)3׬ch/fx                      # Header variable slot

  # Propagate roles through parentheses
  # ir is the role of the expression ending at each position (truncated to the right)
  rsl-˜ns×(1cf/fr)((crev))r           # Add block roles; make strand elements ¯1
  ptcpns                                  # Pass-through parentheses: not in strands
  pppt∧»esrp1˜r<0                       # Parens enclosing one object (maybe with assignment) don't change roles
  ir((rp0˜(1+es)×3=⊢)⌈⊢-es<2≤⊢)r+pp×(IT¬pp)r # Propagate modifier roles
  ir(IT¬ptir=0)((⊏-⊢)(+`¬pp)(⊢⌊1⌈+))ir # ...and function roles
  r+pt×»ir                                 # Roles at pt were 0; set them now
  nr׬nx(0ir)1=nr                      # Assume 𝕎 can't be Nothing
  ir(ir×0=nr)-nr                           # Include nothingness
  r-(r=¯4)1»r=¯1                          # Lone ⇐ to role ¯5
  "Dot must be preceded by a subject"_err_(rev) (r=4)r=0
  r(׬-⊢)dl                               # Namespace and dot to ¯1

  # Prep for lexical resolution before reordering 𝕩
  xv𝕩-vi
  {i(𝕨i)(𝕩)ie(𝕩e)(𝕨)e}´bp        # Highlight all contents of a pair when error reporting
  𝕩˜ghgghfr˜grir˜grl(l⊏⍋gs)∾/grsr>sl

  # Parsing part 1
  a(¯5<∧≤¯3)rpsa<r<0                   # a: assignment, ps: part separator
  tr1erir˜IT»ps                         # er: expression role; tr: train or modifier expression
  no0⌈-irne0⌈-erneignx˜gr           # Nothing value; expression
  "Nothing (·) cannot be assigned"_nerr ne×a
  "Can't use Nothing (·) as predicate"_nerr ne×𝕩=pred
  oa⌽/hg<op(er<2)r2roop∨«opm2r=3    # op: active modifiers; ro: mod or right operand
  "Missing operand"_nerr op×2(«⌈m2×»)no2×m2ror∊↕2
  s𝕩=sepfo𝕩2+⊑bB,1+⊑bH                # Separators, function open { or ;
  lssfo<IT lo𝕩=4+⊑bB                    # List Separators: after ⟨lo, not {fo
  "Double subjects (missing ‿?)"_err_(G) «ro»<r=0
  mm𝕩=2+⊑bGmatr<mm∧«ir1mm1»ps        # Modified assignment; monadic modified
  "No right-hand side in non-modified assignment"_err_(G) ma<mm
  os(⊣-T)⌽¬roma                      # Operator skip: distance rightward to derived function start
  at1+⊏os+ai/aaf¯4airaratr       # Assignment target; af for actual (non-export) assignment
  "Role of the two sides in assignment must match"_err_(at⊏G) afar0ater
  akaf+(0ar)+(aima)+(bG)-˜ai𝕩          # Class of assignment: 1⇐ 2⇐? 3←? 4↩? 5+↩?
  athjac«-(ak6¨hj)(at)0¨𝕩          # Header assignment is 6 temporarily
  aa×gacgac»+`(1»0=+`)×giac        # Broadcast ac to the entire target
  api/(𝕩=⊑bO)apaa2=no                   # Assignment placeholder
  "Can't use Nothing (·) in lists"_nerr (¬ap)×no×(gr⊏¬ns)∨»lols
  ac-3×ah6=ac                             # Assignment is header; 6→3
  nxaa×1=no                               # Prevent assignment to 𝕨 if it's ·
  nfH ac<xv=vi-˜bG                        # Namespace bodies
  fwH ginx                                # Bodies where 𝕨 must be defined
  {"Can't return Nothing (·)"_err_(𝕩⊏⍋Rev) 2=fwnf¬×𝕩nr} 1-˜0ccrev
  fvfwfwI1Tcf                          # If a body fails on 𝕨, later ones won't see 𝕨
  (´(1fv)<)"Invalid use of 𝕨 in monadic case""Unreachable body"_err_(/CB) 1fwcw=0
  cw2×fwcw×fx
  nngfi2=cwno(⊣-=)nnne(⊣-=)nn        # 2=cw indicates 𝕨 is never Nothing
  aid(¯6≤∧<nv)𝕩-vi                       # Assignable identifer
  hq/hp(gah)𝕩nv+vi                     # Header constant
  atc(hg<psaar0)<aidhp(ps𝕩=⊑bL)𝕩(=(3+⊑)<M)bB
  "Assignment target must be a name or list of targets"_err_(G) (aatcap)<aa
  "Can't nest assignments (write aliases with ⇐)"_err_(ai⊏G) ((5aigac)ak=2)<aiaa
  "Can't use result of function/modifier assignment without parentheses"_err_(G) hg<(0<er)(0r)∧»>aa
  af>almaiaaalalm/ai                   # aliases al
  ai/˜afat/˜af1¨hj

  # Lexical resolution (independent of parsing part 2 below)
  di/dm»dc                                # Dots aren't scoped
  id/(hudmgi⊏«aaa)<(0≤∧<nv)xv         # Identifier indices in xv
  sa0<scspacd(icidac)M 22           # Which accesses are definitions
  "Can't define special name"_err_(SP) sasc<4
  idfidfiidvidxv                       # Function index and name ID
  dpd(0=idf)idv<≠def                     # Definitions of vars in def
  "Redefinition"_err_(dp/ID) 0=dpf(dp/idv)def
  d(0dpf)(dp/)dzda0¨da/def0         # Turn def ¯1 ← into ↩
  dn(dgzda(dfd/idf)∾≠fsc)dadvd/idv   # Identifier name ID, per-block
  # Order every referenced identifier, and an undeclaration for each declaration
  ixf((1=ic)+idf¯1cb/gf)df(𝕩)1-˜ccgf# First order by block index, open for real and closed for virtual
  ig(⍋⊏(ixxidvdv))⊏⍋ixf                # Then order by name
  {"Redefinition"_err_(𝕩·(d/)ID) ¬ixx(»𝕩)ixf} (d)/ig
  ig<(d)/(ds+`igd¯1¨dv)ig          # Last order by declaration depth
  d˜igid˜igic˜ig
  du+´¬»0<dsuv(duig)idv              # Number undefined (always sorted to front)
  ("Undefined identifier"Pl·⍷/uv)_err_(du↑ID) uv≥≠def
  ix(ic<3)ia0<ic                         # Which are exports, assignments
  idd(⊢-(uvded-0def)(du↓IT d))idfd  # Identifier frame depth
  "Can't export from surrounding scope"_err_(ID) ix0<idd
  dxdgzda(digd/ig)ixad(/≥1↓PN)ix     # Exported identifier mask
  idi(uv⊏∾(¯1+`dud)digda↓⊢)(fsc+⊒)deddf # Slot within frame
  uu(ia<1«d)d(⊣+`(1ixa)<PN)0<idd       # Unused marker
  spi((spfspfi)3×fx)+3+spxv            # Special name index
  uuspi+6×spf                          # and unused marker
  idor323/1+g˜hj-1, di, idsp        # Identifier bytecode ordering
  ido32+uu(⊢+2×>)iasa                     # Opcode
  idoc32¨hj,0¨hj,he/hv
        64¨di,dixv, ido,idd0¨sp,idispi  # Identifier bytecode: instruction, depth, slot

  # Parsing part 2
  tatr2(>∨|)ps(⊢-T)+`¬ro                  # Train argument (first-level)
  fa/(fehgtaro∨«ps<aa)<ff(r=1)∨»op   # Active functions: cases fe are excluded
  "Second-level parts of a train must be functions"_err_(G) tr>feff
  dy2nyfa2«no2׬(trr0)ro<r=0        # Dyadic
  obpr⊏/¯1(⊢-»)u⍷∧pr𝕩˜pi/hg<𝕩<sep      # Objects to be loaded
  cnpilt/𝕩clvi+nvob(cl-˜u)+lt𝕩    # Constants
  bkcgi                                   # Block loads
  llsll˜(¬lo/1«ps)+-»1(lo1)/+`ls0     # List Length
  dr(hd¬/hj)∾/s>(2=ne)ls∨»r=¯5rt/fo    # Drop (block separator) and return
  qp/𝕩=pred                                # Predicate
  fl(dy×⊏os)+fa+dy                       # Function application site
  dr((1+dy)×fn2=fmfane)/fl             # Turn function applications on · to drops
  fn¬fnfa/˜fnfl/˜fn                    # And remove them

  # Object code generation: numbers oc ordered by source location (after rev) oi
  ao48+(0(1+⊑bG)-˜ai𝕩+ma+mm)∾-hd         # Assignment opcode
  oroiidorg˜oilcn,cn,bk,bk,hq,api,2/l,at,dr,qp,al+1,al+1,oa+1oaos,fl,rt
  ocor⊏∾idoc0¨cn,ob,1¨bk,1+↕≠bk,43¨hq,44¨api,⥊⍉(11+laa)ll,ao,6¨dr,42¨qp,66¨al,vi-˜(al-1)𝕩
               24+oar,16+(fn/dy+2×fm1=ny)+4×0<faer,¯1rc7+nf
  # Instruction source positions
  ui81314((»+`)+¨)(idor)∾≠¨oil  # at,oa+…,fl locations
  oj(g˜at-10/˜¨aihj,oa,fa)((ui))oi
  indoj,(g˜fa⊏IT»¬roma)((¯1ui))oj(¯1˜or)¨ie
  # Indices for multi-body blocks
  cm(fx1cw)0<utut(ch/)ch            # Dyad- and inverse-only generate as multiple
  cj/cv1+1=ciwcw˜ci/cm                 # Number of copies
  ck4(2×ciut)+1<ciw                      # Position
  cg¯1+`cifcicf                          # Which block
  ckt(2(cfcm)/fx)(cif/·⍋⊏cg)cv+ck
  cickt/(¯1(↑∾˜cj(⊣+⊏)ck+cg⊏↓)0∾+`ckt)cjci
  # Output
  fzcf/ft,cffx,ci((cf/cm)/)/cf       # Per-function data
  cz/1oroc-rt,fsc+≠¨dn,dn,dx         # Per-body data
  oc¯1rc,u,fz,cz,ind                    # Overall output
}

Compile{
  defaults⟨⟩‿(!"System values not supported"¨)‿⟨⟩‿(0)
  primsSysvarsredef  (≠↓defaults˙) (4<≠)𝕨
  tok,role,val,t0,t1txsysvars Tokenize 𝕩
  oc,prim,blk,bdy,oirole,val,t0,t1,redef»0¨vars Parse tok
  oc, primprims1val, <˘⍉>blk, <˘⍉>bdy, oi, tx
}