123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392 |
- package checker
- import (
- "kumachan/loader"
- "kumachan/transformer/node"
- )
- func (impl SemiTypedTuple) SemiExprVal() {}
- type SemiTypedTuple struct {
- Values [] SemiExpr
- }
- func (impl SemiTypedBundle) SemiExprVal() {}
- type SemiTypedBundle struct {
- Index map[string] uint
- Values [] SemiExpr
- KeyNodes [] node.Node
- }
- func (impl Product) ExprVal() {}
- type Product struct {
- Values [] Expr
- }
- func (impl Get) ExprVal() {}
- type Get struct {
- Product Expr
- Index uint
- }
- func (impl Set) ExprVal() {}
- type Set struct {
- Product Expr
- Index uint
- NewValue Expr
- }
- func CheckTuple(tuple node.Tuple, ctx ExprContext) (SemiExpr, *ExprError) {
- var info = ctx.GetExprInfo(tuple.Node)
- var L = len(tuple.Elements)
- if L == 0 {
- return LiftTyped(Expr {
- Type: AnonymousType { Unit {} },
- Value: UnitValue {},
- Info: info,
- }), nil
- } else if L == 1 {
- var expr, err = Check(tuple.Elements[0], ctx)
- if err != nil { return SemiExpr{}, err }
- return expr, nil
- } else {
- var el_exprs = make([]SemiExpr, L)
- var el_types = make([]Type, L)
- for i, el := range tuple.Elements {
- var expr, err = Check(el, ctx)
- if err != nil { return SemiExpr{}, err }
- el_exprs[i] = expr
- switch typed := expr.Value.(type) {
- case TypedExpr:
- el_types[i] = typed.Type
- }
- }
- return SemiExpr {
- Value: SemiTypedTuple { el_exprs },
- Info: info,
- }, nil
- }
- }
- func CheckBundle(bundle node.Bundle, ctx ExprContext) (SemiExpr, *ExprError) {
- var info = ctx.GetExprInfo(bundle.Node)
- switch update := bundle.Update.(type) {
- case node.Update:
- var base_semi, err = Check(update.Base, ctx)
- if err != nil { return SemiExpr{}, err }
- switch b := base_semi.Value.(type) {
- case TypedExpr:
- if IsBundleLiteral(Expr(b)) { return SemiExpr{}, &ExprError {
- Point: ctx.GetErrorPoint(update.Base.Node),
- Concrete: E_SetToLiteralBundle {},
- } }
- var L = len(bundle.Values)
- if !(L >= 1) { panic("something went wrong") }
- var base = Expr(b)
- switch target := UnboxBundle(base.Type, ctx).(type) {
- case Bundle:
- var occurred_names = make(map[string] bool)
- var current_base = base
- for _, field := range bundle.Values {
- var name = loader.Id2String(field.Key)
- var target_field, exists = target.Fields[name]
- if !exists {
- return SemiExpr{}, &ExprError {
- Point: ctx.GetErrorPoint(field.Key.Node),
- Concrete: E_FieldDoesNotExist {
- Field: name,
- Target: ctx.DescribeType(base.Type),
- },
- }
- }
- var _, duplicate = occurred_names[name]
- if duplicate {
- return SemiExpr{}, &ExprError {
- Point: ctx.GetErrorPoint(field.Key.Node),
- Concrete: E_ExprDuplicateField { name },
- }
- }
- occurred_names[name] = true
- var value_node = DesugarOmittedFieldValue(field)
- var value_semi, err1 = Check(value_node, ctx)
- if err1 != nil { return SemiExpr{}, err1 }
- var value, err2 = AssignTo(target_field.Type, value_semi, ctx)
- if err2 != nil { return SemiExpr{}, err2 }
- current_base = Expr {
- Type: current_base.Type,
- Value: Set {
- Product: current_base,
- Index: target_field.Index,
- NewValue: value,
- },
- Info: current_base.Info,
- }
- }
- var final = current_base
- return SemiExpr {
- Value: TypedExpr(final),
- Info: info,
- }, nil
- case BR_BundleButOpaque:
- return SemiExpr{}, &ExprError {
- Point: base.Info.ErrorPoint,
- Concrete: E_SetToOpaqueBundle {},
- }
- case BR_NonBundle:
- return SemiExpr{}, &ExprError {
- Point: base.Info.ErrorPoint,
- Concrete: E_SetToNonBundle {},
- }
- default:
- panic("impossible branch")
- }
- case SemiTypedBundle:
- return SemiExpr{}, &ExprError {
- Point: ctx.GetErrorPoint(update.Base.Node),
- Concrete: E_SetToLiteralBundle {},
- }
- default:
- return SemiExpr{}, &ExprError {
- Point: ctx.GetErrorPoint(update.Base.Node),
- Concrete: E_SetToNonBundle {},
- }
- }
- default:
- var L = len(bundle.Values)
- if L == 0 {
- return LiftTyped(Expr {
- Type: AnonymousType { Unit {} },
- Value: UnitValue {},
- Info: info,
- }), nil
- } else {
- var f_exprs = make([]SemiExpr, L)
- var f_index_map = make(map[string]uint, L)
- var f_key_nodes = make([]node.Node, L)
- for i, field := range bundle.Values {
- var name = loader.Id2String(field.Key)
- var _, exists = f_index_map[name]
- if exists { return SemiExpr{}, &ExprError {
- Point: ctx.GetErrorPoint(field.Key.Node),
- Concrete: E_ExprDuplicateField { name },
- } }
- var value = DesugarOmittedFieldValue(field)
- var expr, err = Check(value, ctx)
- if err != nil { return SemiExpr{}, err }
- f_exprs[i] = expr
- f_index_map[name] = uint(i)
- f_key_nodes[i] = field.Key.Node
- }
- return SemiExpr {
- Value: SemiTypedBundle {
- Index: f_index_map,
- Values: f_exprs,
- KeyNodes: f_key_nodes,
- },
- Info: info,
- }, nil
- }
- }
- }
- func CheckGet(get node.Get, ctx ExprContext) (SemiExpr, *ExprError) {
- var base_semi, err = Check(get.Base, ctx)
- if err != nil { return SemiExpr{}, err }
- switch b := base_semi.Value.(type) {
- case TypedExpr:
- if IsBundleLiteral(Expr(b)) { return SemiExpr{}, &ExprError {
- Point: ctx.GetErrorPoint(get.Base.Node),
- Concrete: E_GetFromLiteralBundle {},
- } }
- var L = len(get.Path)
- if !(L >= 1) { panic("something went wrong") }
- var base = Expr(b)
- for _, member := range get.Path {
- switch bundle := UnboxBundle(base.Type, ctx).(type) {
- case Bundle:
- var key = loader.Id2String(member.Name)
- var field, exists = bundle.Fields[key]
- if !exists { return SemiExpr{}, &ExprError {
- Point: ctx.GetErrorPoint(member.Node),
- Concrete: E_FieldDoesNotExist {
- Field: key,
- Target: ctx.DescribeType(AnonymousType{bundle}),
- },
- } }
- var expr = Expr {
- Type: field.Type,
- Value: Get {
- Product: Expr(base),
- Index: field.Index,
- },
- Info: ctx.GetExprInfo(member.Node),
- }
- base = expr
- case BR_BundleButOpaque:
- return SemiExpr{}, &ExprError {
- Point: base.Info.ErrorPoint,
- Concrete: E_GetFromOpaqueBundle {},
- }
- case BR_NonBundle:
- return SemiExpr{}, &ExprError {
- Point: base.Info.ErrorPoint,
- Concrete: E_GetFromNonBundle {},
- }
- default:
- panic("impossible branch")
- }
- }
- var final = base
- return LiftTyped(final), nil
- case SemiTypedBundle:
- return SemiExpr{}, &ExprError {
- Point: ctx.GetErrorPoint(get.Base.Node),
- Concrete: E_GetFromLiteralBundle {},
- }
- default:
- return SemiExpr{}, &ExprError {
- Point: ctx.GetErrorPoint(get.Base.Node),
- Concrete: E_GetFromNonBundle {},
- }
- }
- }
- func AssignTupleTo(expected Type, tuple SemiTypedTuple, info ExprInfo, ctx ExprContext) (Expr, *ExprError) {
- var non_nil_expected Type
- if expected == nil {
- non_nil_expected = AnonymousType {
- Tuple {
- // Fill with nil
- Elements: make([]Type, len(tuple.Values)),
- },
- }
- } else {
- non_nil_expected = expected
- }
- switch E := non_nil_expected.(type) {
- case AnonymousType:
- switch tuple_t := E.Repr.(type) {
- case Tuple:
- var required = len(tuple_t.Elements)
- var given = len(tuple.Values)
- if given != required {
- return Expr{}, &ExprError {
- Point: info.ErrorPoint,
- Concrete: E_TupleSizeNotMatching {
- Required: required,
- Given: given,
- GivenType: ctx.DescribeType(AnonymousType { tuple_t }),
- },
- }
- }
- var typed_exprs = make([]Expr, given)
- for i, el := range tuple.Values {
- var el_expected = tuple_t.Elements[i]
- var typed, err = AssignTo(el_expected, el, ctx)
- if err != nil { return Expr{}, err }
- typed_exprs[i] = typed
- }
- return Expr {
- Type: expected,
- Info: info,
- Value: Product { typed_exprs },
- }, nil
- }
- }
- return Expr{}, &ExprError {
- Point: info.ErrorPoint,
- Concrete: E_TupleAssignedToNonTupleType {},
- }
- }
- func AssignBundleTo(expected Type, bundle SemiTypedBundle, info ExprInfo, ctx ExprContext) (Expr, *ExprError) {
- var err = RequireExplicitType(expected, info)
- if err != nil { return Expr{}, err }
- switch E := expected.(type) {
- case AnonymousType:
- switch bundle_t := E.Repr.(type) {
- case Bundle:
- var values = make([]Expr, len(bundle_t.Fields))
- for field_name, field := range bundle_t.Fields {
- var given_index, exists = bundle.Index[field_name]
- if !exists {
- return Expr{}, &ExprError {
- Point: info.ErrorPoint,
- Concrete: E_MissingField {
- Field: field_name,
- Type: ctx.DescribeType(field.Type),
- },
- }
- }
- var given_value = bundle.Values[given_index]
- var value, err = AssignTo(field.Type, given_value, ctx)
- if err != nil { return Expr{}, err }
- values[field.Index] = value
- }
- for given_field_name, index := range bundle.Index {
- var _, exists = bundle_t.Fields[given_field_name]
- if !exists {
- var key_node = bundle.KeyNodes[index]
- return Expr{}, &ExprError {
- Point: ctx.GetErrorPoint(key_node),
- Concrete: E_SurplusField { given_field_name },
- }
- }
- }
- return Expr {
- Type: expected,
- Info: info,
- Value: Product { values },
- }, nil
- }
- }
- return Expr{}, &ExprError {
- Point: info.ErrorPoint,
- Concrete: E_BundleAssignedToNonBundleType {},
- }
- }
- func IsBundleLiteral(expr Expr) bool {
- switch expr.Value.(type) {
- case Product:
- switch t := expr.Type.(type) {
- case AnonymousType:
- switch t.Repr.(type) {
- case Bundle:
- return true
- }
- }
- }
- return false
- }
- func DesugarOmittedFieldValue(field node.FieldValue) node.Expr {
- switch val_expr := field.Value.(type) {
- case node.Expr:
- return val_expr
- default:
- return node.Expr {
- Node: field.Node,
- Call: node.Call {
- Node: field.Node,
- Func: node.VariousTerm {
- Node: field.Node,
- Term: node.Ref {
- Node: field.Node,
- Module: node.Identifier {
- Node: field.Node,
- Name: []rune(""),
- },
- Specific: false,
- Id: field.Key,
- TypeArgs: make([]node.VariousType, 0),
- },
- },
- },
- }
- }
- }
|