Page Menu
Home
WickedGov Phorge
Search
Configure Global Search
Log In
Files
F1432443
CommentsRegistry.php
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Size
10 KB
Referenced Files
None
Subscribers
None
CommentsRegistry.php
View Options
<?php
/**
* This file is part of the Peast package
*
* (c) Marco Marchiò <marco.mm89@gmail.com>
*
* For the full copyright and license information refer to the LICENSE file
* distributed with this source code
*/
namespace
Peast\Syntax
;
/**
* Comments registry class. Internal class used to manage comments
*
* @author Marco Marchiò <marco.mm89@gmail.com>
*/
class
CommentsRegistry
{
/**
* Map of the indices where nodes start
*
* @var int
*/
protected
$nodesStartMap
=
array
();
/**
* Map of the indices where nodes end
*
* @var int
*/
protected
$nodesEndMap
=
array
();
/**
* Comments buffer
*
* @var array
*/
protected
$buffer
=
null
;
/**
* Last token index
*
* @var int
*/
protected
$lastTokenIndex
=
null
;
/**
* Comments registry
*
* @var array
*/
protected
$registry
=
array
();
/**
* Class constructor
*
* @param Parser $parser Parser
*/
public
function
__construct
(
Parser
$parser
)
{
$parser
->
getEventsEmitter
()
->
addListener
(
"NodeCompleted"
,
array
(
$this
,
"onNodeCompleted"
))
->
addListener
(
"EndParsing"
,
array
(
$this
,
"onEndParsing"
));
$parser
->
getScanner
()->
getEventsEmitter
()
->
addListener
(
"TokenConsumed"
,
array
(
$this
,
"onTokenConsumed"
))
->
addListener
(
"EndReached"
,
array
(
$this
,
"onTokenConsumed"
))
->
addListener
(
"FreezeState"
,
array
(
$this
,
"onScannerFreezeState"
))
->
addListener
(
"ResetState"
,
array
(
$this
,
"onScannerResetState"
));
}
/**
* Listener called every time the scanner compose the array that represents
* its current state
*
* @param array $state State
*
* @return void
*/
public
function
onScannerFreezeState
(&
$state
)
{
//Register the current last token index
$state
[
"commentsLastTokenIndex"
]
=
$this
->
lastTokenIndex
;
}
/**
* Listener called every time the scanner reset its state using the given
* array
*
* @param array $state State
*
* @return void
*/
public
function
onScannerResetState
(&
$state
)
{
//Reset the last token index and delete it from the state array
$this
->
lastTokenIndex
=
$state
[
"commentsLastTokenIndex"
];
unset
(
$state
[
"commentsLastTokenIndex"
]);
}
/**
* Listener called every time a token is consumed and when the scanner
* reaches the end of the source
*
* @param Token|null $token Consumed token or null if the end has
* been reached
*
* @return void
*/
public
function
onTokenConsumed
(
$token
=
null
)
{
//Check if it's a comment
if
(
$token
&&
$token
->
type
===
Token
::
TYPE_COMMENT
)
{
//If there is not an open comments buffer, create it
if
(!
$this
->
buffer
)
{
$this
->
buffer
=
array
(
"prev"
=>
$this
->
lastTokenIndex
,
"next"
=>
null
,
"comments"
=>
array
()
);
}
//Add the comment token to the buffer
$this
->
buffer
[
"comments"
][]
=
$token
;
}
else
{
if
(
$token
)
{
$loc
=
$token
->
location
;
//Store the token end position
$this
->
lastTokenIndex
=
$loc
->
end
->
getIndex
();
if
(
$this
->
buffer
)
{
//Fill the "next" key on the comments buffer with the token
//start position
$this
->
buffer
[
"next"
]
=
$loc
->
start
->
getIndex
();
}
}
//If there is an open comment buffer, close it and move it to the
//registry
if
(
$buffer
=
$this
->
buffer
)
{
//Use the location as key to add the group of comments to the
//registry, in this way if comments are reprocessed they won't
//be duplicated
$key
=
implode
(
"-"
,
array
(
$buffer
[
"prev"
]
!==
null
?
$buffer
[
"prev"
]
:
""
,
$buffer
[
"next"
]
!==
null
?
$buffer
[
"next"
]
:
""
));
$this
->
registry
[
$key
]
=
$this
->
buffer
;
$this
->
buffer
=
null
;
}
}
}
/**
* Listener called every time a node is completed by the parser
*
* @param Node\Node $node Completed node
*
* @return void
*/
public
function
onNodeCompleted
(
Node\Node
$node
)
{
//Every time a node is completed, register its start and end indices
//in the relative properties
$loc
=
$node
->
location
;
foreach
(
array
(
"Start"
,
"End"
)
as
$pos
)
{
$val
=
$loc
->{
"get$pos"
}()->
getIndex
();
$map
=
&
$this
->{
"nodes{$pos}Map"
};
if
(!
isset
(
$map
[
$val
]))
{
$map
[
$val
]
=
array
();
}
$map
[
$val
][]
=
$node
;
}
}
/**
* Listener called when parsing process ends
*
* @return void
*/
public
function
onEndParsing
()
{
//Return if there are no comments to process
if
(
$this
->
registry
)
{
//Make sure nodes start indices map is sorted
ksort
(
$this
->
nodesStartMap
);
//Loop all comment groups in the registry
foreach
(
$this
->
registry
as
$group
)
{
$this
->
findNodeForCommentsGroup
(
$group
);
}
}
}
/**
* Finds the node to attach the given comments group
*
* @param array $group Comments group
*
* @return void
*/
public
function
findNodeForCommentsGroup
(
$group
)
{
$next
=
$group
[
"next"
];
$prev
=
$group
[
"prev"
];
$comments
=
$group
[
"comments"
];
$leading
=
true
;
//If the group of comments has a next token index that appears
//in the map of start node indices, add the group to the
//corresponding node's leading comments. This associates
//comments that appear immediately before a node.
//For example: /*comment*/ for (;;){}
if
(
isset
(
$this
->
nodesStartMap
[
$next
]))
{
$nodes
=
$this
->
nodesStartMap
[
$next
];
}
//If the group of comments has a previous token index that appears
//in the map of end node indices, add the group to the
//corresponding node's trailing comments. This associates
//comments that appear immediately after a node.
//For example: for (;;){} /*comment*/
elseif
(
isset
(
$this
->
nodesEndMap
[
$prev
]))
{
$nodes
=
$this
->
nodesEndMap
[
$prev
];
$leading
=
false
;
}
//Otherwise, find a node that wraps the comments position.
//This associates inner comments:
//For example: for /*comment*/ (;;){}
else
{
//Calculate comments group boundaries
$start
=
$comments
[
0
]->
location
->
start
->
getIndex
();
$end
=
$comments
[
count
(
$comments
)
-
1
]->
location
->
end
->
getIndex
();
$nodes
=
array
();
//Loop all the entries in the start index map
foreach
(
$this
->
nodesStartMap
as
$idx
=>
$ns
)
{
//If the index is higher than the start index of the comments
//group, stop
if
(
$idx
>
$start
)
{
break
;
}
foreach
(
$ns
as
$node
)
{
//Check if the comments group is inside node indices range
if
(
$node
->
location
->
end
->
getIndex
()
>=
$end
)
{
$nodes
[]
=
$node
;
}
}
}
//If comments can't be associated with any node, associate it as
//leading comments of the program, this happens when the source is
//empty
if
(!
$nodes
)
{
$firstNode
=
array_values
(
$this
->
nodesStartMap
);
$nodes
=
array
(
$firstNode
[
0
][
0
]);
}
}
//If there are multiple possible nodes to associate the comments to,
//find the shortest one
if
(
count
(
$nodes
)
>
1
)
{
usort
(
$nodes
,
array
(
$this
,
"compareNodesLength"
));
}
$this
->
associateComments
(
$nodes
[
0
],
$comments
,
$leading
);
}
/**
* Compares node length
*
* @param Node\Node $node1 First node
* @param Node\Node $node2 Second node
*
* @return int
*
* @codeCoverageIgnore
*/
public
function
compareNodesLength
(
$node1
,
$node2
)
{
$loc1
=
$node1
->
location
;
$length1
=
$loc1
->
end
->
getIndex
()
-
$loc1
->
start
->
getIndex
();
$loc2
=
$node2
->
location
;
$length2
=
$loc2
->
end
->
getIndex
()
-
$loc2
->
start
->
getIndex
();
//If the nodes have the same length make sure to choose nodes
//different from Program nodes
if
(
$length1
===
$length2
)
{
if
(
$node1
instanceof
Node\Program
)
{
$length1
+=
1000
;
}
elseif
(
$node2
instanceof
Node\Program
)
{
$length2
+=
1000
;
}
}
return
$length1
<
$length2
?
-
1
:
1
;
}
/**
* Adds comments to the given node
*
* @param Node\Node $node Node
* @param array $comments Array of comments to add
* @param bool $leading True to add comments as leading comments
* or false to add them as trailing comments
*
* @return void
*/
public
function
associateComments
(
$node
,
$comments
,
$leading
)
{
$fn
=
(
$leading
?
"Leading"
:
"Trailing"
)
.
"Comments"
;
$currentComments
=
$node
->{
"get$fn"
}();
foreach
(
$comments
as
$comment
)
{
$loc
=
$comment
->
location
;
$commentNode
=
new
Node\Comment
;
$commentNode
->
location
->
start
=
$loc
->
start
;
$commentNode
->
location
->
end
=
$loc
->
end
;
$commentNode
->
setRawText
(
$comment
->
value
);
$currentComments
[]
=
$commentNode
;
}
$node
->{
"set$fn"
}(
$currentComments
);
}
}
File Metadata
Details
Attached
Mime Type
text/x-php
Expires
Sat, May 16, 21:45 (1 d, 6 h)
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
81/0b/16e72461a60a49d770a569c8eefe
Default Alt Text
CommentsRegistry.php (10 KB)
Attached To
Mode
rMWPROD MediaWiki Production
Attached
Detach File
Event Timeline
Log In to Comment