@recaptime-dev's working patches + fork for Phorge, a community fork of Phabricator. (Upstream dev and stable branches are at upstream/main and upstream/stable respectively.)
hq.recaptime.dev/wiki/Phorge
phorge
phabricator
1<?php
2
3/**
4 * Generates valid context-free code for most programming languages that could
5 * pass as C. Except for PHP. But includes Java (mostly).
6 */
7abstract class PhutilCLikeCodeSnippetContextFreeGrammar
8 extends PhutilCodeSnippetContextFreeGrammar {
9
10 protected function buildRuleSet() {
11 return array(
12 $this->getStmtTerminationGrammarSet(),
13 $this->getVarNameGrammarSet(),
14 $this->getNullExprGrammarSet(),
15 $this->getNumberGrammarSet(),
16 $this->getExprGrammarSet(),
17 $this->getCondGrammarSet(),
18 $this->getLoopGrammarSet(),
19 $this->getStmtGrammarSet(),
20 $this->getAssignmentGrammarSet(),
21 $this->getArithExprGrammarSet(),
22 $this->getBoolExprGrammarSet(),
23 $this->getBoolValGrammarSet(),
24 $this->getTernaryExprGrammarSet(),
25
26 $this->getFuncNameGrammarSet(),
27 $this->getFuncCallGrammarSet(),
28 $this->getFuncCallParamGrammarSet(),
29 $this->getFuncDeclGrammarSet(),
30 $this->getFuncParamGrammarSet(),
31 $this->getFuncBodyGrammarSet(),
32 $this->getFuncReturnGrammarSet(),
33 );
34 }
35
36 protected function getStartGrammarSet() {
37 $start_grammar = parent::getStartGrammarSet();
38
39 $start_grammar['start'][] = '[funcdecl]';
40
41 return $start_grammar;
42 }
43
44 protected function getStmtTerminationGrammarSet() {
45 return $this->buildGrammarSet('term', array(';'));
46 }
47
48 protected function getFuncCallGrammarSet() {
49 return $this->buildGrammarSet('funccall',
50 array(
51 '[funcname]([funccallparam])',
52 ));
53 }
54
55 protected function getFuncCallParamGrammarSet() {
56 return $this->buildGrammarSet('funccallparam',
57 array(
58 '',
59 '[expr]',
60 '[expr], [expr]',
61 ));
62 }
63
64 protected function getFuncDeclGrammarSet() {
65 return $this->buildGrammarSet('funcdecl',
66 array(
67 'function [funcname]([funcparam]) '.
68 '{[funcbody, indent, block, trim=right]}',
69 ));
70 }
71
72 protected function getFuncParamGrammarSet() {
73 return $this->buildGrammarSet('funcparam',
74 array(
75 '',
76 '[varname]',
77 '[varname], [varname]',
78 '[varname], [varname], [varname]',
79 ));
80 }
81
82 protected function getFuncBodyGrammarSet() {
83 return $this->buildGrammarSet('funcbody',
84 array(
85 "[stmt]\n[stmt]\n[funcreturn]",
86 "[stmt]\n[stmt]\n[stmt]\n[funcreturn]",
87 "[stmt]\n[stmt]\n[stmt]\n[stmt]\n[funcreturn]",
88 ));
89 }
90
91 protected function getFuncReturnGrammarSet() {
92 return $this->buildGrammarSet('funcreturn',
93 array(
94 'return [expr][term]',
95 '',
96 ));
97 }
98
99 // Not really C, but put it here because of the curly braces and mostly shared
100 // among Java and PHP
101 protected function getClassDeclGrammarSet() {
102 return $this->buildGrammarSet('classdecl',
103 array(
104 '[classinheritancemod] class [classname] {[classbody, indent, block]}',
105 'class [classname] {[classbody, indent, block]}',
106 ));
107 }
108
109 protected function getClassNameGrammarSet() {
110 return $this->buildGrammarSet('classname',
111 array(
112 'MuffinHouse',
113 'MuffinReader',
114 'MuffinAwesomizer',
115 'SuperException',
116 'Librarian',
117 'Book',
118 'Ball',
119 'BallOfCode',
120 'AliceAndBobsSharedSecret',
121 'FileInputStream',
122 'FileOutputStream',
123 'BufferedReader',
124 'BufferedWriter',
125 'Cardigan',
126 'HouseOfCards',
127 'UmbrellaClass',
128 'GenericThing',
129 ));
130 }
131
132 protected function getClassBodyGrammarSet() {
133 return $this->buildGrammarSet('classbody',
134 array(
135 '[methoddecl]',
136 "[methoddecl]\n\n[methoddecl]",
137 "[propdecl]\n[propdecl]\n\n[methoddecl]\n\n[methoddecl]",
138 "[propdecl]\n[propdecl]\n[propdecl]\n\n[methoddecl]\n\n[methoddecl]".
139 "\n\n[methoddecl]",
140 ));
141 }
142
143 protected function getVisibilityGrammarSet() {
144 return $this->buildGrammarSet('visibility',
145 array(
146 'private',
147 'protected',
148 'public',
149 ));
150 }
151
152 protected function getClassInheritanceModGrammarSet() {
153 return $this->buildGrammarSet('classinheritancemod',
154 array(
155 'final',
156 'abstract',
157 ));
158 }
159
160 // Keeping this separate so we won't give abstract methods a function body
161 protected function getMethodInheritanceModGrammarSet() {
162 return $this->buildGrammarSet('methodinheritancemod',
163 array(
164 'final',
165 ));
166 }
167
168 protected function getMethodDeclGrammarSet() {
169 return $this->buildGrammarSet('methoddecl',
170 array(
171 '[visibility] [methodfuncdecl]',
172 '[visibility] [methodfuncdecl]',
173 '[methodinheritancemod] [visibility] [methodfuncdecl]',
174 '[abstractmethoddecl]',
175 ));
176 }
177
178 protected function getMethodFuncDeclGrammarSet() {
179 return $this->buildGrammarSet('methodfuncdecl',
180 array(
181 'function [funcname]([funcparam]) '.
182 '{[methodbody, indent, block, trim=right]}',
183 ));
184 }
185
186 protected function getMethodBodyGrammarSet() {
187 return $this->buildGrammarSet('methodbody',
188 array(
189 "[methodstmt]\n[methodbody]",
190 "[methodstmt]\n[funcreturn]",
191 ));
192 }
193
194 protected function getMethodStmtGrammarSet() {
195 $stmts = $this->getStmtGrammarSet();
196
197 return $this->buildGrammarSet('methodstmt',
198 array_merge(
199 $stmts['stmt'],
200 array(
201 '[methodcall][term]',
202 )));
203 }
204
205 protected function getMethodCallGrammarSet() {
206 // Java/JavaScript
207 return $this->buildGrammarSet('methodcall',
208 array(
209 'this.[funccall]',
210 '[varname].[funccall]',
211 '[classname].[funccall]',
212 ));
213 }
214
215 protected function getAbstractMethodDeclGrammarSet() {
216 return $this->buildGrammarSet('abstractmethoddecl',
217 array(
218 'abstract function [funcname]([funcparam])[term]',
219 ));
220 }
221
222 protected function getPropDeclGrammarSet() {
223 return $this->buildGrammarSet('propdecl',
224 array(
225 '[visibility] [varname][term]',
226 ));
227 }
228
229 protected function getClassRuleSets() {
230 return array(
231 $this->getClassInheritanceModGrammarSet(),
232 $this->getMethodInheritanceModGrammarSet(),
233 $this->getClassDeclGrammarSet(),
234 $this->getClassNameGrammarSet(),
235 $this->getClassBodyGrammarSet(),
236 $this->getMethodDeclGrammarSet(),
237 $this->getMethodFuncDeclGrammarSet(),
238 $this->getMethodBodyGrammarSet(),
239 $this->getMethodStmtGrammarSet(),
240 $this->getMethodCallGrammarSet(),
241 $this->getAbstractMethodDeclGrammarSet(),
242 $this->getPropDeclGrammarSet(),
243 $this->getVisibilityGrammarSet(),
244 );
245 }
246
247 public function generateClass() {
248 $rules = array_merge($this->getRules(), $this->getClassRuleSets());
249 $rules['start'] = array('[classdecl]');
250 $count = 0;
251 return $this->applyRules('[start]', $count, $rules);
252 }
253
254}