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