Files

133 lines
3.1 KiB
Go

package checker
import (
"strings"
"aego/script/abi"
"aego/script/ast"
"aego/script/diag"
"aego/script/resolver"
"aego/script/types"
)
func (c *checker) typeExpr(e ast.TypeExpr) *types.Type {
switch t := e.(type) {
case *ast.SliceType:
el := c.typeExpr(t.Elem)
if el == types.Invalid {
return types.Invalid
}
return c.u.SliceOf(el)
case *ast.NamedType:
return c.namedType(t)
}
return types.Invalid
}
func (c *checker) noArgs(t *ast.NamedType) {
if len(t.Args) > 0 {
c.errorf(diag.BadTypeArg, t.Args[0].Span(), "%s is not generic", t.Name.Name)
}
}
func (c *checker) namedType(t *ast.NamedType) *types.Type {
var obj *resolver.Object
if t.Pkg != nil {
p := c.lookup(t.Pkg.Name)
if p == nil || p.Kind != resolver.ObjPkg {
c.errorf(diag.UndefinedName, t.Pkg.Sp, "undefined package %s", t.Pkg.Name)
return types.Invalid
}
c.use(t.Pkg, p)
switch {
case p.Target == "":
return types.Invalid
case p.Host:
ht := c.hostType(p.Target, t.Name.Name)
if ht == nil {
c.errorf(diag.UnknownHost, t.Name.Sp, "%s has no type %s", p.Target, t.Name.Name)
return types.Invalid
}
c.noArgs(t)
return ht
}
if obj = c.member(t.Name, p); obj == nil {
return types.Invalid
}
} else {
if obj = c.lookup(t.Name.Name); obj == nil {
c.errorf(diag.UndefinedName, t.Name.Sp, "undefined: %s", t.Name.Name)
return types.Invalid
}
c.use(t.Name, obj)
}
switch obj.Kind {
case resolver.ObjType:
c.noArgs(t)
return obj.Type
case resolver.ObjGeneric:
return c.generic(obj.Name, t)
}
c.errorf(diag.NotAType, t.Name.Sp, "%s is not a type", t.Name.Name)
return types.Invalid
}
func (c *checker) generic(name string, t *ast.NamedType) *types.Type {
if len(t.Args) != 1 {
c.errorf(diag.BadTypeArg, t.Sp, "%s needs exactly one type argument", name)
return types.Invalid
}
arg, ok := t.Args[0].(*ast.NamedType)
if !ok {
c.errorf(diag.BadTypeArg, t.Args[0].Span(), "%s argument must be a type name", name)
return types.Invalid
}
switch name {
case "AssetRef":
if kind, ok := types.AssetKind(arg.Name.Name); ok && arg.Pkg == nil && len(arg.Args) == 0 {
return c.u.AssetRef(kind)
}
if data, ok := c.dataArg(arg, name); ok {
return c.u.AssetRef(dataPrefix + data)
}
return types.Invalid
case "TableRef":
if data, ok := c.dataArg(arg, name); ok {
return c.u.AssetRef(tablePrefix + data)
}
return types.Invalid
case "ScriptRef":
full, ok := c.scriptTarget(arg)
if !ok {
return types.Invalid
}
return c.u.ScriptRef(full)
}
comp := c.component(arg)
if comp == nil {
return types.Invalid
}
return c.u.ComponentRef(comp)
}
func (c *checker) component(arg *ast.NamedType) *abi.Component {
name := arg.Name.Name
if arg.Pkg != nil {
name = arg.Pkg.Name + "." + name
}
list := c.surface.Components(name)
switch len(list) {
case 1:
return list[0]
case 0:
c.errorf(diag.BadTypeArg, arg.Sp, "unknown component %s", name)
default:
names := make([]string, len(list))
for i, l := range list {
names[i] = l.Name
}
c.errorf(diag.BadTypeArg, arg.Sp, "component name %s is ambiguous, write one of: %s", name, strings.Join(names, ", "))
}
return nil
}