package otto import ( ) func (self *_parser) ParseStatement() _node { switch self.Peek().Kind { case ";": self.Next() node := newEmptyNode() self.markNode(node) return node case "if": return self.ParseIf() case "do": return self.ParseDoWhile() case "while": return self.ParseWhile() case "for": return self.ParseForOrForIn() case "continue": return self.ParseContinue() case "with": return self.ParseWith() case "break": return self.ParseBreak() case "{": return self.ParseBlock() case "var": return self.ParseVariableStatement() case "function": self.ParseFunctionDeclaration() // TODO Should be FunctionDeclarationStatement node := newEmptyNode() self.markNode(node) return node case "switch": return self.ParseSwitch() case "return": return self.ParseReturnStatement() case "throw": return self.ParseThrow() case "try": return self.ParseTryCatch() } expression := self.ParseExpression() if identifier, yes := expression.(*_identifierNode); yes && self.Accept(":") { _labelSet := self.Scope()._labelSet label := identifier.Value if _labelSet[label] { panic(self.History(-2).newSyntaxError("Label '%s' has already been declared", label)) } _labelSet[label] = true statement := self.ParseStatement() delete(_labelSet, label) { _labelSet = nil switch node := statement.(type) { case *_doWhileNode: _labelSet = node._labelSet case *_whileNode: _labelSet = node._labelSet case *_switchNode: _labelSet = node._labelSet case *_forNode: _labelSet = node._labelSet case *_forInNode: _labelSet = node._labelSet } if _labelSet != nil { _labelSet[label] = true } } return statement } self.ConsumeSemicolon() return expression } //func (self *_parser) parseSource() []_node { // nodeList := self.parseStatementUntil(func() bool { // return self.Match("EOF") // }); // return self.ParseStatement() //} func (self *_parser) parseSourceElement() _node { return self.ParseStatement() } func (self *_parser) ParseTryCatch() _node { self.Expect("try") node := newTryCatchNode(self.ParseBlock()) found := false if self.Accept("catch") { self.Expect("(") identifier := self.ConsumeIdentifier().Value self.Expect(")") node.Catch = newCatchNode(identifier, self.ParseBlock()) found = true } if self.Accept("finally") { node.Finally = self.ParseBlock() found = true } if !found { panic(self.Peek().newSyntaxError("Missing catch or finally after try")) } return node } func (self *_parser) ParseWith() _node { self.Expect("with") return newWithNode(self.ParseExpression(), self.ParseStatement()) } func (self *_parser) ParseContinue() _node { result := self.ParseContinueBreak("continue", func(kind string) _node { return newContinueNode(kind) }) if self.Scope().InIteration { return result } panic(self.Peek().newSyntaxError("Illegal continue statement")) } func (self *_parser) ParseBreak() _node { result := self.ParseContinueBreak("break", func(kind string) _node { return newBreakNode(kind) }) if self.Scope().InIteration || self.Scope().InSwitch { return result } panic(self.Peek().newSyntaxError("Illegal break statement")) } func (self *_parser) ParseContinueBreak(kind string, _newNode func(string) _node) _node { self.Expect(kind) if self.Accept(";") || self.Accept("\n") { return _newNode("") } label := "" if self.Match("identifier") { identifier := self.ConsumeIdentifier() label = identifier.Value if !self.Scope().HasLabel(label) { panic(self.History(-1).newSyntaxError("Undefined label '%s'", label)) } } self.ConsumeSemicolon() return _newNode(label) } func (self *_parser) parseInFunction(parse func() _node) _node { in := self.Scope().InFunction self.Scope().InFunction = true defer func(){ self.Scope().InFunction = in }() return parse() } func (self *_parser) parseInSwitch(parse func() _node) _node { in := self.Scope().InSwitch self.Scope().InSwitch = true defer func(){ self.Scope().InSwitch = in }() return parse() } func (self *_parser) parseInIteration(parse func() _node) _node { in := self.Scope().InIteration self.Scope().InIteration = true defer func(){ self.Scope().InIteration = in }() return parse() } func (self *_parser) ParseDoWhile() _node { self.Expect("do") body := self.parseInIteration(func() _node{ return self.ParseStatement() }) self.Expect("while") self.Expect("(") test := self.ParseExpression() self.Expect(")") node := newDoWhileNode(test, body) node._labelSet[""] = true return node } func (self *_parser) ParseWhile() _node { self.Expect("while") self.Expect("(") test := self.ParseExpression() self.Expect(")") body := self.parseInIteration(func() _node{ return self.ParseStatement() }) node := newWhileNode(test, body) node._labelSet[""] = true return node } func (self *_parser) ParseIf() _node { self.Expect("if") self.Expect("(") node := newIfNode(self.ParseExpression(), nil) self.Expect(")") node.Consequent = self.ParseStatement() if self.Accept("else") { node.Alternate = self.ParseStatement() } return node } func (self *_parser) parseStatementUntil(stop func() bool) []_node { list := []_node{} for { if stop() { break } list = append(list, self.ParseStatement()) } return list } func (self *_parser) ParseBlock() *_blockNode { node := newBlockNode() self.markNode(node) self.Expect("{") node.Body = self.parseStatementUntil(func() bool { return self.Accept("}") }) return node } func (self *_parser) ParseReturnStatement() _node { self.Expect("return") if !self.Scope().InFunction { panic(self.History(-1).newSyntaxError("Illegal return statement")) } node := newReturnNode() self.markNode(node) if self.Match("\n") { return node } if !self.Match(";") { if !self.Match("}") && !self.Match("EOF") { node.Argument = self.ParseExpression() } } self.ConsumeSemicolon() return node } func (self *_parser) ParseThrow() _node { self.Expect("throw") if self.Match("\n") { // TODO Better error message panic(self.Peek().newSyntaxError("Illegal newline after throw")) } node := newThrowNode(self.ParseExpression()) self.markNode(node) self.ConsumeSemicolon() return node } func (self *_parser) ParseSwitch() _node { self.Expect("switch") self.Expect("(") discriminant := self.ParseExpression() self.Expect(")") switchNode := newSwitchNode(discriminant) self.markNode(switchNode) self.Expect("{") self.parseInSwitch(func() _node { for i := 0; true; i++ { if self.Accept("}") { break } result := self.ParseCase() if result.Test == nil { if switchNode.Default != -1 { panic(hereBeDragons("Already saw a default:")) } switchNode.Default = i } switchNode.AddCase(result) } return nil }) switchNode._labelSet[""] = true return switchNode } func (self *_parser) ParseCase() *_caseNode { var node *_caseNode if self.Accept("default") { node = newDefaultCaseNode() self.markNode(node) } else { self.Expect("case") node = newCaseNode(self.ParseExpression()) self.markNode(node) } self.Expect(":") node.Body = self.parseStatementUntil(func() bool { return false || self.Match("EOF") || self.Match("}") || self.Match("default") || self.Match("case") }) return node } func (self *_parser) ParseVariable() *_variableDeclarationNode { node := newVariableDeclarationNode(self.ConsumeIdentifier().Value) self.markNode(node) for _, value := range []string{"=", ":="} { if self.Accept(value) { node.Operator = value node.Initializer = self.ParseAssignmentExpression() break } } return node } func (self *_parser) ParseVariableDeclaration() *_variableDeclarationListNode { self.Expect("var") node := newVariableDeclarationListNode() self.markNode(node) for { variable := self.ParseVariable() node.VariableList = append(node.VariableList, variable) self.Scope().AddVariable(variable.Identifier) if !self.Accept(",") { break } } return node } func (self *_parser) ParseVariableStatement() *_variableDeclarationListNode { node := self.ParseVariableDeclaration() self.ConsumeSemicolon() return node } func (self *_parser) ParseFunction(declare bool) _node { self.Expect("function") functionNode := newFunctionNode() self.markNode(functionNode) if self.Match("identifier") { identifier := self.ConsumeIdentifier() if declare { self.Scope().AddFunction(identifier.Value, functionNode) } } else if declare { // Trigger a panic, because we really should see // an identifier here self.Expect("identifier") } token := self.Peek() if token.Kind != "(" { panic(self.Unexpected(token)) } self.Expect("(") for !self.Accept(")") { identifier := self.ConsumeIdentifier().Value functionNode.AddParameter(identifier) if identifier == "arguments" { functionNode.ArgumentsIsParameter = true } if !self.Match(")") { self.Expect(",") } } { self.EnterScope() defer self.LeaveScope() self.parseInFunction(func() _node { functionNode.Body = self.ParseBlock().Body return nil }) functionNode.VariableList = self.Scope().VariableList functionNode.FunctionList = self.Scope().FunctionList } return functionNode; } /*func (self *_parser) ParseFunctionParameterList() []string {*/ /* parameterList := []string{}*/ /* for !self.Match("EOF") {*/ /* identifier := self.ConsumeIdentifier().Value*/ /* parameterList = append(parameterList, identifier)*/ /* }*/ /* return parameterList*/ /*}*/ func (self *_parser) ParseFunctionDeclaration() { self.ParseFunction(true) } func (self *_parser) parseForIn(into _node) *_forInNode { // Already have consumed " in" source := self.ParseExpression() self.Expect(")") body := self.parseInIteration(func() _node{ return self.ParseStatement() }) node := newForInNode(into, source, body) self.markNode(node) node._labelSet[""] = true return node } func (self *_parser) parseFor(initial _node) *_forNode { // Already have consumed " ;" var test, update _node if !self.Match(";") { test = self.ParseExpression() } self.Expect(";") if !self.Match(")") { update = self.ParseExpression() } self.Expect(")") body := self.parseInIteration(func() _node{ return self.ParseStatement() }) node := newForNode(initial, test, update, body) self.markNode(node) node._labelSet[""] = true return node } func (self *_parser) ParseForOrForIn() _node { self.Expect("for") self.Expect("(") var left _node isIn := false if !self.Match(";") { previousAllowIn := self.Scope().AllowIn self.Scope().AllowIn = false if self.Match("var") { declarationList := self.ParseVariableDeclaration() if len(declarationList.VariableList) == 1 && self.Accept("in") { isIn = true // We only want (there should be only) one _declaration // (12.2 Variable Statement) left = declarationList.VariableList[0] } else { left = declarationList } } else { left = self.ParseExpression() isIn = self.Accept("in") } self.Scope().AllowIn = previousAllowIn } if !isIn { self.Expect(";") return self.parseFor(left) } else { switch left.Type() { case nodeIdentifier, nodeDotMember, nodeBracketMember, nodeVariableDeclaration: default: panic(self.History(-1).newSyntaxError("Invalid left-hand side in for-in")) } } return self.parseForIn(left) }