blob: 15055a24395ddc5bb29910e2050163a6829f6e58 [file] [log] [blame]
// Copyright 2017 The Wuffs Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//go:generate go run gen.go
package check
import (
"fmt"
"github.com/google/wuffs/lang/builtin"
"github.com/google/wuffs/lang/parse"
a "github.com/google/wuffs/lang/ast"
t "github.com/google/wuffs/lang/token"
)
var (
exprIn = a.NewExpr(a.FlagsTypeChecked, 0, 0, t.IDIn, nil, nil, nil, nil)
exprOut = a.NewExpr(a.FlagsTypeChecked, 0, 0, t.IDOut, nil, nil, nil, nil)
exprThis = a.NewExpr(a.FlagsTypeChecked, 0, 0, t.IDThis, nil, nil, nil, nil)
)
// typeExprFoo is an *ast.Node MType (implicit type).
var (
typeExprGeneric = a.NewTypeExpr(0, 0, t.IDDiamond, nil, nil, nil)
typeExprIdeal = a.NewTypeExpr(0, 0, t.IDDoubleZ, nil, nil, nil)
typeExprList = a.NewTypeExpr(0, 0, t.IDDollar, nil, nil, nil)
typeExprU8 = a.NewTypeExpr(0, 0, t.IDU8, nil, nil, nil)
typeExprU16 = a.NewTypeExpr(0, 0, t.IDU16, nil, nil, nil)
typeExprU32 = a.NewTypeExpr(0, 0, t.IDU32, nil, nil, nil)
typeExprU64 = a.NewTypeExpr(0, 0, t.IDU64, nil, nil, nil)
typeExprBool = a.NewTypeExpr(0, 0, t.IDBool, nil, nil, nil)
typeExprStatus = a.NewTypeExpr(0, 0, t.IDStatus, nil, nil, nil)
typeExprReader1 = a.NewTypeExpr(0, 0, t.IDReader1, nil, nil, nil)
typeExprWriter1 = a.NewTypeExpr(0, 0, t.IDWriter1, nil, nil, nil)
typeExprImageConfig = a.NewTypeExpr(0, 0, t.IDImageConfig, nil, nil, nil)
typeExprSliceU8 = a.NewTypeExpr(t.IDColon, 0, 0, nil, nil, typeExprU8)
// TODO: delete this.
typeExprPlaceholder = a.NewTypeExpr(0, 0, t.IDU8, nil, nil, nil)
typeExprPlaceholder16 = a.NewTypeExpr(0, 0, t.IDU16, nil, nil, nil)
typeExprPlaceholder32 = a.NewTypeExpr(0, 0, t.IDU32, nil, nil, nil)
)
// typeMap maps from variable names (as token IDs) to types.
type typeMap map[t.ID]*a.TypeExpr
var builtInTypeMap = typeMap{
t.IDU8: typeExprU8,
t.IDU16: typeExprU16,
t.IDU32: typeExprU32,
t.IDU64: typeExprU64,
t.IDBool: typeExprBool,
t.IDStatus: typeExprStatus,
t.IDReader1: typeExprReader1,
t.IDWriter1: typeExprWriter1,
t.IDImageConfig: typeExprImageConfig,
}
func (c *Checker) builtInFunc(qqid t.QQID) (*a.Func, error) {
if c.builtInFuncs == nil {
err := error(nil)
c.builtInFuncs, err = parseBuiltInFuncs(c.tm, builtin.Funcs, false)
if err != nil {
return nil, err
}
}
return c.builtInFuncs[qqid], nil
}
func (c *Checker) builtInSliceFunc(qqid t.QQID) (*a.Func, error) {
if c.builtInSliceFuncs == nil {
err := error(nil)
c.builtInSliceFuncs, err = parseBuiltInFuncs(c.tm, builtin.SliceFuncs, true)
if err != nil {
return nil, err
}
}
return c.builtInSliceFuncs[qqid], nil
}
func parseBuiltInFuncs(tm *t.Map, ss []string, generic bool) (map[t.QQID]*a.Func, error) {
m := map[t.QQID]*a.Func{}
buf := []byte(nil)
opts := parse.Options{
AllowBuiltIns: true,
}
for _, s := range ss {
buf = buf[:0]
buf = append(buf, "pub func "...)
buf = append(buf, s...)
buf = append(buf, "{}\n"...)
const filename = "builtin.wuffs"
tokens, _, err := t.Tokenize(tm, filename, buf)
if err != nil {
return nil, fmt.Errorf("check: could not tokenize built-in funcs: %v", err)
}
if generic {
for i := range tokens {
if tokens[i].ID == builtin.GenericReplaceFrom {
tokens[i].ID = builtin.GenericReplaceTo
}
}
}
file, err := parse.Parse(tm, filename, tokens, &opts)
if err != nil {
return nil, fmt.Errorf("check: could not parse built-in funcs: %v", err)
}
tlds := file.TopLevelDecls()
if len(tlds) != 1 || tlds[0].Kind() != a.KFunc {
return nil, fmt.Errorf("check: parsing %q: got %d top level decls, want %d", s, len(tlds), 1)
}
f := tlds[0].Func()
m[f.QQID()] = f
}
return m, nil
}
func (c *Checker) resolveFunc(typ *a.TypeExpr) (*a.Func, error) {
if typ.Decorator().Key() != t.KeyOpenParen {
return nil, fmt.Errorf("check: resolveFunc cannot look up non-func TypeExpr %q", typ.Str(c.tm))
}
lTyp := typ.Receiver()
lQID := lTyp.QID()
qqid := t.QQID{lQID[0], lQID[1], typ.FuncName()}
if lTyp.Decorator().Key() == t.KeyColon {
// lTyp is a slice.
qqid[0] = 0
qqid[1] = t.IDDiamond
if f, err := c.builtInSliceFunc(qqid); err != nil {
return nil, err
} else if f != nil {
return f, nil
}
} else {
if f, err := c.builtInFunc(qqid); err != nil {
return nil, err
} else if f != nil {
return f, nil
}
if f := c.funcs[qqid]; f != nil {
return f, nil
}
}
return nil, fmt.Errorf("check: resolveFunc cannot look up %q", typ.Str(c.tm))
}