// 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 (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 (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 }