├── README.md ├── example ├── app.js ├── codemirror │ ├── css │ │ ├── csscolors.css │ │ ├── docs.css │ │ ├── jscolors.css │ │ ├── people.jpg │ │ ├── sparqlcolors.css │ │ └── xmlcolors.css │ └── js │ │ ├── codemirror.js │ │ ├── editor.js │ │ ├── highlight.js │ │ ├── mirrorframe.js │ │ ├── parsecss.js │ │ ├── parsedummy.js │ │ ├── parsehtmlmixed.js │ │ ├── parsejavascript.js │ │ ├── parsesparql.js │ │ ├── parsexml.js │ │ ├── select.js │ │ ├── stringstream.js │ │ ├── tokenize.js │ │ ├── tokenizejavascript.js │ │ ├── undo.js │ │ └── util.js ├── example.html └── parser.browser.js ├── javascript.pegjs ├── js2cs.js ├── out ├── js2cs.coffee ├── js2cs.recompiled.js └── test.coffee ├── parser.js └── test ├── jquery-1.4.2.js └── test.js /README.md: -------------------------------------------------------------------------------- 1 | Usage 2 | ---------- 3 | 4 | [CoffeeScript](http://www.coffeescript.com) 5 | 6 | 7 | node js2cs.js file_to_convert 8 | 9 | 10 | Options: --debug, --ilevel, --convert 11 | 12 | --debug: Print the AST tree to STDIO. 13 | 14 | --ilevel: Show node types, names and indent levels. 15 | 16 | --convert: Output converted program to stdout. 17 | 18 | Browser demo is in /example 19 | 20 | Known Limitations 21 | -------------------- 22 | 23 | * Limited by PEG.js's ability to read your syntax. You may (will) have to refactor it to use this tool. 24 | 25 | * No support for LabelledStatement. Only used with BreakStatement (break) which is not used in Coffee. 26 | 27 | * Untested. Not symbol-for-symbol, token-for-token. 28 | 29 | * For Statements are turned into While statements in Coffee because Coffee's For is one-way to JavaScript (can't be translated back to that.) 30 | 31 | * Comma operator (,) compiles to \n. Not supported in CoffeeScript. 32 | 33 | * Postfix expression like ++i is not handled yet. 34 | 35 | * Else if is NOT supported by the PEGjs grammar. You can use if { stuff; } else { if() { stuff; } }. 36 | 37 | * No one line if statements. 38 | 39 | -- 40 | Jonathan Silverman ("jsilver") 41 | -------------------------------------------------------------------------------- /example/app.js: -------------------------------------------------------------------------------- 1 | String.prototype.trim = function () { 2 | return this.replace(/^\s*/, "").replace(/\s*$/, ""); 3 | } 4 | 5 | var parseJs = function(js) { 6 | return parser.parse(js); 7 | } 8 | var output = ''; 9 | var error = ''; 10 | var iteration = 0; 11 | var indent_level = 0; 12 | var increaseIndent = function() { 13 | indent_level = indent_level + 1; 14 | } 15 | var decreaseIndent = function() { 16 | indent_level = indent_level - 1; 17 | } 18 | var indent = function() 19 | { 20 | for(var c = 0; c < indent_level; c++) 21 | { 22 | addToOut(" "); 23 | } 24 | } 25 | var addToOut = function(out) { 26 | output += out; 27 | } 28 | var removeBlankLines = function(out) { 29 | var return_me = out.replace(/\n\n/g, "\n"); 30 | while (return_me.indexOf("\n\n") > 0) 31 | { 32 | return_me = return_me.replace(/\n\n/g, "\n"); 33 | } 34 | return return_me; 35 | } 36 | 37 | /* calls parseNode on a collection of child nodes (statements, elements, properties, clauses) */ 38 | var parseChildNodes = function(nodes) { 39 | for(var i = 0; i < nodes.length; i++) { 40 | /* some logic */ 41 | _node = nodes[i]; 42 | is_last_statement = (i < nodes.length -1); 43 | is_just_var = (is_last_statement && (_node.type == "Variable")); /* variables are not declared this way in coffee */ 44 | is_break = (_node.type == "BreakStatement"); /* not used in coffee */ 45 | /* also don't parse labelledStatement. it's not used and we can't have empty cases if we wanna self host */ 46 | is_labelled_statement = (_node.type == "LabelledStatement"); 47 | /* indenter */ 48 | 49 | if(!(is_break) && !(is_labelled_statement)) { 50 | indent(); 51 | } 52 | 53 | /* token parser */ 54 | if(!(is_just_var) && !(is_break) && !(is_labelled_statement)) 55 | { 56 | parseNode(_node); 57 | } 58 | /* line breaker */ 59 | /*if((is_last_statement) && !(is_break) && !(is_just_var)) 60 | { 61 | addToOut("\n"); 62 | } 63 | */ 64 | addToOut("\n"); 65 | } 66 | } 67 | 68 | /* eats tokens and makes coffee */ 69 | var parseNode = function(node) { 70 | switch(node.type) 71 | { 72 | case("Program"): 73 | if(node.elements) 74 | { 75 | parseChildNodes(node.elements); 76 | } 77 | break; 78 | case("This"): 79 | addToOut("@"); 80 | break; 81 | case("Function"): 82 | if(node.params.length > 0) 83 | { 84 | addToOut("("); 85 | for(var i = 0; i < node.params.length; i++) 86 | { 87 | /* this tokenizer is probably broken. node.params node should be parsed. */ 88 | 89 | addToOut(node.params[i]); 90 | 91 | /*arseNode(node.params[i]);*/ 92 | if(i < node.params.length - 1) 93 | { 94 | addToOut(", "); 95 | } 96 | } 97 | addToOut(")"); 98 | } 99 | addToOut("->\n"); 100 | increaseIndent(); 101 | if(node.elements) 102 | { 103 | parseChildNodes(node.elements); 104 | } 105 | decreaseIndent(); 106 | break; 107 | case("Block"): 108 | increaseIndent(); 109 | if(node.statements) 110 | { 111 | parseChildNodes(node.statements); 112 | } 113 | decreaseIndent(); 114 | break; 115 | case("SwitchStatement"): 116 | addToOut("switch "); 117 | parseNode(node.expression); 118 | addToOut("\n"); 119 | increaseIndent(); 120 | parseChildNodes(node.clauses); 121 | decreaseIndent(); 122 | break; 123 | case("CaseClause"): 124 | addToOut("when "); 125 | parseNode(node.selector); 126 | /* 2 is the minimum because break; is a statement too 127 | if((node.statements.length > 2) || (node.statements.length == 1)) 128 | { 129 | */ 130 | addToOut("\n"); 131 | increaseIndent(); 132 | if(node.statements) 133 | { 134 | parseChildNodes(node.statements); 135 | } 136 | decreaseIndent(); 137 | /* 138 | } 139 | else 140 | { 141 | if(node.statements.length == 2) 142 | { 143 | addToOut(" then "); 144 | if(node.statements) 145 | { 146 | parseNode(node.statements[0]); 147 | } 148 | } 149 | } 150 | */ 151 | break; 152 | case("DefaultClause"): 153 | addToOut("else "); 154 | if(node.statements.length > 1) 155 | { 156 | addToOut("\n"); 157 | increaseIndent(); 158 | if(node.statements) 159 | { 160 | parseChildNodes(node.statements); 161 | } 162 | decreaseIndent(); 163 | } 164 | else 165 | { 166 | if(node.statements.length == 1) 167 | { 168 | if(node.statements) 169 | { 170 | parseNode(node.statements[0]); 171 | } 172 | } 173 | } 174 | break; 175 | case("IfStatement"): 176 | /* condition */ 177 | if(node.condition.operator != "!") 178 | { 179 | addToOut("if "); 180 | parseNode(node.condition); 181 | } 182 | else 183 | { 184 | addToOut("unless "); 185 | /* skip next node, it's "not" */ 186 | parseNode(node.condition.expression); 187 | } 188 | addToOut("\n"); 189 | /* statements */ 190 | increaseIndent(); 191 | if(node.ifStatement.statements) 192 | { 193 | parseChildNodes(node.ifStatement.statements); 194 | } 195 | decreaseIndent(); 196 | if(node.elseStatement != null) { 197 | addToOut("\n"); 198 | indent(); 199 | addToOut("else"); /* limitation: javascript.pegjs doesnt know else 200 | if */ 201 | addToOut("\n"); 202 | increaseIndent(); 203 | if(node.elseStatement.statements) 204 | { 205 | parseChildNodes(node.elseStatement.statements); 206 | } 207 | decreaseIndent(); 208 | } 209 | break; 210 | case("ForStatement"): 211 | /* converts to while because this mode is unsupported */ 212 | parseNode(node.initializer); 213 | addToOut("\n"); 214 | indent(); 215 | addToOut("while "); 216 | parseNode(node.test); 217 | addToOut("\n"); 218 | increaseIndent(); 219 | indent(); 220 | parseNode(node.counter); /* if possible do a test on the counter to see if it's ++i or i++ (they are different) */ 221 | decreaseIndent(); 222 | if(node.statement) 223 | { 224 | parseNode(node.statement); 225 | } 226 | break; 227 | case("WhileStatement"): 228 | addToOut("while "); 229 | parseNode(node.condition); 230 | addToOut("\n"); 231 | if(node.statement) 232 | { 233 | parseNode(node.statement); 234 | } 235 | break; 236 | case("TryStatement"): 237 | /* epic self translating challenge here */ 238 | addToOut("try\n"); 239 | parseNode(node.block); 240 | addToOut("\n"); 241 | if(node['catch']) { 242 | addToOut("catch "); 243 | parseNode(node['catch']); 244 | } 245 | if(node['finally']) { 246 | addToOut("finally\n"); 247 | parseNode(node['finally']); 248 | } 249 | break; 250 | case("Catch"): 251 | if(node.identifier) 252 | { 253 | addToOut(node.identifier); 254 | } 255 | addToOut("\n"); 256 | parseNode(node.block); 257 | addToOut("\n"); 258 | break; 259 | case("Finally"): 260 | parseNode(node.block); 261 | break; 262 | case("AssignmentExpression"): 263 | parseNode(node.left); 264 | addToOut(": "); 265 | parseNode(node.right); 266 | break; 267 | case("PropertyAssignment"): 268 | /*addToOut(node.name);*/ 269 | parseNode(node.name); 270 | addToOut(": "); 271 | parseNode(node.value); 272 | break; 273 | case("PropertyAccess"): 274 | parseNode(node.base); 275 | if(node.name.type) 276 | { 277 | /* 278 | var node_dot_name_is_numeric_literal = (node.name.type == "NumericLiteral"); 279 | var node_dot_name_is_string_literal = (node.name.type == "StringLiteral"); 280 | if(node.base.type != "This" && !(node_dot_name_is_numeric_literal) && !(node_dot_name_is_string_literal)) { addToOut("."); } 281 | 282 | if(node_dot_name_is_numeric_literal || node_dot_name_is_string_literal) { addToOut("["); } 283 | 284 | if(node.base.type == "Variable") 285 | { 286 | addToOut("."); 287 | parseNode(node.name); 288 | } 289 | else 290 | { */ 291 | if(node.base.type != "This") { 292 | if(node.name.type != "FunctionCall") 293 | { 294 | addToOut("["); 295 | parseNode(node.name); 296 | addToOut("]"); 297 | } 298 | else 299 | { 300 | addToOut("."); 301 | parseNode(node.name); 302 | } 303 | } 304 | else 305 | { 306 | parseNode(node.name); 307 | } 308 | /* 309 | else 310 | { 311 | parseNode(node.name); 312 | } 313 | } 314 | 315 | if(node_dot_name_is_numeric_literal || node_dot_name_is_string_literal) { addToOut("]"); } 316 | */ 317 | } 318 | else 319 | { 320 | if(node.name.type == undefined || node.name.type == "null") 321 | { 322 | if(node.base.type != "This") { addToOut("."); } 323 | addToOut(node.name.trim()); 324 | /*if(node.base.type != "This") { addToOut("']"); }*/ 325 | } 326 | } 327 | 328 | break; 329 | case("BinaryExpression"): 330 | parseNode(node.left); 331 | addToOut(" "); 332 | switch(node.operator) 333 | { 334 | /* switch to "not" and "isnt" or something here */ 335 | case("!"): 336 | addToOut("not "); 337 | break; 338 | case("==="): 339 | addToOut("is "); 340 | break; 341 | case("=="): 342 | addToOut("is "); 343 | break; 344 | case("!=="): 345 | addToOut("isnt "); 346 | break; 347 | case("&&"): 348 | addToOut("and "); 349 | break; 350 | case("||"): 351 | addToOut("or "); 352 | break; 353 | case(","): 354 | addToOut("\n"); /* no support for that operator yet. try to evaluate on seperate lines. */ 355 | break; 356 | default: 357 | addToOut(node.operator); 358 | addToOut(" "); 359 | } 360 | parseNode(node.right); 361 | break; 362 | case("UnaryExpression"): 363 | switch(node.operator) 364 | { 365 | case('!'): 366 | addToOut("not "); 367 | break; 368 | default: 369 | addToOut(node.operator); 370 | } 371 | parseNode(node.expression); 372 | break; 373 | case("ConditionalExpression"): 374 | addToOut("if "); 375 | parseNode(node.condition); 376 | addToOut(" "); 377 | parseNode(node.trueExpression); 378 | addToOut(" else "); 379 | parseNode(node.falseExpression); 380 | break; 381 | case("PostfixExpression"): 382 | switch(node.operator) 383 | { 384 | case('++'): 385 | parseNode(node.expression); 386 | addToOut(" = "); 387 | parseNode(node.expression); 388 | addToOut(" + 1"); 389 | break; 390 | case('--'): 391 | parseNode(node.expression); 392 | addToOut(" = "); 393 | parseNode(node.expression); 394 | addToOut(" - 1"); 395 | break; 396 | } 397 | addToOut("\n"); 398 | break; 399 | case("Variable"): 400 | if(!(node.name.substr(0, 3) == "var")) 401 | { 402 | addToOut(node.name.trim()); 403 | } 404 | else 405 | { 406 | if(node.name.substr(0, 3) == "var") 407 | { 408 | /* -5 because of 4 for "var " and 1 for " " after */ 409 | addToOut(node.name.substr(4, node.name.length - 4).trim()); 410 | } 411 | } 412 | break; 413 | case("FunctionCall"): 414 | parseNode(node.name); 415 | addToOut("("); 416 | if(node.arguments.length > 0) 417 | { 418 | 419 | for(var i = 0; i < node.arguments.length; i++) 420 | { 421 | parseNode(node.arguments[i]); 422 | if(i < node.arguments.length - 1) 423 | { 424 | addToOut(", "); 425 | } 426 | } 427 | } 428 | addToOut(")"); 429 | break; 430 | case('StringLiteral'): 431 | /* be sure to escape any control characters you need here with \ */ 432 | var escapedValue = node.value.replace(/\n/g, "\\n"); 433 | addToOut('"' + escapedValue + '"'); 434 | break; 435 | case('NumericLiteral'): 436 | addToOut(node.value); 437 | break; 438 | case('RegularExpressionLiteral'): 439 | addToOut("/"); 440 | addToOut(node.body); 441 | addToOut("/" + node.flags); 442 | break; 443 | case('NullLiteral'): 444 | addToOut("null"); 445 | break; 446 | case('ArrayLiteral'): 447 | if(node.elements.length > 0) 448 | { 449 | addToOut("["); 450 | for(var i = 0; i < node.elements.length; i++) 451 | { 452 | parseNode(node.elements[i]); 453 | if(i < node.elements.length - 1) 454 | { 455 | addToOut(", "); 456 | } 457 | } 458 | addToOut("]"); 459 | } 460 | break; 461 | case('ObjectLiteral'): 462 | if(node.properties.length > 0) 463 | { 464 | addToOut("{\n"); 465 | increaseIndent(); 466 | if(node.properties) 467 | { 468 | parseChildNodes(node.properties); 469 | } 470 | decreaseIndent(); 471 | addToOut("\n}"); 472 | } 473 | break; 474 | case('BooleanLiteral'): 475 | if(node.value == true) 476 | { 477 | addToOut("yes"); 478 | } 479 | else 480 | { 481 | if(node.value == false) 482 | { 483 | addToOut("no"); 484 | } 485 | } 486 | break; 487 | } 488 | } 489 | 490 | /* 491 | parseJs(js); 492 | now i have ast 493 | parseNode(ast); 494 | */ 495 | /* now i have output */ 496 | 497 | 498 | 499 | -------------------------------------------------------------------------------- /example/codemirror/css/csscolors.css: -------------------------------------------------------------------------------- 1 | html { 2 | cursor: text; 3 | } 4 | 5 | .editbox { 6 | margin: .4em; 7 | padding: 0; 8 | font-family: monospace; 9 | font-size: 10pt; 10 | color: black; 11 | } 12 | 13 | pre.code, .editbox { 14 | color: #666; 15 | } 16 | 17 | .editbox p { 18 | margin: 0; 19 | } 20 | 21 | span.css-at { 22 | color: #708; 23 | } 24 | 25 | span.css-unit { 26 | color: #281; 27 | } 28 | 29 | span.css-value { 30 | color: #708; 31 | } 32 | 33 | span.css-identifier { 34 | color: black; 35 | } 36 | 37 | span.css-selector { 38 | color: #11B; 39 | } 40 | 41 | span.css-important { 42 | color: #00F; 43 | } 44 | 45 | span.css-colorcode { 46 | color: #299; 47 | } 48 | 49 | span.css-comment { 50 | color: #A70; 51 | } 52 | 53 | span.css-string { 54 | color: #A22; 55 | } 56 | -------------------------------------------------------------------------------- /example/codemirror/css/docs.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | padding: 3em 6em; 4 | color: black; 5 | max-width: 50em; 6 | } 7 | 8 | h1 { 9 | font-size: 22pt; 10 | } 11 | 12 | .underline { 13 | border-bottom: 3px solid #C44; 14 | } 15 | 16 | h2 { 17 | font-size: 14pt; 18 | } 19 | 20 | h3 { 21 | font-size: 12pt; 22 | } 23 | 24 | p.rel { 25 | padding-left: 2em; 26 | text-indent: -2em; 27 | } 28 | 29 | div.border { 30 | border: 1px solid black; 31 | } 32 | 33 | code { 34 | font-family: courier, monospace; 35 | font-size: 90%; 36 | color: #144; 37 | } 38 | 39 | pre.code { 40 | margin: 1.1em 12px; 41 | border: 1px solid #CCCCCC; 42 | color: black; 43 | padding: .4em; 44 | font-family: courier, monospace; 45 | } 46 | 47 | .warn { 48 | color: #C00; 49 | } 50 | -------------------------------------------------------------------------------- /example/codemirror/css/jscolors.css: -------------------------------------------------------------------------------- 1 | html { 2 | cursor: text; 3 | } 4 | 5 | .editbox { 6 | margin: .4em; 7 | padding: 0; 8 | font-family: monospace; 9 | font-size: 10pt; 10 | color: black; 11 | } 12 | 13 | pre.code, .editbox { 14 | color: #666666; 15 | } 16 | 17 | .editbox p { 18 | margin: 0; 19 | } 20 | 21 | span.js-punctuation { 22 | color: #666666; 23 | } 24 | 25 | span.js-operator { 26 | color: #666666; 27 | } 28 | 29 | span.js-keyword { 30 | color: #770088; 31 | } 32 | 33 | span.js-atom { 34 | color: #228811; 35 | } 36 | 37 | span.js-variable { 38 | color: black; 39 | } 40 | 41 | span.js-variabledef { 42 | color: #0000FF; 43 | } 44 | 45 | span.js-localvariable { 46 | color: #004499; 47 | } 48 | 49 | span.js-property { 50 | color: black; 51 | } 52 | 53 | span.js-comment { 54 | color: #AA7700; 55 | } 56 | 57 | span.js-string { 58 | color: #AA2222; 59 | } 60 | -------------------------------------------------------------------------------- /example/codemirror/css/people.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mixflame/js2cs/211fc0c4b32402f1b06e01cfcfea5a159fa8380c/example/codemirror/css/people.jpg -------------------------------------------------------------------------------- /example/codemirror/css/sparqlcolors.css: -------------------------------------------------------------------------------- 1 | html { 2 | cursor: text; 3 | } 4 | 5 | .editbox { 6 | margin: .4em; 7 | padding: 0; 8 | font-family: monospace; 9 | font-size: 10pt; 10 | color: black; 11 | } 12 | 13 | .editbox p { 14 | margin: 0; 15 | } 16 | 17 | span.sp-keyword { 18 | color: #708; 19 | } 20 | 21 | span.sp-prefixed { 22 | color: #5d1; 23 | } 24 | 25 | span.sp-var { 26 | color: #00c; 27 | } 28 | 29 | span.sp-comment { 30 | color: #a70; 31 | } 32 | 33 | span.sp-literal { 34 | color: #a22; 35 | } 36 | 37 | span.sp-uri { 38 | color: #292; 39 | } 40 | 41 | span.sp-operator { 42 | color: #088; 43 | } 44 | -------------------------------------------------------------------------------- /example/codemirror/css/xmlcolors.css: -------------------------------------------------------------------------------- 1 | html { 2 | cursor: text; 3 | } 4 | 5 | .editbox { 6 | margin: .4em; 7 | padding: 0; 8 | font-family: monospace; 9 | font-size: 10pt; 10 | color: black; 11 | } 12 | 13 | .editbox p { 14 | margin: 0; 15 | } 16 | 17 | span.xml-tagname { 18 | color: #A0B; 19 | } 20 | 21 | span.xml-attribute { 22 | color: #281; 23 | } 24 | 25 | span.xml-punctuation { 26 | color: black; 27 | } 28 | 29 | span.xml-attname { 30 | color: #00F; 31 | } 32 | 33 | span.xml-comment { 34 | color: #A70; 35 | } 36 | 37 | span.xml-cdata { 38 | color: #48A; 39 | } 40 | 41 | span.xml-processing { 42 | color: #999; 43 | } 44 | 45 | span.xml-entity { 46 | color: #A22; 47 | } 48 | 49 | span.xml-error { 50 | color: #F00 !important; 51 | } 52 | 53 | span.xml-text { 54 | color: black; 55 | } 56 | -------------------------------------------------------------------------------- /example/codemirror/js/codemirror.js: -------------------------------------------------------------------------------- 1 | /* CodeMirror main module 2 | * 3 | * Implements the CodeMirror constructor and prototype, which take care 4 | * of initializing the editor frame, and providing the outside interface. 5 | */ 6 | 7 | // The CodeMirrorConfig object is used to specify a default 8 | // configuration. If you specify such an object before loading this 9 | // file, the values you put into it will override the defaults given 10 | // below. You can also assign to it after loading. 11 | var CodeMirrorConfig = window.CodeMirrorConfig || {}; 12 | 13 | var CodeMirror = (function(){ 14 | function setDefaults(object, defaults) { 15 | for (var option in defaults) { 16 | if (!object.hasOwnProperty(option)) 17 | object[option] = defaults[option]; 18 | } 19 | } 20 | function forEach(array, action) { 21 | for (var i = 0; i < array.length; i++) 22 | action(array[i]); 23 | } 24 | 25 | // These default options can be overridden by passing a set of 26 | // options to a specific CodeMirror constructor. See manual.html for 27 | // their meaning. 28 | setDefaults(CodeMirrorConfig, { 29 | stylesheet: [], 30 | path: "", 31 | parserfile: [], 32 | basefiles: ["util.js", "stringstream.js", "select.js", "undo.js", "editor.js", "tokenize.js"], 33 | iframeClass: null, 34 | passDelay: 200, 35 | passTime: 50, 36 | lineNumberDelay: 200, 37 | lineNumberTime: 50, 38 | continuousScanning: false, 39 | saveFunction: null, 40 | onChange: null, 41 | undoDepth: 50, 42 | undoDelay: 800, 43 | disableSpellcheck: true, 44 | textWrapping: true, 45 | readOnly: false, 46 | width: "", 47 | height: "300px", 48 | minHeight: 100, 49 | autoMatchParens: false, 50 | parserConfig: null, 51 | tabMode: "indent", // or "spaces", "default", "shift" 52 | reindentOnLoad: false, 53 | activeTokens: null, 54 | cursorActivity: null, 55 | lineNumbers: false, 56 | indentUnit: 2, 57 | domain: null 58 | }); 59 | 60 | function addLineNumberDiv(container) { 61 | var nums = document.createElement("DIV"), 62 | scroller = document.createElement("DIV"); 63 | nums.style.position = "absolute"; 64 | nums.style.height = "100%"; 65 | if (nums.style.setExpression) { 66 | try {nums.style.setExpression("height", "this.previousSibling.offsetHeight + 'px'");} 67 | catch(e) {} // Seems to throw 'Not Implemented' on some IE8 versions 68 | } 69 | nums.style.top = "0px"; 70 | nums.style.left = "0px"; 71 | nums.style.overflow = "hidden"; 72 | container.appendChild(nums); 73 | scroller.className = "CodeMirror-line-numbers"; 74 | nums.appendChild(scroller); 75 | scroller.innerHTML = "
1
"; 76 | return nums; 77 | } 78 | 79 | function frameHTML(options) { 80 | if (typeof options.parserfile == "string") 81 | options.parserfile = [options.parserfile]; 82 | if (typeof options.stylesheet == "string") 83 | options.stylesheet = [options.stylesheet]; 84 | 85 | var html = [""]; 86 | // Hack to work around a bunch of IE8-specific problems. 87 | html.push(""); 88 | forEach(options.stylesheet, function(file) { 89 | html.push(""); 90 | }); 91 | forEach(options.basefiles.concat(options.parserfile), function(file) { 92 | if (!/^https?:/.test(file)) file = options.path + file; 93 | html.push(" 10 | 11 | 12 | 13 | 42 | 43 | 44 | 45 |
46 |

JavaScript to CoffeeScript Compiler

47 |

Syntax error:

48 | 49 |

Input JavaScript

50 | 615 |
616 |

Resultant CoffeeScript

617 | 618 | 619 |

this is a product of mindynamics and jsilver. made with love

620 |
621 | 622 | 623 | -------------------------------------------------------------------------------- /js2cs.js: -------------------------------------------------------------------------------- 1 | /*#!/usr/bin/env node*/ 2 | var pegjs = require('./parser'); 3 | var parser = pegjs.parser; 4 | var sys = require('sys'); 5 | var fs = require('fs'); 6 | 7 | /* object inspect method */ 8 | var p = function(obj) 9 | { 10 | var obj_inspect = sys.inspect(obj, true, 100); 11 | sys.puts(obj_inspect); 12 | } 13 | 14 | /* the missing trim method */ 15 | String.prototype.trim = function() 16 | { 17 | var str_to_return = this.replace(/^\s*/, ""); 18 | str_to_return = str_to_return.replace(/\s*$/, ""); 19 | return str_to_return; 20 | } 21 | 22 | /* argument section */ 23 | var _runmode; 24 | var _filename = process.argv[process.argv.length - 1]; 25 | if(process.argv[process.argv.length - 2].substr(0,2) == "--") 26 | { 27 | _runmode = process.argv[process.argv.length - 2]; 28 | } 29 | else 30 | { 31 | _runmode = "--convert"; 32 | } 33 | 34 | /* read input (sync) */ 35 | try 36 | { 37 | var string_raw_js = fs.readFileSync(_filename, "utf8"); 38 | } catch(e) { 39 | sys.log("Failed to read input file.. Did you specify one?"); 40 | process.exit(1); 41 | } 42 | 43 | 44 | /* parse section */ 45 | try{ 46 | var ast = parser.parse(string_raw_js); 47 | } catch(e) { 48 | sys.log(e.name + " on line " + e.line + " on column " + e.column + ": " + e.message); 49 | process.exit(1); 50 | } 51 | 52 | var output = ''; 53 | var iteration = 0; 54 | var indent_level = 0; 55 | var increaseIndent = function() { 56 | indent_level = indent_level + 1; 57 | } 58 | var decreaseIndent = function() { 59 | indent_level = indent_level - 1; 60 | } 61 | var indent = function() 62 | { 63 | for(var c = 0; c < indent_level; c++) 64 | { 65 | addToOut(" "); 66 | } 67 | } 68 | var addToOut = function(out) { 69 | output += out; 70 | } 71 | var removeBlankLines = function(out) { 72 | var return_me = out.replace(/\n\n/g, "\n"); 73 | while (!(return_me.indexOf("\n\n") == -1)) 74 | { 75 | return_me = return_me.replace(/\n\n/g, "\n"); 76 | } 77 | return return_me; 78 | } 79 | 80 | /* calls parseNode on a collection of child nodes (statements, elements, properties, clauses) */ 81 | var parseChildNodes = function(nodes) { 82 | for(var i = 0; i < nodes.length; i++) { 83 | /* some logic */ 84 | _node = nodes[i]; 85 | is_last_statement = (i < nodes.length -1); 86 | is_just_var = (is_last_statement && (_node.type == "Variable")); /* variables are not declared this way in coffee */ 87 | is_break = (_node.type == "BreakStatement"); /* not used in coffee */ 88 | /* also don't parse labelledStatement. it's not used and we can't have empty cases if we wanna self host */ 89 | is_labelled_statement = (_node.type == "LabelledStatement"); 90 | /* indenter */ 91 | 92 | if(!(is_break) && !(is_labelled_statement)) { 93 | indent(); 94 | } 95 | 96 | /* token parser */ 97 | if(!(is_just_var) && !(is_break) && !(is_labelled_statement)) 98 | { 99 | parseNode(_node); 100 | } 101 | /* line breaker */ 102 | /*if((is_last_statement) && !(is_break) && !(is_just_var)) 103 | { 104 | addToOut("\n"); 105 | } 106 | */ 107 | addToOut("\n"); 108 | } 109 | } 110 | 111 | /* eats tokens and makes coffee */ 112 | var parseNode = function(node) { 113 | iteration = iteration + 1; 114 | 115 | if(_runmode == "--debug") 116 | { 117 | sys.puts(iteration + " " + node.type); 118 | p(node); 119 | } 120 | 121 | if(_runmode == "--ilevel") 122 | { 123 | sys.puts(iteration + " (" + indent_level + ") " + node.type + " - " + node.name); 124 | } 125 | 126 | switch(node.type) 127 | { 128 | case("Program"): 129 | if(node.elements) 130 | { 131 | parseChildNodes(node.elements); 132 | } 133 | break; 134 | case("This"): 135 | addToOut("@"); 136 | break; 137 | case("Function"): 138 | if(node.params.length > 0) 139 | { 140 | addToOut("("); 141 | for(var i = 0; i < node.params.length; i++) 142 | { 143 | addToOut(node.params[i]); 144 | if(i < node.params.length - 1) 145 | { 146 | addToOut(", "); 147 | } 148 | } 149 | addToOut(")"); 150 | } 151 | addToOut("->\n"); 152 | increaseIndent(); 153 | if(node.elements) 154 | { 155 | parseChildNodes(node.elements); 156 | } 157 | decreaseIndent(); 158 | break; 159 | case("Block"): 160 | increaseIndent(); 161 | if(node.statements) 162 | { 163 | parseChildNodes(node.statements); 164 | } 165 | decreaseIndent(); 166 | break; 167 | case("SwitchStatement"): 168 | addToOut("switch "); 169 | parseNode(node.expression); 170 | addToOut("\n"); 171 | increaseIndent(); 172 | parseChildNodes(node.clauses); 173 | decreaseIndent(); 174 | break; 175 | case("CaseClause"): 176 | addToOut("when "); 177 | parseNode(node.selector); 178 | addToOut("\n"); 179 | increaseIndent(); 180 | if(node.statements) 181 | { 182 | parseChildNodes(node.statements); 183 | } 184 | decreaseIndent(); 185 | break; 186 | case("DefaultClause"): 187 | addToOut("else "); 188 | if(node.statements.length > 1) 189 | { 190 | addToOut("\n"); 191 | increaseIndent(); 192 | if(node.statements) 193 | { 194 | parseChildNodes(node.statements); 195 | } 196 | decreaseIndent(); 197 | } 198 | else 199 | { 200 | if(node.statements.length == 1) 201 | { 202 | if(node.statements) 203 | { 204 | parseNode(node.statements[0]); 205 | } 206 | } 207 | } 208 | break; 209 | case("IfStatement"): 210 | /* condition */ 211 | if(node.condition.operator != "!") 212 | { 213 | addToOut("if "); 214 | parseNode(node.condition); 215 | } 216 | else 217 | { 218 | addToOut("unless "); 219 | /* skip next node, it's "not" */ 220 | parseNode(node.condition.expression); 221 | } 222 | addToOut("\n"); 223 | /* statements */ 224 | increaseIndent(); 225 | if(node.ifStatement.statements) 226 | { 227 | parseChildNodes(node.ifStatement.statements); 228 | } 229 | decreaseIndent(); 230 | if(node.elseStatement != null) { 231 | addToOut("\n"); 232 | indent(); 233 | addToOut("else"); 234 | addToOut("\n"); 235 | increaseIndent(); 236 | if(node.elseStatement.statements) 237 | { 238 | parseChildNodes(node.elseStatement.statements); 239 | } 240 | decreaseIndent(); 241 | } 242 | break; 243 | case("ForStatement"): 244 | parseNode(node.initializer); 245 | addToOut("\n"); 246 | indent(); 247 | addToOut("while "); 248 | parseNode(node.test); 249 | addToOut("\n"); 250 | increaseIndent(); 251 | indent(); 252 | parseNode(node.counter); 253 | decreaseIndent(); 254 | if(node.statement) 255 | { 256 | parseNode(node.statement); 257 | } 258 | break; 259 | case("WhileStatement"): 260 | addToOut("while "); 261 | parseNode(node.condition); 262 | addToOut("\n"); 263 | if(node.statement) 264 | { 265 | parseNode(node.statement); 266 | } 267 | break; 268 | case("TryStatement"): 269 | addToOut("try\n"); 270 | parseNode(node.block); 271 | addToOut("\n"); 272 | if(node['catch']) { 273 | addToOut("catch "); 274 | parseNode(node['catch']); 275 | } 276 | if(node['finally']) { 277 | addToOut("finally\n"); 278 | parseNode(node['finally']); 279 | } 280 | break; 281 | case("Catch"): 282 | if(node.identifier) 283 | { 284 | addToOut(node.identifier); 285 | } 286 | addToOut("\n"); 287 | parseNode(node.block); 288 | addToOut("\n"); 289 | break; 290 | case("Finally"): 291 | parseNode(node.block); 292 | break; 293 | case("AssignmentExpression"): 294 | parseNode(node.left); 295 | addToOut(": "); 296 | parseNode(node.right); 297 | break; 298 | case("PropertyAssignment"): 299 | parseNode(node.name); 300 | addToOut(": "); 301 | parseNode(node.value); 302 | break; 303 | case("PropertyAccess"): 304 | parseNode(node.base); 305 | if(node.name.type) 306 | { 307 | if(node.base.type != "This") { 308 | if(node.name.type != "FunctionCall") 309 | { 310 | addToOut("["); 311 | parseNode(node.name); 312 | addToOut("]"); 313 | } 314 | else 315 | { 316 | addToOut("."); 317 | parseNode(node.name); 318 | } 319 | } 320 | else 321 | { 322 | parseNode(node.name); 323 | } 324 | } 325 | else 326 | { 327 | if(node.name.type == undefined || node.name.type == "null") 328 | { 329 | if(node.base.type != "This") { addToOut("."); } 330 | addToOut(node.name.trim()); 331 | } 332 | } 333 | 334 | break; 335 | case("BinaryExpression"): 336 | parseNode(node.left); 337 | switch(node.operator) 338 | { 339 | /* switch to "not" and "isnt" or something here */ 340 | case("!"): 341 | addToOut(" not "); 342 | break; 343 | case("==="): 344 | addToOut(" is "); 345 | break; 346 | case("=="): 347 | addToOut(" is "); 348 | break; 349 | case("!=="): 350 | addToOut(" isnt "); 351 | break; 352 | case("&&"): 353 | addToOut(" and "); 354 | break; 355 | case("||"): 356 | addToOut(" or "); 357 | break; 358 | case(","): 359 | addToOut(", "); /* normal mode , for loop \n */ 360 | break; 361 | default: 362 | addToOut(" "); 363 | addToOut(node.operator); 364 | addToOut(" "); 365 | } 366 | parseNode(node.right); 367 | break; 368 | case("UnaryExpression"): 369 | switch(node.operator) 370 | { 371 | case('!'): 372 | addToOut("not "); 373 | break; 374 | default: 375 | addToOut(node.operator); 376 | } 377 | parseNode(node.expression); 378 | break; 379 | case("ConditionalExpression"): 380 | addToOut("if "); 381 | parseNode(node.condition); 382 | addToOut(" "); 383 | parseNode(node.trueExpression); 384 | addToOut(" else "); 385 | parseNode(node.falseExpression); 386 | break; 387 | case("PostfixExpression"): 388 | switch(node.operator) 389 | { 390 | case('++'): 391 | parseNode(node.expression); 392 | addToOut(" = "); 393 | parseNode(node.expression); 394 | addToOut(" + 1"); 395 | break; 396 | case('--'): 397 | parseNode(node.expression); 398 | addToOut(" = "); 399 | parseNode(node.expression); 400 | addToOut(" - 1"); 401 | break; 402 | } 403 | addToOut("\n"); 404 | break; 405 | case("Variable"): 406 | if(!(node.name.substr(0, 3) == "var")) 407 | { 408 | addToOut(node.name.trim()); 409 | } 410 | else 411 | { 412 | if(node.name.substr(0, 3) == "var") 413 | { 414 | addToOut(node.name.substr(4, node.name.length - 4).trim()); 415 | } 416 | } 417 | break; 418 | case("FunctionCall"): 419 | parseNode(node.name); 420 | addToOut("("); 421 | if(node.arguments.length > 0) 422 | { 423 | 424 | for(var i = 0; i < node.arguments.length; i++) 425 | { 426 | parseNode(node.arguments[i]); 427 | if(i < node.arguments.length - 1) 428 | { 429 | addToOut(", "); 430 | } 431 | } 432 | } 433 | addToOut(")"); 434 | break; 435 | case('StringLiteral'): 436 | var escapedValue = node.value.replace(/\n/g, "\\n"); 437 | addToOut('"' + escapedValue + '"'); 438 | break; 439 | case('NumericLiteral'): 440 | addToOut(node.value); 441 | break; 442 | case('RegularExpressionLiteral'): 443 | addToOut("/"); 444 | addToOut(node.body); 445 | addToOut("/" + node.flags); 446 | break; 447 | case('NullLiteral'): 448 | addToOut("null"); 449 | break; 450 | case('ArrayLiteral'): 451 | if(node.elements.length > 0) 452 | { 453 | addToOut("["); 454 | for(var i = 0; i < node.elements.length; i++) 455 | { 456 | parseNode(node.elements[i]); 457 | if(i < node.elements.length - 1) 458 | { 459 | addToOut(", "); 460 | } 461 | } 462 | addToOut("]"); 463 | } 464 | break; 465 | case('ObjectLiteral'): 466 | if(node.properties.length > 0) 467 | { 468 | addToOut("{\n"); 469 | increaseIndent(); 470 | if(node.properties) 471 | { 472 | parseChildNodes(node.properties); 473 | } 474 | decreaseIndent(); 475 | addToOut("\n}"); 476 | } 477 | break; 478 | case('BooleanLiteral'): 479 | if(node.value == true) 480 | { 481 | addToOut("yes"); 482 | } 483 | else 484 | { 485 | if(node.value == false) 486 | { 487 | addToOut("no"); 488 | } 489 | } 490 | break; 491 | } 492 | } 493 | 494 | parseNode(ast); 495 | 496 | if(_runmode == "--convert") 497 | { 498 | sys.puts(removeBlankLines(output)); 499 | } 500 | else 501 | { 502 | if(_runmode == "--showjs") 503 | { 504 | sys.puts("Original JavaScript: "); 505 | sys.puts(string_raw_js); 506 | sys.puts("Generated CoffeeScript: "); 507 | sys.puts(output); 508 | } 509 | } 510 | -------------------------------------------------------------------------------- /out/js2cs.coffee: -------------------------------------------------------------------------------- 1 | pegjs: require("./parser") 2 | parser: pegjs.parser 3 | sys: require("sys") 4 | fs: require("fs") 5 | p: (obj)-> 6 | obj_inspect: sys.inspect(obj, yes, 100) 7 | sys.puts(obj_inspect) 8 | String.prototype.trim: -> 9 | str_to_return: @replace(/^\s*/, "") 10 | str_to_return: str_to_return.replace(/\s*$/, "") 11 | return str_to_return 12 | _filename: process.argv[process.argv.length - 1] 13 | if process.argv[process.argv.length - 2].substr(0, 2) is "--" 14 | _runmode: process.argv[process.argv.length - 2] 15 | else 16 | _runmode: "--convert" 17 | try 18 | string_raw_js: fs.readFileSync(_filename, "utf8") 19 | catch e 20 | sys.log("Failed to read input file.. Did you specify one?") 21 | process.exit(1) 22 | try 23 | ast: parser.parse(string_raw_js) 24 | catch e 25 | sys.log(e.name + " on line " + e.line + " on column " + e.column + ": " + e.message) 26 | process.exit(1) 27 | output: "" 28 | iteration: 0 29 | indent_level: 0 30 | increaseIndent: -> 31 | indent_level: indent_level + 1 32 | decreaseIndent: -> 33 | indent_level: indent_level - 1 34 | indent: -> 35 | c: 0 36 | while c < indent_level 37 | c = c + 1 38 | addToOut(" ") 39 | addToOut: (out)-> 40 | output: out 41 | removeBlankLines: (out)-> 42 | return_me: out.replace(/\n\n/g, "\n") 43 | while(return_me.indexOf("\n\n") > 0) 44 | return_me: return_me.replace(/\n\n/g, "\n") 45 | return return_me 46 | parseChildNodes: (nodes)-> 47 | i: 0 48 | while i < nodes.length 49 | i = i + 1 50 | _node: nodes[i] 51 | is_last_statement: i < nodes.length - 1 52 | is_just_var: is_last_statement and _node.type is "Variable" 53 | is_break: _node.type is "BreakStatement" 54 | is_labelled_statement: _node.type is "LabelledStatement" 55 | if not is_break and not is_labelled_statement 56 | indent() 57 | if not is_just_var and not is_break and not is_labelled_statement 58 | parseNode(_node) 59 | addToOut("\n") 60 | parseNode: (node)-> 61 | iteration: iteration + 1 62 | if _runmode is "--debug" 63 | sys.puts(iteration + " " + node.type) 64 | p(node) 65 | if _runmode is "--ilevel" 66 | sys.puts(iteration + " (" + indent_level + ") " + node.type + " - " + node.name) 67 | switch node.type 68 | when "Program" 69 | if node.elements 70 | parseChildNodes(node.elements) 71 | when "This" 72 | addToOut("@") 73 | when "Function" 74 | if node.params.length > 0 75 | addToOut("(") 76 | i: 0 77 | while i < node.params.length 78 | i = i + 1 79 | addToOut(node.params[i]) 80 | if i < node.params.length - 1 81 | addToOut(", ") 82 | addToOut(")") 83 | addToOut("->\n") 84 | increaseIndent() 85 | if node.elements 86 | parseChildNodes(node.elements) 87 | decreaseIndent() 88 | when "Block" 89 | increaseIndent() 90 | if node.statements 91 | parseChildNodes(node.statements) 92 | decreaseIndent() 93 | when "SwitchStatement" 94 | addToOut("switch ") 95 | parseNode(node.expression) 96 | addToOut("\n") 97 | increaseIndent() 98 | parseChildNodes(node.clauses) 99 | decreaseIndent() 100 | when "CaseClause" 101 | addToOut("when ") 102 | parseNode(node.selector) 103 | addToOut("\n") 104 | increaseIndent() 105 | if node.statements 106 | parseChildNodes(node.statements) 107 | decreaseIndent() 108 | when "DefaultClause" 109 | addToOut("else ") 110 | if node.statements.length > 1 111 | addToOut("\n") 112 | increaseIndent() 113 | if node.statements 114 | parseChildNodes(node.statements) 115 | decreaseIndent() 116 | else 117 | if node.statements.length is 1 118 | if node.statements 119 | parseNode(node.statements[0]) 120 | when "IfStatement" 121 | if node.condition.operator != "!" 122 | addToOut("if ") 123 | parseNode(node.condition) 124 | else 125 | addToOut("unless ") 126 | parseNode(node.condition.expression) 127 | addToOut("\n") 128 | increaseIndent() 129 | if node.ifStatement.statements 130 | parseChildNodes(node.ifStatement.statements) 131 | decreaseIndent() 132 | if node.elseStatement != null 133 | addToOut("\n") 134 | indent() 135 | addToOut("else") 136 | addToOut("\n") 137 | increaseIndent() 138 | if node.elseStatement.statements 139 | parseChildNodes(node.elseStatement.statements) 140 | decreaseIndent() 141 | when "ForStatement" 142 | parseNode(node.initializer) 143 | addToOut("\n") 144 | indent() 145 | addToOut("while ") 146 | parseNode(node.test) 147 | addToOut("\n") 148 | increaseIndent() 149 | indent() 150 | parseNode(node.counter) 151 | decreaseIndent() 152 | if node.statement 153 | parseNode(node.statement) 154 | when "WhileStatement" 155 | addToOut("while ") 156 | parseNode(node.condition) 157 | addToOut("\n") 158 | if node.statement 159 | parseNode(node.statement) 160 | when "TryStatement" 161 | addToOut("try\n") 162 | parseNode(node.block) 163 | addToOut("\n") 164 | if node["catch"] 165 | addToOut("catch ") 166 | parseNode(node["catch"]) 167 | if node["finally"] 168 | addToOut("finally\n") 169 | parseNode(node["finally"]) 170 | when "Catch" 171 | if node.identifier 172 | addToOut(node.identifier) 173 | addToOut("\n") 174 | parseNode(node.block) 175 | addToOut("\n") 176 | when "Finally" 177 | parseNode(node.block) 178 | when "AssignmentExpression" 179 | parseNode(node.left) 180 | addToOut(": ") 181 | parseNode(node.right) 182 | when "PropertyAssignment" 183 | parseNode(node.name) 184 | addToOut(": ") 185 | parseNode(node.value) 186 | when "PropertyAccess" 187 | parseNode(node.base) 188 | if node.name.type 189 | if node.base.type != "This" 190 | if node.name.type != "FunctionCall" 191 | addToOut("[") 192 | parseNode(node.name) 193 | addToOut("]") 194 | else 195 | addToOut(".") 196 | parseNode(node.name) 197 | else 198 | parseNode(node.name) 199 | else 200 | if node.name.type is undefined or node.name.type is "null" 201 | if node.base.type != "This" 202 | addToOut(".") 203 | addToOut(node.name.trim()) 204 | when "BinaryExpression" 205 | parseNode(node.left) 206 | addToOut(" ") 207 | switch node.operator 208 | when "!" 209 | addToOut("not ") 210 | when "===" 211 | addToOut("is ") 212 | when "==" 213 | addToOut("is ") 214 | when "!==" 215 | addToOut("isnt ") 216 | when "&&" 217 | addToOut("and ") 218 | when "||" 219 | addToOut("or ") 220 | when "," 221 | addToOut("\n") 222 | else 223 | addToOut(node.operator) 224 | addToOut(" ") 225 | parseNode(node.right) 226 | when "UnaryExpression" 227 | switch node.operator 228 | when "!" 229 | addToOut("not ") 230 | else addToOut(node.operator) 231 | parseNode(node.expression) 232 | when "ConditionalExpression" 233 | addToOut("if ") 234 | parseNode(node.condition) 235 | addToOut(" ") 236 | parseNode(node.trueExpression) 237 | addToOut(" else ") 238 | parseNode(node.falseExpression) 239 | when "PostfixExpression" 240 | switch node.operator 241 | when "++" 242 | parseNode(node.expression) 243 | addToOut(" = ") 244 | parseNode(node.expression) 245 | addToOut(" + 1") 246 | when "--" 247 | parseNode(node.expression) 248 | addToOut(" = ") 249 | parseNode(node.expression) 250 | addToOut(" - 1") 251 | addToOut("\n") 252 | when "Variable" 253 | unless node.name.substr(0, 3) is "var" 254 | addToOut(node.name.trim()) 255 | else 256 | if node.name.substr(0, 3) is "var" 257 | addToOut() 258 | when "FunctionCall" 259 | parseNode(node.name) 260 | addToOut("(") 261 | if node.arguments.length > 0 262 | i: 0 263 | while i < node.arguments.length 264 | i = i + 1 265 | parseNode(node.arguments[i]) 266 | if i < node.arguments.length - 1 267 | addToOut(", ") 268 | addToOut(")") 269 | when "StringLiteral" 270 | escapedValue: node.value.replace(/\n/g, "\n") 271 | addToOut(""" + escapedValue + """) 272 | when "NumericLiteral" 273 | addToOut(node.value) 274 | when "RegularExpressionLiteral" 275 | addToOut("/") 276 | addToOut(node.body) 277 | addToOut("/" + node.flags) 278 | when "NullLiteral" 279 | addToOut("null") 280 | when "ArrayLiteral" 281 | if node.elements.length > 0 282 | addToOut("[") 283 | i: 0 284 | while i < node.elements.length 285 | i = i + 1 286 | parseNode(node.elements[i]) 287 | if i < node.elements.length - 1 288 | addToOut(", ") 289 | addToOut("]") 290 | when "ObjectLiteral" 291 | if node.properties.length > 0 292 | addToOut("{\n") 293 | increaseIndent() 294 | if node.properties 295 | parseChildNodes(node.properties) 296 | decreaseIndent() 297 | addToOut("\n}") 298 | when "BooleanLiteral" 299 | if node.value is yes 300 | addToOut("yes") 301 | else 302 | if node.value is no 303 | addToOut("no") 304 | parseNode(ast) 305 | if _runmode is "--convert" 306 | sys.puts(removeBlankLines(output)) 307 | else 308 | if _runmode is "--showjs" 309 | sys.puts("Original JavaScript: ") 310 | sys.puts(string_raw_js) 311 | sys.puts("Generated CoffeeScript: ") 312 | sys.puts(output) 313 | 314 | -------------------------------------------------------------------------------- /out/js2cs.recompiled.js: -------------------------------------------------------------------------------- 1 | var _filename, _runmode, addToOut, ast, decreaseIndent, fs, increaseIndent, indent, indent_level, iteration, output, p, parseChildNodes, parseNode, parser, pegjs, removeBlankLines, string_raw_js, sys; 2 | pegjs = require("./parser"); 3 | parser = pegjs.parser; 4 | sys = require("sys"); 5 | fs = require("fs"); 6 | p = function(obj) { 7 | var obj_inspect; 8 | obj_inspect = sys.inspect(obj, true, 100); 9 | return sys.puts(obj_inspect); 10 | }; 11 | String.prototype.trim = function() { 12 | var str_to_return; 13 | str_to_return = this.replace(/^\s*/, ""); 14 | str_to_return = str_to_return.replace(/\s*$/, ""); 15 | return str_to_return; 16 | }; 17 | _filename = process.argv[process.argv.length - 1]; 18 | process.argv[process.argv.length - 2].substr(0, 2) === "--" ? (_runmode = process.argv[process.argv.length - 2]) : (_runmode = "--convert"); 19 | try { 20 | string_raw_js = fs.readFileSync(_filename, "utf8"); 21 | } catch (e) { 22 | sys.log("Failed to read input file.. Did you specify one?"); 23 | process.exit(1); 24 | } 25 | try { 26 | ast = parser.parse(string_raw_js); 27 | } catch (e) { 28 | sys.log(e.name + " on line " + e.line + " on column " + e.column + ": " + e.message); 29 | process.exit(1); 30 | } 31 | output = ""; 32 | iteration = 0; 33 | indent_level = 0; 34 | increaseIndent = function() { 35 | indent_level = indent_level + 1; 36 | return indent_level; 37 | }; 38 | decreaseIndent = function() { 39 | indent_level = indent_level - 1; 40 | return indent_level; 41 | }; 42 | indent = function() { 43 | var _a, c; 44 | c = 0; 45 | _a = []; 46 | while (c < indent_level) { 47 | _a.push((function() { 48 | c = c + 1; 49 | return addToOut(" "); 50 | })()); 51 | } 52 | return _a; 53 | }; 54 | addToOut = function(out) { 55 | output = out; 56 | return output; 57 | }; 58 | removeBlankLines = function(out) { 59 | var return_me; 60 | return_me = out.replace(/\n\n/g, "\n"); 61 | while ((return_me.indexOf("\n\n") > 0)) { 62 | return_me = return_me.replace(/\n\n/g, "\n"); 63 | } 64 | return return_me; 65 | }; 66 | parseChildNodes = function(nodes) { 67 | var _a, _node, i, is_break, is_just_var, is_labelled_statement, is_last_statement; 68 | i = 0; 69 | _a = []; 70 | while (i < nodes.length) { 71 | _a.push((function() { 72 | i = i + 1; 73 | _node = nodes[i]; 74 | is_last_statement = i < nodes.length - 1; 75 | is_just_var = is_last_statement && _node.type === "Variable"; 76 | is_break = _node.type === "BreakStatement"; 77 | is_labelled_statement = _node.type === "LabelledStatement"; 78 | !is_break && !is_labelled_statement ? indent() : null; 79 | !is_just_var && !is_break && !is_labelled_statement ? parseNode(_node) : null; 80 | return addToOut("\n"); 81 | })()); 82 | } 83 | return _a; 84 | }; 85 | parseNode = function(node) { 86 | var _a, _b, _c, _d, escapedValue, i; 87 | iteration = iteration + 1; 88 | if (_runmode === "--debug") { 89 | sys.puts(iteration + " " + node.type); 90 | p(node); 91 | } 92 | _runmode === "--ilevel" ? sys.puts(iteration + " (" + indent_level + ") " + node.type + " - " + node.name) : null; 93 | if ((_a = node.type) === "Program") { 94 | return node.elements ? parseChildNodes(node.elements) : null; 95 | } else if (_a === "This") { 96 | return addToOut("@"); 97 | } else if (_a === "Function") { 98 | if (node.params.length > 0) { 99 | addToOut("("); 100 | i = 0; 101 | while (i < node.params.length) { 102 | i = i + 1; 103 | addToOut(node.params[i]); 104 | i < node.params.length - 1 ? addToOut(", ") : null; 105 | } 106 | addToOut(")"); 107 | } 108 | addToOut("->\n"); 109 | increaseIndent(); 110 | node.elements ? parseChildNodes(node.elements) : null; 111 | return decreaseIndent(); 112 | } else if (_a === "Block") { 113 | increaseIndent(); 114 | node.statements ? parseChildNodes(node.statements) : null; 115 | return decreaseIndent(); 116 | } else if (_a === "SwitchStatement") { 117 | addToOut("switch "); 118 | parseNode(node.expression); 119 | addToOut("\n"); 120 | increaseIndent(); 121 | parseChildNodes(node.clauses); 122 | return decreaseIndent(); 123 | } else if (_a === "CaseClause") { 124 | addToOut("when "); 125 | parseNode(node.selector); 126 | addToOut("\n"); 127 | increaseIndent(); 128 | node.statements ? parseChildNodes(node.statements) : null; 129 | return decreaseIndent(); 130 | } else if (_a === "DefaultClause") { 131 | addToOut("else "); 132 | if (node.statements.length > 1) { 133 | addToOut("\n"); 134 | increaseIndent(); 135 | node.statements ? parseChildNodes(node.statements) : null; 136 | return decreaseIndent(); 137 | } else { 138 | return node.statements.length === 1 ? node.statements ? parseNode(node.statements[0]) : null : null; 139 | } 140 | } else if (_a === "IfStatement") { 141 | if (node.condition.operator !== "!") { 142 | addToOut("if "); 143 | parseNode(node.condition); 144 | } else { 145 | addToOut("unless "); 146 | parseNode(node.condition.expression); 147 | } 148 | addToOut("\n"); 149 | increaseIndent(); 150 | node.ifStatement.statements ? parseChildNodes(node.ifStatement.statements) : null; 151 | decreaseIndent(); 152 | if (node.elseStatement !== null) { 153 | addToOut("\n"); 154 | indent(); 155 | addToOut("else"); 156 | addToOut("\n"); 157 | increaseIndent(); 158 | node.elseStatement.statements ? parseChildNodes(node.elseStatement.statements) : null; 159 | return decreaseIndent(); 160 | } 161 | } else if (_a === "ForStatement") { 162 | parseNode(node.initializer); 163 | addToOut("\n"); 164 | indent(); 165 | addToOut("while "); 166 | parseNode(node.test); 167 | addToOut("\n"); 168 | increaseIndent(); 169 | indent(); 170 | parseNode(node.counter); 171 | decreaseIndent(); 172 | return node.statement ? parseNode(node.statement) : null; 173 | } else if (_a === "WhileStatement") { 174 | addToOut("while "); 175 | parseNode(node.condition); 176 | addToOut("\n"); 177 | return node.statement ? parseNode(node.statement) : null; 178 | } else if (_a === "TryStatement") { 179 | addToOut("try\n"); 180 | parseNode(node.block); 181 | addToOut("\n"); 182 | if (node["catch"]) { 183 | addToOut("catch "); 184 | parseNode(node["catch"]); 185 | } 186 | if (node["finally"]) { 187 | addToOut("finally\n"); 188 | return parseNode(node["finally"]); 189 | } 190 | } else if (_a === "Catch") { 191 | node.identifier ? addToOut(node.identifier) : null; 192 | addToOut("\n"); 193 | parseNode(node.block); 194 | return addToOut("\n"); 195 | } else if (_a === "Finally") { 196 | return parseNode(node.block); 197 | } else if (_a === "AssignmentExpression") { 198 | parseNode(node.left); 199 | addToOut(": "); 200 | return parseNode(node.right); 201 | } else if (_a === "PropertyAssignment") { 202 | parseNode(node.name); 203 | addToOut(": "); 204 | return parseNode(node.value); 205 | } else if (_a === "PropertyAccess") { 206 | parseNode(node.base); 207 | if (node.name.type) { 208 | if (node.base.type !== "This") { 209 | if (node.name.type !== "FunctionCall") { 210 | addToOut("["); 211 | parseNode(node.name); 212 | return addToOut("]"); 213 | } else { 214 | addToOut("."); 215 | return parseNode(node.name); 216 | } 217 | } else { 218 | return parseNode(node.name); 219 | } 220 | } else { 221 | if (node.name.type === undefined || node.name.type === "null") { 222 | node.base.type !== "This" ? addToOut(".") : null; 223 | return addToOut(node.name.trim()); 224 | } 225 | } 226 | } else if (_a === "BinaryExpression") { 227 | parseNode(node.left); 228 | addToOut(" "); 229 | if ((_b = node.operator) === "!") { 230 | addToOut("not "); 231 | } else if (_b === "===") { 232 | addToOut("is "); 233 | } else if (_b === "==") { 234 | addToOut("is "); 235 | } else if (_b === "!==") { 236 | addToOut("isnt "); 237 | } else if (_b === "&&") { 238 | addToOut("and "); 239 | } else if (_b === "||") { 240 | addToOut("or "); 241 | } else if (_b === ",") { 242 | addToOut("\n"); 243 | } else { 244 | addToOut(node.operator); 245 | addToOut(" "); 246 | } 247 | return parseNode(node.right); 248 | } else if (_a === "UnaryExpression") { 249 | if ((_c = node.operator) === "!") { 250 | addToOut("not "); 251 | } else { 252 | addToOut(node.operator); 253 | } 254 | return parseNode(node.expression); 255 | } else if (_a === "ConditionalExpression") { 256 | addToOut("if "); 257 | parseNode(node.condition); 258 | addToOut(" "); 259 | parseNode(node.trueExpression); 260 | addToOut(" else "); 261 | return parseNode(node.falseExpression); 262 | } else if (_a === "PostfixExpression") { 263 | if ((_d = node.operator) === "++") { 264 | parseNode(node.expression); 265 | addToOut(" = "); 266 | parseNode(node.expression); 267 | addToOut(" + 1"); 268 | } else if (_d === "--") { 269 | parseNode(node.expression); 270 | addToOut(" = "); 271 | parseNode(node.expression); 272 | addToOut(" - 1"); 273 | } 274 | return addToOut("\n"); 275 | } else if (_a === "Variable") { 276 | return !(node.name.substr(0, 3) === "var") ? addToOut(node.name.trim()) : node.name.substr(0, 3) === "var" ? addToOut() : null; 277 | } else if (_a === "FunctionCall") { 278 | parseNode(node.name); 279 | addToOut("("); 280 | if (node.arguments.length > 0) { 281 | i = 0; 282 | while (i < node.arguments.length) { 283 | i = i + 1; 284 | parseNode(node.arguments[i]); 285 | i < node.arguments.length - 1 ? addToOut(", ") : null; 286 | } 287 | } 288 | return addToOut(")"); 289 | } else if (_a === "StringLiteral") { 290 | escapedValue = node.value.replace(/\n/g, "\n"); 291 | return addToOut("+ escapedValue +"); 292 | } else if (_a === "NumericLiteral") { 293 | return addToOut(node.value); 294 | } else if (_a === "RegularExpressionLiteral") { 295 | addToOut("/"); 296 | addToOut(node.body); 297 | return addToOut("/" + node.flags); 298 | } else if (_a === "NullLiteral") { 299 | return addToOut("null"); 300 | } else if (_a === "ArrayLiteral") { 301 | if (node.elements.length > 0) { 302 | addToOut("["); 303 | i = 0; 304 | while (i < node.elements.length) { 305 | i = i + 1; 306 | parseNode(node.elements[i]); 307 | i < node.elements.length - 1 ? addToOut(", ") : null; 308 | } 309 | return addToOut("]"); 310 | } 311 | } else if (_a === "ObjectLiteral") { 312 | if (node.properties.length > 0) { 313 | addToOut("{\n"); 314 | increaseIndent(); 315 | node.properties ? parseChildNodes(node.properties) : null; 316 | decreaseIndent(); 317 | return addToOut("\n}"); 318 | } 319 | } else if (_a === "BooleanLiteral") { 320 | return node.value === true ? addToOut("yes") : node.value === false ? addToOut("no") : null; 321 | } 322 | }; 323 | parseNode(ast); 324 | if (_runmode === "--convert") { 325 | sys.puts(removeBlankLines(output)); 326 | } else { 327 | if (_runmode === "--showjs") { 328 | sys.puts("Original JavaScript: "); 329 | sys.puts(string_raw_js); 330 | sys.puts("Generated CoffeeScript: "); 331 | sys.puts(output); 332 | } 333 | } 334 | -------------------------------------------------------------------------------- /out/test.coffee: -------------------------------------------------------------------------------- 1 | _e: 0, _g: _f.length 2 | while _e < _g 3 | _e = _e + 1 4 | thing() 5 | 6 | -------------------------------------------------------------------------------- /test/test.js: -------------------------------------------------------------------------------- 1 | for(_e = 0, _g = _f.length; _e < _g; _e++) 2 | { 3 | thing(); 4 | } 5 | --------------------------------------------------------------------------------