jscover.mozilla.javascript.tools.idswitch.Main Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of rhino Show documentation
Show all versions of rhino Show documentation
Rhino is an open-source implementation of JavaScript written entirely in
Java. It is typically embedded into Java applications to provide
scripting to end users.
/* -*- Mode: java; tab-width: 4; indent-tabs-mode: 1; c-basic-offset: 4 -*-
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
package jscover.mozilla.javascript.tools.idswitch;
import java.io.*;
import java.util.*;
import java.text.SimpleDateFormat;
import jscover.mozilla.javascript.EvaluatorException;
import jscover.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 List all_pairs = new ArrayList();
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.clear();
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.toArray(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.add(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;
}
}