1
|
|
|
<?php |
2
|
|
|
namespace gossi\formatter\formatters; |
3
|
|
|
|
4
|
|
|
use gossi\formatter\entities\Group; |
5
|
|
|
use phootwork\tokenizer\Token; |
6
|
|
|
|
7
|
|
|
class WhitespaceFormatter extends SpecializedFormatter { |
|
|
|
|
8
|
|
|
|
9
|
|
|
private static $BLOCK_CONTEXT_MAPPING = [ |
10
|
|
|
T_IF => 'ifelse', |
11
|
|
|
T_ELSEIF => 'ifelse', |
12
|
|
|
T_WHILE => 'while', |
13
|
|
|
T_FOREACH => 'foreach', |
14
|
|
|
T_FOR => 'for', |
15
|
|
|
T_CATCH => 'catch' |
16
|
|
|
]; |
17
|
|
|
|
18
|
|
|
private static $SYNTAX = [ |
19
|
|
|
')' => 'close', |
20
|
|
|
'(' => 'open', |
21
|
|
|
',' => 'comma', |
22
|
|
|
';' => 'semicolon', |
23
|
|
|
':' => 'colon', |
24
|
|
|
'=>' => 'arrow', |
25
|
|
|
'->' => 'arrow', // function invocation |
26
|
|
|
'::' => 'doublecolon', // function invocation |
27
|
|
|
'?' => 'questionmark' |
28
|
|
|
]; |
29
|
|
|
|
30
|
2 |
|
protected function doVisitToken(Token $token) { |
31
|
2 |
|
$this->applyKeywords($token); |
32
|
2 |
|
$this->applyAssignments($token); |
33
|
2 |
|
$this->applyOperators($token); |
34
|
2 |
|
$this->applyPrefixPostfix($token); |
35
|
2 |
|
$this->applyUnary($token); |
|
|
|
|
36
|
2 |
|
$this->applySyntax($token); |
37
|
2 |
|
} |
38
|
|
|
|
39
|
2 |
|
private function applyKeywords(Token $token) { |
40
|
2 |
|
if ($this->matcher->isKeyword($token)) { |
41
|
1 |
|
$this->defaultFormatter->addPostWrite(' '); |
42
|
1 |
|
} |
43
|
2 |
|
} |
44
|
|
|
|
45
|
2 |
|
private function applyAssignments(Token $token) { |
46
|
2 |
|
if ($this->matcher->isAssignment($token)) { |
47
|
2 |
|
$this->whitespaceBeforeAfter('assignment', 'assignments'); |
48
|
2 |
|
} |
49
|
2 |
|
} |
50
|
|
|
|
51
|
2 |
|
private function applyOperators(Token $token) { |
52
|
2 |
|
if ($this->matcher->isOperator($token)) { |
53
|
2 |
|
$this->whitespaceBeforeAfter('binary', 'operators'); |
54
|
2 |
|
} |
55
|
2 |
|
} |
56
|
|
|
|
57
|
2 |
|
private function applyPrefixPostfix(Token $token) { |
58
|
2 |
|
if ($token->type == T_INC || $token->type == T_DEC) { |
59
|
|
|
// pre |
60
|
1 |
|
if ($this->nextToken->type == T_VAR) { |
61
|
|
|
$this->whitespaceBeforeAfter('prefix', 'operators'); |
62
|
|
|
} |
63
|
|
|
|
64
|
|
|
// post |
65
|
1 |
|
else if ($this->prevToken->type == T_VAR) { |
66
|
|
|
$this->whitespaceBeforeAfter('postfix', 'operators'); |
67
|
|
|
} |
68
|
1 |
|
} |
69
|
2 |
|
} |
70
|
|
|
|
71
|
|
|
/** |
72
|
|
|
* @TODO |
73
|
|
|
* @param Token $token |
74
|
|
|
*/ |
75
|
2 |
|
private function applyUnary(Token $token) { |
|
|
|
|
76
|
|
|
|
77
|
2 |
|
} |
78
|
|
|
|
79
|
2 |
|
private function applySyntax(Token $token) { |
80
|
2 |
|
if (array_key_exists($token->contents, self::$SYNTAX)) { |
81
|
2 |
|
$key = self::$SYNTAX[$token->contents]; |
82
|
2 |
|
$group = $this->context->getGroupContext(); |
83
|
|
|
|
84
|
|
|
// return when semicolon is not inside a block context |
85
|
2 |
|
if ($token->contents == ';' && $group->type != Group::BLOCK) { |
86
|
2 |
|
return; |
87
|
|
|
} |
88
|
|
|
|
89
|
|
|
// anyway find context and apply it |
90
|
2 |
|
$context = $this->findContext($token); |
91
|
2 |
|
$this->whitespaceBeforeAfter($key, $context); |
92
|
2 |
|
} |
93
|
2 |
|
} |
94
|
|
|
|
95
|
2 |
|
private function findContext(Token $token) { |
|
|
|
|
96
|
2 |
|
$group = $this->context->getGroupContext(); |
97
|
2 |
|
$context = 'default'; |
98
|
|
|
|
99
|
|
|
// first check the context of the current line |
100
|
2 |
|
$line = $this->context->getLineContext(); |
101
|
2 |
|
if (!empty($line)) { |
102
|
|
|
$context = $line; |
103
|
|
|
} |
104
|
|
|
|
105
|
|
|
// is it a parens group? |
106
|
2 |
|
else if ($group->type == Group::GROUP) { |
107
|
1 |
|
$context = 'grouping'; |
108
|
1 |
|
} |
109
|
|
|
|
110
|
|
|
// a function call? |
111
|
2 |
|
else if ($group->type == Group::CALL) { |
112
|
2 |
|
$context = 'function_invocation'; |
113
|
2 |
|
} |
114
|
|
|
|
115
|
|
|
// field access? |
116
|
2 |
|
else if ($token->contents === '->' || $token->contents === '::') { |
117
|
1 |
|
$context = 'field_access'; |
118
|
1 |
|
} |
119
|
|
|
|
120
|
|
|
// or a given block statement? |
121
|
2 |
|
else if ($group->type == Group::BLOCK |
122
|
2 |
|
&& isset(self::$BLOCK_CONTEXT_MAPPING[$group->token->type])) { |
123
|
2 |
|
$context = self::$BLOCK_CONTEXT_MAPPING[$group->token->type]; |
124
|
2 |
|
} |
125
|
|
|
|
126
|
2 |
|
return $context; |
127
|
|
|
} |
128
|
|
|
|
129
|
2 |
|
private function whitespaceBeforeAfter($key, $context = 'default') { |
130
|
2 |
|
if ($this->config->getWhitespace('before_' . $key, $context)) { |
131
|
2 |
|
$this->defaultFormatter->addPreWrite(' '); |
132
|
2 |
|
} |
133
|
|
|
|
134
|
2 |
|
if ($this->config->getWhitespace('after_' . $key, $context)) { |
135
|
2 |
|
$this->defaultFormatter->addPostWrite(' '); |
136
|
2 |
|
} |
137
|
2 |
|
} |
138
|
|
|
|
139
|
|
|
} |
140
|
|
|
|
This check marks property names that have not been written in camelCase.
In camelCase names are written without any punctuation, the start of each new word being marked by a capital letter. Thus the name database connection string becomes
databaseConnectionString
.