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 getBody(name string, fun *tp.Function) (body string) { var start int var end int depth := 0 if fun.Instruction != nil { if len(fun.Instruction.Children) > 0 { for _, instruction := range fun.Instruction.Children { if *instruction.Type != constants.Instruction_TEXT { start = int(null.GetInt32(instruction.LineNumber)) break } } done := false thisInstruction := fun.Instruction.Children[len(fun.Instruction.Children)-1] for !done { if len(thisInstruction.Children) > 0 { thisInstruction = thisInstruction.Children[len(thisInstruction.Children)-1] depth += 1 } else { done = true end = int(null.GetInt32(thisInstruction.LineNumber)) } } } else { return "" } } else { return " [native function]" } data, err := ioutil.ReadFile("packages/" + name + "/functions.ts") if err != nil { panic("Couldnt find functions file for " + name) } lines := strings.Split(string(data), "\n") body = strings.Join(lines[start-1:end+depth], "\n") return }
func FindAncestralType(pkg *tp.Package, thisType int32) int32 { someType := pkg.Types[thisType] implements := null.GetInt32(someType.Implements) if implements != 0 { return implements } return -1 }
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 "" }
// TODO(SJ) : This should really return a list of descendants func (pkg *Package) FindDescendantType(thisType int32) int { for index, someType := range pkg.Types { implements := null.GetInt32(someType.Implements) if implements == thisType && implements != 0 { // The implements field defaults to 0. Base doesn't implement Base. Text doesn't implement Base // TODO(SJ): make the default value -1 so I know if its not set versus something is inheriting from base // pkg.Log.Info("=== %v is ancestor of %v === (%v is of type %v and implements : %v)\n", thisType, someType, null.GetString(someType.Name), index, implements) // println("CHECK:", someType.GetName(), "implements", pkg.GetTypeName(someType.GetImplements())) return index } } return -1 }
func (ctx *LinkingContext) link(objId, scopeType int) { obj := ctx.Objects[objId] if null.GetBool(obj.Linked) == false { obj.ScopeTypeId = proto.Int(scopeType) obj.Linked = proto.Bool(true) path := obj.GetName() ctx.files = append(ctx.files, path) ctx.ProcessInstruction(obj.Root, scopeType, path) ctx.files = ctx.files[:(len(ctx.files) - 1)] } else { if scopeType != int(null.GetInt32(obj.ScopeTypeId)) { ctx.error("script", "Imported a script in two different scopes! Not processing second import.") } } }
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 (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 (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 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 (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 (d *DefinitionList) generatePackageDocs(name string) { options := packager.BuildOptions() options["generate_docs"] = true pkg := packager.NewPackage(packager.DefaultPackagePath, options) pkg.Load(name) for tindex, ttype := range pkg.Types { ttypeString := null.GetString(ttype.Name) for _, fun := range pkg.Functions { stub := FuncStub(pkg.Package, fun) if tindex == int(null.GetInt32(fun.ScopeTypeId)) && d.Definitions[ttypeString][stub] == nil { function := &FunctionDefinition{ Name: null.GetString(fun.Name), ParentScope: ttypeString, ShortStub: ShortFuncStub(pkg.Package, fun), PackageName: name, } function.setID() description := null.GetString(fun.Description) if len(description) > 0 { lines := make([]string, 0) // Trim the description. Haml doesn't like extra new lines for _, line := range strings.Split(description, "\n") { if len(strings.TrimLeft(line, " \r\n")) > 0 { lines = append(lines, line) } } //function.Description = description // Hacky ... I need a way to specify the indent level to play nice w haml: function.Description = strings.Join(lines, "\n ") } // Description / Examples will come when we can look at comment nodes function.Stub = stub segments := strings.Split(function.Stub, ")") function.CallPattern = segments[0] + ")" function.ReturnType = fun.ReturnTypeString(pkg.Package) function.YieldType = fun.OpensTypeString(pkg.Package) //println("Getting body for function: " + stub + " from package : " + name) ancestralScope, ancestralStub := d.findAncestralFunction(pkg.Package, fun) if ancestralScope != nil { //println("Found ancestral function in scope:" + *ancestralScope) ancestralFunction := d.Definitions[*ancestralScope][*ancestralStub] delete(d.Definitions[*ancestralScope], *ancestralStub) // Delete it //println("Loading body from package:" + ancestralFunction.PackageName) function.Body = getBody(ancestralFunction.PackageName, fun) } else { function.Body = getBody(name, fun) } // Hacky ... I need a way to specify the indent level for the body text to play nice w haml: function.Body = strings.Join(strings.Split(function.Body, "\n"), "\n ") if d.Definitions[ttypeString] == nil { d.Definitions[ttypeString] = make(map[string]*FunctionDefinition) } d.Definitions[ttypeString][stub] = function } } } 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 (pkg *Package) resolveFunctionDescendants(fun *tp.Function) { // Check if this function contains any types that have descendants // name := fun.Stub(pkg.Package) // pkg.Log.Infof("Checking for inheritance on function: %v", name) newFun := &tp.Function{} inherit := false // Iterate over ScopeType, Arg types, return Type, opens Type // ScopeType thisTypeId := null.GetInt32(fun.ScopeTypeId) newType := pkg.Package.FindDescendantType(thisTypeId) if newType != -1 { if !inherit { // pkg.Log.Infof("\t -- ScopeType : Found ancestral type. Cloning function %v\n", null.GetString(fun.Name)) newFun = fun.Clone().(*tp.Function) // pkg.Log.Infof("\t -- New fun: %v", newFun) inherit = true } // pkg.Log.Infof("\t -- Resetting scopeId") newFun.ScopeTypeId = proto.Int32(int32(newType)) } // ReturnType thisTypeId = null.GetInt32(fun.ReturnTypeId) newType = pkg.Package.FindDescendantType(thisTypeId) if newType != -1 { if !inherit { // pkg.Log.Infof("\t -- ReturnType : Found ancestral type. Cloning function %v\n", null.GetString(fun.Name)) newFun = fun.Clone().(*tp.Function) // pkg.Log.Infof("\t -- New fun: %v", newFun) inherit = true } // pkg.Log.Infof("\t -- Resetting returnId") newFun.ReturnTypeId = proto.Int32(int32(newType)) } // OpensType thisTypeId = null.GetInt32(fun.OpensTypeId) newType = pkg.Package.FindDescendantType(thisTypeId) if newType != -1 { if !inherit { // pkg.Log.Infof("\t -- OpensType : Found ancestral type. Cloning function %v\n", null.GetString(fun.Name)) newFun = fun.Clone().(*tp.Function) // pkg.Log.Infof("\t -- New fun: %v", newFun) inherit = true } // pkg.Log.Infof("\t -- Resetting openTypeId") newFun.OpensTypeId = proto.Int32(int32(newType)) } // Arguments for index, arg := range fun.Args { thisTypeId = null.GetInt32(arg.TypeId) newType = pkg.Package.FindDescendantType(thisTypeId) if newType != -1 { if !inherit { // pkg.Log.Infof("\t -- ArgType : Found ancestral type. Cloning function %v\n", null.GetString(fun.Name)) newFun = fun.Clone().(*tp.Function) // pkg.Log.Infof("\t -- New fun: %v", newFun) inherit = true } // pkg.Log.Infof("\t -- Resetting argument") newFun.Args[index].TypeId = proto.Int32(int32(newType)) } } // pkg.Log.Infof("\t -- Old function: %v\n\t -- New function: %v\n", fun, newFun) if inherit { resolveDefinition(pkg.Package, newFun, "") pkg.Package.Functions = append(pkg.Package.Functions, newFun) // println("replicated", pkg.Package.GetTypeName(newFun.GetScopeTypeId()), newFun.Stub(pkg.Package)) } }
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) }
func (fun *Function) OpensTypeString(pkg2 protoface.Package) string { pkg := pkg2.(*Package) return pkg.GetTypeName(null.GetInt32(fun.OpensTypeId)) }