func printPackage(p *tp.Package, indLvl int) { printIndent("Name -> %v", indLvl, p.GetName()) printIndent("Path -> %v", indLvl, p.GetPath()) printIndent("Dependencies:", indLvl) for ind, item := range p.GetDependencies() { printIndent("Dependecny[%v] -> %v", indLvl+1, ind, item) } printIndent("Types:", indLvl) for ind, item := range p.GetTypes() { printIndent("Type[%v] -> %v", indLvl+1, ind, item) } printIndent("Functions:", indLvl) for ind, item := range p.GetFunctions() { printIndent("Function[%v]:", indLvl+1, ind) printFunction(item, indLvl+2) } }
func NewLinkingContext(pkg *tp.Package) *LinkingContext { // Setup the function map! functionLookup := make([]FuncMap, len(pkg.Types)) types := make([]string, len(pkg.Types)) for typeId, typeObj := range pkg.Types { funcMap := make(FuncMap) types[typeId] = typeObj.GetName() implements := functionLookup[typeObj.GetImplements()] for index, fun := range pkg.Functions { stub := fun.Stub(pkg) funScopeId := fun.GetScopeTypeId() inherited := false // funScopeId is ancestor of typeId if (implements != nil) && pkg.AncestorOf(funScopeId, int32(typeId)) { _, inherited = implements[stub] } if (funScopeId == int32(typeId)) || inherited { funcMap[stub] = index } } functionLookup[typeId] = funcMap } // Setup the main context object ctx := &LinkingContext{ funList: functionLookup, types: types, Errors: make([]string, 0), Transform: &tp.Transform{ Pkg: pkg, }, } // Find Text type int -- need its ID to deal with Text literals during processing ctx.textType = pkg.GetTypeId("Text") return ctx }
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 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 ReadPackageDefinitions(pkg *tp.Package, projectPath, scriptPath, fileName string) { //pkg.Println(" -- reading definitions") _, err := ioutil.ReadFile(filepath.Join(projectPath, scriptPath, fileName)) //()("READING DEFINITIONS:", location) if err != nil { //pkg.Log.Infof("\t -- no user defined functions found") // msg := fmt.Sprintf("unable to open function definition file: %s", location) // println(msg) // panic(msg) return } definitions := parser.ParseFile(projectPath, scriptPath, fileName, false, make([]string, 0)) // Create a map of pre-packaged function signatures prepackaged := make(map[string]bool) for _, f := range pkg.Functions { var sig string baseSig := f.Stub(pkg) if baseSig == "name,Text" || baseSig == "text" { sig = fmt.Sprintf("%s.%s", f.ScopeTypeString(pkg), f.Stub(pkg)) } else { sig = baseSig } prepackaged[sig] = true } // println("*****************") // println("*****************") // println() // println() for _, function := range definitions.Functions { if function.GetName() == "@import" { // check if it's an import stub first ... importPath := function.GetDescription() // Verify the existence of the imported file from here, so that we can // report the name of the file that contains the import statement. importExists, existsErr := exists(filepath.Join(projectPath, importPath)) if !importExists || (existsErr != nil) { errURL := "http://help.moovweb.com/entries/22335641-importing-non-existent-files-in-functions-main-ts" msg := fmt.Sprintf("\n********\nin file %s:\nattempting to import nonexistent file %s\nPlease consult %s for more information about this error.\n********\n", filepath.Join(scriptPath, fileName), importPath, errURL) panic(msg) } ReadPackageDefinitions(pkg, projectPath, filepath.Dir(importPath), filepath.Base(importPath)) } else { // otherwise if it's not an import stub ... //pkg.Log.Infof("\t -- function: %v", function) resolveDefinition(pkg, function, filepath.Join(scriptPath, fileName)) // After resolving a user-defined function, see if its fully resolved signature // is the same as the signature of a prepackaged function. If so, throw an error. // var newSig string // newBaseSig := function.Stub(pkg) // if newBaseSig == "name,Text" || // newBaseSig == "text" { // newSig = fmt.Sprintf("%s.%s", function.ScopeTypeString(pkg), function.Stub(pkg)) // } else { // newSig = newBaseSig // } // // present := false // _, present := prepackaged[newSig] // if present { // msg := fmt.Sprintf("Attempt to redefine prepackaged function: %s", strings.Replace(newSig, ",", "(", 1)+")") // println(msg) // panic(msg) // } pkg.Functions = append(pkg.Functions, function) } } }