func (p *Parser) Parse() *tp.ScriptObject { script := new(tp.ScriptObject) // script.Name = proto.String(p.FullPath) if !p.RootFile || TritiumParserShowRewriterFileName { script.Name = proto.String(filepath.Join(p.ScriptPath, p.FileName)) } else { script.Name = proto.String("__rewriter__") } stmts := tp.ListInstructions() defs := make([]*tp.Function, 0) // Add a new constructor in instruction.go // Look for the namespace directive first. if p.peek().Lexeme == NAMESPACE { p.namespaces() } for p.peek().Lexeme != EOF { switch p.peek().Lexeme { case FUNC: defs = append(defs, p.definition()) case OPEN: p.open(false) default: stmt := p.statement() stmts = append(stmts, stmt) // need to intersperse imports with definitions if constants.Instruction_InstructionType_name[int32(stmt.GetType())] == "IMPORT" { // Make a special function stub that represents the import. // Need to do this because we can't mix definitions and instructions in // the same array. imp := new(tp.Function) imp.Name = proto.String("@import") imp.Description = proto.String(stmt.GetValue()) defs = append(defs, imp) } } } if len(defs) == 0 { defs = nil } var line int32 if len(stmts) == 0 { stmts = nil } else { line = *stmts[0].LineNumber } script.Functions = defs script.Root = tp.MakeBlock(stmts, line) // if defs == nil && p.currentNamespace() != "tritium" { // panic(fmt.Sprintf("%s: %d -- custom modules may only be declared in function definition files", p.FileName, moduleLineNum)) // } return script }
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) 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 } } }
// can't re-use the legacy native function resolver because it's a method of a // type that provides its own helpers and contextual data, all of which would // be too hard to reproduce func (pkgr *Packager) resolveNativeDeclaration(f *tp.Function, path string) { // first we should check that the signature refers to something that actually exists sigStr := strings.Replace(f.Stub(pkgr.Package), ",", ".", -1) if whale.LookupBuiltIn(sigStr) == nil { panic(fmt.Sprintf("attempt to provide signature for nonexistent native function `%s` in `%s`", sigStr, path)) } // now turn the type names into the appropriate numeric ids if returnType := f.GetReturnType(); len(returnType) > 0 { f.ReturnTypeId = proto.Int32(int32(pkgr.TypeMap[returnType])) f.ReturnType = nil } if scopeType := f.GetScopeType(); len(scopeType) > 0 { f.ScopeTypeId = proto.Int32(int32(pkgr.TypeMap[scopeType])) f.ScopeType = nil } if opensType := f.GetOpensType(); len(opensType) > 0 { f.OpensTypeId = proto.Int32(int32(pkgr.TypeMap[opensType])) f.OpensType = nil } for _, arg := range f.Args { if typeName := arg.GetTypeString(); len(typeName) > 0 { arg.TypeId = proto.Int32(int32(pkgr.TypeMap[typeName])) arg.TypeString = nil } } }
func (p *Parser) definition() *tp.Function { isSignature := false node := new(tp.Function) // functions should be injected only into the first specified namespace node.Namespace = proto.String(p.Defspace) funcLineNo := p.pop().LineNumber // pop the `@func` keyword contextType := "" if p.peek().Lexeme == TYPE { contextType = p.pop().Value if p.peek().Lexeme != DOT { p.error("function context and function name must be separated by '.'") } p.pop() // pop the dot } if p.peek().Lexeme != ID { p.error("invalid function name in definition") } funcName := p.pop().Value funcFile := "" if len(p.ScriptPath) > 0 && p.ScriptPath != "." { funcFile = filepath.Join(p.ScriptPath, p.FileName) } if p.peek().Lexeme != LPAREN { p.error("parenthesized parameter list expected in function declaration") } p.pop() // pop the lparen params := p.parameters(funcName) if len(params) == 0 { params = nil } p.pop() // pop the rparen returnType := "" opensType := "" if p.peek().Lexeme == TYPE { isSignature = true returnType = p.pop().Value if p.peek().Lexeme == TYPE { opensType = p.pop().Value } } node.Name = proto.String(funcName) if len(funcFile) > 0 { node.Filename = proto.String(funcFile) } node.LineNumber = proto.Int32(funcLineNo) node.Args = params node.ScopeType = proto.String(contextType) node.ReturnType = proto.String(returnType) node.OpensType = proto.String(opensType) if isSignature { if p.peek().Lexeme == LBRACE { p.error("body not permitted in signature for built-in " + funcName) } node.BuiltIn = proto.Bool(true) return node } node.BuiltIn = proto.Bool(false) if p.peek().Lexeme != LBRACE { p.error("definition for " + funcName + " is missing a body") } funcBody := &tp.Instruction{ Type: proto.Int32(constants.Instruction_BLOCK), // Children: p.block(), // use the wrapper to get a better error message Children: p.function_body(*node.Name), } node.Instruction = funcBody return node }
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 printFunction(f *tp.Function, indLvl int) { printIndent("Name -> %v", indLvl, f.GetName()) printIndent("Description -> %v", indLvl, f.GetDescription()) printIndent("Filename -> %v", indLvl, f.GetFilename()) printIndent("Line Number -> %v", indLvl, f.GetLineNumber()) printIndent("Namespace -> %v", indLvl, f.GetNamespace()) printIndent("Scope Type Id -> %v", indLvl, f.GetScopeTypeId()) printIndent("Scope Type -> %v", indLvl, f.GetScopeType()) printIndent("Return Type Id -> %v", indLvl, f.GetReturnTypeId()) printIndent("Return Type -> %v", indLvl, f.GetReturnType()) printIndent("Opens Type Id -> %v", indLvl, f.GetOpensTypeId()) printIndent("Opens Type -> %v", indLvl, f.GetOpensType()) printIndent("BuiltIn -> %v", indLvl, f.GetBuiltIn()) printIndent("Arguments:", indLvl) for ind, item := range f.GetArgs() { printIndent("Argument[%d] -> %v", indLvl, ind, item) } printIndent("Instruction:", indLvl) printInstruction(f.GetInstruction(), indLvl+1) }