123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230 |
- package checker
- import (
- "kumachan/loader"
- "kumachan/transformer/node"
- . "kumachan/error"
- )
- type MaybePattern interface { CheckerMaybePattern() }
- func (impl Pattern) CheckerMaybePattern() {}
- type Pattern struct {
- Point ErrorPoint
- Concrete ConcretePattern
- }
- type ConcretePattern interface { CheckerPattern() }
- func (impl TrivialPattern) CheckerPattern() {}
- type TrivialPattern struct {
- ValueName string
- ValueType Type
- Point ErrorPoint
- }
- func (impl TuplePattern) CheckerPattern() {}
- type TuplePattern struct {
- Items [] PatternItem
- }
- func (impl BundlePattern) CheckerPattern() {}
- type BundlePattern struct {
- Items [] PatternItem
- }
- type PatternItem struct {
- Name string
- Index uint
- Type Type
- Point ErrorPoint
- }
- func PatternFrom (
- p_node node.VariousPattern,
- input Type,
- ctx ExprContext,
- ) (Pattern, *ExprError) {
- var err_result = func(e ConcreteExprError) (Pattern, *ExprError) {
- return Pattern{}, &ExprError {
- Point: ctx.GetErrorPoint(p_node.Node),
- Concrete: e,
- }
- }
- switch p := p_node.Pattern.(type) {
- case node.PatternTrivial:
- return Pattern {
- Point: ctx.GetErrorPoint(p_node.Node),
- Concrete: TrivialPattern {
- ValueName: loader.Id2String(p.Name),
- ValueType: input,
- Point: ctx.GetErrorPoint(p.Name.Node),
- },
- }, nil
- case node.PatternTuple:
- switch tuple := UnboxTuple(input, ctx).(type) {
- case Tuple:
- var required = len(p.Names)
- var given = len(tuple.Elements)
- if given != required {
- return err_result(E_TupleSizeNotMatching {
- Required: required,
- Given: given,
- GivenType: ctx.DescribeType(AnonymousType { tuple }),
- })
- } else {
- var occurred = make(map[string]bool)
- var ignored = 0
- var items = make([]PatternItem, 0)
- for i, identifier := range p.Names {
- var name = loader.Id2String(identifier)
- if name == IgnoreMark {
- ignored += 1
- } else {
- var _, duplicate = occurred[name]
- if duplicate {
- return Pattern{}, &ExprError {
- Point: ctx.GetErrorPoint(identifier.Node),
- Concrete: E_DuplicateBinding { name },
- }
- }
- occurred[name] = true
- items = append(items, PatternItem {
- Name: loader.Id2String(identifier),
- Index: uint(i),
- Type: tuple.Elements[i],
- Point: ctx.GetErrorPoint(identifier.Node),
- })
- }
- }
- if ignored == len(p.Names) {
- return err_result(E_EntireValueIgnored {})
- } else {
- return Pattern {
- Point: ctx.GetErrorPoint(p_node.Node),
- Concrete: TuplePattern { items },
- }, nil
- }
- }
- case TR_NonTuple:
- return err_result(E_MatchingNonTupleType {})
- case TR_TupleButOpaque:
- return err_result(E_MatchingOpaqueTupleType {})
- default:
- panic("impossible branch")
- }
- case node.PatternBundle:
- switch bundle := UnboxBundle(input, ctx).(type) {
- case Bundle:
- var occurred = make(map[string]bool)
- var items = make([]PatternItem, len(p.Names))
- for i, identifier := range p.Names {
- var name = loader.Id2String(identifier)
- var field, exists = bundle.Fields[name]
- if exists && name == IgnoreMark {
- // field should not be named using IgnoreMark;
- // IgnoreMark used in bundle pattern considered
- // as "field does not exist" error
- panic("something went wrong")
- }
- if !exists {
- return Pattern{}, &ExprError {
- Point: ctx.GetErrorPoint(identifier.Node),
- Concrete: E_FieldDoesNotExist {
- Field: name,
- Target: ctx.DescribeType(input),
- },
- }
- }
- var _, duplicate = occurred[name]
- if duplicate {
- return Pattern{}, &ExprError {
- Point: ctx.GetErrorPoint(identifier.Node),
- Concrete: E_DuplicateBinding { name },
- }
- }
- occurred[name] = true
- items[i] = PatternItem {
- Name: loader.Id2String(identifier),
- Index: field.Index,
- Type: field.Type,
- Point: ctx.GetErrorPoint(identifier.Node),
- }
- }
- return Pattern {
- Point: ctx.GetErrorPoint(p_node.Node),
- Concrete: BundlePattern { items },
- }, nil
- case BR_NonBundle:
- return err_result(E_MatchingNonBundleType {})
- case BR_BundleButOpaque:
- return err_result(E_MatchingOpaqueBundleType {})
- default:
- panic("impossible branch")
- }
- default:
- panic("impossible branch")
- }
- }
- func (ctx ExprContext) WithShadowingPatternMatching(p Pattern) ExprContext {
- var added = make(map[string]Type)
- switch P := p.Concrete.(type) {
- case TrivialPattern:
- added[P.ValueName] = P.ValueType
- case TuplePattern:
- var added = make(map[string]Type)
- for _, item := range P.Items {
- added[item.Name] = item.Type
- }
- case BundlePattern:
- var added = make(map[string]Type)
- for _, item := range P.Items {
- added[item.Name] = item.Type
- }
- default:
- panic("impossible branch")
- }
- var new_ctx, _ = ctx.WithAddedLocalValues(added)
- return new_ctx
- }
- func (ctx ExprContext) WithPatternMatching(p Pattern) (ExprContext, *ExprError) {
- var err_result = func(e ConcreteExprError) (ExprContext, *ExprError) {
- return ExprContext{}, &ExprError {
- Point: p.Point,
- Concrete: e,
- }
- }
- var check = func(added map[string]Type) (ExprContext, *ExprError) {
- var new_ctx, shadowed = ctx.WithAddedLocalValues(added)
- if shadowed != "" {
- return err_result(E_DuplicateBinding { shadowed })
- } else {
- return new_ctx, nil
- }
- }
- switch P := p.Concrete.(type) {
- case TrivialPattern:
- if P.ValueName == IgnoreMark {
- return err_result(E_EntireValueIgnored {})
- } else {
- var added = make(map[string]Type)
- added[P.ValueName] = P.ValueType
- return check(added)
- }
- case TuplePattern:
- var added = make(map[string]Type)
- for _, item := range P.Items {
- added[item.Name] = item.Type
- }
- return check(added)
- case BundlePattern:
- var added = make(map[string]Type)
- for _, item := range P.Items {
- added[item.Name] = item.Type
- }
- return check(added)
- default:
- panic("impossible branch")
- }
- }
|