mirror of
https://github.com/decatur/j2js-compiler.git
synced 2025-01-18 12:25:42 +01:00
first commit
This commit is contained in:
commit
089e0cf208
12
.classpath
Normal file
12
.classpath
Normal file
@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<classpath>
|
||||
<classpathentry kind="src" path="src/main/resources"/>
|
||||
<classpathentry kind="src" output="target/test-classes" path="src/test/resources"/>
|
||||
<classpathentry kind="src" output="target/test-classes" path="src/test/java"/>
|
||||
<classpathentry kind="src" path="src/main/java"/>
|
||||
<classpathentry exported="true" kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
|
||||
<classpathentry kind="con" path="org.eclipse.jdt.junit.JUNIT_CONTAINER/4"/>
|
||||
<classpathentry kind="lib" path="libs/commons-io-1.4.jar"/>
|
||||
<classpathentry kind="lib" path="libs/bcel-5.1.jar"/>
|
||||
<classpathentry kind="output" path="target/classes"/>
|
||||
</classpath>
|
7
.gitignore
vendored
Normal file
7
.gitignore
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
git.txt
|
||||
pom.xml
|
||||
src/main/resources/META-INF/*
|
||||
src/site/**/*
|
||||
src/test/**/*
|
||||
launchConfig/**/*
|
||||
target/**/*
|
17
.project
Normal file
17
.project
Normal file
@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<projectDescription>
|
||||
<name>j2js-compiler</name>
|
||||
<comment></comment>
|
||||
<projects>
|
||||
</projects>
|
||||
<buildSpec>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.jdt.core.javabuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
</buildSpec>
|
||||
<natures>
|
||||
<nature>org.eclipse.jdt.core.javanature</nature>
|
||||
</natures>
|
||||
</projectDescription>
|
271
.settings/org.eclipse.jdt.core.prefs
Normal file
271
.settings/org.eclipse.jdt.core.prefs
Normal file
@ -0,0 +1,271 @@
|
||||
#Wed Sep 03 00:07:36 CEST 2008
|
||||
eclipse.preferences.version=1
|
||||
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
|
||||
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.5
|
||||
org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
|
||||
org.eclipse.jdt.core.compiler.compliance=1.5
|
||||
org.eclipse.jdt.core.compiler.debug.lineNumber=generate
|
||||
org.eclipse.jdt.core.compiler.debug.localVariable=generate
|
||||
org.eclipse.jdt.core.compiler.debug.sourceFile=generate
|
||||
org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
|
||||
org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
|
||||
org.eclipse.jdt.core.compiler.source=1.5
|
||||
org.eclipse.jdt.core.formatter.align_type_members_on_columns=false
|
||||
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=16
|
||||
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=16
|
||||
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call=16
|
||||
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation=16
|
||||
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression=16
|
||||
org.eclipse.jdt.core.formatter.alignment_for_assignment=0
|
||||
org.eclipse.jdt.core.formatter.alignment_for_binary_expression=16
|
||||
org.eclipse.jdt.core.formatter.alignment_for_compact_if=16
|
||||
org.eclipse.jdt.core.formatter.alignment_for_conditional_expression=80
|
||||
org.eclipse.jdt.core.formatter.alignment_for_enum_constants=0
|
||||
org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer=16
|
||||
org.eclipse.jdt.core.formatter.alignment_for_multiple_fields=16
|
||||
org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration=16
|
||||
org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration=16
|
||||
org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation=16
|
||||
org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration=16
|
||||
org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration=16
|
||||
org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration=16
|
||||
org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration=16
|
||||
org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration=16
|
||||
org.eclipse.jdt.core.formatter.blank_lines_after_imports=1
|
||||
org.eclipse.jdt.core.formatter.blank_lines_after_package=1
|
||||
org.eclipse.jdt.core.formatter.blank_lines_before_field=1
|
||||
org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration=0
|
||||
org.eclipse.jdt.core.formatter.blank_lines_before_imports=1
|
||||
org.eclipse.jdt.core.formatter.blank_lines_before_member_type=1
|
||||
org.eclipse.jdt.core.formatter.blank_lines_before_method=1
|
||||
org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk=1
|
||||
org.eclipse.jdt.core.formatter.blank_lines_before_package=0
|
||||
org.eclipse.jdt.core.formatter.blank_lines_between_import_groups=1
|
||||
org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations=1
|
||||
org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration=end_of_line
|
||||
org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration=end_of_line
|
||||
org.eclipse.jdt.core.formatter.brace_position_for_array_initializer=end_of_line
|
||||
org.eclipse.jdt.core.formatter.brace_position_for_block=end_of_line
|
||||
org.eclipse.jdt.core.formatter.brace_position_for_block_in_case=end_of_line
|
||||
org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration=end_of_line
|
||||
org.eclipse.jdt.core.formatter.brace_position_for_enum_constant=end_of_line
|
||||
org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration=end_of_line
|
||||
org.eclipse.jdt.core.formatter.brace_position_for_method_declaration=end_of_line
|
||||
org.eclipse.jdt.core.formatter.brace_position_for_switch=end_of_line
|
||||
org.eclipse.jdt.core.formatter.brace_position_for_type_declaration=end_of_line
|
||||
org.eclipse.jdt.core.formatter.comment.clear_blank_lines=false
|
||||
org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment=false
|
||||
org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment=false
|
||||
org.eclipse.jdt.core.formatter.comment.format_block_comments=true
|
||||
org.eclipse.jdt.core.formatter.comment.format_comments=true
|
||||
org.eclipse.jdt.core.formatter.comment.format_header=false
|
||||
org.eclipse.jdt.core.formatter.comment.format_html=true
|
||||
org.eclipse.jdt.core.formatter.comment.format_javadoc_comments=true
|
||||
org.eclipse.jdt.core.formatter.comment.format_line_comments=true
|
||||
org.eclipse.jdt.core.formatter.comment.format_source_code=true
|
||||
org.eclipse.jdt.core.formatter.comment.indent_parameter_description=true
|
||||
org.eclipse.jdt.core.formatter.comment.indent_root_tags=true
|
||||
org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags=insert
|
||||
org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter=insert
|
||||
org.eclipse.jdt.core.formatter.comment.line_length=80
|
||||
org.eclipse.jdt.core.formatter.compact_else_if=true
|
||||
org.eclipse.jdt.core.formatter.continuation_indentation=2
|
||||
org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer=2
|
||||
org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line=false
|
||||
org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header=true
|
||||
org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header=true
|
||||
org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header=true
|
||||
org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header=true
|
||||
org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases=true
|
||||
org.eclipse.jdt.core.formatter.indent_empty_lines=false
|
||||
org.eclipse.jdt.core.formatter.indent_statements_compare_to_block=true
|
||||
org.eclipse.jdt.core.formatter.indent_statements_compare_to_body=true
|
||||
org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases=true
|
||||
org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch=false
|
||||
org.eclipse.jdt.core.formatter.indentation.size=4
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation=insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable=insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_member=insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_in_empty_annotation_declaration=insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_in_empty_anonymous_type_declaration=insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_in_empty_block=insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_constant=insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_declaration=insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_in_empty_method_body=insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_in_empty_type_declaration=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_binary_operator=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_ellipsis=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_unary_operator=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_binary_operator=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_ellipsis=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_semicolon=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_unary_operator=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation=do not insert
|
||||
org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line=false
|
||||
org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line=false
|
||||
org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line=false
|
||||
org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line=false
|
||||
org.eclipse.jdt.core.formatter.lineSplit=80
|
||||
org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column=false
|
||||
org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column=false
|
||||
org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body=0
|
||||
org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve=1
|
||||
org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line=true
|
||||
org.eclipse.jdt.core.formatter.tabulation.char=space
|
||||
org.eclipse.jdt.core.formatter.tabulation.size=4
|
||||
org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations=false
|
||||
org.eclipse.jdt.core.formatter.wrap_before_binary_operator=true
|
6
.settings/org.eclipse.jdt.ui.prefs
Normal file
6
.settings/org.eclipse.jdt.ui.prefs
Normal file
@ -0,0 +1,6 @@
|
||||
#Wed Sep 03 00:07:35 CEST 2008
|
||||
eclipse.preferences.version=1
|
||||
formatter_profile=_MyProfile
|
||||
formatter_settings_version=11
|
||||
internal.default.compliance=default
|
||||
org.eclipse.jdt.ui.text.custom_code_templates=<?xml version\="1.0" encoding\="UTF-8"?><templates><template autoinsert\="true" context\="gettercomment_context" deleted\="false" description\="Comment for getter method" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.gettercomment" name\="gettercomment">/**\r\n * @return Returns the ${bare_field_name}.\r\n */</template><template autoinsert\="true" context\="settercomment_context" deleted\="false" description\="Comment for setter method" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.settercomment" name\="settercomment">/**\r\n * @param ${param} The ${bare_field_name} to set.\r\n */</template><template autoinsert\="true" context\="constructorcomment_context" deleted\="false" description\="Comment for created constructors" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.constructorcomment" name\="constructorcomment">/**\r\n * ${tags}\r\n */</template><template autoinsert\="true" context\="filecomment_context" deleted\="false" description\="Comment for created Java files" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.filecomment" name\="filecomment">/**\r\n * \r\n */</template><template autoinsert\="true" context\="typecomment_context" deleted\="false" description\="Comment for created types" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.typecomment" name\="typecomment">/**\r\n * @author ${user}\r\n *\r\n * ${tags}\r\n */</template><template autoinsert\="true" context\="fieldcomment_context" deleted\="false" description\="Comment for fields" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.fieldcomment" name\="fieldcomment">/**\r\n * \r\n */</template><template autoinsert\="true" context\="methodcomment_context" deleted\="false" description\="Comment for non-overriding methods" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.methodcomment" name\="methodcomment">/**\r\n * ${tags}\r\n */</template><template autoinsert\="true" context\="overridecomment_context" deleted\="false" description\="Comment for overriding methods" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.overridecomment" name\="overridecomment">/* (non-Javadoc)\r\n * ${see_to_overridden}\r\n */</template><template autoinsert\="true" context\="newtype_context" deleted\="false" description\="Newly created files" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.newtype" name\="newtype">${filecomment}\r\n${package_declaration}\r\n\r\n${typecomment}\r\n${type_declaration}</template><template autoinsert\="true" context\="catchblock_context" deleted\="false" description\="Code in new catch blocks" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.catchblock" name\="catchblock">// ${todo} Auto-generated catch block\r\n${exception_var}.printStackTrace();</template><template autoinsert\="true" context\="methodbody_context" deleted\="false" description\="Code in created method stubs" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.methodbody" name\="methodbody">// ${todo} Auto-generated method stub\r\n${body_statement}</template><template autoinsert\="true" context\="constructorbody_context" deleted\="false" description\="Code in created constructor stubs" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.constructorbody" name\="constructorbody">${body_statement}\r\n// ${todo} Auto-generated constructor stub</template><template autoinsert\="true" context\="getterbody_context" deleted\="false" description\="Code in created getters" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.getterbody" name\="getterbody">return ${field};</template><template autoinsert\="true" context\="setterbody_context" deleted\="false" description\="Code in created setters" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.setterbody" name\="setterbody">${field} \= ${param};</template></templates>
|
6
.settings/org.eclipse.wst.validation.prefs
Normal file
6
.settings/org.eclipse.wst.validation.prefs
Normal file
@ -0,0 +1,6 @@
|
||||
#Wed Oct 24 00:47:12 CEST 2007
|
||||
DELEGATES_PREFERENCE=delegateValidatorListorg.eclipse.wst.wsdl.validation.internal.eclipse.WSDLDelegatingValidator\=org.eclipse.wst.wsdl.validation.internal.eclipse.Validator;org.eclipse.wst.xsd.core.internal.validation.eclipse.XSDDelegatingValidator\=org.eclipse.wst.xsd.core.internal.validation.eclipse.Validator;
|
||||
USER_BUILD_PREFERENCE=enabledBuildValidatorListorg.eclipse.wst.dtd.core.internal.validation.eclipse.Validator;org.eclipse.wst.xsd.core.internal.validation.eclipse.XSDDelegatingValidator;org.eclipse.wst.html.internal.validation.HTMLValidator;org.eclipse.jst.jsp.core.internal.validation.JSPBatchValidator;org.eclipse.wst.xml.core.internal.validation.eclipse.Validator;org.eclipse.wst.wsi.ui.internal.WSIMessageValidator;org.eclipse.wst.wsdl.validation.internal.eclipse.WSDLDelegatingValidator;
|
||||
USER_MANUAL_PREFERENCE=enabledManualValidatorListorg.eclipse.wst.dtd.core.internal.validation.eclipse.Validator;org.eclipse.wst.xsd.core.internal.validation.eclipse.XSDDelegatingValidator;org.eclipse.wst.html.internal.validation.HTMLValidator;org.eclipse.jst.jsp.core.internal.validation.JSPBatchValidator;org.eclipse.wst.xml.core.internal.validation.eclipse.Validator;org.eclipse.wst.wsi.ui.internal.WSIMessageValidator;org.eclipse.wst.wsdl.validation.internal.eclipse.WSDLDelegatingValidator;
|
||||
USER_PREFERENCE=overrideGlobalPreferencesfalse
|
||||
eclipse.preferences.version=1
|
21
LICENSE
Normal file
21
LICENSE
Normal file
@ -0,0 +1,21 @@
|
||||
A FreeBSD Licence
|
||||
|
||||
Copyright(c) 2011, the j2js Project. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification, are permitted provided
|
||||
that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this list of conditions and
|
||||
the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions
|
||||
and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE FREEBSD PROJECT ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FREEBSD
|
||||
PROJECT OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
3
README.md
Normal file
3
README.md
Normal file
@ -0,0 +1,3 @@
|
||||
#j2js-compiler
|
||||
|
||||
A Java Bytecode to JavaScript Cross-Compiler.
|
BIN
libs/bcel-5.1.jar
Normal file
BIN
libs/bcel-5.1.jar
Normal file
Binary file not shown.
BIN
libs/commons-io-1.4.jar
Normal file
BIN
libs/commons-io-1.4.jar
Normal file
Binary file not shown.
40
src/main/java/Checker.java
Normal file
40
src/main/java/Checker.java
Normal file
@ -0,0 +1,40 @@
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileReader;
|
||||
import java.util.HashSet;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import com.j2js.Const;
|
||||
|
||||
/**
|
||||
* Copyright by Wolfgang Kuehn 2005
|
||||
* Created on Feb 27, 2005
|
||||
*/
|
||||
public class Checker {
|
||||
public static void main(String argv[]) throws Exception {
|
||||
BufferedReader reader = new BufferedReader(new FileReader(new File("src/com/j2js/Pass1.java")));
|
||||
Pattern p = Pattern.compile(".*case\\s+Const\\.(\\w*)\\s*:.*");
|
||||
HashSet<String> set = new HashSet<String>();
|
||||
|
||||
String line;
|
||||
while ((line=reader.readLine())!=null) {
|
||||
Matcher m = p.matcher(line);
|
||||
if (m.matches()) {
|
||||
String name = m.group(1);
|
||||
//System.out.println("Adding " + name);
|
||||
set.add(name);
|
||||
}
|
||||
}
|
||||
|
||||
int missingCount = 0;
|
||||
for (int i=0; i<Const.instructionTypes.length; i++) {
|
||||
String name = Const.instructionTypes[i].getName();
|
||||
if (!set.contains(name.toUpperCase())) {
|
||||
missingCount++;
|
||||
System.out.println(name.toUpperCase());
|
||||
}
|
||||
}
|
||||
System.out.println("Missing count: " + missingCount);
|
||||
}
|
||||
}
|
67
src/main/java/Enhancer.java
Normal file
67
src/main/java/Enhancer.java
Normal file
@ -0,0 +1,67 @@
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileReader;
|
||||
import java.io.FileWriter;
|
||||
import java.util.Date;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import com.j2js.Const;
|
||||
import com.j2js.Form;
|
||||
import com.j2js.InstructionType;
|
||||
|
||||
/**
|
||||
* Copyright by Wolfgang Kuehn 2005
|
||||
* Created on Feb 27, 2005
|
||||
*/
|
||||
public class Enhancer {
|
||||
public static void main(String argv[]) throws Exception {
|
||||
File source = new File("src/com/j2js/Pass1.java");
|
||||
File temp = new File("temp/Pass1_" + new Date().getTime() + ".java");
|
||||
if (!source.renameTo(temp)) {
|
||||
throw new RuntimeException("Could not move " + source + " to "+ temp);
|
||||
}
|
||||
BufferedReader reader = new BufferedReader(new FileReader(temp));
|
||||
FileWriter writer = new FileWriter(source);
|
||||
Pattern p = Pattern.compile(".*case\\s+Const\\.(\\w*)\\s*:.*");
|
||||
|
||||
String line;
|
||||
while ((line=reader.readLine())!=null) {
|
||||
Matcher m = p.matcher(line);
|
||||
if (m.matches()) {
|
||||
String name = m.group(1);
|
||||
System.out.println("Enhancing " + name);
|
||||
int index = ((Integer) Const.class.getField(name).get(null)).intValue();
|
||||
InstructionType it = Const.instructionTypes[index];
|
||||
|
||||
for (int i=0; i<it.getFormCount(); i++) {
|
||||
Form form = it.getForm(i);
|
||||
// Discard previously generated code.
|
||||
reader.readLine();
|
||||
reader.readLine();
|
||||
String head = "\n //";
|
||||
if (it.getFormCount() > 1) {
|
||||
head += " (" + i + ")";
|
||||
}
|
||||
line += head + " Format: " + it.getName();
|
||||
for (int j=0; j<form.getOperands().length; j++) {
|
||||
Form.Value value = form.getOperands()[j];
|
||||
line += ", " + value.name + "(" + value.type + ")";
|
||||
}
|
||||
line += head + " Operand stack: ...";
|
||||
for (int j=0; j<form.getIns().length; j++) {
|
||||
Form.Value value = form.getIns()[j];
|
||||
line += ", " + value.name + "(" + value.type + ")";
|
||||
}
|
||||
line += " -> ...";
|
||||
for (int j=0; j<form.getOuts().length; j++) {
|
||||
Form.Value value = form.getOuts()[j];
|
||||
line += ", " + value.name + "(" + value.type + ")";
|
||||
}
|
||||
}
|
||||
}
|
||||
writer.write(line + "\n");
|
||||
}
|
||||
writer.close();
|
||||
}
|
||||
}
|
62
src/main/java/com/j2js/ASTNodeStack.java
Normal file
62
src/main/java/com/j2js/ASTNodeStack.java
Normal file
@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Created on 20.09.2005
|
||||
*/
|
||||
package com.j2js;
|
||||
|
||||
import com.j2js.J2JSCompiler;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import com.j2js.dom.ASTNode;
|
||||
import com.j2js.dom.Expression;
|
||||
|
||||
/**
|
||||
* @author wolfgang
|
||||
*/
|
||||
public class ASTNodeStack extends ArrayList<ASTNode> {
|
||||
|
||||
public ASTNodeStack() {
|
||||
super();
|
||||
}
|
||||
|
||||
public ASTNodeStack(ASTNodeStack other) {
|
||||
super(other);
|
||||
}
|
||||
|
||||
public ASTNodeStack(Expression expression) {
|
||||
super();
|
||||
push(expression);
|
||||
}
|
||||
|
||||
public Expression pop() {
|
||||
if (size() == 0) throw new RuntimeException("Cannot pop empty stack");
|
||||
return (Expression) remove(size() - 1);
|
||||
}
|
||||
|
||||
public void push(ASTNode node) {
|
||||
add(node);
|
||||
}
|
||||
|
||||
public void rotate(int offset) {
|
||||
if (offset == 0) return;
|
||||
if (offset > size()) throw new IndexOutOfBoundsException();
|
||||
ASTNode node = pop();
|
||||
add(size()-offset, node);
|
||||
}
|
||||
|
||||
public Expression peek() {
|
||||
return peek(0);
|
||||
}
|
||||
|
||||
private static Object safeCast(Object object, Class clazz) {
|
||||
if (!clazz.isInstance(object)) {
|
||||
throw new RuntimeException("Expected " + clazz + ", but was " + object);
|
||||
}
|
||||
return object;
|
||||
}
|
||||
|
||||
public Expression peek(int offset) {
|
||||
if (size()-1 < offset) return null;
|
||||
return (Expression) ASTNodeStack.safeCast(get(size()-1-offset), Expression.class);
|
||||
}
|
||||
}
|
28
src/main/java/com/j2js/AnnotationAttribute.java
Normal file
28
src/main/java/com/j2js/AnnotationAttribute.java
Normal file
@ -0,0 +1,28 @@
|
||||
package com.j2js;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.bcel.classfile.Attribute;
|
||||
import org.apache.bcel.classfile.ConstantPool;
|
||||
import org.apache.bcel.classfile.Visitor;
|
||||
|
||||
public class AnnotationAttribute extends Attribute {
|
||||
|
||||
Map<String, String>[] annotations;
|
||||
|
||||
protected AnnotationAttribute(byte tag, int nameIndex, int length, ConstantPool constantPool) {
|
||||
super(tag, nameIndex, length, constantPool);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accept(Visitor arg0) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public Attribute copy(ConstantPool arg0) {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
}
|
58
src/main/java/com/j2js/AnnotationReader.java
Normal file
58
src/main/java/com/j2js/AnnotationReader.java
Normal file
@ -0,0 +1,58 @@
|
||||
package com.j2js;
|
||||
|
||||
import java.io.DataInputStream;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.bcel.classfile.Attribute;
|
||||
import org.apache.bcel.classfile.AttributeReader;
|
||||
import org.apache.bcel.classfile.Constant;
|
||||
import org.apache.bcel.classfile.ConstantPool;
|
||||
import org.apache.bcel.classfile.ConstantUtf8;
|
||||
|
||||
import com.j2js.assembly.ClassUnit;
|
||||
import com.j2js.assembly.Project;
|
||||
import com.j2js.assembly.Signature;
|
||||
|
||||
public class AnnotationReader implements AttributeReader{
|
||||
|
||||
private ClassUnit classUnit;
|
||||
|
||||
public AnnotationReader(ClassUnit theClassUnit) {
|
||||
classUnit = theClassUnit;
|
||||
}
|
||||
|
||||
public Attribute createAttribute(int name_index, int length, DataInputStream file, ConstantPool constantPool) {
|
||||
Map<String, String>[] annotations = null;
|
||||
// TODO: Annotation
|
||||
try {
|
||||
int attCount = file.readUnsignedShort();
|
||||
annotations = new HashMap[attCount];
|
||||
for (int j=0; j<attCount; j++) {
|
||||
HashMap<String, String> map = new HashMap<String, String>();
|
||||
annotations[j] = map;
|
||||
int nameIndex = file.readUnsignedShort();
|
||||
Constant constant = constantPool.getConstant(nameIndex);
|
||||
Signature signature = Project.getSingleton().getSignature(((ConstantUtf8) constant).getBytes());
|
||||
map.put("$signature", signature.toString());
|
||||
int fieldCount = file.readUnsignedShort();
|
||||
for (int i=0; i<fieldCount; i++) {
|
||||
int fieldIndex = file.readUnsignedShort();
|
||||
constant = constantPool.getConstant(fieldIndex);
|
||||
String key = ((ConstantUtf8) constant).getBytes();
|
||||
byte b = file.readByte();
|
||||
fieldIndex = file.readUnsignedShort();
|
||||
constant = constantPool.getConstant(fieldIndex);
|
||||
String value = Pass1.constantToString(constant, constantPool);
|
||||
map.put(key, value);
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
}
|
||||
|
||||
AnnotationAttribute att = new AnnotationAttribute((byte) 0, name_index, length, constantPool);
|
||||
att.annotations = annotations;
|
||||
classUnit.annotations = annotations;
|
||||
return att;
|
||||
}
|
||||
}
|
435
src/main/java/com/j2js/Assembly.java
Normal file
435
src/main/java/com/j2js/Assembly.java
Normal file
@ -0,0 +1,435 @@
|
||||
package com.j2js;
|
||||
|
||||
import com.j2js.J2JSCompiler;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileWriter;
|
||||
import java.io.FilenameFilter;
|
||||
import java.io.IOException;
|
||||
import java.io.Writer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
|
||||
import com.j2js.FileObject;
|
||||
import com.j2js.Log;
|
||||
import com.j2js.Utils;
|
||||
import com.j2js.assembly.ClassUnit;
|
||||
import com.j2js.assembly.ConstructorUnit;
|
||||
import com.j2js.assembly.JavaScriptCompressor;
|
||||
import com.j2js.assembly.JunkWriter;
|
||||
import com.j2js.assembly.MemberUnit;
|
||||
import com.j2js.assembly.ProcedureUnit;
|
||||
import com.j2js.assembly.Project;
|
||||
import com.j2js.assembly.Signature;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public class Assembly {
|
||||
|
||||
public List<String> entryPoints = new ArrayList<String>();
|
||||
|
||||
private final static String DECLARECLASS = "dcC";
|
||||
|
||||
private transient Log logger;
|
||||
|
||||
private transient String entryPointClassName;
|
||||
|
||||
private Project project;
|
||||
private Set<Signature> taintedSignatures = new HashSet<Signature>();
|
||||
private Set<Signature> unprocessedTaintedSignatures = new HashSet<Signature>();
|
||||
String[] patterns;
|
||||
private Collection<ClassUnit> resolvedTypes = new ArrayList<ClassUnit>();
|
||||
private transient File targetLocation;
|
||||
|
||||
public Assembly() {
|
||||
patterns = Utils.getProperty("j2js.taintIfInstantiated").split(";");
|
||||
for (int i=0; i<patterns.length; i++) {
|
||||
// Remove all whitespace, quote '.', '(', ')', and transform
|
||||
// '*' to '.*'.
|
||||
String pattern = patterns[i].replaceAll("\\s", "");
|
||||
pattern = pattern.replaceAll("\\.", "\\\\.");
|
||||
pattern = pattern.replaceAll("\\*", ".*");
|
||||
pattern = pattern.replaceAll("\\(", "\\\\(");
|
||||
pattern = pattern.replaceAll("\\)", "\\\\)");
|
||||
patterns[i] = pattern;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Pipes a file on the class path into a stream.
|
||||
*
|
||||
* @param writer the sream into which to pipe
|
||||
* @param classPath the array of directories in which to locate the file
|
||||
* @param relativeFilePath the name of the file
|
||||
*
|
||||
* @throws IOException
|
||||
*/
|
||||
private void pipeFileToStream(Writer writer, String relativeFilePath) throws IOException {
|
||||
FileObject fileObject = J2JSCompiler.compiler.fileManager.getFileForInput(relativeFilePath);
|
||||
String content;
|
||||
if (J2JSCompiler.compiler.isCompression()) {
|
||||
JavaScriptCompressor compressor = new JavaScriptCompressor();
|
||||
content = compressor.compress(fileObject.openInputStream());
|
||||
} else {
|
||||
content = IOUtils.toString(fileObject.openInputStream());
|
||||
}
|
||||
writer.write(content);
|
||||
}
|
||||
|
||||
private void removeOldAssemblies(File assembly) {
|
||||
final String numericPostfixPattern = "-[0-9]*$";
|
||||
final String prefix = assembly.getName().replaceAll(numericPostfixPattern, "");
|
||||
|
||||
File[] oldAssemblies = assembly.getParentFile().listFiles(new FilenameFilter() {
|
||||
public boolean accept(File dir1, String name) {
|
||||
return name.matches(prefix + numericPostfixPattern);
|
||||
}
|
||||
});
|
||||
|
||||
if (oldAssemblies == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (File oldAssemblyDir : oldAssemblies) {
|
||||
for (File file : oldAssemblyDir.listFiles()) {
|
||||
file.delete();
|
||||
}
|
||||
oldAssemblyDir.delete();
|
||||
}
|
||||
}
|
||||
|
||||
public int createAssembly() throws IOException {
|
||||
logger = Log.getLogger();
|
||||
logger.debug("Packing ...");
|
||||
|
||||
removeOldAssemblies(targetLocation);
|
||||
|
||||
String loaderName = J2JSCompiler.compiler.getTargetPlatform().toLowerCase();
|
||||
Writer writer;
|
||||
|
||||
if ("javascript".equals(loaderName)) {
|
||||
writer = new FileWriter(targetLocation);
|
||||
pipeFileToStream(writer, "javascript/loaders/" + loaderName + ".js");
|
||||
} else {
|
||||
targetLocation.mkdirs();
|
||||
writer = new JunkWriter(targetLocation);
|
||||
}
|
||||
writer.write("// Assembly generated by j2js " + Utils.getVersion() + " on " + Utils.currentTimeStamp() + "\n");
|
||||
pipeFileToStream(writer, "javascript/runtime.js");
|
||||
writer.write("j2js.assemblyVersion = 'j2js Assembly " + targetLocation.getName() + "@" + Utils.currentTimeStamp() + "';\n");
|
||||
|
||||
writer.write("j2js.userData = {};\n");
|
||||
|
||||
int classCount = 0;
|
||||
for (ClassUnit fileUnit : project.getClasses()) {
|
||||
if (!fileUnit.isTainted()) continue;
|
||||
writer.write("j2js.");
|
||||
writer.write(DECLARECLASS);
|
||||
writer.write("(\"" + fileUnit.getSignature() + "\"");
|
||||
writer.write(", " + fileUnit.getSignature().getId());
|
||||
writer.write(");\n");
|
||||
classCount++;
|
||||
}
|
||||
|
||||
project.currentGeneratedMethods = 0;
|
||||
|
||||
if (J2JSCompiler.compiler.getSingleEntryPoint() != null) {
|
||||
Signature signature = project.getSignature(J2JSCompiler.compiler.getSingleEntryPoint());
|
||||
ClassUnit clazz = project.getClassUnit(signature.className());
|
||||
clazz.write(0, writer);
|
||||
} else {
|
||||
ClassUnit object = project.getJavaLangObject();
|
||||
object.write(0, writer);
|
||||
|
||||
for (ClassUnit cu : project.getClasses()) {
|
||||
// TODO Interface: Generate them nicely.
|
||||
if (cu.isInterface) {
|
||||
cu.write(0, writer);
|
||||
}
|
||||
}
|
||||
|
||||
// for (ClassUnit cu : project.getClasses()) {
|
||||
// if (cu.isInterface && cu.getInterfaces().size() != 0) {
|
||||
// cu.write(0, writer);
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
if (getProject().getOrCreateClassUnit("java.lang.String").isTainted()) {
|
||||
writer.write("String.prototype.clazz = j2js.forName('java.lang.String');\n");
|
||||
}
|
||||
|
||||
writer.write("j2js.onLoad('" + entryPointClassName + "#main(java.lang.String[])void');\n");
|
||||
|
||||
// String resourcePath = J2JSCompiler.compiler.resourcePath;
|
||||
// if (resourcePath != null) {
|
||||
// resolveResources(new File(J2JSCompiler.compiler.getBaseDir(), resourcePath), writer);
|
||||
// }
|
||||
|
||||
writer.close();
|
||||
|
||||
if ("web".equals(loaderName)) {
|
||||
Writer loader = new FileWriter(new File(targetLocation, "/0.js"));
|
||||
loader.write("var j2js = {assemblySize:");
|
||||
loader.write(Integer.toString(((JunkWriter) writer).getSize()));
|
||||
loader.write("};\n");
|
||||
pipeFileToStream(loader, "javascript/loaders/" + loaderName + ".js");
|
||||
loader.close();
|
||||
}
|
||||
|
||||
return project.currentGeneratedMethods;
|
||||
}
|
||||
|
||||
// private void resolveResources(File resourcePath, Writer writer) throws FileNotFoundException, IOException {
|
||||
// File cssPath = new File(resourcePath, "/style.css");
|
||||
// BufferedReader reader = new BufferedReader(new FileReader(cssPath));
|
||||
// StringBuffer buffer = new StringBuffer();
|
||||
//
|
||||
// do {
|
||||
// String line = reader.readLine();
|
||||
// if (line == null) break;
|
||||
// buffer.append(line.trim());
|
||||
// buffer.append(" ");
|
||||
// } while (true);
|
||||
//
|
||||
// reader.close();
|
||||
//
|
||||
// writer.write("j2js.style = \"" + buffer.toString() + "\";\n");
|
||||
// }
|
||||
|
||||
// private void writeDependency() {
|
||||
// Iterator iter = taintedSignatures.iterator();
|
||||
// while (iter.hasNext()) {
|
||||
// Signature signature = (Signature) iter.next();
|
||||
// logger.fine(signature + " <- " + signature.referer);
|
||||
// }
|
||||
// }
|
||||
|
||||
public void processTainted() {
|
||||
while (unprocessedTaintedSignatures.size() > 0) {
|
||||
processSingle(popSignature());
|
||||
if (unprocessedTaintedSignatures.size() == 0) {
|
||||
processOverWrittenMembers();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void processSingle(Signature signature) {
|
||||
ClassUnit clazz = resolve(signature.className());
|
||||
String methodPart = signature.relativeSignature();
|
||||
boolean found = false;
|
||||
for (MemberUnit member : clazz.getMembers(methodPart)) {
|
||||
taint(member);
|
||||
found = true;
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
//logger.severe("No such method: " + signature);
|
||||
throw new RuntimeException("No such method: " + signature);
|
||||
}
|
||||
|
||||
// MemberUnit member = clazz.getMember(methodPart);
|
||||
// if (member != null) {
|
||||
// taint(member);
|
||||
// } else {
|
||||
// logger.severe("No such method: " + signature);
|
||||
// }
|
||||
}
|
||||
|
||||
private ClassUnit resolve(String className) {
|
||||
ClassUnit clazz = project.getOrCreateClassUnit(className);
|
||||
|
||||
if (className.startsWith("[")) {
|
||||
project.resolve(clazz);
|
||||
} else {
|
||||
project.resolve(clazz);
|
||||
taint(className + "#<clinit>()void");
|
||||
}
|
||||
|
||||
resolvedTypes.add(clazz);
|
||||
|
||||
return clazz;
|
||||
}
|
||||
|
||||
/**
|
||||
* Taint the signatures of methods matching a pattern.
|
||||
*/
|
||||
private void taintImplicitelyAccessedMembers(ClassUnit clazz) {
|
||||
// TODO: This method is called multiple times for each clazz. This
|
||||
// should not be the case!
|
||||
// System.out.println(clazz.toString());
|
||||
for (MemberUnit member : clazz.getDeclaredMembers()) {
|
||||
for (int i=0; i<patterns.length; i++) {
|
||||
if (member.getAbsoluteSignature().toString().matches(patterns[i])) {
|
||||
taint(member.getAbsoluteSignature());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Taints all members which overwrite another tainted member.
|
||||
*/
|
||||
private void taintIfSuperTainted(ClassUnit clazz) {
|
||||
if (clazz.getName().equals("java.lang.Object")) return;
|
||||
|
||||
for (MemberUnit member : clazz.getDeclaredMembers()) {
|
||||
for (ClassUnit superType : clazz.getSupertypes()) {
|
||||
Signature signature = Project.getSingleton().getSignature(superType.getName(), member.getSignature().toString());
|
||||
if (taintedSignatures.contains(signature)) {
|
||||
taint(member);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Taint all signatures targeted by the specified method.
|
||||
*/
|
||||
private void taintTargetSignatures(ProcedureUnit method) {
|
||||
for (Signature targetSignature : method.getTargetSignatures()) {
|
||||
taint(targetSignature);
|
||||
}
|
||||
}
|
||||
|
||||
private void processOverWrittenMembers() {
|
||||
Iterator<ClassUnit> classIterator = resolvedTypes.iterator();
|
||||
while (classIterator.hasNext()) {
|
||||
ClassUnit clazz = classIterator.next();
|
||||
if (clazz.isConstructorTainted) taintIfSuperTainted(clazz);;
|
||||
}
|
||||
}
|
||||
|
||||
public void taint(String signature) {
|
||||
signature = signature.replaceAll("\\s", "");
|
||||
// if (signature.indexOf('*') != -1) {
|
||||
// if (!signature.endsWith(".*")) {
|
||||
// throw new RuntimeException("Package signature must end with '.*'");
|
||||
// }
|
||||
// signature = signature.substring(0, signature.length()-2);
|
||||
// File[] files = Utils.resolvePackage(J2JSCompiler.compiler.getClassPath(), signature);
|
||||
// for (int i=0; i<files.length; i++) {
|
||||
// String name = files[i].getName();
|
||||
// if (name.endsWith(".class")) {
|
||||
// taint(signature + '.' + name.substring(0, name.length()-6));
|
||||
// }
|
||||
// }
|
||||
// } else {
|
||||
Signature s = Project.getSingleton().getSignature(signature);
|
||||
if (s.isClass()) {
|
||||
ClassUnit clazz = resolve(s.className());
|
||||
for (MemberUnit member : clazz.getDeclaredMembers()) {
|
||||
taint(member.getAbsoluteSignature());
|
||||
}
|
||||
} else {
|
||||
taint(s);
|
||||
}
|
||||
// }
|
||||
}
|
||||
|
||||
private Signature popSignature() {
|
||||
Iterator<Signature> iter = unprocessedTaintedSignatures.iterator();
|
||||
Signature signature = iter.next();
|
||||
iter.remove();
|
||||
return signature;
|
||||
}
|
||||
|
||||
public void taint(Signature signature) {
|
||||
if (!signature.toString().contains("#")) {
|
||||
throw new IllegalArgumentException("Signature must be field or method: " + signature);
|
||||
}
|
||||
|
||||
if (taintedSignatures.contains(signature)) return;
|
||||
|
||||
taintedSignatures.add(signature);
|
||||
unprocessedTaintedSignatures.add(signature);
|
||||
}
|
||||
|
||||
public void taint(MemberUnit member) {
|
||||
member.setTainted();
|
||||
// TODO: Tainting super types in neccesary for generating only?
|
||||
member.getDeclaringClass().setSuperTainted();
|
||||
if (member instanceof ProcedureUnit) {
|
||||
taintTargetSignatures((ProcedureUnit) member);
|
||||
if (member instanceof ConstructorUnit) {
|
||||
member.getDeclaringClass().isConstructorTainted = true;
|
||||
taintImplicitelyAccessedMembers(member.getDeclaringClass());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see #getProject()
|
||||
*/
|
||||
public void setProject(Project project) {
|
||||
this.project = project;
|
||||
}
|
||||
|
||||
public Project getProject() {
|
||||
return project;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Returns the entryPointClassName.
|
||||
*/
|
||||
public String getEntryPointClassName() {
|
||||
return entryPointClassName;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* The static <code>main(String[])void</code> method of the specified class is executed
|
||||
* after the assembly is loaded by the script engine.
|
||||
* </p>
|
||||
* <p>
|
||||
* In web mode, the values of the URL query string are passed to this method.
|
||||
* </p>
|
||||
*
|
||||
* @param entryPointClassName (required) the class signature
|
||||
*/
|
||||
public Assembly setEntryPointClassName(String entryPointClassName) {
|
||||
this.entryPointClassName = entryPointClassName;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Returns the targetLocation.
|
||||
*/
|
||||
public File getTargetLocation() {
|
||||
return targetLocation;
|
||||
}
|
||||
|
||||
/**
|
||||
* The assembly is written to the specified directory
|
||||
*
|
||||
* @param targetLocation (required) the directory the assembly is written to
|
||||
*/
|
||||
public void setTargetLocation(File targetLocation) {
|
||||
this.targetLocation = targetLocation;
|
||||
}
|
||||
|
||||
/**
|
||||
* Signature of a field or method to include in the assembly.
|
||||
* <p>
|
||||
* <strong>Note</strong>: Normally you will only add those entrypoints which
|
||||
* the static code analyser cannot detect, for example methods called through
|
||||
* reflection.
|
||||
* </p>
|
||||
*
|
||||
* @param memberSignature the member to include
|
||||
*/
|
||||
public void addEntryPoint(String memberSignature) {
|
||||
entryPoints.add(memberSignature);
|
||||
}
|
||||
|
||||
}
|
2480
src/main/java/com/j2js/Const.java
Normal file
2480
src/main/java/com/j2js/Const.java
Normal file
File diff suppressed because it is too large
Load Diff
29
src/main/java/com/j2js/ConstGenerator.java
Normal file
29
src/main/java/com/j2js/ConstGenerator.java
Normal file
@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Created on 26.12.2005
|
||||
* Copyright Wolfgang Kuehn 2005
|
||||
*/
|
||||
package com.j2js;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import javax.xml.transform.Result;
|
||||
import javax.xml.transform.TransformerFactory;
|
||||
import javax.xml.transform.Transformer;
|
||||
import javax.xml.transform.stream.StreamResult;
|
||||
import javax.xml.transform.stream.StreamSource;
|
||||
|
||||
/**
|
||||
* @author kuehn
|
||||
*/
|
||||
public class ConstGenerator {
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
TransformerFactory factory = TransformerFactory.newInstance();
|
||||
StreamSource xslSource = new StreamSource(new File("src/com/j2js/instructions.xsl"));
|
||||
Transformer xltTransformer = factory.newTransformer(xslSource);
|
||||
|
||||
StreamSource xmlSource = new StreamSource(new File("src/com/j2js/instructions.xml"));
|
||||
Result result = new StreamResult(new File("src/com/j2js/Const.java"));
|
||||
xltTransformer.transform(xmlSource, result);
|
||||
}
|
||||
}
|
105
src/main/java/com/j2js/Diff.java
Normal file
105
src/main/java/com/j2js/Diff.java
Normal file
@ -0,0 +1,105 @@
|
||||
package com.j2js;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
import java.io.LineNumberReader;
|
||||
import java.io.Reader;
|
||||
|
||||
/**
|
||||
* Copyright by Wolfgang Kuehn 2005
|
||||
* Created on Feb 26, 2005
|
||||
*/
|
||||
public class Diff {
|
||||
|
||||
private int lookAheadLines = 5;
|
||||
private LineNumberReader in1;
|
||||
private LineNumberReader in2;
|
||||
private int skipLineCount = 0;
|
||||
|
||||
public Diff(Reader r1, Reader r2) {
|
||||
in1 = new LineNumberReader(r1);
|
||||
in2 = new LineNumberReader(r2);
|
||||
}
|
||||
|
||||
public Diff(File f1, File f2) throws FileNotFoundException {
|
||||
this(new FileReader(f1), new FileReader(f2));
|
||||
}
|
||||
|
||||
public boolean apply() throws IOException {
|
||||
boolean equal = true;
|
||||
int lineCount = 0;
|
||||
|
||||
while (true) {
|
||||
lineCount++;
|
||||
String l1 = in1.readLine();
|
||||
String l2 = in2.readLine();
|
||||
if (l1==null || l2==null) {
|
||||
break;
|
||||
} else if (l1==null && l2!=null) {
|
||||
equal = false;
|
||||
System.out.println("File 2 extends File 1 at line " + in2.getLineNumber());
|
||||
break;
|
||||
} else if (l1!=null && l2==null) {
|
||||
equal = false;
|
||||
System.out.println("File 1 extends File 2 at line " + in1.getLineNumber());
|
||||
break;
|
||||
}
|
||||
|
||||
if (lineCount > skipLineCount && !l1.equals(l2)) {
|
||||
equal = false;
|
||||
System.out.println("Mismatch");
|
||||
System.out.println("File 1 Line " + in1.getLineNumber() + ": " + l1);
|
||||
System.out.println("File 2 Line " + in2.getLineNumber() + ": " + l2);
|
||||
|
||||
if (!sync()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
in1.close();
|
||||
in2.close();
|
||||
|
||||
return equal;
|
||||
}
|
||||
|
||||
private boolean sync() throws IOException {
|
||||
int maxCharactersInLine = 200;
|
||||
int readAheadLimit = lookAheadLines * maxCharactersInLine;
|
||||
|
||||
in2.mark(readAheadLimit);
|
||||
in1.mark(readAheadLimit);
|
||||
|
||||
for (int i=0; i<lookAheadLines; i++) {
|
||||
String l1 = in1.readLine();
|
||||
if (l1==null) break;
|
||||
|
||||
for (int j=0; j<lookAheadLines; j++) {
|
||||
String l2 = in2.readLine();
|
||||
if (l2==null) break;
|
||||
if (l1.equals(l2)) return true;
|
||||
}
|
||||
try {
|
||||
in2.reset();
|
||||
} catch (IOException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Returns the skipLineCount.
|
||||
*/
|
||||
public int getSkipLineCount() {
|
||||
return skipLineCount;
|
||||
}
|
||||
/**
|
||||
* @param theSkipLineCount The skipLineCount to set.
|
||||
*/
|
||||
public void setSkipLineCount(int theSkipLineCount) {
|
||||
skipLineCount = theSkipLineCount;
|
||||
}
|
||||
}
|
53
src/main/java/com/j2js/ExceptionHandler.java
Normal file
53
src/main/java/com/j2js/ExceptionHandler.java
Normal file
@ -0,0 +1,53 @@
|
||||
package com.j2js;
|
||||
|
||||
/*
|
||||
* Created on May 27, 2004
|
||||
*
|
||||
* To change the template for this generated file go to
|
||||
* Window - Preferences - Java - Code Generation - Code and Comments
|
||||
*/
|
||||
|
||||
import org.apache.bcel.Constants;
|
||||
import org.apache.bcel.classfile.CodeException;
|
||||
import org.apache.bcel.classfile.ConstantPool;
|
||||
import org.apache.bcel.generic.Type;
|
||||
|
||||
import com.j2js.dom.*;
|
||||
|
||||
/**
|
||||
* @author wolfgang
|
||||
*
|
||||
* To change the template for this generated type comment go to
|
||||
* Window - Preferences - Java - Code Generation - Code and Comments
|
||||
*/
|
||||
public class ExceptionHandler extends ASTNode {
|
||||
|
||||
private CodeException codeException;
|
||||
|
||||
public ExceptionHandler(CodeException theCodeException) {
|
||||
codeException = theCodeException;
|
||||
}
|
||||
|
||||
public int getStartPC() {
|
||||
return codeException.getStartPC();
|
||||
}
|
||||
|
||||
public int getEndPC() {
|
||||
return codeException.getEndPC();
|
||||
}
|
||||
|
||||
public int getHandlerPC() {
|
||||
return codeException.getHandlerPC();
|
||||
}
|
||||
|
||||
public Type getCatchType(ConstantPool cp) {
|
||||
if (codeException.getCatchType() == 0) return null;
|
||||
String signature = cp.getConstantString(codeException.getCatchType(), Constants.CONSTANT_Class);
|
||||
return Type.getType("L" + signature +";");
|
||||
}
|
||||
|
||||
public boolean isDefault() {
|
||||
return codeException.getCatchType()==0;
|
||||
}
|
||||
|
||||
}
|
32
src/main/java/com/j2js/ExceptionHandlers.java
Normal file
32
src/main/java/com/j2js/ExceptionHandlers.java
Normal file
@ -0,0 +1,32 @@
|
||||
package com.j2js;
|
||||
|
||||
/*
|
||||
* Created on May 27, 2004
|
||||
*/
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import org.apache.bcel.classfile.Code;
|
||||
import org.apache.bcel.classfile.CodeException;
|
||||
|
||||
/**
|
||||
* @author wolfgang
|
||||
*/
|
||||
public class ExceptionHandlers extends ArrayList<ExceptionHandler> {
|
||||
|
||||
public ExceptionHandlers(Code code) {
|
||||
|
||||
// Join all contiguous CodeExceptions with equal handler PC.
|
||||
// This is to eliminate multi-entrant execption handlers.
|
||||
CodeException previousCodeException = null;
|
||||
for (CodeException codeException : code.getExceptionTable()) {
|
||||
if (previousCodeException != null &&
|
||||
previousCodeException.getHandlerPC() == codeException.getHandlerPC()) {
|
||||
previousCodeException.setEndPC(codeException.getEndPC());
|
||||
} else {
|
||||
add(new ExceptionHandler(codeException));
|
||||
}
|
||||
previousCodeException = codeException;
|
||||
}
|
||||
}
|
||||
}
|
76
src/main/java/com/j2js/FileManager.java
Normal file
76
src/main/java/com/j2js/FileManager.java
Normal file
@ -0,0 +1,76 @@
|
||||
package com.j2js;
|
||||
|
||||
import com.j2js.J2JSCompiler;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.jar.JarEntry;
|
||||
import java.util.jar.JarFile;
|
||||
|
||||
/**
|
||||
* A FileManager can resolve relative file names against a class path.
|
||||
* <p>
|
||||
* The file names "java/lang.package-info", "java/lang/package-info" and
|
||||
* "java.lang.package-info" are valid and equivalent.
|
||||
* </p>
|
||||
*
|
||||
* @author wolle
|
||||
*/
|
||||
public class FileManager {
|
||||
|
||||
private List<Object> path = new ArrayList<Object>();
|
||||
|
||||
/**
|
||||
* Create a new FileManager.
|
||||
*
|
||||
* @param classPath list of file system directories or jar files.
|
||||
*/
|
||||
public FileManager(List<File> classPath) {
|
||||
Log.getLogger().info("Resolving class path " + classPath);
|
||||
|
||||
// Replace all jar files on classPath by instances of JarFile.
|
||||
// Non-existing files are sorted out.
|
||||
for (File file : classPath) {
|
||||
if (!file.exists()) {
|
||||
J2JSCompiler.errorCount++;
|
||||
Log.getLogger().error("Cannot find resource on class path: " + file.getAbsolutePath());
|
||||
continue;
|
||||
}
|
||||
|
||||
if (file.getName().endsWith(".jar")) {
|
||||
try {
|
||||
path.add(new JarFile(file));
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
} else {
|
||||
path.add(file);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves a file given by name along the class path.
|
||||
*/
|
||||
public FileObject getFileForInput(String relativeName) {
|
||||
for (Object o : path) {
|
||||
if (o instanceof JarFile) {
|
||||
JarFile jarFile = (JarFile) o;
|
||||
JarEntry entry = jarFile.getJarEntry(relativeName);
|
||||
if (entry != null) {
|
||||
return new FileObject(jarFile, entry);
|
||||
}
|
||||
} else {
|
||||
File file = new File(((File) o), relativeName);
|
||||
if (file.exists()) {
|
||||
return new FileObject(file);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
throw new RuntimeException("Could not find " + relativeName + " on class path");
|
||||
}
|
||||
|
||||
}
|
54
src/main/java/com/j2js/FileObject.java
Normal file
54
src/main/java/com/j2js/FileObject.java
Normal file
@ -0,0 +1,54 @@
|
||||
package com.j2js;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.jar.JarEntry;
|
||||
import java.util.jar.JarFile;
|
||||
|
||||
/**
|
||||
* File abstraction for tools. In this context, file means an abstraction of regular
|
||||
* files and other sources of data.
|
||||
*
|
||||
* @author wolle
|
||||
*/
|
||||
public class FileObject {
|
||||
|
||||
private long lastModified;
|
||||
private InputStream in;
|
||||
|
||||
FileObject(JarFile jarFile, JarEntry entry) {
|
||||
try {
|
||||
in = jarFile.getInputStream(entry);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
lastModified = entry.getTime();
|
||||
}
|
||||
|
||||
FileObject(File file) {
|
||||
try {
|
||||
in = new FileInputStream(file);
|
||||
} catch (FileNotFoundException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
lastModified = file.lastModified();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an InputStream for this file object.
|
||||
*/
|
||||
public InputStream openInputStream() throws IOException {
|
||||
return in;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Returns the lastModified.
|
||||
*/
|
||||
public long getLastModified() {
|
||||
return lastModified;
|
||||
}
|
||||
|
||||
}
|
109
src/main/java/com/j2js/Form.java
Normal file
109
src/main/java/com/j2js/Form.java
Normal file
@ -0,0 +1,109 @@
|
||||
package com.j2js;
|
||||
|
||||
import org.apache.bcel.generic.Type;
|
||||
|
||||
/**
|
||||
* @author wolfgang
|
||||
*/
|
||||
public class Form {
|
||||
|
||||
public static int CATEGORY1 = 1;
|
||||
public static int CATEGORY2 = 2;
|
||||
|
||||
public static class Value {
|
||||
public String type;
|
||||
public String name;
|
||||
|
||||
public Value(String theType, String theName) {
|
||||
type = theType;
|
||||
name = theName;
|
||||
}
|
||||
|
||||
public int getCategory() {
|
||||
return type.equals("cat2") || type.equals("long") || type.equals("double")?CATEGORY2:CATEGORY1;
|
||||
}
|
||||
}
|
||||
|
||||
private int index;
|
||||
private Form.Value[] ins;
|
||||
private Form.Value[] outs;
|
||||
private Form.Value[] operands;
|
||||
private Type type;
|
||||
|
||||
/**
|
||||
* @return Returns the ins.
|
||||
*/
|
||||
public Form.Value[] getIns() {
|
||||
return ins;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param theIns The ins to set.
|
||||
*/
|
||||
public void setIns(Form.Value[] theIns) {
|
||||
ins = theIns;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Returns the operands.
|
||||
*/
|
||||
public Form.Value[] getOperands() {
|
||||
return operands;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param theOperands The operands to set.
|
||||
*/
|
||||
public void setOperands(Form.Value[] theOperands) {
|
||||
operands = theOperands;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Returns the outs.
|
||||
*/
|
||||
public Form.Value[] getOuts() {
|
||||
return outs;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param theOuts The outs to set.
|
||||
*/
|
||||
public void setOuts(Form.Value[] theOuts) {
|
||||
outs = theOuts;
|
||||
|
||||
if (theOuts.length != 1) return;
|
||||
|
||||
String s = theOuts[0].type;
|
||||
if (s.equals("object")) type = Type.OBJECT;
|
||||
else if (s.equals("int")) type = Type.INT;
|
||||
else if (s.equals("short")) type = Type.SHORT;
|
||||
else if (s.equals("byte")) type = Type.SHORT;
|
||||
else if (s.equals("long")) type = Type.LONG;
|
||||
else if (s.equals("float")) type = Type.FLOAT;
|
||||
else if (s.equals("double")) type = Type.DOUBLE;
|
||||
else if (!s.equals("cat1") && !s.equals("returnAddress") && !s.equals(""))
|
||||
throw new RuntimeException("Unhandled type: " + s);
|
||||
}
|
||||
|
||||
public int getOpStackDelta() {
|
||||
return getOuts().length - getIns().length;
|
||||
}
|
||||
|
||||
public Type getResultType() {
|
||||
if (type == null) throw new RuntimeException("Result type is not available for " + this);
|
||||
|
||||
return type;
|
||||
}
|
||||
/**
|
||||
* @return Returns the index.
|
||||
*/
|
||||
public int getIndex() {
|
||||
return index;
|
||||
}
|
||||
/**
|
||||
* @param theIndex The index to set.
|
||||
*/
|
||||
public void setIndex(int theIndex) {
|
||||
index = theIndex;
|
||||
}
|
||||
}
|
59
src/main/java/com/j2js/InstructionType.java
Normal file
59
src/main/java/com/j2js/InstructionType.java
Normal file
@ -0,0 +1,59 @@
|
||||
package com.j2js;
|
||||
|
||||
/**
|
||||
* @author wolfgang
|
||||
*/
|
||||
public class InstructionType {
|
||||
|
||||
private short code;
|
||||
private String name;
|
||||
private Form[] forms;
|
||||
|
||||
public InstructionType(short theCode, String theName, int formCount) {
|
||||
code = theCode;
|
||||
name = theName;
|
||||
forms = new Form[formCount];
|
||||
}
|
||||
|
||||
public int getFormCount() {
|
||||
return forms.length;
|
||||
}
|
||||
|
||||
public void setForm(Form form, int index) {
|
||||
forms[index] = form;
|
||||
form.setIndex(index);
|
||||
}
|
||||
|
||||
public Form getForm(int index) {
|
||||
return forms[index];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Returns the name.
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param theName The name to set.
|
||||
*/
|
||||
public void setName(String theName) {
|
||||
name = theName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Returns the code.
|
||||
*/
|
||||
public short getCode() {
|
||||
return code;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param theCode The code to set.
|
||||
*/
|
||||
public void setCode(short theCode) {
|
||||
code = theCode;
|
||||
}
|
||||
|
||||
}
|
357
src/main/java/com/j2js/J2JSCompiler.java
Normal file
357
src/main/java/com/j2js/J2JSCompiler.java
Normal file
@ -0,0 +1,357 @@
|
||||
// Copyright 2011 The j2js Authors. All Rights Reserved.
|
||||
//
|
||||
// This file is part of j2js.
|
||||
//
|
||||
// j2js is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// j2js is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with j2js. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package com.j2js;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.j2js.FileManager;
|
||||
import com.j2js.Log;
|
||||
import com.j2js.Utils;
|
||||
import com.j2js.assembly.Project;
|
||||
import com.j2js.visitors.JavaScriptGenerator;
|
||||
|
||||
/**
|
||||
* The cross-compiler translates Java class files into JavaScript code and assembles all reachable code
|
||||
* into assemblies.
|
||||
* <p>
|
||||
* For details please refer to the <a href="../../../compile.html">plugin description</a>.
|
||||
*
|
||||
* @author Wolfgang Kuehn
|
||||
*/
|
||||
public class J2JSCompiler {
|
||||
|
||||
public static J2JSCompiler compiler;
|
||||
|
||||
public static int errorCount = 0;
|
||||
|
||||
private File basedir;
|
||||
private File cacheFile;
|
||||
|
||||
List<com.j2js.Assembly> assemblies = new ArrayList<Assembly>();
|
||||
|
||||
private List<File> classpath = new ArrayList<File>();
|
||||
|
||||
public FileManager fileManager;
|
||||
|
||||
public boolean optimize = true;
|
||||
public boolean failOnError = true;
|
||||
private boolean compression = true;
|
||||
|
||||
private String singleEntryPoint;
|
||||
private String targetPlatform;
|
||||
public int reductionLevel = 5;
|
||||
|
||||
private int junkSizeInKiloBytes = Integer.MAX_VALUE;
|
||||
|
||||
private boolean generateLineNumbers = false;
|
||||
|
||||
public int compileCount = 0;
|
||||
public JavaScriptGenerator generator;
|
||||
|
||||
private Log logger;
|
||||
|
||||
// Begin main
|
||||
public static void main(String argv[]) throws Exception {
|
||||
if ( argv == null || argv.length != 4 ) {
|
||||
StringBuffer sb = new StringBuffer();
|
||||
sb.append("Usage: java ");
|
||||
sb.append(J2JSCompiler.class.getName());
|
||||
sb.append(" <basedir> <classpathElements> <entryPointClassName> <targetLocation>");
|
||||
System.out.print(sb.toString());
|
||||
return;
|
||||
}
|
||||
|
||||
File basedir = new File(argv[0]);
|
||||
String classpathElements = argv[1];
|
||||
String entryPointClassName = argv[2];
|
||||
|
||||
Assembly assembly = new Assembly();
|
||||
assembly.setEntryPointClassName(entryPointClassName);
|
||||
|
||||
assembly.setTargetLocation(new File(basedir, argv[3]));
|
||||
|
||||
J2JSCompiler compiler = new J2JSCompiler();
|
||||
compiler.setBasedir(basedir);
|
||||
compiler.addClasspathElements(classpathElements);
|
||||
compiler.addAssembly(assembly);
|
||||
compiler.setGenerateLineNumbers(true);
|
||||
compiler.execute();
|
||||
}
|
||||
// End main
|
||||
|
||||
/**
|
||||
* Create new compiler with the current directory as basedir.
|
||||
*/
|
||||
public J2JSCompiler() {
|
||||
setBasedir(new File(System.getProperty("user.dir")));
|
||||
setTargetPlatform("web");
|
||||
}
|
||||
|
||||
public void execute() throws Exception {
|
||||
if (logger == null) {
|
||||
setLogger(new Log());
|
||||
}
|
||||
|
||||
for (Assembly assembly : assemblies) {
|
||||
execute(assembly);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isMavenExecution() {
|
||||
return System.getProperty("localRepository") != null;
|
||||
}
|
||||
|
||||
public void execute(Assembly assembly) throws Exception {
|
||||
J2JSCompiler.compiler = this;
|
||||
|
||||
logger.info("Entry point is " + assembly.getEntryPointClassName() + "#main(java.lang.String[])void");
|
||||
|
||||
if (classpath == null) {
|
||||
throw new RuntimeException("Field classPath must be set");
|
||||
}
|
||||
|
||||
if (assembly.getEntryPointClassName() == null) {
|
||||
throw new RuntimeException("Field assembly.entryPointClassName must be set");
|
||||
}
|
||||
|
||||
if (cacheFile == null) {
|
||||
setCacheFile(new File(basedir, "target/j2js.cache"));
|
||||
}
|
||||
|
||||
if (assembly.getTargetLocation() == null) {
|
||||
throw new RuntimeException("Field assembly.targetLocation must be set");
|
||||
//assembly.setTargetLocation(new File(basedir, "target/classes/assemblies/" + assembly.getEntryPointClassName().replaceAll("\\.", "/")));
|
||||
}
|
||||
|
||||
logger.info("Creating assembly " + assembly.getTargetLocation());
|
||||
|
||||
fileManager = new FileManager(classpath);
|
||||
Project project = Project.createSingleton(getCacheFile());
|
||||
assembly.setProject(project);
|
||||
generator = new JavaScriptGenerator(project);
|
||||
|
||||
errorCount = 0;
|
||||
|
||||
assembly.addEntryPoint(assembly.getEntryPointClassName() + "#main(java.lang.String[])void");
|
||||
|
||||
for (String memberSignature : assembly.entryPoints) {
|
||||
assembly.taint(memberSignature);
|
||||
}
|
||||
|
||||
long startTime = System.currentTimeMillis();
|
||||
|
||||
// Used by the JavaScript JVM. The static code analyser would miss these.
|
||||
|
||||
String[] signatures = Utils.getProperty("j2js.preTaintedSignatures").split(";");
|
||||
for (int i=0; i<signatures.length; i++) {
|
||||
assembly.taint(signatures[i]);
|
||||
}
|
||||
|
||||
if (J2JSCompiler.compiler.getSingleEntryPoint() != null) {
|
||||
assembly.processSingle(project.getSignature(getSingleEntryPoint()));
|
||||
} else {
|
||||
assembly.processTainted();
|
||||
}
|
||||
|
||||
int methodCount;
|
||||
try {
|
||||
methodCount = assembly.createAssembly();
|
||||
|
||||
if (getCacheFile() != null) {
|
||||
Project.write();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new Exception("Error while creating assembly", e);
|
||||
}
|
||||
|
||||
logger.info(
|
||||
timesName("Compiled|Compiled", compileCount, "class|classes") +
|
||||
", " + timesName("packed|packed", methodCount, "method|methods") + ".");
|
||||
logger.info("Execution time was " + (System.currentTimeMillis()-startTime) + " millis.");
|
||||
|
||||
if (errorCount > 0) {
|
||||
logger.error("There " + timesName("was|were", errorCount, "error|errors") + ".");
|
||||
}
|
||||
}
|
||||
|
||||
private String timesName(String verb, int count, String noun) {
|
||||
String[] verbs = verb.split("\\|");
|
||||
String[] nouns = noun.split("\\|");
|
||||
int index = (count==1?0:1);
|
||||
return verbs[index] + " " + count + " " + nouns[index];
|
||||
}
|
||||
|
||||
public void setCompression(boolean isCompression) {
|
||||
this.compression = isCompression;
|
||||
}
|
||||
|
||||
public boolean isCompression() {
|
||||
return compression;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* For debugging. Internal use only.
|
||||
*/
|
||||
public void setSingleEntryPoint(String signature) {
|
||||
singleEntryPoint = signature;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see #setSingleEntryPoint(String)
|
||||
*/
|
||||
public String getSingleEntryPoint() {
|
||||
return singleEntryPoint;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets one of the target platforms "web" or "javascript".
|
||||
*
|
||||
* @param targetPlatform optional; default is "web"
|
||||
*/
|
||||
public void setTargetPlatform(String targetPlatform) {
|
||||
targetPlatform = targetPlatform.toLowerCase();
|
||||
if ("web".equals(targetPlatform) || "javascript".equals(targetPlatform)) {
|
||||
this.targetPlatform = targetPlatform;
|
||||
} else {
|
||||
throw new IllegalArgumentException("Target platform must be web or javascript");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see #setTargetPlatform(String)
|
||||
*/
|
||||
public String getTargetPlatform() {
|
||||
return targetPlatform;
|
||||
}
|
||||
|
||||
public List<File> getClasspath() {
|
||||
return classpath;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param classpathElements (optional) additional class path elements
|
||||
*/
|
||||
public void addClasspathElements(List<File> classpathElements) {
|
||||
classpath.addAll(classpathElements);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param classpathElement (optional) additional class path element
|
||||
*/
|
||||
public void addClasspathElement(File classpathElement) {
|
||||
classpath.add(classpathElement);
|
||||
}
|
||||
|
||||
/**
|
||||
* Semicolon- or whitespace-separated list of class path elements.
|
||||
*
|
||||
* @param classPathElements (optional) additional class path elements
|
||||
* @see #setClasspathElements(List)
|
||||
*/
|
||||
public void addClasspathElements(String classPathElements) {
|
||||
String[] array = classPathElements.split("(;|,)");
|
||||
for (String path : array) {
|
||||
path = path.trim();
|
||||
if (path.length() > 0) {
|
||||
addClasspathElement(Utils.resolve(basedir, path));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void setClasspathElements(List<String> classpathElements) {
|
||||
for (Object part : classpathElements) {
|
||||
addClasspathElements((String) part);
|
||||
}
|
||||
}
|
||||
|
||||
public void setFailOnError(boolean flag) {
|
||||
failOnError = flag;
|
||||
}
|
||||
|
||||
public boolean isFailOnError() {
|
||||
return failOnError;
|
||||
}
|
||||
|
||||
public File getCacheFile() {
|
||||
return cacheFile;
|
||||
}
|
||||
|
||||
public void setCacheFile(File theCacheFile) {
|
||||
cacheFile = theCacheFile;
|
||||
}
|
||||
|
||||
public List<com.j2js.Assembly> getAssemblies() {
|
||||
return assemblies;
|
||||
}
|
||||
|
||||
public void setAssemlies(List<com.j2js.Assembly> assemblies) {
|
||||
this.assemblies = assemblies;
|
||||
}
|
||||
|
||||
public void setGenerateLineNumbers(boolean theGenerateLineNumbers) {
|
||||
generateLineNumbers = theGenerateLineNumbers;
|
||||
}
|
||||
|
||||
public boolean isGenerateLineNumbers() {
|
||||
return generateLineNumbers;
|
||||
}
|
||||
|
||||
public void setJunkSizeInKiloBytes(int junkSizeInKiloBytes) {
|
||||
if (junkSizeInKiloBytes < 1) {
|
||||
throw new RuntimeException("Junk size must be greater than zero.");
|
||||
}
|
||||
this.junkSizeInKiloBytes = junkSizeInKiloBytes;
|
||||
}
|
||||
|
||||
public int getJunkSizeInKiloBytes() {
|
||||
return junkSizeInKiloBytes;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Returns the logger.
|
||||
*/
|
||||
public Log getLogger() {
|
||||
return logger;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the logger.
|
||||
*/
|
||||
public void setLogger(Log logger) {
|
||||
this.logger = logger;
|
||||
Log.logger = logger;
|
||||
}
|
||||
|
||||
public void setBasedir(File basedir) {
|
||||
this.basedir = basedir;
|
||||
}
|
||||
|
||||
public File getBasedir() {
|
||||
return basedir;
|
||||
}
|
||||
|
||||
public void addAssembly(Assembly assembly) {
|
||||
assemblies.add(assembly);
|
||||
}
|
||||
|
||||
}
|
76
src/main/java/com/j2js/LineNumberCursor.java
Normal file
76
src/main/java/com/j2js/LineNumberCursor.java
Normal file
@ -0,0 +1,76 @@
|
||||
package com.j2js;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Comparator;
|
||||
|
||||
import org.apache.bcel.classfile.Code;
|
||||
import org.apache.bcel.classfile.LineNumber;
|
||||
import org.apache.bcel.classfile.LineNumberTable;
|
||||
|
||||
import com.j2js.dom.ASTNode;
|
||||
|
||||
public class LineNumberCursor {
|
||||
|
||||
private class LineNumberComparator implements Comparator<LineNumber> {
|
||||
|
||||
public int compare(LineNumber arg0, LineNumber arg1) {
|
||||
return arg0.getStartPC() - arg1.getStartPC();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private LineNumber[] lineNumbers = null;
|
||||
private int index = 0;
|
||||
private int markedLineNumber = -1;
|
||||
private int length;
|
||||
|
||||
public LineNumberCursor(Code code) {
|
||||
if (code == null) return;
|
||||
LineNumberTable table = code.getLineNumberTable();
|
||||
if (table == null) return;
|
||||
lineNumbers = table.getLineNumberTable();
|
||||
length = lineNumbers.length;
|
||||
// TODO: Is table already ordered?
|
||||
Arrays.sort(lineNumbers, new LineNumberComparator());
|
||||
}
|
||||
|
||||
public boolean hasLineNumbers() {
|
||||
return lineNumbers != null;
|
||||
}
|
||||
|
||||
public int getLineNumber(ASTNode node) {
|
||||
if (!hasLineNumbers()) return -1;
|
||||
|
||||
while (node.getBeginIndex() == Integer.MAX_VALUE && node.getPreviousSibling() != null) {
|
||||
node = node.getPreviousSibling();
|
||||
}
|
||||
|
||||
int pc = node.getBeginIndex();
|
||||
L: if (pc > lineNumbers[index].getStartPC()) {
|
||||
do {
|
||||
if (index+1 == length) break L;
|
||||
index ++;
|
||||
} while (pc >= lineNumbers[index].getStartPC());
|
||||
index --;
|
||||
} else if (pc < lineNumbers[index].getStartPC()) {
|
||||
do {
|
||||
if (index == 0) break L;
|
||||
index --;
|
||||
} while (pc <= lineNumbers[index].getStartPC());
|
||||
index ++;
|
||||
}
|
||||
|
||||
return lineNumbers[index].getLineNumber();
|
||||
}
|
||||
|
||||
public int getAndMarkLineNumber(ASTNode node) {
|
||||
if (!hasLineNumbers()) return -1;
|
||||
|
||||
int lineNumber = getLineNumber(node);
|
||||
if (lineNumber == markedLineNumber) return -1;
|
||||
|
||||
markedLineNumber = lineNumber;
|
||||
return lineNumber;
|
||||
}
|
||||
|
||||
}
|
132
src/main/java/com/j2js/Log.java
Normal file
132
src/main/java/com/j2js/Log.java
Normal file
@ -0,0 +1,132 @@
|
||||
/*
|
||||
* Copyright 2005 by Wolfgang Kuehn
|
||||
* Created on 04.10.2005
|
||||
*/
|
||||
package com.j2js;
|
||||
|
||||
|
||||
/**
|
||||
* @author wolfgang
|
||||
*/
|
||||
public class Log {
|
||||
|
||||
public static Log logger;
|
||||
|
||||
public static Log getLogger() {
|
||||
return logger;
|
||||
}
|
||||
|
||||
private int state = INFO;
|
||||
|
||||
/**
|
||||
* @return Returns the state.
|
||||
*/
|
||||
public int getState() {
|
||||
return state;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param state The state to set.
|
||||
*/
|
||||
public void setState(int state) {
|
||||
this.state = state;
|
||||
}
|
||||
|
||||
public static final int DEBUG = 3;
|
||||
public static final int INFO = 2;
|
||||
public static final int WARN = 1;
|
||||
public static final int ERROR = 0;
|
||||
|
||||
public void debug(CharSequence arg0, Throwable arg1) {
|
||||
if (isDebugEnabled()) {
|
||||
System.out.println("[DEBUG] " + arg0);
|
||||
arg1.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public void debug(CharSequence arg0) {
|
||||
if (isDebugEnabled()) {
|
||||
System.out.println("[DEBUG] " + arg0);
|
||||
}
|
||||
}
|
||||
|
||||
public void debug(Throwable arg0) {
|
||||
if (isDebugEnabled()) {
|
||||
arg0.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public void error(CharSequence arg0, Throwable arg1) {
|
||||
if (isErrorEnabled()) {
|
||||
System.out.println("[ERROR] " + arg0);
|
||||
arg1.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public void error(CharSequence arg0) {
|
||||
if (isErrorEnabled()) {
|
||||
System.out.println("[ERROR] " + arg0);
|
||||
}
|
||||
}
|
||||
|
||||
public void error(Throwable arg0) {
|
||||
if (isErrorEnabled()) {
|
||||
arg0.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public void info(CharSequence arg0, Throwable arg1) {
|
||||
if (isInfoEnabled()) {
|
||||
System.out.println("[INFO] " + arg0);
|
||||
arg1.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public void info(CharSequence arg0) {
|
||||
if (isInfoEnabled()) {
|
||||
System.out.println("[INFO] " + arg0);
|
||||
}
|
||||
}
|
||||
|
||||
public void info(Throwable arg0) {
|
||||
if (isInfoEnabled()) {
|
||||
arg0.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isDebugEnabled() {
|
||||
return state >= DEBUG;
|
||||
}
|
||||
|
||||
public boolean isErrorEnabled() {
|
||||
return state >= ERROR;
|
||||
}
|
||||
|
||||
public boolean isInfoEnabled() {
|
||||
return state >= INFO;
|
||||
}
|
||||
|
||||
public boolean isWarnEnabled() {
|
||||
return state >= WARN;
|
||||
}
|
||||
|
||||
public void warn(CharSequence arg0, Throwable arg1) {
|
||||
if (isWarnEnabled()) {
|
||||
System.out.println("[WARNING] " + arg0);
|
||||
arg1.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public void warn(CharSequence arg0) {
|
||||
if (isWarnEnabled()) {
|
||||
System.out.println("[WARNING] " + arg0);
|
||||
}
|
||||
}
|
||||
|
||||
public void warn(Throwable arg0) {
|
||||
if (isWarnEnabled()) {
|
||||
arg0.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
38
src/main/java/com/j2js/OperandState.java
Normal file
38
src/main/java/com/j2js/OperandState.java
Normal file
@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Created on 20.10.2004
|
||||
*
|
||||
* To change the template for this generated file go to
|
||||
* Window - Preferences - Java - Code Generation - Code and Comments
|
||||
*/
|
||||
package com.j2js;
|
||||
|
||||
import com.j2js.dom.ASTNode;
|
||||
|
||||
/**
|
||||
* @author kuehn
|
||||
*
|
||||
* To change the template for this generated type comment go to
|
||||
* Window - Preferences - Java - Code Generation - Code and Comments
|
||||
*/
|
||||
public class OperandState {
|
||||
|
||||
int code;
|
||||
int beginIndex;
|
||||
int endIndex;
|
||||
|
||||
ASTNode stmt;
|
||||
|
||||
OperandState(int theCode) {
|
||||
code = theCode;
|
||||
}
|
||||
|
||||
OperandState(int theCode, int theBeginIndex, ASTNode theStmt) {
|
||||
code = theCode;
|
||||
beginIndex = theBeginIndex;
|
||||
stmt = theStmt;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "State: " + code + " " + stmt;
|
||||
}
|
||||
}
|
324
src/main/java/com/j2js/Optimizer.java
Normal file
324
src/main/java/com/j2js/Optimizer.java
Normal file
@ -0,0 +1,324 @@
|
||||
package com.j2js;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.bcel.generic.Type;
|
||||
|
||||
import com.j2js.dom.ASTNode;
|
||||
import com.j2js.dom.Assignable;
|
||||
import com.j2js.dom.Assignment;
|
||||
import com.j2js.dom.Block;
|
||||
import com.j2js.dom.Expression;
|
||||
import com.j2js.dom.FieldAccess;
|
||||
import com.j2js.dom.InfixExpression;
|
||||
import com.j2js.dom.MethodDeclaration;
|
||||
import com.j2js.dom.NumberLiteral;
|
||||
import com.j2js.dom.PStarExpression;
|
||||
import com.j2js.dom.PostfixExpression;
|
||||
import com.j2js.dom.PrefixExpression;
|
||||
import com.j2js.dom.VariableBinding;
|
||||
import com.j2js.dom.VariableDeclaration;
|
||||
|
||||
public class Optimizer {
|
||||
|
||||
private MethodDeclaration methodDecl;
|
||||
private List tempDecls;
|
||||
|
||||
public Optimizer(MethodDeclaration theMethodDecl, List theTempDecls) {
|
||||
methodDecl = theMethodDecl;
|
||||
tempDecls = theTempDecls;
|
||||
}
|
||||
|
||||
public static Expression negate(Expression expr) {
|
||||
PrefixExpression pe = new PrefixExpression();
|
||||
pe.setOperator(PrefixExpression.NOT);
|
||||
pe.setOperand(expr);
|
||||
return pe;
|
||||
}
|
||||
|
||||
/**
|
||||
* Simplifies the (possibly negated) expression.
|
||||
*/
|
||||
public static Expression simplifyBooleanExpression(Expression expr, boolean negate) {
|
||||
if (expr instanceof PrefixExpression) {
|
||||
PrefixExpression pe = (PrefixExpression) expr;
|
||||
if (pe.getOperator() != PrefixExpression.NOT) return expr;
|
||||
return simplifyBooleanExpression((Expression) pe.getOperand(), !negate);
|
||||
}
|
||||
|
||||
if (expr instanceof InfixExpression && expr.getTypeBinding() == Type.BOOLEAN) {
|
||||
InfixExpression in = (InfixExpression) expr;
|
||||
InfixExpression.Operator op = in.getOperator();
|
||||
if (negate) {
|
||||
op = op.getComplement();
|
||||
if (op != InfixExpression.Operator.CONDITIONAL_AND && op != InfixExpression.Operator.CONDITIONAL_OR)
|
||||
negate = false;
|
||||
}
|
||||
InfixExpression out = new InfixExpression(op);
|
||||
out.widen(in);
|
||||
out.setOperands(simplifyBooleanExpression(in.getLeftOperand(), negate), simplifyBooleanExpression(in.getRightOperand(), negate));
|
||||
return out;
|
||||
}
|
||||
|
||||
if (negate) {
|
||||
PrefixExpression pe = new PrefixExpression();
|
||||
pe.setOperator(PrefixExpression.NOT);
|
||||
pe.setOperand(expr);
|
||||
return pe;
|
||||
}
|
||||
|
||||
return expr;
|
||||
}
|
||||
|
||||
private boolean representSameAssignables(Assignable a, Assignable b) {
|
||||
if (!(a instanceof FieldAccess && b instanceof FieldAccess)) return false;
|
||||
FieldAccess faa = (FieldAccess) a;
|
||||
FieldAccess fab = (FieldAccess) b;
|
||||
if (!faa.getName().equals(fab.getName())) return false;
|
||||
if (faa.getExpression() instanceof VariableBinding && fab.getExpression() instanceof VariableBinding ) {
|
||||
VariableBinding vba = (VariableBinding) faa.getExpression();
|
||||
VariableBinding vbb = (VariableBinding) fab.getExpression();
|
||||
return vba.getVariableDeclaration() == vbb.getVariableDeclaration();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reduces occurences of
|
||||
* temp = x;
|
||||
* y = temp;
|
||||
* to
|
||||
* y = x;
|
||||
*/
|
||||
// private ASTNode bar1(ASTNode child, ASTNode next) {
|
||||
// if (child instanceof Assignment && next instanceof Assignment) {
|
||||
// Assignment a1 = (Assignment) child;
|
||||
// Assignment a2 = (Assignment) next;
|
||||
// if (a1.getLeftHandSide().equals(a2.getRightHandSide())) {
|
||||
// a2.setRightHandSide(a1.getRightHandSide());
|
||||
// child.getParentBlock().removeChild(child);
|
||||
// return next;
|
||||
// }
|
||||
// }
|
||||
// return child;
|
||||
// }
|
||||
|
||||
private VariableBinding fetchVariableBinding(Expression expr, VariableDeclaration decl) {
|
||||
ASTNode child = expr.getFirstChild();
|
||||
while (child != null) {
|
||||
if (child instanceof VariableBinding && ((VariableBinding) child).getVariableDeclaration() == decl)
|
||||
return (VariableBinding) child;
|
||||
VariableBinding vb = fetchVariableBinding((Expression) child, decl);
|
||||
if (vb != null) return vb;
|
||||
child = child.getNextSibling();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* If the specified expression corresponds to
|
||||
* xy + 1 or xy - (-1),
|
||||
* returns the INCREMENT operator. If the specified expression corresponds to
|
||||
* xy - 1 or xy + (-1),
|
||||
* returns the DECREMENT operator. Otherwise, null is returned.
|
||||
* @param expr
|
||||
* @return
|
||||
*/
|
||||
private PStarExpression.Operator getOp(InfixExpression expr) {
|
||||
NumberLiteral nl;
|
||||
if (expr.getRightOperand() instanceof NumberLiteral) {
|
||||
nl = (NumberLiteral) expr.getRightOperand();
|
||||
} else return null;
|
||||
|
||||
PStarExpression.Operator op;
|
||||
if (expr.getOperator() == InfixExpression.Operator.PLUS) {
|
||||
op = PStarExpression.INCREMENT;
|
||||
} else if (expr.getOperator() == InfixExpression.Operator.MINUS) {
|
||||
op = PStarExpression.DECREMENT;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (NumberLiteral.isOne(nl)) {
|
||||
// We are ok.
|
||||
} else if (NumberLiteral.isMinusOne(nl)) {
|
||||
op = op.complement();
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
return op;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reduces
|
||||
* vb = x.y; (1)
|
||||
* x.y = vb + 1; (2)
|
||||
* ...
|
||||
* expr(vb);
|
||||
* to incremental form
|
||||
* expr(x.y++);
|
||||
* Likewise decrement.
|
||||
*/
|
||||
private boolean reduceXCrement(VariableDeclaration decl) {
|
||||
Assignment a1 = null;
|
||||
Assignment a2 = null;
|
||||
VariableBinding vb1 = null;
|
||||
VariableBinding vb2 = null;
|
||||
|
||||
Assignable fa1 = null;
|
||||
Assignable fa2 = null;
|
||||
|
||||
InfixExpression sum = null;
|
||||
|
||||
|
||||
Iterator iter = decl.vbs.iterator();
|
||||
|
||||
while (iter.hasNext()) {
|
||||
VariableBinding vb = (VariableBinding) iter.next();
|
||||
|
||||
if (vb.getParentNode() instanceof Assignment) {
|
||||
Assignment a = (Assignment) vb.getParentNode();
|
||||
if (a.getLeftHandSide() == vb && a.getRightHandSide() instanceof Assignable) {
|
||||
vb1 = vb;
|
||||
a1 = a;
|
||||
fa1 = (Assignable) a.getRightHandSide();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (vb.getParentNode() instanceof InfixExpression) {
|
||||
InfixExpression infix = (InfixExpression) vb.getParentNode();
|
||||
if (infix.getParentNode() instanceof Assignment) {
|
||||
Assignment a = (Assignment) infix.getParentNode();
|
||||
if (a.getLeftHandSide() instanceof Assignable) {
|
||||
vb2 = vb;
|
||||
fa2 = (Assignable) a.getLeftHandSide();
|
||||
a2 = a;
|
||||
sum = infix;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (a1 == null || a2 == null) return false;
|
||||
if (!fa1.isSame(fa2)) return false;
|
||||
|
||||
PStarExpression.Operator operator = getOp(sum);
|
||||
if (operator == null) return false;
|
||||
|
||||
PStarExpression p = new PostfixExpression();
|
||||
p.setOperand((Expression) fa1);
|
||||
p.setOperator(operator);
|
||||
|
||||
decl.vbs.remove(vb1);
|
||||
decl.vbs.remove(vb2);
|
||||
VariableBinding vb = decl.vbs.get(0);
|
||||
vb.getParentBlock().replaceChild(p, vb);
|
||||
|
||||
Block b = a1.getParentBlock();
|
||||
b.removeChild(a1);
|
||||
b.removeChild(a2);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reduces
|
||||
* vb = x.y op z; (3)
|
||||
* x.y = vb; (4)
|
||||
* ...
|
||||
* expr(vb);
|
||||
* to incremental form
|
||||
* expr(x.y op= z) or expr(++x.y);
|
||||
* Likewise decrement.
|
||||
*/
|
||||
private boolean reduceYCrement(VariableDeclaration decl) {
|
||||
Assignment a1 = null;
|
||||
Assignment a2 = null;
|
||||
VariableBinding vb1 = null;
|
||||
VariableBinding vb2 = null;
|
||||
|
||||
Assignable fa1 = null;
|
||||
Assignable fa2 = null;
|
||||
|
||||
InfixExpression infixExpr = null;
|
||||
|
||||
Iterator iter = decl.vbs.iterator();
|
||||
|
||||
while (iter.hasNext()) {
|
||||
VariableBinding vb = (VariableBinding) iter.next();
|
||||
|
||||
if (!(vb.getParentNode() instanceof Assignment)) continue;
|
||||
|
||||
Assignment a = (Assignment) vb.getParentNode();
|
||||
if (a.getRightHandSide() == vb && a.getLeftHandSide() instanceof Assignable) {
|
||||
vb2 = vb;
|
||||
a2 = a;
|
||||
fa2 = (Assignable) a.getLeftHandSide();
|
||||
continue;
|
||||
}
|
||||
|
||||
if (a.getLeftHandSide() == vb && a.getRightHandSide() instanceof InfixExpression) {
|
||||
InfixExpression infix = (InfixExpression) a.getRightHandSide();
|
||||
if (!(infix.getLeftOperand() instanceof Assignable)) continue;
|
||||
vb1 = vb;
|
||||
a1 = a;
|
||||
fa1 = (Assignable) infix.getLeftOperand();
|
||||
infixExpr = infix;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (a1 == null || a2 == null) return false;
|
||||
if (!fa1.isSame(fa2)) return false;
|
||||
|
||||
decl.vbs.remove(vb1);
|
||||
decl.vbs.remove(vb2);
|
||||
VariableBinding vb = decl.vbs.get(0);
|
||||
Expression replacement = null;
|
||||
|
||||
PStarExpression.Operator operator = getOp(infixExpr);
|
||||
if (operator != null) {
|
||||
PrefixExpression p = new PrefixExpression();
|
||||
p.setOperand((Expression) fa1);
|
||||
p.setOperator(operator);
|
||||
replacement = p;
|
||||
} else {
|
||||
InfixExpression.Operator op = infixExpr.getOperator();
|
||||
Assignment.Operator opp = Assignment.Operator.lookup(op.toString() + '=');
|
||||
Assignment a = new Assignment(opp);
|
||||
a.setLeftHandSide((Expression) fa2);
|
||||
a.setRightHandSide(infixExpr.getRightOperand());
|
||||
replacement = a;
|
||||
}
|
||||
|
||||
vb.getParentBlock().replaceChild(replacement, vb);
|
||||
|
||||
Block b = a1.getParentBlock();
|
||||
b.removeChild(a1);
|
||||
b.removeChild(a2);
|
||||
return true;
|
||||
}
|
||||
|
||||
public void optimize() {
|
||||
if (false) return;
|
||||
// Review this code. For example j2js.fa(obj, name)++ is illegal!
|
||||
|
||||
Iterator iter = tempDecls.iterator();
|
||||
while (iter.hasNext()) {
|
||||
VariableDeclaration decl = (VariableDeclaration) iter.next();
|
||||
int count = decl.vbs.size();
|
||||
if (count == 3) {
|
||||
if (reduceXCrement(decl)) {
|
||||
iter.remove();
|
||||
methodDecl.removeLocalVariable(decl.getName());
|
||||
} else if (reduceYCrement(decl)) {
|
||||
iter.remove();
|
||||
methodDecl.removeLocalVariable(decl.getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
25
src/main/java/com/j2js/ParseException.java
Normal file
25
src/main/java/com/j2js/ParseException.java
Normal file
@ -0,0 +1,25 @@
|
||||
package com.j2js;
|
||||
|
||||
import com.j2js.dom.ASTNode;
|
||||
|
||||
/**
|
||||
* @author kuehn
|
||||
*/
|
||||
public class ParseException extends RuntimeException {
|
||||
|
||||
private ASTNode astNode;
|
||||
|
||||
public ParseException(String msg, ASTNode node) {
|
||||
super(msg);
|
||||
astNode = node;
|
||||
}
|
||||
|
||||
public ParseException(Throwable cause, ASTNode node) {
|
||||
super(cause);
|
||||
astNode = node;
|
||||
}
|
||||
|
||||
public ASTNode getAstNode() {
|
||||
return astNode;
|
||||
}
|
||||
}
|
204
src/main/java/com/j2js/Parser.java
Normal file
204
src/main/java/com/j2js/Parser.java
Normal file
@ -0,0 +1,204 @@
|
||||
package com.j2js;
|
||||
|
||||
import com.j2js.J2JSCompiler;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Modifier;
|
||||
|
||||
import com.j2js.Pass1;
|
||||
import com.j2js.ParseException;
|
||||
|
||||
import org.apache.bcel.classfile.Attribute;
|
||||
import org.apache.bcel.classfile.AttributeReader;
|
||||
import org.apache.bcel.classfile.ClassParser;
|
||||
import org.apache.bcel.classfile.JavaClass;
|
||||
import org.apache.bcel.classfile.ConstantPool;
|
||||
import org.apache.bcel.classfile.Method;
|
||||
import org.apache.bcel.classfile.Field;
|
||||
import org.apache.bcel.generic.ObjectType;
|
||||
import org.apache.bcel.generic.Type;
|
||||
|
||||
import com.j2js.assembly.ClassUnit;
|
||||
import com.j2js.assembly.Project;
|
||||
import com.j2js.assembly.Signature;
|
||||
import com.j2js.dom.*;
|
||||
|
||||
/**
|
||||
* @author wolfgang
|
||||
*/
|
||||
public class Parser {
|
||||
|
||||
public static String getResourcePath(String name) {
|
||||
name = name.replace('.', '/') + ".class";
|
||||
java.net.URL url = Parser.class.getClassLoader().getResource(name);
|
||||
if (url == null) throw new RuntimeException("Resource not found: " + name);
|
||||
return url.getPath();
|
||||
}
|
||||
|
||||
private JavaClass jc;
|
||||
private ClassUnit fileUnit;
|
||||
|
||||
public Parser(ClassUnit theFileUnit) {
|
||||
fileUnit = theFileUnit;
|
||||
fileUnit.annotations = null;
|
||||
|
||||
AttributeReader r = new AnnotationReader(fileUnit);
|
||||
Attribute.addAttributeReader("RuntimeVisibleAnnotations", r);
|
||||
|
||||
try {
|
||||
ClassParser cp = new ClassParser(fileUnit.getClassFile().openInputStream(), fileUnit.getName());
|
||||
jc = cp.parse();
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public TypeDeclaration parse() {
|
||||
|
||||
// Attribute[] attributes = jc.getAttributes();
|
||||
// for (int i=0; i<attributes.length; i++) {
|
||||
// Logger.getLogger().info(attributes[i].toString());
|
||||
// }
|
||||
|
||||
org.apache.bcel.classfile.Method[] bcelMethods = jc.getMethods();
|
||||
|
||||
ObjectType type = new ObjectType(jc.getClassName());
|
||||
TypeDeclaration typeDecl = new TypeDeclaration(type, jc.getAccessFlags());
|
||||
|
||||
fileUnit.isInterface = Modifier.isInterface(typeDecl.getAccess());
|
||||
|
||||
if (!type.getClassName().equals("java.lang.Object")) {
|
||||
// For an interface, the super class is always java.lang.Object, see 4.1 VM Spec.
|
||||
// TODO Interface: Why cant we ignore it?
|
||||
//if (!Modifier.isInterface(typeDecl.getAccess())) {
|
||||
ObjectType superType = new ObjectType(jc.getSuperclassName());
|
||||
typeDecl.setSuperType(superType);
|
||||
ClassUnit superUnit = Project.getSingleton().getOrCreateClassUnit(superType.getClassName());
|
||||
fileUnit.setSuperUnit(superUnit);
|
||||
//}
|
||||
|
||||
// TODO: This should be executed also for java.lang.Object.
|
||||
String[] interfaceNames = jc.getInterfaceNames();
|
||||
for (int i=0; i<interfaceNames.length; i++) {
|
||||
ObjectType interfaceType = new ObjectType(interfaceNames[i]);
|
||||
ClassUnit interfaceUnit = Project.getSingleton().getOrCreateClassUnit(interfaceType.getClassName());
|
||||
fileUnit.addInterface(interfaceUnit);
|
||||
}
|
||||
}
|
||||
|
||||
Field[] fields = jc.getFields();
|
||||
for (int i=0; i<fields.length; i++) {
|
||||
Field field = fields[i];
|
||||
VariableDeclaration variableDecl = new VariableDeclaration(VariableDeclaration.NON_LOCAL);
|
||||
variableDecl.setName(field.getName());
|
||||
variableDecl.setModifiers(field.getModifiers());
|
||||
variableDecl.setType(field.getType());
|
||||
|
||||
typeDecl.addField(variableDecl);
|
||||
}
|
||||
|
||||
for (int i=0; i<bcelMethods.length; i++) {
|
||||
Method method = bcelMethods[i];
|
||||
|
||||
// Java 5 generates a "bridge synthetic" accessor method for some
|
||||
// methods used in a generic context (for example Comparator.compare(Object, Object)
|
||||
// will call Comparator.compare(String, String)). Those methods are essential!
|
||||
//if (Modifier.isVolatile(method.getAccessFlags())) continue;
|
||||
|
||||
MethodBinding binding = MethodBinding.lookup(jc.getClassName(), method.getName(), method.getSignature());
|
||||
|
||||
if (J2JSCompiler.compiler.getSingleEntryPoint() != null) {
|
||||
Signature signature = Project.getSingleton().getSignature(binding.toString());
|
||||
String singleSignature = J2JSCompiler.compiler.getSingleEntryPoint();
|
||||
if (!signature.toString().equals(singleSignature)) continue;
|
||||
}
|
||||
|
||||
MethodDeclaration methodDecl = new MethodDeclaration(binding, method.getAccessFlags(), method.getCode());
|
||||
typeDecl.addMethod(methodDecl);
|
||||
|
||||
parseMethod(typeDecl, methodDecl, method);
|
||||
}
|
||||
|
||||
return typeDecl;
|
||||
}
|
||||
|
||||
public void parseMethod(TypeDeclaration typeDecl, MethodDeclaration methodDecl, Method method) {
|
||||
Type[] types = method.getArgumentTypes();
|
||||
|
||||
int offset;
|
||||
if (Modifier.isStatic(methodDecl.getAccess())) {
|
||||
offset = 0;
|
||||
} else {
|
||||
// Reference to this is first argument for member method.
|
||||
offset = 1;
|
||||
}
|
||||
for (int i=0; i<types.length; i++) {
|
||||
VariableDeclaration variableDecl = new VariableDeclaration(VariableDeclaration.LOCAL_PARAMETER);
|
||||
variableDecl.setName(VariableDeclaration.getLocalVariableName(method, offset, 0));
|
||||
variableDecl.setType(types[i]);
|
||||
methodDecl.addParameter(variableDecl);
|
||||
offset += types[i].getSize();
|
||||
}
|
||||
|
||||
if (methodDecl.getCode() == null) return;
|
||||
|
||||
Log.getLogger().debug("Parsing " + methodDecl.toString());
|
||||
Pass1 pass1 = new Pass1(jc);
|
||||
|
||||
try {
|
||||
pass1.parse(method, methodDecl);
|
||||
} catch (Throwable ex) {
|
||||
ASTNode node = null;
|
||||
if (ex instanceof ParseException) {
|
||||
node = ((ParseException) ex).getAstNode();
|
||||
} else {
|
||||
node = Pass1.getCurrentNode();
|
||||
}
|
||||
|
||||
if (J2JSCompiler.compiler.isFailOnError()) {
|
||||
throw Utils.generateException(ex, methodDecl, node);
|
||||
} else {
|
||||
String msg = Utils.generateExceptionMessage(methodDecl, node);
|
||||
J2JSCompiler.errorCount++;
|
||||
Log.getLogger().error(msg + "\n" + Utils.stackTraceToString(ex));
|
||||
}
|
||||
|
||||
Block body = new Block();
|
||||
ThrowStatement throwStmt = new ThrowStatement();
|
||||
MethodBinding binding = MethodBinding.lookup("java.lang.RuntimeException", "<init>", "(java/lang/String)V;");
|
||||
ClassInstanceCreation cic = new ClassInstanceCreation(methodDecl, binding);
|
||||
cic.addArgument(new StringLiteral("Unresolved decompilation problem"));
|
||||
throwStmt.setExpression(cic);
|
||||
body.appendChild(throwStmt);
|
||||
methodDecl.setBody(body);
|
||||
|
||||
}
|
||||
|
||||
// Remove from body last expressionless return statement.
|
||||
if (J2JSCompiler.compiler.optimize && methodDecl.getBody().getLastChild() instanceof ReturnStatement) {
|
||||
ReturnStatement ret = (ReturnStatement) methodDecl.getBody().getLastChild();
|
||||
if (ret.getExpression() == null) {
|
||||
methodDecl.getBody().removeChild(ret);
|
||||
}
|
||||
}
|
||||
|
||||
Pass1.dump(methodDecl.getBody(), "Body of " + methodDecl.toString());
|
||||
|
||||
// if (typeDecl.getClassName().equals("java.lang.String")) {
|
||||
// if (methodDecl.isInstanceConstructor()) {
|
||||
//
|
||||
// }
|
||||
// }
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
public ConstantPool getConstantPool() {
|
||||
return jc.getConstantPool();
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return jc.getClassName();
|
||||
}
|
||||
|
||||
}
|
2233
src/main/java/com/j2js/Pass1.java
Normal file
2233
src/main/java/com/j2js/Pass1.java
Normal file
File diff suppressed because it is too large
Load Diff
160
src/main/java/com/j2js/Utils.java
Normal file
160
src/main/java/com/j2js/Utils.java
Normal file
@ -0,0 +1,160 @@
|
||||
package com.j2js;
|
||||
|
||||
import com.j2js.J2JSCompiler;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
import java.text.DateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.Properties;
|
||||
|
||||
|
||||
import org.apache.bcel.generic.ArrayType;
|
||||
import org.apache.bcel.generic.BasicType;
|
||||
import org.apache.bcel.generic.ObjectType;
|
||||
import org.apache.bcel.generic.Type;
|
||||
|
||||
import com.j2js.dom.ASTNode;
|
||||
import com.j2js.dom.MethodDeclaration;
|
||||
|
||||
/**
|
||||
* @author j2js.com
|
||||
*/
|
||||
public final class Utils {
|
||||
|
||||
private static final String propertiesFile = "j2js.properties";
|
||||
private static final Properties properties;
|
||||
|
||||
static {
|
||||
properties = new Properties();
|
||||
try {
|
||||
properties.load(Utils.class.getClassLoader().getResourceAsStream(propertiesFile));
|
||||
} catch (Exception e) {
|
||||
J2JSCompiler.errorCount++;
|
||||
Log.getLogger().error("Could not read from classpath: " + propertiesFile);
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private Utils() {}
|
||||
|
||||
public static String generateExceptionMessage(MethodDeclaration methodDecl, ASTNode node) {
|
||||
String msg = null;
|
||||
if (node != null) {
|
||||
int line = methodDecl.getLineNumberCursor().getLineNumber(node);
|
||||
if (line != -1) {
|
||||
msg = "Error near line " + line;
|
||||
}
|
||||
}
|
||||
if (msg == null) {
|
||||
msg = "Error";
|
||||
}
|
||||
|
||||
msg += " in " + methodDecl.getMethodBinding();
|
||||
|
||||
return msg;
|
||||
}
|
||||
|
||||
public static RuntimeException generateException(Throwable e, MethodDeclaration methodDecl, ASTNode node) {
|
||||
String msg = generateExceptionMessage(methodDecl, node);
|
||||
J2JSCompiler.errorCount++;
|
||||
Log.getLogger().error(msg);
|
||||
return new RuntimeException(msg, e);
|
||||
}
|
||||
|
||||
public static String stackTraceToString(Throwable e) {
|
||||
StringWriter sw = new StringWriter();
|
||||
PrintWriter writer = new PrintWriter(sw);
|
||||
e.printStackTrace(writer);
|
||||
writer.close();
|
||||
return sw.getBuffer().toString();
|
||||
}
|
||||
|
||||
public static String currentTimeStamp() {
|
||||
return DateFormat.getDateTimeInstance().format(new Date());
|
||||
}
|
||||
|
||||
public static String getVersion() {
|
||||
return (String) properties.get("j2js.version");
|
||||
}
|
||||
|
||||
public static String getProperty(String key) {
|
||||
return (String) properties.get(key);
|
||||
}
|
||||
|
||||
public static String getSignature(Type type) {
|
||||
String signature;
|
||||
|
||||
if (type instanceof ArrayType) {
|
||||
ArrayType aType = (ArrayType) type;
|
||||
signature = getSignature(aType.getBasicType());
|
||||
for (int i = 0; i<aType.getDimensions(); i++) {
|
||||
signature += "[]";
|
||||
}
|
||||
} else if (type instanceof ObjectType) {
|
||||
signature = ((ObjectType) type).getClassName();
|
||||
} else {
|
||||
if (!(type instanceof BasicType)) throw new RuntimeException();
|
||||
signature = type.toString();
|
||||
}
|
||||
|
||||
return signature;
|
||||
}
|
||||
|
||||
public static String escape(String str) {
|
||||
int len = str.length();
|
||||
StringBuffer buf = new StringBuffer(len + 5);
|
||||
char[] ch = str.toCharArray();
|
||||
|
||||
for (int i = 0; i < len; i++) {
|
||||
switch (ch[i]) {
|
||||
case '\\' :
|
||||
buf.append("\\\\");
|
||||
break;
|
||||
case '\n' :
|
||||
buf.append("\\n");
|
||||
break;
|
||||
case '\r' :
|
||||
buf.append("\\r");
|
||||
break;
|
||||
case '\t' :
|
||||
buf.append("\\t");
|
||||
break;
|
||||
case '\b' :
|
||||
buf.append("\\b");
|
||||
break;
|
||||
case '"' :
|
||||
buf.append("\\\"");
|
||||
break;
|
||||
default :
|
||||
buf.append(ch[i]);
|
||||
}
|
||||
}
|
||||
|
||||
return '"' + buf.toString() + '"';
|
||||
}
|
||||
|
||||
|
||||
|
||||
// public static File[] resolvePackage(File[] classPath, String signature) {
|
||||
// File dir = resolve(classPath, signature.replaceAll("\\.", "/"));
|
||||
// if (!dir.isDirectory()) {
|
||||
// throw new RuntimeException("Package " + signature + " could not be resolved");
|
||||
// }
|
||||
// return dir.listFiles();
|
||||
// }
|
||||
|
||||
/**
|
||||
* If path is absolute, returns the file with the given path. Otherwise returns
|
||||
* the file with path resolved against baseDir.
|
||||
*/
|
||||
public static File resolve(File baseDir, String path) {
|
||||
File resolvedFile = new File(path);
|
||||
if (!resolvedFile.isAbsolute()) {
|
||||
resolvedFile = new File(baseDir, path);
|
||||
}
|
||||
return resolvedFile;
|
||||
}
|
||||
|
||||
}
|
288
src/main/java/com/j2js/assembly/ClassUnit.java
Normal file
288
src/main/java/com/j2js/assembly/ClassUnit.java
Normal file
@ -0,0 +1,288 @@
|
||||
package com.j2js.assembly;
|
||||
|
||||
import com.j2js.J2JSCompiler;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Writer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
|
||||
import com.j2js.FileObject;
|
||||
import com.j2js.Log;
|
||||
|
||||
/**
|
||||
* Instances of ClassUnit represent classes and interfaces managed by a project.
|
||||
*
|
||||
* @author wolle
|
||||
*/
|
||||
public class ClassUnit extends Unit {
|
||||
|
||||
static final long serialVersionUID = 1;
|
||||
|
||||
// Time stamp at which unit was last compiled.
|
||||
private long lastCompiled;
|
||||
|
||||
/**
|
||||
* Returns the time stamp at which the class file was last modified.
|
||||
*/
|
||||
public long getLastModified() {
|
||||
return getClassFile().getLastModified();
|
||||
}
|
||||
|
||||
// All members declared by this class, mapped by relative signature.
|
||||
private Map<String, MemberUnit> declaredMembers;
|
||||
|
||||
// The super class.
|
||||
private ClassUnit superUnit;
|
||||
|
||||
// All interfaces implemented by this unit.
|
||||
private Collection<ClassUnit> interfaces;
|
||||
|
||||
// All derived classes.
|
||||
private Collection<ClassUnit> subUnits;
|
||||
|
||||
public boolean isInterface = false;
|
||||
|
||||
public boolean isConstructorTainted = false;
|
||||
|
||||
public Map<String, String>[] annotations;
|
||||
|
||||
private Project project;
|
||||
|
||||
// Transient fields start here.
|
||||
private transient boolean isResolved = false;
|
||||
|
||||
// The class file of this unit.
|
||||
private transient FileObject classFile;
|
||||
|
||||
public ClassUnit() {
|
||||
}
|
||||
|
||||
public ClassUnit(Project theProject, Signature theSignature) {
|
||||
project = theProject;
|
||||
|
||||
interfaces = new HashSet<ClassUnit>();
|
||||
declaredMembers = new HashMap<String, MemberUnit>();
|
||||
subUnits = new HashSet<ClassUnit>();
|
||||
lastCompiled = -1;
|
||||
setSignature(theSignature);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset all fields filled by compilation.
|
||||
*/
|
||||
void clear() {
|
||||
// Do not remove registered subunits!
|
||||
lastCompiled = -1;
|
||||
removeInterfaces();
|
||||
setSuperUnit(null);
|
||||
declaredMembers.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this unit is up to date.
|
||||
*/
|
||||
public boolean isUpToDate() {
|
||||
return lastCompiled >= getLastModified();
|
||||
}
|
||||
|
||||
public Collection<ClassUnit> getInterfaces() {
|
||||
return interfaces;
|
||||
}
|
||||
|
||||
public void addInterface(ClassUnit interfaceUnit) {
|
||||
interfaces.add(interfaceUnit);
|
||||
//interfaceUnit.addSubUnit(this);
|
||||
}
|
||||
|
||||
private void removeInterfaces() {
|
||||
Iterator iter = interfaces.iterator();
|
||||
while (iter.hasNext()) {
|
||||
ClassUnit interfaceUnit = (ClassUnit) iter.next();
|
||||
interfaceUnit.removeSubUnit(this);
|
||||
iter.remove();
|
||||
}
|
||||
}
|
||||
|
||||
public void addSubUnit(ClassUnit subUnit) {
|
||||
if (subUnit == null) throw new NullPointerException();
|
||||
subUnits.add(subUnit);
|
||||
}
|
||||
|
||||
public void removeSubUnit(ClassUnit subUnit) {
|
||||
if (subUnit == null) throw new NullPointerException();
|
||||
subUnits.remove(subUnit);
|
||||
}
|
||||
|
||||
public Collection<ClassUnit> getSubUnits() {
|
||||
return subUnits;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the declared member with the specified signature.
|
||||
*/
|
||||
public MemberUnit getDeclaredMember(String signature) {
|
||||
if (signature == null) throw new NullPointerException();
|
||||
return declaredMembers.get(signature);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all types to which this class can be converted, i.e., the collection of
|
||||
* all supertypes and implemented interfaces and the class itself.
|
||||
*/
|
||||
public Collection<ClassUnit> getSupertypes() {
|
||||
TypeCollector collector = new TypeCollector();
|
||||
project.visitSuperTypes(this, collector);
|
||||
return collector.collectedTypes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a member object that reflects the specified public member method of the class
|
||||
* or interface represented by this Class object.
|
||||
*/
|
||||
// public MemberUnit getMember(String signature) {
|
||||
// if (signature == null) throw new NullPointerException();
|
||||
//
|
||||
// ClassUnit clazz = this;
|
||||
// do {
|
||||
// MemberUnit member = clazz.getDeclaredMember(signature);
|
||||
// if (member != null) return member;
|
||||
// clazz = clazz.getSuperUnit();
|
||||
// } while (clazz != null);
|
||||
//
|
||||
// return null;
|
||||
// }
|
||||
|
||||
public Collection<MemberUnit> getMembers(String signature) {
|
||||
if (signature == null) throw new NullPointerException();
|
||||
ArrayList<MemberUnit> list = new ArrayList<MemberUnit>();
|
||||
|
||||
for (ClassUnit clazz : getSupertypes()) {
|
||||
MemberUnit member = clazz.getDeclaredMember(signature);
|
||||
if (member != null) list.add(member);
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
public Collection<MemberUnit> getDeclaredMembers() {
|
||||
if (!isResolved) throw new RuntimeException("Class is not yet resolved: " + getName());
|
||||
return declaredMembers.values();
|
||||
}
|
||||
|
||||
public void addMemberUnit(MemberUnit unit) {
|
||||
declaredMembers.put(unit.getSignature().toString(), unit);
|
||||
}
|
||||
|
||||
public ClassUnit getSuperUnit() {
|
||||
return superUnit;
|
||||
}
|
||||
|
||||
public void setSuperUnit(ClassUnit theSuperUnit) {
|
||||
if (superUnit != null) {
|
||||
superUnit.removeSubUnit(this);
|
||||
}
|
||||
superUnit = theSuperUnit;
|
||||
if (superUnit != null) {
|
||||
superUnit.addSubUnit(this);
|
||||
}
|
||||
}
|
||||
|
||||
public void write(int depth, Writer writer) throws IOException {
|
||||
if (!isTainted()) return;
|
||||
|
||||
Log.getLogger().debug(getIndent(depth) + this);
|
||||
|
||||
if (getData() != null) {
|
||||
writer.write(getData());
|
||||
} else {
|
||||
// TODO: Is it correct to return so soon?
|
||||
return;
|
||||
}
|
||||
|
||||
if (interfaces.size() > 0) {
|
||||
//Logger.getLogger().info("Class + " + this.getName() + " has interfaces: ");
|
||||
|
||||
writer.write("_T.interfaces = [");
|
||||
int i = 0;
|
||||
for (ClassUnit interFace : interfaces) {
|
||||
//Logger.getLogger().info(">>>" + interFace.getName());
|
||||
if (i++ > 0) writer.write(", ");
|
||||
writer.write(String.valueOf(interFace.getSignature().getId()));
|
||||
}
|
||||
writer.write("];\n");
|
||||
}
|
||||
|
||||
if (annotations != null) {
|
||||
writer.write("_T.annotations = ");
|
||||
Serializer serializer = new Serializer(writer);
|
||||
serializer.serialize(annotations);
|
||||
writer.write(";\n");
|
||||
}
|
||||
|
||||
for (MemberUnit member : getDeclaredMembers()) {
|
||||
if (member.isTainted()) {
|
||||
member.write(depth + 1, writer);
|
||||
if (member instanceof ProcedureUnit) {
|
||||
project.currentGeneratedMethods++;
|
||||
writer.flush();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (ClassUnit child : getSubUnits()) {
|
||||
// TODO Interface: Interfaces must not extend java.lang.Object!
|
||||
//if (!child.isInterface) {
|
||||
child.write(depth + 1, writer);
|
||||
//}
|
||||
}
|
||||
}
|
||||
|
||||
void setSignature(Signature theSignature) {
|
||||
super.setSignature(theSignature);
|
||||
}
|
||||
|
||||
public FileObject getClassFile() {
|
||||
if (classFile == null) {
|
||||
classFile = J2JSCompiler.compiler.fileManager.getFileForInput(
|
||||
getSignature().toString().replaceAll("\\.", "/") + ".class");
|
||||
}
|
||||
return classFile;
|
||||
}
|
||||
|
||||
public void setLastCompiled(long theLastCompiled) {
|
||||
lastCompiled = theLastCompiled;
|
||||
}
|
||||
|
||||
public boolean isResolved() {
|
||||
return isResolved;
|
||||
}
|
||||
|
||||
public void setSuperTainted() {
|
||||
ClassUnit clazz = this;
|
||||
do {
|
||||
clazz.setTainted();
|
||||
clazz = clazz.getSuperUnit();
|
||||
} while (clazz != null);
|
||||
|
||||
for (ClassUnit i : interfaces) {
|
||||
i.setSuperTainted();
|
||||
}
|
||||
}
|
||||
|
||||
public void setResolved(boolean theIsResolved) {
|
||||
isResolved = theIsResolved;
|
||||
}
|
||||
public String getName() {
|
||||
return getSignature().className();
|
||||
}
|
||||
|
||||
public Project getProject() {
|
||||
return project;
|
||||
}
|
||||
|
||||
}
|
14
src/main/java/com/j2js/assembly/ConstructorUnit.java
Normal file
14
src/main/java/com/j2js/assembly/ConstructorUnit.java
Normal file
@ -0,0 +1,14 @@
|
||||
package com.j2js.assembly;
|
||||
|
||||
/**
|
||||
* ConstructorUnit provides information about, and access to, a single constructor for a class.
|
||||
*
|
||||
* @author wolle
|
||||
*/
|
||||
public class ConstructorUnit extends ProcedureUnit {
|
||||
|
||||
public ConstructorUnit(Signature theSignature, ClassUnit theDeclaringClazz) {
|
||||
super(theSignature, theDeclaringClazz);
|
||||
}
|
||||
|
||||
}
|
21
src/main/java/com/j2js/assembly/FieldUnit.java
Normal file
21
src/main/java/com/j2js/assembly/FieldUnit.java
Normal file
@ -0,0 +1,21 @@
|
||||
package com.j2js.assembly;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Writer;
|
||||
|
||||
/**
|
||||
* A FieldUnit provides information about, and dynamic access to, a single field of a class or an interface.
|
||||
*
|
||||
* @author wolle
|
||||
*/
|
||||
public class FieldUnit extends MemberUnit {
|
||||
|
||||
public FieldUnit(Signature theSignature, ClassUnit theDeclaringClazz) {
|
||||
super(theSignature, theDeclaringClazz);
|
||||
}
|
||||
|
||||
void write(int depth, Writer writer) throws IOException {
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
69
src/main/java/com/j2js/assembly/JavaScriptCompressor.java
Normal file
69
src/main/java/com/j2js/assembly/JavaScriptCompressor.java
Normal file
@ -0,0 +1,69 @@
|
||||
package com.j2js.assembly;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
|
||||
public class JavaScriptCompressor {
|
||||
|
||||
private int CODE = 0;
|
||||
private int LINECOMMENT = 1;
|
||||
private int MULTILINECOMMENT = 2;
|
||||
private int STRING = 3;
|
||||
|
||||
public String compress(InputStream input) throws FileNotFoundException, IOException {
|
||||
BufferedReader reader = new BufferedReader(new InputStreamReader(input));
|
||||
StringBuffer buffer = new StringBuffer();
|
||||
int state = CODE;
|
||||
char c;
|
||||
char lastC = 0;
|
||||
|
||||
do {
|
||||
int i = reader.read();
|
||||
if (i == -1) break;
|
||||
c = (char) i;
|
||||
|
||||
if (state == LINECOMMENT) {
|
||||
if (c == '\n') {
|
||||
state = CODE;
|
||||
buffer.append(c);
|
||||
} // else ignore character.
|
||||
} else if (state == MULTILINECOMMENT) {
|
||||
if (c == '/' && lastC == '*') {
|
||||
state = CODE;
|
||||
} // else ignore character.
|
||||
} else if (state == STRING) {
|
||||
if (c == '"') {
|
||||
state = CODE;
|
||||
}
|
||||
buffer.append(c);
|
||||
} else if (c == '/' && lastC == c) {
|
||||
state = LINECOMMENT;
|
||||
buffer.deleteCharAt(buffer.length()-1);
|
||||
} else if (c == '*' && lastC == '/') {
|
||||
state = MULTILINECOMMENT;
|
||||
buffer.deleteCharAt(buffer.length()-1);
|
||||
} else if (c == '"') {
|
||||
state = STRING;
|
||||
buffer.append(c);
|
||||
} else {
|
||||
int length = buffer.length();
|
||||
if (length > 0 && Character.isWhitespace(c) && Character.isWhitespace(buffer.charAt(length-1))) {
|
||||
|
||||
} else {
|
||||
buffer.append(c);
|
||||
}
|
||||
}
|
||||
lastC = c;
|
||||
} while (true);
|
||||
|
||||
reader.close();
|
||||
|
||||
return buffer.toString();
|
||||
}
|
||||
|
||||
}
|
81
src/main/java/com/j2js/assembly/JunkWriter.java
Normal file
81
src/main/java/com/j2js/assembly/JunkWriter.java
Normal file
@ -0,0 +1,81 @@
|
||||
package com.j2js.assembly;
|
||||
|
||||
import com.j2js.J2JSCompiler;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileWriter;
|
||||
import java.io.FilterWriter;
|
||||
import java.io.IOException;
|
||||
import java.io.StringWriter;
|
||||
|
||||
import com.j2js.Log;
|
||||
|
||||
public class JunkWriter extends FilterWriter {
|
||||
|
||||
private File assembly;
|
||||
private int junkCount = 0;
|
||||
private int sizeOfCurrentJunk;
|
||||
private int sizeOfAllJunks = 0;
|
||||
|
||||
public JunkWriter(File assembly) throws IOException {
|
||||
super(new StringWriter());
|
||||
this.assembly = assembly;
|
||||
startNewJunk();
|
||||
}
|
||||
|
||||
private void startNewJunk() throws IOException {
|
||||
sizeOfAllJunks += sizeOfCurrentJunk;
|
||||
|
||||
if (junkCount > 0) {
|
||||
write("j2js.loadScript(" + sizeOfAllJunks + ");");
|
||||
out.flush();
|
||||
out.close();
|
||||
}
|
||||
|
||||
Log logger = Log.getLogger();
|
||||
String newJunkName = (junkCount + 1) + ".js";
|
||||
logger.info("Creating assembly " + newJunkName);
|
||||
out = new FileWriter(new File(assembly, newJunkName));
|
||||
sizeOfCurrentJunk = 0;
|
||||
junkCount++;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(char[] cbuf, int off, int len) throws IOException {
|
||||
super.write(cbuf, off, len);
|
||||
sizeOfCurrentJunk += len;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(int c) throws IOException {
|
||||
super.write(c);
|
||||
sizeOfCurrentJunk++;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(String str, int off, int len) throws IOException {
|
||||
super.write(str, off, len);
|
||||
sizeOfCurrentJunk += len;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void flush() throws IOException {
|
||||
super.flush();
|
||||
if (sizeOfCurrentJunk/1024 > J2JSCompiler.compiler.getJunkSizeInKiloBytes()) {
|
||||
startNewJunk();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
sizeOfAllJunks += sizeOfCurrentJunk;
|
||||
// Set to 0 in case super.close() calls flush().
|
||||
sizeOfCurrentJunk = 0;
|
||||
super.close();
|
||||
}
|
||||
|
||||
public int getSize() {
|
||||
return sizeOfAllJunks;
|
||||
}
|
||||
|
||||
}
|
32
src/main/java/com/j2js/assembly/MemberUnit.java
Normal file
32
src/main/java/com/j2js/assembly/MemberUnit.java
Normal file
@ -0,0 +1,32 @@
|
||||
package com.j2js.assembly;
|
||||
|
||||
/**
|
||||
* The MemberUnit class is the base class for Field, Method and Constructor objects.
|
||||
*
|
||||
* @author wolle
|
||||
*/
|
||||
public abstract class MemberUnit extends Unit {
|
||||
|
||||
// The class to which this method belongs.
|
||||
ClassUnit declaringClass;
|
||||
|
||||
MemberUnit(Signature theSignature, ClassUnit theDeclaringClazz) {
|
||||
setSignature(theSignature);
|
||||
declaringClass = theDeclaringClazz;
|
||||
declaringClass.addMemberUnit(this);
|
||||
}
|
||||
|
||||
public ClassUnit getDeclaringClass() {
|
||||
return declaringClass;
|
||||
}
|
||||
|
||||
public Signature getAbsoluteSignature() {
|
||||
Signature s = Project.getSingleton().getSignature(declaringClass.toString(), getSignature().toString());
|
||||
return s;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return declaringClass.getName() + "#" + super.toString();
|
||||
}
|
||||
|
||||
}
|
14
src/main/java/com/j2js/assembly/MethodUnit.java
Normal file
14
src/main/java/com/j2js/assembly/MethodUnit.java
Normal file
@ -0,0 +1,14 @@
|
||||
package com.j2js.assembly;
|
||||
|
||||
/**
|
||||
* A MethodUnit provides information about, and access to, a single method on a class or interface.
|
||||
*
|
||||
* @author wolle
|
||||
*/
|
||||
public class MethodUnit extends ProcedureUnit {
|
||||
|
||||
public MethodUnit(Signature theSignature, ClassUnit theDeclaringClazz) {
|
||||
super(theSignature, theDeclaringClazz);
|
||||
}
|
||||
|
||||
}
|
51
src/main/java/com/j2js/assembly/ProcedureUnit.java
Normal file
51
src/main/java/com/j2js/assembly/ProcedureUnit.java
Normal file
@ -0,0 +1,51 @@
|
||||
package com.j2js.assembly;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Writer;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
|
||||
import com.j2js.Log;
|
||||
|
||||
public abstract class ProcedureUnit extends MemberUnit {
|
||||
|
||||
// Set of all member signatures targeted by this method.
|
||||
private Collection<Signature> targetSignatures = new HashSet<Signature>();
|
||||
|
||||
public ProcedureUnit(Signature theSignature, ClassUnit theDeclaringClazz) {
|
||||
super(theSignature, theDeclaringClazz);
|
||||
}
|
||||
|
||||
public void addTarget(Signature targetSignature) {
|
||||
if (!targetSignature.toString().contains("#")) {
|
||||
throw new IllegalArgumentException("Signature must be field or method: " + targetSignature);
|
||||
}
|
||||
//Logger.getLogger().info("Adding " + this + " -> " + targetSignature);
|
||||
targetSignatures.add(targetSignature);
|
||||
}
|
||||
|
||||
public void removeTargets() {
|
||||
Iterator iter = targetSignatures.iterator();
|
||||
while (iter.hasNext()) {
|
||||
iter.next();
|
||||
iter.remove();
|
||||
}
|
||||
}
|
||||
|
||||
void write(int depth, Writer writer) throws IOException {
|
||||
if (getData() == null) return;
|
||||
Log.getLogger().debug(getIndent(depth) + getSignature());
|
||||
writer.write(getData());
|
||||
}
|
||||
|
||||
public String getData() {
|
||||
if (!declaringClass.isResolved()) throw new RuntimeException("Class must be resolved");
|
||||
return super.getData();
|
||||
}
|
||||
|
||||
public Collection<Signature> getTargetSignatures() {
|
||||
return targetSignatures;
|
||||
}
|
||||
|
||||
}
|
330
src/main/java/com/j2js/assembly/Project.java
Normal file
330
src/main/java/com/j2js/assembly/Project.java
Normal file
@ -0,0 +1,330 @@
|
||||
package com.j2js.assembly;
|
||||
|
||||
import com.j2js.J2JSCompiler;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.io.Serializable;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Stack;
|
||||
|
||||
import org.apache.bcel.generic.ArrayType;
|
||||
import org.apache.bcel.generic.ObjectType;
|
||||
import org.apache.bcel.generic.ReferenceType;
|
||||
import org.apache.bcel.generic.Type;
|
||||
|
||||
import com.j2js.Log;
|
||||
import com.j2js.Utils;
|
||||
import com.j2js.dom.ArrayCreation;
|
||||
import com.j2js.dom.FieldAccess;
|
||||
import com.j2js.dom.MethodBinding;
|
||||
import com.j2js.dom.MethodDeclaration;
|
||||
import com.j2js.dom.MethodInvocation;
|
||||
import com.j2js.dom.TypeDeclaration;
|
||||
|
||||
public class Project implements Serializable {
|
||||
|
||||
static final long serialVersionUID = 0;
|
||||
|
||||
private static Project singleton;
|
||||
|
||||
// All managed classes mapped by class name.
|
||||
private Map<String, ClassUnit> classesByName;
|
||||
private ClassUnit javaLangObject;
|
||||
private boolean compressed;
|
||||
private boolean generateLineNumbers;
|
||||
private Map<String, Signature> signatures;
|
||||
|
||||
private transient Stack<Integer> ids;
|
||||
private transient int currentId;
|
||||
private transient int currentIndex;
|
||||
|
||||
public transient int currentGeneratedMethods;
|
||||
|
||||
public static Project getSingleton() {
|
||||
if (singleton == null) throw new NullPointerException();
|
||||
return singleton;
|
||||
}
|
||||
|
||||
public static Project createSingleton(File cacheFile) {
|
||||
|
||||
if (cacheFile != null && cacheFile.exists()) {
|
||||
Log.getLogger().info("Using cache " + cacheFile);
|
||||
try {
|
||||
read(cacheFile);
|
||||
} catch (Exception e) {
|
||||
Log.getLogger().warn("Could not read cache:\n" + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
if (singleton == null ||
|
||||
singleton.compressed != J2JSCompiler.compiler.isCompression() ||
|
||||
singleton.generateLineNumbers != J2JSCompiler.compiler.isGenerateLineNumbers()) {
|
||||
// Cache does not exist, could not be read, or compression does not match.
|
||||
singleton = new Project();
|
||||
singleton.clear();
|
||||
}
|
||||
|
||||
return singleton;
|
||||
}
|
||||
|
||||
private static void read(File file) throws Exception {
|
||||
FileInputStream fis = new FileInputStream(file);
|
||||
ObjectInputStream ois = new ObjectInputStream(fis);
|
||||
singleton = (Project) ois.readObject();
|
||||
ois.close();
|
||||
}
|
||||
|
||||
public static void write() throws IOException {
|
||||
File file = J2JSCompiler.compiler.getCacheFile();
|
||||
if (file.exists() && !file.canWrite()) {
|
||||
throw new IOException("Cannot write " + file);
|
||||
}
|
||||
FileOutputStream fos = new FileOutputStream(file);
|
||||
ObjectOutputStream oos = new ObjectOutputStream(fos);
|
||||
oos.writeObject(singleton);
|
||||
oos.close();
|
||||
}
|
||||
|
||||
public Signature getArraySignature(Type type) {
|
||||
String signatureString = type.getSignature();
|
||||
/* Examples:
|
||||
* L[java.lang.Integer;; -> [java.lang.Integer;
|
||||
* L[I; -> [I
|
||||
*/
|
||||
if (!signatureString.startsWith("L") || !signatureString.endsWith(";")) {
|
||||
throw new RuntimeException("Not a class signature: " + signatureString);
|
||||
}
|
||||
signatureString = signatureString.substring(1, signatureString.length()-1);
|
||||
return getSignature(signatureString);
|
||||
}
|
||||
|
||||
/**
|
||||
* All request for a signature delegate to this method.
|
||||
*/
|
||||
public Signature getSignature(String signatureString) {
|
||||
if (signatureString.endsWith(";")) {
|
||||
//throw new RuntimeException("Invalid signature: " + signatureString);
|
||||
}
|
||||
signatureString = signatureString.replaceAll("/", ".");
|
||||
|
||||
Signature signature = signatures.get(signatureString);
|
||||
if (signature == null) {
|
||||
signature = new Signature(signatureString, getUniqueId());
|
||||
signatures.put(signatureString, signature);
|
||||
}
|
||||
|
||||
return signature;
|
||||
}
|
||||
|
||||
public Signature getSignature(String className, String relativeSignature) {
|
||||
return getSignature(className + '#' + relativeSignature);
|
||||
}
|
||||
|
||||
public Signature getSignature(FieldAccess fa) {
|
||||
return getSignature(fa.getType().getClassName(), fa.getName());
|
||||
}
|
||||
|
||||
private int getUniqueId() {
|
||||
if (ids == null) {
|
||||
ids = new Stack<Integer>();
|
||||
for (Signature signature : signatures.values()) {
|
||||
ids.add(signature.getId());
|
||||
}
|
||||
Collections.sort(ids);
|
||||
}
|
||||
|
||||
while (currentIndex<ids.size() && ids.get(currentIndex) == currentId) {
|
||||
currentId += 1;
|
||||
currentIndex += 1;
|
||||
}
|
||||
|
||||
currentId++;
|
||||
return currentId - 1;
|
||||
}
|
||||
|
||||
private void clear() {
|
||||
classesByName = new HashMap<String, ClassUnit>();
|
||||
javaLangObject = null;
|
||||
|
||||
signatures = new HashMap<String, Signature>();
|
||||
ids = null;
|
||||
currentId = 0;
|
||||
currentIndex = 0;
|
||||
compressed = J2JSCompiler.compiler.isCompression();
|
||||
generateLineNumbers = J2JSCompiler.compiler.isGenerateLineNumbers();
|
||||
}
|
||||
|
||||
public void remove(ClassUnit clazz) {
|
||||
classesByName.remove(clazz);
|
||||
}
|
||||
|
||||
void visitSuperTypes(ClassUnit clazz, TypeVisitor visitor) {
|
||||
visitor.visit(clazz);
|
||||
ClassUnit superClass = clazz.getSuperUnit();
|
||||
if (superClass != null) {
|
||||
visitSuperTypes(superClass, visitor);
|
||||
}
|
||||
|
||||
for (ClassUnit interfaceUnit : clazz.getInterfaces()) {
|
||||
visitor.visit(interfaceUnit);
|
||||
visitSuperTypes(interfaceUnit, visitor);
|
||||
}
|
||||
}
|
||||
|
||||
public ClassUnit getJavaLangObject() {
|
||||
return javaLangObject;
|
||||
}
|
||||
|
||||
public ClassUnit getClassUnit(String className) {
|
||||
ClassUnit clazz = classesByName.get(className);
|
||||
if (clazz != null) return clazz;
|
||||
|
||||
throw new RuntimeException("No such unit: " + className);
|
||||
}
|
||||
|
||||
public ClassUnit getClassUnit(ReferenceType type) {
|
||||
String signature;
|
||||
if (type instanceof ArrayType) {
|
||||
ArrayType aType = (ArrayType) type;
|
||||
signature = Utils.getSignature(aType.getBasicType());
|
||||
for (int i = 0; i<aType.getDimensions(); i++) {
|
||||
signature += "[]";
|
||||
}
|
||||
} else {
|
||||
signature = Utils.getSignature(type);
|
||||
}
|
||||
|
||||
return getClassUnit(signature);
|
||||
}
|
||||
|
||||
public ClassUnit getOrCreateClassUnit(String className) {
|
||||
ClassUnit classUnit = classesByName.get(className);
|
||||
if (classUnit != null) return classUnit;
|
||||
|
||||
Signature signature = Project.singleton.getSignature(className);
|
||||
classUnit = new ClassUnit(this, signature);
|
||||
classesByName.put(className, classUnit);
|
||||
|
||||
if (className.equals("java.lang.Object")) {
|
||||
javaLangObject = classUnit;
|
||||
}
|
||||
|
||||
return classUnit;
|
||||
}
|
||||
|
||||
private MemberUnit getMemberUnitOrNull(String className, Signature signature) {
|
||||
ClassUnit classUnit = getOrCreateClassUnit(className);
|
||||
if (classUnit == null) return null;
|
||||
return classUnit.getDeclaredMember(signature.toString());
|
||||
}
|
||||
|
||||
private MemberUnit getMemberUnit(String className, Signature signature) {
|
||||
MemberUnit unit = getMemberUnitOrNull(className, signature);
|
||||
if (unit == null) {
|
||||
throw new RuntimeException("No such unit: " + className + "#"+ signature);
|
||||
}
|
||||
|
||||
return unit;
|
||||
}
|
||||
|
||||
public ProcedureUnit getProcedureUnit(MethodBinding methodBinding) {
|
||||
Signature signature = Project.singleton.getSignature(methodBinding.getRelativeSignature());
|
||||
String className = methodBinding.getDeclaringClass().getClassName();
|
||||
return (ProcedureUnit) getMemberUnit(className, signature);
|
||||
}
|
||||
|
||||
public ProcedureUnit getOrCreateProcedureUnit(MethodBinding methodBinding) {
|
||||
Signature signature = Project.singleton.getSignature(methodBinding.getRelativeSignature());
|
||||
String className = methodBinding.getDeclaringClass().getClassName();
|
||||
return (ProcedureUnit) getOrCreateMemberUnit(className, signature);
|
||||
}
|
||||
|
||||
private MemberUnit getOrCreateMemberUnit(String className, Signature signature) {
|
||||
MemberUnit member = getMemberUnitOrNull(className, signature);
|
||||
|
||||
if (member == null) {
|
||||
ClassUnit clazz = getClassUnit(className);
|
||||
if (signature.isMethod()) {
|
||||
member = new MethodUnit(signature, clazz);
|
||||
} else if (signature.isConstructor()) {
|
||||
member = new ConstructorUnit(signature, clazz);
|
||||
} else {
|
||||
member = new FieldUnit(signature, clazz);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
return member;
|
||||
}
|
||||
|
||||
// public Unit getOrCreateUnit(String signature) {
|
||||
// String array[] = signature.split("#");
|
||||
// Unit unit;
|
||||
// if (array.length == 1) {
|
||||
// unit = getOrCreateClassUnit(signature);
|
||||
// } else {
|
||||
// unit = getOrCreateMemberUnit(array[0], Project.singleton.getSignature(array[1]));
|
||||
// }
|
||||
// return unit;
|
||||
// }
|
||||
|
||||
public FieldUnit getOrCreateFieldUnit(ObjectType type, String name) {
|
||||
return (FieldUnit) getOrCreateMemberUnit(type.getClassName(), Project.singleton.getSignature(name));
|
||||
}
|
||||
|
||||
public void addReference(MethodDeclaration decl, FieldAccess fa) {
|
||||
ProcedureUnit source = getOrCreateProcedureUnit(decl.getMethodBinding());
|
||||
source.addTarget(Project.singleton.getSignature(fa));
|
||||
}
|
||||
|
||||
public void addReference(MethodDeclaration decl, MethodInvocation invocation) {
|
||||
ProcedureUnit source = getOrCreateProcedureUnit(decl.getMethodBinding());
|
||||
source.addTarget(Project.singleton.getSignature(invocation.getMethodBinding().toString()));
|
||||
}
|
||||
|
||||
public void addReference(MethodDeclaration decl, ArrayCreation ac) {
|
||||
ProcedureUnit source = getOrCreateProcedureUnit(decl.getMethodBinding());
|
||||
Signature signature = Project.getSingleton().getArraySignature(ac.getTypeBinding());
|
||||
for (int i = 0; i<ac.getDimensions().size(); i++) {
|
||||
// TODO: Target must be a field or method. Is length the right way?
|
||||
source.addTarget(Project.singleton.getSignature(signature.toString().substring(i)+"#length"));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a live collection of all classes managed by this project.
|
||||
*/
|
||||
public Collection<ClassUnit> getClasses() {
|
||||
return classesByName.values();
|
||||
}
|
||||
|
||||
public void resolve(ClassUnit clazz) {
|
||||
if (clazz.isResolved()) return;
|
||||
|
||||
if (clazz.getName().startsWith("[")) {
|
||||
// This is an array type and not a class.
|
||||
clazz.setSuperUnit(getJavaLangObject());
|
||||
//clazz.setTainted();
|
||||
clazz.setResolved(true);
|
||||
// We need a member (and we chose length) in addReference(..) to taint the class.
|
||||
new FieldUnit(getSignature("length"), clazz);
|
||||
|
||||
TypeDeclaration typeDecl = new TypeDeclaration(new ObjectType(clazz.getName()), 0);
|
||||
typeDecl.setSuperType(Type.OBJECT);
|
||||
typeDecl.visit(J2JSCompiler.compiler.generator);
|
||||
} else {
|
||||
TypeResolver resolver = new TypeResolver(this, J2JSCompiler.compiler.generator);
|
||||
visitSuperTypes(clazz, resolver);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
153
src/main/java/com/j2js/assembly/Serializer.java
Normal file
153
src/main/java/com/j2js/assembly/Serializer.java
Normal file
@ -0,0 +1,153 @@
|
||||
package com.j2js.assembly;
|
||||
|
||||
import java.util.List;
|
||||
import java.io.IOException;
|
||||
import java.io.NotSerializableException;
|
||||
import java.io.Writer;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.Map;
|
||||
|
||||
public class Serializer {
|
||||
private Writer writer;
|
||||
private SimpleDateFormat dateFormatter = new SimpleDateFormat("dd.MM.yyyy");
|
||||
|
||||
/** Creates a new instance of Serializer */
|
||||
public Serializer(Writer theWriter) {
|
||||
writer = theWriter;
|
||||
}
|
||||
|
||||
public void serialize(Object object) throws NotSerializableException {
|
||||
try {
|
||||
this.serializeInternal(object);
|
||||
} catch (IOException e) {
|
||||
throw new NotSerializableException(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private void serializeInternal(Object object) throws IOException {
|
||||
if (object==null) {
|
||||
writer.write("null");
|
||||
} else if (object instanceof String) {
|
||||
quote((String)object);
|
||||
} else if (object instanceof Number) {
|
||||
numberToString((Number) object);
|
||||
} else if (object instanceof Map) {
|
||||
serializeMap((Map) object);
|
||||
} else if (object instanceof List) {
|
||||
serializeArray((List) object);
|
||||
} else if (object.getClass().isArray()) {
|
||||
serializeArray((Object[]) object);// && object.getClass().getComponentType().equals(Double.TYPE) double[]) object);
|
||||
} else if (object instanceof Boolean) {
|
||||
writer.write(((Boolean)object).toString());
|
||||
} else if (object instanceof Date) {
|
||||
quote(dateFormatter.format((Date) object));
|
||||
} else {
|
||||
throw serializeError("Unknown object type " + object.getClass().toString());
|
||||
}
|
||||
}
|
||||
|
||||
private void serializeArray(List list) throws IOException {
|
||||
String sep = "";
|
||||
|
||||
writer.write('[');
|
||||
for (Object o : list) {
|
||||
writer.write(sep);
|
||||
sep = ",";
|
||||
this.serializeInternal(o);
|
||||
}
|
||||
writer.write(']');
|
||||
}
|
||||
|
||||
private void serializeArray(Object[] array) throws IOException {
|
||||
String sep = "";
|
||||
|
||||
writer.write('[');
|
||||
for (int i=0; i<array.length; i++) {
|
||||
writer.write(sep);
|
||||
sep = ",";
|
||||
serializeInternal(array[i]);
|
||||
}
|
||||
writer.write(']');
|
||||
}
|
||||
|
||||
private void serializeMap(Map<String, ?> map) throws IOException {
|
||||
String sep = "";
|
||||
|
||||
writer.write('{');
|
||||
for (String key : map.keySet()) {
|
||||
writer.write(sep);
|
||||
sep = ",";
|
||||
Object value = map.get(key);
|
||||
if (key.matches("\\w*")) {
|
||||
writer.write(key);
|
||||
} else {
|
||||
writer.write("\"" + key + "\"");
|
||||
}
|
||||
|
||||
writer.write(':');
|
||||
this.serializeInternal(value);
|
||||
}
|
||||
writer.write('}');
|
||||
}
|
||||
|
||||
/**
|
||||
* Stream a numeric value.
|
||||
* @exception NotSerializableException If number is infinite or not a number.
|
||||
* @param n A Number
|
||||
* @return A String.
|
||||
*/
|
||||
private void numberToString(Number n) throws IOException {
|
||||
if (n instanceof Double && (((Double) n).isInfinite() || ((Double) n).isNaN())) {
|
||||
throw serializeError("Can only serialize finite numbers");
|
||||
}
|
||||
if (n instanceof Float && (((Float) n).isInfinite() || ((Float) n).isNaN())) {
|
||||
throw serializeError("Can only serialize finite numbers");
|
||||
}
|
||||
|
||||
writer.write(n.toString().toLowerCase());
|
||||
}
|
||||
|
||||
private void numberToString(double n) throws IOException {
|
||||
writer.write(String.valueOf(n));
|
||||
}
|
||||
|
||||
/**
|
||||
* Stream a string in double quotes " with the following backslash replacements:
|
||||
* " -> \"
|
||||
* \ -> \\
|
||||
* @param string A String
|
||||
*/
|
||||
private void quote(String s) throws IOException {
|
||||
if (s == null) {
|
||||
writer.write("null");
|
||||
return;
|
||||
}
|
||||
writer.write('"');
|
||||
int l = s.length();
|
||||
for (int i=0; i<l; i++) {
|
||||
char c = s.charAt(i);
|
||||
switch (c) {
|
||||
case '\"':
|
||||
writer.write("\\\"");
|
||||
break;
|
||||
case '\\':
|
||||
writer.write("\\\\");
|
||||
break;
|
||||
case '\r':
|
||||
writer.write("\\r");
|
||||
break;
|
||||
case '\n':
|
||||
writer.write("\\n");
|
||||
break;
|
||||
default:
|
||||
writer.write(c);
|
||||
}
|
||||
}
|
||||
writer.write('"');
|
||||
}
|
||||
|
||||
private NotSerializableException serializeError(String message) {
|
||||
return new NotSerializableException(message);
|
||||
}
|
||||
}
|
106
src/main/java/com/j2js/assembly/Signature.java
Normal file
106
src/main/java/com/j2js/assembly/Signature.java
Normal file
@ -0,0 +1,106 @@
|
||||
package com.j2js.assembly;
|
||||
|
||||
import com.j2js.J2JSCompiler;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
|
||||
/**
|
||||
* An instance of class Signature represents the signature of
|
||||
* a field, a constructor, a method, or a class.
|
||||
*
|
||||
* @author wolle
|
||||
*/
|
||||
public class Signature implements Serializable {
|
||||
|
||||
private String signatureString;
|
||||
private int id;
|
||||
|
||||
Signature(String theSignatureString, int theId) {
|
||||
signatureString = theSignatureString;
|
||||
id = theId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Examples:
|
||||
* Ljava.lang.Integer; -> java.lang.Integer
|
||||
* L[I; -> [I
|
||||
*/
|
||||
// public String getClassName() {
|
||||
// if (!signatureString.startsWith("L") || !signatureString.endsWith(";")) {
|
||||
// throw new RuntimeException("Not a class signature: " + signatureString);
|
||||
// }
|
||||
// return signatureString.substring(1, signatureString.length()-1);
|
||||
// }
|
||||
|
||||
public int hashCode() {
|
||||
return signatureString.hashCode();
|
||||
}
|
||||
|
||||
public boolean equals(Object obj) {
|
||||
if (obj instanceof Signature) {
|
||||
return signatureString.equals(((Signature) obj).signatureString);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return signatureString;
|
||||
}
|
||||
|
||||
public boolean isClass() {
|
||||
return signatureString.indexOf('#') == -1;
|
||||
}
|
||||
|
||||
public boolean isArrayType() {
|
||||
return isClass() && signatureString.startsWith("[");
|
||||
}
|
||||
|
||||
public boolean isConstructor() {
|
||||
return signatureString.startsWith("<init>");
|
||||
}
|
||||
|
||||
public boolean isMethod() {
|
||||
return !isConstructor() && signatureString.indexOf('(') != -1;
|
||||
}
|
||||
|
||||
public boolean isField() {
|
||||
return !isClass() && signatureString.indexOf('(') == -1;
|
||||
}
|
||||
|
||||
public String className() {
|
||||
String array[] = signatureString.split("#");
|
||||
//if (array[0].startsWith("[")) array[0] = array[0].substring(1);
|
||||
return array[0];
|
||||
}
|
||||
|
||||
public String relativeSignature() {
|
||||
String array[] = signatureString.split("#");
|
||||
if (array.length != 2) {
|
||||
throw new RuntimeException("Not a method signature: " + this);
|
||||
}
|
||||
return array[1];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the relative signature.
|
||||
*/
|
||||
public Signature relative() {
|
||||
return Project.getSingleton().getSignature(relativeSignature());
|
||||
}
|
||||
|
||||
public int getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public String getCommentedId() {
|
||||
StringBuffer sb = new StringBuffer();
|
||||
sb.append(String.valueOf(getId()));
|
||||
if (!J2JSCompiler.compiler.isCompression()) {
|
||||
sb.append(" /*");
|
||||
sb.append(toString());
|
||||
sb.append("*/");
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
13
src/main/java/com/j2js/assembly/TypeCollector.java
Normal file
13
src/main/java/com/j2js/assembly/TypeCollector.java
Normal file
@ -0,0 +1,13 @@
|
||||
package com.j2js.assembly;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
|
||||
public class TypeCollector implements TypeVisitor {
|
||||
|
||||
Collection<ClassUnit> collectedTypes = new HashSet<ClassUnit>();
|
||||
|
||||
public void visit(ClassUnit clazz) {
|
||||
collectedTypes.add(clazz);
|
||||
}
|
||||
}
|
77
src/main/java/com/j2js/assembly/TypeResolver.java
Normal file
77
src/main/java/com/j2js/assembly/TypeResolver.java
Normal file
@ -0,0 +1,77 @@
|
||||
package com.j2js.assembly;
|
||||
|
||||
import com.j2js.J2JSCompiler;
|
||||
|
||||
import com.j2js.Log;
|
||||
import com.j2js.Parser;
|
||||
import com.j2js.dom.TypeDeclaration;
|
||||
import com.j2js.visitors.JavaScriptGenerator;
|
||||
|
||||
public class TypeResolver implements TypeVisitor {
|
||||
|
||||
private JavaScriptGenerator generator;
|
||||
private Project project;
|
||||
|
||||
public TypeResolver(Project theProject, JavaScriptGenerator theGenerator) {
|
||||
project = theProject;
|
||||
generator = theGenerator;
|
||||
}
|
||||
|
||||
public void visit(ClassUnit clazz) {
|
||||
if (clazz.isResolved()) return;
|
||||
|
||||
Log logger = Log.getLogger();
|
||||
|
||||
if (clazz.getSignature().toString().startsWith("[")) {
|
||||
// Class is an array class without class file: Do nothing.
|
||||
} else if (!clazz.isUpToDate()) {
|
||||
clazz.clear();
|
||||
try {
|
||||
compile(clazz);
|
||||
J2JSCompiler.compiler.compileCount++;
|
||||
} catch (RuntimeException ex) {
|
||||
J2JSCompiler.errorCount++;
|
||||
logger.error(ex.toString());
|
||||
//ex.printStackTrace();
|
||||
if (J2JSCompiler.compiler.failOnError) {
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
logger.debug("Up to date: " + clazz);
|
||||
}
|
||||
|
||||
clazz.setResolved(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Compiles the unit.
|
||||
*/
|
||||
private void compile(ClassUnit classUnit) {
|
||||
|
||||
if (classUnit.getClassFile() == null) {
|
||||
Log.getLogger().warn("Cannot read " + classUnit.getClassFile());
|
||||
return;
|
||||
}
|
||||
|
||||
Log.getLogger().info("Cross-Compiling " + classUnit);
|
||||
|
||||
TypeDeclaration typeDecl = parse(classUnit);
|
||||
|
||||
// TODO
|
||||
//if (!Modifier.isInterface(typeDecl.getAccess())) {
|
||||
typeDecl.visit(generator);
|
||||
//}
|
||||
|
||||
// Set not current date but date of last modification. This is
|
||||
// independent of system clock.
|
||||
classUnit.setLastCompiled(classUnit.getLastModified());
|
||||
}
|
||||
|
||||
private TypeDeclaration parse(ClassUnit classUnit) {
|
||||
Parser parser = new Parser(classUnit);
|
||||
TypeDeclaration typeDecl = parser.parse();
|
||||
|
||||
return typeDecl;
|
||||
}
|
||||
}
|
5
src/main/java/com/j2js/assembly/TypeVisitor.java
Normal file
5
src/main/java/com/j2js/assembly/TypeVisitor.java
Normal file
@ -0,0 +1,5 @@
|
||||
package com.j2js.assembly;
|
||||
|
||||
public interface TypeVisitor {
|
||||
public void visit(ClassUnit clazz);
|
||||
}
|
62
src/main/java/com/j2js/assembly/Unit.java
Normal file
62
src/main/java/com/j2js/assembly/Unit.java
Normal file
@ -0,0 +1,62 @@
|
||||
package com.j2js.assembly;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Serializable;
|
||||
import java.io.Writer;
|
||||
|
||||
import com.j2js.Log;
|
||||
|
||||
|
||||
public abstract class Unit implements Serializable {
|
||||
|
||||
private Signature signature;
|
||||
|
||||
private String data;
|
||||
|
||||
private transient boolean isTainted = false;
|
||||
private static transient String[] indentPerDepth = new String[10];
|
||||
|
||||
public Unit() {
|
||||
}
|
||||
|
||||
abstract void write(int depth, Writer writer) throws IOException;
|
||||
|
||||
String getIndent(int depth) {
|
||||
String indent = indentPerDepth[depth];
|
||||
if (indent == null) {
|
||||
indent = "";
|
||||
for (int i=0; i<depth; i++) indent += '\t';
|
||||
}
|
||||
return indent;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return signature.toString();
|
||||
}
|
||||
|
||||
public Signature getSignature() {
|
||||
return signature;
|
||||
}
|
||||
|
||||
void setSignature(Signature theSignature) {
|
||||
signature = theSignature;
|
||||
}
|
||||
|
||||
public String getData() {
|
||||
return data;
|
||||
}
|
||||
|
||||
public void setData(String theData) {
|
||||
data = theData;
|
||||
}
|
||||
|
||||
public boolean isTainted() {
|
||||
return isTainted;
|
||||
}
|
||||
|
||||
public void setTainted() {
|
||||
if (!isTainted) Log.getLogger().debug("Taint " + this);
|
||||
isTainted = true;
|
||||
}
|
||||
|
||||
}
|
84
src/main/java/com/j2js/builder/Configuration.java
Normal file
84
src/main/java/com/j2js/builder/Configuration.java
Normal file
@ -0,0 +1,84 @@
|
||||
package com.j2js.builder;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.net.URI;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import javax.xml.bind.JAXBContext;
|
||||
import javax.xml.bind.Marshaller;
|
||||
import javax.xml.bind.Unmarshaller;
|
||||
import javax.xml.bind.annotation.XmlElement;
|
||||
import javax.xml.bind.annotation.XmlRootElement;
|
||||
|
||||
|
||||
@XmlRootElement(name = "j2js-configuration")
|
||||
public class Configuration {
|
||||
|
||||
@XmlElement(name = "basedir")
|
||||
public File basedir = new File(".");
|
||||
|
||||
@XmlElement(name = "uaCommand", required = true)
|
||||
public String uaCommand;
|
||||
|
||||
@XmlElement(name = "uaArg")
|
||||
public List<String> uaArgs = new ArrayList<String>();
|
||||
|
||||
@XmlElement(name = "devModeWebSocketURL", required = true)
|
||||
public URI devModeWebSocketURL;
|
||||
|
||||
@XmlElement(name = "devModeHttpURL", required = true)
|
||||
public URI devModeHttpURL;
|
||||
|
||||
public void write(OutputStream os) {
|
||||
try {
|
||||
JAXBContext context = JAXBContext.newInstance(Configuration.class);
|
||||
Marshaller m = context.createMarshaller();
|
||||
m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
|
||||
m.marshal(this, os);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static Configuration read() {
|
||||
File file = new File(System.getProperty("user.home") + "/.m2/j2js.xml");
|
||||
InputStream is = null;
|
||||
try {
|
||||
is = new FileInputStream(file);
|
||||
} catch (FileNotFoundException e) {
|
||||
throw new RuntimeException("Could not read file " + file);
|
||||
}
|
||||
System.out.println("Reading j2js configuration from " + file);
|
||||
return Configuration.read(is);
|
||||
}
|
||||
|
||||
public static Configuration read(InputStream inStream) {
|
||||
JAXBContext context;
|
||||
try {
|
||||
context = JAXBContext.newInstance(Configuration.class);
|
||||
Unmarshaller um = context.createUnmarshaller();
|
||||
return (Configuration) um.unmarshal(inStream);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
// public ApplicationConfiguration getApplicationConfiguration(String applicationName) {
|
||||
// if ( applicationName == null ) {
|
||||
// throw new NullPointerException("applicationName cannot be null.");
|
||||
// }
|
||||
//
|
||||
// for (ApplicationConfiguration applConfig : applications) {
|
||||
// if ( applicationName.equals(applConfig.applicationName) ) {
|
||||
// return applConfig;
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// return null;
|
||||
// }
|
||||
}
|
29
src/main/java/com/j2js/cfg/ConditionalEdge.java
Normal file
29
src/main/java/com/j2js/cfg/ConditionalEdge.java
Normal file
@ -0,0 +1,29 @@
|
||||
package com.j2js.cfg;
|
||||
|
||||
import com.j2js.dom.BooleanExpression;
|
||||
|
||||
public class ConditionalEdge extends Edge {
|
||||
|
||||
private BooleanExpression expression;
|
||||
private boolean negate = false;
|
||||
|
||||
ConditionalEdge(Graph graph, Node theSource, Node theTarget) {
|
||||
super(graph, theSource, theTarget);
|
||||
}
|
||||
|
||||
public BooleanExpression getBooleanExpression() {
|
||||
return expression;
|
||||
}
|
||||
|
||||
public void setBooleanExpression(BooleanExpression expr) {
|
||||
expression = expr;
|
||||
}
|
||||
|
||||
public boolean isNegate() {
|
||||
return negate;
|
||||
}
|
||||
|
||||
public void setNegate(boolean theNegate) {
|
||||
negate = theNegate;
|
||||
}
|
||||
}
|
387
src/main/java/com/j2js/cfg/ControlFlowGraph.java
Normal file
387
src/main/java/com/j2js/cfg/ControlFlowGraph.java
Normal file
@ -0,0 +1,387 @@
|
||||
package com.j2js.cfg;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.SortedMap;
|
||||
import java.util.TreeMap;
|
||||
|
||||
import com.j2js.ASTNodeStack;
|
||||
import com.j2js.cfg.transformation.Transformation;
|
||||
import com.j2js.dom.ASTNode;
|
||||
import com.j2js.dom.Block;
|
||||
import com.j2js.dom.BooleanExpression;
|
||||
import com.j2js.dom.InfixExpression;
|
||||
import com.j2js.dom.TryStatement;
|
||||
|
||||
/**
|
||||
* Instances of this class represent a Control Flow Graph CFG.
|
||||
*/
|
||||
public class ControlFlowGraph extends Graph {
|
||||
|
||||
// Ordering is only used by method getNodeAt().
|
||||
private SortedMap<Integer, Node> nodesByPc = new TreeMap<Integer, Node>();
|
||||
|
||||
// The single entry point of control.
|
||||
private Node sourceNode;
|
||||
|
||||
private List tryStatements;
|
||||
|
||||
public ControlFlowGraph(List theTryStatements) {
|
||||
tryStatements = theTryStatements;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the try statement which contains the specified node.
|
||||
*/
|
||||
private TryStatement selectTryStatement(Node node) {
|
||||
int pc = node.getInitialPc();
|
||||
for (int i=0; i<tryStatements.size(); i++) {
|
||||
TryStatement tryStmt = (TryStatement) tryStatements.get(i);
|
||||
Block block = tryStmt.getTryBlock();
|
||||
if (pc >= block.getBeginIndex() && pc <= block.getEndIndex()) return tryStmt;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
public Node createNode(int pc) {
|
||||
return createNode(pc, Node.class);
|
||||
}
|
||||
|
||||
public Node getOrCreateNode(int pc) {
|
||||
Node node = getNode(pc);
|
||||
if (node == null) {
|
||||
node = createNode(pc, Node.class);
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
public Node createNode(int pc, Class nodeClass) {
|
||||
if (pc < 0) throw new RuntimeException("Program counter may not be negative");
|
||||
|
||||
Node node = super.createNode(nodeClass);
|
||||
node.setInitialPc(pc);
|
||||
if (nodesByPc.put(node.getInitialPc(), node) != null) {
|
||||
throw new RuntimeException("Node already exists: " + node);
|
||||
}
|
||||
|
||||
if (pc == 0) sourceNode = node;
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the largest (w.r. to its initial pc) node closest to the specified pc.
|
||||
*/
|
||||
public Node getNodeAt(int pc) {
|
||||
int minPcDelta = Integer.MAX_VALUE;
|
||||
Node node = null;
|
||||
for (Node n : getNodes()) {
|
||||
if (n.getInitialPc() <= pc && pc-n.getInitialPc() < minPcDelta) {
|
||||
minPcDelta = pc-n.getInitialPc();
|
||||
node = n;
|
||||
if (minPcDelta == 0) return node;
|
||||
}
|
||||
}
|
||||
|
||||
if (node == null) {
|
||||
throw new RuntimeException("No node at pc " + pc);
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
/**
|
||||
* Splits a node at the given pc value into two nodes nodeA and nodeB.
|
||||
* nodeB will start at pc and will have the outbound edges of the original node, and an
|
||||
* extra edge is added from nodeA to nodeB.
|
||||
*/
|
||||
public Node split(Node node, int pc) {
|
||||
if (node.block.getBeginIndex() >= pc) throw new RuntimeException("Block must contain program counter");
|
||||
|
||||
Node nodeB = createNode(pc);
|
||||
|
||||
// Reroot all outbound edges at nodeB.
|
||||
for (Edge edge : new ArrayList<Edge>(node.getOutEdges())) {
|
||||
edge.reroot(nodeB);
|
||||
}
|
||||
|
||||
addEdge(node, nodeB);
|
||||
|
||||
// Transfer code starting at pc to nodeB.
|
||||
ASTNode astNode = node.block.getFirstChild();
|
||||
while (astNode != null) {
|
||||
if (astNode.getBeginIndex() >= pc) {
|
||||
node.setCurrentPc(astNode.getBeginIndex()-1);
|
||||
nodeB.block.appendChildren(astNode, node.block.getLastChild());
|
||||
break;
|
||||
}
|
||||
astNode = astNode.getNextSibling();
|
||||
}
|
||||
|
||||
// Transfer stack to nodeB.
|
||||
nodeB.stack = node.stack;
|
||||
node.stack = new ASTNodeStack();
|
||||
|
||||
return nodeB;
|
||||
}
|
||||
|
||||
public Node[] getOrSplitNodeAt(Node currentNode, int pc) {
|
||||
Node targetNode = getNodeAt(pc);
|
||||
if (targetNode.getInitialPc() != pc) {
|
||||
// No node starts at target pc. We have to split the node.
|
||||
Node nodeB = split(targetNode, pc);
|
||||
if (targetNode == currentNode) {
|
||||
currentNode = nodeB;
|
||||
}
|
||||
targetNode = nodeB;
|
||||
}
|
||||
return new Node[]{currentNode, targetNode};
|
||||
}
|
||||
|
||||
/**
|
||||
* Redirect all incoming edges for try bodys to its try header.
|
||||
*/
|
||||
private void processTrys() {
|
||||
for (int i=0; i<tryStatements.size(); i++) {
|
||||
TryStatement stmt = (TryStatement) tryStatements.get(i);
|
||||
TryHeaderNode header = stmt.header;
|
||||
Node tryNode = header.getTryBody();
|
||||
|
||||
if (tryNode == sourceNode) sourceNode = header;
|
||||
|
||||
for (Edge edge : new ArrayList<Edge>(tryNode.getInEdges())) {
|
||||
int pc = edge.source.getInitialPc();
|
||||
if (pc >= stmt.getBeginIndex() && pc <= stmt.getEndIndex()) continue;
|
||||
if (edge.source == header) continue;
|
||||
edge.redirect(header);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reroots all local edges exiting a try body at the corresponding try header.
|
||||
*/
|
||||
private void processTrys2() {
|
||||
for (Node node: nodesByPc.values()) {
|
||||
TryStatement sourceTry = selectTryStatement(node);
|
||||
if (sourceTry == null) continue;
|
||||
|
||||
for (Edge edge : node.getOutEdges()) {
|
||||
if (edge.target.getInEdges().size() != 1) {
|
||||
continue;
|
||||
}
|
||||
TryStatement targetTry = selectTryStatement(edge.target);
|
||||
if (targetTry == null || targetTry != sourceTry) {
|
||||
edge.reroot(sourceTry.header);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reroot the fall through successor directly at the try header.
|
||||
*/
|
||||
private void processTrys1() {
|
||||
for (int i=0; i<tryStatements.size(); i++) {
|
||||
TryStatement stmt = (TryStatement) tryStatements.get(i);
|
||||
TryHeaderNode header = stmt.header;
|
||||
Node finallyNode = header.getFinallyNode();
|
||||
if (finallyNode == null) continue;
|
||||
|
||||
Iterator iter = finallyNode.jsrCallers.iterator();
|
||||
while (iter.hasNext()) {
|
||||
Node node = (Node) iter.next();
|
||||
// TODO: Be independant of pc!
|
||||
if (node.getInitialPc() > finallyNode.getInitialPc()) {
|
||||
removeInEdges(node);
|
||||
addEdge(header, node);
|
||||
node.setDomParent(header);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Node getSource() {
|
||||
return sourceNode;
|
||||
}
|
||||
|
||||
public Node getNode(int pc) {
|
||||
return nodesByPc.get(pc);
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the set of all successors of the specified predecessor which are not dominated by it.
|
||||
* Each node in this set is then marked as a global target of the predecessor.
|
||||
* If the predecessor is a branch, then a newly created node will function as the referer.
|
||||
*/
|
||||
private void markGlobalTargets(Node predecessor) {
|
||||
for (Edge edge : predecessor.getOutEdges()) {
|
||||
Node target = edge.target;
|
||||
if (target.getDomParent() == predecessor)
|
||||
continue;
|
||||
|
||||
if (predecessor.isBranch()) {
|
||||
Node node = createNode(Node.class);
|
||||
edge.redirect(node);
|
||||
node.setDomParent(predecessor);
|
||||
edge = addEdge(node, target);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* For each node in tree, mark global targets.
|
||||
*/
|
||||
void visitToMark(Node node) {
|
||||
// Be concurrent safe.
|
||||
for (Node child : new ArrayList<Node>(node.getDomChildren())) {
|
||||
visitToMark(child);
|
||||
}
|
||||
|
||||
markGlobalTargets(node);
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursively (depth first) traverses the dominator tree rooted at the specified node and post-processes
|
||||
* all possible reductions.
|
||||
*/
|
||||
void visit(Node node) {
|
||||
|
||||
// Be concurrent safe.
|
||||
for (Node child : new ArrayList<Node>(node.getDomChildren())) {
|
||||
visit(child);
|
||||
}
|
||||
|
||||
do {
|
||||
Transformation t = Transformation.select(this, node);
|
||||
if (t == null) break;
|
||||
node = t.apply();
|
||||
dump("After transformation");
|
||||
} while (true);
|
||||
|
||||
if (node.getDomChildren().size() > 0) {
|
||||
throw new RuntimeException("Could not reduce graph at " + node);
|
||||
}
|
||||
}
|
||||
|
||||
public void replaceNode(Node node, Node newNode) {
|
||||
|
||||
super.replaceNode(node, newNode);
|
||||
|
||||
if (newNode != null) {
|
||||
nodesByPc.put(node.getInitialPc(), newNode);
|
||||
} else {
|
||||
nodesByPc.remove(node.getInitialPc());
|
||||
}
|
||||
|
||||
if (node == sourceNode) {
|
||||
if (newNode == null) {
|
||||
throw new RuntimeException("Cannot remove source node " + sourceNode);
|
||||
}
|
||||
sourceNode = newNode;
|
||||
}
|
||||
}
|
||||
|
||||
public Block reduce() {
|
||||
processTrys();
|
||||
processTrys2();
|
||||
|
||||
dump("Before Shortcuts");
|
||||
processShortcuts();
|
||||
|
||||
DominatorTree builder = new DominatorTree(this);
|
||||
builder.build();
|
||||
|
||||
processTrys1();
|
||||
|
||||
visitToMark(getSource());
|
||||
dump("Begin reduce");
|
||||
|
||||
visit(getSource());
|
||||
|
||||
if (size() != 1) {
|
||||
throw new RuntimeException("Could not reduce graph");
|
||||
}
|
||||
|
||||
Block block = new Block();
|
||||
|
||||
rollOut(getSource(), block);
|
||||
|
||||
return block;
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs an OR or AND shortcut on two branches A and B by replacing them with new node A&B or A|B.
|
||||
*/
|
||||
boolean performAndOrShortcut(Node a, Node b) {
|
||||
if (b.getInEdges().size() != 1) return false;
|
||||
if (b.block.getChildCount() > 0) {
|
||||
// Node b is not a mere conditional.
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
ConditionalEdge aToC;
|
||||
ConditionalEdge bToC;
|
||||
boolean isOR = true;
|
||||
|
||||
while(true) {
|
||||
aToC = a.getConditionalEdge(isOR);
|
||||
bToC = b.getConditionalEdge(isOR);
|
||||
if (bToC.target == aToC.target) break;
|
||||
if (!isOR) return false;
|
||||
isOR = false;
|
||||
}
|
||||
|
||||
if (aToC.target.getInEdges().size() != 2) return false;
|
||||
|
||||
ConditionalEdge bToD = b.getConditionalEdge(!isOR);
|
||||
ConditionalEdge aToB = a.getConditionalEdge(!isOR);
|
||||
|
||||
aToB.redirect(bToD.target);
|
||||
removeEdge(bToC);
|
||||
removeEdge(bToD);
|
||||
removeNode(b);
|
||||
|
||||
InfixExpression infix = new InfixExpression(
|
||||
isOR?InfixExpression.Operator.CONDITIONAL_OR:InfixExpression.Operator.CONDITIONAL_AND);
|
||||
// Note that the order aToC, then bToC is important.
|
||||
infix.setOperands(
|
||||
aToC.getBooleanExpression().getExpression(),
|
||||
bToC.getBooleanExpression().getExpression());
|
||||
|
||||
BooleanExpression be = new BooleanExpression(infix);
|
||||
aToC.setBooleanExpression(be);
|
||||
aToB.setBooleanExpression(be);
|
||||
|
||||
logger.debug("Created shortcut and removed " + b);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public void processShortcuts() {
|
||||
Collection<Node> branches = new HashSet<Node>();
|
||||
for (Node node : getNodes()) {
|
||||
if (node.isBranch()) branches.add(node);
|
||||
}
|
||||
|
||||
L: while (true) {
|
||||
Iterator<Node> iter = branches.iterator();
|
||||
while (iter.hasNext()) {
|
||||
Node branch = iter.next();
|
||||
for (Node node: branch.succs()) {
|
||||
if (node.isBranch() && performAndOrShortcut(branch, node)) {
|
||||
branches.remove(node);
|
||||
continue L;
|
||||
}
|
||||
}
|
||||
}
|
||||
break L;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
233
src/main/java/com/j2js/cfg/DominatorTree.java
Normal file
233
src/main/java/com/j2js/cfg/DominatorTree.java
Normal file
@ -0,0 +1,233 @@
|
||||
package com.j2js.cfg;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import com.j2js.Log;
|
||||
|
||||
/**
|
||||
* Class to build the dominator tree of a given control flow graph.
|
||||
* The algorithm is according Purdum-Moore, which isn't as fast as Lengauer-Tarjan, but a lot simpler.
|
||||
*/
|
||||
public class DominatorTree {
|
||||
|
||||
private ControlFlowGraph graph;
|
||||
|
||||
public DominatorTree(ControlFlowGraph theGraph) {
|
||||
graph = theGraph;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the pre-order index of a node.
|
||||
*/
|
||||
private void visit(Node node, Collection<Node> visited) {
|
||||
// Establish preorder index.
|
||||
node.setPreOrderIndex(visited.size());
|
||||
visited.add(node);
|
||||
|
||||
for (Node succ : node.succs()) {
|
||||
if (! visited.contains(succ)) {
|
||||
visit(succ, visited);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the dominator tree and store it in the respective nodes.
|
||||
* It will remove all unreachable nodes on the way!
|
||||
*/
|
||||
public void build() {
|
||||
|
||||
// Construct list of nodes in pre-order order.
|
||||
ArrayList<Node> preOrder = new ArrayList<Node>();
|
||||
|
||||
visit(graph.getSource(), preOrder);
|
||||
|
||||
// Remove unreachable nodes.
|
||||
for (Node node : new ArrayList<Node>(graph.getNodes())) {
|
||||
if (!preOrder.contains(node)) {
|
||||
Log.getLogger().warn("Unreachable code detected and removed");
|
||||
//Logger.getLogger().info("Removed " + node);
|
||||
graph.removeInEdges(node);
|
||||
graph.removeOutEdges(node);
|
||||
graph.removeNode(node);
|
||||
} else if (node.getPreOrderIndex() == -1) {
|
||||
throw new RuntimeException("Pre-order not set for " + node);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int size = graph.size(); // The number of vertices in the cfg
|
||||
|
||||
Map snkPreds = new HashMap(); // The predacessor vertices from the sink
|
||||
|
||||
|
||||
// Determine the predacessors of the cfg's sink node
|
||||
//insertEdgesToSink(graph, snkPreds, reverse);
|
||||
|
||||
// Get the index of the root
|
||||
int rootIndex = graph.getSource().getPreOrderIndex();
|
||||
|
||||
if (rootIndex < 0 || rootIndex >= size) throw new RuntimeException("Root index out of range");
|
||||
|
||||
// Bit matrix indicating the dominators of each node.
|
||||
// If bit j of dom[i] is set, then node j dominates node i.
|
||||
BitSet[] domMatrix = new BitSet[size];
|
||||
|
||||
// Initially, all the bits in the dominance matrix are set, except
|
||||
// for the root node. The root node is initialized to have itself
|
||||
// as an immediate dominator.
|
||||
for (int i = 0; i < size; i++) {
|
||||
BitSet domVector = new BitSet(size);
|
||||
|
||||
if (i == rootIndex) {
|
||||
// Only root dominates root.
|
||||
domVector.set(rootIndex);
|
||||
}
|
||||
else {
|
||||
// Assume that all nodes dominate non-root node i.
|
||||
domVector.set(0, size);
|
||||
}
|
||||
|
||||
domMatrix[i] = domVector;
|
||||
}
|
||||
|
||||
// Did the dominator bit vector array change?
|
||||
boolean changed;
|
||||
|
||||
do {
|
||||
changed = false;
|
||||
|
||||
// Fetch all nodes in pre-order.
|
||||
Iterator nodes = preOrder.iterator();
|
||||
|
||||
// Compute the dominators of each node in the cfg. We iterate
|
||||
// over every node in the cfg. The dominators of a node N are
|
||||
// found by taking the intersection of the dominator bit vectors
|
||||
// of each predacessor of N and unioning that with N. This
|
||||
// process is repeated until no changes are made to any dominator
|
||||
// bit vector.
|
||||
|
||||
while (nodes.hasNext()) {
|
||||
Node node = (Node) nodes.next();
|
||||
|
||||
int i = node.getPreOrderIndex();
|
||||
|
||||
if (i < 0 || i >= size) throw new RuntimeException("Unreachable node " + node);
|
||||
|
||||
// We already know the dominators of the root, keep looking
|
||||
if (i == rootIndex) {
|
||||
continue;
|
||||
}
|
||||
|
||||
BitSet oldSet = domMatrix[i];
|
||||
|
||||
// domVector := intersection of dom(pred) for all pred(node).
|
||||
BitSet domVector = new BitSet(size);
|
||||
domVector.or(oldSet);
|
||||
|
||||
|
||||
Collection preds = node.preds();
|
||||
|
||||
Iterator e = preds.iterator();
|
||||
|
||||
// Find the intersection of the dominators of node's
|
||||
// predacessors.
|
||||
while (e.hasNext()) {
|
||||
Node pred = (Node) e.next();
|
||||
|
||||
int j = pred.getPreOrderIndex();
|
||||
if (j == -1) throw new RuntimeException("Unreachable node " + pred);
|
||||
|
||||
domVector.and(domMatrix[j]);
|
||||
}
|
||||
|
||||
// Don't forget to account for the sink node if node is a
|
||||
// leaf node. Appearantly, there are not edges between
|
||||
// leaf nodes and the sink node!
|
||||
preds = (Collection) snkPreds.get(node);
|
||||
|
||||
if (preds != null) {
|
||||
e = preds.iterator();
|
||||
|
||||
while (e.hasNext()) {
|
||||
Node pred = (Node) e.next();
|
||||
|
||||
int j = pred.getPreOrderIndex();
|
||||
|
||||
domVector.and(domMatrix[j]);
|
||||
}
|
||||
}
|
||||
|
||||
// Include yourself in your dominators?!
|
||||
domVector.set(i);
|
||||
|
||||
// If the set changed, set the changed bit.
|
||||
if (!domVector.equals(oldSet)) {
|
||||
changed = true;
|
||||
domMatrix[i] = domVector;
|
||||
}
|
||||
}
|
||||
} while (changed);
|
||||
|
||||
// Once we have the predacessor bit vectors all squared away, we can
|
||||
// determine which vertices dominate which vertices.
|
||||
|
||||
// Initialize each node's (post)dominator parent and children
|
||||
for (Node node : graph.getNodes()) {
|
||||
node.setDomParent(null);
|
||||
node.getDomChildren().clear();
|
||||
}
|
||||
|
||||
// A node's immediate dominator is its closest dominator. So, we
|
||||
// start with the dominators, dom(b), of a node, b. To find the
|
||||
// imediate dominator of b, we remove all nodes from dom(b) that
|
||||
// dominate any node in dom(b).
|
||||
|
||||
for (Node node : graph.getNodes()) {
|
||||
int i = node.getPreOrderIndex();
|
||||
|
||||
if (i < 0 || i >= size) throw new RuntimeException("Unreachable node " + node);
|
||||
|
||||
if (i == rootIndex) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Find the immediate dominator
|
||||
// idom := dom(node) - dom(dom(node)) - node
|
||||
BitSet domVector = domMatrix[i];
|
||||
|
||||
BitSet idom = new BitSet(size);
|
||||
idom.or(domVector);
|
||||
idom.clear(i);
|
||||
|
||||
for (int j = 0; j < size; j++) {
|
||||
if (i != j && domVector.get(j)) {
|
||||
// idom = idom - (domMatrix[j] - {j})
|
||||
BitSet b = new BitSet(size);
|
||||
// Complement of domMatrix[j].
|
||||
b.or(domMatrix[j]); b.flip(0, size);
|
||||
b.set(j);
|
||||
idom.and(b);
|
||||
}
|
||||
}
|
||||
|
||||
Node parent = null;
|
||||
|
||||
// A node should only have one immediate dominator.
|
||||
for (int j = 0; j < size; j++) {
|
||||
if (idom.get(j)) {
|
||||
Node p = preOrder.get(j);
|
||||
if (parent != null)
|
||||
throw new RuntimeException(node + " has more than one immediate dominator: " + parent + " and " + p);
|
||||
parent = p;
|
||||
}
|
||||
}
|
||||
|
||||
if (parent == null)
|
||||
throw new RuntimeException(node + " has 0 immediate dominators");
|
||||
|
||||
node.setDomParent(parent);
|
||||
}
|
||||
}
|
||||
}
|
78
src/main/java/com/j2js/cfg/Edge.java
Normal file
78
src/main/java/com/j2js/cfg/Edge.java
Normal file
@ -0,0 +1,78 @@
|
||||
/*
|
||||
* Copyright 2005 by Wolfgang Kuehn
|
||||
* Created on 12.11.2005
|
||||
*/
|
||||
package com.j2js.cfg;
|
||||
|
||||
/**
|
||||
* @author wolfgang
|
||||
*/
|
||||
public class Edge {
|
||||
|
||||
private Graph graph;
|
||||
public Node source;
|
||||
public Node target;
|
||||
public EdgeType type;
|
||||
private Node orgSource;
|
||||
|
||||
Edge(Graph theGraph, Node theSource, Node theTarget) {
|
||||
graph = theGraph;
|
||||
source = theSource;
|
||||
target = theTarget;
|
||||
}
|
||||
|
||||
public boolean equals(Object other) {
|
||||
if (other == null || !(other instanceof Edge)) return false;
|
||||
Edge otherEdge = (Edge) other;
|
||||
return source.getId().equals(otherEdge.source.getId()) && target.getId().equals(otherEdge.target.getId());
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace the target of this edge.
|
||||
*/
|
||||
public void reroot(Node newSource) {
|
||||
source.outEdges.remove(this);
|
||||
newSource.outEdges.add(this);
|
||||
source = newSource;
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace the target of this edge.
|
||||
*/
|
||||
public void redirect(Node newTarget) {
|
||||
target.inEdges.remove(this);
|
||||
newTarget.inEdges.add(this);
|
||||
target = newTarget;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this edge is a backward (i.e. loop) edge.
|
||||
*/
|
||||
public boolean isBackEdge() {
|
||||
return target.isDomAncestor(source);
|
||||
}
|
||||
|
||||
public boolean isGlobal() {
|
||||
return orgSource != null;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
String s = getClass().getName();
|
||||
// Extract unqualified class name.
|
||||
s = s.substring(s.lastIndexOf('.')+1);
|
||||
return s + " " + source.getId() + " -> " + target.getId();
|
||||
}
|
||||
|
||||
public Node getOrgSource() {
|
||||
if (orgSource == null) {
|
||||
return source;
|
||||
}
|
||||
return orgSource;
|
||||
}
|
||||
|
||||
public void setOrgSource(Node theOrgSource) {
|
||||
orgSource = theOrgSource;
|
||||
}
|
||||
|
||||
|
||||
}
|
17
src/main/java/com/j2js/cfg/EdgeCollections.java
Normal file
17
src/main/java/com/j2js/cfg/EdgeCollections.java
Normal file
@ -0,0 +1,17 @@
|
||||
package com.j2js.cfg;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
public class EdgeCollections {
|
||||
|
||||
public static Set<Node> getSources(Collection<Edge> edges) {
|
||||
HashSet<Node> sources = new HashSet<Node>();
|
||||
for (Edge edge : edges) {
|
||||
sources.add(edge.source);
|
||||
}
|
||||
return sources;
|
||||
}
|
||||
|
||||
}
|
17
src/main/java/com/j2js/cfg/EdgeType.java
Normal file
17
src/main/java/com/j2js/cfg/EdgeType.java
Normal file
@ -0,0 +1,17 @@
|
||||
package com.j2js.cfg;
|
||||
|
||||
public class EdgeType {
|
||||
public static EdgeType FINALLY = new EdgeType("Finally");
|
||||
public static EdgeType CATCH = new EdgeType("Catch");
|
||||
public static EdgeType TRYBODY = new EdgeType("TryBody");
|
||||
|
||||
private String name;
|
||||
|
||||
private EdgeType(String theName) {
|
||||
name = theName;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return name;
|
||||
}
|
||||
}
|
286
src/main/java/com/j2js/cfg/Graph.java
Normal file
286
src/main/java/com/j2js/cfg/Graph.java
Normal file
@ -0,0 +1,286 @@
|
||||
package com.j2js.cfg;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import com.j2js.Log;
|
||||
import com.j2js.cfg.Node;
|
||||
|
||||
import com.j2js.dom.Block;
|
||||
import com.j2js.dom.BooleanExpression;
|
||||
import com.j2js.dom.BreakStatement;
|
||||
import com.j2js.dom.IfStatement;
|
||||
|
||||
public abstract class Graph {
|
||||
|
||||
private Map<String, Node> nodes = new HashMap<String, Node>();
|
||||
|
||||
int nodeIdSequence = 0;
|
||||
|
||||
Log logger = Log.getLogger();
|
||||
|
||||
public Graph() {
|
||||
}
|
||||
|
||||
public Node getNodeById(String id) {
|
||||
return nodes.get(id);
|
||||
}
|
||||
|
||||
public Node createNode(Class nodeClass) {
|
||||
return createNode(nodeClass, Integer.toString(nodeIdSequence++, 26));
|
||||
}
|
||||
|
||||
public Node createNode(Class nodeClass, String id) {
|
||||
Node node;
|
||||
try {
|
||||
Constructor constructor = nodeClass.getConstructor(new Class[]{Graph.class});
|
||||
node = (Node) constructor.newInstance(new Object[] {this});
|
||||
} catch (InstantiationException e) {
|
||||
throw new RuntimeException(e);
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new RuntimeException(e);
|
||||
} catch (NoSuchMethodException e) {
|
||||
throw new RuntimeException(e);
|
||||
} catch (InvocationTargetException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
node.id = id;
|
||||
nodes.put(id, node);
|
||||
return node;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if node set A is contained in node set B.
|
||||
*/
|
||||
public boolean isContained(Set nodesA, Node[] nodesB) {
|
||||
Set<Node> foo = new HashSet<Node>(Arrays.asList(nodesB));
|
||||
return foo.containsAll(nodesA);
|
||||
}
|
||||
|
||||
/**
|
||||
* Redirects all inbound edges of a node to another node.
|
||||
*/
|
||||
public void replaceAsTarget(Node oldTarget, Node newTarget) {
|
||||
for (Edge edge : new ArrayList<Edge>(oldTarget.getInEdges())) {
|
||||
edge.redirect(newTarget);
|
||||
}
|
||||
}
|
||||
|
||||
public Edge removeEdge(Node source, Node target) {
|
||||
Edge edge = getEdge(source, target);
|
||||
return removeEdge(edge);
|
||||
}
|
||||
|
||||
public Edge removeEdge(Edge edge) {
|
||||
edge.source.getOutEdges().remove(edge);
|
||||
edge.target.getInEdges().remove(edge);
|
||||
return edge;
|
||||
}
|
||||
|
||||
// public void replaceNodes(Node header, List nodes, Node newNode) {
|
||||
// replaceNodes(header, (Node[]) nodes.toArray(new Node[nodes.size()]), newNode);
|
||||
// }
|
||||
|
||||
public String getEdgeId(Node source, Node target) {
|
||||
return source.getId() + "->" + target.getId();
|
||||
}
|
||||
|
||||
public void addIfElseEdge(Node source, Node ifTarget, Node elseTarget, BooleanExpression be) {
|
||||
ConditionalEdge ifEdge = (ConditionalEdge) addEdge(source, ifTarget, ConditionalEdge.class);
|
||||
ifEdge.setBooleanExpression(be);
|
||||
ConditionalEdge elseEdge = (ConditionalEdge) addEdge(source, elseTarget, ConditionalEdge.class);
|
||||
elseEdge.setBooleanExpression(be);
|
||||
elseEdge.setNegate(true);
|
||||
}
|
||||
|
||||
public Edge addEdge(Node source, Node target) {
|
||||
return addEdge(source, target, Edge.class);
|
||||
}
|
||||
|
||||
public Edge addEdge(Node source, Node target, Class clazz) {
|
||||
Edge edge = getEdge(source, target);
|
||||
if (edge != null) {
|
||||
// TODO: Why not allow adding multiple edges? This is possible
|
||||
// anyway through reroot or redirect!
|
||||
throw new RuntimeException("Edge already exists");
|
||||
}
|
||||
if (clazz.equals(Edge.class)) {
|
||||
edge = new Edge(this, source, target);
|
||||
} else if (clazz.equals(SwitchEdge.class)) {
|
||||
edge = new SwitchEdge(this, source, target);
|
||||
} else if (clazz.equals(ConditionalEdge.class)) {
|
||||
edge = new ConditionalEdge(this, source, target);
|
||||
} else {
|
||||
throw new RuntimeException("Illegal edge class " + clazz);
|
||||
}
|
||||
source.addEdge(edge);
|
||||
if (source != target) {
|
||||
target.addEdge(edge);
|
||||
}
|
||||
return edge;
|
||||
}
|
||||
|
||||
public Edge getEdge(Node source, Node target) {
|
||||
for (Edge edge : source.getOutEdges()) {
|
||||
if (edge.target == target) return edge;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void removeNode(Node node) {
|
||||
replaceNode(node, null);
|
||||
}
|
||||
|
||||
public Set<Edge> removeOutEdges(Node node) {
|
||||
Set<Edge> outEdges = new HashSet<Edge>(node.outEdges);
|
||||
Iterator iter = outEdges.iterator();
|
||||
while (iter.hasNext()) {
|
||||
Edge edge = (Edge) iter.next();
|
||||
removeEdge(edge);
|
||||
}
|
||||
|
||||
return outEdges;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all in-edges to the specified node.
|
||||
*
|
||||
* @return the set of removed in-edges
|
||||
*/
|
||||
public Set removeInEdges(Node node) {
|
||||
Set<Edge> inEdges = new HashSet<Edge>(node.inEdges);
|
||||
Iterator<Edge> iter = inEdges.iterator();
|
||||
while (iter.hasNext()) {
|
||||
Edge edge = iter.next();
|
||||
removeEdge(edge);
|
||||
}
|
||||
|
||||
return inEdges;
|
||||
}
|
||||
|
||||
public Set removeSelfEdges(Node node) {
|
||||
Set<Edge> selfEdges = new HashSet<Edge>();
|
||||
|
||||
for (Edge edge: new HashSet<Edge>(node.outEdges)) {
|
||||
if (edge.target != node) continue;
|
||||
removeEdge(edge);
|
||||
selfEdges.add(edge);
|
||||
}
|
||||
|
||||
return selfEdges;
|
||||
}
|
||||
|
||||
public void rerootGlobalOutEdges(Node node, Node newSource) {
|
||||
Edge[] edges = node.getOutEdgesArray();
|
||||
for (int i=0; i<edges.length; i++) {
|
||||
Edge edge = edges[i];
|
||||
if (edge.isGlobal()) {
|
||||
edge.reroot(newSource);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void rerootOutEdges(Node node, Node newSource, boolean localToGlobal) {
|
||||
Edge[] edges = node.getOutEdgesArray();
|
||||
for (int i=0; i<edges.length; i++) {
|
||||
Edge edge = edges[i];
|
||||
edge.reroot(newSource);
|
||||
if (localToGlobal && !edge.isGlobal()) {
|
||||
edge.setOrgSource(node);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void replaceNode(Node oldNode, Node newNode) {
|
||||
nodes.remove(oldNode.getId());
|
||||
|
||||
if (newNode != null) {
|
||||
// Redirect all in-edges for oldNode to newNode.
|
||||
replaceAsTarget(oldNode, newNode);
|
||||
|
||||
// Reroot all out-edges from oldNode at newNode, making local edges global.
|
||||
rerootOutEdges(oldNode, newNode, true);
|
||||
|
||||
newNode.setDomParent(oldNode.getDomParent());
|
||||
for (Node child : new ArrayList<Node>(oldNode.getDomChildren())) {
|
||||
child.setDomParent(newNode);
|
||||
}
|
||||
}
|
||||
|
||||
if (oldNode.inEdges.size() > 0 || oldNode.outEdges.size() > 0)
|
||||
throw new RuntimeException("Cannot replace node with edges");
|
||||
|
||||
oldNode.setDomParent(null);
|
||||
}
|
||||
|
||||
public Collection<Node> getNodes() {
|
||||
return nodes.values();
|
||||
}
|
||||
|
||||
public int size() {
|
||||
return getNodes().size();
|
||||
}
|
||||
|
||||
public Block reduceDumb() {
|
||||
Block block = new Block();
|
||||
|
||||
for (Node node : getNodes()) {
|
||||
block.appendChild(node.block);
|
||||
|
||||
if (node.isBranch()) {
|
||||
IfStatement ifStmt = new IfStatement();
|
||||
ConditionalEdge cEdge = node.getConditionalEdge(true);
|
||||
ifStmt.setExpression(cEdge.getBooleanExpression().getExpression());
|
||||
ifStmt.setIfBlock(new Block());
|
||||
Block targetBlock = cEdge.target.block;
|
||||
ifStmt.getIfBlock().appendChild(new BreakStatement(targetBlock));
|
||||
ifStmt.setElseBlock(new Block());
|
||||
targetBlock = node.getConditionalEdge(false).target.block;
|
||||
ifStmt.getElseBlock().appendChild(new BreakStatement(targetBlock));
|
||||
block.appendChild(ifStmt);
|
||||
} else {
|
||||
for (Edge e : node.getOutEdges()) {
|
||||
BreakStatement bStmt = new BreakStatement(e.target.block);
|
||||
node.block.appendChild(bStmt);
|
||||
}
|
||||
}
|
||||
}
|
||||
return block;
|
||||
}
|
||||
|
||||
boolean isTarget(Node n, Set edgeSet) {
|
||||
Iterator iter = edgeSet.iterator();
|
||||
while (iter.hasNext()) {
|
||||
Edge e = (Edge) iter.next();
|
||||
if (n == e.target) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void rollOut(Node node, Block targetBlock) {
|
||||
if (node.trans != null) {
|
||||
node.trans.rollOut(targetBlock);
|
||||
} else {
|
||||
targetBlock.appendChildren(node.block);
|
||||
}
|
||||
}
|
||||
|
||||
public void dump(String msg) {
|
||||
StringBuffer sb = new StringBuffer();
|
||||
sb.append(msg + " ...\n");
|
||||
for (Node node : getNodes()) {
|
||||
sb.append(node.describe() + "\n");
|
||||
//dump(node.block, "Block");
|
||||
}
|
||||
sb.append("... " + msg);
|
||||
logger.debug(sb.toString());
|
||||
}
|
||||
}
|
334
src/main/java/com/j2js/cfg/Node.java
Normal file
334
src/main/java/com/j2js/cfg/Node.java
Normal file
@ -0,0 +1,334 @@
|
||||
/*
|
||||
* Copyright 2005 by Wolfgang Kuehn
|
||||
* Created on 12.11.2005
|
||||
*/
|
||||
package com.j2js.cfg;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import com.j2js.ASTNodeStack;
|
||||
import com.j2js.cfg.transformation.Transformation;
|
||||
import com.j2js.dom.Block;
|
||||
import com.j2js.dom.Expression;
|
||||
import com.j2js.dom.IfStatement;
|
||||
|
||||
/**
|
||||
* @author wolfgang
|
||||
*/
|
||||
public class Node {
|
||||
|
||||
public class Reference {
|
||||
public Node source;
|
||||
public boolean isBackward = false;
|
||||
}
|
||||
|
||||
public static int NON_HEADER = 0;
|
||||
public static int REDUCIBLE = 1;
|
||||
public static int IRREDUCIBLE = 2;
|
||||
|
||||
String id;
|
||||
|
||||
Set<Edge> inEdges = new LinkedHashSet<Edge>();
|
||||
Set<Edge> outEdges = new LinkedHashSet<Edge>();
|
||||
Graph graph;
|
||||
private int currentPc = -1;
|
||||
private int initialPc = -1;
|
||||
public ASTNodeStack stack = new ASTNodeStack();
|
||||
public Block block = new Block();
|
||||
public boolean closed = false;
|
||||
|
||||
protected int preOrderIndex = -1;
|
||||
|
||||
private Node domParent; // Block that (immediately) dominates this Block
|
||||
private Set<Node> domChildren = new HashSet<Node>(); // Blocks that this Block dominates
|
||||
|
||||
IfStatement ifStmt;
|
||||
public Expression switchExpression;
|
||||
|
||||
public Transformation trans;
|
||||
public Collection<Node> jsrCallers = new HashSet<Node>();
|
||||
|
||||
public boolean isSwitchHeader = false;
|
||||
|
||||
public Node(Graph theGraph, int pc) {
|
||||
this(theGraph);
|
||||
setInitialPc(pc);
|
||||
}
|
||||
|
||||
public Node(Graph theGraph) {
|
||||
graph = theGraph;
|
||||
}
|
||||
|
||||
public int getComplexity() {
|
||||
Node node = this;
|
||||
int complexity = 0;
|
||||
while (node.trans != null) {
|
||||
complexity++;
|
||||
node = node.trans.header;
|
||||
}
|
||||
return complexity;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Returns the pc.
|
||||
*/
|
||||
public int getCurrentPc() {
|
||||
return currentPc;
|
||||
}
|
||||
/**
|
||||
* @param pc The pc to set.
|
||||
*/
|
||||
public void setCurrentPc(int pc) {
|
||||
currentPc = pc;
|
||||
}
|
||||
|
||||
public void close() {
|
||||
closed = true;
|
||||
}
|
||||
|
||||
public void addEdge(Edge e) {
|
||||
if (e.source == this) {
|
||||
if (!outEdges.add(e)) {
|
||||
throw new RuntimeException("\n" + this + "\nalready bound to " + e);
|
||||
}
|
||||
}
|
||||
|
||||
if (e.target == this) {
|
||||
if (!inEdges.add(e)) {
|
||||
throw new RuntimeException("" + this + " already bound to " + e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
String s = getClass().getName();
|
||||
// Same as getClass().getSimpleName() in JDK 5.0.
|
||||
s = s.replaceFirst(".*\\.", "");
|
||||
|
||||
s += " " + id + "[" + initialPc + ", " + currentPc + "]";
|
||||
//if (preOrderIndex >= 0) s += " preIndex=" + preOrderIndex;
|
||||
if (domParent != null) s += " dominated by " + domParent.id;
|
||||
if (isLoopHeader()) s += " LH";
|
||||
return s;
|
||||
}
|
||||
|
||||
public String describe() {
|
||||
String s = toString();
|
||||
Iterator iter = outEdges.iterator();
|
||||
while (iter.hasNext()) {
|
||||
Edge e = (Edge) iter.next();
|
||||
s += "\n\t" + e;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return Returns the inEdges.
|
||||
*/
|
||||
public Set<Edge> getInEdges() {
|
||||
return inEdges;
|
||||
}
|
||||
|
||||
public Edge getSelfEdge() {
|
||||
Iterator iterator = inEdges.iterator();
|
||||
while (iterator.hasNext()) {
|
||||
Edge edge = (Edge) iterator.next();
|
||||
if (edge.source == this) return edge;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// public Set getGlobalInEdges() {
|
||||
// HashSet set = new HashSet();
|
||||
// Iterator iterator = inEdges.iterator();
|
||||
// while (iterator.hasNext()) {
|
||||
// Edge edge = (Edge) iterator.next();
|
||||
// if (edge.global) set.add(edge);
|
||||
// }
|
||||
// return set;
|
||||
// }
|
||||
|
||||
// public Set getForewardOutEdges() {
|
||||
// HashSet set = new HashSet();
|
||||
// Iterator iterator = outEdges.iterator();
|
||||
// while (iterator.hasNext()) {
|
||||
// Edge edge = (Edge) iterator.next();
|
||||
// if (!edge.isBackEdge()) set.add(edge);
|
||||
// }
|
||||
// return set;
|
||||
// }
|
||||
|
||||
/**
|
||||
* @return Returns the outEdges.
|
||||
*/
|
||||
public Set<Edge> getOutEdges() {
|
||||
return outEdges;
|
||||
}
|
||||
|
||||
public Edge[] getOutEdgesArray() {
|
||||
return outEdges.toArray(new Edge[outEdges.size()]);
|
||||
}
|
||||
|
||||
public Edge[] getInEdgesArray() {
|
||||
return inEdges.toArray(new Edge[inEdges.size()]);
|
||||
}
|
||||
|
||||
public int getPreOrderIndex() {
|
||||
return preOrderIndex;
|
||||
}
|
||||
|
||||
public void setPreOrderIndex(int thePreOrderIndex) {
|
||||
preOrderIndex = thePreOrderIndex;
|
||||
}
|
||||
|
||||
public Set<Node> succs() {
|
||||
Set<Node> list = new LinkedHashSet<Node>();
|
||||
Edge[] edges = getOutEdgesArray();
|
||||
for (int i=edges.length-1; i>=0; i--) {
|
||||
list.add(edges[i].target);
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
public Set<Node> preds() {
|
||||
Set<Node> list = new LinkedHashSet<Node>();
|
||||
Iterator iter = inEdges.iterator();
|
||||
while (iter.hasNext()) {
|
||||
Edge e = (Edge) iter.next();
|
||||
list.add(e.source);
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
public Node getPred() {
|
||||
int count = inEdges.size();
|
||||
if (count != 1) throw new RuntimeException("Requested unique predecessor, found " + count);
|
||||
return inEdges.iterator().next().source;
|
||||
}
|
||||
|
||||
public Node getSucc() {
|
||||
return getOutEdge().target;
|
||||
}
|
||||
|
||||
public Edge getLocalOutEdgeOrNull() {
|
||||
Edge outEdge = null;
|
||||
Iterator iter = outEdges.iterator();
|
||||
while (iter.hasNext()) {
|
||||
Edge edge = (Edge) iter.next();
|
||||
if (outEdge != null) new RuntimeException("Found multiple local out-edges");
|
||||
outEdge = edge;
|
||||
}
|
||||
return outEdge;
|
||||
}
|
||||
|
||||
public Edge getOutEdge() {
|
||||
int count = outEdges.size();
|
||||
if (count != 1) throw new RuntimeException("Requested unique successor, found " + count);
|
||||
return outEdges.iterator().next();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this node is equal to or dominates the specified node.
|
||||
*/
|
||||
public boolean isDomAncestor(Node node) {
|
||||
do {
|
||||
if (node == null) return false;
|
||||
if (node == this) return true;
|
||||
node = node.getDomParent();
|
||||
} while (true);
|
||||
}
|
||||
|
||||
public Set<Node> getDomChildren() {
|
||||
return domChildren;
|
||||
}
|
||||
|
||||
public Node getDomChild() {
|
||||
if (domChildren.size() != 1) throw new RuntimeException("Node must have single child");
|
||||
return getDomChildren().iterator().next();
|
||||
}
|
||||
|
||||
public Node getDomParent() {
|
||||
return domParent;
|
||||
}
|
||||
|
||||
public void setDomParent(Node newDomParent) {
|
||||
// If this Block already had a dominator specified, remove
|
||||
// it from its dominator's children.
|
||||
if (domParent != null) {
|
||||
domParent.domChildren.remove(this);
|
||||
}
|
||||
|
||||
domParent = newDomParent;
|
||||
|
||||
// Add this Block to its new dominator's children.
|
||||
if (domParent != null) {
|
||||
domParent.domChildren.add(this);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isBranch() {
|
||||
Edge[] edges = getOutEdgesArray();
|
||||
if (edges.length != 2) return false;
|
||||
if (edges[0] instanceof ConditionalEdge && edges[1] instanceof ConditionalEdge) return true;
|
||||
if ((edges[0] instanceof ConditionalEdge) || (edges[1] instanceof ConditionalEdge))
|
||||
throw new RuntimeException("Node must not have mixed edges");
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns either the true or false edge.
|
||||
*/
|
||||
public ConditionalEdge getConditionalEdge(boolean trueFalse) {
|
||||
if (!isBranch()) throw new RuntimeException("Node must be a branch");
|
||||
Iterator<Edge> iter = outEdges.iterator();
|
||||
Edge edge = iter.next();
|
||||
if (!trueFalse) edge = iter.next();
|
||||
return (ConditionalEdge) edge;
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public int getInitialPc() {
|
||||
return initialPc;
|
||||
}
|
||||
|
||||
public Graph getGraph() {
|
||||
return graph;
|
||||
}
|
||||
|
||||
public void setInitialPc(int theInitialPc) {
|
||||
initialPc = theInitialPc;
|
||||
currentPc = theInitialPc;
|
||||
}
|
||||
|
||||
public boolean isLoopHeader() {
|
||||
Iterator iter = inEdges.iterator();
|
||||
while (iter.hasNext()) {
|
||||
Edge edge = (Edge) iter.next();
|
||||
if (edge.isBackEdge()) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean hasSelfEdges() {
|
||||
Iterator iter = outEdges.iterator();
|
||||
while (iter.hasNext()) {
|
||||
Edge edge = (Edge) iter.next();
|
||||
if (edge.target == this) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// public void replaceEdge(Edge oldEdge, Edge newEdge) {
|
||||
// source.outEdges.remove(this);
|
||||
// newSource.outEdges.add(this);
|
||||
// source = newSource;
|
||||
// }
|
||||
}
|
14
src/main/java/com/j2js/cfg/SwitchEdge.java
Normal file
14
src/main/java/com/j2js/cfg/SwitchEdge.java
Normal file
@ -0,0 +1,14 @@
|
||||
package com.j2js.cfg;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.j2js.dom.NumberLiteral;
|
||||
|
||||
public class SwitchEdge extends Edge {
|
||||
public List<NumberLiteral> expressions = new ArrayList<NumberLiteral>();
|
||||
|
||||
SwitchEdge(Graph graph, Node theSource, Node theTarget) {
|
||||
super(graph, theSource, theTarget);
|
||||
}
|
||||
}
|
74
src/main/java/com/j2js/cfg/TryHeaderNode.java
Normal file
74
src/main/java/com/j2js/cfg/TryHeaderNode.java
Normal file
@ -0,0 +1,74 @@
|
||||
package com.j2js.cfg;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import com.j2js.dom.TryStatement;
|
||||
|
||||
public class TryHeaderNode extends Node {
|
||||
|
||||
public TryStatement tryStmt;
|
||||
|
||||
public TryHeaderNode(Graph theGraph) {
|
||||
super(theGraph);
|
||||
}
|
||||
|
||||
public void setTryBody(Node theTryBody) {
|
||||
Edge edge = graph.addEdge(this, theTryBody);
|
||||
edge.type = EdgeType.TRYBODY;
|
||||
}
|
||||
|
||||
public void setFinallyNode(Node theFinallyNode) {
|
||||
Edge edge = graph.addEdge(this, theFinallyNode);
|
||||
edge.type = EdgeType.FINALLY;
|
||||
//finallyNode = theFinallyNode;
|
||||
}
|
||||
|
||||
public void addCatchNode(Node node) {
|
||||
Edge edge = graph.addEdge(this, node);
|
||||
edge.type = EdgeType.CATCH;
|
||||
//catchNodes.add(node);
|
||||
}
|
||||
|
||||
public Node getSuccessor() {
|
||||
Iterator iter = outEdges.iterator();
|
||||
while (iter.hasNext()) {
|
||||
Edge edge = (Edge) iter.next();
|
||||
if (edge.type == null) return edge.target;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public Node getTryBody() {
|
||||
Iterator iter = outEdges.iterator();
|
||||
while (iter.hasNext()) {
|
||||
Edge edge = (Edge) iter.next();
|
||||
if (edge.type == EdgeType.TRYBODY) return edge.target;
|
||||
}
|
||||
throw new RuntimeException();
|
||||
}
|
||||
|
||||
public Node getFinallyNode() {
|
||||
Iterator iter = outEdges.iterator();
|
||||
while (iter.hasNext()) {
|
||||
Edge edge = (Edge) iter.next();
|
||||
if (edge.type == EdgeType.FINALLY) return edge.target;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public List<Node> getCatchNodes() {
|
||||
List<Node> catchNodes = new ArrayList<Node>();
|
||||
for (Edge edge : outEdges) {
|
||||
if (edge.type == EdgeType.CATCH) catchNodes.add(edge.target);
|
||||
}
|
||||
|
||||
return catchNodes;
|
||||
}
|
||||
|
||||
public TryStatement getTryStatement() {
|
||||
return tryStmt;
|
||||
}
|
||||
|
||||
}
|
11
src/main/java/com/j2js/cfg/WrapperNode.java
Normal file
11
src/main/java/com/j2js/cfg/WrapperNode.java
Normal file
@ -0,0 +1,11 @@
|
||||
package com.j2js.cfg;
|
||||
|
||||
public class WrapperNode extends Node{
|
||||
|
||||
Node node;
|
||||
|
||||
public WrapperNode(Graph theGraph) {
|
||||
super(theGraph);
|
||||
}
|
||||
|
||||
}
|
47
src/main/java/com/j2js/cfg/transformation/Loop.java
Normal file
47
src/main/java/com/j2js/cfg/transformation/Loop.java
Normal file
@ -0,0 +1,47 @@
|
||||
package com.j2js.cfg.transformation;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.Set;
|
||||
|
||||
import com.j2js.cfg.Edge;
|
||||
import com.j2js.dom.Block;
|
||||
import com.j2js.dom.BooleanLiteral;
|
||||
import com.j2js.dom.WhileStatement;
|
||||
|
||||
|
||||
public class Loop extends Transformation {
|
||||
|
||||
private Set selfEdges;
|
||||
|
||||
public boolean applies_() {
|
||||
return header.hasSelfEdges();
|
||||
}
|
||||
|
||||
public void apply_() {
|
||||
// Remove self edges.
|
||||
selfEdges = graph.removeSelfEdges(header);
|
||||
}
|
||||
|
||||
void rollOut_(Block block) {
|
||||
WhileStatement loopStmt = new WhileStatement();
|
||||
Block loopBody = new Block();
|
||||
loopStmt.setBlock(loopBody);
|
||||
loopStmt.setExpression(new BooleanLiteral(true));
|
||||
|
||||
block.appendChild(loopStmt);
|
||||
|
||||
Iterator iter = selfEdges.iterator();
|
||||
while (iter.hasNext()) {
|
||||
Edge edge = (Edge) iter.next();
|
||||
if (!edge.isGlobal()) continue;
|
||||
loopStmt.isLabeled();
|
||||
produceJump(edge, loopStmt);
|
||||
}
|
||||
|
||||
graph.rollOut(header, loopBody);
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return super.toString() + "(" + header + ")";
|
||||
}
|
||||
}
|
77
src/main/java/com/j2js/cfg/transformation/Merge.java
Normal file
77
src/main/java/com/j2js/cfg/transformation/Merge.java
Normal file
@ -0,0 +1,77 @@
|
||||
package com.j2js.cfg.transformation;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.Set;
|
||||
|
||||
import com.j2js.cfg.ControlFlowGraph;
|
||||
import com.j2js.cfg.Edge;
|
||||
import com.j2js.cfg.EdgeCollections;
|
||||
import com.j2js.cfg.Node;
|
||||
import com.j2js.dom.Block;
|
||||
|
||||
/**
|
||||
* @author wolfgang
|
||||
*/
|
||||
public class Merge extends Transformation {
|
||||
|
||||
private Node tail;
|
||||
private Set inEdgesForTail;
|
||||
|
||||
public Merge() {
|
||||
}
|
||||
|
||||
public Merge(ControlFlowGraph theGraph) {
|
||||
graph = theGraph;
|
||||
}
|
||||
|
||||
public boolean applies_() {
|
||||
HashSet<Node> headerSet = new HashSet<Node>();
|
||||
headerSet.add(header);
|
||||
|
||||
for (Node child : header.getDomChildren()) {
|
||||
if (EdgeCollections.getSources(child.getInEdges()).equals(headerSet)) {
|
||||
tail = child;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public void apply_() {
|
||||
// Remove all in-edges to Tail.
|
||||
inEdgesForTail = graph.removeInEdges(tail);
|
||||
|
||||
// Reroot all out-edges from Tail.
|
||||
graph.rerootOutEdges(tail, newNode, false);
|
||||
|
||||
//Remove Tail.
|
||||
graph.removeNode(tail);
|
||||
}
|
||||
|
||||
void rollOut_(Block block) {
|
||||
Block labeledBlock = block;
|
||||
|
||||
Iterator iter = inEdgesForTail.iterator();
|
||||
while (iter.hasNext()) {
|
||||
Edge edge = (Edge) iter.next();
|
||||
if (!edge.isGlobal()) continue;
|
||||
|
||||
if (labeledBlock == block) {
|
||||
labeledBlock = new Block();
|
||||
block.appendChild(labeledBlock);
|
||||
}
|
||||
|
||||
produceJump(edge, labeledBlock);
|
||||
}
|
||||
|
||||
graph.rollOut(header, labeledBlock);
|
||||
graph.rollOut(tail, block);
|
||||
block.appendChildren(newNode.block);
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return super.toString() + "(" + header + ", " + tail + ")";
|
||||
}
|
||||
}
|
83
src/main/java/com/j2js/cfg/transformation/Switch.java
Normal file
83
src/main/java/com/j2js/cfg/transformation/Switch.java
Normal file
@ -0,0 +1,83 @@
|
||||
package com.j2js.cfg.transformation;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.j2js.cfg.Edge;
|
||||
import com.j2js.cfg.Node;
|
||||
import com.j2js.cfg.SwitchEdge;
|
||||
import com.j2js.dom.Block;
|
||||
import com.j2js.dom.NumberLiteral;
|
||||
import com.j2js.dom.SwitchCase;
|
||||
import com.j2js.dom.SwitchStatement;
|
||||
|
||||
/**
|
||||
*/
|
||||
public class Switch extends Transformation {
|
||||
|
||||
private List<Node> caseGroups = new ArrayList<Node>();
|
||||
private List<List<NumberLiteral>> caseGroupExpressions = new ArrayList<List<NumberLiteral>>();
|
||||
|
||||
public boolean applies_() {
|
||||
return header.isSwitchHeader;
|
||||
}
|
||||
|
||||
private void removeFallThroughEdgesl() {
|
||||
Edge prevPotentialFallThroughEdge = null;
|
||||
|
||||
for (Edge e : header.getOutEdges()) {
|
||||
if (!(e instanceof SwitchEdge)) continue;
|
||||
|
||||
SwitchEdge edge = (SwitchEdge) e;
|
||||
Node caseGroup = edge.target;
|
||||
|
||||
if (prevPotentialFallThroughEdge != null && prevPotentialFallThroughEdge.target == caseGroup) {
|
||||
// This is a fall through edge.
|
||||
graph.removeEdge(prevPotentialFallThroughEdge);
|
||||
}
|
||||
|
||||
prevPotentialFallThroughEdge = caseGroup.getLocalOutEdgeOrNull();
|
||||
}
|
||||
}
|
||||
|
||||
void apply_() {
|
||||
removeFallThroughEdgesl();
|
||||
|
||||
for (Edge e : new ArrayList<Edge>(header.getOutEdges())) {
|
||||
if (!(e instanceof SwitchEdge)) continue;
|
||||
|
||||
SwitchEdge edge = (SwitchEdge) e;
|
||||
Node caseGroup = edge.target;
|
||||
caseGroups.add(caseGroup);
|
||||
caseGroupExpressions.add(edge.expressions);
|
||||
graph.rerootOutEdges(caseGroup, newNode, true);
|
||||
graph.removeOutEdges(caseGroup);
|
||||
graph.removeInEdges(caseGroup);
|
||||
graph.removeNode(caseGroup);
|
||||
}
|
||||
}
|
||||
|
||||
void rollOut_(Block block) {
|
||||
SwitchStatement switchStmt = new SwitchStatement();
|
||||
switchStmt.setExpression(header.switchExpression);
|
||||
|
||||
for (int i=0; i<caseGroups.size(); i++) {
|
||||
Node scNode = caseGroups.get(i);
|
||||
SwitchCase switchCase = new SwitchCase(scNode.getInitialPc());
|
||||
switchCase.setExpressions(caseGroupExpressions.get(i));
|
||||
switchStmt.appendChild(switchCase);
|
||||
|
||||
graph.rollOut(scNode, switchCase);
|
||||
}
|
||||
|
||||
block.appendChild(switchStmt);
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
String s = super.toString() + "(" + header;
|
||||
for (int i=0; i<caseGroups.size(); i++) {
|
||||
s += ", " + caseGroups.get(i);
|
||||
}
|
||||
return s + ")";
|
||||
}
|
||||
}
|
116
src/main/java/com/j2js/cfg/transformation/Transformation.java
Normal file
116
src/main/java/com/j2js/cfg/transformation/Transformation.java
Normal file
@ -0,0 +1,116 @@
|
||||
package com.j2js.cfg.transformation;
|
||||
|
||||
import com.j2js.Log;
|
||||
import com.j2js.Optimizer;
|
||||
import com.j2js.cfg.ConditionalEdge;
|
||||
import com.j2js.cfg.ControlFlowGraph;
|
||||
import com.j2js.cfg.Edge;
|
||||
import com.j2js.cfg.Graph;
|
||||
import com.j2js.cfg.Node;
|
||||
import com.j2js.dom.Block;
|
||||
import com.j2js.dom.BooleanExpression;
|
||||
import com.j2js.dom.BreakStatement;
|
||||
import com.j2js.dom.ContinueStatement;
|
||||
import com.j2js.dom.Expression;
|
||||
import com.j2js.dom.IfStatement;
|
||||
|
||||
public abstract class Transformation {
|
||||
|
||||
static Class[] transformations = new Class[] {
|
||||
Switch.class,
|
||||
Try.class,
|
||||
//If.class,
|
||||
//IfElse.class,
|
||||
Loop.class,
|
||||
// Merge must be applied after Loop.
|
||||
Merge.class
|
||||
};
|
||||
|
||||
public static Transformation select(Graph graph, Node node) {
|
||||
|
||||
for (int i=0; i<transformations.length; i++) {
|
||||
Transformation t = fetch(i);
|
||||
if (t.applies(node)) {
|
||||
return t;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
static Transformation fetch(int index) {
|
||||
Transformation t = null;
|
||||
try {
|
||||
t = (Transformation) transformations[index].newInstance();
|
||||
} catch (InstantiationException e) {
|
||||
throw new RuntimeException(e);
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
ControlFlowGraph graph;
|
||||
public Node header;
|
||||
Node newNode;
|
||||
|
||||
public Transformation() {
|
||||
}
|
||||
|
||||
public Node apply() {
|
||||
newNode = graph.createNode(Node.class);
|
||||
newNode.setInitialPc(header.getInitialPc());
|
||||
newNode.trans = this;
|
||||
apply_();
|
||||
|
||||
// Remove Header.
|
||||
graph.replaceNode(header, newNode);
|
||||
|
||||
Log.getLogger().debug(toString() + " -> " + newNode);
|
||||
return newNode;
|
||||
}
|
||||
|
||||
public boolean applies(Node node) {
|
||||
graph = (ControlFlowGraph) node.getGraph();
|
||||
header = node;
|
||||
return applies_();
|
||||
}
|
||||
|
||||
abstract boolean applies_();
|
||||
abstract void apply_();
|
||||
abstract void rollOut_(Block block);
|
||||
|
||||
public void rollOut(Block block) {
|
||||
rollOut_(block);
|
||||
block.appendChildren(newNode.block);
|
||||
}
|
||||
|
||||
void produceJump(Edge edge, Block labeledBlock) {
|
||||
Node referer = edge.getOrgSource();
|
||||
Block breakBlock;
|
||||
if (edge instanceof ConditionalEdge) {
|
||||
ConditionalEdge condEdge = (ConditionalEdge) edge;
|
||||
BooleanExpression condExpr = condEdge.getBooleanExpression();
|
||||
Expression expr = Optimizer.simplifyBooleanExpression(condExpr.getExpression(), condEdge.isNegate());
|
||||
IfStatement ifStmt = new IfStatement();
|
||||
ifStmt.setExpression(expr);
|
||||
referer.block.appendChild(ifStmt);
|
||||
Block ifBlock = new Block();
|
||||
ifStmt.setIfBlock(ifBlock);
|
||||
breakBlock = ifBlock;
|
||||
} else {
|
||||
breakBlock = referer.block;
|
||||
}
|
||||
|
||||
if (edge.isBackEdge()) {
|
||||
breakBlock.appendChild(new ContinueStatement(labeledBlock));
|
||||
} else {
|
||||
breakBlock.appendChild(new BreakStatement(labeledBlock));
|
||||
}
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return getClass().getName();
|
||||
}
|
||||
}
|
77
src/main/java/com/j2js/cfg/transformation/Try.java
Normal file
77
src/main/java/com/j2js/cfg/transformation/Try.java
Normal file
@ -0,0 +1,77 @@
|
||||
package com.j2js.cfg.transformation;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import com.j2js.cfg.Node;
|
||||
import com.j2js.cfg.TryHeaderNode;
|
||||
import com.j2js.dom.Block;
|
||||
import com.j2js.dom.CatchClause;
|
||||
import com.j2js.dom.TryStatement;
|
||||
|
||||
public class Try extends Transformation {
|
||||
|
||||
private Node tryBodyNode;
|
||||
private List catchNodes;
|
||||
private Node finallyNode;
|
||||
|
||||
boolean applies_() {
|
||||
return header instanceof TryHeaderNode;
|
||||
}
|
||||
|
||||
void apply_() {
|
||||
TryHeaderNode head = (TryHeaderNode) header;
|
||||
catchNodes = head.getCatchNodes();
|
||||
|
||||
for (Node catchNode : head.getCatchNodes()) {
|
||||
graph.rerootOutEdges(catchNode, newNode, false);
|
||||
graph.removeInEdges(catchNode);
|
||||
graph.removeNode(catchNode);
|
||||
}
|
||||
|
||||
tryBodyNode = head.getTryBody();
|
||||
graph.rerootOutEdges(tryBodyNode, newNode, false);
|
||||
graph.removeInEdges(tryBodyNode);
|
||||
graph.removeNode(tryBodyNode);
|
||||
|
||||
finallyNode = head.getFinallyNode();
|
||||
if (finallyNode != null) {
|
||||
Block b = finallyNode.block;
|
||||
// Remove return address.
|
||||
b.removeChild(b.getFirstChild());
|
||||
// Remove return statement.
|
||||
b.removeChild(b.getLastChild());
|
||||
graph.rerootOutEdges(finallyNode, newNode, false);
|
||||
graph.removeInEdges(finallyNode);
|
||||
graph.removeNode(finallyNode);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void rollOut_(Block block) {
|
||||
TryHeaderNode head = (TryHeaderNode) header;
|
||||
|
||||
TryStatement stmt = head.getTryStatement();
|
||||
block.appendChild(stmt);
|
||||
|
||||
graph.rollOut(tryBodyNode, stmt.getTryBlock());
|
||||
|
||||
if (finallyNode != null) {
|
||||
stmt.setFinallyBlock(new Block());
|
||||
graph.rollOut(finallyNode, stmt.getFinallyBlock());
|
||||
}
|
||||
|
||||
CatchClause cc = (CatchClause) stmt.getCatchStatements().getFirstChild();
|
||||
Iterator iter = catchNodes.iterator();
|
||||
while (iter.hasNext()) {
|
||||
Node catchNode = (Node) iter.next();
|
||||
graph.rollOut(catchNode, cc);
|
||||
cc = (CatchClause) cc.getNextSibling();
|
||||
}
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return super.toString() + "(" + header + ")";
|
||||
}
|
||||
|
||||
}
|
200
src/main/java/com/j2js/dom/ASTNode.java
Normal file
200
src/main/java/com/j2js/dom/ASTNode.java
Normal file
@ -0,0 +1,200 @@
|
||||
package com.j2js.dom;
|
||||
|
||||
import com.j2js.visitors.AbstractVisitor;
|
||||
|
||||
/*
|
||||
* Statement.java
|
||||
*
|
||||
* Created on 21. Mai 2004, 11:45
|
||||
*/
|
||||
|
||||
/**
|
||||
*
|
||||
* @author kuehn
|
||||
*/
|
||||
public class ASTNode {
|
||||
|
||||
public static final int BEFORE = 0;
|
||||
public static final int AFTER = 1;
|
||||
public static final int SAME = 2;
|
||||
public static final int CONTAINS = 3;
|
||||
public static final int ISCONTAINED = 4;
|
||||
|
||||
int beginIndex = Integer.MAX_VALUE;
|
||||
int endIndex = Integer.MIN_VALUE;
|
||||
private ASTNode parent = null;
|
||||
private ASTNode previousSibling = null;
|
||||
private ASTNode nextSibling = null;
|
||||
|
||||
private int stackDelta = 0;
|
||||
|
||||
public ASTNode() {
|
||||
super();
|
||||
}
|
||||
|
||||
public ASTNode(int theBeginIndex, int theEndIndex) {
|
||||
setRange(theBeginIndex, theEndIndex);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Returns the stackDelta.
|
||||
*/
|
||||
public int getStackDelta() {
|
||||
return stackDelta;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param theStackDelta The stackDelta to set.
|
||||
*/
|
||||
public void setStackDelta(int theStackDelta) {
|
||||
stackDelta = theStackDelta;
|
||||
}
|
||||
|
||||
public void widen(ASTNode node) {
|
||||
leftWiden(node.beginIndex);
|
||||
rightWiden(node.endIndex);
|
||||
}
|
||||
|
||||
public void leftWiden(int targetBeginIndex) {
|
||||
if (targetBeginIndex < beginIndex) beginIndex = targetBeginIndex;
|
||||
}
|
||||
|
||||
public void rightWiden(int targetEndIndex) {
|
||||
if (targetEndIndex > endIndex) endIndex = targetEndIndex;
|
||||
}
|
||||
|
||||
public void setRange(int theBeginIndex, int theEndIndex) {
|
||||
setBeginIndex(theBeginIndex);
|
||||
setEndIndex(theEndIndex);
|
||||
}
|
||||
|
||||
// private void checkRange() {
|
||||
// if (endIndex!=Integer.MIN_VALUE && beginIndex!=Integer.MAX_VALUE && endIndex<beginIndex) {
|
||||
// throw new RuntimeException("Begin index greater than end index: " + beginIndex + ">" + endIndex);
|
||||
// }
|
||||
// }
|
||||
|
||||
/** Getter for property beginIndex.
|
||||
* @return Value of property beginIndex.
|
||||
*/
|
||||
public int getBeginIndex() {
|
||||
return beginIndex;
|
||||
}
|
||||
|
||||
/** Setter for property beginIndex.
|
||||
* @param theBeginIndex New value of property beginIndex.
|
||||
*/
|
||||
public void setBeginIndex(int theBeginIndex) {
|
||||
beginIndex = theBeginIndex;
|
||||
}
|
||||
|
||||
/** Getter for property endIndex.
|
||||
* @return Value of property endIndex.
|
||||
*/
|
||||
public int getEndIndex() {
|
||||
return endIndex;
|
||||
}
|
||||
|
||||
/** Setter for property endIndex.
|
||||
* @param endIndex New value of property endIndex.
|
||||
*/
|
||||
public void setEndIndex(int theEndIndex) {
|
||||
endIndex = theEndIndex;
|
||||
}
|
||||
|
||||
public boolean isRightSiblingOf(ASTNode leftSibling) {
|
||||
for (ASTNode node=this; node!=null; node=node.getPreviousSibling()) {
|
||||
if (node == leftSibling) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public ASTNode rightMostSibling() {
|
||||
for (ASTNode node=this;;) {
|
||||
if (node.getNextSibling() == null) {
|
||||
return node;
|
||||
}
|
||||
node = node.getNextSibling();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isAncestorOf(ASTNode node) {
|
||||
do {
|
||||
node = node.getParentNode();
|
||||
if (node == this) {
|
||||
return true;
|
||||
}
|
||||
} while (node != null);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(getClass().getSimpleName());
|
||||
if (getBeginIndex() != Integer.MAX_VALUE) {
|
||||
sb.append("[");
|
||||
sb.append(getBeginIndex());
|
||||
sb.append(", ");
|
||||
sb.append(getEndIndex());
|
||||
sb.append("]");
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Returns the parent.
|
||||
*/
|
||||
public ASTNode getParentNode() {
|
||||
return parent;
|
||||
}
|
||||
|
||||
public Block getParentBlock() {
|
||||
return (Block) parent;
|
||||
}
|
||||
|
||||
public Block getLogicalParentBlock() {
|
||||
if (parent != null && parent.parent instanceof IfStatement) {
|
||||
return (Block) parent.parent;
|
||||
}
|
||||
return (Block) parent;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param theParent The parent to set.
|
||||
*/
|
||||
public void setParentNode(ASTNode theParent) {
|
||||
parent = theParent;
|
||||
}
|
||||
|
||||
public void visit(AbstractVisitor visitor) {
|
||||
visitor.visit(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Returns the nextSibling.
|
||||
*/
|
||||
public ASTNode getNextSibling() {
|
||||
return nextSibling;
|
||||
}
|
||||
/**
|
||||
* @param theNextSibling The nextSibling to set.
|
||||
*/
|
||||
public void setNextSibling(ASTNode theNextSibling) {
|
||||
nextSibling = theNextSibling;
|
||||
}
|
||||
/**
|
||||
* @return Returns the previousSibling.
|
||||
*/
|
||||
public ASTNode getPreviousSibling() {
|
||||
return previousSibling;
|
||||
}
|
||||
/**
|
||||
* @param thePreviousSibling The previousSibling to set.
|
||||
*/
|
||||
public void setPreviousSibling(ASTNode thePreviousSibling) {
|
||||
previousSibling = thePreviousSibling;
|
||||
}
|
||||
}
|
54
src/main/java/com/j2js/dom/ArrayAccess.java
Normal file
54
src/main/java/com/j2js/dom/ArrayAccess.java
Normal file
@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Created on Oct 31, 2004
|
||||
*/
|
||||
package com.j2js.dom;
|
||||
|
||||
import com.j2js.visitors.AbstractVisitor;
|
||||
|
||||
/**
|
||||
* @author wolfgang
|
||||
*/
|
||||
public class ArrayAccess extends Expression implements Assignable {
|
||||
|
||||
public void visit(AbstractVisitor visitor) {
|
||||
visitor.visit(this);
|
||||
}
|
||||
|
||||
public boolean isSame(Object obj) {
|
||||
if (!(obj instanceof ArrayAccess)) return false;
|
||||
ArrayAccess other = (ArrayAccess) obj;
|
||||
if (getArray() instanceof VariableBinding && other.getArray() instanceof VariableBinding) {
|
||||
VariableBinding vba = (VariableBinding) getArray();
|
||||
VariableBinding vbb = (VariableBinding) other.getArray();
|
||||
return vba.getVariableDeclaration() == vbb.getVariableDeclaration();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Returns the array.
|
||||
*/
|
||||
public Expression getArray() {
|
||||
return (Expression) getChildAt(0);
|
||||
}
|
||||
/**
|
||||
* @param array The array to set.
|
||||
*/
|
||||
public void setArray(Expression array) {
|
||||
widen(array);
|
||||
setChildAt(0, array);
|
||||
}
|
||||
/**
|
||||
* @return Returns the index.
|
||||
*/
|
||||
public Expression getIndex() {
|
||||
return (Expression) getChildAt(1);
|
||||
}
|
||||
/**
|
||||
* @param index The index to set.
|
||||
*/
|
||||
public void setIndex(Expression index) {
|
||||
widen(index);
|
||||
setChildAt(1, index);
|
||||
}
|
||||
}
|
50
src/main/java/com/j2js/dom/ArrayCreation.java
Normal file
50
src/main/java/com/j2js/dom/ArrayCreation.java
Normal file
@ -0,0 +1,50 @@
|
||||
package com.j2js.dom;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.bcel.generic.Type;
|
||||
|
||||
import com.j2js.assembly.Project;
|
||||
import com.j2js.visitors.AbstractVisitor;
|
||||
|
||||
/**
|
||||
* @author wolfgang
|
||||
*/
|
||||
public class ArrayCreation extends Expression {
|
||||
|
||||
private List<ASTNode> dimensions;
|
||||
private ArrayInitializer initializer;
|
||||
|
||||
public ArrayCreation(MethodDeclaration methodDecl, Type theType, List<ASTNode> theDimensions) {
|
||||
type = theType;
|
||||
dimensions = theDimensions;
|
||||
for (ASTNode dimension : dimensions) {
|
||||
this.widen(dimension);
|
||||
}
|
||||
Project.getSingleton().addReference(methodDecl, this);
|
||||
}
|
||||
|
||||
public void visit(AbstractVisitor visitor) {
|
||||
visitor.visit(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Returns the initializer.
|
||||
*/
|
||||
public ArrayInitializer getInitializer() {
|
||||
return initializer;
|
||||
}
|
||||
/**
|
||||
* @param theInitializer The initializer to set.
|
||||
*/
|
||||
public void setInitializer(ArrayInitializer theInitializer) {
|
||||
initializer = theInitializer;
|
||||
}
|
||||
/**
|
||||
* @return Returns the dimensions.
|
||||
*/
|
||||
public List<ASTNode> getDimensions() {
|
||||
return dimensions;
|
||||
}
|
||||
|
||||
}
|
24
src/main/java/com/j2js/dom/ArrayInitializer.java
Normal file
24
src/main/java/com/j2js/dom/ArrayInitializer.java
Normal file
@ -0,0 +1,24 @@
|
||||
package com.j2js.dom;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.j2js.visitors.AbstractVisitor;
|
||||
|
||||
/**
|
||||
* @author wolfgang
|
||||
*/
|
||||
public class ArrayInitializer extends Expression {
|
||||
|
||||
private List<Expression> expressions = new java.util.ArrayList<Expression>();
|
||||
|
||||
public void visit(AbstractVisitor visitor) {
|
||||
visitor.visit(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Returns the expressions.
|
||||
*/
|
||||
public List<Expression> getExpressions() {
|
||||
return expressions;
|
||||
}
|
||||
}
|
17
src/main/java/com/j2js/dom/Assignable.java
Normal file
17
src/main/java/com/j2js/dom/Assignable.java
Normal file
@ -0,0 +1,17 @@
|
||||
/*
|
||||
* Copyright 2005 by Wolfgang Kuehn
|
||||
* Created on 16.10.2005
|
||||
*/
|
||||
package com.j2js.dom;
|
||||
|
||||
/**
|
||||
* Tagging interface for all node types which are legal assignment targets.
|
||||
*/
|
||||
public interface Assignable {
|
||||
|
||||
/**
|
||||
* Returns true if the specified Assignable corresponds to this Assignable.
|
||||
*/
|
||||
public boolean isSame(Object obj);
|
||||
|
||||
}
|
96
src/main/java/com/j2js/dom/Assignment.java
Normal file
96
src/main/java/com/j2js/dom/Assignment.java
Normal file
@ -0,0 +1,96 @@
|
||||
package com.j2js.dom;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
import com.j2js.visitors.AbstractVisitor;
|
||||
|
||||
/**
|
||||
* @author kuehn
|
||||
*/
|
||||
public class Assignment extends Expression {
|
||||
|
||||
static public class Operator {
|
||||
|
||||
static private HashMap<String, Operator> opsByToken = new HashMap<String, Operator>();
|
||||
|
||||
static public Operator lookup(String token) {
|
||||
return opsByToken.get(token);
|
||||
}
|
||||
|
||||
static public Operator ASSIGN = new Operator("=");
|
||||
static public Operator PLUS_ASSIGN = new Operator("+=");
|
||||
static public Operator MINUS_ASSIGN = new Operator("-=");
|
||||
static public Operator TIMES_ASSIGN = new Operator("*=");
|
||||
static public Operator DIVIDE_ASSIGN = new Operator("/=");
|
||||
static public Operator BIT_AND_ASSIGN = new Operator("&=");
|
||||
static public Operator BIT_OR_ASSIGN = new Operator("|=");
|
||||
static public Operator BIT_XOR_ASSIGN = new Operator("^=");
|
||||
static public Operator REMAINDER_ASSIGN = new Operator("%=");
|
||||
static public Operator LEFT_SHIFT_ASSIGN = new Operator("<<=");
|
||||
static public Operator RIGHT_SHIFT_SIGNED_ASSIGN = new Operator(">>=");
|
||||
static public Operator RIGHT_SHIFT_UNSIGNED_ASSIGN = new Operator(">>>=");
|
||||
|
||||
private String token;
|
||||
|
||||
Operator(String theToken) {
|
||||
token = theToken;
|
||||
opsByToken.put(theToken, this);
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return token;
|
||||
}
|
||||
}
|
||||
|
||||
private Operator operator;
|
||||
|
||||
public Assignment(Operator theOperator) {
|
||||
super();
|
||||
operator = theOperator;
|
||||
}
|
||||
|
||||
public void visit(AbstractVisitor visitor) {
|
||||
visitor.visit(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param rightHandSide The rightHandSide to set.
|
||||
*/
|
||||
public void setRightHandSide(Expression rightHandSide) {
|
||||
widen(rightHandSide);
|
||||
setChildAt(1, rightHandSide);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Returns the rightHandSide.
|
||||
*/
|
||||
public Expression getRightHandSide() {
|
||||
return (Expression) getChildAt(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param leftHandSide The leftHandSide to set.
|
||||
*/
|
||||
public void setLeftHandSide(Expression leftHandSide) {
|
||||
setChildAt(0, leftHandSide);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Returns the leftHandSide.
|
||||
*/
|
||||
public Expression getLeftHandSide() {
|
||||
return (Expression) getChildAt(0);
|
||||
}
|
||||
/**
|
||||
* @return Returns the operator.
|
||||
*/
|
||||
public Operator getOperator() {
|
||||
return operator;
|
||||
}
|
||||
/**
|
||||
* @param theOerator The operator to set.
|
||||
*/
|
||||
public void setOperator(Operator theOperator) {
|
||||
operator = theOperator;
|
||||
}
|
||||
}
|
356
src/main/java/com/j2js/dom/Block.java
Normal file
356
src/main/java/com/j2js/dom/Block.java
Normal file
@ -0,0 +1,356 @@
|
||||
package com.j2js.dom;
|
||||
|
||||
import com.j2js.Log;
|
||||
import com.j2js.visitors.AbstractVisitor;
|
||||
import org.w3c.dom.DOMException;
|
||||
|
||||
/*
|
||||
* Block.java
|
||||
*
|
||||
* Created on 21. Mai 2004, 11:38
|
||||
*/
|
||||
public class Block extends ASTNode {
|
||||
|
||||
public static int TAG = 0;
|
||||
|
||||
private String label;
|
||||
|
||||
private ASTNode firstChild = null;
|
||||
private ASTNode lastChild = null;
|
||||
private int childCount = 0;
|
||||
|
||||
public Block() {
|
||||
super();
|
||||
}
|
||||
|
||||
public Block(int theBeginIndex) {
|
||||
setBeginIndex(theBeginIndex);
|
||||
}
|
||||
|
||||
public Block(int theBeginIndex, int theEndIndex) {
|
||||
this(theBeginIndex);
|
||||
setRange(theBeginIndex, theEndIndex);
|
||||
}
|
||||
|
||||
// public Block getFooBlock() {
|
||||
// Block block = this;
|
||||
// while (block!=null) {
|
||||
// if (!block.getClass().equals(Block.class)) {
|
||||
// return block;
|
||||
// }
|
||||
// block = block.getParentBlock();
|
||||
// }
|
||||
// return this;
|
||||
// }
|
||||
|
||||
public int getTargetPc() {
|
||||
if (lastChild instanceof Jump) {
|
||||
return ((Jump) lastChild).getTargetIndex();
|
||||
}
|
||||
return Integer.MAX_VALUE;
|
||||
}
|
||||
|
||||
public int getTargetIndex() {
|
||||
return beginIndex;
|
||||
}
|
||||
|
||||
public void setBeginIndex(int theBeginIndex) {
|
||||
super.setBeginIndex(theBeginIndex);
|
||||
}
|
||||
|
||||
public void visit(AbstractVisitor visitor) {
|
||||
visitor.visit(this);
|
||||
}
|
||||
|
||||
public void appendChildren(ASTNode begin, ASTNode end) {
|
||||
if (begin == null || end == null) {
|
||||
throw new RuntimeException("Illegal null parameters");
|
||||
}
|
||||
if (begin.getParentBlock() != null)
|
||||
(begin.getParentBlock()).removeChildren(begin, end);
|
||||
|
||||
if (firstChild == null) {
|
||||
setFirstChildInternal(begin);
|
||||
} else {
|
||||
ASTNode prev = getLastChild();
|
||||
prev.setNextSibling(begin);
|
||||
begin.setPreviousSibling(prev);
|
||||
}
|
||||
setLastChildInternal(end);
|
||||
|
||||
ASTNode node = begin;
|
||||
while (node != null) {
|
||||
node.setParentNode(this);
|
||||
childCount++;
|
||||
if (node == end) break;
|
||||
node = node.getNextSibling();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends all children of the specified block to this block.
|
||||
* @param sourceBlock
|
||||
*/
|
||||
public void appendChildren(Block sourceBlock) {
|
||||
if (sourceBlock.getChildCount() > 0) {
|
||||
appendChildren(sourceBlock.getFirstChild(), sourceBlock.getLastChild());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the specified node at the index. Returns the replaced node, or null if the index
|
||||
* was equal to the cild count.
|
||||
*/
|
||||
public ASTNode setChildAt(int index, ASTNode newChild) {
|
||||
if (index == childCount) {
|
||||
appendChild(newChild);
|
||||
return null;
|
||||
} else if (index < 0 || index > childCount) {
|
||||
throw new RuntimeException("Index " + index + " out of range [0, " + childCount + "]");
|
||||
}
|
||||
|
||||
return replaceChild(newChild, getChildAt(index));
|
||||
}
|
||||
|
||||
public ASTNode getChildAt(int index) {
|
||||
if (childCount == 0) {
|
||||
throw new RuntimeException("Requested child at index " + index + ", but block has no children");
|
||||
}
|
||||
if (index < 0 || index >= childCount) {
|
||||
throw new RuntimeException("Index " + index + " out of range [0, " + (childCount-1) + "]");
|
||||
}
|
||||
|
||||
if (index == childCount-1) {
|
||||
return getLastChild();
|
||||
}
|
||||
|
||||
ASTNode node = getFirstChild();
|
||||
int i = 0;
|
||||
while (i < index) {
|
||||
i++;
|
||||
node = node.getNextSibling();
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
public ASTNode appendChild(ASTNode newChild) {
|
||||
Log.getLogger().debug("Appending " + newChild + " to " + this);
|
||||
|
||||
unlink(newChild);
|
||||
|
||||
if (firstChild == null) {
|
||||
newChild.setPreviousSibling(null);
|
||||
setFirstChildInternal(newChild);
|
||||
} else {
|
||||
ASTNode prev = getLastChild();
|
||||
prev.setNextSibling(newChild);
|
||||
newChild.setPreviousSibling(prev);
|
||||
}
|
||||
setLastChildInternal(newChild);
|
||||
newChild.setParentNode(this);
|
||||
childCount++;
|
||||
|
||||
return newChild;
|
||||
}
|
||||
|
||||
public ASTNode replaceChild(ASTNode newChild, ASTNode oldChild) {
|
||||
Log.getLogger().debug("Replacing " + oldChild + " by " + newChild + " in " + this);
|
||||
if (oldChild.getParentNode() != this) {
|
||||
throw new DOMException(DOMException.NOT_FOUND_ERR, "Node " + oldChild + " is not a child of " + this);
|
||||
}
|
||||
unlink(newChild);
|
||||
if (oldChild.getPreviousSibling() != null) {
|
||||
oldChild.getPreviousSibling().setNextSibling(newChild);
|
||||
}
|
||||
if (oldChild.getNextSibling() != null) {
|
||||
oldChild.getNextSibling().setPreviousSibling(newChild);
|
||||
}
|
||||
newChild.setPreviousSibling(oldChild.getPreviousSibling());
|
||||
newChild.setNextSibling(oldChild.getNextSibling());
|
||||
newChild.setParentNode(this);
|
||||
if (getFirstChild() == oldChild) {
|
||||
setFirstChildInternal(newChild);
|
||||
}
|
||||
if (getLastChild() == oldChild) {
|
||||
setLastChildInternal(newChild);
|
||||
}
|
||||
oldChild.setPreviousSibling(null);
|
||||
oldChild.setNextSibling(null);
|
||||
oldChild.setParentNode(null);
|
||||
return oldChild;
|
||||
}
|
||||
|
||||
public ASTNode removeChild(ASTNode oldChild) {
|
||||
Log.getLogger().debug("Removing " + oldChild + " from " + this);
|
||||
removeChildren(oldChild, oldChild);
|
||||
|
||||
oldChild.setPreviousSibling(null);
|
||||
oldChild.setNextSibling(null);
|
||||
return oldChild;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all children from begin to end inclusively.
|
||||
*/
|
||||
private void removeChildren(ASTNode begin, ASTNode end) {
|
||||
if (begin == null || end == null) throw new RuntimeException("Illegal null parameters");
|
||||
ASTNode node = begin;
|
||||
while (node!= null) {
|
||||
if (node.getParentNode() != this) {
|
||||
throw new DOMException(DOMException.NOT_FOUND_ERR, "Node " + node + " is not a child of " + this);
|
||||
}
|
||||
node.setParentNode(null);
|
||||
childCount--;
|
||||
if (node == end) break;
|
||||
node = node.getNextSibling();
|
||||
}
|
||||
|
||||
|
||||
if (node != end) {
|
||||
throw new RuntimeException("Node " + end + " is not a right-sibling of " + begin);
|
||||
}
|
||||
|
||||
if (begin.getPreviousSibling() != null) {
|
||||
begin.getPreviousSibling().setNextSibling(end.getNextSibling());
|
||||
}
|
||||
if (end.getNextSibling() != null) {
|
||||
end.getNextSibling().setPreviousSibling(begin.getPreviousSibling());
|
||||
}
|
||||
if (getFirstChild() == begin) {
|
||||
setFirstChildInternal(end.getNextSibling());
|
||||
}
|
||||
if (getLastChild() == end) {
|
||||
setLastChildInternal(begin.getPreviousSibling());
|
||||
}
|
||||
}
|
||||
|
||||
public void removeChildren() {
|
||||
if (getFirstChild() != null) {
|
||||
removeChildren(getFirstChild(), getLastChild());
|
||||
}
|
||||
}
|
||||
|
||||
public int getChildCount() {
|
||||
return childCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts the node newChild after the existing child node refChild.
|
||||
* If refChild is null, insert newChild at the beginning of the list of children.
|
||||
*
|
||||
* @param newChild The node to insert
|
||||
* @param refChild The reference node, i.e., the node before which the new node must be inserted
|
||||
* @return
|
||||
*/
|
||||
// public ASTNode insertAfter(ASTNode newChild, ASTNode refChild) {
|
||||
// if (refChild == null) {
|
||||
// refChild = getFirstChild();
|
||||
// } else {
|
||||
// refChild = refChild.getNextSibling();
|
||||
// }
|
||||
// return insertBefore(newChild, refChild);
|
||||
// }
|
||||
|
||||
/**
|
||||
* Inserts the node newChild before the existing child node refChild.
|
||||
* If refChild is null, insert newChild at the end of the list of children.
|
||||
*
|
||||
* @param newChild The node to insert
|
||||
* @param refChild The reference node, i.e., the node before which the new node must be inserted
|
||||
* @return
|
||||
*/
|
||||
public ASTNode insertBefore(ASTNode newChild, ASTNode refChild) {
|
||||
if (refChild == null) {
|
||||
return appendChild(newChild);
|
||||
}
|
||||
|
||||
Log.getLogger().debug("Inserting " + newChild + " before " + refChild + " in " + this);
|
||||
|
||||
if (refChild.getParentNode() != this) {
|
||||
throw new DOMException(DOMException.NOT_FOUND_ERR, "Reference " + refChild + " is not a child of " + this);
|
||||
}
|
||||
|
||||
unlink(newChild);
|
||||
|
||||
if (refChild.getPreviousSibling() != null) {
|
||||
refChild.getPreviousSibling().setNextSibling(newChild);
|
||||
}
|
||||
newChild.setPreviousSibling(refChild.getPreviousSibling());
|
||||
newChild.setNextSibling(refChild);
|
||||
newChild.setParentNode(this);
|
||||
childCount++;
|
||||
|
||||
refChild.setPreviousSibling(newChild);
|
||||
|
||||
if (getFirstChild() == refChild) {
|
||||
setFirstChildInternal(newChild);
|
||||
}
|
||||
|
||||
return newChild;
|
||||
}
|
||||
|
||||
public void addStatements(java.util.List statements) {
|
||||
for (int i=0; i<statements.size(); i++) {
|
||||
appendChild((ASTNode)statements.get(i));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public ASTNode getFirstChild() {
|
||||
return firstChild;
|
||||
}
|
||||
|
||||
public ASTNode getLastChild() {
|
||||
return lastChild;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param firstChild The firstChild to set.
|
||||
*/
|
||||
private void setFirstChildInternal(ASTNode newFirstChild) {
|
||||
firstChild = newFirstChild;
|
||||
if (firstChild != null) {
|
||||
firstChild.setPreviousSibling(null);
|
||||
beginIndex = Math.min(beginIndex, firstChild.getBeginIndex());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param lastChild The lastChild to set.
|
||||
*/
|
||||
private void setLastChildInternal(ASTNode newLastChild) {
|
||||
lastChild = newLastChild;
|
||||
if (lastChild != null) {
|
||||
lastChild.setNextSibling(null);
|
||||
endIndex = Math.max(endIndex, lastChild.getEndIndex());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* If the specified node is contained in a tree, remove it.
|
||||
*/
|
||||
private void unlink(ASTNode node) {
|
||||
if (node.getParentBlock() != null) {
|
||||
node.getParentBlock().removeChild(node);
|
||||
}
|
||||
}
|
||||
|
||||
public String getLabel() {
|
||||
if (label == null) throw new RuntimeException("Statement is not labeled");
|
||||
return label;
|
||||
}
|
||||
|
||||
public void setLabel(String theLabel) {
|
||||
label = theLabel;
|
||||
}
|
||||
|
||||
public boolean isLabeled() {
|
||||
return label != null;
|
||||
}
|
||||
|
||||
public String setLabeled() {
|
||||
if (label == null) label = "L" + (++TAG);
|
||||
return label;
|
||||
}
|
||||
}
|
15
src/main/java/com/j2js/dom/BooleanExpression.java
Normal file
15
src/main/java/com/j2js/dom/BooleanExpression.java
Normal file
@ -0,0 +1,15 @@
|
||||
package com.j2js.dom;
|
||||
|
||||
public class BooleanExpression implements Cloneable {
|
||||
private Expression expression;
|
||||
|
||||
public BooleanExpression(Expression newExpression) {
|
||||
expression = newExpression;
|
||||
}
|
||||
|
||||
public Expression getExpression() {
|
||||
return expression;
|
||||
}
|
||||
|
||||
|
||||
}
|
36
src/main/java/com/j2js/dom/BooleanLiteral.java
Normal file
36
src/main/java/com/j2js/dom/BooleanLiteral.java
Normal file
@ -0,0 +1,36 @@
|
||||
package com.j2js.dom;
|
||||
|
||||
import com.j2js.visitors.AbstractVisitor;
|
||||
|
||||
/**
|
||||
* @author wolfgang
|
||||
*/
|
||||
public class BooleanLiteral extends Expression {
|
||||
// Note: Never ever use TRUE as part of a DOM.
|
||||
public static BooleanLiteral FALSE = new BooleanLiteral(false);
|
||||
// Note: Never ever use TRUE as part of a DOM.
|
||||
public static BooleanLiteral TRUE = new BooleanLiteral(true);
|
||||
|
||||
private boolean value;
|
||||
|
||||
public BooleanLiteral(boolean theValue) {
|
||||
value = theValue;
|
||||
}
|
||||
|
||||
public void visit(AbstractVisitor visitor) {
|
||||
visitor.visit(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Returns the value.
|
||||
*/
|
||||
public boolean getValue() {
|
||||
return value;
|
||||
}
|
||||
/**
|
||||
* @param theValue The value to set.
|
||||
*/
|
||||
public void setValue(boolean theValue) {
|
||||
value = theValue;
|
||||
}
|
||||
}
|
67
src/main/java/com/j2js/dom/Branch.java
Normal file
67
src/main/java/com/j2js/dom/Branch.java
Normal file
@ -0,0 +1,67 @@
|
||||
package com.j2js.dom;
|
||||
|
||||
/**
|
||||
* @author wolfgang
|
||||
*/
|
||||
public class Branch extends Expression {
|
||||
|
||||
private int targetIndex = -1;
|
||||
private ASTNode target;
|
||||
|
||||
public Branch() {
|
||||
super();
|
||||
}
|
||||
|
||||
public Branch(int theTargetIndex) {
|
||||
setTargetIndex(theTargetIndex);
|
||||
}
|
||||
|
||||
public boolean isBackward() {
|
||||
return getTargetIndex() <= getBeginIndex();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Returns the targetIndex.
|
||||
*/
|
||||
public int getTargetIndex() {
|
||||
return targetIndex;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param theTargetIndex The targetIndex to set.
|
||||
*/
|
||||
public void setTargetIndex(int theTargetIndex) {
|
||||
targetIndex = theTargetIndex;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
String s = getClass().getName()
|
||||
+ "[" + getBeginIndex() + ", " + getEndIndex() + ", " + targetIndex + "] -> ";
|
||||
if (target != null) {
|
||||
Exception e = new Exception();
|
||||
if (target == this) {
|
||||
s += "self";
|
||||
} else if (e.getStackTrace().length>20) {
|
||||
s += "...";
|
||||
} else {
|
||||
s += "" + target.toString();
|
||||
}
|
||||
} else {
|
||||
s += "null";
|
||||
}
|
||||
return s;
|
||||
}
|
||||
/**
|
||||
* @return Returns the target.
|
||||
*/
|
||||
public ASTNode getTarget() {
|
||||
return target;
|
||||
}
|
||||
/**
|
||||
* @param theTarget The target to set.
|
||||
*/
|
||||
public void setTarget(ASTNode theTarget) {
|
||||
target = theTarget;
|
||||
if (theTarget != null) targetIndex = theTarget.getBeginIndex();
|
||||
}
|
||||
}
|
19
src/main/java/com/j2js/dom/BreakStatement.java
Normal file
19
src/main/java/com/j2js/dom/BreakStatement.java
Normal file
@ -0,0 +1,19 @@
|
||||
package com.j2js.dom;
|
||||
|
||||
import com.j2js.visitors.AbstractVisitor;
|
||||
|
||||
public class BreakStatement extends LabeledJump {
|
||||
|
||||
public BreakStatement(String theLabel) {
|
||||
super(theLabel);
|
||||
}
|
||||
|
||||
public BreakStatement(Block block) {
|
||||
super(block);
|
||||
}
|
||||
|
||||
public void visit(AbstractVisitor visitor) {
|
||||
visitor.visit(this);
|
||||
}
|
||||
|
||||
}
|
31
src/main/java/com/j2js/dom/CastExpression.java
Normal file
31
src/main/java/com/j2js/dom/CastExpression.java
Normal file
@ -0,0 +1,31 @@
|
||||
package com.j2js.dom;
|
||||
|
||||
import com.j2js.visitors.AbstractVisitor;
|
||||
|
||||
/**
|
||||
* @author kuehn
|
||||
*/
|
||||
public class CastExpression extends Expression {
|
||||
|
||||
private Expression expression;
|
||||
|
||||
public void visit(AbstractVisitor visitor) {
|
||||
visitor.visit(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param theExpression The expression to set.
|
||||
*/
|
||||
public void setExpression(Expression theExpression) {
|
||||
widen(theExpression);
|
||||
expression = theExpression;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Returns the expression.
|
||||
*/
|
||||
public Expression getExpression() {
|
||||
return expression;
|
||||
}
|
||||
|
||||
}
|
45
src/main/java/com/j2js/dom/CatchClause.java
Normal file
45
src/main/java/com/j2js/dom/CatchClause.java
Normal file
@ -0,0 +1,45 @@
|
||||
package com.j2js.dom;
|
||||
|
||||
import com.j2js.visitors.AbstractVisitor;
|
||||
|
||||
|
||||
/*
|
||||
* CatchStatement.java
|
||||
*
|
||||
* Created on 22. Mai 2004, 22:49
|
||||
*/
|
||||
|
||||
/**
|
||||
*
|
||||
* @author kuehn
|
||||
*/
|
||||
public class CatchClause extends Block {
|
||||
|
||||
private VariableDeclaration exception;
|
||||
|
||||
/** Creates a new instance of CatchStatement */
|
||||
//public CatchStatement() {
|
||||
//}
|
||||
|
||||
public CatchClause(int theBeginIndex) {
|
||||
super(theBeginIndex);
|
||||
}
|
||||
|
||||
public void visit(AbstractVisitor visitor) {
|
||||
visitor.visit(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Returns the exception.
|
||||
*/
|
||||
public VariableDeclaration getException() {
|
||||
return exception;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param theException The exception to set.
|
||||
*/
|
||||
public void setException(VariableDeclaration theException) {
|
||||
exception = theException;
|
||||
}
|
||||
}
|
24
src/main/java/com/j2js/dom/ClassInstanceCreation.java
Normal file
24
src/main/java/com/j2js/dom/ClassInstanceCreation.java
Normal file
@ -0,0 +1,24 @@
|
||||
package com.j2js.dom;
|
||||
|
||||
import org.apache.bcel.generic.ObjectType;
|
||||
|
||||
import com.j2js.visitors.AbstractVisitor;
|
||||
|
||||
/**
|
||||
* @author wolfgang
|
||||
*/
|
||||
public class ClassInstanceCreation extends MethodInvocation {
|
||||
|
||||
public ClassInstanceCreation(ObjectType theType) {
|
||||
type = theType;
|
||||
}
|
||||
|
||||
public ClassInstanceCreation(MethodDeclaration methodDecl, MethodBinding methodBinding) {
|
||||
super(methodDecl, methodBinding);
|
||||
}
|
||||
|
||||
public void visit(AbstractVisitor visitor) {
|
||||
visitor.visit(this);
|
||||
}
|
||||
|
||||
}
|
22
src/main/java/com/j2js/dom/ClassLiteral.java
Normal file
22
src/main/java/com/j2js/dom/ClassLiteral.java
Normal file
@ -0,0 +1,22 @@
|
||||
package com.j2js.dom;
|
||||
|
||||
import com.j2js.assembly.Signature;
|
||||
import com.j2js.visitors.AbstractVisitor;
|
||||
|
||||
public class ClassLiteral extends Expression {
|
||||
|
||||
private Signature signature;
|
||||
|
||||
public ClassLiteral(Signature theSignature) {
|
||||
signature = theSignature;
|
||||
}
|
||||
|
||||
public void visit(AbstractVisitor visitor) {
|
||||
visitor.visit(this);
|
||||
}
|
||||
|
||||
public Signature getSignature() {
|
||||
return signature;
|
||||
}
|
||||
|
||||
}
|
41
src/main/java/com/j2js/dom/ConditionalBranch.java
Normal file
41
src/main/java/com/j2js/dom/ConditionalBranch.java
Normal file
@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Created on Feb 13, 2005
|
||||
*/
|
||||
package com.j2js.dom;
|
||||
|
||||
/**
|
||||
* Copyright by Wolfgang Kuehn 2005
|
||||
*/
|
||||
public class ConditionalBranch extends Branch {
|
||||
|
||||
private Expression expression;
|
||||
|
||||
public ConditionalBranch(int targetIndex) {
|
||||
super(targetIndex);
|
||||
}
|
||||
|
||||
/**
|
||||
* This constructor is for testing purposes only!!
|
||||
*/
|
||||
public ConditionalBranch(int theBeginIndex, int theEndIndex, int targetIndex) {
|
||||
super(targetIndex);
|
||||
setExpression(new Expression(theBeginIndex, theEndIndex));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Returns the condition.
|
||||
*/
|
||||
public Expression getExpression() {
|
||||
return expression;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param condition The condition to set.
|
||||
*/
|
||||
public void setExpression(Expression theExpression) {
|
||||
expression = theExpression;
|
||||
widen(theExpression);
|
||||
appendChild(theExpression);
|
||||
}
|
||||
|
||||
}
|
61
src/main/java/com/j2js/dom/ConditionalExpression.java
Normal file
61
src/main/java/com/j2js/dom/ConditionalExpression.java
Normal file
@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Created on Sep 10, 2005
|
||||
*/
|
||||
package com.j2js.dom;
|
||||
|
||||
import com.j2js.visitors.AbstractVisitor;
|
||||
|
||||
/**
|
||||
* @author wolfgang
|
||||
*/
|
||||
public class ConditionalExpression extends Expression {
|
||||
|
||||
private Expression conditionExpression = null;
|
||||
private Expression thenExpression = null;
|
||||
private Expression elseExpression = null;
|
||||
|
||||
public void visit(AbstractVisitor visitor) {
|
||||
visitor.visit(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Returns the conditionExpression.
|
||||
*/
|
||||
public Expression getConditionExpression() {
|
||||
return conditionExpression;
|
||||
}
|
||||
/**
|
||||
* @param theConditionExpression The conditionExpression to set.
|
||||
*/
|
||||
public void setConditionExpression(Expression theConditionExpression) {
|
||||
widen(theConditionExpression);
|
||||
conditionExpression = theConditionExpression;
|
||||
}
|
||||
/**
|
||||
* @return Returns the elseExpression.
|
||||
*/
|
||||
public Expression getElseExpression() {
|
||||
return elseExpression;
|
||||
}
|
||||
/**
|
||||
* @param theElseExpression The elseExpression to set.
|
||||
*/
|
||||
public void setElseExpression(Expression theElseExpression) {
|
||||
widen(theElseExpression);
|
||||
elseExpression = theElseExpression;
|
||||
}
|
||||
/**
|
||||
* @return Returns the thenExpression.
|
||||
*/
|
||||
public Expression getThenExpression() {
|
||||
return thenExpression;
|
||||
}
|
||||
/**
|
||||
* @param theThenExpression The thenExpression to set.
|
||||
*/
|
||||
public void setThenExpression(Expression theThenExpression) {
|
||||
widen(theThenExpression);
|
||||
thenExpression = theThenExpression;
|
||||
}
|
||||
|
||||
}
|
16
src/main/java/com/j2js/dom/ContinueStatement.java
Normal file
16
src/main/java/com/j2js/dom/ContinueStatement.java
Normal file
@ -0,0 +1,16 @@
|
||||
package com.j2js.dom;
|
||||
|
||||
import com.j2js.visitors.AbstractVisitor;
|
||||
|
||||
public class ContinueStatement extends LabeledJump {
|
||||
|
||||
public ContinueStatement(Block block) {
|
||||
super(block);
|
||||
}
|
||||
|
||||
public void visit(AbstractVisitor visitor) {
|
||||
visitor.visit(this);
|
||||
}
|
||||
|
||||
}
|
||||
|
32
src/main/java/com/j2js/dom/DoStatement.java
Normal file
32
src/main/java/com/j2js/dom/DoStatement.java
Normal file
@ -0,0 +1,32 @@
|
||||
package com.j2js.dom;
|
||||
|
||||
import com.j2js.visitors.AbstractVisitor;
|
||||
|
||||
/*
|
||||
* DoStatement.java
|
||||
*
|
||||
* Created on 21. Mai 2004, 17:30
|
||||
*/
|
||||
|
||||
/**
|
||||
*
|
||||
* @author kuehn
|
||||
*/
|
||||
public class DoStatement extends LoopStatement {
|
||||
|
||||
public DoStatement() {
|
||||
super();
|
||||
}
|
||||
|
||||
public DoStatement(int theBeginIndex) {
|
||||
super(theBeginIndex);
|
||||
}
|
||||
|
||||
public DoStatement(int theBeginIndex, int theEndIndex) {
|
||||
super(theBeginIndex, theEndIndex);
|
||||
}
|
||||
|
||||
public void visit(AbstractVisitor visitor) {
|
||||
visitor.visit(this);
|
||||
}
|
||||
}
|
52
src/main/java/com/j2js/dom/Expression.java
Normal file
52
src/main/java/com/j2js/dom/Expression.java
Normal file
@ -0,0 +1,52 @@
|
||||
package com.j2js.dom;
|
||||
|
||||
import org.apache.bcel.generic.Type;
|
||||
|
||||
import com.j2js.Form;
|
||||
|
||||
/**
|
||||
* Copyright by Wolfgang Kuehn 2005
|
||||
* Created on Feb 17, 2005
|
||||
*/
|
||||
public class Expression extends Block implements Cloneable {
|
||||
|
||||
Type type = Type.UNKNOWN;
|
||||
|
||||
public Expression() {
|
||||
super();
|
||||
}
|
||||
|
||||
public Expression(int theBeginIndex, int theEndIndex) {
|
||||
super(theBeginIndex, theEndIndex);
|
||||
}
|
||||
|
||||
public Object clone() {
|
||||
if (getChildCount() > 0) throw new RuntimeException("Cannot clone expression with children");
|
||||
ASTNode node;
|
||||
try {
|
||||
node = (ASTNode) super.clone();
|
||||
} catch (CloneNotSupportedException e) {
|
||||
return null;
|
||||
}
|
||||
node.setParentNode(null);
|
||||
node.setPreviousSibling(null);
|
||||
node.setNextSibling(null);
|
||||
return node;
|
||||
}
|
||||
|
||||
public Type getTypeBinding() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public void setTypeBinding(Type theType) {
|
||||
type = theType;
|
||||
}
|
||||
|
||||
public int getCategory() {
|
||||
if (getTypeBinding().getType() == Type.LONG.getType()) return Form.CATEGORY2;
|
||||
if (getTypeBinding().getType() == Type.DOUBLE.getType()) return Form.CATEGORY2;
|
||||
return Form.CATEGORY1;
|
||||
//return getTypeBinding().getType() == Type.LONG.getType() || getTypeBinding().getType() == Type.DOUBLE.getType()?Form.CATEGORY2:Form.CATEGORY1;
|
||||
}
|
||||
|
||||
}
|
85
src/main/java/com/j2js/dom/FieldAccess.java
Normal file
85
src/main/java/com/j2js/dom/FieldAccess.java
Normal file
@ -0,0 +1,85 @@
|
||||
package com.j2js.dom;
|
||||
|
||||
import org.apache.bcel.generic.ObjectType;
|
||||
|
||||
import com.j2js.assembly.Project;
|
||||
import com.j2js.visitors.AbstractVisitor;
|
||||
|
||||
/**
|
||||
* @author wolfgang
|
||||
*/
|
||||
public abstract class FieldAccess extends Expression {
|
||||
|
||||
private String name;
|
||||
private ObjectType type;
|
||||
//private MethodDeclaration methodDecl;
|
||||
|
||||
public FieldAccess() {
|
||||
}
|
||||
|
||||
public void initialize(MethodDeclaration methodDecl) {
|
||||
Project.getSingleton().addReference(methodDecl, this);
|
||||
}
|
||||
|
||||
public void visit(AbstractVisitor visitor) {
|
||||
visitor.visit(this);
|
||||
}
|
||||
|
||||
// if (!faa.getName().equals(fab.getName())) return false;
|
||||
//
|
||||
public boolean isSame(Object obj) {
|
||||
if (!(obj instanceof FieldAccess)) return false;
|
||||
FieldAccess other = (FieldAccess) obj;
|
||||
if (!name.equals(other.name)) return false;
|
||||
if (getExpression() instanceof VariableBinding && other.getExpression() instanceof VariableBinding) {
|
||||
VariableBinding vba = (VariableBinding) getExpression();
|
||||
VariableBinding vbb = (VariableBinding) other.getExpression();
|
||||
return vba.getVariableDeclaration() == vbb.getVariableDeclaration();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Returns the expression.
|
||||
*/
|
||||
public Expression getExpression() {
|
||||
return (Expression) getFirstChild();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param expression The expression to set.
|
||||
*/
|
||||
public void setExpression(Expression expression) {
|
||||
widen(expression);
|
||||
removeChildren();
|
||||
appendChild(expression);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Returns the name.
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param theName The name to set.
|
||||
*/
|
||||
public void setName(String theName) {
|
||||
name = theName;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return super.toString() + " " + name;
|
||||
}
|
||||
|
||||
public ObjectType getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public void setType(ObjectType theType) {
|
||||
if (type != null) throw new RuntimeException("Type is already set");
|
||||
type = theType;
|
||||
}
|
||||
|
||||
}
|
14
src/main/java/com/j2js/dom/FieldRead.java
Normal file
14
src/main/java/com/j2js/dom/FieldRead.java
Normal file
@ -0,0 +1,14 @@
|
||||
package com.j2js.dom;
|
||||
|
||||
import com.j2js.visitors.AbstractVisitor;
|
||||
|
||||
public class FieldRead extends FieldAccess {
|
||||
|
||||
public FieldRead() {
|
||||
}
|
||||
|
||||
public void visit(AbstractVisitor visitor) {
|
||||
visitor.visit(this);
|
||||
}
|
||||
|
||||
}
|
14
src/main/java/com/j2js/dom/FieldWrite.java
Normal file
14
src/main/java/com/j2js/dom/FieldWrite.java
Normal file
@ -0,0 +1,14 @@
|
||||
package com.j2js.dom;
|
||||
|
||||
import com.j2js.visitors.AbstractVisitor;
|
||||
|
||||
public class FieldWrite extends FieldAccess implements Assignable {
|
||||
|
||||
public FieldWrite() {
|
||||
}
|
||||
|
||||
public void visit(AbstractVisitor visitor) {
|
||||
visitor.visit(this);
|
||||
}
|
||||
|
||||
}
|
13
src/main/java/com/j2js/dom/Goto.java
Normal file
13
src/main/java/com/j2js/dom/Goto.java
Normal file
@ -0,0 +1,13 @@
|
||||
/*
|
||||
* Copyright 2005 by Wolfgang Kuehn
|
||||
* Created on 12.11.2005
|
||||
*/
|
||||
package com.j2js.dom;
|
||||
|
||||
/**
|
||||
* @author wolfgang
|
||||
*/
|
||||
public class Goto extends ASTNode {
|
||||
|
||||
|
||||
}
|
46
src/main/java/com/j2js/dom/IfStatement.java
Normal file
46
src/main/java/com/j2js/dom/IfStatement.java
Normal file
@ -0,0 +1,46 @@
|
||||
package com.j2js.dom;
|
||||
|
||||
import com.j2js.visitors.AbstractVisitor;
|
||||
|
||||
/**
|
||||
* @author kuehn
|
||||
*/
|
||||
public class IfStatement extends Block {
|
||||
|
||||
public IfStatement() {
|
||||
super();
|
||||
}
|
||||
|
||||
public Expression getExpression() {
|
||||
return (Expression) getChildAt(0);
|
||||
}
|
||||
|
||||
public void setExpression(Expression expression) {
|
||||
widen(expression);
|
||||
setChildAt(0, expression);
|
||||
}
|
||||
|
||||
public Block getIfBlock() {
|
||||
return (Block) getChildAt(1);
|
||||
}
|
||||
|
||||
public void setIfBlock(Block block) {
|
||||
widen(block);
|
||||
setChildAt(1, block);
|
||||
}
|
||||
|
||||
public Block getElseBlock() {
|
||||
if (getChildCount() < 3) return null;
|
||||
return (Block) getChildAt(2);
|
||||
}
|
||||
|
||||
public void setElseBlock(Block block) {
|
||||
widen(block);
|
||||
setChildAt(2, block);
|
||||
}
|
||||
|
||||
public void visit(AbstractVisitor visitor) {
|
||||
visitor.visit(this);
|
||||
}
|
||||
|
||||
}
|
111
src/main/java/com/j2js/dom/InfixExpression.java
Normal file
111
src/main/java/com/j2js/dom/InfixExpression.java
Normal file
@ -0,0 +1,111 @@
|
||||
package com.j2js.dom;
|
||||
|
||||
import com.j2js.visitors.AbstractVisitor;
|
||||
|
||||
/**
|
||||
* @author kuehn
|
||||
*/
|
||||
public class InfixExpression extends Expression {
|
||||
|
||||
static public class Operator {
|
||||
static public Operator CONDITIONAL_AND = new Operator("&&");
|
||||
static public Operator CONDITIONAL_OR = new Operator("||");
|
||||
static public Operator PLUS = new Operator("+");
|
||||
static public Operator MINUS = new Operator("-");
|
||||
static public Operator TIMES = new Operator("*");
|
||||
static public Operator DIVIDE = new Operator("/");
|
||||
static public Operator REMAINDER = new Operator("%");
|
||||
static public Operator XOR = new Operator("^");
|
||||
static public Operator AND = new Operator("&");
|
||||
static public Operator OR = new Operator("|");
|
||||
static public Operator EQUALS = new Operator("==");
|
||||
static public Operator NOT_EQUALS = new Operator("!=");
|
||||
static public Operator GREATER_EQUALS = new Operator(">=");
|
||||
static public Operator GREATER = new Operator(">");
|
||||
static public Operator LESS_EQUALS = new Operator("<=");
|
||||
static public Operator LESS = new Operator("<");
|
||||
static public Operator RIGHT_SHIFT_SIGNED = new Operator(">>");
|
||||
static public Operator LEFT_SHIFT = new Operator("<<");
|
||||
static public Operator RIGHT_SHIFT_UNSIGNED = new Operator(">>>");
|
||||
|
||||
static {
|
||||
EQUALS.complement = NOT_EQUALS;
|
||||
NOT_EQUALS.complement = EQUALS;
|
||||
GREATER_EQUALS.complement = LESS;
|
||||
GREATER.complement = LESS_EQUALS;
|
||||
LESS_EQUALS.complement = GREATER;
|
||||
LESS.complement = GREATER_EQUALS;
|
||||
CONDITIONAL_AND.complement = CONDITIONAL_OR;
|
||||
CONDITIONAL_OR.complement = CONDITIONAL_AND;
|
||||
}
|
||||
|
||||
private String token;
|
||||
private Operator complement;
|
||||
|
||||
Operator(String theToken) {
|
||||
token = theToken;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return token;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Returns the complement.
|
||||
*/
|
||||
public Operator getComplement() {
|
||||
return complement;
|
||||
}
|
||||
}
|
||||
|
||||
private Operator operator;
|
||||
|
||||
public InfixExpression(Operator op) {
|
||||
super();
|
||||
operator = op;
|
||||
if (operator.getComplement() != null) type = org.apache.bcel.generic.Type.BOOLEAN;
|
||||
}
|
||||
|
||||
public void visit(AbstractVisitor visitor) {
|
||||
visitor.visit(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Returns the leftOperand.
|
||||
*/
|
||||
public Expression getLeftOperand() {
|
||||
return (Expression) getChildAt(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param leftOperand The leftOperand to set.
|
||||
*/
|
||||
public void setOperands(Expression leftOperand, Expression rightOperand) {
|
||||
widen(leftOperand);
|
||||
widen(rightOperand);
|
||||
removeChildren();
|
||||
appendChild(leftOperand);
|
||||
appendChild(rightOperand);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Returns the rightOperand.
|
||||
*/
|
||||
public Expression getRightOperand() {
|
||||
return (Expression) getChildAt(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Returns the operator.
|
||||
*/
|
||||
public Operator getOperator() {
|
||||
return operator;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param theOperator The operator to set.
|
||||
*/
|
||||
public void setOperator(Operator theOperator) {
|
||||
operator = theOperator;
|
||||
}
|
||||
}
|
31
src/main/java/com/j2js/dom/InstanceofExpression.java
Normal file
31
src/main/java/com/j2js/dom/InstanceofExpression.java
Normal file
@ -0,0 +1,31 @@
|
||||
package com.j2js.dom;
|
||||
|
||||
import org.apache.bcel.generic.Type;
|
||||
|
||||
import com.j2js.visitors.AbstractVisitor;
|
||||
|
||||
/**
|
||||
* Copyright by Wolfgang Kuehn 2005
|
||||
* Created on Feb 27, 2005
|
||||
*/
|
||||
public class InstanceofExpression extends Expression {
|
||||
private Expression leftOperand;
|
||||
private Type rightOperand;
|
||||
|
||||
public void visit(AbstractVisitor visitor) {
|
||||
visitor.visit(this);
|
||||
}
|
||||
|
||||
public Expression getLeftOperand() {
|
||||
return leftOperand;
|
||||
}
|
||||
public void setLeftOperand(Expression theLeftOperand) {
|
||||
leftOperand = theLeftOperand;
|
||||
}
|
||||
public Type getRightOperand() {
|
||||
return rightOperand;
|
||||
}
|
||||
public void setRightOperand(Type theRightOperand) {
|
||||
rightOperand = theRightOperand;
|
||||
}
|
||||
}
|
20
src/main/java/com/j2js/dom/Jump.java
Normal file
20
src/main/java/com/j2js/dom/Jump.java
Normal file
@ -0,0 +1,20 @@
|
||||
package com.j2js.dom;
|
||||
|
||||
/**
|
||||
* @author wolfgang
|
||||
*/
|
||||
public class Jump extends Branch {
|
||||
|
||||
public Jump() {
|
||||
super();
|
||||
}
|
||||
|
||||
public Jump(int targetIndex) {
|
||||
super(targetIndex);
|
||||
}
|
||||
|
||||
// public Jump(int beginIndex, int endIndex, int targetIndex) {
|
||||
// this(targetIndex);
|
||||
// setRange(beginIndex, endIndex);
|
||||
// }
|
||||
}
|
12
src/main/java/com/j2js/dom/JumpSubRoutine.java
Normal file
12
src/main/java/com/j2js/dom/JumpSubRoutine.java
Normal file
@ -0,0 +1,12 @@
|
||||
package com.j2js.dom;
|
||||
|
||||
/**
|
||||
* @author wolfgang
|
||||
*/
|
||||
public class JumpSubRoutine extends Branch {
|
||||
|
||||
public JumpSubRoutine(int targetIndex) {
|
||||
super(targetIndex);
|
||||
}
|
||||
|
||||
}
|
20
src/main/java/com/j2js/dom/LabeledJump.java
Normal file
20
src/main/java/com/j2js/dom/LabeledJump.java
Normal file
@ -0,0 +1,20 @@
|
||||
package com.j2js.dom;
|
||||
|
||||
abstract public class LabeledJump extends Jump {
|
||||
|
||||
String label;
|
||||
|
||||
public LabeledJump(String newLabel) {
|
||||
super();
|
||||
label = newLabel;
|
||||
}
|
||||
|
||||
public LabeledJump(Block block) {
|
||||
super();
|
||||
label = block.setLabeled();
|
||||
}
|
||||
|
||||
public String getLabel() {
|
||||
return label;
|
||||
}
|
||||
}
|
44
src/main/java/com/j2js/dom/LoopStatement.java
Normal file
44
src/main/java/com/j2js/dom/LoopStatement.java
Normal file
@ -0,0 +1,44 @@
|
||||
package com.j2js.dom;
|
||||
|
||||
/*
|
||||
* LoopStatement.java
|
||||
*
|
||||
* Created on 21. Mai 2004, 16:51
|
||||
*/
|
||||
|
||||
/**
|
||||
*
|
||||
* @author kuehn
|
||||
*/
|
||||
public class LoopStatement extends Block {
|
||||
|
||||
public LoopStatement() {
|
||||
super();
|
||||
}
|
||||
|
||||
public LoopStatement(int theBeginIndex) {
|
||||
super(theBeginIndex);
|
||||
}
|
||||
|
||||
public LoopStatement(int theBeginIndex, int theEndIndex) {
|
||||
super(theBeginIndex, theEndIndex);
|
||||
}
|
||||
|
||||
public Expression getExpression() {
|
||||
return (Expression) getChildAt(1);
|
||||
}
|
||||
|
||||
public void setExpression(Expression expression) {
|
||||
widen(expression);
|
||||
setChildAt(1, expression);
|
||||
}
|
||||
|
||||
public Block getBlock() {
|
||||
return (Block) getChildAt(0);
|
||||
}
|
||||
|
||||
public void setBlock(Block block) {
|
||||
widen(block);
|
||||
setChildAt(0, block);
|
||||
}
|
||||
}
|
120
src/main/java/com/j2js/dom/MethodBinding.java
Normal file
120
src/main/java/com/j2js/dom/MethodBinding.java
Normal file
@ -0,0 +1,120 @@
|
||||
/*
|
||||
* Created on 29.01.2006
|
||||
* Copyright Wolfgang Kuehn 2005
|
||||
*/
|
||||
package com.j2js.dom;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.bcel.Constants;
|
||||
import org.apache.bcel.classfile.ConstantCP;
|
||||
import org.apache.bcel.classfile.ConstantNameAndType;
|
||||
import org.apache.bcel.classfile.ConstantPool;
|
||||
import org.apache.bcel.generic.ObjectType;
|
||||
import org.apache.bcel.generic.Type;
|
||||
|
||||
import com.j2js.Utils;
|
||||
|
||||
/**
|
||||
* @author kuehn
|
||||
*/
|
||||
public class MethodBinding {
|
||||
|
||||
private static Map<String, MethodBinding> methodBindingsByKey = new HashMap<String, MethodBinding>();
|
||||
|
||||
public static MethodBinding lookup(int index, ConstantPool constantPool) {
|
||||
ConstantCP methodRef = (ConstantCP) constantPool.getConstant(index);
|
||||
ConstantNameAndType nameAndType = (ConstantNameAndType)
|
||||
constantPool.getConstant(methodRef.getNameAndTypeIndex(), Constants.CONSTANT_NameAndType);
|
||||
|
||||
String name = nameAndType.getName(constantPool);
|
||||
String signature = nameAndType.getSignature(constantPool);
|
||||
|
||||
return lookup(methodRef.getClass(constantPool), name, signature);
|
||||
}
|
||||
|
||||
public static MethodBinding lookup(String className, String name, String signature) {
|
||||
String key = className + "#" + name + signature;
|
||||
|
||||
MethodBinding binding = methodBindingsByKey.get(key);
|
||||
if (binding != null) return binding;
|
||||
|
||||
binding = new MethodBinding();
|
||||
binding.declaringClass = new ObjectType(className);
|
||||
binding.name = name;
|
||||
binding.parameterTypes = Type.getArgumentTypes(signature);
|
||||
binding.returnType = Type.getReturnType(signature);
|
||||
binding.signature = signature;
|
||||
|
||||
methodBindingsByKey.put(key, binding);
|
||||
|
||||
return binding;
|
||||
}
|
||||
|
||||
private ObjectType declaringClass;
|
||||
private String name;
|
||||
private Type[] parameterTypes;
|
||||
private Type returnType;
|
||||
private String signature;
|
||||
|
||||
private MethodBinding() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the type binding representing the class or interface that declares this method or constructor.
|
||||
*/
|
||||
public ObjectType getDeclaringClass() {
|
||||
return declaringClass;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of the method declared in this binding.
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of type bindings representing the formal parameter types, in declaration order, of this method or constructor.
|
||||
*/
|
||||
public Type[] getParameterTypes() {
|
||||
return parameterTypes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the binding for the return type of this method.
|
||||
*/
|
||||
public Type getReturnType() {
|
||||
return returnType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether this binding is for a constructor or a method.
|
||||
*/
|
||||
public boolean isConstructor() {
|
||||
return "<init>".equals(name);
|
||||
}
|
||||
|
||||
public String getSignature() {
|
||||
return signature;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return getDeclaringClass().getClassName() + "#" + getRelativeSignature();
|
||||
}
|
||||
|
||||
public String getRelativeSignature() {
|
||||
String signature = getName() + "(";
|
||||
String sep = "";
|
||||
for (int i = 0; i < getParameterTypes().length; i++) {
|
||||
Type type = getParameterTypes()[i];
|
||||
signature += sep + Utils.getSignature(type);
|
||||
sep = ",";
|
||||
}
|
||||
signature += ")";
|
||||
signature += Utils.getSignature(returnType);
|
||||
return signature;
|
||||
}
|
||||
|
||||
}
|
134
src/main/java/com/j2js/dom/MethodDeclaration.java
Normal file
134
src/main/java/com/j2js/dom/MethodDeclaration.java
Normal file
@ -0,0 +1,134 @@
|
||||
package com.j2js.dom;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.bcel.classfile.Code;
|
||||
import org.apache.bcel.generic.Type;
|
||||
|
||||
import com.j2js.LineNumberCursor;
|
||||
import com.j2js.assembly.Project;
|
||||
import com.j2js.visitors.AbstractVisitor;
|
||||
|
||||
/**
|
||||
* @author wolfgang
|
||||
*/
|
||||
public class MethodDeclaration extends ASTNode {
|
||||
|
||||
private String tempPrefix = "_";
|
||||
private Block block;
|
||||
private Map<String, VariableDeclaration> parameters = new LinkedHashMap<String, VariableDeclaration>();
|
||||
private Map<String, VariableDeclaration> localVariables = new HashMap<String, VariableDeclaration>();
|
||||
private int accessFlags;
|
||||
private Code code;
|
||||
private MethodBinding methodBinding;
|
||||
private LineNumberCursor lineNumberCursor;
|
||||
|
||||
public MethodDeclaration(MethodBinding theMethodBinding, int theAccessFlags, Code theCode) {
|
||||
methodBinding = theMethodBinding;
|
||||
accessFlags = theAccessFlags;
|
||||
code = theCode;
|
||||
lineNumberCursor = new LineNumberCursor(code);
|
||||
Project.getSingleton().getOrCreateProcedureUnit(methodBinding);
|
||||
}
|
||||
|
||||
public int getAccess() {
|
||||
return accessFlags;
|
||||
}
|
||||
|
||||
public void visit(AbstractVisitor visitor) {
|
||||
visitor.visit(this);
|
||||
}
|
||||
|
||||
public boolean isInstanceConstructor() {
|
||||
return methodBinding.getName().equals("<init>");
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Returns the block.
|
||||
*/
|
||||
public Block getBody() {
|
||||
return block;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param theBlock The block to set.
|
||||
*/
|
||||
public void setBody(Block theBlock) {
|
||||
block = theBlock;
|
||||
theBlock.setParentNode(this);
|
||||
}
|
||||
|
||||
public VariableBinding createVariableBinding(String name, Type type, boolean isWrite) {
|
||||
if (type == null) throw new NullPointerException();
|
||||
|
||||
VariableDeclaration decl = getParameter(name);
|
||||
if (decl == null) {
|
||||
decl = getLocalVariable(name);
|
||||
}
|
||||
if (decl == null) {
|
||||
decl = new VariableDeclaration(!isWrite);
|
||||
decl.setName(name);
|
||||
decl.setType(type);
|
||||
addLocalVariable(decl);
|
||||
}
|
||||
|
||||
VariableBinding binding = new VariableBinding(decl);
|
||||
|
||||
return binding;
|
||||
}
|
||||
|
||||
private int vbCount = 0;
|
||||
public VariableBinding createAnonymousVariableBinding(Type type, boolean isWrite) {
|
||||
String name = tempPrefix + (vbCount++);
|
||||
VariableBinding vb = createVariableBinding(name, type, isWrite);
|
||||
vb.setTemporary(true);
|
||||
return vb;
|
||||
}
|
||||
|
||||
public void addParameter(VariableDeclaration variableDecl) {
|
||||
parameters.put(variableDecl.getName(), variableDecl);
|
||||
}
|
||||
|
||||
public Collection<VariableDeclaration> getParameters() {
|
||||
return parameters.values();
|
||||
}
|
||||
|
||||
public VariableDeclaration getParameter(String name) {
|
||||
return parameters.get(name);
|
||||
}
|
||||
|
||||
public void addLocalVariable(VariableDeclaration variableDecl) {
|
||||
localVariables.put(variableDecl.getName(), variableDecl);
|
||||
}
|
||||
|
||||
public void removeLocalVariable(String name) {
|
||||
localVariables.remove(name);
|
||||
}
|
||||
|
||||
public Collection<VariableDeclaration> getLocalVariables() {
|
||||
return localVariables.values();
|
||||
}
|
||||
|
||||
public VariableDeclaration getLocalVariable(String name) {
|
||||
return localVariables.get(name);
|
||||
}
|
||||
|
||||
public MethodBinding getMethodBinding() {
|
||||
return methodBinding;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return methodBinding.toString();
|
||||
}
|
||||
|
||||
public Code getCode() {
|
||||
return code;
|
||||
}
|
||||
|
||||
public LineNumberCursor getLineNumberCursor() {
|
||||
return lineNumberCursor;
|
||||
}
|
||||
}
|
118
src/main/java/com/j2js/dom/MethodInvocation.java
Normal file
118
src/main/java/com/j2js/dom/MethodInvocation.java
Normal file
@ -0,0 +1,118 @@
|
||||
package com.j2js.dom;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.bcel.generic.Type;
|
||||
|
||||
import com.j2js.ASTNodeStack;
|
||||
import com.j2js.assembly.Project;
|
||||
import com.j2js.visitors.AbstractVisitor;
|
||||
|
||||
/**
|
||||
* @author kuehn
|
||||
*/
|
||||
public class MethodInvocation extends Expression {
|
||||
|
||||
private Expression expression;
|
||||
private MethodDeclaration methodDecl;
|
||||
|
||||
/**
|
||||
* Special handling for superclass, private, and instance initialization method invocations.
|
||||
*/
|
||||
public boolean isSpecial = false;
|
||||
private MethodBinding methodBinding;
|
||||
|
||||
public MethodInvocation() {
|
||||
}
|
||||
|
||||
public MethodInvocation(MethodDeclaration theMethodDecl) {
|
||||
methodDecl = theMethodDecl;
|
||||
}
|
||||
|
||||
public MethodInvocation(MethodDeclaration theMethodDecl, MethodBinding theMethodBinding) {
|
||||
methodDecl = theMethodDecl;
|
||||
setMethodBinding(theMethodBinding);
|
||||
}
|
||||
|
||||
public Type getTypeBinding() {
|
||||
if (methodBinding == null) return super.getTypeBinding();
|
||||
return methodBinding.getReturnType();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this method invocation applies to a super class of the specified class.
|
||||
*/
|
||||
public boolean isSuper(String currentClassName) {
|
||||
if (!isSpecial) return false;
|
||||
// Use resolved class unless
|
||||
// 1) the resolved method is not an instance initialization method,
|
||||
if (methodBinding.isConstructor()) return false;
|
||||
// 2) and the class of the resolved method is a superclass of the current class and
|
||||
String name = methodBinding.getDeclaringClass().getClassName();
|
||||
if (currentClassName.equals(name)) return false;
|
||||
|
||||
// TODO: The resolved class is different from the current class, but this does not imply that
|
||||
// the resolved class is a superclass! Problem: How do we get this information without loading
|
||||
// the class hierarchy?
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Returns the arguments.
|
||||
*/
|
||||
public List getArguments() {
|
||||
ASTNodeStack stack = new ASTNodeStack();
|
||||
ASTNode node = getFirstChild();
|
||||
if (expression != null) {
|
||||
node = node.getNextSibling();
|
||||
}
|
||||
|
||||
while (node != null) {
|
||||
stack.add(node);
|
||||
node = node.getNextSibling();
|
||||
}
|
||||
|
||||
return stack;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param arguments The arguments to set.
|
||||
*/
|
||||
public void addArgument(Expression argument) {
|
||||
widen(argument);
|
||||
appendChild(argument);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Returns the expression.
|
||||
*/
|
||||
public Expression getExpression() {
|
||||
return expression;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param expression The expression to set.
|
||||
*/
|
||||
public void setExpression(Expression targetExpression) {
|
||||
if (expression != null) {
|
||||
throw new RuntimeException("Expression is already set");
|
||||
}
|
||||
expression = targetExpression;
|
||||
widen(expression);
|
||||
insertBefore(expression, getFirstChild());
|
||||
}
|
||||
|
||||
public void visit(AbstractVisitor visitor) {
|
||||
visitor.visit(this);
|
||||
}
|
||||
|
||||
public MethodBinding getMethodBinding() {
|
||||
return methodBinding;
|
||||
}
|
||||
|
||||
public void setMethodBinding(MethodBinding theMethodBinding) {
|
||||
methodBinding = theMethodBinding;
|
||||
Project.getSingleton().addReference(methodDecl, this);
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user