aboutsummaryrefslogtreecommitdiff
path: root/vm.bqn
blob: a481a695d4e12aed2f08ff064cd6ca62d3264ca5 (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
MakeVar โ† { program ๐•Š name:
  vโ†@
  Get  โ‡ !โˆ˜"Runtime: Variable referenced before definition"
  SetU โ‡ !โˆ˜"โ†ฉ: Variable modified before definition"
  SetN โ‡ {
    Get โ†ฉ {๐•คโ‹„v}
    (SetU โ†ฉ {vโ†ฉ๐•ฉ}) ๐•ฉ
  }
  SetQ โ‡ 0โˆ˜SetN
  GetC โ‡ {
    r โ† Get๐•ฉ
    Getโ†ฉSetUโ†ฉSetNโ†ฉ!โˆ˜"Internal error: Variable used after clear"
    r
  }
  GetF โ‡ {program ๐•ฉ.Field name}
}
vnot โ† { SetUโ‡SetNโ‡โŠข โ‹„ SetQโ‡0ห™ }
MakeEnv โ† { ๐•Špโ€ฟvโ€ฟnโ€ฟe:
  ns โ† v-โ‰ n  # Number of special names
  parent โ‡ p
  program โ‡ p.program
  vars โ‡ programโŠธMakeVarยจ (nsโฅŠยฏ1) โˆพ n
  MakeNS โ‡ {๐•ค
    v โ† @ โŠฃยดยจ n โŠ” nsโ†“vars  # Lookup table
    Field โ‡ {๐•จ๐•Ši:
      cross โ† ๐•จ { ๐•จ1โŠ˜โ‰ก๐•ฉ ? โŠข ; โŠ‘ ๐•ฉ.names โА โŠโŸœ๐•จ.names } program
      (Cross i) โŠ‘ v
    }
  }
}

VO โ† { dโ†๐•@, sโ†๐•@, sโŠ‘ยท{๐•ฉ.vars}{๐•ฉ.parent}โŸd }

nothing  โ† {โ‡}
skipMark โ† {โ‡}

Namespace โ† {๐•ฉ.MakeNS@}
ReadNS โ† { eโ€ฟi ๐•Š ๐•ฉ:
  "Key lookup in non-namespace" ! 6=โ€ขType๐•ฉ
  (e.program ๐•ฉ.Field i).Get @
}

ref โ† {
  Matcher โ‡ {๐•Š const:
    SetQ โ‡ constห™ โ‰ข โŠข
  }
  Array โ‡ {๐•Š arr:
    Get  โ‡ {๐•ฉ.Get@}ยจ arrห™
    _set_ โ† {S _๐•ฃ_ e:
      Err โ† {(eโˆพ": "โˆพ๐•ฉ)!eโ‰ก@ โ‹„ โŸจ1โŸฉ}
      {
        0=โ€ขType๐•ฉ ? arr โ‰กโ—‹โ‰ขโ—ถโŸจErrโˆ˜"Target and value shapes don't match", SยจโŸฉ ๐•ฉ ;
        # TODO "Cannot extract non-name from namespace" if ๐•จ.GetF doesn't exist
        6=โ€ขType๐•ฉ ? SโŸœ({(๐•จ.GetF ๐•ฉ).Get@}โŸœ๐•ฉ)ยจ arr ;
        Err "Multiple targets but atomic value"
      }
    }
    SetN โ‡    {๐•จ.SetN๐•ฉ}_set_"โ†"
    SetU โ‡    {๐•จ.SetU๐•ฉ}_set_"โ†"
    SetQ โ‡ โˆจยด {๐•จ.SetQ๐•ฉ}_set_@โŽŠโŸจ1โŸฉ # TODO fix GetF errors and avoid โŽŠ
  }
  Alias โ‡ {envโ€ฟname ๐•Š r:
    SetNโ€ฟSetUโ€ฟSetQ โ‡ r
    GetF โ‡ {env.program ๐•ฉ.Field name}
  }
}

Get โ† {๐•ฉ.Get @}โš‡0

MakeStack โ† {
  s โ† ๐•ฉ                          # Stack (a list)
  cont โ‡ 1                       # Whether to continue execution
  rslt โ‡ skipMark                # Result: skipMark to abort current body
  Push โ‡ {sโˆพโ†ฉ<๐•ฉ}                 # Push a value
  Pop  โ‡ {tโ†-๐•ฉ โ‹„ (sโ†“หœโ†ฉt) โŠข โŒฝtโ†‘s} # Pop ๐•ฉ values; return as list
  Peek โ‡ {๐•คโ‹„ยฏ1โŠ‘s}                # Return but don't pop top value
  Ret  โ‡ {rsltโ†ฉ๐•ฉ โ‹„ contโ†ฉ0 โ‹„ "Internal compiler error: Wrong stack size"!๐•จโ‰ฅโ‰ s}
  Skip โ‡ {๐•คโ‹„       contโ†ฉ0}
}

ops โ† ((!โˆ˜"Unknown opcode")ห™โŠฃยดโŠข)ยจ โŠ”ห โ‰> โŸจ
  # Constants and drop
   0โ€ฟ{iโ†๐•@ โ‹„ {s๐•Še: s.Push         iโŠ‘e.program.consts } }
   1โ€ฟ{iโ†๐•@ โ‹„ {s๐•Še: s.Push e {๐•Ž๐•ฉ}หœ iโŠ‘e.program.blocks } }
   6โ€ฟ(       {s๐•Še: s.Pop 1 }ห™)
  # Returns
   7โ€ฟ(       {s๐•Še: 0 s.Ret โŠ‘s.Pop 1 }ห™)
   8โ€ฟ(       {s๐•Še: 1 s.Ret Namespace e }ห™)
  # Arrays
  11โ€ฟ{iโ†๐•@ โ‹„ {s๐•Še: s.Push           โŒฝs.Pop i } }
  12โ€ฟ{iโ†๐•@ โ‹„ {s๐•Še: s.Push ref.Array โŒฝs.Pop i } }
  # Application
  16โ€ฟ(       {s๐•Še: s.Push {   fโ€ฟx:   F x }   s.Pop 2 }ห™)
  17โ€ฟ(       {s๐•Še: s.Push { wโ€ฟfโ€ฟx: w F x }   s.Pop 3 }ห™)
  20โ€ฟ(       {s๐•Še: s.Push {   gโ€ฟh:   G H }   s.Pop 2 }ห™)
  21โ€ฟ(       {s๐•Še: s.Push { fโ€ฟgโ€ฟh: F G H }   s.Pop 3 }ห™)
  26โ€ฟ(       {s๐•Še: s.Push { fโ€ฟm  : F _m    } s.Pop 2 }ห™)
  27โ€ฟ(       {s๐•Še: s.Push { fโ€ฟmโ€ฟg: F _m_ g } s.Pop 3 }ห™)
  # Application with Nothing
  18โ€ฟ(       {s๐•Še: s.Push {   fโ€ฟx:                     FโŸ(nothingโŠธโ‰ข) x } s.Pop 2 }ห™) # Like 16
  19โ€ฟ(       {s๐•Še: s.Push { wโ€ฟfโ€ฟx: (nothingโ‰ขwห™)โ—ถโŸจF,wห™โŠธFโŸฉโŸ(nothingโŠธโ‰ข) x } s.Pop 3 }ห™) # Like 17
  23โ€ฟ(       {s๐•Še: s.Push { fโ€ฟgโ€ฟh: {fโ‰กnothing?G H;F G H}               } s.Pop 3 }ห™) # Like 21
  22โ€ฟ(       {s๐•Še: "Left argument required" ! nothingโ‰ขs.Peek@ }ห™)
  # Variables
  32โ€ฟ{vโ†VO๐•ฉโ‹„ {s๐•Še: s.Push (V e).Get @ } }
  34โ€ฟ{vโ†VO๐•ฉโ‹„ {s๐•Še: s.Push (V e).GetC@ } }
  33โ€ฟ{vโ†VO๐•ฉโ‹„ {s๐•Še: s.Push  V e        } }
  # Headers
  42โ€ฟ(       {s๐•Še: {0:s.Skip@; 1:@; ๐•Š:!"Predicate value must be 0 or 1"} โŠ‘s.Pop 1 }ห™)
  43โ€ฟ(       {s๐•Še: s.Push ref.Matcher โŠ‘s.Pop 1 }ห™)
  44โ€ฟ(       {s๐•Še: s.Push vnot }ห™)
  # Assignment
  47โ€ฟ(       {s๐•Še: s.SkipโŸโŠข{rโ€ฟ  v: r.SetQ   v           } s.Pop 2 }ห™)  # r:
  48โ€ฟ(       {s๐•Še: s.Push { rโ€ฟ  v: r.SetNโŠธโŠข v           } s.Pop 2 }ห™)  # r  โ†v
  49โ€ฟ(       {s๐•Še: s.Push { rโ€ฟ  v: r.SetUโŠธโŠข v           } s.Pop 2 }ห™)  # r  โ†ฉv
  50โ€ฟ(       {s๐•Še: s.Push { rโ€ฟfโ€ฟx: r.SetUโŠธโŠข (r.Get@)F x } s.Pop 3 }ห™)  # r Fโ†ฉx
  51โ€ฟ(       {s๐•Še: s.Push { rโ€ฟf  : r.SetUโŠธโŠข F r.Get@    } s.Pop 2 }ห™)  # r Fโ†ฉ
  # Namespaces
  64โ€ฟ{iโ†๐•@ โ‹„ {s๐•Še: s.Push eโ€ฟi ReadNS    โŠ‘s.Pop 1 } }
  66โ€ฟ{iโ†๐•@ โ‹„ {s๐•Še: s.Push eโ€ฟi ref.Alias โŠ‘s.Pop 1 } }
โŸฉ

RunBC โ† { bcโ€ฟposโ€ฟenv:
  Next โ† {๐•คโ‹„ (pos+โ†ฉ1) โŠข posโŠ‘bc }
  stack โ† MakeStack โŸจโŸฉ
  Step โ† {๐•Š:
    op โ† (Next@) โŠ‘ ops
    op โ†ฉ Op next
    stack Op env
    stack.cont
  }
  _while_ โ† {๐”ฝโŸ๐”พโˆ˜๐”ฝ_๐•ฃ_๐”พโˆ˜๐”ฝโŸ๐”พ๐•ฉ}
  Step _while_ โŠข 1
  stack.rslt
}

{ VM bcโ€ฟconstsโ€ฟblockInfoโ€ฟbodyInfoโ€ฟlocโ€ฟtoken:

  bodies โ† {startโ€ฟvarsโ€ฟnamesโ€ฟexport:
    {parent ๐•Š args:
      env โ† MakeEnv parentโ€ฟvarsโ€ฟnamesโ€ฟexport
      (โŠข {๐•ฉ.SetN ๐•จ}ยจ โ‰ โ†‘env.varsห™) args
      RunBC bcโ€ฟstartโ€ฟenv
    }
  }ยจ bodyInfo

  blocks โ† {typeโ€ฟimmโ€ฟbody:
    inner โ† imm โŠ‘ type โŠ‘ โŸจ
      2โฅŠโŸจ{๐•Šn: N โŸจโŸฉ}โŸฉ
      {๐•Šn: {dโ†N ๐•ฃโ€ฟ๐•—  โ‹„๐•จD๐•ฉ}}โ€ฟ{๐•Šn: {N ๐•ฃโ€ฟ๐•—  }}
      {๐•Šn: {dโ†N ๐•ฃโ€ฟ๐•—โ€ฟ๐•˜โ‹„๐•จD๐•ฉ}}โ€ฟ{๐•Šn: {N ๐•ฃโ€ฟ๐•—โ€ฟ๐•˜}}
    โŸฉ
    outer โ† imm โŠ‘ โŸจ
      {
        mโ€ฟd: {๐•Šv: {M ๐•คโ€ฟ๐•ฉโ€ฟnothingโˆพv;D ๐•คโ€ฟ๐•ฉโ€ฟ๐•จโˆพv}} ;
        โŸจbโŸฉ: {๐•Šv: {B ๐•คโ€ฟ๐•ฉโ€ฟ(๐•จโŠฃnothing)โˆพv}}
      }
      โŠ‘
    โŸฉ

    nmc โ† "No matching case"
    Then โ† {first ๐•Š next: {skipMarkโ‰ขrโ†๐•จFirst๐•ฉ ? r ; ๐•จNext๐•ฉ}}
    run โ† {
      1=โ€ขType ๐•ฉ ?
      โŸจ(๐•ฉโŠ‘bodies) Then {!โˆ˜nmc}โŸฉ
    ;
      "Internal compiler error: Invalid body indices" ! 1==๐•ฉ
      ! (โ‰ ๐•ฉ) โ‰ก 2-imm
      e โ† {imm ? โŸจnmcโŸฉ ;
        (0=โ‰ ยจ๐•ฉ) nmcโŸโŠฃยจ "Left argument "โŠธโˆพยจโŸจ"not allowed","required"โŸฉ
      }๐•ฉ
      ๐•ฉ ThenยดโŸœ(โŠโŸœbodies)หœโŸœ{!โˆ˜๐•ฉ}ยจ e
    } body

    {๐•Š parent:
      Inner Outer {parentห™ ๐• โŠข}ยจ run
    }
  }ยจ blockInfo

  program โ† {
    constsโ‡consts
    blocksโ‡blocks
    namesโ‡0โŠ‘2โŠ‘token
  }
  
  (โŠ‘blocks){๐”ฝ} {programโ‡program}
}