// 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 }
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 }