Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 9871
0.00% covered (danger)
0.00%
0 / 368
CRAP
0.00% covered (danger)
0.00%
0 / 2
GrammarCacheEntry
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
2
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
2
Grammar
0.00% covered (danger)
0.00%
0 / 9867
0.00% covered (danger)
0.00%
0 / 367
7072940
0.00% covered (danger)
0.00%
0 / 1
 initialize
0.00% covered (danger)
0.00%
0 / 11
0.00% covered (danger)
0.00%
0 / 1
2
 resetState
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 assert
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
6
 unreachable
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 startOffset
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 endOffset
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 tsrOffsets
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 1
20
 emitChunk
0.00% covered (danger)
0.00%
0 / 9
0.00% covered (danger)
0.00%
0 / 1
12
 isXMLTag
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
6
 a0
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 1
6
 a1
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 1
6
 a2
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 a3
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 a4
0.00% covered (danger)
0.00%
0 / 7
0.00% covered (danger)
0.00%
0 / 1
12
 a5
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 a6
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 a7
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 a8
0.00% covered (danger)
0.00%
0 / 11
0.00% covered (danger)
0.00%
0 / 1
20
 a9
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 a10
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 a11
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 a12
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
6
 a13
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 a14
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 a15
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 a16
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 a17
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 a18
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 a19
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
6
 a20
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 a21
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 a22
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 a23
0.00% covered (danger)
0.00%
0 / 16
0.00% covered (danger)
0.00%
0 / 1
2
 a24
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 a25
0.00% covered (danger)
0.00%
0 / 9
0.00% covered (danger)
0.00%
0 / 1
30
 a26
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 a27
0.00% covered (danger)
0.00%
0 / 6
0.00% covered (danger)
0.00%
0 / 1
6
 a28
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 a29
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 a30
0.00% covered (danger)
0.00%
0 / 16
0.00% covered (danger)
0.00%
0 / 1
2
 a31
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 a32
0.00% covered (danger)
0.00%
0 / 13
0.00% covered (danger)
0.00%
0 / 1
6
 a33
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 a34
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 a35
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 a36
0.00% covered (danger)
0.00%
0 / 11
0.00% covered (danger)
0.00%
0 / 1
20
 a37
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
6
 a38
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 a39
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 a40
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 a41
0.00% covered (danger)
0.00%
0 / 11
0.00% covered (danger)
0.00%
0 / 1
20
 a42
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 a43
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 a44
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 a45
0.00% covered (danger)
0.00%
0 / 23
0.00% covered (danger)
0.00%
0 / 1
20
 a46
0.00% covered (danger)
0.00%
0 / 6
0.00% covered (danger)
0.00%
0 / 1
6
 a47
0.00% covered (danger)
0.00%
0 / 6
0.00% covered (danger)
0.00%
0 / 1
6
 a48
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 a49
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
6
 a50
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 a51
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 a52
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 a53
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
6
 a54
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 a55
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
6
 a56
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 a57
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 a58
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 a59
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 a60
0.00% covered (danger)
0.00%
0 / 7
0.00% covered (danger)
0.00%
0 / 1
6
 a61
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 a62
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 a63
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 a64
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 a65
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 a66
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 a67
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 a68
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 a69
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 a70
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
6
 a71
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
6
 a72
0.00% covered (danger)
0.00%
0 / 14
0.00% covered (danger)
0.00%
0 / 1
12
 a73
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 a74
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 a75
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
6
 a76
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 a77
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 a78
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 a79
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 a80
0.00% covered (danger)
0.00%
0 / 9
0.00% covered (danger)
0.00%
0 / 1
6
 a81
0.00% covered (danger)
0.00%
0 / 20
0.00% covered (danger)
0.00%
0 / 1
56
 a82
0.00% covered (danger)
0.00%
0 / 7
0.00% covered (danger)
0.00%
0 / 1
6
 a83
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
6
 a84
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 a85
0.00% covered (danger)
0.00%
0 / 6
0.00% covered (danger)
0.00%
0 / 1
2
 a86
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 a87
0.00% covered (danger)
0.00%
0 / 72
0.00% covered (danger)
0.00%
0 / 1
306
 a88
0.00% covered (danger)
0.00%
0 / 23
0.00% covered (danger)
0.00%
0 / 1
56
 a89
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
6
 a90
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
6
 a91
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
6
 a92
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 a93
0.00% covered (danger)
0.00%
0 / 34
0.00% covered (danger)
0.00%
0 / 1
42
 a94
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 a95
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 a96
0.00% covered (danger)
0.00%
0 / 7
0.00% covered (danger)
0.00%
0 / 1
12
 a97
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 a98
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 a99
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 a100
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 a101
0.00% covered (danger)
0.00%
0 / 12
0.00% covered (danger)
0.00%
0 / 1
12
 a102
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 a103
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 a104
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 a105
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 a106
0.00% covered (danger)
0.00%
0 / 9
0.00% covered (danger)
0.00%
0 / 1
2
 a107
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 a108
0.00% covered (danger)
0.00%
0 / 23
0.00% covered (danger)
0.00%
0 / 1
56
 a109
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 a110
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 a111
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 a112
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 a113
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
12
 a114
0.00% covered (danger)
0.00%
0 / 13
0.00% covered (danger)
0.00%
0 / 1
56
 a115
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
12
 a116
0.00% covered (danger)
0.00%
0 / 12
0.00% covered (danger)
0.00%
0 / 1
30
 a117
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 a118
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 1
2
 a119
0.00% covered (danger)
0.00%
0 / 22
0.00% covered (danger)
0.00%
0 / 1
2
 a120
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 a121
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 1
12
 a122
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
12
 a123
0.00% covered (danger)
0.00%
0 / 18
0.00% covered (danger)
0.00%
0 / 1
2
 a124
0.00% covered (danger)
0.00%
0 / 49
0.00% covered (danger)
0.00%
0 / 1
132
 a125
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 a126
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 a127
0.00% covered (danger)
0.00%
0 / 8
0.00% covered (danger)
0.00%
0 / 1
12
 a128
0.00% covered (danger)
0.00%
0 / 7
0.00% covered (danger)
0.00%
0 / 1
6
 a129
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 a130
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
2
 a131
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 a132
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
6
 a133
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
2
 a134
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 a135
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 a136
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 a137
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 a138
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 1
2
 a139
0.00% covered (danger)
0.00%
0 / 22
0.00% covered (danger)
0.00%
0 / 1
12
 a140
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 a141
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 a142
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 a143
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
2
 a144
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 a145
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 a146
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 a147
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 a148
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 a149
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
6
 a150
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
6
 a151
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 a152
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 a153
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 1
20
 a154
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 a155
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 a156
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 a157
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 a158
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 a159
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 a160
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 a161
0.00% covered (danger)
0.00%
0 / 31
0.00% covered (danger)
0.00%
0 / 1
56
 a162
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 a163
0.00% covered (danger)
0.00%
0 / 6
0.00% covered (danger)
0.00%
0 / 1
2
 a164
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 a165
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
2
 a166
0.00% covered (danger)
0.00%
0 / 9
0.00% covered (danger)
0.00%
0 / 1
30
 a167
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 a168
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
12
 a169
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 a170
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 a171
0.00% covered (danger)
0.00%
0 / 49
0.00% covered (danger)
0.00%
0 / 1
420
 a172
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
2
 a173
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 a174
0.00% covered (danger)
0.00%
0 / 6
0.00% covered (danger)
0.00%
0 / 1
12
 a175
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 a176
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
12
 a177
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
2
 a178
0.00% covered (danger)
0.00%
0 / 9
0.00% covered (danger)
0.00%
0 / 1
30
 a179
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 1
12
 a180
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 a181
0.00% covered (danger)
0.00%
0 / 6
0.00% covered (danger)
0.00%
0 / 1
2
 a182
0.00% covered (danger)
0.00%
0 / 7
0.00% covered (danger)
0.00%
0 / 1
2
 a183
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 a184
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 a185
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 a186
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 a187
0.00% covered (danger)
0.00%
0 / 6
0.00% covered (danger)
0.00%
0 / 1
2
 a188
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 a189
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 a190
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 streamstart_async
0.00% covered (danger)
0.00%
0 / 48
0.00% covered (danger)
0.00%
0 / 1
132
 parsestart
0.00% covered (danger)
0.00%
0 / 32
0.00% covered (danger)
0.00%
0 / 1
110
 parsetable_start_tag
0.00% covered (danger)
0.00%
0 / 77
0.00% covered (danger)
0.00%
0 / 1
420
 parseurl
0.00% covered (danger)
0.00%
0 / 171
0.00% covered (danger)
0.00%
0 / 1
1560
 parserow_syntax_table_args
0.00% covered (danger)
0.00%
0 / 46
0.00% covered (danger)
0.00%
0 / 1
132
 parsetable_attributes
0.00% covered (danger)
0.00%
0 / 39
0.00% covered (danger)
0.00%
0 / 1
156
 parsegeneric_newline_attributes
0.00% covered (danger)
0.00%
0 / 22
0.00% covered (danger)
0.00%
0 / 1
72
 parsetplarg_or_template_or_bust
0.00% covered (danger)
0.00%
0 / 33
0.00% covered (danger)
0.00%
0 / 1
132
 parseextlink
0.00% covered (danger)
0.00%
0 / 142
0.00% covered (danger)
0.00%
0 / 1
870
 parselist_item
0.00% covered (danger)
0.00%
0 / 24
0.00% covered (danger)
0.00%
0 / 1
72
 parsetlb
0.00% covered (danger)
0.00%
0 / 35
0.00% covered (danger)
0.00%
0 / 1
72
 parsenewlineToken
0.00% covered (danger)
0.00%
0 / 18
0.00% covered (danger)
0.00%
0 / 1
12
 parsespace
0.00% covered (danger)
0.00%
0 / 18
0.00% covered (danger)
0.00%
0 / 1
30
 parsecomment
0.00% covered (danger)
0.00%
0 / 70
0.00% covered (danger)
0.00%
0 / 1
342
 parsepipe
0.00% covered (danger)
0.00%
0 / 24
0.00% covered (danger)
0.00%
0 / 1
56
 parseurl_protocol
0.00% covered (danger)
0.00%
0 / 73
0.00% covered (danger)
0.00%
0 / 1
380
 parseipv6urladdr
0.00% covered (danger)
0.00%
0 / 46
0.00% covered (danger)
0.00%
0 / 1
132
 discardinline_breaks
