function.go 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183
  1. package checker
  2. import (
  3. . "kumachan/error"
  4. "kumachan/loader"
  5. "kumachan/transformer/node"
  6. )
  7. type GenericFunction struct {
  8. Node node.Node
  9. Public bool
  10. TypeParams [] string
  11. DeclaredType Func
  12. Body node.Body
  13. }
  14. type FunctionReference struct {
  15. Function *GenericFunction // Pointer to the underlying function
  16. IsImported bool // If it is imported from another module
  17. ModuleName string
  18. }
  19. // Map from module names to their corresponding function collections
  20. type FunctionStore map[string] FunctionCollection
  21. // Map from names of available functions in the module to their references
  22. type FunctionCollection map[string] []FunctionReference
  23. // Procedure to collect all functions in a module hierarchy
  24. func CollectFunctions(mod *loader.Module, reg TypeRegistry, store FunctionStore) (FunctionCollection, *FunctionError) {
  25. /**
  26. * Input: a root module, a type registry and an empty function store
  27. * Output: collected functions of the root module (or an error)
  28. * Effect: fill all collected functions into the function store
  29. */
  30. // 1. Check if the module was visited, if so, return the existing result
  31. var mod_name = mod.Name
  32. var existing, exists = store[mod_name]
  33. if exists {
  34. return existing, nil
  35. }
  36. // 2. Iterate over all modules imported by the current module
  37. var collection = make(FunctionCollection)
  38. for _, imported := range mod.ImpMap {
  39. // 2.1. Call self recursively to collect functions of imported modules
  40. var imp_col, err = CollectFunctions(imported, reg, store)
  41. if err != nil { return nil, err }
  42. // 2.2. Iterate over all functions in imported modules
  43. for name, refs := range imp_col {
  44. for _, ref := range refs {
  45. if !ref.IsImported && ref.Function.Public {
  46. // 2.2.1. If the function is exported, import it
  47. var _, exists = collection[name]
  48. if !exists {
  49. collection[name] = make([]FunctionReference, 0)
  50. }
  51. // Note: conflict (unsafe overload) must not happen there,
  52. // since public functions have local signatures
  53. collection[name] = append(collection[name], FunctionReference {
  54. Function: ref.Function,
  55. IsImported: true,
  56. })
  57. }
  58. }
  59. }
  60. }
  61. // 3. Iterate over all function declarations in the current module
  62. for _, cmd := range mod.Node.Commands {
  63. switch c := cmd.Command.(type) {
  64. case node.DeclFunction:
  65. // 3.1. Get the names of the function and its type parameters
  66. var decl = c
  67. var name = loader.Id2String(decl.Name)
  68. if name == IgnoreMark {
  69. // 3.1.1. If the function name is invalid, throw an error.
  70. return nil, &FunctionError {
  71. Point: ErrorPoint { AST: mod.AST, Node: decl.Name.Node },
  72. Concrete: E_InvalidFunctionName { name },
  73. }
  74. }
  75. var params = make([]string, len(decl.Params))
  76. for i, p := range decl.Params {
  77. params[i] = loader.Id2String(p)
  78. }
  79. // 3.2. Create a context for evaluating types
  80. var ctx = TypeContext {
  81. Module: mod,
  82. Params: params,
  83. Ireg: reg,
  84. }
  85. // 3.3. Evaluate the function signature using the created context
  86. var sig, err = TypeFromRepr(decl.Repr, ctx)
  87. if err != nil { return nil, &FunctionError {
  88. Point: err.Point,
  89. Concrete: E_SignatureInvalid {
  90. FuncName: name,
  91. TypeError: err,
  92. },
  93. } }
  94. // 3.4. If the function is public, ensure its signature type
  95. // to be a local type of this module.
  96. var is_public = decl.Public
  97. if is_public && !(IsLocalType(sig, mod_name)) {
  98. return nil, &FunctionError {
  99. Point: ErrorPoint {
  100. AST: mod.AST, Node: decl.Repr.Node,
  101. },
  102. Concrete: E_SignatureNonLocal {
  103. FuncName: name,
  104. },
  105. }
  106. }
  107. // 3.5. Construct a representation and a reference of the function
  108. var func_type = sig.(AnonymousType).Repr.(Func)
  109. var gf = &GenericFunction {
  110. Public: is_public,
  111. TypeParams: params,
  112. DeclaredType: func_type,
  113. Body: decl.Body.Body,
  114. Node: decl.Node,
  115. }
  116. var ref = FunctionReference {
  117. IsImported: false,
  118. Function: gf,
  119. ModuleName: mod_name,
  120. }
  121. // 3.6. Check if the name of the function is in use
  122. var _, exists = collection[name]
  123. if exists {
  124. // 3.6.1. If in use, try to overload it
  125. var err_point = ErrorPoint {
  126. AST: mod.AST, Node: decl.Name.Node,
  127. }
  128. var err = CheckOverload (
  129. collection[name], func_type, name, params, err_point,
  130. )
  131. if err != nil { return nil, err }
  132. collection[name] = append(collection[name], ref)
  133. } else {
  134. // 3.6.2. If not, collect the function
  135. collection[name] = []FunctionReference { ref }
  136. }
  137. }
  138. }
  139. // 4. Register all collected functions of the current module to the store
  140. store[mod_name] = collection
  141. // 5. Return all collected functions of the current module
  142. return collection, nil
  143. }
  144. func CheckOverload (
  145. functions [] FunctionReference,
  146. added_type Func,
  147. added_name string,
  148. added_params [] string,
  149. err_point ErrorPoint,
  150. ) *FunctionError {
  151. for _, existing := range functions {
  152. var existing_t = AnonymousType { existing.Function.DeclaredType }
  153. var added_t = AnonymousType { added_type }
  154. var cannot_overload = AreTypesOverloadUnsafe(existing_t, added_t)
  155. if cannot_overload {
  156. var existing_params = existing.Function.TypeParams
  157. return &FunctionError {
  158. Point: err_point,
  159. Concrete: E_InvalidOverload {
  160. BetweenLocal: !(existing.IsImported),
  161. AddedName: added_name,
  162. AddedModule: existing.ModuleName,
  163. AddedType: DescribeTypeWithParams (
  164. added_t, added_params,
  165. ),
  166. ExistingType: DescribeTypeWithParams (
  167. existing_t, existing_params,
  168. ),
  169. },
  170. }
  171. }
  172. }
  173. return nil
  174. }