Пример #1
0
// compile compiles an expression AST.  callCtx should be true if this
// AST is in the function position of a function call node; it allows
// the returned expression to be a type or a built-in function (which
// otherwise result in errors).
func (a *exprCompiler) compile(x ast.Expr, callCtx bool) *expr {
	ei := &exprInfo{a.compiler, x.Pos()}

	switch x := x.(type) {
	// Literals
	case *ast.BasicLit:
		switch x.Kind {
		case token.INT:
			return ei.compileIntLit(string(x.Value))
		case token.FLOAT:
			return ei.compileFloatLit(string(x.Value))
		case token.CHAR:
			return ei.compileCharLit(string(x.Value))
		case token.STRING:
			return ei.compileStringLit(string(x.Value))
		default:
			log.Crashf("unexpected basic literal type %v", x.Kind)
		}

	case *ast.CompositeLit:
		goto notimpl

	case *ast.FuncLit:
		decl := ei.compileFuncType(a.block, x.Type)
		if decl == nil {
			// TODO(austin) Try compiling the body,
			// perhaps with dummy argument definitions
			return nil
		}
		fn := ei.compileFunc(a.block, decl, x.Body)
		if fn == nil {
			return nil
		}
		if a.constant {
			a.diagAt(x, "function literal used in constant expression")
			return nil
		}
		return ei.compileFuncLit(decl, fn)

	// Types
	case *ast.ArrayType:
		// TODO(austin) Use a multi-type case
		goto typeexpr

	case *ast.ChanType:
		goto typeexpr

	case *ast.Ellipsis:
		goto typeexpr

	case *ast.FuncType:
		goto typeexpr

	case *ast.InterfaceType:
		goto typeexpr

	case *ast.MapType:
		goto typeexpr

	// Remaining expressions
	case *ast.BadExpr:
		// Error already reported by parser
		a.silentErrors++
		return nil

	case *ast.BinaryExpr:
		l, r := a.compile(x.X, false), a.compile(x.Y, false)
		if l == nil || r == nil {
			return nil
		}
		return ei.compileBinaryExpr(x.Op, l, r)

	case *ast.CallExpr:
		l := a.compile(x.Fun, true)
		args := make([]*expr, len(x.Args))
		bad := false
		for i, arg := range x.Args {
			if i == 0 && l != nil && (l.t == Type(makeType) || l.t == Type(newType)) {
				argei := &exprInfo{a.compiler, arg.Pos()}
				args[i] = argei.exprFromType(a.compileType(a.block, arg))
			} else {
				args[i] = a.compile(arg, false)
			}
			if args[i] == nil {
				bad = true
			}
		}
		if bad || l == nil {
			return nil
		}
		if a.constant {
			a.diagAt(x, "function call in constant context")
			return nil
		}

		if l.valType != nil {
			a.diagAt(x, "type conversions not implemented")
			return nil
		} else if ft, ok := l.t.(*FuncType); ok && ft.builtin != "" {
			return ei.compileBuiltinCallExpr(a.block, ft, args)
		} else {
			return ei.compileCallExpr(a.block, l, args)
		}

	case *ast.Ident:
		return ei.compileIdent(a.block, a.constant, callCtx, x.Name())

	case *ast.IndexExpr:
		l, r := a.compile(x.X, false), a.compile(x.Index, false)
		if l == nil || r == nil {
			return nil
		}
		return ei.compileIndexExpr(l, r)

	case *ast.SliceExpr:
		end := x.End
		if end == nil {
			// TODO: set end to len(x.X)
			panic("unimplemented")
		}
		arr := a.compile(x.X, false)
		lo := a.compile(x.Index, false)
		hi := a.compile(end, false)
		if arr == nil || lo == nil || hi == nil {
			return nil
		}
		return ei.compileSliceExpr(arr, lo, hi)

	case *ast.KeyValueExpr:
		goto notimpl

	case *ast.ParenExpr:
		return a.compile(x.X, callCtx)

	case *ast.SelectorExpr:
		v := a.compile(x.X, false)
		if v == nil {
			return nil
		}
		return ei.compileSelectorExpr(v, x.Sel.Name())

	case *ast.StarExpr:
		// We pass down our call context because this could be
		// a pointer type (and thus a type conversion)
		v := a.compile(x.X, callCtx)
		if v == nil {
			return nil
		}
		if v.valType != nil {
			// Turns out this was a pointer type, not a dereference
			return ei.exprFromType(NewPtrType(v.valType))
		}
		return ei.compileStarExpr(v)

	case *ast.StringList:
		strings := make([]*expr, len(x.Strings))
		bad := false
		for i, s := range x.Strings {
			strings[i] = a.compile(s, false)
			if strings[i] == nil {
				bad = true
			}
		}
		if bad {
			return nil
		}
		return ei.compileStringList(strings)

	case *ast.StructType:
		goto notimpl

	case *ast.TypeAssertExpr:
		goto notimpl

	case *ast.UnaryExpr:
		v := a.compile(x.X, false)
		if v == nil {
			return nil
		}
		return ei.compileUnaryExpr(x.Op, v)
	}
	log.Crashf("unexpected ast node type %T", x)
	panic()

typeexpr:
	if !callCtx {
		a.diagAt(x, "type used as expression")
		return nil
	}
	return ei.exprFromType(a.compileType(a.block, x))

notimpl:
	a.diagAt(x, "%T expression node not implemented", x)
	return nil
}
Пример #2
0
func (sc *PackageScoping) MangleExpr(e ast.Expr) ast.Expr {
	switch e := e.(type) {
	case *ast.CallExpr:
		for i := range e.Args {
			e.Args[i] = sc.MangleExpr(e.Args[i])
		}
		sc.MangleExpr(e.Fun)
		if fn, ok := e.Fun.(*ast.Ident); ok {
			switch fn.Name {
			case "print", "println":
				sc.Do("runtime.print")
				sc.Do("runtime.print_int")
			case "new":
				sc.Do("runtime.malloc")
			}
		}
	case *ast.Ident:
		if pkg, ok := sc.Globals[e.Name]; ok {
			// It's a global identifier, so we need to mangle it...
			sc.Do(pkg + "." + e.Name)
			oldname := e.Name
			e.Name = ManglePackageAndName(pkg, e.Name)
			fmt.Println("Name is", e.Name, "from", pkg, oldname)
		} else {
			// Nothing to do here, it is a local identifier or builtin.
		}
	case *ast.BasicLit:
		// Nothing to do here, a literal is never imported.
	case *ast.BinaryExpr:
		e.X = sc.MangleExpr(e.X)
		e.Y = sc.MangleExpr(e.Y)
		// FIXME: We could do better here if we had type information...
		switch e.Op {
		case token.EQL:
			sc.Do("runtime.strings_equal")
		case token.NEQ:
			sc.Do("runtime.strings_unequal")
		}
	case *ast.UnaryExpr:
		sc.MangleExpr(e.X)
	case *ast.ParenExpr:
		sc.MangleExpr(e.X)
	case *ast.IndexExpr:
		e.X = sc.MangleExpr(e.X)
		e.Index = sc.MangleExpr(e.Index)
	case *ast.SliceExpr:
		e.X = sc.MangleExpr(e.X)
		e.Low = sc.MangleExpr(e.Low)
		e.High = sc.MangleExpr(e.High)
		sc.Do("runtime.slice_string")
	case *ast.StarExpr:
		sc.MangleExpr(e.X)
	case *ast.SelectorExpr:
		if b, ok := e.X.(*ast.Ident); ok {
			if theimp, ok := sc.Imports[b.Name]; ok {
				sc.Do(theimp + "." + e.Sel.Name)
				e.Sel.Name = ManglePackageAndName(theimp, e.Sel.Name)
				return e.Sel
			} else {
				fmt.Println("not a package: ", b.Name)
				fmt.Println("Imports are", sc.Imports)
				sc.MangleExpr(e.X)
			}
		} else {
			sc.MangleExpr(e.X)
		}
	case *ast.StructType:
		for _, f := range e.Fields.List {
			sc.MangleExpr(f.Type)
		}
	case *ast.CompositeLit:
		e.Type = sc.MangleExpr(e.Type)
		for i := range e.Elts {
			e.Elts[i] = sc.MangleExpr(e.Elts[i])
		}
	case *ast.MapType:
		e.Key = sc.MangleExpr(e.Key)
		e.Value = sc.MangleExpr(e.Value)
	case *ast.Ellipsis:
		e.Elt = sc.MangleExpr(e.Elt)
	case *ast.InterfaceType:
		for _, field := range e.Methods.List {
			field.Type = sc.MangleExpr(field.Type)
		}
	case *ast.ArrayType:
		e.Len = sc.MangleExpr(e.Len)
		e.Elt = sc.MangleExpr(e.Elt)
	case *ast.TypeAssertExpr:
		e.X = sc.MangleExpr(e.X)
		e.Type = sc.MangleExpr(e.Type)
	case *ast.FuncType:
		for _, field := range e.Params.List {
			field.Type = sc.MangleExpr(field.Type)
		}
		for _, field := range e.Results.List {
			field.Type = sc.MangleExpr(field.Type)
		}
	case *ast.FuncLit:
		for _, field := range e.Type.Params.List {
			field.Type = sc.MangleExpr(field.Type)
		}
		for _, field := range e.Type.Results.List {
			field.Type = sc.MangleExpr(field.Type)
		}
		sc.MangleStatement(e.Body)
	case *ast.KeyValueExpr:
		e.Key = sc.MangleExpr(e.Key)
		e.Value = sc.MangleExpr(e.Value)
	case nil:
		// Nothing to do with nil expression
	default:
		panic(fmt.Sprintf("Tracked weird expression of type %T", e))
	}
	return e
}