pattern.go 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230
  1. package checker
  2. import (
  3. "kumachan/loader"
  4. "kumachan/transformer/node"
  5. . "kumachan/error"
  6. )
  7. type MaybePattern interface { CheckerMaybePattern() }
  8. func (impl Pattern) CheckerMaybePattern() {}
  9. type Pattern struct {
  10. Point ErrorPoint
  11. Concrete ConcretePattern
  12. }
  13. type ConcretePattern interface { CheckerPattern() }
  14. func (impl TrivialPattern) CheckerPattern() {}
  15. type TrivialPattern struct {
  16. ValueName string
  17. ValueType Type
  18. Point ErrorPoint
  19. }
  20. func (impl TuplePattern) CheckerPattern() {}
  21. type TuplePattern struct {
  22. Items [] PatternItem
  23. }
  24. func (impl BundlePattern) CheckerPattern() {}
  25. type BundlePattern struct {
  26. Items [] PatternItem
  27. }
  28. type PatternItem struct {
  29. Name string
  30. Index uint
  31. Type Type
  32. Point ErrorPoint
  33. }
  34. func PatternFrom (
  35. p_node node.VariousPattern,
  36. input Type,
  37. ctx ExprContext,
  38. ) (Pattern, *ExprError) {
  39. var err_result = func(e ConcreteExprError) (Pattern, *ExprError) {
  40. return Pattern{}, &ExprError {
  41. Point: ctx.GetErrorPoint(p_node.Node),
  42. Concrete: e,
  43. }
  44. }
  45. switch p := p_node.Pattern.(type) {
  46. case node.PatternTrivial:
  47. return Pattern {
  48. Point: ctx.GetErrorPoint(p_node.Node),
  49. Concrete: TrivialPattern {
  50. ValueName: loader.Id2String(p.Name),
  51. ValueType: input,
  52. Point: ctx.GetErrorPoint(p.Name.Node),
  53. },
  54. }, nil
  55. case node.PatternTuple:
  56. switch tuple := UnboxTuple(input, ctx).(type) {
  57. case Tuple:
  58. var required = len(p.Names)
  59. var given = len(tuple.Elements)
  60. if given != required {
  61. return err_result(E_TupleSizeNotMatching {
  62. Required: required,
  63. Given: given,
  64. GivenType: ctx.DescribeType(AnonymousType { tuple }),
  65. })
  66. } else {
  67. var occurred = make(map[string]bool)
  68. var ignored = 0
  69. var items = make([]PatternItem, 0)
  70. for i, identifier := range p.Names {
  71. var name = loader.Id2String(identifier)
  72. if name == IgnoreMark {
  73. ignored += 1
  74. } else {
  75. var _, duplicate = occurred[name]
  76. if duplicate {
  77. return Pattern{}, &ExprError {
  78. Point: ctx.GetErrorPoint(identifier.Node),
  79. Concrete: E_DuplicateBinding { name },
  80. }
  81. }
  82. occurred[name] = true
  83. items = append(items, PatternItem {
  84. Name: loader.Id2String(identifier),
  85. Index: uint(i),
  86. Type: tuple.Elements[i],
  87. Point: ctx.GetErrorPoint(identifier.Node),
  88. })
  89. }
  90. }
  91. if ignored == len(p.Names) {
  92. return err_result(E_EntireValueIgnored {})
  93. } else {
  94. return Pattern {
  95. Point: ctx.GetErrorPoint(p_node.Node),
  96. Concrete: TuplePattern { items },
  97. }, nil
  98. }
  99. }
  100. case TR_NonTuple:
  101. return err_result(E_MatchingNonTupleType {})
  102. case TR_TupleButOpaque:
  103. return err_result(E_MatchingOpaqueTupleType {})
  104. default:
  105. panic("impossible branch")
  106. }
  107. case node.PatternBundle:
  108. switch bundle := UnboxBundle(input, ctx).(type) {
  109. case Bundle:
  110. var occurred = make(map[string]bool)
  111. var items = make([]PatternItem, len(p.Names))
  112. for i, identifier := range p.Names {
  113. var name = loader.Id2String(identifier)
  114. var field, exists = bundle.Fields[name]
  115. if exists && name == IgnoreMark {
  116. // field should not be named using IgnoreMark;
  117. // IgnoreMark used in bundle pattern considered
  118. // as "field does not exist" error
  119. panic("something went wrong")
  120. }
  121. if !exists {
  122. return Pattern{}, &ExprError {
  123. Point: ctx.GetErrorPoint(identifier.Node),
  124. Concrete: E_FieldDoesNotExist {
  125. Field: name,
  126. Target: ctx.DescribeType(input),
  127. },
  128. }
  129. }
  130. var _, duplicate = occurred[name]
  131. if duplicate {
  132. return Pattern{}, &ExprError {
  133. Point: ctx.GetErrorPoint(identifier.Node),
  134. Concrete: E_DuplicateBinding { name },
  135. }
  136. }
  137. occurred[name] = true
  138. items[i] = PatternItem {
  139. Name: loader.Id2String(identifier),
  140. Index: field.Index,
  141. Type: field.Type,
  142. Point: ctx.GetErrorPoint(identifier.Node),
  143. }
  144. }
  145. return Pattern {
  146. Point: ctx.GetErrorPoint(p_node.Node),
  147. Concrete: BundlePattern { items },
  148. }, nil
  149. case BR_NonBundle:
  150. return err_result(E_MatchingNonBundleType {})
  151. case BR_BundleButOpaque:
  152. return err_result(E_MatchingOpaqueBundleType {})
  153. default:
  154. panic("impossible branch")
  155. }
  156. default:
  157. panic("impossible branch")
  158. }
  159. }
  160. func (ctx ExprContext) WithShadowingPatternMatching(p Pattern) ExprContext {
  161. var added = make(map[string]Type)
  162. switch P := p.Concrete.(type) {
  163. case TrivialPattern:
  164. added[P.ValueName] = P.ValueType
  165. case TuplePattern:
  166. var added = make(map[string]Type)
  167. for _, item := range P.Items {
  168. added[item.Name] = item.Type
  169. }
  170. case BundlePattern:
  171. var added = make(map[string]Type)
  172. for _, item := range P.Items {
  173. added[item.Name] = item.Type
  174. }
  175. default:
  176. panic("impossible branch")
  177. }
  178. var new_ctx, _ = ctx.WithAddedLocalValues(added)
  179. return new_ctx
  180. }
  181. func (ctx ExprContext) WithPatternMatching(p Pattern) (ExprContext, *ExprError) {
  182. var err_result = func(e ConcreteExprError) (ExprContext, *ExprError) {
  183. return ExprContext{}, &ExprError {
  184. Point: p.Point,
  185. Concrete: e,
  186. }
  187. }
  188. var check = func(added map[string]Type) (ExprContext, *ExprError) {
  189. var new_ctx, shadowed = ctx.WithAddedLocalValues(added)
  190. if shadowed != "" {
  191. return err_result(E_DuplicateBinding { shadowed })
  192. } else {
  193. return new_ctx, nil
  194. }
  195. }
  196. switch P := p.Concrete.(type) {
  197. case TrivialPattern:
  198. if P.ValueName == IgnoreMark {
  199. return err_result(E_EntireValueIgnored {})
  200. } else {
  201. var added = make(map[string]Type)
  202. added[P.ValueName] = P.ValueType
  203. return check(added)
  204. }
  205. case TuplePattern:
  206. var added = make(map[string]Type)
  207. for _, item := range P.Items {
  208. added[item.Name] = item.Type
  209. }
  210. return check(added)
  211. case BundlePattern:
  212. var added = make(map[string]Type)
  213. for _, item := range P.Items {
  214. added[item.Name] = item.Type
  215. }
  216. return check(added)
  217. default:
  218. panic("impossible branch")
  219. }
  220. }