func (v *CompileVisitor) Declare(vname string, t *ast.Type) { switch SizeOnStack(t) { case 4: v.Append(x86.Commented(x86.PushL(x86.Imm32(0)), "This is variable "+vname)) case 8: v.Append(x86.Commented(x86.PushL(x86.Imm32(0)), "This is variable "+vname)) v.Append(x86.Commented(x86.PushL(x86.Imm32(0)), "This is variable "+vname)) default: panic(fmt.Sprintf("I don't handle variables with length %s", SizeOnStack(t))) } v.Stack.DefineVariable(vname, t) }
func (v *CompileVisitor) CompileExpression(exp ast.Expr) { switch e := exp.(type) { case *ast.BasicLit: switch e.Kind { case token.STRING: str, err := strconv.Unquote(string(e.Value)) if err != nil { panic(err) } n, ok := v.string_literals[str] if !ok { panic(fmt.Sprintf("I don't recognize the string: %s", string(e.Value))) } v.Append( x86.Commented(x86.PushL(x86.Symbol(n)), "Pushing string literal "+string(e.Value)), x86.PushL(x86.Imm32(len(str)))) v.Stack.Push(StringType) // let the stack know we've pushed a literal default: panic(fmt.Sprintf("I don't know how to deal with literal: %s", e)) } case *ast.CallExpr: if fn, ok := e.Fun.(*ast.Ident); ok { pos := myfiles.Position(fn.Pos()) switch fn.Name { case "println", "print": if len(e.Args) != 1 { panic(fmt.Sprintf("%s expects just one argument, not %d", fn.Name, len(e.Args))) } argtype := ExprType(e.Args[0], v.Stack) if argtype.N != ast.String || argtype.Form != ast.Basic { panic(fmt.Sprintf("Argument to %s has type %s but should have type string!", fn.Name, argtype)) } v.Stack = v.Stack.New("arguments") v.CompileExpression(e.Args[0]) v.Append(x86.Commented(x86.Call(x86.Symbol(fn.Name)), fmt.Sprint(pos.Filename, ": line ", pos.Line))) v.Stack = v.Stack.Parent // A hack to let the callee clean up arguments default: // This must not be a built-in function... functype := v.Stack.Lookup(fn.Name) if functype.Type().Form != ast.Function { panic("Function " + fn.Name + " is not actually a function!") } for i := 0; i < int(functype.Type().N); i++ { // Put zeros on the stack for the return values (and define these things) v.Declare(functype.Type().Params.Objects[i].Name, functype.Type().Params.Objects[i].Type) } v.Stack = v.Stack.New("arguments") for i := len(e.Args) - 1; i >= 0; i-- { v.CompileExpression(e.Args[i]) } // FIXME: I assume here that there is no return value! v.Append(x86.Commented(x86.Call(x86.Symbol("main_"+fn.Name)), fmt.Sprint(pos.Filename, ": line ", pos.Line))) v.Stack = v.Stack.Parent // A hack to let the callee clean up arguments } } else { panic(fmt.Sprintf("I don't know how to deal with complicated function: %s", e.Fun)) } case *ast.Ident: evar := v.Stack.Lookup(e.Name) switch SizeOnStack(evar.Type()) { case 4: v.Append(x86.Commented(x86.MovL(evar.InMemory(), x86.EAX), "Reading variable "+e.Name)) v.Append(x86.PushL(x86.EAX)) v.Stack.DefineVariable("_copy_of_"+e.Name, evar.Type()) case 8: v.Append(x86.Comment(fmt.Sprintf("The offset of %s is %s", e.Name, evar.InMemory()))) v.Append(x86.Commented(x86.MovL(evar.InMemory().Add(4), x86.EAX), "Reading variable "+e.Name)) v.Append(x86.MovL(evar.InMemory(), x86.EBX)) v.Append(x86.PushL(x86.EAX)) v.Append(x86.PushL(x86.EBX)) v.Stack.DefineVariable("_copy_of_"+e.Name, evar.Type()) default: panic(fmt.Sprintf("I don't handle variables with length %s", SizeOnStack(evar.Type()))) } default: panic(fmt.Sprintf("I can't handle expressions such as: %T value %s", exp, exp)) } }