0.00% covered (danger)
0.00%
0 / 41
0.00% covered (danger)
0.00%
0 / 1
90
 parseno_punctuation_char
0.00% covered (danger)
0.00%
0 / 18
0.00% covered (danger)
0.00%
0 / 1
20
 parsetplarg_or_template
0.00% covered (danger)
0.00%
0 / 37
0.00% covered (danger)
0.00%
0 / 1
110
 parsehtmlentity
0.00% covered (danger)
0.00%
0 / 19
0.00% covered (danger)
0.00%
0 / 1
12
 parseoptional_spaces
0.00% covered (danger)
0.00%
0 / 24
0.00% covered (danger)
0.00%
0 / 1
56
 discardpipe
0.00% covered (danger)
0.00%
0 / 24
0.00% covered (danger)
0.00%
0 / 1
56
 parsetable_attribute
0.00% covered (danger)
0.00%
0 / 70
0.00% covered (danger)
0.00%
0 / 1
272
 discardoptionalSpaceToken
0.00% covered (danger)
0.00%
0 / 19
0.00% covered (danger)
0.00%
0 / 1
12
 parsebroken_table_attribute_name_char
0.00% covered (danger)
0.00%
0 / 22
0.00% covered (danger)
0.00%
0 / 1
30
 parsegeneric_newline_attribute
0.00% covered (danger)
0.00%
0 / 76
0.00% covered (danger)
0.00%
0 / 1
420
 parseextlink_nonipv6url
0.00% covered (danger)
0.00%
0 / 18
0.00% covered (danger)
0.00%
0 / 1
42
 discardspace
0.00% covered (danger)
0.00%
0 / 18
0.00% covered (danger)
0.00%
0 / 1
30
 discardunispace
0.00% covered (danger)
0.00%
0 / 18
0.00% covered (danger)
0.00%
0 / 1
20
 parseinlineline
0.00% covered (danger)
0.00%
0 / 73
0.00% covered (danger)
0.00%
0 / 1
380
 parsedtdd
0.00% covered (danger)
0.00%
0 / 85
0.00% covered (danger)
0.00%
0 / 1
380
 parsehacky_dl_uses
0.00% covered (danger)
0.00%
0 / 94
0.00% covered (danger)
0.00%
0 / 1
812
 parseli
0.00% covered (danger)
0.00%
0 / 47
0.00% covered (danger)
0.00%
0 / 1
210
 discardeof
0.00% covered (danger)
0.00%
0 / 18
0.00% covered (danger)
0.00%
0 / 1
12
 parseblock
0.00% covered (danger)
0.00%
0 / 78
0.00% covered (danger)
0.00%
0 / 1
342
 discardnewline
0.00% covered (danger)
0.00%
0 / 24
0.00% covered (danger)
0.00%
0 / 1
56
 parsetplarg_or_template_guarded
0.00% covered (danger)
0.00%
0 / 191
0.00% covered (danger)
0.00%
0 / 1
1806
 parseraw_htmlentity
0.00% covered (danger)
0.00%
0 / 51
0.00% covered (danger)
0.00%
0 / 1
156
 parseoptionalSpaceToken
0.00% covered (danger)
0.00%
0 / 19
0.00% covered (danger)
0.00%
0 / 1
12
 parsetable_attribute_name
0.00% covered (danger)
0.00%
0 / 131
0.00% covered (danger)
0.00%
0 / 1
992
 parsetable_att_value
0.00% covered (danger)
0.00%
0 / 176
0.00% covered (danger)
0.00%
0 / 1
2256
 discardspace_or_newline_or_solidus
0.00% covered (danger)
0.00%
0 / 41
0.00% covered (danger)
0.00%
0 / 1
72
 parsegeneric_attribute_name
0.00% covered (danger)
0.00%
0 / 104
0.00% covered (danger)
0.00%
0 / 1
756
 discardspace_or_newline
0.00% covered (danger)
0.00%
0 / 17
0.00% covered (danger)
0.00%
0 / 1
20
 parsegeneric_att_value
0.00% covered (danger)
0.00%
0 / 193
0.00% covered (danger)
0.00%
0 / 1
1980
 parseextlink_nonipv6url_parameterized
0.00% covered (danger)
0.00%
0 / 92
0.00% covered (danger)
0.00%
0 / 1
650
 parseurltext
0.00% covered (danger)
0.00%
0 / 99
0.00% covered (danger)
0.00%
0 / 1
462
 parseinline_element
0.00% covered (danger)
0.00%
0 / 152
0.00% covered (danger)
0.00%
0 / 1
930
 discardlist_char
0.00% covered (danger)
0.00%
0 / 17
0.00% covered (danger)
0.00%
0 / 1
20
 parselist_char
0.00% covered (danger)
0.00%
0 / 17
0.00% covered (danger)
0.00%
0 / 1
20
 parsedtdd_colon
0.00% covered (danger)
0.00%
0 / 37
0.00% covered (danger)
0.00%
0 / 1
110
 discardeolf
0.00% covered (danger)
0.00%
0 / 17
0.00% covered (danger)
0.00%
0 / 1
12
 parsetable_line
0.00% covered (danger)
0.00%
0 / 51
0.00% covered (danger)
0.00%
0 / 1
210
 parsesol
0.00% covered (danger)
0.00%
0 / 35
0.00% covered (danger)
0.00%
0 / 1
132
 discardcomment
0.00% covered (danger)
0.00%
0 / 70
0.00% covered (danger)
0.00%
0 / 1
342
 discardsof
0.00% covered (danger)
0.00%
0 / 18
0.00% covered (danger)
0.00%
0 / 1
12
 parseredirect
0.00% covered (danger)
0.00%
0 / 72
0.00% covered (danger)
0.00%
0 / 1
380
 parsesol_transparent
0.00% covered (danger)
0.00%
0 / 27
0.00% covered (danger)
0.00%
0 / 1
90
 parseblock_line
0.00% covered (danger)
0.00%
0 / 50
0.00% covered (danger)
0.00%
0 / 1
182
 parseblock_lines
0.00% covered (danger)
0.00%
0 / 48
0.00% covered (danger)
0.00%
0 / 1
156
 discardtplarg
0.00% covered (danger)
0.00%
0 / 16
0.00% covered (danger)
0.00%
0 / 1
20
 parsetemplate
0.00% covered (danger)
0.00%
0 / 16
0.00% covered (danger)
0.00%
0 / 1
20
 parsebroken_template
0.00% covered (danger)
0.00%
0 / 29
0.00% covered (danger)
0.00%
0 / 1
72
 parsetplarg
0.00% covered (danger)
0.00%
0 / 16
0.00% covered (danger)
0.00%
0 / 1
20
 discardwikilink
0.00% covered (danger)
0.00%
0 / 21
0.00% covered (danger)
0.00%
0 / 1
56
 parsedirective
0.00% covered (danger)
0.00%
0 / 72
0.00% covered (danger)
0.00%
0 / 1
306
 parsehtml_tag
0.00% covered (danger)
0.00%
0 / 18
0.00% covered (danger)
0.00%
0 / 1
42
 parsetable_attribute_preprocessor_text_single
0.00% covered (danger)
0.00%
0 / 63
0.00% covered (danger)
0.00%
0 / 1
380
 parsetable_attribute_preprocessor_text_double
0.00% covered (danger)
0.00%
0 / 63
0.00% covered (danger)
0.00%
0 / 1
380
 parsetable_attribute_preprocessor_text
0.00% covered (danger)
0.00%
0 / 65
0.00% covered (danger)
0.00%
0 / 1
420
 parseless_than
0.00% covered (danger)
0.00%
0 / 32
0.00% covered (danger)
0.00%
0 / 1
42
 parseattribute_preprocessor_text_single
0.00% covered (danger)
0.00%
0 / 78
0.00% covered (danger)
0.00%
0 / 1
552
 parseattribute_preprocessor_text_double
0.00% covered (danger)
0.00%
0 / 78
0.00% covered (danger)
0.00%
0 / 1
552
 parseattribute_preprocessor_text
0.00% covered (danger)
0.00%
0 / 80
0.00% covered (danger)
0.00%
0 / 1
600
 parseautolink
0.00% covered (danger)
0.00%
0 / 47
0.00% covered (danger)
0.00%
0 / 1
156
 parsebehavior_switch
0.00% covered (danger)
0.00%
0 / 44
0.00% covered (danger)
0.00%
0 / 1
132
 parsetext_char
0.00% covered (danger)
0.00%
0 / 17
0.00% covered (danger)
0.00%
0 / 1
20
 parseangle_bracket_markup
0.00% covered (danger)
0.00%
0 / 30
0.00% covered (danger)
0.00%
0 / 1
110
 parselang_variant_or_tpl
0.00% covered (danger)
0.00%
0 / 221
0.00% covered (danger)
0.00%
0 / 1
2450
 parsewikilink
0.00% covered (danger)
0.00%
0 / 21
0.00% covered (danger)
0.00%
0 / 1
56
 parsequote
0.00% covered (danger)
0.00%
0 / 42
0.00% covered (danger)
0.00%
0 / 1
132
 parseinlineline_break_on_colon
0.00% covered (danger)
0.00%
0 / 18
0.00% covered (danger)
0.00%
0 / 1
42
 parsetable_content_line
0.00% covered (danger)
0.00%
0 / 41
0.00% covered (danger)
0.00%
0 / 1
182
 parsetable_end_tag
0.00% covered (danger)
0.00%
0 / 48
0.00% covered (danger)
0.00%
0 / 1
110
 parsesol_prefix
0.00% covered (danger)
0.00%
0 / 24
0.00% covered (danger)
0.00%
0 / 1
20
 parseempty_lines_with_comments
0.00% covered (danger)
0.00%
0 / 61
0.00% covered (danger)
0.00%
0 / 1
240
 parseredirect_word
0.00% covered (danger)
0.00%
0 / 76
0.00% covered (danger)
0.00%
0 / 1
306
 parseinclude_limits
0.00% covered (danger)
0.00%
0 / 35
0.00% covered (danger)
0.00%
0 / 1
90
 parseannotation_tag
0.00% covered (danger)
0.00%
0 / 43
0.00% covered (danger)
0.00%
0 / 1
132
 parseheading
0.00% covered (danger)
0.00%
0 / 116
0.00% covered (danger)
0.00%
0 / 1
702
 parsehr
0.00% covered (danger)
0.00%
0 / 67
0.00% covered (danger)
0.00%
0 / 1
342
 discardtplarg_preproc
