mirror of
https://github.com/cincheo/jsweet.git
synced 2025-12-15 07:19:22 +00:00
initial commit
This commit is contained in:
parent
740a2d7d60
commit
d80a07a5c8
33
.classpath
Normal file
33
.classpath
Normal file
@ -0,0 +1,33 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<classpath>
|
||||
<classpathentry kind="src" output="target/classes" path="src">
|
||||
<attributes>
|
||||
<attribute name="optional" value="true"/>
|
||||
<attribute name="maven.pomderived" value="true"/>
|
||||
</attributes>
|
||||
</classpathentry>
|
||||
<classpathentry kind="src" output="target/test-classes" path="test">
|
||||
<attributes>
|
||||
<attribute name="ignore_optional_problems" value="true"/>
|
||||
<attribute name="optional" value="true"/>
|
||||
<attribute name="maven.pomderived" value="true"/>
|
||||
</attributes>
|
||||
</classpathentry>
|
||||
<classpathentry kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER">
|
||||
<attributes>
|
||||
<attribute name="maven.pomderived" value="true"/>
|
||||
</attributes>
|
||||
</classpathentry>
|
||||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8">
|
||||
<attributes>
|
||||
<attribute name="maven.pomderived" value="true"/>
|
||||
</attributes>
|
||||
</classpathentry>
|
||||
<classpathentry excluding="**" kind="src" output="target/classes" path="resources">
|
||||
<attributes>
|
||||
<attribute name="maven.pomderived" value="true"/>
|
||||
</attributes>
|
||||
</classpathentry>
|
||||
<classpathentry kind="con" path="org.eclipse.jdt.junit.JUNIT_CONTAINER/4"/>
|
||||
<classpathentry kind="output" path="target/classes"/>
|
||||
</classpath>
|
||||
23
.project
Normal file
23
.project
Normal file
@ -0,0 +1,23 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<projectDescription>
|
||||
<name>jsweet</name>
|
||||
<comment></comment>
|
||||
<projects>
|
||||
</projects>
|
||||
<buildSpec>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.jdt.core.javabuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.m2e.core.maven2Builder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
</buildSpec>
|
||||
<natures>
|
||||
<nature>org.eclipse.m2e.core.maven2Nature</nature>
|
||||
<nature>org.eclipse.jdt.core.javanature</nature>
|
||||
</natures>
|
||||
</projectDescription>
|
||||
297
.settings/org.eclipse.jdt.core.prefs
Normal file
297
.settings/org.eclipse.jdt.core.prefs
Normal file
@ -0,0 +1,297 @@
|
||||
eclipse.preferences.version=1
|
||||
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
|
||||
org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate
|
||||
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
|
||||
org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
|
||||
org.eclipse.jdt.core.compiler.compliance=1.8
|
||||
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.problem.forbiddenReference=warning
|
||||
org.eclipse.jdt.core.compiler.source=1.8
|
||||
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_annotation=0
|
||||
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_method_declaration=0
|
||||
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_resources_in_try=80
|
||||
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.alignment_for_union_type_in_multicatch=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=0
|
||||
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_lambda_body=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_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_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.comment.new_lines_at_block_boundaries=true
|
||||
org.eclipse.jdt.core.formatter.comment.new_lines_at_javadoc_boundaries=true
|
||||
org.eclipse.jdt.core.formatter.comment.preserve_white_space_between_code_and_line_comments=false
|
||||
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.disabling_tag=@formatter\:off
|
||||
org.eclipse.jdt.core.formatter.enabling_tag=@formatter\:on
|
||||
org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line=false
|
||||
org.eclipse.jdt.core.formatter.format_line_comment_starting_on_first_column=true
|
||||
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_on_field=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_method=insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_package=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_annotation_on_type=insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_after_label=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_after_type_annotation=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_lambda_arrow=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_try=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_semicolon_in_try_resources=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_try=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_lambda_arrow=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_try=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_semicolon_in_try_resources=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.join_lines_in_comments=true
|
||||
org.eclipse.jdt.core.formatter.join_wrapped_lines=true
|
||||
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=160
|
||||
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=tab
|
||||
org.eclipse.jdt.core.formatter.tabulation.size=4
|
||||
org.eclipse.jdt.core.formatter.use_on_off_tags=false
|
||||
org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations=false
|
||||
org.eclipse.jdt.core.formatter.wrap_before_binary_operator=true
|
||||
org.eclipse.jdt.core.formatter.wrap_before_or_operator_multicatch=true
|
||||
org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested=true
|
||||
3
.settings/org.eclipse.jdt.ui.prefs
Normal file
3
.settings/org.eclipse.jdt.ui.prefs
Normal file
@ -0,0 +1,3 @@
|
||||
eclipse.preferences.version=1
|
||||
formatter_profile=_w160
|
||||
formatter_settings_version=12
|
||||
4
.settings/org.eclipse.m2e.core.prefs
Normal file
4
.settings/org.eclipse.m2e.core.prefs
Normal file
@ -0,0 +1,4 @@
|
||||
activeProfiles=
|
||||
eclipse.preferences.version=1
|
||||
resolveWorkspaceProjects=true
|
||||
version=1
|
||||
53
LICENSE.txt
Normal file
53
LICENSE.txt
Normal file
@ -0,0 +1,53 @@
|
||||
Apache License
|
||||
|
||||
Version 2.0, January 2004
|
||||
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions:
|
||||
|
||||
You must give any other recipients of the Work or Derivative Works a copy of this License; and
|
||||
You must cause any modified files to carry prominent notices stating that You changed the files; and
|
||||
You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and
|
||||
If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License.
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
43
build.xml
Normal file
43
build.xml
Normal file
@ -0,0 +1,43 @@
|
||||
<project name="jsweet" basedir="." default="install-toolsjar">
|
||||
|
||||
<property environment="env" />
|
||||
|
||||
<condition property="maven.bin" value="${env.MAVEN_HOME}\bin\mvn.cmd" else="${env.MAVEN_HOME}/bin/mvn">
|
||||
<os family="winnt" />
|
||||
</condition>
|
||||
|
||||
<target name="install-toolsjar">
|
||||
<property name="lib.path" value="C:/Program Files/Java/jdk1.8.0_60/lib/tools.jar">
|
||||
</property>
|
||||
<echo>installing local tools.jar in local maven: ${lib.path}</echo>
|
||||
<echo>Java home: ${env.JAVA_HOME}</echo>
|
||||
<echo>Maven home: ${env.MAVEN_HOME}</echo>
|
||||
<echo>WARNING: this script requires that your JAVA_HOME environment variable points to the Java 8 JDK (not JRE)</echo>
|
||||
<echo>note that under Eclipse, you can locally set your JAVA_HOME variable in "External tools configuration -> Environment"</echo>
|
||||
<property name="lib.name" value="tools">
|
||||
</property>
|
||||
<property name="lib.version" value="8">
|
||||
</property>
|
||||
<exec executable="${maven.bin}" failonerror="true">
|
||||
<arg line="install:install-file -Dfile='${lib.path}' -DgroupId=com.sun -DartifactId=${lib.name} -Dpackaging=jar -Dversion=${lib.version}" />
|
||||
</exec>
|
||||
<echo>WARNING: a successful build does not necessarily mean that you installed the right version of tools.jar</echo>
|
||||
</target>
|
||||
|
||||
<target name="deploy-toolsjar">
|
||||
<property name="lib.path" value="${env.JAVA_HOME}/lib/tools.jar">
|
||||
</property>
|
||||
<echo>installing local tools.jar in local maven: ${lib.path}</echo>
|
||||
<echo>WARNING: this script requires that your JAVA_HOME environment variable points to the Java 8 JDK (not JRE)</echo>
|
||||
<echo>note that under Eclipse, you can locally set your JAVA_HOME variable in "External tools configuration -> Environment"</echo>
|
||||
<property name="lib.name" value="tools">
|
||||
</property>
|
||||
<property name="lib.version" value="8">
|
||||
</property>
|
||||
<exec executable="${maven.bin}" failonerror="true">
|
||||
<arg line="deploy:deploy-file -Dfile='${lib.path}' -Durl=http://jsweet.org:8081/artifactory/libs-release-local -DrepositoryId=jsweet-release -DgroupId=com.sun -DartifactId=${lib.name} -Dpackaging=jar -Dversion=${lib.version}" />
|
||||
</exec>
|
||||
<echo>WARNING: a successful build does not necessarily mean that you installed the right version of tools.jar</echo>
|
||||
</target>
|
||||
|
||||
</project>
|
||||
14
copyright.txt
Normal file
14
copyright.txt
Normal file
@ -0,0 +1,14 @@
|
||||
/* Copyright 2015 CINCHEO SAS
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
256
pom.xml
Normal file
256
pom.xml
Normal file
@ -0,0 +1,256 @@
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>org.jsweet</groupId>
|
||||
<artifactId>jsweet-transpiler</artifactId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
<name>JSweet transpiler</name>
|
||||
<description>Programming Web applications with Java 8</description>
|
||||
<developers>
|
||||
<developer>
|
||||
<id>rpawlak</id>
|
||||
<name>Renaud Pawlak</name>
|
||||
<email>renaud.pawlak@gmail.com</email>
|
||||
</developer>
|
||||
</developers>
|
||||
<licenses>
|
||||
<license>
|
||||
<name>The Apache Software License, Version 2.0</name>
|
||||
<url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
|
||||
<distribution>repo</distribution>
|
||||
</license>
|
||||
</licenses>
|
||||
<properties>
|
||||
<timestamp>${maven.build.timestamp}</timestamp>
|
||||
<maven.build.timestamp.format>yyyy-MM-dd HH:mm:ss</maven.build.timestamp.format>
|
||||
</properties>
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>diff_match_patch</id>
|
||||
<url>http://google-diff-match-patch.googlecode.com/svn/trunk/maven</url>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>jsweet-central</id>
|
||||
<name>libs-release</name>
|
||||
<url>http://repository.jsweet.org/artifactory/libs-release-local</url>
|
||||
</repository>
|
||||
<repository>
|
||||
<snapshots />
|
||||
<id>jsweet-snapshots</id>
|
||||
<name>libs-snapshot</name>
|
||||
<url>http://repository.jsweet.org/artifactory/libs-snapshot-local</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
<build>
|
||||
<sourceDirectory>src</sourceDirectory>
|
||||
<testSourceDirectory>test</testSourceDirectory>
|
||||
<resources>
|
||||
<resource>
|
||||
<directory>resources</directory>
|
||||
<filtering>true</filtering>
|
||||
</resource>
|
||||
</resources>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.1</version>
|
||||
<configuration>
|
||||
<source>1.8</source>
|
||||
<target>1.8</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<version>2.18.1</version>
|
||||
<configuration>
|
||||
<includes>
|
||||
<include>**/*.java</include>
|
||||
</includes>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-assembly-plugin</artifactId>
|
||||
<version>2.4</version>
|
||||
<configuration>
|
||||
<archive>
|
||||
<manifest>
|
||||
<mainClass>org.jsweet.JSweetCommandLineLauncher</mainClass>
|
||||
</manifest>
|
||||
</archive>
|
||||
<descriptorRefs>
|
||||
<descriptorRef>jar-with-dependencies</descriptorRef>
|
||||
</descriptorRefs>
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>make-assembly</id>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>attached</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-javadoc-plugin</artifactId>
|
||||
<version>2.10.3</version>
|
||||
<configuration>
|
||||
<javadocVersion>1.8</javadocVersion>
|
||||
<sourcepath>src</sourcepath>
|
||||
<encoding>UTF-8</encoding>
|
||||
<fixTags>all</fixTags>
|
||||
<failOnError>false</failOnError>
|
||||
<reportOutputDirectory>/var/www/apidocs/org/jsweet</reportOutputDirectory>
|
||||
<destDir>jsweet-transpiler-${project.version}</destDir>
|
||||
<header><![CDATA[<a href="http://www.jsweet.org" target="_blank" style="text-transform: lowercase">http://www.jsweet.org<a>]]></header>
|
||||
<bottom><![CDATA[<center>Copyright 2015, <a href="http://www.cincheo.org" target="_blank">Cinchéo SAS<a> - Web site: <a href="http://www.jsweet.org" target="_blank">http://www.jsweet.org<a><center>]]></bottom>
|
||||
<stylesheetfile>/var/www/apidocs/stylesheet.css</stylesheetfile>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
<dependencies>
|
||||
<!-- Install this dependency using the build.xml file in the JSweet project -->
|
||||
<dependency>
|
||||
<groupId>com.sun</groupId>
|
||||
<artifactId>tools</artifactId>
|
||||
<version>8</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>edu.princeton.cup</groupId>
|
||||
<artifactId>java-cup</artifactId>
|
||||
<version>10k</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>de.jflex</groupId>
|
||||
<artifactId>jflex</artifactId>
|
||||
<version>1.3.5</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-lang3</artifactId>
|
||||
<version>3.3.2</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>commons-io</groupId>
|
||||
<artifactId>commons-io</artifactId>
|
||||
<version>2.4</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<version>4.12</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>diff_match_patch</groupId>
|
||||
<artifactId>diff_match_patch</artifactId>
|
||||
<version>current</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>log4j</groupId>
|
||||
<artifactId>log4j</artifactId>
|
||||
<version>1.2.17</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.code.gson</groupId>
|
||||
<artifactId>gson</artifactId>
|
||||
<version>2.2.4</version>
|
||||
<scope>compile</scope>
|
||||
<optional>false</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.martiansoftware</groupId>
|
||||
<artifactId>jsap</artifactId>
|
||||
<version>2.1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ant</groupId>
|
||||
<artifactId>ant</artifactId>
|
||||
<version>1.6.5</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.javassist</groupId>
|
||||
<artifactId>javassist</artifactId>
|
||||
<version>3.20.0-GA</version>
|
||||
</dependency>
|
||||
<!-- Test-only dependencies for testing candies -->
|
||||
<dependency>
|
||||
<groupId>org.jsweet.candies</groupId>
|
||||
<artifactId>core</artifactId>
|
||||
<version>1.0.1-SNAPSHOT</version>
|
||||
<scope>test</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jsweet.candies</groupId>
|
||||
<artifactId>body-parser</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
<scope>test</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jsweet.candies</groupId>
|
||||
<artifactId>node</artifactId>
|
||||
<version>0.12.1-SNAPSHOT</version>
|
||||
<scope>test</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jsweet.candies</groupId>
|
||||
<artifactId>errorhandler</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
<scope>test</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jsweet.candies</groupId>
|
||||
<artifactId>socket.io</artifactId>
|
||||
<version>1.3.50001-SNAPSHOT</version>
|
||||
<scope>test</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jsweet.candies</groupId>
|
||||
<artifactId>jquery</artifactId>
|
||||
<version>1.10.1-SNAPSHOT</version>
|
||||
<scope>test</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jsweet.candies</groupId>
|
||||
<artifactId>angular</artifactId>
|
||||
<version>1.4.1-SNAPSHOT</version>
|
||||
<scope>test</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jsweet.candies</groupId>
|
||||
<artifactId>angular-route</artifactId>
|
||||
<version>1.3.1-SNAPSHOT</version>
|
||||
<scope>test</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<organization>
|
||||
<name>JSweet</name>
|
||||
<url>http://www.jsweet.org</url>
|
||||
</organization>
|
||||
<distributionManagement>
|
||||
<repository>
|
||||
<id>jsweet-release</id>
|
||||
<name>libs-release</name>
|
||||
<url>http://repository.jsweet.org/artifactory/libs-release-local</url>
|
||||
</repository>
|
||||
<snapshotRepository>
|
||||
<id>jsweet-snapshots</id>
|
||||
<name>libs-snapshot</name>
|
||||
<url>http://repository.jsweet.org/artifactory/libs-snapshot-local</url>
|
||||
</snapshotRepository>
|
||||
</distributionManagement>
|
||||
</project>
|
||||
4
resources/application.properties
Normal file
4
resources/application.properties
Normal file
@ -0,0 +1,4 @@
|
||||
# application.properties
|
||||
application.name=${pom.name}
|
||||
application.version=${pom.version}
|
||||
application.buildDate=${timestamp}
|
||||
8
resources/log4j.properties
Normal file
8
resources/log4j.properties
Normal file
@ -0,0 +1,8 @@
|
||||
# Root logger option
|
||||
log4j.rootLogger=DEBUG, stdout
|
||||
|
||||
# Direct log messages to stdout
|
||||
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
|
||||
log4j.appender.stdout.Target=System.out
|
||||
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
|
||||
log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss.sss} %-5p %c{1}:%L - %m%n
|
||||
261
src/org/jsweet/JSweetCommandLineLauncher.java
Normal file
261
src/org/jsweet/JSweetCommandLineLauncher.java
Normal file
@ -0,0 +1,261 @@
|
||||
/* Copyright 2015 CINCHEO SAS
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.jsweet;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.LinkedList;
|
||||
|
||||
import org.jsweet.transpiler.JSweetProblem;
|
||||
import org.jsweet.transpiler.JSweetTranspiler;
|
||||
import org.jsweet.transpiler.ModuleKind;
|
||||
import org.jsweet.transpiler.Severity;
|
||||
import org.jsweet.transpiler.SourceFile;
|
||||
import org.jsweet.transpiler.TranspilationHandler;
|
||||
import org.jsweet.transpiler.util.Util;
|
||||
|
||||
import com.martiansoftware.jsap.FlaggedOption;
|
||||
import com.martiansoftware.jsap.JSAP;
|
||||
import com.martiansoftware.jsap.JSAPException;
|
||||
import com.martiansoftware.jsap.JSAPResult;
|
||||
import com.martiansoftware.jsap.Switch;
|
||||
import com.martiansoftware.jsap.stringparsers.EnumeratedStringParser;
|
||||
import com.martiansoftware.jsap.stringparsers.FileStringParser;
|
||||
import com.sun.tools.javac.main.JavaCompiler;
|
||||
|
||||
/**
|
||||
* The command line launcher for the JSweet transpiler.
|
||||
*
|
||||
* @author Renaud Pawlak
|
||||
*/
|
||||
public class JSweetCommandLineLauncher {
|
||||
|
||||
private static int errorCount = 0;
|
||||
|
||||
/**
|
||||
* JSweet transpiler command line entry point. To use the JSweet transpiler
|
||||
* from Java, see {@link JSweetTranspiler}.
|
||||
*/
|
||||
public static void main(String[] args) {
|
||||
try {
|
||||
JSAP jsapSpec;
|
||||
JSAPResult jsapArgs = parseArgs(jsapSpec = defineArgs(), args);
|
||||
|
||||
if (!jsapArgs.success()) {
|
||||
printUsage(jsapSpec);
|
||||
}
|
||||
|
||||
String classPath = jsapArgs.getString("classpath");
|
||||
System.out.println("classpath: " + classPath);
|
||||
|
||||
File tsOutputDir = jsapArgs.getFile("tsout");
|
||||
tsOutputDir.mkdirs();
|
||||
System.out.println("ts output dir: " + tsOutputDir);
|
||||
|
||||
File jsOutputDir = null;
|
||||
if (jsapArgs.getFile("jsout") != null) {
|
||||
jsOutputDir = jsapArgs.getFile("jsout");
|
||||
jsOutputDir.mkdirs();
|
||||
}
|
||||
System.out.println("js output dir: " + jsOutputDir);
|
||||
|
||||
File inputDir = new File(jsapArgs.getString("input"));
|
||||
System.out.println("input dir: " + inputDir);
|
||||
|
||||
LinkedList<File> files = new LinkedList<File>();
|
||||
Util.addFiles(".java", inputDir, files);
|
||||
|
||||
JSweetTranspiler transpiler = new JSweetTranspiler(tsOutputDir, jsOutputDir, classPath);
|
||||
transpiler.setBundle(jsapArgs.getBoolean("bundle"));
|
||||
|
||||
File bundlesDirectory = null;
|
||||
if (jsapArgs.getFile("bundlesDirectory") != null) {
|
||||
bundlesDirectory = jsapArgs.getFile("bundlesDirectory");
|
||||
bundlesDirectory.getParentFile().mkdirs();
|
||||
}
|
||||
System.out.println("bundles directory: " + bundlesDirectory);
|
||||
transpiler.setBundlesDirectory(bundlesDirectory);
|
||||
|
||||
transpiler.setPreserveSourceLineNumbers(jsapArgs.getBoolean("debug"));
|
||||
if (args.length > 4) {
|
||||
File f = new File(args[4]);
|
||||
if (f.exists()) {
|
||||
transpiler.setTsDefDirs(f);
|
||||
System.out.println("tsdef dir: " + args[4]);
|
||||
} else {
|
||||
System.out.println("WARNING: tsdef dir does not exist - " + args[4]);
|
||||
}
|
||||
}
|
||||
|
||||
transpiler.setModuleKind(ModuleKind.valueOf(jsapArgs.getString("module")));
|
||||
|
||||
TranspilationHandler transpilationHandler = new TranspilationHandler() {
|
||||
@Override
|
||||
public void report(JSweetProblem problem, SourcePosition sourcePosition, String message) {
|
||||
String file = "<unknown>";
|
||||
String startLine = "<unknown>";
|
||||
if (sourcePosition != null) {
|
||||
if (sourcePosition.getFile() != null) {
|
||||
file = sourcePosition.getFile().getName();
|
||||
}
|
||||
startLine = "" + sourcePosition.getStartLine();
|
||||
}
|
||||
System.out.println(problem.getSeverity() + ": " + message + " at " + file + ":" + startLine);
|
||||
if (problem.getSeverity() == Severity.ERROR) {
|
||||
errorCount++;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCompleted(JSweetTranspiler transpiler, boolean fullPass, SourceFile[] files) {
|
||||
}
|
||||
};
|
||||
|
||||
transpiler.setEncoding(jsapArgs.getString("encoding"));
|
||||
|
||||
transpiler.transpile(transpilationHandler, SourceFile.toSourceFiles(files));
|
||||
|
||||
System.out.println("transpilation done, errors: " + errorCount);
|
||||
} catch (Throwable t) {
|
||||
t.printStackTrace();
|
||||
System.exit(1);
|
||||
}
|
||||
System.exit(errorCount > 0 ? 1 : 0);
|
||||
}
|
||||
|
||||
private static JSAP defineArgs() throws JSAPException {
|
||||
// Verbose output
|
||||
JSAP jsap = new JSAP();
|
||||
Switch switchArg;
|
||||
FlaggedOption optionArg;
|
||||
|
||||
// help
|
||||
switchArg = new Switch("help");
|
||||
switchArg.setShortFlag('h');
|
||||
switchArg.setLongFlag("help");
|
||||
switchArg.setDefault("false");
|
||||
jsap.registerParameter(switchArg);
|
||||
|
||||
// Java compiler's encoding
|
||||
optionArg = new FlaggedOption("encoding");
|
||||
optionArg.setLongFlag("encoding");
|
||||
optionArg.setStringParser(JSAP.STRING_PARSER);
|
||||
optionArg.setRequired(false);
|
||||
optionArg.setDefault("UTF-8");
|
||||
optionArg.setHelp("Force the Java compiler to use a specific encoding (UTF-8, UTF-16, ...).");
|
||||
jsap.registerParameter(optionArg);
|
||||
|
||||
// Input directory
|
||||
optionArg = new FlaggedOption("input");
|
||||
optionArg.setShortFlag('i');
|
||||
optionArg.setLongFlag("input");
|
||||
optionArg.setStringParser(JSAP.STRING_PARSER);
|
||||
optionArg.setRequired(true);
|
||||
optionArg.setHelp("An input dir containing Java files to be transpiled.");
|
||||
jsap.registerParameter(optionArg);
|
||||
|
||||
// TypeScript output directory
|
||||
optionArg = new FlaggedOption("tsout");
|
||||
optionArg.setLongFlag("tsout");
|
||||
optionArg.setDefault(".ts");
|
||||
optionArg.setHelp("Specify where to place generated TypeScript files.");
|
||||
optionArg.setStringParser(FileStringParser.getParser());
|
||||
optionArg.setRequired(false);
|
||||
jsap.registerParameter(optionArg);
|
||||
|
||||
// JavaScript output directory
|
||||
optionArg = new FlaggedOption("jsout");
|
||||
optionArg.setShortFlag('o');
|
||||
optionArg.setLongFlag("jsout");
|
||||
optionArg.setDefault("js");
|
||||
optionArg.setHelp("Specify where to place generated JavaScript files (ignored if jsFile is specified).");
|
||||
optionArg.setStringParser(FileStringParser.getParser());
|
||||
optionArg.setRequired(false);
|
||||
jsap.registerParameter(optionArg);
|
||||
|
||||
// Classpath
|
||||
optionArg = new FlaggedOption("classpath");
|
||||
optionArg.setLongFlag("classpath");
|
||||
optionArg.setHelp("The JSweet transpilation classpath (candy jars). This classpath should at least contain the core candy.");
|
||||
optionArg.setStringParser(JSAP.STRING_PARSER);
|
||||
optionArg.setRequired(false);
|
||||
jsap.registerParameter(optionArg);
|
||||
|
||||
// Module
|
||||
optionArg = new FlaggedOption("module");
|
||||
optionArg.setLongFlag("module");
|
||||
optionArg.setShortFlag('m');
|
||||
optionArg.setDefault("none");
|
||||
optionArg.setHelp("The module kind (none, commonjs, amd, system or umd).");
|
||||
optionArg.setStringParser(EnumeratedStringParser.getParser("none;commonjs;amd;system;umd"));
|
||||
optionArg.setRequired(false);
|
||||
jsap.registerParameter(optionArg);
|
||||
|
||||
// Bundle
|
||||
switchArg = new Switch("bundle");
|
||||
switchArg.setLongFlag("bundle");
|
||||
switchArg.setShortFlag('b');
|
||||
switchArg.setHelp(
|
||||
"Bundle up the generated files and used modules to bundle files, which can be used in the browser. Bundles contain all the dependencies and are thus standalone. There is one bundle generated per entry (a Java 'main' method) in the program. By default, bundles are generated in the entry directory, but the output directory can be set by using the --bundlesDirectory option. NOTE: bundles will be generated only when choosing the commonjs module kind.");
|
||||
switchArg.setDefault("false");
|
||||
jsap.registerParameter(switchArg);
|
||||
|
||||
// Bundles directory
|
||||
optionArg = new FlaggedOption("bundlesDirectory");
|
||||
optionArg.setLongFlag("bundlesDirectory");
|
||||
optionArg.setHelp("Generate all the bundles (see option --bundle) within the given directory.");
|
||||
optionArg.setStringParser(FileStringParser.getParser());
|
||||
optionArg.setRequired(false);
|
||||
jsap.registerParameter(optionArg);
|
||||
|
||||
// Debug
|
||||
switchArg = new Switch("debug");
|
||||
switchArg.setLongFlag("debug");
|
||||
switchArg.setShortFlag('d');
|
||||
switchArg.setHelp(
|
||||
"Set the transpiler to debug mode. In debug mode, source map files are generated so that it is possible to debug them in the browser. This feature is not available yet when using the --module option.");
|
||||
switchArg.setDefault("false");
|
||||
jsap.registerParameter(switchArg);
|
||||
|
||||
return jsap;
|
||||
}
|
||||
|
||||
private static JSAPResult parseArgs(JSAP jsapSpec, String[] commandLineArgs) {
|
||||
System.out.println("JSweet transpiler version " + JSweetConfig.getVersionNumber() + " (build date: " + JSweetConfig.getBuildDate() + ")");
|
||||
System.out.println("Java compiler version: " + JavaCompiler.version());
|
||||
|
||||
if (jsapSpec == null) {
|
||||
throw new IllegalStateException("no args, please call setArgs before");
|
||||
}
|
||||
JSAPResult arguments = jsapSpec.parse(commandLineArgs);
|
||||
if (!arguments.success()) {
|
||||
// print out specific error messages describing the problems
|
||||
for (java.util.Iterator<?> errs = arguments.getErrorMessageIterator(); errs.hasNext();) {
|
||||
System.out.println("Error: " + errs.next());
|
||||
}
|
||||
}
|
||||
if (!arguments.success() || arguments.getBoolean("help")) {
|
||||
}
|
||||
|
||||
return arguments;
|
||||
}
|
||||
|
||||
private static void printUsage(JSAP jsapSpec) {
|
||||
System.out.println("Usage: java -jar <jsweet-jar-with-dependencies> [option(s)]");
|
||||
System.out.println(" options:\n");
|
||||
System.out.println(jsapSpec.getHelp());
|
||||
System.exit(-1);
|
||||
}
|
||||
|
||||
}
|
||||
303
src/org/jsweet/JSweetConfig.java
Normal file
303
src/org/jsweet/JSweetConfig.java
Normal file
@ -0,0 +1,303 @@
|
||||
/* Copyright 2015 CINCHEO SAS
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.jsweet;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.util.HashSet;
|
||||
import java.util.Properties;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* This class contains static constants and utilities.
|
||||
*
|
||||
* @author Renaud Pawlak
|
||||
*/
|
||||
public abstract class JSweetConfig {
|
||||
|
||||
private JSweetConfig() {
|
||||
}
|
||||
|
||||
/**
|
||||
* The properties coming from application.properties.
|
||||
*/
|
||||
public static Properties APPLICATION_PROPERTIES = new Properties();
|
||||
|
||||
static {
|
||||
try (InputStream in = JSweetConfig.class.getResourceAsStream("/application.properties")) {
|
||||
APPLICATION_PROPERTIES.load(in);
|
||||
in.close();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The version coming from Maven.
|
||||
*/
|
||||
public static String getVersionNumber() {
|
||||
return APPLICATION_PROPERTIES.getProperty("application.version");
|
||||
}
|
||||
|
||||
/**
|
||||
* The build date coming from Maven.
|
||||
*/
|
||||
public static String getBuildDate() {
|
||||
return APPLICATION_PROPERTIES.getProperty("application.buildDate");
|
||||
}
|
||||
|
||||
/**
|
||||
* The Maven group id where candies are deployed.
|
||||
*/
|
||||
public static String MAVEN_CANDIES_GROUP = "org.jsweet.candies";
|
||||
|
||||
private final static String JAVA_PACKAGE = "java";
|
||||
private final static String ROOT_PACKAGE = "jsweet";
|
||||
/** The constant for the JSweet lang package. */
|
||||
public final static String LANG_PACKAGE = ROOT_PACKAGE + ".lang";
|
||||
/** The constant for the JSweet util package. */
|
||||
public final static String UTIL_PACKAGE = ROOT_PACKAGE + ".util";
|
||||
/** The constant for the JSweet dom package. */
|
||||
public final static String DOM_PACKAGE = ROOT_PACKAGE + ".dom";
|
||||
/**
|
||||
* The constant for the JSweet lib package (where the definitions need to
|
||||
* be).
|
||||
*/
|
||||
public final static String LIBS_PACKAGE = "def";
|
||||
/**
|
||||
* The constant for the package generates top-level classes (one cannot use
|
||||
* unnamed package in Java).
|
||||
*/
|
||||
public static final String GLOBALS_PACKAGE_NAME = "globals";
|
||||
/**
|
||||
* The constant for the classes where members are generated as top-level
|
||||
* elements (global variables and functions).
|
||||
*/
|
||||
public static final String GLOBALS_CLASS_NAME = "Globals";
|
||||
/** The constant for predefined utilities. */
|
||||
public static final String UTIL_CLASSNAME = UTIL_PACKAGE + ".Globals";
|
||||
/**
|
||||
* The constant for the interface name that contains all the generated
|
||||
* string types (short name).
|
||||
*/
|
||||
public static final String STRING_TYPES_INTERFACE_NAME = "StringTypes";
|
||||
/** The constant for the function classes package. */
|
||||
public static final String FUNCTION_CLASSES_PACKAGE = UTIL_PACKAGE + ".function";
|
||||
/** The constant for the tuple classes package. */
|
||||
public static final String TUPLE_CLASSES_PACKAGE = UTIL_PACKAGE + ".tuple";
|
||||
/** The constant for the tuple classes prefix. */
|
||||
public static final String TUPLE_CLASSES_PREFIX = "Tuple";
|
||||
/** The constant for the package containing union types. */
|
||||
public static final String UNION_PACKAGE = UTIL_PACKAGE + ".union";
|
||||
/** The constant for the Union core class full name. */
|
||||
public static final String UNION_CLASS_NAME = UNION_PACKAGE + ".Union";
|
||||
/** The constant for indexed access function. */
|
||||
public static final String INDEXED_GET_FUCTION_NAME = "$get";
|
||||
/** The constant for indexed assignment function. */
|
||||
public static final String INDEXED_SET_FUCTION_NAME = "$set";
|
||||
public static final String INDEXED_DELETE_FUCTION_NAME = "$delete";
|
||||
public static final String NEW_FUNCTION_NAME = "$new";
|
||||
public static final String ANONYMOUS_FUNCTION_NAME = "$apply";
|
||||
public static final String ANONYMOUS_STATIC_FUNCTION_NAME = "$applyStatic";
|
||||
|
||||
/**
|
||||
* Default name of the directory where the TypeScript definition files can
|
||||
* be found.
|
||||
*/
|
||||
public static final String TS_LIBS_DIR_NAME = "typings";
|
||||
|
||||
/**
|
||||
* The constant for main functions (translate to global code, which is
|
||||
* executed when the file is loaded).
|
||||
*/
|
||||
public static final String MAIN_FUNCTION_NAME = "main";
|
||||
|
||||
/**
|
||||
* The TypeScript module file names, when transpiling with modules (without
|
||||
* extension).
|
||||
*/
|
||||
public static final String MODULE_FILE_NAME = "module";
|
||||
|
||||
public static final String OBJECT_CLASSNAME = JSweetConfig.LANG_PACKAGE + ".Object";
|
||||
|
||||
public static final String ANNOTATION_DISABLED = JSweetConfig.LANG_PACKAGE + ".Disabled";
|
||||
public static final String ANNOTATION_ERASED = JSweetConfig.LANG_PACKAGE + ".Erased";
|
||||
public static final String ANNOTATION_AMBIENT = JSweetConfig.LANG_PACKAGE + ".Ambient";
|
||||
public static final String ANNOTATION_MIXIN = JSweetConfig.LANG_PACKAGE + ".Mixin";
|
||||
public static final String ANNOTATION_OBJECT_TYPE = JSweetConfig.LANG_PACKAGE + ".ObjectType";
|
||||
public static final String ANNOTATION_MODULE = JSweetConfig.LANG_PACKAGE + ".Module";
|
||||
public static final String ANNOTATION_INTERFACE = JSweetConfig.LANG_PACKAGE + ".Interface";
|
||||
public static final String ANNOTATION_OPTIONAL = JSweetConfig.LANG_PACKAGE + ".Optional";
|
||||
public static final String ANNOTATION_STRING_TYPE = JSweetConfig.LANG_PACKAGE + ".StringType";
|
||||
public static final String ANNOTATION_ROOT = JSweetConfig.LANG_PACKAGE + ".Root";
|
||||
public static final String ANNOTATION_NAME = JSweetConfig.LANG_PACKAGE + ".Name";
|
||||
public static final String ANNOTATION_FUNCTIONAL_INTERFACE = FunctionalInterface.class.getName();
|
||||
|
||||
/**
|
||||
* This map contains the Java keywords that are taken into account in the
|
||||
* generation for avoiding keyword clashes.
|
||||
*/
|
||||
public static final Set<String> JAVA_KEYWORDS = new HashSet<String>();
|
||||
|
||||
/**
|
||||
* This map contains the JS keywords that are taken into account in the
|
||||
* generation for avoiding keyword clashes.
|
||||
*/
|
||||
public static final Set<String> JS_KEYWORDS = new HashSet<String>();
|
||||
|
||||
/**
|
||||
* This map contains the TS keywords that are taken into account in strict
|
||||
* mode (within classes).
|
||||
*/
|
||||
public static final Set<String> TS_STRICT_MODE_KEYWORDS = new HashSet<String>();
|
||||
|
||||
/**
|
||||
* This map contains the TS keywords that are taken into account at top
|
||||
* level.
|
||||
*/
|
||||
public static final Set<String> TS_TOP_LEVEL_KEYWORDS = new HashSet<String>();
|
||||
|
||||
static {
|
||||
// note TS keywords are removed from that list
|
||||
JAVA_KEYWORDS.add("abstract");
|
||||
JAVA_KEYWORDS.add("assert");
|
||||
// JAVA_KEYWORDS.add("boolean");
|
||||
JAVA_KEYWORDS.add("break");
|
||||
JAVA_KEYWORDS.add("byte");
|
||||
JAVA_KEYWORDS.add("case");
|
||||
JAVA_KEYWORDS.add("catch");
|
||||
JAVA_KEYWORDS.add("char");
|
||||
// JAVA_KEYWORDS.add("class");
|
||||
JAVA_KEYWORDS.add("const");
|
||||
JAVA_KEYWORDS.add("continue");
|
||||
JAVA_KEYWORDS.add("default");
|
||||
JAVA_KEYWORDS.add("do");
|
||||
JAVA_KEYWORDS.add("double");
|
||||
JAVA_KEYWORDS.add("else");
|
||||
// JAVA_KEYWORDS.add("enum");
|
||||
JAVA_KEYWORDS.add("extends");
|
||||
JAVA_KEYWORDS.add("final");
|
||||
JAVA_KEYWORDS.add("finally");
|
||||
JAVA_KEYWORDS.add("float");
|
||||
JAVA_KEYWORDS.add("for");
|
||||
JAVA_KEYWORDS.add("goto");
|
||||
JAVA_KEYWORDS.add("if");
|
||||
// JAVA_KEYWORDS.add("implements");
|
||||
JAVA_KEYWORDS.add("import");
|
||||
JAVA_KEYWORDS.add("instanceof");
|
||||
JAVA_KEYWORDS.add("int");
|
||||
// JAVA_KEYWORDS.add("interface");
|
||||
JAVA_KEYWORDS.add("long");
|
||||
JAVA_KEYWORDS.add("native");
|
||||
JAVA_KEYWORDS.add("new");
|
||||
JAVA_KEYWORDS.add("package");
|
||||
JAVA_KEYWORDS.add("private");
|
||||
JAVA_KEYWORDS.add("protected");
|
||||
JAVA_KEYWORDS.add("public");
|
||||
JAVA_KEYWORDS.add("return");
|
||||
JAVA_KEYWORDS.add("short");
|
||||
JAVA_KEYWORDS.add("static");
|
||||
JAVA_KEYWORDS.add("strictfp");
|
||||
JAVA_KEYWORDS.add("super");
|
||||
JAVA_KEYWORDS.add("switch");
|
||||
JAVA_KEYWORDS.add("synchronized");
|
||||
JAVA_KEYWORDS.add("this");
|
||||
JAVA_KEYWORDS.add("throw");
|
||||
JAVA_KEYWORDS.add("throws");
|
||||
JAVA_KEYWORDS.add("transient");
|
||||
JAVA_KEYWORDS.add("try");
|
||||
// JAVA_KEYWORDS.add("void");
|
||||
JAVA_KEYWORDS.add("volatile");
|
||||
JAVA_KEYWORDS.add("while");
|
||||
|
||||
JS_KEYWORDS.add("function");
|
||||
JS_KEYWORDS.add("var");
|
||||
JS_KEYWORDS.add("typeof");
|
||||
|
||||
TS_STRICT_MODE_KEYWORDS.add("as");
|
||||
TS_STRICT_MODE_KEYWORDS.add("implements");
|
||||
TS_STRICT_MODE_KEYWORDS.add("interface");
|
||||
TS_STRICT_MODE_KEYWORDS.add("let");
|
||||
TS_STRICT_MODE_KEYWORDS.add("package");
|
||||
TS_STRICT_MODE_KEYWORDS.add("private");
|
||||
TS_STRICT_MODE_KEYWORDS.add("protected");
|
||||
TS_STRICT_MODE_KEYWORDS.add("public");
|
||||
TS_STRICT_MODE_KEYWORDS.add("static");
|
||||
TS_STRICT_MODE_KEYWORDS.add("yield");
|
||||
TS_STRICT_MODE_KEYWORDS.add("symbol");
|
||||
TS_STRICT_MODE_KEYWORDS.add("type");
|
||||
TS_STRICT_MODE_KEYWORDS.add("from");
|
||||
TS_STRICT_MODE_KEYWORDS.add("of");
|
||||
|
||||
TS_TOP_LEVEL_KEYWORDS.add("require");
|
||||
}
|
||||
|
||||
/**
|
||||
* This function return a Javascript-friendly identifier from a
|
||||
* Java-formatted one.
|
||||
*
|
||||
* @param identifier
|
||||
* the Java-formatted identifier
|
||||
* @return the Javascript-friendly identifier
|
||||
*/
|
||||
public static String toJsIdentifier(String identifier) {
|
||||
// "trick" to change back java keywords, which are reserved to valid js
|
||||
// identifier (ex: Catch => catch, New => new)
|
||||
// TODO : but we should actually check if identifier's target has a
|
||||
// @Name
|
||||
if (!identifier.isEmpty() //
|
||||
&& Character.isUpperCase(identifier.charAt(0)) //
|
||||
&& (identifier.length() <= 1 || Character.isLowerCase(identifier.charAt(1))) //
|
||||
&& JSweetConfig.JAVA_KEYWORDS.contains(identifier.toLowerCase()) && !JSweetConfig.TS_STRICT_MODE_KEYWORDS.contains(identifier.toLowerCase())) {
|
||||
return identifier.toLowerCase();
|
||||
}
|
||||
return identifier;
|
||||
}
|
||||
|
||||
public static boolean isJDKReplacementMode() {
|
||||
return "java.lang".equals(LANG_PACKAGE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the JSweet object's fully qualified name.
|
||||
*/
|
||||
public static String getObjectClassName() {
|
||||
return LANG_PACKAGE + ".Object";
|
||||
}
|
||||
|
||||
/**
|
||||
* Tells if this qualified name belongs to the JDK (starts with
|
||||
* {@value #JAVA_PACKAGE}).
|
||||
*/
|
||||
public static boolean isJDKPath(String qualifiedName) {
|
||||
return qualifiedName.startsWith(JAVA_PACKAGE + ".");
|
||||
}
|
||||
|
||||
/**
|
||||
* Tells if this qualified name belongs to any TypeScript library definition
|
||||
* (starts with {@value #LIBS_PACKAGE}).
|
||||
*/
|
||||
public static boolean isLibPath(String qualifiedName) {
|
||||
return qualifiedName.startsWith(LIBS_PACKAGE + ".");
|
||||
}
|
||||
|
||||
/**
|
||||
* Tells if this qualified name belongs to one of the JSweet core package
|
||||
* (starts with {@value #ROOT_PACKAGE}).
|
||||
*/
|
||||
public static boolean isJSweetPath(String qualifiedName) {
|
||||
return qualifiedName.startsWith(ROOT_PACKAGE + ".");
|
||||
}
|
||||
|
||||
}
|
||||
21
src/org/jsweet/package-info.java
Normal file
21
src/org/jsweet/package-info.java
Normal file
@ -0,0 +1,21 @@
|
||||
/* Copyright 2015 CINCHEO SAS
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
/**
|
||||
* This package provides the JSweet configuration classes and some command line launchers.
|
||||
*
|
||||
* @author Renaud Pawlak
|
||||
*/
|
||||
package org.jsweet;
|
||||
|
||||
30
src/org/jsweet/transpiler/EcmaScriptComplianceLevel.java
Normal file
30
src/org/jsweet/transpiler/EcmaScriptComplianceLevel.java
Normal file
@ -0,0 +1,30 @@
|
||||
/* Copyright 2015 CINCHEO SAS
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.jsweet.transpiler;
|
||||
|
||||
/**
|
||||
* An enumeration for the EcmaScript versions.
|
||||
*/
|
||||
public enum EcmaScriptComplianceLevel implements Comparable<EcmaScriptComplianceLevel> {
|
||||
|
||||
ES3, ES5, ES6;
|
||||
|
||||
/**
|
||||
* Compares two compliance levels.
|
||||
*/
|
||||
public boolean higherThan(EcmaScriptComplianceLevel other) {
|
||||
return compareTo(other) > 0;
|
||||
}
|
||||
}
|
||||
179
src/org/jsweet/transpiler/JSweetContext.java
Normal file
179
src/org/jsweet/transpiler/JSweetContext.java
Normal file
@ -0,0 +1,179 @@
|
||||
/* Copyright 2015 CINCHEO SAS
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.jsweet.transpiler;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.jsweet.transpiler.OverloadScanner.Overload;
|
||||
import org.jsweet.transpiler.util.DirectedGraph;
|
||||
|
||||
import com.sun.tools.javac.code.Symbol.ClassSymbol;
|
||||
import com.sun.tools.javac.code.Symbol.PackageSymbol;
|
||||
import com.sun.tools.javac.code.Symtab;
|
||||
import com.sun.tools.javac.code.Types;
|
||||
import com.sun.tools.javac.util.Context;
|
||||
import com.sun.tools.javac.util.Names;
|
||||
|
||||
/**
|
||||
* The transpiler context, which is an extension of the Java compiler context.
|
||||
*
|
||||
* @author Renaud Pawlak
|
||||
*/
|
||||
public class JSweetContext extends Context {
|
||||
/**
|
||||
* A cache of method overloads.
|
||||
*
|
||||
* @see OverloadScanner
|
||||
* @see OverloadScanner.Overload
|
||||
*/
|
||||
public Map<ClassSymbol, Map<String, Overload>> overloads = new HashMap<>();
|
||||
|
||||
/**
|
||||
* An overload is a container of methods have the same name but different
|
||||
* signatures.
|
||||
*
|
||||
* @param clazz
|
||||
* the class to look into
|
||||
* @param methodName
|
||||
* the method name
|
||||
* @return an overload that contains 0 to many methods matching the given
|
||||
* name
|
||||
*/
|
||||
public Overload getOverload(ClassSymbol clazz, String methodName) {
|
||||
Map<String, Overload> m = overloads.get(clazz);
|
||||
if (m == null) {
|
||||
return null;
|
||||
}
|
||||
return m.get(methodName);
|
||||
}
|
||||
|
||||
/**
|
||||
* The Java compiler symbol table for fast access.
|
||||
*/
|
||||
public Symtab symtab;
|
||||
|
||||
/**
|
||||
* The Java compiler names for fast access.
|
||||
*/
|
||||
public Names names;
|
||||
|
||||
/**
|
||||
* The Java compiler types for fast access.
|
||||
*/
|
||||
public Types types;
|
||||
|
||||
/**
|
||||
* A flag to tell if the transpiler is in module mode or not.
|
||||
*/
|
||||
public boolean useModules = false;
|
||||
|
||||
/**
|
||||
* The source files that are being transpiled.
|
||||
*/
|
||||
public SourceFile[] sourceFiles;
|
||||
|
||||
private List<String> usedModules = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* Register a module that is used by the transpiled program.
|
||||
*
|
||||
* @param moduleName
|
||||
* the module being used
|
||||
*/
|
||||
public void registerUsedModule(String moduleName) {
|
||||
if (!usedModules.contains(moduleName)) {
|
||||
usedModules.add(moduleName);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The list of modules used by the transpiled program.
|
||||
*/
|
||||
public List<String> getUsedModules() {
|
||||
return usedModules;
|
||||
}
|
||||
|
||||
private Map<PackageSymbol, Set<String>> importedNamesInPackages = new HashMap<>();
|
||||
|
||||
/**
|
||||
* Register a name that is imported by the given package of the transpiled
|
||||
* program.
|
||||
*
|
||||
* @param package
|
||||
* the package that is importing the name
|
||||
* @param name
|
||||
* the name being imported
|
||||
*/
|
||||
public void registerImportedName(PackageSymbol packageSymbol, String name) {
|
||||
Set<String> importedNames = importedNamesInPackages.get(packageSymbol);
|
||||
if (importedNames == null) {
|
||||
importedNames = new HashSet<>();
|
||||
importedNamesInPackages.put(packageSymbol, importedNames);
|
||||
}
|
||||
if (!importedNames.contains(name)) {
|
||||
importedNames.add(name);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The list of names imported by the given package of the transpiled
|
||||
* program.
|
||||
*/
|
||||
public Set<String> getImportedNames(PackageSymbol packageSymbol) {
|
||||
Set<String> importedNames = importedNamesInPackages.get(packageSymbol);
|
||||
if (importedNames == null) {
|
||||
importedNames = new HashSet<>();
|
||||
importedNamesInPackages.put(packageSymbol, importedNames);
|
||||
}
|
||||
return importedNames;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears the names imported by the given package.
|
||||
*/
|
||||
public void clearImportedNames(PackageSymbol packageSymbol) {
|
||||
Set<String> importedNames = new HashSet<>();
|
||||
importedNamesInPackages.put(packageSymbol, importedNames);
|
||||
}
|
||||
|
||||
/**
|
||||
* Source files containing a main method.
|
||||
*/
|
||||
public List<File> entryFiles = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* A graph containing the module dependencies when using modules (empty
|
||||
* otherwise).
|
||||
*/
|
||||
public DirectedGraph<PackageSymbol> packageDependencies = new DirectedGraph<>();
|
||||
|
||||
/**
|
||||
* Stores the root package namee (i.e. packages contained in the default
|
||||
* package or in a package annotated with the {@link jsweet.lang.Root} annotation).
|
||||
*/
|
||||
public Set<String> rootPackageNames = new HashSet<>();
|
||||
|
||||
/**
|
||||
* Globally imported name (in the global namespace).
|
||||
*/
|
||||
public Set<String> globalImports = new HashSet<>();
|
||||
|
||||
}
|
||||
355
src/org/jsweet/transpiler/JSweetProblem.java
Normal file
355
src/org/jsweet/transpiler/JSweetProblem.java
Normal file
@ -0,0 +1,355 @@
|
||||
/* Copyright 2015 CINCHEO SAS
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.jsweet.transpiler;
|
||||
|
||||
/**
|
||||
* This enumeration holds all the possible JSweet transpilation problems
|
||||
* (warnings and errors) and the associated messages.
|
||||
*
|
||||
* @author Renaud Pawlak
|
||||
*/
|
||||
public enum JSweetProblem {
|
||||
|
||||
/**
|
||||
* Raised when the Java compiler reports errors.
|
||||
*/
|
||||
JAVA_ERRORS(Severity.ERROR),
|
||||
/**
|
||||
* Raised when the Tsc transpiler reports an error.
|
||||
*/
|
||||
INTERNAL_TSC_ERROR(Severity.ERROR),
|
||||
/**
|
||||
* Raised when the Tsc transpiler (or the expected version) is not found if
|
||||
* required.
|
||||
*/
|
||||
TSC_CANNOT_START(Severity.ERROR),
|
||||
/**
|
||||
* Raised when Node is not found.
|
||||
*/
|
||||
NODE_CANNOT_START(Severity.ERROR),
|
||||
/**
|
||||
* Raised when the program tries to access a forbidden Java type.
|
||||
*
|
||||
* <p>
|
||||
* By default, all Java types are forbidden except for some classes in the
|
||||
* java.lang: Object, String, Boolean, Number, Integer, Double, Void.
|
||||
*/
|
||||
JDK_TYPE(Severity.ERROR),
|
||||
/**
|
||||
* Raised when the program tries to access a forbidden Java method.
|
||||
*/
|
||||
JDK_METHOD(Severity.ERROR),
|
||||
/**
|
||||
* Raised when the program tries to access an erased method (Erased
|
||||
* annotation).
|
||||
*/
|
||||
ERASED_METHOD(Severity.ERROR),
|
||||
/**
|
||||
* Raised when the program misuses a class annotated with the Erased
|
||||
* annotation.
|
||||
*/
|
||||
ERASED_CLASS_CONSTRUCTOR(Severity.ERROR),
|
||||
/**
|
||||
* Raised when the program tries to use the synchronized keyword.
|
||||
*/
|
||||
SYNCHRONIZATION(Severity.ERROR),
|
||||
/**
|
||||
* Raised when a method has the same name as a field, including fields
|
||||
* defined in superclasses.
|
||||
*/
|
||||
METHOD_CONFLICTS_FIELD(Severity.ERROR),
|
||||
/**
|
||||
* Raised when a field has the same name as a method, including methods
|
||||
* defined in superclasses.
|
||||
*/
|
||||
FIELD_CONFLICTS_METHOD(Severity.ERROR),
|
||||
/**
|
||||
* Raised when an inner class is found.
|
||||
*/
|
||||
INNER_CLASS(Severity.ERROR),
|
||||
/**
|
||||
* Raised when a class initializer is something else than a field
|
||||
* assignment.
|
||||
*/
|
||||
INVALID_INITIALIZER_STATEMENT(Severity.ERROR),
|
||||
/**
|
||||
* Raised when a non-optional field has not been initialized.
|
||||
*/
|
||||
UNINITIALIZED_FIELD(Severity.ERROR),
|
||||
/**
|
||||
* Raised when an @Optional annotation is set to a field that is not member
|
||||
* of an interface.
|
||||
*/
|
||||
USELESS_OPTIONAL_ANNOTATION(Severity.WARNING),
|
||||
/**
|
||||
* Raised when a local variable uses a forbidden JS keyword (var, function,
|
||||
* typeof, ...).
|
||||
*/
|
||||
JS_KEYWORD_CONFLICT(Severity.WARNING),
|
||||
/**
|
||||
* Raised when a private visibility is used in an interface.
|
||||
*/
|
||||
INVALID_PRIVATE_IN_INTERFACE(Severity.ERROR),
|
||||
/**
|
||||
* Raised when a static modifier is used in an interface.
|
||||
*/
|
||||
INVALID_STATIC_IN_INTERFACE(Severity.ERROR),
|
||||
/**
|
||||
* Raised when a method body is defined in an interface.
|
||||
*/
|
||||
INVALID_METHOD_BODY_IN_INTERFACE(Severity.ERROR),
|
||||
/**
|
||||
* Raised when a field initializer is defined in an interface.
|
||||
*/
|
||||
INVALID_FIELD_INITIALIZER_IN_INTERFACE(Severity.ERROR),
|
||||
/**
|
||||
* Raised when an initializer is defined in an interface.
|
||||
*/
|
||||
INVALID_INITIALIZER_IN_INTERFACE(Severity.ERROR),
|
||||
/**
|
||||
* Raised when an overload is not valid.
|
||||
*/
|
||||
INVALID_OVERLOAD(Severity.ERROR),
|
||||
/**
|
||||
* Raised when a member is named 'constructor'.
|
||||
*/
|
||||
CONSTRUCTOR_MEMBER(Severity.ERROR),
|
||||
/**
|
||||
* Raised when a class annotated with @Interface is not abstract.
|
||||
*/
|
||||
INTERFACE_MUST_BE_ABSTRACT(Severity.ERROR),
|
||||
/**
|
||||
* Raised when a native modifier is used at the wrong place (only allowed in
|
||||
* definitions).
|
||||
*/
|
||||
NATIVE_MODIFIER_IS_NOT_ALLOWED(Severity.ERROR),
|
||||
|
||||
/**
|
||||
* Raised when instanceof is applied to an interface.
|
||||
*/
|
||||
INVALID_INSTANCEOF_INTERFACE(Severity.ERROR),
|
||||
/**
|
||||
* Raised when the program tries to use a label.
|
||||
*/
|
||||
LABELS_ARE_NOT_SUPPORTED(Severity.ERROR),
|
||||
/**
|
||||
* Raised when a try statement does not declare a catch or a finally clause.
|
||||
*/
|
||||
TRY_WITHOUT_CATCH_OR_FINALLY(Severity.ERROR),
|
||||
/**
|
||||
* Raised when a try statement declares multiple catch clauses.
|
||||
*/
|
||||
TRY_WITH_MULTIPLE_CATCHES(Severity.ERROR),
|
||||
/**
|
||||
* Raised when a try-with-resource statement is used in the program.
|
||||
*/
|
||||
UNSUPPORTED_TRY_WITH_RESOURCE(Severity.ERROR),
|
||||
/**
|
||||
* Raised when a set is used in a global context (no enclosing class)
|
||||
*/
|
||||
GLOBAL_INDEXER_SET(Severity.ERROR),
|
||||
/**
|
||||
* Raised when a get is used in a global context (no enclosing class)
|
||||
*/
|
||||
GLOBAL_INDEXER_GET(Severity.ERROR),
|
||||
/**
|
||||
* Raised when a delete is used in a global context (no enclosing class)
|
||||
*/
|
||||
GLOBAL_DELETE(Severity.ERROR),
|
||||
/**
|
||||
* Raised when a constructor is defined in a global class
|
||||
*/
|
||||
GLOBAL_CONSTRUCTOR_DEF(Severity.ERROR),
|
||||
/**
|
||||
* Raised if global class is instantiated
|
||||
*/
|
||||
GLOBAL_CANNOT_BE_INSTANTIATED(Severity.ERROR),
|
||||
/**
|
||||
* Raised when a string literal is expected.
|
||||
*/
|
||||
STRING_LITERAL_EXPECTED(Severity.ERROR),
|
||||
/**
|
||||
* Raised when an enum defines a field.
|
||||
*/
|
||||
INVALID_FIELD_IN_ENUM(Severity.ERROR),
|
||||
/**
|
||||
* Raised when an enum defines a constructor.
|
||||
*/
|
||||
INVALID_CONSTRUCTOR_IN_ENUM(Severity.ERROR),
|
||||
/**
|
||||
* Raised when an enum defines a method.
|
||||
*/
|
||||
INVALID_METHOD_IN_ENUM(Severity.ERROR),
|
||||
/**
|
||||
* Raised when an ambient method defines an implementation.
|
||||
*/
|
||||
INVALID_METHOD_BODY_IN_AMBIENT(Severity.ERROR),
|
||||
/**
|
||||
* Raised when an ambient constructor defines an implementation that is not
|
||||
* empty.
|
||||
*/
|
||||
INVALID_NON_EMPTY_CONSTRUCTOR_IN_AMBIENT(Severity.ERROR),
|
||||
/**
|
||||
* Raised when an ambient member uses an invalid modifier.
|
||||
*/
|
||||
INVALID_MODIFIER_IN_AMBIENT(Severity.ERROR),
|
||||
/**
|
||||
* Raised when an indexed set goes against indexed get type.
|
||||
*/
|
||||
INDEXED_SET_TYPE_MISMATCH(Severity.ERROR),
|
||||
/**
|
||||
* Raised when an union type assignment is not compatible with one of the
|
||||
* union-ed types.
|
||||
*/
|
||||
UNION_TYPE_MISMATCH(Severity.ERROR),
|
||||
/**
|
||||
* Raised when an union type assignment is not compatible with one of the
|
||||
* union-ed types.
|
||||
*/
|
||||
BUNDLE_WITH_COMMONJS(Severity.WARNING),
|
||||
/**
|
||||
* Raised when a bundle cannot be done because of a cycle in the
|
||||
* module/packages.
|
||||
*/
|
||||
BUNDLE_HAS_CYCLE(Severity.ERROR),
|
||||
/**
|
||||
* Raised when a bundle cannot be done because it has no entries.
|
||||
*/
|
||||
BUNDLE_HAS_NO_ENTRIES(Severity.WARNING),
|
||||
/**
|
||||
* Raised when a package is named after an invalid name (typically a
|
||||
* TypeScript keyword).
|
||||
*/
|
||||
PACKAGE_NAME_CONTAINS_KEYWORD(Severity.ERROR);
|
||||
|
||||
private Severity severity;
|
||||
|
||||
/**
|
||||
* Gets the severity of this problem.
|
||||
*/
|
||||
public Severity getSeverity() {
|
||||
return severity;
|
||||
}
|
||||
|
||||
private JSweetProblem(Severity severity) {
|
||||
this.severity = severity;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the associated message.
|
||||
*/
|
||||
public String getMessage(Object... params) {
|
||||
switch (this) {
|
||||
case JAVA_ERRORS:
|
||||
return String.format("Javac reports %s error(s) that should be fixed before compiling", params);
|
||||
case INTERNAL_TSC_ERROR:
|
||||
return String.format("Internal TypeScript error: %s", params);
|
||||
case NODE_CANNOT_START:
|
||||
return String.format("Cannot find Node.js: install first and make sure that the 'node' command is in your execution path", params);
|
||||
case TSC_CANNOT_START:
|
||||
return String.format("Cannot find TypeScript compiler: install first and make sure that the 'tsc' command is in your execution path", params);
|
||||
case JDK_TYPE:
|
||||
return String.format("Invalid access to JDK type %s from JSweet", params);
|
||||
case JDK_METHOD:
|
||||
return String.format("Invalid access to JDK method %s from JSweet", params);
|
||||
case ERASED_METHOD:
|
||||
return String.format("Invalid access to erased method %s", params);
|
||||
case ERASED_CLASS_CONSTRUCTOR:
|
||||
return String.format("Erased class constructors must take exactly one parameter", params);
|
||||
case SYNCHRONIZATION:
|
||||
return String.format("Synchronization is not allowed in JSweet", params);
|
||||
case METHOD_CONFLICTS_FIELD:
|
||||
return String.format("Method %s has the same name as a field in %s", params);
|
||||
case FIELD_CONFLICTS_METHOD:
|
||||
return String.format("Field %s has the same name as a method in %s", params);
|
||||
case INNER_CLASS:
|
||||
return String.format("Inner classes are not allowed in JSweet: %s", params);
|
||||
case INVALID_INITIALIZER_STATEMENT:
|
||||
return String.format("Invalid initializer statement; only field assignments are allowed", params);
|
||||
case UNINITIALIZED_FIELD:
|
||||
return String.format("Field %s is not optional (see @Optional) but has not been initialized", params);
|
||||
case USELESS_OPTIONAL_ANNOTATION:
|
||||
return String.format("Useless @Optional field %s (fields are optional by default in classes, use @Interface to define %s as an interface)", params);
|
||||
case JS_KEYWORD_CONFLICT:
|
||||
return String.format("Local variable name '%s' is not allowed and is automatically generated to '_jsweet_%s'", params);
|
||||
case INVALID_METHOD_BODY_IN_INTERFACE:
|
||||
return String.format("Method %s cannot define a body in interface %s", params);
|
||||
case INVALID_PRIVATE_IN_INTERFACE:
|
||||
return String.format("Member %s cannot be private in interface %s", params);
|
||||
case INVALID_STATIC_IN_INTERFACE:
|
||||
return String.format("Member %s cannot be static in interface %s", params);
|
||||
case INVALID_FIELD_INITIALIZER_IN_INTERFACE:
|
||||
return String.format("Field %s cannot be initialized in interface %s", params);
|
||||
case INVALID_INITIALIZER_IN_INTERFACE:
|
||||
return String.format("No initialization blocks are allowed in interface %s", params);
|
||||
case INVALID_OVERLOAD:
|
||||
return String.format("Invalid overload of method %s", params);
|
||||
case CONSTRUCTOR_MEMBER:
|
||||
return String.format("Invalid member name 'constructor'", params);
|
||||
case INTERFACE_MUST_BE_ABSTRACT:
|
||||
return String.format("@Interface '%s' must be abstract", params);
|
||||
case NATIVE_MODIFIER_IS_NOT_ALLOWED:
|
||||
return String.format("Method %s cannot be native", params);
|
||||
case INVALID_INSTANCEOF_INTERFACE:
|
||||
return String.format("Operator 'instanceof' cannot apply to interfaces", params);
|
||||
case LABELS_ARE_NOT_SUPPORTED:
|
||||
return String.format("Labels are not supported", params);
|
||||
case TRY_WITHOUT_CATCH_OR_FINALLY:
|
||||
return String.format("Try statement must define at least a catch or a finally clause", params);
|
||||
case UNSUPPORTED_TRY_WITH_RESOURCE:
|
||||
return String.format("Try-with-resource statement is not supported", params);
|
||||
case TRY_WITH_MULTIPLE_CATCHES:
|
||||
return String.format("Try statement cannot define more than one catch clause", params);
|
||||
case GLOBAL_INDEXER_GET:
|
||||
return String.format("Indexer cannot be used in a global context", params);
|
||||
case GLOBAL_INDEXER_SET:
|
||||
return String.format("Indexer cannot be used in a global context", params);
|
||||
case GLOBAL_DELETE:
|
||||
return String.format("static delete cannot be used in a global context", params);
|
||||
case STRING_LITERAL_EXPECTED:
|
||||
return String.format("String literal expected", params);
|
||||
case GLOBAL_CONSTRUCTOR_DEF:
|
||||
return String.format("Global class cannot have constructor", params);
|
||||
case GLOBAL_CANNOT_BE_INSTANTIATED:
|
||||
return String.format("Global classes cannot be instantiated", params);
|
||||
case INVALID_CONSTRUCTOR_IN_ENUM:
|
||||
return String.format("Constructors are not allowed in enums", params);
|
||||
case INVALID_FIELD_IN_ENUM:
|
||||
return String.format("Fields are not allowed in enums", params);
|
||||
case INVALID_METHOD_IN_ENUM:
|
||||
return String.format("Methods are not allowed in enums", params);
|
||||
case INVALID_METHOD_BODY_IN_AMBIENT:
|
||||
return String.format("Method %s is an ambiant declaration and cannot define an implementation", params);
|
||||
case INVALID_NON_EMPTY_CONSTRUCTOR_IN_AMBIENT:
|
||||
return String.format("Constructor is an ambiant declaration and must have an empty body", params);
|
||||
case INVALID_MODIFIER_IN_AMBIENT:
|
||||
return String.format("Modifier '%s' is not allowed in an ambiant declaration", params);
|
||||
case INDEXED_SET_TYPE_MISMATCH:
|
||||
return String.format("Type mismatch, expecting '%s' (inferred from the indexed getter type)", params);
|
||||
case UNION_TYPE_MISMATCH:
|
||||
return String.format("Type mismatch in union type", params);
|
||||
case BUNDLE_WITH_COMMONJS:
|
||||
return String.format("No bundle file generated: choose the 'commonjs' module kind when specifying a bundle file", params);
|
||||
case BUNDLE_HAS_CYCLE:
|
||||
return String.format("No bundle file generated: cycle detected in package graph %s", params);
|
||||
case BUNDLE_HAS_NO_ENTRIES:
|
||||
return String.format("No bundle file generated: no entries found, you must define at least one main method", params);
|
||||
case PACKAGE_NAME_CONTAINS_KEYWORD:
|
||||
return String.format("A package name cannot contain top-level keyword(s): %s", params);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
1193
src/org/jsweet/transpiler/JSweetTranspiler.java
Normal file
1193
src/org/jsweet/transpiler/JSweetTranspiler.java
Normal file
File diff suppressed because it is too large
Load Diff
49
src/org/jsweet/transpiler/ModuleKind.java
Normal file
49
src/org/jsweet/transpiler/ModuleKind.java
Normal file
@ -0,0 +1,49 @@
|
||||
/* Copyright 2015 CINCHEO SAS
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.jsweet.transpiler;
|
||||
|
||||
/**
|
||||
* An enumeration of the support module kinds.
|
||||
*
|
||||
* @author Renaud Pawlak
|
||||
* @see JSweetTranspiler#setModuleKind(ModuleKind)
|
||||
*/
|
||||
public enum ModuleKind {
|
||||
/**
|
||||
* The generated code is flat and does not use modules.
|
||||
*/
|
||||
none,
|
||||
/**
|
||||
* The generated code uses <code>commonjs</code> module kind, which can run
|
||||
* under <code>node</code> and be bundled for running in a Web browser.
|
||||
*
|
||||
* @see JSweetTranspiler#setModuleKind(ModuleKind)
|
||||
*/
|
||||
commonjs,
|
||||
/**
|
||||
* The generated code uses the <code>amd</code> module kind. This can run on
|
||||
* <code>require.js</code> enabled Web browsers.
|
||||
*/
|
||||
amd,
|
||||
/**
|
||||
* The generated code uses the <code>system</code> module kind.
|
||||
*/
|
||||
system,
|
||||
/**
|
||||
* The generated code uses the <code>umd</code> (EcmaScript 6 Universal
|
||||
* Module Definition) module kind.
|
||||
*/
|
||||
umd
|
||||
}
|
||||
214
src/org/jsweet/transpiler/OverloadScanner.java
Normal file
214
src/org/jsweet/transpiler/OverloadScanner.java
Normal file
@ -0,0 +1,214 @@
|
||||
/* Copyright 2015 CINCHEO SAS
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.jsweet.transpiler;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.lang.model.element.Element;
|
||||
|
||||
import org.jsweet.JSweetConfig;
|
||||
import org.jsweet.transpiler.util.Util;
|
||||
|
||||
import com.sun.tools.javac.code.Symbol.TypeSymbol;
|
||||
import com.sun.tools.javac.code.Types;
|
||||
import com.sun.tools.javac.code.Symbol.ClassSymbol;
|
||||
import com.sun.tools.javac.code.Symbol.MethodSymbol;
|
||||
import com.sun.tools.javac.tree.JCTree;
|
||||
import com.sun.tools.javac.tree.JCTree.JCClassDecl;
|
||||
import com.sun.tools.javac.tree.JCTree.JCCompilationUnit;
|
||||
import com.sun.tools.javac.tree.JCTree.JCExpression;
|
||||
import com.sun.tools.javac.tree.JCTree.JCExpressionStatement;
|
||||
import com.sun.tools.javac.tree.JCTree.JCLiteral;
|
||||
import com.sun.tools.javac.tree.JCTree.JCMethodDecl;
|
||||
import com.sun.tools.javac.tree.JCTree.JCMethodInvocation;
|
||||
import com.sun.tools.javac.tree.JCTree.JCReturn;
|
||||
import com.sun.tools.javac.tree.JCTree.JCStatement;
|
||||
import com.sun.tools.javac.tree.TreeScanner;
|
||||
|
||||
/**
|
||||
* This AST scanner detects method overloads and gather them into
|
||||
* {@link Overload} objects.
|
||||
*
|
||||
* @author Renaud Pawlak
|
||||
*/
|
||||
public class OverloadScanner extends TreeScanner {
|
||||
|
||||
JSweetContext context;
|
||||
Types types;
|
||||
int pass = 1;
|
||||
|
||||
/**
|
||||
* Gathers methods overloading each other.
|
||||
*
|
||||
* @author Renaud Pawlak
|
||||
*/
|
||||
public class Overload {
|
||||
/**
|
||||
* The method name.
|
||||
*/
|
||||
public String methodName;
|
||||
/**
|
||||
* The methods carrying the same name.
|
||||
*/
|
||||
public List<MethodSymbol> methods = new ArrayList<>();
|
||||
/**
|
||||
* Tells if this overload is valid wrt to JSweet conventions.
|
||||
*/
|
||||
public boolean isValid = true;
|
||||
/**
|
||||
* The core method of the overload, that is to say the one holding the
|
||||
* implementation.
|
||||
*/
|
||||
public MethodSymbol coreMethod;
|
||||
/**
|
||||
* The default values for the parameters of the core method.
|
||||
*/
|
||||
public JCLiteral[] defaultValues;
|
||||
|
||||
/**
|
||||
* Checks the validity of the overload and calculates the default
|
||||
* values.
|
||||
*/
|
||||
public void calculate() {
|
||||
if (methods.size() < 2) {
|
||||
return;
|
||||
}
|
||||
methods.sort((m1, m2) -> {
|
||||
int i = m2.getParameters().size() - m1.getParameters().size();
|
||||
if (i == 0) {
|
||||
isValid = false;
|
||||
}
|
||||
return i;
|
||||
});
|
||||
if (isValid) {
|
||||
coreMethod = methods.get(0);
|
||||
defaultValues = new JCLiteral[coreMethod.getParameters().size()];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new overload scanner.
|
||||
*/
|
||||
public OverloadScanner(JSweetContext context) {
|
||||
this.context = context;
|
||||
this.types = Types.instance(context);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an overload instance for the given class and method.
|
||||
*/
|
||||
public Overload getOverload(ClassSymbol clazz, MethodSymbol method) {
|
||||
Map<String, Overload> m = context.overloads.get(clazz);
|
||||
if (m == null) {
|
||||
m = new HashMap<>();
|
||||
context.overloads.put(clazz, m);
|
||||
}
|
||||
String name = method.getSimpleName().toString();
|
||||
Overload overload = m.get(name);
|
||||
if (overload == null) {
|
||||
overload = new Overload();
|
||||
overload.methodName = name;
|
||||
m.put(name, overload);
|
||||
}
|
||||
return overload;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitClassDef(JCClassDecl classdecl) {
|
||||
if (classdecl.sym.isInterface() || Util.hasAnnotationType(classdecl.sym, JSweetConfig.ANNOTATION_INTERFACE)) {
|
||||
return;
|
||||
}
|
||||
if (pass == 1) {
|
||||
ClassSymbol clazz = classdecl.sym;
|
||||
for (Element e : clazz.getEnclosedElements()) {
|
||||
if (e instanceof MethodSymbol) {
|
||||
MethodSymbol method = (MethodSymbol) e;
|
||||
Overload overload = getOverload(clazz, method);
|
||||
overload.methods.add(method);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (JCTree member : classdecl.defs) {
|
||||
if (member instanceof JCMethodDecl) {
|
||||
this.scan(member);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitMethodDef(JCMethodDecl methodDecl) {
|
||||
Element e = methodDecl.sym.getEnclosingElement();
|
||||
if (!(e instanceof ClassSymbol)) {
|
||||
return;
|
||||
}
|
||||
Overload overload = context.getOverload(((ClassSymbol) e), methodDecl.name.toString());
|
||||
if (overload != null && overload.methods.size() > 1 && overload.isValid) {
|
||||
if (!methodDecl.sym.equals(overload.coreMethod)) {
|
||||
if (methodDecl.body != null && methodDecl.body.stats.size() == 1) {
|
||||
JCMethodInvocation invocation = null;
|
||||
JCStatement stat = methodDecl.body.stats.get(0);
|
||||
if (stat instanceof JCReturn) {
|
||||
if (((JCReturn) stat).expr instanceof JCMethodInvocation) {
|
||||
invocation = (JCMethodInvocation) ((JCReturn) stat).expr;
|
||||
}
|
||||
} else if (stat instanceof JCExpressionStatement) {
|
||||
if (((JCExpressionStatement) stat).expr instanceof JCMethodInvocation) {
|
||||
invocation = (JCMethodInvocation) ((JCExpressionStatement) stat).expr;
|
||||
}
|
||||
}
|
||||
if (invocation == null) {
|
||||
overload.isValid = false;
|
||||
} else {
|
||||
MethodSymbol method = Util.findMethodDeclarationInType(types, (TypeSymbol) e, invocation);
|
||||
if (method != null && method.getSimpleName().toString().equals(overload.methodName)) {
|
||||
if (invocation.getArguments() != null) {
|
||||
for (int i = 0; i < invocation.getArguments().size(); i++) {
|
||||
JCExpression expr = invocation.getArguments().get(i);
|
||||
if (expr instanceof JCLiteral) {
|
||||
overload.defaultValues[i] = (JCLiteral) expr;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
overload.isValid = false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
overload.isValid = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes all the overload of a given compilation unit.
|
||||
*/
|
||||
public void process(JCCompilationUnit cu) {
|
||||
scan(cu);
|
||||
for (Map<String, Overload> overloads : context.overloads.values()) {
|
||||
for (Overload overload : overloads.values()) {
|
||||
overload.calculate();
|
||||
}
|
||||
}
|
||||
pass++;
|
||||
scan(cu);
|
||||
}
|
||||
|
||||
}
|
||||
38
src/org/jsweet/transpiler/Severity.java
Normal file
38
src/org/jsweet/transpiler/Severity.java
Normal file
@ -0,0 +1,38 @@
|
||||
/* Copyright 2015 CINCHEO SAS
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.jsweet.transpiler;
|
||||
|
||||
/**
|
||||
* The severity of a tranpilation event.
|
||||
*
|
||||
* @author Renaud Pawlak
|
||||
*/
|
||||
public enum Severity {
|
||||
|
||||
/**
|
||||
* Just a message to the programmer.
|
||||
*/
|
||||
MESSAGE,
|
||||
/**
|
||||
* A potential problem to be reported to the programmer.
|
||||
*/
|
||||
WARNING,
|
||||
/**
|
||||
* A problem that will end up stopping the transpilation process with
|
||||
* reporting a failure.
|
||||
*/
|
||||
ERROR;
|
||||
|
||||
}
|
||||
249
src/org/jsweet/transpiler/SourceFile.java
Normal file
249
src/org/jsweet/transpiler/SourceFile.java
Normal file
@ -0,0 +1,249 @@
|
||||
/* Copyright 2015 CINCHEO SAS
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.jsweet.transpiler;
|
||||
|
||||
import static java.util.Arrays.asList;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Collection;
|
||||
import java.util.LinkedList;
|
||||
|
||||
/**
|
||||
* A source file represents a Java source file and holds information on the
|
||||
* transpiled output files (Typescript and Javascript files).
|
||||
*
|
||||
* @author Renaud Pawlak
|
||||
*/
|
||||
public class SourceFile {
|
||||
|
||||
private static void addFiles(String extension, File file, LinkedList<File> files) {
|
||||
if (file.isDirectory()) {
|
||||
for (File f : file.listFiles()) {
|
||||
addFiles(extension, f, files);
|
||||
}
|
||||
} else if (file.getName().endsWith(extension)) {
|
||||
files.add(file);
|
||||
} else {
|
||||
System.out.println("ignoring unrecognized file: " + file);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all the Java source files found in the given dirs and their subdirs.
|
||||
*/
|
||||
public static SourceFile[] getSourceFiles(File... dirs) {
|
||||
return getSourceFiles(asList(dirs));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all the Java source files found in the given dirs and their subdirs.
|
||||
*/
|
||||
public static SourceFile[] getSourceFiles(Iterable<File> dirs) {
|
||||
LinkedList<File> files = new LinkedList<>();
|
||||
for (File dir : dirs) {
|
||||
addFiles(".java", dir, files);
|
||||
}
|
||||
return toSourceFiles(files);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts files to source files.
|
||||
*/
|
||||
public static SourceFile[] toSourceFiles(File[] javaFiles) {
|
||||
return toSourceFiles(asList(javaFiles));
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts files to source files.
|
||||
*/
|
||||
public static SourceFile[] toSourceFiles(Collection<File> javaFiles) {
|
||||
SourceFile[] dest = new SourceFile[javaFiles.size()];
|
||||
int i = 0;
|
||||
for (File javaFile : javaFiles) {
|
||||
dest[i++] = new SourceFile(javaFile);
|
||||
}
|
||||
return dest;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts file paths to source files.
|
||||
*/
|
||||
public static SourceFile[] toSourceFiles(String... javaFilePaths) {
|
||||
SourceFile[] dest = new SourceFile[javaFilePaths.length];
|
||||
int i = 0;
|
||||
for (String javaFilePath : javaFilePaths) {
|
||||
dest[i++] = new SourceFile(new File(javaFilePath));
|
||||
}
|
||||
return dest;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts source files to files.
|
||||
*/
|
||||
public static File[] toFiles(SourceFile... sourceFiles) {
|
||||
File[] dest = new File[sourceFiles.length];
|
||||
for (int i = 0; i < sourceFiles.length; i++) {
|
||||
dest[i] = sourceFiles[i].javaFile;
|
||||
}
|
||||
return dest;
|
||||
}
|
||||
|
||||
/**
|
||||
* Touch the given source files.
|
||||
*
|
||||
* @see #touch()
|
||||
*/
|
||||
public static void touch(SourceFile... sourceFiles) {
|
||||
for (int i = 0; i < sourceFiles.length; i++) {
|
||||
sourceFiles[i].touch();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts source files to file paths.
|
||||
*/
|
||||
public static String[] toPaths(SourceFile[] sourceFiles) {
|
||||
String[] dest = new String[sourceFiles.length];
|
||||
for (int i = 0; i < sourceFiles.length; i++) {
|
||||
dest[i] = sourceFiles[i].javaFile.getPath();
|
||||
}
|
||||
return dest;
|
||||
}
|
||||
|
||||
private File javaFile;
|
||||
|
||||
/**
|
||||
* Internally used by {@link JSweetTranspiler}.
|
||||
*/
|
||||
long javaFileLastTranspiled = 0;
|
||||
|
||||
/**
|
||||
* Internally used by {@link JSweetTranspiler}.
|
||||
*/
|
||||
File tsFile;
|
||||
|
||||
/**
|
||||
* Internally used by {@link JSweetTranspiler}.
|
||||
*/
|
||||
File jsFile;
|
||||
|
||||
/**
|
||||
* Internally used by {@link JSweetTranspiler}.
|
||||
*/
|
||||
File jsMapFile;
|
||||
|
||||
/**
|
||||
* Internally used by {@link JSweetTranspiler}.
|
||||
*/
|
||||
long jsFileLastTranspiled = 0;
|
||||
|
||||
/**
|
||||
* Creates a source file from a file.
|
||||
*/
|
||||
public SourceFile(File javaFile) {
|
||||
this.javaFile = javaFile;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return javaFile.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the Java file.
|
||||
*/
|
||||
public File getJavaFile() {
|
||||
return javaFile;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the Java file.
|
||||
*/
|
||||
public void setJavaFile(File javaFile) {
|
||||
this.javaFile = javaFile;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the Typescript file (null until transpiled by
|
||||
* {@link JSweetTranspiler}).
|
||||
*/
|
||||
public File getTsFile() {
|
||||
return tsFile;
|
||||
}
|
||||
|
||||
/**
|
||||
* Internally used by {@link JSweetTranspiler}.
|
||||
*/
|
||||
protected void setTsFile(File tsFile) {
|
||||
this.tsFile = tsFile;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the Javascript file (null until transpiled by
|
||||
* {@link JSweetTranspiler}).
|
||||
*/
|
||||
public File getJsFile() {
|
||||
return jsFile;
|
||||
}
|
||||
|
||||
/**
|
||||
* Internally used by {@link JSweetTranspiler}.
|
||||
*/
|
||||
protected void setJsFile(File jsFile) {
|
||||
this.jsFile = jsFile;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the Javascript map file (null if not generated).
|
||||
*/
|
||||
public File getJsMapFile() {
|
||||
return jsMapFile;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the timestamp of the last Java file transpilation.
|
||||
*/
|
||||
public long getJavaFileLastTranspiled() {
|
||||
return javaFileLastTranspiled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the timestamp of the last generation of the Javascript file.
|
||||
*/
|
||||
public long getJsFileLastTranspiled() {
|
||||
return jsFileLastTranspiled;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
if (javaFile != null) {
|
||||
return javaFile.hashCode();
|
||||
} else {
|
||||
return super.hashCode();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears the transpilation information as if the file was not transpiled.
|
||||
*/
|
||||
public void touch() {
|
||||
tsFile = null;
|
||||
jsFile = null;
|
||||
jsMapFile = null;
|
||||
javaFileLastTranspiled = 0;
|
||||
jsFileLastTranspiled = 0;
|
||||
}
|
||||
|
||||
}
|
||||
121
src/org/jsweet/transpiler/TranspilationHandler.java
Normal file
121
src/org/jsweet/transpiler/TranspilationHandler.java
Normal file
@ -0,0 +1,121 @@
|
||||
/* Copyright 2015 CINCHEO SAS
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.jsweet.transpiler;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import com.sun.tools.javac.tree.JCTree;
|
||||
|
||||
/**
|
||||
* Objects implementing this interface handle transpilation errors and warnings.
|
||||
*
|
||||
* @author Renaud Pawlak
|
||||
*/
|
||||
public interface TranspilationHandler {
|
||||
|
||||
/**
|
||||
* A position in a source file.
|
||||
*
|
||||
* @author Renaud Pawlak
|
||||
*/
|
||||
static class SourcePosition {
|
||||
public SourcePosition(File file, JCTree sourceElement, int startPosition, int endPosition, int startLine, int startColumn, int endLine, int endColumn) {
|
||||
super();
|
||||
this.file = file;
|
||||
this.startPosition = startPosition;
|
||||
this.endPosition = endPosition;
|
||||
this.startLine = startLine;
|
||||
this.startColumn = startColumn;
|
||||
this.endLine = endLine;
|
||||
this.endColumn = endColumn;
|
||||
this.sourceElement = sourceElement;
|
||||
}
|
||||
|
||||
private File file;
|
||||
private int startPosition;
|
||||
private int endPosition;
|
||||
private int startLine;
|
||||
private int startColumn;
|
||||
private int endLine;
|
||||
private int endColumn;
|
||||
private JCTree sourceElement;
|
||||
|
||||
public File getFile() {
|
||||
return file;
|
||||
}
|
||||
|
||||
public int getStartPosition() {
|
||||
return startPosition;
|
||||
}
|
||||
|
||||
public int getEndPosition() {
|
||||
return endPosition;
|
||||
}
|
||||
|
||||
public int getStartLine() {
|
||||
return startLine;
|
||||
}
|
||||
|
||||
public int getStartColumn() {
|
||||
return startColumn;
|
||||
}
|
||||
|
||||
public int getEndLine() {
|
||||
return endLine;
|
||||
}
|
||||
|
||||
public int getEndColumn() {
|
||||
return endColumn;
|
||||
}
|
||||
|
||||
public JCTree getSourceElement() {
|
||||
return sourceElement;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "" + file + "(" + getStartLine() + "," + getStartColumn() + ")";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is called by the transpiler when a problem needs to be
|
||||
* reported.
|
||||
*
|
||||
* @param problem
|
||||
* the reported problem
|
||||
* @param sourcePosition
|
||||
* the position in the source file
|
||||
* @param message
|
||||
* the reported message
|
||||
*/
|
||||
public void report(JSweetProblem problem, SourcePosition sourcePosition, String message);
|
||||
|
||||
/**
|
||||
* This method is invoked when the tranpilation process ends.
|
||||
*
|
||||
* @param transpiler
|
||||
* the transpiler that generates this event
|
||||
* @param fullPass
|
||||
* true for a full transpilation (i.e. a non-watch mode
|
||||
* transpilation or first pass of a watch mode), false for an
|
||||
* incremental transpilation in the watch mode
|
||||
* @param files
|
||||
* the files that were transpiled (can be different from
|
||||
* <code>transpiler.getWatchedFiles()</code> in a non-full pass)
|
||||
*/
|
||||
public void onCompleted(JSweetTranspiler transpiler, boolean fullPass, SourceFile[] files);
|
||||
|
||||
}
|
||||
230
src/org/jsweet/transpiler/TypeChecker.java
Normal file
230
src/org/jsweet/transpiler/TypeChecker.java
Normal file
@ -0,0 +1,230 @@
|
||||
/* Copyright 2015 CINCHEO SAS
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.jsweet.transpiler;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.jsweet.JSweetConfig;
|
||||
import org.jsweet.transpiler.util.AbstractTreePrinter;
|
||||
import org.jsweet.transpiler.util.Util;
|
||||
|
||||
import com.sun.tools.javac.code.Symbol.MethodSymbol;
|
||||
import com.sun.tools.javac.code.Type;
|
||||
import com.sun.tools.javac.code.Type.ClassType;
|
||||
import com.sun.tools.javac.code.Types;
|
||||
import com.sun.tools.javac.tree.JCTree;
|
||||
import com.sun.tools.javac.tree.JCTree.JCArrayTypeTree;
|
||||
import com.sun.tools.javac.tree.JCTree.JCAssign;
|
||||
import com.sun.tools.javac.tree.JCTree.JCExpression;
|
||||
import com.sun.tools.javac.tree.JCTree.JCFieldAccess;
|
||||
import com.sun.tools.javac.tree.JCTree.JCMethodInvocation;
|
||||
import com.sun.tools.javac.tree.JCTree.JCVariableDecl;
|
||||
import com.sun.tools.javac.util.Name;
|
||||
|
||||
/**
|
||||
* This helper class performs extra type checking for the JSweet transpiler
|
||||
* (additionally to Java default type checking).
|
||||
*
|
||||
* <p>
|
||||
* It checks that JSweet authorized APIs are used, and that auxiliary types
|
||||
* such as unions are valid.
|
||||
*
|
||||
* @author Renaud Pawlak
|
||||
*/
|
||||
public class TypeChecker {
|
||||
|
||||
static final Set<String> AUTHORIZED_ACCESSED_TYPES = new HashSet<String>();
|
||||
static final Set<String> AUTHORIZED_DECLARED_TYPES = new HashSet<String>();
|
||||
/**
|
||||
* Java types that represent numbers (qualified names).
|
||||
*/
|
||||
public static final Set<String> NUMBER_TYPES = new HashSet<String>();
|
||||
/**
|
||||
* Java types that represent numbers (simple names).
|
||||
*/
|
||||
public static final Set<String> NUMBER_TYPE_NAMES = new HashSet<String>();
|
||||
/**
|
||||
* Methods that can be invoked on <code>java.lang.Object</code> from JSweet.
|
||||
*/
|
||||
public static final Set<String> AUTHORIZED_OBJECT_METHODS = new HashSet<String>();
|
||||
/**
|
||||
* Methods that can be invoked on <code>java.lang.String</code> from JSweet.
|
||||
*/
|
||||
public static final Set<String> AUTHORIZED_STRING_METHODS = new HashSet<String>();
|
||||
/**
|
||||
* Methods that cannot be invoked on <code>java.util.function</code> classes from JSweet.
|
||||
*/
|
||||
public static final Set<String> FORBIDDEN_JDK_FUNCTIONAL_METHODS = new HashSet<String>();
|
||||
|
||||
static {
|
||||
// AUTHORIZED_ACCESSED_TYPES.add(String.class.getName());
|
||||
|
||||
AUTHORIZED_DECLARED_TYPES.add(String.class.getName());
|
||||
AUTHORIZED_DECLARED_TYPES.add(Object.class.getName());
|
||||
AUTHORIZED_DECLARED_TYPES.add(Class.class.getName());
|
||||
AUTHORIZED_DECLARED_TYPES.add(Boolean.class.getName());
|
||||
AUTHORIZED_DECLARED_TYPES.add(Void.class.getName());
|
||||
|
||||
NUMBER_TYPES.add(Integer.class.getName());
|
||||
NUMBER_TYPES.add(Double.class.getName());
|
||||
NUMBER_TYPES.add(Number.class.getName());
|
||||
NUMBER_TYPES.add(Float.class.getName());
|
||||
NUMBER_TYPES.add(Byte.class.getName());
|
||||
NUMBER_TYPES.add(Short.class.getName());
|
||||
|
||||
NUMBER_TYPE_NAMES.add(Integer.class.getSimpleName());
|
||||
NUMBER_TYPE_NAMES.add(Double.class.getSimpleName());
|
||||
NUMBER_TYPE_NAMES.add(Number.class.getSimpleName());
|
||||
NUMBER_TYPE_NAMES.add(Float.class.getSimpleName());
|
||||
NUMBER_TYPE_NAMES.add(Byte.class.getSimpleName());
|
||||
NUMBER_TYPE_NAMES.add(Short.class.getSimpleName());
|
||||
|
||||
// TODO: remove runnable?
|
||||
AUTHORIZED_DECLARED_TYPES.add(Runnable.class.getName());
|
||||
|
||||
AUTHORIZED_OBJECT_METHODS.add("toString");
|
||||
AUTHORIZED_STRING_METHODS.add("charAt(int)");
|
||||
AUTHORIZED_STRING_METHODS.add("concat(java.lang.String)");
|
||||
AUTHORIZED_STRING_METHODS.add("indexOf(java.lang.String)");
|
||||
AUTHORIZED_STRING_METHODS.add("lastIndexOf(java.lang.String)");
|
||||
AUTHORIZED_STRING_METHODS.add("lastIndexOf(java.lang.String,int)");
|
||||
AUTHORIZED_STRING_METHODS.add("substring(int)");
|
||||
AUTHORIZED_STRING_METHODS.add("substring(int,int)");
|
||||
AUTHORIZED_STRING_METHODS.add("replace(java.lang.String,java.lang.String)");
|
||||
AUTHORIZED_STRING_METHODS.add("split(java.lang.String)");
|
||||
AUTHORIZED_STRING_METHODS.add("trim()");
|
||||
AUTHORIZED_STRING_METHODS.add("toLowerCase()");
|
||||
AUTHORIZED_STRING_METHODS.add("toUpperCase()");
|
||||
|
||||
FORBIDDEN_JDK_FUNCTIONAL_METHODS.add("and");
|
||||
FORBIDDEN_JDK_FUNCTIONAL_METHODS.add("negate");
|
||||
FORBIDDEN_JDK_FUNCTIONAL_METHODS.add("or");
|
||||
FORBIDDEN_JDK_FUNCTIONAL_METHODS.add("andThen");
|
||||
}
|
||||
|
||||
private AbstractTreePrinter translator;
|
||||
|
||||
/**
|
||||
* Creates a new type checker object.
|
||||
*/
|
||||
public TypeChecker(AbstractTreePrinter translator) {
|
||||
this.translator = translator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that the given invocation conforms to JSweet contraints.
|
||||
*/
|
||||
public boolean checkApply(JCMethodInvocation invocation, MethodSymbol methSym) {
|
||||
if (Util.hasAnnotationType(methSym, JSweetConfig.ANNOTATION_ERASED)) {
|
||||
translator.report(invocation, JSweetProblem.ERASED_METHOD, methSym);
|
||||
}
|
||||
if (!JSweetConfig.isJDKReplacementMode()) {
|
||||
if (methSym.owner.toString().startsWith("java.")) {
|
||||
if (invocation.meth instanceof JCFieldAccess && "super".equals(((JCFieldAccess) invocation.meth).selected.toString())) {
|
||||
translator.report(invocation, JSweetProblem.JDK_METHOD, methSym);
|
||||
return false;
|
||||
}
|
||||
if (AUTHORIZED_OBJECT_METHODS.contains(methSym.name.toString())) {
|
||||
return true;
|
||||
}
|
||||
if (methSym.owner.toString().equals(String.class.getName()) && AUTHORIZED_STRING_METHODS.contains(methSym.toString())) {
|
||||
return true;
|
||||
}
|
||||
translator.report(invocation, JSweetProblem.JDK_METHOD, methSym);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that the given type is JSweet compatible.
|
||||
*/
|
||||
public boolean checkType(JCTree declaringElement, Name declaringElementName, JCExpression typeExpression) {
|
||||
if (!JSweetConfig.isJDKReplacementMode()) {
|
||||
if (typeExpression instanceof JCArrayTypeTree) {
|
||||
return checkType(declaringElement, declaringElementName, ((JCArrayTypeTree) typeExpression).elemtype);
|
||||
}
|
||||
String type = typeExpression.type.tsym.toString();
|
||||
if (type.startsWith("java.")) {
|
||||
if (!(AUTHORIZED_DECLARED_TYPES.contains(type) || NUMBER_TYPES.contains(type) || type.startsWith("java.util.function"))) {
|
||||
translator.report(declaringElement, declaringElementName, JSweetProblem.JDK_TYPE, type);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that the given field access conforms to JSweet contraints.
|
||||
*/
|
||||
public boolean checkSelect(JCFieldAccess select) {
|
||||
if (!JSweetConfig.isJDKReplacementMode()) {
|
||||
if (select.selected.type instanceof ClassType) {
|
||||
String type = select.selected.type.tsym.toString();
|
||||
if (type.startsWith("java.")) {
|
||||
if (!(AUTHORIZED_ACCESSED_TYPES.contains(type) || type.startsWith("java.util.function"))) {
|
||||
translator.report(select, JSweetProblem.JDK_TYPE, type);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean checkUnionTypeAssignment(Types types, JCTree parent, Type assigned, JCMethodInvocation union) {
|
||||
if (union.args.head.type.tsym.getQualifiedName().toString().startsWith(JSweetConfig.UNION_CLASS_NAME)) {
|
||||
if (!Util.containsAssignableType(types, union.args.head.type.getTypeArguments(), assigned)) {
|
||||
translator.report(parent, JSweetProblem.UNION_TYPE_MISMATCH);
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (!Util.containsAssignableType(types, assigned.getTypeArguments(), union.args.head.type)) {
|
||||
translator.report(parent, JSweetProblem.UNION_TYPE_MISMATCH);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that the given union type assignment conforms to JSweet contraints.
|
||||
*/
|
||||
public boolean checkUnionTypeAssignment(Types types, JCTree parent, JCMethodInvocation union) {
|
||||
if (parent instanceof JCVariableDecl) {
|
||||
JCVariableDecl decl = (JCVariableDecl) parent;
|
||||
if (decl.init == union) {
|
||||
return checkUnionTypeAssignment(types, parent, decl.type, union);
|
||||
}
|
||||
} else if (parent instanceof JCAssign) {
|
||||
JCAssign assign = (JCAssign) parent;
|
||||
if (assign.rhs == union) {
|
||||
return checkUnionTypeAssignment(types, parent, assign.lhs.type, union);
|
||||
}
|
||||
} else if (parent instanceof JCMethodInvocation) {
|
||||
JCMethodInvocation invocation = (JCMethodInvocation) parent;
|
||||
for (JCTree arg : invocation.args) {
|
||||
if (arg == union) {
|
||||
return checkUnionTypeAssignment(types, parent, arg.type, union);
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
340
src/org/jsweet/transpiler/candies/CandiesMerger.java
Normal file
340
src/org/jsweet/transpiler/candies/CandiesMerger.java
Normal file
@ -0,0 +1,340 @@
|
||||
/* Copyright 2015 CINCHEO SAS
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.jsweet.transpiler.candies;
|
||||
|
||||
import static java.util.Arrays.asList;
|
||||
import static org.jsweet.JSweetConfig.ANNOTATION_MIXIN;
|
||||
import static org.jsweet.JSweetConfig.ANNOTATION_ROOT;
|
||||
import static org.jsweet.JSweetConfig.STRING_TYPES_INTERFACE_NAME;
|
||||
import static org.jsweet.JSweetConfig.UTIL_PACKAGE;
|
||||
|
||||
import java.io.File;
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.AnnotatedElement;
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import org.apache.log4j.Logger;
|
||||
import org.jsweet.JSweetConfig;
|
||||
|
||||
import javassist.ClassPool;
|
||||
import javassist.CtClass;
|
||||
import javassist.CtConstructor;
|
||||
import javassist.CtField;
|
||||
import javassist.CtMethod;
|
||||
import javassist.CtNewConstructor;
|
||||
import javassist.CtNewMethod;
|
||||
import javassist.NotFoundException;
|
||||
import javassist.bytecode.DuplicateMemberException;
|
||||
|
||||
/**
|
||||
* This class implements a JSweet bytecode-level candy merger. When mixin
|
||||
* classes are applied to target classes, the merger generates new classes that
|
||||
* contain all the target and mixin classes members.
|
||||
*
|
||||
* @author Renaud Pawlak
|
||||
*/
|
||||
public class CandiesMerger {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(CandiesMerger.class);
|
||||
|
||||
private static final List<String> BUILTIN_MIXINS = asList(UTIL_PACKAGE + "." + STRING_TYPES_INTERFACE_NAME);
|
||||
|
||||
private File targetDir;
|
||||
private List<String> candyClassPathEntries;
|
||||
private URLClassLoader candyClassLoader;
|
||||
private ClassPool classPool;
|
||||
|
||||
private Map<String, ClassPool> candyClassPools;
|
||||
|
||||
/**
|
||||
* Overrides the default behavior so that it never uses any other class
|
||||
* loaders to look up classes.
|
||||
*/
|
||||
private static class CandyClassLoader extends URLClassLoader {
|
||||
|
||||
public CandyClassLoader(URL[] urls) {
|
||||
super(urls);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
|
||||
Class<?> c = findLoadedClass(name);
|
||||
if (c == null) {
|
||||
try {
|
||||
c = findClass(name);
|
||||
resolveClass(c);
|
||||
} catch (ClassNotFoundException e) {
|
||||
return super.loadClass(name, resolve);
|
||||
}
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new candies merger that will merge the candies found in the
|
||||
* classpath and output the result to the given target directory.
|
||||
*/
|
||||
public CandiesMerger(File targetDir, List<String> candyClassPathEntries) {
|
||||
logger.debug("new candies merger");
|
||||
logger.debug("targetDir: " + targetDir.getAbsolutePath());
|
||||
logger.debug("candies classpath entries: " + candyClassPathEntries);
|
||||
this.targetDir = targetDir;
|
||||
this.candyClassPathEntries = candyClassPathEntries;
|
||||
this.candyClassLoader = new CandyClassLoader(candyClassPathEntries.stream().map((entry) -> {
|
||||
try {
|
||||
return new File(entry).toURI().toURL();
|
||||
} catch (Exception e) {
|
||||
logger.error("wrong class path entry " + entry, e);
|
||||
return null;
|
||||
}
|
||||
}).toArray(size -> new URL[size]));
|
||||
logger.debug("classloader URLs: " + Arrays.asList(candyClassLoader.getURLs()));
|
||||
|
||||
this.candyClassPools = new HashMap<>();
|
||||
this.classPool = new ClassPool(ClassPool.getDefault());
|
||||
for (String entry : candyClassPathEntries) {
|
||||
try {
|
||||
this.classPool.appendClassPath(entry);
|
||||
|
||||
ClassPool candyClassPool = new ClassPool();
|
||||
candyClassPool.appendClassPath(entry);
|
||||
candyClassPools.put(entry, candyClassPool);
|
||||
} catch (Exception e) {
|
||||
logger.error("wrong class path entry " + entry, e);
|
||||
}
|
||||
}
|
||||
|
||||
logger.debug("candies class pools: " + candyClassPools);
|
||||
}
|
||||
|
||||
private Annotation getAnnotation(AnnotatedElement element, String annotationName) {
|
||||
try {
|
||||
@SuppressWarnings("unchecked")
|
||||
Class<? extends Annotation> annotationClass = (Class<? extends Annotation>) candyClassLoader.loadClass(annotationName);
|
||||
return element.getAnnotation(annotationClass);
|
||||
} catch (Exception e) {
|
||||
logger.error("error retreiving annotation " + annotationName, e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private <T> T getProperty(Annotation annotation, String property) {
|
||||
try {
|
||||
return (T) annotation.annotationType().getDeclaredMethod(property).invoke(annotation);
|
||||
} catch (Exception e) {
|
||||
logger.error("error retreiving annotation property " + property, e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public Map<Class<?>, List<Class<?>>> merge() {
|
||||
File defDir = new File(targetDir, JSweetConfig.LIBS_PACKAGE);
|
||||
List<Class<?>> libPackages = new ArrayList<Class<?>>();
|
||||
findLibPackages(defDir, libPackages);
|
||||
logger.debug("lib packages: " + libPackages);
|
||||
Map<Class<?>, List<Class<?>>> toBeMerged = new HashMap<>();
|
||||
for (Class<?> libPackage : libPackages) {
|
||||
// adds mixins from @Root annotation infos
|
||||
Class<?>[] libMixins = getProperty(getAnnotation(libPackage, ANNOTATION_ROOT), "mixins");
|
||||
for (Class<?> mixin : libMixins) {
|
||||
Class<?> target = getProperty(getAnnotation(mixin, ANNOTATION_MIXIN), "target");
|
||||
List<Class<?>> mixins = toBeMerged.get(target);
|
||||
if (mixins == null) {
|
||||
mixins = new ArrayList<>();
|
||||
toBeMerged.put(target, mixins);
|
||||
}
|
||||
mixins.add(mixin);
|
||||
}
|
||||
}
|
||||
logger.debug("mixins to be merged: " + toBeMerged);
|
||||
for (Entry<Class<?>, List<Class<?>>> e : toBeMerged.entrySet()) {
|
||||
mergeMixins(e.getValue(), e.getKey());
|
||||
}
|
||||
|
||||
for (String builtinMixinClassName : BUILTIN_MIXINS) {
|
||||
try {
|
||||
List<CtClass> mixinClasses = new LinkedList<>();
|
||||
for (ClassPool classPool : candyClassPools.values()) {
|
||||
try {
|
||||
CtClass mixinCtClass = classPool.get(builtinMixinClassName);
|
||||
if (mixinCtClass != null) {
|
||||
mixinClasses.add(mixinCtClass);
|
||||
}
|
||||
} catch (NotFoundException e) {
|
||||
// mixin class not found, not a problem
|
||||
}
|
||||
}
|
||||
logger.info(mixinClasses.size() + " classes found for " + builtinMixinClassName);
|
||||
if (mixinClasses.size() > 1) {
|
||||
CtClass ctTarget = mixinClasses.get(0);
|
||||
for (CtClass ctMixin : mixinClasses.subList(1, mixinClasses.size())) {
|
||||
mergeMixin(ctTarget, ctMixin);
|
||||
}
|
||||
ctTarget.writeFile(targetDir.getPath());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.warn("error merging mixin " + builtinMixinClassName, e);
|
||||
}
|
||||
}
|
||||
|
||||
return toBeMerged;
|
||||
}
|
||||
|
||||
private void findLibPackages(File dir, List<Class<?>> libPackages) {
|
||||
logger.debug("findLibPackages: " + dir + " - " + dir.getAbsolutePath());
|
||||
String packageName = dir.getPath().substring(targetDir.getPath().length() + 1).replace(File.separatorChar, '.');
|
||||
Class<?> packageInfo = null;
|
||||
try {
|
||||
// trick to force the package to load (we are only interested in the
|
||||
// packages with the Root annotation, so the package-info class must
|
||||
// exist
|
||||
packageInfo = candyClassLoader.loadClass(packageName + ".package-info");
|
||||
} catch (ClassNotFoundException e) {
|
||||
// swallow
|
||||
}
|
||||
if (packageInfo != null) {
|
||||
if (getAnnotation(packageInfo, ANNOTATION_ROOT) != null) {
|
||||
libPackages.add(packageInfo);
|
||||
}
|
||||
}
|
||||
File[] children = dir.listFiles();
|
||||
if (children != null) {
|
||||
for (File f : children) {
|
||||
if (f.isDirectory()) {
|
||||
findLibPackages(f, libPackages);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void mergeMixins(List<Class<?>> mixins, Class<?> target) {
|
||||
try {
|
||||
logger.debug("merging: " + mixins + " -> " + target);
|
||||
CtClass ctTarget = classPool.get(target.getName());
|
||||
for (Class<?> mixin : mixins) {
|
||||
CtClass ctMixin = classPool.get(mixin.getName());
|
||||
mergeMixin(ctTarget, ctMixin);
|
||||
}
|
||||
ctTarget.writeFile(targetDir.getPath());
|
||||
} catch (Exception e) {
|
||||
logger.warn("error merging mixin", e);
|
||||
}
|
||||
}
|
||||
|
||||
private void mergeMixin(CtClass ctTarget, CtClass ctMixin) throws NotFoundException {
|
||||
mergeMixin(ctTarget, ctMixin, true);
|
||||
}
|
||||
|
||||
private boolean hasField(CtClass clazz, String name) {
|
||||
try {
|
||||
return clazz.getDeclaredField(name) != null;
|
||||
} catch (Exception e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean hasMethod(CtClass clazz, String name) {
|
||||
try {
|
||||
return clazz.getDeclaredMethod(name) != null;
|
||||
} catch (Exception e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private void mergeMixin(CtClass ctTarget, CtClass ctMixin, boolean verbose) throws NotFoundException {
|
||||
if (verbose)
|
||||
logger.debug("merging: " + ctMixin.getName() + " -> " + ctTarget.getName());
|
||||
int memberCount = 0;
|
||||
int ignoredDuplicates = 0;
|
||||
for (CtClass ctInnerClass : ctMixin.getDeclaredClasses()) {
|
||||
try {
|
||||
if (!ctTarget.getSimpleName().equals(JSweetConfig.STRING_TYPES_INTERFACE_NAME)
|
||||
|| !hasField(ctTarget, ctInnerClass.getSimpleName().substring(ctInnerClass.getSimpleName().indexOf('$') + 1))) {
|
||||
// TODO : ouch, not the good way
|
||||
CtClass ctTargetInner = ctTarget.makeNestedClass(ctInnerClass.getSimpleName(), true);
|
||||
mergeMixin(ctTargetInner, ctInnerClass, false);
|
||||
memberCount++;
|
||||
logger.debug("merged inner class " + ctInnerClass.getSimpleName());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.warn("error merging inner class: " + ctInnerClass, e);
|
||||
}
|
||||
}
|
||||
for (CtMethod ctMethod : ctMixin.getDeclaredMethods()) {
|
||||
try {
|
||||
if (!hasMethod(ctTarget, ctMethod.getName())) {
|
||||
ctTarget.addMethod(CtNewMethod.copy(ctMethod, ctTarget, null));
|
||||
memberCount++;
|
||||
} else {
|
||||
// ignore duplicate members
|
||||
ignoredDuplicates++;
|
||||
}
|
||||
} catch (DuplicateMemberException e) {
|
||||
// ignore duplicate members
|
||||
ignoredDuplicates++;
|
||||
} catch (Exception e) {
|
||||
logger.warn("error merging method", e);
|
||||
}
|
||||
}
|
||||
for (CtField ctField : ctMixin.getDeclaredFields()) {
|
||||
try {
|
||||
if (!hasField(ctTarget, ctField.getName())) {
|
||||
ctTarget.addField(new CtField(ctField, ctTarget));
|
||||
memberCount++;
|
||||
} else {
|
||||
// ignore duplicate members
|
||||
ignoredDuplicates++;
|
||||
}
|
||||
} catch (DuplicateMemberException e) {
|
||||
// ignore duplicate members
|
||||
ignoredDuplicates++;
|
||||
} catch (Exception e) {
|
||||
logger.warn("error merging field", e);
|
||||
}
|
||||
}
|
||||
for (CtConstructor ctConstructor : ctMixin.getDeclaredConstructors()) {
|
||||
try {
|
||||
ctTarget.addConstructor(CtNewConstructor.copy(ctConstructor, ctTarget, null));
|
||||
memberCount++;
|
||||
} catch (DuplicateMemberException e) {
|
||||
// ignore duplicate members
|
||||
ignoredDuplicates++;
|
||||
} catch (Exception e) {
|
||||
logger.warn("error merging constructor", e);
|
||||
}
|
||||
}
|
||||
if (verbose)
|
||||
logger.debug("merged " + memberCount + " member(s) and ignored " + ignoredDuplicates + " duplicates");
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the classpath entries that correspond to JSweet candies.
|
||||
*/
|
||||
public List<String> getCandyClassPathEntries() {
|
||||
return candyClassPathEntries;
|
||||
}
|
||||
|
||||
}
|
||||
329
src/org/jsweet/transpiler/candies/CandiesProcessor.java
Normal file
329
src/org/jsweet/transpiler/candies/CandiesProcessor.java
Normal file
@ -0,0 +1,329 @@
|
||||
/* Copyright 2015 CINCHEO SAS
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.jsweet.transpiler.candies;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.jar.JarEntry;
|
||||
import java.util.jar.JarFile;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.apache.commons.io.FilenameUtils;
|
||||
import org.apache.commons.lang3.ArrayUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.log4j.Logger;
|
||||
import org.jsweet.JSweetConfig;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
|
||||
/**
|
||||
* The candies processor extracts and processes what is required from the candy
|
||||
* jars in order to ensure safe transpilation.
|
||||
*
|
||||
* <ul>
|
||||
* <li>The embedded TypeScript definition files (*.d.ts)</li>
|
||||
* <li>Cross-candies mixins, which are merged by {@link CandiesMerger}</li>
|
||||
* </ul>
|
||||
*/
|
||||
public class CandiesProcessor {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(CandiesProcessor.class);
|
||||
private final static Gson gson = new GsonBuilder().setPrettyPrinting().create();
|
||||
|
||||
private String classPath;
|
||||
|
||||
/**
|
||||
* The name of the directory that will contain the candies.
|
||||
*/
|
||||
public static final String CANDIES_DIR_NAME = "candies";
|
||||
/**
|
||||
* This directory will contain the sources.
|
||||
*/
|
||||
public static final String CANDIES_SOURCES_DIR_NAME = CANDIES_DIR_NAME + File.separator + "src";
|
||||
/**
|
||||
* This directory will contain processed (merged) bytecode.
|
||||
*/
|
||||
public static final String CANDIES_PROCESSED_DIR_NAME = CANDIES_DIR_NAME + File.separator + "processed";
|
||||
/**
|
||||
* The name of the file that stores processed candies info.
|
||||
*/
|
||||
public static final String CANDIES_STORE_FILE_NAME = CANDIES_DIR_NAME + File.separator + CandiesStore.class.getSimpleName() + ".json";
|
||||
/**
|
||||
* The name of the directory that contains the TypeScript source files.
|
||||
*/
|
||||
public static final String CANDIES_TSDEFS_DIR_NAME = CANDIES_DIR_NAME + File.separator + JSweetConfig.TS_LIBS_DIR_NAME;
|
||||
|
||||
private File candiesSourceDir;
|
||||
private File candiesProcessedDir;
|
||||
private File candiesStoreFile;
|
||||
private File candiesTsdefsDir;
|
||||
private List<String> candyClassPathEntries;
|
||||
private boolean forceCandiesCompatibility;
|
||||
|
||||
/**
|
||||
* Create a candies processor.
|
||||
*
|
||||
* @param workingDir
|
||||
* the directory where the processor will save all cache and
|
||||
* temporary data for processing
|
||||
* @param classPath
|
||||
* the classpath where the processor will seek for JSweet candies
|
||||
*/
|
||||
public CandiesProcessor(File workingDir, String classPath) {
|
||||
this.classPath = (classPath == null ? System.getProperty("java.class.path") : classPath);
|
||||
String[] cp = this.classPath.split(File.pathSeparator);
|
||||
int[] indices = new int[0];
|
||||
for (int i = 0; i < cp.length; i++) {
|
||||
if (cp[i].replace('\\', '/').endsWith("org/jsweet/lib/core-bin/latest/core-bin-latest.jar")) {
|
||||
logger.warn("candies processor ignores classpath entry: " + cp[i]);
|
||||
indices = ArrayUtils.add(indices, i);
|
||||
}
|
||||
if (cp[i].replace('\\', '/').matches(".*org/jsweet/lib/.*-testbundle/.*/.*-testbundle-.*\\.jar")) {
|
||||
logger.warn("candies processor ignores classpath entry: " + cp[i]);
|
||||
indices = ArrayUtils.add(indices, i);
|
||||
}
|
||||
}
|
||||
cp = ArrayUtils.removeAll(cp, indices);
|
||||
this.classPath = StringUtils.join(cp, File.pathSeparator);
|
||||
logger.info("candies processor classpath: " + this.classPath);
|
||||
candiesSourceDir = new File(workingDir, CANDIES_SOURCES_DIR_NAME);
|
||||
candiesProcessedDir = new File(workingDir, CANDIES_PROCESSED_DIR_NAME);
|
||||
candiesStoreFile = new File(workingDir, CANDIES_STORE_FILE_NAME);
|
||||
candiesTsdefsDir = new File(workingDir, CANDIES_TSDEFS_DIR_NAME);
|
||||
logger.debug("processed classes dir: " + getCandiesProcessedDir() + " - " + getCandiesProcessedDir().getAbsolutePath());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the directory that contains the processed (merged) candies.
|
||||
*/
|
||||
public File getCandiesProcessedDir() {
|
||||
return candiesProcessedDir;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the directory that contains the orginal TypeScript source code of
|
||||
* the processed (merged) candies.
|
||||
*/
|
||||
public File getCandiesTsdefsDir() {
|
||||
return candiesTsdefsDir;
|
||||
}
|
||||
|
||||
/**
|
||||
* Do the processing for the candies jars found in the classpath.
|
||||
*/
|
||||
public void processCandies() throws IOException {
|
||||
CandiesStore candiesStore = getCandiesStore();
|
||||
|
||||
List<CandyDescriptor> newCandiesDescriptors = getCandiesDescriptorsFromClassPath(new HashMap<CandyDescriptor, File>());
|
||||
CandiesStore newStore = new CandiesStore(newCandiesDescriptors);
|
||||
if (newStore.equals(candiesStore)) {
|
||||
logger.info("candies are up to date");
|
||||
return;
|
||||
}
|
||||
|
||||
this.candiesStore = newStore;
|
||||
logger.info("candies changed, processing candies: " + this.candiesStore);
|
||||
|
||||
try {
|
||||
extractCandies();
|
||||
|
||||
mergeCandies();
|
||||
|
||||
writeCandiesStore();
|
||||
|
||||
} catch (Throwable t) {
|
||||
logger.error("cannot generate candies bundle", t);
|
||||
// exit with fatal if no jar ?
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Ignore candies version check and tries to transpile anyway
|
||||
*
|
||||
* @param force
|
||||
* whether check should be disabled or not<
|
||||
*/
|
||||
public void setForceCandiesCompatibility(boolean force) {
|
||||
this.forceCandiesCompatibility = force;
|
||||
}
|
||||
|
||||
private void mergeCandies() {
|
||||
logger.info("merging candies");
|
||||
CandiesMerger merger = new CandiesMerger(candiesProcessedDir, candyClassPathEntries);
|
||||
Map<Class<?>, List<Class<?>>> mergedMixins = merger.merge();
|
||||
extractSourcesForClasses(mergedMixins.keySet());
|
||||
}
|
||||
|
||||
private List<CandyDescriptor> getCandiesDescriptorsFromClassPath(Map<CandyDescriptor, File> jarFilesCollector) throws IOException {
|
||||
List<CandyDescriptor> candiesDescriptors = new LinkedList<>();
|
||||
for (String classPathEntry : classPath.split("[" + System.getProperty("path.separator") + "]")) {
|
||||
if (classPathEntry.endsWith(".jar")) {
|
||||
File jarFile = new File(classPathEntry);
|
||||
try (JarFile jarFileHandle = new JarFile(jarFile)) {
|
||||
JarEntry candySpecificEntry = jarFileHandle.getJarEntry("META-INF/maven/" + JSweetConfig.MAVEN_CANDIES_GROUP);
|
||||
boolean isCandy = candySpecificEntry != null;
|
||||
if (isCandy) {
|
||||
CandyDescriptor descriptor = CandyDescriptor.fromCandyJar(jarFileHandle);
|
||||
|
||||
checkCandyVersion(descriptor);
|
||||
candiesDescriptors.add(descriptor);
|
||||
jarFilesCollector.put(descriptor, jarFile);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return candiesDescriptors;
|
||||
}
|
||||
|
||||
private void checkCandyVersion(CandyDescriptor candy) {
|
||||
// TODO : check major version change
|
||||
// we assume candies will always remain compatible with jsweet minor
|
||||
// versions changes
|
||||
}
|
||||
|
||||
private void extractCandies() throws IOException {
|
||||
File extractedSourcesDir = candiesSourceDir;
|
||||
File extractedTsDefsDir = candiesTsdefsDir;
|
||||
File extractedClassesDir = candiesProcessedDir;
|
||||
FileUtils.deleteQuietly(extractedSourcesDir);
|
||||
FileUtils.deleteQuietly(extractedTsDefsDir);
|
||||
FileUtils.deleteQuietly(extractedClassesDir);
|
||||
extractedSourcesDir.mkdirs();
|
||||
extractedTsDefsDir.mkdirs();
|
||||
extractedClassesDir.mkdirs();
|
||||
candyClassPathEntries = new ArrayList<>();
|
||||
|
||||
for (String classPathEntry : classPath.split("[" + System.getProperty("path.separator") + "]")) {
|
||||
if (classPathEntry.endsWith(".jar")) {
|
||||
File jarFileDescriptor = new File(classPathEntry);
|
||||
logger.info("scanning sources in jar: " + classPathEntry);
|
||||
try (JarFile jarFile = new JarFile(jarFileDescriptor)) {
|
||||
JarEntry candySpecificEntry = jarFile.getJarEntry("META-INF/maven/" + JSweetConfig.MAVEN_CANDIES_GROUP);
|
||||
boolean isCandy = candySpecificEntry != null;
|
||||
if (isCandy) {
|
||||
candyClassPathEntries.add(classPathEntry);
|
||||
String groupName = FilenameUtils.getBaseName(jarFile.getName());
|
||||
String versionName = jarFileDescriptor.getParentFile().getName();
|
||||
|
||||
// remove version
|
||||
groupName = groupName.substring(0, groupName.lastIndexOf("-" + versionName));
|
||||
int i = groupName.indexOf("--");
|
||||
if (i > 0) {
|
||||
groupName = groupName.substring(0, i);
|
||||
}
|
||||
|
||||
boolean isCore = "core".equals(groupName);
|
||||
extractCandy(jarFile, new File(extractedSourcesDir, FilenameUtils.getBaseName(jarFile.getName())), extractedTsDefsDir,
|
||||
isCore ? tsDefName -> false : null, extractedClassesDir);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void extractCandy(JarFile jarFile, File javaOutputDirectory, File tsDefOutputDirectory, Predicate<String> isTsDefToBeExtracted,
|
||||
File classesOutputDirectory) {
|
||||
logger.info("extract candy: " + jarFile.getName() + " javaOutputDirectory=" + javaOutputDirectory + " tsDefOutputDirectory=" + tsDefOutputDirectory
|
||||
+ " classesOutputDirectory=" + classesOutputDirectory);
|
||||
|
||||
jarFile.stream()
|
||||
.filter(entry -> entry.getName().endsWith(".d.ts") && entry.getName().startsWith("src/") || entry.getName().endsWith("package-info.class")) //
|
||||
.forEach(entry -> {
|
||||
File out;
|
||||
if (entry.getName().endsWith(".java")) {
|
||||
out = new File(javaOutputDirectory + "/" + entry.getName().substring(4));
|
||||
} else if (entry.getName().endsWith(".d.ts")) {
|
||||
if (isTsDefToBeExtracted != null && !isTsDefToBeExtracted.test(entry.getName())) {
|
||||
return;
|
||||
}
|
||||
|
||||
out = new File(tsDefOutputDirectory + "/" + entry.getName());
|
||||
} else {
|
||||
out = new File(classesOutputDirectory + "/" + entry.getName());
|
||||
}
|
||||
out.getParentFile().mkdirs();
|
||||
try {
|
||||
FileUtils.copyInputStreamToFile(jarFile.getInputStream(entry), out);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void extractSourcesForClasses(Collection<Class<?>> classes) {
|
||||
logger.info("extract sources for: " + classes);
|
||||
|
||||
List<String> files = classes.stream().map(c -> "src/" + c.getName().replace('.', '/') + ".java").collect(Collectors.toList());
|
||||
for (String candyClassPathEntry : candyClassPathEntries) {
|
||||
try (JarFile jarFile = new JarFile(candyClassPathEntry)) {
|
||||
jarFile.stream().filter(entry -> files.contains(entry.getName())) //
|
||||
.forEach(entry -> {
|
||||
File out = new File(candiesSourceDir + "/" + entry.getName().substring(4));
|
||||
out.getParentFile().mkdirs();
|
||||
try {
|
||||
logger.debug("extracting source: " + out);
|
||||
FileUtils.copyInputStreamToFile(jarFile.getInputStream(entry), out);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
});
|
||||
} catch (Exception e) {
|
||||
logger.error("error extracting sources for " + candyClassPathEntry, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private CandiesStore candiesStore;
|
||||
|
||||
private CandiesStore getCandiesStore() {
|
||||
if (candiesStore == null) {
|
||||
if (candiesStoreFile.exists()) {
|
||||
try {
|
||||
candiesStore = gson.fromJson(FileUtils.readFileToString(candiesStoreFile), CandiesStore.class);
|
||||
} catch (Exception e) {
|
||||
logger.error("cannot read candies index", e);
|
||||
}
|
||||
}
|
||||
|
||||
if (candiesStore == null) {
|
||||
candiesStore = new CandiesStore();
|
||||
}
|
||||
}
|
||||
|
||||
return candiesStore;
|
||||
}
|
||||
|
||||
private void writeCandiesStore() {
|
||||
if (candiesStore != null) {
|
||||
try {
|
||||
FileUtils.write(candiesStoreFile, gson.toJson(candiesStore));
|
||||
} catch (Exception e) {
|
||||
logger.error("cannot read candies index", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
53
src/org/jsweet/transpiler/candies/CandiesStore.java
Normal file
53
src/org/jsweet/transpiler/candies/CandiesStore.java
Normal file
@ -0,0 +1,53 @@
|
||||
/* Copyright 2015 CINCHEO SAS
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.jsweet.transpiler.candies;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* A class that is serialized to store information on the processed candies.
|
||||
*/
|
||||
class CandiesStore {
|
||||
List<CandyDescriptor> candies = new LinkedList<>();
|
||||
|
||||
public CandiesStore() {
|
||||
this(new LinkedList<CandyDescriptor>());
|
||||
}
|
||||
|
||||
public CandiesStore(List<CandyDescriptor> candiesDescriptors) {
|
||||
this.candies = candiesDescriptors;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return candies.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (!(obj instanceof CandiesStore)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
CandiesStore other = (CandiesStore) obj;
|
||||
return candies.size() == other.candies.size() && candies.containsAll(other.candies);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getClass().getSimpleName() + "=" + candies;
|
||||
}
|
||||
}
|
||||
103
src/org/jsweet/transpiler/candies/CandyDescriptor.java
Normal file
103
src/org/jsweet/transpiler/candies/CandyDescriptor.java
Normal file
@ -0,0 +1,103 @@
|
||||
/* Copyright 2015 CINCHEO SAS
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.jsweet.transpiler.candies;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.jar.JarEntry;
|
||||
import java.util.jar.JarFile;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
|
||||
/**
|
||||
* A candy descriptor for the candies store.
|
||||
*
|
||||
* @see CandiesStore
|
||||
*/
|
||||
class CandyDescriptor {
|
||||
String name;
|
||||
String version;
|
||||
long lastUpdateTimestamp;
|
||||
String modelVersion;
|
||||
|
||||
public CandyDescriptor(String name, String version, long lastUpdateTimestamp, String modelVersion) {
|
||||
this.name = name;
|
||||
this.version = version;
|
||||
this.lastUpdateTimestamp = lastUpdateTimestamp;
|
||||
this.modelVersion = modelVersion;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return name.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (!(obj instanceof CandyDescriptor)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
CandyDescriptor other = (CandyDescriptor) obj;
|
||||
return name.equals(other.name) //
|
||||
&& version.equals(other.version) //
|
||||
&& lastUpdateTimestamp == other.lastUpdateTimestamp;
|
||||
}
|
||||
|
||||
private final static Pattern MODEL_VERSION_PATTERN = Pattern.compile("[\\<]groupId[\\>]org[.]jsweet[.]candies[.](.*)[\\<]/groupId[\\>]");
|
||||
private final static Pattern ARTIFACT_ID_PATTERN = Pattern.compile("[\\<]artifactId[\\>](.*)[\\<]/artifactId[\\>]");
|
||||
private final static Pattern VERSION_PATTERN = Pattern.compile("[\\<]version[\\>](.*)[\\<]/version[\\>]");
|
||||
|
||||
public static CandyDescriptor fromCandyJar(JarFile jarFile) throws IOException {
|
||||
JarEntry pomEntry = jarFile.stream() //
|
||||
.filter(e -> e.getName().endsWith("pom.xml")) //
|
||||
.findFirst().get();
|
||||
|
||||
String pomContent = IOUtils.toString(jarFile.getInputStream(pomEntry));
|
||||
|
||||
// take only general part
|
||||
String pomGeneralPart = pomContent.substring(0, pomContent.indexOf("<dependencies>"));
|
||||
|
||||
// extract candy model version from <groupId></groupId>
|
||||
Matcher matcher = MODEL_VERSION_PATTERN.matcher(pomGeneralPart);
|
||||
String modelVersion = "unknown";
|
||||
if (matcher.find()) {
|
||||
modelVersion = matcher.group(1);
|
||||
}
|
||||
|
||||
// extract name from <artifactId></artifactId>
|
||||
matcher = ARTIFACT_ID_PATTERN.matcher(pomGeneralPart);
|
||||
String name = "unknown";
|
||||
if (matcher.find()) {
|
||||
name = matcher.group(1);
|
||||
}
|
||||
|
||||
matcher = VERSION_PATTERN.matcher(pomGeneralPart);
|
||||
String version = "unknown";
|
||||
if (matcher.find()) {
|
||||
version = matcher.group(1);
|
||||
}
|
||||
|
||||
long lastUpdateTimestamp = jarFile.getEntry("META-INF/MANIFEST.MF").getTime();
|
||||
|
||||
return new CandyDescriptor(name, version, lastUpdateTimestamp, modelVersion);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "(" + name + "-" + version + ",t=" + lastUpdateTimestamp + ")";
|
||||
}
|
||||
}
|
||||
24
src/org/jsweet/transpiler/candies/package-info.java
Normal file
24
src/org/jsweet/transpiler/candies/package-info.java
Normal file
@ -0,0 +1,24 @@
|
||||
/* Copyright 2015 CINCHEO SAS
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
/**
|
||||
* This package contains the candies processing implementation.
|
||||
*
|
||||
* <p>
|
||||
* The candies processor extract the candies found in the classpath. It then
|
||||
* merges the bytecode of classes that are declared as mixins. Candies jar files
|
||||
* contains the sources (for Javadoc), bytecode (for Java compiling), and the
|
||||
* original TypeScript source code for compiling with <code>tsc</code>.
|
||||
*/
|
||||
package org.jsweet.transpiler.candies;
|
||||
30
src/org/jsweet/transpiler/package-info.java
Normal file
30
src/org/jsweet/transpiler/package-info.java
Normal file
@ -0,0 +1,30 @@
|
||||
/* Copyright 2015 CINCHEO SAS
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
/**
|
||||
* This package contains the JSweet Java to JavaScript transpiler
|
||||
* implementation.
|
||||
*
|
||||
* <p>
|
||||
* The entry point is {@link org.jsweet.transpiler.JSweetTranspiler} with the
|
||||
* {@link org.jsweet.transpiler.JSweetTranspiler#transpile(TranspilationHandler, SourceFile...)}
|
||||
* function.
|
||||
*
|
||||
* <p>
|
||||
* The JSweet transpiler transpiles to TypeScript and uses <code>tsc</code> to
|
||||
* transpile to JavaScript.
|
||||
*
|
||||
* @author Renaud Pawlak
|
||||
*/
|
||||
package org.jsweet.transpiler;
|
||||
576
src/org/jsweet/transpiler/typescript/Java2TypeScriptAdapter.java
Normal file
576
src/org/jsweet/transpiler/typescript/Java2TypeScriptAdapter.java
Normal file
@ -0,0 +1,576 @@
|
||||
/* Copyright 2015 CINCHEO SAS
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.jsweet.transpiler.typescript;
|
||||
|
||||
import static org.jsweet.JSweetConfig.ANNOTATION_ERASED;
|
||||
import static org.jsweet.JSweetConfig.ANNOTATION_FUNCTIONAL_INTERFACE;
|
||||
import static org.jsweet.JSweetConfig.ANNOTATION_OBJECT_TYPE;
|
||||
import static org.jsweet.JSweetConfig.ANNOTATION_ROOT;
|
||||
import static org.jsweet.JSweetConfig.ANNOTATION_STRING_TYPE;
|
||||
import static org.jsweet.JSweetConfig.GLOBALS_CLASS_NAME;
|
||||
import static org.jsweet.JSweetConfig.GLOBALS_PACKAGE_NAME;
|
||||
import static org.jsweet.JSweetConfig.INDEXED_DELETE_FUCTION_NAME;
|
||||
import static org.jsweet.JSweetConfig.INDEXED_GET_FUCTION_NAME;
|
||||
import static org.jsweet.JSweetConfig.INDEXED_SET_FUCTION_NAME;
|
||||
import static org.jsweet.JSweetConfig.LANG_PACKAGE;
|
||||
import static org.jsweet.JSweetConfig.TUPLE_CLASSES_PACKAGE;
|
||||
import static org.jsweet.JSweetConfig.UNION_CLASS_NAME;
|
||||
import static org.jsweet.JSweetConfig.UTIL_CLASSNAME;
|
||||
import static org.jsweet.JSweetConfig.UTIL_PACKAGE;
|
||||
import static org.jsweet.JSweetConfig.isJDKPath;
|
||||
import static org.jsweet.JSweetConfig.isJSweetPath;
|
||||
import static org.jsweet.transpiler.util.Util.getFirstAnnotationValue;
|
||||
import static org.jsweet.transpiler.util.Util.getRootRelativeJavaName;
|
||||
import static org.jsweet.transpiler.util.Util.getRootRelativeName;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
|
||||
import javax.lang.model.element.AnnotationMirror;
|
||||
import javax.lang.model.element.ElementKind;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.jsweet.JSweetConfig;
|
||||
import org.jsweet.transpiler.JSweetProblem;
|
||||
import org.jsweet.transpiler.JSweetTranspiler;
|
||||
import org.jsweet.transpiler.TypeChecker;
|
||||
import org.jsweet.transpiler.util.AbstractPrinterAdapter;
|
||||
import org.jsweet.transpiler.util.AbstractTreePrinter;
|
||||
import org.jsweet.transpiler.util.Util;
|
||||
|
||||
import com.sun.source.tree.Tree.Kind;
|
||||
import com.sun.tools.javac.code.Symbol;
|
||||
import com.sun.tools.javac.code.Symbol.MethodSymbol;
|
||||
import com.sun.tools.javac.code.Symbol.PackageSymbol;
|
||||
import com.sun.tools.javac.code.Symbol.TypeSymbol;
|
||||
import com.sun.tools.javac.tree.JCTree;
|
||||
import com.sun.tools.javac.tree.JCTree.JCClassDecl;
|
||||
import com.sun.tools.javac.tree.JCTree.JCExpression;
|
||||
import com.sun.tools.javac.tree.JCTree.JCFieldAccess;
|
||||
import com.sun.tools.javac.tree.JCTree.JCIdent;
|
||||
import com.sun.tools.javac.tree.JCTree.JCImport;
|
||||
import com.sun.tools.javac.tree.JCTree.JCMethodInvocation;
|
||||
import com.sun.tools.javac.tree.JCTree.JCNewClass;
|
||||
import com.sun.tools.javac.tree.JCTree.JCTypeApply;
|
||||
import com.sun.tools.javac.tree.JCTree.JCTypeCast;
|
||||
import com.sun.tools.javac.util.Log;
|
||||
|
||||
/**
|
||||
* This is an adapter for the TypeScript code generator. It overrides the
|
||||
* default adapter's behavior.
|
||||
*
|
||||
* @author Renaud Pawlak
|
||||
*/
|
||||
public class Java2TypeScriptAdapter extends AbstractPrinterAdapter {
|
||||
|
||||
private Map<String, String> typesMapping = new HashMap<String, String>();
|
||||
|
||||
public Java2TypeScriptAdapter() {
|
||||
typesMapping.put(String.class.getName(), "string");
|
||||
typesMapping.put(String.class.getName(), "string");
|
||||
typesMapping.put(Runnable.class.getName(), "() => void");
|
||||
typesMapping.put(Number.class.getName(), "number");
|
||||
typesMapping.put(Integer.class.getName(), "number");
|
||||
typesMapping.put(Short.class.getName(), "number");
|
||||
typesMapping.put(Float.class.getName(), "number");
|
||||
typesMapping.put(Byte.class.getName(), "number");
|
||||
typesMapping.put(Double.class.getName(), "number");
|
||||
typesMapping.put(Boolean.class.getName(), "boolean");
|
||||
typesMapping.put(Void.class.getName(), "void");
|
||||
typesMapping.put("double", "number");
|
||||
typesMapping.put("int", "number");
|
||||
typesMapping.put("float", "number");
|
||||
typesMapping.put("byte", "number");
|
||||
typesMapping.put("short", "number");
|
||||
typesMapping.put("Class", "Function");
|
||||
typesMapping.put(LANG_PACKAGE + ".Object", "Object");
|
||||
typesMapping.put(LANG_PACKAGE + ".Boolean", "boolean");
|
||||
typesMapping.put(LANG_PACKAGE + ".String", "string");
|
||||
typesMapping.put(LANG_PACKAGE + ".Number", "number");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String needsImport(JCImport importDecl, String qualifiedName) {
|
||||
if (isJSweetPath(qualifiedName) || isJDKPath(qualifiedName) || qualifiedName.endsWith(GLOBALS_PACKAGE_NAME + "." + GLOBALS_CLASS_NAME)) {
|
||||
return null;
|
||||
}
|
||||
if (importDecl.qualid.type != null && Util.hasAnnotationType(importDecl.qualid.type.tsym, ANNOTATION_ERASED, ANNOTATION_OBJECT_TYPE)) {
|
||||
return null;
|
||||
}
|
||||
if (importDecl.isStatic()) {
|
||||
if (importDecl.getQualifiedIdentifier() instanceof JCFieldAccess) {
|
||||
JCFieldAccess fa = (JCFieldAccess) importDecl.getQualifiedIdentifier();
|
||||
String name = getRootRelativeJavaName(fa.selected.type.tsym);
|
||||
String methodName = fa.name.toString();
|
||||
|
||||
// function is a top-level global function (no need to import)
|
||||
if (GLOBALS_CLASS_NAME.equals(name)) {
|
||||
return null;
|
||||
}
|
||||
if (!getPrinter().getContext().useModules && name.endsWith(GLOBALS_PACKAGE_NAME + "." + GLOBALS_CLASS_NAME)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (JSweetConfig.TS_STRICT_MODE_KEYWORDS.contains(methodName.toLowerCase())) {
|
||||
// if method name is a reserved ts keyword, we have to fully
|
||||
// qualify calls to it (hence discarding any import)
|
||||
return null;
|
||||
}
|
||||
boolean globals = name.endsWith("." + JSweetConfig.GLOBALS_CLASS_NAME);
|
||||
if (globals) {
|
||||
name = name.substring(0, name.length() - JSweetConfig.GLOBALS_CLASS_NAME.length() - 1);
|
||||
}
|
||||
// function belong to the current package (no need to
|
||||
// import)
|
||||
if (getPrinter().getContext().useModules) {
|
||||
if (getPrinter().getCompilationUnit().packge.getQualifiedName().toString().equals(name)) {
|
||||
return null;
|
||||
}
|
||||
} else {
|
||||
if (getPrinter().getCompilationUnit().packge.getQualifiedName().toString().startsWith(name)) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
// MethodSymbol staticMethSymbol =
|
||||
// Util.findMethodDeclarationInType(getPrinter().getContext().types,
|
||||
// fa.selected.type.tsym, "" + fa.name, null);
|
||||
// String methodName = Util.getActualName(staticMethSymbol);
|
||||
return StringUtils.isBlank(name) ? null : name + "." + getIdentifier(methodName);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return super.needsImport(importDecl, qualifiedName);
|
||||
}
|
||||
|
||||
private boolean isWithinGlobals(String targetClassName) {
|
||||
if (targetClassName == null || targetClassName.endsWith("." + GLOBALS_CLASS_NAME)) {
|
||||
JCClassDecl c = getPrinter().getParent(JCClassDecl.class);
|
||||
return c != null && c.sym.getQualifiedName().toString().endsWith("." + GLOBALS_CLASS_NAME);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean substituteMethodInvocation(JCMethodInvocation invocation) {
|
||||
if ("System.out.println".equals(invocation.meth.toString())) {
|
||||
getPrinter().print("console.info(").print(invocation.args.head).print(")");
|
||||
return true;
|
||||
}
|
||||
if ("System.err.println".equals(invocation.meth.toString())) {
|
||||
getPrinter().print("console.error(").print(invocation.args.head).print(")");
|
||||
return true;
|
||||
}
|
||||
if ("super".equals(invocation.meth.toString())) {
|
||||
// we omit call to super if class extends nothing or if parent is an
|
||||
// interface
|
||||
if (getPrinter().getParent(JCClassDecl.class).extending == null //
|
||||
|| Util.isInterface(getPrinter().getParent(JCClassDecl.class).extending.type.tsym)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
JCFieldAccess fieldAccess = null;
|
||||
TypeSymbol targetType = null;
|
||||
String targetClassName = null;
|
||||
String targetMethodName = null;
|
||||
if (invocation.getMethodSelect() instanceof JCFieldAccess) {
|
||||
fieldAccess = (JCFieldAccess) invocation.getMethodSelect();
|
||||
targetType = fieldAccess.selected.type.tsym;
|
||||
targetClassName = targetType.getQualifiedName().toString();
|
||||
targetMethodName = fieldAccess.name.toString();
|
||||
} else {
|
||||
targetMethodName = invocation.getMethodSelect().toString();
|
||||
}
|
||||
|
||||
// System.out.println(invocation+" ===> "+fieldAccess+" :
|
||||
// targetClassName="+targetClassName+"
|
||||
// targetMethodName="+targetMethodName+
|
||||
// " ownerClassName="+ownerClassName);
|
||||
|
||||
if (targetType != null && targetType.getKind() == ElementKind.ENUM) {
|
||||
// TODO: enum type simple name will not be valid when uses as fully
|
||||
// qualified name (not imported)
|
||||
String relTarget = getPrinter().getContext().useModules ? targetType.getSimpleName().toString() : getRootRelativeName(targetType);
|
||||
if (targetMethodName.equals("name")) {
|
||||
getPrinter().print(relTarget).print("[").print(fieldAccess.selected).print("]");
|
||||
return true;
|
||||
}
|
||||
if (targetMethodName.equals("ordinal")) {
|
||||
getPrinter().print(relTarget).print("[").print(relTarget).print("[").print(fieldAccess.selected).print("]").print("]");
|
||||
return true;
|
||||
}
|
||||
if (targetMethodName.equals("valueOf") && invocation.getArguments().size() == 1) {
|
||||
getPrinter().print(fieldAccess.selected).print("[").print(invocation.getArguments().head).print("]");
|
||||
return true;
|
||||
}
|
||||
if (targetMethodName.equals("values")) {
|
||||
getPrinter().print("function() { var result: number[] = []; for(var val in ").print(relTarget)
|
||||
.print(") { if(!isNaN(val)) { result.push(parseInt(val,10)); } } return result; }()");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (matchesMethod(targetClassName, targetMethodName, UTIL_CLASSNAME, "$export")) {
|
||||
if (invocation.args.head.getKind() != Kind.STRING_LITERAL) {
|
||||
getPrinter().report(invocation.args.head, JSweetProblem.STRING_LITERAL_EXPECTED);
|
||||
}
|
||||
String varName = "_exportedVar_" + StringUtils.strip(invocation.args.head.toString(), "\"");
|
||||
getPrinter().footer.append("declare var " + varName + ";\n");
|
||||
if (invocation.args.size() == 1) {
|
||||
getPrinter().print(varName);
|
||||
} else {
|
||||
getPrinter().print(varName + " = ").print(invocation.args.tail.head).print("; ");
|
||||
getPrinter().print("console.log('" + JSweetTranspiler.EXPORTED_VAR_BEGIN + StringUtils.strip(invocation.args.head.toString(), "\"") + "='+")
|
||||
.print(varName).print("+'" + JSweetTranspiler.EXPORTED_VAR_END + "');");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if (matchesMethod(targetClassName, targetMethodName, UTIL_CLASSNAME, "array")) {
|
||||
getPrinter().print(invocation.args.head);
|
||||
return true;
|
||||
}
|
||||
if (matchesMethod(targetClassName, targetMethodName, UTIL_CLASSNAME, "function")) {
|
||||
getPrinter().printArgList(invocation.args);
|
||||
return true;
|
||||
}
|
||||
if (matchesMethod(targetClassName, targetMethodName, UTIL_CLASSNAME, "string")) {
|
||||
getPrinter().printArgList(invocation.args);
|
||||
return true;
|
||||
}
|
||||
if (matchesMethod(targetClassName, targetMethodName, UTIL_CLASSNAME, "bool")) {
|
||||
getPrinter().printArgList(invocation.args);
|
||||
return true;
|
||||
}
|
||||
if (matchesMethod(targetClassName, targetMethodName, UTIL_CLASSNAME, "number")) {
|
||||
getPrinter().printArgList(invocation.args);
|
||||
return true;
|
||||
}
|
||||
if (matchesMethod(targetClassName, targetMethodName, UTIL_CLASSNAME, "integer")) {
|
||||
getPrinter().printArgList(invocation.args);
|
||||
return true;
|
||||
}
|
||||
if (matchesMethod(targetClassName, targetMethodName, UTIL_CLASSNAME, "object")) {
|
||||
getPrinter().printArgList(invocation.args);
|
||||
return true;
|
||||
}
|
||||
if (matchesMethod(targetClassName, targetMethodName, UTIL_CLASSNAME, "union")) {
|
||||
getPrinter().typeChecker.checkUnionTypeAssignment(getPrinter().getContext().types, getPrinter().getParent(), invocation);
|
||||
getPrinter().print("<any>");
|
||||
getPrinter().printArgList(invocation.args);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (matchesMethod(targetClassName, targetMethodName, null, INDEXED_GET_FUCTION_NAME)) {
|
||||
if (isWithinGlobals(targetClassName)) {
|
||||
report(invocation, JSweetProblem.GLOBAL_INDEXER_GET);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (fieldAccess != null && !fieldAccess.toString().equals(UTIL_CLASSNAME + "." + INDEXED_GET_FUCTION_NAME)) {
|
||||
getPrinter().print(fieldAccess.selected).print("[").print(invocation.args.head).print("]");
|
||||
} else {
|
||||
getPrinter().print("this[").print(invocation.args.head).print("]");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if (matchesMethod(targetClassName, targetMethodName, null, INDEXED_SET_FUCTION_NAME)) {
|
||||
|
||||
if (isWithinGlobals(targetClassName)) {
|
||||
report(invocation, JSweetProblem.GLOBAL_INDEXER_SET);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (fieldAccess != null && !fieldAccess.toString().equals(UTIL_CLASSNAME + "." + INDEXED_SET_FUCTION_NAME)) {
|
||||
// check the type through the getter
|
||||
for (Symbol e : fieldAccess.selected.type.tsym.getEnclosedElements()) {
|
||||
if (e instanceof MethodSymbol && INDEXED_GET_FUCTION_NAME.equals(e.getSimpleName().toString())) {
|
||||
MethodSymbol getMethod = (MethodSymbol) e;
|
||||
TypeSymbol getterType = getMethod.getReturnType().tsym;
|
||||
TypeSymbol argType = invocation.args.tail.head.type.tsym;
|
||||
if (!Util.isAssignable(getPrinter().getContext().types, getterType, argType)) {
|
||||
report(invocation.args.tail.head, JSweetProblem.INDEXED_SET_TYPE_MISMATCH, getterType);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
getPrinter().print(fieldAccess.selected).print("[").print(invocation.args.head).print("] = ").print(invocation.args.tail.head);
|
||||
} else {
|
||||
getPrinter().print("this[").print(invocation.args.head).print("] = <any>").print(invocation.args.tail.head);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if (matchesMethod(targetClassName, targetMethodName, null, INDEXED_DELETE_FUCTION_NAME)) {
|
||||
if (isWithinGlobals(targetClassName)) {
|
||||
report(invocation, JSweetProblem.GLOBAL_DELETE);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (fieldAccess != null && !fieldAccess.toString().equals(UTIL_CLASSNAME + "." + INDEXED_DELETE_FUCTION_NAME)) {
|
||||
getPrinter().print("delete ").print(fieldAccess.selected).print("[").print(invocation.args.head).print("]");
|
||||
} else {
|
||||
getPrinter().print("delete this[").print(invocation.args.head).print("]");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
if (targetClassName != null && targetClassName.endsWith(GLOBALS_CLASS_NAME)) {
|
||||
if (getPrinter().getContext().useModules) {
|
||||
if (JSweetConfig.GLOBALS_PACKAGE_NAME.equals(targetType.getEnclosingElement().getSimpleName().toString())) {
|
||||
getPrinter().print(JSweetConfig.GLOBALS_PACKAGE_NAME).print(".");
|
||||
}
|
||||
}
|
||||
getPrinter().printIdentifier(targetMethodName).print("(").printArgList(invocation.args).print(")");
|
||||
return true;
|
||||
}
|
||||
if (fieldAccess == null && matchesMethod(targetClassName, targetMethodName, null, "$super")) {
|
||||
getPrinter().print("super(").printArgList(invocation.args).print(")");
|
||||
return true;
|
||||
}
|
||||
if (fieldAccess != null && targetClassName != null
|
||||
&& (targetClassName.startsWith(UTIL_PACKAGE + ".function.") || targetClassName.startsWith(Function.class.getPackage().getName()))) {
|
||||
if (targetClassName.startsWith(Function.class.getPackage().getName()) && TypeChecker.FORBIDDEN_JDK_FUNCTIONAL_METHODS.contains(targetMethodName)) {
|
||||
getPrinter().report(invocation, JSweetProblem.JDK_METHOD, targetMethodName);
|
||||
}
|
||||
getPrinter().print(fieldAccess.getExpression()).print("(").printArgList(invocation.args).print(")");
|
||||
return true;
|
||||
}
|
||||
if (fieldAccess != null && targetClassName != null && targetClassName.equals(java.lang.Runnable.class.getName())) {
|
||||
getPrinter().print(fieldAccess.getExpression()).print("(").printArgList(invocation.args).print(")");
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!JSweetConfig.isJDKReplacementMode()) {
|
||||
Log log = Log.instance(getPrinter().getContext());
|
||||
if (String.class.getName().equals(targetClassName)) {
|
||||
log.rawError(invocation.pos, "Invalid use of native Java class. Use string(a_java_string) to convert to JSweet String first.");
|
||||
}
|
||||
}
|
||||
|
||||
return super.substituteMethodInvocation(invocation);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean substituteFieldAccess(JCFieldAccess fieldAccess) {
|
||||
String name = fieldAccess.name.toString();
|
||||
// translate tuple accesses
|
||||
if (name.startsWith("$") && name.length() > 1 && Character.isDigit(name.charAt(1))) {
|
||||
try {
|
||||
int i = Integer.parseInt(name.substring(1));
|
||||
getPrinter().print(fieldAccess.selected);
|
||||
getPrinter().print("[" + i + "]");
|
||||
return true;
|
||||
} catch (NumberFormatException e) {
|
||||
// swallow
|
||||
}
|
||||
}
|
||||
|
||||
AnnotationMirror annotation;
|
||||
if ((annotation = Util.getAnnotation(fieldAccess.sym, ANNOTATION_STRING_TYPE)) != null) {
|
||||
getPrinter().print("\"");
|
||||
getPrinter().printIdentifier(getFirstAnnotationValue(annotation, fieldAccess.name).toString());
|
||||
getPrinter().print("\"");
|
||||
return true;
|
||||
}
|
||||
String selected = fieldAccess.selected.toString();
|
||||
if (selected.equals(GLOBALS_CLASS_NAME)) {
|
||||
getPrinter().printIdentifier(fieldAccess.name.toString());
|
||||
return true;
|
||||
}
|
||||
|
||||
if (fieldAccess.selected.type.tsym instanceof PackageSymbol) {
|
||||
if (Util.hasAnnotationType(fieldAccess.selected.type.tsym, ANNOTATION_ROOT)) {
|
||||
if (fieldAccess.type != null && fieldAccess.type.tsym != null) {
|
||||
getPrinter().printIdentifier(Util.getActualName(fieldAccess.type.tsym));
|
||||
} else {
|
||||
getPrinter().printIdentifier(name);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return super.substituteFieldAccess(fieldAccess);
|
||||
}
|
||||
|
||||
private AbstractTreePrinter printArguments(List<JCExpression> arguments) {
|
||||
int i = 1;
|
||||
for (JCExpression argument : arguments) {
|
||||
getPrinter().print("p" + (i++) + ": ");
|
||||
substituteAndPrintType(argument, false).print(",");
|
||||
}
|
||||
if (arguments.size() > 0) {
|
||||
getPrinter().removeLastChar();
|
||||
}
|
||||
return getPrinter();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean substituteNewClass(JCNewClass newClass) {
|
||||
String fullType = newClass.type.tsym.toString();
|
||||
if (fullType.startsWith(JSweetConfig.TUPLE_CLASSES_PACKAGE + ".")) {
|
||||
getPrinter().print("[").printArgList(newClass.args).print("]");
|
||||
return true;
|
||||
}
|
||||
if (typesMapping.containsKey(fullType)) {
|
||||
getPrinter().print("<").print(typesMapping.get(fullType)).print(">");
|
||||
}
|
||||
return super.substituteNewClass(newClass);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AbstractTreePrinter substituteAndPrintType(JCTree typeTree, boolean arrayComponent) {
|
||||
// String fullName=typeTree.type.getModelType().toString();
|
||||
// if(fullName.startsWith(Console.class.getPackage().getName())) {
|
||||
// return "any";
|
||||
// }
|
||||
if (Util.hasAnnotationType(typeTree.type.tsym, ANNOTATION_ERASED)) {
|
||||
return getPrinter().print("any");
|
||||
}
|
||||
if (Util.hasAnnotationType(typeTree.type.tsym, ANNOTATION_OBJECT_TYPE)) {
|
||||
// TODO: in case of object types, we should replace with the org
|
||||
// object type...
|
||||
return getPrinter().print("any");
|
||||
}
|
||||
String typeFullName = typeTree.type.getModelType().toString();
|
||||
if (Runnable.class.getName().equals(typeFullName)) {
|
||||
if (arrayComponent) {
|
||||
getPrinter().print("(");
|
||||
}
|
||||
getPrinter().print("() => void");
|
||||
if (arrayComponent) {
|
||||
getPrinter().print(")");
|
||||
}
|
||||
return getPrinter();
|
||||
}
|
||||
if (typeTree instanceof JCTypeApply) {
|
||||
JCTypeApply typeApply = ((JCTypeApply) typeTree);
|
||||
String typeName = typeApply.clazz.toString();
|
||||
if (typeFullName.startsWith(TUPLE_CLASSES_PACKAGE + ".")) {
|
||||
getPrinter().print("[");
|
||||
for (JCExpression argument : typeApply.arguments) {
|
||||
substituteAndPrintType(argument, arrayComponent).print(",");
|
||||
}
|
||||
if (typeApply.arguments.length() > 0) {
|
||||
getPrinter().removeLastChar();
|
||||
}
|
||||
getPrinter().print("]");
|
||||
return getPrinter();
|
||||
}
|
||||
if (typeFullName.startsWith(UNION_CLASS_NAME)) {
|
||||
getPrinter().print("(");
|
||||
for (JCExpression argument : typeApply.arguments) {
|
||||
substituteAndPrintType(argument, arrayComponent).print("|");
|
||||
}
|
||||
if (typeApply.arguments.length() > 0) {
|
||||
getPrinter().removeLastChar();
|
||||
}
|
||||
getPrinter().print(")");
|
||||
return getPrinter();
|
||||
}
|
||||
if (typeFullName.startsWith(UTIL_PACKAGE + ".") || typeFullName.startsWith("java.util.function.")) {
|
||||
if (typeName.endsWith("Consumer")) {
|
||||
if (arrayComponent) {
|
||||
getPrinter().print("(");
|
||||
}
|
||||
getPrinter().print("(");
|
||||
printArguments(typeApply.arguments);
|
||||
getPrinter().print(") => void");
|
||||
if (arrayComponent) {
|
||||
getPrinter().print(")");
|
||||
}
|
||||
return getPrinter();
|
||||
} else if (typeName.endsWith("Function")) {
|
||||
if (arrayComponent) {
|
||||
getPrinter().print("(");
|
||||
}
|
||||
getPrinter().print("(");
|
||||
printArguments(typeApply.arguments.subList(0, typeApply.arguments.length() - 1));
|
||||
getPrinter().print(") => ");
|
||||
substituteAndPrintType(typeApply.arguments.get(typeApply.arguments.length() - 1), arrayComponent);
|
||||
if (arrayComponent) {
|
||||
getPrinter().print(")");
|
||||
}
|
||||
return getPrinter();
|
||||
} else if (typeName.endsWith("Supplier")) {
|
||||
if (arrayComponent) {
|
||||
getPrinter().print("(");
|
||||
}
|
||||
getPrinter().print("(");
|
||||
getPrinter().print(") => ");
|
||||
substituteAndPrintType(typeApply.arguments.get(0), arrayComponent);
|
||||
if (arrayComponent) {
|
||||
getPrinter().print(")");
|
||||
}
|
||||
return getPrinter();
|
||||
} else if (typeName.endsWith("Predicate")) {
|
||||
if (arrayComponent) {
|
||||
getPrinter().print("(");
|
||||
}
|
||||
getPrinter().print("(");
|
||||
printArguments(typeApply.arguments);
|
||||
getPrinter().print(") => boolean");
|
||||
if (arrayComponent) {
|
||||
getPrinter().print(")");
|
||||
}
|
||||
return getPrinter();
|
||||
}
|
||||
}
|
||||
if (typeFullName.startsWith(Class.class.getName() + "<")) {
|
||||
getPrinter().print("typeof ");
|
||||
return substituteAndPrintType(typeApply.arguments.head, arrayComponent);
|
||||
}
|
||||
} else {
|
||||
if (typesMapping.containsKey(typeFullName)) {
|
||||
return getPrinter().print(typesMapping.get(typeFullName));
|
||||
}
|
||||
}
|
||||
return super.substituteAndPrintType(typeTree, arrayComponent);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean substituteIdentifier(JCIdent identifier) {
|
||||
AnnotationMirror annotation;
|
||||
if ((annotation = Util.getAnnotation(identifier.sym, ANNOTATION_STRING_TYPE)) != null) {
|
||||
getPrinter().print("\"");
|
||||
getPrinter().printIdentifier(getFirstAnnotationValue(annotation, identifier).toString());
|
||||
getPrinter().print("\"");
|
||||
return true;
|
||||
}
|
||||
if (identifier.sym.owner.getQualifiedName().toString().endsWith("." + GLOBALS_CLASS_NAME)) {
|
||||
getPrinter().printIdentifier(identifier.toString());
|
||||
return true;
|
||||
}
|
||||
if (TypeChecker.NUMBER_TYPE_NAMES.contains(identifier.toString()) && TypeChecker.NUMBER_TYPES.contains(identifier.type.toString())) {
|
||||
getPrinter().print("number");
|
||||
return true;
|
||||
}
|
||||
return super.substituteIdentifier(identifier);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean needsTypeCast(JCTypeCast cast) {
|
||||
if (Util.hasAnnotationType(cast.clazz.type.tsym, ANNOTATION_ERASED, ANNOTATION_OBJECT_TYPE, ANNOTATION_FUNCTIONAL_INTERFACE)) {
|
||||
return false;
|
||||
} else {
|
||||
return super.needsTypeCast(cast);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getIdentifier(String identifier) {
|
||||
return JSweetConfig.toJsIdentifier(identifier);
|
||||
}
|
||||
}
|
||||
1646
src/org/jsweet/transpiler/typescript/Java2TypeScriptTranslator.java
Normal file
1646
src/org/jsweet/transpiler/typescript/Java2TypeScriptTranslator.java
Normal file
File diff suppressed because it is too large
Load Diff
23
src/org/jsweet/transpiler/typescript/package-info.java
Normal file
23
src/org/jsweet/transpiler/typescript/package-info.java
Normal file
@ -0,0 +1,23 @@
|
||||
/* Copyright 2015 CINCHEO SAS
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
/**
|
||||
* This package contains the actual translation to TypeScript.
|
||||
*
|
||||
* <p>
|
||||
* The translation is implemented as a Java code tree scanner.
|
||||
*
|
||||
* @author Renaud Pawlak
|
||||
*/
|
||||
package org.jsweet.transpiler.typescript;
|
||||
268
src/org/jsweet/transpiler/util/AbstractPrinterAdapter.java
Normal file
268
src/org/jsweet/transpiler/util/AbstractPrinterAdapter.java
Normal file
@ -0,0 +1,268 @@
|
||||
/* Copyright 2015 CINCHEO SAS
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.jsweet.transpiler.util;
|
||||
|
||||
import static org.jsweet.transpiler.util.Util.getRootRelativeName;
|
||||
|
||||
import org.jsweet.transpiler.JSweetProblem;
|
||||
|
||||
import com.sun.tools.javac.code.Type.MethodType;
|
||||
import com.sun.tools.javac.tree.JCTree;
|
||||
import com.sun.tools.javac.tree.JCTree.JCArrayAccess;
|
||||
import com.sun.tools.javac.tree.JCTree.JCArrayTypeTree;
|
||||
import com.sun.tools.javac.tree.JCTree.JCAssign;
|
||||
import com.sun.tools.javac.tree.JCTree.JCExpression;
|
||||
import com.sun.tools.javac.tree.JCTree.JCFieldAccess;
|
||||
import com.sun.tools.javac.tree.JCTree.JCIdent;
|
||||
import com.sun.tools.javac.tree.JCTree.JCImport;
|
||||
import com.sun.tools.javac.tree.JCTree.JCLiteral;
|
||||
import com.sun.tools.javac.tree.JCTree.JCMethodInvocation;
|
||||
import com.sun.tools.javac.tree.JCTree.JCNewClass;
|
||||
import com.sun.tools.javac.tree.JCTree.JCTypeApply;
|
||||
import com.sun.tools.javac.tree.JCTree.JCTypeCast;
|
||||
import com.sun.tools.javac.tree.JCTree.JCVariableDecl;
|
||||
import com.sun.tools.javac.util.Name;
|
||||
|
||||
/**
|
||||
* A printer adapter, which can be overridden to change the default printer
|
||||
* behavior.
|
||||
*
|
||||
* @author Renaud Pawlak
|
||||
*/
|
||||
public abstract class AbstractPrinterAdapter {
|
||||
|
||||
private AbstractTreePrinter printer;
|
||||
|
||||
/**
|
||||
* Reports a problem during the printing phase.
|
||||
*
|
||||
* @param tree
|
||||
* the code where the problem occurred
|
||||
* @param problem
|
||||
* the reported problem
|
||||
* @param params
|
||||
* the parameters if any
|
||||
*/
|
||||
protected void report(JCTree tree, JSweetProblem problem, Object... params) {
|
||||
printer.report(tree, problem, params);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reports a problem during the printing phase.
|
||||
*
|
||||
* @param tree
|
||||
* the code where the problem occurred
|
||||
* @param name
|
||||
* the name of the element if any
|
||||
* @param problem
|
||||
* the reported problem
|
||||
* @param params
|
||||
* the parameters if any
|
||||
*/
|
||||
protected void report(JCTree tree, Name name, JSweetProblem problem, Object... params) {
|
||||
printer.report(tree, name, problem, params);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the print value of the given literal tree.
|
||||
*/
|
||||
public String getLiteralStringValue(JCTree tree) {
|
||||
return (String) ((JCLiteral) tree).value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Substitutes the value of an array access expression.
|
||||
*
|
||||
* @param arrayAccess
|
||||
* the array access being printed
|
||||
* @return true if substituted
|
||||
*/
|
||||
public boolean substituteArrayAccess(JCArrayAccess arrayAccess) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Substitutes the value of an identifier.
|
||||
*
|
||||
* @param identifier
|
||||
* the identifier being printed
|
||||
* @return true if substituted
|
||||
*/
|
||||
public boolean substituteIdentifier(JCIdent identifier) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Substitutes the value of a <code>new</code> expression.
|
||||
*
|
||||
* @param newClass
|
||||
* the new being printed
|
||||
* @return true if substituted
|
||||
*/
|
||||
public boolean substituteNewClass(JCNewClass newClass) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Substitutes the value of a <em>field access</em> expression.
|
||||
*
|
||||
* @param fieldAccess
|
||||
* the field access being printed
|
||||
* @return true if substituted
|
||||
*/
|
||||
public boolean substituteFieldAccess(JCFieldAccess fieldAccess) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the candidate method matches the target method.
|
||||
*/
|
||||
public boolean matchesMethod(String targetClassName, String targetMethodName, String candidateClassName, String candidateMethodName) {
|
||||
if (targetClassName != null) {
|
||||
return (candidateClassName == null || targetClassName.equals(candidateClassName))
|
||||
&& (candidateMethodName == null || targetMethodName.equals(candidateMethodName));
|
||||
} else {
|
||||
return targetMethodName.equals(candidateMethodName);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean matchesWithResultType(JCMethodInvocation invocation, Class<?> resultClass, String methodName) {
|
||||
String[] select = invocation.getMethodSelect().toString().split("\\.");
|
||||
if (methodName.equals(select[select.length - 1]) && resultClass.getName().equals(((MethodType) invocation.getMethodSelect().type).restype.toString())) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean matchesField(JCFieldAccess fieldAccess, Class<?> targetClass, String fieldName) {
|
||||
return (fieldName.equals(fieldAccess.name.toString()) && targetClass.getName().equals(fieldAccess.selected.type.getModelType().toString()));
|
||||
}
|
||||
|
||||
public JCFieldAccess matchesField(JCAssign assignment, Class<?> targetClass, String fieldName) {
|
||||
if (assignment.lhs instanceof JCFieldAccess) {
|
||||
JCFieldAccess fa = (JCFieldAccess) assignment.lhs;
|
||||
if (matchesField(fa, targetClass, fieldName)) {
|
||||
return fa;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the import qualified id if the given import requires an import
|
||||
* statement to be printed.
|
||||
*
|
||||
* @param importDecl
|
||||
* the given import declaration
|
||||
* @param qualifiedName
|
||||
* the qualified import id
|
||||
* @return the possibly adapted qualified id or null if the import should be
|
||||
* ignored by the printer
|
||||
*/
|
||||
public String needsImport(JCImport importDecl, String qualifiedName) {
|
||||
if (importDecl.isStatic()) {
|
||||
return null;
|
||||
} else {
|
||||
return getRootRelativeName(importDecl.getQualifiedIdentifier().type.tsym);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tells if this cast is required to be printed or not.
|
||||
*/
|
||||
public boolean needsTypeCast(JCTypeCast cast) {
|
||||
return true;
|
||||
}
|
||||
|
||||
public AbstractTreePrinter substituteAndPrintType(JCTree typeTree) {
|
||||
return substituteAndPrintType(typeTree, false);
|
||||
}
|
||||
|
||||
public AbstractTreePrinter substituteAndPrintType(JCTree typeTree, boolean arrayComponent) {
|
||||
if (typeTree instanceof JCTypeApply) {
|
||||
JCTypeApply typeApply = ((JCTypeApply) typeTree);
|
||||
substituteAndPrintType(typeApply.clazz, arrayComponent);
|
||||
if (!typeApply.arguments.isEmpty()) {
|
||||
getPrinter().print("<");
|
||||
for (JCExpression argument : typeApply.arguments) {
|
||||
substituteAndPrintType(argument, arrayComponent).print(",");
|
||||
}
|
||||
if (typeApply.arguments.length() > 0) {
|
||||
getPrinter().removeLastChar();
|
||||
}
|
||||
getPrinter().print(">");
|
||||
}
|
||||
return getPrinter();
|
||||
} else {
|
||||
if (typeTree instanceof JCArrayTypeTree) {
|
||||
return substituteAndPrintType(((JCArrayTypeTree) typeTree).elemtype, true).print("[]");
|
||||
}
|
||||
|
||||
return getPrinter().print(typeTree);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tells if the printer needs to print the given variable declaration.
|
||||
*/
|
||||
public boolean needsVariableDecl(JCVariableDecl variableDecl, VariableKind kind) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Substitutes the value of a <em>method invocation</em> expression.
|
||||
*
|
||||
* @param invocation
|
||||
* the invocation being printed
|
||||
* @return true if substituted
|
||||
*/
|
||||
public boolean substituteMethodInvocation(JCMethodInvocation invocation) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Substitutes the value of a <em>field assignment</em> expression.
|
||||
*
|
||||
* @param assign
|
||||
* the field assignment being printed
|
||||
* @return true if substituted
|
||||
*/
|
||||
public boolean substituteAssignment(JCAssign assign) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the printer attached to this adapter.
|
||||
*/
|
||||
public AbstractTreePrinter getPrinter() {
|
||||
return printer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the printer attached to this adapter.
|
||||
*/
|
||||
public void setPrinter(AbstractTreePrinter printer) {
|
||||
this.printer = printer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the adapted identifier string.
|
||||
*/
|
||||
public String getIdentifier(String identifier) {
|
||||
return identifier;
|
||||
}
|
||||
|
||||
}
|
||||
418
src/org/jsweet/transpiler/util/AbstractTreePrinter.java
Normal file
418
src/org/jsweet/transpiler/util/AbstractTreePrinter.java
Normal file
@ -0,0 +1,418 @@
|
||||
/* Copyright 2015 CINCHEO SAS
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.jsweet.transpiler.util;
|
||||
|
||||
import static org.apache.commons.lang3.StringUtils.isBlank;
|
||||
import static org.apache.commons.lang3.StringUtils.join;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Stack;
|
||||
|
||||
import org.jsweet.transpiler.JSweetContext;
|
||||
import org.jsweet.transpiler.TranspilationHandler;
|
||||
import org.jsweet.transpiler.TypeChecker;
|
||||
|
||||
import com.sun.tools.javac.tree.JCTree;
|
||||
import com.sun.tools.javac.tree.JCTree.JCCompilationUnit;
|
||||
|
||||
/**
|
||||
* A tree printer is a kind of tree scanner specialized in pretty printing the
|
||||
* scanned AST of a compilation unit (source file).
|
||||
*
|
||||
* @author Renaud Pawlak
|
||||
*/
|
||||
public abstract class AbstractTreePrinter extends AbstractTreeScanner {
|
||||
|
||||
/**
|
||||
* Represents a position in the source file.
|
||||
*
|
||||
* @author Renaud Pawlak
|
||||
*/
|
||||
public static class Position {
|
||||
/**
|
||||
* The character position.
|
||||
*/
|
||||
public int position;
|
||||
/**
|
||||
* The position's line.
|
||||
*/
|
||||
public int line;
|
||||
/**
|
||||
* The position's column.
|
||||
*/
|
||||
public int column;
|
||||
|
||||
/**
|
||||
* Creates a new position.
|
||||
*/
|
||||
public Position(int position, int line, int column) {
|
||||
super();
|
||||
this.position = position;
|
||||
this.line = line;
|
||||
this.column = column;
|
||||
}
|
||||
}
|
||||
|
||||
private Stack<Position> positionStack = new Stack<>();
|
||||
|
||||
/**
|
||||
* A footer to be printed at the end of the output.
|
||||
*/
|
||||
public StringBuilder footer = new StringBuilder();
|
||||
|
||||
/**
|
||||
* The position stack of the scanner.
|
||||
*/
|
||||
public Stack<Position> getPositionStack() {
|
||||
return positionStack;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method must be overridden to define the printer output files
|
||||
* extension.
|
||||
*/
|
||||
public abstract String getTargetFilesExtension();
|
||||
|
||||
private static final String INDENT = " ";
|
||||
|
||||
private StringBuilder out = new StringBuilder();
|
||||
|
||||
private int indent = 0;
|
||||
|
||||
private AbstractPrinterAdapter adapter;
|
||||
|
||||
public TypeChecker typeChecker;
|
||||
|
||||
private int currentLine = 1;
|
||||
|
||||
private int currentColumn = 0;
|
||||
|
||||
private boolean preserveSourceLineNumbers = true;
|
||||
|
||||
/**
|
||||
* Creates a new printer.
|
||||
*
|
||||
* @param logHandler
|
||||
* the handler that reports logs and problems
|
||||
* @param context
|
||||
* the scanning context
|
||||
* @param compilationUnit
|
||||
* the source file to be printed
|
||||
* @param adapter
|
||||
* the printer adapter
|
||||
* @param preserveSourceLineNumbers
|
||||
* tells if the output source code should try to preserve the
|
||||
* line numbers of the original Java code
|
||||
*/
|
||||
public AbstractTreePrinter(TranspilationHandler logHandler, JSweetContext context, JCCompilationUnit compilationUnit, AbstractPrinterAdapter adapter,
|
||||
boolean preserveSourceLineNumbers) {
|
||||
super(logHandler, context, compilationUnit);
|
||||
this.typeChecker = new TypeChecker(this);
|
||||
this.adapter = adapter;
|
||||
this.adapter.setPrinter(this);
|
||||
this.preserveSourceLineNumbers = preserveSourceLineNumbers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets this output of this printer.
|
||||
*/
|
||||
public String getOutput() {
|
||||
return out.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Print a given AST.
|
||||
*/
|
||||
public AbstractTreePrinter print(JCTree tree) {
|
||||
scan(tree);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enters the given tree (se {@link #scan(JCTree)}.
|
||||
*/
|
||||
protected void enter(JCTree tree) {
|
||||
super.enter(tree);
|
||||
if (this.preserveSourceLineNumbers && !stack.isEmpty()) {
|
||||
int line = compilationUnit.lineMap.getLineNumber(stack.peek().pos);
|
||||
// adjusting line...
|
||||
while (currentLine < line) {
|
||||
out.append("\n");
|
||||
currentColumn = 0;
|
||||
currentLine++;
|
||||
}
|
||||
while (currentLine != 1 && currentLine > line && out.charAt(out.length() - 1) == '\n') {
|
||||
out.deleteCharAt(out.length() - 1);
|
||||
currentColumn = 0;
|
||||
currentLine--;
|
||||
}
|
||||
if (currentLine != line) {
|
||||
System.out.println("cannot adjust line for: " + tree.getClass() + " at line " + line);
|
||||
}
|
||||
// adjusting columns... (TODO: does not work)
|
||||
// int column =
|
||||
// compilationUnit.lineMap.getColumnNumber(stack.peek().pos);
|
||||
// while (currentColumn < column) {
|
||||
// // System.out.println("adding a column on "+tree.getClass());
|
||||
// out.append(" ");
|
||||
// currentColumn++;
|
||||
// }
|
||||
// while (currentColumn > column
|
||||
// && ((currentColumn == 1 && out.charAt(out.length() - 1) == ' ')
|
||||
// || (currentColumn > 1 && out.charAt(out.length() - 2) == ' '))) {
|
||||
// out.deleteCharAt(out.length() - 1);
|
||||
// currentColumn--;
|
||||
// }
|
||||
// if (currentColumn != column) {
|
||||
// System.out.println("cannot adjust column for: " + tree.getClass()
|
||||
// + " at position " + line + ", " + column + " - " + (currentColumn
|
||||
// - column));
|
||||
// }
|
||||
}
|
||||
positionStack.push(new Position(getCurrentPosition(), currentLine, currentColumn));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onRollbacked(JCTree target) {
|
||||
super.onRollbacked(target);
|
||||
Position position = positionStack.peek();
|
||||
out.delete(position.position, out.length());
|
||||
currentColumn = position.column;
|
||||
currentLine = position.line;
|
||||
}
|
||||
|
||||
/**
|
||||
* Exits the currently scanned tree.
|
||||
*/
|
||||
@Override
|
||||
protected void exit() {
|
||||
super.exit();
|
||||
positionStack.pop();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the current character count of the output.
|
||||
*/
|
||||
public int getCurrentPosition() {
|
||||
return out.length();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the lastly printed character.
|
||||
*/
|
||||
public char getLastPrintedChar() {
|
||||
return out.charAt(out.length() - 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints an indentation for the current indentation value.
|
||||
*/
|
||||
public AbstractTreePrinter printIndent() {
|
||||
for (int i = 0; i < indent; i++) {
|
||||
out.append(INDENT);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Increments the current indentation value.
|
||||
*/
|
||||
public AbstractTreePrinter startIndent() {
|
||||
indent++;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrements the current indentation value.
|
||||
*/
|
||||
public AbstractTreePrinter endIndent() {
|
||||
indent--;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs a string.
|
||||
*/
|
||||
public AbstractTreePrinter print(String string) {
|
||||
out.append(string);
|
||||
currentColumn += string.length();
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs an identifier.
|
||||
*/
|
||||
public AbstractTreePrinter printIdentifier(String identifier) {
|
||||
String adaptedIdentifier = getAdapter().getIdentifier(identifier);
|
||||
out.append(adaptedIdentifier);
|
||||
currentColumn += adaptedIdentifier.length();
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a space to the output.
|
||||
*/
|
||||
public AbstractTreePrinter space() {
|
||||
print(" ");
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the last output character.
|
||||
*/
|
||||
public AbstractTreePrinter removeLastChar() {
|
||||
out.deleteCharAt(out.length() - 1);
|
||||
currentColumn--;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the last output characters.
|
||||
*/
|
||||
public AbstractTreePrinter removeLastChars(int count) {
|
||||
if (count > 0) {
|
||||
out.delete(out.length() - count, out.length());
|
||||
}
|
||||
currentColumn -= count;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the last printed indentation.
|
||||
*/
|
||||
public AbstractTreePrinter removeLastIndent() {
|
||||
removeLastChars(indent * INDENT.length());
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs a new line.
|
||||
*/
|
||||
public AbstractTreePrinter println() {
|
||||
if (this.preserveSourceLineNumbers) {
|
||||
out.append(" ");
|
||||
currentColumn++;
|
||||
return this;
|
||||
}
|
||||
out.append("\n");
|
||||
currentLine++;
|
||||
currentColumn = 0;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the printed result as a string.
|
||||
*/
|
||||
public String getResult() {
|
||||
return out.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the adapter attached to this printer.
|
||||
*/
|
||||
public AbstractPrinterAdapter getAdapter() {
|
||||
return adapter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the adapter attached to this printer.
|
||||
*/
|
||||
public void setAdapter(AbstractPrinterAdapter adapter) {
|
||||
this.adapter = adapter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Print a comma-separated list of subtrees.
|
||||
*/
|
||||
public AbstractTreePrinter printArgList(List<? extends JCTree> args) {
|
||||
for (JCTree arg : args) {
|
||||
print(arg);
|
||||
print(", ");
|
||||
}
|
||||
if (!args.isEmpty()) {
|
||||
removeLastChars(2);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Print a comma-separated list of type subtrees.
|
||||
*/
|
||||
public AbstractTreePrinter printTypeArgList(List<? extends JCTree> args) {
|
||||
for (JCTree arg : args) {
|
||||
getAdapter().substituteAndPrintType(arg);
|
||||
print(", ");
|
||||
}
|
||||
if (!args.isEmpty()) {
|
||||
removeLastChars(2);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the current line of the printed output.
|
||||
*/
|
||||
public int getCurrentLine() {
|
||||
return currentLine;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the current column of the printed output.
|
||||
*/
|
||||
public int getCurrentColumn() {
|
||||
return currentColumn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the current compilation unit.
|
||||
*/
|
||||
public JCCompilationUnit getCompilationUnit() {
|
||||
return compilationUnit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tells if this printer tries to preserve the original line numbers of the
|
||||
* Java input.
|
||||
*/
|
||||
public boolean isPreserveLineNumbers() {
|
||||
return preserveSourceLineNumbers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the Javadoc attached to the given element if any.
|
||||
*/
|
||||
protected String getJavaDoc(JCTree element) {
|
||||
String javaDoc = compilationUnit.docComments.getCommentText(element);
|
||||
return javaDoc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints the Javadoc attached to the given element if any.
|
||||
*/
|
||||
protected AbstractTreePrinter printJavaDoc(JCTree element) {
|
||||
String doc = getJavaDoc(element);
|
||||
if (!isBlank(doc)) {
|
||||
print("/**");
|
||||
println();
|
||||
print(" * ");
|
||||
print(join(doc.split("\n"), "\n * "));
|
||||
println();
|
||||
print(" */");
|
||||
println();
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
}
|
||||
158
src/org/jsweet/transpiler/util/AbstractTreeScanner.java
Normal file
158
src/org/jsweet/transpiler/util/AbstractTreeScanner.java
Normal file
@ -0,0 +1,158 @@
|
||||
/* Copyright 2015 CINCHEO SAS
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.jsweet.transpiler.util;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Stack;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.jsweet.transpiler.JSweetContext;
|
||||
import org.jsweet.transpiler.JSweetProblem;
|
||||
import org.jsweet.transpiler.TranspilationHandler;
|
||||
|
||||
import com.sun.tools.javac.code.Symtab;
|
||||
import com.sun.tools.javac.code.Types;
|
||||
import com.sun.tools.javac.tree.JCTree;
|
||||
import com.sun.tools.javac.tree.JCTree.JCCompilationUnit;
|
||||
import com.sun.tools.javac.tree.TreeScanner;
|
||||
import com.sun.tools.javac.util.DiagnosticSource;
|
||||
import com.sun.tools.javac.util.Log;
|
||||
import com.sun.tools.javac.util.Name;
|
||||
import com.sun.tools.javac.util.Names;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Renaud Pawlak
|
||||
*/
|
||||
public abstract class AbstractTreeScanner extends TreeScanner {
|
||||
|
||||
private TranspilationHandler logHandler;
|
||||
|
||||
public void report(JCTree tree, JSweetProblem problem, Object... params) {
|
||||
report(tree, null, problem, params);
|
||||
}
|
||||
|
||||
public void report(JCTree tree, Name name, JSweetProblem problem, Object... params) {
|
||||
if (logHandler == null) {
|
||||
System.err.println(problem.getMessage(params));
|
||||
} else {
|
||||
int s = tree.getStartPosition();
|
||||
int e = tree.getEndPosition(diagnosticSource.getEndPosTable());
|
||||
if (e == -1) {
|
||||
e = s;
|
||||
}
|
||||
if (name != null) {
|
||||
e += name.length();
|
||||
}
|
||||
logHandler.report(problem,
|
||||
new TranspilationHandler.SourcePosition(new File(compilationUnit.sourcefile.getName()), tree, s, e, diagnosticSource.getLineNumber(s),
|
||||
diagnosticSource.getColumnNumber(s, false), diagnosticSource.getLineNumber(e), diagnosticSource.getColumnNumber(e, false)), problem
|
||||
.getMessage(params));
|
||||
}
|
||||
}
|
||||
|
||||
protected Stack<JCTree> stack = new Stack<JCTree>();
|
||||
|
||||
protected JCCompilationUnit compilationUnit;
|
||||
|
||||
protected JSweetContext context;
|
||||
|
||||
public JSweetContext getContext() {
|
||||
return context;
|
||||
}
|
||||
|
||||
protected DiagnosticSource diagnosticSource;
|
||||
|
||||
public AbstractTreeScanner(TranspilationHandler logHandler, JSweetContext context, JCCompilationUnit compilationUnit) {
|
||||
this.logHandler = logHandler;
|
||||
this.context = context;
|
||||
this.context.symtab = Symtab.instance(context);
|
||||
this.context.names = Names.instance(context);
|
||||
this.context.types = Types.instance(context);
|
||||
this.compilationUnit = compilationUnit;
|
||||
this.diagnosticSource = new DiagnosticSource(compilationUnit.sourcefile, Log.instance(context));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void scan(JCTree tree) {
|
||||
if (tree == null) {
|
||||
return;
|
||||
}
|
||||
enter(tree);
|
||||
try {
|
||||
tree.accept(this);
|
||||
} catch (RollbackException rollback) {
|
||||
if (rollback.getTarget() == tree) {
|
||||
onRollbacked(tree);
|
||||
if (rollback.getOnRollbacked() != null) {
|
||||
rollback.getOnRollbacked().accept(tree);
|
||||
}
|
||||
} else {
|
||||
throw rollback;
|
||||
}
|
||||
} finally {
|
||||
exit();
|
||||
}
|
||||
}
|
||||
|
||||
protected void onRollbacked(JCTree target) {
|
||||
}
|
||||
|
||||
protected void rollback(JCTree target, Consumer<JCTree> onRollbacked) {
|
||||
throw new RollbackException(target, onRollbacked);
|
||||
}
|
||||
|
||||
protected void enter(JCTree tree) {
|
||||
stack.push(tree);
|
||||
}
|
||||
|
||||
protected void exit() {
|
||||
stack.pop();
|
||||
}
|
||||
|
||||
public Stack<JCTree> getStack() {
|
||||
return this.stack;
|
||||
}
|
||||
|
||||
public JCTree getParent() {
|
||||
return this.stack.get(this.stack.size() - 2);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T extends JCTree> T getParent(Class<T> type) {
|
||||
for (int i = this.stack.size() - 2; i >= 0; i--) {
|
||||
if (type.isAssignableFrom(this.stack.get(i).getClass())) {
|
||||
return (T) this.stack.get(i);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T extends JCTree> T getParent(Class<T> type, JCTree from) {
|
||||
for (int i = this.stack.size() - 1; i >= 0; i--) {
|
||||
if (this.stack.get(i) == from) {
|
||||
for (int j = i - 1; j >= 0; j--) {
|
||||
if (type.isAssignableFrom(this.stack.get(j).getClass())) {
|
||||
return (T) this.stack.get(j);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,45 @@
|
||||
/* Copyright 2015 CINCHEO SAS
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.jsweet.transpiler.util;
|
||||
|
||||
import org.jsweet.transpiler.JSweetProblem;
|
||||
import org.jsweet.transpiler.JSweetTranspiler;
|
||||
import org.jsweet.transpiler.SourceFile;
|
||||
import org.jsweet.transpiler.TranspilationHandler;
|
||||
|
||||
/**
|
||||
* This is a simple transpilation handler that reports problems to the default
|
||||
* output stream.
|
||||
*
|
||||
* @author Renaud Pawlak
|
||||
*/
|
||||
public class ConsoleTranspilationHandler implements TranspilationHandler {
|
||||
|
||||
@Override
|
||||
public void report(JSweetProblem problem, SourcePosition sourcePosition, String message) {
|
||||
if (sourcePosition == null || sourcePosition.getFile() == null) {
|
||||
System.out.println(problem.getSeverity().toString() + ": " + message);
|
||||
} else {
|
||||
System.out
|
||||
.println(problem.getSeverity().toString() + ": " + message + " at " + sourcePosition.getFile() + "(" + sourcePosition.getStartLine() + ")");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCompleted(JSweetTranspiler transpiler, boolean fullPass, SourceFile[] files) {
|
||||
System.out.println("end");
|
||||
}
|
||||
|
||||
}
|
||||
510
src/org/jsweet/transpiler/util/DirectedGraph.java
Normal file
510
src/org/jsweet/transpiler/util/DirectedGraph.java
Normal file
@ -0,0 +1,510 @@
|
||||
/* Copyright 2015 CINCHEO SAS
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.jsweet.transpiler.util;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
* This class defines a directed graph collection type, that is to say a set of
|
||||
* elements (aka nodes) linked together with directed edges. It is particularly
|
||||
* useful for the <i>topological sort</i>, which is implemented as depicted in
|
||||
* Wikipedia and this <a href=
|
||||
* "http://stackoverflow.com/questions/2739392/sample-directed-graph-and-topological-sort-code"
|
||||
* >StackOverflow thread</a>
|
||||
*
|
||||
* <p>
|
||||
* Example of use:
|
||||
*
|
||||
* <pre>
|
||||
* Graph<Integer> g = new Graph<Integer>();
|
||||
* g.add(7, 5, 3, 11, 8, 2, 9, 10);
|
||||
* g.buildEdges(new Comparator<Integer>() {
|
||||
* @Override
|
||||
* public int compare(Integer o1, Integer o2) {
|
||||
* if (o1 == 5 && o2 == 3) {
|
||||
* return 1;
|
||||
* }
|
||||
* return 0;
|
||||
* }
|
||||
* });
|
||||
* System.out.println(g.topologicalSort());
|
||||
* </pre>
|
||||
*
|
||||
* <p>
|
||||
* Prints out: <code>[11, 10, 8, 7, 2, 3, 5, 9]</code> (5 is always after 3,
|
||||
* because of the edge built by the comparator, however, the remainder is in
|
||||
* random order).
|
||||
*
|
||||
* @author Renaud Pawlak
|
||||
*
|
||||
* @param <T>
|
||||
* the types of the nodes in the graph
|
||||
*/
|
||||
public class DirectedGraph<T> implements Collection<T> {
|
||||
|
||||
private Map<T, Node<T>> nodes = new HashMap<T, Node<T>>();
|
||||
|
||||
/**
|
||||
* Constructs an empty graph collection.
|
||||
*/
|
||||
public DirectedGraph() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a set of elements to the nodes of this graph.
|
||||
*/
|
||||
@Override
|
||||
public boolean addAll(Collection<? extends T> elements) {
|
||||
for (T element : elements) {
|
||||
add(element);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an element to the nodes.
|
||||
*/
|
||||
@Override
|
||||
public boolean add(T element) {
|
||||
if(nodes.containsKey(element)) {
|
||||
return false;
|
||||
}
|
||||
Node<T> node = new Node<T>(this, element);
|
||||
nodes.put(element, node);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears all the nodes of this graph.
|
||||
*/
|
||||
@Override
|
||||
public void clear() {
|
||||
nodes.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tells if this graph contains the given object as a node.
|
||||
*/
|
||||
@Override
|
||||
public boolean contains(Object o) {
|
||||
return nodes.containsKey(o);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tells if this graph contains the given collection as a node.
|
||||
*/
|
||||
@Override
|
||||
public boolean containsAll(Collection<?> c) {
|
||||
for (Object o : c) {
|
||||
if (!contains(o)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Equals two graphs.
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (!(obj instanceof DirectedGraph)) {
|
||||
return false;
|
||||
} else {
|
||||
return nodes.equals(((DirectedGraph<?>) obj).nodes);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return nodes.hashCode();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this graph has no nodes.
|
||||
*/
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return nodes.isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an iterator to iterate on graph nodes.
|
||||
*/
|
||||
@Override
|
||||
public Iterator<T> iterator() {
|
||||
return nodes.keySet().iterator();
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes an object from the graph nodes (if exists).
|
||||
*/
|
||||
@Override
|
||||
public boolean remove(Object o) {
|
||||
return nodes.remove(o) != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all the objects from the graph nodes (if exists).
|
||||
*/
|
||||
@Override
|
||||
public boolean removeAll(Collection<?> c) {
|
||||
for (Object o : c) {
|
||||
remove(o);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Keeps only the elements of the given collection in the graph.
|
||||
*/
|
||||
@Override
|
||||
public boolean retainAll(Collection<?> c) {
|
||||
boolean b = false;
|
||||
for (T element : nodes.keySet()) {
|
||||
if (!c.contains(element)) {
|
||||
remove(element);
|
||||
b = true;
|
||||
}
|
||||
}
|
||||
return b;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the nodes count in this graph.
|
||||
*/
|
||||
@Override
|
||||
public int size() {
|
||||
return nodes.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the graph's nodes as an array (not sorted).
|
||||
*/
|
||||
@Override
|
||||
public Object[] toArray() {
|
||||
return nodes.keySet().toArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the graph's nodes as a well-typed array (not sorted).
|
||||
*/
|
||||
@Override
|
||||
public <U> U[] toArray(U[] a) {
|
||||
return toArray(a);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a set of elements to the nodes of this graph.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public void add(T... elements) {
|
||||
for (T element : elements) {
|
||||
add(element);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an edge between the given elements (nodes).
|
||||
*
|
||||
* @param sourceElement
|
||||
* the source element/node
|
||||
* @param destinationElement
|
||||
* the destination element/node
|
||||
*/
|
||||
public void addEdge(T sourceElement, T destinationElement) {
|
||||
if (sourceElement.equals(destinationElement)) {
|
||||
return;
|
||||
}
|
||||
if (hasEdge(sourceElement, destinationElement)) {
|
||||
return;
|
||||
}
|
||||
nodes.get(sourceElement).addEdge(destinationElement);
|
||||
}
|
||||
|
||||
/**
|
||||
* Automatically builds the edges between all the nodes of the graph by
|
||||
* using the given comparator. If the comparator returns 0, then no edge is
|
||||
* constructor between the compared nodes.
|
||||
*
|
||||
* @param nodeComparator
|
||||
* a comparator which is used to build the edges
|
||||
*/
|
||||
public <U extends T> void buildEdges(Comparator<U> nodeComparator) {
|
||||
for (T e1 : nodes.keySet()) {
|
||||
for (T e2 : nodes.keySet()) {
|
||||
@SuppressWarnings("unchecked")
|
||||
int i = nodeComparator.compare((U) e1, (U) e2);
|
||||
if (i < 0) {
|
||||
addEdge(e1, e2);
|
||||
}
|
||||
if (i > 0) {
|
||||
addEdge(e2, e1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds some edges form the source elements to the given destination
|
||||
* elements.
|
||||
*
|
||||
* @param sourceElement
|
||||
* the source of the edges
|
||||
* @param destinationElements
|
||||
* the destination elements of the edges
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public void addEdges(T sourceElement, T... destinationElements) {
|
||||
nodes.get(sourceElement).addEdges(destinationElements);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tells if this graph contains an edge between the given source and the
|
||||
* destination elements/nodes.
|
||||
*
|
||||
* @param sourceElement
|
||||
* the source node
|
||||
* @param destinationElement
|
||||
* the destination node
|
||||
* @return true if an edge is found, false otherwise
|
||||
*/
|
||||
public boolean hasEdge(T sourceElement, T destinationElement) {
|
||||
if (nodes.get(sourceElement) == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (Edge<T> edge : nodes.get(sourceElement).outEdges) {
|
||||
if (edge.to.element == destinationElement) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public List<T> getDestinationElements(T sourceElement) {
|
||||
List<T> l = new ArrayList<T>();
|
||||
if (nodes.get(sourceElement) == null) {
|
||||
return null;
|
||||
}
|
||||
for (Edge<T> edge : nodes.get(sourceElement).outEdges) {
|
||||
l.add(edge.to.element);
|
||||
}
|
||||
return l;
|
||||
}
|
||||
|
||||
public List<T> getSourceElements(T destinationElement) {
|
||||
if (nodes.get(destinationElement) == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
List<T> l = new ArrayList<T>();
|
||||
for (Edge<T> edge : nodes.get(destinationElement).inEdges) {
|
||||
l.add(edge.from.element);
|
||||
}
|
||||
return l;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuffer s = new StringBuffer();
|
||||
s.append("[");
|
||||
for (T element : nodes.keySet()) {
|
||||
s.append(element.toString());
|
||||
s.append("->");
|
||||
s.append(getDestinationElements(element));
|
||||
s.append(",");
|
||||
}
|
||||
if (!nodes.isEmpty()) {
|
||||
s.deleteCharAt(s.length() - 1);
|
||||
}
|
||||
s.append("]");
|
||||
return s.toString();
|
||||
}
|
||||
|
||||
public static class Node<T> {
|
||||
private DirectedGraph<T> graph;
|
||||
public final T element;
|
||||
public final HashSet<Edge<T>> inEdges;
|
||||
public final HashSet<Edge<T>> usedInEdges;
|
||||
public final HashSet<Edge<T>> outEdges;
|
||||
public final HashSet<Edge<T>> usedOutEdges;
|
||||
|
||||
public Node(DirectedGraph<T> graph, T element) {
|
||||
this.graph = graph;
|
||||
this.element = element;
|
||||
inEdges = new HashSet<Edge<T>>();
|
||||
usedInEdges = new HashSet<Edge<T>>();
|
||||
outEdges = new HashSet<Edge<T>>();
|
||||
usedOutEdges = new HashSet<Edge<T>>();
|
||||
}
|
||||
|
||||
public void addEdge(T destinationElement) {
|
||||
Node<T> node = graph.nodes.get(destinationElement);
|
||||
if (node == null) {
|
||||
graph.add(destinationElement);
|
||||
node = graph.nodes.get(destinationElement);
|
||||
}
|
||||
Edge<T> e = new Edge<T>(this, node);
|
||||
outEdges.add(e);
|
||||
node.inEdges.add(e);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public void addEdges(T... destinationElements) {
|
||||
for (T destinationElement : destinationElements) {
|
||||
addEdge(destinationElement);
|
||||
}
|
||||
}
|
||||
|
||||
public void useInEdge(Edge<T> edge) {
|
||||
if (inEdges.remove(edge)) {
|
||||
usedInEdges.add(edge);
|
||||
}
|
||||
}
|
||||
|
||||
public void useOutEdge(Edge<T> edge) {
|
||||
if (outEdges.remove(edge)) {
|
||||
usedOutEdges.add(edge);
|
||||
}
|
||||
}
|
||||
|
||||
public void resetEdges() {
|
||||
inEdges.addAll(usedInEdges);
|
||||
usedInEdges.clear();
|
||||
outEdges.addAll(usedOutEdges);
|
||||
usedOutEdges.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Node[" + element + "]";
|
||||
}
|
||||
}
|
||||
|
||||
public static class Edge<T> {
|
||||
public final Node<T> from;
|
||||
public final Node<T> to;
|
||||
|
||||
public Edge(Node<T> from, Node<T> to) {
|
||||
this.from = from;
|
||||
this.to = to;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Edge[" + from + "->" + to + "]";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
@SuppressWarnings("unchecked")
|
||||
Edge<T> e = (Edge<T>) obj;
|
||||
return e.from == from && e.to == to;
|
||||
}
|
||||
}
|
||||
|
||||
private List<T> toElements(List<Node<T>> nodes) {
|
||||
List<T> elements = new ArrayList<T>();
|
||||
for (Node<T> node : nodes) {
|
||||
elements.add(node.element);
|
||||
}
|
||||
return elements;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sorts this graph using a topological sort algorithm given in this <a
|
||||
* href=
|
||||
* "http://stackoverflow.com/questions/2739392/sample-directed-graph-and-topological-sort-code"
|
||||
* >StackOverflow thread</a>.
|
||||
*
|
||||
* @return the list of nodes, sorted according to the topological sort
|
||||
* @throws CycleFoundException
|
||||
* thrown if a cycle is found in the graph (in that case no
|
||||
* topological sort is possible)
|
||||
*/
|
||||
public List<T> topologicalSort(Consumer<Node<T>> cycleHandler) {
|
||||
List<Node<T>> allNodes = new ArrayList<Node<T>>(nodes.values());
|
||||
// L <- Empty list that will contain the sorted elements
|
||||
ArrayList<Node<T>> L = new ArrayList<Node<T>>();
|
||||
|
||||
// S <- Set of all nodes with no incoming edges
|
||||
HashSet<Node<T>> S = new HashSet<Node<T>>();
|
||||
for (Node<T> n : allNodes) {
|
||||
if (n.inEdges.size() == 0) {
|
||||
S.add(n);
|
||||
}
|
||||
}
|
||||
|
||||
// while S is non-empty do
|
||||
while (!S.isEmpty()) {
|
||||
// remove a node n from S
|
||||
Node<T> n = S.iterator().next();
|
||||
S.remove(n);
|
||||
|
||||
// insert n into L
|
||||
L.add(n);
|
||||
|
||||
// for each node m with an edge e from n to m do
|
||||
for (Iterator<Edge<T>> it = new ArrayList<>(n.outEdges).iterator(); it.hasNext();) {
|
||||
// remove edge e from the graph
|
||||
Edge<T> e = it.next();
|
||||
Node<T> m = e.to;
|
||||
n.useOutEdge(e); // Remove edge from n
|
||||
m.useInEdge(e); // Remove edge from m
|
||||
|
||||
// if m has no other incoming edges then insert m into S
|
||||
if (m.inEdges.isEmpty()) {
|
||||
S.add(m);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Check to see if all edges are removed
|
||||
for (Node<T> n : allNodes) {
|
||||
if (!n.inEdges.isEmpty()) {
|
||||
if (cycleHandler != null) {
|
||||
cycleHandler.accept(n);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (Node<T> n : allNodes) {
|
||||
n.resetEdges();
|
||||
}
|
||||
return toElements(L);
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
DirectedGraph<Integer> g = new DirectedGraph<Integer>();
|
||||
g.add(7, 5, 3, 11, 8, 2, 9, 10);
|
||||
g.buildEdges(new Comparator<Integer>() {
|
||||
@Override
|
||||
public int compare(Integer o1, Integer o2) {
|
||||
if (o1 == 5 && o2 == 3) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
});
|
||||
System.out.println(g.topologicalSort(null));
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,86 @@
|
||||
/* Copyright 2015 CINCHEO SAS
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.jsweet.transpiler.util;
|
||||
|
||||
import org.jsweet.transpiler.JSweetProblem;
|
||||
import org.jsweet.transpiler.JSweetTranspiler;
|
||||
import org.jsweet.transpiler.SourceFile;
|
||||
import org.jsweet.transpiler.TranspilationHandler;
|
||||
|
||||
/**
|
||||
* An error count decorator for a transpilation handler.
|
||||
*
|
||||
* @author Renaud Pawlak
|
||||
*/
|
||||
public class ErrorCountTranspilationHandler implements TranspilationHandler {
|
||||
|
||||
private TranspilationHandler delegate;
|
||||
private int errorCount = 0;
|
||||
private int warningCount = 0;
|
||||
private int problemCount = 0;
|
||||
|
||||
/**
|
||||
* Decorates the given transpilation handler.
|
||||
*/
|
||||
public ErrorCountTranspilationHandler(TranspilationHandler delegate) {
|
||||
this.delegate = delegate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Count the problems and delegates to the decorated transpilation handler.
|
||||
*/
|
||||
public void report(JSweetProblem problem, SourcePosition sourcePosition, String message) {
|
||||
switch (problem.getSeverity()) {
|
||||
case ERROR:
|
||||
problemCount++;
|
||||
errorCount++;
|
||||
break;
|
||||
case WARNING:
|
||||
problemCount++;
|
||||
warningCount++;
|
||||
break;
|
||||
default:
|
||||
problemCount++;
|
||||
}
|
||||
delegate.report(problem, sourcePosition, message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the error count.
|
||||
*/
|
||||
public int getErrorCount() {
|
||||
return errorCount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCompleted(JSweetTranspiler transpiler, boolean fullPass, SourceFile[] files) {
|
||||
delegate.onCompleted(transpiler, fullPass, files);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the warning count.
|
||||
*/
|
||||
public int getWarningCount() {
|
||||
return warningCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the problem count (error + warning count).
|
||||
*/
|
||||
public int getProblemCount() {
|
||||
return problemCount;
|
||||
}
|
||||
|
||||
}
|
||||
44
src/org/jsweet/transpiler/util/EvaluationResult.java
Normal file
44
src/org/jsweet/transpiler/util/EvaluationResult.java
Normal file
@ -0,0 +1,44 @@
|
||||
/* Copyright 2015 CINCHEO SAS
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.jsweet.transpiler.util;
|
||||
|
||||
import org.jsweet.transpiler.JSweetTranspiler;
|
||||
|
||||
/**
|
||||
* An evaluation result of a JSweet program.
|
||||
*
|
||||
* @author Renaud Pawlak
|
||||
* @see JSweetTranspiler#eval(org.jsweet.transpiler.TranspilationHandler,
|
||||
* org.jsweet.transpiler.SourceFile...)
|
||||
* @see JSweetTranspiler#eval(String,
|
||||
* org.jsweet.transpiler.TranspilationHandler,
|
||||
* org.jsweet.transpiler.SourceFile...)
|
||||
*/
|
||||
public interface EvaluationResult {
|
||||
/**
|
||||
* Get access to the value of an exported variable (exported with a call to
|
||||
* the jsweet.util.Globals.$export function).
|
||||
*
|
||||
* @param variableName
|
||||
* the variable to access
|
||||
* @return the value as it was exported during the program execution
|
||||
*/
|
||||
<T> T get(String variableName);
|
||||
|
||||
/**
|
||||
* Gets the execution trace of the program execution.
|
||||
*/
|
||||
String getExecutionTrace();
|
||||
}
|
||||
146
src/org/jsweet/transpiler/util/JavaCompilationEnvironment.java
Normal file
146
src/org/jsweet/transpiler/util/JavaCompilationEnvironment.java
Normal file
@ -0,0 +1,146 @@
|
||||
/* Copyright 2015 CINCHEO SAS
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.jsweet.transpiler.util;
|
||||
|
||||
import static org.jsweet.transpiler.util.Util.toJavaFileObjects;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.util.List;
|
||||
|
||||
import javax.tools.JavaFileManager;
|
||||
import javax.tools.JavaFileObject;
|
||||
|
||||
import org.jsweet.transpiler.JSweetContext;
|
||||
|
||||
import com.sun.tools.javac.code.Lint.LintCategory;
|
||||
import com.sun.tools.javac.code.Symtab;
|
||||
import com.sun.tools.javac.code.Types;
|
||||
import com.sun.tools.javac.file.JavacFileManager;
|
||||
import com.sun.tools.javac.main.JavaCompiler;
|
||||
import com.sun.tools.javac.main.Option;
|
||||
import com.sun.tools.javac.tree.JCTree.JCCompilationUnit;
|
||||
import com.sun.tools.javac.util.Log;
|
||||
import com.sun.tools.javac.util.Names;
|
||||
import com.sun.tools.javac.util.Options;
|
||||
|
||||
/**
|
||||
* This utility class encapsulates a <code>javac</code> compilation environment.
|
||||
*
|
||||
* @author Renaud Pawlak
|
||||
*/
|
||||
public class JavaCompilationEnvironment {
|
||||
/**
|
||||
* Creates a new compilation environment with the given classpath.
|
||||
*/
|
||||
public static JavaCompilationEnvironment create(String classPath) {
|
||||
JSweetContext context = new JSweetContext();
|
||||
Options options = Options.instance(context);
|
||||
options.put(Option.CLASSPATH, classPath);
|
||||
options.put(Option.XLINT, "path");
|
||||
context.put(Log.outKey, new PrintWriter(System.out));
|
||||
|
||||
// options.put(Option.XLINT_CUSTOM.text + "-" +
|
||||
// LintCategory.OPTIONS.option, "true");
|
||||
// options.remove(Option.XLINT_CUSTOM.text +
|
||||
// LintCategory.OPTIONS.option);
|
||||
|
||||
options.put(Option.XLINT_CUSTOM.text + "-" + LintCategory.OVERRIDES.option, "true");
|
||||
|
||||
JavacFileManager.preRegister(context);
|
||||
JavaFileManager fileManager = context.get(JavaFileManager.class);
|
||||
|
||||
Log log = Log.instance(context);
|
||||
log.emitWarnings = false;
|
||||
log.suppressNotes = true;
|
||||
Types javacTypes = Types.instance(context);
|
||||
|
||||
JavaCompiler compiler = JavaCompiler.instance(context);
|
||||
compiler.attrParseOnly = true;
|
||||
compiler.verbose = false;
|
||||
compiler.genEndPos = true;
|
||||
compiler.keepComments = true;
|
||||
|
||||
Names names = Names.instance(context);
|
||||
Symtab symtab = Symtab.instance(context);
|
||||
|
||||
return new JavaCompilationEnvironment(fileManager, compiler, options, context, log, javacTypes, names, symtab);
|
||||
}
|
||||
|
||||
/**
|
||||
* The Java file manager.
|
||||
*/
|
||||
public final JavaFileManager fileManager;
|
||||
/**
|
||||
* The Java compiler.
|
||||
*/
|
||||
public final JavaCompiler compiler;
|
||||
/**
|
||||
* The compilation context.
|
||||
*/
|
||||
public final JSweetContext context;
|
||||
/**
|
||||
* The log object.
|
||||
*/
|
||||
public final Log log;
|
||||
/**
|
||||
* The compiler's type holder.
|
||||
*/
|
||||
public final Types types;
|
||||
/**
|
||||
* The compiler's symbol table.
|
||||
*/
|
||||
public final Symtab symtab;
|
||||
/**
|
||||
* The compiler's name holder.
|
||||
*/
|
||||
public final Names names;
|
||||
/**
|
||||
* The compiler's options.
|
||||
*/
|
||||
public final Options options;
|
||||
|
||||
private JavaCompilationEnvironment( //
|
||||
JavaFileManager fileManager, //
|
||||
JavaCompiler compiler, //
|
||||
Options options, //
|
||||
JSweetContext context, //
|
||||
Log log, //
|
||||
Types javacTypes, //
|
||||
Names names, //
|
||||
Symtab symtab) {
|
||||
this.fileManager = fileManager;
|
||||
this.compiler = compiler;
|
||||
this.options = options;
|
||||
this.context = context;
|
||||
this.log = log;
|
||||
this.types = javacTypes;
|
||||
this.names = names;
|
||||
this.symtab = symtab;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses and attributes the given files within this compilation
|
||||
* environment.
|
||||
*/
|
||||
public List<JCCompilationUnit> parseAndAttributeJavaFiles(List<File> javaFiles) throws IOException {
|
||||
List<JavaFileObject> sources = toJavaFileObjects(fileManager, javaFiles);
|
||||
List<JCCompilationUnit> compilationUnits = compiler.enterTrees(compiler.parseFiles(sources));
|
||||
compiler.attribute(compiler.todo);
|
||||
return compilationUnits;
|
||||
}
|
||||
|
||||
}
|
||||
207
src/org/jsweet/transpiler/util/ProcessUtil.java
Normal file
207
src/org/jsweet/transpiler/util/ProcessUtil.java
Normal file
@ -0,0 +1,207 @@
|
||||
/* Copyright 2015 CINCHEO SAS
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.jsweet.transpiler.util;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.InputStreamReader;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.apache.commons.lang3.ArrayUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
/**
|
||||
* A set of utilities to launch external processes from Java.
|
||||
*
|
||||
* @author Renaud Pawlak
|
||||
*/
|
||||
public class ProcessUtil {
|
||||
private final static Logger logger = Logger.getLogger(ProcessUtil.class);
|
||||
|
||||
/**
|
||||
* A static field that stores the user home directory.
|
||||
*/
|
||||
public static File USER_HOME_DIR = new File(System.getProperty("user.home"));
|
||||
|
||||
/**
|
||||
* Runs the given command.
|
||||
*
|
||||
* @param command
|
||||
* the command name
|
||||
* @param stdoutConsumer
|
||||
* consumes the standard output stream as lines of characters
|
||||
* @param errorHandler
|
||||
* upcalled when the command does not terminate successfully
|
||||
* @param args
|
||||
* the command-line arguments
|
||||
* @return the process that was created to execute the command (exited at
|
||||
* this point)
|
||||
*/
|
||||
public static Process runCommand(String command, Consumer<String> stdoutConsumer, Runnable errorHandler, String... args) {
|
||||
return runCommand(command, null, false, stdoutConsumer, null, errorHandler, args);
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs the given command in an asynchronous manner.
|
||||
*
|
||||
* @param command
|
||||
* the command name
|
||||
* @param stdoutConsumer
|
||||
* consumes the standard output stream as lines of characters
|
||||
* @param endConsumer
|
||||
* called when the process actually ends
|
||||
* @param errorHandler
|
||||
* upcalled when the command does not terminate successfully
|
||||
* @param args
|
||||
* the command-line arguments
|
||||
* @return the process that was created to execute the command (can be still
|
||||
* running at this point)
|
||||
*/
|
||||
public static Process runAsyncCommand(String command, Consumer<String> stdoutConsumer, Consumer<Process> endConsumer, Runnable errorHandler,
|
||||
String... args) {
|
||||
return runCommand(command, null, true, stdoutConsumer, endConsumer, errorHandler, args);
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs the given command.
|
||||
*
|
||||
* @param command
|
||||
* the command name
|
||||
* @param directory
|
||||
* the working directory of the created process
|
||||
* @param async
|
||||
* tells if the command should be run asynchronously (in a
|
||||
* separate thread)
|
||||
* @param stdoutConsumer
|
||||
* consumes the standard output stream as lines of characters
|
||||
* @param endConsumer
|
||||
* called when the process actually ends
|
||||
* @param errorHandler
|
||||
* upcalled when the command does not terminate successfully
|
||||
* @param args
|
||||
* the command-line arguments
|
||||
* @return the process that was created to execute the command (can be still
|
||||
* running at this point if <code>async</code> is <code>true</code>)
|
||||
*/
|
||||
public static Process runCommand(String command, File directory, boolean async, Consumer<String> stdoutConsumer, Consumer<Process> endConsumer,
|
||||
Runnable errorHandler, String... args) {
|
||||
|
||||
String[] cmd;
|
||||
if (System.getProperty("os.name").startsWith("Windows")) {
|
||||
cmd = new String[] { "cmd", "/c" };
|
||||
} else {
|
||||
cmd = new String[0];
|
||||
}
|
||||
cmd = ArrayUtils.addAll(cmd, command);
|
||||
cmd = ArrayUtils.addAll(cmd, args);
|
||||
|
||||
logger.debug("run command: " + StringUtils.join(cmd, " "));
|
||||
Process[] process = { null };
|
||||
try {
|
||||
|
||||
ProcessBuilder processBuilder = new ProcessBuilder(cmd);
|
||||
processBuilder.redirectErrorStream(true);
|
||||
if (directory != null) {
|
||||
processBuilder.directory(directory);
|
||||
}
|
||||
|
||||
process[0] = processBuilder.start();
|
||||
|
||||
Runnable runnable = new Runnable() {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
try (BufferedReader in = new BufferedReader(new InputStreamReader(process[0].getInputStream()))) {
|
||||
String line;
|
||||
while ((line = in.readLine()) != null) {
|
||||
if (stdoutConsumer != null) {
|
||||
stdoutConsumer.accept(line);
|
||||
} else {
|
||||
logger.info(command + " - " + line);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
process[0].waitFor();
|
||||
if (endConsumer != null) {
|
||||
endConsumer.accept(process[0]);
|
||||
}
|
||||
if (process[0].exitValue() != 0) {
|
||||
if (errorHandler != null) {
|
||||
errorHandler.run();
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.error(e.getMessage(), e);
|
||||
if (errorHandler != null) {
|
||||
errorHandler.run();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
if (async) {
|
||||
new Thread(runnable).start();
|
||||
} else {
|
||||
runnable.run();
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
logger.error(e.getMessage(), e);
|
||||
if (errorHandler != null) {
|
||||
errorHandler.run();
|
||||
}
|
||||
}
|
||||
return process[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* Installs a <code>node<code> package with <code>npm</code> (assumes that
|
||||
* <code>node</code> is installed).
|
||||
*
|
||||
* @param nodePackageName
|
||||
* the package name
|
||||
* @param global
|
||||
* <code>true</code> for adding the <code>-g</code> option
|
||||
*/
|
||||
public static void installNodePackage(String nodePackageName, boolean global) {
|
||||
logger.debug("installing " + nodePackageName + " with npm");
|
||||
if (global) {
|
||||
runCommand("npm", USER_HOME_DIR, false, null, null, null, "install", nodePackageName, "-g");
|
||||
} else {
|
||||
runCommand("npm", USER_HOME_DIR, false, null, null, null, "install", nodePackageName);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Uninstalls a <code>node<code> package with <code>npm</code> (assumes that
|
||||
* <code>node</code> is installed).
|
||||
*
|
||||
* @param nodePackageName
|
||||
* the package name
|
||||
* @param global
|
||||
* <code>true</code> for adding the <code>-g</code> option
|
||||
*/
|
||||
public static void uninstallNodePackage(String nodePackageName, boolean global) {
|
||||
logger.debug("uninstalling " + nodePackageName + " with npm");
|
||||
if (global) {
|
||||
runCommand("npm", USER_HOME_DIR, false, null, null, null, "uninstall", nodePackageName, "-g");
|
||||
} else {
|
||||
runCommand("npm", USER_HOME_DIR, false, null, null, null, "uninstall", nodePackageName);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
56
src/org/jsweet/transpiler/util/ReferenceGrabber.java
Normal file
56
src/org/jsweet/transpiler/util/ReferenceGrabber.java
Normal file
@ -0,0 +1,56 @@
|
||||
/* Copyright 2015 CINCHEO SAS
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.jsweet.transpiler.util;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import com.sun.tools.javac.code.Symbol.ClassSymbol;
|
||||
import com.sun.tools.javac.code.Symbol.TypeSymbol;
|
||||
import com.sun.tools.javac.tree.JCTree.JCFieldAccess;
|
||||
import com.sun.tools.javac.tree.JCTree.JCNewClass;
|
||||
import com.sun.tools.javac.tree.TreeScanner;
|
||||
|
||||
/**
|
||||
* A utility scanner that grabs all references to types used within a code tree.
|
||||
*
|
||||
* @author Renaud Pawlak
|
||||
*/
|
||||
public class ReferenceGrabber extends TreeScanner {
|
||||
|
||||
/**
|
||||
* The grabbed references.
|
||||
*/
|
||||
public Set<TypeSymbol> referencedTypes = new HashSet<>();
|
||||
|
||||
@Override
|
||||
public void visitNewClass(JCNewClass newClass) {
|
||||
add(newClass.clazz.type.tsym);
|
||||
super.visitNewClass(newClass);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitSelect(JCFieldAccess fieldAccess) {
|
||||
if (fieldAccess.selected.type != null && (fieldAccess.selected.type.tsym instanceof ClassSymbol)) {
|
||||
add(fieldAccess.selected.type.tsym);
|
||||
}
|
||||
super.visitSelect(fieldAccess);
|
||||
}
|
||||
|
||||
private void add(TypeSymbol type) {
|
||||
referencedTypes.add(type);
|
||||
}
|
||||
|
||||
}
|
||||
61
src/org/jsweet/transpiler/util/RollbackException.java
Normal file
61
src/org/jsweet/transpiler/util/RollbackException.java
Normal file
@ -0,0 +1,61 @@
|
||||
/* Copyright 2015 CINCHEO SAS
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.jsweet.transpiler.util;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import com.sun.tools.javac.tree.JCTree;
|
||||
|
||||
/**
|
||||
* This exception can be thrown to rollback the scanning of an AST.
|
||||
*
|
||||
* @author Renaud Pawlak
|
||||
*/
|
||||
public class RollbackException extends RuntimeException {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private JCTree target;
|
||||
private Consumer<JCTree> onRollbacked;
|
||||
|
||||
/**
|
||||
* Rollback up to the target.
|
||||
*
|
||||
* @param target
|
||||
* the target
|
||||
* @param onRollbacked
|
||||
* the handler to be executed once rollbacked.
|
||||
*/
|
||||
public RollbackException(JCTree target, Consumer<JCTree> onRollbacked) {
|
||||
super();
|
||||
this.target = target;
|
||||
this.onRollbacked = onRollbacked;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the target of the rollback.
|
||||
*/
|
||||
public JCTree getTarget() {
|
||||
return target;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the rollback handler.
|
||||
*/
|
||||
public Consumer<JCTree> getOnRollbacked() {
|
||||
return onRollbacked;
|
||||
}
|
||||
|
||||
}
|
||||
717
src/org/jsweet/transpiler/util/Util.java
Normal file
717
src/org/jsweet/transpiler/util/Util.java
Normal file
@ -0,0 +1,717 @@
|
||||
/* Copyright 2015 CINCHEO SAS
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.jsweet.transpiler.util;
|
||||
|
||||
import static java.util.Arrays.asList;
|
||||
import static org.apache.commons.lang3.StringUtils.isBlank;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Stack;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import javax.lang.model.element.AnnotationMirror;
|
||||
import javax.lang.model.element.AnnotationValue;
|
||||
import javax.lang.model.element.Element;
|
||||
import javax.lang.model.element.ElementKind;
|
||||
import javax.lang.model.element.ExecutableElement;
|
||||
import javax.lang.model.element.Modifier;
|
||||
import javax.tools.JavaFileManager;
|
||||
import javax.tools.JavaFileObject;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.log4j.Logger;
|
||||
import org.jsweet.JSweetConfig;
|
||||
|
||||
import com.sun.tools.javac.code.Attribute;
|
||||
import com.sun.tools.javac.code.Attribute.Compound;
|
||||
import com.sun.tools.javac.code.Flags;
|
||||
import com.sun.tools.javac.code.Symbol;
|
||||
import com.sun.tools.javac.code.Symbol.ClassSymbol;
|
||||
import com.sun.tools.javac.code.Symbol.MethodSymbol;
|
||||
import com.sun.tools.javac.code.Symbol.PackageSymbol;
|
||||
import com.sun.tools.javac.code.Symbol.TypeSymbol;
|
||||
import com.sun.tools.javac.code.Symbol.VarSymbol;
|
||||
import com.sun.tools.javac.code.Type;
|
||||
import com.sun.tools.javac.code.Type.MethodType;
|
||||
import com.sun.tools.javac.code.Types;
|
||||
import com.sun.tools.javac.file.JavacFileManager;
|
||||
import com.sun.tools.javac.tree.JCTree;
|
||||
import com.sun.tools.javac.tree.JCTree.JCAnnotation;
|
||||
import com.sun.tools.javac.tree.JCTree.JCAssign;
|
||||
import com.sun.tools.javac.tree.JCTree.JCBlock;
|
||||
import com.sun.tools.javac.tree.JCTree.JCCase;
|
||||
import com.sun.tools.javac.tree.JCTree.JCCatch;
|
||||
import com.sun.tools.javac.tree.JCTree.JCClassDecl;
|
||||
import com.sun.tools.javac.tree.JCTree.JCEnhancedForLoop;
|
||||
import com.sun.tools.javac.tree.JCTree.JCExpression;
|
||||
import com.sun.tools.javac.tree.JCTree.JCForLoop;
|
||||
import com.sun.tools.javac.tree.JCTree.JCIdent;
|
||||
import com.sun.tools.javac.tree.JCTree.JCLambda;
|
||||
import com.sun.tools.javac.tree.JCTree.JCLiteral;
|
||||
import com.sun.tools.javac.tree.JCTree.JCMethodDecl;
|
||||
import com.sun.tools.javac.tree.JCTree.JCMethodInvocation;
|
||||
import com.sun.tools.javac.tree.JCTree.JCNewArray;
|
||||
import com.sun.tools.javac.tree.JCTree.JCStatement;
|
||||
import com.sun.tools.javac.tree.JCTree.JCVariableDecl;
|
||||
import com.sun.tools.javac.tree.TreeScanner;
|
||||
import com.sun.tools.javac.util.Name;
|
||||
|
||||
/**
|
||||
* Various utilities.
|
||||
*
|
||||
* @author Renaud Pawlak
|
||||
*/
|
||||
public class Util {
|
||||
|
||||
private static long id = 121;
|
||||
|
||||
/**
|
||||
* Returns a unique id (incremental).
|
||||
*/
|
||||
public static long getId() {
|
||||
return id++;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tells if the given type is within the Java sources being compiled.
|
||||
*/
|
||||
public static boolean isSourceType(ClassSymbol clazz) {
|
||||
// hack to know if it is a source file or a class file
|
||||
return (clazz.sourcefile != null && clazz.sourcefile.getClass().getName().equals("com.sun.tools.javac.file.RegularFileObject"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursively adds files to the given list.
|
||||
*
|
||||
* @param extension
|
||||
* the extension to filter with
|
||||
* @param file
|
||||
* the root file/directory to look into recursively
|
||||
* @param files
|
||||
* the list to add the files matching the extension
|
||||
*/
|
||||
public static void addFiles(String extension, File file, LinkedList<File> files) {
|
||||
if (file.isDirectory()) {
|
||||
for (File f : file.listFiles()) {
|
||||
addFiles(extension, f, files);
|
||||
}
|
||||
} else if (file.getName().endsWith(extension)) {
|
||||
files.add(file);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the full signature of the given method.
|
||||
*/
|
||||
public static String getFullMethodSignature(MethodSymbol method) {
|
||||
return method.getEnclosingElement().getQualifiedName() + "." + method.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tells if the given symbol is annotated with one of the given annotation
|
||||
* type names.
|
||||
*/
|
||||
public static boolean hasAnnotationType(Symbol symbol, String... annotationTypes) {
|
||||
for (Compound a : symbol.getAnnotationMirrors()) {
|
||||
for (String annotationType : annotationTypes) {
|
||||
if (annotationType.equals(a.type.toString())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the symbol's annotation that correspond to the given annotation type
|
||||
* name if exists.
|
||||
*/
|
||||
public static AnnotationMirror getAnnotation(Symbol symbol, String annotationType) {
|
||||
for (Compound a : symbol.getAnnotationMirrors()) {
|
||||
if (annotationType.equals(a.type.toString())) {
|
||||
return a;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets repeatable annotations. By convention, the container must be named
|
||||
* after the contained name + 's'.
|
||||
*
|
||||
* @param symbol
|
||||
* the annotated symbol
|
||||
* @param annotationType
|
||||
* the qualified name of the repeated annotation
|
||||
* @return
|
||||
*/
|
||||
public static List<AnnotationMirror> getAnnotations(Symbol symbol, String annotationType) {
|
||||
List<AnnotationMirror> annotations = new ArrayList<>();
|
||||
for (Compound a : symbol.getAnnotationMirrors()) {
|
||||
if ((annotationType + "s").equals(a.type.toString())) {
|
||||
Attribute.Array array = (Attribute.Array) a.values.head.snd;
|
||||
for (Attribute attr : array.values) {
|
||||
annotations.add((AnnotationMirror) attr);
|
||||
}
|
||||
return annotations;
|
||||
} else if (annotationType.equals(a.type.toString())) {
|
||||
annotations.add(a);
|
||||
return annotations;
|
||||
}
|
||||
}
|
||||
return annotations;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the annotation tree that matches the given type name.
|
||||
*/
|
||||
public static JCAnnotation getAnnotation(List<JCAnnotation> annotations, String annotationType) {
|
||||
for (JCAnnotation a : annotations) {
|
||||
if (annotationType.equals(a.type.toString())) {
|
||||
return a;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tells if the given type declaration contains some method declarations.
|
||||
*/
|
||||
public static boolean containsMethods(JCClassDecl classDeclaration) {
|
||||
for (JCTree member : classDeclaration.getMembers()) {
|
||||
if (member instanceof JCMethodDecl) {
|
||||
JCMethodDecl method = (JCMethodDecl) member;
|
||||
if (method.pos == classDeclaration.pos) {
|
||||
continue;
|
||||
}
|
||||
return true;
|
||||
// if (method.body != null) {
|
||||
// return true;
|
||||
// }
|
||||
} else if (member instanceof JCVariableDecl) {
|
||||
if (((JCVariableDecl) member).mods.getFlags().contains(Modifier.STATIC)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tells if the given type is a Java interface.
|
||||
*/
|
||||
public static boolean isInterface(TypeSymbol typeSymbol) {
|
||||
return (typeSymbol.type.isInterface() || Util.hasAnnotationType(typeSymbol, JSweetConfig.ANNOTATION_INTERFACE));
|
||||
}
|
||||
|
||||
private static void putVar(Map<String, VarSymbol> vars, VarSymbol varSymbol) {
|
||||
vars.put(varSymbol.getSimpleName().toString(), varSymbol);
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds all the variables accessible within the current scanning scope.
|
||||
*/
|
||||
public static void fillAllVariablesInScope(Map<String, VarSymbol> vars, Stack<JCTree> scanningStack, JCTree from, JCTree to) {
|
||||
if (from == to) {
|
||||
return;
|
||||
}
|
||||
int i = scanningStack.indexOf(from);
|
||||
if (i == -1 || i == 0) {
|
||||
return;
|
||||
}
|
||||
JCTree parent = scanningStack.get(i - 1);
|
||||
List<JCStatement> statements = null;
|
||||
switch (parent.getKind()) {
|
||||
case BLOCK:
|
||||
statements = ((JCBlock) parent).stats;
|
||||
break;
|
||||
case CASE:
|
||||
statements = ((JCCase) parent).stats;
|
||||
break;
|
||||
case CATCH:
|
||||
putVar(vars, ((JCCatch) parent).param.sym);
|
||||
break;
|
||||
case FOR_LOOP:
|
||||
if (((JCForLoop) parent).init != null) {
|
||||
for (JCStatement s : ((JCForLoop) parent).init) {
|
||||
if (s instanceof JCVariableDecl) {
|
||||
putVar(vars, ((JCVariableDecl) s).sym);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case ENHANCED_FOR_LOOP:
|
||||
putVar(vars, ((JCEnhancedForLoop) parent).var.sym);
|
||||
break;
|
||||
default:
|
||||
|
||||
}
|
||||
if (statements != null) {
|
||||
for (JCStatement s : statements) {
|
||||
if (s == from) {
|
||||
break;
|
||||
} else if (s instanceof JCVariableDecl) {
|
||||
putVar(vars, ((JCVariableDecl) s).sym);
|
||||
}
|
||||
}
|
||||
}
|
||||
fillAllVariablesInScope(vars, scanningStack, parent, to);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fills the given map with all the variables beeing accessed within the
|
||||
* given code tree.
|
||||
*/
|
||||
public static void fillAllVariableAccesses(final Map<String, VarSymbol> vars, final JCTree tree) {
|
||||
new TreeScanner() {
|
||||
@Override
|
||||
public void visitIdent(JCIdent ident) {
|
||||
if (ident.sym.getKind() == ElementKind.LOCAL_VARIABLE) {
|
||||
putVar(vars, (VarSymbol) ident.sym);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitLambda(JCLambda lambda) {
|
||||
if (lambda == tree) {
|
||||
super.visitLambda(lambda);
|
||||
}
|
||||
}
|
||||
}.scan(tree);
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the method declaration within the given type, for the given
|
||||
* invocation.
|
||||
*/
|
||||
public static MethodSymbol findMethodDeclarationInType(Types types, TypeSymbol typeSymbol, JCMethodInvocation invocation) {
|
||||
String meth = invocation.meth.toString();
|
||||
String methName = meth.substring(meth.lastIndexOf('.') + 1);
|
||||
return findMethodDeclarationInType(types, typeSymbol, methName, (MethodType) invocation.meth.type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the method in the given type that matches the given name and
|
||||
* signature.
|
||||
*/
|
||||
public static MethodSymbol findMethodDeclarationInType(Types types, TypeSymbol typeSymbol, String methodName, MethodType methodType) {
|
||||
if (typeSymbol == null || typeSymbol.getEnclosedElements() == null) {
|
||||
return null;
|
||||
}
|
||||
for (Element element : typeSymbol.getEnclosedElements()) {
|
||||
if ((element instanceof MethodSymbol) && methodName.equals(element.getSimpleName().toString())) {
|
||||
if (methodType == null) {
|
||||
return (MethodSymbol) element;
|
||||
}
|
||||
if (types.isSubSignature(methodType, ((MethodSymbol) element).type)) {
|
||||
return (MethodSymbol) element;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (typeSymbol instanceof ClassSymbol && ((ClassSymbol) typeSymbol).getSuperclass() != null) {
|
||||
return findMethodDeclarationInType(types, ((ClassSymbol) typeSymbol).getSuperclass().tsym, methodName, methodType);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the field in the given type that matches the given name.
|
||||
*/
|
||||
public static VarSymbol findFieldDeclaration(ClassSymbol classSymbol, Name name) {
|
||||
Iterator<Symbol> it = classSymbol.members_field.getElementsByName(name, (symbol) -> {
|
||||
return symbol instanceof VarSymbol;
|
||||
}).iterator();
|
||||
if (it.hasNext()) {
|
||||
return (VarSymbol) it.next();
|
||||
} else {
|
||||
if (classSymbol.getSuperclass().tsym instanceof ClassSymbol) {
|
||||
return findFieldDeclaration((ClassSymbol) classSymbol.getSuperclass().tsym, name);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the actual name of a symbol from a JSweet convention, so including
|
||||
* potential <code>jsweet.lang.Name</code> annotation.
|
||||
*/
|
||||
public static String getActualName(Symbol symbol) {
|
||||
String name = symbol.getSimpleName().toString();
|
||||
if (Util.hasAnnotationType(symbol, JSweetConfig.ANNOTATION_NAME)) {
|
||||
String originalName = Util.getAnnotationValue(symbol, JSweetConfig.ANNOTATION_NAME, null);
|
||||
if (!isBlank(originalName)) {
|
||||
name = originalName;
|
||||
}
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
private static void getRootRelativeName(StringBuilder sb, Symbol symbol) {
|
||||
if (!Util.hasAnnotationType(symbol, JSweetConfig.ANNOTATION_ROOT)) {
|
||||
if (sb.length() > 0 && !"".equals(symbol.toString())) {
|
||||
sb.insert(0, ".");
|
||||
}
|
||||
|
||||
String name = symbol.getSimpleName().toString();
|
||||
if (Util.hasAnnotationType(symbol, JSweetConfig.ANNOTATION_NAME)) {
|
||||
String originalName = Util.getAnnotationValue(symbol, JSweetConfig.ANNOTATION_NAME, null);
|
||||
if (!isBlank(originalName)) {
|
||||
name = originalName;
|
||||
}
|
||||
}
|
||||
|
||||
sb.insert(0, name);
|
||||
symbol = (symbol instanceof PackageSymbol) ? ((PackageSymbol) symbol).owner : symbol.getEnclosingElement();
|
||||
if (symbol != null) {
|
||||
getRootRelativeName(sb, symbol);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets root package (see <code>jsweet.lang.Root</code>) enclosing the given
|
||||
* symbol.
|
||||
*/
|
||||
public static PackageSymbol getRootPackage(Symbol symbol) {
|
||||
if ((symbol instanceof PackageSymbol) && Util.hasAnnotationType(symbol, JSweetConfig.ANNOTATION_ROOT)) {
|
||||
return null;
|
||||
}
|
||||
Symbol parent = (symbol instanceof PackageSymbol) ? ((PackageSymbol) symbol).owner : symbol.getEnclosingElement();
|
||||
if (parent != null && Util.hasAnnotationType(parent, JSweetConfig.ANNOTATION_ROOT)) {
|
||||
if (symbol instanceof PackageSymbol) {
|
||||
return (PackageSymbol) symbol;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
} else {
|
||||
if (parent == null || (parent instanceof PackageSymbol && StringUtils.isBlank(parent.getSimpleName()))) {
|
||||
if (symbol instanceof PackageSymbol) {
|
||||
return (PackageSymbol) symbol;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
} else {
|
||||
return getRootPackage(parent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void getRootRelativeJavaName(StringBuilder sb, Symbol symbol) {
|
||||
if (!Util.hasAnnotationType(symbol, JSweetConfig.ANNOTATION_ROOT)) {
|
||||
if (sb.length() > 0 && !"".equals(symbol.toString())) {
|
||||
sb.insert(0, ".");
|
||||
}
|
||||
|
||||
String name = symbol.getSimpleName().toString();
|
||||
|
||||
sb.insert(0, name);
|
||||
symbol = (symbol instanceof PackageSymbol) ? ((PackageSymbol) symbol).owner : symbol.getEnclosingElement();
|
||||
if (symbol != null) {
|
||||
getRootRelativeJavaName(sb, symbol);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tells if this qualified name denotes a JSweet globals class.
|
||||
*/
|
||||
public static boolean isGlobalsClassName(String qualifiedName) {
|
||||
return qualifiedName != null
|
||||
&& (JSweetConfig.GLOBALS_CLASS_NAME.equals(qualifiedName) || qualifiedName.endsWith("." + JSweetConfig.GLOBALS_CLASS_NAME));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the qualified name of a symbol relatively to the root package
|
||||
* (potentially annotated with <code>jsweet.lang.Root</code>). This function
|
||||
* takes into account potential <code>jsweet.lang.Name</code> annotations).
|
||||
*/
|
||||
public static String getRootRelativeName(Symbol symbol) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
getRootRelativeName(sb, symbol);
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the qualified name of a symbol relatively to the root package
|
||||
* (potentially annotated with <code>jsweet.lang.Root</code>). This function
|
||||
* ignores <code>jsweet.lang.Name</code> annotations).
|
||||
*/
|
||||
public static String getRootRelativeJavaName(Symbol symbol) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
getRootRelativeJavaName(sb, symbol);
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the first value of the 'value' property.
|
||||
*/
|
||||
public static Object getFirstAnnotationValue(AnnotationMirror annotation, Object defaultValue) {
|
||||
for (AnnotationValue value : annotation.getElementValues().values()) {
|
||||
return value.getValue();
|
||||
}
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value of the given annotation property.
|
||||
*
|
||||
* @param annotation
|
||||
* the annotation
|
||||
* @param propertyName
|
||||
* the name of the annotation property to get the value of
|
||||
* @param defaultValue
|
||||
* the value to return if not found
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <T> T getAnnotationValue(AnnotationMirror annotation, String propertyName, T defaultValue) {
|
||||
for (Map.Entry<? extends ExecutableElement, ? extends AnnotationValue> annoProperty : annotation.getElementValues().entrySet()) {
|
||||
if (annoProperty.getKey().getSimpleName().toString().equals(propertyName)) {
|
||||
return (T) annoProperty.getValue().getValue();
|
||||
}
|
||||
}
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the first value of the 'value' property for the given annotation
|
||||
* type if found on the given symbol.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <T> T getAnnotationValue(Symbol symbol, String annotationType, T defaultValue) {
|
||||
AnnotationMirror anno = getAnnotation(symbol, annotationType);
|
||||
T val = defaultValue;
|
||||
if (anno != null) {
|
||||
val = (T) getFirstAnnotationValue(anno, defaultValue);
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tells if this parameter declaration is varargs.
|
||||
*/
|
||||
public static boolean isVarargs(JCVariableDecl varDecl) {
|
||||
return (varDecl.mods.flags & Flags.VARARGS) == Flags.VARARGS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the file from a Java file object.
|
||||
*/
|
||||
public static File toFile(JavaFileObject javaFileObject) {
|
||||
return new File(javaFileObject.getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Transforms a Java iterable to a javac list.
|
||||
*/
|
||||
public static <T> com.sun.tools.javac.util.List<T> toJCList(Iterable<T> collection) {
|
||||
return com.sun.tools.javac.util.List.from(collection);
|
||||
}
|
||||
|
||||
/**
|
||||
* Transforms a list of source files to Java file objects (used by javac).
|
||||
*/
|
||||
public static com.sun.tools.javac.util.List<JavaFileObject> toJavaFileObjects(JavaFileManager fileManager, Collection<File> sourceFiles)
|
||||
throws IOException {
|
||||
com.sun.tools.javac.util.List<JavaFileObject> fileObjects = com.sun.tools.javac.util.List.nil();
|
||||
JavacFileManager javacFileManager = (JavacFileManager) fileManager;
|
||||
for (JavaFileObject fo : javacFileManager.getJavaFileObjectsFromFiles(sourceFiles)) {
|
||||
fileObjects = fileObjects.append(fo);
|
||||
}
|
||||
if (fileObjects.length() != sourceFiles.size()) {
|
||||
throw new IOException("invalid file list");
|
||||
}
|
||||
return fileObjects;
|
||||
}
|
||||
|
||||
/**
|
||||
* Transforms a source file to a Java file object (used by javac).
|
||||
*/
|
||||
public static JavaFileObject toJavaFileObject(JavaFileManager fileManager, File sourceFile) throws IOException {
|
||||
List<JavaFileObject> javaFileObjects = toJavaFileObjects(fileManager, asList(sourceFile));
|
||||
return javaFileObjects.isEmpty() ? null : javaFileObjects.get(0);
|
||||
}
|
||||
|
||||
private final static Pattern REGEX_CHARS = Pattern.compile("([\\\\*+\\[\\](){}\\$.?\\^|])");
|
||||
|
||||
/**
|
||||
* This function will escape special characters within a string to ensure
|
||||
* that the string will not be parsed as a regular expression. This is
|
||||
* helpful with accepting using input that needs to be used in functions
|
||||
* that take a regular expression as an argument (such as
|
||||
* String.replaceAll(), or String.split()).
|
||||
*
|
||||
* @param regex
|
||||
* - argument which we wish to escape.
|
||||
* @return - Resulting string with the following characters escaped:
|
||||
* [](){}+*^?$.\
|
||||
*/
|
||||
public static String escapeRegex(final String regex) {
|
||||
Matcher match = REGEX_CHARS.matcher(regex);
|
||||
return match.replaceAll("\\\\$1");
|
||||
}
|
||||
|
||||
/**
|
||||
* Varargs to mutable list.
|
||||
*/
|
||||
@SafeVarargs
|
||||
public static final <T> List<T> list(T... items) {
|
||||
ArrayList<T> list = new ArrayList<T>(items.length);
|
||||
for (T item : items) {
|
||||
list.add(item);
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tells if two type symbols are assignable.
|
||||
*/
|
||||
public static boolean isAssignable(Types types, TypeSymbol to, TypeSymbol from) {
|
||||
if (to.equals(from)) {
|
||||
return true;
|
||||
} else {
|
||||
return from.isSubClass(to, types);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tells if the given list contains an type which is assignable from type.
|
||||
*/
|
||||
public static boolean containsAssignableType(Types types, List<Type> list, Type type) {
|
||||
for (Type t : list) {
|
||||
if (types.isAssignable(t, type)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the relative path to reach a symbol from another one.
|
||||
*
|
||||
* @param fromSymbol
|
||||
* the start path
|
||||
* @param toSymbol
|
||||
* the end path
|
||||
* @return the '/'-separated path
|
||||
* @see #getRelativePath(String, String)
|
||||
*/
|
||||
public static String getRelativePath(Symbol fromSymbol, Symbol toSymbol) {
|
||||
return Util.getRelativePath("/" + fromSymbol.getQualifiedName().toString().replace('.', '/'),
|
||||
"/" + toSymbol.getQualifiedName().toString().replace('.', '/'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the relative path that links the two given paths.
|
||||
*
|
||||
* <pre>
|
||||
* assertEquals("../c", Util.getRelativePath("/a/b", "/a/c"));
|
||||
* assertEquals("..", Util.getRelativePath("/a/b", "/a"));
|
||||
* assertEquals("../e", Util.getRelativePath("/a/b/c", "/a/b/e"));
|
||||
* assertEquals("d", Util.getRelativePath("/a/b/c", "/a/b/c/d"));
|
||||
* assertEquals("d/e", Util.getRelativePath("/a/b/c", "/a/b/c/d/e"));
|
||||
* assertEquals("../../../d/e/f", Util.getRelativePath("/a/b/c", "/d/e/f"));
|
||||
* assertEquals("../..", Util.getRelativePath("/a/b/c", "/a"));
|
||||
* assertEquals("..", Util.getRelativePath("/a/b/c", "/a/b"));
|
||||
* </pre>
|
||||
*
|
||||
* <p>
|
||||
* Thanks to:
|
||||
* http://mrpmorris.blogspot.com/2007/05/convert-absolute-path-to-relative-
|
||||
* path.html
|
||||
*
|
||||
* <p>
|
||||
* Bug fix: Renaud Pawlak
|
||||
*
|
||||
* @param fromPath
|
||||
* the path to start from
|
||||
* @param toPath
|
||||
* the path to reach
|
||||
*/
|
||||
public static String getRelativePath(String fromPath, String toPath) {
|
||||
StringBuilder relativePath = null;
|
||||
|
||||
fromPath = fromPath.replaceAll("\\\\", "/");
|
||||
toPath = toPath.replaceAll("\\\\", "/");
|
||||
|
||||
if (!fromPath.equals(toPath)) {
|
||||
String[] fromSegments = fromPath.split("/");
|
||||
String[] toSegments = toPath.split("/");
|
||||
|
||||
// Get the shortest of the two paths
|
||||
int length = fromSegments.length < toSegments.length ? fromSegments.length : toSegments.length;
|
||||
|
||||
// Use to determine where in the loop we exited
|
||||
int lastCommonRoot = -1;
|
||||
int index;
|
||||
|
||||
// Find common root
|
||||
for (index = 0; index < length; index++) {
|
||||
if (fromSegments[index].equals(toSegments[index])) {
|
||||
lastCommonRoot = index;
|
||||
} else {
|
||||
break;
|
||||
// If we didn't find a common prefix then throw
|
||||
}
|
||||
}
|
||||
if (lastCommonRoot != -1) {
|
||||
// Build up the relative path
|
||||
relativePath = new StringBuilder();
|
||||
// Add on the ..
|
||||
for (index = lastCommonRoot + 1; index < fromSegments.length; index++) {
|
||||
if (fromSegments[index].length() > 0) {
|
||||
relativePath.append("../");
|
||||
}
|
||||
}
|
||||
for (index = lastCommonRoot + 1; index < toSegments.length - 1; index++) {
|
||||
relativePath.append(toSegments[index] + "/");
|
||||
}
|
||||
if (!fromPath.startsWith(toPath)) {
|
||||
relativePath.append(toSegments[toSegments.length - 1]);
|
||||
} else {
|
||||
if (relativePath.length() > 0) {
|
||||
relativePath.deleteCharAt(relativePath.length() - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return relativePath == null ? null : relativePath.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the extensions of the given file name.
|
||||
* @param fileName the given file name (can contain path)
|
||||
* @return the file name without the extension
|
||||
*/
|
||||
public static String removeExtension(String fileName) {
|
||||
int index = fileName.lastIndexOf('.');
|
||||
if (index == -1) {
|
||||
return fileName;
|
||||
} else {
|
||||
return fileName.substring(0, index);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
26
src/org/jsweet/transpiler/util/VariableKind.java
Normal file
26
src/org/jsweet/transpiler/util/VariableKind.java
Normal file
@ -0,0 +1,26 @@
|
||||
/* Copyright 2015 CINCHEO SAS
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.jsweet.transpiler.util;
|
||||
|
||||
/**
|
||||
* An enum to differentiate fields and local variable in an AST.
|
||||
*
|
||||
* @author Renaud Pawlak
|
||||
*/
|
||||
public enum VariableKind {
|
||||
|
||||
FIELD, LOCAL
|
||||
|
||||
}
|
||||
20
src/org/jsweet/transpiler/util/package-info.java
Normal file
20
src/org/jsweet/transpiler/util/package-info.java
Normal file
@ -0,0 +1,20 @@
|
||||
/* Copyright 2015 CINCHEO SAS
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
/**
|
||||
* This package contains utilities for the JSweet transpiler.
|
||||
*
|
||||
* @author Renaud Pawlak
|
||||
*/
|
||||
package org.jsweet.transpiler.util;
|
||||
1
target/.gitignore
vendored
Normal file
1
target/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
/classes/
|
||||
Loading…
x
Reference in New Issue
Block a user