Skip to content

Commit 0dd3702

Browse files
authored
Refactor deref (#398)
* Refactor deref types * Refactor deref opcode inserts * Add multiple pointers deref
1 parent d2100ec commit 0dd3702

File tree

8 files changed

+232
-93
lines changed

8 files changed

+232
-93
lines changed

ast/node.go

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,6 @@ type NilNode struct {
5050
type IdentifierNode struct {
5151
base
5252
Value string
53-
Deref bool
5453
FieldIndex []int
5554
Method bool // true if method, false if field
5655
MethodIndex int // index of method, set only if Method is true
@@ -106,10 +105,9 @@ type MemberNode struct {
106105
Property Node
107106
Name string // Name of the filed or method. Used for error reporting.
108107
Optional bool
109-
Deref bool
110108
FieldIndex []int
111109

112-
// TODO: Replace with a single MethodIndex field of &int type.
110+
// TODO: Combine Method and MethodIndex into a single MethodIndex field of &int type.
113111
Method bool
114112
MethodIndex int
115113
}

checker/checker.go

Lines changed: 10 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -135,18 +135,14 @@ func (v *visitor) IdentifierNode(node *ast.IdentifierNode) (reflect.Type, info)
135135
// when the arguments are known in CallNode.
136136
return anyType, info{fn: fn}
137137
}
138-
if v.config.Types == nil {
139-
node.Deref = true
140-
} else if t, ok := v.config.Types[node.Value]; ok {
138+
if t, ok := v.config.Types[node.Value]; ok {
141139
if t.Ambiguous {
142140
return v.error(node, "ambiguous identifier %v", node.Value)
143141
}
144-
d, c := deref(t.Type)
145-
node.Deref = c
146142
node.Method = t.Method
147143
node.MethodIndex = t.MethodIndex
148144
node.FieldIndex = t.FieldIndex
149-
return d, info{method: t.Method}
145+
return t.Type, info{method: t.Method}
150146
}
151147
if v.config.Strict {
152148
return v.error(node, "unknown name %v", node.Value)
@@ -180,6 +176,8 @@ func (v *visitor) ConstantNode(node *ast.ConstantNode) (reflect.Type, info) {
180176
func (v *visitor) UnaryNode(node *ast.UnaryNode) (reflect.Type, info) {
181177
t, _ := v.visit(node.Node)
182178

179+
t = deref(t)
180+
183181
switch node.Operator {
184182

185183
case "!", "not":
@@ -209,6 +207,9 @@ func (v *visitor) BinaryNode(node *ast.BinaryNode) (reflect.Type, info) {
209207
l, _ := v.visit(node.Left)
210208
r, _ := v.visit(node.Right)
211209

210+
l = deref(l)
211+
r = deref(r)
212+
212213
// check operator overloading
213214
if fns, ok := v.config.Operators[node.Operator]; ok {
214215
t, _, ok := conf.FindSuitableOperatorOverload(fns, v.config.Types, l, r)
@@ -427,34 +428,27 @@ func (v *visitor) MemberNode(node *ast.MemberNode) (reflect.Type, info) {
427428

428429
switch base.Kind() {
429430
case reflect.Interface:
430-
node.Deref = true
431431
return anyType, info{}
432432

433433
case reflect.Map:
434434
if prop != nil && !prop.AssignableTo(base.Key()) && !isAny(prop) {
435435
return v.error(node.Property, "cannot use %v to get an element from %v", prop, base)
436436
}
437-
t, c := deref(base.Elem())
438-
node.Deref = c
439-
return t, info{}
437+
return base.Elem(), info{}
440438

441439
case reflect.Array, reflect.Slice:
442440
if !isInteger(prop) && !isAny(prop) {
443441
return v.error(node.Property, "array elements can only be selected using an integer (got %v)", prop)
444442
}
445-
t, c := deref(base.Elem())
446-
node.Deref = c
447-
return t, info{}
443+
return base.Elem(), info{}
448444

449445
case reflect.Struct:
450446
if name, ok := node.Property.(*ast.StringNode); ok {
451447
propertyName := name.Value
452448
if field, ok := fetchField(base, propertyName); ok {
453-
t, c := deref(field.Type)
454-
node.Deref = c
455449
node.FieldIndex = field.Index
456450
node.Name = propertyName
457-
return t, info{}
451+
return field.Type, info{}
458452
}
459453
if len(v.parents) > 1 {
460454
if _, ok := v.parents[len(v.parents)-2].(*ast.CallNode); ok {

checker/types.go

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -204,25 +204,23 @@ func fetchField(t reflect.Type, name string) (reflect.StructField, bool) {
204204
return reflect.StructField{}, false
205205
}
206206

207-
func deref(t reflect.Type) (reflect.Type, bool) {
207+
func deref(t reflect.Type) reflect.Type {
208208
if t == nil {
209-
return nil, false
209+
return nil
210210
}
211211
if t.Kind() == reflect.Interface {
212-
return t, true
212+
return t
213213
}
214-
found := false
215214
for t != nil && t.Kind() == reflect.Ptr {
216215
e := t.Elem()
217216
switch e.Kind() {
218217
case reflect.Struct, reflect.Map, reflect.Array, reflect.Slice:
219-
return t, false
218+
return t
220219
default:
221-
found = true
222220
t = e
223221
}
224222
}
225-
return t, found
223+
return t
226224
}
227225

228226
func isIntegerOrArithmeticOperation(node ast.Node) bool {

compiler/compiler.go

Lines changed: 52 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -224,11 +224,6 @@ func (c *compiler) IdentifierNode(node *ast.IdentifierNode) {
224224
} else {
225225
c.emit(OpLoadConst, c.addConstant(node.Value))
226226
}
227-
if node.Deref {
228-
c.emit(OpDeref)
229-
} else if node.Type() == nil {
230-
c.emit(OpDeref)
231-
}
232227
}
233228

234229
func (c *compiler) IntegerNode(node *ast.IntegerNode) {
@@ -289,6 +284,7 @@ func (c *compiler) ConstantNode(node *ast.ConstantNode) {
289284

290285
func (c *compiler) UnaryNode(node *ast.UnaryNode) {
291286
c.compile(node.Node)
287+
c.derefInNeeded(node.Node)
292288

293289
switch node.Operator {
294290

@@ -313,7 +309,9 @@ func (c *compiler) BinaryNode(node *ast.BinaryNode) {
313309
switch node.Operator {
314310
case "==":
315311
c.compile(node.Left)
312+
c.derefInNeeded(node.Left)
316313
c.compile(node.Right)
314+
c.derefInNeeded(node.Left)
317315

318316
if l == r && l == reflect.Int {
319317
c.emit(OpEqualInt)
@@ -325,114 +323,155 @@ func (c *compiler) BinaryNode(node *ast.BinaryNode) {
325323

326324
case "!=":
327325
c.compile(node.Left)
326+
c.derefInNeeded(node.Left)
328327
c.compile(node.Right)
328+
c.derefInNeeded(node.Left)
329329
c.emit(OpEqual)
330330
c.emit(OpNot)
331331

332332
case "or", "||":
333333
c.compile(node.Left)
334+
c.derefInNeeded(node.Left)
334335
end := c.emit(OpJumpIfTrue, placeholder)
335336
c.emit(OpPop)
336337
c.compile(node.Right)
338+
c.derefInNeeded(node.Right)
337339
c.patchJump(end)
338340

339341
case "and", "&&":
340342
c.compile(node.Left)
343+
c.derefInNeeded(node.Left)
341344
end := c.emit(OpJumpIfFalse, placeholder)
342345
c.emit(OpPop)
343346
c.compile(node.Right)
347+
c.derefInNeeded(node.Right)
344348
c.patchJump(end)
345349

346350
case "<":
347351
c.compile(node.Left)
352+
c.derefInNeeded(node.Left)
348353
c.compile(node.Right)
354+
c.derefInNeeded(node.Right)
349355
c.emit(OpLess)
350356

351357
case ">":
352358
c.compile(node.Left)
359+
c.derefInNeeded(node.Left)
353360
c.compile(node.Right)
361+
c.derefInNeeded(node.Right)
354362
c.emit(OpMore)
355363

356364
case "<=":
357365
c.compile(node.Left)
366+
c.derefInNeeded(node.Left)
358367
c.compile(node.Right)
368+
c.derefInNeeded(node.Right)
359369
c.emit(OpLessOrEqual)
360370

361371
case ">=":
362372
c.compile(node.Left)
373+
c.derefInNeeded(node.Left)
363374
c.compile(node.Right)
375+
c.derefInNeeded(node.Right)
364376
c.emit(OpMoreOrEqual)
365377

366378
case "+":
367379
c.compile(node.Left)
380+
c.derefInNeeded(node.Left)
368381
c.compile(node.Right)
382+
c.derefInNeeded(node.Right)
369383
c.emit(OpAdd)
370384

371385
case "-":
372386
c.compile(node.Left)
387+
c.derefInNeeded(node.Left)
373388
c.compile(node.Right)
389+
c.derefInNeeded(node.Right)
374390
c.emit(OpSubtract)
375391

376392
case "*":
377393
c.compile(node.Left)
394+
c.derefInNeeded(node.Left)
378395
c.compile(node.Right)
396+
c.derefInNeeded(node.Right)
379397
c.emit(OpMultiply)
380398

381399
case "/":
382400
c.compile(node.Left)
401+
c.derefInNeeded(node.Left)
383402
c.compile(node.Right)
403+
c.derefInNeeded(node.Right)
384404
c.emit(OpDivide)
385405

386406
case "%":
387407
c.compile(node.Left)
408+
c.derefInNeeded(node.Left)
388409
c.compile(node.Right)
410+
c.derefInNeeded(node.Right)
389411
c.emit(OpModulo)
390412

391413
case "**", "^":
392414
c.compile(node.Left)
415+
c.derefInNeeded(node.Left)
393416
c.compile(node.Right)
417+
c.derefInNeeded(node.Right)
394418
c.emit(OpExponent)
395419

396420
case "in":
397421
c.compile(node.Left)
422+
c.derefInNeeded(node.Left)
398423
c.compile(node.Right)
424+
c.derefInNeeded(node.Right)
399425
c.emit(OpIn)
400426

401427
case "matches":
402428
if node.Regexp != nil {
403429
c.compile(node.Left)
430+
c.derefInNeeded(node.Left)
404431
c.emit(OpMatchesConst, c.addConstant(node.Regexp))
405432
} else {
406433
c.compile(node.Left)
434+
c.derefInNeeded(node.Left)
407435
c.compile(node.Right)
436+
c.derefInNeeded(node.Right)
408437
c.emit(OpMatches)
409438
}
410439

411440
case "contains":
412441
c.compile(node.Left)
442+
c.derefInNeeded(node.Left)
413443
c.compile(node.Right)
444+
c.derefInNeeded(node.Right)
414445
c.emit(OpContains)
415446

416447
case "startsWith":
417448
c.compile(node.Left)
449+
c.derefInNeeded(node.Left)
418450
c.compile(node.Right)
451+
c.derefInNeeded(node.Right)
419452
c.emit(OpStartsWith)
420453

421454
case "endsWith":
422455
c.compile(node.Left)
456+
c.derefInNeeded(node.Left)
423457
c.compile(node.Right)
458+
c.derefInNeeded(node.Right)
424459
c.emit(OpEndsWith)
425460

426461
case "..":
427462
c.compile(node.Left)
463+
c.derefInNeeded(node.Left)
428464
c.compile(node.Right)
465+
c.derefInNeeded(node.Right)
429466
c.emit(OpRange)
430467

431468
case "??":
432469
c.compile(node.Left)
470+
c.derefInNeeded(node.Left)
433471
end := c.emit(OpJumpIfNotNil, placeholder)
434472
c.emit(OpPop)
435473
c.compile(node.Right)
474+
c.derefInNeeded(node.Right)
436475
c.patchJump(end)
437476

438477
default:
@@ -461,7 +500,6 @@ func (c *compiler) MemberNode(node *ast.MemberNode) {
461500
return
462501
}
463502
op := OpFetch
464-
original := node
465503
index := node.FieldIndex
466504
path := []string{node.Name}
467505
base := node.Node
@@ -470,21 +508,15 @@ func (c *compiler) MemberNode(node *ast.MemberNode) {
470508
for !node.Optional {
471509
ident, ok := base.(*ast.IdentifierNode)
472510
if ok && len(ident.FieldIndex) > 0 {
473-
if ident.Deref {
474-
panic("IdentifierNode should not be dereferenced")
475-
}
476511
index = append(ident.FieldIndex, index...)
477512
path = append([]string{ident.Value}, path...)
478513
c.emitLocation(ident.Location(), OpLoadField, c.addConstant(
479514
&runtime.Field{Index: index, Path: path},
480515
))
481-
goto deref
516+
return
482517
}
483518
member, ok := base.(*ast.MemberNode)
484519
if ok && len(member.FieldIndex) > 0 {
485-
if member.Deref {
486-
panic("MemberNode should not be dereferenced")
487-
}
488520
index = append(member.FieldIndex, index...)
489521
path = append([]string{member.Name}, path...)
490522
node = member
@@ -509,13 +541,6 @@ func (c *compiler) MemberNode(node *ast.MemberNode) {
509541
&runtime.Field{Index: index, Path: path},
510542
))
511543
}
512-
513-
deref:
514-
if original.Deref {
515-
c.emit(OpDeref)
516-
} else if original.Type() == nil {
517-
c.emit(OpDeref)
518-
}
519544
}
520545

521546
func (c *compiler) SliceNode(node *ast.SliceNode) {
@@ -734,6 +759,13 @@ func (c *compiler) PairNode(node *ast.PairNode) {
734759
c.compile(node.Value)
735760
}
736761

762+
func (c *compiler) derefInNeeded(node ast.Node) {
763+
switch kind(node) {
764+
case reflect.Ptr, reflect.Interface:
765+
c.emit(OpDeref)
766+
}
767+
}
768+
737769
func kind(node ast.Node) reflect.Kind {
738770
t := node.Type()
739771
if t == nil {

0 commit comments

Comments
 (0)