0.00% covered (danger)
0.00%
0 / 134
0.00% covered (danger)
0.00%
0 / 1
1332
 parsetemplate_preproc
0.00% covered (danger)
0.00%
0 / 175
0.00% covered (danger)
0.00%
0 / 1
2450
 parsetplarg_preproc
0.00% covered (danger)
0.00%
0 / 134
0.00% covered (danger)
0.00%
0 / 1
1332
 discardwikilink_preproc
0.00% covered (danger)
0.00%
0 / 67
0.00% covered (danger)
0.00%
0 / 1
342
 discardbroken_wikilink
0.00% covered (danger)
0.00%
0 / 65
0.00% covered (danger)
0.00%
0 / 1
306
 parsewellformed_extension_tag
0.00% covered (danger)
0.00%
0 / 35
0.00% covered (danger)
0.00%
0 / 1
90
 parsexmlish_tag
0.00% covered (danger)
0.00%
0 / 71
0.00% covered (danger)
0.00%
0 / 1
420
 parseautourl
0.00% covered (danger)
0.00%
0 / 182
0.00% covered (danger)
0.00%
0 / 1
1560
 parseautoref
0.00% covered (danger)
0.00%
0 / 57
0.00% covered (danger)
0.00%
0 / 1
210
 parseisbn
0.00% covered (danger)
0.00%
0 / 125
0.00% covered (danger)
0.00%
0 / 1
992
 discardbehavior_text
0.00% covered (danger)
0.00%
0 / 46
0.00% covered (danger)
0.00%
0 / 1
156
 parsemaybe_extension_tag
0.00% covered (danger)
0.00%
0 / 35
0.00% covered (danger)
0.00%
0 / 1
90
 parselang_variant
0.00% covered (danger)
0.00%
0 / 21
0.00% covered (danger)
0.00%
0 / 1
56
 parsewikilink_preproc
0.00% covered (danger)
0.00%
0 / 67
0.00% covered (danger)
0.00%
0 / 1
342
 parsebroken_wikilink
0.00% covered (danger)
0.00%
0 / 65
0.00% covered (danger)
0.00%
0 / 1
306
 parsetable_heading_tags
0.00% covered (danger)
0.00%
0 / 16
0.00% covered (danger)
0.00%
0 / 1
20
 parsetable_row_tag
0.00% covered (danger)
0.00%
0 / 73
0.00% covered (danger)
0.00%
0 / 1
380
 parsetable_data_tags
0.00% covered (danger)
0.00%
0 / 55
0.00% covered (danger)
0.00%
0 / 1
210
 parsetable_caption_tag
0.00% covered (danger)
0.00%
0 / 57
0.00% covered (danger)
0.00%
0 / 1
240
 parsenewline
0.00% covered (danger)
0.00%
0 / 24
0.00% covered (danger)
0.00%
0 / 1
56
 discardinclude_check
0.00% covered (danger)
0.00%
0 / 33
0.00% covered (danger)
0.00%
0 / 1
30
 parsetvar_old_syntax_closing_HACK
0.00% covered (danger)
0.00%
0 / 40
0.00% covered (danger)
0.00%
0 / 1
72
 discardannotation_check
0.00% covered (danger)
0.00%
0 / 33
0.00% covered (danger)
0.00%
0 / 1
30
 discardsol
0.00% covered (danger)
0.00%
0 / 35
0.00% covered (danger)
0.00%
0 / 1
132
 parsetemplate_param_value
0.00% covered (danger)
0.00%
0 / 23
0.00% covered (danger)
0.00%
0 / 1
56
 discardnl_comment_space
0.00% covered (danger)
0.00%
0 / 20
0.00% covered (danger)
0.00%
0 / 1
20
 parsenl_comment_space
0.00% covered (danger)
0.00%
0 / 20
0.00% covered (danger)
0.00%
0 / 1
20
 parseparsoid_fragment_marker
0.00% covered (danger)
0.00%
0 / 38
0.00% covered (danger)
0.00%
0 / 1
110
 parsetemplate_param
0.00% covered (danger)
0.00%
0 / 76
0.00% covered (danger)
0.00%
0 / 1
306
 parsewikilink_preprocessor_text
0.00% covered (danger)
0.00%
0 / 91
0.00% covered (danger)
0.00%
0 / 1
756
 parsewikilink_content
0.00% covered (danger)
0.00%
0 / 41
0.00% covered (danger)
0.00%
0 / 1
132
 parsexmlish_start
0.00% covered (danger)
0.00%
0 / 37
0.00% covered (danger)
0.00%
0 / 1
72
 parseRFC
0.00% covered (danger)
0.00%
0 / 34
0.00% covered (danger)
0.00%
0 / 1
56
 parsePMID
0.00% covered (danger)
0.00%
0 / 34
0.00% covered (danger)
0.00%
0 / 1
56
 parsespace_or_nbsp
0.00% covered (danger)
0.00%
0 / 47
0.00% covered (danger)
0.00%
0 / 1
72
 discardend_of_word
0.00% covered (danger)
0.00%
0 / 25
0.00% covered (danger)
0.00%
0 / 1
30
 parsespace_or_nbsp_or_dash
0.00% covered (danger)
0.00%
0 / 21
0.00% covered (danger)
0.00%
0 / 1
30
 discardtext_char
0.00% covered (danger)
0.00%
0 / 17
0.00% covered (danger)
0.00%
0 / 1
20
 discardextension_check
0.00% covered (danger)
0.00%
0 / 33
0.00% covered (danger)
0.00%
0 / 1
30
 parselang_variant_preproc
0.00% covered (danger)
0.00%
0 / 126
0.00% covered (danger)
0.00%
0 / 1
756
 parsebroken_lang_variant
0.00% covered (danger)
0.00%
0 / 28
0.00% covered (danger)
0.00%
0 / 1
72
 parsetable_heading_tags_parameterized
0.00% covered (danger)
0.00%
0 / 40
0.00% covered (danger)
0.00%
0 / 1
132
 parsetable_data_tag
0.00% covered (danger)
0.00%
0 / 50
0.00% covered (danger)
0.00%
0 / 1
182
 parsetds
0.00% covered (danger)
0.00%
0 / 35
0.00% covered (danger)
0.00%
0 / 1
110
 parsenested_block_in_table
0.00% covered (danger)
0.00%
0 / 76
0.00% covered (danger)
0.00%
0 / 1
462
 parsetemplate_param_text
0.00% covered (danger)
0.00%
0 / 32
0.00% covered (danger)
0.00%
0 / 1
132
 discardnewlineToken
0.00% covered (danger)
0.00%
0 / 18
0.00% covered (danger)
0.00%
0 / 1
12
 parsetemplate_param_name
0.00% covered (danger)
0.00%
0 / 30
0.00% covered (danger)
0.00%
0 / 1
72
 parselink_text
0.00% covered (danger)
0.00%
0 / 18
0.00% covered (danger)
0.00%
0 / 1
42
 parsetag_name
0.00% covered (danger)
0.00%
0 / 24
0.00% covered (danger)
0.00%
0 / 1
42
 parseunispace
0.00% covered (danger)
0.00%
0 / 18
0.00% covered (danger)
0.00%
0 / 1
20
 parseopt_lang_variant_flags
0.00% covered (danger)
0.00%
0 / 41
0.00% covered (danger)
0.00%
0 / 1
132
 parselang_variant_text
0.00% covered (danger)
0.00%
0 / 34
0.00% covered (danger)
0.00%
0 / 1
156
 parselang_variant_option_list
0.00% covered (danger)
0.00%
0 / 76
0.00% covered (danger)
0.00%
0 / 1
380
 parsetable_heading_tag
0.00% covered (danger)
0.00%
0 / 48
0.00% covered (danger)
0.00%
0 / 1
156
 parseths
0.00% covered (danger)
0.00%
0 / 41
0.00% covered (danger)
0.00%
0 / 1
182
 parsepipe_pipe
0.00% covered (danger)
0.00%
0 / 24
0.00% covered (danger)
0.00%
0 / 1
72
 parsenested_block
0.00% covered (danger)
0.00%
0 / 36
0.00% covered (danger)
0.00%
0 / 1
90
 parselink_text_parameterized
0.00% covered (danger)
0.00%
0 / 129
0.00% covered (danger)
0.00%
0 / 1
1332
 parselang_variant_flags
0.00% covered (danger)
0.00%
0 / 77
0.00% covered (danger)
0.00%
0 / 1
506
 parselang_variant_option
0.00% covered (danger)
0.00%
0 / 163
0.00% covered (danger)
0.00%
0 / 1
1980
 discardbogus_lang_variant_option
0.00% covered (danger)
0.00%
0 / 20
0.00% covered (danger)
0.00%
0 / 1
56
 parsefull_table_in_link_caption
0.00% covered (danger)
0.00%
0 / 36
0.00% covered (danger)
0.00%
0 / 1
90
 parselang_variant_flag
0.00% covered (danger)
0.00%
0 / 74
0.00% covered (danger)
0.00%
0 / 1
342
 parselang_variant_name
0.00% covered (danger)
0.00%
0 / 44
0.00% covered (danger)
0.00%
0 / 1
182
 parselang_variant_nowiki
0.00% covered (danger)
0.00%
0 / 38
0.00% covered (danger)
0.00%
0 / 1
132
 parselang_variant_text_no_semi
0.00% covered (danger)
0.00%
0 / 18
0.00% covered (danger)
0.00%
0 / 1
42
 parselang_variant_text_no_semi_or_arrow
0.00% covered (danger)
0.00%
0 / 18
0.00% covered (danger)
0.00%
0 / 1
42
 discardlang_variant_text
0.00% covered (danger)
0.00%
0 / 34
0.00% covered (danger)
0.00%
0 / 1
156
 parsefull_table_in_link_caption_parameterized
0.00% covered (danger)
0.00%
0 / 75
0.00% covered (danger)
0.00%
0 / 1
600
 discardnowiki
0.00% covered (danger)
0.00%
0 / 35
0.00% covered (danger)
0.00%
0 / 1
90
 parsenowiki_text
0.00% covered (danger)
0.00%
0 / 23
0.00% covered (danger)
0.00%
0 / 1
56
 discardnowiki_check
0.00% covered (danger)
0.00%
0 / 33
0.00% covered (danger)
0.00%
0 / 1
30
 parsenowiki
0.00% covered (danger)
0.00%
0 / 35
0.00% covered (danger)
0.00%
0 / 1
90
 parse
