diff options
| author | Dmitry Vyukov <dvyukov@google.com> | 2017-09-04 19:52:42 +0200 |
|---|---|---|
| committer | Dmitry Vyukov <dvyukov@google.com> | 2017-09-04 20:25:22 +0200 |
| commit | 8094a4202f10d59457a2a33d4e276b32c0ca16bf (patch) | |
| tree | 433f87a6376e637c0ec1aae185f67343024220d1 /pkg/compiler/compiler.go | |
| parent | f29b943c0b672ff7f02c1046416f1b85d7344bfb (diff) | |
pkg/compiler: move checking code to a separate file
Diffstat (limited to 'pkg/compiler/compiler.go')
| -rw-r--r-- | pkg/compiler/compiler.go | 390 |
1 files changed, 0 insertions, 390 deletions
diff --git a/pkg/compiler/compiler.go b/pkg/compiler/compiler.go index a192ed8d7..fe3f28d77 100644 --- a/pkg/compiler/compiler.go +++ b/pkg/compiler/compiler.go @@ -105,237 +105,6 @@ func (comp *compiler) warning(pos ast.Pos, msg string, args ...interface{}) { comp.warnings = append(comp.warnings, warn{pos, fmt.Sprintf(msg, args...)}) } -func (comp *compiler) check() { - // TODO: check len in syscall arguments referring to parent. - // TODO: incorrect name is referenced in len type - // TODO: no constructor for a resource - - comp.checkNames() - comp.checkFields() - comp.checkTypes() - comp.checkRecursion() -} - -func (comp *compiler) checkNames() { - calls := make(map[string]*ast.Call) - for _, decl := range comp.desc.Nodes { - switch decl.(type) { - case *ast.Resource, *ast.Struct: - pos, typ, name := decl.Info() - if builtinTypes[name] != nil { - comp.error(pos, "%v name %v conflicts with builtin type", typ, name) - continue - } - if prev := comp.resources[name]; prev != nil { - comp.error(pos, "type %v redeclared, previously declared as resource at %v", - name, prev.Pos) - continue - } - if prev := comp.structs[name]; prev != nil { - _, typ, _ := prev.Info() - comp.error(pos, "type %v redeclared, previously declared as %v at %v", - name, typ, prev.Pos) - continue - } - if res, ok := decl.(*ast.Resource); ok { - comp.resources[name] = res - } else if str, ok := decl.(*ast.Struct); ok { - comp.structs[name] = str - } - case *ast.IntFlags: - n := decl.(*ast.IntFlags) - name := n.Name.Name - if prev := comp.intFlags[name]; prev != nil { - comp.error(n.Pos, "flags %v redeclared, previously declared at %v", - name, prev.Pos) - continue - } - comp.intFlags[name] = n - case *ast.StrFlags: - n := decl.(*ast.StrFlags) - name := n.Name.Name - if prev := comp.strFlags[name]; prev != nil { - comp.error(n.Pos, "string flags %v redeclared, previously declared at %v", - name, prev.Pos) - continue - } - comp.strFlags[name] = n - case *ast.Call: - c := decl.(*ast.Call) - name := c.Name.Name - if prev := calls[name]; prev != nil { - comp.error(c.Pos, "syscall %v redeclared, previously declared at %v", - name, prev.Pos) - } - calls[name] = c - } - } -} - -func (comp *compiler) checkFields() { - const maxArgs = 9 // executor does not support more - for _, decl := range comp.desc.Nodes { - switch n := decl.(type) { - case *ast.Struct: - _, typ, name := n.Info() - fields := make(map[string]bool) - for _, f := range n.Fields { - fn := f.Name.Name - if fn == "parent" { - comp.error(f.Pos, "reserved field name %v in %v %v", fn, typ, name) - } - if fields[fn] { - comp.error(f.Pos, "duplicate field %v in %v %v", fn, typ, name) - } - fields[fn] = true - } - if !n.IsUnion && len(n.Fields) < 1 { - comp.error(n.Pos, "struct %v has no fields, need at least 1 field", name) - } - if n.IsUnion && len(n.Fields) < 2 { - comp.error(n.Pos, "union %v has only %v field, need at least 2 fields", - name, len(n.Fields)) - } - case *ast.Call: - name := n.Name.Name - args := make(map[string]bool) - for _, a := range n.Args { - an := a.Name.Name - if an == "parent" { - comp.error(a.Pos, "reserved argument name %v in syscall %v", - an, name) - } - if args[an] { - comp.error(a.Pos, "duplicate argument %v in syscall %v", - an, name) - } - args[an] = true - } - if len(n.Args) > maxArgs { - comp.error(n.Pos, "syscall %v has %v arguments, allowed maximum is %v", - name, len(n.Args), maxArgs) - } - } - } -} - -func (comp *compiler) checkTypes() { - for _, decl := range comp.desc.Nodes { - switch n := decl.(type) { - case *ast.Resource: - comp.checkType(n.Base, false, true) - case *ast.Struct: - for _, f := range n.Fields { - comp.checkType(f.Type, false, false) - } - comp.checkStruct(n) - case *ast.Call: - for _, a := range n.Args { - comp.checkType(a.Type, true, false) - } - if n.Ret != nil { - comp.checkType(n.Ret, true, false) - } - } - } -} - -func (comp *compiler) checkRecursion() { - checked := make(map[string]bool) - for _, decl := range comp.desc.Nodes { - switch n := decl.(type) { - case *ast.Resource: - comp.checkResourceRecursion(n) - case *ast.Struct: - comp.checkStructRecursion(checked, n) - } - } -} - -func (comp *compiler) checkResourceRecursion(n *ast.Resource) { - var seen []string - for n != nil { - if arrayContains(seen, n.Name.Name) { - chain := "" - for _, r := range seen { - chain += r + "->" - } - chain += n.Name.Name - comp.error(n.Pos, "recursive resource %v", chain) - return - } - seen = append(seen, n.Name.Name) - n = comp.resources[n.Base.Ident] - } -} - -type pathElem struct { - Pos ast.Pos - Struct string - Field string -} - -func (comp *compiler) checkStructRecursion(checked map[string]bool, n *ast.Struct) { - var path []pathElem - comp.checkStructRecursion1(checked, n, path) -} - -func (comp *compiler) checkStructRecursion1(checked map[string]bool, n *ast.Struct, path []pathElem) { - name := n.Name.Name - if checked[name] { - return - } - for i, elem := range path { - if elem.Struct != name { - continue - } - path = path[i:] - str := "" - for _, elem := range path { - str += fmt.Sprintf("%v.%v -> ", elem.Struct, elem.Field) - } - str += name - comp.error(path[0].Pos, "recursive declaration: %v (mark some pointers as opt)", str) - checked[name] = true - return - } - for _, f := range n.Fields { - path = append(path, pathElem{ - Pos: f.Pos, - Struct: name, - Field: f.Name.Name, - }) - comp.recurseField(checked, f.Type, path) - path = path[:len(path)-1] - } - checked[name] = true -} - -func (comp *compiler) recurseField(checked map[string]bool, t *ast.Type, path []pathElem) { - desc := comp.getTypeDesc(t) - if desc == typeStruct { - comp.checkStructRecursion1(checked, comp.structs[t.Ident], path) - return - } - _, args, base := comp.getArgsBase(t, "", sys.DirIn, false) - if desc == typePtr && base.IsOptional { - return // optional pointers prune recursion - } - for i, arg := range args { - if desc.Args[i].Type == typeArgType { - comp.recurseField(checked, arg, path) - } - } -} - -func (comp *compiler) checkStruct(n *ast.Struct) { - if n.IsUnion { - comp.parseUnionAttrs(n) - } else { - comp.parseStructAttrs(n) - } -} - func (comp *compiler) parseUnionAttrs(n *ast.Struct) (varlen bool) { for _, attr := range n.Attrs { switch attr.Name { @@ -389,99 +158,6 @@ func (comp *compiler) getTypeDesc(t *ast.Type) *typeDesc { return nil } -func (comp *compiler) checkType(t *ast.Type, isArg, isResourceBase bool) { - if unexpected, _, ok := checkTypeKind(t, kindIdent); !ok { - comp.error(t.Pos, "unexpected %v, expect type", unexpected) - return - } - desc := comp.getTypeDesc(t) - if desc == nil { - comp.error(t.Pos, "unknown type %v", t.Ident) - return - } - if !desc.AllowColon && t.HasColon { - comp.error(t.Pos2, "unexpected ':'") - return - } - if isArg && !desc.CanBeArg { - comp.error(t.Pos, "%v can't be syscall argument/return", t.Ident) - return - } - if isResourceBase && !desc.ResourceBase { - comp.error(t.Pos, "%v can't be resource base (int types can)", t.Ident) - return - } - args, opt := removeOpt(t) - if opt && (desc.CantBeOpt || isResourceBase) { - what := "resource base" - if desc.CantBeOpt { - what = t.Ident - } - pos := t.Args[len(t.Args)-1].Pos - comp.error(pos, "%v can't be marked as opt", what) - return - } - addArgs := 0 - needBase := !isArg && desc.NeedBase - if needBase { - addArgs++ // last arg must be base type, e.g. const[0, int32] - } - if len(args) > len(desc.Args)+addArgs || len(args) < len(desc.Args)-desc.OptArgs+addArgs { - comp.error(t.Pos, "wrong number of arguments for type %v, expect %v", - t.Ident, expectedTypeArgs(desc, needBase)) - return - } - if needBase { - base := args[len(args)-1] - args = args[:len(args)-1] - comp.checkTypeArg(t, base, typeArgBase) - } - err0 := comp.errors - for i, arg := range args { - if desc.Args[i].Type == typeArgType { - comp.checkType(arg, false, false) - } else { - comp.checkTypeArg(t, arg, desc.Args[i]) - } - } - if err0 != comp.errors { - return - } - if desc.Check != nil { - _, args, base := comp.getArgsBase(t, "", sys.DirIn, isArg) - desc.Check(comp, t, args, base) - } -} - -func (comp *compiler) checkTypeArg(t, arg *ast.Type, argDesc namedArg) { - desc := argDesc.Type - if len(desc.Names) != 0 { - if unexpected, _, ok := checkTypeKind(arg, kindIdent); !ok { - comp.error(arg.Pos, "unexpected %v for %v argument of %v type, expect %+v", - unexpected, argDesc.Name, t.Ident, desc.Names) - return - } - if !arrayContains(desc.Names, arg.Ident) { - comp.error(arg.Pos, "unexpected value %v for %v argument of %v type, expect %+v", - arg.Ident, argDesc.Name, t.Ident, desc.Names) - return - } - } else { - if unexpected, expect, ok := checkTypeKind(arg, desc.Kind); !ok { - comp.error(arg.Pos, "unexpected %v for %v argument of %v type, expect %v", - unexpected, argDesc.Name, t.Ident, expect) - return - } - } - if !desc.AllowColon && arg.HasColon { - comp.error(arg.Pos2, "unexpected ':'") - return - } - if desc.Check != nil { - desc.Check(comp, arg) - } -} - func (comp *compiler) getArgsBase(t *ast.Type, field string, dir sys.Dir, isArg bool) ( *typeDesc, []*ast.Type, sys.IntTypeCommon) { desc := comp.getTypeDesc(t) @@ -496,72 +172,6 @@ func (comp *compiler) getArgsBase(t *ast.Type, field string, dir sys.Dir, isArg return desc, args, base } -func expectedTypeArgs(desc *typeDesc, needBase bool) string { - expect := "" - for i, arg := range desc.Args { - if expect != "" { - expect += ", " - } - opt := i >= len(desc.Args)-desc.OptArgs - if opt { - expect += "[" - } - expect += arg.Name - if opt { - expect += "]" - } - } - if needBase { - if expect != "" { - expect += ", " - } - expect += typeArgBase.Name - } - if !desc.CantBeOpt { - if expect != "" { - expect += ", " - } - expect += "[opt]" - } - if expect == "" { - expect = "no arguments" - } - return expect -} - -func checkTypeKind(t *ast.Type, kind int) (unexpected string, expect string, ok bool) { - switch { - case kind == kindAny: - ok = true - case t.String != "": - ok = kind == kindString - if !ok { - unexpected = fmt.Sprintf("string %q", t.String) - } - case t.Ident != "": - ok = kind == kindIdent - if !ok { - unexpected = fmt.Sprintf("identifier %v", t.Ident) - } - default: - ok = kind == kindInt - if !ok { - unexpected = fmt.Sprintf("int %v", t.Value) - } - } - if !ok { - switch kind { - case kindString: - expect = "string" - case kindIdent: - expect = "identifier" - case kindInt: - expect = "int" - } - } - return -} - func removeOpt(t *ast.Type) ([]*ast.Type, bool) { args := t.Args if len(args) != 0 && args[len(args)-1].Ident == "opt" { |
