dispatch.go 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
  1. package compiler
  2. import (
  3. "fmt"
  4. "kumachan/standalone/ctn"
  5. "kumachan/interpreter/program"
  6. "kumachan/lang/source"
  7. "kumachan/lang/typsys"
  8. )
  9. func fillDispatchInfo(fd fragmentDraft, hdr *Header, ctx *NsHeaderMap, errs *source.Errors) {
  10. hdr.typeMap.ForEach(func(_ string, C *typsys.TypeDef) {
  11. var _, C_is_interface = C.Content.(typsys.Interface)
  12. for _, I_ := range C.Interfaces {
  13. var I, exists = ctx.lookupType(I_)
  14. if !(exists) { panic("something went wrong") }
  15. if C_is_interface {
  16. // do nothing here (case handled elsewhere)
  17. } else {
  18. var _, err = createDispatchTable(C, I, fd, ctx)
  19. source.ErrorsJoin(errs, err)
  20. }
  21. }
  22. })
  23. }
  24. func createDispatchTable (
  25. C *typsys.TypeDef,
  26. I *typsys.TypeDef,
  27. fd fragmentDraft,
  28. ctx *NsHeaderMap,
  29. ) (*program.DispatchTable, *source.Error) {
  30. var loc = C.Info.Location
  31. var spec, ok = I.Content.(typsys.Interface)
  32. if !(ok) { panic("something went wrong") }
  33. var pair = dispatchKey {
  34. ConcreteType: C.Ref.ItemName,
  35. InterfaceType: I.Ref,
  36. }
  37. { var t, ok = fd.createDispatchTable(pair)
  38. if !(ok) {
  39. return nil, source.MakeError(loc,
  40. E_DuplicateInterface { I.Ref.String() })
  41. }
  42. if !(haveIdenticalTypeParams(C, I)) {
  43. return nil, source.MakeError(loc,
  44. E_TypeParamsNotIdentical {
  45. Concrete: C.Ref.String(),
  46. Interface: I.Ref.String(),
  47. })
  48. }
  49. var methods = make([] *program.Function, len(spec.FieldList))
  50. for i, field := range spec.FieldList {
  51. var method_name = field.Name
  52. var expected_type = field.Type
  53. var f, ok = ctx.lookupMethod(C.Ref, method_name)
  54. if !(ok) {
  55. if record, is_record := C.Content.(typsys.Record); is_record {
  56. if index, found := record.FieldIndexMap[method_name]; found {
  57. if typsys.Equal(record.FieldList[index].Type, expected_type) {
  58. var getter = new(program.Function)
  59. getter.SetName(fmt.Sprintf("[field_%d_%p]", index, getter))
  60. getter.SetFieldValueGetterValueByIndex(index)
  61. methods[i] = getter
  62. continue
  63. }}}
  64. return nil, source.MakeError(loc,
  65. E_MissingMethod {
  66. Concrete: C.Ref.String(),
  67. Interface: I.Ref.String(),
  68. Method: method_name,
  69. })
  70. }
  71. var actual_type = f.output.type_
  72. if !(typsys.Equal(actual_type, expected_type)) {
  73. return nil, source.MakeError(loc,
  74. E_WrongMethodType {
  75. Concrete: C.Ref.String(),
  76. Interface: I.Ref.String(),
  77. Method: method_name,
  78. Expected: typsys.Describe(expected_type),
  79. Actual: typsys.Describe(actual_type),
  80. })
  81. }
  82. var key = userFunKey {
  83. name: method_name,
  84. assoc: C.Ref.ItemName,
  85. }
  86. methods[i] = fd.createOrGetUserFun(key)
  87. }
  88. var children = make([] *program.DispatchTable, len(I.Interfaces))
  89. for i, II_ := range I.Interfaces {
  90. var II, exists = ctx.lookupType(II_)
  91. if !(exists) { panic("something went wrong") }
  92. var child, err = createDispatchTable(C, II, fd, ctx)
  93. if err != nil { return nil, err }
  94. child.SetParent(t)
  95. children[i] = child
  96. }
  97. t.SetName(pair.Describe(fd.namespace()))
  98. t.SetInterface(I.Ref.String())
  99. t.SetMethods(methods)
  100. t.SetChildren(children)
  101. return t, nil }
  102. }
  103. type dispatchKey struct {
  104. ConcreteType string
  105. InterfaceType source.Ref
  106. }
  107. func (pair dispatchKey) Describe(ns string) string {
  108. var C = source.MakeRef(ns, pair.ConcreteType)
  109. var I = pair.InterfaceType
  110. return fmt.Sprintf("(%s,%s)", C, I)
  111. }
  112. func dispatchKeyCompare(a dispatchKey, b dispatchKey) ctn.Ordering {
  113. var o = ctn.StringCompare(a.ConcreteType, b.ConcreteType)
  114. if o != ctn.Equal {
  115. return o
  116. } else {
  117. return source.RefCompare(a.InterfaceType, b.InterfaceType)
  118. }
  119. }