예제 #1
0
파일: const.go 프로젝트: glycerine/llgo
// zeroConst returns a new "zero" constant of the specified type,
// which must not be an array or struct type: the zero values of
// aggregates are well-defined but cannot be represented by Const.
//
func zeroConst(t types.Type) *Const {
	switch t := t.(type) {
	case *types.Basic:
		switch {
		case t.Info()&types.IsBoolean != 0:
			return NewConst(exact.MakeBool(false), t)
		case t.Info()&types.IsNumeric != 0:
			return NewConst(exact.MakeInt64(0), t)
		case t.Info()&types.IsString != 0:
			return NewConst(exact.MakeString(""), t)
		case t.Kind() == types.UnsafePointer:
			fallthrough
		case t.Kind() == types.UntypedNil:
			return nilConst(t)
		default:
			panic(fmt.Sprint("zeroConst for unexpected type:", t))
		}
	case *types.Pointer, *types.Slice, *types.Interface, *types.Chan, *types.Map, *types.Signature:
		return nilConst(t)
	case *types.Named:
		return NewConst(zeroConst(t.Underlying()).Value, t)
	case *types.Array, *types.Struct, *types.Tuple:
		panic(fmt.Sprint("zeroConst applied to aggregate:", t))
	}
	panic(fmt.Sprint("zeroConst: unexpected ", t))
}
예제 #2
0
// Conversion type-checks the conversion T(x).
// The result is in x.
func (check *Checker) conversion(x *operand, T Type) {
	constArg := x.mode == constant

	var ok bool
	switch {
	case constArg && isConstType(T):
		// constant conversion
		switch t := T.Underlying().(*Basic); {
		case representableConst(x.val, check.conf, t.kind, &x.val):
			ok = true
		case x.isInteger() && isString(t):
			codepoint := int64(-1)
			if i, ok := exact.Int64Val(x.val); ok {
				codepoint = i
			}
			// If codepoint < 0 the absolute value is too large (or unknown) for
			// conversion. This is the same as converting any other out-of-range
			// value - let string(codepoint) do the work.
			x.val = exact.MakeString(string(codepoint))
			ok = true
		}
	case x.convertibleTo(check.conf, T):
		// non-constant conversion
		x.mode = value
		ok = true
	}

	if !ok {
		check.errorf(x.pos(), "cannot convert %s to %s", x, T)
		x.mode = invalid
		return
	}

	// The conversion argument types are final. For untyped values the
	// conversion provides the type, per the spec: "A constant may be
	// given a type explicitly by a constant declaration or conversion,...".
	final := x.typ
	if isUntyped(x.typ) {
		final = T
		// - For conversions to interfaces, use the argument's default type.
		// - For conversions of untyped constants to non-constant types, also
		//   use the default type (e.g., []byte("foo") should report string
		//   not []byte as type for the constant "foo").
		// - Keep untyped nil for untyped nil arguments.
		if IsInterface(T) || constArg && !isConstType(T) {
			final = defaultType(x.typ)
		}
		check.updateExprType(x.expr, final, true)
	}

	x.typ = T
}
예제 #3
0
파일: import.go 프로젝트: glycerine/llgo
func (p *importer) value() exact.Value {
	switch kind := exact.Kind(p.int()); kind {
	case falseTag:
		return exact.MakeBool(false)
	case trueTag:
		return exact.MakeBool(true)
	case int64Tag:
		return exact.MakeInt64(p.int64())
	case floatTag:
		return p.float()
	case fractionTag:
		return p.fraction()
	case complexTag:
		re := p.fraction()
		im := p.fraction()
		return exact.BinaryOp(re, token.ADD, exact.MakeImag(im))
	case stringTag:
		return exact.MakeString(p.string())
	default:
		panic(fmt.Sprintf("unexpected value kind %d", kind))
	}
}
예제 #4
0
파일: testmain.go 프로젝트: glycerine/llgo
// CreateTestMainPackage creates and returns a synthetic "main"
// package that runs all the tests of the supplied packages, similar
// to the one that would be created by the 'go test' tool.
//
// It returns nil if the program contains no tests.
//
func (prog *Program) CreateTestMainPackage(pkgs ...*Package) *Package {
	pkgs, tests, benchmarks, examples := FindTests(pkgs)
	if len(pkgs) == 0 {
		return nil
	}

	testmain := &Package{
		Prog:    prog,
		Members: make(map[string]Member),
		values:  make(map[types.Object]Value),
		Object:  types.NewPackage("test$main", "main"),
	}

	// Build package's init function.
	init := &Function{
		name:      "init",
		Signature: new(types.Signature),
		Synthetic: "package initializer",
		Pkg:       testmain,
		Prog:      prog,
	}
	init.startBody()

	if testMainStartBodyHook != nil {
		testMainStartBodyHook(init)
	}

	// Initialize packages to test.
	var pkgpaths []string
	for _, pkg := range pkgs {
		var v Call
		v.Call.Value = pkg.init
		v.setType(types.NewTuple())
		init.emit(&v)

		pkgpaths = append(pkgpaths, pkg.Object.Path())
	}
	sort.Strings(pkgpaths)
	init.emit(new(Return))
	init.finishBody()
	testmain.init = init
	testmain.Object.MarkComplete()
	testmain.Members[init.name] = init

	// For debugging convenience, define an unexported const
	// that enumerates the packages.
	packagesConst := types.NewConst(token.NoPos, testmain.Object, "packages", tString,
		exact.MakeString(strings.Join(pkgpaths, " ")))
	memberFromObject(testmain, packagesConst, nil)

	// Create main *types.Func and *ssa.Function
	mainFunc := types.NewFunc(token.NoPos, testmain.Object, "main", new(types.Signature))
	memberFromObject(testmain, mainFunc, nil)
	main := testmain.Func("main")
	main.Synthetic = "test main function"

	main.startBody()

	if testMainStartBodyHook != nil {
		testMainStartBodyHook(main)
	}

	if testingPkg := prog.ImportedPackage("testing"); testingPkg != nil {
		testingMain := testingPkg.Func("Main")
		testingMainParams := testingMain.Signature.Params()

		// The generated code is as if compiled from this:
		//
		// func main() {
		//      match      := func(_, _ string) (bool, error) { return true, nil }
		//      tests      := []testing.InternalTest{{"TestFoo", TestFoo}, ...}
		//      benchmarks := []testing.InternalBenchmark{...}
		//      examples   := []testing.InternalExample{...}
		// 	testing.Main(match, tests, benchmarks, examples)
		// }

		matcher := &Function{
			name:      "matcher",
			Signature: testingMainParams.At(0).Type().(*types.Signature),
			Synthetic: "test matcher predicate",
			parent:    main,
			Pkg:       testmain,
			Prog:      prog,
		}
		main.AnonFuncs = append(main.AnonFuncs, matcher)
		matcher.startBody()
		matcher.emit(&Return{Results: []Value{vTrue, nilConst(types.Universe.Lookup("error").Type())}})
		matcher.finishBody()

		// Emit call: testing.Main(matcher, tests, benchmarks, examples).
		var c Call
		c.Call.Value = testingMain
		c.Call.Args = []Value{
			matcher,
			testMainSlice(main, tests, testingMainParams.At(1).Type()),
			testMainSlice(main, benchmarks, testingMainParams.At(2).Type()),
			testMainSlice(main, examples, testingMainParams.At(3).Type()),
		}
		emitTailCall(main, &c)
	} else {
		// The program does not import "testing", but FindTests
		// returned non-nil, which must mean there were Examples
		// but no Tests or Benchmarks.
		// We'll simply call them from testmain.main; this will
		// ensure they don't panic, but will not check any
		// "Output:" comments.
		for _, eg := range examples {
			var c Call
			c.Call.Value = eg
			c.setType(types.NewTuple())
			main.emit(&c)
		}
		main.emit(&Return{})
		main.currentBlock = nil
	}

	main.finishBody()

	testmain.Members["main"] = main

	if prog.mode&PrintPackages != 0 {
		printMu.Lock()
		testmain.WriteTo(os.Stdout)
		printMu.Unlock()
	}

	if prog.mode&SanityCheckFunctions != 0 {
		sanityCheckPackage(testmain)
	}

	prog.packages[testmain.Object] = testmain

	return testmain
}
예제 #5
0
파일: const.go 프로젝트: glycerine/llgo
// stringConst returns a 'string' constant that evaluates to s.
func stringConst(s string) *Const {
	return NewConst(exact.MakeString(s), tString)
}
예제 #6
0
파일: parser.go 프로젝트: glycerine/llgo
// ConstValue     = string | "false" | "true" | ["-"] (int ["'"] | FloatOrComplex) .
// FloatOrComplex = float ["i" | ("+"|"-") float "i"] .
func (p *parser) parseConstValue() (val exact.Value, typ types.Type) {
	switch p.tok {
	case scanner.String:
		str := p.parseString()
		val = exact.MakeString(str)
		typ = types.Typ[types.UntypedString]
		return

	case scanner.Ident:
		b := false
		switch p.lit {
		case "false":
		case "true":
			b = true

		default:
			p.errorf("expected const value, got %s (%q)", scanner.TokenString(p.tok), p.lit)
		}

		p.next()
		val = exact.MakeBool(b)
		typ = types.Typ[types.UntypedBool]
		return
	}

	sign := ""
	if p.tok == '-' {
		p.next()
		sign = "-"
	}

	switch p.tok {
	case scanner.Int:
		val = exact.MakeFromLiteral(sign+p.lit, token.INT)
		if val == nil {
			p.error("could not parse integer literal")
		}

		p.next()
		if p.tok == '\'' {
			p.next()
			typ = types.Typ[types.UntypedRune]
		} else {
			typ = types.Typ[types.UntypedInt]
		}

	case scanner.Float:
		re := sign + p.lit
		p.next()

		var im string
		switch p.tok {
		case '+':
			p.next()
			im = p.expect(scanner.Float)

		case '-':
			p.next()
			im = "-" + p.expect(scanner.Float)

		case scanner.Ident:
			// re is in fact the imaginary component. Expect "i" below.
			im = re
			re = "0"

		default:
			val = exact.MakeFromLiteral(re, token.FLOAT)
			if val == nil {
				p.error("could not parse float literal")
			}
			typ = types.Typ[types.UntypedFloat]
			return
		}

		p.expectKeyword("i")
		reval := exact.MakeFromLiteral(re, token.FLOAT)
		if reval == nil {
			p.error("could not parse real component of complex literal")
		}
		imval := exact.MakeFromLiteral(im+"i", token.IMAG)
		if imval == nil {
			p.error("could not parse imag component of complex literal")
		}
		val = exact.BinaryOp(reval, token.ADD, imval)
		typ = types.Typ[types.UntypedComplex]

	default:
		p.errorf("expected const value, got %s (%q)", scanner.TokenString(p.tok), p.lit)
	}

	return
}