function js_beautify($js_source_text, $tab_size = 4) { global $output, $token_text, $last_type, $last_text, $in, $ins, $indent, $tab_string; global $input, $input_length; $tab_string = str_repeat(' ', $tab_size); $input = $js_source_text; $input_length = strlen($input); $last_word = ''; // last TK_WORD passed $last_type = TK_START_EXPR; // last token type $last_text = ''; // last token text $output = ''; // words which should always start on new line. // simple hack for cases when lines aren't ending with semicolon. // feel free to tell me about the ones that need to be added. $line_starters = explode(',', 'continue,try,throw,return,var,if,switch,case,default,for,while,break,function'); // states showing if we are currently in expression (i.e. "if" case) - IN_EXPR, or in usual block (like, procedure), IN_BLOCK. // some formatting depends on that. $in = IN_BLOCK; $ins = array($in); $indent = 0; $pos = 0; // parser position $in_case = false; // flag for parser that case/default has been processed, and next colon needs special attention while (true) { list($token_text, $token_type) = get_next_token($pos); if ($token_type == TK_EOF) { break; } // $output .= " [$token_type:$last_type]"; switch ($token_type) { case TK_START_EXPR: in(IN_EXPR); if ($last_type == TK_END_EXPR or $last_type == TK_START_EXPR) { // do nothing on (( and )( and ][ and ]( .. } elseif ($last_type != TK_WORD and $last_type != TK_OPERATOR) { space(); } elseif (in_array($last_word, $line_starters) and $last_word != 'function') { space(); } token(); break; case TK_END_EXPR: token(); in_pop(); break; case TK_START_BLOCK: in(IN_BLOCK); if ($last_type != TK_OPERATOR and $last_type != TK_START_EXPR) { if ($last_type == TK_START_BLOCK) { nl(); } else { space(); } } token(); indent(); break; case TK_END_BLOCK: if ($last_type == TK_END_EXPR) { unindent(); nl(); } elseif ($last_type == TK_END_BLOCK) { unindent(); nl(); } elseif ($last_type == TK_START_BLOCK) { // nothing unindent(); } else { unindent(); nl(); } token(); in_pop(); break; case TK_WORD: if ($token_text == 'case' or $token_text == 'default') { if ($last_text == ':') { // switch cases following one another remove_indent(); } else { $indent--; nl(); $indent++; } token(); $in_case = true; break; } $prefix = PRINT_NONE; if ($last_type == TK_END_BLOCK) { if (!in_array($token_text, array('else', 'catch', 'finally'))) { $prefix = PRINT_NL; } else { $prefix = PRINT_SPACE; space(); } } elseif ($last_type == TK_END_COMMAND && $in == IN_BLOCK) { $prefix = PRINT_NL; } elseif ($last_type == TK_END_COMMAND && $in == IN_EXPR) { $prefix = PRINT_SPACE; } elseif ($last_type == TK_WORD) { if ($last_word == 'else') { // else if $prefix = PRINT_SPACE; } else { $prefix = PRINT_SPACE; } } elseif ($last_type == TK_START_BLOCK) { $prefix = PRINT_NL; } elseif ($last_type == TK_END_EXPR) { space(); } if (in_array($token_text, $line_starters) or $prefix == PRINT_NL) { if ($last_text == 'else') { // no need to force newline on else break // DONOTHING space(); } elseif (($last_type == TK_START_EXPR or $last_text == '=') and $token_text == 'function') { // no need to force newline on 'function': (function // DONOTHING } elseif ($last_type == TK_WORD and ($last_text == 'return' or $last_text == 'throw')) { // no newline between 'return nnn' space(); } else { if ($last_type != TK_END_EXPR) { if (($last_type != TK_START_EXPR or $token_text != 'var') and $last_text != ':') { // no need to force newline on 'var': for (var x = 0...) if ($token_text == 'if' and $last_type == TK_WORD and $last_word == 'else') { // no newline for } else if { space(); } else { nl(); } } } } } elseif ($prefix == PRINT_SPACE) { space(); } token(); $last_word = $token_text; break; case TK_END_COMMAND: token(); break; case TK_STRING: if ($last_type == TK_START_BLOCK or $last_type == TK_END_BLOCK) { nl(); } elseif ($last_type == TK_WORD) { space(); } token(); break; case TK_OPERATOR: $start_delim = true; $end_delim = true; if ($token_text == ':' and $in_case) { token(); // colon really asks for separate treatment nl(); $expecting_case = false; break; } $in_case = false; if ($token_text == ',') { if ($last_type == TK_END_BLOCK) { token(); nl(); } else { if ($in == IN_BLOCK) { token(); nl(); } else { token(); space(); } } break; } elseif ($token_text == '--' or $token_text == '++') { // unary operators special case if ($last_text == ';') { // space for (;; ++i) $start_delim = true; $end_delim = false; } else { $start_delim = false; $end_delim = false; } } elseif ($token_text == '!' and $last_type == TK_START_EXPR) { // special case handling: if (!a) $start_delim = false; $end_delim = false; } elseif ($last_type == TK_OPERATOR) { $start_delim = false; $end_delim = false; } elseif ($last_type == TK_END_EXPR) { $start_delim = true; $end_delim = true; } elseif ($token_text == '.') { // decimal digits or object.property $start_delim = false; $end_delim = false; } elseif ($token_text == ':') { // zz: xx // can't differentiate ternary op, so for now it's a ? b: c; without space before colon $start_delim = false; } if ($start_delim) { space(); } token(); if ($end_delim) { space(); } break; case TK_BLOCK_COMMENT: nl(); token(); nl(); break; case TK_COMMENT: //if ($last_type != TK_COMMENT) { nl(); //} token(); nl(); break; case TK_UNKNOWN: token(); break; } if ($token_type != TK_COMMENT) { $last_type = $token_type; $last_text = $token_text; } } // clean empty lines from redundant spaces $output = preg_replace('/^ +$/m', '', $output); return $output; }
function install_rule(lime $lime, $lhs) { // This is the part that has to break the rule into subrules if necessary. $rhs = $this->rhs; // First, make sure this thing is well-formed. if (!end($rhs) instanceof lime_action) { $rhs[] = new lime_action('', null); } $prec_sym = null; if ($this->prec_glyph) { $prec_sym = $lime->sym($this->prec_glyph); } // Now, split it into chunks based on the actions. $lang = $lime->language(); $result_code = $lang->default_result(); $look = -1; $subrule = array(); $subsymbol = ''; $preamble = ''; while ($rhs) { $it = array_shift($rhs); ++$look; if ($it instanceof lime_glyph) { $subrule[] = $it->data; } elseif ($it instanceof lime_action) { $code = unindent($it->data); // It's an action. // Is it the last one? if ($rhs) { // no. $subsymbol = $lime->trump_up_bogus_lhs($lhs); $action = $lang->default_result() . $preamble . $code; $lime->add_raw_rule($subsymbol, $subrule, $action, $look, false, $prec_sym); $subrule = array($subsymbol); } else { // yes. $action = $result_code . $preamble . $code; $lime->add_raw_rule($lhs, $subrule, $action, $look, true, $prec_sym); } } else { impossible(); } if ($it->name == '$') { $result_code = $lang->result_pos($look); } elseif ($it->name) { $preamble .= $lang->bind($it->name, $look); } } }