func (pkg *Package) resolveHeader(function *tp.Function) { returnType := null.GetString(function.ReturnType) if len(returnType) > 0 { function.ReturnTypeId = proto.Int32(int32(pkg.findTypeIndex(returnType))) function.ReturnType = nil } scopeType := null.GetString(function.ScopeType) if len(scopeType) > 0 { function.ScopeTypeId = proto.Int32(int32(pkg.findTypeIndex(scopeType))) function.ScopeType = nil } opensType := null.GetString(function.OpensType) if len(opensType) > 0 { function.OpensTypeId = proto.Int32(int32(pkg.findTypeIndex(opensType))) function.OpensType = nil } for _, arg := range function.Args { typeName := null.GetString(arg.TypeString) if len(typeName) > 0 { arg.TypeId = proto.Int32(int32(pkg.findTypeIndex(typeName))) arg.TypeString = nil } } }
func (m *Mixer) Write(path string) (outputPath string, err error) { name := null.GetString(m.Name) version := null.GetString(m.Version) outputPath = filepath.Join(path, name+"-"+version+".mxr") bytes, err := pb.Marshal(m) if err != nil { return } bytes = crypto.Encrypt(bytes) err = os.MkdirAll(path, fileutil.DIR_PERMS) if err != nil { return } err = ioutil.WriteFile(outputPath, bytes, fileutil.FILE_PERMS) if err != nil { return } return }
func (pkg *Package) Merge(otherPackage *tp.Package) { if otherPackage == nil { return } //// Reflection would make this code cleaner: var existingTypeId int for _, someType := range otherPackage.Types { existingTypeId = pkg.GetTypeId(null.GetString(someType.Name)) if existingTypeId == -1 { pkg.Types = append(pkg.Types, someType) } } for _, function := range otherPackage.Functions { if null.GetBool(function.BuiltIn) { pkg.resolveHeader(function) } else { resolveDefinition(pkg.Package, function, "") } pkg.Package.Functions = append(pkg.Package.Functions, function) } for _, dependency := range otherPackage.Dependencies { pkg.Dependencies = append(pkg.Dependencies, dependency) } otherName := null.GetString(otherPackage.Name) pkg.Dependencies = append(pkg.Dependencies, otherName) pkg.Log.Infof("Added dependency (" + otherName + ") to " + null.GetString(pkg.Name) + "'s loaded dependencies") }
func ancestralFuncStub(pkg *tp.Package, fun *tp.Function) *string { foundAncestor := false name := null.GetString(fun.Name) args := "" for _, arg := range fun.Args { argType := null.GetInt32(arg.TypeId) ancestralArgType := FindAncestralType(pkg, argType) if ancestralArgType != -1 { foundAncestor = true argType = ancestralArgType } argTypeString := pkg.GetTypeName(argType) argName := argTypeString argName = argName + " %" + null.GetString(arg.Name) args = args + ", " + argName } if len(args) > 1 { args = args[2:] } returnType := null.GetInt32(fun.ReturnTypeId) ancestralReturnType := FindAncestralType(pkg, returnType) if ancestralReturnType != -1 { foundAncestor = true returnType = ancestralReturnType } returnTypeString := pkg.GetTypeName(returnType) returnVal := name + "(" + args + ") " + returnTypeString + " " opensType := null.GetInt32(fun.OpensTypeId) ancestralOpensType := FindAncestralType(pkg, opensType) if ancestralOpensType != -1 { foundAncestor = true opensType = ancestralOpensType } opensTypeString := pkg.GetTypeName(opensType) if opensTypeString != "Base" { returnVal = returnVal + opensTypeString } if foundAncestor { return &returnVal } return nil }
func BuildMixer(buildPath string, name string, dataPath string) *Mixer { rawPath, err := findInBuildPath(buildPath, name) if err != nil { panic(err.Error()) } path := *rawPath raw_mixer := tp.NewMixer(filepath.Clean(path)) mixer := &Mixer{ Mixer: raw_mixer, LibraryPath: buildPath, DefinitionPath: path, DataPath: dataPath, } // println("func BuildMixer") // println("build path:", buildPath) // println("definition path:", path) // println() rewritersDirectory := filepath.Join(path, "/rewriters") mixer.Rewriters = tp.CollectFiles(rewritersDirectory) packageDirectory := filepath.Join(path, "/package") mixer.RootPackage = NewRootPackage(packageDirectory, null.GetString(mixer.Name), dataPath) mixer.loadDependentMixers() error := BuildRootPackage(mixer.RootPackage, packageDirectory, null.GetString(mixer.Name)) if error == nil { //mixer.RootPackage = pkg // Now that we're done resolving, slice off the members! (Ouch) mixer.Package = mixer.RootPackage.Package } else if error.Code != NOT_FOUND { //TODO : Put this into a debug log panic(error.Message) } versionFile := filepath.Join(mixer.DefinitionPath, "..", "..", "JENKINS") buildNumber, err := ioutil.ReadFile(versionFile) if err == nil { mixer.Version = proto.String(null.GetString(mixer.Version) + "." + strings.Trim(string(buildNumber), "\n\r ")) } return mixer }
func (result *CheckResult) CheckForLocationExport(script *tp.ScriptObject) { iterate(script, func(ins *tp.Instruction) { if *ins.Type == constants.Instruction_FUNCTION_CALL { name := null.GetString(ins.Value) if name == "export" { if ins.Arguments != nil { if null.GetString(ins.Arguments[0].Value) == "location" { result.AddScriptWarning(script, ins, "Incorrect export of location! Use \"Location\" not \"location\"") } } } } }) }
func ShortFuncStub(pkg *tp.Package, fun *tp.Function) string { name := null.GetString(fun.Name) args := "" for _, arg := range fun.Args { t := pkg.Types[int(null.GetInt32(arg.TypeId))] argName := null.GetString(t.Name) argName = argName args = args + ", " + argName } if len(args) > 1 { args = args[2:] } returnVal := name + "(" + args + ")" return returnVal }
func (f *Function) BaseSignature(pkg2 protoface.Package) string { pkg := pkg2.(*Package) args := "(" for i, arg := range f.Args { argName := null.GetString(arg.TypeString) if argName == "" { t := pkg.Types[int(null.GetInt32(arg.TypeId))] argName = null.GetString(t.Name) } if i != 0 { args += "," } args += argName } return fmt.Sprintf("%s.%s%s)", pkg.GetTypeName(f.GetScopeTypeId()), f.GetName(), args) }
func (pkg *Package) GetTypeId(name string) int { for id, typ := range pkg.Types { if null.GetString(typ.Name) == name { return id } } return -1 }
func (f *Function) Stub(pkg2 protoface.Package) string { pkg := pkg2.(*Package) ns := f.GetNamespace() if len(ns) == 0 { ns = "tritium" } fname := fmt.Sprintf("%s.%s", ns, f.GetName()) args := "" for _, arg := range f.Args { argName := null.GetString(arg.TypeString) if argName == "" { t := pkg.Types[int(null.GetInt32(arg.TypeId))] argName = null.GetString(t.Name) } args = args + "," + argName } return fname + args }
func (result *CheckResult) CheckForSelectText(script *tp.ScriptObject) { tester := MustCompile("([^\\[\\(^]|^)(text|comment)\\(\\)([^=]|$)") iterate(script, func(ins *tp.Instruction) { if *ins.Type == constants.Instruction_FUNCTION_CALL { name := null.GetString(ins.Value) if name == "$" || name == "select" || name == "move_here" || name == "move_to" || name == "move" { for _, arg := range ins.Arguments { xpath := null.GetString(arg.Value) if tester.Match([]byte(xpath)) { result.AddScriptWarning(script, ins, "Shouldn't use comment()/text() in '"+xpath+"'") } } } } }) }
func (m *Mixer) Inspect(printFunctions bool) { println("\tRewriters:") for _, rewriter := range m.Rewriters { fmt.Printf("\t\t -- %v\n", null.GetString(rewriter.Path)) } println("\tRoot Package:") fmt.Printf(m.packageSummary(printFunctions)) }
func (m *Mixer) Merge(otherMixer *Mixer) { // TODO(SJ) : Make sure there are no name collision in the following unions if len(otherMixer.Rewriters) > 0 { if len(m.Rewriters) > 0 { thisName := null.GetString(m.Name) otherName := null.GetString(otherMixer.Name) panic(fmt.Sprintf("Duplicate sets of rewriters. Mixer (%v) and mixer (%v) both define rewriters.", thisName, otherName)) } m.Rewriters = otherMixer.Rewriters } // Merge only exists on (tritium) packager.Package m.RootPackage.Merge(otherMixer.Package) // m.RootPackage.Dependencies = append(m.RootPackage.Dependencies, null.GetString(otherMixer.Name) ) }
func FuncStub(pkg *tp.Package, fun *tp.Function) string { name := null.GetString(fun.Name) args := "" for _, arg := range fun.Args { t := pkg.Types[int(null.GetInt32(arg.TypeId))] argName := null.GetString(t.Name) argName = argName + " %" + null.GetString(arg.Name) args = args + ", " + argName } if len(args) > 1 { args = args[2:] } returnVal := name + "(" + args + ") " + fun.ReturnTypeString(pkg) + " " opens := fun.OpensTypeString(pkg) if opens != "Base" { returnVal = returnVal + opens } return returnVal }
func (pkg *Package) findTypeIndex(name string) int { for index, typeObj := range pkg.Types { if name == null.GetString(typeObj.Name) { return index } } log.Panic("Bad type load order, type ", name, " unknown") return -1 }
func getRawTemplate(segmentName string, mixer *tp.Mixer) (rawTemplate []uint8, err error) { for _, segment := range mixer.Rewriters { _, thisName := filepath.Split(null.GetString(segment.Path)) if thisName == segmentName { return segment.Data, nil } } return nil, errors.New(fmt.Sprintf("Could not find rewriter: %v", segmentName)) }
func (result *CheckResult) CheckForNotMisuse(script *tp.ScriptObject) { iterate(script, func(ins *tp.Instruction) { if *ins.Type == constants.Instruction_FUNCTION_CALL { name := null.GetString(ins.Value) if name == "match" || name == "with" { if ins.Arguments != nil { for _, arg := range ins.Arguments { if *arg.Type == constants.Instruction_FUNCTION_CALL { if null.GetString(arg.Value) == "not" { result.AddScriptWarning(script, ins, "Possible misuse of not()– remember not is the opposite of with!") } } } } } } }) }
func (fun *Function) Clone() protoface.Function { bytes, err := pb.Marshal(fun) if err != nil { panic("Couldn't clone function" + null.GetString(fun.Name)) } newFun := &Function{} pb.Unmarshal(bytes, newFun) return newFun }
func Process(pkg *tp.Package) string { for tindex, ttype := range pkg.Types { ttypeString := null.GetString(ttype.Name) println() for _, fun := range pkg.Functions { if tindex == int(null.GetInt32(fun.ScopeTypeId)) { println(ttypeString + "." + FuncStub(pkg, fun)) } } } return "" }
func (result *CheckResult) CheckXpath(script *tp.ScriptObject) { iterate(script, func(ins *tp.Instruction) { if *ins.Type == constants.Instruction_FUNCTION_CALL { name := null.GetString(ins.Value) // These all take xpath as the first param for _, xpath_func := range xpath_funcs { if name == xpath_func { if ins.Arguments != nil { if len(ins.Arguments) > 0 { test_xpath := null.GetString(ins.Arguments[0].Value) err := xpath.Check(test_xpath) if err != nil { result.AddXpathWarning(script, ins, err.Error()) } } } } } } }) }
func (pkg *Package) GetProtoTypeId(name *string) *int32 { scopeTypeId := 0 typeName := null.GetString(name) if len(typeName) > 0 { scopeTypeId = pkg.GetTypeId(typeName) if scopeTypeId == -1 { panic("Didn't find type " + typeName) } //println("Set scope ID to ", scopeTypeId) } return pb.Int32(int32(scopeTypeId)) }
func NewObjectLinkingContext(pkg *tp.Package, objs []*tp.ScriptObject, projectPath, scriptPath string) *LinkingContext { // Setup object lookup map! objScriptLookup := make(map[string]int, len(objs)) for index, obj := range objs { objScriptLookup[null.GetString(obj.Name)] = index } ctx := NewLinkingContext(pkg) ctx.objMap = objScriptLookup ctx.Objects = objs ctx.ProjectFolder = projectPath ctx.ScriptsFolder = scriptPath ctx.Visiting = make(map[string]bool, 0) return ctx }
func (m *Mixer) Unpack(path string) { fullPath := filepath.Join(path, null.GetString(m.Name)+"-"+null.GetString(m.Version)) err := os.MkdirAll(fullPath, 0755) if err != nil { panic(err.Error()) } err = m.unpackFiles(filepath.Join(fullPath, "rewriters"), m.Rewriters) if err != nil { panic(err) } summary := m.packageSummary(true) packageFile := filepath.Join(fullPath, "package-summary.txt") err = ioutil.WriteFile(packageFile, []byte(summary), 0644) if err != nil { fmt.Printf("Warning : Couldn't write package summary") } fmt.Printf("* %v\n", packageFile) }
func (m *Mixer) packageSummary(printFunctions bool) string { summary := "" if m.Package != nil { summary += fmt.Sprintf("\t\t -- Name: %v\n", null.GetString(m.Package.Name)) summary += fmt.Sprintf("\t\t -- Types: %v\n", m.Package.Types) summary += fmt.Sprintf("\t\t -- Dependencies: %v\n", m.Package.Dependencies) if printFunctions { summary += fmt.Sprintf("\t\t -- Functions (%v):\n", len(m.Package.Functions)) for _, function := range m.Package.Functions { summary += fmt.Sprintf("\t\t\t %v\n", function.Stub(m.Package)) } } } return summary }
func (fun *Function) DebugInfo(pkg2 protoface.Package) string { pkg := pkg2.(*Package) name := fun.NameString() scopeType := fun.ScopeTypeString(pkg) returnType := fun.ReturnTypeString(pkg) openType := fun.OpensTypeString(pkg) args := "" for _, arg := range fun.Args { argName := null.GetString(arg.TypeString) if argName == "" { argName = pkg.GetTypeName(null.GetInt32(arg.TypeId)) } args = args + "," + argName } return "@func " + scopeType + "." + name + "(" + args + ") " + returnType + " " + openType }
func (pkg *Package) write() { // path, name := filepath.Split(pkg.location) // path, name := filepath.Split(pkg.LoadPath) // outputFilename := filepath.Join(path, name, name+".tpkg") name := null.GetString(pkg.Name) outputFilename := filepath.Join(pkg.LoadPath, name+".tpkg") bytes, err := proto.Marshal(pkg.Package) if err != nil { panic("Could not marshal package: " + name + " (" + err.Error() + ")") } bytes = crypto.Encrypt(bytes) ioutil.WriteFile(outputFilename, bytes, os.FileMode(0666)) pkg.OutputFile = outputFilename pkg.Println(" -- output: " + outputFilename) }
func (f *File) AbsolutePath(dir string) string { return filepath.Join(dir, null.GetString(f.Path)) }
func (ctx *LinkingContext) ProcessInstructionWithLocalScope(ins *tp.Instruction, scopeType int, localScope LocalDef, caller string, path string, justRoot bool) (returnType int) { returnType = -1 ins.IsValid = proto.Bool(true) switch *ins.Type { case constants.Instruction_IMPORT: importLocation := ins.GetValue() // keep track of which files we're inside of, to detect circular imports val, present := ctx.Visiting[importLocation] if present && val { ctx.error(ins, "Circular import detected: %s", importLocation) panic(fmt.Sprintf("Circular import detected: %s", importLocation)) } ctx.Visiting[importLocation] = true importId, ok := ctx.objMap[importLocation] if ok != true { ctx.error(ins, "Invalid import `%s`", ins.String()) } // if we're linking the whole tree, then recurse if !justRoot { // Make sure this object is linked with the right scopeType ctx.link(importId, scopeType) // otherwise just set the script object's scope type } else { ctx.Objects[importId].ScopeTypeId = proto.Int(scopeType) } // pop the import stack (for circular import detection) ctx.Visiting[importLocation] = false ins.ObjectId = proto.Int(importId) ins.Value = nil case constants.Instruction_LOCAL_VAR: name := null.GetString(ins.Value) if name == "1" || name == "2" || name == "3" || name == "4" || name == "5" || name == "6" || name == "7" { if len(ins.Arguments) > 0 { // We are going to assign something to this variable returnType = ctx.ProcessInstructionWithLocalScope(ins.Arguments[0], scopeType, localScope, caller, path, justRoot) if returnType != ctx.textType { ctx.error(ins, "Numeric local vars can ONLY be Text") } } if ins.Children != nil { for _, child := range ins.Children { ctx.ProcessInstructionWithLocalScope(child, ctx.textType, localScope, caller, path, justRoot) } } returnType = ctx.textType } else { // Not numeric. typeId, found := localScope[name] if found { returnType = typeId if len(ins.Arguments) > 0 { ctx.error(ins, "The local variable \"%%%s\" has been assigned before and cannot be reassigned! Open a scope on it if you need to alter the contents.", name) } else { if ins.Children != nil { for _, child := range ins.Children { returnType = ctx.ProcessInstructionWithLocalScope(child, typeId, localScope, caller, path, justRoot) } } } } else { if len(ins.Arguments) > 0 { // We are going to assign something to this variable // But first, check for possible mutation and prevent it for now. if ins.Children != nil { ctx.error(ins, "May not open a scope during initialization of local variable \"%%%s\".", name) } returnType = ctx.ProcessInstructionWithLocalScope(ins.Arguments[0], scopeType, localScope, caller, path, justRoot) localScope[name] = returnType } else { ctx.error(ins, "I've never seen the variable \"%%%s\" before! Please assign a value before usage.", name) } } } case constants.Instruction_FUNCTION_CALL: stub := null.GetString(ins.Value) if stub == "yield" { ins.YieldTypeId = proto.Int32(int32(scopeType)) } namespaces := ins.Namespaces() // ins.Namespace = nil // need to figure out where to do this step // process the args if ins.Arguments != nil { for _, arg := range ins.Arguments { argReturn := ctx.ProcessInstructionWithLocalScope(arg, scopeType, localScope, caller, path, justRoot) if argReturn == -1 { ctx.error(ins, "Invalid argument object %q", arg.String()) return } stub = stub + "," + ctx.types[argReturn] } } // for each namespace specified by the user, look up the function wrt the current context type + function name var funcId int var ok bool for _, ns := range namespaces { funcId, ok = ctx.funList[scopeType][ns+"."+stub] if ok { break } } if !ok { readableCalleeStub := readableStub(stub) readableCallerStub := readableStub(caller) location := "" if len(path) > 0 { location = path } else { location = "Package " + ctx.Pkg.GetName() } msg := fmt.Sprintf("%s:%d: function %s.%s does not exist in namespace %s", location, ins.GetLineNumber(), ctx.types[scopeType], readableCalleeStub, namespaces[0]) for i := 1; i < len(namespaces)-1; i++ { msg += ", " + namespaces[i] } if len(namespaces) > 1 { msg += " or " + namespaces[len(namespaces)-1] } msg += fmt.Sprintf("; (called from %s.%s).", ctx.types[scopeType], readableCallerStub) ctx.error(ins, msg) // message := fmt.Sprintf("Available functions in %s.%s:\n", ns, ctx.types[scopeType]) // ns := strings.SplitN(stub, ".", 2)[0] // nsPrefix := ns + "." // for funcName, _ := range ctx.funList[scopeType] { // if strings.HasPrefix(funcName, nsPrefix) { // message += "\t" + nsPrefix + readableStub(funcName) + "\n" // } // } // log.Printf("%s\n", message) // ctx.error(ins, "%s:%d: could not find function %s.%s.%s (called from %s.%s.%s)", location, ins.GetLineNumber(), ns, ctx.types[scopeType], readableCalleeStub, callerNamespace, ctx.types[scopeType], readableCallerStub) } else { ins.FunctionId = proto.Int32(int32(funcId)) fun := ctx.Pkg.Functions[funcId] returnType = int(null.GetInt32(fun.ReturnTypeId)) opensScopeType := int(null.GetInt32(fun.OpensTypeId)) if opensScopeType == 0 { // If we're a Base scope, don't mess with texas! opensScopeType = scopeType } // If it inherits: inheritedOpensScopeType := ctx.Pkg.FindDescendantType(int32(opensScopeType)) if inheritedOpensScopeType != -1 { opensScopeType = inheritedOpensScopeType } // Copy the local scope parentScope := localScope localScope = make(LocalDef, len(parentScope)) for s, t := range parentScope { localScope[s] = t } if ins.Children != nil { for _, child := range ins.Children { ctx.ProcessInstructionWithLocalScope(child, opensScopeType, localScope, stub, path, justRoot) // thread the name of the caller through the linkages } } } case constants.Instruction_TEXT: returnType = ctx.textType case constants.Instruction_BLOCK: if ins.Children != nil { for _, child := range ins.Children { returnType = ctx.ProcessInstructionWithLocalScope(child, scopeType, localScope, caller, path, justRoot) } } } return }
func resolveDefinition(pkg *tp.Package, fun *tp.Function, path string) { linkingContext := linker.NewLinkingContext(pkg) // pkg.Log.Infof("\t -- Resolving --\n") // pkg.Log.Infof("\t\t -- function: %v\n", fun) // Re-uses linker's logic to resolve function definitions if null.GetBool(fun.BuiltIn) == false { typeName := null.GetString(fun.ScopeType) // DON'T DO THE FOLLOWING HERE -- NEED TO RESOLVE INHERITANCE FIRST // // Make sure we're not replacing an existing function bacause it's (currently) a security risk // typeID := fun.GetScopeTypeId() // siblingFuncs := linkingContext.FunctionsIn(typeID) // // println("CHECKING FOR FRATRICIDE IN", typeName) // _, present := siblingFuncs[fun.Stub(pkg)] // if present { // msg := fmt.Sprintf("Redefining an existing function is not permitted: %s", fun.Stub(pkg)) // panic(msg) // } // // for name, sib := range siblingFuncs { // // println("\t", name, sib) // // } // ///////////////////////////////////////////////////////////////////////////// if len(typeName) != 0 { // When I pass in functions from the inheritance resolver, they're typeId is already set fun.ScopeTypeId = pkg.GetProtoTypeId(fun.ScopeType) fun.ScopeType = nil } localScope := make(linker.LocalDef, len(fun.Args)) // fun.ReturnTypeId = pkg.GetProtoTypeId(fun.ReturnType) for _, arg := range fun.Args { argTypeName := arg.TypeString var argTypeId int if argTypeName != nil { // Similar deal. Input functions from inheritance resolution already have ids set arg.TypeId = pkg.GetProtoTypeId(arg.TypeString) //println("Processing %", null.GetString(arg.Name)) argTypeId = pkg.GetTypeId(null.GetString(arg.TypeString)) arg.TypeString = nil } else { argTypeId = int(null.GetInt32(arg.TypeId)) } localScope[null.GetString(arg.Name)] = argTypeId } //pkg.Log.Infof("Some insitruction: %v, %s", fun.Instruction, null.GetString(fun.Name) ) scopeTypeId := int(null.GetInt32(fun.ScopeTypeId)) //pkg.Log.Infof("\t\t -- opening scope type : %v\n", scopeTypeId) returnType := linkingContext.ProcessInstructionWithLocalScope(fun.Instruction, scopeTypeId, localScope, *fun.Name, path, false) if linkingContext.HasErrors() { message := "" for _, msg := range linkingContext.Errors { message = message + "\n" + msg } panic(message) } fun.ReturnTypeId = proto.Int32(int32(returnType)) if fun.Instruction != nil { fun.Instruction.IterateAll(func(ins *tp.Instruction) { if *ins.Type == constants.Instruction_FUNCTION_CALL { if null.GetString(ins.Value) == "yield" { fun.OpensTypeId = ins.YieldTypeId } } }) } } //pkg.Log.Infof("\t\t -- done --\n") }
func (r *CheckResult) AddXpathWarning(obj *tp.ScriptObject, ins *tp.Instruction, message string) { warning := NewWarning(WARNING_XPATH, null.GetString(obj.Name), int(null.GetInt32(ins.LineNumber)), message) print("F") r.Warnings = append(r.Warnings, warning) }