278
vendor/github.com/robertkrimen/otto/ast/comments.go
generated
vendored
Normal file
278
vendor/github.com/robertkrimen/otto/ast/comments.go
generated
vendored
Normal file
@@ -0,0 +1,278 @@
|
||||
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 // Before a key in an object
|
||||
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
|
||||
IF // After an if keyword
|
||||
WHILE // After a while keyword
|
||||
DO // After do keyword
|
||||
FOR // After a for keyword
|
||||
WITH // After a with keyword
|
||||
TBD
|
||||
)
|
||||
|
||||
// Comment contains the data of the comment
|
||||
type Comment struct {
|
||||
Begin file.Idx
|
||||
Text string
|
||||
Position CommentPosition
|
||||
}
|
||||
|
||||
// NewComment creates a new comment
|
||||
func NewComment(text string, idx file.Idx) *Comment {
|
||||
comment := &Comment{
|
||||
Begin: idx,
|
||||
Text: text,
|
||||
Position: TBD,
|
||||
}
|
||||
|
||||
return comment
|
||||
}
|
||||
|
||||
// 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"
|
||||
case IF:
|
||||
return "If"
|
||||
case WHILE:
|
||||
return "While"
|
||||
case DO:
|
||||
return "Do"
|
||||
case FOR:
|
||||
return "For"
|
||||
case WITH:
|
||||
return "With"
|
||||
default:
|
||||
return "???"
|
||||
}
|
||||
}
|
||||
|
||||
// String returns a stringified version of the comment
|
||||
func (c Comment) String() string {
|
||||
return fmt.Sprintf("Comment: %v", c.Text)
|
||||
}
|
||||
|
||||
// Comments defines the current view of comments from the parser
|
||||
type Comments struct {
|
||||
// CommentMap is a reference to the parser comment map
|
||||
CommentMap CommentMap
|
||||
// Comments lists the comments scanned, not linked to a node yet
|
||||
Comments []*Comment
|
||||
// future lists the comments after a line break during a sequence of comments
|
||||
future []*Comment
|
||||
// Current is node for which comments are linked to
|
||||
Current Expression
|
||||
|
||||
// wasLineBreak determines if a line break occured while scanning for comments
|
||||
wasLineBreak bool
|
||||
// primary determines whether or not processing a primary expression
|
||||
primary bool
|
||||
// afterBlock determines whether or not being after a block statement
|
||||
afterBlock bool
|
||||
}
|
||||
|
||||
func NewComments() *Comments {
|
||||
comments := &Comments{
|
||||
CommentMap: CommentMap{},
|
||||
}
|
||||
|
||||
return comments
|
||||
}
|
||||
|
||||
func (c *Comments) String() string {
|
||||
return fmt.Sprintf("NODE: %v, Comments: %v, Future: %v(LINEBREAK:%v)", c.Current, len(c.Comments), len(c.future), c.wasLineBreak)
|
||||
}
|
||||
|
||||
// FetchAll returns all the currently scanned comments,
|
||||
// including those from the next line
|
||||
func (c *Comments) FetchAll() []*Comment {
|
||||
defer func() {
|
||||
c.Comments = nil
|
||||
c.future = nil
|
||||
}()
|
||||
|
||||
return append(c.Comments, c.future...)
|
||||
}
|
||||
|
||||
// Fetch returns all the currently scanned comments
|
||||
func (c *Comments) Fetch() []*Comment {
|
||||
defer func() {
|
||||
c.Comments = nil
|
||||
}()
|
||||
|
||||
return c.Comments
|
||||
}
|
||||
|
||||
// ResetLineBreak marks the beginning of a new statement
|
||||
func (c *Comments) ResetLineBreak() {
|
||||
c.wasLineBreak = false
|
||||
}
|
||||
|
||||
// MarkPrimary will mark the context as processing a primary expression
|
||||
func (c *Comments) MarkPrimary() {
|
||||
c.primary = true
|
||||
c.wasLineBreak = false
|
||||
}
|
||||
|
||||
// AfterBlock will mark the context as being after a block.
|
||||
func (c *Comments) AfterBlock() {
|
||||
c.afterBlock = true
|
||||
}
|
||||
|
||||
// AddComment adds a comment to the view.
|
||||
// Depending on the context, comments are added normally or as post line break.
|
||||
func (c *Comments) AddComment(comment *Comment) {
|
||||
if c.primary {
|
||||
if !c.wasLineBreak {
|
||||
c.Comments = append(c.Comments, comment)
|
||||
} else {
|
||||
c.future = append(c.future, comment)
|
||||
}
|
||||
} else {
|
||||
if !c.wasLineBreak || (c.Current == nil && !c.afterBlock) {
|
||||
c.Comments = append(c.Comments, comment)
|
||||
} else {
|
||||
c.future = append(c.future, comment)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MarkComments will mark the found comments as the given position.
|
||||
func (c *Comments) MarkComments(position CommentPosition) {
|
||||
for _, comment := range c.Comments {
|
||||
if comment.Position == TBD {
|
||||
comment.Position = position
|
||||
}
|
||||
}
|
||||
for _, c := range c.future {
|
||||
if c.Position == TBD {
|
||||
c.Position = position
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Unset the current node and apply the comments to the current expression.
|
||||
// Resets context variables.
|
||||
func (c *Comments) Unset() {
|
||||
if c.Current != nil {
|
||||
c.applyComments(c.Current, c.Current, TRAILING)
|
||||
c.Current = nil
|
||||
}
|
||||
c.wasLineBreak = false
|
||||
c.primary = false
|
||||
c.afterBlock = false
|
||||
}
|
||||
|
||||
// SetExpression sets the current expression.
|
||||
// It is applied the found comments, unless the previous expression has not been unset.
|
||||
// It is skipped if the node is already set or if it is a part of the previous node.
|
||||
func (c *Comments) SetExpression(node Expression) {
|
||||
// Skipping same node
|
||||
if c.Current == node {
|
||||
return
|
||||
}
|
||||
if c.Current != nil && c.Current.Idx1() == node.Idx1() {
|
||||
c.Current = node
|
||||
return
|
||||
}
|
||||
previous := c.Current
|
||||
c.Current = node
|
||||
|
||||
// Apply the found comments and futures to the node and the previous.
|
||||
c.applyComments(node, previous, TRAILING)
|
||||
}
|
||||
|
||||
// PostProcessNode applies all found comments to the given node
|
||||
func (c *Comments) PostProcessNode(node Node) {
|
||||
c.applyComments(node, nil, TRAILING)
|
||||
}
|
||||
|
||||
// applyComments applies both the comments and the future comments to the given node and the previous one,
|
||||
// based on the context.
|
||||
func (c *Comments) applyComments(node, previous Node, position CommentPosition) {
|
||||
if previous != nil {
|
||||
c.CommentMap.AddComments(previous, c.Comments, position)
|
||||
c.Comments = nil
|
||||
} else {
|
||||
c.CommentMap.AddComments(node, c.Comments, position)
|
||||
c.Comments = nil
|
||||
}
|
||||
// Only apply the future comments to the node if the previous is set.
|
||||
// This is for detecting end of line comments and which node comments on the following lines belongs to
|
||||
if previous != nil {
|
||||
c.CommentMap.AddComments(node, c.future, position)
|
||||
c.future = nil
|
||||
}
|
||||
}
|
||||
|
||||
// AtLineBreak will mark a line break
|
||||
func (c *Comments) AtLineBreak() {
|
||||
c.wasLineBreak = true
|
||||
}
|
||||
|
||||
// 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 {
|
||||
if comment.Position == TBD {
|
||||
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]
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user