@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
at upstream/main 254 lines 6.9 kB view raw
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}