github.com/tardisgo/tardisgo@v0.0.0-20161119180838-e0dd9a7e46b5/pogo/language.go (about) 1 // Copyright 2014 Elliott Stoneham and The TARDIS Go Authors 2 // Use of this source code is governed by an MIT-style 3 // license that can be found in the LICENSE file. 4 5 package pogo 6 7 import ( 8 "bytes" 9 "errors" 10 "fmt" 11 "go/types" 12 "os" 13 "strings" 14 "sync" 15 16 "github.com/tardisgo/tardisgo/tgossa" 17 "github.com/tardisgo/tardisgo/tgoutil" 18 "golang.org/x/tools/go/ssa" 19 ) 20 21 // The Language interface enables multiple target languages for TARDIS Go. 22 type Language interface { 23 RegisterName(val ssa.Value) string 24 DeclareTempVar(ssa.Value) string 25 LanguageName() string 26 FileTypeSuffix() string // e.g. ".go" ".js" ".hx" 27 FileStart(packageName, headerText string) string 28 FileEnd() string 29 SetPosHash() string 30 RunDefers(usesGr bool) string 31 GoClassStart() string 32 GoClassEnd(*ssa.Package) string 33 SubFnStart(int, bool, []ssa.Instruction) string 34 SubFnEnd(id int, pos int, mustSplit bool) string 35 SubFnCall(int) string 36 FuncName(*ssa.Function) string 37 FieldAddr(register string, v interface{}, errorInfo string) string 38 IndexAddr(register string, v interface{}, errorInfo string) string 39 Comment(string) string 40 LangName(p, o string) string 41 Const(lit ssa.Const, position string) (string, string) 42 NamedConst(packageName, objectName string, val ssa.Const, position string) string 43 Global(packageName, objectName string, glob ssa.Global, position string, isPublic bool) string 44 FuncStart(pName, mName string, fn *ssa.Function, blks []*ssa.BasicBlock, posStr string, isPublic, trackPhi, usesGr bool, canOptMap map[string]bool, reconstruct []tgossa.BlockFormat) string 45 RunEnd(fn *ssa.Function) string 46 FuncEnd(fn *ssa.Function) string 47 BlockStart(block []*ssa.BasicBlock, num int, emitPhi bool) string 48 BlockEnd(block []*ssa.BasicBlock, num int, emitPhi bool) string 49 Jump(to int, from int, code string) string 50 If(v interface{}, trueNext, falseNext, phi int, trueCode, falseCode, errorInfo string) string 51 Phi(register string, phiEntries []int, valEntries []interface{}, defaultValue, errorInfo string) string 52 LangType(types.Type, bool, string) string 53 Value(v interface{}, errorInfo string) string 54 BinOp(register string, regTyp types.Type, op string, v1, v2 interface{}, errorInfo string) string 55 UnOp(register string, regTyp types.Type, op string, v interface{}, commaOK bool, errorInfo string) string 56 Store(v1, v2 interface{}, errorInfo string) string 57 Send(v1, v2 interface{}, errorInfo string) string 58 Ret(values []*ssa.Value, errorInfo string) string 59 RegEq(r string) string 60 Call(register string, cc ssa.CallCommon, args []ssa.Value, isBuiltin, isGo, isDefer, usesGr bool, fnToCall, errorInfo string) string 61 Convert(register, langType string, destType types.Type, v interface{}, errorInfo string) string 62 MakeInterface(register string, regTyp types.Type, v interface{}, errorInfo string) string 63 ChangeInterface(register string, regTyp types.Type, v interface{}, errorInfo string) string 64 ChangeType(register string, regTyp, v interface{}, errorInfo string) string 65 Alloc(register string, heap bool, v interface{}, errorInfo string) string 66 MakeClosure(register string, v interface{}, errorInfo string) string 67 MakeSlice(register string, v interface{}, errorInfo string) string 68 MakeChan(register string, v interface{}, errorInfo string) string 69 MakeMap(register string, v interface{}, errorInfo string) string 70 Slice(register string, x, low, high interface{}, errorInfo string) string 71 Index(register string, v1, v2 interface{}, errorInfo string) string 72 RangeCheck(x, i interface{}, length int, errorInfo string) string 73 Field(register string, v interface{}, fNum int, name, errorInfo string, isFunctionName bool) string 74 MapUpdate(Map, Key, Value interface{}, errorInfo string) string 75 Lookup(register string, Map, Key interface{}, commaOk bool, errorInfo string) string 76 Extract(register string, tuple interface{}, index int, errorInfo string) string 77 Range(register string, v interface{}, errorInfo string) string 78 Next(register string, v interface{}, isString bool, errorInfo string) string 79 Panic(v1 interface{}, errorInfo string, usesGr bool) string 80 TypeStart(*types.Named, string) string 81 //TypeEnd(*types.Named, string) string 82 TypeAssert(Register string, X ssa.Value, AssertedType types.Type, CommaOk bool, errorInfo string) string 83 EmitTypeInfo() string 84 EmitInvoke(register, path string, isGo, isDefer, usesGr bool, callCommon interface{}, errorInfo string) string 85 FunctionOverloaded(pkg, fun string) bool 86 Select(isSelect bool, register string, v interface{}, CommaOK bool, errorInfo string) string 87 PeepholeOpt(opt, register string, code []ssa.Instruction, errorInfo string) string 88 DebugRef(userName string, v interface{}, errorInfo string) string 89 CanInline(v interface{}) bool 90 PhiCode(allTargets bool, targetPhi int, code []ssa.Instruction, errorInfo string) string 91 InitLang(*Compilation, *LanguageEntry) Language 92 } 93 94 // LanguageEntry holds the static infomation about each of the languages, expect this list to extend as more languages are added. 95 type LanguageEntry struct { 96 Language // A type implementing all of the interface methods. 97 buffer bytes.Buffer // Where the output is collected. 98 InstructionLimit int // How many instructions in a function before we need to split it up. 99 SubFnInstructionLimit int // When we split up a function, how large can each sub-function be? 100 PackageConstVarName string // The special constant name to specify a Package/Module name in the target language. 101 HeaderConstVarName string // The special constant name for a target-specific header. 102 Goruntime string // The location of the core implementation go runtime code for this target language. 103 TestFS string // the location of the test zipped file system, if present 104 LineCommentMark string // what marks the comment at the end of a line 105 StatementTerminator string // what marks the end of a statement, usually ";" 106 PseudoPkgPaths []string // paths of packages containing pseudo-functions 107 IgnorePrefixes []string // the prefixes to code to ignore during peephole optimization 108 files []FileOutput // files to write if no errors in compilation 109 GOROOT string // static part of the GOROOT path 110 TgtDir string // Target directory to write to 111 } 112 113 // FileOutput provides temporary storage of output file data, pending correct compilation 114 type FileOutput struct { 115 filename string 116 data []byte 117 } 118 119 // LanguageList holds the languages that can be targeted, and compilation run data 120 var LanguageList = make([]LanguageEntry, 0, 10) 121 var languageListAppendMutex sync.Mutex 122 123 // FindTargetLang returns the 1st LanguageList entry for the given language 124 func FindTargetLang(s string) (k int, e error) { 125 var v LanguageEntry 126 for k, v = range LanguageList { 127 if v.LanguageName() == s { 128 return 129 } 130 } 131 return -1, errors.New("Target Language Not Found: " + s) 132 } 133 134 // Utility comment emitter function. 135 func (comp *Compilation) emitComment(cmt string) { 136 l := comp.TargetLang 137 fmt.Fprintln(&LanguageList[l].buffer, LanguageList[l].Comment(cmt)) 138 } 139 140 // is there more than one package with this name? 141 // TODO consider using this function in pogo.emitFunctions() 142 func (comp *Compilation) isDupPkg(pn string) bool { 143 pnCount := 0 144 ap := comp.rootProgram.AllPackages() 145 for p := range ap { 146 if pn == ap[p].Pkg.Name() { 147 pnCount++ 148 } 149 } 150 return pnCount > 1 151 } 152 153 // FuncPathName returns a unique function path and name. 154 func (comp *Compilation) FuncPathName(fn *ssa.Function) (path, name string) { 155 rx := fn.Signature.Recv() 156 pf := tgoutil.MakeID(comp.rootProgram.Fset.Position(fn.Pos()).String()) //fmt.Sprintf("fn%d", fn.Pos()) 157 if rx != nil { // it is not the name of a normal function, but that of a method, so append the method description 158 pf = rx.Type().String() // NOTE no underlying() 159 } else { 160 if fn.Pkg != nil { 161 pf = fn.Pkg.Pkg.Path() // was .Name(), but not unique 162 } else { 163 goroot := tgoutil.MakeID(LanguageList[comp.TargetLang].GOROOT + string(os.PathSeparator)) 164 pf1 := strings.Split(pf, goroot) // make auto-generated names shorter 165 if len(pf1) == 2 { 166 pf = pf1[1] 167 } // TODO use GOPATH for names not in std pkgs 168 } 169 } 170 return pf, fn.Name() 171 }