aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFelix Lange <fjl@twurst.com>2016-02-19 20:17:10 +0800
committerFelix Lange <fjl@twurst.com>2016-02-19 20:17:10 +0800
commitc305005d831eccf9d65c7b55f817390d2334e666 (patch)
treec15ee2d32fca381b8fcd45ad7d761a3d93b367a3
parent17649edd85b98f00f781415ff02da8441e52db99 (diff)
parent6777531a2d3367ef3cee933d7a36945eecb37090 (diff)
downloaddexon-c305005d831eccf9d65c7b55f817390d2334e666.tar.gz
dexon-c305005d831eccf9d65c7b55f817390d2334e666.tar.zst
dexon-c305005d831eccf9d65c7b55f817390d2334e666.zip
Merge pull request #2227 from bas-vk/mathrandom
console: seed random number generator
-rw-r--r--Godeps/Godeps.json2
-rw-r--r--Godeps/_workspace/src/github.com/robertkrimen/otto/ast/comments.go92
-rw-r--r--Godeps/_workspace/src/github.com/robertkrimen/otto/ast/node.go8
-rw-r--r--Godeps/_workspace/src/github.com/robertkrimen/otto/builtin_math.go8
-rw-r--r--Godeps/_workspace/src/github.com/robertkrimen/otto/cmpl_parse.go3
-rw-r--r--Godeps/_workspace/src/github.com/robertkrimen/otto/otto.go4
-rw-r--r--Godeps/_workspace/src/github.com/robertkrimen/otto/parser/expression.go285
-rw-r--r--Godeps/_workspace/src/github.com/robertkrimen/otto/parser/lexer.go47
-rw-r--r--Godeps/_workspace/src/github.com/robertkrimen/otto/parser/parser.go87
-rw-r--r--Godeps/_workspace/src/github.com/robertkrimen/otto/parser/statement.go306
-rw-r--r--Godeps/_workspace/src/github.com/robertkrimen/otto/runtime.go1
-rw-r--r--jsre/jsre.go18
12 files changed, 815 insertions, 46 deletions
diff --git a/Godeps/Godeps.json b/Godeps/Godeps.json
index dcf0a60cb..2858ef0c9 100644
--- a/Godeps/Godeps.json
+++ b/Godeps/Godeps.json
@@ -84,7 +84,7 @@
},
{
"ImportPath": "github.com/robertkrimen/otto",
- "Rev": "c21072f61b64b51ea58138ccacf0a85d54b9f07c"
+ "Rev": "53221230c215611a90762720c9042ac782ef74ee"
},
{
"ImportPath": "github.com/syndtr/goleveldb/leveldb",
diff --git a/Godeps/_workspace/src/github.com/robertkrimen/otto/ast/comments.go b/Godeps/_workspace/src/github.com/robertkrimen/otto/ast/comments.go
new file mode 100644
index 000000000..227e34ecb
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/robertkrimen/otto/ast/comments.go
@@ -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]
+ }
+ }
+}
diff --git a/Godeps/_workspace/src/github.com/robertkrimen/otto/ast/node.go b/Godeps/_workspace/src/github.com/robertkrimen/otto/ast/node.go
index eb46f8601..8a651dc2f 100644
--- a/Godeps/_workspace/src/github.com/robertkrimen/otto/ast/node.go
+++ b/Godeps/_workspace/src/github.com/robertkrimen/otto/ast/node.go
@@ -86,6 +86,11 @@ type (
Identifier Identifier
}
+ EmptyExpression struct {
+ Begin file.Idx
+ End file.Idx
+ }
+
FunctionLiteral struct {
Function file.Idx
Name *Identifier
@@ -185,6 +190,7 @@ func (*BracketExpression) _expressionNode() {}
func (*CallExpression) _expressionNode() {}
func (*ConditionalExpression) _expressionNode() {}
func (*DotExpression) _expressionNode() {}
+func (*EmptyExpression) _expressionNode() {}
func (*FunctionLiteral) _expressionNode() {}
func (*Identifier) _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 *ConditionalExpression) Idx0() file.Idx { return self.Test.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 *Identifier) Idx0() file.Idx { return self.Idx }
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 *ConditionalExpression) Idx1() file.Idx { return self.Test.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 *Identifier) Idx1() file.Idx { return file.Idx(int(self.Idx) + len(self.Name)) }
func (self *NewExpression) Idx1() file.Idx { return self.RightParenthesis + 1 }
diff --git a/Godeps/_workspace/src/github.com/robertkrimen/otto/builtin_math.go b/Godeps/_workspace/src/github.com/robertkrimen/otto/builtin_math.go
index a9f4a55c1..7ce90c339 100644
--- a/Godeps/_workspace/src/github.com/robertkrimen/otto/builtin_math.go
+++ b/Godeps/_workspace/src/github.com/robertkrimen/otto/builtin_math.go
@@ -117,7 +117,13 @@ func builtinMath_pow(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 {
diff --git a/Godeps/_workspace/src/github.com/robertkrimen/otto/cmpl_parse.go b/Godeps/_workspace/src/github.com/robertkrimen/otto/cmpl_parse.go
index e758a5230..f1e002d39 100644
--- a/Godeps/_workspace/src/github.com/robertkrimen/otto/cmpl_parse.go
+++ b/Godeps/_workspace/src/github.com/robertkrimen/otto/cmpl_parse.go
@@ -82,6 +82,9 @@ func (cmpl *_compiler) parseExpression(in ast.Expression) _nodeExpression {
identifier: in.Identifier.Name,
}
+ case *ast.EmptyExpression:
+ return nil
+
case *ast.FunctionLiteral:
name := ""
if in.Name != nil {
diff --git a/Godeps/_workspace/src/github.com/robertkrimen/otto/otto.go b/Godeps/_workspace/src/github.com/robertkrimen/otto/otto.go
index 2ec033cbc..613533082 100644
--- a/Godeps/_workspace/src/github.com/robertkrimen/otto/otto.go
+++ b/Godeps/_workspace/src/github.com/robertkrimen/otto/otto.go
@@ -363,6 +363,10 @@ func (self Otto) SetDebuggerHandler(fn func(vm *Otto)) {
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.
type Context struct {
diff --git a/Godeps/_workspace/src/github.com/robertkrimen/otto/parser/expression.go b/Godeps/_workspace/src/github.com/robertkrimen/otto/parser/expression.go
index 8baf22f7c..a23a7279a 100644
--- a/Godeps/_workspace/src/github.com/robertkrimen/otto/parser/expression.go
+++ b/Godeps/_workspace/src/github.com/robertkrimen/otto/parser/expression.go
@@ -12,10 +12,14 @@ func (self *_parser) parseIdentifier() *ast.Identifier {
literal := self.literal
idx := self.idx
self.next()
- return &ast.Identifier{
+ comments := self.findComments(false)
+ exp := &ast.Identifier{
Name: literal,
Idx: idx,
}
+
+ self.commentMap.AddComments(exp, comments, ast.TRAILING)
+ return exp
}
func (self *_parser) parsePrimaryExpression() ast.Expression {
@@ -196,11 +200,20 @@ func (self *_parser) parseVariableDeclarationList(var_ file.Idx) []ast.Expressio
var list []ast.Expression
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 {
break
}
self.next()
+
}
self.scope.declare(&ast.VariableDeclaration{
@@ -211,10 +224,13 @@ func (self *_parser) parseVariableDeclarationList(var_ file.Idx) []ast.Expressio
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
value := ""
self.next()
+
+ comments := self.findComments(false)
+
switch tkn {
case token.IDENTIFIER:
value = literal
@@ -238,15 +254,14 @@ func (self *_parser) parseObjectPropertyKey() (string, string) {
value = literal
}
}
- return literal, value
+ return literal, value, comments
}
func (self *_parser) parseObjectProperty() ast.Property {
-
- literal, value := self.parseObjectPropertyKey()
+ literal, value, comments := self.parseObjectPropertyKey()
if literal == "get" && self.token != token.COLON {
idx := self.idx
- _, value := self.parseObjectPropertyKey()
+ _, value, _ := self.parseObjectPropertyKey()
parameterList := self.parseFunctionParameterList()
node := &ast.FunctionLiteral{
@@ -261,7 +276,7 @@ func (self *_parser) parseObjectProperty() ast.Property {
}
} else if literal == "set" && self.token != token.COLON {
idx := self.idx
- _, value := self.parseObjectPropertyKey()
+ _, value, _ := self.parseObjectPropertyKey()
parameterList := self.parseFunctionParameterList()
node := &ast.FunctionLiteral{
@@ -277,63 +292,128 @@ func (self *_parser) parseObjectProperty() ast.Property {
}
self.expect(token.COLON)
+ comments2 := self.findComments(false)
- return ast.Property{
+ exp := ast.Property{
Key: value,
Kind: "value",
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 {
var value []ast.Property
idx0 := self.expect(token.LEFT_BRACE)
+
+ var comments2 []*ast.Comment
for self.token != token.RIGHT_BRACE && self.token != token.EOF {
+
+ // Leading comments for object literal
+ comments := self.findComments(false)
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)
if self.token == token.COMMA {
self.next()
+
+ // Find leading comments after trailing comma
+ comments2 = self.findComments(false)
continue
}
}
idx1 := self.expect(token.RIGHT_BRACE)
- return &ast.ObjectLiteral{
+ exp := &ast.ObjectLiteral{
LeftBrace: idx0,
RightBrace: idx1,
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 {
-
idx0 := self.expect(token.LEFT_BRACKET)
+ var comments2 []*ast.Comment
+ var comments []*ast.Comment
var value []ast.Expression
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 {
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
}
- 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 {
self.expect(token.COMMA)
}
+
+ // This comment belongs to the following expression, or trailing
+ comments2 = self.findComments(false)
}
idx1 := self.expect(token.RIGHT_BRACKET)
- return &ast.ArrayLiteral{
+ array := &ast.ArrayLiteral{
LeftBracket: idx0,
RightBracket: idx1,
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) {
idx0 = self.expect(token.LEFT_PARENTHESIS)
if self.token != token.RIGHT_PARENTHESIS {
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 {
break
}
@@ -346,12 +426,17 @@ func (self *_parser) parseArgumentList() (argumentList []ast.Expression, idx0, i
func (self *_parser) parseCallExpression(left ast.Expression) ast.Expression {
argumentList, idx0, idx1 := self.parseArgumentList()
- return &ast.CallExpression{
+ exp := &ast.CallExpression{
Callee: left,
LeftParenthesis: idx0,
ArgumentList: argumentList,
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 {
@@ -402,6 +487,11 @@ func (self *_parser) parseNewExpression() ast.Expression {
node.LeftParenthesis = idx0
node.RightParenthesis = idx1
}
+
+ if self.mode&StoreComments != 0 {
+ self.commentMap.AddComments(node, self.findComments(false), ast.TRAILING)
+ }
+
return node
}
@@ -414,6 +504,10 @@ func (self *_parser) parseLeftHandSideExpression() ast.Expression {
left = self.parsePrimaryExpression()
}
+ if self.mode&StoreComments != 0 {
+ self.commentMap.AddComments(left, self.findComments(false), ast.TRAILING)
+ }
+
for {
if self.token == token.PERIOD {
left = self.parseDotMember(left)
@@ -442,6 +536,10 @@ func (self *_parser) parseLeftHandSideExpressionAllowCall() ast.Expression {
left = self.parsePrimaryExpression()
}
+ if self.mode&StoreComments != 0 {
+ self.commentMap.AddComments(left, self.findComments(false), ast.TRAILING)
+ }
+
for {
if self.token == token.PERIOD {
left = self.parseDotMember(left)
@@ -476,12 +574,18 @@ func (self *_parser) parsePostfixExpression() ast.Expression {
self.nextStatement()
return &ast.BadExpression{From: idx, To: self.idx}
}
- return &ast.UnaryExpression{
+ exp := &ast.UnaryExpression{
Operator: tkn,
Idx: idx,
Operand: operand,
Postfix: true,
}
+
+ if self.mode&StoreComments != 0 {
+ self.commentMap.AddComments(exp, self.findComments(false), ast.TRAILING)
+ }
+
+ return exp
}
return operand
@@ -496,16 +600,30 @@ func (self *_parser) parseUnaryExpression() ast.Expression {
tkn := self.token
idx := self.idx
self.next()
- return &ast.UnaryExpression{
+
+ comments := self.findComments(false)
+
+ exp := &ast.UnaryExpression{
Operator: tkn,
Idx: idx,
Operand: self.parseUnaryExpression(),
}
+
+ if self.mode&StoreComments != 0 {
+ self.commentMap.AddComments(exp.Operand, comments, ast.LEADING)
+ }
+ return exp
case token.INCREMENT, token.DECREMENT:
tkn := self.token
idx := self.idx
self.next()
+
+ comments := self.findComments(false)
+
operand := self.parseUnaryExpression()
+ if self.mode&StoreComments != 0 {
+ self.commentMap.AddComments(operand, comments, ast.LEADING)
+ }
switch operand.(type) {
case *ast.Identifier, *ast.DotExpression, *ast.BracketExpression:
default:
@@ -531,11 +649,18 @@ func (self *_parser) parseMultiplicativeExpression() ast.Expression {
self.token == token.REMAINDER {
tkn := self.token
self.next()
+
+ comments := self.findComments(false)
+
left = &ast.BinaryExpression{
Operator: tkn,
Left: left,
Right: next(),
}
+
+ if self.mode&StoreComments != 0 {
+ self.commentMap.AddComments(left.(*ast.BinaryExpression).Right, comments, ast.LEADING)
+ }
}
return left
@@ -548,11 +673,18 @@ func (self *_parser) parseAdditiveExpression() ast.Expression {
for self.token == token.PLUS || self.token == token.MINUS {
tkn := self.token
self.next()
+
+ comments := self.findComments(false)
+
left = &ast.BinaryExpression{
Operator: tkn,
Left: left,
Right: next(),
}
+
+ if self.mode&StoreComments != 0 {
+ self.commentMap.AddComments(left.(*ast.BinaryExpression).Right, comments, ast.LEADING)
+ }
}
return left
@@ -566,11 +698,18 @@ func (self *_parser) parseShiftExpression() ast.Expression {
self.token == token.UNSIGNED_SHIFT_RIGHT {
tkn := self.token
self.next()
+
+ comments := self.findComments(false)
+
left = &ast.BinaryExpression{
Operator: tkn,
Left: left,
Right: next(),
}
+
+ if self.mode&StoreComments != 0 {
+ self.commentMap.AddComments(left.(*ast.BinaryExpression).Right, comments, ast.LEADING)
+ }
}
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:
tkn := self.token
self.next()
- return &ast.BinaryExpression{
+
+ comments := self.findComments(false)
+
+ exp := &ast.BinaryExpression{
Operator: tkn,
Left: left,
Right: self.parseRelationalExpression(),
Comparison: true,
}
+
+ if self.mode&StoreComments != 0 {
+ self.commentMap.AddComments(exp.Right, comments, ast.LEADING)
+ }
+ return exp
case token.INSTANCEOF:
tkn := self.token
self.next()
- return &ast.BinaryExpression{
+
+ comments := self.findComments(false)
+
+ exp := &ast.BinaryExpression{
Operator: tkn,
Left: left,
Right: self.parseRelationalExpression(),
}
+
+ if self.mode&StoreComments != 0 {
+ self.commentMap.AddComments(exp.Right, comments, ast.LEADING)
+ }
+ return exp
case token.IN:
if !allowIn {
return left
}
tkn := self.token
self.next()
- return &ast.BinaryExpression{
+
+ comments := self.findComments(false)
+
+ exp := &ast.BinaryExpression{
Operator: tkn,
Left: left,
Right: self.parseRelationalExpression(),
}
+
+ if self.mode&StoreComments != 0 {
+ self.commentMap.AddComments(exp.Right, comments, ast.LEADING)
+ }
+ return exp
}
return left
@@ -628,12 +791,19 @@ func (self *_parser) parseEqualityExpression() ast.Expression {
self.token == token.STRICT_EQUAL || self.token == token.STRICT_NOT_EQUAL {
tkn := self.token
self.next()
+
+ comments := self.findComments(false)
+
left = &ast.BinaryExpression{
Operator: tkn,
Left: left,
Right: next(),
Comparison: true,
}
+
+ if self.mode&StoreComments != 0 {
+ self.commentMap.AddComments(left.(*ast.BinaryExpression).Right, comments, ast.LEADING)
+ }
}
return left
@@ -646,11 +816,18 @@ func (self *_parser) parseBitwiseAndExpression() ast.Expression {
for self.token == token.AND {
tkn := self.token
self.next()
+
+ comments := self.findComments(false)
+
left = &ast.BinaryExpression{
Operator: tkn,
Left: left,
Right: next(),
}
+
+ if self.mode&StoreComments != 0 {
+ self.commentMap.AddComments(left.(*ast.BinaryExpression).Right, comments, ast.LEADING)
+ }
}
return left
@@ -663,11 +840,18 @@ func (self *_parser) parseBitwiseExclusiveOrExpression() ast.Expression {
for self.token == token.EXCLUSIVE_OR {
tkn := self.token
self.next()
+
+ comments := self.findComments(false)
+
left = &ast.BinaryExpression{
Operator: tkn,
Left: left,
Right: next(),
}
+
+ if self.mode&StoreComments != 0 {
+ self.commentMap.AddComments(left.(*ast.BinaryExpression).Right, comments, ast.LEADING)
+ }
}
return left
@@ -680,11 +864,18 @@ func (self *_parser) parseBitwiseOrExpression() ast.Expression {
for self.token == token.OR {
tkn := self.token
self.next()
+
+ comments := self.findComments(false)
+
left = &ast.BinaryExpression{
Operator: tkn,
Left: left,
Right: next(),
}
+
+ if self.mode&StoreComments != 0 {
+ self.commentMap.AddComments(left.(*ast.BinaryExpression).Right, comments, ast.LEADING)
+ }
}
return left
@@ -697,11 +888,18 @@ func (self *_parser) parseLogicalAndExpression() ast.Expression {
for self.token == token.LOGICAL_AND {
tkn := self.token
self.next()
+
+ comments := self.findComments(false)
+
left = &ast.BinaryExpression{
Operator: tkn,
Left: left,
Right: next(),
}
+
+ if self.mode&StoreComments != 0 {
+ self.commentMap.AddComments(left.(*ast.BinaryExpression).Right, comments, ast.LEADING)
+ }
}
return left
@@ -714,11 +912,18 @@ func (self *_parser) parseLogicalOrExpression() ast.Expression {
for self.token == token.LOGICAL_OR {
tkn := self.token
self.next()
+
+ comments := self.findComments(false)
+
left = &ast.BinaryExpression{
Operator: tkn,
Left: left,
Right: next(),
}
+
+ if self.mode&StoreComments != 0 {
+ self.commentMap.AddComments(left.(*ast.BinaryExpression).Right, comments, ast.LEADING)
+ }
}
return left
@@ -729,13 +934,29 @@ func (self *_parser) parseConditionlExpression() ast.Expression {
if self.token == token.QUESTION_MARK {
self.next()
+
+ // Comments before the consequence
+ comments1 := self.findComments(false)
+
consequent := self.parseAssignmentExpression()
+ if self.mode&StoreComments != 0 {
+ self.commentMap.AddComments(consequent, comments1, ast.LEADING)
+ }
+
self.expect(token.COLON)
- return &ast.ConditionalExpression{
+
+ // Comments before the alternate
+ comments2 := self.findComments(false)
+ exp := &ast.ConditionalExpression{
Test: left,
Consequent: consequent,
Alternate: self.parseAssignmentExpression(),
}
+
+ if self.mode&StoreComments != 0 {
+ self.commentMap.AddComments(exp.Alternate, comments2, ast.LEADING)
+ }
+ return exp
}
return left
@@ -783,17 +1004,30 @@ func (self *_parser) parseAssignmentExpression() ast.Expression {
self.nextStatement()
return &ast.BadExpression{From: idx, To: self.idx}
}
- return &ast.AssignExpression{
+
+ comments := self.findComments(false)
+
+ exp := &ast.AssignExpression{
Left: left,
Operator: operator,
Right: self.parseAssignmentExpression(),
}
+
+ if self.mode&StoreComments != 0 {
+ self.commentMap.AddComments(exp.Right, comments, ast.LEADING)
+ }
+
+ return exp
}
return left
}
func (self *_parser) parseExpression() ast.Expression {
+
+ comments := self.findComments(false)
+ statementComments := self.fetchComments()
+
next := self.parseAssignmentExpression
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
}
diff --git a/Godeps/_workspace/src/github.com/robertkrimen/otto/parser/lexer.go b/Godeps/_workspace/src/github.com/robertkrimen/otto/parser/lexer.go
index bc3e74f77..a510c76d2 100644
--- a/Godeps/_workspace/src/github.com/robertkrimen/otto/parser/lexer.go
+++ b/Godeps/_workspace/src/github.com/robertkrimen/otto/parser/lexer.go
@@ -120,6 +120,7 @@ func isLineTerminator(chr rune) bool {
func (self *_parser) scan() (tkn token.Token, literal string, idx file.Idx) {
self.implicitSemicolon = false
+ self.skippedLineBreak = false
for {
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)
case '/':
if self.chr == '/' {
+ if self.mode&StoreComments != 0 {
+ runes := self.readSingleLineComment()
+ literal = string(runes)
+ tkn = token.COMMENT
+ return
+ }
self.skipSingleLineComment()
continue
} else if self.chr == '*' {
+ if self.mode&StoreComments != 0 {
+ literal = string(self.readMultiLineComment())
+ tkn = token.COMMENT
+ return
+ }
self.skipMultiLineComment()
continue
} 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() {
for self.chr != -1 {
self.read()
@@ -442,6 +487,7 @@ func (self *_parser) skipWhiteSpace() {
continue
case '\r':
if self._peek() == '\n' {
+ self.skippedLineBreak = true
self.read()
}
fallthrough
@@ -449,6 +495,7 @@ func (self *_parser) skipWhiteSpace() {
if self.insertSemicolon {
return
}
+ self.skippedLineBreak = true
self.read()
continue
}
diff --git a/Godeps/_workspace/src/github.com/robertkrimen/otto/parser/parser.go b/Godeps/_workspace/src/github.com/robertkrimen/otto/parser/parser.go
index 92ac5b0c7..18328edd6 100644
--- a/Godeps/_workspace/src/github.com/robertkrimen/otto/parser/parser.go
+++ b/Godeps/_workspace/src/github.com/robertkrimen/otto/parser/parser.go
@@ -49,12 +49,13 @@ type Mode uint
const (
IgnoreRegExpErrors Mode = 1 << iota // Ignore RegExp compatibility errors (allow backtracking)
+ StoreComments // Store the comments from source to the comments map
)
type _parser struct {
- str string
- length int
- base int
+ str string
+ length int
+ base int
chr rune // The current character
chrOffset int // The offset of current character
@@ -79,15 +80,22 @@ type _parser struct {
mode Mode
file *file.File
+
+ comments []*ast.Comment
+ commentMap *ast.CommentMap
+ skippedLineBreak bool
}
func _newParser(filename, src string, base int) *_parser {
return &_parser{
- chr: ' ', // This is set so we can start scanning by skipping whitespace
- str: src,
- length: len(src),
- base: base,
- file: file.NewFile(filename, src, base),
+ chr: ' ', // This is set so we can start scanning by skipping whitespace
+ str: src,
+ length: len(src),
+ base: 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 {
self.errors.Sort()
}
+
+ self.addCommentStatements(program, ast.FINAL)
+
return program, self.errors.Err()
}
@@ -270,3 +281,63 @@ func (self *_parser) position(idx file.Idx) file.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
+}
diff --git a/Godeps/_workspace/src/github.com/robertkrimen/otto/parser/statement.go b/Godeps/_workspace/src/github.com/robertkrimen/otto/parser/statement.go
index 2059d3856..987ac02c1 100644
--- a/Godeps/_workspace/src/github.com/robertkrimen/otto/parser/statement.go
+++ b/Godeps/_workspace/src/github.com/robertkrimen/otto/parser/statement.go
@@ -7,10 +7,24 @@ import (
func (self *_parser) parseBlockStatement() *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.List = self.parseStatementList()
+
+ self.consumeComments(node, ast.FINAL)
+
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
}
@@ -21,7 +35,14 @@ func (self *_parser) parseEmptyStatement() ast.Statement {
func (self *_parser) parseStatementList() (list []ast.Statement) {
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
@@ -77,6 +98,9 @@ func (self *_parser) parseStatement() ast.Statement {
// LabelledStatement
colon := self.idx
self.next() // :
+
+ comments := self.findComments(false)
+
label := identifier.Name
for _, value := range self.scope.labels {
if label == value {
@@ -86,11 +110,17 @@ func (self *_parser) parseStatement() ast.Statement {
self.scope.labels = append(self.scope.labels, label) // Push the label
statement := self.parseStatement()
self.scope.labels = self.scope.labels[:len(self.scope.labels)-1] // Pop the label
- return &ast.LabelledStatement{
+ exp := &ast.LabelledStatement{
Label: identifier,
Colon: colon,
Statement: statement,
}
+
+ if self.mode&StoreComments != 0 {
+ self.commentMap.AddComments(exp, comments, ast.TRAILING)
+ }
+
+ return exp
}
self.optionalSemicolon()
@@ -107,16 +137,26 @@ func (self *_parser) parseTryStatement() ast.Statement {
Body: self.parseBlockStatement(),
}
+ if self.mode&StoreComments != 0 {
+ self.commentMap.AddComments(node.Body, self.findComments(true), ast.TRAILING)
+ }
+
if self.token == token.CATCH {
catch := self.idx
self.next()
self.expect(token.LEFT_PARENTHESIS)
+ comments := self.findComments(true)
if self.token != token.IDENTIFIER {
self.expect(token.IDENTIFIER)
self.nextStatement()
return &ast.BadStatement{From: catch, To: self.idx}
} else {
identifier := self.parseIdentifier()
+
+ if self.mode&StoreComments != 0 {
+ self.commentMap.AddComments(identifier, comments, ast.LEADING)
+ }
+
self.expect(token.RIGHT_PARENTHESIS)
node.Catch = &ast.CatchStatement{
Catch: catch,
@@ -124,11 +164,22 @@ func (self *_parser) parseTryStatement() ast.Statement {
Body: self.parseBlockStatement(),
}
}
+
+ if self.mode&StoreComments != 0 {
+ self.commentMap.AddComments(node.Catch, self.findComments(true), ast.TRAILING)
+ }
}
if self.token == token.FINALLY {
self.next()
+
+ comments := self.findComments(true)
+
node.Finally = self.parseBlockStatement()
+
+ if self.mode&StoreComments != 0 {
+ self.commentMap.AddComments(node.Finally, comments, ast.LEADING)
+ }
}
if node.Catch == nil && node.Finally == nil {
@@ -143,10 +194,15 @@ func (self *_parser) parseFunctionParameterList() *ast.ParameterList {
opening := self.expect(token.LEFT_PARENTHESIS)
var list []*ast.Identifier
for self.token != token.RIGHT_PARENTHESIS && self.token != token.EOF {
+ comments := self.findComments(true)
if self.token != token.IDENTIFIER {
self.expect(token.IDENTIFIER)
} 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 {
self.expect(token.COMMA)
@@ -218,12 +274,24 @@ func (self *_parser) parseFunctionBlock(node *ast.FunctionLiteral) {
func (self *_parser) parseDebuggerStatement() ast.Statement {
idx := self.expect(token.DEBUGGER)
+ comments := self.findComments(true)
+
node := &ast.DebuggerStatement{
Debugger: idx,
}
+ if self.mode&StoreComments != 0 {
+ self.commentMap.AddComments(node, comments, ast.TRAILING)
+ }
+
self.semicolon()
+ if !self.skippedLineBreak {
+ if self.mode&StoreComments != 0 {
+ self.commentMap.AddComments(node, self.findComments(false), ast.TRAILING)
+ }
+ }
+
return node
}
@@ -309,30 +377,77 @@ func (self *_parser) parseSwitchStatement() ast.Statement {
func (self *_parser) parseWithStatement() ast.Statement {
self.expect(token.WITH)
+
+ // Find the comments after with
+ comments := self.findComments(true)
+
self.expect(token.LEFT_PARENTHESIS)
+
node := &ast.WithStatement{
Object: self.parseExpression(),
}
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()
+ // 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
}
func (self *_parser) parseCaseStatement() *ast.CaseStatement {
+ var comments []*ast.Comment
+
node := &ast.CaseStatement{
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 {
self.next()
} else {
self.expect(token.CASE)
+
+ comments = self.findComments(true)
+
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)
+ if self.mode&StoreComments != 0 {
+ self.commentMap.AddComments(node.Test, self.findComments(false), ast.TRAILING)
+ }
+
for {
if self.token == token.EOF ||
self.token == token.RIGHT_BRACE ||
@@ -340,8 +455,12 @@ func (self *_parser) parseCaseStatement() *ast.CaseStatement {
self.token == token.DEFAULT {
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
@@ -360,44 +479,84 @@ func (self *_parser) parseForIn(into ast.Expression) *ast.ForInStatement {
// Already have consumed "<into> in"
+ // Comments after the in, before the expression
+ comments := self.findComments(true)
+
source := self.parseExpression()
+ if self.mode&StoreComments != 0 {
+ self.commentMap.AddComments(source, comments, ast.LEADING)
+ }
+
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,
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 {
// Already have consumed "<initializer> ;"
+ comments := self.findComments(true)
+
var test, update ast.Expression
if self.token != token.SEMICOLON {
test = self.parseExpression()
+ if self.mode&StoreComments != 0 {
+ self.commentMap.AddComments(test, comments, ast.LEADING)
+ }
}
self.expect(token.SEMICOLON)
+ comments = self.findComments(true)
+
if self.token != token.RIGHT_PARENTHESIS {
update = self.parseExpression()
+ if self.mode&StoreComments != 0 {
+ self.commentMap.AddComments(update, comments, ast.LEADING)
+ }
}
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,
Test: test,
Update: update,
- Body: self.parseIterationStatement(),
+ Body: body,
}
+
+ self.commentMap.MoveComments(body, forstatement, ast.TRAILING)
+
+ return forstatement
}
func (self *_parser) parseForOrForInStatement() ast.Statement {
idx := self.expect(token.FOR)
self.expect(token.LEFT_PARENTHESIS)
+ comments := self.findComments(true)
+
var left []ast.Expression
forIn := false
@@ -435,11 +594,19 @@ func (self *_parser) parseForOrForInStatement() ast.Statement {
self.nextStatement()
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])
}
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 {
@@ -447,12 +614,27 @@ func (self *_parser) parseVariableStatement() *ast.VariableStatement {
idx := self.expect(token.VAR)
list := self.parseVariableDeclarationList(idx)
- self.semicolon()
- return &ast.VariableStatement{
+ statement := &ast.VariableStatement{
Var: idx,
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 {
@@ -463,7 +645,13 @@ func (self *_parser) parseDoWhileStatement() ast.Statement {
}()
self.expect(token.DO)
+
+ comments := self.findComments(true)
+
node := &ast.DoWhileStatement{}
+ if self.mode&StoreComments != 0 {
+ self.commentMap.AddComments(node, comments, ast.KEY)
+ }
if self.token == token.LEFT_BRACE {
node.Body = self.parseBlockStatement()
} else {
@@ -471,49 +659,123 @@ func (self *_parser) parseDoWhileStatement() ast.Statement {
}
self.expect(token.WHILE)
+
+ comments = self.findComments(true)
+
self.expect(token.LEFT_PARENTHESIS)
node.Test = self.parseExpression()
+ if self.mode&StoreComments != 0 {
+ self.commentMap.AddComments(node.Test, comments, ast.LEADING)
+ }
+
self.expect(token.RIGHT_PARENTHESIS)
+ if self.mode&StoreComments != 0 {
+ self.commentMap.AddComments(node.Test, self.findComments(false), ast.TRAILING)
+ }
+
return node
}
func (self *_parser) parseWhileStatement() ast.Statement {
self.expect(token.WHILE)
+
+ // Comments after while keyword
+ comments := self.findComments(true)
+
self.expect(token.LEFT_PARENTHESIS)
node := &ast.WhileStatement{
Test: self.parseExpression(),
}
+
+ // Add the while comments
+ if self.mode&StoreComments != 0 {
+ self.commentMap.AddComments(node, comments, ast.KEY)
+ }
+
self.expect(token.RIGHT_PARENTHESIS)
+
+ // Finding comments prior to the body
+ comments = self.findComments(true)
+
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
}
func (self *_parser) parseIfStatement() ast.Statement {
self.expect(token.IF)
+
+ comments := self.findComments(true)
+
self.expect(token.LEFT_PARENTHESIS)
node := &ast.IfStatement{
Test: self.parseExpression(),
}
+
+ if self.mode&StoreComments != 0 {
+ self.commentMap.AddComments(node, comments, ast.KEY)
+ }
+
self.expect(token.RIGHT_PARENTHESIS)
+ comments = self.findComments(true)
+
if self.token == token.LEFT_BRACE {
node.Consequent = self.parseBlockStatement()
} else {
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 {
self.next()
+ comments = self.findComments(true)
+
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
}
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 {
@@ -524,10 +786,19 @@ func (self *_parser) parseSourceElements() []ast.Statement {
break
}
+ if self.token == token.COMMENT {
+ self.parseCommentElement()
+ continue
+ }
+
body = append(body, self.parseSourceElement())
}
for self.token != token.EOF {
+ if self.token == token.COMMENT {
+ self.parseCommentElement()
+ continue
+ }
body = append(body, self.parseSourceElement())
}
@@ -546,6 +817,9 @@ func (self *_parser) parseProgram() *ast.Program {
func (self *_parser) parseBreakStatement() ast.Statement {
idx := self.expect(token.BREAK)
+
+ breakComments := self.findComments(true)
+
semicolon := self.implicitSemicolon
if self.token == token.SEMICOLON {
semicolon = true
@@ -557,10 +831,16 @@ func (self *_parser) parseBreakStatement() ast.Statement {
if !self.scope.inIteration && !self.scope.inSwitch {
goto illegal
}
- return &ast.BranchStatement{
+ breakStatement := &ast.BranchStatement{
Idx: idx,
Token: token.BREAK,
}
+
+ if self.mode&StoreComments != 0 {
+ self.commentMap.AddComments(breakStatement, breakComments, ast.TRAILING)
+ }
+
+ return breakStatement
}
if self.token == token.IDENTIFIER {
diff --git a/Godeps/_workspace/src/github.com/robertkrimen/otto/runtime.go b/Godeps/_workspace/src/github.com/robertkrimen/otto/runtime.go
index 168cb1cde..a998f7acc 100644
--- a/Godeps/_workspace/src/github.com/robertkrimen/otto/runtime.go
+++ b/Godeps/_workspace/src/github.com/robertkrimen/otto/runtime.go
@@ -55,6 +55,7 @@ type _runtime struct {
otto *Otto
eval *_object // The builtin eval, for determine indirect versus direct invocation
debugger func(*Otto)
+ random func() float64
labels []string // FIXME
lck sync.Mutex
diff --git a/jsre/jsre.go b/jsre/jsre.go
index a4c9d970b..f4464910d 100644
--- a/jsre/jsre.go
+++ b/jsre/jsre.go
@@ -18,8 +18,11 @@
package jsre
import (
+ crand "crypto/rand"
+ "encoding/binary"
"fmt"
"io/ioutil"
+ "math/rand"
"sync"
"time"
@@ -70,6 +73,18 @@ func New(assetPath string) *JSRE {
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
// when JSRE is created. Use Stop() before exiting to properly stop it.
// 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.
func (self *JSRE) runEventLoop() {
vm := otto.New()
+ r := randomSource()
+ vm.SetRandomSource(r.Float64)
+
registry := map[*jsTimer]*jsTimer{}
ready := make(chan *jsTimer)