Beispiel #1
0
//ranges through config file and checks all expressions.
// prints result messages to stdout
func (c *checker) CheckAll() ([]CheckResult, error) {
	result := []CheckResult{}
	cnf, err := conf.ReadConfigFile(c.configFile)
	if err != nil {
		return nil, err
	}
	for _, section := range cnf.GetSections() {
		if section == "default" {
			continue
		}
		expr, _ := cnf.GetString(section, "expr")
		_, r, err := types.Eval(expr, c.pkg, c.sc)
		if err != nil {
			fmt.Fprintln(os.Stderr, err)
			continue
		}
		cr := &CheckResult{
			Name: section,
		}
		var m string
		if exact.BoolVal(r) {
			m, err = cnf.GetString(section, "true")
			if err != nil {
				continue
			}
		} else {
			m, err = cnf.GetString(section, "false")
			if err != nil {
				continue
			}
		}
		val, err := cnf.GetString(section, "val")
		if err == nil {
			t, v, err := types.Eval(val, c.pkg, c.sc)
			if err == nil {
				if types.Identical(t, types.Typ[types.UntypedFloat]) || types.Identical(t, types.Typ[types.Float64]) {
					x, _ := exact.Float64Val(v)
					cr.Value = x
				}
			}
		}
		owner, err := cnf.GetString(section, "owner")
		if err == nil {
			cr.Owner = owner
		} else {
			cr.Owner = "unknown"
		}

		_, msg, err := types.Eval(m, c.pkg, c.sc)
		if err != nil {
			cr.Message = m
		} else {
			cr.Message = exact.StringVal(msg)
		}
		result = append(result, *cr)
	}
	return result, nil
}
Beispiel #2
0
func (c *FunctionCache) NamedFunction(name string, signature string) llvm.Value {
	f, _ := c.functions[name+":"+signature]
	if !f.IsNil() {
		return f
	}

	if strings.HasPrefix(name, c.module.Name+".") {
		obj := c.pkg.Scope().Lookup(name[len(c.module.Name)+1:])
		if obj == nil {
			panic("Missing function: " + name)
		}
		value := c.Resolve(c.objectdata[obj].Ident)
		f = llvm.ConstExtractValue(value.LLVMValue(), []uint32{0})
	} else {
		if c.runtimetypespkg == nil {
			// Parse the runtime package, since we may need to refer to
			// its types.
			buildpkg, err := build.Import("github.com/axw/llgo/pkg/runtime", "", 0)
			if err != nil {
				panic(err)
			}

			// All types visible to the compiler are in "types.go".
			runtimefiles := []string{path.Join(buildpkg.Dir, "types.go")}

			fset := token.NewFileSet()
			files, err := parseFiles(fset, runtimefiles)
			if err != nil {
				panic(err)
			}
			c.runtimetypespkg, err = c.typecheck("runtime", fset, files)
			if err != nil {
				panic(err)
			}
		}

		pkg := c.runtimetypespkg
		scope := pkg.Scope().Child(0)
		ftype, _, err := types.Eval(signature+"{panic()}", pkg, scope)
		if err != nil {
			panic(err)
		}
		llvmfntyp := c.types.ToLLVM(ftype).StructElementTypes()[0].ElementType()
		f = llvm.AddFunction(c.module.Module, name, llvmfntyp)
	}
	c.functions[name+":"+signature] = f
	return f
}
Beispiel #3
0
func (p *Package) Eval(name string) (result Type, err error) {
	t, _, typesErr := types.Eval(name, p.Package, p.Scope())
	if typesErr != nil {
		err = typesErr
		return
	}
	result = Type{
		Package:    p,
		Pointer:    isPointer(t),
		Name:       strings.TrimLeft(name, Pointer(true).String()), // trims the * if it exists
		comparable: isComparable(t),
		numeric:    isNumeric(t),
		ordered:    isOrdered(t),
		Type:       t,
	}
	return
}
Beispiel #4
0
func TestExportedType(t *testing.T) {
	tests := []struct {
		typString string
		exp       bool
	}{
		{"int", true},
		{"string", false}, // references the shadowed builtin "string"
		{"T", true},
		{"t", false},
		{"*T", true},
		{"*t", false},
		{"map[int]complex128", true},
	}
	for _, test := range tests {
		src := `package foo; type T int; type t int; type string struct{}`
		fset := token.NewFileSet()
		file, err := parser.ParseFile(fset, "foo.go", src, 0)
		if err != nil {
			t.Fatalf("Parsing %q: %v", src, err)
		}
		// use the package name as package path
		pkg, err := types.Check(file.Name.Name, fset, []*ast.File{file})
		if err != nil {
			t.Fatalf("Type checking %q: %v", src, err)
		}
		// Use the first child scope of the package, which will be the file scope.
		scope := pkg.Scope().Child(0)
		typ, _, err := types.Eval(test.typString, pkg, scope)
		if err != nil {
			t.Errorf("types.Eval(%q): %v", test.typString, err)
			continue
		}
		if got := exportedType(typ); got != test.exp {
			t.Errorf("exportedType(%v) = %t, want %t", typ, got, test.exp)
		}
	}
}
Beispiel #5
0
// Returns one gen Package per Go package found in current directory
func getPackages() (result []*Package) {
	fset := token.NewFileSet()
	rootDir := "./"
	astPackages, err := parser.ParseDir(fset, rootDir, nil, parser.ParseComments)
	if err != nil {
		errs = append(errs, err)
	}

	for name, astPackage := range astPackages {
		pkg := &Package{Name: name}

		typesPkg, err := types.Check(name, fset, getAstFiles(astPackage, rootDir))
		if err != nil {
			errs = append(errs, err)
		}

		// fall back to Universe scope if types.Check fails; "best-effort" to handle primitives, at least
		scope := types.Universe
		if typesPkg != nil {
			scope = typesPkg.Scope()
		}

		docPkg := doc.New(astPackage, name, doc.AllDecls)
		for _, docType := range docPkg.Types {

			// look for deprecated struct tags, used for 'custom methods' in older version of gen
			if t, _, err := types.Eval(docType.Name, typesPkg, scope); err == nil {
				checkDeprecatedTags(t)
			}

			// identify marked-up types
			spec, found := getGenSpec(docType.Doc, docType.Name)
			if !found {
				continue
			}

			typ := &Type{
				Package: pkg,
				Pointer: spec.Pointer,
				Name:    docType.Name,
			}

			standardMethods, projectionMethods, err := determineMethods(spec)
			if err != nil {
				errs = append(errs, err)
			}

			// assemble standard methods with type verification
			t, _, err := types.Eval(typ.LocalName(), typesPkg, scope)
			known := err == nil

			if !known {
				addError(fmt.Sprintf("failed to evaluate type %s (%s)", typ.Name, err))
			}

			if known {
				numeric := isNumeric(t)
				comparable := isComparable(t)
				ordered := isOrdered(t)

				for _, s := range standardMethods {
					st, ok := standardTemplates[s]

					if !ok {
						addError(fmt.Sprintf("unknown standard method %s", s))
					}

					valid := (!st.RequiresNumeric || numeric) && (!st.RequiresComparable || comparable) && (!st.RequiresOrdered || ordered)

					if valid {
						typ.StandardMethods = append(typ.StandardMethods, s)
					}
				}
			}

			// assemble projections with type verification
			if spec.Projections != nil {
				if spec.Projections.Negated {
					addError(fmt.Sprintf("negation of projected types (see projection tag on %s) is unsupported", docType.Name))
				}

				for _, s := range spec.Projections.Items {
					numeric := false
					comparable := true // sensible default?
					ordered := false

					t, _, err := types.Eval(s, typesPkg, scope)
					known := err == nil

					if !known {
						addError(fmt.Sprintf("unable to identify type %s, projected on %s (%s)", s, docType.Name, err))
					} else {
						numeric = isNumeric(t)
						comparable = isComparable(t)
						ordered = isOrdered(t)
					}

					for _, m := range projectionMethods {
						pt, ok := projectionTemplates[m]

						if !ok {
							addError(fmt.Sprintf("unknown projection method %v", m))
							continue
						}

						valid := (!pt.RequiresNumeric || numeric) && (!pt.RequiresComparable || comparable) && (!pt.RequiresOrdered || ordered)

						if valid {
							typ.AddProjection(m, s)
						}
					}
				}
			}

			if spec.Containers != nil {
				if spec.Containers.Negated {
					addError(fmt.Sprintf("negation of containers (see containers tag on %s) is unsupported", docType.Name))
				}

				typ.Containers = spec.Containers.Items
			}

			determineImports(typ)

			pkg.Types = append(pkg.Types, typ)
		}

		// only add it to the results if there is something there
		if len(pkg.Types) > 0 {
			result = append(result, pkg)
		}
	}

	return
}
Beispiel #6
0
func getTypes(directive string, filter func(os.FileInfo) bool) ([]Type, error) {
	typs := make([]Type, 0)

	fset := token.NewFileSet()
	rootDir := "./"

	astPackages, astErr := parser.ParseDir(fset, rootDir, filter, parser.ParseComments)

	if astErr != nil {
		return typs, astErr
	}

	for name, astPackage := range astPackages {
		astFiles, astErr := getAstFiles(astPackage, rootDir)

		if astErr != nil {
			return typs, astErr
		}

		typesPkg, typesErr := types.Check(name, fset, astFiles)

		if typesErr != nil {
			return typs, typesErr
		}

		pkg := &Package{typesPkg}

		// doc package is handy for pulling types and their comments
		docPkg := doc.New(astPackage, name, doc.AllDecls)

		for _, docType := range docPkg.Types {

			pointer, tags, found, tagErr := parseTags(directive, docType.Doc)

			if tagErr != nil {
				return typs, tagErr
			}

			if !found {
				continue
			}

			typ := Type{
				Package: pkg,
				Pointer: pointer,
				Name:    docType.Name,
				Tags:    tags,
			}

			t, _, err := types.Eval(typ.LocalName(), typesPkg, typesPkg.Scope())
			known := err == nil

			if !known {
				err = errors.New(fmt.Sprintf("failed to evaluate type %s (%s)", typ.Name, err))
				continue
			}

			typ.comparable = isComparable(t)
			typ.numeric = isNumeric(t)
			typ.ordered = isOrdered(t)
			typ.Type = t

			typs = append(typs, typ)
		}
	}

	return typs, nil
}