mirror of
https://github.com/robertkrimen/otto
synced 2025-09-28 18:45:22 +08:00
535 lines
11 KiB
Go
535 lines
11 KiB
Go
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
|
|
}
|
|
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
|
|
})
|
|
|
|
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)
|
|
}
|
|
}
|
|
|
|
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 "<into> 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 "<initial> ;"
|
|
|
|
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)
|
|
}
|