From d7c5ad7d6263fd1baf9bfdbaa4c50b70ef2fbdb2 Mon Sep 17 00:00:00 2001 From: Alexander Sulfrian Date: Tue, 8 Jun 2010 08:22:05 +0200 Subject: reverted folder structure change for better mergeing with upstream --- .../javascript/tools/idswitch/CodePrinter.java | 212 +++++++ .../javascript/tools/idswitch/FileBody.java | 191 +++++++ .../javascript/tools/idswitch/IdValuePair.java | 58 ++ .../mozilla/javascript/tools/idswitch/Main.java | 612 +++++++++++++++++++++ .../javascript/tools/idswitch/SwitchGenerator.java | 491 +++++++++++++++++ 5 files changed, 1564 insertions(+) create mode 100644 trunk/infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/idswitch/CodePrinter.java create mode 100644 trunk/infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/idswitch/FileBody.java create mode 100644 trunk/infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/idswitch/IdValuePair.java create mode 100644 trunk/infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/idswitch/Main.java create mode 100644 trunk/infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/idswitch/SwitchGenerator.java (limited to 'trunk/infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/idswitch') diff --git a/trunk/infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/idswitch/CodePrinter.java b/trunk/infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/idswitch/CodePrinter.java new file mode 100644 index 0000000..dd4f689 --- /dev/null +++ b/trunk/infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/idswitch/CodePrinter.java @@ -0,0 +1,212 @@ +/* -*- Mode: java; tab-width: 4; indent-tabs-mode: 1; c-basic-offset: 4 -*- + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Rhino code, released + * May 6, 1999. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1997-1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Igor Bukanov + * + * Alternatively, the contents of this file may be used under the terms of + * the GNU General Public License Version 2 or later (the "GPL"), in which + * case the provisions of the GPL are applicable instead of those above. If + * you wish to allow use of your version of this file only under the terms of + * the GPL and not to allow others to use your version of this file under the + * MPL, indicate your decision by deleting the provisions above and replacing + * them with the notice and other provisions required by the GPL. If you do + * not delete the provisions above, a recipient may use your version of this + * file under either the MPL or the GPL. + * + * ***** END LICENSE BLOCK ***** */ +package org.mozilla.javascript.tools.idswitch; + +class CodePrinter { + +// length of u-type escape like \u12AB + private static final int LITERAL_CHAR_MAX_SIZE = 6; + + private String lineTerminator = "\n"; + + private int indentStep = 4; + private int indentTabSize = 8; + + private char[] buffer = new char[1 << 12]; // 4K + private int offset; + + public String getLineTerminator() { return lineTerminator; } + public void setLineTerminator(String value) { lineTerminator = value; } + + public int getIndentStep() { return indentStep; } + public void setIndentStep(int char_count) { indentStep = char_count; } + + public int getIndentTabSize() { return indentTabSize; } + public void setIndentTabSize(int tab_size) { indentTabSize = tab_size; } + + public void clear() { + offset = 0; + } + + private int ensure_area(int area_size) { + int begin = offset; + int end = begin + area_size; + if (end > buffer.length) { + int new_capacity = buffer.length * 2; + if (end > new_capacity) { new_capacity = end; } + char[] tmp = new char[new_capacity]; + System.arraycopy(buffer, 0, tmp, 0, begin); + buffer = tmp; + } + return begin; + } + + private int add_area(int area_size) { + int pos = ensure_area(area_size); + offset = pos + area_size; + return pos; + } + + public int getOffset() { + return offset; + } + + public int getLastChar() { + return offset == 0 ? -1 : buffer[offset - 1]; + } + + public void p(char c) { + int pos = add_area(1); + buffer[pos] = c; + } + + public void p(String s) { + int l = s.length(); + int pos = add_area(l); + s.getChars(0, l, buffer, pos); + } + + public final void p(char[] array) { + p(array, 0, array.length); + } + + public void p(char[] array, int begin, int end) { + int l = end - begin; + int pos = add_area(l); + System.arraycopy(array, begin, buffer, pos, l); + } + + public void p(int i) { + p(Integer.toString(i)); + } + + public void qchar(int c) { + int pos = ensure_area(2 + LITERAL_CHAR_MAX_SIZE); + buffer[pos] = '\''; + pos = put_string_literal_char(pos + 1, c, false); + buffer[pos] = '\''; + offset = pos + 1; + } + + public void qstring(String s) { + int l = s.length(); + int pos = ensure_area(2 + LITERAL_CHAR_MAX_SIZE * l); + buffer[pos] = '"'; + ++pos; + for (int i = 0; i != l; ++i) { + pos = put_string_literal_char(pos, s.charAt(i), true); + } + buffer[pos] = '"'; + offset = pos + 1; + } + + private int put_string_literal_char(int pos, int c, boolean in_string) { + boolean backslash_symbol = true; + switch (c) { + case '\b': c = 'b'; break; + case '\t': c = 't'; break; + case '\n': c = 'n'; break; + case '\f': c = 'f'; break; + case '\r': c = 'r'; break; + case '\'': backslash_symbol = !in_string; break; + case '"': backslash_symbol = in_string; break; + default: backslash_symbol = false; + } + + if (backslash_symbol) { + buffer[pos] = '\\'; + buffer[pos + 1] = (char)c; + pos += 2; + } + else if (' ' <= c && c <= 126) { + buffer[pos] = (char)c; + ++pos; + } + else { + buffer[pos] = '\\'; + buffer[pos + 1] = 'u'; + buffer[pos + 2] = digit_to_hex_letter(0xF & (c >> 12)); + buffer[pos + 3] = digit_to_hex_letter(0xF & (c >> 8)); + buffer[pos + 4] = digit_to_hex_letter(0xF & (c >> 4)); + buffer[pos + 5] = digit_to_hex_letter(0xF & c); + pos += 6; + } + return pos; + } + + private static char digit_to_hex_letter(int d) { + return (char)((d < 10) ? '0' + d : 'A' - 10 + d); + } + + public void indent(int level) { + int visible_size = indentStep * level; + int indent_size, tab_count; + if (indentTabSize <= 0) { + tab_count = 0; indent_size = visible_size; + } + else { + tab_count = visible_size / indentTabSize; + indent_size = tab_count + visible_size % indentTabSize; + } + int pos = add_area(indent_size); + int tab_end = pos + tab_count; + int indent_end = pos + indent_size; + for (; pos != tab_end; ++pos) { buffer[pos] = '\t'; } + for (; pos != indent_end; ++pos) { buffer[pos] = ' '; } + } + + public void nl() { + p('\n'); + } + + public void line(int indent_level, String s) { + indent(indent_level); p(s); nl(); + } + + public void erase(int begin, int end) { + System.arraycopy(buffer, end, buffer, begin, offset - end); + offset -= end - begin; + } + + public String toString() { + return new String(buffer, 0, offset); + } + + + +} diff --git a/trunk/infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/idswitch/FileBody.java b/trunk/infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/idswitch/FileBody.java new file mode 100644 index 0000000..60bdfb4 --- /dev/null +++ b/trunk/infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/idswitch/FileBody.java @@ -0,0 +1,191 @@ +/* -*- Mode: java; tab-width: 4; indent-tabs-mode: 1; c-basic-offset: 4 -*- + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Rhino code, released + * May 6, 1999. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1997-1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Igor Bukanov + * + * Alternatively, the contents of this file may be used under the terms of + * the GNU General Public License Version 2 or later (the "GPL"), in which + * case the provisions of the GPL are applicable instead of those above. If + * you wish to allow use of your version of this file only under the terms of + * the GPL and not to allow others to use your version of this file under the + * MPL, indicate your decision by deleting the provisions above and replacing + * them with the notice and other provisions required by the GPL. If you do + * not delete the provisions above, a recipient may use your version of this + * file under either the MPL or the GPL. + * + * ***** END LICENSE BLOCK ***** */ +package org.mozilla.javascript.tools.idswitch; + +import java.io.IOException; +import java.io.Reader; +import java.io.Writer; + +public class FileBody { + + private static class ReplaceItem { + ReplaceItem next; + int begin; + int end; + String replacement; + + ReplaceItem(int begin, int end, String text) { + this.begin = begin; + this.end = end; + this.replacement = text; + } + } + + private char[] buffer = new char[1 << 14]; // 16K + private int bufferEnd; + private int lineBegin; + private int lineEnd; + private int nextLineStart; + + private int lineNumber; + + ReplaceItem firstReplace; + ReplaceItem lastReplace; + + + public char[] getBuffer() { return buffer; } + + public void readData(Reader r) throws IOException { + int capacity = buffer.length; + int offset = 0; + for (;;) { + int n_read = r.read(buffer, offset, capacity - offset); + if (n_read < 0) { break; } + offset += n_read; + if (capacity == offset) { + capacity *= 2; + char[] tmp = new char[capacity]; + System.arraycopy(buffer, 0, tmp, 0, offset); + buffer = tmp; + } + } + bufferEnd = offset; + } + + public void writeInitialData(Writer w) throws IOException { + w.write(buffer, 0, bufferEnd); + } + + public void writeData(Writer w) throws IOException { + int offset = 0; + for (ReplaceItem x = firstReplace; x != null; x = x.next) { + int before_replace = x.begin - offset; + if (before_replace > 0) { + w.write(buffer, offset, before_replace); + } + w.write(x.replacement); + offset = x.end; + } + int tail = bufferEnd - offset; + if (tail != 0) { + w.write(buffer, offset, tail); + } + } + + public boolean wasModified() { return firstReplace != null; } + + public boolean setReplacement(int begin, int end, String text) { + if (equals(text, buffer, begin, end)) { return false; } + + ReplaceItem item = new ReplaceItem(begin, end, text); + if (firstReplace == null) { + firstReplace = lastReplace = item; + } + else if (begin < firstReplace.begin) { + item.next = firstReplace; + firstReplace = item; + } + else { + ReplaceItem cursor = firstReplace; + ReplaceItem next = cursor.next; + while (next != null) { + if (begin < next.begin) { + item.next = next; + cursor.next = item; + break; + } + cursor = next; + next = next.next; + } + if (next == null) { + lastReplace.next = item; + } + } + + return true; + } + + public int getLineNumber() { return lineNumber; } + + public int getLineBegin() { return lineBegin; } + + public int getLineEnd() { return lineEnd; } + + public void startLineLoop() { + lineNumber = 0; + lineBegin = lineEnd = nextLineStart = 0; + } + + public boolean nextLine() { + if (nextLineStart == bufferEnd) { + lineNumber = 0; return false; + } + int i; int c = 0; + for (i = nextLineStart; i != bufferEnd; ++i) { + c = buffer[i]; + if (c == '\n' || c == '\r') { break; } + } + lineBegin = nextLineStart; + lineEnd = i; + if (i == bufferEnd) { + nextLineStart = i; + } + else if (c == '\r' && i + 1 != bufferEnd && buffer[i + 1] == '\n') { + nextLineStart = i + 2; + } + else { + nextLineStart = i + 1; + } + ++lineNumber; + return true; + } + + private static boolean equals(String str, char[] array, int begin, int end) + { + if (str.length() == end - begin) { + for (int i = begin, j = 0; i != end; ++i, ++j) { + if (array[i] != str.charAt(j)) { return false; } + } + return true; + } + return false; + } + +} + + diff --git a/trunk/infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/idswitch/IdValuePair.java b/trunk/infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/idswitch/IdValuePair.java new file mode 100644 index 0000000..69d5065 --- /dev/null +++ b/trunk/infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/idswitch/IdValuePair.java @@ -0,0 +1,58 @@ +/* -*- Mode: java; tab-width: 4; indent-tabs-mode: 1; c-basic-offset: 4 -*- + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Rhino code, released + * May 6, 1999. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1997-1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Igor Bukanov + * + * Alternatively, the contents of this file may be used under the terms of + * the GNU General Public License Version 2 or later (the "GPL"), in which + * case the provisions of the GPL are applicable instead of those above. If + * you wish to allow use of your version of this file only under the terms of + * the GPL and not to allow others to use your version of this file under the + * MPL, indicate your decision by deleting the provisions above and replacing + * them with the notice and other provisions required by the GPL. If you do + * not delete the provisions above, a recipient may use your version of this + * file under either the MPL or the GPL. + * + * ***** END LICENSE BLOCK ***** */ +package org.mozilla.javascript.tools.idswitch; + +public class IdValuePair +{ + public final int idLength; + public final String id; + public final String value; + + private int lineNumber; + + public IdValuePair(String id, String value) { + this.idLength = id.length(); + this.id = id; + this.value = value; + } + + public int getLineNumber() { return lineNumber; } + + public void setLineNumber(int value) { lineNumber = value; } +} + diff --git a/trunk/infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/idswitch/Main.java b/trunk/infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/idswitch/Main.java new file mode 100644 index 0000000..ae1d038 --- /dev/null +++ b/trunk/infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/idswitch/Main.java @@ -0,0 +1,612 @@ +/* -*- Mode: java; tab-width: 4; indent-tabs-mode: 1; c-basic-offset: 4 -*- + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Rhino code, released + * May 6, 1999. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1997-1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Igor Bukanov + * + * Alternatively, the contents of this file may be used under the terms of + * the GNU General Public License Version 2 or later (the "GPL"), in which + * case the provisions of the GPL are applicable instead of those above. If + * you wish to allow use of your version of this file only under the terms of + * the GPL and not to allow others to use your version of this file under the + * MPL, indicate your decision by deleting the provisions above and replacing + * them with the notice and other provisions required by the GPL. If you do + * not delete the provisions above, a recipient may use your version of this + * file under either the MPL or the GPL. + * + * ***** END LICENSE BLOCK ***** */ +package org.mozilla.javascript.tools.idswitch; + +import java.io.*; +import java.util.*; +import java.text.SimpleDateFormat; + +import org.mozilla.javascript.EvaluatorException; +import org.mozilla.javascript.tools.ToolErrorReporter; + +public class Main { + + private static final String SWITCH_TAG_STR = "string_id_map"; + private static final String GENERATED_TAG_STR = "generated"; + private static final String STRING_TAG_STR = "string"; + + private static final int + NORMAL_LINE = 0, + SWITCH_TAG = 1, + GENERATED_TAG = 2, + STRING_TAG = 3; + + private final Vector all_pairs = new Vector(); + + private ToolErrorReporter R; + private CodePrinter P; + private FileBody body; + private String source_file; + + private int tag_definition_end; + + private int tag_value_start; + private int tag_value_end; + + private static boolean is_value_type(int id) { + if (id == STRING_TAG) { return true; } + return false; + } + + private static String tag_name(int id) { + switch (id) { + case SWITCH_TAG: return SWITCH_TAG_STR; + case -SWITCH_TAG: return "/" + SWITCH_TAG_STR; + case GENERATED_TAG: return GENERATED_TAG_STR; + case -GENERATED_TAG: return "/" + GENERATED_TAG_STR; + } + return ""; + } + + void process_file(String file_path) throws IOException { + source_file = file_path; + + body = new FileBody(); + + InputStream is; + if (file_path.equals("-")) { + is = System.in; + } + else { + is = new FileInputStream(file_path); + } + try { + Reader r = new InputStreamReader(is, "ASCII"); + body.readData(r); + } + finally { is.close(); } + + process_file(); + + if (body.wasModified()) { + OutputStream os; + if (file_path.equals("-")) { + os = System.out; + } + else { + os = new FileOutputStream(file_path); + } + + try { + Writer w = new OutputStreamWriter(os); + body.writeData(w); + w.flush(); + } + finally { os.close(); } + } + } + + private void process_file() { + int cur_state = 0; + char[] buffer = body.getBuffer(); + + int generated_begin = -1, generated_end = -1; + int time_stamp_begin = -1, time_stamp_end = -1; + + body.startLineLoop(); + while (body.nextLine()) { + int begin = body.getLineBegin(); + int end = body.getLineEnd(); + + int tag_id = extract_line_tag_id(buffer, begin, end); + boolean bad_tag = false; + switch (cur_state) { + case NORMAL_LINE: + if (tag_id == SWITCH_TAG) { + cur_state = SWITCH_TAG; + all_pairs.removeAllElements(); + generated_begin = -1; + } + else if (tag_id == -SWITCH_TAG) { + bad_tag = true; + } + break; + case SWITCH_TAG: + if (tag_id == 0) { + look_for_id_definitions(buffer, begin, end, false); + } + else if (tag_id == STRING_TAG) { + look_for_id_definitions(buffer, begin, end, true); + } + else if (tag_id == GENERATED_TAG) { + if (generated_begin >= 0) { bad_tag = true; } + else { + cur_state = GENERATED_TAG; + time_stamp_begin = tag_definition_end; + time_stamp_end = end; + } + } + else if (tag_id == -SWITCH_TAG) { + cur_state = 0; + if (generated_begin >= 0 && !all_pairs.isEmpty()) { + generate_java_code(); + String code = P.toString(); + boolean different = body.setReplacement + (generated_begin, generated_end, code); + if (different) { + String stamp = get_time_stamp(); + body.setReplacement + (time_stamp_begin, time_stamp_end, stamp); + } + } + + break; + } + else { + bad_tag = true; + } + break; + case GENERATED_TAG: + if (tag_id == 0) { + if (generated_begin < 0) { generated_begin = begin; } + } + else if (tag_id == -GENERATED_TAG) { + if (generated_begin < 0) { generated_begin = begin; } + cur_state = SWITCH_TAG; + generated_end = begin; + } + else { + bad_tag = true; + } + break; + } + if (bad_tag) { + String text = ToolErrorReporter.getMessage( + "msg.idswitch.bad_tag_order", tag_name(tag_id)); + throw R.runtimeError + (text, source_file, body.getLineNumber(), null, 0); + } + } + + if (cur_state != 0) { + String text = ToolErrorReporter.getMessage( + "msg.idswitch.file_end_in_switch", tag_name(cur_state)); + throw R.runtimeError + (text, source_file, body.getLineNumber(), null, 0); + } + } + + private String get_time_stamp() { + SimpleDateFormat f = new SimpleDateFormat + (" 'Last update:' yyyy-MM-dd HH:mm:ss z"); + return f.format(new Date()); + } + + private void generate_java_code() { + + P.clear(); + + IdValuePair[] pairs = new IdValuePair[all_pairs.size()]; + all_pairs.copyInto(pairs); + + SwitchGenerator g = new SwitchGenerator(); + g.char_tail_test_threshold = 2; + g.setReporter(R); + g.setCodePrinter(P); + + g.generateSwitch(pairs, "0"); + } + + private int extract_line_tag_id(char[] array, int cursor, int end) { + int id = 0; + cursor = skip_white_space(array, cursor, end); + int after_leading_white_space = cursor; + cursor = look_for_slash_slash(array, cursor, end); + if (cursor != end) { + boolean at_line_start = (after_leading_white_space + 2 == cursor); + cursor = skip_white_space(array, cursor, end); + if (cursor != end && array[cursor] == '#') { + ++cursor; + + boolean end_tag = false; + if (cursor != end && array[cursor] == '/') { + ++cursor; end_tag = true; + } + + int tag_start = cursor; + + for (; cursor != end; ++cursor) { + int c = array[cursor]; + if (c == '#' || c == '=' ||is_white_space(c)) { break; } + } + + if (cursor != end) { + int tag_end = cursor; + cursor = skip_white_space(array, cursor, end); + if (cursor != end) { + int c = array[cursor]; + if (c == '=' || c == '#') { + id = get_tag_id + (array, tag_start, tag_end, at_line_start); + if (id != 0) { + String bad = null; + if (c == '#') { + if (end_tag) { + id = -id; + if (is_value_type(id)) { + bad = "msg.idswitch.no_end_usage"; + } + } + tag_definition_end = cursor + 1; + } + else { + if (end_tag) { + bad = "msg.idswitch.no_end_with_value"; + } + else if (!is_value_type(id)) { + bad = "msg.idswitch.no_value_allowed"; + } + id = extract_tag_value + (array, cursor + 1, end, id); + } + if (bad != null) { + String s = ToolErrorReporter.getMessage( + bad, tag_name(id)); + throw R.runtimeError + (s, source_file, body.getLineNumber(), + null, 0); + } + } + } + } + } + } + } + return id; + } + +// Return position after first of // or end if not found + private int look_for_slash_slash(char[] array, int cursor, int end) { + while (cursor + 2 <= end) { + int c = array[cursor++]; + if (c == '/') { + c = array[cursor++]; + if (c == '/') { + return cursor; + } + } + } + return end; + } + + private int extract_tag_value(char[] array, int cursor, int end, int id) { + // cursor points after #[^#=]+= + // ALERT: implement support for quoted strings + boolean found = false; + cursor = skip_white_space(array, cursor, end); + if (cursor != end) { + int value_start = cursor; + int value_end = cursor; + while (cursor != end) { + int c = array[cursor]; + if (is_white_space(c)) { + int after_space = skip_white_space(array, cursor + 1, end); + if (after_space != end && array[after_space] == '#') { + value_end = cursor; + cursor = after_space; + break; + } + cursor = after_space + 1; + } + else if (c == '#') { + value_end = cursor; + break; + } + else { + ++cursor; + } + } + if (cursor != end) { + // array[cursor] is '#' here + found = true; + tag_value_start = value_start; + tag_value_end = value_end; + tag_definition_end = cursor + 1; + } + } + return (found) ? id : 0; + } + + private int get_tag_id + (char[] array, int begin, int end, boolean at_line_start) + { + if (at_line_start) { + if (equals(SWITCH_TAG_STR, array, begin, end)) { + return SWITCH_TAG; + } + if (equals(GENERATED_TAG_STR, array, begin, end)) { + return GENERATED_TAG; + } + } + if (equals(STRING_TAG_STR, array, begin, end)) { + return STRING_TAG; + } + return 0; + } + + private void look_for_id_definitions + (char[] array, int begin, int end, boolean use_tag_value_as_string) + { + // Look for the pattern + // '^[ \t]+Id_([a-zA-Z0-9_]+)[ \t]*=.*$' + // where \1 gives field or method name + int cursor = begin; + // Skip tab and spaces at the beginning + cursor = skip_white_space(array, cursor, end); + int id_start = cursor; + int name_start = skip_matched_prefix("Id_", array, cursor, end); + if (name_start >= 0) { + // Found Id_ prefix + cursor = name_start; + cursor = skip_name_char(array, cursor, end); + int name_end = cursor; + if (name_start != name_end) { + cursor = skip_white_space(array, cursor, end); + if (cursor != end) { + if (array[cursor] == '=') { + int id_end = name_end; + if (use_tag_value_as_string) { + name_start = tag_value_start; + name_end = tag_value_end; + } + // Got the match + add_id(array, id_start, id_end, name_start, name_end); + } + } + } + } + } + + private void add_id + (char[] array, int id_start, int id_end, int name_start, int name_end) + { + String name = new String(array, name_start, name_end - name_start); + String value = new String(array, id_start, id_end - id_start); + + IdValuePair pair = new IdValuePair(name, value); + + pair.setLineNumber(body.getLineNumber()); + + all_pairs.addElement(pair); + } + + private static boolean is_white_space(int c) { + return c == ' ' || c == '\t'; + } + + private static int skip_white_space(char[] array, int begin, int end) { + int cursor = begin; + for (; cursor != end; ++cursor) { + int c = array[cursor]; + if (!is_white_space(c)) { break; } + } + return cursor; + } + + private static int skip_matched_prefix + (String prefix, char[] array, int begin, int end) + { + int cursor = -1; + int prefix_length = prefix.length(); + if (prefix_length <= end - begin) { + cursor = begin; + for (int i = 0; i != prefix_length; ++i, ++cursor) { + if (prefix.charAt(i) != array[cursor]) { + cursor = -1; break; + } + } + } + return cursor; + } + + private static boolean equals(String str, char[] array, int begin, int end) + { + if (str.length() == end - begin) { + for (int i = begin, j = 0; i != end; ++i, ++j) { + if (array[i] != str.charAt(j)) { return false; } + } + return true; + } + return false; + } + + private static int skip_name_char(char[] array, int begin, int end) { + int cursor = begin; + for (; cursor != end; ++cursor) { + int c = array[cursor]; + if (!('a' <= c && c <= 'z') && !('A' <= c && c <= 'Z')) { + if (!('0' <= c && c <= '9')) { + if (c != '_') { + break; + } + } + } + } + return cursor; + } + + public static void main(String[] args) { + Main self = new Main(); + int status = self.exec(args); + System.exit(status); + } + + private int exec(String[] args) { + R = new ToolErrorReporter(true, System.err); + + int arg_count = process_options(args); + + if (arg_count == 0) { + option_error(ToolErrorReporter.getMessage( + "msg.idswitch.no_file_argument")); + return -1; + } + if (arg_count > 1) { + option_error(ToolErrorReporter.getMessage( + "msg.idswitch.too_many_arguments")); + return -1; + } + + P = new CodePrinter(); + P.setIndentStep(4); + P.setIndentTabSize(0); + + try { + process_file(args[0]); + } + catch (IOException ex) { + print_error(ToolErrorReporter.getMessage( + "msg.idswitch.io_error", ex.toString())); + return -1; + } + catch (EvaluatorException ex) { + return -1; + } + return 0; + } + + private int process_options(String[] args) { + + int status = 1; + + boolean show_usage = false; + boolean show_version = false; + + int N = args.length; + L: for (int i = 0; i != N; ++i) { + String arg = args[i]; + int arg_length = arg.length(); + if (arg_length >= 2) { + if (arg.charAt(0) == '-') { + if (arg.charAt(1) == '-') { + if (arg_length == 2) { + args[i] = null; break; + } + if (arg.equals("--help")) { + show_usage = true; + } + else if (arg.equals("--version")) { + show_version = true; + } + else { + option_error(ToolErrorReporter.getMessage( + "msg.idswitch.bad_option", arg)); + status = -1; break L; + } + } + else { + for (int j = 1; j != arg_length; ++j) { + char c = arg.charAt(j); + switch (c) { + case 'h': show_usage = true; break; + default: + option_error( + ToolErrorReporter.getMessage( + "msg.idswitch.bad_option_char", + String.valueOf(c))); + status = -1; + break L; + } + + } + } + args[i] = null; + } + } + } + + if (status == 1) { + if (show_usage) { show_usage(); status = 0; } + if (show_version) { show_version(); status = 0; } + } + + if (status != 1) { System.exit(status); } + + return remove_nulls(args); + } + + private void show_usage() { + System.out.println( + ToolErrorReporter.getMessage("msg.idswitch.usage")); + System.out.println(); + } + + private void show_version() { + System.out.println( + ToolErrorReporter.getMessage("msg.idswitch.version")); + } + + private void option_error(String str) { + print_error( + ToolErrorReporter.getMessage("msg.idswitch.bad_invocation", str)); + } + + private void print_error(String text) { + System.err.println(text); + } + + private int remove_nulls(String[] array) { + int N = array.length; + int cursor = 0; + for (; cursor != N; ++cursor) { + if (array[cursor] == null) { break; } + } + int destination = cursor; + if (cursor != N) { + ++cursor; + for (; cursor != N; ++cursor) { + String elem = array[cursor]; + if (elem != null) { + array[destination] = elem; ++destination; + } + } + } + return destination; + } +} + diff --git a/trunk/infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/idswitch/SwitchGenerator.java b/trunk/infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/idswitch/SwitchGenerator.java new file mode 100644 index 0000000..3db99d6 --- /dev/null +++ b/trunk/infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/idswitch/SwitchGenerator.java @@ -0,0 +1,491 @@ +/* -*- Mode: java; tab-width: 4; indent-tabs-mode: 1; c-basic-offset: 4 -*- + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Rhino code, released + * May 6, 1999. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1997-1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Igor Bukanov + * + * Alternatively, the contents of this file may be used under the terms of + * the GNU General Public License Version 2 or later (the "GPL"), in which + * case the provisions of the GPL are applicable instead of those above. If + * you wish to allow use of your version of this file only under the terms of + * the GPL and not to allow others to use your version of this file under the + * MPL, indicate your decision by deleting the provisions above and replacing + * them with the notice and other provisions required by the GPL. If you do + * not delete the provisions above, a recipient may use your version of this + * file under either the MPL or the GPL. + * + * ***** END LICENSE BLOCK ***** */ +package org.mozilla.javascript.tools.idswitch; + +import org.mozilla.javascript.EvaluatorException; +import org.mozilla.javascript.tools.ToolErrorReporter; + +public class SwitchGenerator { + + String v_switch_label = "L0"; + String v_label = "L"; + String v_s = "s"; + String v_c = "c"; + String v_guess = "X"; + String v_id = "id"; + String v_length_suffix = "_length"; + + int use_if_threshold = 3; + int char_tail_test_threshold = 2; + + private IdValuePair[] pairs; + private String default_value; + private int[] columns; + private boolean c_was_defined; + + private CodePrinter P; + private ToolErrorReporter R; + private String source_file; + + public CodePrinter getCodePrinter() { return P; } + public void setCodePrinter(CodePrinter value) { P = value; } + + public ToolErrorReporter getReporter() { return R; } + public void setReporter(ToolErrorReporter value) { R = value; } + + public String getSourceFileName() { return source_file; } + public void setSourceFileName(String value) { source_file = value; } + + public void generateSwitch(String[] pairs, String default_value) { + int N = pairs.length / 2; + IdValuePair[] id_pairs = new IdValuePair[N]; + for (int i = 0; i != N; ++i) { + id_pairs[i] = new IdValuePair(pairs[2 * i], pairs[2 * i + 1]); + } + generateSwitch(id_pairs, default_value); + + } + + public void generateSwitch(IdValuePair[] pairs, String default_value) { + int begin = 0; + int end = pairs.length; + if (begin == end) { return; } + this.pairs = pairs; + this.default_value = default_value; + + generate_body(begin, end, 2); + } + + private void generate_body(int begin, int end, int indent_level) { + P.indent(indent_level); + P.p(v_switch_label); P.p(": { "); + P.p(v_id); P.p(" = "); P.p(default_value); + P.p("; String "); P.p(v_guess); P.p(" = null;"); + + c_was_defined = false; + int c_def_begin = P.getOffset(); + P.p(" int "); P.p(v_c); P.p(';'); + int c_def_end = P.getOffset(); + P.nl(); + + generate_length_switch(begin, end, indent_level + 1); + + if (!c_was_defined) { + P.erase(c_def_begin, c_def_end); + } + + P.indent(indent_level + 1); + P.p("if ("); P.p(v_guess); P.p("!=null && "); + P.p(v_guess); P.p("!="); P.p(v_s); + P.p(" && !"); P.p(v_guess); P.p(".equals("); P.p(v_s); P.p(")) "); + P.p(v_id); P.p(" = "); P.p(default_value); P.p(";"); P.nl(); + + // Add break at end of block to suppress warning for unused label + P.indent(indent_level + 1); + P.p("break "); P.p(v_switch_label); P.p(";"); P.nl(); + + P.line(indent_level, "}"); + } + + private void generate_length_switch(int begin, int end, int indent_level) { + + sort_pairs(begin, end, -1); + + check_all_is_different(begin, end); + + int lengths_count = count_different_lengths(begin, end); + + columns = new int[pairs[end - 1].idLength]; + + boolean use_if; + if (lengths_count <= use_if_threshold) { + use_if = true; + if (lengths_count != 1) { + P.indent(indent_level); + P.p("int "); P.p(v_s); P.p(v_length_suffix); + P.p(" = "); P.p(v_s); P.p(".length();"); + P.nl(); + } + } + else { + use_if = false; + P.indent(indent_level); + P.p(v_label); P.p(": switch ("); + P.p(v_s); P.p(".length()) {"); + P.nl(); + } + + int same_length_begin = begin; + int cur_l = pairs[begin].idLength, l = 0; + for (int i = begin;;) { + ++i; + if (i == end || (l = pairs[i].idLength) != cur_l) { + int next_indent; + if (use_if) { + P.indent(indent_level); + if (same_length_begin != begin) { P.p("else "); } + P.p("if ("); + if (lengths_count == 1) { + P.p(v_s); P.p(".length()=="); + } + else { + P.p(v_s); P.p(v_length_suffix); P.p("=="); + } + P.p(cur_l); + P.p(") {"); + next_indent = indent_level + 1; + } + else { + P.indent(indent_level); + P.p("case "); P.p(cur_l); P.p(":"); + next_indent = indent_level + 1; + } + generate_letter_switch + (same_length_begin, i, next_indent, !use_if, use_if); + if (use_if) { + P.p("}"); P.nl(); + } + else { + P.p("break "); P.p(v_label); P.p(";"); P.nl(); + } + + if (i == end) { break; } + same_length_begin = i; + cur_l = l; + } + } + + if (!use_if) { + P.indent(indent_level); P.p("}"); P.nl(); + } + + } + + private void generate_letter_switch + (int begin, int end, + int indent_level, boolean label_was_defined, boolean inside_if) + { + int L = pairs[begin].idLength; + + for (int i = 0; i != L; ++i) { + columns[i] = i; + } + + generate_letter_switch_r + (begin, end, L, indent_level, label_was_defined, inside_if); + } + + + private boolean generate_letter_switch_r + (int begin, int end, int L, + int indent_level, boolean label_was_defined, boolean inside_if) + { + boolean next_is_unreachable = false; + if (begin + 1 == end) { + P.p(' '); + IdValuePair pair = pairs[begin]; + if (L > char_tail_test_threshold) { + P.p(v_guess); P.p("="); P.qstring(pair.id); P.p(";"); + P.p(v_id); P.p("="); P.p(pair.value); P.p(";"); + } + else { + if (L == 0) { + next_is_unreachable = true; + P.p(v_id); P.p("="); P.p(pair.value); + P.p("; break "); P.p(v_switch_label); P.p(";"); + } + else { + P.p("if ("); + int column = columns[0]; + P.p(v_s); P.p(".charAt("); P.p(column); P.p(")=="); + P.qchar(pair.id.charAt(column)); + for (int i = 1; i != L; ++i) { + P.p(" && "); + column = columns[i]; + P.p(v_s); P.p(".charAt("); P.p(column); P.p(")=="); + P.qchar(pair.id.charAt(column)); + } + P.p(") {"); + P.p(v_id); P.p("="); P.p(pair.value); + P.p("; break "); P.p(v_switch_label); P.p(";}"); + } + } + P.p(' '); + return next_is_unreachable; + } + + int max_column_index = find_max_different_column(begin, end, L); + int max_column = columns[max_column_index]; + int count = count_different_chars(begin, end, max_column); + + columns[max_column_index] = columns[L - 1]; + + if (inside_if) { P.nl(); P.indent(indent_level); } + else { P.p(' '); } + + boolean use_if; + if (count <= use_if_threshold) { + use_if = true; + c_was_defined = true; + P.p(v_c); P.p("="); P.p(v_s); + P.p(".charAt("); P.p(max_column); P.p(");"); + } + else { + use_if = false; + if (!label_was_defined) { + label_was_defined = true; + P.p(v_label); P.p(": "); + } + P.p("switch ("); P.p(v_s); + P.p(".charAt("); P.p(max_column); P.p(")) {"); + } + + int same_char_begin = begin; + int cur_ch = pairs[begin].id.charAt(max_column), ch = 0; + for (int i = begin;;) { + ++i; + if (i == end || (ch = pairs[i].id.charAt(max_column)) != cur_ch) { + int next_indent; + if (use_if) { + P.nl(); P.indent(indent_level); + if (same_char_begin != begin) { P.p("else "); } + P.p("if ("); P.p(v_c); P.p("=="); + P.qchar(cur_ch); P.p(") {"); + next_indent = indent_level + 1; + } + else { + P.nl(); P.indent(indent_level); + P.p("case "); P.qchar(cur_ch); P.p(":"); + next_indent = indent_level + 1; + } + boolean after_unreachable = generate_letter_switch_r + (same_char_begin, i, L - 1, + next_indent, label_was_defined, use_if); + if (use_if) { + P.p("}"); + } + else { + if (!after_unreachable) { + P.p("break "); P.p(v_label); P.p(";"); + } + } + if (i == end) { break; } + same_char_begin = i; + cur_ch = ch; + } + } + + if (use_if) { + P.nl(); + if (inside_if) { P.indent(indent_level - 1); } + else { P.indent(indent_level); } + } + else { + P.nl(); P.indent(indent_level); P.p("}"); + if (inside_if) { P.nl(); P.indent(indent_level - 1);} + else { P.p(' '); } + } + + columns[max_column_index] = max_column; + + return next_is_unreachable; + } + + + private int count_different_lengths(int begin, int end) { + int lengths_count = 0; + int cur_l = -1; + for (; begin != end; ++begin) { + int l = pairs[begin].idLength; + if (cur_l != l) { + ++lengths_count; cur_l = l; + } + } + return lengths_count; + } + + private int find_max_different_column(int begin, int end, int L) { + int max_count = 0; + int max_index = 0; + + for (int i = 0; i != L; ++i) { + int column = columns[i]; + sort_pairs(begin, end, column); + int count = count_different_chars(begin, end, column); + if (count == end - begin) { return i; } + if (max_count < count) { + max_count = count; + max_index = i; + } + } + + if (max_index != L - 1) { + sort_pairs(begin, end, columns[max_index]); + } + + return max_index; + } + + private int count_different_chars(int begin, int end, int column) { + int chars_count = 0; + int cur_ch = -1; + for (; begin != end; ++begin) { + int ch = pairs[begin].id.charAt(column); + if (ch != cur_ch) { + ++chars_count; cur_ch = ch; + } + } + return chars_count; + } + + private void check_all_is_different(int begin, int end) { + if (begin != end) { + IdValuePair prev = pairs[begin]; + while (++begin != end) { + IdValuePair current = pairs[begin]; + if (prev.id.equals(current.id)) { + throw on_same_pair_fail(prev, current); + } + prev = current; + } + } + } + + private EvaluatorException on_same_pair_fail(IdValuePair a, IdValuePair b) { + int line1 = a.getLineNumber(), line2 = b.getLineNumber(); + if (line2 > line1) { int tmp = line1; line1 = line2; line2 = tmp; } + String error_text = ToolErrorReporter.getMessage( + "msg.idswitch.same_string", a.id, new Integer(line2)); + return R.runtimeError(error_text, source_file, line1, null, 0); + } + + private void sort_pairs(int begin, int end, int comparator) { + heap4Sort(pairs, begin, end - begin, comparator); + } + + private static boolean bigger + (IdValuePair a, IdValuePair b, int comparator) + { + if (comparator < 0) { + // For length selection switch it is enough to compare just length, + // but to detect same strings full comparison is essential + //return a.idLength > b.idLength; + int diff = a.idLength - b.idLength; + if (diff != 0) { return diff > 0; } + return a.id.compareTo(b.id) > 0; + } + else { + return a.id.charAt(comparator) > b.id.charAt(comparator); + } + } + + private static void heap4Sort + (IdValuePair[] array, int offset, int size, int comparator) + { + if (size <= 1) { return; } + makeHeap4(array, offset, size, comparator); + while (size > 1) { + --size; + IdValuePair v1 = array[offset + size]; + IdValuePair v2 = array[offset + 0]; + array[offset + size] = v2; + array[offset + 0] = v1; + heapify4(array, offset, size, 0, comparator); + } + } + + private static void makeHeap4 + (IdValuePair[] array, int offset, int size, int comparator) + { + for (int i = ((size + 2) >> 2); i != 0;) { + --i; + heapify4(array, offset, size, i, comparator); + } + } + + private static void heapify4 + (IdValuePair[] array, int offset, int size, int i, int comparator) + { + int new_i1, new_i2, new_i3; + IdValuePair i_val = array[offset + i]; + for (;;) { + int base = (i << 2); + new_i1 = base | 1; + new_i2 = base | 2; + new_i3 = base | 3; + int new_i4 = base + 4; + if (new_i4 >= size) { break; } + IdValuePair val1 = array[offset + new_i1]; + IdValuePair val2 = array[offset + new_i2]; + IdValuePair val3 = array[offset + new_i3]; + IdValuePair val4 = array[offset + new_i4]; + if (bigger(val2, val1, comparator)) { + val1 = val2; new_i1 = new_i2; + } + if (bigger(val4, val3, comparator)) { + val3 = val4; new_i3 = new_i4; + } + if (bigger(val3, val1, comparator)) { + val1 = val3; new_i1 = new_i3; + } + if (bigger(i_val, val1, comparator)) { return; } + array[offset + i] = val1; + array[offset + new_i1] = i_val; + i = new_i1; + } + if (new_i1 < size) { + IdValuePair val1 = array[offset + new_i1]; + if (new_i2 != size) { + IdValuePair val2 = array[offset + new_i2]; + if (bigger(val2, val1, comparator)) { + val1 = val2; new_i1 = new_i2; + } + if (new_i3 != size) { + IdValuePair val3 = array[offset + new_i3]; + if (bigger(val3, val1, comparator)) { + val1 = val3; new_i1 = new_i3; + } + } + } + if (bigger(val1, i_val, comparator)) { + array[offset + i] = val1; + array[offset + new_i1] = i_val; + } + } + } +} -- cgit v1.2.3