github.com/tardisgo/tardisgo@v0.0.0-20161119180838-e0dd9a7e46b5/pogo/begin.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  	"fmt"
     9  	"go/token"
    10  	"sort"
    11  	"strconv"
    12  	"strings"
    13  
    14  	"go/constant"
    15  	"golang.org/x/tools/go/ssa"
    16  )
    17  
    18  // Recycle the Compilation resources.
    19  func (comp *Compilation) Recycle() { LanguageList[comp.TargetLang] = LanguageEntry{} }
    20  
    21  // Compile provides the entry point for the pogo package,
    22  // returning a pogo.Compilation structure and error
    23  func Compile(mainPkg *ssa.Package, debug, trace bool, langName, testFSname string) (*Compilation, error) {
    24  	comp := &Compilation{
    25  		mainPackage: mainPkg,
    26  		rootProgram: mainPkg.Prog,
    27  		DebugFlag:   debug,
    28  		TraceFlag:   trace,
    29  	}
    30  
    31  	k, e := FindTargetLang(langName)
    32  	if e != nil {
    33  		return nil, e
    34  	}
    35  	// make a new language list entry for this compilation
    36  	newLang := LanguageList[k]
    37  	languageListAppendMutex.Lock()
    38  	LanguageList = append(LanguageList, newLang)
    39  	comp.TargetLang = len(LanguageList) - 1
    40  	languageListAppendMutex.Unlock()
    41  	LanguageList[comp.TargetLang].Language =
    42  		LanguageList[comp.TargetLang].Language.InitLang(
    43  			comp, &LanguageList[comp.TargetLang])
    44  	LanguageList[comp.TargetLang].TestFS = testFSname
    45  	//fmt.Printf("DEBUG created TargetLang[%d]=%#v\n",
    46  	//	comp.TargetLang, LanguageList[comp.TargetLang])
    47  
    48  	comp.initErrors()
    49  	comp.initTypes()
    50  	comp.setupPosHash()
    51  	comp.loadSpecialConsts()
    52  	comp.emitFileStart()
    53  	comp.emitFunctions()
    54  	comp.emitGoClass(comp.mainPackage)
    55  	comp.emitTypeInfo()
    56  	comp.emitFileEnd()
    57  	if comp.hadErrors && comp.stopOnError {
    58  		err := fmt.Errorf("no output files generated")
    59  		comp.LogError("", "pogo", err)
    60  		return nil, err
    61  	}
    62  	comp.writeFiles()
    63  	return comp, nil
    64  }
    65  
    66  // The main Go class contains those elements that don't fit in functions
    67  func (comp *Compilation) emitGoClass(mainPkg *ssa.Package) {
    68  	comp.emitGoClassStart()
    69  	comp.emitNamedConstants()
    70  	comp.emitGlobals()
    71  	comp.emitGoClassEnd(mainPkg)
    72  	comp.WriteAsClass("Go", "")
    73  }
    74  
    75  // special constant name used in TARDIS Go to put text in the header of files
    76  const pogoHeader = "tardisgoHeader"
    77  const pogoLibList = "tardisgoLibList"
    78  
    79  func (comp *Compilation) loadSpecialConsts() {
    80  	hxPkg := ""
    81  	l := comp.TargetLang
    82  	ph := LanguageList[l].HeaderConstVarName
    83  	targetPackage := LanguageList[l].PackageConstVarName
    84  	header := ""
    85  	allPack := comp.rootProgram.AllPackages()
    86  	sort.Sort(PackageSorter(allPack))
    87  	for _, pkg := range allPack {
    88  		allMem := MemberNamesSorted(pkg)
    89  		for _, mName := range allMem {
    90  			mem := pkg.Members[mName]
    91  			if mem.Token() == token.CONST {
    92  				switch mName {
    93  				case ph, pogoHeader: // either the language-specific constant, or the standard one
    94  					lit := mem.(*ssa.NamedConst).Value
    95  					switch lit.Value.Kind() {
    96  					case constant.String:
    97  						h, err := strconv.Unquote(lit.Value.String())
    98  						if err != nil {
    99  							comp.LogError(comp.CodePosition(lit.Pos())+"Special pogo header constant "+ph+" or "+pogoHeader,
   100  								"pogo", err)
   101  						} else {
   102  							header += h + "\n"
   103  						}
   104  					}
   105  				case targetPackage:
   106  					lit := mem.(*ssa.NamedConst).Value
   107  					switch lit.Value.Kind() {
   108  					case constant.String:
   109  						hp, err := strconv.Unquote(lit.Value.String())
   110  						if err != nil {
   111  							comp.LogError(comp.CodePosition(lit.Pos())+"Special targetPackage constant ", "pogo", err)
   112  						}
   113  						hxPkg = hp
   114  					default:
   115  						comp.LogError(comp.CodePosition(lit.Pos()), "pogo",
   116  							fmt.Errorf("special targetPackage constant not a string"))
   117  					}
   118  				case pogoLibList:
   119  					lit := mem.(*ssa.NamedConst).Value
   120  					switch lit.Value.Kind() {
   121  					case constant.String:
   122  						lrp, err := strconv.Unquote(lit.Value.String())
   123  						if err != nil {
   124  							comp.LogError(comp.CodePosition(lit.Pos())+"Special "+pogoLibList+" constant ", "pogo", err)
   125  						}
   126  						comp.LibListNoDCE = strings.Split(lrp, ",")
   127  						for lib := range comp.LibListNoDCE {
   128  							comp.LibListNoDCE[lib] = strings.TrimSpace(comp.LibListNoDCE[lib])
   129  						}
   130  					default:
   131  						comp.LogError(comp.CodePosition(lit.Pos()), "pogo",
   132  							fmt.Errorf("special targetPackage constant not a string"))
   133  					}
   134  				}
   135  			}
   136  		}
   137  	}
   138  	comp.hxPkgName = hxPkg
   139  	comp.headerText = header
   140  }
   141  
   142  // emit the standard file header for target language
   143  func (comp *Compilation) emitFileStart() {
   144  	l := comp.TargetLang
   145  	fmt.Fprintln(&LanguageList[l].buffer,
   146  		LanguageList[l].FileStart(comp.hxPkgName, comp.headerText))
   147  }
   148  
   149  // emit the tail of the required language file
   150  func (comp *Compilation) emitFileEnd() {
   151  	l := comp.TargetLang
   152  	fmt.Fprintln(&LanguageList[l].buffer, LanguageList[l].FileEnd())
   153  	for w := range comp.warnings {
   154  		comp.emitComment(comp.warnings[w])
   155  	}
   156  	comp.emitComment("Package List:")
   157  	allPack := comp.rootProgram.AllPackages()
   158  	sort.Sort(PackageSorter(allPack))
   159  	for pkgIdx := range allPack {
   160  		comp.emitComment(" " + allPack[pkgIdx].String())
   161  	}
   162  }
   163  
   164  // emit the start of the top level type definition for each language
   165  func (comp *Compilation) emitGoClassStart() {
   166  	l := comp.TargetLang
   167  	fmt.Fprintln(&LanguageList[l].buffer, LanguageList[l].GoClassStart())
   168  }
   169  
   170  // emit the end of the top level type definition for each language file
   171  func (comp *Compilation) emitGoClassEnd(pak *ssa.Package) {
   172  	l := comp.TargetLang
   173  	fmt.Fprintln(&LanguageList[l].buffer, LanguageList[l].GoClassEnd(pak))
   174  }
   175  
   176  /*
   177  func (comp *Compilation) UsingPackage(pkgName string) bool {
   178  	//println("DEBUG UsingPackage() looking for: ", pkgName)
   179  	pkgName = "package " + pkgName
   180  	pkgs := comp.rootProgram.AllPackages()
   181  	for p := range pkgs {
   182  		//println("DEBUG UsingPackage() considering pkg: ", pkgs[p].String())
   183  		if pkgs[p].String() == pkgName {
   184  			//println("DEBUG UsingPackage()  ", pkgName, " = true")
   185  			return true
   186  		}
   187  	}
   188  	//println("DEBUG UsingPackage()  ", pkgName, " =false")
   189  	return false
   190  }
   191  */