mirror of https://github.com/status-im/op-geth.git
Merge pull request #2227 from bas-vk/mathrandom
console: seed random number generator
This commit is contained in:
commit
c305005d83
|
@ -84,7 +84,7 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "github.com/robertkrimen/otto",
|
"ImportPath": "github.com/robertkrimen/otto",
|
||||||
"Rev": "c21072f61b64b51ea58138ccacf0a85d54b9f07c"
|
"Rev": "53221230c215611a90762720c9042ac782ef74ee"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "github.com/syndtr/goleveldb/leveldb",
|
"ImportPath": "github.com/syndtr/goleveldb/leveldb",
|
||||||
|
|
92
Godeps/_workspace/src/github.com/robertkrimen/otto/ast/comments.go
generated
vendored
Normal file
92
Godeps/_workspace/src/github.com/robertkrimen/otto/ast/comments.go
generated
vendored
Normal file
|
@ -0,0 +1,92 @@
|
||||||
|
package ast
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/robertkrimen/otto/file"
|
||||||
|
)
|
||||||
|
|
||||||
|
// CommentPosition determines where the comment is in a given context
|
||||||
|
type CommentPosition int
|
||||||
|
|
||||||
|
const (
|
||||||
|
_ CommentPosition = iota
|
||||||
|
LEADING // Before the pertinent expression
|
||||||
|
TRAILING // After the pertinent expression
|
||||||
|
KEY // After a key or keyword
|
||||||
|
COLON // After a colon in a field declaration
|
||||||
|
FINAL // Final comments in a block, not belonging to a specific expression or the comment after a trailing , in an array or object literal
|
||||||
|
TBD
|
||||||
|
)
|
||||||
|
|
||||||
|
// Comment contains the data of the comment
|
||||||
|
type Comment struct {
|
||||||
|
Begin file.Idx
|
||||||
|
Text string
|
||||||
|
Position CommentPosition
|
||||||
|
}
|
||||||
|
|
||||||
|
// String returns a stringified version of the position
|
||||||
|
func (cp CommentPosition) String() string {
|
||||||
|
switch cp {
|
||||||
|
case LEADING:
|
||||||
|
return "Leading"
|
||||||
|
case TRAILING:
|
||||||
|
return "Trailing"
|
||||||
|
case KEY:
|
||||||
|
return "Key"
|
||||||
|
case COLON:
|
||||||
|
return "Colon"
|
||||||
|
case FINAL:
|
||||||
|
return "Final"
|
||||||
|
default:
|
||||||
|
return "???"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// String returns a stringified version of the comment
|
||||||
|
func (c Comment) String() string {
|
||||||
|
return fmt.Sprintf("Comment: %v", c.Text)
|
||||||
|
}
|
||||||
|
|
||||||
|
// CommentMap is the data structure where all found comments are stored
|
||||||
|
type CommentMap map[Node][]*Comment
|
||||||
|
|
||||||
|
// AddComment adds a single comment to the map
|
||||||
|
func (cm CommentMap) AddComment(node Node, comment *Comment) {
|
||||||
|
list := cm[node]
|
||||||
|
list = append(list, comment)
|
||||||
|
|
||||||
|
cm[node] = list
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddComments adds a slice of comments, given a node and an updated position
|
||||||
|
func (cm CommentMap) AddComments(node Node, comments []*Comment, position CommentPosition) {
|
||||||
|
for _, comment := range comments {
|
||||||
|
comment.Position = position
|
||||||
|
cm.AddComment(node, comment)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Size returns the size of the map
|
||||||
|
func (cm CommentMap) Size() int {
|
||||||
|
size := 0
|
||||||
|
for _, comments := range cm {
|
||||||
|
size += len(comments)
|
||||||
|
}
|
||||||
|
|
||||||
|
return size
|
||||||
|
}
|
||||||
|
|
||||||
|
// MoveComments moves comments with a given position from a node to another
|
||||||
|
func (cm CommentMap) MoveComments(from, to Node, position CommentPosition) {
|
||||||
|
for i, c := range cm[from] {
|
||||||
|
if c.Position == position {
|
||||||
|
cm.AddComment(to, c)
|
||||||
|
|
||||||
|
// Remove the comment from the "from" slice
|
||||||
|
cm[from][i] = cm[from][len(cm[from])-1]
|
||||||
|
cm[from][len(cm[from])-1] = nil
|
||||||
|
cm[from] = cm[from][:len(cm[from])-1]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -86,6 +86,11 @@ type (
|
||||||
Identifier Identifier
|
Identifier Identifier
|
||||||
}
|
}
|
||||||
|
|
||||||
|
EmptyExpression struct {
|
||||||
|
Begin file.Idx
|
||||||
|
End file.Idx
|
||||||
|
}
|
||||||
|
|
||||||
FunctionLiteral struct {
|
FunctionLiteral struct {
|
||||||
Function file.Idx
|
Function file.Idx
|
||||||
Name *Identifier
|
Name *Identifier
|
||||||
|
@ -185,6 +190,7 @@ func (*BracketExpression) _expressionNode() {}
|
||||||
func (*CallExpression) _expressionNode() {}
|
func (*CallExpression) _expressionNode() {}
|
||||||
func (*ConditionalExpression) _expressionNode() {}
|
func (*ConditionalExpression) _expressionNode() {}
|
||||||
func (*DotExpression) _expressionNode() {}
|
func (*DotExpression) _expressionNode() {}
|
||||||
|
func (*EmptyExpression) _expressionNode() {}
|
||||||
func (*FunctionLiteral) _expressionNode() {}
|
func (*FunctionLiteral) _expressionNode() {}
|
||||||
func (*Identifier) _expressionNode() {}
|
func (*Identifier) _expressionNode() {}
|
||||||
func (*NewExpression) _expressionNode() {}
|
func (*NewExpression) _expressionNode() {}
|
||||||
|
@ -399,6 +405,7 @@ func (self *BracketExpression) Idx0() file.Idx { return self.Left.Idx0() }
|
||||||
func (self *CallExpression) Idx0() file.Idx { return self.Callee.Idx0() }
|
func (self *CallExpression) Idx0() file.Idx { return self.Callee.Idx0() }
|
||||||
func (self *ConditionalExpression) Idx0() file.Idx { return self.Test.Idx0() }
|
func (self *ConditionalExpression) Idx0() file.Idx { return self.Test.Idx0() }
|
||||||
func (self *DotExpression) Idx0() file.Idx { return self.Left.Idx0() }
|
func (self *DotExpression) Idx0() file.Idx { return self.Left.Idx0() }
|
||||||
|
func (self *EmptyExpression) Idx0() file.Idx { return self.Begin }
|
||||||
func (self *FunctionLiteral) Idx0() file.Idx { return self.Function }
|
func (self *FunctionLiteral) Idx0() file.Idx { return self.Function }
|
||||||
func (self *Identifier) Idx0() file.Idx { return self.Idx }
|
func (self *Identifier) Idx0() file.Idx { return self.Idx }
|
||||||
func (self *NewExpression) Idx0() file.Idx { return self.New }
|
func (self *NewExpression) Idx0() file.Idx { return self.New }
|
||||||
|
@ -447,6 +454,7 @@ func (self *BracketExpression) Idx1() file.Idx { return self.RightBracket +
|
||||||
func (self *CallExpression) Idx1() file.Idx { return self.RightParenthesis + 1 }
|
func (self *CallExpression) Idx1() file.Idx { return self.RightParenthesis + 1 }
|
||||||
func (self *ConditionalExpression) Idx1() file.Idx { return self.Test.Idx1() }
|
func (self *ConditionalExpression) Idx1() file.Idx { return self.Test.Idx1() }
|
||||||
func (self *DotExpression) Idx1() file.Idx { return self.Identifier.Idx1() }
|
func (self *DotExpression) Idx1() file.Idx { return self.Identifier.Idx1() }
|
||||||
|
func (self *EmptyExpression) Idx1() file.Idx { return self.End }
|
||||||
func (self *FunctionLiteral) Idx1() file.Idx { return self.Body.Idx1() }
|
func (self *FunctionLiteral) Idx1() file.Idx { return self.Body.Idx1() }
|
||||||
func (self *Identifier) Idx1() file.Idx { return file.Idx(int(self.Idx) + len(self.Name)) }
|
func (self *Identifier) Idx1() file.Idx { return file.Idx(int(self.Idx) + len(self.Name)) }
|
||||||
func (self *NewExpression) Idx1() file.Idx { return self.RightParenthesis + 1 }
|
func (self *NewExpression) Idx1() file.Idx { return self.RightParenthesis + 1 }
|
||||||
|
|
|
@ -117,7 +117,13 @@ func builtinMath_pow(call FunctionCall) Value {
|
||||||
}
|
}
|
||||||
|
|
||||||
func builtinMath_random(call FunctionCall) Value {
|
func builtinMath_random(call FunctionCall) Value {
|
||||||
return toValue_float64(rand.Float64())
|
var v float64
|
||||||
|
if call.runtime.random != nil {
|
||||||
|
v = call.runtime.random()
|
||||||
|
} else {
|
||||||
|
v = rand.Float64()
|
||||||
|
}
|
||||||
|
return toValue_float64(v)
|
||||||
}
|
}
|
||||||
|
|
||||||
func builtinMath_round(call FunctionCall) Value {
|
func builtinMath_round(call FunctionCall) Value {
|
||||||
|
|
|
@ -82,6 +82,9 @@ func (cmpl *_compiler) parseExpression(in ast.Expression) _nodeExpression {
|
||||||
identifier: in.Identifier.Name,
|
identifier: in.Identifier.Name,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case *ast.EmptyExpression:
|
||||||
|
return nil
|
||||||
|
|
||||||
case *ast.FunctionLiteral:
|
case *ast.FunctionLiteral:
|
||||||
name := ""
|
name := ""
|
||||||
if in.Name != nil {
|
if in.Name != nil {
|
||||||
|
|
|
@ -363,6 +363,10 @@ func (self Otto) SetDebuggerHandler(fn func(vm *Otto)) {
|
||||||
self.runtime.debugger = fn
|
self.runtime.debugger = fn
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (self Otto) SetRandomSource(fn func() float64) {
|
||||||
|
self.runtime.random = fn
|
||||||
|
}
|
||||||
|
|
||||||
// Context is a structure that contains information about the current execution
|
// Context is a structure that contains information about the current execution
|
||||||
// context.
|
// context.
|
||||||
type Context struct {
|
type Context struct {
|
||||||
|
|
|
@ -12,10 +12,14 @@ func (self *_parser) parseIdentifier() *ast.Identifier {
|
||||||
literal := self.literal
|
literal := self.literal
|
||||||
idx := self.idx
|
idx := self.idx
|
||||||
self.next()
|
self.next()
|
||||||
return &ast.Identifier{
|
comments := self.findComments(false)
|
||||||
|
exp := &ast.Identifier{
|
||||||
Name: literal,
|
Name: literal,
|
||||||
Idx: idx,
|
Idx: idx,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.commentMap.AddComments(exp, comments, ast.TRAILING)
|
||||||
|
return exp
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *_parser) parsePrimaryExpression() ast.Expression {
|
func (self *_parser) parsePrimaryExpression() ast.Expression {
|
||||||
|
@ -196,11 +200,20 @@ func (self *_parser) parseVariableDeclarationList(var_ file.Idx) []ast.Expressio
|
||||||
var list []ast.Expression
|
var list []ast.Expression
|
||||||
|
|
||||||
for {
|
for {
|
||||||
list = append(list, self.parseVariableDeclaration(&declarationList))
|
comments := self.findComments(false)
|
||||||
|
|
||||||
|
decl := self.parseVariableDeclaration(&declarationList)
|
||||||
|
if self.mode&StoreComments != 0 {
|
||||||
|
self.commentMap.AddComments(decl, comments, ast.LEADING)
|
||||||
|
self.commentMap.AddComments(decl, self.findComments(false), ast.TRAILING)
|
||||||
|
}
|
||||||
|
|
||||||
|
list = append(list, decl)
|
||||||
if self.token != token.COMMA {
|
if self.token != token.COMMA {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
self.next()
|
self.next()
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
self.scope.declare(&ast.VariableDeclaration{
|
self.scope.declare(&ast.VariableDeclaration{
|
||||||
|
@ -211,10 +224,13 @@ func (self *_parser) parseVariableDeclarationList(var_ file.Idx) []ast.Expressio
|
||||||
return list
|
return list
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *_parser) parseObjectPropertyKey() (string, string) {
|
func (self *_parser) parseObjectPropertyKey() (string, string, []*ast.Comment) {
|
||||||
idx, tkn, literal := self.idx, self.token, self.literal
|
idx, tkn, literal := self.idx, self.token, self.literal
|
||||||
value := ""
|
value := ""
|
||||||
self.next()
|
self.next()
|
||||||
|
|
||||||
|
comments := self.findComments(false)
|
||||||
|
|
||||||
switch tkn {
|
switch tkn {
|
||||||
case token.IDENTIFIER:
|
case token.IDENTIFIER:
|
||||||
value = literal
|
value = literal
|
||||||
|
@ -238,15 +254,14 @@ func (self *_parser) parseObjectPropertyKey() (string, string) {
|
||||||
value = literal
|
value = literal
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return literal, value
|
return literal, value, comments
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *_parser) parseObjectProperty() ast.Property {
|
func (self *_parser) parseObjectProperty() ast.Property {
|
||||||
|
literal, value, comments := self.parseObjectPropertyKey()
|
||||||
literal, value := self.parseObjectPropertyKey()
|
|
||||||
if literal == "get" && self.token != token.COLON {
|
if literal == "get" && self.token != token.COLON {
|
||||||
idx := self.idx
|
idx := self.idx
|
||||||
_, value := self.parseObjectPropertyKey()
|
_, value, _ := self.parseObjectPropertyKey()
|
||||||
parameterList := self.parseFunctionParameterList()
|
parameterList := self.parseFunctionParameterList()
|
||||||
|
|
||||||
node := &ast.FunctionLiteral{
|
node := &ast.FunctionLiteral{
|
||||||
|
@ -261,7 +276,7 @@ func (self *_parser) parseObjectProperty() ast.Property {
|
||||||
}
|
}
|
||||||
} else if literal == "set" && self.token != token.COLON {
|
} else if literal == "set" && self.token != token.COLON {
|
||||||
idx := self.idx
|
idx := self.idx
|
||||||
_, value := self.parseObjectPropertyKey()
|
_, value, _ := self.parseObjectPropertyKey()
|
||||||
parameterList := self.parseFunctionParameterList()
|
parameterList := self.parseFunctionParameterList()
|
||||||
|
|
||||||
node := &ast.FunctionLiteral{
|
node := &ast.FunctionLiteral{
|
||||||
|
@ -277,63 +292,128 @@ func (self *_parser) parseObjectProperty() ast.Property {
|
||||||
}
|
}
|
||||||
|
|
||||||
self.expect(token.COLON)
|
self.expect(token.COLON)
|
||||||
|
comments2 := self.findComments(false)
|
||||||
|
|
||||||
return ast.Property{
|
exp := ast.Property{
|
||||||
Key: value,
|
Key: value,
|
||||||
Kind: "value",
|
Kind: "value",
|
||||||
Value: self.parseAssignmentExpression(),
|
Value: self.parseAssignmentExpression(),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if self.mode&StoreComments != 0 {
|
||||||
|
self.commentMap.AddComments(exp.Value, comments, ast.KEY)
|
||||||
|
self.commentMap.AddComments(exp.Value, comments2, ast.COLON)
|
||||||
|
}
|
||||||
|
return exp
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *_parser) parseObjectLiteral() ast.Expression {
|
func (self *_parser) parseObjectLiteral() ast.Expression {
|
||||||
var value []ast.Property
|
var value []ast.Property
|
||||||
idx0 := self.expect(token.LEFT_BRACE)
|
idx0 := self.expect(token.LEFT_BRACE)
|
||||||
|
|
||||||
|
var comments2 []*ast.Comment
|
||||||
for self.token != token.RIGHT_BRACE && self.token != token.EOF {
|
for self.token != token.RIGHT_BRACE && self.token != token.EOF {
|
||||||
|
|
||||||
|
// Leading comments for object literal
|
||||||
|
comments := self.findComments(false)
|
||||||
property := self.parseObjectProperty()
|
property := self.parseObjectProperty()
|
||||||
|
if self.mode&StoreComments != 0 {
|
||||||
|
self.commentMap.AddComments(property.Value, comments, ast.LEADING)
|
||||||
|
self.commentMap.AddComments(property.Value, comments2, ast.LEADING)
|
||||||
|
}
|
||||||
value = append(value, property)
|
value = append(value, property)
|
||||||
if self.token == token.COMMA {
|
if self.token == token.COMMA {
|
||||||
self.next()
|
self.next()
|
||||||
|
|
||||||
|
// Find leading comments after trailing comma
|
||||||
|
comments2 = self.findComments(false)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
idx1 := self.expect(token.RIGHT_BRACE)
|
idx1 := self.expect(token.RIGHT_BRACE)
|
||||||
|
|
||||||
return &ast.ObjectLiteral{
|
exp := &ast.ObjectLiteral{
|
||||||
LeftBrace: idx0,
|
LeftBrace: idx0,
|
||||||
RightBrace: idx1,
|
RightBrace: idx1,
|
||||||
Value: value,
|
Value: value,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if self.mode&StoreComments != 0 {
|
||||||
|
self.commentMap.AddComments(exp, comments2, ast.FINAL)
|
||||||
|
}
|
||||||
|
self.consumeComments(exp, ast.FINAL)
|
||||||
|
|
||||||
|
return exp
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *_parser) parseArrayLiteral() ast.Expression {
|
func (self *_parser) parseArrayLiteral() ast.Expression {
|
||||||
|
|
||||||
idx0 := self.expect(token.LEFT_BRACKET)
|
idx0 := self.expect(token.LEFT_BRACKET)
|
||||||
|
var comments2 []*ast.Comment
|
||||||
|
var comments []*ast.Comment
|
||||||
var value []ast.Expression
|
var value []ast.Expression
|
||||||
for self.token != token.RIGHT_BRACKET && self.token != token.EOF {
|
for self.token != token.RIGHT_BRACKET && self.token != token.EOF {
|
||||||
|
// Find leading comments for both empty and non-empty expressions
|
||||||
|
comments = self.findComments(false)
|
||||||
|
|
||||||
if self.token == token.COMMA {
|
if self.token == token.COMMA {
|
||||||
self.next()
|
self.next()
|
||||||
value = append(value, nil)
|
|
||||||
|
// This kind of comment requires a special empty expression node.
|
||||||
|
empty := &ast.EmptyExpression{self.idx, self.idx}
|
||||||
|
|
||||||
|
if self.mode&StoreComments != 0 {
|
||||||
|
self.commentMap.AddComments(empty, comments, ast.LEADING)
|
||||||
|
self.commentMap.AddComments(empty, comments2, ast.LEADING)
|
||||||
|
}
|
||||||
|
|
||||||
|
value = append(value, empty)
|
||||||
|
|
||||||
|
// This comment belongs to the following expression, or trailing
|
||||||
|
comments2 = self.findComments(false)
|
||||||
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
value = append(value, self.parseAssignmentExpression())
|
|
||||||
|
exp := self.parseAssignmentExpression()
|
||||||
|
if self.mode&StoreComments != 0 {
|
||||||
|
self.commentMap.AddComments(exp, comments, ast.LEADING)
|
||||||
|
self.commentMap.AddComments(exp, comments2, ast.LEADING)
|
||||||
|
}
|
||||||
|
|
||||||
|
value = append(value, exp)
|
||||||
if self.token != token.RIGHT_BRACKET {
|
if self.token != token.RIGHT_BRACKET {
|
||||||
self.expect(token.COMMA)
|
self.expect(token.COMMA)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This comment belongs to the following expression, or trailing
|
||||||
|
comments2 = self.findComments(false)
|
||||||
}
|
}
|
||||||
idx1 := self.expect(token.RIGHT_BRACKET)
|
idx1 := self.expect(token.RIGHT_BRACKET)
|
||||||
|
|
||||||
return &ast.ArrayLiteral{
|
array := &ast.ArrayLiteral{
|
||||||
LeftBracket: idx0,
|
LeftBracket: idx0,
|
||||||
RightBracket: idx1,
|
RightBracket: idx1,
|
||||||
Value: value,
|
Value: value,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This is where comments after a possible trailing comma are added
|
||||||
|
if self.mode&StoreComments != 0 {
|
||||||
|
self.commentMap.AddComments(array, comments2, ast.FINAL)
|
||||||
|
}
|
||||||
|
|
||||||
|
return array
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *_parser) parseArgumentList() (argumentList []ast.Expression, idx0, idx1 file.Idx) {
|
func (self *_parser) parseArgumentList() (argumentList []ast.Expression, idx0, idx1 file.Idx) {
|
||||||
idx0 = self.expect(token.LEFT_PARENTHESIS)
|
idx0 = self.expect(token.LEFT_PARENTHESIS)
|
||||||
if self.token != token.RIGHT_PARENTHESIS {
|
if self.token != token.RIGHT_PARENTHESIS {
|
||||||
for {
|
for {
|
||||||
argumentList = append(argumentList, self.parseAssignmentExpression())
|
comments := self.findComments(false)
|
||||||
|
exp := self.parseAssignmentExpression()
|
||||||
|
if self.mode&StoreComments != 0 {
|
||||||
|
self.commentMap.AddComments(exp, comments, ast.LEADING)
|
||||||
|
}
|
||||||
|
argumentList = append(argumentList, exp)
|
||||||
if self.token != token.COMMA {
|
if self.token != token.COMMA {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
@ -346,12 +426,17 @@ func (self *_parser) parseArgumentList() (argumentList []ast.Expression, idx0, i
|
||||||
|
|
||||||
func (self *_parser) parseCallExpression(left ast.Expression) ast.Expression {
|
func (self *_parser) parseCallExpression(left ast.Expression) ast.Expression {
|
||||||
argumentList, idx0, idx1 := self.parseArgumentList()
|
argumentList, idx0, idx1 := self.parseArgumentList()
|
||||||
return &ast.CallExpression{
|
exp := &ast.CallExpression{
|
||||||
Callee: left,
|
Callee: left,
|
||||||
LeftParenthesis: idx0,
|
LeftParenthesis: idx0,
|
||||||
ArgumentList: argumentList,
|
ArgumentList: argumentList,
|
||||||
RightParenthesis: idx1,
|
RightParenthesis: idx1,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if self.mode&StoreComments != 0 {
|
||||||
|
self.commentMap.AddComments(exp, self.findComments(false), ast.TRAILING)
|
||||||
|
}
|
||||||
|
return exp
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *_parser) parseDotMember(left ast.Expression) ast.Expression {
|
func (self *_parser) parseDotMember(left ast.Expression) ast.Expression {
|
||||||
|
@ -402,6 +487,11 @@ func (self *_parser) parseNewExpression() ast.Expression {
|
||||||
node.LeftParenthesis = idx0
|
node.LeftParenthesis = idx0
|
||||||
node.RightParenthesis = idx1
|
node.RightParenthesis = idx1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if self.mode&StoreComments != 0 {
|
||||||
|
self.commentMap.AddComments(node, self.findComments(false), ast.TRAILING)
|
||||||
|
}
|
||||||
|
|
||||||
return node
|
return node
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -414,6 +504,10 @@ func (self *_parser) parseLeftHandSideExpression() ast.Expression {
|
||||||
left = self.parsePrimaryExpression()
|
left = self.parsePrimaryExpression()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if self.mode&StoreComments != 0 {
|
||||||
|
self.commentMap.AddComments(left, self.findComments(false), ast.TRAILING)
|
||||||
|
}
|
||||||
|
|
||||||
for {
|
for {
|
||||||
if self.token == token.PERIOD {
|
if self.token == token.PERIOD {
|
||||||
left = self.parseDotMember(left)
|
left = self.parseDotMember(left)
|
||||||
|
@ -442,6 +536,10 @@ func (self *_parser) parseLeftHandSideExpressionAllowCall() ast.Expression {
|
||||||
left = self.parsePrimaryExpression()
|
left = self.parsePrimaryExpression()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if self.mode&StoreComments != 0 {
|
||||||
|
self.commentMap.AddComments(left, self.findComments(false), ast.TRAILING)
|
||||||
|
}
|
||||||
|
|
||||||
for {
|
for {
|
||||||
if self.token == token.PERIOD {
|
if self.token == token.PERIOD {
|
||||||
left = self.parseDotMember(left)
|
left = self.parseDotMember(left)
|
||||||
|
@ -476,12 +574,18 @@ func (self *_parser) parsePostfixExpression() ast.Expression {
|
||||||
self.nextStatement()
|
self.nextStatement()
|
||||||
return &ast.BadExpression{From: idx, To: self.idx}
|
return &ast.BadExpression{From: idx, To: self.idx}
|
||||||
}
|
}
|
||||||
return &ast.UnaryExpression{
|
exp := &ast.UnaryExpression{
|
||||||
Operator: tkn,
|
Operator: tkn,
|
||||||
Idx: idx,
|
Idx: idx,
|
||||||
Operand: operand,
|
Operand: operand,
|
||||||
Postfix: true,
|
Postfix: true,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if self.mode&StoreComments != 0 {
|
||||||
|
self.commentMap.AddComments(exp, self.findComments(false), ast.TRAILING)
|
||||||
|
}
|
||||||
|
|
||||||
|
return exp
|
||||||
}
|
}
|
||||||
|
|
||||||
return operand
|
return operand
|
||||||
|
@ -496,16 +600,30 @@ func (self *_parser) parseUnaryExpression() ast.Expression {
|
||||||
tkn := self.token
|
tkn := self.token
|
||||||
idx := self.idx
|
idx := self.idx
|
||||||
self.next()
|
self.next()
|
||||||
return &ast.UnaryExpression{
|
|
||||||
|
comments := self.findComments(false)
|
||||||
|
|
||||||
|
exp := &ast.UnaryExpression{
|
||||||
Operator: tkn,
|
Operator: tkn,
|
||||||
Idx: idx,
|
Idx: idx,
|
||||||
Operand: self.parseUnaryExpression(),
|
Operand: self.parseUnaryExpression(),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if self.mode&StoreComments != 0 {
|
||||||
|
self.commentMap.AddComments(exp.Operand, comments, ast.LEADING)
|
||||||
|
}
|
||||||
|
return exp
|
||||||
case token.INCREMENT, token.DECREMENT:
|
case token.INCREMENT, token.DECREMENT:
|
||||||
tkn := self.token
|
tkn := self.token
|
||||||
idx := self.idx
|
idx := self.idx
|
||||||
self.next()
|
self.next()
|
||||||
|
|
||||||
|
comments := self.findComments(false)
|
||||||
|
|
||||||
operand := self.parseUnaryExpression()
|
operand := self.parseUnaryExpression()
|
||||||
|
if self.mode&StoreComments != 0 {
|
||||||
|
self.commentMap.AddComments(operand, comments, ast.LEADING)
|
||||||
|
}
|
||||||
switch operand.(type) {
|
switch operand.(type) {
|
||||||
case *ast.Identifier, *ast.DotExpression, *ast.BracketExpression:
|
case *ast.Identifier, *ast.DotExpression, *ast.BracketExpression:
|
||||||
default:
|
default:
|
||||||
|
@ -531,11 +649,18 @@ func (self *_parser) parseMultiplicativeExpression() ast.Expression {
|
||||||
self.token == token.REMAINDER {
|
self.token == token.REMAINDER {
|
||||||
tkn := self.token
|
tkn := self.token
|
||||||
self.next()
|
self.next()
|
||||||
|
|
||||||
|
comments := self.findComments(false)
|
||||||
|
|
||||||
left = &ast.BinaryExpression{
|
left = &ast.BinaryExpression{
|
||||||
Operator: tkn,
|
Operator: tkn,
|
||||||
Left: left,
|
Left: left,
|
||||||
Right: next(),
|
Right: next(),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if self.mode&StoreComments != 0 {
|
||||||
|
self.commentMap.AddComments(left.(*ast.BinaryExpression).Right, comments, ast.LEADING)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return left
|
return left
|
||||||
|
@ -548,11 +673,18 @@ func (self *_parser) parseAdditiveExpression() ast.Expression {
|
||||||
for self.token == token.PLUS || self.token == token.MINUS {
|
for self.token == token.PLUS || self.token == token.MINUS {
|
||||||
tkn := self.token
|
tkn := self.token
|
||||||
self.next()
|
self.next()
|
||||||
|
|
||||||
|
comments := self.findComments(false)
|
||||||
|
|
||||||
left = &ast.BinaryExpression{
|
left = &ast.BinaryExpression{
|
||||||
Operator: tkn,
|
Operator: tkn,
|
||||||
Left: left,
|
Left: left,
|
||||||
Right: next(),
|
Right: next(),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if self.mode&StoreComments != 0 {
|
||||||
|
self.commentMap.AddComments(left.(*ast.BinaryExpression).Right, comments, ast.LEADING)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return left
|
return left
|
||||||
|
@ -566,11 +698,18 @@ func (self *_parser) parseShiftExpression() ast.Expression {
|
||||||
self.token == token.UNSIGNED_SHIFT_RIGHT {
|
self.token == token.UNSIGNED_SHIFT_RIGHT {
|
||||||
tkn := self.token
|
tkn := self.token
|
||||||
self.next()
|
self.next()
|
||||||
|
|
||||||
|
comments := self.findComments(false)
|
||||||
|
|
||||||
left = &ast.BinaryExpression{
|
left = &ast.BinaryExpression{
|
||||||
Operator: tkn,
|
Operator: tkn,
|
||||||
Left: left,
|
Left: left,
|
||||||
Right: next(),
|
Right: next(),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if self.mode&StoreComments != 0 {
|
||||||
|
self.commentMap.AddComments(left.(*ast.BinaryExpression).Right, comments, ast.LEADING)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return left
|
return left
|
||||||
|
@ -590,31 +729,55 @@ func (self *_parser) parseRelationalExpression() ast.Expression {
|
||||||
case token.LESS, token.LESS_OR_EQUAL, token.GREATER, token.GREATER_OR_EQUAL:
|
case token.LESS, token.LESS_OR_EQUAL, token.GREATER, token.GREATER_OR_EQUAL:
|
||||||
tkn := self.token
|
tkn := self.token
|
||||||
self.next()
|
self.next()
|
||||||
return &ast.BinaryExpression{
|
|
||||||
|
comments := self.findComments(false)
|
||||||
|
|
||||||
|
exp := &ast.BinaryExpression{
|
||||||
Operator: tkn,
|
Operator: tkn,
|
||||||
Left: left,
|
Left: left,
|
||||||
Right: self.parseRelationalExpression(),
|
Right: self.parseRelationalExpression(),
|
||||||
Comparison: true,
|
Comparison: true,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if self.mode&StoreComments != 0 {
|
||||||
|
self.commentMap.AddComments(exp.Right, comments, ast.LEADING)
|
||||||
|
}
|
||||||
|
return exp
|
||||||
case token.INSTANCEOF:
|
case token.INSTANCEOF:
|
||||||
tkn := self.token
|
tkn := self.token
|
||||||
self.next()
|
self.next()
|
||||||
return &ast.BinaryExpression{
|
|
||||||
|
comments := self.findComments(false)
|
||||||
|
|
||||||
|
exp := &ast.BinaryExpression{
|
||||||
Operator: tkn,
|
Operator: tkn,
|
||||||
Left: left,
|
Left: left,
|
||||||
Right: self.parseRelationalExpression(),
|
Right: self.parseRelationalExpression(),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if self.mode&StoreComments != 0 {
|
||||||
|
self.commentMap.AddComments(exp.Right, comments, ast.LEADING)
|
||||||
|
}
|
||||||
|
return exp
|
||||||
case token.IN:
|
case token.IN:
|
||||||
if !allowIn {
|
if !allowIn {
|
||||||
return left
|
return left
|
||||||
}
|
}
|
||||||
tkn := self.token
|
tkn := self.token
|
||||||
self.next()
|
self.next()
|
||||||
return &ast.BinaryExpression{
|
|
||||||
|
comments := self.findComments(false)
|
||||||
|
|
||||||
|
exp := &ast.BinaryExpression{
|
||||||
Operator: tkn,
|
Operator: tkn,
|
||||||
Left: left,
|
Left: left,
|
||||||
Right: self.parseRelationalExpression(),
|
Right: self.parseRelationalExpression(),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if self.mode&StoreComments != 0 {
|
||||||
|
self.commentMap.AddComments(exp.Right, comments, ast.LEADING)
|
||||||
|
}
|
||||||
|
return exp
|
||||||
}
|
}
|
||||||
|
|
||||||
return left
|
return left
|
||||||
|
@ -628,12 +791,19 @@ func (self *_parser) parseEqualityExpression() ast.Expression {
|
||||||
self.token == token.STRICT_EQUAL || self.token == token.STRICT_NOT_EQUAL {
|
self.token == token.STRICT_EQUAL || self.token == token.STRICT_NOT_EQUAL {
|
||||||
tkn := self.token
|
tkn := self.token
|
||||||
self.next()
|
self.next()
|
||||||
|
|
||||||
|
comments := self.findComments(false)
|
||||||
|
|
||||||
left = &ast.BinaryExpression{
|
left = &ast.BinaryExpression{
|
||||||
Operator: tkn,
|
Operator: tkn,
|
||||||
Left: left,
|
Left: left,
|
||||||
Right: next(),
|
Right: next(),
|
||||||
Comparison: true,
|
Comparison: true,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if self.mode&StoreComments != 0 {
|
||||||
|
self.commentMap.AddComments(left.(*ast.BinaryExpression).Right, comments, ast.LEADING)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return left
|
return left
|
||||||
|
@ -646,11 +816,18 @@ func (self *_parser) parseBitwiseAndExpression() ast.Expression {
|
||||||
for self.token == token.AND {
|
for self.token == token.AND {
|
||||||
tkn := self.token
|
tkn := self.token
|
||||||
self.next()
|
self.next()
|
||||||
|
|
||||||
|
comments := self.findComments(false)
|
||||||
|
|
||||||
left = &ast.BinaryExpression{
|
left = &ast.BinaryExpression{
|
||||||
Operator: tkn,
|
Operator: tkn,
|
||||||
Left: left,
|
Left: left,
|
||||||
Right: next(),
|
Right: next(),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if self.mode&StoreComments != 0 {
|
||||||
|
self.commentMap.AddComments(left.(*ast.BinaryExpression).Right, comments, ast.LEADING)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return left
|
return left
|
||||||
|
@ -663,11 +840,18 @@ func (self *_parser) parseBitwiseExclusiveOrExpression() ast.Expression {
|
||||||
for self.token == token.EXCLUSIVE_OR {
|
for self.token == token.EXCLUSIVE_OR {
|
||||||
tkn := self.token
|
tkn := self.token
|
||||||
self.next()
|
self.next()
|
||||||
|
|
||||||
|
comments := self.findComments(false)
|
||||||
|
|
||||||
left = &ast.BinaryExpression{
|
left = &ast.BinaryExpression{
|
||||||
Operator: tkn,
|
Operator: tkn,
|
||||||
Left: left,
|
Left: left,
|
||||||
Right: next(),
|
Right: next(),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if self.mode&StoreComments != 0 {
|
||||||
|
self.commentMap.AddComments(left.(*ast.BinaryExpression).Right, comments, ast.LEADING)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return left
|
return left
|
||||||
|
@ -680,11 +864,18 @@ func (self *_parser) parseBitwiseOrExpression() ast.Expression {
|
||||||
for self.token == token.OR {
|
for self.token == token.OR {
|
||||||
tkn := self.token
|
tkn := self.token
|
||||||
self.next()
|
self.next()
|
||||||
|
|
||||||
|
comments := self.findComments(false)
|
||||||
|
|
||||||
left = &ast.BinaryExpression{
|
left = &ast.BinaryExpression{
|
||||||
Operator: tkn,
|
Operator: tkn,
|
||||||
Left: left,
|
Left: left,
|
||||||
Right: next(),
|
Right: next(),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if self.mode&StoreComments != 0 {
|
||||||
|
self.commentMap.AddComments(left.(*ast.BinaryExpression).Right, comments, ast.LEADING)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return left
|
return left
|
||||||
|
@ -697,11 +888,18 @@ func (self *_parser) parseLogicalAndExpression() ast.Expression {
|
||||||
for self.token == token.LOGICAL_AND {
|
for self.token == token.LOGICAL_AND {
|
||||||
tkn := self.token
|
tkn := self.token
|
||||||
self.next()
|
self.next()
|
||||||
|
|
||||||
|
comments := self.findComments(false)
|
||||||
|
|
||||||
left = &ast.BinaryExpression{
|
left = &ast.BinaryExpression{
|
||||||
Operator: tkn,
|
Operator: tkn,
|
||||||
Left: left,
|
Left: left,
|
||||||
Right: next(),
|
Right: next(),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if self.mode&StoreComments != 0 {
|
||||||
|
self.commentMap.AddComments(left.(*ast.BinaryExpression).Right, comments, ast.LEADING)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return left
|
return left
|
||||||
|
@ -714,11 +912,18 @@ func (self *_parser) parseLogicalOrExpression() ast.Expression {
|
||||||
for self.token == token.LOGICAL_OR {
|
for self.token == token.LOGICAL_OR {
|
||||||
tkn := self.token
|
tkn := self.token
|
||||||
self.next()
|
self.next()
|
||||||
|
|
||||||
|
comments := self.findComments(false)
|
||||||
|
|
||||||
left = &ast.BinaryExpression{
|
left = &ast.BinaryExpression{
|
||||||
Operator: tkn,
|
Operator: tkn,
|
||||||
Left: left,
|
Left: left,
|
||||||
Right: next(),
|
Right: next(),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if self.mode&StoreComments != 0 {
|
||||||
|
self.commentMap.AddComments(left.(*ast.BinaryExpression).Right, comments, ast.LEADING)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return left
|
return left
|
||||||
|
@ -729,13 +934,29 @@ func (self *_parser) parseConditionlExpression() ast.Expression {
|
||||||
|
|
||||||
if self.token == token.QUESTION_MARK {
|
if self.token == token.QUESTION_MARK {
|
||||||
self.next()
|
self.next()
|
||||||
|
|
||||||
|
// Comments before the consequence
|
||||||
|
comments1 := self.findComments(false)
|
||||||
|
|
||||||
consequent := self.parseAssignmentExpression()
|
consequent := self.parseAssignmentExpression()
|
||||||
|
if self.mode&StoreComments != 0 {
|
||||||
|
self.commentMap.AddComments(consequent, comments1, ast.LEADING)
|
||||||
|
}
|
||||||
|
|
||||||
self.expect(token.COLON)
|
self.expect(token.COLON)
|
||||||
return &ast.ConditionalExpression{
|
|
||||||
|
// Comments before the alternate
|
||||||
|
comments2 := self.findComments(false)
|
||||||
|
exp := &ast.ConditionalExpression{
|
||||||
Test: left,
|
Test: left,
|
||||||
Consequent: consequent,
|
Consequent: consequent,
|
||||||
Alternate: self.parseAssignmentExpression(),
|
Alternate: self.parseAssignmentExpression(),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if self.mode&StoreComments != 0 {
|
||||||
|
self.commentMap.AddComments(exp.Alternate, comments2, ast.LEADING)
|
||||||
|
}
|
||||||
|
return exp
|
||||||
}
|
}
|
||||||
|
|
||||||
return left
|
return left
|
||||||
|
@ -783,17 +1004,30 @@ func (self *_parser) parseAssignmentExpression() ast.Expression {
|
||||||
self.nextStatement()
|
self.nextStatement()
|
||||||
return &ast.BadExpression{From: idx, To: self.idx}
|
return &ast.BadExpression{From: idx, To: self.idx}
|
||||||
}
|
}
|
||||||
return &ast.AssignExpression{
|
|
||||||
|
comments := self.findComments(false)
|
||||||
|
|
||||||
|
exp := &ast.AssignExpression{
|
||||||
Left: left,
|
Left: left,
|
||||||
Operator: operator,
|
Operator: operator,
|
||||||
Right: self.parseAssignmentExpression(),
|
Right: self.parseAssignmentExpression(),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if self.mode&StoreComments != 0 {
|
||||||
|
self.commentMap.AddComments(exp.Right, comments, ast.LEADING)
|
||||||
|
}
|
||||||
|
|
||||||
|
return exp
|
||||||
}
|
}
|
||||||
|
|
||||||
return left
|
return left
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *_parser) parseExpression() ast.Expression {
|
func (self *_parser) parseExpression() ast.Expression {
|
||||||
|
|
||||||
|
comments := self.findComments(false)
|
||||||
|
statementComments := self.fetchComments()
|
||||||
|
|
||||||
next := self.parseAssignmentExpression
|
next := self.parseAssignmentExpression
|
||||||
left := next()
|
left := next()
|
||||||
|
|
||||||
|
@ -811,5 +1045,10 @@ func (self *_parser) parseExpression() ast.Expression {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if self.mode&StoreComments != 0 {
|
||||||
|
self.commentMap.AddComments(left, comments, ast.LEADING)
|
||||||
|
self.commentMap.AddComments(left, statementComments, ast.LEADING)
|
||||||
|
}
|
||||||
|
|
||||||
return left
|
return left
|
||||||
}
|
}
|
||||||
|
|
|
@ -120,6 +120,7 @@ func isLineTerminator(chr rune) bool {
|
||||||
func (self *_parser) scan() (tkn token.Token, literal string, idx file.Idx) {
|
func (self *_parser) scan() (tkn token.Token, literal string, idx file.Idx) {
|
||||||
|
|
||||||
self.implicitSemicolon = false
|
self.implicitSemicolon = false
|
||||||
|
self.skippedLineBreak = false
|
||||||
|
|
||||||
for {
|
for {
|
||||||
self.skipWhiteSpace()
|
self.skipWhiteSpace()
|
||||||
|
@ -238,9 +239,20 @@ func (self *_parser) scan() (tkn token.Token, literal string, idx file.Idx) {
|
||||||
tkn = self.switch2(token.MULTIPLY, token.MULTIPLY_ASSIGN)
|
tkn = self.switch2(token.MULTIPLY, token.MULTIPLY_ASSIGN)
|
||||||
case '/':
|
case '/':
|
||||||
if self.chr == '/' {
|
if self.chr == '/' {
|
||||||
|
if self.mode&StoreComments != 0 {
|
||||||
|
runes := self.readSingleLineComment()
|
||||||
|
literal = string(runes)
|
||||||
|
tkn = token.COMMENT
|
||||||
|
return
|
||||||
|
}
|
||||||
self.skipSingleLineComment()
|
self.skipSingleLineComment()
|
||||||
continue
|
continue
|
||||||
} else if self.chr == '*' {
|
} else if self.chr == '*' {
|
||||||
|
if self.mode&StoreComments != 0 {
|
||||||
|
literal = string(self.readMultiLineComment())
|
||||||
|
tkn = token.COMMENT
|
||||||
|
return
|
||||||
|
}
|
||||||
self.skipMultiLineComment()
|
self.skipMultiLineComment()
|
||||||
continue
|
continue
|
||||||
} else {
|
} else {
|
||||||
|
@ -411,6 +423,39 @@ func (self *_RegExp_parser) read() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (self *_parser) readSingleLineComment() (result []rune) {
|
||||||
|
for self.chr != -1 {
|
||||||
|
self.read()
|
||||||
|
if isLineTerminator(self.chr) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
result = append(result, self.chr)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get rid of the trailing -1
|
||||||
|
result = result[:len(result)-1]
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *_parser) readMultiLineComment() (result []rune) {
|
||||||
|
self.read()
|
||||||
|
for self.chr >= 0 {
|
||||||
|
chr := self.chr
|
||||||
|
self.read()
|
||||||
|
if chr == '*' && self.chr == '/' {
|
||||||
|
self.read()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
result = append(result, chr)
|
||||||
|
}
|
||||||
|
|
||||||
|
self.errorUnexpected(0, self.chr)
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
func (self *_parser) skipSingleLineComment() {
|
func (self *_parser) skipSingleLineComment() {
|
||||||
for self.chr != -1 {
|
for self.chr != -1 {
|
||||||
self.read()
|
self.read()
|
||||||
|
@ -442,6 +487,7 @@ func (self *_parser) skipWhiteSpace() {
|
||||||
continue
|
continue
|
||||||
case '\r':
|
case '\r':
|
||||||
if self._peek() == '\n' {
|
if self._peek() == '\n' {
|
||||||
|
self.skippedLineBreak = true
|
||||||
self.read()
|
self.read()
|
||||||
}
|
}
|
||||||
fallthrough
|
fallthrough
|
||||||
|
@ -449,6 +495,7 @@ func (self *_parser) skipWhiteSpace() {
|
||||||
if self.insertSemicolon {
|
if self.insertSemicolon {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
self.skippedLineBreak = true
|
||||||
self.read()
|
self.read()
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
|
@ -49,12 +49,13 @@ type Mode uint
|
||||||
|
|
||||||
const (
|
const (
|
||||||
IgnoreRegExpErrors Mode = 1 << iota // Ignore RegExp compatibility errors (allow backtracking)
|
IgnoreRegExpErrors Mode = 1 << iota // Ignore RegExp compatibility errors (allow backtracking)
|
||||||
|
StoreComments // Store the comments from source to the comments map
|
||||||
)
|
)
|
||||||
|
|
||||||
type _parser struct {
|
type _parser struct {
|
||||||
str string
|
str string
|
||||||
length int
|
length int
|
||||||
base int
|
base int
|
||||||
|
|
||||||
chr rune // The current character
|
chr rune // The current character
|
||||||
chrOffset int // The offset of current character
|
chrOffset int // The offset of current character
|
||||||
|
@ -79,15 +80,22 @@ type _parser struct {
|
||||||
mode Mode
|
mode Mode
|
||||||
|
|
||||||
file *file.File
|
file *file.File
|
||||||
|
|
||||||
|
comments []*ast.Comment
|
||||||
|
commentMap *ast.CommentMap
|
||||||
|
skippedLineBreak bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func _newParser(filename, src string, base int) *_parser {
|
func _newParser(filename, src string, base int) *_parser {
|
||||||
return &_parser{
|
return &_parser{
|
||||||
chr: ' ', // This is set so we can start scanning by skipping whitespace
|
chr: ' ', // This is set so we can start scanning by skipping whitespace
|
||||||
str: src,
|
str: src,
|
||||||
length: len(src),
|
length: len(src),
|
||||||
base: base,
|
base: base,
|
||||||
file: file.NewFile(filename, src, base),
|
file: file.NewFile(filename, src, base),
|
||||||
|
comments: make([]*ast.Comment, 0),
|
||||||
|
commentMap: &ast.CommentMap{},
|
||||||
|
skippedLineBreak: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -184,6 +192,9 @@ func (self *_parser) parse() (*ast.Program, error) {
|
||||||
if false {
|
if false {
|
||||||
self.errors.Sort()
|
self.errors.Sort()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.addCommentStatements(program, ast.FINAL)
|
||||||
|
|
||||||
return program, self.errors.Err()
|
return program, self.errors.Err()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -270,3 +281,63 @@ func (self *_parser) position(idx file.Idx) file.Position {
|
||||||
|
|
||||||
return position
|
return position
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// findComments finds the following comments.
|
||||||
|
// Comments on the same line will be grouped together and returned.
|
||||||
|
// After the first line break, comments will be added as statement comments.
|
||||||
|
func (self *_parser) findComments(ignoreLineBreak bool) []*ast.Comment {
|
||||||
|
if self.mode&StoreComments == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
comments := make([]*ast.Comment, 0)
|
||||||
|
|
||||||
|
newline := false
|
||||||
|
|
||||||
|
for self.implicitSemicolon == false || ignoreLineBreak {
|
||||||
|
if self.token != token.COMMENT {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
comment := &ast.Comment{
|
||||||
|
Begin: self.idx,
|
||||||
|
Text: self.literal,
|
||||||
|
Position: ast.TBD,
|
||||||
|
}
|
||||||
|
|
||||||
|
newline = self.skippedLineBreak || newline
|
||||||
|
|
||||||
|
if newline && !ignoreLineBreak {
|
||||||
|
self.comments = append(self.comments, comment)
|
||||||
|
} else {
|
||||||
|
comments = append(comments, comment)
|
||||||
|
}
|
||||||
|
|
||||||
|
self.next()
|
||||||
|
}
|
||||||
|
|
||||||
|
return comments
|
||||||
|
}
|
||||||
|
|
||||||
|
// addCommentStatements will add the previously parsed, not positioned comments to the provided node
|
||||||
|
func (self *_parser) addCommentStatements(node ast.Node, position ast.CommentPosition) {
|
||||||
|
if len(self.comments) > 0 {
|
||||||
|
self.commentMap.AddComments(node, self.comments, position)
|
||||||
|
|
||||||
|
// Reset comments
|
||||||
|
self.comments = make([]*ast.Comment, 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// fetchComments fetches the current comments, resets the slice and returns the comments
|
||||||
|
func (self *_parser) fetchComments() (comments []*ast.Comment) {
|
||||||
|
comments = self.comments
|
||||||
|
self.comments = nil
|
||||||
|
|
||||||
|
return comments
|
||||||
|
}
|
||||||
|
|
||||||
|
// consumeComments consumes the current comments and appends them to the provided node
|
||||||
|
func (self *_parser) consumeComments(node ast.Node, position ast.CommentPosition) {
|
||||||
|
self.commentMap.AddComments(node, self.comments, position)
|
||||||
|
self.comments = nil
|
||||||
|
}
|
||||||
|
|
|
@ -7,10 +7,24 @@ import (
|
||||||
|
|
||||||
func (self *_parser) parseBlockStatement() *ast.BlockStatement {
|
func (self *_parser) parseBlockStatement() *ast.BlockStatement {
|
||||||
node := &ast.BlockStatement{}
|
node := &ast.BlockStatement{}
|
||||||
|
|
||||||
|
// Find comments before the leading brace
|
||||||
|
if self.mode&StoreComments != 0 {
|
||||||
|
self.commentMap.AddComments(node, self.findComments(false), ast.LEADING)
|
||||||
|
}
|
||||||
|
|
||||||
node.LeftBrace = self.expect(token.LEFT_BRACE)
|
node.LeftBrace = self.expect(token.LEFT_BRACE)
|
||||||
node.List = self.parseStatementList()
|
node.List = self.parseStatementList()
|
||||||
|
|
||||||
|
self.consumeComments(node, ast.FINAL)
|
||||||
|
|
||||||
node.RightBrace = self.expect(token.RIGHT_BRACE)
|
node.RightBrace = self.expect(token.RIGHT_BRACE)
|
||||||
|
|
||||||
|
// Find comments after the trailing brace
|
||||||
|
if self.mode&StoreComments != 0 {
|
||||||
|
self.commentMap.AddComments(node, self.findComments(false), ast.TRAILING)
|
||||||
|
}
|
||||||
|
|
||||||
return node
|
return node
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,7 +35,14 @@ func (self *_parser) parseEmptyStatement() ast.Statement {
|
||||||
|
|
||||||
func (self *_parser) parseStatementList() (list []ast.Statement) {
|
func (self *_parser) parseStatementList() (list []ast.Statement) {
|
||||||
for self.token != token.RIGHT_BRACE && self.token != token.EOF {
|
for self.token != token.RIGHT_BRACE && self.token != token.EOF {
|
||||||
list = append(list, self.parseStatement())
|
if self.token == token.COMMENT {
|
||||||
|
self.parseCommentElement()
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
statement := self.parseStatement()
|
||||||
|
list = append(list, statement)
|
||||||
|
|
||||||
|
self.addCommentStatements(statement, ast.LEADING)
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
|
@ -77,6 +98,9 @@ func (self *_parser) parseStatement() ast.Statement {
|
||||||
// LabelledStatement
|
// LabelledStatement
|
||||||
colon := self.idx
|
colon := self.idx
|
||||||
self.next() // :
|
self.next() // :
|
||||||
|
|
||||||
|
comments := self.findComments(false)
|
||||||
|
|
||||||
label := identifier.Name
|
label := identifier.Name
|
||||||
for _, value := range self.scope.labels {
|
for _, value := range self.scope.labels {
|
||||||
if label == value {
|
if label == value {
|
||||||
|
@ -86,11 +110,17 @@ func (self *_parser) parseStatement() ast.Statement {
|
||||||
self.scope.labels = append(self.scope.labels, label) // Push the label
|
self.scope.labels = append(self.scope.labels, label) // Push the label
|
||||||
statement := self.parseStatement()
|
statement := self.parseStatement()
|
||||||
self.scope.labels = self.scope.labels[:len(self.scope.labels)-1] // Pop the label
|
self.scope.labels = self.scope.labels[:len(self.scope.labels)-1] // Pop the label
|
||||||
return &ast.LabelledStatement{
|
exp := &ast.LabelledStatement{
|
||||||
Label: identifier,
|
Label: identifier,
|
||||||
Colon: colon,
|
Colon: colon,
|
||||||
Statement: statement,
|
Statement: statement,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if self.mode&StoreComments != 0 {
|
||||||
|
self.commentMap.AddComments(exp, comments, ast.TRAILING)
|
||||||
|
}
|
||||||
|
|
||||||
|
return exp
|
||||||
}
|
}
|
||||||
|
|
||||||
self.optionalSemicolon()
|
self.optionalSemicolon()
|
||||||
|
@ -107,16 +137,26 @@ func (self *_parser) parseTryStatement() ast.Statement {
|
||||||
Body: self.parseBlockStatement(),
|
Body: self.parseBlockStatement(),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if self.mode&StoreComments != 0 {
|
||||||
|
self.commentMap.AddComments(node.Body, self.findComments(true), ast.TRAILING)
|
||||||
|
}
|
||||||
|
|
||||||
if self.token == token.CATCH {
|
if self.token == token.CATCH {
|
||||||
catch := self.idx
|
catch := self.idx
|
||||||
self.next()
|
self.next()
|
||||||
self.expect(token.LEFT_PARENTHESIS)
|
self.expect(token.LEFT_PARENTHESIS)
|
||||||
|
comments := self.findComments(true)
|
||||||
if self.token != token.IDENTIFIER {
|
if self.token != token.IDENTIFIER {
|
||||||
self.expect(token.IDENTIFIER)
|
self.expect(token.IDENTIFIER)
|
||||||
self.nextStatement()
|
self.nextStatement()
|
||||||
return &ast.BadStatement{From: catch, To: self.idx}
|
return &ast.BadStatement{From: catch, To: self.idx}
|
||||||
} else {
|
} else {
|
||||||
identifier := self.parseIdentifier()
|
identifier := self.parseIdentifier()
|
||||||
|
|
||||||
|
if self.mode&StoreComments != 0 {
|
||||||
|
self.commentMap.AddComments(identifier, comments, ast.LEADING)
|
||||||
|
}
|
||||||
|
|
||||||
self.expect(token.RIGHT_PARENTHESIS)
|
self.expect(token.RIGHT_PARENTHESIS)
|
||||||
node.Catch = &ast.CatchStatement{
|
node.Catch = &ast.CatchStatement{
|
||||||
Catch: catch,
|
Catch: catch,
|
||||||
|
@ -124,11 +164,22 @@ func (self *_parser) parseTryStatement() ast.Statement {
|
||||||
Body: self.parseBlockStatement(),
|
Body: self.parseBlockStatement(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if self.mode&StoreComments != 0 {
|
||||||
|
self.commentMap.AddComments(node.Catch, self.findComments(true), ast.TRAILING)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.token == token.FINALLY {
|
if self.token == token.FINALLY {
|
||||||
self.next()
|
self.next()
|
||||||
|
|
||||||
|
comments := self.findComments(true)
|
||||||
|
|
||||||
node.Finally = self.parseBlockStatement()
|
node.Finally = self.parseBlockStatement()
|
||||||
|
|
||||||
|
if self.mode&StoreComments != 0 {
|
||||||
|
self.commentMap.AddComments(node.Finally, comments, ast.LEADING)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if node.Catch == nil && node.Finally == nil {
|
if node.Catch == nil && node.Finally == nil {
|
||||||
|
@ -143,10 +194,15 @@ func (self *_parser) parseFunctionParameterList() *ast.ParameterList {
|
||||||
opening := self.expect(token.LEFT_PARENTHESIS)
|
opening := self.expect(token.LEFT_PARENTHESIS)
|
||||||
var list []*ast.Identifier
|
var list []*ast.Identifier
|
||||||
for self.token != token.RIGHT_PARENTHESIS && self.token != token.EOF {
|
for self.token != token.RIGHT_PARENTHESIS && self.token != token.EOF {
|
||||||
|
comments := self.findComments(true)
|
||||||
if self.token != token.IDENTIFIER {
|
if self.token != token.IDENTIFIER {
|
||||||
self.expect(token.IDENTIFIER)
|
self.expect(token.IDENTIFIER)
|
||||||
} else {
|
} else {
|
||||||
list = append(list, self.parseIdentifier())
|
identifier := self.parseIdentifier()
|
||||||
|
if self.mode&StoreComments != 0 {
|
||||||
|
self.commentMap.AddComments(identifier, comments, ast.LEADING)
|
||||||
|
}
|
||||||
|
list = append(list, identifier)
|
||||||
}
|
}
|
||||||
if self.token != token.RIGHT_PARENTHESIS {
|
if self.token != token.RIGHT_PARENTHESIS {
|
||||||
self.expect(token.COMMA)
|
self.expect(token.COMMA)
|
||||||
|
@ -218,12 +274,24 @@ func (self *_parser) parseFunctionBlock(node *ast.FunctionLiteral) {
|
||||||
func (self *_parser) parseDebuggerStatement() ast.Statement {
|
func (self *_parser) parseDebuggerStatement() ast.Statement {
|
||||||
idx := self.expect(token.DEBUGGER)
|
idx := self.expect(token.DEBUGGER)
|
||||||
|
|
||||||
|
comments := self.findComments(true)
|
||||||
|
|
||||||
node := &ast.DebuggerStatement{
|
node := &ast.DebuggerStatement{
|
||||||
Debugger: idx,
|
Debugger: idx,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if self.mode&StoreComments != 0 {
|
||||||
|
self.commentMap.AddComments(node, comments, ast.TRAILING)
|
||||||
|
}
|
||||||
|
|
||||||
self.semicolon()
|
self.semicolon()
|
||||||
|
|
||||||
|
if !self.skippedLineBreak {
|
||||||
|
if self.mode&StoreComments != 0 {
|
||||||
|
self.commentMap.AddComments(node, self.findComments(false), ast.TRAILING)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return node
|
return node
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -309,30 +377,77 @@ func (self *_parser) parseSwitchStatement() ast.Statement {
|
||||||
|
|
||||||
func (self *_parser) parseWithStatement() ast.Statement {
|
func (self *_parser) parseWithStatement() ast.Statement {
|
||||||
self.expect(token.WITH)
|
self.expect(token.WITH)
|
||||||
|
|
||||||
|
// Find the comments after with
|
||||||
|
comments := self.findComments(true)
|
||||||
|
|
||||||
self.expect(token.LEFT_PARENTHESIS)
|
self.expect(token.LEFT_PARENTHESIS)
|
||||||
|
|
||||||
node := &ast.WithStatement{
|
node := &ast.WithStatement{
|
||||||
Object: self.parseExpression(),
|
Object: self.parseExpression(),
|
||||||
}
|
}
|
||||||
self.expect(token.RIGHT_PARENTHESIS)
|
self.expect(token.RIGHT_PARENTHESIS)
|
||||||
|
|
||||||
|
// Add the key comments
|
||||||
|
if self.mode&StoreComments != 0 {
|
||||||
|
self.commentMap.AddComments(node, comments, ast.KEY)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find the leading comments for the body
|
||||||
|
comments = self.findComments(true)
|
||||||
|
|
||||||
node.Body = self.parseStatement()
|
node.Body = self.parseStatement()
|
||||||
|
|
||||||
|
// Add the body comments
|
||||||
|
if self.mode&StoreComments != 0 {
|
||||||
|
self.commentMap.AddComments(node.Body, comments, ast.LEADING)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Move the trailing comments to the with statement
|
||||||
|
self.commentMap.MoveComments(node.Body, node, ast.TRAILING)
|
||||||
|
|
||||||
return node
|
return node
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *_parser) parseCaseStatement() *ast.CaseStatement {
|
func (self *_parser) parseCaseStatement() *ast.CaseStatement {
|
||||||
|
|
||||||
|
var comments []*ast.Comment
|
||||||
|
|
||||||
node := &ast.CaseStatement{
|
node := &ast.CaseStatement{
|
||||||
Case: self.idx,
|
Case: self.idx,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if self.mode&StoreComments != 0 {
|
||||||
|
self.commentMap.AddComments(node, self.findComments(true), ast.LEADING)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Consume current comments
|
||||||
|
self.consumeComments(node, ast.LEADING)
|
||||||
|
|
||||||
if self.token == token.DEFAULT {
|
if self.token == token.DEFAULT {
|
||||||
self.next()
|
self.next()
|
||||||
} else {
|
} else {
|
||||||
self.expect(token.CASE)
|
self.expect(token.CASE)
|
||||||
|
|
||||||
|
comments = self.findComments(true)
|
||||||
|
|
||||||
node.Test = self.parseExpression()
|
node.Test = self.parseExpression()
|
||||||
|
if self.mode&StoreComments != 0 {
|
||||||
|
self.commentMap.AddComments(node.Test, comments, ast.LEADING)
|
||||||
|
}
|
||||||
|
|
||||||
|
comments = self.findComments(true)
|
||||||
|
if self.mode&StoreComments != 0 {
|
||||||
|
self.commentMap.AddComments(node.Test, comments, ast.TRAILING)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
self.expect(token.COLON)
|
self.expect(token.COLON)
|
||||||
|
|
||||||
|
if self.mode&StoreComments != 0 {
|
||||||
|
self.commentMap.AddComments(node.Test, self.findComments(false), ast.TRAILING)
|
||||||
|
}
|
||||||
|
|
||||||
for {
|
for {
|
||||||
if self.token == token.EOF ||
|
if self.token == token.EOF ||
|
||||||
self.token == token.RIGHT_BRACE ||
|
self.token == token.RIGHT_BRACE ||
|
||||||
|
@ -340,8 +455,12 @@ func (self *_parser) parseCaseStatement() *ast.CaseStatement {
|
||||||
self.token == token.DEFAULT {
|
self.token == token.DEFAULT {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
node.Consequent = append(node.Consequent, self.parseStatement())
|
consequent := self.parseStatement()
|
||||||
|
node.Consequent = append(node.Consequent, consequent)
|
||||||
|
|
||||||
|
if self.mode&StoreComments != 0 {
|
||||||
|
self.commentMap.AddComments(consequent, self.findComments(false), ast.TRAILING)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return node
|
return node
|
||||||
|
@ -360,44 +479,84 @@ func (self *_parser) parseForIn(into ast.Expression) *ast.ForInStatement {
|
||||||
|
|
||||||
// Already have consumed "<into> in"
|
// Already have consumed "<into> in"
|
||||||
|
|
||||||
|
// Comments after the in, before the expression
|
||||||
|
comments := self.findComments(true)
|
||||||
|
|
||||||
source := self.parseExpression()
|
source := self.parseExpression()
|
||||||
|
if self.mode&StoreComments != 0 {
|
||||||
|
self.commentMap.AddComments(source, comments, ast.LEADING)
|
||||||
|
}
|
||||||
|
|
||||||
self.expect(token.RIGHT_PARENTHESIS)
|
self.expect(token.RIGHT_PARENTHESIS)
|
||||||
|
|
||||||
return &ast.ForInStatement{
|
comments = self.findComments(true)
|
||||||
|
body := self.parseIterationStatement()
|
||||||
|
if self.mode&StoreComments != 0 {
|
||||||
|
self.commentMap.AddComments(body, comments, ast.LEADING)
|
||||||
|
}
|
||||||
|
|
||||||
|
forin := &ast.ForInStatement{
|
||||||
Into: into,
|
Into: into,
|
||||||
Source: source,
|
Source: source,
|
||||||
Body: self.parseIterationStatement(),
|
Body: body,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.commentMap.MoveComments(body, forin, ast.TRAILING)
|
||||||
|
|
||||||
|
return forin
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *_parser) parseFor(initializer ast.Expression) *ast.ForStatement {
|
func (self *_parser) parseFor(initializer ast.Expression) *ast.ForStatement {
|
||||||
|
|
||||||
// Already have consumed "<initializer> ;"
|
// Already have consumed "<initializer> ;"
|
||||||
|
|
||||||
|
comments := self.findComments(true)
|
||||||
|
|
||||||
var test, update ast.Expression
|
var test, update ast.Expression
|
||||||
|
|
||||||
if self.token != token.SEMICOLON {
|
if self.token != token.SEMICOLON {
|
||||||
test = self.parseExpression()
|
test = self.parseExpression()
|
||||||
|
if self.mode&StoreComments != 0 {
|
||||||
|
self.commentMap.AddComments(test, comments, ast.LEADING)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
self.expect(token.SEMICOLON)
|
self.expect(token.SEMICOLON)
|
||||||
|
|
||||||
|
comments = self.findComments(true)
|
||||||
|
|
||||||
if self.token != token.RIGHT_PARENTHESIS {
|
if self.token != token.RIGHT_PARENTHESIS {
|
||||||
update = self.parseExpression()
|
update = self.parseExpression()
|
||||||
|
if self.mode&StoreComments != 0 {
|
||||||
|
self.commentMap.AddComments(update, comments, ast.LEADING)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
self.expect(token.RIGHT_PARENTHESIS)
|
self.expect(token.RIGHT_PARENTHESIS)
|
||||||
|
|
||||||
return &ast.ForStatement{
|
comments = self.findComments(true)
|
||||||
|
|
||||||
|
body := self.parseIterationStatement()
|
||||||
|
if self.mode&StoreComments != 0 {
|
||||||
|
self.commentMap.AddComments(body, comments, ast.LEADING)
|
||||||
|
}
|
||||||
|
|
||||||
|
forstatement := &ast.ForStatement{
|
||||||
Initializer: initializer,
|
Initializer: initializer,
|
||||||
Test: test,
|
Test: test,
|
||||||
Update: update,
|
Update: update,
|
||||||
Body: self.parseIterationStatement(),
|
Body: body,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.commentMap.MoveComments(body, forstatement, ast.TRAILING)
|
||||||
|
|
||||||
|
return forstatement
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *_parser) parseForOrForInStatement() ast.Statement {
|
func (self *_parser) parseForOrForInStatement() ast.Statement {
|
||||||
idx := self.expect(token.FOR)
|
idx := self.expect(token.FOR)
|
||||||
self.expect(token.LEFT_PARENTHESIS)
|
self.expect(token.LEFT_PARENTHESIS)
|
||||||
|
|
||||||
|
comments := self.findComments(true)
|
||||||
|
|
||||||
var left []ast.Expression
|
var left []ast.Expression
|
||||||
|
|
||||||
forIn := false
|
forIn := false
|
||||||
|
@ -435,11 +594,19 @@ func (self *_parser) parseForOrForInStatement() ast.Statement {
|
||||||
self.nextStatement()
|
self.nextStatement()
|
||||||
return &ast.BadStatement{From: idx, To: self.idx}
|
return &ast.BadStatement{From: idx, To: self.idx}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if self.mode&StoreComments != 0 {
|
||||||
|
self.commentMap.AddComments(left[0], comments, ast.LEADING)
|
||||||
|
}
|
||||||
return self.parseForIn(left[0])
|
return self.parseForIn(left[0])
|
||||||
}
|
}
|
||||||
|
|
||||||
self.expect(token.SEMICOLON)
|
self.expect(token.SEMICOLON)
|
||||||
return self.parseFor(&ast.SequenceExpression{Sequence: left})
|
initializer := &ast.SequenceExpression{Sequence: left}
|
||||||
|
if self.mode&StoreComments != 0 {
|
||||||
|
self.commentMap.AddComments(initializer, comments, ast.LEADING)
|
||||||
|
}
|
||||||
|
return self.parseFor(initializer)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *_parser) parseVariableStatement() *ast.VariableStatement {
|
func (self *_parser) parseVariableStatement() *ast.VariableStatement {
|
||||||
|
@ -447,12 +614,27 @@ func (self *_parser) parseVariableStatement() *ast.VariableStatement {
|
||||||
idx := self.expect(token.VAR)
|
idx := self.expect(token.VAR)
|
||||||
|
|
||||||
list := self.parseVariableDeclarationList(idx)
|
list := self.parseVariableDeclarationList(idx)
|
||||||
self.semicolon()
|
|
||||||
|
|
||||||
return &ast.VariableStatement{
|
statement := &ast.VariableStatement{
|
||||||
Var: idx,
|
Var: idx,
|
||||||
List: list,
|
List: list,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.commentMap.MoveComments(statement.List[len(statement.List)-1], statement, ast.TRAILING)
|
||||||
|
|
||||||
|
if self.mode&StoreComments != 0 {
|
||||||
|
self.commentMap.AddComments(statement, self.findComments(true), ast.TRAILING)
|
||||||
|
}
|
||||||
|
|
||||||
|
self.semicolon()
|
||||||
|
|
||||||
|
if self.skippedLineBreak {
|
||||||
|
if self.mode&StoreComments != 0 {
|
||||||
|
self.commentMap.AddComments(statement, self.findComments(false), ast.TRAILING)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return statement
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *_parser) parseDoWhileStatement() ast.Statement {
|
func (self *_parser) parseDoWhileStatement() ast.Statement {
|
||||||
|
@ -463,7 +645,13 @@ func (self *_parser) parseDoWhileStatement() ast.Statement {
|
||||||
}()
|
}()
|
||||||
|
|
||||||
self.expect(token.DO)
|
self.expect(token.DO)
|
||||||
|
|
||||||
|
comments := self.findComments(true)
|
||||||
|
|
||||||
node := &ast.DoWhileStatement{}
|
node := &ast.DoWhileStatement{}
|
||||||
|
if self.mode&StoreComments != 0 {
|
||||||
|
self.commentMap.AddComments(node, comments, ast.KEY)
|
||||||
|
}
|
||||||
if self.token == token.LEFT_BRACE {
|
if self.token == token.LEFT_BRACE {
|
||||||
node.Body = self.parseBlockStatement()
|
node.Body = self.parseBlockStatement()
|
||||||
} else {
|
} else {
|
||||||
|
@ -471,49 +659,123 @@ func (self *_parser) parseDoWhileStatement() ast.Statement {
|
||||||
}
|
}
|
||||||
|
|
||||||
self.expect(token.WHILE)
|
self.expect(token.WHILE)
|
||||||
|
|
||||||
|
comments = self.findComments(true)
|
||||||
|
|
||||||
self.expect(token.LEFT_PARENTHESIS)
|
self.expect(token.LEFT_PARENTHESIS)
|
||||||
node.Test = self.parseExpression()
|
node.Test = self.parseExpression()
|
||||||
|
if self.mode&StoreComments != 0 {
|
||||||
|
self.commentMap.AddComments(node.Test, comments, ast.LEADING)
|
||||||
|
}
|
||||||
|
|
||||||
self.expect(token.RIGHT_PARENTHESIS)
|
self.expect(token.RIGHT_PARENTHESIS)
|
||||||
|
|
||||||
|
if self.mode&StoreComments != 0 {
|
||||||
|
self.commentMap.AddComments(node.Test, self.findComments(false), ast.TRAILING)
|
||||||
|
}
|
||||||
|
|
||||||
return node
|
return node
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *_parser) parseWhileStatement() ast.Statement {
|
func (self *_parser) parseWhileStatement() ast.Statement {
|
||||||
self.expect(token.WHILE)
|
self.expect(token.WHILE)
|
||||||
|
|
||||||
|
// Comments after while keyword
|
||||||
|
comments := self.findComments(true)
|
||||||
|
|
||||||
self.expect(token.LEFT_PARENTHESIS)
|
self.expect(token.LEFT_PARENTHESIS)
|
||||||
node := &ast.WhileStatement{
|
node := &ast.WhileStatement{
|
||||||
Test: self.parseExpression(),
|
Test: self.parseExpression(),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add the while comments
|
||||||
|
if self.mode&StoreComments != 0 {
|
||||||
|
self.commentMap.AddComments(node, comments, ast.KEY)
|
||||||
|
}
|
||||||
|
|
||||||
self.expect(token.RIGHT_PARENTHESIS)
|
self.expect(token.RIGHT_PARENTHESIS)
|
||||||
|
|
||||||
|
// Finding comments prior to the body
|
||||||
|
comments = self.findComments(true)
|
||||||
|
|
||||||
node.Body = self.parseIterationStatement()
|
node.Body = self.parseIterationStatement()
|
||||||
|
|
||||||
|
// Adding the comments prior to the body
|
||||||
|
if self.mode&StoreComments != 0 {
|
||||||
|
self.commentMap.AddComments(node.Body, comments, ast.LEADING)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Move the trailing comments to the while statement
|
||||||
|
self.commentMap.MoveComments(node.Body, node, ast.TRAILING)
|
||||||
|
|
||||||
return node
|
return node
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *_parser) parseIfStatement() ast.Statement {
|
func (self *_parser) parseIfStatement() ast.Statement {
|
||||||
self.expect(token.IF)
|
self.expect(token.IF)
|
||||||
|
|
||||||
|
comments := self.findComments(true)
|
||||||
|
|
||||||
self.expect(token.LEFT_PARENTHESIS)
|
self.expect(token.LEFT_PARENTHESIS)
|
||||||
node := &ast.IfStatement{
|
node := &ast.IfStatement{
|
||||||
Test: self.parseExpression(),
|
Test: self.parseExpression(),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if self.mode&StoreComments != 0 {
|
||||||
|
self.commentMap.AddComments(node, comments, ast.KEY)
|
||||||
|
}
|
||||||
|
|
||||||
self.expect(token.RIGHT_PARENTHESIS)
|
self.expect(token.RIGHT_PARENTHESIS)
|
||||||
|
|
||||||
|
comments = self.findComments(true)
|
||||||
|
|
||||||
if self.token == token.LEFT_BRACE {
|
if self.token == token.LEFT_BRACE {
|
||||||
node.Consequent = self.parseBlockStatement()
|
node.Consequent = self.parseBlockStatement()
|
||||||
} else {
|
} else {
|
||||||
node.Consequent = self.parseStatement()
|
node.Consequent = self.parseStatement()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if self.mode&StoreComments != 0 {
|
||||||
|
self.commentMap.AddComments(node.Consequent, comments, ast.LEADING)
|
||||||
|
self.commentMap.AddComments(node.Consequent, self.findComments(true), ast.TRAILING)
|
||||||
|
}
|
||||||
|
|
||||||
if self.token == token.ELSE {
|
if self.token == token.ELSE {
|
||||||
self.next()
|
self.next()
|
||||||
|
comments = self.findComments(true)
|
||||||
|
|
||||||
node.Alternate = self.parseStatement()
|
node.Alternate = self.parseStatement()
|
||||||
|
|
||||||
|
if self.mode&StoreComments != 0 {
|
||||||
|
self.commentMap.AddComments(node.Alternate, comments, ast.LEADING)
|
||||||
|
self.commentMap.AddComments(node.Alternate, self.findComments(false), ast.TRAILING)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return node
|
return node
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *_parser) parseSourceElement() ast.Statement {
|
func (self *_parser) parseSourceElement() ast.Statement {
|
||||||
return self.parseStatement()
|
|
||||||
|
statementComment := self.fetchComments()
|
||||||
|
|
||||||
|
statement := self.parseStatement()
|
||||||
|
|
||||||
|
if self.mode&StoreComments != 0 {
|
||||||
|
self.commentMap.AddComments(statement, statementComment, ast.LEADING)
|
||||||
|
}
|
||||||
|
|
||||||
|
return statement
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *_parser) parseCommentElement() {
|
||||||
|
literal := self.literal
|
||||||
|
idx := self.expect(token.COMMENT)
|
||||||
|
self.comments = append(self.comments, &ast.Comment{
|
||||||
|
Begin: idx,
|
||||||
|
Text: literal,
|
||||||
|
Position: ast.LEADING,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *_parser) parseSourceElements() []ast.Statement {
|
func (self *_parser) parseSourceElements() []ast.Statement {
|
||||||
|
@ -524,10 +786,19 @@ func (self *_parser) parseSourceElements() []ast.Statement {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if self.token == token.COMMENT {
|
||||||
|
self.parseCommentElement()
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
body = append(body, self.parseSourceElement())
|
body = append(body, self.parseSourceElement())
|
||||||
}
|
}
|
||||||
|
|
||||||
for self.token != token.EOF {
|
for self.token != token.EOF {
|
||||||
|
if self.token == token.COMMENT {
|
||||||
|
self.parseCommentElement()
|
||||||
|
continue
|
||||||
|
}
|
||||||
body = append(body, self.parseSourceElement())
|
body = append(body, self.parseSourceElement())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -546,6 +817,9 @@ func (self *_parser) parseProgram() *ast.Program {
|
||||||
|
|
||||||
func (self *_parser) parseBreakStatement() ast.Statement {
|
func (self *_parser) parseBreakStatement() ast.Statement {
|
||||||
idx := self.expect(token.BREAK)
|
idx := self.expect(token.BREAK)
|
||||||
|
|
||||||
|
breakComments := self.findComments(true)
|
||||||
|
|
||||||
semicolon := self.implicitSemicolon
|
semicolon := self.implicitSemicolon
|
||||||
if self.token == token.SEMICOLON {
|
if self.token == token.SEMICOLON {
|
||||||
semicolon = true
|
semicolon = true
|
||||||
|
@ -557,10 +831,16 @@ func (self *_parser) parseBreakStatement() ast.Statement {
|
||||||
if !self.scope.inIteration && !self.scope.inSwitch {
|
if !self.scope.inIteration && !self.scope.inSwitch {
|
||||||
goto illegal
|
goto illegal
|
||||||
}
|
}
|
||||||
return &ast.BranchStatement{
|
breakStatement := &ast.BranchStatement{
|
||||||
Idx: idx,
|
Idx: idx,
|
||||||
Token: token.BREAK,
|
Token: token.BREAK,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if self.mode&StoreComments != 0 {
|
||||||
|
self.commentMap.AddComments(breakStatement, breakComments, ast.TRAILING)
|
||||||
|
}
|
||||||
|
|
||||||
|
return breakStatement
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.token == token.IDENTIFIER {
|
if self.token == token.IDENTIFIER {
|
||||||
|
|
|
@ -55,6 +55,7 @@ type _runtime struct {
|
||||||
otto *Otto
|
otto *Otto
|
||||||
eval *_object // The builtin eval, for determine indirect versus direct invocation
|
eval *_object // The builtin eval, for determine indirect versus direct invocation
|
||||||
debugger func(*Otto)
|
debugger func(*Otto)
|
||||||
|
random func() float64
|
||||||
|
|
||||||
labels []string // FIXME
|
labels []string // FIXME
|
||||||
lck sync.Mutex
|
lck sync.Mutex
|
||||||
|
|
18
jsre/jsre.go
18
jsre/jsre.go
|
@ -18,8 +18,11 @@
|
||||||
package jsre
|
package jsre
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
crand "crypto/rand"
|
||||||
|
"encoding/binary"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
|
"math/rand"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
@ -70,6 +73,18 @@ func New(assetPath string) *JSRE {
|
||||||
return re
|
return re
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// randomSource returns a pseudo random value generator.
|
||||||
|
func randomSource() *rand.Rand {
|
||||||
|
bytes := make([]byte, 8)
|
||||||
|
seed := time.Now().UnixNano()
|
||||||
|
if _, err := crand.Read(bytes); err == nil {
|
||||||
|
seed = int64(binary.LittleEndian.Uint64(bytes))
|
||||||
|
}
|
||||||
|
|
||||||
|
src := rand.NewSource(seed)
|
||||||
|
return rand.New(src)
|
||||||
|
}
|
||||||
|
|
||||||
// This function runs the main event loop from a goroutine that is started
|
// This function runs the main event loop from a goroutine that is started
|
||||||
// when JSRE is created. Use Stop() before exiting to properly stop it.
|
// when JSRE is created. Use Stop() before exiting to properly stop it.
|
||||||
// The event loop processes vm access requests from the evalQueue in a
|
// The event loop processes vm access requests from the evalQueue in a
|
||||||
|
@ -81,6 +96,9 @@ func New(assetPath string) *JSRE {
|
||||||
// called from JS through an RPC call.
|
// called from JS through an RPC call.
|
||||||
func (self *JSRE) runEventLoop() {
|
func (self *JSRE) runEventLoop() {
|
||||||
vm := otto.New()
|
vm := otto.New()
|
||||||
|
r := randomSource()
|
||||||
|
vm.SetRandomSource(r.Float64)
|
||||||
|
|
||||||
registry := map[*jsTimer]*jsTimer{}
|
registry := map[*jsTimer]*jsTimer{}
|
||||||
ready := make(chan *jsTimer)
|
ready := make(chan *jsTimer)
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue