@@ -8,108 +8,213 @@ extension Program where Input.Element: Hashable {
8
8
9
9
// Map tokens to actual addresses
10
10
var addressTokens : [ InstructionAddress ? ] = [ ]
11
- var addressFixups : [ ( InstructionAddress , AddressToken ) ] = [ ]
11
+ var addressFixups : [ ( InstructionAddress , AddressFixup ) ] = [ ]
12
12
13
13
// Registers
14
14
var nextBoolRegister = BoolRegister ( 0 )
15
+ var nextIntRegister = IntRegister ( 0 )
16
+
17
+ // Special addresses or instructions
18
+ var failAddressToken : AddressToken ? = nil
15
19
16
20
public init ( ) { }
17
21
}
18
22
}
19
23
20
24
extension Program . Builder {
25
+ struct AddressFixup {
26
+ var first : AddressToken
27
+ var second : AddressToken ? = nil
28
+
29
+ init ( _ a: AddressToken ) { self . first = a }
30
+ init ( _ a: AddressToken , _ b: AddressToken ) {
31
+ self . first = a
32
+ self . second = b
33
+ }
34
+ }
35
+ }
36
+
37
+ extension Program . Builder {
38
+ // TODO: We want a better strategy for fixups, leaving
39
+ // the operand in a differenet form isn't great...
40
+
21
41
public init < S: Sequence > ( staticElements: S ) where S. Element == Input . Element {
22
42
staticElements. forEach { elements. store ( $0) }
23
43
}
24
44
25
45
public mutating func buildNop( _ r: StringRegister ? = nil ) {
26
- instructions. append ( . nop( r ) )
46
+ instructions. append ( . init ( . nop, . init ( optionalString : r ) ) )
27
47
}
28
48
public mutating func buildNop( _ s: String ) {
29
49
buildNop ( strings. store ( s) )
30
50
}
31
51
52
+ public mutating func buildDecrement(
53
+ _ i: IntRegister , nowZero: BoolRegister
54
+ ) {
55
+ instructions. append ( . init(
56
+ . decrement, . init( bool: nowZero, int: i) ) )
57
+ }
58
+
59
+ public mutating func buildMoveImmediate(
60
+ _ value: UInt64 , into: IntRegister
61
+ ) {
62
+ instructions. append ( . init(
63
+ . moveImmediate, . init( immediate: value, int: into) ) )
64
+ }
65
+
66
+ // TODO: generic
67
+ public mutating func buildMoveImmediate(
68
+ _ value: Int , into: IntRegister
69
+ ) {
70
+ let uint = UInt64 ( truncatingIfNeeded: value)
71
+ assert ( uint == value)
72
+ buildMoveImmediate ( uint, into: into)
73
+ }
74
+
32
75
public mutating func buildBranch( to t: AddressToken ) {
33
- instructions. append ( . branch ( ) )
76
+ instructions. append ( . init ( . branch ) )
34
77
fixup ( to: t)
35
78
}
36
79
public mutating func buildCondBranch(
37
80
_ condition: BoolRegister , to t: AddressToken
38
81
) {
39
- instructions. append ( . condBranch( condition: condition) )
82
+ instructions. append (
83
+ . init( . condBranch, . init( bool: condition) ) )
84
+ fixup ( to: t)
85
+ }
86
+
87
+ public mutating func buildCondBranch(
88
+ to t: AddressToken , ifZeroElseDecrement i: IntRegister
89
+ ) {
90
+ instructions. append (
91
+ . init( . condBranchZeroElseDecrement, . init( int: i) ) )
40
92
fixup ( to: t)
41
93
}
42
94
43
95
public mutating func buildSave( _ t: AddressToken ) {
44
- instructions. append ( . save ( ) )
96
+ instructions. append ( . init ( . save ) )
45
97
fixup ( to: t)
46
98
}
47
99
public mutating func buildSaveAddress( _ t: AddressToken ) {
48
- instructions. append ( . saveAddress ( ) )
100
+ instructions. append ( . init ( . saveAddress ) )
49
101
fixup ( to: t)
50
102
}
103
+ public mutating func buildSplit(
104
+ to: AddressToken , saving: AddressToken
105
+ ) {
106
+ instructions. append ( . init( . splitSaving) )
107
+ fixup ( to: ( to, saving) )
108
+ }
51
109
52
110
public mutating func buildClear( ) {
53
- instructions. append ( . clear ( ) )
111
+ instructions. append ( . init ( . clear ) )
54
112
}
55
113
public mutating func buildRestore( ) {
56
- instructions. append ( . restore ( ) )
114
+ instructions. append ( . init ( . restore ) )
57
115
}
58
116
public mutating func buildFail( ) {
59
- instructions. append ( . fail ( ) )
117
+ instructions. append ( . init ( . fail ) )
60
118
}
61
119
public mutating func buildCall( _ t: AddressToken ) {
62
- instructions. append ( . call ( ) )
120
+ instructions. append ( . init ( . call ) )
63
121
fixup ( to: t)
64
122
}
65
123
public mutating func buildRet( ) {
66
- instructions. append ( . ret ( ) )
124
+ instructions. append ( . init ( . ret ) )
67
125
}
68
126
69
127
public mutating func buildAbort( _ s: StringRegister ? = nil ) {
70
- instructions. append ( . abort( s) )
128
+ instructions. append ( . init(
129
+ . abort, . init( optionalString: s) ) )
71
130
}
72
131
public mutating func buildAbort( _ s: String ) {
73
132
buildAbort ( strings. store ( s) )
74
133
}
75
134
76
- public mutating func buildConsume ( _ n: Distance ) {
77
- instructions. append ( . consume ( n ) )
135
+ public mutating func buildAdvance ( _ n: Distance ) {
136
+ instructions. append ( . init ( . advance , . init ( distance : n ) ) )
78
137
}
79
138
80
139
public mutating func buildMatch( _ e: Input . Element ) {
81
- instructions. append ( . match( elements. store ( e) ) )
140
+ instructions. append ( . init(
141
+ . match, . init( element: elements. store ( e) ) ) )
82
142
}
83
143
84
- public mutating func buildConsume( by p: @escaping Program . ConsumeFunction ) {
85
- instructions. append ( . consume( by: makeConsumeFunction ( p) ) )
144
+ public mutating func buildConsume(
145
+ by p: @escaping Program . ConsumeFunction
146
+ ) {
147
+ instructions. append ( . init(
148
+ . consumeBy, . init( consumer: makeConsumeFunction ( p) ) ) )
86
149
}
87
150
88
- public mutating func buildAssert( _ e: Input . Element , into c: BoolRegister ) {
89
- instructions. append ( . assertion( condition: c, elements. store ( e) ) )
151
+ public mutating func buildAssert(
152
+ _ e: Input . Element , into cond: BoolRegister
153
+ ) {
154
+ instructions. append ( . init( . assertion, . init(
155
+ element: elements. store ( e) , bool: cond) ) )
90
156
}
91
157
92
158
public mutating func buildAccept( ) {
93
- instructions. append ( . accept ( ) )
159
+ instructions. append ( . init ( . accept ) )
94
160
}
95
161
96
162
public mutating func buildPrint( _ s: StringRegister ) {
97
- instructions. append ( . print( s ) )
163
+ instructions. append ( . init ( . print, . init ( string : s ) ) )
98
164
}
99
165
100
- public func assemble( ) -> Program {
166
+ // TODO: Mutating because of fail address fixup, drop when
167
+ // that's removed
168
+ public mutating func assemble( ) -> Program {
169
+ // TODO: This will add a fail instruction at the end every
170
+ // time it's assembled. Better to do to the local instruction
171
+ // list copy, but that complicates logic. It's possible we
172
+ // end up going a different route all-together eventually,
173
+ // though.
174
+ if let tok = failAddressToken {
175
+ label ( tok)
176
+ buildFail ( )
177
+ }
178
+
101
179
// Do a pass to map address tokens to addresses
102
180
var instructions = instructions
103
181
for (instAddr, tok) in addressFixups {
104
- instructions [ instAddr. rawValue] . operand. initializePayload (
105
- addressTokens [ tok. rawValue] !
106
- )
182
+ // FIXME: based on opcode, decide if we split...
183
+ // Unfortunate...
184
+ let inst = instructions [ instAddr. rawValue]
185
+ let addr = addressTokens [ tok. first. rawValue] !
186
+ let payload : Instruction . Payload
187
+
188
+ switch inst. opcode {
189
+ case . condBranch:
190
+ payload = . init( addr: addr, bool: inst. payload. bool)
191
+
192
+ case . condBranchZeroElseDecrement:
193
+ payload = . init( addr: addr, int: inst. payload. int)
194
+
195
+ case . branch, . save, . saveAddress, . call:
196
+ payload = . init( addr: addr)
197
+
198
+ case . splitSaving:
199
+ guard let fix2 = tok. second else {
200
+ fatalError ( " unreachable " )
201
+ }
202
+ let saving = addressTokens [ fix2. rawValue] !
203
+ payload = . init( addr: addr, addr2: saving)
204
+
205
+ default : fatalError ( " unreachable " )
206
+
207
+ }
208
+
209
+ instructions [ instAddr. rawValue] = . init(
210
+ inst. opcode, payload)
107
211
}
108
212
109
213
var regInfo = Program . RegisterInfo ( )
110
214
regInfo. elements = elements. count
111
215
regInfo. strings = strings. count
112
216
regInfo. bools = nextBoolRegister. rawValue
217
+ regInfo. ints = nextIntRegister. rawValue
113
218
regInfo. consumeFunctions = consumeFunctions. count
114
219
115
220
return Program (
@@ -155,22 +260,76 @@ extension Program.Builder {
155
260
public mutating func fixup( to t: AddressToken ) {
156
261
assert ( !instructions. isEmpty)
157
262
addressFixups. append (
158
- ( InstructionAddress ( instructions. endIndex- 1 ) , t) )
263
+ ( InstructionAddress ( instructions. endIndex- 1 ) , . init( t) ) )
264
+ }
265
+
266
+ // Associate the most recently added instruction with
267
+ // the provided tokens, ensuring it is fixed up during
268
+ // assembly
269
+ public mutating func fixup(
270
+ to ts: ( AddressToken , AddressToken )
271
+ ) {
272
+ assert ( !instructions. isEmpty)
273
+ addressFixups. append ( (
274
+ InstructionAddress ( instructions. endIndex- 1 ) ,
275
+ . init( ts. 0 , ts. 1 ) ) )
276
+ }
277
+
278
+ // Push an "empty" save point which will, upon restore, just restore from
279
+ // the next save point. Currently, this is modelled by a branch to a "fail"
280
+ // instruction, which the builder will ensure exists for us.
281
+ //
282
+ // This is useful for possessive quantification that needs some initial save
283
+ // point to "ratchet" upon a successful match.
284
+ public mutating func pushEmptySavePoint( ) {
285
+ if failAddressToken == nil {
286
+ failAddressToken = makeAddress ( )
287
+ }
288
+ buildSaveAddress ( failAddressToken!)
159
289
}
290
+
160
291
}
161
292
162
293
// Register helpers
163
294
extension Program . Builder {
164
- public mutating func makeRegister ( ) -> BoolRegister {
295
+ public mutating func makeBoolRegister ( ) -> BoolRegister {
165
296
defer { nextBoolRegister. rawValue += 1 }
166
297
return nextBoolRegister
167
298
}
299
+ public mutating func makeIntRegister( ) -> IntRegister {
300
+ defer { nextIntRegister. rawValue += 1 }
301
+ return nextIntRegister
302
+ }
303
+
304
+ // Allocate and initialize a register
305
+ public mutating func makeIntRegister(
306
+ initialValue: Int
307
+ ) -> IntRegister {
308
+ let r = makeIntRegister ( )
309
+ self . buildMoveImmediate ( initialValue, into: r)
310
+ return r
311
+ }
312
+
313
+ // 'kill' or release allocated registers
314
+ public mutating func kill( _ r: IntRegister ) {
315
+ // TODO: Release/reuse registers, for now nop makes
316
+ // reading the code easier
317
+ buildNop ( " kill \( r) " )
318
+ }
319
+ public mutating func kill( _ r: BoolRegister ) {
320
+ // TODO: Release/reuse registers, for now nop makes
321
+ // reading the code easier
322
+ buildNop ( " kill \( r) " )
323
+ }
168
324
169
325
public mutating func makeConsumeFunction(
170
326
_ f: @escaping Program . ConsumeFunction
171
327
) -> ConsumeFunctionRegister {
172
328
defer { consumeFunctions. append ( f) }
173
329
return ConsumeFunctionRegister ( consumeFunctions. count)
174
330
}
331
+
332
+ // TODO: consider releasing registers
333
+
175
334
}
176
335
0 commit comments