0.00% covered (danger)
0.00%
0 / 42
0.00% covered (danger)
0.00%
0 / 1
420
1<?php
2/*
3 * DO NOT EDIT MANUALLY.
4 * File generated from Grammar.pegphp with `npm run regen-php-tokenizer`.
5 */
6
7
8namespace Wikimedia\Parsoid\Wt2Html;
9
10
11    use Wikimedia\Assert\UnreachableException;
12    use Wikimedia\JsonCodec\JsonCodec;
13    use Wikimedia\Parsoid\Config\Env;
14    use Wikimedia\Parsoid\Config\SiteConfig;
15    use Wikimedia\Parsoid\Core\DomSourceRange;
16    use Wikimedia\Parsoid\NodeData\DataMw;
17    use Wikimedia\Parsoid\NodeData\DataParsoid;
18    use Wikimedia\Parsoid\NodeData\TempData;
19    use Wikimedia\Parsoid\Tokens\CommentTk;
20    use Wikimedia\Parsoid\Tokens\EOFTk;
21    use Wikimedia\Parsoid\Tokens\EndTagTk;
22    use Wikimedia\Parsoid\Tokens\KV;
23    use Wikimedia\Parsoid\Tokens\KVSourceRange;
24    use Wikimedia\Parsoid\Tokens\NlTk;
25    use Wikimedia\Parsoid\Tokens\SelfclosingTagTk;
26    use Wikimedia\Parsoid\Tokens\SourceRange;
27    use Wikimedia\Parsoid\Tokens\TagTk;
28    use Wikimedia\Parsoid\Tokens\Token;
29    use Wikimedia\Parsoid\Utils\DOMDataUtils;
30    use Wikimedia\Parsoid\Utils\PHPUtils;
31    use Wikimedia\Parsoid\Utils\TokenUtils;
32    use Wikimedia\Parsoid\Utils\Utils;
33    use Wikimedia\Parsoid\Utils\WTUtils;
34    use Wikimedia\Parsoid\Wikitext\Consts;
35
36
37
38class GrammarCacheEntry {
39    public $nextPos;
40    public $result;
41    public $preproc;
42    public $th;
43
44
45    public function __construct( $nextPos, $result, $preproc, $th ) {
46        $this->nextPos = $nextPos;
47        $this->result = $result;
48        $this->preproc = $preproc;
49        $this->th = $th;
50
51    }
52}
53
54
55class Grammar extends \Wikimedia\WikiPEG\PEGParserBase {
56    // initializer
57    
58    /** @var Env */
59    private $env;
60
61    /** @var SiteConfig */
62    private $siteConfig;
63
64    /** @var array */
65    private $pipelineOpts;
66
67    /** @var int */
68    private $pipelineOffset;
69
70    private $extTags;
71
72    private $startTime;
73
74    /** @var string */
75    private $reUrltextLookahead;
76
77    /** @var string */
78    private $urltextPlainSegment = '';
79
80    /** @var bool */
81    private $urltextFoundAutolink = false;
82
83    protected function initialize() {
84        $this->env = $this->options['env'];
85        $this->siteConfig = $this->env->getSiteConfig();
86
87        $tokenizer = $this->options['pegTokenizer'];
88        $this->pipelineOpts = $tokenizer->getOptions();
89        // FIXME: inTemplate option may not always be set in
90        // standalone tokenizers user by some pipelines handlers.
91        $this->pipelineOffset = $this->options['pipelineOffset'] ?? 0;
92        $this->extTags = $this->siteConfig->getExtensionTagNameMap();
93
94        // Non-greedy text_char sequence: stop at ampersand, double-underscore,
95         // magic link prefix or protocol
96        $this->reUrltextLookahead = '!(?:' .
97            '([^-\'<[{\n\r:;\]}|\!=&]*?)' .
98            '(?:__|$|[-\'<[{\n\r:;\]}|\!=&]|(RFC|PMID|ISBN|' .
99            '(?i)' . $this->siteConfig->getProtocolsRegex( true ) .
100            ')))!A';
101    }
102
103    private $prevOffset = 0;
104    private $headingIndex = 0;
105
106    public function resetState() {
107        $this->prevOffset = 0;
108        $this->headingIndex = 0;
109    }
110
111    private function assert( $condition, $text ) {
112        if ( !$condition ) {
113            throw new \RuntimeException( "Grammar.pegphp assertion failure: $text" );
114        }
115    }
116
117    private function unreachable() {
118        throw new UnreachableException( "Grammar.pegphp: this should be unreachable" );
119    }
120
121    // Some shorthands for legibility
122    private function startOffset() {
123        return $this->savedPos;
124    }
125
126    private function endOffset() {
127        return $this->currPos;
128    }
129
130    private function tsrOffsets( $flag = 'default' ): SourceRange {
131        switch ( $flag ) {
132            case 'start':
133                return new SourceRange( $this->savedPos, $this->savedPos );
134            case 'end':
135                return new SourceRange( $this->currPos, $this->currPos );
136            default:
137                return new SourceRange( $this->savedPos, $this->currPos );
138        }
139    }
140
141    /*
142     * Emit a chunk of tokens to our consumers.  Once this has been done, the
143     * current expression can return an empty list (true).
144     */
145    private function emitChunk( $tokens ) {
146        // FIXME: We don't expect nulls here, but looks like
147        // hack from I1c695ab6cdd3655e98877c175ddbabdee9dc44b7
148        // introduces them. Work around it for now!
149        if ( !$tokens ) {
150            return [];
151        }
152
153        // Shift tsr of all tokens by the pipeline offset
154        TokenUtils::shiftTokenTSR( $tokens, $this->pipelineOffset );
155        $this->env->log( 'trace/peg', $this->options['pipelineId'] ?? '0', '---->   ', $tokens );
156
157        $i = null;
158        $n = count( $tokens );
159
160        // Enforce parsing resource limits
161        for ( $i = 0;  $i < $n;  $i++ ) {
162            TokenizerUtils::enforceParserResourceLimits( $this->env, $tokens[ $i ] );
163        }
164
165        return $tokens;
166    }
167
168    /* ------------------------------------------------------------------------
169     * Extension tags should be parsed with higher priority than anything else.
170     *
171     * The trick we use is to strip out the content inside a matching tag-pair
172     * and not tokenize it. The content, if it needs to parsed (for example,
173     * for <ref>, <*include*> tags), is parsed in a fresh tokenizer context
174     * which means any error correction that needs to happen is restricted to
175     * the scope of the extension content and doesn't spill over to the higher
176     * level.  Ex: <math><!--foo</math>.
177     *
178     * IGNORE: {{ this just balances the blocks in this comment for pegjs
179     *
180     * This trick also lets us prevent extension content (that don't accept WT)
181     * from being parsed as wikitext (Ex: <math>\frac{foo\frac{bar}}</math>)
182     * We don't want the "}}" being treated as a template closing tag and
183     * closing outer templates.
184     * --------------------------------------------------------------------- */
185
186    private function isXMLTag( string $name ): bool {
187        $lName = mb_strtolower( $name );
188        return isset( Consts::$HTML['HTML5Tags'][$lName] ) ||
189            isset( Consts::$HTML['OlderHTMLTags'][$lName] );
190    }
191
192
193
194    // cache init
195      protected $cache = [];
196
197    // expectations
198    protected $expectations = [
199        0 => ["type" => "end", "description" => "end of input"],
2001 => ["type" => "other", "description" => "start"],
2012 => ["type" => "other", "description" => "table_start_tag"],
2023 => ["type" => "class", "value" => "['{]", "description" => "['{]"],
2034 => ["type" => "literal", "value" => "&", "description" => "\"&\""],
2045 => ["type" => "other", "description" => "table_attributes"],
2056 => ["type" => "other", "description" => "generic_newline_attributes"],
2067 => ["type" => "any", "description" => "any character"],
2078 => ["type" => "other", "description" => "extlink"],
2089 => ["type" => "other", "description" => "tlb"],
20910 => ["type" => "class", "value" => "[ \\t]", "description" => "[ \\t]"],
21011 => ["type" => "literal", "value" => "<!--", "description" => "\"<!--\""],
21112 => ["type" => "literal", "value" => "-->", "description" => "\"-->\""],
21213 => ["type" => "literal", "value" => "|", "description" => "\"|\""],
21314 => ["type" => "literal", "value" => "{{!}}", "description" => "\"{{!}}\""],
21415 => ["type" => "literal", "value" => "//", "description" => "\"//\""],
21516 => ["type" => "class", "value" => "[A-Za-z]", "description" => "[A-Za-z]"],
21617 => ["type" => "class", "value" => "[-A-Za-z0-9+.]", "description" => "[-A-Za-z0-9+.]"],
21718 => ["type" => "literal", "value" => ":", "description" => "\":\""],
21819 => ["type" => "literal", "value" => "[", "description" => "\"[\""],
21920 => ["type" => "class", "value" => "[0-9A-Fa-f:.]", "description" => "[0-9A-Fa-f:.]"],
22021 => ["type" => "literal", "value" => "]", "description" => "\"]\""],
22122 => ["type" => "class", "value" => "[^ \\]\\[\\r\\n\"'<>\\x00-\\x20\\x7f&\\u00A0\\u1680\\u180E\\u2000-\\u200A\\u202F\\u205F\\u3000{]", "description" => "[^ \\]\\[\\r\\n\"'<>\\x00-\\x20\\x7f&\\u00A0\\u1680\\u180E\\u2000-\\u200A\\u202F\\u205F\\u3000{]"],
22223 => ["type" => "literal", "value" => "=", "description" => "\"=\""],
22324 => ["type" => "class", "value" => "[\\0/=>]", "description" => "[\\0/=>]"],
22425 => ["type" => "class", "value" => "[ \\u00A0\\u1680\\u2000-\\u200A\\u202F\\u205F\\u3000]", "description" => "[ \\u00A0\\u1680\\u2000-\\u200A\\u202F\\u205F\\u3000]"],
22526 => ["type" => "literal", "value" => ";", "description" => "\";\""],
22627 => ["type" => "literal", "value" => "\x0a", "description" => "\"\\n\""],
22728 => ["type" => "literal", "value" => "\x0d\x0a", "description" => "\"\\r\\n\""],
22829 => ["type" => "literal", "value" => "{", "description" => "\"{\""],
22930 => ["type" => "class", "value" => "[#0-9a-zA-Z\u{5e8}\u{5dc}\u{5de}\u{631}\u{644}\u{645}]", "description" => "[#0-9a-zA-Z\u{5e8}\u{5dc}\u{5de}\u{631}\u{644}\u{645}]"],
23031 => ["type" => "class", "value" => "[\"'=]", "description" => "[\"'=]"],
23132 => ["type" => "class", "value" => "[^ \\t\\r\\n\\0/=><&{}\\-!|\\[]", "description" => "[^ \\t\\r\\n\\0/=><&{}\\-!|\\[]"],
23233 => ["type" => "literal", "value" => "'", "description" => "\"'\""],
23334 => ["type" => "literal", "value" => "\"", "description" => "\"\\\"\""],
23435 => ["type" => "literal", "value" => "/", "description" => "\"/\""],
23536 => ["type" => "class", "value" => "[^ \\t\\r\\n\\0/=><&{}\\-!|]", "description" => "[^ \\t\\r\\n\\0/=><&{}\\-!|]"],
23637 => ["type" => "class", "value" => "[ \\t\\n\\r\\x0c]", "description" => "[ \\t\\n\\r\\x0c]"],
23738 => ["type" => "class", "value" => "[^<[{\\n\\r|!\\]}\\-\\t&=\"' \\u00A0\\u1680\\u180E\\u2000-\\u200A\\u202F\\u205F\\u3000]", "description" => "[^<[{\\n\\r|!\\]}\\-\\t&=\"' \\u00A0\\u1680\\u180E\\u2000-\\u200A\\u202F\\u205F\\u3000]"],
23839 => ["type" => "class", "value" => "[&|{\\-!}=]", "description" => "[&|{\\-!}=]"],
23940 => ["type" => "class", "value" => "[']", "description" => "[']"],
24041 => ["type" => "literal", "value" => "[[", "description" => "\"[[\""],
24142 => ["type" => "class", "value" => "[*#:;]", "description" => "[*#:;]"],
24243 => ["type" => "literal", "value" => "{{", "description" => "\"{{\""],
24344 => ["type" => "class", "value" => "[^{}&<\\-!\\['\\r\\n|]", "description" => "[^{}&<\\-!\\['\\r\\n|]"],
24445 => ["type" => "class", "value" => "[{}&<\\-!\\[]", "description" => "[{}&<\\-!\\[]"],
24546 => ["type" => "class", "value" => "[^{}&<\\-!\\[\"\\r\\n|]", "description" => "[^{}&<\\-!\\[\"\\r\\n|]"],
24647 => ["type" => "class", "value" => "[^{}&<\\-!\\[ \\t\\n\\r\\x0c|]", "description" => "[^{}&<\\-!\\[ \\t\\n\\r\\x0c|]"],
24748 => ["type" => "literal", "value" => "<", "description" => "\"<\""],
24849 => ["type" => "class", "value" => "[^{}&<\\-|/'>]", "description" => "[^{}&<\\-|/'>]"],
24950 => ["type" => "class", "value" => "[{}&\\-|/]", "description" => "[{}&\\-|/]"],
25051 => ["type" => "class", "value" => "[^{}&<\\-|/\">]", "description" => "[^{}&<\\-|/\">]"],
25152 => ["type" => "class", "value" => "[^{}&<\\-|/ \\t\\n\\r\\x0c>]", "description" => "[^{}&<\\-|/ \\t\\n\\r\\x0c>]"],
25253 => ["type" => "literal", "value" => "__", "description" => "\"__\""],
25354 => ["type" => "class", "value" => "[^-'<[{\\n\\r:;\\]}|!=]", "description" => "[^-'<[{\\n\\r:;\\]}|!=]"],
25455 => ["type" => "literal", "value" => "-", "description" => "\"-\""],
25556 => ["type" => "literal", "value" => "''", "description" => "\"''\""],
25657 => ["type" => "literal", "value" => "}", "description" => "\"}\""],
25758 => ["type" => "class", "value" => "[ \\t\\n\\r\\0\\x0b]", "description" => "[ \\t\\n\\r\\0\\x0b]"],
25859 => ["type" => "literal", "value" => "----", "description" => "\"----\""],
25960 => ["type" => "literal", "value" => "{{{", "description" => "\"{{{\""],
26061 => ["type" => "literal", "value" => "}}}", "description" => "\"}}}\""],
26162 => ["type" => "literal", "value" => "}}", "description" => "\"}}\""],
26263 => ["type" => "literal", "value" => "]]", "description" => "\"]]\""],
26364 => ["type" => "literal", "value" => ">", "description" => "\">\""],
26465 => ["type" => "class", "value" => "[0-9]", "description" => "[0-9]"],
26566 => ["type" => "literal", "value" => "ISBN", "description" => "\"ISBN\""],
26667 => ["type" => "class", "value" => "[xX]", "description" => "[xX]"],
26768 => ["type" => "literal", "value" => "+", "description" => "\"+\""],
26869 => ["type" => "literal", "value" => "</>", "description" => "\"</>\""],
26970 => ["type" => "literal", "value" => "#parsoid\x00fragment:", "description" => "\"#parsoid\\u0000fragment:\""],
27071 => ["type" => "class", "value" => "[^<[{\\n\\r\\t|!\\]}{ &\\-]", "description" => "[^<[{\\n\\r\\t|!\\]}{ &\\-]"],
27172 => ["type" => "class", "value" => "[!<\\-\\}\\]\\n\\r]", "description" => "[!<\\-\\}\\]\\n\\r]"],
27273 => ["type" => "literal", "value" => "RFC", "description" => "\"RFC\""],
27374 => ["type" => "literal", "value" => "PMID", "description" => "\"PMID\""],
27475 => ["type" => "literal", "value" => "-{", "description" => "\"-{\""],
27576 => ["type" => "literal", "value" => "}-", "description" => "\"}-\""],
27677 => ["type" => "literal", "value" => "!", "description" => "\"!\""],
27778 => ["type" => "class", "value" => "[^\\t\\n\\v />\\0]", "description" => "[^\\t\\n\\v />\\0]"],
27879 => ["type" => "literal", "value" => "!!", "description" => "\"!!\""],
27980 => ["type" => "literal", "value" => "||", "description" => "\"||\""],
28081 => ["type" => "literal", "value" => "{{!}}{{!}}", "description" => "\"{{!}}{{!}}\""],
28182 => ["type" => "literal", "value" => "=>", "description" => "\"=>\""],
28283 => ["type" => "class", "value" => "[-+A-Z]", "description" => "[-+A-Z]"],
28384 => ["type" => "class", "value" => "[^{}|;]", "description" => "[^{}|;]"],
28485 => ["type" => "class", "value" => "[a-z]", "description" => "[a-z]"],
28586 => ["type" => "class", "value" => "[-a-zA-Z]", "description" => "[-a-zA-Z]"],
286    ];
287
288    // actions
289    private function a0() {
290
291                $this->startTime = null;
292                if ( $this->env->profiling() ) {
293                    $profile = $this->env->getCurrentProfile();
294                    $this->startTime = microtime( true );
295                }
296                return true;
297            
298}
299private function a1($t) {
300
301                if ( $this->env->profiling() ) {
302                    $profile = $this->env->getCurrentProfile();
303                    $profile->bumpTimeUse(
304                        'PEG', 1000 * ( microtime( true ) - $this->startTime ), 'PEG' );
305                }
306                return true;
307            
308}
309private function a2($t) {
310 return $t; 
311}
312private function a3() {
313
314            // "tlb" matches "block" matches "sol" matches "newlineToken"
315            // But, "tlb" is prefixed with a !eof clause, so, we should only
316            // get here on eof. So, safe to unconditionally terminate the
317            // generator loop here.
318            return false;
319        
320}
321private function a4($t, $n) {
322
323        if ( count( $t ) ) {
324            $ret = TokenizerUtils::flattenIfArray( $t );
325        } else {
326            $ret = [];
327        }
328        if ( count( $n ) ) {
329            PHPUtils::pushArray($ret, $n);
330        }
331        $ret[] = new EOFTk();
332        return $ret;
333    
334}
335private function a5($sc) {
336 return $this->endOffset(); 
337}
338private function a6($sc, $startPos, $b, $p) {
339 $this->unreachable(); 
340}
341private function a7($sc, $startPos, $b, $p, $ta) {
342 return $this->endOffset(); 
343}
344private function a8($sc, $startPos, $b, $p, $ta, $tsEndPos, $s2) {
345
346        $coms = TokenizerUtils::popComments( $ta );
347        if ( $coms ) {
348            $tsEndPos = $coms['commentStartPos'];
349        }
350
351        $dp = new DataParsoid;
352        $dp->tsr = new SourceRange( $startPos, $tsEndPos );
353        if ( $p !== '|' ) {
354            // Variation from default
355            $dp->startTagSrc = $b . $p;
356        }
357
358        return array_merge( $sc,
359            [ new TagTk( 'table', $ta, $dp ) ],
360            $coms ? $coms['buf'] : [],
361            $s2 );
362    
363}
364private function a9($proto, $addr, $he) {
365 return $he; 
366}
367private function a10($proto, $addr, $r) {
368 return $r; 
369}
370private function a11($proto, $addr, $c) {
371 return $c; 
372}
373private function a12($proto, $addr, $path) {
374 return $addr !== '' || count( $path ) > 0; 
375}
376private function a13($proto, $addr, $path) {
377
378        return TokenizerUtils::flattenString( array_merge( [ $proto, $addr ], $path ) );
379    
380}
381private function a14($as, $s, $p) {
382
383        return [ $as, $s, $p ];
384    
385}
386private function a15($b) {
387 return $b; 
388}
389private function a16($r) {
390 return TokenizerUtils::flattenIfArray( $r ); 
391}
392private function a17() {
393 return $this->endOffset(); 
394}
395private function a18($p0, $addr, $target) {
396 return TokenizerUtils::flattenString( [ $addr, $target ] ); 
397}
398private function a19($p0, $flat) {
399
400            // Protocol must be valid and there ought to be at least one
401            // post-protocol character.  So strip last char off target
402            // before testing protocol.
403            if ( is_array( $flat ) ) {
404                // There are templates present, alas.
405                return count( $flat ) > 0;
406            }
407            return Utils::isProtocolValid( substr( $flat, 0, -1 ), $this->env );
408        
409}
410private function a20($p0, $flat) {
411 return $this->endOffset(); 
412}
413private function a21($p0, $flat, $p1, $sp) {
414 return $this->endOffset(); 
415}
416private function a22($p0, $flat, $p1, $sp, $p2, $content) {
417 return $this->endOffset(); 
418}
419private function a23($p0, $flat, $p1, $sp, $p2, $content, $p3) {
420
421            $tsr1 = new SourceRange( $p0, $p1 );
422            $tsr2 = new SourceRange( $p2, $p3 );
423            $dp = new DataParsoid;
424            $dp->tsr = $this->tsrOffsets();
425            $dp->getTemp()->extLinkContentOffsets = $tsr2;
426            return [
427                new SelfclosingTagTk(
428                    'extlink',
429                    [
430                        new KV( 'href', $flat, $tsr1->expandTsrV() ),
431                        new KV( 'mw:content', $content ?? '', $tsr2->expandTsrV() ),
432                        new KV( 'spaces', $sp )
433                    ],
434                    $dp
435                )
436            ]; 
437}
438private function a24($r) {
439 return $r; 
440}
441private function a25($b) {
442
443        // Clear the tokenizer's backtracking cache after matching each
444        // toplevelblock. There won't be any backtracking as a document is just a
445        // sequence of toplevelblocks, so the cache for previous toplevelblocks
446        // will never be needed.
447        $end = $this->startOffset();
448        for ( ;  $this->prevOffset < $end;  $this->prevOffset++ ) {
449            unset( $this->cache[$this->prevOffset] );
450        }
451
452        $tokens = null;
453        if ( is_array( $b ) && count( $b ) ) {
454            $tokens = TokenizerUtils::flattenIfArray( $b );
455        } elseif ( is_string( $b ) ) {
456            $tokens = [ $b ];
457        }
458
459        // Emit tokens for this toplevelblock. This feeds a chunk to the parser pipeline.
460        return $this->emitChunk( $tokens );
461    
462}
463private function a26() {
464 return [ new NlTk( $this->tsrOffsets() ) ]; 
465}
466private function a27($c, $cEnd) {
467
468        $data = WTUtils::encodeComment( $c );
469        $dp = new DataParsoid;
470        $dp->tsr = $this->tsrOffsets();
471        if ( $cEnd !== '-->' ) {
472            $dp->unclosedComment = true;
473        }
474        return [ new CommentTk( $data, $dp ) ];
475    
476}
477private function a28($p) {
478 return Utils::isProtocolValid( $p, $this->env ); 
479}
480private function a29($p) {
481 return $p; 
482}
483private function a30($annOrExtTag, $h, $extlink, $intemplate, &$preproc, $equal, $table, $templateArg, $tableCellArg, $semicolon, $arrow, $linkdesc, $colon, &$th) {
484
485            return TokenizerUtils::inlineBreaks( $this->input, $this->endOffset(), [
486                'annOrExtTag' => $annOrExtTag,
487                'h' => $h,
488                'extlink' => $extlink,
489                'intemplate' => $intemplate,
490                'preproc' => $preproc,
491                'equal' => $equal,
492                'table' => $table,
493                'templateArg' => $templateArg,
494                'tableCellArg' => $tableCellArg,
495                'semicolon' => $semicolon,
496                'arrow' => $arrow,
497                'linkdesc' => $linkdesc,
498                'colon' => $colon,
499                'th' => $th
500            ], $this->env );
501        
502}
503private function a31($t) {
504
505        return $t;
506    
507}
508private function a32($cc) {
509
510        // if this is an invalid entity, don't tag it with 'mw:Entity'
511        // note that some entities (like &acE;) decode to 2 codepoints!
512        if ( mb_strlen( $cc ) > 2 /* decoded entity would be 1-2 codepoints */ ) {
513            return $cc;
514        }
515        $dpStart = new DataParsoid;
516        $dpStart->src = $this->text();
517        $dpStart->srcContent = $cc;
518        $dpStart->tsr = $this->tsrOffsets( 'start' );
519        $dpEnd = new DataParsoid;
520        $dpEnd->tsr = $this->tsrOffsets( 'end' );
521        return [
522            // If this changes, the nowiki extension's toDOM will need to follow suit
523            new TagTk( 'span', [ new KV( 'typeof', 'mw:Entity' ) ], $dpStart ),
524            $cc,
525            new EndTagTk( 'span', [], $dpEnd )
526        ];
527    
528}
529private function a33($s) {
530 return $this->endOffset(); 
531}
532private function a34($s, $namePos0, $name) {
533 return $this->endOffset(); 
534}
535private function a35($s, $namePos0, $name, $namePos1, $v) {
536 return $v; 
537}
538private function a36($s, $namePos0, $name, $namePos1, $vd) {
539
540    // NB: Keep in sync w/ generic_newline_attribute
541    $res = null;
542    // Encapsulate protected attributes.
543    if ( gettype( $name ) === 'string' ) {
544        $name = TokenizerUtils::protectAttrs( $name );
545    }
546    $nameSO = new SourceRange( $namePos0, $namePos1 );
547    if ( $vd !== null ) {
548        $res = new KV( $name, $vd['value'], $nameSO->join( $vd['srcOffsets'] ) );
549        $res->vsrc = $vd['srcOffsets']->substr( $this->input );
550    } else {
551        $res = new KV( $name, '', $nameSO->expandTsrK() );
552    }
553    if ( is_array( $name ) ) {
554        $res->ksrc = $nameSO->substr( $this->input );
555    }
556    return $res;
557
558}
559private function a37($s) {
560
561        if ( $s !== '' ) {
562            return [ $s ];
563        } else {
564            return [];
565        }
566    
567}
568private function a38($c) {
569 return new KV( $c, '' ); 
570}
571private function a39($namePos0, $name) {
572 return $this->endOffset(); 
573}
574private function a40($namePos0, $name, $namePos1, $v) {
575 return $v; 
576}
577private function a41($namePos0, $name, $namePos1, $vd) {
578
579    // NB: Keep in sync w/ table_attibute
580    $res = null;
581    // Encapsulate protected attributes.
582    if ( is_string( $name ) ) {
583        $name = TokenizerUtils::protectAttrs( $name );
584    }
585    $nameSO = new SourceRange( $namePos0, $namePos1 );
586    if ( $vd !== null ) {
587        $res = new KV( $name, $vd['value'], $nameSO->join( $vd['srcOffsets'] ) );
588        $res->vsrc = $vd['srcOffsets']->substr( $this->input );
589    } else {
590        $res = new KV( $name, '', $nameSO->expandTsrK() );
591    }
592    if ( is_array( $name ) ) {
593        $res->ksrc = $nameSO->substr( $this->input );
594    }
595    return $res;
596
597}
598private function a42($s) {
599 return $s; 
600}
601private function a43($c) {
602
603        return TokenizerUtils::flattenStringlist( $c );
604    
605}
606private function a44($lc) {
607 return $lc; 
608}
609private function a45($bullets, $colons, $d) {
610
611        $bulletToks = [];
612        // Leave bullets as an array -- list handler expects this
613        // TSR: +1 for the leading ";"
614        $numBullets = count( $bullets ) + 1;
615        $tsr = $this->tsrOffsets( 'start' );
616        $tsr->end += $numBullets;
617        $li1Bullets = $bullets;
618        $li1Bullets[] = ';';
619        $dp = new DataParsoid;
620        $dp->tsr = $tsr;
621        $bulletToks[] = new TagTk( 'listItem', [ new KV( 'bullets', $li1Bullets, $tsr->expandTsrV() ) ], $dp );
622        foreach ( $colons as $colon) {
623            if ( $colon[0] ) { // can be null because of "?" in dtdd_colon
624                $bulletToks[] = $colon[0];
625            }
626            $cpos = $colon[1];
627            // TSR: -1 for the intermediate ":"
628            $li2Bullets = $bullets;
629            $li2Bullets[] = ':';
630            $tsr2 = new SourceRange( $cpos - 1, $cpos );
631            $dp2 = new DataParsoid;
632            $dp2->tsr = $tsr2;
633            $dp2->stx = 'row';
634            $bulletToks[] = new TagTk( 'listItem', [ new KV( 'bullets', $li2Bullets, $tsr2->expandTsrV() ) ], $dp2 );
635        }
636
637        if ( $d ) {
638            $bulletToks = array_merge( $bulletToks, $d );
639        }
640        return $bulletToks;
641    
642}
643private function a46($bullets, $tbl, $line) {
644
645    // Leave bullets as an array -- list handler expects this
646    $tsr = $this->tsrOffsets( 'start' );
647    $tsr->end += count( $bullets );
648    $dp = new DataParsoid;
649    $dp->tsr = $tsr;
650    $li = new TagTk( 'listItem', [ new KV( 'bullets', $bullets, $tsr->expandTsrV() ) ], $dp );
651    return TokenizerUtils::flattenIfArray( [ $li, $tbl, $line ?: [] ] );
652
653}
654private function a47($bullets, $c) {
655
656        // Leave bullets as an array -- list handler expects this
657        $tsr = $this->tsrOffsets( 'start' );
658        $tsr->end += count( $bullets );
659        $dp = new DataParsoid;
660        $dp->tsr = $tsr;
661        $li = new TagTk( 'listItem', [ new KV( 'bullets', $bullets, $tsr->expandTsrV() ) ], $dp );
662        return array_merge( [ $li ], $c ?: [] );
663    
664}
665private function a48() {
666 return $this->endOffset() === $this->inputLength; 
667}
668private function a49($r, $cil, $bl) {
669
670        return array_merge( [ $r ], $cil, $bl ?: [] );
671    
672}
673private function a50($a) {
674 return $a; 
675}
676private function a51($a, $b) {
677 return [ $a, $b ]; 
678}
679private function a52($m) {
680
681        return Utils::decodeWtEntities( $m );
682    
683}
684private function a53($q, $x, $ill) {
685 return array_merge( [$x], $ill ?: [] ); 
686}
687private function a54($q, $t) {
688 return $t; 
689}
690private function a55($q, $r) {
691 return count( $r ) > 0 || $q !== ''; 
692}
693private function a56($q, $r) {
694
695        array_unshift( $r, $q );
696        return TokenizerUtils::flattenString( $r );
697    
698}
699private function a57($s, $t, $q) {
700
701        return TokenizerUtils::getAttrVal( $t, $this->startOffset() + strlen( $s ), $this->endOffset() - strlen( $q ) );
702    
703}
704private function a58($s, $t) {
705
706        return TokenizerUtils::getAttrVal( $t, $this->startOffset() + strlen( $s ), $this->endOffset() );
707    
708}
709private function a59($r) {
710
711        return TokenizerUtils::flattenString( $r );
712    
713}
714private function a60() {
715
716            if ( preg_match( $this->reUrltextLookahead, $this->input, $m, 0, $this->currPos ) ) {
717                $plain = $m[1];
718                $this->urltextPlainSegment = $plain;
719                $this->urltextFoundAutolink = ( $m[2] ?? '' ) !== '';
720                return (bool)strlen( $plain );
721            } else {
722                $this->urltextFoundAutolink = false;
723                return false;
724            }
725        
726}
727private function a61() {
728
729            $this->currPos += strlen( $this->urltextPlainSegment );
730            return $this->urltextPlainSegment;
731        
732}
733private function a62() {
734 return $this->urltextFoundAutolink; 
735}
736private function a63($al) {
737 return $al; 
738}
739private function a64($he) {
740 return $he; 
741}
742private function a65($bs) {
743 return $bs; 
744}
745private function a66($c) {
746 return $this->endOffset(); 
747}
748private function a67($c, $cpos) {
749
750    return [ $c, $cpos ];
751
752}
753private function a68($tl) {
754
755        return $tl;
756    
757}
758private function a69($sp, $elc, $st) {
759
760    return [ $sp, $elc ?? [], $st ];
761
762}
763private function a70() {
764 return $this->endOffset() === 0 && !$this->pipelineOffset; 
765}
766private function a71($rw, $sp, $c, $wl) {
767
768        return count( $wl ) === 1 && $wl[0] instanceof Token;
769    
770}
771private function a72($rw, $sp, $c, $wl) {
772
773        $link = $wl[0];
774        if ( $sp ) {
775            $rw .= $sp;
776        }
777        if ( $c ) {
778            $rw .= $c;
779        }
780        // Build a redirect token
781        $dp = new DataParsoid;
782        $dp->src = $rw;
783        $dp->tsr = $this->tsrOffsets();
784        $dp->linkTk = $link;
785        $redirect = new SelfclosingTagTk( 'mw:redirect',
786            // Put 'href' into attributes so it gets template-expanded
787            [ $link->getAttributeKV( 'href' ) ],
788            $dp
789        );
790        return $redirect;
791    
792}
793private function a73($st, $tl) {
794
795        return array_merge( $st, $tl );
796    
797}
798private function a74($s, $os, $so) {
799 return array_merge( $os, $so ); 
800}
801private function a75($s, $s2, $bl) {
802
803        return array_merge( $s, $s2 ?: [], $bl );
804    
805}
806private function a76(&$preproc, $t) {
807
808        $preproc = null;
809        return $t;
810    
811}
812private function a77($v) {
813 return $v; 
814}
815private function a78($e) {
816 return $e; 
817}
818private function a79() {
819 return Utils::isUniWord(Utils::lastUniChar( $this->input, $this->endOffset() ) ); 
820}
821private function a80($bs) {
822
823        if ( $this->siteConfig->isBehaviorSwitch( $bs ) ) {
824            $dp = new DataParsoid;
825            $dp->tsr = $this->tsrOffsets();
826            $dp->src = $bs;
827            $dp->magicSrc = $bs;
828            return [
829                new SelfclosingTagTk( 'behavior-switch', [ new KV( 'word', $bs ) ], $dp )
830            ];
831        } else {
832            return [ $bs ];
833        }
834    
835}
836private function a81($quotes) {
837
838        // sequences of four or more than five quotes are assumed to start
839        // with some number of plain-text apostrophes.
840        $plainticks = 0;
841        $result = [];
842        if ( strlen( $quotes ) === 4 ) {
843            $plainticks = 1;
844        } elseif ( strlen( $quotes ) > 5 ) {
845            $plainticks = strlen( $quotes ) - 5;
846        }
847        if ( $plainticks > 0 ) {
848            $result[] = substr( $quotes, 0, $plainticks );
849        }
850        // mw-quote token will be consumed in token transforms
851        $tsr = $this->tsrOffsets();
852        $tsr->start += $plainticks;
853        $dp = new DataParsoid;
854        $dp->tsr = $tsr;
855        $mwq = new SelfclosingTagTk( 'mw-quote',
856            [ new KV( 'value', substr( $quotes, $plainticks ) ) ],
857            $dp );
858        if ( strlen( $quotes ) > 2 ) {
859            $mwq->addAttribute( 'isSpace_1', $tsr->start > 0 && substr( $this->input, $tsr->start - 1, 1 ) === ' ');
860            $mwq->addAttribute( 'isSpace_2', $tsr->start > 1 && substr( $this->input, $tsr->start - 2, 1 ) === ' ');
861        }
862        $result[] = $mwq;
863        return $result;
864    
865}
866private function a82($sc, $startPos, $p, $b) {
867
868        $dp = new DataParsoid;
869        $dp->tsr = new SourceRange( $startPos, $this->endOffset() );
870        $tblEnd = new EndTagTk( 'table', [], $dp );
871        if ( $p !== '|' ) {
872            // p+"<brace-char>" is triggering some bug in pegJS
873            // I cannot even use that expression in the comment!
874            $tblEnd->dataParsoid->endTagSrc = $p . $b;
875        }
876        array_push( $sc, $tblEnd );
877        return $sc;
878    
879}
880private function a83() {
881
882        // Use the sol flag only at the start of the input
883        // Flag should always be an actual boolean (not falsy or undefined)
884        $this->assert( is_bool( $this->options['sol'] ), 'sol should be boolean' );
885        return $this->endOffset() === 0 && $this->options['sol'];
886    
887}
888private function a84() {
889
890        return [];
891    
892}
893private function a85($p, $c) {
894
895        $dp = new DataParsoid;
896        $dp->tsr = new SourceRange( $p, $this->endOffset() );
897        $dp->tokens = TokenizerUtils::flattenIfArray( $c );
898        return [
899            new SelfclosingTagTk( 'meta', [ new KV( 'typeof', 'mw:EmptyLine' ) ], $dp )
900        ];
901    
902}
903private function a86($rw) {
904
905            return preg_match( $this->env->getSiteConfig()->getMagicWordMatcher( 'redirect' ), $rw );
906        
907}
908private function a87($t) {
909
910        $tagName = mb_strtolower( $t->getName() );
911        switch ( $tagName ) {
912            case 'includeonly':
913                $typeOf = 'mw:Includes/IncludeOnly';
914                break;
915            case 'noinclude':
916                $typeOf = 'mw:Includes/NoInclude';
917                break;
918            case 'onlyinclude':
919                $typeOf = 'mw:Includes/OnlyInclude';
920                break;
921            default:
922                $this->unreachable();
923        }
924
925        $isEnd = ( $t instanceof EndTagTk );
926        if ( $isEnd ) {
927            $typeOf .= '/End';
928        }
929
930        $dp = new DataParsoid;
931        $dp->tsr = $t->dataParsoid->tsr;
932        $dp->src = $dp->tsr->substr( $this->input );
933
934        $meta = new SelfclosingTagTk(
935            'meta', [ new KV( 'typeof', $typeOf ) ], $dp
936        );
937
938        $startTagWithContent = false;
939        if ( $t instanceof TagTk ) {
940            $endTagRE = '~.*?(</' . preg_quote( $tagName, '~' ) . '\s*>)~iusA';
941            $startTagWithContent = preg_match(
942                $endTagRE, $this->input, $content, 0, $dp->tsr->start
943            );
944        }
945
946        if ( !empty( $this->pipelineOpts['inTemplate'] ) ) {
947            switch ( $tagName ) {
948                case 'includeonly':
949                    // Drop the tag
950                    return [];
951                case 'noinclude':
952                    if ( $startTagWithContent ) {
953                        // Skip the content
954                        $this->currPos = $dp->tsr->start + strlen( $content[0] );
955                    }
956                    // Drop it all
957                    return [];
958                case 'onlyinclude':
959                    if ( $startTagWithContent ) {
960                        // Parse the content, strip eof, and shift tsr
961                        $contentSrc = $content[0];
962                        $endOffset = $dp->tsr->start + strlen( $contentSrc );
963                        $endTagWidth = strlen( $content[1] );
964                        $tagOffsets = new DomSourceRange(
965                            $dp->tsr->start, $endOffset,
966                            $dp->tsr->length(), $endTagWidth
967                        );
968                        $this->currPos = $tagOffsets->innerEnd();
969                        $justContent = $tagOffsets->stripTags( $contentSrc );
970                        // FIXME: What about the pipelineOpts of the current pipeline?
971                        $tokenizer = new PegTokenizer( $this->env );
972                        $tokenizer->setSourceOffsets( $tagOffsets->innerRange() );
973                        $contentToks = $tokenizer->tokenizeSync(
974                            $justContent, [ 'sol' => true ]
975                        );
976                        TokenUtils::stripEOFTkFromTokens( $contentToks );
977                        array_unshift( $contentToks, $t );
978                        return $contentToks;
979                    } else {
980                        return [$t];
981                    }
982            }
983        } else {
984            $tokens = [ $meta ];
985            if ( $tagName === 'includeonly' ) {
986                if ( $startTagWithContent ) {
987                    // Add the content / end tag to the meta for roundtripping
988                    $dp->tsr->end = $dp->tsr->start + strlen( $content[0] );
989                    $dp->src = $dp->tsr->substr( $this->input );
990                    $meta->dataMw = new DataMw( [ 'src' => $dp->src ] );
991                    $this->currPos = $dp->tsr->end;
992                    // FIXME: We shouldn't bother with this because SelfclosingTk
993                    // was never balanced to begin with
994                    if ( strlen( $content[1] ) ) {
995                        $eDp = new DataParsoid;
996                        $eDp->tsr = new SourceRange( $dp->tsr->end, $dp->tsr->end );
997                        $eDp->src = $eDp->tsr->substr( $this->input );
998                        $tokens[] = new SelfclosingTagTk( 'meta', [
999                            new KV( 'typeof', 'mw:Includes/IncludeOnly/End' )
1000                        ], $eDp );
1001                    }
1002                } elseif ( !( $t instanceof EndTagTk ) ) {
1003                    $meta->dataMw = new DataMw( [ 'src' => $dp->src ] );
1004                } else {
1005                    // Compatibility with the legacy parser which leaves these in
1006                    // as strings, which the sanitizer will do for us
1007                    array_pop( $tokens );
1008                    $tokens[] = $t;
1009                }
1010            }
1011            return $tokens;
1012        }
1013    
1014}
1015private function a88($t) {
1016
1017            $end = ( $t instanceof EndTagTk );
1018            $attribs = $t->attribs;
1019            $tagName = mb_strtolower( $t->getName() );
1020            $tsr = $t->dataParsoid->tsr;
1021
1022            // We already applied this logic in WTUtils::isAnnotationTag
1023            // to get here so we can make some assumptions.
1024            if ( !$this->siteConfig->isAnnotationTag( $tagName ) ) {
1025                $pipepos = strpos( $tagName, '|' );
1026                $strBeforePipe = substr( $tagName, 0, $pipepos );
1027                $newName = substr( $tagName, $pipepos + 1, strlen( $tagName ) - $pipepos - 1 );
1028                $attribs = [ new KV( "name", $newName ) ];
1029                $tagName = $strBeforePipe;
1030            }
1031
1032            $metaAttrs = [ new KV( 'typeof', 'mw:Annotation/' . $tagName . ( $end ? '/End' : '' ) ) ];
1033            $datamw = null;
1034            if ( count( $attribs ) > 0 ) {
1035                $attrMap = [];
1036                foreach ( $attribs as $attr ) {
1037                    // If the key or the value is not a string,
1038                    // we replace it by the thing that generated it and
1039                    // consider that wikitext as a raw string instead.
1040                    $k = is_string( $attr->k ) ? $attr->k : $attr->ksrc;
1041                    $v = is_string( $attr->v ) ? $attr->v : $attr->vsrc;
1042                    $attrMap[$k] = $v;
1043                }
1044                // Possible follow-up in T295168 for attribute sanitation
1045                // T367616: 'attrs' should be renamed to 'extAttrs'
1046                $datamw = new DataMw( [ 'attrs' => (object)$attrMap ] );
1047            }
1048            $dp = new DataParsoid();
1049            $dp->tsr = $tsr;
1050            $this->env->hasAnnotations = true;
1051
1052            return new SelfclosingTagTk ( 'meta', $metaAttrs, $dp, $datamw );
1053        
1054}
1055private function a89($tag) {
1056
1057        // FIXME: Suppress annotation meta tokens from template pipelines
1058        // since they may not have TSR values and won't get recognized as
1059        // annotation ranges. Without TSR, they might end up stuck in
1060        // fosterable positions and cause havoc on edits by breaking selser.
1061        if ( empty( $this->pipelineOpts['inTemplate'] ) ) {
1062            return $tag;
1063        } else {
1064            return '';
1065        }
1066    
1067}
1068private function a90($s, $ill) {
1069 return $ill ?: []; 
1070}
1071private function a91($s, $ce) {
1072 return $ce || strlen( $s ) > 2; 
1073}
1074private function a92($s, $ce) {
1075 return $this->endOffset(); 
1076}
1077private function a93($s, $ce, $endTPos, $spc) {
1078
1079            $c = null;
1080            $e = null;
1081            $level = null;
1082            if ( $ce ) {
1083                $c = $ce[0];
1084                $e = $ce[1];
1085                $level = min( strlen( $s ), strlen( $e ) );
1086            } else {
1087                // split up equal signs into two equal parts, with at least
1088                // one character in the middle.
1089                $level = (int)floor( ( strlen( $s ) - 1 ) / 2 );
1090                $c = [ str_repeat( '=', strlen( $s ) - 2 * $level ) ];
1091                $s = $e = str_repeat( '=', $level );
1092            }
1093            $level = min( 6, $level );
1094            // convert surplus equals into text
1095            if ( strlen( $s ) > $level ) {
1096                $extras1 = substr( $s, 0, strlen( $s ) - $level );
1097                if ( is_string( $c[0] ) ) {
1098                    $c[0] = $extras1 . $c[0];
1099                } else {
1100                    array_unshift( $c, $extras1 );
1101                }
1102            }
1103            if ( strlen( $e ) > $level ) {
1104                $extras2 = substr( $e, 0, strlen( $e ) - $level );
1105                $lastElem = PHPUtils::lastItem( $c );
1106                if ( is_string( $lastElem ) ) {
1107                    $c[count( $c ) - 1] .= $extras2;
1108                } else {
1109                    $c[] = $extras2;
1110                }
1111            }
1112
1113            $tagDP = new DataParsoid;
1114            $tagDP->tsr = $this->tsrOffsets( 'start' );
1115            $tagDP->tsr->end += $level;
1116            // Match the old parser's behavior by
1117            // (a) making headingIndex part of tokenizer state
1118            //   (don't reuse pipeline! see $this->resetState above)
1119            // (b) assigning the index when ==*== is tokenized,
1120            //   even if we're inside a template argument
1121            //   or other context which won't end up putting the heading
1122            //   on the output page.  T213468/T214538
1123            $this->headingIndex++;
1124            $tagDP->getTemp()->headingIndex = $this->headingIndex;
1125            $res = [ new TagTk( 'h' . $level, [], $tagDP ) ];
1126
1127            PHPUtils::pushArray( $res, $c );
1128
1129            $endTagDP = new DataParsoid;
1130            $endTagDP->tsr = new SourceRange( $endTPos - $level, $endTPos );
1131            $res[] = new EndTagTk( 'h' . $level, [], $endTagDP );
1132            $res[] = $spc;
1133            return $res;
1134        
1135}
1136private function a94($d) {
1137 return null; 
1138}
1139private function a95($d) {
1140 return true; 
1141}
1142private function a96($d, $lineContent) {
1143
1144        $dataParsoid = new DataParsoid;
1145        $dataParsoid->tsr = $this->tsrOffsets();
1146        if ( $lineContent !== null ) {
1147            $dataParsoid->lineContent = $lineContent;
1148        }
1149        if ( strlen( $d ) > 0 ) {
1150            $dataParsoid->extra_dashes = strlen( $d );
1151        }
1152        return [new SelfclosingTagTk( 'hr', [], $dataParsoid )];
1153    
1154}
1155private function a97($p, $target) {
1156 return $this->endOffset(); 
1157}
1158private function a98($p, $target, $p0, $v) {
1159 return $this->endOffset(); 
1160}
1161private function a99($p, $target, $p0, $v, $p1) {
1162
1163                // empty argument
1164                return [ 'tokens' => $v, 'srcOffsets' => new SourceRange( $p0, $p1 ) ];
1165            
1166}
1167private function a100($p, $target, $r) {
1168 return $r; 
1169}
1170private function a101($p, $target, $params) {
1171
1172        $kvs = [];
1173
1174        if ( $target === null ) {
1175            $target = [ 'tokens' => '', 'srcOffsets' => new SourceRange( $p, $p ) ];
1176        }
1177        // Insert target as first positional attribute, so that it can be
1178        // generically expanded. The TemplateHandler then needs to shift it out
1179        // again.
1180        $kvs[] = new KV( TokenizerUtils::flattenIfArray( $target['tokens'] ), '', $target['srcOffsets']->expandTsrK() );
1181
1182        foreach ( $params as $o ) {
1183            $s = $o['srcOffsets'];
1184            $kvs[] = new KV( '', TokenizerUtils::flattenIfArray( $o['tokens'] ), $s->expandTsrV() );
1185        }
1186
1187        $dp = new DataParsoid;
1188        $dp->tsr = $this->tsrOffsets();
1189        $dp->src = $this->text();
1190        $obj = new SelfclosingTagTk( 'templatearg', $kvs, $dp );
1191        return $obj;
1192    
1193}
1194private function a102($leadWS, $target) {
1195 return $this->endOffset(); 
1196}
1197private function a103($leadWS, $target, $p0, $v) {
1198 return $this->endOffset(); 
1199}
1200private function a104($leadWS, $target, $p0, $v, $p1) {
1201
1202                // empty argument
1203                $tsr0 = new SourceRange( $p0, $p1 );
1204                return new KV( '', TokenizerUtils::flattenIfArray( $v ), $tsr0->expandTsrV() );
1205            
1206}
1207private function a105($leadWS, $target, $r) {
1208 return $r; 
1209}
1210private function a106($leadWS, $target, $params, $trailWS) {
1211
1212        // Insert target as first positional attribute, so that it can be
1213        // generically expanded. The TemplateHandler then needs to shift it out
1214        // again.
1215        array_unshift( $params, new KV( TokenizerUtils::flattenIfArray( $target['tokens'] ), '', $target['srcOffsets']->expandTsrK() ) );
1216        $dp = new DataParsoid;
1217        $dp->tsr = $this->tsrOffsets();
1218        $dp->src = $this->text();
1219        $tmp = $dp->getTemp();
1220        $tmp->leadWS = $leadWS;
1221        $tmp->trailWS = $trailWS;
1222        $obj = new SelfclosingTagTk( 'template', $params, $dp );
1223        return $obj;
1224    
1225}
1226private function a107($spos, $target) {
1227 return $this->endOffset(); 
1228}
1229private function a108($spos, $target, $tpos, $lcs) {
1230
1231        $pipeTrick = count( $lcs ) === 1 && count( $lcs[0]->v ) === 0;
1232        $textTokens = [];
1233        if ( $target === null || $pipeTrick ) {
1234            $textTokens[] = '[[';
1235            if ( $target ) {
1236                $textTokens[] = $target;
1237            }
1238            foreach ( $lcs as $a ) {
1239                // a is a mw:maybeContent attribute
1240                $textTokens[] = '|';
1241                if ( count( $a->v ) > 0 ) {
1242                    $textTokens[] = $a->v;
1243                }
1244            }
1245            $textTokens[] = ']]';
1246            return $textTokens;
1247        }
1248        $obj = new SelfclosingTagTk( 'wikilink' );
1249        $tsr = new SourceRange( $spos, $tpos );
1250        $hrefKV = new KV( 'href', $target, $tsr->expandTsrV() );
1251        $hrefKV->vsrc = $tsr->substr( $this->input );
1252        // XXX: Point to object with path, revision and input information
1253        // obj.source = input;
1254        $obj->attribs[] = $hrefKV;
1255        $obj->attribs = array_merge( $obj->attribs, $lcs );
1256        $dp = new DataParsoid;
1257        $dp->tsr = $this->tsrOffsets();
1258        $dp->src = $this->text();
1259        $obj->dataParsoid = $dp;
1260        return [ $obj ];
1261    
1262}
1263private function a109(&$preproc) {
1264 $preproc =  null; return true; 
1265}
1266private function a110(&$preproc, $a) {
1267
1268        return $a;
1269    
1270}
1271private function a111($extToken) {
1272 return $extToken->getName() === 'extension'; 
1273}
1274private function a112($extToken) {
1275 return $extToken; 
1276}
1277private function a113($annOrExtTag, $start) {
1278
1279        // Only enforce ascii alpha first char for non-extension tags.