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  }