зеркало из https://github.com/mozilla/pjs.git
Add idswitch package.
This commit is contained in:
Родитель
5c6de514ee
Коммит
e479370659
|
@ -0,0 +1,209 @@
|
|||
/* -*- Mode: java; tab-width: 4; indent-tabs-mode: 1; c-basic-offset: 4 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape 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/NPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS
|
||||
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr
|
||||
* 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 Netscape are
|
||||
* Copyright (C) 1997-1999 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Igor Bukanov
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the
|
||||
* terms of the GNU Public License (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 NPL, indicate your decision by
|
||||
* deleting the provisions above and replace 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 NPL or the GPL.
|
||||
*/
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,188 @@
|
|||
/* -*- Mode: java; tab-width: 4; indent-tabs-mode: 1; c-basic-offset: 4 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape 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/NPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS
|
||||
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr
|
||||
* 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 Netscape are
|
||||
* Copyright (C) 1997-1999 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Igor Bukanov
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the
|
||||
* terms of the GNU Public License (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 NPL, indicate your decision by
|
||||
* deleting the provisions above and replace 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 NPL or the GPL.
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,55 @@
|
|||
/* -*- Mode: java; tab-width: 4; indent-tabs-mode: 1; c-basic-offset: 4 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape 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/NPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS
|
||||
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr
|
||||
* 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 Netscape are
|
||||
* Copyright (C) 1997-1999 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Igor Bukanov
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the
|
||||
* terms of the GNU Public License (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 NPL, indicate your decision by
|
||||
* deleting the provisions above and replace 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 NPL or the GPL.
|
||||
*/
|
||||
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; }
|
||||
}
|
||||
|
|
@ -0,0 +1,504 @@
|
|||
/* -*- Mode: java; tab-width: 4; indent-tabs-mode: 1; c-basic-offset: 4 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape 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/NPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS
|
||||
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr
|
||||
* 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 Netscape are
|
||||
* Copyright (C) 1997-1999 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Igor Bukanov
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the
|
||||
* terms of the GNU Public License (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 NPL, indicate your decision by
|
||||
* deleting the provisions above and replace 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 NPL or the GPL.
|
||||
*/
|
||||
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 StringIdMap {
|
||||
|
||||
private static final String PROGRAM_NAME = "StringIdMap";
|
||||
|
||||
private static final String SWITCH_TAG_STR = "string_id_map";
|
||||
private static final String GENERATED_TAG_STR = "generated";
|
||||
|
||||
private static final int
|
||||
NORMAL_LINE = 0,
|
||||
SWITCH_TAG = 1,
|
||||
GENERATED_TAG = 2;
|
||||
|
||||
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 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() throws IOException {
|
||||
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();
|
||||
L: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 0:
|
||||
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);
|
||||
}
|
||||
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 = R.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 = R.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");
|
||||
String dateString = f.format(new Date());
|
||||
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);
|
||||
if (cursor + 2 <= end) {
|
||||
if (array[cursor] == '/' || array[cursor + 1] == '/') {
|
||||
cursor += 2;
|
||||
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 == '#' || is_white_space(c)) { break; }
|
||||
}
|
||||
|
||||
if (cursor != end) {
|
||||
int tag_end = cursor;
|
||||
cursor = skip_white_space(array, cursor, end);
|
||||
if (cursor != end && array[cursor] == '#') {
|
||||
id = get_tag_id(array, tag_start, tag_end);
|
||||
if (id != 0) {
|
||||
if (end_tag) { id = -id; }
|
||||
tag_definition_end = cursor + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return id;
|
||||
}
|
||||
|
||||
private int get_tag_id(char[] array, int begin, int end) {
|
||||
if (equals(SWITCH_TAG_STR, array, begin, end)) {
|
||||
return SWITCH_TAG;
|
||||
}
|
||||
if (equals(GENERATED_TAG_STR, array, begin, end)) {
|
||||
return GENERATED_TAG;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
private void look_for_id_definitions(char[] array, int begin, int end)
|
||||
{
|
||||
// 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 begining
|
||||
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] == '=') {
|
||||
// Got the match
|
||||
add_id(array, id_start, name_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) {
|
||||
StringIdMap self = new StringIdMap();
|
||||
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(R.getMessage
|
||||
("msg.idswitch.no_file_argument"));
|
||||
return -1;
|
||||
}
|
||||
if (arg_count > 1) {
|
||||
option_error(R.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(R.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(R.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(R.getMessage
|
||||
("msg.idswitch.bad_option_char",
|
||||
"" + 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(R.getMessage("msg.idswitch.usage"));
|
||||
System.out.println();
|
||||
}
|
||||
|
||||
private void show_version() {
|
||||
System.out.println(R.getMessage("msg.idswitch.version"));
|
||||
}
|
||||
|
||||
private void option_error(String str) {
|
||||
print_error(R.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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,485 @@
|
|||
/* -*- Mode: java; tab-width: 4; indent-tabs-mode: 1; c-basic-offset: 4 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape 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/NPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS
|
||||
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr
|
||||
* 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 Netscape are
|
||||
* Copyright (C) 1997-1999 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Igor Bukanov
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the
|
||||
* terms of the GNU Public License (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 NPL, indicate your decision by
|
||||
* deleting the provisions above and replace 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 NPL or the GPL.
|
||||
*/
|
||||
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();
|
||||
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) {
|
||||
StringBuffer sb = new StringBuffer();
|
||||
int line1 = a.getLineNumber(), line2 = b.getLineNumber();
|
||||
if (line2 > line1) { int tmp = line1; line1 = line2; line2 = tmp; }
|
||||
String error_text = R.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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Загрузка…
Ссылка в новой задаче