123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212 |
- package compiler
- import (
- "strings"
- "kumachan/standalone/ctn"
- "kumachan/lang/source"
- "kumachan/lang/typsys"
- "kumachan/lang/textual/ast"
- "kumachan/interpreter/program"
- )
- type NsHeaderMap struct { Map ctn.Map[string,*Header] }
- func groupHeaders(list ([] *Header), errs *source.Errors) *NsHeaderMap {
- var m0 = ctn.MakeMutMap[string,*([]*Header)](ctn.StringCompare)
- var m1 = ctn.MakeMutMap[string,*Header](ctn.StringCompare)
- for _, hdr := range list {
- var ns = hdr.namespace
- var existing, exists = m0.Lookup(ns)
- if !(exists) {
- var ptr = new([] *Header)
- m0.Insert(ns, ptr)
- existing = ptr
- }
- *existing = append(*existing, hdr)
- }
- m0.ForEach(func(ns string, ptr *([]*Header)) {
- m1.Insert(ns, mergeNsHeaders(ns, *ptr, errs))
- })
- return &NsHeaderMap { Map: m1.Map() }
- }
- func mergeNsHeaders(ns string, list ([] *Header), errs *source.Errors) *Header {
- var all_als_ns = ctn.MakeMutMap[string,*aliasTarget[string]](ctn.StringCompare)
- var all_als_ref = ctn.MakeMutMap[string,*aliasTarget[source.Ref]](ctn.StringCompare)
- var all_types = ctn.MakeMutMap[string,*typsys.TypeDef](ctn.StringCompare)
- var all_user = ctn.MakeMutMap[string,ctn.Map[string,*funHeader]](ctn.StringCompare)
- var all_gen = ctn.MakeMutMap[genFunKey,*funHeader](genFunKeyCompare)
- for _, hdr := range list {
- if hdr.namespace != ns {
- panic("invalid arguments")
- }
- hdr.nsAliasMap.ForEach(func(name string, item *aliasTarget[string]) {
- var _, duplicate = all_als_ns.Lookup(name)
- if duplicate {
- var loc = item.Location
- source.ErrorsJoin(errs, source.MakeError(loc,
- E_DuplicateAlias { Name: name }))
- } else {
- all_als_ns.Insert(name, item)
- }
- })
- hdr.refAliasMap.ForEach(func(name string, item *aliasTarget[source.Ref]) {
- var _, duplicate = all_als_ref.Lookup(name)
- if duplicate {
- var loc = item.Location
- source.ErrorsJoin(errs, source.MakeError(loc,
- E_DuplicateAlias { Name: name }))
- } else {
- all_als_ref.Insert(name, item)
- }
- })
- hdr.typeMap.ForEach(func(name string, item *typsys.TypeDef) {
- var _, duplicate = all_types.Lookup(name)
- if duplicate {
- var loc = item.Info.Location
- source.ErrorsJoin(errs, source.MakeError(loc,
- E_DuplicateTypeDecl { Name: name }))
- } else {
- all_types.Insert(name, item)
- }
- })
- hdr.userFunMap.ForEach(func(name string, items ctn.Map[string,*funHeader]) {
- var group = (func() ctn.Map[string, *funHeader] {
- var group, exists = all_user.Lookup(name)
- if exists {
- return group
- } else {
- return ctn.MakeMap[string,*funHeader](ctn.StringCompare)
- }
- })()
- items.ForEach(func(assoc string, item *funHeader) {
- var duplicate = group.Has(assoc)
- if duplicate {
- var loc = item.funInfo.Location
- source.ErrorsJoin(errs, source.MakeError(loc,
- E_DuplicateFunDecl { Name: name, Assoc: assoc }))
- } else {
- group = group.Inserted(assoc, item)
- }
- })
- all_user.Insert(name, group)
- })
- hdr.genFunMap.ForEach(func(key genFunKey, item *funHeader) {
- all_gen.Insert(key, item)
- })
- }
- return &Header {
- namespace: ns,
- nsAliasMap: all_als_ns.Map(),
- refAliasMap: all_als_ref.Map(),
- typeMap: all_types.Map(),
- userFunMap: all_user.Map(),
- genFunMap: all_gen.Map(),
- }
- }
- func (ctx *NsHeaderMap) FindType(ref source.Ref) (*typsys.TypeDef, bool) {
- return ctx.lookupType(ref)
- }
- func (ctx *NsHeaderMap) generateTypeInfo() program.TypeInfo {
- var reg = make(map[source.Ref] *typsys.TypeDef)
- ctx.Map.ForEach(func(ns string, hdr *Header) {
- hdr.typeMap.ForEach(func(name string, def *typsys.TypeDef) {
- var ref = source.MakeRef(ns, name)
- reg[ref] = def
- })
- })
- return program.TypeInfo {
- TypeRegistry: reg,
- }
- }
- func (ctx* NsHeaderMap) tryRedirectRef(ns string, ref *source.Ref) bool {
- if hdr, ok := ctx.Map.Lookup(ns); ok {
- if target, ok := hdr.nsAliasMap.Lookup(ref.Namespace); ok {
- if target.Valid {
- *ref = source.MakeRef(target.Target, ref.ItemName)
- return true
- }}
- if ref.Namespace == "" {
- if target, ok := hdr.refAliasMap.Lookup(ref.ItemName); ok {
- if target.Valid {
- *ref = target.Target
- return true
- }}
- }
- }
- if ns != "" {
- if ref.Namespace == "" {
- *ref = source.MakeRef(ns, ref.ItemName)
- return true
- }
- }
- return false
- }
- func (ctx *NsHeaderMap) lookupType(ref source.Ref) (*typsys.TypeDef, bool) {
- if hdr, ok := ctx.Map.Lookup(ref.Namespace); ok {
- if def, ok := hdr.typeMap.Lookup(ref.ItemName); ok {
- return def, true
- }}
- return nil, false
- }
- func (ctx *NsHeaderMap) lookupMethod(recv_ref source.Ref, name string) (*funHeader, bool) {
- if hdr, ok := ctx.Map.Lookup(recv_ref.Namespace); ok {
- if group, ok := hdr.userFunMap.Lookup(name); ok {
- if f, ok := group.Lookup(recv_ref.ItemName); ok {
- if f.funKind == FK_Method {
- return f, true
- }
- }}}
- return nil, false
- }
- func (ctx *NsHeaderMap) lookupExactFunction(ref source.Ref, assoc string, kind FunKind) (*funHeader, string, userFunKey, bool) {
- if hdr, ok := ctx.Map.Lookup(ref.Namespace); ok {
- if group, ok := hdr.userFunMap.Lookup(ref.ItemName); ok {
- if f, ok := group.Lookup(assoc); ok {
- if f.funKind == kind {
- var ns = ref.Namespace
- var key = userFunKey {
- name: ref.ItemName,
- assoc: assoc,
- }
- return f, ns, key, true
- }
- }}}
- return nil, "", userFunKey{}, false
- }
- func (ctx *NsHeaderMap) lookupFunction(ref source.Ref, r0 ctn.Maybe[source.Ref], kind FunKind) (*funHeader, string, userFunKey, bool) {
- if r0, ok := r0.Value(); ok {
- var ns, item = ref.Namespace, ref.ItemName
- var NS, A = r0.Namespace, r0.ItemName
- if ((NS != "") && (ns == "")) {
- if f, ns, key, ok := ctx.lookupExactFunction(ref, "", kind); ok {
- return f, ns, key, true
- }
- return ctx.lookupExactFunction(source.MakeRef(NS, item), A, kind)
- }
- if (NS == ns) {
- if f, ns, key, ok := ctx.lookupExactFunction(ref, A, kind); ok {
- return f, ns, key, true
- }
- return ctx.lookupExactFunction(ref, "", kind)
- }
- }
- return ctx.lookupExactFunction(ref, "", kind)
- }
- func (ctx *NsHeaderMap) lookupAssignableKindFunctions(ref source.Ref) ([] func()(*funHeader,string,userFunKey)) {
- var ns = ref.Namespace
- var name = ref.ItemName
- var list = make([] func()(*funHeader,string,userFunKey), 0)
- if hdr, ok := ctx.Map.Lookup(ns); ok {
- if group, ok := hdr.userFunMap.Lookup(name); ok {
- group.ForEach(func(assoc string, f *funHeader) {
- if isAssignableKindFunction(f) {
- list = append(list, func() (*funHeader, string, userFunKey) {
- var key = userFunKey { name: name, assoc: assoc }
- return f, ns, key
- })
- }
- })
- }}
- return list
- }
- type Header struct {
- namespace string
- nsAliasMap ctn.Map[string, *aliasTarget[string]]
- refAliasMap ctn.Map[string, *aliasTarget[source.Ref]]
- typeMap ctn.Map[string, *typsys.TypeDef]
- userFunMap ctn.Map[string, ctn.Map[string, *funHeader]]
- genFunMap ctn.Map[genFunKey, *funHeader]
- }
- type aliasTarget[T any] struct {
- Valid bool
- Target T
- Location source.Location
- }
- type funHeader struct {
- funKind FunKind
- funInfo FunInfo
- variadic bool
- typeParams [] string
- output funOutput
- inputsExplicit *typsys.Fields
- inputsImplicit *typsys.Fields
- }
- type funOutput struct {
- type_ typsys.Type
- loc source.Location
- }
- type FunKind int
- const (
- FK_Generated FunKind = iota
- FK_Ordinary
- FK_Operator
- FK_Method
- FK_Const
- FK_Entry
- )
- type FunInfo struct {
- Location source.Location
- Document string
- }
- func isAssignableKindFunction(f *funHeader) bool {
- switch f.funKind {
- case FK_Ordinary, FK_Operator, FK_Const:
- return true
- }
- return false
- }
- func someFunctionKindAssignable(group ctn.Map[string,*funHeader]) bool {
- var result = false
- group.ForEach(func(_ string, f *funHeader) {
- result = (result || isAssignableKindFunction(f))
- })
- return result
- }
- type genFunKey struct {
- typeName string
- funName string
- fieldName string
- }
- func (key genFunKey) Describe(ns string) string {
- var elements = [] string { ns, key.typeName, key.funName, key.fieldName }
- var buf strings.Builder
- buf.WriteRune('[')
- buf.WriteString(strings.Join(elements, ","))
- buf.WriteRune(']')
- return buf.String()
- }
- func genFunKeyCompare(a genFunKey, b genFunKey) ctn.Ordering {
- var o = ctn.StringCompare(a.typeName, b.typeName)
- if o != ctn.Equal {
- return o
- } else {
- var o = ctn.StringCompare(a.funName, b.funName)
- if o != ctn.Equal {
- return o
- } else {
- return ctn.StringCompare(a.fieldName, b.fieldName)
- }
- }
- }
- func analyze(root *ast.Root, errs *source.Errors) (*Header,*Impl) {
- var ns = ast.MaybeId2String(root.Namespace)
- var als_ns = ctn.MakeMutMap[string,*aliasTarget[string]](ctn.StringCompare)
- var als_ref = ctn.MakeMutMap[string,*aliasTarget[source.Ref]](ctn.StringCompare)
- var types = ctn.MakeMutMap[string,*typsys.TypeDef](ctn.StringCompare)
- var types_gen = ctn.MakeMutMap[string,generatedConstList](ctn.StringCompare)
- var user_hdr = ctn.MakeMutMap[string,ctn.Map[string,*funHeader]](ctn.StringCompare)
- var user_impl = ctn.MakeMutMap[userFunKey,funImpl](userFunKeyCompare)
- var user_gen = ctn.MakeMutMap[userFunKey,generatedConstList](userFunKeyCompare)
- var gen_hdr = ctn.MakeMutMap[genFunKey,*funHeader](genFunKeyCompare)
- var gen_impl = ctn.MakeMutMap[genFunKey,funImpl](genFunKeyCompare)
- for _, alias := range root.Aliases {
- if alias.Off {
- continue
- }
- var loc = alias.Location
- switch T := alias.Target.AliasTarget.(type) {
- case ast.AliasToNamespace:
- var target = ast.Id2String(T.Namespace)
- var name = ast.MaybeId2String(alias.Name)
- var duplicate = als_ns.Has(name)
- if duplicate {
- source.ErrorsJoin(errs, source.MakeError(loc,
- E_DuplicateAlias {
- Name: name,
- }))
- continue
- }
- als_ns.Insert(name, &aliasTarget[string] {
- Valid: true,
- Target: target,
- Location: loc,
- })
- case ast.AliasToRefBase:
- var target = getRef(T.RefBase)
- var name = (func() string {
- if name := ast.MaybeId2String(alias.Name); name != "" {
- return name
- } else {
- return target.ItemName
- }
- })()
- var duplicate = als_ref.Has(name)
- if duplicate {
- source.ErrorsJoin(errs, source.MakeError(loc,
- E_DuplicateAlias {
- Name: name,
- }))
- continue
- }
- als_ref.Insert(name, &aliasTarget[source.Ref] {
- Valid: true,
- Target: target,
- Location: loc,
- })
- default:
- panic("impossible branch")
- }
- }
- var pm = makeParamMapping(root.Statements)
- for _, stmt := range root.Statements {
- switch S := stmt.Statement.(type) {
- case ast.DeclType:
- if S.Off {
- continue
- }
- var name = ast.Id2String(S.Name)
- if types.Has(name) {
- source.ErrorsJoin(errs, source.MakeError(S.Location,
- E_DuplicateTypeDecl {
- Name: name,
- }))
- continue
- }
- var loc = S.Location
- var doc = ast.GetDocContent(S.Docs)
- var info = typsys.Info { Location: loc, Document: doc }
- var ref = source.MakeRef(ns, name)
- var ifs = ctn.MapEach(S.Implements, getRef)
- var params = ctn.MapEach(S.TypeParams, ast.Id2String)
- var ctx = createTypeConsContext(params)
- var gen = make(generatedConstList, 0)
- var content = makeTypeDefContent(S.TypeDef, ctx, &gen, errs)
- types_gen.Insert(name, gen)
- types.Insert(name, &typsys.TypeDef {
- Info: info,
- Ref: ref,
- Interfaces: ifs,
- Parameters: params,
- Content: content,
- })
- default:
- var u = unifyFunDecl(S, pm, ns)
- if u.off {
- continue
- }
- var name = ast.Id2String(u.name)
- var group = (func() ctn.Map[string, *funHeader] {
- var group, exists = user_hdr.Lookup(name)
- if exists {
- return group
- } else {
- return ctn.MakeMap[string,*funHeader](ctn.StringCompare)
- }
- })()
- var params = ctn.MapEach(u.sig.TypeParams, ast.Id2String)
- var ctx = createTypeConsContext(params)
- var kind = u.kind
- var assoc = getAssocTypeName(u.sig.Inputs, kind, ns, ctx)
- var duplicate = group.Has(assoc)
- if duplicate {
- source.ErrorsJoin(errs, source.MakeError(u.loc,
- E_DuplicateFunDecl {
- Name: name,
- Assoc: assoc,
- }))
- continue
- }
- var key = userFunKey { name: name, assoc: assoc }
- var impl = u.impl
- var loc = u.loc
- var doc = ast.GetDocContent(u.doc)
- var info = FunInfo { Location: loc, Document: doc }
- var va = u.va
- var gen = make(generatedConstList, 0)
- var in_exp_ = u.sig.Inputs
- var in_imp_ = u.sig.Implicit
- var in_exp = makeFunInputFields(in_exp_, nil, ctx, &gen, errs)
- var in_imp = makeFunInputFields(in_imp_, in_exp, ctx, &gen, errs)
- var out_t = makeType(u.sig.Output, ctx)
- var out = funOutput { type_: out_t, loc: u.sig.Output.Location }
- user_gen.Insert(key, gen)
- user_hdr.Insert(name, group.Inserted(assoc, &funHeader {
- funKind: kind,
- funInfo: info,
- variadic: va,
- typeParams: params,
- output: out,
- inputsExplicit: in_exp,
- inputsImplicit: in_imp,
- }))
- user_impl.Insert(key, impl)
- }
- }
- types_gen.ForEach(func(src_type_name string, list generatedConstList) {
- var params = (func() ([] string) {
- var src_type_def, ok = types.Lookup(src_type_name)
- if !(ok) { panic("something went wrong") }
- return src_type_def.Parameters
- })()
- list.consume(params, func(item_name string, item_hdr *funHeader, item_impl funImpl) {
- var key = genFunKey {
- typeName: src_type_name,
- fieldName: item_name,
- }
- if gen_hdr.Has(key) { panic("something went wrong") }
- gen_hdr.Insert(key, item_hdr)
- gen_impl.Insert(key, item_impl)
- })
- })
- user_gen.ForEach(func(fun_key userFunKey, list generatedConstList) {
- var params = (func() ([] string) {
- var group = (func() ctn.Map[string, *funHeader] {
- var group, ok = user_hdr.Lookup(fun_key.name)
- if !(ok) { panic("something went wrong") }
- return group
- })()
- var f_hdr, ok = group.Lookup(fun_key.assoc)
- if !(ok) { panic("something went wrong") }
- return f_hdr.typeParams
- })()
- list.consume(params, func(item_name string, item_hdr *funHeader, item_impl funImpl) {
- var key = genFunKey {
- funName: fun_key.name,
- typeName: fun_key.assoc,
- fieldName: item_name,
- }
- if gen_hdr.Has(key) { panic("something went wrong") }
- gen_hdr.Insert(key, item_hdr)
- gen_impl.Insert(key, item_impl)
- })
- })
- var hdr = &Header {
- namespace: ns,
- nsAliasMap: als_ns.Map(),
- refAliasMap: als_ref.Map(),
- typeMap: types.Map(),
- userFunMap: user_hdr.Map(),
- genFunMap: gen_hdr.Map(),
- }
- var impl = &Impl {
- namespace: ns,
- userFunMap: user_impl.Map(),
- genFunMap: gen_impl.Map(),
- }
- return hdr, impl
- }
- type generatedConst struct {
- name string
- val funImpl
- typ typsys.Type
- loc source.Location
- doc string
- }
- type generatedConstList ([] generatedConst)
- func (list generatedConstList) consume(params ([] string), k func(string,*funHeader,funImpl)) {
- for _, item := range list {
- var info = FunInfo {
- Location: item.loc,
- Document: item.doc,
- }
- var out = funOutput {
- type_: item.typ,
- loc: item.loc,
- }
- var item_hdr = &funHeader {
- funKind: FK_Generated,
- funInfo: info,
- typeParams: params,
- output: out,
- inputsExplicit: &typsys.Fields {},
- inputsImplicit: &typsys.Fields {},
- }
- var item_impl = item.val
- k(item.name, item_hdr, item_impl)
- }
- }
- func checkHeader(hdr *Header, ctx *NsHeaderMap, errs *source.Errors) {
- validateAlterHeaderAliases(hdr, ctx, errs)
- validateAlterHeaderTypes(hdr, ctx, errs)
- validateHeaderFunctions(hdr, ctx, errs)
- }
- func validateAlterHeaderAliases(hdr *Header, ctx *NsHeaderMap, errs *source.Errors) {
- var hasRelevantRef = func(ref source.Ref) bool {
- if ref_hdr, ok := ctx.Map.Lookup(ref.Namespace); ok {
- if ref_hdr.typeMap.Has(ref.ItemName) {
- return true
- }
- if group, ok := ref_hdr.userFunMap.Lookup(ref.ItemName); ok {
- if someFunctionKindAssignable(group) {
- return true
- }}
- }
- return false
- }
- var setInvalidAndThrow = func(valid *bool, err *source.Error) {
- *valid = false
- source.ErrorsJoin(errs, err)
- }
- hdr.nsAliasMap.ForEach(func(name string, target *aliasTarget[string]) {
- var v, loc = &(target.Valid), target.Location
- if ctx.Map.Has(name) {
- setInvalidAndThrow(v, source.MakeError(loc,
- E_InvalidAlias {
- Name: name,
- }))
- }
- if !(ctx.Map.Has(target.Target)) {
- setInvalidAndThrow(v, source.MakeError(loc,
- E_AliasTargetNotFound {
- Target: ("namespace " + target.Target),
- }))
- }
- })
- hdr.refAliasMap.ForEach(func(name string, target *aliasTarget[source.Ref]) {
- var v, loc = &(target.Valid), target.Location
- if hasRelevantRef(source.MakeRef("", name)) {
- setInvalidAndThrow(v, source.MakeError(loc,
- E_InvalidAlias {
- Name: name,
- }))
- }
- if !(hasRelevantRef(target.Target)) {
- setInvalidAndThrow(v, source.MakeError(loc,
- E_AliasTargetNotFound {
- Target: target.Target.String(),
- }))
- }
- })
- }
- func validateAlterHeaderTypes(hdr *Header, ctx *NsHeaderMap, errs *source.Errors) {
- var ns = hdr.namespace
- var validateAlterSingleType = func(t *typsys.Type, loc source.Location) {
- var err = validateAlterType(t, loc, ns, ctx)
- source.ErrorsJoin(errs, err)
- }
- var validateAlterFieldTypes = func(fields *typsys.Fields) {
- for i := range fields.FieldList {
- var field = &(fields.FieldList[i])
- if field.Type != nil {
- var loc = field.Info.Location
- var field_t = &(field.Type)
- validateAlterSingleType(field_t, loc)
- }
- }
- }
- hdr.typeMap.ForEach(func(_ string, def *typsys.TypeDef) {
- for i := range def.Interfaces {
- var ref = &(def.Interfaces[i])
- var loc = def.Info.Location
- var err = validateAlterInterfaceTypeRef(ref, loc, ns, ctx)
- source.ErrorsJoin(errs, err)
- }
- var fields, ok = (func() (*typsys.Fields, bool) {
- switch content := def.Content.(type) {
- case typsys.Record: return content.Fields, true
- case typsys.Union: return content.Fields, true
- case typsys.Interface: return content.Fields, true
- default: return nil, false
- }
- })()
- if ok {
- validateAlterFieldTypes(fields)
- }
- })
- hdr.userFunMap.ForEach(func(_ string, group ctn.Map[string,*funHeader]) {
- group.ForEach(func(_ string, f *funHeader) {
- validateAlterFieldTypes(f.inputsExplicit)
- validateAlterFieldTypes(f.inputsImplicit)
- validateAlterSingleType(&(f.output.type_), f.output.loc)
- })})
- hdr.genFunMap.ForEach(func(_ genFunKey, f *funHeader) {
- validateAlterFieldTypes(f.inputsExplicit)
- validateAlterFieldTypes(f.inputsImplicit)
- validateAlterSingleType(&(f.output.type_), f.output.loc)
- })
- }
- func validateAlterType(t *typsys.Type, loc source.Location, ns string, ctx *NsHeaderMap) *source.Error {
- var first_error *source.Error = nil
- var throw = func(err *source.Error) {
- if first_error == nil {
- first_error = err
- }
- }
- *t = typsys.Transform(*t, func(t typsys.Type) (typsys.Type, bool) {
- if ref_type, ok := t.(typsys.RefType); ok {
- var ref = ref_type.Def
- var def, exists = ctx.lookupType(ref)
- var ref_altered = false
- if !(exists) {
- if ctx.tryRedirectRef(ns, &ref) {
- ref_altered = true
- def, exists = ctx.lookupType(ref)
- }
- }
- if !(exists) {
- throw(source.MakeError(loc,
- E_NoSuchType {
- ref.String(),
- }))
- return program.T_InvalidType(), true
- }
- var required = len(def.Parameters)
- var given = len(ref_type.Args)
- if given != required {
- throw(source.MakeError(loc,
- E_TypeArgsWrongQuantity {
- Type: ref.String(),
- Given: given,
- Required: required,
- }))
- return program.T_InvalidType(), true
- }
- if ref_altered {
- return typsys.RefType {
- Def: ref,
- Args: ref_type.Args,
- }, true
- }
- }
- return nil, false
- })
- return first_error
- }
- func validateAlterInterfaceTypeRef(ref *source.Ref, loc source.Location, ns string, ctx *NsHeaderMap) *source.Error {
- // NOTE: this function requires T_InvalidType to be an interface type
- var def, exists = ctx.lookupType(*ref)
- if !(exists) {
- if ctx.tryRedirectRef(ns, ref) {
- def, exists = ctx.lookupType(*ref)
- }
- }
- if !(exists) {
- var err = source.MakeError(loc, E_NoSuchType { (*ref).String() })
- *ref = program.T_InvalidType().(typsys.RefType).Def
- return err
- }
- var _, ok = def.Content.(typsys.Interface)
- if !(ok) {
- var err = source.MakeError(loc, E_NotInterface { (*ref).String() })
- *ref = program.T_InvalidType().(typsys.RefType).Def
- return err
- }
- return nil
- }
- func validateHeaderFunctions(hdr *Header, ctx *NsHeaderMap, errs *source.Errors) {
- hdr.userFunMap.ForEach(func(name string, group ctn.Map[string,*funHeader]) {
- group.ForEach(func(assoc string, f *funHeader) {
- if f.funKind == FK_Method {
- var ns = hdr.namespace
- var type_ref = source.MakeRef(ns, assoc)
- if def, ok := ctx.lookupType(type_ref); ok {
- var conflict = (func() bool {
- if R, ok := def.Content.(typsys.Record); ok {
- var _, conflict = R.FieldIndexMap[name]
- return conflict
- }
- if I, ok := def.Content.(typsys.Interface); ok {
- var _, conflict = I.FieldIndexMap[name]
- return conflict
- }
- return false
- })()
- if conflict {
- var err = source.MakeError(f.funInfo.Location,
- E_MethodNameUnavailable {
- Name: name,
- })
- source.ErrorsJoin(errs, err)
- }
- }
- }
- if f.funKind == FK_Operator {
- var in_exp = f.inputsExplicit.FieldList
- if len(in_exp) == 0 {
- var loc = f.funInfo.Location
- source.ErrorsJoin(errs, source.MakeError(loc,
- E_MissingOperatorParameter {}))
- } else if in_exp[0].Info.HasDefaultValue {
- var loc = f.funInfo.Location
- source.ErrorsJoin(errs, source.MakeError(loc,
- E_OperatorFirstParameterHasDefaultValue {}))
- }
- }
- if f.variadic {
- var in_exp = f.inputsExplicit.FieldList
- var arity = len(in_exp)
- if arity == 0 {
- var loc = f.funInfo.Location
- source.ErrorsJoin(errs, source.MakeError(loc,
- E_MissingVariadicParameter {}))
- } else {
- var last_index = (arity - 1)
- var last = in_exp[last_index]
- if _, ok := program.T_List_(last.Type); ok {
- // OK
- } else {
- var loc = f.funInfo.Location
- source.ErrorsJoin(errs, source.MakeError(loc,
- E_InvalidVariadicParameter {}))
- }
- }
- }
- for _, imp_field := range f.inputsImplicit.FieldList {
- if P, _, ok := ast.SplitImplicitRef(imp_field.Name); ok {
- var ok = false
- for _, p := range f.typeParams {
- if p == P {
- ok = true
- break
- }
- }
- if !(ok) {
- var loc = imp_field.Info.Location
- source.ErrorsJoin(errs, source.MakeError(loc,
- E_NoSuchTypeParameter { P }))
- }
- }
- }
- })})
- }
- type typeConsContext struct {
- parameters map[string] struct{}
- }
- func createTypeConsContext(params ([] string)) *typeConsContext {
- return &typeConsContext {
- parameters: (func() (map[string] struct{}) {
- var set = make(map[string] struct{})
- for _, p := range params {
- set[p] = struct{}{}
- }
- return set
- })(),
- }
- }
- func (ctx *typeConsContext) hasTypeParameter() bool {
- return (len(ctx.parameters) > 0)
- }
- func (ctx *typeConsContext) isTypeParameter(name string) bool {
- var _, is_parameter = ctx.parameters[name]
- return is_parameter
- }
- func makeType(t ast.Type, ctx *typeConsContext) typsys.Type {
- var param_name, is_param = getTypeParamName(t.Ref.Base, ctx)
- if is_param {
- return typsys.ParameterType {
- Name: param_name,
- }
- } else {
- var def_ref = getRef(t.Ref.Base)
- var args = make([] typsys.Type, len(t.Ref.TypeArgs))
- for i := range t.Ref.TypeArgs {
- args[i] = makeType(t.Ref.TypeArgs[i], ctx)
- }
- return typsys.RefType {
- Def: def_ref,
- Args: args,
- }
- }
- }
- func makeTypeDefContent (
- content ast.VariousTypeDef,
- ctx *typeConsContext,
- gen *generatedConstList,
- errs *source.Errors,
- ) typsys.TypeDefContent {
- type fieldNode struct {
- loc source.Location
- doc [] ast.Doc
- name ast.Identifier
- type_ ctn.Maybe[ast.Type]
- dv ast.MaybeExpr
- }
- var collect = func(kind string, nodes ([] fieldNode)) typsys.Fields {
- var fields = make([] typsys.Field, len(nodes))
- var index = make(map[string] int)
- for i, node := range nodes {
- var name = ast.Id2String(node.name)
- if !(isValidFieldName(name)) {
- source.ErrorsJoin(errs, source.MakeError(
- node.loc,
- E_InvalidFieldName {
- FieldKind: kind,
- FieldName: name,
- },
- ))
- continue
- }
- if _, duplicate := index[name]; duplicate {
- source.ErrorsJoin(errs, source.MakeError(
- node.loc,
- E_DuplicateField {
- FieldKind: kind,
- FieldName: name,
- },
- ))
- continue
- }
- var loc = node.loc
- var doc = ast.GetDocContent(node.doc)
- var type_ typsys.Type
- if type_node, ok := node.type_.Value(); ok {
- type_ = makeType(type_node, ctx)
- }
- var default_, has_default = node.dv.(ast.Expr)
- if has_default {
- *gen = append(*gen, generatedConst {
- name: name,
- val: funImplAstExpr { default_ },
- typ: type_,
- loc: default_.Location,
- doc: "",
- })
- }
- var info = typsys.FieldInfo {
- Info: typsys.Info { Location: loc, Document: doc },
- HasDefaultValue: has_default,
- }
- fields[i] = typsys.Field {
- Info: info,
- Name: name,
- Type: type_,
- }
- index[name] = i
- }
- return typsys.Fields {
- FieldIndexMap: index,
- FieldList: fields,
- }
- }
- switch C := content.TypeDef.(type) {
- case ast.Record:
- var nodes = ctn.MapEach(C.Def.Fields, func(raw ast.Field) fieldNode {
- return fieldNode {
- loc: raw.Location,
- doc: raw.Docs,
- name: raw.Name,
- type_: ctn.Just(raw.Type),
- dv: raw.Default,
- }
- })
- var fields = collect("field", nodes)
- return typsys.Record {
- Fields: &fields,
- }
- case ast.Interface:
- var nodes = ctn.MapEach(C.Methods, func(raw ast.Method) fieldNode {
- return fieldNode {
- loc: raw.Location,
- doc: raw.Docs,
- name: raw.Name,
- type_: ctn.Just(raw.Type),
- dv: nil,
- }
- })
- var methods = collect("method", nodes)
- return typsys.Interface {
- Fields: &methods,
- }
- case ast.Union:
- var nodes = make([] fieldNode, 0)
- for _, item := range C.Items {
- nodes = append(nodes, fieldNode {
- loc: item.Location,
- doc: nil,
- name: item.Ref.Base.Item,
- type_: ctn.Just(item),
- dv: nil,
- })
- }
- var items = collect("item", nodes)
- return typsys.Union {
- Fields: &items,
- }
- case ast.Enum:
- if ctx.hasTypeParameter() {
- source.ErrorsJoin(errs, source.MakeError(
- content.Location,
- E_GenericEnum {},
- ))
- }
- var nodes = make([] fieldNode, 0)
- for _, item := range C.Items {
- nodes = append(nodes, fieldNode {
- loc: item.Location,
- doc: item.Docs,
- name: item.Name,
- type_: nil,
- dv: nil,
- })
- }
- var items = collect("item", nodes)
- return typsys.Enum {
- Fields: &items,
- }
- case ast.NativeTypeDef:
- return typsys.NativeContent {}
- default:
- panic("impossible branch")
- }
- }
- func makeFunInputFields (
- inputs ast.MaybeInputs,
- saved *typsys.Fields,
- ctx *typeConsContext,
- gen *generatedConstList,
- errs *source.Errors,
- ) *typsys.Fields {
- if inputs, ok := inputs.(ast.Inputs); ok {
- var nodes = inputs.Content.Fields
- var fields = make([] typsys.Field, len(nodes))
- var index = make(map[string] int)
- for i, node := range nodes {
- var name = ast.Id2String(node.Name)
- if !(isValidFieldName(name)) {
- source.ErrorsJoin(errs, source.MakeError(
- node.Location,
- E_InvalidFieldName {
- FieldKind: "input",
- FieldName: name,
- },
- ))
- continue
- }
- var _, duplicate = index[name]
- if !(duplicate) {
- if saved != nil {
- _, duplicate = saved.FieldIndexMap[name]
- }
- }
- if duplicate {
- source.ErrorsJoin(errs, source.MakeError(
- node.Location,
- E_DuplicateField {
- FieldKind: "input",
- FieldName: name,
- },
- ))
- continue
- }
- var loc = node.Location
- var doc = ast.GetDocContent(node.Docs)
- var type_ = makeType(node.Type, ctx)
- var default_, has_default = node.Default.(ast.Expr)
- if has_default {
- *gen = append(*gen, generatedConst {
- name: name,
- val: funImplAstExpr { default_ },
- typ: type_,
- loc: default_.Location,
- doc: "",
- })
- }
- var info = typsys.FieldInfo {
- Info: typsys.Info { Location: loc, Document: doc },
- HasDefaultValue: has_default,
- }
- fields[i] = typsys.Field {
- Info: info,
- Name: name,
- Type: type_,
- }
- index[name] = i
- }
- return &typsys.Fields {
- FieldIndexMap: index,
- FieldList: fields,
- }
- } else {
- return &typsys.Fields {}
- }
- }
- func getTypeParamName(rb ast.RefBase, ctx *typeConsContext) (string, bool) {
- var _, ns_specified = rb.NS.(ast.Identifier)
- var ns_not_specified = !(ns_specified)
- var item_name = ast.Id2String(rb.Item)
- if ns_not_specified && ctx.isTypeParameter(item_name) {
- return item_name, true
- } else {
- return "", false
- }
- }
- func getRef(rb ast.RefBase) source.Ref {
- var ns = ast.MaybeId2String(rb.NS)
- var item = ast.Id2String(rb.Item)
- return source.MakeRef(ns, item)
- }
- func isValidFieldName(name string) bool {
- return (name != Underscore)
- }
- const This = "this"
- type unifiedFunDecl struct {
- kind FunKind
- va bool
- name ast.Identifier
- sig ast.FunctionSignature
- loc source.Location
- doc [] ast.Doc
- off bool
- impl funImpl
- }
- type paramMapping (map[string] ([] ast.Identifier))
- func makeParamMapping(stmts ([] ast.VariousStatement)) paramMapping {
- var pm = make(paramMapping)
- for _, stmt := range stmts {
- switch S := stmt.Statement.(type) {
- case ast.DeclType:
- var name = ast.Id2String(S.Name)
- var _, exists = pm[name]
- if !(exists) {
- pm[name] = S.TypeParams
- }
- }
- }
- return pm
- }
- func unifyFunDecl(stmt ast.Statement, pm paramMapping, ns string) *unifiedFunDecl {
- switch S := stmt.(type) {
- case ast.DeclFunction:
- var kind = (func() FunKind {
- if S.Operator {
- return FK_Operator
- } else {
- return FK_Ordinary
- }
- })()
- return &unifiedFunDecl {
- kind: kind,
- va: S.Variadic,
- name: S.Name,
- sig: S.Signature,
- loc: S.Location,
- doc: S.Docs,
- off: S.Off,
- impl: funImplFromAstBody(S.Body),
- }
- case ast.DeclConst:
- var sig = ast.FunctionSignature {
- Node: S.Type.Node,
- Output: S.Type,
- }
- return &unifiedFunDecl {
- kind: FK_Const,
- name: S.Name,
- sig: sig,
- loc: S.Location,
- doc: S.Docs,
- off: S.Off,
- impl: funImplFromAstBody(S.Body),
- }
- case ast.DeclMethod:
- var recv = S.Receiver
- var recv_type, recv_params = getReceiverTypeAndParams(recv, pm, ns)
- var recv_inputs = getReceiverInputs(recv_type)
- var sig = ast.FunctionSignature {
- Node: S.Node,
- TypeParams: recv_params,
- Inputs: recv_inputs,
- Output: S.Type,
- }
- return &unifiedFunDecl {
- kind: FK_Method,
- name: S.Name,
- sig: sig,
- loc: S.Location,
- doc: S.Docs,
- off: S.Off,
- impl: funImplFromAstBody(S.Body),
- }
- case ast.DeclEntry:
- var empty = ast.String2Id("", S.Node)
- var expr = ast.WrapBlockAsExpr(S.Content)
- var ob_null_t = program.AT_Observable(program.AT_Null())(S.Node)
- var sig = ast.FunctionSignature {
- Node: S.Node,
- Output: ob_null_t,
- }
- return &unifiedFunDecl {
- kind: FK_Entry,
- name: empty,
- sig: sig,
- loc: S.Location,
- doc: S.Docs,
- off: S.Off,
- impl: funImplAstExpr { expr },
- }
- // case ast.DeclAsset:
- // var name = ast.String2Id(S.Name, S.Node)
- // var path = S.Content.Path
- // var data = S.Content.Data
- // var asset_t = program.AT_Asset()(S.Node)
- // var sig = ast.FunctionSignature {
- // Node: S.Node,
- // Output: asset_t,
- // }
- // return &unifiedFunDecl {
- // kind: FK_Const,
- // name: name,
- // sig: sig,
- // loc: S.Location,
- // impl: funImplLoadedAsset { path, data },
- // }
- default:
- panic("impossible branch")
- }
- }
- func getReceiverTypeAndParams(recv ast.Identifier, pm paramMapping, ns string) (ast.Type, ([] ast.Identifier)) {
- var recv_name = ast.Id2String(recv)
- var recv_params = pm[recv_name]
- var recv_type = ast.Type {
- Node: recv.Node,
- Ref: ast.Ref {
- Node: recv.Node,
- Base: ast.RefBase {
- Node: recv.Node,
- NS: ast.String2Id(ns, recv.Node),
- Item: recv,
- },
- TypeArgs: ctn.MapEach(recv_params, func(param ast.Identifier) ast.Type {
- return ast.Type {
- Node: param.Node,
- Ref: ast.Ref {
- Node: param.Node,
- Base: ast.RefBase {
- Node: param.Node,
- Item: param,
- },
- },
- }
- }),
- },
- }
- return recv_type, recv_params
- }
- func getReceiverInputs(recv_type ast.Type) ast.Inputs {
- var content = ast.RecordDef {
- Node: recv_type.Node,
- Fields: [] ast.Field { {
- Node: recv_type.Node,
- Name: ast.String2Id(This, recv_type.Node),
- Type: recv_type,
- } },
- }
- return ast.Inputs {
- Node: recv_type.Node,
- Content: content,
- }
- }
- func getAssocTypeName(inputs ast.Inputs, kind FunKind, ns string, ctx *typeConsContext) string {
- switch kind {
- case FK_Operator, FK_Method:
- var fields = inputs.Content.Fields
- if len(fields) > 0 {
- var first = fields[0]
- var ref = getRef(first.Type.Ref.Base)
- if ref.Namespace == ns {
- if !((ref.Namespace == "") && ctx.isTypeParameter(ref.ItemName)) {
- return ref.ItemName
- }}
- }
- }
- return ""
- }
|