[NOTHING CHANGED] Move to maven and massive clean and fixup #93

Closed
farmboy0 wants to merge 43 commits from farmboy0/master into master
144 changed files with 17201 additions and 14311 deletions
Showing only changes of commit e7e6190f9c - Show all commits

390
.ide/formatter.xml Normal file
View File

@@ -0,0 +1,390 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<profiles version="21">
<profile kind="CodeFormatterProfile" name="LuaJ" version="21">
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_ellipsis" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_for_statment" value="common_lines"/>
<setting id="org.eclipse.jdt.core.formatter.comment.new_lines_at_block_boundaries" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_package" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.format_javadoc_comments" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.indentation.size" value="4"/>
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_enum_constant_declaration" value="common_lines"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.align_with_spaces" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.continuation_indentation" value="1"/>
<setting id="org.eclipse.jdt.core.formatter.number_of_blank_lines_before_code_block" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_switch_case_expressions" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_after_package" value="1"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.indent_root_tags" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.wrap_before_or_operator_multicatch" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.enabling_tag" value="@formatter:on"/>
<setting id="org.eclipse.jdt.core.formatter.comment.count_line_length_from_starting_position" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_record_components" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.wrap_before_multiplicative_operator" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_method" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_parameterized_type_references" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_logical_operator" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.keep_annotation_declaration_on_one_line" value="one_line_never"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_record_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_enum_constant" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_multiplicative_operator" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.preserve_white_space_between_code_and_line_comments" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_abstract_method" value="1"/>
<setting id="org.eclipse.jdt.core.formatter.keep_enum_constant_declaration_on_one_line" value="one_line_never"/>
<setting id="org.eclipse.jdt.core.formatter.align_variable_declarations_on_columns" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_union_type_in_multicatch" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_catch_clause" value="common_lines"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_multiplicative_operator" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.keep_anonymous_type_declaration_on_one_line" value="one_line_never"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_switch_case_expressions" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.wrap_before_shift_operator" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_block" value="end_of_line"/>
<setting id="org.eclipse.jdt.core.formatter.number_of_blank_lines_at_end_of_code_block" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_bitwise_operator" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_type_parameters" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_compact_loops" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.keep_simple_for_body_on_same_line" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_unary_operator" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.format_line_comment_starting_on_first_column" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_annotation" value="common_lines"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_ellipsis" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_try_resources" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_annotations_on_enum_constant" value="49"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.text_block_indentation" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.align_type_members_on_columns" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_assignment" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_module_statements" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.align_tags_names_descriptions" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.keep_if_then_body_block_on_one_line" value="one_line_never"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.align_assignment_statements_on_columns" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_block_in_case" value="end_of_line"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_conditional_expression_chain" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.comment.format_header" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_type_annotations" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.wrap_before_assertion_message_operator" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_method_declaration" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.align_fields_grouping_blank_lines" value="1"/>
<setting id="org.eclipse.jdt.core.formatter.comment.new_lines_at_javadoc_boundaries" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_bitwise_operator" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration" value="end_of_line"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_resources_in_try" value="80"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.format_source_code" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_field" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_method" value="1"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_not_operator" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_type_annotation" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.format_html" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_method_delcaration" value="common_lines"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_compact_if" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.indent_empty_lines" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_type_arguments" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_unary_operator" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_annotations_on_package" value="49"/>
<setting id="org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_label" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_arrow_in_switch_case" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_record_header" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.wrap_before_bitwise_operator" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_try" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_lambda_arrow" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.indent_tag_description" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_record_constructor" value="end_of_line"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_string_concatenation" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_multiple_fields" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_array_initializer" value="end_of_line"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_shift_operator" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_shift_operator" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.keep_simple_do_while_body_on_same_line" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_record_components" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_expressions_in_for_loop_header" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.wrap_before_additive_operator" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.keep_simple_getter_setter_on_one_line" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_string_concatenation" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_lambda_arrow" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.join_lines_in_comments" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_record_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_relational_operator" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_between_import_groups" value="1"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_logical_operator" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_method_invocation" value="common_lines"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_after_imports" value="1"/>
<setting id="org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_record_declaration" value="common_lines"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_switch_statement" value="common_lines"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_arrow_in_switch_default" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.disabling_tag" value="@formatter:off"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_enum_constants" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_imports" value="1"/>
<setting id="org.eclipse.jdt.core.formatter.number_of_blank_lines_at_end_of_method_body" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_if_while_statement" value="common_lines"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_arrow_in_switch_case" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_field" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations" value="1"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.indent_statements_compare_to_block" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration" value="end_of_line"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.align_tags_descriptions_grouped" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.comment.line_length" value="80"/>
<setting id="org.eclipse.jdt.core.formatter.use_on_off_tags" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.keep_method_body_on_one_line" value="one_line_preserve"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.keep_loop_body_block_on_one_line" value="one_line_never"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_method_declaration" value="end_of_line"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.keep_type_declaration_on_one_line" value="one_line_never"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_additive_operator" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_record_constructor" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_relational_operator" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.keep_record_declaration_on_one_line" value="one_line_never"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration" value="end_of_line"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_lambda_body" value="end_of_line"/>
<setting id="org.eclipse.jdt.core.formatter.compact_else_if" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_try" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_annotations_on_parameter" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_relational_operator" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve" value="1"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_additive_operator" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_string_concatenation" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.format_line_comments" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_record_declaration" value="end_of_line"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.number_of_blank_lines_after_code_block" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_conditional_expression" value="80"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_type" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_annotations_on_type" value="49"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_annotations_on_local_variable" value="49"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration" value="end_of_line"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_arrow_in_switch_default" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.insert_new_line_between_different_tags" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_additive_operator" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.join_wrapped_lines" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_annotations_on_field" value="49"/>
<setting id="org.eclipse.jdt.core.formatter.wrap_before_conditional_operator" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_shift_operator" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_try_clause" value="common_lines"/>
<setting id="org.eclipse.jdt.core.formatter.keep_code_block_on_one_line" value="one_line_never"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_record_components" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.tabulation.size" value="4"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_bitwise_operator" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_try" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_try_resources" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer" value="2"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_record_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.wrap_before_assignment_operator" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_switch" value="end_of_line"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.keep_lambda_body_block_on_one_line" value="one_line_never"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_annotations_on_method" value="49"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.keep_record_constructor_on_one_line" value="one_line_never"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_record_declaration" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_assertion_message" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk" value="1"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_member_type" value="1"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_logical_operator" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_record_declaration" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_semicolon" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.wrap_before_relational_operator" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.format_block_comments" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_after_last_class_body_declaration" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.indent_statements_compare_to_body" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.keep_simple_while_body_on_same_line" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.wrap_before_logical_operator" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_between_statement_group_in_switch" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_lambda_declaration" value="common_lines"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.keep_enum_declaration_on_one_line" value="one_line_never"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_enum_constant" value="end_of_line"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_type_declaration" value="end_of_line"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_multiplicative_operator" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_package" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.indent_parameter_description" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_code_block" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.tabulation.char" value="tab"/>
<setting id="org.eclipse.jdt.core.formatter.wrap_before_string_concatenation" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.lineSplit" value="120"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch" value="insert"/>
</profile>
</profiles>

View File

@@ -21,16 +21,16 @@
******************************************************************************/
package org.luaj.vm2;
/**
* String buffer for use in string library methods, optimized for production
* of StrValue instances.
* String buffer for use in string library methods, optimized for production of
* StrValue instances.
* <p>
* The buffer can begin initially as a wrapped {@link LuaValue}
* and only when concatenation actually occurs are the bytes first copied.
* The buffer can begin initially as a wrapped {@link LuaValue} and only when
* concatenation actually occurs are the bytes first copied.
* <p>
* To convert back to a {@link LuaValue} again,
* the function {@link Buffer#value()} is used.
* To convert back to a {@link LuaValue} again, the function
* {@link Buffer#value()} is used.
*
* @see LuaValue
* @see LuaValue#buffer()
* @see LuaString
@@ -57,6 +57,7 @@ public final class Buffer {
/**
* Create buffer with default capacity
*
* @see #DEFAULT_CAPACITY
*/
public Buffer() {
@@ -65,10 +66,11 @@ public final class Buffer {
/**
* Create buffer with specified initial capacity
*
* @param initialCapacity the initial capacity
*/
public Buffer( int initialCapacity ) {
bytes = new byte[ initialCapacity ];
public Buffer(int initialCapacity) {
bytes = new byte[initialCapacity];
length = 0;
offset = 0;
value = null;
@@ -76,6 +78,7 @@ public final class Buffer {
/**
* Create buffer with specified initial value
*
* @param value the initial value
*/
public Buffer(LuaValue value) {
@@ -86,6 +89,7 @@ public final class Buffer {
/**
* Get buffer contents as a {@link LuaValue}
*
* @return value as a {@link LuaValue}, converting as necessary
*/
public LuaValue value() {
@@ -94,6 +98,7 @@ public final class Buffer {
/**
* Set buffer contents as a {@link LuaValue}
*
* @param value value to set
*/
public Buffer setvalue(LuaValue value) {
@@ -105,15 +110,17 @@ public final class Buffer {
/**
* Convert the buffer to a {@link LuaString}
*
* @return the value as a {@link LuaString}
*/
public final LuaString tostring() {
realloc( length, 0 );
return LuaString.valueOf( bytes, offset, length );
realloc(length, 0);
return LuaString.valueOf(bytes, offset, length);
}
/**
* Convert the buffer to a Java String
*
* @return the value as a Java String
*/
public String tojstring() {
@@ -122,6 +129,7 @@ public final class Buffer {
/**
* Convert the buffer to a Java String
*
* @return the value as a Java String
*/
public String toString() {
@@ -130,117 +138,139 @@ public final class Buffer {
/**
* Append a single byte to the buffer.
*
* @return {@code this} to allow call chaining
*/
public final Buffer append( byte b ) {
makeroom( 0, 1 );
bytes[ offset + length++ ] = b;
public final Buffer append(byte b) {
makeroom(0, 1);
bytes[offset+length++] = b;
return this;
}
/**
* Append a {@link LuaValue} to the buffer.
*
* @return {@code this} to allow call chaining
*/
public final Buffer append( LuaValue val ) {
append( val.strvalue() );
public final Buffer append(LuaValue val) {
append(val.strvalue());
return this;
}
/**
* Append a {@link LuaString} to the buffer.
*
* @return {@code this} to allow call chaining
*/
public final Buffer append( LuaString str ) {
public final Buffer append(LuaString str) {
final int n = str.m_length;
makeroom( 0, n );
str.copyInto( 0, bytes, offset + length, n );
makeroom(0, n);
str.copyInto(0, bytes, offset+length, n);
length += n;
return this;
}
/**
* Append a Java String to the buffer.
* The Java string will be converted to bytes using the UTF8 encoding.
* Append a Java String to the buffer. The Java string will be converted to
* bytes using the UTF8 encoding.
*
* @return {@code this} to allow call chaining
* @see LuaString#encodeToUtf8(char[], int, byte[], int)
*/
public final Buffer append( String str ) {
public final Buffer append(String str) {
char[] c = str.toCharArray();
final int n = LuaString.lengthAsUtf8( c );
makeroom( 0, n );
LuaString.encodeToUtf8( c, c.length, bytes, offset + length );
final int n = LuaString.lengthAsUtf8(c);
makeroom(0, n);
LuaString.encodeToUtf8(c, c.length, bytes, offset+length);
length += n;
return this;
}
/** Concatenate this buffer onto a {@link LuaValue}
* @param lhs the left-hand-side value onto which we are concatenating {@code this}
/**
* Concatenate this buffer onto a {@link LuaValue}
*
* @param lhs the left-hand-side value onto which we are concatenating
* {@code this}
* @return {@link Buffer} for use in call chaining.
*/
public Buffer concatTo(LuaValue lhs) {
return setvalue(lhs.concat(value()));
}
/** Concatenate this buffer onto a {@link LuaString}
* @param lhs the left-hand-side value onto which we are concatenating {@code this}
/**
* Concatenate this buffer onto a {@link LuaString}
*
* @param lhs the left-hand-side value onto which we are concatenating
* {@code this}
* @return {@link Buffer} for use in call chaining.
*/
public Buffer concatTo(LuaString lhs) {
return value!=null&&!value.isstring()? setvalue(lhs.concat(value)): prepend(lhs);
return value != null && !value.isstring()? setvalue(lhs.concat(value)): prepend(lhs);
}
/** Concatenate this buffer onto a {@link LuaNumber}
/**
* Concatenate this buffer onto a {@link LuaNumber}
* <p>
* The {@link LuaNumber} will be converted to a string before concatenating.
* @param lhs the left-hand-side value onto which we are concatenating {@code this}
*
* @param lhs the left-hand-side value onto which we are concatenating
* {@code this}
* @return {@link Buffer} for use in call chaining.
*/
public Buffer concatTo(LuaNumber lhs) {
return value!=null&&!value.isstring()? setvalue(lhs.concat(value)): prepend(lhs.strvalue());
return value != null && !value.isstring()? setvalue(lhs.concat(value)): prepend(lhs.strvalue());
}
/** Concatenate bytes from a {@link LuaString} onto the front of this buffer
* @param s the left-hand-side value which we will concatenate onto the front of {@code this}
/**
* Concatenate bytes from a {@link LuaString} onto the front of this buffer
*
* @param s the left-hand-side value which we will concatenate onto the
* front of {@code this}
* @return {@link Buffer} for use in call chaining.
*/
public Buffer prepend(LuaString s) {
int n = s.m_length;
makeroom( n, 0 );
System.arraycopy( s.m_bytes, s.m_offset, bytes, offset-n, n );
makeroom(n, 0);
System.arraycopy(s.m_bytes, s.m_offset, bytes, offset-n, n);
offset -= n;
length += n;
value = null;
return this;
}
/** Ensure there is enough room before and after the bytes.
* @param nbefore number of unused bytes which must precede the data after this completes
* @param nafter number of unused bytes which must follow the data after this completes
/**
* Ensure there is enough room before and after the bytes.
*
* @param nbefore number of unused bytes which must precede the data after
* this completes
* @param nafter number of unused bytes which must follow the data after
* this completes
*/
public final void makeroom( int nbefore, int nafter ) {
if ( value != null ) {
public final void makeroom(int nbefore, int nafter) {
if (value != null) {
LuaString s = value.strvalue();
value = null;
length = s.m_length;
offset = nbefore;
bytes = new byte[nbefore+length+nafter];
System.arraycopy(s.m_bytes, s.m_offset, bytes, offset, length);
} else if ( offset+length+nafter > bytes.length || offset<nbefore ) {
} else if (offset+length+nafter > bytes.length || offset < nbefore) {
int n = nbefore+length+nafter;
int m = n<32? 32: n<length*2? length*2: n;
realloc( m, nbefore==0? 0: m-length-nafter );
int m = n < 32? 32: n < length*2? length*2: n;
realloc(m, nbefore == 0? 0: m-length-nafter);
}
}
/** Reallocate the internal storage for the buffer
/**
* Reallocate the internal storage for the buffer
*
* @param newSize the size of the buffer to use
* @param newOffset the offset to use
*/
private final void realloc( int newSize, int newOffset ) {
if ( newSize != bytes.length ) {
byte[] newBytes = new byte[ newSize ];
System.arraycopy( bytes, offset, newBytes, newOffset, length );
private final void realloc(int newSize, int newOffset) {
if (newSize != bytes.length) {
byte[] newBytes = new byte[newSize];
System.arraycopy(bytes, offset, newBytes, newOffset, length);
bytes = newBytes;
offset = newOffset;
}

View File

@@ -33,73 +33,94 @@ import org.luaj.vm2.lib.PackageLib;
import org.luaj.vm2.lib.ResourceFinder;
/**
* Global environment used by luaj. Contains global variables referenced by executing lua.
* Global environment used by luaj. Contains global variables referenced by
* executing lua.
* <p>
*
* <h3>Constructing and Initializing Instances</h3>
* Typically, this is constructed indirectly by a call to
* <h3>Constructing and Initializing Instances</h3> Typically, this is
* constructed indirectly by a call to
* {@link org.luaj.vm2.lib.jse.JsePlatform#standardGlobals()} or
* {@link org.luaj.vm2.lib.jme.JmePlatform#standardGlobals()},
* and then used to load lua scripts for execution as in the following example.
* <pre> {@code
* {@link org.luaj.vm2.lib.jme.JmePlatform#standardGlobals()}, and then used to
* load lua scripts for execution as in the following example.
*
* <pre>
* {
* &#64;code
* Globals globals = JsePlatform.standardGlobals();
* globals.load( new StringReader("print 'hello'"), "main.lua" ).call();
* } </pre>
* globals.load(new StringReader("print 'hello'"), "main.lua").call();
* }
* </pre>
*
* The creates a complete global environment with the standard libraries loaded.
* <p>
* For specialized circumstances, the Globals may be constructed directly and loaded
* with only those libraries that are needed, for example.
* <pre> {@code
* For specialized circumstances, the Globals may be constructed directly and
* loaded with only those libraries that are needed, for example.
*
* <pre>
* {
* &#64;code
* Globals globals = new Globals();
* globals.load( new BaseLib() );
* } </pre>
* globals.load(new BaseLib());
* }
* </pre>
*
* <h3>Loading and Executing Lua Code</h3>
* Globals contains convenience functions to load and execute lua source code given a Reader.
* A simple example is:
* <pre> {@code
* <h3>Loading and Executing Lua Code</h3> Globals contains convenience
* functions to load and execute lua source code given a Reader. A simple
* example is:
*
* <pre>
* {@code
* globals.load( new StringReader("print 'hello'"), "main.lua" ).call();
* } </pre>
* }
* </pre>
*
* <h3>Fine-Grained Control of Compiling and Loading Lua</h3>
* Executable LuaFunctions are created from lua code in several steps
* <h3>Fine-Grained Control of Compiling and Loading Lua</h3> Executable
* LuaFunctions are created from lua code in several steps
* <ul>
* <li>find the resource using the platform's {@link ResourceFinder}
* <li>compile lua to lua bytecode using {@link Compiler}
* <li>load lua bytecode to a {@link Prototype} using {@link Undumper}
* <li>construct {@link LuaClosure} from {@link Prototype} with {@link Globals} using {@link Loader}
* <li>construct {@link LuaClosure} from {@link Prototype} with {@link Globals}
* using {@link Loader}
* </ul>
* <p>
* There are alternate flows when the direct lua-to-Java bytecode compiling {@link org.luaj.vm2.luajc.LuaJC} is used.
* There are alternate flows when the direct lua-to-Java bytecode compiling
* {@link org.luaj.vm2.luajc.LuaJC} is used.
* <ul>
* <li>compile lua to lua bytecode using {@link Compiler} or load precompiled code using {@link Undumper}
* <li>convert lua bytecode to equivalent Java bytecode using {@link org.luaj.vm2.luajc.LuaJC} that implements {@link Loader} directly
* <li>compile lua to lua bytecode using {@link Compiler} or load precompiled
* code using {@link Undumper}
* <li>convert lua bytecode to equivalent Java bytecode using
* {@link org.luaj.vm2.luajc.LuaJC} that implements {@link Loader} directly
* </ul>
*
* <h3>Java Field</h3>
* Certain public fields are provided that contain the current values of important global state:
* <h3>Java Field</h3> Certain public fields are provided that contain the
* current values of important global state:
* <ul>
* <li>{@link #STDIN} Current value for standard input in the laaded {@link IoLib}, if any.
* <li>{@link #STDOUT} Current value for standard output in the loaded {@link IoLib}, if any.
* <li>{@link #STDERR} Current value for standard error in the loaded {@link IoLib}, if any.
* <li>{@link #STDIN} Current value for standard input in the laaded
* {@link IoLib}, if any.
* <li>{@link #STDOUT} Current value for standard output in the loaded
* {@link IoLib}, if any.
* <li>{@link #STDERR} Current value for standard error in the loaded
* {@link IoLib}, if any.
* <li>{@link #finder} Current loaded {@link ResourceFinder}, if any.
* <li>{@link #compiler} Current loaded {@link Compiler}, if any.
* <li>{@link #undumper} Current loaded {@link Undumper}, if any.
* <li>{@link #loader} Current loaded {@link Loader}, if any.
* </ul>
*
* <h3>Lua Environment Variables</h3>
* When using {@link org.luaj.vm2.lib.jse.JsePlatform} or {@link org.luaj.vm2.lib.jme.JmePlatform},
* these environment variables are created within the Globals.
* <h3>Lua Environment Variables</h3> When using
* {@link org.luaj.vm2.lib.jse.JsePlatform} or
* {@link org.luaj.vm2.lib.jme.JmePlatform}, these environment variables are
* created within the Globals.
* <ul>
* <li>"_G" Pointer to this Globals.
* <li>"_VERSION" String containing the version of luaj.
* </ul>
*
* <h3>Use in Multithreaded Environments</h3>
* In a multi-threaded server environment, each server thread should create one Globals instance,
* which will be logically distinct and not interfere with each other, but share certain
* static immutable resources such as class data and string data.
* <h3>Use in Multithreaded Environments</h3> In a multi-threaded server
* environment, each server thread should create one Globals instance, which
* will be logically distinct and not interfere with each other, but share
* certain static immutable resources such as class data and string data.
* <p>
*
* @see org.luaj.vm2.lib.jse.JsePlatform
@@ -126,7 +147,9 @@ public class Globals extends LuaTable {
/** The installed ResourceFinder for looking files by name. */
public ResourceFinder finder;
/** The currently running thread. Should not be changed by non-library code. */
/**
* The currently running thread. Should not be changed by non-library code.
*/
public LuaThread running = new LuaThread(this);
/** The BaseLib instance loaded into this Globals */
@@ -135,18 +158,30 @@ public class Globals extends LuaTable {
/** The PackageLib instance loaded into this Globals */
public PackageLib package_;
/** The DebugLib instance loaded into this Globals, or null if debugging is not enabled */
/**
* The DebugLib instance loaded into this Globals, or null if debugging is
* not enabled
*/
public DebugLib debuglib;
/** Interface for module that converts a Prototype into a LuaFunction with an environment. */
/**
* Interface for module that converts a Prototype into a LuaFunction with an
* environment.
*/
public interface Loader {
/** Convert the prototype into a LuaFunction with the supplied environment. */
/**
* Convert the prototype into a LuaFunction with the supplied
* environment.
*/
LuaFunction load(Prototype prototype, String chunkname, LuaValue env) throws IOException;
}
/** Interface for module that converts lua source text into a prototype. */
public interface Compiler {
/** Compile lua source into a Prototype. The InputStream is assumed to be in UTF-8. */
/**
* Compile lua source into a Prototype. The InputStream is assumed to be
* in UTF-8.
*/
Prototype compile(InputStream stream, String chunkname) throws IOException;
}
@@ -156,99 +191,141 @@ public class Globals extends LuaTable {
Prototype undump(InputStream stream, String chunkname) throws IOException;
}
/** Check that this object is a Globals object, and return it, otherwise throw an error. */
/**
* Check that this object is a Globals object, and return it, otherwise
* throw an error.
*/
public Globals checkglobals() {
return this;
}
/** The installed loader.
* @see Loader */
/**
* The installed loader.
*
* @see Loader
*/
public Loader loader;
/** The installed compiler.
* @see Compiler */
/**
* The installed compiler.
*
* @see Compiler
*/
public Compiler compiler;
/** The installed undumper.
* @see Undumper */
/**
* The installed undumper.
*
* @see Undumper
*/
public Undumper undumper;
/** Convenience function for loading a file that is either binary lua or lua source.
/**
* Convenience function for loading a file that is either binary lua or lua
* source.
*
* @param filename Name of the file to load.
* @return LuaValue that can be call()'ed or invoke()'ed.
* @throws LuaError if the file could not be loaded.
*/
public LuaValue loadfile(String filename) {
try {
return load(finder.findResource(filename), "@"+filename, "bt", this);
return load(finder.findResource(filename), "@" + filename, "bt", this);
} catch (Exception e) {
return error("load "+filename+": "+e);
return error("load " + filename + ": " + e);
}
}
/** Convenience function to load a string value as a script. Must be lua source.
* @param script Contents of a lua script, such as "print 'hello, world.'"
/**
* Convenience function to load a string value as a script. Must be lua
* source.
*
* @param script Contents of a lua script, such as "print 'hello,
* world.'"
* @param chunkname Name that will be used within the chunk as the source.
* @return LuaValue that may be executed via .call(), .invoke(), or .method() calls.
* @return LuaValue that may be executed via .call(), .invoke(), or
* .method() calls.
* @throws LuaError if the script could not be compiled.
*/
public LuaValue load(String script, String chunkname) {
return load(new StrReader(script), chunkname);
}
/** Convenience function to load a string value as a script. Must be lua source.
/**
* Convenience function to load a string value as a script. Must be lua
* source.
*
* @param script Contents of a lua script, such as "print 'hello, world.'"
* @return LuaValue that may be executed via .call(), .invoke(), or .method() calls.
* @return LuaValue that may be executed via .call(), .invoke(), or
* .method() calls.
* @throws LuaError if the script could not be compiled.
*/
public LuaValue load(String script) {
return load(new StrReader(script), script);
}
/** Convenience function to load a string value as a script with a custom environment.
* Must be lua source.
* @param script Contents of a lua script, such as "print 'hello, world.'"
/**
* Convenience function to load a string value as a script with a custom
* environment. Must be lua source.
*
* @param script Contents of a lua script, such as "print 'hello,
* world.'"
* @param chunkname Name that will be used within the chunk as the source.
* @param environment LuaTable to be used as the environment for the loaded function.
* @return LuaValue that may be executed via .call(), .invoke(), or .method() calls.
* @param environment LuaTable to be used as the environment for the loaded
* function.
* @return LuaValue that may be executed via .call(), .invoke(), or
* .method() calls.
* @throws LuaError if the script could not be compiled.
*/
public LuaValue load(String script, String chunkname, LuaTable environment) {
return load(new StrReader(script), chunkname, environment);
}
/** Load the content form a reader as a text file. Must be lua source.
* The source is converted to UTF-8, so any characters appearing in quoted literals
* above the range 128 will be converted into multiple bytes.
* @param reader Reader containing text of a lua script, such as "print 'hello, world.'"
/**
* Load the content form a reader as a text file. Must be lua source. The
* source is converted to UTF-8, so any characters appearing in quoted
* literals above the range 128 will be converted into multiple bytes.
*
* @param reader Reader containing text of a lua script, such as "print
* 'hello, world.'"
* @param chunkname Name that will be used within the chunk as the source.
* @return LuaValue that may be executed via .call(), .invoke(), or .method() calls.
* @return LuaValue that may be executed via .call(), .invoke(), or
* .method() calls.
* @throws LuaError if the script could not be compiled.
*/
public LuaValue load(Reader reader, String chunkname) {
return load(new UTF8Stream(reader), chunkname, "t", this);
}
/** Load the content form a reader as a text file, supplying a custom environment.
* Must be lua source. The source is converted to UTF-8, so any characters
* appearing in quoted literals above the range 128 will be converted into
* multiple bytes.
* @param reader Reader containing text of a lua script, such as "print 'hello, world.'"
/**
* Load the content form a reader as a text file, supplying a custom
* environment. Must be lua source. The source is converted to UTF-8, so any
* characters appearing in quoted literals above the range 128 will be
* converted into multiple bytes.
*
* @param reader Reader containing text of a lua script, such as "print
* 'hello, world.'"
* @param chunkname Name that will be used within the chunk as the source.
* @param environment LuaTable to be used as the environment for the loaded function.
* @return LuaValue that may be executed via .call(), .invoke(), or .method() calls.
* @param environment LuaTable to be used as the environment for the loaded
* function.
* @return LuaValue that may be executed via .call(), .invoke(), or
* .method() calls.
* @throws LuaError if the script could not be compiled.
*/
public LuaValue load(Reader reader, String chunkname, LuaTable environment) {
return load(new UTF8Stream(reader), chunkname, "t", environment);
}
/** Load the content form an input stream as a binary chunk or text file.
/**
* Load the content form an input stream as a binary chunk or text file.
*
* @param is InputStream containing a lua script or compiled lua"
* @param chunkname Name that will be used within the chunk as the source.
* @param mode String containing 'b' or 't' or both to control loading as binary or text or either.
* @param environment LuaTable to be used as the environment for the loaded function.
* */
* @param mode String containing 'b' or 't' or both to control
* loading as binary or text or either.
* @param environment LuaTable to be used as the environment for the loaded
* function.
*/
public LuaValue load(InputStream is, String chunkname, String mode, LuaValue environment) {
try {
Prototype p = loadPrototype(is, chunkname, mode);
@@ -256,16 +333,20 @@ public class Globals extends LuaTable {
} catch (LuaError l) {
throw l;
} catch (Exception e) {
return error("load "+chunkname+": "+e);
return error("load " + chunkname + ": " + e);
}
}
/** Load lua source or lua binary from an input stream into a Prototype.
* The InputStream is either a binary lua chunk starting with the lua binary chunk signature,
* or a text input file. If it is a text input file, it is interpreted as a UTF-8 byte sequence.
/**
* Load lua source or lua binary from an input stream into a Prototype. The
* InputStream is either a binary lua chunk starting with the lua binary
* chunk signature, or a text input file. If it is a text input file, it is
* interpreted as a UTF-8 byte sequence.
*
* @param is Input stream containing a lua script or compiled lua"
* @param chunkname Name that will be used within the chunk as the source.
* @param mode String containing 'b' or 't' or both to control loading as binary or text or either.
* @param mode String containing 'b' or 't' or both to control loading
* as binary or text or either.
*/
public Prototype loadPrototype(InputStream is, String chunkname, String mode) throws IOException {
if (mode.indexOf('b') >= 0) {
@@ -282,21 +363,25 @@ public class Globals extends LuaTable {
if (mode.indexOf('t') >= 0) {
return compilePrototype(is, chunkname);
}
error("Failed to load prototype "+chunkname+" using mode '"+mode+"'");
error("Failed to load prototype " + chunkname + " using mode '" + mode + "'");
return null;
}
/** Compile lua source from a Reader into a Prototype. The characters in the reader
* are converted to bytes using the UTF-8 encoding, so a string literal containing
* characters with codepoints 128 or above will be converted into multiple bytes.
/**
* Compile lua source from a Reader into a Prototype. The characters in the
* reader are converted to bytes using the UTF-8 encoding, so a string
* literal containing characters with codepoints 128 or above will be
* converted into multiple bytes.
*/
public Prototype compilePrototype(Reader reader, String chunkname) throws IOException {
return compilePrototype(new UTF8Stream(reader), chunkname);
}
/** Compile lua source from an InputStream into a Prototype.
* The input is assumed to be UTf-8, but since bytes in the range 128-255 are passed along as
* literal bytes, any ASCII-compatible encoding such as ISO 8859-1 may also be used.
/**
* Compile lua source from an InputStream into a Prototype. The input is
* assumed to be UTf-8, but since bytes in the range 128-255 are passed
* along as literal bytes, any ASCII-compatible encoding such as ISO 8859-1
* may also be used.
*/
public Prototype compilePrototype(InputStream stream, String chunkname) throws IOException {
if (compiler == null)
@@ -304,9 +389,13 @@ public class Globals extends LuaTable {
return compiler.compile(stream, chunkname);
}
/** Function which yields the current thread.
* @param args Arguments to supply as return values in the resume function of the resuming thread.
* @return Values supplied as arguments to the resume() call that reactivates this thread.
/**
* Function which yields the current thread.
*
* @param args Arguments to supply as return values in the resume function
* of the resuming thread.
* @return Values supplied as arguments to the resume() call that
* reactivates this thread.
*/
public Varargs yield(Varargs args) {
if (running == null || running.isMainThread())
@@ -320,21 +409,25 @@ public class Globals extends LuaTable {
final String s;
int i = 0;
final int n;
StrReader(String s) {
this.s = s;
n = s.length();
}
public void close() throws IOException {
i = n;
}
public int read() throws IOException {
return i < n ? s.charAt(i++) : -1;
return i < n? s.charAt(i++): -1;
}
public int read(char[] cbuf, int off, int len) throws IOException {
int j = 0;
for (; j < len && i < n; ++j, ++i)
cbuf[off+j] = s.charAt(i);
return j > 0 || len == 0 ? j : -1;
return j > 0 || len == 0? j: -1;
}
}
@@ -344,48 +437,60 @@ public class Globals extends LuaTable {
abstract static class AbstractBufferedStream extends InputStream {
protected byte[] b;
protected int i = 0, j = 0;
protected AbstractBufferedStream(int buflen) {
this.b = new byte[buflen];
}
abstract protected int avail() throws IOException;
public int read() throws IOException {
int a = avail();
return (a <= 0 ? -1 : 0xff & b[i++]);
return (a <= 0? -1: 0xff & b[i++]);
}
public int read(byte[] b) throws IOException {
return read(b, 0, b.length);
}
public int read(byte[] b, int i0, int n) throws IOException {
int a = avail();
if (a <= 0) return -1;
if (a <= 0)
return -1;
final int n_read = Math.min(a, n);
System.arraycopy(this.b, i, b, i0, n_read);
i += n_read;
return n_read;
}
public long skip(long n) throws IOException {
final long k = Math.min(n, j - i);
final long k = Math.min(n, j-i);
i += k;
return k;
}
public int available() throws IOException {
return j - i;
return j-i;
}
}
/** Simple converter from Reader to InputStream using UTF8 encoding that will work
* on both JME and JSE.
* This class may be moved to its own package in the future.
/**
* Simple converter from Reader to InputStream using UTF8 encoding that will
* work on both JME and JSE. This class may be moved to its own package in
* the future.
*/
static class UTF8Stream extends AbstractBufferedStream {
private final char[] c = new char[32];
private final Reader r;
UTF8Stream(Reader r) {
super(96);
this.r = r;
}
protected int avail() throws IOException {
if (i < j) return j - i;
if (i < j)
return j-i;
int n = r.read(c);
if (n < 0)
return -1;
@@ -399,31 +504,38 @@ public class Globals extends LuaTable {
j = LuaString.encodeToUtf8(c, n, b, i = 0);
return j;
}
public void close() throws IOException {
r.close();
}
}
/** Simple buffered InputStream that supports mark.
* Used to examine an InputStream for a 4-byte binary lua signature,
* and fall back to text input when the signature is not found,
* as well as speed up normal compilation and reading of lua scripts.
* This class may be moved to its own package in the future.
/**
* Simple buffered InputStream that supports mark. Used to examine an
* InputStream for a 4-byte binary lua signature, and fall back to text
* input when the signature is not found, as well as speed up normal
* compilation and reading of lua scripts. This class may be moved to its
* own package in the future.
*/
static class BufferedStream extends AbstractBufferedStream {
private final InputStream s;
public BufferedStream(InputStream s) {
this(128, s);
}
BufferedStream(int buflen, InputStream s) {
super(buflen);
this.s = s;
}
protected int avail() throws IOException {
if (i < j) return j - i;
if (j >= b.length) i = j = 0;
if (i < j)
return j-i;
if (j >= b.length)
i = j = 0;
// leave previous bytes in place to implement mark()/reset().
int n = s.read(b, j, b.length - j);
int n = s.read(b, j, b.length-j);
if (n < 0)
return -1;
if (n == 0) {
@@ -436,21 +548,25 @@ public class Globals extends LuaTable {
j += n;
return n;
}
public void close() throws IOException {
s.close();
}
public synchronized void mark(int n) {
if (i > 0 || n > b.length) {
byte[] dest = n > b.length ? new byte[n] : b;
System.arraycopy(b, i, dest, 0, j - i);
byte[] dest = n > b.length? new byte[n]: b;
System.arraycopy(b, i, dest, 0, j-i);
j -= i;
i = 0;
b = dest;
}
}
public boolean markSupported() {
return true;
}
public synchronized void reset() throws IOException {
i = 0;
}

View File

@@ -25,78 +25,102 @@ import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStream;
/**
* Class to undump compiled lua bytecode into a {@link Prototype} instances.
* <p>
* The {@link LoadState} class provides the default {@link Globals.Undumper}
* which is used to undump a string of bytes that represent a lua binary file
* using either the C-based lua compiler, or luaj's
* {@link org.luaj.vm2.compiler.LuaC} compiler.
* <p>
* The canonical method to load and execute code is done
* indirectly using the Globals:
* <pre> {@code
* Globals globals = JsePlatform.standardGlobals();
* LuaValue chunk = globasl.load("print('hello, world')", "main.lua");
* chunk.call();
* } </pre>
* This should work regardless of which {@link Globals.Compiler} or {@link Globals.Undumper}
* have been installed.
* <p>
* By default, when using {@link org.luaj.vm2.lib.jse.JsePlatform} or
* {@link org.luaj.vm2.lib.jme.JmePlatform}
* to construct globals, the {@link LoadState} default undumper is installed
* as the default {@link Globals.Undumper}.
* <p>
*
* A lua binary file is created via the {@link org.luaj.vm2.compiler.DumpState} class
:
* <pre> {@code
* Globals globals = JsePlatform.standardGlobals();
* Prototype p = globals.compilePrototype(new StringReader("print('hello, world')"), "main.lua");
* ByteArrayOutputStream o = new ByteArrayOutputStream();
* org.luaj.vm2.compiler.DumpState.dump(p, o, false);
* byte[] lua_binary_file_bytes = o.toByteArray();
* } </pre>
*
* The {@link LoadState}'s default undumper {@link #instance}
* may be used directly to undump these bytes:
* <pre> {@code
* Class to undump compiled lua bytecode into a {@link Prototype} instances.
* <p>
* The {@link LoadState} class provides the default {@link Globals.Undumper}
* which is used to undump a string of bytes that represent a lua binary file
* using either the C-based lua compiler, or luaj's
* {@link org.luaj.vm2.compiler.LuaC} compiler.
* <p>
* The canonical method to load and execute code is done indirectly using the
* Globals:
*
* <pre>
* {
* &#64;code
* Globals globals = JsePlatform.standardGlobals();
* LuaValue chunk = globasl.load("print('hello, world')", "main.lua");
* chunk.call();
* }
* </pre>
*
* This should work regardless of which {@link Globals.Compiler} or
* {@link Globals.Undumper} have been installed.
* <p>
* By default, when using {@link org.luaj.vm2.lib.jse.JsePlatform} or
* {@link org.luaj.vm2.lib.jme.JmePlatform} to construct globals, the
* {@link LoadState} default undumper is installed as the default
* {@link Globals.Undumper}.
* <p>
*
* A lua binary file is created via the {@link org.luaj.vm2.compiler.DumpState}
* class :
*
* <pre>
* {
* &#64;code
* Globals globals = JsePlatform.standardGlobals();
* Prototype p = globals.compilePrototype(new StringReader("print('hello, world')"), "main.lua");
* ByteArrayOutputStream o = new ByteArrayOutputStream();
* org.luaj.vm2.compiler.DumpState.dump(p, o, false);
* byte[] lua_binary_file_bytes = o.toByteArray();
* }
* </pre>
*
* The {@link LoadState}'s default undumper {@link #instance} may be used
* directly to undump these bytes:
*
* <pre>
* {@code
* Prototypep = LoadState.instance.undump(new ByteArrayInputStream(lua_binary_file_bytes), "main.lua");
* LuaClosure c = new LuaClosure(p, globals);
* c.call();
* } </pre>
*
*
* More commonly, the {@link Globals.Undumper} may be used to undump them:
* <pre> {@code
* Prototype p = globals.loadPrototype(new ByteArrayInputStream(lua_binary_file_bytes), "main.lua", "b");
* LuaClosure c = new LuaClosure(p, globals);
* c.call();
* } </pre>
*
* @see Globals.Compiler
* @see Globals.Undumper
* @see LuaClosure
* @see LuaFunction
* @see org.luaj.vm2.compiler.LuaC
* @see org.luaj.vm2.luajc.LuaJC
* @see Globals#compiler
* @see Globals#load(InputStream, String, LuaValue)
*/
* }
* </pre>
*
*
* More commonly, the {@link Globals.Undumper} may be used to undump them:
*
* <pre>
* {
* &#64;code
* Prototype p = globals.loadPrototype(new ByteArrayInputStream(lua_binary_file_bytes), "main.lua", "b");
* LuaClosure c = new LuaClosure(p, globals);
* c.call();
* }
* </pre>
*
* @see Globals.Compiler
* @see Globals.Undumper
* @see LuaClosure
* @see LuaFunction
* @see org.luaj.vm2.compiler.LuaC
* @see org.luaj.vm2.luajc.LuaJC
* @see Globals#compiler
* @see Globals#load(InputStream, String, LuaValue)
*/
public class LoadState {
/** Shared instance of Globals.Undumper to use loading prototypes from binary lua files */
/**
* Shared instance of Globals.Undumper to use loading prototypes from binary
* lua files
*/
public static final Globals.Undumper instance = new GlobalsUndumper();
/** format corresponding to non-number-patched lua, all numbers are floats or doubles */
/**
* format corresponding to non-number-patched lua, all numbers are floats or
* doubles
*/
public static final int NUMBER_FORMAT_FLOATS_OR_DOUBLES = 0;
/** format corresponding to non-number-patched lua, all numbers are ints */
public static final int NUMBER_FORMAT_INTS_ONLY = 1;
/** format corresponding to number-patched lua, all numbers are 32-bit (4 byte) ints */
/**
* format corresponding to number-patched lua, all numbers are 32-bit (4
* byte) ints
*/
public static final int NUMBER_FORMAT_NUM_PATCH_INT32 = 4;
// type constants
@@ -113,7 +137,10 @@ public class LoadState {
public static final int LUA_TTHREAD = 8;
public static final int LUA_TVALUE = 9;
/** The character encoding to use for file encoding. Null means the default encoding */
/**
* The character encoding to use for file encoding. Null means the default
* encoding
*/
public static String encoding = null;
/** Signature byte indicating the file is a compiled binary chunk */
@@ -122,11 +149,9 @@ public class LoadState {
/** Data to catch conversion errors */
public static final byte[] LUAC_TAIL = { (byte) 0x19, (byte) 0x93, '\r', '\n', (byte) 0x1a, '\n', };
/** Name for compiled chunks */
public static final String SOURCE_BINARY_STRING = "binary string";
/** for header of binary files -- this is Lua 5.2 */
public static final int LUAC_VERSION = 0x52;
@@ -161,118 +186,132 @@ public class LoadState {
/** Read buffer */
private byte[] buf = new byte[512];
/** Install this class as the standard Globals.Undumper for the supplied Globals */
/**
* Install this class as the standard Globals.Undumper for the supplied
* Globals
*/
public static void install(Globals globals) {
globals.undumper = instance;
}
/** Load a 4-byte int value from the input stream
/**
* Load a 4-byte int value from the input stream
*
* @return the int value laoded.
**/
int loadInt() throws IOException {
is.readFully(buf,0,4);
return luacLittleEndian?
(buf[3] << 24) | ((0xff & buf[2]) << 16) | ((0xff & buf[1]) << 8) | (0xff & buf[0]):
(buf[0] << 24) | ((0xff & buf[1]) << 16) | ((0xff & buf[2]) << 8) | (0xff & buf[3]);
is.readFully(buf, 0, 4);
return luacLittleEndian? (buf[3]<<24) | ((0xff & buf[2])<<16) | ((0xff & buf[1])<<8) | (0xff & buf[0])
: (buf[0]<<24) | ((0xff & buf[1])<<16) | ((0xff & buf[2])<<8) | (0xff & buf[3]);
}
/** Load an array of int values from the input stream
/**
* Load an array of int values from the input stream
*
* @return the array of int values laoded.
**/
int[] loadIntArray() throws IOException {
int n = loadInt();
if ( n == 0 )
if (n == 0)
return NOINTS;
// read all data at once
int m = n << 2;
if ( buf.length < m )
int m = n<<2;
if (buf.length < m)
buf = new byte[m];
is.readFully(buf,0,m);
is.readFully(buf, 0, m);
int[] array = new int[n];
for ( int i=0, j=0; i<n; ++i, j+=4 )
array[i] = luacLittleEndian?
(buf[j+3] << 24) | ((0xff & buf[j+2]) << 16) | ((0xff & buf[j+1]) << 8) | (0xff & buf[j+0]):
(buf[j+0] << 24) | ((0xff & buf[j+1]) << 16) | ((0xff & buf[j+2]) << 8) | (0xff & buf[j+3]);
for (int i = 0, j = 0; i < n; ++i, j += 4)
array[i] = luacLittleEndian
? (buf[j+3]<<24) | ((0xff & buf[j+2])<<16) | ((0xff & buf[j+1])<<8) | (0xff & buf[j+0])
: (buf[j+0]<<24) | ((0xff & buf[j+1])<<16) | ((0xff & buf[j+2])<<8) | (0xff & buf[j+3]);
return array;
}
/** Load a long value from the input stream
/**
* Load a long value from the input stream
*
* @return the long value laoded.
**/
long loadInt64() throws IOException {
int a,b;
if ( this.luacLittleEndian ) {
int a, b;
if (this.luacLittleEndian) {
a = loadInt();
b = loadInt();
} else {
b = loadInt();
a = loadInt();
}
return (((long)b)<<32) | (((long)a)&0xffffffffL);
return (((long) b)<<32) | (((long) a) & 0xffffffffL);
}
/** Load a lua strin gvalue from the input stream
/**
* Load a lua strin gvalue from the input stream
*
* @return the {@link LuaString} value laoded.
**/
LuaString loadString() throws IOException {
int size = this.luacSizeofSizeT == 8? (int) loadInt64(): loadInt();
if ( size == 0 )
if (size == 0)
return null;
byte[] bytes = new byte[size];
is.readFully( bytes, 0, size );
return LuaString.valueUsing( bytes, 0, bytes.length - 1 );
is.readFully(bytes, 0, size);
return LuaString.valueUsing(bytes, 0, bytes.length-1);
}
/**
* Convert bits in a long value to a {@link LuaValue}.
*
* @param bits long value containing the bits
* @return {@link LuaInteger} or {@link LuaDouble} whose value corresponds to the bits provided.
* @return {@link LuaInteger} or {@link LuaDouble} whose value corresponds
* to the bits provided.
*/
public static LuaValue longBitsToLuaNumber( long bits ) {
if ( ( bits & ( ( 1L << 63 ) - 1 ) ) == 0L ) {
public static LuaValue longBitsToLuaNumber(long bits) {
if ((bits & ((1L<<63)-1)) == 0L) {
return LuaValue.ZERO;
}
int e = (int)((bits >> 52) & 0x7ffL) - 1023;
int e = (int) ((bits>>52) & 0x7ffL)-1023;
if ( e >= 0 && e < 31 ) {
if (e >= 0 && e < 31) {
long f = bits & 0xFFFFFFFFFFFFFL;
int shift = 52 - e;
long intPrecMask = ( 1L << shift ) - 1;
if ( ( f & intPrecMask ) == 0 ) {
int intValue = (int)( f >> shift ) | ( 1 << e );
return LuaInteger.valueOf( ( ( bits >> 63 ) != 0 ) ? -intValue : intValue );
int shift = 52-e;
long intPrecMask = (1L<<shift)-1;
if ((f & intPrecMask) == 0) {
int intValue = (int) (f>>shift) | (1<<e);
return LuaInteger.valueOf(((bits>>63) != 0)? -intValue: intValue);
}
}
return LuaValue.valueOf( Double.longBitsToDouble(bits) );
return LuaValue.valueOf(Double.longBitsToDouble(bits));
}
/**
* Load a number from a binary chunk
*
* @return the {@link LuaValue} loaded
* @throws IOException if an i/o exception occurs
*/
LuaValue loadNumber() throws IOException {
if ( luacNumberFormat == NUMBER_FORMAT_INTS_ONLY ) {
return LuaInteger.valueOf( loadInt() );
if (luacNumberFormat == NUMBER_FORMAT_INTS_ONLY) {
return LuaInteger.valueOf(loadInt());
} else {
return longBitsToLuaNumber( loadInt64() );
return longBitsToLuaNumber(loadInt64());
}
}
/**
* Load a list of constants from a binary chunk
*
* @param f the function prototype
* @throws IOException if an i/o exception occurs
*/
void loadConstants(Prototype f) throws IOException {
int n = loadInt();
LuaValue[] values = n>0? new LuaValue[n]: NOVALUES;
for ( int i=0; i<n; i++ ) {
switch ( is.readByte() ) {
LuaValue[] values = n > 0? new LuaValue[n]: NOVALUES;
for (int i = 0; i < n; i++) {
switch (is.readByte()) {
case LUA_TNIL:
values[i] = LuaValue.NIL;
break;
@@ -280,7 +319,7 @@ public class LoadState {
values[i] = (0 != is.readUnsignedByte()? LuaValue.TRUE: LuaValue.FALSE);
break;
case LUA_TINT:
values[i] = LuaInteger.valueOf( loadInt() );
values[i] = LuaInteger.valueOf(loadInt());
break;
case LUA_TNUMBER:
values[i] = loadNumber();
@@ -295,17 +334,16 @@ public class LoadState {
f.k = values;
n = loadInt();
Prototype[] protos = n>0? new Prototype[n]: NOPROTOS;
for ( int i=0; i<n; i++ )
Prototype[] protos = n > 0? new Prototype[n]: NOPROTOS;
for (int i = 0; i < n; i++)
protos[i] = loadFunction(f.source);
f.p = protos;
}
void loadUpvalues(Prototype f) throws IOException {
int n = loadInt();
f.upvalues = n>0? new Upvaldesc[n]: NOUPVALDESCS;
for (int i=0; i<n; i++) {
f.upvalues = n > 0? new Upvaldesc[n]: NOUPVALDESCS;
for (int i = 0; i < n; i++) {
boolean instack = is.readByte() != 0;
int idx = ((int) is.readByte()) & 0xff;
f.upvalues[i] = new Upvaldesc(null, instack, idx);
@@ -314,15 +352,16 @@ public class LoadState {
/**
* Load the debug info for a function prototype
*
* @param f the function Prototype
* @throws IOException if there is an i/o exception
*/
void loadDebug( Prototype f ) throws IOException {
void loadDebug(Prototype f) throws IOException {
f.source = loadString();
f.lineinfo = loadIntArray();
int n = loadInt();
f.locvars = n>0? new LocVars[n]: NOLOCVARS;
for ( int i=0; i<n; i++ ) {
f.locvars = n > 0? new LocVars[n]: NOLOCVARS;
for (int i = 0; i < n; i++) {
LuaString varname = loadString();
int startpc = loadInt();
int endpc = loadInt();
@@ -330,12 +369,13 @@ public class LoadState {
}
n = loadInt();
for ( int i=0; i<n; i++ )
for (int i = 0; i < n; i++)
f.upvalues[i].name = loadString();
}
/**
* Load a function prototype from the input stream
*
* @param p name of the source
* @return {@link Prototype} instance that was loaded
* @throws IOException
@@ -366,6 +406,7 @@ public class LoadState {
/**
* Load the lua chunk header values.
*
* @throws IOException if an i/o exception occurs.
*/
public void loadHeader() throws IOException {
@@ -377,33 +418,35 @@ public class LoadState {
luacSizeofInstruction = is.readByte();
luacSizeofLuaNumber = is.readByte();
luacNumberFormat = is.readByte();
for (int i=0; i < LUAC_TAIL.length; ++i)
for (int i = 0; i < LUAC_TAIL.length; ++i)
if (is.readByte() != LUAC_TAIL[i])
throw new LuaError("Unexpeted byte in luac tail of header, index="+i);
throw new LuaError("Unexpeted byte in luac tail of header, index=" + i);
}
/**
* Load input stream as a lua binary chunk if the first 4 bytes are the lua binary signature.
* @param stream InputStream to read, after having read the first byte already
* Load input stream as a lua binary chunk if the first 4 bytes are the lua
* binary signature.
*
* @param stream InputStream to read, after having read the first byte
* already
* @param chunkname Name to apply to the loaded chunk
* @return {@link Prototype} that was loaded, or null if the first 4 bytes were not the lua signature.
* @return {@link Prototype} that was loaded, or null if the first 4 bytes
* were not the lua signature.
* @throws IOException if an IOException occurs
*/
public static Prototype undump(InputStream stream, String chunkname) throws IOException {
// check rest of signature
if ( stream.read() != LUA_SIGNATURE[0]
|| stream.read() != LUA_SIGNATURE[1]
|| stream.read() != LUA_SIGNATURE[2]
|| stream.read() != LUA_SIGNATURE[3] )
if (stream.read() != LUA_SIGNATURE[0] || stream.read() != LUA_SIGNATURE[1] || stream.read() != LUA_SIGNATURE[2]
|| stream.read() != LUA_SIGNATURE[3])
return null;
// load file as a compiled chunk
String sname = getSourceName(chunkname);
LoadState s = new LoadState( stream, sname );
LoadState s = new LoadState(stream, sname);
s.loadHeader();
// check format
switch ( s.luacNumberFormat ) {
switch (s.luacNumberFormat) {
case NUMBER_FORMAT_FLOATS_OR_DOUBLES:
case NUMBER_FORMAT_INTS_ONLY:
case NUMBER_FORMAT_NUM_PATCH_INT32:
@@ -411,32 +454,32 @@ public class LoadState {
default:
throw new LuaError("unsupported int size");
}
return s.loadFunction( LuaString.valueOf(sname) );
return s.loadFunction(LuaString.valueOf(sname));
}
/**
* Construct a source name from a supplied chunk name
*
* @param name String name that appears in the chunk
* @return source file name
*/
public static String getSourceName(String name) {
String sname = name;
if ( name.startsWith("@") || name.startsWith("=") )
if (name.startsWith("@") || name.startsWith("="))
sname = name.substring(1);
else if ( name.startsWith("\033") )
else if (name.startsWith("\033"))
sname = SOURCE_BINARY_STRING;
return sname;
}
/** Private constructor for create a load state */
private LoadState( InputStream stream, String name ) {
private LoadState(InputStream stream, String name) {
this.name = name;
this.is = new DataInputStream( stream );
this.is = new DataInputStream(stream);
}
private static final class GlobalsUndumper implements Globals.Undumper {
public Prototype undump(InputStream stream, String chunkname)
throws IOException {
public Prototype undump(InputStream stream, String chunkname) throws IOException {
return LoadState.undump(stream, chunkname);
}
}

View File

@@ -22,7 +22,8 @@
package org.luaj.vm2;
/**
* Data class to hold debug information relating to local variables for a {@link Prototype}
* Data class to hold debug information relating to local variables for a
* {@link Prototype}
*/
public class LocVars {
/** The local variable name */
@@ -36,6 +37,7 @@ public class LocVars {
/**
* Construct a LocVars instance.
*
* @param varname The local variable name
* @param startpc The instruction offset when the variable comes into scope
* @param endpc The instruction offset when the variable goes out of scope
@@ -47,6 +49,6 @@ public class LocVars {
}
public String tojstring() {
return varname+" "+startpc+"-"+endpc;
return varname + " " + startpc + "-" + endpc;
}
}

View File

@@ -21,12 +21,11 @@
******************************************************************************/
package org.luaj.vm2;
/**
* Constants for lua limits and opcodes.
* <p>
* This is a direct translation of C lua distribution header file constants
* for bytecode creation and processing.
* This is a direct translation of C lua distribution header file constants for
* bytecode creation and processing.
*/
public class Lua {
/** version is supplied by ant build task */
@@ -54,29 +53,27 @@ public class Lua {
unsigned argument.
===========================================================================*/
/* basic instruction format */
public static final int iABC = 0;
public static final int iABx = 1;
public static final int iAsBx = 2;
public static final int iAx = 3;
/*
** size and position of opcode arguments.
*/
public static final int SIZE_C = 9;
public static final int SIZE_B = 9;
public static final int SIZE_Bx = (SIZE_C + SIZE_B);
public static final int SIZE_Bx = (SIZE_C+SIZE_B);
public static final int SIZE_A = 8;
public static final int SIZE_Ax = (SIZE_C + SIZE_B + SIZE_A);
public static final int SIZE_Ax = (SIZE_C+SIZE_B+SIZE_A);
public static final int SIZE_OP = 6;
public static final int POS_OP = 0;
public static final int POS_A = (POS_OP + SIZE_OP);
public static final int POS_C = (POS_A + SIZE_A);
public static final int POS_B = (POS_C + SIZE_C);
public static final int POS_A = (POS_OP+SIZE_OP);
public static final int POS_C = (POS_A+SIZE_A);
public static final int POS_B = (POS_C+SIZE_C);
public static final int POS_Bx = POS_C;
public static final int POS_Ax = POS_A;
@@ -105,40 +102,39 @@ public class Lua {
** the following macros help to manipulate instructions
*/
public static int GET_OPCODE(int i) {
return (i >> POS_OP) & MAX_OP;
return (i>>POS_OP) & MAX_OP;
}
public static int GETARG_A(int i) {
return (i >> POS_A) & MAXARG_A;
return (i>>POS_A) & MAXARG_A;
}
public static int GETARG_Ax(int i) {
return (i >> POS_Ax) & MAXARG_Ax;
return (i>>POS_Ax) & MAXARG_Ax;
}
public static int GETARG_B(int i) {
return (i >> POS_B) & MAXARG_B;
return (i>>POS_B) & MAXARG_B;
}
public static int GETARG_C(int i) {
return (i >> POS_C) & MAXARG_C;
return (i>>POS_C) & MAXARG_C;
}
public static int GETARG_Bx(int i) {
return (i >> POS_Bx) & MAXARG_Bx;
return (i>>POS_Bx) & MAXARG_Bx;
}
public static int GETARG_sBx(int i) {
return ((i >> POS_Bx) & MAXARG_Bx) - MAXARG_sBx;
return ((i>>POS_Bx) & MAXARG_Bx)-MAXARG_sBx;
}
/*
** Macros to operate RK indices
*/
/** this bit 1 means constant (0 means register) */
public static final int BITRK = (1 << (SIZE_B - 1));
public static final int BITRK = (1<<(SIZE_B-1));
/** test whether value is a constant */
public static boolean ISK(int x) {
@@ -147,30 +143,27 @@ public class Lua {
/** gets the index of the constant */
public static int INDEXK(int r) {
return ((int)(r) & ~BITRK);
return ((int) (r) & ~BITRK);
}
public static final int MAXINDEXRK = (BITRK - 1);
public static final int MAXINDEXRK = (BITRK-1);
/** code a constant index as a RK value */
public static int RKASK(int x) {
return ((x) | BITRK);
}
/**
** invalid register that fits in 8 bits
*/
public static final int NO_REG = MAXARG_A;
/*
** R(x) - register
** Kst(x) - constant (in constant table)
** RK(x) == if ISK(x) then Kst(INDEXK(x)) else R(x)
*/
/*
** grep "ORDER OP" if you change these enums
*/
@@ -178,10 +171,10 @@ public class Lua {
/*----------------------------------------------------------------------
name args description
------------------------------------------------------------------------*/
public static final int OP_MOVE = 0;/* A B R(A) := R(B) */
public static final int OP_LOADK = 1;/* A Bx R(A) := Kst(Bx) */
public static final int OP_LOADKX = 2;/* A R(A) := Kst(extra arg) */
public static final int OP_LOADBOOL = 3;/* A B C R(A) := (Bool)B; if (C) pc++ */
public static final int OP_MOVE = 0; /* A B R(A) := R(B) */
public static final int OP_LOADK = 1; /* A Bx R(A) := Kst(Bx) */
public static final int OP_LOADKX = 2; /* A R(A) := Kst(extra arg) */
public static final int OP_LOADBOOL = 3; /* A B C R(A) := (Bool)B; if (C) pc++ */
public static final int OP_LOADNIL = 4; /* A B R(A) := ... := R(A+B) := nil */
public static final int OP_GETUPVAL = 5; /* A B R(A) := UpValue[B] */
@@ -234,7 +227,7 @@ public class Lua {
public static final int OP_EXTRAARG = 39; /* Ax extra (larger) argument for previous opcode */
public static final int NUM_OPCODES = OP_EXTRAARG + 1;
public static final int NUM_OPCODES = OP_EXTRAARG+1;
/* pseudo-opcodes used in parsing only. */
public static final int OP_GT = 63; // >
@@ -263,7 +256,6 @@ public class Lua {
(*) All `skips' (pc++) assume that next instruction is a jump
===========================================================================*/
/*
** masks for instruction properties. The format is:
** bits 0-1: op mode
@@ -325,17 +317,21 @@ public class Lua {
public static int getOpMode(int m) {
return luaP_opmodes[m] & 3;
}
public static int getBMode(int m) {
return (luaP_opmodes[m] >> 4) & 3;
return (luaP_opmodes[m]>>4) & 3;
}
public static int getCMode(int m) {
return (luaP_opmodes[m] >> 2) & 3;
return (luaP_opmodes[m]>>2) & 3;
}
public static boolean testAMode(int m) {
return 0 != (luaP_opmodes[m] & (1 << 6));
return 0 != (luaP_opmodes[m] & (1<<6));
}
public static boolean testTMode(int m) {
return 0 != (luaP_opmodes[m] & (1 << 7));
return 0 != (luaP_opmodes[m] & (1<<7));
}
/* number of list items to accumulate before a SETLIST instruction */
@@ -343,19 +339,19 @@ public class Lua {
private static final int MAXSRC = 80;
public static String chunkid( String source ) {
if ( source.startsWith("=") )
public static String chunkid(String source) {
if (source.startsWith("="))
return source.substring(1);
String end = "";
if ( source.startsWith("@") ) {
if (source.startsWith("@")) {
source = source.substring(1);
} else {
source = "[string \""+source;
source = "[string \"" + source;
end = "\"]";
}
int n = source.length() + end.length();
if ( n > MAXSRC )
source = source.substring(0,MAXSRC-end.length()-3) + "...";
return source + end;
int n = source.length()+end.length();
if (n > MAXSRC)
source = source.substring(0, MAXSRC-end.length()-3) + "...";
return source+end;
}
}

View File

@@ -24,16 +24,16 @@ package org.luaj.vm2;
/**
* Extension of {@link LuaValue} which can hold a Java boolean as its value.
* <p>
* These instance are not instantiated directly by clients.
* Instead, there are exactly twon instances of this class,
* {@link LuaValue#TRUE} and {@link LuaValue#FALSE}
* representing the lua values {@code true} and {@code false}.
* The function {@link LuaValue#valueOf(boolean)} will always
* These instance are not instantiated directly by clients. Instead, there are
* exactly twon instances of this class, {@link LuaValue#TRUE} and
* {@link LuaValue#FALSE} representing the lua values {@code true} and
* {@code false}. The function {@link LuaValue#valueOf(boolean)} will always
* return one of these two values.
* <p>
* Any {@link LuaValue} can be converted to its equivalent
* boolean representation using {@link LuaValue#toboolean()}
* Any {@link LuaValue} can be converted to its equivalent boolean
* representation using {@link LuaValue#toboolean()}
* <p>
*
* @see LuaValue
* @see LuaValue#valueOf(boolean)
* @see LuaValue#TRUE
@@ -70,11 +70,12 @@ public final class LuaBoolean extends LuaValue {
}
public LuaValue not() {
return v ? FALSE : LuaValue.TRUE;
return v? FALSE: LuaValue.TRUE;
}
/**
* Return the boolean value for this boolean
*
* @return value as a Java boolean
*/
public boolean booleanValue() {
@@ -86,7 +87,7 @@ public final class LuaBoolean extends LuaValue {
}
public String tojstring() {
return v ? "true" : "false";
return v? "true": "false";
}
public boolean optboolean(boolean defval) {

View File

@@ -26,44 +26,56 @@ import org.luaj.vm2.lib.DebugLib.CallFrame;
/**
* Extension of {@link LuaFunction} which executes lua bytecode.
* <p>
* A {@link LuaClosure} is a combination of a {@link Prototype}
* and a {@link LuaValue} to use as an environment for execution.
* Normally the {@link LuaValue} is a {@link Globals} in which case the environment
* will contain standard lua libraries.
* A {@link LuaClosure} is a combination of a {@link Prototype} and a
* {@link LuaValue} to use as an environment for execution. Normally the
* {@link LuaValue} is a {@link Globals} in which case the environment will
* contain standard lua libraries.
*
* <p>
* There are three main ways {@link LuaClosure} instances are created:
* <ul>
* <li>Construct an instance using {@link #LuaClosure(Prototype, LuaValue)}</li>
* <li>Construct it indirectly by loading a chunk via {@link Globals#load(java.io.Reader, String)}
* <li>Execute the lua bytecode {@link Lua#OP_CLOSURE} as part of bytecode processing
* <li>Construct it indirectly by loading a chunk via
* {@link Globals#load(java.io.Reader, String)}
* <li>Execute the lua bytecode {@link Lua#OP_CLOSURE} as part of bytecode
* processing
* </ul>
* <p>
* To construct it directly, the {@link Prototype} is typically created via a compiler such as
* {@link org.luaj.vm2.compiler.LuaC}:
* <pre> {@code
* To construct it directly, the {@link Prototype} is typically created via a
* compiler such as {@link org.luaj.vm2.compiler.LuaC}:
*
* <pre>
* {
* &#64;code
* String script = "print( 'hello, world' )";
* InputStream is = new ByteArrayInputStream(script.getBytes());
* Prototype p = LuaC.instance.compile(is, "script");
* LuaValue globals = JsePlatform.standardGlobals();
* LuaClosure f = new LuaClosure(p, globals);
* f.call();
* }</pre>
* }
* </pre>
* <p>
* To construct it indirectly, the {@link Globals#load(java.io.Reader, String)} method may be used:
* <pre> {@code
* To construct it indirectly, the {@link Globals#load(java.io.Reader, String)}
* method may be used:
*
* <pre>
* {
* &#64;code
* Globals globals = JsePlatform.standardGlobals();
* LuaFunction f = globals.load(new StringReader(script), "script");
* LuaClosure c = f.checkclosure(); // This may fail if LuaJC is installed.
* c.call();
* }</pre>
* }
* </pre>
* <p>
* In this example, the "checkclosure()" may fail if direct lua-to-java-bytecode
* compiling using LuaJC is installed, because no LuaClosure is created in that case
* and the value returned is a {@link LuaFunction} but not a {@link LuaClosure}.
* compiling using LuaJC is installed, because no LuaClosure is created in that
* case and the value returned is a {@link LuaFunction} but not a
* {@link LuaClosure}.
* <p>
* Since a {@link LuaClosure} is a {@link LuaFunction} which is a {@link LuaValue},
* all the value operations can be used directly such as:
* Since a {@link LuaClosure} is a {@link LuaFunction} which is a
* {@link LuaValue}, all the value operations can be used directly such as:
* <ul>
* <li>{@link LuaValue#call()}</li>
* <li>{@link LuaValue#call(LuaValue)}</li>
@@ -73,8 +85,9 @@ import org.luaj.vm2.lib.DebugLib.CallFrame;
* <li>{@link LuaValue#method(String,LuaValue)}</li>
* <li>{@link LuaValue#invokemethod(String)}</li>
* <li>{@link LuaValue#invokemethod(String,Varargs)}</li>
* <li> ...</li>
* <li>...</li>
* </ul>
*
* @see LuaValue
* @see LuaFunction
* @see LuaValue#isclosure()
@@ -92,8 +105,11 @@ public class LuaClosure extends LuaFunction {
final Globals globals;
/** Create a closure around a Prototype with a specific environment.
* If the prototype has upvalues, the environment will be written into the first upvalue.
/**
* Create a closure around a Prototype with a specific environment. If the
* prototype has upvalues, the environment will be written into the first
* upvalue.
*
* @param p the Prototype to construct this Closure for.
* @param env the environment to associate with the closure.
*/
@@ -108,11 +124,10 @@ public class LuaClosure extends LuaFunction {
this.upValues = NOUPVALUES;
else {
this.upValues = new UpValue[p.upvalues.length];
this.upValues[0] = new UpValue(new LuaValue[] {env}, 0);
this.upValues[0] = new UpValue(new LuaValue[] { env }, 0);
}
}
public boolean isclosure() {
return true;
}
@@ -138,33 +153,52 @@ public class LuaClosure extends LuaFunction {
public final LuaValue call() {
LuaValue[] stack = getNewStack();
return execute(stack,NONE).arg1();
return execute(stack, NONE).arg1();
}
public final LuaValue call(LuaValue arg) {
LuaValue[] stack = getNewStack();
switch ( p.numparams ) {
default: stack[0]=arg; return execute(stack,NONE).arg1();
case 0: return execute(stack,arg).arg1();
switch (p.numparams) {
default:
stack[0] = arg;
return execute(stack, NONE).arg1();
case 0:
return execute(stack, arg).arg1();
}
}
public final LuaValue call(LuaValue arg1, LuaValue arg2) {
LuaValue[] stack = getNewStack();
switch ( p.numparams ) {
default: stack[0]=arg1; stack[1]=arg2; return execute(stack,NONE).arg1();
case 1: stack[0]=arg1; return execute(stack,arg2).arg1();
case 0: return execute(stack,p.is_vararg!=0? varargsOf(arg1,arg2): NONE).arg1();
switch (p.numparams) {
default:
stack[0] = arg1;
stack[1] = arg2;
return execute(stack, NONE).arg1();
case 1:
stack[0] = arg1;
return execute(stack, arg2).arg1();
case 0:
return execute(stack, p.is_vararg != 0? varargsOf(arg1, arg2): NONE).arg1();
}
}
public final LuaValue call(LuaValue arg1, LuaValue arg2, LuaValue arg3) {
LuaValue[] stack = getNewStack();
switch ( p.numparams ) {
default: stack[0]=arg1; stack[1]=arg2; stack[2]=arg3; return execute(stack,NONE).arg1();
case 2: stack[0]=arg1; stack[1]=arg2; return execute(stack,arg3).arg1();
case 1: stack[0]=arg1; return execute(stack,p.is_vararg!=0? varargsOf(arg2,arg3): NONE).arg1();
case 0: return execute(stack,p.is_vararg!=0? varargsOf(arg1,arg2,arg3): NONE).arg1();
switch (p.numparams) {
default:
stack[0] = arg1;
stack[1] = arg2;
stack[2] = arg3;
return execute(stack, NONE).arg1();
case 2:
stack[0] = arg1;
stack[1] = arg2;
return execute(stack, arg3).arg1();
case 1:
stack[0] = arg1;
return execute(stack, p.is_vararg != 0? varargsOf(arg2, arg3): NONE).arg1();
case 0:
return execute(stack, p.is_vararg != 0? varargsOf(arg1, arg2, arg3): NONE).arg1();
}
}
@@ -174,14 +208,14 @@ public class LuaClosure extends LuaFunction {
public final Varargs onInvoke(Varargs varargs) {
LuaValue[] stack = getNewStack();
for ( int i=0; i<p.numparams; i++ )
for (int i = 0; i < p.numparams; i++)
stack[i] = varargs.arg(i+1);
return execute(stack,p.is_vararg!=0? varargs.subargs(p.numparams+1): NONE);
return execute(stack, p.is_vararg != 0? varargs.subargs(p.numparams+1): NONE);
}
protected Varargs execute( LuaValue[] stack, Varargs varargs ) {
protected Varargs execute(LuaValue[] stack, Varargs varargs) {
// loop through instructions
int i,a,b,c,pc=0,top=0;
int i, a, b, c, pc = 0, top = 0;
LuaValue o;
Varargs v = NONE;
int[] code = p.code;
@@ -189,24 +223,24 @@ public class LuaClosure extends LuaFunction {
// upvalues are only possible when closures create closures
// TODO: use linked list.
UpValue[] openups = p.p.length>0? new UpValue[stack.length]: null;
UpValue[] openups = p.p.length > 0? new UpValue[stack.length]: null;
// allow for debug hooks
if (globals != null && globals.debuglib != null)
globals.debuglib.onCall( this, varargs, stack );
globals.debuglib.onCall(this, varargs, stack);
// process instructions
try {
for (; true; ++pc) {
if (globals != null && globals.debuglib != null)
globals.debuglib.onInstruction( pc, v, top );
globals.debuglib.onInstruction(pc, v, top);
// pull out instruction
i = code[pc];
a = ((i>>6) & 0xff);
// process the op code
switch ( i & 0x3f ) {
switch (i & 0x3f) {
case Lua.OP_MOVE:/* A B R(A):= R(B) */
stack[a] = stack[i>>>23];
@@ -221,20 +255,20 @@ public class LuaClosure extends LuaFunction {
i = code[pc];
if ((i & 0x3f) != Lua.OP_EXTRAARG) {
int op = i & 0x3f;
throw new LuaError("OP_EXTRAARG expected after OP_LOADKX, got " +
(op < Print.OPNAMES.length - 1 ? Print.OPNAMES[op] : "UNKNOWN_OP_" + op));
throw new LuaError("OP_EXTRAARG expected after OP_LOADKX, got "
+ (op < Print.OPNAMES.length-1? Print.OPNAMES[op]: "UNKNOWN_OP_" + op));
}
stack[a] = k[i>>>6];
continue;
case Lua.OP_LOADBOOL:/* A B C R(A):= (Bool)B: if (C) pc++ */
stack[a] = (i>>>23!=0)? LuaValue.TRUE: LuaValue.FALSE;
if ((i&(0x1ff<<14)) != 0)
stack[a] = (i>>>23 != 0)? LuaValue.TRUE: LuaValue.FALSE;
if ((i & (0x1ff<<14)) != 0)
++pc; /* skip next instruction (if C) */
continue;
case Lua.OP_LOADNIL: /* A B R(A):= ...:= R(A+B):= nil */
for ( b=i>>>23; b-->=0; )
for (b = i>>>23; b-- >= 0;)
stack[a++] = LuaValue.NIL;
continue;
@@ -243,15 +277,16 @@ public class LuaClosure extends LuaFunction {
continue;
case Lua.OP_GETTABUP: /* A B C R(A) := UpValue[B][RK(C)] */
stack[a] = upValues[i>>>23].getValue().get((c=(i>>14)&0x1ff)>0xff? k[c&0x0ff]: stack[c]);
stack[a] = upValues[i>>>23].getValue().get((c = (i>>14) & 0x1ff) > 0xff? k[c & 0x0ff]: stack[c]);
continue;
case Lua.OP_GETTABLE: /* A B C R(A):= R(B)[RK(C)] */
stack[a] = stack[i>>>23].get((c=(i>>14)&0x1ff)>0xff? k[c&0x0ff]: stack[c]);
stack[a] = stack[i>>>23].get((c = (i>>14) & 0x1ff) > 0xff? k[c & 0x0ff]: stack[c]);
continue;
case Lua.OP_SETTABUP: /* A B C UpValue[A][RK(B)] := RK(C) */
upValues[a].getValue().set(((b=i>>>23)>0xff? k[b&0x0ff]: stack[b]), (c=(i>>14)&0x1ff)>0xff? k[c&0x0ff]: stack[c]);
upValues[a].getValue().set(((b = i>>>23) > 0xff? k[b & 0x0ff]: stack[b]),
(c = (i>>14) & 0x1ff) > 0xff? k[c & 0x0ff]: stack[c]);
continue;
case Lua.OP_SETUPVAL: /* A B UpValue[B]:= R(A) */
@@ -259,40 +294,47 @@ public class LuaClosure extends LuaFunction {
continue;
case Lua.OP_SETTABLE: /* A B C R(A)[RK(B)]:= RK(C) */
stack[a].set(((b=i>>>23)>0xff? k[b&0x0ff]: stack[b]), (c=(i>>14)&0x1ff)>0xff? k[c&0x0ff]: stack[c]);
stack[a].set(((b = i>>>23) > 0xff? k[b & 0x0ff]: stack[b]),
(c = (i>>14) & 0x1ff) > 0xff? k[c & 0x0ff]: stack[c]);
continue;
case Lua.OP_NEWTABLE: /* A B C R(A):= {} (size = B,C) */
stack[a] = new LuaTable(i>>>23,(i>>14)&0x1ff);
stack[a] = new LuaTable(i>>>23, (i>>14) & 0x1ff);
continue;
case Lua.OP_SELF: /* A B C R(A+1):= R(B): R(A):= R(B)[RK(C)] */
stack[a+1] = (o = stack[i>>>23]);
stack[a] = o.get((c=(i>>14)&0x1ff)>0xff? k[c&0x0ff]: stack[c]);
stack[a] = o.get((c = (i>>14) & 0x1ff) > 0xff? k[c & 0x0ff]: stack[c]);
continue;
case Lua.OP_ADD: /* A B C R(A):= RK(B) + RK(C) */
stack[a] = ((b=i>>>23)>0xff? k[b&0x0ff]: stack[b]).add((c=(i>>14)&0x1ff)>0xff? k[c&0x0ff]: stack[c]);
stack[a] = ((b = i>>>23) > 0xff? k[b & 0x0ff]: stack[b])
.add((c = (i>>14) & 0x1ff) > 0xff? k[c & 0x0ff]: stack[c]);
continue;
case Lua.OP_SUB: /* A B C R(A):= RK(B) - RK(C) */
stack[a] = ((b=i>>>23)>0xff? k[b&0x0ff]: stack[b]).sub((c=(i>>14)&0x1ff)>0xff? k[c&0x0ff]: stack[c]);
stack[a] = ((b = i>>>23) > 0xff? k[b & 0x0ff]: stack[b])
.sub((c = (i>>14) & 0x1ff) > 0xff? k[c & 0x0ff]: stack[c]);
continue;
case Lua.OP_MUL: /* A B C R(A):= RK(B) * RK(C) */
stack[a] = ((b=i>>>23)>0xff? k[b&0x0ff]: stack[b]).mul((c=(i>>14)&0x1ff)>0xff? k[c&0x0ff]: stack[c]);
stack[a] = ((b = i>>>23) > 0xff? k[b & 0x0ff]: stack[b])
.mul((c = (i>>14) & 0x1ff) > 0xff? k[c & 0x0ff]: stack[c]);
continue;
case Lua.OP_DIV: /* A B C R(A):= RK(B) / RK(C) */
stack[a] = ((b=i>>>23)>0xff? k[b&0x0ff]: stack[b]).div((c=(i>>14)&0x1ff)>0xff? k[c&0x0ff]: stack[c]);
stack[a] = ((b = i>>>23) > 0xff? k[b & 0x0ff]: stack[b])
.div((c = (i>>14) & 0x1ff) > 0xff? k[c & 0x0ff]: stack[c]);
continue;
case Lua.OP_MOD: /* A B C R(A):= RK(B) % RK(C) */
stack[a] = ((b=i>>>23)>0xff? k[b&0x0ff]: stack[b]).mod((c=(i>>14)&0x1ff)>0xff? k[c&0x0ff]: stack[c]);
stack[a] = ((b = i>>>23) > 0xff? k[b & 0x0ff]: stack[b])
.mod((c = (i>>14) & 0x1ff) > 0xff? k[c & 0x0ff]: stack[c]);
continue;
case Lua.OP_POW: /* A B C R(A):= RK(B) ^ RK(C) */
stack[a] = ((b=i>>>23)>0xff? k[b&0x0ff]: stack[b]).pow((c=(i>>14)&0x1ff)>0xff? k[c&0x0ff]: stack[c]);
stack[a] = ((b = i>>>23) > 0xff? k[b & 0x0ff]: stack[b])
.pow((c = (i>>14) & 0x1ff) > 0xff? k[c & 0x0ff]: stack[c]);
continue;
case Lua.OP_UNM: /* A B R(A):= -R(B) */
@@ -309,11 +351,10 @@ public class LuaClosure extends LuaFunction {
case Lua.OP_CONCAT: /* A B C R(A):= R(B).. ... ..R(C) */
b = i>>>23;
c = (i>>14)&0x1ff;
{
if ( c > b+1 ) {
c = (i>>14) & 0x1ff; {
if (c > b+1) {
Buffer sb = stack[c].buffer();
while ( --c>=b )
while ( --c >= b )
sb.concatTo(stack[c]);
stack[a] = sb.value();
} else {
@@ -325,7 +366,7 @@ public class LuaClosure extends LuaFunction {
case Lua.OP_JMP: /* A sBx pc+=sBx; if (A) close all upvalues >= R(A - 1) */
pc += (i>>>14)-0x1ffff;
if (a > 0) {
for (--a, b = openups.length; --b>=0; )
for (--a, b = openups.length; --b >= 0;)
if (openups[b] != null && openups[b].index >= a) {
openups[b].close();
openups[b] = null;
@@ -334,93 +375,123 @@ public class LuaClosure extends LuaFunction {
continue;
case Lua.OP_EQ: /* A B C if ((RK(B) == RK(C)) ~= A) then pc++ */
if ( ((b=i>>>23)>0xff? k[b&0x0ff]: stack[b]).eq_b((c=(i>>14)&0x1ff)>0xff? k[c&0x0ff]: stack[c]) != (a!=0) )
if (((b = i>>>23) > 0xff? k[b & 0x0ff]: stack[b])
.eq_b((c = (i>>14) & 0x1ff) > 0xff? k[c & 0x0ff]: stack[c]) != (a != 0))
++pc;
continue;
case Lua.OP_LT: /* A B C if ((RK(B) < RK(C)) ~= A) then pc++ */
if ( ((b=i>>>23)>0xff? k[b&0x0ff]: stack[b]).lt_b((c=(i>>14)&0x1ff)>0xff? k[c&0x0ff]: stack[c]) != (a!=0) )
if (((b = i>>>23) > 0xff? k[b & 0x0ff]: stack[b])
.lt_b((c = (i>>14) & 0x1ff) > 0xff? k[c & 0x0ff]: stack[c]) != (a != 0))
++pc;
continue;
case Lua.OP_LE: /* A B C if ((RK(B) <= RK(C)) ~= A) then pc++ */
if ( ((b=i>>>23)>0xff? k[b&0x0ff]: stack[b]).lteq_b((c=(i>>14)&0x1ff)>0xff? k[c&0x0ff]: stack[c]) != (a!=0) )
if (((b = i>>>23) > 0xff? k[b & 0x0ff]: stack[b])
.lteq_b((c = (i>>14) & 0x1ff) > 0xff? k[c & 0x0ff]: stack[c]) != (a != 0))
++pc;
continue;
case Lua.OP_TEST: /* A C if not (R(A) <=> C) then pc++ */
if ( stack[a].toboolean() != ((i&(0x1ff<<14))!=0) )
if (stack[a].toboolean() != ((i & (0x1ff<<14)) != 0))
++pc;
continue;
case Lua.OP_TESTSET: /* A B C if (R(B) <=> C) then R(A):= R(B) else pc++ */
/* note: doc appears to be reversed */
if ( (o=stack[i>>>23]).toboolean() != ((i&(0x1ff<<14))!=0) )
if ((o = stack[i>>>23]).toboolean() != ((i & (0x1ff<<14)) != 0))
++pc;
else
stack[a] = o; // TODO: should be sBx?
continue;
case Lua.OP_CALL: /* A B C R(A), ... ,R(A+C-2):= R(A)(R(A+1), ... ,R(A+B-1)) */
switch ( i & (Lua.MASK_B | Lua.MASK_C) ) {
case (1<<Lua.POS_B) | (0<<Lua.POS_C): v=stack[a].invoke(NONE); top=a+v.narg(); continue;
case (2<<Lua.POS_B) | (0<<Lua.POS_C): v=stack[a].invoke(stack[a+1]); top=a+v.narg(); continue;
case (1<<Lua.POS_B) | (1<<Lua.POS_C): stack[a].call(); continue;
case (2<<Lua.POS_B) | (1<<Lua.POS_C): stack[a].call(stack[a+1]); continue;
case (3<<Lua.POS_B) | (1<<Lua.POS_C): stack[a].call(stack[a+1],stack[a+2]); continue;
case (4<<Lua.POS_B) | (1<<Lua.POS_C): stack[a].call(stack[a+1],stack[a+2],stack[a+3]); continue;
case (1<<Lua.POS_B) | (2<<Lua.POS_C): stack[a] = stack[a].call(); continue;
case (2<<Lua.POS_B) | (2<<Lua.POS_C): stack[a] = stack[a].call(stack[a+1]); continue;
case (3<<Lua.POS_B) | (2<<Lua.POS_C): stack[a] = stack[a].call(stack[a+1],stack[a+2]); continue;
case (4<<Lua.POS_B) | (2<<Lua.POS_C): stack[a] = stack[a].call(stack[a+1],stack[a+2],stack[a+3]); continue;
switch (i & (Lua.MASK_B | Lua.MASK_C)) {
case (1<<Lua.POS_B) | (0<<Lua.POS_C):
v = stack[a].invoke(NONE);
top = a+v.narg();
continue;
case (2<<Lua.POS_B) | (0<<Lua.POS_C):
v = stack[a].invoke(stack[a+1]);
top = a+v.narg();
continue;
case (1<<Lua.POS_B) | (1<<Lua.POS_C):
stack[a].call();
continue;
case (2<<Lua.POS_B) | (1<<Lua.POS_C):
stack[a].call(stack[a+1]);
continue;
case (3<<Lua.POS_B) | (1<<Lua.POS_C):
stack[a].call(stack[a+1], stack[a+2]);
continue;
case (4<<Lua.POS_B) | (1<<Lua.POS_C):
stack[a].call(stack[a+1], stack[a+2], stack[a+3]);
continue;
case (1<<Lua.POS_B) | (2<<Lua.POS_C):
stack[a] = stack[a].call();
continue;
case (2<<Lua.POS_B) | (2<<Lua.POS_C):
stack[a] = stack[a].call(stack[a+1]);
continue;
case (3<<Lua.POS_B) | (2<<Lua.POS_C):
stack[a] = stack[a].call(stack[a+1], stack[a+2]);
continue;
case (4<<Lua.POS_B) | (2<<Lua.POS_C):
stack[a] = stack[a].call(stack[a+1], stack[a+2], stack[a+3]);
continue;
default:
b = i>>>23;
c = (i>>14)&0x1ff;
v = stack[a].invoke(b>0?
varargsOf(stack, a+1, b-1): // exact arg count
c = (i>>14) & 0x1ff;
v = stack[a].invoke(b > 0? varargsOf(stack, a+1, b-1): // exact arg count
varargsOf(stack, a+1, top-v.narg()-(a+1), v)); // from prev top
if ( c > 0 ) {
if (c > 0) {
v.copyto(stack, a, c-1);
v = NONE;
} else {
top = a + v.narg();
top = a+v.narg();
v = v.dealias();
}
continue;
}
case Lua.OP_TAILCALL: /* A B C return R(A)(R(A+1), ... ,R(A+B-1)) */
switch ( i & Lua.MASK_B ) {
case (1<<Lua.POS_B): return new TailcallVarargs(stack[a], NONE);
case (2<<Lua.POS_B): return new TailcallVarargs(stack[a], stack[a+1]);
case (3<<Lua.POS_B): return new TailcallVarargs(stack[a], varargsOf(stack[a+1],stack[a+2]));
case (4<<Lua.POS_B): return new TailcallVarargs(stack[a], varargsOf(stack[a+1],stack[a+2],stack[a+3]));
switch (i & Lua.MASK_B) {
case (1<<Lua.POS_B):
return new TailcallVarargs(stack[a], NONE);
case (2<<Lua.POS_B):
return new TailcallVarargs(stack[a], stack[a+1]);
case (3<<Lua.POS_B):
return new TailcallVarargs(stack[a], varargsOf(stack[a+1], stack[a+2]));
case (4<<Lua.POS_B):
return new TailcallVarargs(stack[a], varargsOf(stack[a+1], stack[a+2], stack[a+3]));
default:
b = i>>>23;
v = b>0?
varargsOf(stack,a+1,b-1): // exact arg count
v = b > 0? varargsOf(stack, a+1, b-1): // exact arg count
varargsOf(stack, a+1, top-v.narg()-(a+1), v); // from prev top
return new TailcallVarargs( stack[a], v );
return new TailcallVarargs(stack[a], v);
}
case Lua.OP_RETURN: /* A B return R(A), ... ,R(A+B-2) (see note) */
b = i>>>23;
switch ( b ) {
case 0: return varargsOf(stack, a, top-v.narg()-a, v);
case 1: return NONE;
case 2: return stack[a];
switch (b) {
case 0:
return varargsOf(stack, a, top-v.narg()-a, v);
case 1:
return NONE;
case 2:
return stack[a];
default:
return varargsOf(stack, a, b-1);
}
case Lua.OP_FORLOOP: /* A sBx R(A)+=R(A+2): if R(A) <?= R(A+1) then { pc+=sBx: R(A+3)=R(A) }*/
{
LuaValue limit = stack[a + 1];
LuaValue step = stack[a + 2];
LuaValue limit = stack[a+1];
LuaValue step = stack[a+2];
LuaValue idx = stack[a].add(step);
if (step.gt_b(0)? idx.lteq_b(limit): idx.gteq_b(limit)) {
stack[a] = idx;
stack[a + 3] = idx;
stack[a+3] = idx;
pc += (i>>>14)-0x1ffff;
}
}
@@ -429,19 +500,19 @@ public class LuaClosure extends LuaFunction {
case Lua.OP_FORPREP: /* A sBx R(A)-=R(A+2): pc+=sBx */
{
LuaValue init = stack[a].checknumber("'for' initial value must be a number");
LuaValue limit = stack[a + 1].checknumber("'for' limit must be a number");
LuaValue step = stack[a + 2].checknumber("'for' step must be a number");
LuaValue limit = stack[a+1].checknumber("'for' limit must be a number");
LuaValue step = stack[a+2].checknumber("'for' step must be a number");
stack[a] = init.sub(step);
stack[a + 1] = limit;
stack[a + 2] = step;
stack[a+1] = limit;
stack[a+2] = step;
pc += (i>>>14)-0x1ffff;
}
continue;
case Lua.OP_TFORCALL: /* A C R(A+3), ... ,R(A+2+C) := R(A)(R(A+1), R(A+2)); */
v = stack[a].invoke(varargsOf(stack[a+1],stack[a+2]));
v = stack[a].invoke(varargsOf(stack[a+1], stack[a+2]));
c = (i>>14) & 0x1ff;
while (--c >= 0)
while ( --c >= 0 )
stack[a+3+c] = v.arg(c+1);
v = NONE;
continue;
@@ -455,22 +526,22 @@ public class LuaClosure extends LuaFunction {
case Lua.OP_SETLIST: /* A B C R(A)[(C-1)*FPF+i]:= R(A+i), 1 <= i <= B */
{
if ( (c=(i>>14)&0x1ff) == 0 )
if ((c = (i>>14) & 0x1ff) == 0)
c = code[++pc];
int offset = (c-1) * Lua.LFIELDS_PER_FLUSH;
int offset = (c-1)*Lua.LFIELDS_PER_FLUSH;
o = stack[a];
if ( (b=i>>>23) == 0 ) {
b = top - a - 1;
int m = b - v.narg();
int j=1;
for ( ;j<=m; j++ )
o.set(offset+j, stack[a + j]);
for ( ;j<=b; j++ )
if ((b = i>>>23) == 0) {
b = top-a-1;
int m = b-v.narg();
int j = 1;
for (; j <= m; j++)
o.set(offset+j, stack[a+j]);
for (; j <= b; j++)
o.set(offset+j, v.arg(j-m));
} else {
o.presize( offset + b );
for (int j=1; j<=b; j++)
o.set(offset+j, stack[a + j]);
o.presize(offset+b);
for (int j = 1; j <= b; j++)
o.set(offset+j, stack[a+j]);
}
}
continue;
@@ -480,7 +551,7 @@ public class LuaClosure extends LuaFunction {
Prototype newp = p.p[i>>>14];
LuaClosure ncl = new LuaClosure(newp, globals);
Upvaldesc[] uv = newp.upvalues;
for ( int j=0, nup=uv.length; j<nup; ++j ) {
for (int j = 0, nup = uv.length; j < nup; ++j) {
if (uv[j].instack) /* upvalue refes to local variable? */
ncl.upValues[j] = findupval(stack, uv[j].idx, openups);
else /* get upvalue from enclosing function */
@@ -492,11 +563,11 @@ public class LuaClosure extends LuaFunction {
case Lua.OP_VARARG: /* A B R(A), R(A+1), ..., R(A+B-1) = vararg */
b = i>>>23;
if ( b == 0 ) {
top = a + (b = varargs.narg());
if (b == 0) {
top = a+(b = varargs.narg());
v = varargs;
} else {
for ( int j=1; j<b; ++j )
for (int j = 1; j < b; ++j)
stack[a+j-1] = varargs.arg(j);
}
continue;
@@ -508,18 +579,18 @@ public class LuaClosure extends LuaFunction {
throw new java.lang.IllegalArgumentException("Illegal opcode: " + (i & 0x3f));
}
}
} catch ( LuaError le ) {
} catch (LuaError le) {
if (le.traceback == null)
processErrorHooks(le, p, pc);
throw le;
} catch ( Exception e ) {
} catch (Exception e) {
LuaError le = new LuaError(e);
processErrorHooks(le, p, pc);
throw le;
} finally {
if ( openups != null )
for ( int u=openups.length; --u>=0; )
if ( openups[u] != null )
if (openups != null)
for (int u = openups.length; --u >= 0;)
if (openups[u] != null)
openups[u].close();
if (globals != null && globals.debuglib != null)
globals.debuglib.onReturn();
@@ -528,20 +599,20 @@ public class LuaClosure extends LuaFunction {
/**
* Run the error hook if there is one
*
* @param msg the message to use in error hook processing.
* */
*/
String errorHook(String msg, int level) {
if (globals == null ) return msg;
if (globals == null)
return msg;
final LuaThread r = globals.running;
if (r.errorfunc == null)
return globals.debuglib != null?
msg + "\n" + globals.debuglib.traceback(level):
msg;
return globals.debuglib != null? msg + "\n" + globals.debuglib.traceback(level): msg;
final LuaValue e = r.errorfunc;
r.errorfunc = null;
try {
return e.call( LuaValue.valueOf(msg) ).tojstring();
} catch ( Throwable t ) {
return e.call(LuaValue.valueOf(msg)).tojstring();
} catch (Throwable t) {
return "error in error handling";
} finally {
r.errorfunc = e;
@@ -557,13 +628,13 @@ public class LuaClosure extends LuaFunction {
frame = globals.debuglib.getCallFrame(le.level);
if (frame != null) {
String src = frame.shortsource();
file = src != null ? src : "?";
file = src != null? src: "?";
line = frame.currentline();
}
}
if (frame == null) {
file = p.source != null? p.source.tojstring(): "?";
line = p.lineinfo != null && pc >= 0 && pc < p.lineinfo.length ? p.lineinfo[pc] : -1;
line = p.lineinfo != null && pc >= 0 && pc < p.lineinfo.length? p.lineinfo[pc]: -1;
}
}
le.fileline = file + ":" + line;
@@ -591,8 +662,7 @@ public class LuaClosure extends LuaFunction {
}
public String name() {
return "<"+p.shortsource()+":"+p.linedefined+">";
return "<" + p.shortsource() + ":" + p.linedefined + ">";
}
}

View File

@@ -26,18 +26,21 @@ import org.luaj.vm2.lib.MathLib;
/**
* Extension of {@link LuaNumber} which can hold a Java double as its value.
* <p>
* These instance are not instantiated directly by clients, but indirectly
* via the static functions {@link LuaValue#valueOf(int)} or {@link LuaValue#valueOf(double)}
* functions. This ensures that values which can be represented as int
* are wrapped in {@link LuaInteger} instead of {@link LuaDouble}.
* These instance are not instantiated directly by clients, but indirectly via
* the static functions {@link LuaValue#valueOf(int)} or
* {@link LuaValue#valueOf(double)} functions. This ensures that values which
* can be represented as int are wrapped in {@link LuaInteger} instead of
* {@link LuaDouble}.
* <p>
* Almost all API's implemented in LuaDouble are defined and documented in {@link LuaValue}.
* Almost all API's implemented in LuaDouble are defined and documented in
* {@link LuaValue}.
* <p>
* However the constants {@link #NAN}, {@link #POSINF}, {@link #NEGINF},
* {@link #JSTR_NAN}, {@link #JSTR_POSINF}, and {@link #JSTR_NEGINF} may be useful
* when dealing with Nan or Infinite values.
* {@link #JSTR_NAN}, {@link #JSTR_POSINF}, and {@link #JSTR_NEGINF} may be
* useful when dealing with Nan or Infinite values.
* <p>
* LuaDouble also defines functions for handling the unique math rules of lua devision and modulo in
* LuaDouble also defines functions for handling the unique math rules of lua
* devision and modulo in
* <ul>
* <li>{@link #ddiv(double, double)}</li>
* <li>{@link #ddiv_d(double, double)}</li>
@@ -45,6 +48,7 @@ import org.luaj.vm2.lib.MathLib;
* <li>{@link #dmod_d(double, double)}</li>
* </ul>
* <p>
*
* @see LuaValue
* @see LuaNumber
* @see LuaInteger
@@ -54,13 +58,13 @@ import org.luaj.vm2.lib.MathLib;
public class LuaDouble extends LuaNumber {
/** Constant LuaDouble representing NaN (not a number) */
public static final LuaDouble NAN = new LuaDouble( Double.NaN );
public static final LuaDouble NAN = new LuaDouble(Double.NaN);
/** Constant LuaDouble representing positive infinity */
public static final LuaDouble POSINF = new LuaDouble( Double.POSITIVE_INFINITY );
public static final LuaDouble POSINF = new LuaDouble(Double.POSITIVE_INFINITY);
/** Constant LuaDouble representing negative infinity */
public static final LuaDouble NEGINF = new LuaDouble( Double.NEGATIVE_INFINITY );
public static final LuaDouble NEGINF = new LuaDouble(Double.NEGATIVE_INFINITY);
/** Constant String representation for NaN (not a number), "nan" */
public static final String JSTR_NAN = "nan";
@@ -76,7 +80,7 @@ public class LuaDouble extends LuaNumber {
public static LuaNumber valueOf(double d) {
int id = (int) d;
return d==id? (LuaNumber) LuaInteger.valueOf(id): (LuaNumber) new LuaDouble(d);
return d == id? (LuaNumber) LuaInteger.valueOf(id): (LuaNumber) new LuaDouble(d);
}
/** Don't allow ints to be boxed by DoubleValues */
@@ -85,8 +89,8 @@ public class LuaDouble extends LuaNumber {
}
public int hashCode() {
long l = Double.doubleToLongBits(v + 1);
return ((int)(l>>32)) + (int) l;
long l = Double.doubleToLongBits(v+1);
return ((int) (l>>32))+(int) l;
}
public boolean islong() {
@@ -94,145 +98,219 @@ public class LuaDouble extends LuaNumber {
}
public byte tobyte() { return (byte) (long) v; }
public char tochar() { return (char) (long) v; }
public double todouble() { return v; }
public float tofloat() { return (float) v; }
public int toint() { return (int) (long) v; }
public long tolong() { return (long) v; }
public short toshort() { return (short) (long) v; }
public double optdouble(double defval) { return v; }
public int optint(int defval) { return (int) (long) v; }
public LuaInteger optinteger(LuaInteger defval) { return LuaInteger.valueOf((int) (long)v); }
public LuaInteger optinteger(LuaInteger defval) { return LuaInteger.valueOf((int) (long) v); }
public long optlong(long defval) { return (long) v; }
public LuaInteger checkinteger() { return LuaInteger.valueOf( (int) (long) v ); }
public LuaInteger checkinteger() { return LuaInteger.valueOf((int) (long) v); }
// unary operators
public LuaValue neg() { return valueOf(-v); }
// object equality, used for key comparison
public boolean equals(Object o) { return o instanceof LuaDouble? ((LuaDouble)o).v == v: false; }
public boolean equals(Object o) { return o instanceof LuaDouble? ((LuaDouble) o).v == v: false; }
// equality w/ metatable processing
public LuaValue eq( LuaValue val ) { return val.raweq(v)? TRUE: FALSE; }
public boolean eq_b( LuaValue val ) { return val.raweq(v); }
public LuaValue eq(LuaValue val) { return val.raweq(v)? TRUE: FALSE; }
public boolean eq_b(LuaValue val) { return val.raweq(v); }
// equality w/o metatable processing
public boolean raweq( LuaValue val ) { return val.raweq(v); }
public boolean raweq( double val ) { return v == val; }
public boolean raweq( int val ) { return v == val; }
public boolean raweq(LuaValue val) { return val.raweq(v); }
public boolean raweq(double val) { return v == val; }
public boolean raweq(int val) { return v == val; }
// basic binary arithmetic
public LuaValue add( LuaValue rhs ) { return rhs.add(v); }
public LuaValue add( double lhs ) { return LuaDouble.valueOf(lhs + v); }
public LuaValue sub( LuaValue rhs ) { return rhs.subFrom(v); }
public LuaValue sub( double rhs ) { return LuaDouble.valueOf(v - rhs); }
public LuaValue sub( int rhs ) { return LuaDouble.valueOf(v - rhs); }
public LuaValue subFrom( double lhs ) { return LuaDouble.valueOf(lhs - v); }
public LuaValue mul( LuaValue rhs ) { return rhs.mul(v); }
public LuaValue mul( double lhs ) { return LuaDouble.valueOf(lhs * v); }
public LuaValue mul( int lhs ) { return LuaDouble.valueOf(lhs * v); }
public LuaValue pow( LuaValue rhs ) { return rhs.powWith(v); }
public LuaValue pow( double rhs ) { return MathLib.dpow(v,rhs); }
public LuaValue pow( int rhs ) { return MathLib.dpow(v,rhs); }
public LuaValue powWith( double lhs ) { return MathLib.dpow(lhs,v); }
public LuaValue powWith( int lhs ) { return MathLib.dpow(lhs,v); }
public LuaValue div( LuaValue rhs ) { return rhs.divInto(v); }
public LuaValue div( double rhs ) { return LuaDouble.ddiv(v,rhs); }
public LuaValue div( int rhs ) { return LuaDouble.ddiv(v,rhs); }
public LuaValue divInto( double lhs ) { return LuaDouble.ddiv(lhs,v); }
public LuaValue mod( LuaValue rhs ) { return rhs.modFrom(v); }
public LuaValue mod( double rhs ) { return LuaDouble.dmod(v,rhs); }
public LuaValue mod( int rhs ) { return LuaDouble.dmod(v,rhs); }
public LuaValue modFrom( double lhs ) { return LuaDouble.dmod(lhs,v); }
public LuaValue add(LuaValue rhs) { return rhs.add(v); }
public LuaValue add(double lhs) { return LuaDouble.valueOf(lhs+v); }
/** Divide two double numbers according to lua math, and return a {@link LuaValue} result.
public LuaValue sub(LuaValue rhs) { return rhs.subFrom(v); }
public LuaValue sub(double rhs) { return LuaDouble.valueOf(v-rhs); }
public LuaValue sub(int rhs) { return LuaDouble.valueOf(v-rhs); }
public LuaValue subFrom(double lhs) { return LuaDouble.valueOf(lhs-v); }
public LuaValue mul(LuaValue rhs) { return rhs.mul(v); }
public LuaValue mul(double lhs) { return LuaDouble.valueOf(lhs*v); }
public LuaValue mul(int lhs) { return LuaDouble.valueOf(lhs*v); }
public LuaValue pow(LuaValue rhs) { return rhs.powWith(v); }
public LuaValue pow(double rhs) { return MathLib.dpow(v, rhs); }
public LuaValue pow(int rhs) { return MathLib.dpow(v, rhs); }
public LuaValue powWith(double lhs) { return MathLib.dpow(lhs, v); }
public LuaValue powWith(int lhs) { return MathLib.dpow(lhs, v); }
public LuaValue div(LuaValue rhs) { return rhs.divInto(v); }
public LuaValue div(double rhs) { return LuaDouble.ddiv(v, rhs); }
public LuaValue div(int rhs) { return LuaDouble.ddiv(v, rhs); }
public LuaValue divInto(double lhs) { return LuaDouble.ddiv(lhs, v); }
public LuaValue mod(LuaValue rhs) { return rhs.modFrom(v); }
public LuaValue mod(double rhs) { return LuaDouble.dmod(v, rhs); }
public LuaValue mod(int rhs) { return LuaDouble.dmod(v, rhs); }
public LuaValue modFrom(double lhs) { return LuaDouble.dmod(lhs, v); }
/**
* Divide two double numbers according to lua math, and return a
* {@link LuaValue} result.
*
* @param lhs Left-hand-side of the division.
* @param rhs Right-hand-side of the division.
* @return {@link LuaValue} for the result of the division,
* taking into account positive and negiative infinity, and Nan
* @return {@link LuaValue} for the result of the division, taking into
* account positive and negiative infinity, and Nan
* @see #ddiv_d(double, double)
*/
public static LuaValue ddiv(double lhs, double rhs) {
return rhs!=0? valueOf( lhs / rhs ): lhs>0? POSINF: lhs==0? NAN: NEGINF;
return rhs != 0? valueOf(lhs/rhs): lhs > 0? POSINF: lhs == 0? NAN: NEGINF;
}
/** Divide two double numbers according to lua math, and return a double result.
/**
* Divide two double numbers according to lua math, and return a double
* result.
*
* @param lhs Left-hand-side of the division.
* @param rhs Right-hand-side of the division.
* @return Value of the division, taking into account positive and negative infinity, and Nan
* @return Value of the division, taking into account positive and negative
* infinity, and Nan
* @see #ddiv(double, double)
*/
public static double ddiv_d(double lhs, double rhs) {
return rhs!=0? lhs / rhs: lhs>0? Double.POSITIVE_INFINITY: lhs==0? Double.NaN: Double.NEGATIVE_INFINITY;
return rhs != 0? lhs/rhs: lhs > 0? Double.POSITIVE_INFINITY: lhs == 0? Double.NaN: Double.NEGATIVE_INFINITY;
}
/** Take modulo double numbers according to lua math, and return a {@link LuaValue} result.
/**
* Take modulo double numbers according to lua math, and return a
* {@link LuaValue} result.
*
* @param lhs Left-hand-side of the modulo.
* @param rhs Right-hand-side of the modulo.
* @return {@link LuaValue} for the result of the modulo,
* using lua's rules for modulo
* @return {@link LuaValue} for the result of the modulo, using lua's rules
* for modulo
* @see #dmod_d(double, double)
*/
public static LuaValue dmod(double lhs, double rhs) {
if (rhs == 0 || lhs == Double.POSITIVE_INFINITY || lhs == Double.NEGATIVE_INFINITY) return NAN;
if (rhs == 0 || lhs == Double.POSITIVE_INFINITY || lhs == Double.NEGATIVE_INFINITY)
return NAN;
if (rhs == Double.POSITIVE_INFINITY) {
return lhs < 0 ? POSINF : valueOf(lhs);
return lhs < 0? POSINF: valueOf(lhs);
}
if (rhs == Double.NEGATIVE_INFINITY) {
return lhs > 0 ? NEGINF : valueOf(lhs);
return lhs > 0? NEGINF: valueOf(lhs);
}
return valueOf( lhs-rhs*Math.floor(lhs/rhs) );
return valueOf(lhs-rhs*Math.floor(lhs/rhs));
}
/** Take modulo for double numbers according to lua math, and return a double result.
/**
* Take modulo for double numbers according to lua math, and return a double
* result.
*
* @param lhs Left-hand-side of the modulo.
* @param rhs Right-hand-side of the modulo.
* @return double value for the result of the modulo,
* using lua's rules for modulo
* @return double value for the result of the modulo, using lua's rules for
* modulo
* @see #dmod(double, double)
*/
public static double dmod_d(double lhs, double rhs) {
if (rhs == 0 || lhs == Double.POSITIVE_INFINITY || lhs == Double.NEGATIVE_INFINITY) return Double.NaN;
if (rhs == 0 || lhs == Double.POSITIVE_INFINITY || lhs == Double.NEGATIVE_INFINITY)
return Double.NaN;
if (rhs == Double.POSITIVE_INFINITY) {
return lhs < 0 ? Double.POSITIVE_INFINITY : lhs;
return lhs < 0? Double.POSITIVE_INFINITY: lhs;
}
if (rhs == Double.NEGATIVE_INFINITY) {
return lhs > 0 ? Double.NEGATIVE_INFINITY : lhs;
return lhs > 0? Double.NEGATIVE_INFINITY: lhs;
}
return lhs-rhs*Math.floor(lhs/rhs);
}
// relational operators
public LuaValue lt( LuaValue rhs ) { return rhs instanceof LuaNumber ? (rhs.gt_b(v)? TRUE: FALSE) : super.lt(rhs); }
public LuaValue lt( double rhs ) { return v < rhs? TRUE: FALSE; }
public LuaValue lt( int rhs ) { return v < rhs? TRUE: FALSE; }
public boolean lt_b( LuaValue rhs ) { return rhs instanceof LuaNumber ? rhs.gt_b(v) : super.lt_b(rhs); }
public boolean lt_b( int rhs ) { return v < rhs; }
public boolean lt_b( double rhs ) { return v < rhs; }
public LuaValue lteq( LuaValue rhs ) { return rhs instanceof LuaNumber ? (rhs.gteq_b(v)? TRUE: FALSE) : super.lteq(rhs); }
public LuaValue lteq( double rhs ) { return v <= rhs? TRUE: FALSE; }
public LuaValue lteq( int rhs ) { return v <= rhs? TRUE: FALSE; }
public boolean lteq_b( LuaValue rhs ) { return rhs instanceof LuaNumber ? rhs.gteq_b(v) : super.lteq_b(rhs); }
public boolean lteq_b( int rhs ) { return v <= rhs; }
public boolean lteq_b( double rhs ) { return v <= rhs; }
public LuaValue gt( LuaValue rhs ) { return rhs instanceof LuaNumber ? (rhs.lt_b(v)? TRUE: FALSE) : super.gt(rhs); }
public LuaValue gt( double rhs ) { return v > rhs? TRUE: FALSE; }
public LuaValue gt( int rhs ) { return v > rhs? TRUE: FALSE; }
public boolean gt_b( LuaValue rhs ) { return rhs instanceof LuaNumber ? rhs.lt_b(v) : super.gt_b(rhs); }
public boolean gt_b( int rhs ) { return v > rhs; }
public boolean gt_b( double rhs ) { return v > rhs; }
public LuaValue gteq( LuaValue rhs ) { return rhs instanceof LuaNumber ? (rhs.lteq_b(v)? TRUE: FALSE) : super.gteq(rhs); }
public LuaValue gteq( double rhs ) { return v >= rhs? TRUE: FALSE; }
public LuaValue gteq( int rhs ) { return v >= rhs? TRUE: FALSE; }
public boolean gteq_b( LuaValue rhs ) { return rhs instanceof LuaNumber ? rhs.lteq_b(v) : super.gteq_b(rhs); }
public boolean gteq_b( int rhs ) { return v >= rhs; }
public boolean gteq_b( double rhs ) { return v >= rhs; }
public LuaValue lt(LuaValue rhs) { return rhs instanceof LuaNumber? (rhs.gt_b(v)? TRUE: FALSE): super.lt(rhs); }
public LuaValue lt(double rhs) { return v < rhs? TRUE: FALSE; }
public LuaValue lt(int rhs) { return v < rhs? TRUE: FALSE; }
public boolean lt_b(LuaValue rhs) { return rhs instanceof LuaNumber? rhs.gt_b(v): super.lt_b(rhs); }
public boolean lt_b(int rhs) { return v < rhs; }
public boolean lt_b(double rhs) { return v < rhs; }
public LuaValue lteq(LuaValue rhs) {
return rhs instanceof LuaNumber? (rhs.gteq_b(v)? TRUE: FALSE): super.lteq(rhs);
}
public LuaValue lteq(double rhs) { return v <= rhs? TRUE: FALSE; }
public LuaValue lteq(int rhs) { return v <= rhs? TRUE: FALSE; }
public boolean lteq_b(LuaValue rhs) { return rhs instanceof LuaNumber? rhs.gteq_b(v): super.lteq_b(rhs); }
public boolean lteq_b(int rhs) { return v <= rhs; }
public boolean lteq_b(double rhs) { return v <= rhs; }
public LuaValue gt(LuaValue rhs) { return rhs instanceof LuaNumber? (rhs.lt_b(v)? TRUE: FALSE): super.gt(rhs); }
public LuaValue gt(double rhs) { return v > rhs? TRUE: FALSE; }
public LuaValue gt(int rhs) { return v > rhs? TRUE: FALSE; }
public boolean gt_b(LuaValue rhs) { return rhs instanceof LuaNumber? rhs.lt_b(v): super.gt_b(rhs); }
public boolean gt_b(int rhs) { return v > rhs; }
public boolean gt_b(double rhs) { return v > rhs; }
public LuaValue gteq(LuaValue rhs) {
return rhs instanceof LuaNumber? (rhs.lteq_b(v)? TRUE: FALSE): super.gteq(rhs);
}
public LuaValue gteq(double rhs) { return v >= rhs? TRUE: FALSE; }
public LuaValue gteq(int rhs) { return v >= rhs? TRUE: FALSE; }
public boolean gteq_b(LuaValue rhs) { return rhs instanceof LuaNumber? rhs.lteq_b(v): super.gteq_b(rhs); }
public boolean gteq_b(int rhs) { return v >= rhs; }
public boolean gteq_b(double rhs) { return v >= rhs; }
// string comparison
public int strcmp( LuaString rhs ) { typerror("attempt to compare number with string"); return 0; }
public int strcmp(LuaString rhs) { typerror("attempt to compare number with string"); return 0; }
public String tojstring() {
/*
@@ -242,13 +320,13 @@ public class LuaDouble extends LuaNumber {
}
*/
long l = (long) v;
if ( l == v )
if (l == v)
return Long.toString(l);
if ( Double.isNaN(v) )
if (Double.isNaN(v))
return JSTR_NAN;
if ( Double.isInfinite(v) )
return (v<0? JSTR_NEGINF: JSTR_POSINF);
return Float.toString((float)v);
if (Double.isInfinite(v))
return (v < 0? JSTR_NEGINF: JSTR_POSINF);
return Float.toString((float) v);
}
public LuaString strvalue() {
@@ -282,14 +360,19 @@ public class LuaDouble extends LuaNumber {
public LuaValue tonumber() {
return this;
}
public int checkint() { return (int) (long) v; }
public long checklong() { return (long) v; }
public LuaNumber checknumber() { return this; }
public double checkdouble() { return v; }
public String checkjstring() {
return tojstring();
}
public LuaString checkstring() {
return LuaString.valueOf(tojstring());
}

View File

@@ -21,22 +21,21 @@
******************************************************************************/
package org.luaj.vm2;
/**
* RuntimeException that is thrown and caught in response to a lua error.
* <p>
* {@link LuaError} is used wherever a lua call to {@code error()}
* would be used within a script.
* {@link LuaError} is used wherever a lua call to {@code error()} would be used
* within a script.
* <p>
* Since it is an unchecked exception inheriting from {@link RuntimeException},
* Java method signatures do notdeclare this exception, althoug it can
* be thrown on almost any luaj Java operation.
* This is analagous to the fact that any lua script can throw a lua error at any time.
* Java method signatures do notdeclare this exception, althoug it can be thrown
* on almost any luaj Java operation. This is analagous to the fact that any lua
* script can throw a lua error at any time.
* <p>
* The LuaError may be constructed with a message object, in which case the message
* is the string representation of that object. getMessageObject will get the object
* supplied at construct time, or a LuaString containing the message of an object
* was not supplied.
* The LuaError may be constructed with a message object, in which case the
* message is the string representation of that object. getMessageObject will
* get the object supplied at construct time, or a LuaString containing the
* message of an object was not supplied.
*/
public class LuaError extends RuntimeException {
private static final long serialVersionUID = 1L;
@@ -51,8 +50,9 @@ public class LuaError extends RuntimeException {
private LuaValue object;
/** Get the string message if it was supplied, or a string
* representation of the message object if that was supplied.
/**
* Get the string message if it was supplied, or a string representation of
* the message object if that was supplied.
*/
public String getMessage() {
if (traceback != null)
@@ -65,24 +65,29 @@ public class LuaError extends RuntimeException {
return m;
}
/** Get the LuaValue that was provided in the constructor, or
* a LuaString containing the message if it was a string error argument.
/**
* Get the LuaValue that was provided in the constructor, or a LuaString
* containing the message if it was a string error argument.
*
* @return LuaValue which was used in the constructor, or a LuaString
* containing the message.
*/
public LuaValue getMessageObject() {
if (object != null) return object;
if (object != null)
return object;
String m = getMessage();
return m != null ? LuaValue.valueOf(m): null;
return m != null? LuaValue.valueOf(m): null;
}
/** Construct LuaError when a program exception occurs.
/**
* Construct LuaError when a program exception occurs.
* <p>
* All errors generated from lua code should throw LuaError(String) instead.
*
* @param cause the Throwable that caused the error, if known.
*/
public LuaError(Throwable cause) {
super( "vm error: "+cause );
super("vm error: " + cause);
this.cause = cause;
this.level = 1;
}
@@ -93,38 +98,37 @@ public class LuaError extends RuntimeException {
* @param message message to supply
*/
public LuaError(String message) {
super( message );
super(message);
this.level = 1;
}
/**
* Construct a LuaError with a message, and level to draw line number information from.
* Construct a LuaError with a message, and level to draw line number
* information from.
*
* @param message message to supply
* @param level where to supply line info from in call stack
*/
public LuaError(String message, int level) {
super( message );
super(message);
this.level = level;
}
/**
* Construct a LuaError with a LuaValue as the message object,
* and level to draw line number information from.
* Construct a LuaError with a LuaValue as the message object, and level to
* draw line number information from.
*
* @param message_object message string or object to supply
*/
public LuaError(LuaValue message_object) {
super( message_object.tojstring() );
super(message_object.tojstring());
this.object = message_object;
this.level = 1;
}
/**
* Get the cause, if any.
*/
public Throwable getCause() {
return cause;
}
public Throwable getCause() { return cause; }
}

View File

@@ -21,21 +21,19 @@
******************************************************************************/
package org.luaj.vm2;
/**
* Base class for functions implemented in Java.
* <p>
* Direct subclass include {@link org.luaj.vm2.lib.LibFunction}
* which is the base class for
* all built-in library functions coded in Java,
* and {@link LuaClosure}, which represents a lua closure
* whose bytecode is interpreted when the function is invoked.
* Direct subclass include {@link org.luaj.vm2.lib.LibFunction} which is the
* base class for all built-in library functions coded in Java, and
* {@link LuaClosure}, which represents a lua closure whose bytecode is
* interpreted when the function is invoked.
*
* @see LuaValue
* @see LuaClosure
* @see org.luaj.vm2.lib.LibFunction
*/
abstract
public class LuaFunction extends LuaValue {
abstract public class LuaFunction extends LuaValue {
/** Shared static metatable for all functions and closures. */
public static LuaValue s_metatable;
@@ -72,20 +70,29 @@ public class LuaFunction extends LuaValue {
return valueOf(tojstring());
}
/** Return the last part of the class name, to be used as a function name in tojstring and elsewhere.
* @return String naming the last part of the class name after the last dot (.) or dollar sign ($).
* If the first character is '_', it is skipped.
/**
* Return the last part of the class name, to be used as a function name in
* tojstring and elsewhere.
*
* @return String naming the last part of the class name after the last dot
* (.) or dollar sign ($). If the first character is '_', it is
* skipped.
*/
public String classnamestub() {
String s = getClass().getName();
int offset = Math.max(s.lastIndexOf('.'), s.lastIndexOf('$')) + 1;
if (s.charAt(offset) == '_') offset++;
int offset = Math.max(s.lastIndexOf('.'), s.lastIndexOf('$'))+1;
if (s.charAt(offset) == '_')
offset++;
return s.substring(offset);
}
/** Return a human-readable name for this function. Returns the last part of the class name by default.
* Is overridden by LuaClosure to return the source file and line, and by LibFunctions to return the name.
* @return common name for this function. */
/**
* Return a human-readable name for this function. Returns the last part of
* the class name by default. Is overridden by LuaClosure to return the
* source file and line, and by LibFunctions to return the name.
*
* @return common name for this function.
*/
public String name() {
return classnamestub();
}

View File

@@ -26,13 +26,13 @@ import org.luaj.vm2.lib.MathLib;
/**
* Extension of {@link LuaNumber} which can hold a Java int as its value.
* <p>
* These instance are not instantiated directly by clients, but indirectly
* via the static functions {@link LuaValue#valueOf(int)} or {@link LuaValue#valueOf(double)}
* functions. This ensures that policies regarding pooling of instances are
* encapsulated.
* These instance are not instantiated directly by clients, but indirectly via
* the static functions {@link LuaValue#valueOf(int)} or
* {@link LuaValue#valueOf(double)} functions. This ensures that policies
* regarding pooling of instances are encapsulated.
* <p>
* There are no API's specific to LuaInteger that are useful beyond what is already
* exposed in {@link LuaValue}.
* There are no API's specific to LuaInteger that are useful beyond what is
* already exposed in {@link LuaValue}.
*
* @see LuaValue
* @see LuaNumber
@@ -44,16 +44,18 @@ public class LuaInteger extends LuaNumber {
private static final LuaInteger[] intValues = new LuaInteger[512];
static {
for ( int i=0; i<512; i++ )
for (int i = 0; i < 512; i++)
intValues[i] = new LuaInteger(i-256);
}
public static LuaInteger valueOf(int i) {
return i<=255 && i>=-256? intValues[i+256]: new LuaInteger(i);
return i <= 255 && i >= -256? intValues[i+256]: new LuaInteger(i);
};
// TODO consider moving this to LuaValue
/** Return a LuaNumber that represents the value provided
/**
* Return a LuaNumber that represents the value provided
*
* @param l long value to represent.
* @return LuaNumber that is eithe LuaInteger or LuaDouble representing l
* @see LuaValue#valueOf(int)
@@ -61,9 +63,8 @@ public class LuaInteger extends LuaNumber {
*/
public static LuaNumber valueOf(long l) {
int i = (int) l;
return l==i? (i<=255 && i>=-256? intValues[i+256]:
(LuaNumber) new LuaInteger(i)):
(LuaNumber) LuaDouble.valueOf(l);
return l == i? (i <= 255 && i >= -256? intValues[i+256]: (LuaNumber) new LuaInteger(i))
: (LuaNumber) LuaDouble.valueOf(l);
}
/** The value being held by this instance. */
@@ -71,6 +72,7 @@ public class LuaInteger extends LuaNumber {
/**
* Package protected constructor.
*
* @see LuaValue#valueOf(int)
**/
LuaInteger(int i) {
@@ -78,20 +80,31 @@ public class LuaInteger extends LuaNumber {
}
public boolean isint() { return true; }
public boolean isinttype() { return true; }
public boolean islong() { return true; }
public byte tobyte() { return (byte) v; }
public char tochar() { return (char) v; }
public double todouble() { return v; }
public float tofloat() { return v; }
public int toint() { return v; }
public long tolong() { return v; }
public short toshort() { return (short) v; }
public double optdouble(double defval) { return v; }
public int optint(int defval) { return v; }
public LuaInteger optinteger(LuaInteger defval) { return this; }
public long optlong(long defval) { return v; }
public String tojstring() {
@@ -131,89 +144,146 @@ public class LuaInteger extends LuaNumber {
}
// unary operators
public LuaValue neg() { return valueOf(-(long)v); }
public LuaValue neg() { return valueOf(-(long) v); }
// object equality, used for key comparison
public boolean equals(Object o) { return o instanceof LuaInteger? ((LuaInteger)o).v == v: false; }
public boolean equals(Object o) { return o instanceof LuaInteger? ((LuaInteger) o).v == v: false; }
// equality w/ metatable processing
public LuaValue eq( LuaValue val ) { return val.raweq(v)? TRUE: FALSE; }
public boolean eq_b( LuaValue val ) { return val.raweq(v); }
public LuaValue eq(LuaValue val) { return val.raweq(v)? TRUE: FALSE; }
public boolean eq_b(LuaValue val) { return val.raweq(v); }
// equality w/o metatable processing
public boolean raweq( LuaValue val ) { return val.raweq(v); }
public boolean raweq( double val ) { return v == val; }
public boolean raweq( int val ) { return v == val; }
public boolean raweq(LuaValue val) { return val.raweq(v); }
public boolean raweq(double val) { return v == val; }
public boolean raweq(int val) { return v == val; }
// arithmetic operators
public LuaValue add( LuaValue rhs ) { return rhs.add(v); }
public LuaValue add( double lhs ) { return LuaDouble.valueOf(lhs + v); }
public LuaValue add( int lhs ) { return LuaInteger.valueOf(lhs + (long)v); }
public LuaValue sub( LuaValue rhs ) { return rhs.subFrom(v); }
public LuaValue sub( double rhs ) { return LuaDouble.valueOf(v - rhs); }
public LuaValue sub( int rhs ) { return LuaDouble.valueOf(v - rhs); }
public LuaValue subFrom( double lhs ) { return LuaDouble.valueOf(lhs - v); }
public LuaValue subFrom( int lhs ) { return LuaInteger.valueOf(lhs - (long)v); }
public LuaValue mul( LuaValue rhs ) { return rhs.mul(v); }
public LuaValue mul( double lhs ) { return LuaDouble.valueOf(lhs * v); }
public LuaValue mul( int lhs ) { return LuaInteger.valueOf(lhs * (long)v); }
public LuaValue pow( LuaValue rhs ) { return rhs.powWith(v); }
public LuaValue pow( double rhs ) { return MathLib.dpow(v,rhs); }
public LuaValue pow( int rhs ) { return MathLib.dpow(v,rhs); }
public LuaValue powWith( double lhs ) { return MathLib.dpow(lhs,v); }
public LuaValue powWith( int lhs ) { return MathLib.dpow(lhs,v); }
public LuaValue div( LuaValue rhs ) { return rhs.divInto(v); }
public LuaValue div( double rhs ) { return LuaDouble.ddiv(v,rhs); }
public LuaValue div( int rhs ) { return LuaDouble.ddiv(v,rhs); }
public LuaValue divInto( double lhs ) { return LuaDouble.ddiv(lhs,v); }
public LuaValue mod( LuaValue rhs ) { return rhs.modFrom(v); }
public LuaValue mod( double rhs ) { return LuaDouble.dmod(v,rhs); }
public LuaValue mod( int rhs ) { return LuaDouble.dmod(v,rhs); }
public LuaValue modFrom( double lhs ) { return LuaDouble.dmod(lhs,v); }
public LuaValue add(LuaValue rhs) { return rhs.add(v); }
public LuaValue add(double lhs) { return LuaDouble.valueOf(lhs+v); }
public LuaValue add(int lhs) { return LuaInteger.valueOf(lhs+(long) v); }
public LuaValue sub(LuaValue rhs) { return rhs.subFrom(v); }
public LuaValue sub(double rhs) { return LuaDouble.valueOf(v-rhs); }
public LuaValue sub(int rhs) { return LuaDouble.valueOf(v-rhs); }
public LuaValue subFrom(double lhs) { return LuaDouble.valueOf(lhs-v); }
public LuaValue subFrom(int lhs) { return LuaInteger.valueOf(lhs-(long) v); }
public LuaValue mul(LuaValue rhs) { return rhs.mul(v); }
public LuaValue mul(double lhs) { return LuaDouble.valueOf(lhs*v); }
public LuaValue mul(int lhs) { return LuaInteger.valueOf(lhs*(long) v); }
public LuaValue pow(LuaValue rhs) { return rhs.powWith(v); }
public LuaValue pow(double rhs) { return MathLib.dpow(v, rhs); }
public LuaValue pow(int rhs) { return MathLib.dpow(v, rhs); }
public LuaValue powWith(double lhs) { return MathLib.dpow(lhs, v); }
public LuaValue powWith(int lhs) { return MathLib.dpow(lhs, v); }
public LuaValue div(LuaValue rhs) { return rhs.divInto(v); }
public LuaValue div(double rhs) { return LuaDouble.ddiv(v, rhs); }
public LuaValue div(int rhs) { return LuaDouble.ddiv(v, rhs); }
public LuaValue divInto(double lhs) { return LuaDouble.ddiv(lhs, v); }
public LuaValue mod(LuaValue rhs) { return rhs.modFrom(v); }
public LuaValue mod(double rhs) { return LuaDouble.dmod(v, rhs); }
public LuaValue mod(int rhs) { return LuaDouble.dmod(v, rhs); }
public LuaValue modFrom(double lhs) { return LuaDouble.dmod(lhs, v); }
// relational operators
public LuaValue lt( LuaValue rhs ) { return rhs instanceof LuaNumber ? (rhs.gt_b(v)? TRUE: FALSE) : super.lt(rhs); }
public LuaValue lt( double rhs ) { return v < rhs? TRUE: FALSE; }
public LuaValue lt( int rhs ) { return v < rhs? TRUE: FALSE; }
public boolean lt_b( LuaValue rhs ) { return rhs instanceof LuaNumber ? rhs.gt_b(v) : super.lt_b(rhs); }
public boolean lt_b( int rhs ) { return v < rhs; }
public boolean lt_b( double rhs ) { return v < rhs; }
public LuaValue lteq( LuaValue rhs ) { return rhs instanceof LuaNumber ? (rhs.gteq_b(v)? TRUE: FALSE) : super.lteq(rhs); }
public LuaValue lteq( double rhs ) { return v <= rhs? TRUE: FALSE; }
public LuaValue lteq( int rhs ) { return v <= rhs? TRUE: FALSE; }
public boolean lteq_b( LuaValue rhs ) { return rhs instanceof LuaNumber ? rhs.gteq_b(v) : super.lteq_b(rhs); }
public boolean lteq_b( int rhs ) { return v <= rhs; }
public boolean lteq_b( double rhs ) { return v <= rhs; }
public LuaValue gt( LuaValue rhs ) { return rhs instanceof LuaNumber ? (rhs.lt_b(v)? TRUE: FALSE) : super.gt(rhs); }
public LuaValue gt( double rhs ) { return v > rhs? TRUE: FALSE; }
public LuaValue gt( int rhs ) { return v > rhs? TRUE: FALSE; }
public boolean gt_b( LuaValue rhs ) { return rhs instanceof LuaNumber ? rhs.lt_b(v) : super.gt_b(rhs); }
public boolean gt_b( int rhs ) { return v > rhs; }
public boolean gt_b( double rhs ) { return v > rhs; }
public LuaValue gteq( LuaValue rhs ) { return rhs instanceof LuaNumber ? (rhs.lteq_b(v)? TRUE: FALSE) : super.gteq(rhs); }
public LuaValue gteq( double rhs ) { return v >= rhs? TRUE: FALSE; }
public LuaValue gteq( int rhs ) { return v >= rhs? TRUE: FALSE; }
public boolean gteq_b( LuaValue rhs ) { return rhs instanceof LuaNumber ? rhs.lteq_b(v) : super.gteq_b(rhs); }
public boolean gteq_b( int rhs ) { return v >= rhs; }
public boolean gteq_b( double rhs ) { return v >= rhs; }
public LuaValue lt(LuaValue rhs) { return rhs instanceof LuaNumber? (rhs.gt_b(v)? TRUE: FALSE): super.lt(rhs); }
public LuaValue lt(double rhs) { return v < rhs? TRUE: FALSE; }
public LuaValue lt(int rhs) { return v < rhs? TRUE: FALSE; }
public boolean lt_b(LuaValue rhs) { return rhs instanceof LuaNumber? rhs.gt_b(v): super.lt_b(rhs); }
public boolean lt_b(int rhs) { return v < rhs; }
public boolean lt_b(double rhs) { return v < rhs; }
public LuaValue lteq(LuaValue rhs) {
return rhs instanceof LuaNumber? (rhs.gteq_b(v)? TRUE: FALSE): super.lteq(rhs);
}
public LuaValue lteq(double rhs) { return v <= rhs? TRUE: FALSE; }
public LuaValue lteq(int rhs) { return v <= rhs? TRUE: FALSE; }
public boolean lteq_b(LuaValue rhs) { return rhs instanceof LuaNumber? rhs.gteq_b(v): super.lteq_b(rhs); }
public boolean lteq_b(int rhs) { return v <= rhs; }
public boolean lteq_b(double rhs) { return v <= rhs; }
public LuaValue gt(LuaValue rhs) { return rhs instanceof LuaNumber? (rhs.lt_b(v)? TRUE: FALSE): super.gt(rhs); }
public LuaValue gt(double rhs) { return v > rhs? TRUE: FALSE; }
public LuaValue gt(int rhs) { return v > rhs? TRUE: FALSE; }
public boolean gt_b(LuaValue rhs) { return rhs instanceof LuaNumber? rhs.lt_b(v): super.gt_b(rhs); }
public boolean gt_b(int rhs) { return v > rhs; }
public boolean gt_b(double rhs) { return v > rhs; }
public LuaValue gteq(LuaValue rhs) {
return rhs instanceof LuaNumber? (rhs.lteq_b(v)? TRUE: FALSE): super.gteq(rhs);
}
public LuaValue gteq(double rhs) { return v >= rhs? TRUE: FALSE; }
public LuaValue gteq(int rhs) { return v >= rhs? TRUE: FALSE; }
public boolean gteq_b(LuaValue rhs) { return rhs instanceof LuaNumber? rhs.lteq_b(v): super.gteq_b(rhs); }
public boolean gteq_b(int rhs) { return v >= rhs; }
public boolean gteq_b(double rhs) { return v >= rhs; }
// string comparison
public int strcmp( LuaString rhs ) { typerror("attempt to compare number with string"); return 0; }
public int strcmp(LuaString rhs) { typerror("attempt to compare number with string"); return 0; }
public int checkint() {
return v;
}
public long checklong() {
return v;
}
public double checkdouble() {
return v;
}
public String checkjstring() {
return String.valueOf(v);
}
public LuaString checkstring() {
return valueOf( String.valueOf(v) );
return valueOf(String.valueOf(v));
}
}

View File

@@ -24,16 +24,16 @@ package org.luaj.vm2;
/**
* Class to encapsulate behavior of the singleton instance {@code nil}
* <p>
* There will be one instance of this class, {@link LuaValue#NIL},
* per Java virtual machine.
* However, the {@link Varargs} instance {@link LuaValue#NONE}
* which is the empty list,
* is also considered treated as a nil value by default.
* There will be one instance of this class, {@link LuaValue#NIL}, per Java
* virtual machine. However, the {@link Varargs} instance {@link LuaValue#NONE}
* which is the empty list, is also considered treated as a nil value by
* default.
* <p>
* Although it is possible to test for nil using Java == operator,
* the recommended approach is to use the method {@link LuaValue#isnil()}
* instead. By using that any ambiguities between
* {@link LuaValue#NIL} and {@link LuaValue#NONE} are avoided.
* Although it is possible to test for nil using Java == operator, the
* recommended approach is to use the method {@link LuaValue#isnil()} instead.
* By using that any ambiguities between {@link LuaValue#NIL} and
* {@link LuaValue#NONE} are avoided.
*
* @see LuaValue
* @see LuaValue#NIL
*/
@@ -91,18 +91,32 @@ public class LuaNil extends LuaValue {
// optional argument conversions - nil alwas falls badk to default value
public boolean optboolean(boolean defval) { return defval; }
public LuaClosure optclosure(LuaClosure defval) { return defval; }
public double optdouble(double defval) { return defval; }
public LuaFunction optfunction(LuaFunction defval) { return defval; }
public int optint(int defval) { return defval; }
public LuaInteger optinteger(LuaInteger defval) { return defval; }
public long optlong(long defval) { return defval; }
public LuaNumber optnumber(LuaNumber defval) { return defval; }
public LuaTable opttable(LuaTable defval) { return defval; }
public LuaThread optthread(LuaThread defval) { return defval; }
public String optjstring(String defval) { return defval; }
public LuaString optstring(LuaString defval) { return defval; }
public Object optuserdata(Object defval) { return defval; }
public Object optuserdata(Class c, Object defval) { return defval; }
public LuaValue optvalue(LuaValue defval) { return defval; }
}

View File

@@ -24,15 +24,15 @@ package org.luaj.vm2;
/**
* Base class for representing numbers as lua values directly.
* <p>
* The main subclasses are {@link LuaInteger} which holds values that fit in a java int,
* and {@link LuaDouble} which holds all other number values.
* The main subclasses are {@link LuaInteger} which holds values that fit in a
* java int, and {@link LuaDouble} which holds all other number values.
*
* @see LuaInteger
* @see LuaDouble
* @see LuaValue
*
*/
abstract
public class LuaNumber extends LuaValue {
abstract public class LuaNumber extends LuaValue {
/** Shared static metatable for all number values represented in lua. */
public static LuaValue s_metatable;
@@ -74,8 +74,11 @@ public class LuaNumber extends LuaValue {
}
public LuaValue concat(LuaValue rhs) { return rhs.concatTo(this); }
public Buffer concat(Buffer rhs) { return rhs.concatTo(this); }
public LuaValue concatTo(LuaNumber lhs) { return strvalue().concatTo(lhs.strvalue()); }
public LuaValue concatTo(LuaString lhs) { return strvalue().concatTo(lhs); }
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -21,43 +21,41 @@
******************************************************************************/
package org.luaj.vm2;
import java.lang.ref.WeakReference;
/**
* Subclass of {@link LuaValue} that implements
* a lua coroutine thread using Java Threads.
* Subclass of {@link LuaValue} that implements a lua coroutine thread using
* Java Threads.
* <p>
* A LuaThread is typically created in response to a scripted call to
* {@code coroutine.create()}
* <p>
* The threads must be initialized with the globals, so that
* the global environment may be passed along according to rules of lua.
* This is done via the constructor arguments {@link #LuaThread(Globals)} or
* The threads must be initialized with the globals, so that the global
* environment may be passed along according to rules of lua. This is done via
* the constructor arguments {@link #LuaThread(Globals)} or
* {@link #LuaThread(Globals, LuaValue)}.
* <p>
* The utility classes {@link org.luaj.vm2.lib.jse.JsePlatform} and
* {@link org.luaj.vm2.lib.jme.JmePlatform}
* see to it that this {@link Globals} are initialized properly.
* {@link org.luaj.vm2.lib.jme.JmePlatform} see to it that this {@link Globals}
* are initialized properly.
* <p>
* The behavior of coroutine threads matches closely the behavior
* of C coroutine library. However, because of the use of Java threads
* to manage call state, it is possible to yield from anywhere in luaj.
* The behavior of coroutine threads matches closely the behavior of C coroutine
* library. However, because of the use of Java threads to manage call state, it
* is possible to yield from anywhere in luaj.
* <p>
* Each Java thread wakes up at regular intervals and checks a weak reference
* to determine if it can ever be resumed. If not, it throws
* {@link OrphanedThread} which is an {@link java.lang.Error}.
* Applications should not catch {@link OrphanedThread}, because it can break
* the thread safety of luaj. The value controlling the polling interval
* is {@link #thread_orphan_check_interval} and may be set by the user.
* Each Java thread wakes up at regular intervals and checks a weak reference to
* determine if it can ever be resumed. If not, it throws {@link OrphanedThread}
* which is an {@link java.lang.Error}. Applications should not catch
* {@link OrphanedThread}, because it can break the thread safety of luaj. The
* value controlling the polling interval is
* {@link #thread_orphan_check_interval} and may be set by the user.
* <p>
* There are two main ways to abandon a coroutine. The first is to call
* {@code yield()} from lua, or equivalently {@link Globals#yield(Varargs)},
* and arrange to have it never resumed possibly by values passed to yield.
* The second is to throw {@link OrphanedThread}, which should put the thread
* in a dead state. In either case all references to the thread must be
* dropped, and the garbage collector must run for the thread to be
* garbage collected.
* {@code yield()} from lua, or equivalently {@link Globals#yield(Varargs)}, and
* arrange to have it never resumed possibly by values passed to yield. The
* second is to throw {@link OrphanedThread}, which should put the thread in a
* dead state. In either case all references to the thread must be dropped, and
* the garbage collector must run for the thread to be garbage collected.
*
*
* @see LuaValue
@@ -73,12 +71,13 @@ public class LuaThread extends LuaValue {
/** The current number of coroutines. Should not be set. */
public static int coroutine_count = 0;
/** Polling interval, in milliseconds, which each thread uses while waiting to
* return from a yielded state to check if the lua threads is no longer
* referenced and therefore should be garbage collected.
* A short polling interval for many threads will consume server resources.
* Orphaned threads cannot be detected and collected unless garbage
* collection is run. This can be changed by Java startup code if desired.
/**
* Polling interval, in milliseconds, which each thread uses while waiting
* to return from a yielded state to check if the lua threads is no longer
* referenced and therefore should be garbage collected. A short polling
* interval for many threads will consume server resources. Orphaned threads
* cannot be detected and collected unless garbage collection is run. This
* can be changed by Java startup code if desired.
*/
public static long thread_orphan_check_interval = 5000;
@@ -87,19 +86,16 @@ public class LuaThread extends LuaValue {
public static final int STATUS_RUNNING = 2;
public static final int STATUS_NORMAL = 3;
public static final int STATUS_DEAD = 4;
public static final String[] STATUS_NAMES = {
"suspended",
"suspended",
"running",
"normal",
"dead",};
public static final String[] STATUS_NAMES = { "suspended", "suspended", "running", "normal", "dead", };
public final State state;
public static final int MAX_CALLSTACK = 256;
/** Thread-local used by DebugLib to store debugging state.
* This is an opaque value that should not be modified by applications. */
/**
* Thread-local used by DebugLib to store debugging state. This is an opaque
* value that should not be modified by applications.
*/
public Object callstack;
public final Globals globals;
@@ -116,6 +112,7 @@ public class LuaThread extends LuaValue {
/**
* Create a LuaThread around a function and environment
*
* @param func The function to execute
*/
public LuaThread(Globals globals, LuaValue func) {
@@ -148,19 +145,15 @@ public class LuaThread extends LuaValue {
return s_metatable;
}
public String getStatus() {
return STATUS_NAMES[state.status];
}
public String getStatus() { return STATUS_NAMES[state.status]; }
public boolean isMainThread() {
return this.state.function == null;
}
public boolean isMainThread() { return this.state.function == null; }
public Varargs resume(Varargs args) {
final LuaThread.State s = this.state;
if (s.status > LuaThread.STATUS_SUSPENDED)
return LuaValue.varargsOf(LuaValue.FALSE,
LuaValue.valueOf("cannot resume "+(s.status==LuaThread.STATUS_DEAD? "dead": "non-suspended")+" coroutine"));
return LuaValue.varargsOf(LuaValue.FALSE, LuaValue.valueOf(
"cannot resume " + (s.status == LuaThread.STATUS_DEAD? "dead": "non-suspended") + " coroutine"));
return s.lua_resume(this, args);
}
@@ -211,7 +204,7 @@ public class LuaThread extends LuaValue {
this.args = args;
if (this.status == STATUS_INITIAL) {
this.status = STATUS_RUNNING;
new Thread(this, "Coroutine-"+(++coroutine_count)).start();
new Thread(this, "Coroutine-" + (++coroutine_count)).start();
} else {
this.notify();
}
@@ -219,9 +212,8 @@ public class LuaThread extends LuaValue {
previous_thread.state.status = STATUS_NORMAL;
this.status = STATUS_RUNNING;
this.wait();
return (this.error != null?
LuaValue.varargsOf(LuaValue.FALSE, LuaValue.valueOf(this.error)):
LuaValue.varargsOf(LuaValue.TRUE, this.result));
return (this.error != null? LuaValue.varargsOf(LuaValue.FALSE, LuaValue.valueOf(this.error))
: LuaValue.varargsOf(LuaValue.TRUE, this.result));
} catch (InterruptedException ie) {
throw new OrphanedThread();
} finally {
@@ -230,7 +222,7 @@ public class LuaThread extends LuaValue {
this.error = null;
globals.running = previous_thread;
if (previous_thread != null)
globals.running.state.status =STATUS_RUNNING;
globals.running.state.status = STATUS_RUNNING;
}
}
@@ -245,7 +237,7 @@ public class LuaThread extends LuaValue {
this.status = STATUS_DEAD;
throw new OrphanedThread();
}
} while (this.status == STATUS_SUSPENDED);
} while ( this.status == STATUS_SUSPENDED );
return this.args;
} catch (InterruptedException ie) {
this.status = STATUS_DEAD;

View File

@@ -21,7 +21,6 @@
******************************************************************************/
package org.luaj.vm2;
public class LuaUserdata extends LuaValue {
public Object m_instance;
@@ -57,10 +56,15 @@ public class LuaUserdata extends LuaValue {
}
public boolean isuserdata() { return true; }
public boolean isuserdata(Class c) { return c.isAssignableFrom(m_instance.getClass()); }
public Object touserdata() { return m_instance; }
public Object touserdata(Class c) { return c.isAssignableFrom(m_instance.getClass())? m_instance: null; }
public Object optuserdata(Object defval) { return m_instance; }
public Object optuserdata(Class c, Object defval) {
if (!c.isAssignableFrom(m_instance.getClass()))
typerror(c.getName());
@@ -81,46 +85,51 @@ public class LuaUserdata extends LuaValue {
}
public Object checkuserdata(Class c) {
if ( c.isAssignableFrom(m_instance.getClass()) )
if (c.isAssignableFrom(m_instance.getClass()))
return m_instance;
return typerror(c.getName());
}
public LuaValue get( LuaValue key ) {
return m_metatable!=null? gettable(this,key): NIL;
public LuaValue get(LuaValue key) {
return m_metatable != null? gettable(this, key): NIL;
}
public void set( LuaValue key, LuaValue value ) {
if ( m_metatable==null || ! settable(this,key,value) )
error( "cannot set "+key+" for userdata" );
public void set(LuaValue key, LuaValue value) {
if (m_metatable == null || !settable(this, key, value))
error("cannot set " + key + " for userdata");
}
public boolean equals( Object val ) {
if ( this == val )
public boolean equals(Object val) {
if (this == val)
return true;
if ( ! (val instanceof LuaUserdata) )
if (!(val instanceof LuaUserdata))
return false;
LuaUserdata u = (LuaUserdata) val;
return m_instance.equals(u.m_instance);
}
// equality w/ metatable processing
public LuaValue eq( LuaValue val ) { return eq_b(val)? TRUE: FALSE; }
public boolean eq_b( LuaValue val ) {
if ( val.raweq(this) ) return true;
if ( m_metatable == null || !val.isuserdata() ) return false;
public LuaValue eq(LuaValue val) { return eq_b(val)? TRUE: FALSE; }
public boolean eq_b(LuaValue val) {
if (val.raweq(this))
return true;
if (m_metatable == null || !val.isuserdata())
return false;
LuaValue valmt = val.getmetatable();
return valmt!=null && LuaValue.eqmtcall(this, m_metatable, val, valmt);
return valmt != null && LuaValue.eqmtcall(this, m_metatable, val, valmt);
}
// equality w/o metatable processing
public boolean raweq( LuaValue val ) { return val.raweq(this); }
public boolean raweq( LuaUserdata val ) {
public boolean raweq(LuaValue val) { return val.raweq(this); }
public boolean raweq(LuaUserdata val) {
return this == val || (m_metatable == val.m_metatable && m_instance.equals(val.m_instance));
}
// __eq metatag processing
public boolean eqmt( LuaValue val ) {
return m_metatable!=null && val.isuserdata()? LuaValue.eqmtcall(this, m_metatable, val, val.getmetatable()): false;
public boolean eqmt(LuaValue val) {
return m_metatable != null && val.isuserdata()? LuaValue.eqmtcall(this, m_metatable, val, val.getmetatable())
: false;
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -38,14 +38,14 @@ interface Metatable {
public LuaValue toLuaValue();
/** Return an instance of Slot appropriate for the given key and value. */
public Slot entry( LuaValue key, LuaValue value );
public Slot entry(LuaValue key, LuaValue value);
/** Returns the given value wrapped in a weak reference if appropriate. */
public LuaValue wrap( LuaValue value );
public LuaValue wrap(LuaValue value);
/**
* Returns the value at the given index in the array, or null if it is a weak reference that
* has been dropped.
* Returns the value at the given index in the array, or null if it is a
* weak reference that has been dropped.
*/
public LuaValue arrayget(LuaValue[] array, int index);
}

View File

@@ -29,7 +29,8 @@ package org.luaj.vm2;
* {@link LuaThread} being used as a coroutine that could not possibly be
* resumed again because there are no more references to the LuaThread with
* which it is associated. Rather than locking up resources forever, this error
* is thrown, and should fall through all the way to the thread's {@link Thread#run()} method.
* is thrown, and should fall through all the way to the thread's
* {@link Thread#run()} method.
* <p>
* Java code mixed with the luaj vm should not catch this error because it may
* occur when the coroutine is not running, so any processing done during error

View File

@@ -26,6 +26,7 @@ import java.io.PrintStream;
/**
* Debug helper class to pretty-print lua bytecodes.
*
* @see Prototype
* @see LuaClosure
*/
@@ -36,57 +37,17 @@ public class Print extends Lua {
public static PrintStream ps = System.out;
/** String names for each lua opcode value. */
public static final String[] OPNAMES = {
"MOVE",
"LOADK",
"LOADKX",
"LOADBOOL",
"LOADNIL",
"GETUPVAL",
"GETTABUP",
"GETTABLE",
"SETTABUP",
"SETUPVAL",
"SETTABLE",
"NEWTABLE",
"SELF",
"ADD",
"SUB",
"MUL",
"DIV",
"MOD",
"POW",
"UNM",
"NOT",
"LEN",
"CONCAT",
"JMP",
"EQ",
"LT",
"LE",
"TEST",
"TESTSET",
"CALL",
"TAILCALL",
"RETURN",
"FORLOOP",
"FORPREP",
"TFORCALL",
"TFORLOOP",
"SETLIST",
"CLOSURE",
"VARARG",
"EXTRAARG",
null,
};
public static final String[] OPNAMES = { "MOVE", "LOADK", "LOADKX", "LOADBOOL", "LOADNIL", "GETUPVAL", "GETTABUP",
"GETTABLE", "SETTABUP", "SETUPVAL", "SETTABLE", "NEWTABLE", "SELF", "ADD", "SUB", "MUL", "DIV", "MOD",
"POW", "UNM", "NOT", "LEN", "CONCAT", "JMP", "EQ", "LT", "LE", "TEST", "TESTSET", "CALL", "TAILCALL",
"RETURN", "FORLOOP", "FORPREP", "TFORCALL", "TFORLOOP", "SETLIST", "CLOSURE", "VARARG", "EXTRAARG", null, };
static void printString(PrintStream ps, final LuaString s) {
ps.print('"');
for (int i = 0, n = s.m_length; i < n; i++) {
int c = s.m_bytes[s.m_offset+i];
if ( c >= ' ' && c <= '~' && c != '\"' && c != '\\' )
if (c >= ' ' && c <= '~' && c != '\"' && c != '\\')
ps.print((char) c);
else {
switch (c) {
@@ -119,7 +80,7 @@ public class Print extends Lua {
break;
default:
ps.print('\\');
ps.print(Integer.toString(1000 + 0xff&c).substring(1));
ps.print(Integer.toString(1000+0xff & c).substring(1));
break;
}
}
@@ -127,29 +88,33 @@ public class Print extends Lua {
ps.print('"');
}
static void printValue( PrintStream ps, LuaValue v ) {
static void printValue(PrintStream ps, LuaValue v) {
if (v == null) {
ps.print("null");
return;
}
switch ( v.type() ) {
case LuaValue.TSTRING: printString( ps, (LuaString) v ); break;
default: ps.print( v.tojstring() );
switch (v.type()) {
case LuaValue.TSTRING:
printString(ps, (LuaString) v);
break;
default:
ps.print(v.tojstring());
}
}
static void printConstant(PrintStream ps, Prototype f, int i) {
printValue( ps, i < f.k.length ? f.k[i] : LuaValue.valueOf("UNKNOWN_CONST_" + i) );
printValue(ps, i < f.k.length? f.k[i]: LuaValue.valueOf("UNKNOWN_CONST_" + i));
}
static void printUpvalue(PrintStream ps, Upvaldesc u) {
ps.print( u.idx + " " );
printValue( ps, u.name );
ps.print(u.idx + " ");
printValue(ps, u.name);
}
/**
* Print the code in a prototype
*
* @param f the {@link Prototype}
*/
public static void printCode(Prototype f) {
@@ -163,16 +128,18 @@ public class Print extends Lua {
/**
* Print an opcode in a prototype
*
* @param f the {@link Prototype}
* @param pc the program counter to look up and print
* @return pc same as above or changed
*/
public static int printOpCode(Prototype f, int pc) {
return printOpCode(ps,f,pc);
return printOpCode(ps, f, pc);
}
/**
* Print an opcode in a prototype
*
* @param ps the {@link PrintStream} to print to
* @param f the {@link Prototype}
* @param pc the program counter to look up and print
@@ -188,33 +155,33 @@ public class Print extends Lua {
int bx = GETARG_Bx(i);
int sbx = GETARG_sBx(i);
int line = getline(f, pc);
ps.print(" " + (pc + 1) + " ");
ps.print(" " + (pc+1) + " ");
if (line > 0)
ps.print("[" + line + "] ");
else
ps.print("[-] ");
if (o >= OPNAMES.length - 1) {
if (o >= OPNAMES.length-1) {
ps.print("UNKNOWN_OP_" + o + " ");
} else {
ps.print(OPNAMES[o] + " ");
switch (getOpMode(o)) {
case iABC:
ps.print( a );
ps.print(a);
if (getBMode(o) != OpArgN)
ps.print(" "+(ISK(b) ? (-1 - INDEXK(b)) : b));
ps.print(" " + (ISK(b)? (-1-INDEXK(b)): b));
if (getCMode(o) != OpArgN)
ps.print(" "+(ISK(c) ? (-1 - INDEXK(c)) : c));
ps.print(" " + (ISK(c)? (-1-INDEXK(c)): c));
break;
case iABx:
if (getBMode(o) == OpArgK) {
ps.print(a + " " + (-1 - bx));
ps.print(a + " " + (-1-bx));
} else {
ps.print(a + " " + (bx));
}
break;
case iAsBx:
if (o == OP_JMP)
ps.print( sbx );
ps.print(sbx);
else
ps.print(a + " " + sbx);
break;
@@ -296,7 +263,7 @@ public class Print extends Lua {
case OP_JMP:
case OP_FORLOOP:
case OP_FORPREP:
ps.print(" ; to " + (sbx + pc + 2));
ps.print(" ; to " + (sbx+pc+2));
break;
case OP_CLOSURE:
if (bx < f.p.length) {
@@ -312,7 +279,7 @@ public class Print extends Lua {
ps.print(" ; " + ((int) c));
break;
case OP_VARARG:
ps.print( " ; is_vararg="+ f.is_vararg );
ps.print(" ; is_vararg=" + f.is_vararg);
break;
default:
break;
@@ -322,7 +289,7 @@ public class Print extends Lua {
}
private static int getline(Prototype f, int pc) {
return pc>0 && f.lineinfo!=null && pc<f.lineinfo.length? f.lineinfo[pc]: -1;
return pc > 0 && f.lineinfo != null && pc < f.lineinfo.length? f.lineinfo[pc]: -1;
}
static void printHeader(Prototype f) {
@@ -333,23 +300,20 @@ public class Print extends Lua {
s = "(bstring)";
else
s = "(string)";
String a = (f.linedefined == 0) ? "main" : "function";
ps.print("\n%" + a + " <" + s + ":" + f.linedefined + ","
+ f.lastlinedefined + "> (" + f.code.length + " instructions, "
+ f.code.length * 4 + " bytes at " + id(f) + ")\n");
ps.print(f.numparams + " param, " + f.maxstacksize + " slot, "
+ f.upvalues.length + " upvalue, ");
ps.print(f.locvars.length + " local, " + f.k.length
+ " constant, " + f.p.length + " function\n");
String a = (f.linedefined == 0)? "main": "function";
ps.print("\n%" + a + " <" + s + ":" + f.linedefined + "," + f.lastlinedefined + "> (" + f.code.length
+ " instructions, " + f.code.length*4 + " bytes at " + id(f) + ")\n");
ps.print(f.numparams + " param, " + f.maxstacksize + " slot, " + f.upvalues.length + " upvalue, ");
ps.print(f.locvars.length + " local, " + f.k.length + " constant, " + f.p.length + " function\n");
}
static void printConstants(Prototype f) {
int i, n = f.k.length;
ps.print("constants (" + n + ") for " + id(f) + ":\n");
for (i = 0; i < n; i++) {
ps.print(" " + (i + 1) + " ");
printValue( ps, f.k[i] );
ps.print( "\n");
ps.print(" " + (i+1) + " ");
printValue(ps, f.k[i]);
ps.print("\n");
}
}
@@ -357,7 +321,8 @@ public class Print extends Lua {
int i, n = f.locvars.length;
ps.print("locals (" + n + ") for " + id(f) + ":\n");
for (i = 0; i < n; i++) {
ps.println(" "+i+" "+f.locvars[i].varname+" "+(f.locvars[i].startpc+1)+" "+(f.locvars[i].endpc+1));
ps.println(
" " + i + " " + f.locvars[i].varname + " " + (f.locvars[i].startpc+1) + " " + (f.locvars[i].endpc+1));
}
}
@@ -369,7 +334,8 @@ public class Print extends Lua {
}
}
/** Pretty-prints contents of a Prototype.
/**
* Pretty-prints contents of a Prototype.
*
* @param prototype Prototype to print.
*/
@@ -377,7 +343,8 @@ public class Print extends Lua {
printFunction(prototype, true);
}
/** Pretty-prints contents of a Prototype in short or long form.
/**
* Pretty-prints contents of a Prototype in short or long form.
*
* @param prototype Prototype to print.
* @param full true to print all fields, false to print short form.
@@ -395,27 +362,29 @@ public class Print extends Lua {
printFunction(prototype.p[i], full);
}
private static void format( String s, int maxcols ) {
private static void format(String s, int maxcols) {
int n = s.length();
if ( n > maxcols )
ps.print( s.substring(0,maxcols) );
if (n > maxcols)
ps.print(s.substring(0, maxcols));
else {
ps.print( s );
for ( int i=maxcols-n; --i>=0; )
ps.print( ' ' );
ps.print(s);
for (int i = maxcols-n; --i >= 0;)
ps.print(' ');
}
}
private static String id(Prototype f) {
return "Proto";
}
private void _assert(boolean b) {
if ( !b )
if (!b)
throw new NullPointerException("_assert failed");
}
/**
* Print the state of a {@link LuaClosure} that is being executed
*
* @param cl the {@link LuaClosure}
* @param pc the program counter
* @param stack the stack of {@link LuaValue}
@@ -426,12 +395,12 @@ public class Print extends Lua {
// print opcode into buffer
PrintStream previous = ps;
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ps = new PrintStream( baos );
printOpCode( cl.p, pc );
ps = new PrintStream(baos);
printOpCode(cl.p, pc);
ps.flush();
ps.close();
ps = previous;
format( baos.toString(), 50 );
format(baos.toString(), 50);
printStack(stack, top, varargs);
ps.println();
}
@@ -439,36 +408,36 @@ public class Print extends Lua {
public static void printStack(LuaValue[] stack, int top, Varargs varargs) {
// print stack
ps.print('[');
for ( int i=0; i<stack.length; i++ ) {
for (int i = 0; i < stack.length; i++) {
LuaValue v = stack[i];
if ( v == null )
if (v == null)
ps.print(STRING_FOR_NULL);
else switch ( v.type() ) {
else
switch (v.type()) {
case LuaValue.TSTRING:
LuaString s = v.checkstring();
ps.print( s.length() < 48?
s.tojstring():
s.substring(0, 32).tojstring()+"...+"+(s.length()-32)+"b");
ps.print(s.length() < 48? s.tojstring()
: s.substring(0, 32).tojstring() + "...+" + (s.length()-32) + "b");
break;
case LuaValue.TFUNCTION:
ps.print( v.tojstring() );
ps.print(v.tojstring());
break;
case LuaValue.TUSERDATA:
Object o = v.touserdata();
if ( o != null ) {
if (o != null) {
String n = o.getClass().getName();
n = n.substring(n.lastIndexOf('.')+1);
ps.print( n+": "+Integer.toHexString(o.hashCode()) );
ps.print(n + ": " + Integer.toHexString(o.hashCode()));
} else {
ps.print( v.toString() );
ps.print(v.toString());
}
break;
default:
ps.print(v.tojstring());
}
if ( i+1 == top )
if (i+1 == top)
ps.print(']');
ps.print( " | " );
ps.print(" | ");
}
ps.print(varargs);
}

View File

@@ -25,54 +25,86 @@ package org.luaj.vm2;
* Prototype representing compiled lua code.
*
* <p>
* This is both a straight translation of the corresponding C type,
* and the main data structure for execution of compiled lua bytecode.
* This is both a straight translation of the corresponding C type, and the main
* data structure for execution of compiled lua bytecode.
*
* <p>
* Generally, the {@link Prototype} is not constructed directly is an intermediate result
* as lua code is loaded using {@link Globals#load(java.io.Reader, String)}:
* <pre> {@code
* Generally, the {@link Prototype} is not constructed directly is an
* intermediate result as lua code is loaded using
* {@link Globals#load(java.io.Reader, String)}:
*
* <pre>
* {
* &#64;code
* Globals globals = JsePlatform.standardGlobals();
* globals.load( new StringReader("print 'hello'"), "main.lua" ).call();
* } </pre>
* globals.load(new StringReader("print 'hello'"), "main.lua").call();
* }
* </pre>
*
* <p>
* To create a {@link Prototype} directly, a compiler such as
* {@link org.luaj.vm2.compiler.LuaC} may be used:
* <pre> {@code
*
* <pre>
* {
* &#64;code
* InputStream is = new ByteArrayInputStream("print('hello,world')".getBytes());
* Prototype p = LuaC.instance.compile(is, "script");
* }</pre>
* }
* </pre>
*
* To simplify loading, the {@link Globals#compilePrototype(java.io.InputStream, String)} method may be used:
* <pre> {@code
* To simplify loading, the
* {@link Globals#compilePrototype(java.io.InputStream, String)} method may be
* used:
*
* <pre>
* {
* &#64;code
* Prototype p = globals.compileProtoytpe(is, "script");
* }</pre>
* }
* </pre>
*
* It may also be loaded from a {@link java.io.Reader} via {@link Globals#compilePrototype(java.io.Reader, String)}:
* <pre> {@code
* It may also be loaded from a {@link java.io.Reader} via
* {@link Globals#compilePrototype(java.io.Reader, String)}:
*
* <pre>
* {
* &#64;code
* Prototype p = globals.compileProtoytpe(new StringReader(script), "script");
* }</pre>
* }
* </pre>
*
* To un-dump a binary file known to be a binary lua file that has been dumped to a string,
* the {@link Globals.Undumper} interface may be used:
* <pre> {@code
* To un-dump a binary file known to be a binary lua file that has been dumped
* to a string, the {@link Globals.Undumper} interface may be used:
*
* <pre>
* {
* &#64;code
* FileInputStream lua_binary_file = new FileInputStream("foo.lc"); // Known to be compiled lua.
* Prototype p = globals.undumper.undump(lua_binary_file, "foo.lua");
* }</pre>
* }
* </pre>
*
* To execute the code represented by the {@link Prototype} it must be supplied to
* the constructor of a {@link LuaClosure}:
* <pre> {@code
* To execute the code represented by the {@link Prototype} it must be supplied
* to the constructor of a {@link LuaClosure}:
*
* <pre>
* {
* &#64;code
* Globals globals = JsePlatform.standardGlobals();
* LuaClosure f = new LuaClosure(p, globals);
* f.call();
* }</pre>
* }
* </pre>
*
* To simplify the debugging of prototype values, the contents may be printed using {@link Print#print}:
* <pre> {@code
* To simplify the debugging of prototype values, the contents may be printed
* using {@link Print#print}:
*
* <pre>
* {@code
* Print.print(p);
* }</pre>
* }
* </pre>
* <p>
*
* @see LuaClosure
@@ -114,10 +146,11 @@ public class Prototype {
}
public String toString() {
return source + ":" + linedefined+"-"+lastlinedefined;
return source + ":" + linedefined + "-" + lastlinedefined;
}
/** Get the name of a local variable.
/**
* Get the name of a local variable.
*
* @param number the local variable number to look up
* @param pc the program counter
@@ -125,7 +158,7 @@ public class Prototype {
*/
public LuaString getlocalname(int number, int pc) {
int i;
for (i = 0; i<locvars.length && locvars[i].startpc <= pc; i++) {
for (i = 0; i < locvars.length && locvars[i].startpc <= pc; i++) {
if (pc < locvars[i].endpc) { /* is variable active? */
number--;
if (number == 0)
@@ -137,9 +170,9 @@ public class Prototype {
public String shortsource() {
String name = source.tojstring();
if ( name.startsWith("@") || name.startsWith("=") )
if (name.startsWith("@") || name.startsWith("="))
name = name.substring(1);
else if ( name.startsWith("\033") )
else if (name.startsWith("\033"))
name = "binary string";
return name;
}

View File

@@ -22,21 +22,20 @@
package org.luaj.vm2;
/**
* Subclass of {@link Varargs} that represents a lua tail call
* in a Java library function execution environment.
* Subclass of {@link Varargs} that represents a lua tail call in a Java library
* function execution environment.
* <p>
* Since Java doesn't have direct support for tail calls,
* any lua function whose {@link Prototype} contains the
* {@link Lua#OP_TAILCALL} bytecode needs a mechanism
* for tail calls when converting lua-bytecode to java-bytecode.
* Since Java doesn't have direct support for tail calls, any lua function whose
* {@link Prototype} contains the {@link Lua#OP_TAILCALL} bytecode needs a
* mechanism for tail calls when converting lua-bytecode to java-bytecode.
* <p>
* The tail call holds the next function and arguments,
* and the client a call to {@link #eval()} executes the function
* repeatedly until the tail calls are completed.
* The tail call holds the next function and arguments, and the client a call to
* {@link #eval()} executes the function repeatedly until the tail calls are
* completed.
* <p>
* Normally, users of luaj need not concern themselves with the
* details of this mechanism, as it is built into the core
* execution framework.
* Normally, users of luaj need not concern themselves with the details of this
* mechanism, as it is built into the core execution framework.
*
* @see Prototype
* @see org.luaj.vm2.luajc.LuaJC
*/
@@ -56,9 +55,7 @@ public class TailcallVarargs extends Varargs {
this.args = LuaValue.varargsOf(object, args);
}
public boolean isTailcall() {
return true;
}
public boolean isTailcall() { return true; }
public Varargs eval() {
while ( result == null ) {
@@ -67,8 +64,7 @@ public class TailcallVarargs extends Varargs {
TailcallVarargs t = (TailcallVarargs) r;
func = t.func;
args = t.args;
}
else {
} else {
result = r;
func = null;
args = null;
@@ -77,8 +73,8 @@ public class TailcallVarargs extends Varargs {
return result;
}
public LuaValue arg( int i ) {
if ( result == null )
public LuaValue arg(int i) {
if (result == null)
eval();
return result.arg(i);
}

View File

@@ -21,9 +21,10 @@
******************************************************************************/
package org.luaj.vm2;
/** Upvalue used with Closure formulation
/**
* Upvalue used with Closure formulation
* <p>
*
* @see LuaClosure
* @see Prototype
*/
@@ -34,10 +35,11 @@ public final class UpValue {
/**
* Create an upvalue relative to a stack
*
* @param stack the stack
* @param index the index on the stack for the upvalue
*/
public UpValue( LuaValue[] stack, int index) {
public UpValue(LuaValue[] stack, int index) {
this.array = stack;
this.index = index;
}
@@ -48,6 +50,7 @@ public final class UpValue {
/**
* Convert this upvalue to a Java String
*
* @return the Java String for this upvalue.
* @see LuaValue#tojstring()
*/
@@ -57,19 +60,17 @@ public final class UpValue {
/**
* Get the value of the upvalue
*
* @return the {@link LuaValue} for this upvalue
*/
public final LuaValue getValue() {
return array[index];
}
public final LuaValue getValue() { return array[index]; }
/**
* Set the value of the upvalue
*
* @param value the {@link LuaValue} to set it to
*/
public final void setValue( LuaValue value ) {
array[index] = value;
}
public final void setValue(LuaValue value) { array[index] = value; }
/**
* Close this upvalue so it is no longer on the stack

View File

@@ -39,6 +39,6 @@ public class Upvaldesc {
}
public String toString() {
return idx + (instack? " instack ": " closed ") + String.valueOf(name);
return idx+(instack? " instack ": " closed ")+String.valueOf(name);
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -29,8 +29,8 @@ import org.luaj.vm2.LuaTable.StrongSlot;
/**
* Subclass of {@link LuaTable} that provides weak key and weak value semantics.
* <p>
* Normally these are not created directly, but indirectly when changing the mode
* of a {@link LuaTable} as lua script executes.
* Normally these are not created directly, but indirectly when changing the
* mode of a {@link LuaTable} as lua script executes.
* <p>
* However, calling the constructors directly when weak tables are required from
* Java will reduce overhead.
@@ -42,11 +42,11 @@ public class WeakTable implements Metatable {
public static LuaTable make(boolean weakkeys, boolean weakvalues) {
LuaString mode;
if ( weakkeys && weakvalues ) {
if (weakkeys && weakvalues) {
mode = LuaString.valueOf("kv");
} else if ( weakkeys ) {
} else if (weakkeys) {
mode = LuaString.valueOf("k");
} else if ( weakvalues ) {
} else if (weakvalues) {
mode = LuaString.valueOf("v");
} else {
return LuaTable.tableOf();
@@ -59,6 +59,7 @@ public class WeakTable implements Metatable {
/**
* Construct a table with weak keys, weak values, or both
*
* @param weakkeys true to let the table have weak keys
* @param weakvalues true to let the table have weak values
*/
@@ -82,19 +83,19 @@ public class WeakTable implements Metatable {
public Slot entry(LuaValue key, LuaValue value) {
value = value.strongvalue();
if ( value == null )
if (value == null)
return null;
if ( weakkeys && !( key.isnumber() || key.isstring() || key.isboolean() )) {
if ( weakvalues && !( value.isnumber() || value.isstring() || value.isboolean() )) {
return new WeakKeyAndValueSlot( key, value, null );
if (weakkeys && !(key.isnumber() || key.isstring() || key.isboolean())) {
if (weakvalues && !(value.isnumber() || value.isstring() || value.isboolean())) {
return new WeakKeyAndValueSlot(key, value, null);
} else {
return new WeakKeySlot( key, value, null );
return new WeakKeySlot(key, value, null);
}
}
if ( weakvalues && ! (value.isnumber() || value.isstring() || value.isboolean() )) {
return new WeakValueSlot( key, value, null );
if (weakvalues && !(value.isnumber() || value.isstring() || value.isboolean())) {
return new WeakValueSlot(key, value, null);
}
return LuaTable.defaultEntry( key, value );
return LuaTable.defaultEntry(key, value);
}
public static abstract class WeakSlot implements Slot {
@@ -109,14 +110,14 @@ public class WeakTable implements Metatable {
this.next = next;
}
public abstract int keyindex( int hashMask );
public abstract int keyindex(int hashMask);
public abstract Slot set(LuaValue value);
public StrongSlot first() {
LuaValue key = strongkey();
LuaValue value = strongvalue();
if ( key != null && value != null ) {
if (key != null && value != null) {
return new LuaTable.NormalEntry(key, value);
} else {
this.key = null;
@@ -127,12 +128,12 @@ public class WeakTable implements Metatable {
public StrongSlot find(LuaValue key) {
StrongSlot first = first();
return ( first != null ) ? first.find( key ) : null;
return (first != null)? first.find(key): null;
}
public boolean keyeq(LuaValue key) {
StrongSlot first = first();
return ( first != null ) && first.keyeq( key );
return (first != null) && first.keyeq(key);
}
public Slot rest() {
@@ -146,46 +147,46 @@ public class WeakTable implements Metatable {
public Slot set(StrongSlot target, LuaValue value) {
LuaValue key = strongkey();
if ( key != null && target.find( key ) != null ) {
return set( value );
} else if ( key != null ) {
if (key != null && target.find(key) != null) {
return set(value);
} else if (key != null) {
// Our key is still good.
next = next.set( target, value );
next = next.set(target, value);
return this;
} else {
// our key was dropped, remove ourselves from the chain.
return next.set( target, value );
return next.set(target, value);
}
}
public Slot add( Slot entry ) {
next = ( next != null ) ? next.add( entry ) : entry;
if ( strongkey() != null && strongvalue() != null ) {
public Slot add(Slot entry) {
next = (next != null)? next.add(entry): entry;
if (strongkey() != null && strongvalue() != null) {
return this;
} else {
return next;
}
}
public Slot remove( StrongSlot target ) {
public Slot remove(StrongSlot target) {
LuaValue key = strongkey();
if ( key == null ) {
return next.remove( target );
} else if ( target.keyeq( key ) ) {
if (key == null) {
return next.remove(target);
} else if (target.keyeq(key)) {
this.value = null;
return this;
} else {
next = next.remove( target );
next = next.remove(target);
return this;
}
}
public Slot relink( Slot rest ) {
if ( strongkey() != null && strongvalue() != null ) {
if ( rest == null && this.next == null ) {
public Slot relink(Slot rest) {
if (strongkey() != null && strongvalue() != null) {
if (rest == null && this.next == null) {
return this;
} else {
return copy( rest );
return copy(rest);
}
} else {
return rest;
@@ -200,25 +201,25 @@ public class WeakTable implements Metatable {
return (LuaValue) value;
}
protected abstract WeakSlot copy( Slot next );
protected abstract WeakSlot copy(Slot next);
}
static class WeakKeySlot extends WeakSlot {
private final int keyhash;
protected WeakKeySlot( LuaValue key, LuaValue value, Slot next ) {
protected WeakKeySlot(LuaValue key, LuaValue value, Slot next) {
super(weaken(key), value, next);
keyhash = key.hashCode();
}
protected WeakKeySlot( WeakKeySlot copyFrom, Slot next ) {
super( copyFrom.key, copyFrom.value, next );
protected WeakKeySlot(WeakKeySlot copyFrom, Slot next) {
super(copyFrom.key, copyFrom.value, next);
this.keyhash = copyFrom.keyhash;
}
public int keyindex( int mask ) {
return LuaTable.hashmod( keyhash, mask );
public int keyindex(int mask) {
return LuaTable.hashmod(keyhash, mask);
}
public Slot set(LuaValue value) {
@@ -227,26 +228,26 @@ public class WeakTable implements Metatable {
}
public LuaValue strongkey() {
return strengthen( key );
return strengthen(key);
}
protected WeakSlot copy( Slot rest ) {
return new WeakKeySlot( this, rest );
protected WeakSlot copy(Slot rest) {
return new WeakKeySlot(this, rest);
}
}
static class WeakValueSlot extends WeakSlot {
protected WeakValueSlot( LuaValue key, LuaValue value, Slot next ) {
super( key, weaken(value), next);
protected WeakValueSlot(LuaValue key, LuaValue value, Slot next) {
super(key, weaken(value), next);
}
protected WeakValueSlot( WeakValueSlot copyFrom, Slot next ) {
super( copyFrom.key, copyFrom.value, next );
protected WeakValueSlot(WeakValueSlot copyFrom, Slot next) {
super(copyFrom.key, copyFrom.value, next);
}
public int keyindex( int mask ) {
return LuaTable.hashSlot( strongkey(), mask );
public int keyindex(int mask) {
return LuaTable.hashSlot(strongkey(), mask);
}
public Slot set(LuaValue value) {
@@ -255,11 +256,11 @@ public class WeakTable implements Metatable {
}
public LuaValue strongvalue() {
return strengthen( value );
return strengthen(value);
}
protected WeakSlot copy(Slot next) {
return new WeakValueSlot( this, next );
return new WeakValueSlot(this, next);
}
}
@@ -267,18 +268,18 @@ public class WeakTable implements Metatable {
private final int keyhash;
protected WeakKeyAndValueSlot( LuaValue key, LuaValue value, Slot next ) {
super( weaken(key), weaken(value), next );
protected WeakKeyAndValueSlot(LuaValue key, LuaValue value, Slot next) {
super(weaken(key), weaken(value), next);
keyhash = key.hashCode();
}
protected WeakKeyAndValueSlot(WeakKeyAndValueSlot copyFrom, Slot next) {
super( copyFrom.key, copyFrom.value, next );
super(copyFrom.key, copyFrom.value, next);
keyhash = copyFrom.keyhash;
}
public int keyindex( int hashMask ) {
return LuaTable.hashmod( keyhash, hashMask );
public int keyindex(int hashMask) {
return LuaTable.hashmod(keyhash, hashMask);
}
public Slot set(LuaValue value) {
@@ -287,25 +288,27 @@ public class WeakTable implements Metatable {
}
public LuaValue strongkey() {
return strengthen( key );
return strengthen(key);
}
public LuaValue strongvalue() {
return strengthen( value );
return strengthen(value);
}
protected WeakSlot copy( Slot next ) {
return new WeakKeyAndValueSlot( this, next );
protected WeakSlot copy(Slot next) {
return new WeakKeyAndValueSlot(this, next);
}
}
/**
* Self-sent message to convert a value to its weak counterpart
*
* @param value value to convert
* @return {@link LuaValue} that is a strong or weak reference, depending on type of {@code value}
* @return {@link LuaValue} that is a strong or weak reference, depending on
* type of {@code value}
*/
protected static LuaValue weaken( LuaValue value ) {
switch ( value.type() ) {
protected static LuaValue weaken(LuaValue value) {
switch (value.type()) {
case LuaValue.TFUNCTION:
case LuaValue.TTHREAD:
case LuaValue.TTABLE:
@@ -319,21 +322,24 @@ public class WeakTable implements Metatable {
/**
* Unwrap a LuaValue from a WeakReference and/or WeakUserdata.
*
* @param ref reference to convert
* @return LuaValue or null
* @see #weaken(LuaValue)
*/
protected static LuaValue strengthen(Object ref) {
if ( ref instanceof WeakReference ) {
if (ref instanceof WeakReference) {
ref = ((WeakReference) ref).get();
}
if ( ref instanceof WeakValue ) {
if (ref instanceof WeakValue) {
return ((WeakValue) ref).strongvalue();
}
return (LuaValue) ref;
}
/** Internal class to implement weak values.
/**
* Internal class to implement weak values.
*
* @see WeakTable
*/
static class WeakValue extends LuaValue {
@@ -344,31 +350,33 @@ public class WeakTable implements Metatable {
}
public int type() {
illegal("type","weak value");
illegal("type", "weak value");
return 0;
}
public String typename() {
illegal("typename","weak value");
illegal("typename", "weak value");
return null;
}
public String toString() {
return "weak<"+ref.get()+">";
return "weak<" + ref.get() + ">";
}
public LuaValue strongvalue() {
Object o = ref.get();
return (LuaValue)o;
return (LuaValue) o;
}
public boolean raweq(LuaValue rhs) {
Object o = ref.get();
return o!=null && rhs.raweq((LuaValue)o);
return o != null && rhs.raweq((LuaValue) o);
}
}
/** Internal class to implement weak userdata values.
/**
* Internal class to implement weak userdata values.
*
* @see WeakTable
*/
static final class WeakUserdata extends WeakValue {
@@ -383,11 +391,11 @@ public class WeakTable implements Metatable {
public LuaValue strongvalue() {
Object u = ref.get();
if ( u != null )
if (u != null)
return (LuaValue) u;
Object o = ob.get();
if ( o != null ) {
LuaValue ud = LuaValue.userdataOf(o,mt);
if (o != null) {
LuaValue ud = LuaValue.userdataOf(o, mt);
ref = new WeakReference(ud);
return ud;
} else {
@@ -397,7 +405,7 @@ public class WeakTable implements Metatable {
}
public LuaValue wrap(LuaValue value) {
return weakvalues ? weaken( value ) : value;
return weakvalues? weaken(value): value;
}
public LuaValue arrayget(LuaValue[] array, int index) {

View File

@@ -44,145 +44,133 @@ public class Constants extends Lua {
static final int LUAI_MAXVARS = 200;
static final int NO_REG = MAXARG_A;
/* OpMode - basic instruction format */
static final int
iABC = 0,
iABx = 1,
iAsBx = 2;
static final int iABC = 0, iABx = 1, iAsBx = 2;
/* OpArgMask */
static final int
OpArgN = 0, /* argument is not used */
static final int OpArgN = 0, /* argument is not used */
OpArgU = 1, /* argument is used */
OpArgR = 2, /* argument is a register or a jump offset */
OpArgK = 3; /* argument is a constant or register/constant */
protected static void _assert(boolean b) {
if (!b)
throw new LuaError("compiler assert failed");
}
static void SET_OPCODE(InstructionPtr i,int o) {
i.set( ( i.get() & (MASK_NOT_OP)) | ((o << POS_OP) & MASK_OP) );
static void SET_OPCODE(InstructionPtr i, int o) {
i.set((i.get() & (MASK_NOT_OP)) | ((o<<POS_OP) & MASK_OP));
}
static void SETARG_A(int[] code, int index, int u) {
code[index] = (code[index] & (MASK_NOT_A)) | ((u << POS_A) & MASK_A);
code[index] = (code[index] & (MASK_NOT_A)) | ((u<<POS_A) & MASK_A);
}
static void SETARG_A(InstructionPtr i,int u) {
i.set( ( i.get() & (MASK_NOT_A)) | ((u << POS_A) & MASK_A) );
static void SETARG_A(InstructionPtr i, int u) {
i.set((i.get() & (MASK_NOT_A)) | ((u<<POS_A) & MASK_A));
}
static void SETARG_B(InstructionPtr i,int u) {
i.set( ( i.get() & (MASK_NOT_B)) | ((u << POS_B) & MASK_B) );
static void SETARG_B(InstructionPtr i, int u) {
i.set((i.get() & (MASK_NOT_B)) | ((u<<POS_B) & MASK_B));
}
static void SETARG_C(InstructionPtr i,int u) {
i.set( ( i.get() & (MASK_NOT_C)) | ((u << POS_C) & MASK_C) );
static void SETARG_C(InstructionPtr i, int u) {
i.set((i.get() & (MASK_NOT_C)) | ((u<<POS_C) & MASK_C));
}
static void SETARG_Bx(InstructionPtr i,int u) {
i.set( ( i.get() & (MASK_NOT_Bx)) | ((u << POS_Bx) & MASK_Bx) );
static void SETARG_Bx(InstructionPtr i, int u) {
i.set((i.get() & (MASK_NOT_Bx)) | ((u<<POS_Bx) & MASK_Bx));
}
static void SETARG_sBx(InstructionPtr i,int u) {
SETARG_Bx( i, u + MAXARG_sBx );
static void SETARG_sBx(InstructionPtr i, int u) {
SETARG_Bx(i, u+MAXARG_sBx);
}
static int CREATE_ABC(int o, int a, int b, int c) {
return ((o << POS_OP) & MASK_OP) |
((a << POS_A) & MASK_A) |
((b << POS_B) & MASK_B) |
((c << POS_C) & MASK_C) ;
return ((o<<POS_OP) & MASK_OP) | ((a<<POS_A) & MASK_A) | ((b<<POS_B) & MASK_B) | ((c<<POS_C) & MASK_C);
}
static int CREATE_ABx(int o, int a, int bc) {
return ((o << POS_OP) & MASK_OP) |
((a << POS_A) & MASK_A) |
((bc << POS_Bx) & MASK_Bx) ;
return ((o<<POS_OP) & MASK_OP) | ((a<<POS_A) & MASK_A) | ((bc<<POS_Bx) & MASK_Bx);
}
static int CREATE_Ax(int o, int a) {
return ((o << POS_OP) & MASK_OP) |
((a << POS_Ax) & MASK_Ax) ;
return ((o<<POS_OP) & MASK_OP) | ((a<<POS_Ax) & MASK_Ax);
}
// vector reallocation
static LuaValue[] realloc(LuaValue[] v, int n) {
LuaValue[] a = new LuaValue[n];
if ( v != null )
System.arraycopy(v, 0, a, 0, Math.min(v.length,n));
if (v != null)
System.arraycopy(v, 0, a, 0, Math.min(v.length, n));
return a;
}
static Prototype[] realloc(Prototype[] v, int n) {
Prototype[] a = new Prototype[n];
if ( v != null )
System.arraycopy(v, 0, a, 0, Math.min(v.length,n));
if (v != null)
System.arraycopy(v, 0, a, 0, Math.min(v.length, n));
return a;
}
static LuaString[] realloc(LuaString[] v, int n) {
LuaString[] a = new LuaString[n];
if ( v != null )
System.arraycopy(v, 0, a, 0, Math.min(v.length,n));
if (v != null)
System.arraycopy(v, 0, a, 0, Math.min(v.length, n));
return a;
}
static LocVars[] realloc(LocVars[] v, int n) {
LocVars[] a = new LocVars[n];
if ( v != null )
System.arraycopy(v, 0, a, 0, Math.min(v.length,n));
if (v != null)
System.arraycopy(v, 0, a, 0, Math.min(v.length, n));
return a;
}
static Upvaldesc[] realloc(Upvaldesc[] v, int n) {
Upvaldesc[] a = new Upvaldesc[n];
if ( v != null )
System.arraycopy(v, 0, a, 0, Math.min(v.length,n));
if (v != null)
System.arraycopy(v, 0, a, 0, Math.min(v.length, n));
return a;
}
static LexState.Vardesc[] realloc(LexState.Vardesc[] v, int n) {
LexState.Vardesc[] a = new LexState.Vardesc[n];
if ( v != null )
System.arraycopy(v, 0, a, 0, Math.min(v.length,n));
if (v != null)
System.arraycopy(v, 0, a, 0, Math.min(v.length, n));
return a;
}
static LexState.Labeldesc[] grow(LexState.Labeldesc[] v, int min_n) {
return v == null ? new LexState.Labeldesc[2] : v.length < min_n ? realloc(v, v.length*2) : v;
return v == null? new LexState.Labeldesc[2]: v.length < min_n? realloc(v, v.length*2): v;
}
static LexState.Labeldesc[] realloc(LexState.Labeldesc[] v, int n) {
LexState.Labeldesc[] a = new LexState.Labeldesc[n];
if ( v != null )
System.arraycopy(v, 0, a, 0, Math.min(v.length,n));
if (v != null)
System.arraycopy(v, 0, a, 0, Math.min(v.length, n));
return a;
}
static int[] realloc(int[] v, int n) {
int[] a = new int[n];
if ( v != null )
System.arraycopy(v, 0, a, 0, Math.min(v.length,n));
if (v != null)
System.arraycopy(v, 0, a, 0, Math.min(v.length, n));
return a;
}
static byte[] realloc(byte[] v, int n) {
byte[] a = new byte[n];
if ( v != null )
System.arraycopy(v, 0, a, 0, Math.min(v.length,n));
if (v != null)
System.arraycopy(v, 0, a, 0, Math.min(v.length, n));
return a;
}
static char[] realloc(char[] v, int n) {
char[] a = new char[n];
if ( v != null )
System.arraycopy(v, 0, a, 0, Math.min(v.length,n));
if (v != null)
System.arraycopy(v, 0, a, 0, Math.min(v.length, n));
return a;
}

View File

@@ -32,35 +32,47 @@ import org.luaj.vm2.LuaString;
import org.luaj.vm2.LuaValue;
import org.luaj.vm2.Prototype;
/** Class to dump a {@link Prototype} into an output stream, as part of compiling.
/**
* Class to dump a {@link Prototype} into an output stream, as part of
* compiling.
* <p>
* Generally, this class is not used directly, but rather indirectly via a command
* line interface tool such as {@link luac}.
* Generally, this class is not used directly, but rather indirectly via a
* command line interface tool such as {@link luac}.
* <p>
* A lua binary file is created via {@link DumpState#dump}:
* <pre> {@code
*
* <pre>
* {
* &#64;code
* Globals globals = JsePlatform.standardGlobals();
* Prototype p = globals.compilePrototype(new StringReader("print('hello, world')"), "main.lua");
* ByteArrayOutputStream o = new ByteArrayOutputStream();
* DumpState.dump(p, o, false);
* byte[] lua_binary_file_bytes = o.toByteArray();
* } </pre>
* }
* </pre>
*
* The {@link LoadState} may be used directly to undump these bytes:
* <pre> {@code
*
* <pre>
* {@code
* Prototypep = LoadState.instance.undump(new ByteArrayInputStream(lua_binary_file_bytes), "main.lua");
* LuaClosure c = new LuaClosure(p, globals);
* c.call();
* } </pre>
* }
* </pre>
*
*
* More commonly, the {@link Globals#undumper} may be used to undump them:
* <pre> {@code
*
* <pre>
* {
* &#64;code
* Prototype p = globals.loadPrototype(new ByteArrayInputStream(lua_binary_file_bytes), "main.lua", "b");
* LuaClosure c = new LuaClosure(p, globals);
* c.call();
* } </pre>
* }
* </pre>
*
* @see luac
* @see LoadState
@@ -72,13 +84,19 @@ public class DumpState {
/** set true to allow integer compilation */
public static boolean ALLOW_INTEGER_CASTING = false;
/** format corresponding to non-number-patched lua, all numbers are floats or doubles */
/**
* format corresponding to non-number-patched lua, all numbers are floats or
* doubles
*/
public static final int NUMBER_FORMAT_FLOATS_OR_DOUBLES = 0;
/** format corresponding to non-number-patched lua, all numbers are ints */
public static final int NUMBER_FORMAT_INTS_ONLY = 1;
/** format corresponding to number-patched lua, all numbers are 32-bit (4 byte) ints */
/**
* format corresponding to number-patched lua, all numbers are 32-bit (4
* byte) ints
*/
public static final int NUMBER_FORMAT_NUM_PATCH_INT32 = 4;
/** default number format */
@@ -97,7 +115,7 @@ public class DumpState {
int status;
public DumpState(OutputStream w, boolean strip) {
this.writer = new DataOutputStream( w );
this.writer = new DataOutputStream(w);
this.strip = strip;
this.status = 0;
}
@@ -107,15 +125,15 @@ public class DumpState {
}
void dumpChar(int b) throws IOException {
writer.write( b );
writer.write(b);
}
void dumpInt(int x) throws IOException {
if ( IS_LITTLE_ENDIAN ) {
writer.writeByte(x&0xff);
writer.writeByte((x>>8)&0xff);
writer.writeByte((x>>16)&0xff);
writer.writeByte((x>>24)&0xff);
if (IS_LITTLE_ENDIAN) {
writer.writeByte(x & 0xff);
writer.writeByte((x>>8) & 0xff);
writer.writeByte((x>>16) & 0xff);
writer.writeByte((x>>24) & 0xff);
} else {
writer.writeInt(x);
}
@@ -123,27 +141,27 @@ public class DumpState {
void dumpString(LuaString s) throws IOException {
final int len = s.len().toint();
dumpInt( len+1 );
s.write( writer, 0, len );
writer.write( 0 );
dumpInt(len+1);
s.write(writer, 0, len);
writer.write(0);
}
void dumpDouble(double d) throws IOException {
long l = Double.doubleToLongBits(d);
if ( IS_LITTLE_ENDIAN ) {
dumpInt( (int) l );
dumpInt( (int) (l>>32) );
if (IS_LITTLE_ENDIAN) {
dumpInt((int) l);
dumpInt((int) (l>>32));
} else {
writer.writeLong(l);
}
}
void dumpCode( final Prototype f ) throws IOException {
void dumpCode(final Prototype f) throws IOException {
final int[] code = f.code;
int n = code.length;
dumpInt( n );
for ( int i=0; i<n; i++ )
dumpInt( code[i] );
dumpInt(n);
for (int i = 0; i < n; i++)
dumpInt(code[i]);
}
void dumpConstants(final Prototype f) throws IOException {
@@ -152,13 +170,13 @@ public class DumpState {
dumpInt(n);
for (i = 0; i < n; i++) {
final LuaValue o = k[i];
switch ( o.type() ) {
switch (o.type()) {
case LuaValue.TNIL:
writer.write(LuaValue.TNIL);
break;
case LuaValue.TBOOLEAN:
writer.write(LuaValue.TBOOLEAN);
dumpChar(o.toboolean() ? 1 : 0);
dumpChar(o.toboolean()? 1: 0);
break;
case LuaValue.TNUMBER:
switch (NUMBER_FORMAT) {
@@ -167,13 +185,13 @@ public class DumpState {
dumpDouble(o.todouble());
break;
case NUMBER_FORMAT_INTS_ONLY:
if ( ! ALLOW_INTEGER_CASTING && ! o.isint() )
throw new java.lang.IllegalArgumentException("not an integer: "+o);
if (!ALLOW_INTEGER_CASTING && !o.isint())
throw new java.lang.IllegalArgumentException("not an integer: " + o);
writer.write(LuaValue.TNUMBER);
dumpInt(o.toint());
break;
case NUMBER_FORMAT_NUM_PATCH_INT32:
if ( o.isint() ) {
if (o.isint()) {
writer.write(LuaValue.TINT);
dumpInt(o.toint());
} else {
@@ -182,12 +200,12 @@ public class DumpState {
}
break;
default:
throw new IllegalArgumentException("number format not supported: "+NUMBER_FORMAT);
throw new IllegalArgumentException("number format not supported: " + NUMBER_FORMAT);
}
break;
case LuaValue.TSTRING:
writer.write(LuaValue.TSTRING);
dumpString((LuaString)o);
dumpString((LuaString) o);
break;
default:
throw new IllegalArgumentException("bad type for " + o);
@@ -203,7 +221,7 @@ public class DumpState {
int n = f.upvalues.length;
dumpInt(n);
for (int i = 0; i < n; i++) {
writer.writeByte(f.upvalues[i].instack ? 1 : 0);
writer.writeByte(f.upvalues[i].instack? 1: 0);
writer.writeByte(f.upvalues[i].idx);
}
}
@@ -214,11 +232,11 @@ public class DumpState {
dumpInt(0);
else
dumpString(f.source);
n = strip ? 0 : f.lineinfo.length;
n = strip? 0: f.lineinfo.length;
dumpInt(n);
for (i = 0; i < n; i++)
dumpInt(f.lineinfo[i]);
n = strip ? 0 : f.locvars.length;
n = strip? 0: f.locvars.length;
dumpInt(n);
for (i = 0; i < n; i++) {
LocVars lvi = f.locvars[i];
@@ -226,7 +244,7 @@ public class DumpState {
dumpInt(lvi.startpc);
dumpInt(lvi.endpc);
}
n = strip ? 0 : f.upvalues.length;
n = strip? 0: f.upvalues.length;
dumpInt(n);
for (i = 0; i < n; i++)
dumpString(f.upvalues[i].name);
@@ -245,23 +263,23 @@ public class DumpState {
}
void dumpHeader() throws IOException {
writer.write( LoadState.LUA_SIGNATURE );
writer.write( LoadState.LUAC_VERSION );
writer.write( LoadState.LUAC_FORMAT );
writer.write( IS_LITTLE_ENDIAN? 1: 0 );
writer.write( SIZEOF_INT );
writer.write( SIZEOF_SIZET );
writer.write( SIZEOF_INSTRUCTION );
writer.write( SIZEOF_LUA_NUMBER );
writer.write( NUMBER_FORMAT );
writer.write( LoadState.LUAC_TAIL );
writer.write(LoadState.LUA_SIGNATURE);
writer.write(LoadState.LUAC_VERSION);
writer.write(LoadState.LUAC_FORMAT);
writer.write(IS_LITTLE_ENDIAN? 1: 0);
writer.write(SIZEOF_INT);
writer.write(SIZEOF_SIZET);
writer.write(SIZEOF_INSTRUCTION);
writer.write(SIZEOF_LUA_NUMBER);
writer.write(NUMBER_FORMAT);
writer.write(LoadState.LUAC_TAIL);
}
/*
** dump Lua function as precompiled chunk
*/
public static int dump( Prototype f, OutputStream w, boolean strip ) throws IOException {
DumpState D = new DumpState(w,strip);
public static int dump(Prototype f, OutputStream w, boolean strip) throws IOException {
DumpState D = new DumpState(w, strip);
D.dumpHeader();
D.dumpFunction(f);
return D.status;
@@ -272,25 +290,29 @@ public class DumpState {
* @param f the function to dump
* @param w the output stream to dump to
* @param stripDebug true to strip debugging info, false otherwise
* @param numberFormat one of NUMBER_FORMAT_FLOATS_OR_DOUBLES, NUMBER_FORMAT_INTS_ONLY, NUMBER_FORMAT_NUM_PATCH_INT32
* @param littleendian true to use little endian for numbers, false for big endian
* @param numberFormat one of NUMBER_FORMAT_FLOATS_OR_DOUBLES,
* NUMBER_FORMAT_INTS_ONLY,
* NUMBER_FORMAT_NUM_PATCH_INT32
* @param littleendian true to use little endian for numbers, false for big
* endian
* @return 0 if dump succeeds
* @throws IOException
* @throws IllegalArgumentException if the number format it not supported
*/
public static int dump(Prototype f, OutputStream w, boolean stripDebug, int numberFormat, boolean littleendian) throws IOException {
switch ( numberFormat ) {
public static int dump(Prototype f, OutputStream w, boolean stripDebug, int numberFormat, boolean littleendian)
throws IOException {
switch (numberFormat) {
case NUMBER_FORMAT_FLOATS_OR_DOUBLES:
case NUMBER_FORMAT_INTS_ONLY:
case NUMBER_FORMAT_NUM_PATCH_INT32:
break;
default:
throw new IllegalArgumentException("number format not supported: "+numberFormat);
throw new IllegalArgumentException("number format not supported: " + numberFormat);
}
DumpState D = new DumpState(w,stripDebug);
DumpState D = new DumpState(w, stripDebug);
D.IS_LITTLE_ENDIAN = littleendian;
D.NUMBER_FORMAT = numberFormat;
D.SIZEOF_LUA_NUMBER = (numberFormat==NUMBER_FORMAT_INTS_ONLY? 4: 8);
D.SIZEOF_LUA_NUMBER = (numberFormat == NUMBER_FORMAT_INTS_ONLY? 4: 8);
D.dumpHeader();
D.dumpFunction(f);
return D.status;

View File

@@ -34,7 +34,6 @@ import org.luaj.vm2.Upvaldesc;
import org.luaj.vm2.compiler.LexState.ConsControl;
import org.luaj.vm2.compiler.LexState.expdesc;
public class FuncState extends Constants {
static class BlockCnt {
@@ -65,13 +64,12 @@ public class FuncState extends Constants {
FuncState() {
}
// =============================================================
// from lcode.h
// =============================================================
InstructionPtr getcodePtr(expdesc e) {
return new InstructionPtr( f.code, e.u.info );
return new InstructionPtr(f.code, e.u.info);
}
int getcode(expdesc e) {
@@ -79,58 +77,53 @@ public class FuncState extends Constants {
}
int codeAsBx(int o, int A, int sBx) {
return codeABx(o,A,sBx+MAXARG_sBx);
return codeABx(o, A, sBx+MAXARG_sBx);
}
void setmultret(expdesc e) {
setreturns(e, LUA_MULTRET);
}
// =============================================================
// from lparser.c
// =============================================================
/* check for repeated labels on the same block */
void checkrepeated (LexState.Labeldesc[] ll, int ll_n, LuaString label) {
void checkrepeated(LexState.Labeldesc[] ll, int ll_n, LuaString label) {
int i;
for (i = bl.firstlabel; i < ll_n; i++) {
if (label.eq_b(ll[i].name)) {
String msg = ls.L.pushfstring(
"label '" + label + " already defined on line " + ll[i].line);
String msg = ls.L.pushfstring("label '" + label + " already defined on line " + ll[i].line);
ls.semerror(msg);
}
}
}
void checklimit(int v, int l, String msg) {
if ( v > l )
errorlimit( l, msg );
if (v > l)
errorlimit(l, msg);
}
void errorlimit (int limit, String what) {
void errorlimit(int limit, String what) {
// TODO: report message logic.
String msg = (f.linedefined == 0) ?
ls.L.pushfstring("main function has more than "+limit+" "+what) :
ls.L.pushfstring("function at line "+f.linedefined+" has more than "+limit+" "+what);
String msg = (f.linedefined == 0)? ls.L.pushfstring("main function has more than " + limit + " " + what)
: ls.L.pushfstring("function at line " + f.linedefined + " has more than " + limit + " " + what);
ls.lexerror(msg, 0);
}
LocVars getlocvar(int i) {
int idx = ls.dyd.actvar[firstlocal + i].idx;
int idx = ls.dyd.actvar[firstlocal+i].idx;
_assert(idx < nlocvars);
return f.locvars[idx];
}
void removevars (int tolevel) {
ls.dyd.n_actvar -= (nactvar - tolevel);
while (nactvar > tolevel)
void removevars(int tolevel) {
ls.dyd.n_actvar -= (nactvar-tolevel);
while ( nactvar > tolevel )
getlocvar(--nactvar).endpc = pc;
}
int searchupvalue (LuaString name) {
int searchupvalue(LuaString name) {
int i;
Upvaldesc[] up = f.upvalues;
for (i = 0; i < nups; i++)
@@ -139,17 +132,17 @@ public class FuncState extends Constants {
return -1; /* not found */
}
int newupvalue (LuaString name, expdesc v) {
checklimit(nups + 1, LUAI_MAXUPVAL, "upvalues");
if (f.upvalues == null || nups + 1 > f.upvalues.length)
f.upvalues = realloc( f.upvalues, nups > 0 ? nups*2 : 1 );
int newupvalue(LuaString name, expdesc v) {
checklimit(nups+1, LUAI_MAXUPVAL, "upvalues");
if (f.upvalues == null || nups+1 > f.upvalues.length)
f.upvalues = realloc(f.upvalues, nups > 0? nups*2: 1);
f.upvalues[nups] = new Upvaldesc(name, v.k == LexState.VLOCAL, v.u.info);
return nups++;
}
int searchvar(LuaString n) {
int i;
for (i = nactvar - 1; i >= 0; i--) {
for (i = nactvar-1; i >= 0; i--) {
if (n.eq_b(getlocvar(i).varname))
return i;
}
@@ -158,7 +151,7 @@ public class FuncState extends Constants {
void markupval(int level) {
BlockCnt bl = this.bl;
while (bl.nactvar > level)
while ( bl.nactvar > level )
bl = bl.previous;
bl.upval = true;
}
@@ -196,7 +189,7 @@ public class FuncState extends Constants {
final LexState.Labeldesc[] gl = ls.dyd.gt;
/* correct pending gotos to current block and try to close it
with visible labels */
while (i < ls.dyd.n_gt) {
while ( i < ls.dyd.n_gt ) {
LexState.Labeldesc gt = gl[i];
if (gt.nactvar > bl.nactvar) {
if (bl.upval)
@@ -208,7 +201,7 @@ public class FuncState extends Constants {
}
}
void enterblock (BlockCnt bl, boolean isloop) {
void enterblock(BlockCnt bl, boolean isloop) {
bl.isloop = isloop;
bl.nactvar = nactvar;
bl.firstlabel = (short) ls.dyd.n_label;
@@ -255,50 +248,49 @@ public class FuncState extends Constants {
return ((k) == LexState.VCALL || (k) == LexState.VVARARG);
}
void lastlistfield (ConsControl cc) {
if (cc.tostore == 0) return;
void lastlistfield(ConsControl cc) {
if (cc.tostore == 0)
return;
if (hasmultret(cc.v.k)) {
this.setmultret(cc.v);
this.setlist(cc.t.u.info, cc.na, LUA_MULTRET);
cc.na--; /** do not count last expression (unknown number of elements) */
}
else {
cc.na--; /**
* do not count last expression (unknown number of
* elements)
*/
} else {
if (cc.v.k != LexState.VVOID)
this.exp2nextreg(cc.v);
this.setlist(cc.t.u.info, cc.na, cc.tostore);
}
}
// =============================================================
// from lcode.c
// =============================================================
void nil(int from, int n) {
int l = from + n - 1; /* last register to set nil */
int l = from+n-1; /* last register to set nil */
if (this.pc > this.lasttarget && pc > 0) { /* no jumps to current position? */
final int previous_code = f.code[pc - 1];
final int previous_code = f.code[pc-1];
if (GET_OPCODE(previous_code) == OP_LOADNIL) {
int pfrom = GETARG_A(previous_code);
int pl = pfrom + GETARG_B(previous_code);
if ((pfrom <= from && from <= pl + 1)
|| (from <= pfrom && pfrom <= l + 1)) { /* can connect both? */
int pl = pfrom+GETARG_B(previous_code);
if ((pfrom <= from && from <= pl+1) || (from <= pfrom && pfrom <= l+1)) { /* can connect both? */
if (pfrom < from)
from = pfrom; /* from = min(from, pfrom) */
if (pl > l)
l = pl; /* l = max(l, pl) */
InstructionPtr previous = new InstructionPtr(this.f.code, this.pc - 1);
InstructionPtr previous = new InstructionPtr(this.f.code, this.pc-1);
SETARG_A(previous, from);
SETARG_B(previous, l - from);
SETARG_B(previous, l-from);
return;
}
} /* else go through */
}
this.codeABC(OP_LOADNIL, from, n - 1, 0);
this.codeABC(OP_LOADNIL, from, n-1, 0);
}
int jump() {
int jpc = this.jpc.i; /* save list of jumps to here */
this.jpc.i = LexState.NO_JUMP;
@@ -308,24 +300,23 @@ public class FuncState extends Constants {
}
void ret(int first, int nret) {
this.codeABC(OP_RETURN, first, nret + 1, 0);
this.codeABC(OP_RETURN, first, nret+1, 0);
}
int condjump(int /* OpCode */op, int A, int B, int C) {
int condjump(int /* OpCode */ op, int A, int B, int C) {
this.codeABC(op, A, B, C);
return this.jump();
}
void fixjump(int pc, int dest) {
InstructionPtr jmp = new InstructionPtr(this.f.code, pc);
int offset = dest - (pc + 1);
_assert (dest != LexState.NO_JUMP);
int offset = dest-(pc+1);
_assert(dest != LexState.NO_JUMP);
if (Math.abs(offset) > MAXARG_sBx)
ls.syntaxerror("control structure too long");
SETARG_sBx(jmp, offset);
}
/*
* * returns current `pc' and marks it as a jump target (to avoid wrong *
* optimizations with consecutive instructions not in the same basic block).
@@ -335,7 +326,6 @@ public class FuncState extends Constants {
return this.pc;
}
int getjump(int pc) {
int offset = GETARG_sBx(this.f.code[pc]);
/* point to itself represents end of list */
@@ -344,19 +334,17 @@ public class FuncState extends Constants {
return LexState.NO_JUMP;
else
/* turn offset into absolute position */
return (pc + 1) + offset;
return (pc+1)+offset;
}
InstructionPtr getjumpcontrol(int pc) {
InstructionPtr pi = new InstructionPtr(this.f.code, pc);
if (pc >= 1 && testTMode(GET_OPCODE(pi.code[pi.idx - 1])))
return new InstructionPtr(pi.code, pi.idx - 1);
if (pc >= 1 && testTMode(GET_OPCODE(pi.code[pi.idx-1])))
return new InstructionPtr(pi.code, pi.idx-1);
else
return pi;
}
/*
* * check whether list has any jump that do not produce a value * (or
* produce an inverted value)
@@ -370,7 +358,6 @@ public class FuncState extends Constants {
return false; /* not found */
}
boolean patchtestreg(int node, int reg) {
InstructionPtr i = this.getjumpcontrol(node);
if (GET_OPCODE(i.get()) != OP_TESTSET)
@@ -385,14 +372,13 @@ public class FuncState extends Constants {
return true;
}
void removevalues(int list) {
for (; list != LexState.NO_JUMP; list = this.getjump(list))
this.patchtestreg(list, NO_REG);
}
void patchlistaux(int list, int vtarget, int reg, int dtarget) {
while (list != LexState.NO_JUMP) {
while ( list != LexState.NO_JUMP ) {
int next = this.getjump(list);
if (this.patchtestreg(list, reg))
this.fixjump(list, vtarget);
@@ -411,17 +397,17 @@ public class FuncState extends Constants {
if (target == this.pc)
this.patchtohere(list);
else {
_assert (target < this.pc);
_assert(target < this.pc);
this.patchlistaux(list, target, NO_REG, target);
}
}
void patchclose(int list, int level) {
level++; /* argument is +1 to reserve 0 as non-op */
while (list != LexState.NO_JUMP) {
while ( list != LexState.NO_JUMP ) {
int next = getjump(list);
_assert(GET_OPCODE(f.code[list]) == OP_JMP
&& (GETARG_A(f.code[list]) == 0 || GETARG_A(f.code[list]) >= level));
_assert(
GET_OPCODE(f.code[list]) == OP_JMP && (GETARG_A(f.code[list]) == 0 || GETARG_A(f.code[list]) >= level));
SETARG_A(f.code, list, level);
list = next;
}
@@ -440,7 +426,7 @@ public class FuncState extends Constants {
else {
int list = l1.i;
int next;
while ((next = this.getjump(list)) != LexState.NO_JUMP)
while ( (next = this.getjump(list)) != LexState.NO_JUMP )
/* find last element */
list = next;
this.fixjump(list, l2);
@@ -448,7 +434,7 @@ public class FuncState extends Constants {
}
void checkstack(int n) {
int newstack = this.freereg + n;
int newstack = this.freereg+n;
if (newstack > this.f.maxstacksize) {
if (newstack >= MAXSTACK)
ls.syntaxerror("function or expression too complex");
@@ -464,7 +450,7 @@ public class FuncState extends Constants {
void freereg(int reg) {
if (!ISK(reg) && reg >= this.nactvar) {
this.freereg--;
_assert (reg == this.freereg);
_assert(reg == this.freereg);
}
}
@@ -472,6 +458,7 @@ public class FuncState extends Constants {
if (e.k == LexState.VNONRELOC)
this.freereg(e.u.info);
}
int addk(LuaValue v) {
if (this.h == null) {
this.h = new Hashtable();
@@ -481,8 +468,8 @@ public class FuncState extends Constants {
final int idx = this.nk;
this.h.put(v, new Integer(idx));
final Prototype f = this.f;
if (f.k == null || nk + 1 >= f.k.length)
f.k = realloc( f.k, nk*2 + 1 );
if (f.k == null || nk+1 >= f.k.length)
f.k = realloc(f.k, nk*2+1);
f.k[this.nk++] = v;
return idx;
}
@@ -492,17 +479,17 @@ public class FuncState extends Constants {
}
int numberK(LuaValue r) {
if ( r instanceof LuaDouble ) {
if (r instanceof LuaDouble) {
double d = r.todouble();
int i = (int) d;
if ( d == (double) i )
if (d == (double) i)
r = LuaInteger.valueOf(i);
}
return this.addk(r);
}
int boolK(boolean b) {
return this.addk((b ? LuaValue.TRUE : LuaValue.FALSE));
return this.addk((b? LuaValue.TRUE: LuaValue.FALSE));
}
int nilK() {
@@ -511,9 +498,9 @@ public class FuncState extends Constants {
void setreturns(expdesc e, int nresults) {
if (e.k == LexState.VCALL) { /* expression is an open function call? */
SETARG_C(this.getcodePtr(e), nresults + 1);
SETARG_C(this.getcodePtr(e), nresults+1);
} else if (e.k == LexState.VVARARG) {
SETARG_B(this.getcodePtr(e), nresults + 1);
SETARG_B(this.getcodePtr(e), nresults+1);
SETARG_A(this.getcodePtr(e), this.freereg);
this.reserveregs(1);
}
@@ -575,8 +562,7 @@ public class FuncState extends Constants {
}
case LexState.VFALSE:
case LexState.VTRUE: {
this.codeABC(OP_LOADBOOL, reg, (e.k == LexState.VTRUE ? 1 : 0),
0);
this.codeABC(OP_LOADBOOL, reg, (e.k == LexState.VTRUE? 1: 0), 0);
break;
}
case LexState.VK: {
@@ -598,7 +584,7 @@ public class FuncState extends Constants {
break;
}
default: {
_assert (e.k == LexState.VVOID || e.k == LexState.VJMP);
_assert(e.k == LexState.VVOID || e.k == LexState.VJMP);
return; /* nothing to do... */
}
}
@@ -609,7 +595,7 @@ public class FuncState extends Constants {
void discharge2anyreg(expdesc e) {
if (e.k != LexState.VNONRELOC) {
this.reserveregs(1);
this.discharge2reg(e, this.freereg - 1);
this.discharge2reg(e, this.freereg-1);
}
}
@@ -622,8 +608,7 @@ public class FuncState extends Constants {
int p_f = LexState.NO_JUMP; /* position of an eventual LOAD false */
int p_t = LexState.NO_JUMP; /* position of an eventual LOAD true */
if (this.need_value(e.t.i) || this.need_value(e.f.i)) {
int fj = (e.k == LexState.VJMP) ? LexState.NO_JUMP : this
.jump();
int fj = (e.k == LexState.VJMP)? LexState.NO_JUMP: this.jump();
p_f = this.code_label(reg, 0, 1);
p_t = this.code_label(reg, 1, 0);
this.patchtohere(fj);
@@ -641,7 +626,7 @@ public class FuncState extends Constants {
this.dischargevars(e);
this.freeexp(e);
this.reserveregs(1);
this.exp2reg(e, this.freereg - 1);
this.exp2reg(e, this.freereg-1);
}
int exp2anyreg(expdesc e) {
@@ -658,7 +643,7 @@ public class FuncState extends Constants {
return e.u.info;
}
void exp2anyregup (expdesc e) {
void exp2anyregup(expdesc e) {
if (e.k != LexState.VUPVAL || e.hasjumps())
exp2anyreg(e);
}
@@ -677,8 +662,7 @@ public class FuncState extends Constants {
case LexState.VFALSE:
case LexState.VNIL: {
if (this.nk <= MAXINDEXRK) { /* constant fit in RK operand? */
e.u.info = (e.k == LexState.VNIL) ? this.nilK()
: this.boolK((e.k == LexState.VTRUE));
e.u.info = (e.k == LexState.VNIL)? this.nilK(): this.boolK((e.k == LexState.VTRUE));
e.k = LexState.VK;
return RKASK(e.u.info);
} else
@@ -715,13 +699,13 @@ public class FuncState extends Constants {
break;
}
case LexState.VINDEXED: {
int op = (var.u.ind_vt == LexState.VLOCAL) ? OP_SETTABLE : OP_SETTABUP;
int op = (var.u.ind_vt == LexState.VLOCAL)? OP_SETTABLE: OP_SETTABUP;
int e = this.exp2RK(ex);
this.codeABC(op, var.u.ind_t, var.u.ind_idx, e);
break;
}
default: {
_assert (false); /* invalid var kind to store */
_assert(false); /* invalid var kind to store */
break;
}
}
@@ -742,12 +726,11 @@ public class FuncState extends Constants {
void invertjump(expdesc e) {
InstructionPtr pc = this.getjumpcontrol(e.u.info);
_assert (testTMode(GET_OPCODE(pc.get()))
&& GET_OPCODE(pc.get()) != OP_TESTSET && Lua
.GET_OPCODE(pc.get()) != OP_TEST);
_assert(testTMode(GET_OPCODE(pc.get())) && GET_OPCODE(pc.get()) != OP_TESTSET
&& Lua.GET_OPCODE(pc.get()) != OP_TEST);
// SETARG_A(pc, !(GETARG_A(pc.get())));
int a = GETARG_A(pc.get());
int nota = (a!=0? 0: 1);
int nota = (a != 0? 0: 1);
SETARG_A(pc, nota);
}
@@ -756,7 +739,7 @@ public class FuncState extends Constants {
int ie = this.getcode(e);
if (GET_OPCODE(ie) == OP_NOT) {
this.pc--; /* remove previous OP_NOT */
return this.condjump(OP_TEST, GETARG_B(ie), 0, (cond!=0? 0: 1));
return this.condjump(OP_TEST, GETARG_B(ie), 0, (cond != 0? 0: 1));
}
/* else go through */
}
@@ -840,7 +823,7 @@ public class FuncState extends Constants {
break;
}
default: {
_assert (false); /* cannot happen */
_assert(false); /* cannot happen */
break;
}
}
@@ -862,7 +845,7 @@ public class FuncState extends Constants {
t.u.ind_t = (short) t.u.info;
t.u.ind_idx = (short) this.exp2RK(k);
LuaC._assert(t.k == LexState.VUPVAL || vkisinreg(t.k));
t.u.ind_vt = (short) ((t.k == LexState.VUPVAL) ? LexState.VUPVAL : LexState.VLOCAL);
t.u.ind_vt = (short) ((t.k == LexState.VUPVAL)? LexState.VUPVAL: LexState.VLOCAL);
t.k = LexState.VINDEXED;
}
@@ -901,13 +884,13 @@ public class FuncState extends Constants {
// break;
return false; /* no constant folding for 'len' */
default:
_assert (false);
_assert(false);
r = null;
break;
}
if ( Double.isNaN(r.todouble()) )
if (Double.isNaN(r.todouble()))
return false; /* do not attempt to produce NaN */
e1.u.setNval( r );
e1.u.setNval(r);
return true;
}
@@ -915,8 +898,7 @@ public class FuncState extends Constants {
if (constfolding(op, e1, e2))
return;
else {
int o2 = (op != OP_UNM && op != OP_LEN) ? this.exp2RK(e2)
: 0;
int o2 = (op != OP_UNM && op != OP_LEN)? this.exp2RK(e2): 0;
int o1 = this.exp2RK(e1);
if (o1 > o2) {
this.freeexp(e1);
@@ -931,7 +913,7 @@ public class FuncState extends Constants {
}
}
void codecomp(int /* OpCode */op, int cond, expdesc e1, expdesc e2) {
void codecomp(int /* OpCode */ op, int cond, expdesc e1, expdesc e2) {
int o1 = this.exp2RK(e1);
int o2 = this.exp2RK(e2);
this.freeexp(e2);
@@ -947,7 +929,7 @@ public class FuncState extends Constants {
e1.k = LexState.VJMP;
}
void prefix(int /* UnOpr */op, expdesc e, int line) {
void prefix(int /* UnOpr */ op, expdesc e, int line) {
expdesc e2 = new expdesc();
e2.init(LexState.VKNUM, 0);
switch (op) {
@@ -969,11 +951,11 @@ public class FuncState extends Constants {
break;
}
default:
_assert (false);
_assert(false);
}
}
void infix(int /* BinOpr */op, expdesc v) {
void infix(int /* BinOpr */ op, expdesc v) {
switch (op) {
case LexState.OPR_AND: {
this.goiftrue(v);
@@ -1004,11 +986,10 @@ public class FuncState extends Constants {
}
}
void posfix(int op, expdesc e1, expdesc e2, int line) {
switch (op) {
case LexState.OPR_AND: {
_assert (e1.t.i == LexState.NO_JUMP); /* list must be closed */
_assert(e1.t.i == LexState.NO_JUMP); /* list must be closed */
this.dischargevars(e2);
this.concat(e2.f, e1.f.i);
// *e1 = *e2;
@@ -1016,7 +997,7 @@ public class FuncState extends Constants {
break;
}
case LexState.OPR_OR: {
_assert (e1.f.i == LexState.NO_JUMP); /* list must be closed */
_assert(e1.f.i == LexState.NO_JUMP); /* list must be closed */
this.dischargevars(e2);
this.concat(e2.t, e1.t.i);
// *e1 = *e2;
@@ -1025,9 +1006,8 @@ public class FuncState extends Constants {
}
case LexState.OPR_CONCAT: {
this.exp2val(e2);
if (e2.k == LexState.VRELOCABLE
&& GET_OPCODE(this.getcode(e2)) == OP_CONCAT) {
_assert (e1.u.info == GETARG_B(this.getcode(e2)) - 1);
if (e2.k == LexState.VRELOCABLE && GET_OPCODE(this.getcode(e2)) == OP_CONCAT) {
_assert(e1.u.info == GETARG_B(this.getcode(e2))-1);
this.freeexp(e1);
SETARG_B(this.getcodePtr(e2), e1.u.info);
e1.k = LexState.VRELOCABLE;
@@ -1075,44 +1055,39 @@ public class FuncState extends Constants {
this.codecomp(OP_LE, 0, e1, e2);
break;
default:
_assert (false);
_assert(false);
}
}
void fixline(int line) {
this.f.lineinfo[this.pc - 1] = line;
this.f.lineinfo[this.pc-1] = line;
}
int code(int instruction, int line) {
Prototype f = this.f;
this.dischargejpc(); /* `pc' will change */
/* put new instruction in code array */
if (f.code == null || this.pc + 1 > f.code.length)
f.code = LuaC.realloc(f.code, this.pc * 2 + 1);
if (f.code == null || this.pc+1 > f.code.length)
f.code = LuaC.realloc(f.code, this.pc*2+1);
f.code[this.pc] = instruction;
/* save corresponding line information */
if (f.lineinfo == null || this.pc + 1 > f.lineinfo.length)
f.lineinfo = LuaC.realloc(f.lineinfo,
this.pc * 2 + 1);
if (f.lineinfo == null || this.pc+1 > f.lineinfo.length)
f.lineinfo = LuaC.realloc(f.lineinfo, this.pc*2+1);
f.lineinfo[this.pc] = line;
return this.pc++;
}
int codeABC(int o, int a, int b, int c) {
_assert (getOpMode(o) == iABC);
_assert (getBMode(o) != OpArgN || b == 0);
_assert (getCMode(o) != OpArgN || c == 0);
_assert(getOpMode(o) == iABC);
_assert(getBMode(o) != OpArgN || b == 0);
_assert(getCMode(o) != OpArgN || c == 0);
return this.code(CREATE_ABC(o, a, b, c), this.ls.lastline);
}
int codeABx(int o, int a, int bc) {
_assert (getOpMode(o) == iABx || getOpMode(o) == iAsBx);
_assert (getCMode(o) == OpArgN);
_assert (bc >= 0 && bc <= Lua.MAXARG_Bx);
_assert(getOpMode(o) == iABx || getOpMode(o) == iAsBx);
_assert(getCMode(o) == OpArgN);
_assert(bc >= 0 && bc <= Lua.MAXARG_Bx);
return this.code(CREATE_ABx(o, a, bc), this.ls.lastline);
}
@@ -1132,16 +1107,16 @@ public class FuncState extends Constants {
}
void setlist(int base, int nelems, int tostore) {
int c = (nelems - 1) / LFIELDS_PER_FLUSH + 1;
int b = (tostore == LUA_MULTRET) ? 0 : tostore;
_assert (tostore != 0);
int c = (nelems-1)/LFIELDS_PER_FLUSH+1;
int b = (tostore == LUA_MULTRET)? 0: tostore;
_assert(tostore != 0);
if (c <= MAXARG_C)
this.codeABC(OP_SETLIST, base, b, c);
else {
this.codeABC(OP_SETLIST, base, b, 0);
this.code(c, this.ls.lastline);
}
this.freereg = (short) (base + 1); /* free registers with list values */
this.freereg = (short) (base+1); /* free registers with list values */
}
}

View File

@@ -24,13 +24,16 @@ package org.luaj.vm2.compiler;
class InstructionPtr {
final int[] code;
final int idx;
InstructionPtr(int[] code, int idx ) {
InstructionPtr(int[] code, int idx) {
this.code = code;
this.idx = idx;
}
int get() {
return code[idx];
}
void set(int value) {
code[idx] = value;
}

View File

@@ -23,8 +23,10 @@ package org.luaj.vm2.compiler;
public class IntPtr {
int i;
IntPtr() {
}
IntPtr(int value) {
this.i = value;
}

File diff suppressed because it is too large Load Diff

View File

@@ -37,30 +37,37 @@ import org.luaj.vm2.lib.BaseLib;
* Compiler for Lua.
*
* <p>
* Compiles lua source files into lua bytecode within a {@link Prototype},
* loads lua binary files directly into a {@link Prototype},
* and optionaly instantiates a {@link LuaClosure} around the result
* using a user-supplied environment.
* Compiles lua source files into lua bytecode within a {@link Prototype}, loads
* lua binary files directly into a {@link Prototype}, and optionaly
* instantiates a {@link LuaClosure} around the result using a user-supplied
* environment.
*
* <p>
* Implements the {@link org.luaj.vm2.Globals.Compiler} interface for loading
* initialized chunks, which is an interface common to
* lua bytecode compiling and java bytecode compiling.
* initialized chunks, which is an interface common to lua bytecode compiling
* and java bytecode compiling.
*
* <p>
* The {@link LuaC} compiler is installed by default by both the
* {@link org.luaj.vm2.lib.jse.JsePlatform} and {@link org.luaj.vm2.lib.jme.JmePlatform} classes,
* so in the following example, the default {@link LuaC} compiler
* will be used:
* <pre> {@code
* {@link org.luaj.vm2.lib.jse.JsePlatform} and
* {@link org.luaj.vm2.lib.jme.JmePlatform} classes, so in the following
* example, the default {@link LuaC} compiler will be used:
*
* <pre>
* {
* &#64;code
* Globals globals = JsePlatform.standardGlobals();
* globals.load(new StringReader("print 'hello'"), "main.lua" ).call();
* } </pre>
* globals.load(new StringReader("print 'hello'"), "main.lua").call();
* }
* </pre>
*
* To load the LuaC compiler manually, use the install method:
* <pre> {@code
*
* <pre>
* {@code
* LuaC.install(globals);
* } </pre>
* }
* </pre>
*
* @see #install(Globals)
* @see Globals#compiler
@@ -77,9 +84,10 @@ public class LuaC extends Constants implements Globals.Compiler, Globals.Loader
/** A sharable instance of the LuaC compiler. */
public static final LuaC instance = new LuaC();
/** Install the compiler so that LoadState will first
* try to use it when handed bytes that are
* not already a compiled lua chunk.
/**
* Install the compiler so that LoadState will first try to use it when
* handed bytes that are not already a compiled lua chunk.
*
* @param globals the Globals into which this is to be installed.
*/
public static void install(Globals globals) {
@@ -89,8 +97,11 @@ public class LuaC extends Constants implements Globals.Compiler, Globals.Loader
protected LuaC() {}
/** Compile lua source into a Prototype.
* @param stream InputStream representing the text source conforming to lua source syntax.
/**
* Compile lua source into a Prototype.
*
* @param stream InputStream representing the text source conforming to
* lua source syntax.
* @param chunkname String name of the chunk to use.
* @return Prototype representing the lua chunk for this source.
* @throws IOException
@@ -103,9 +114,10 @@ public class LuaC extends Constants implements Globals.Compiler, Globals.Loader
return new LuaClosure(prototype, env);
}
/** @deprecated
* Use Globals.load(InputString, String, String) instead,
* or LuaC.compile(InputStream, String) and construct LuaClosure directly.
/**
* @deprecated Use Globals.load(InputString, String, String) instead, or
* LuaC.compile(InputStream, String) and construct LuaClosure
* directly.
*/
public LuaValue load(InputStream stream, String chunkname, Globals globals) throws IOException {
return new LuaClosure(compile(stream, chunkname), globals);
@@ -114,22 +126,23 @@ public class LuaC extends Constants implements Globals.Compiler, Globals.Loader
static class CompileState {
int nCcalls = 0;
private Hashtable strings = new Hashtable();
protected CompileState() {}
/** Parse the input */
Prototype luaY_parser(InputStream z, String name) throws IOException{
Prototype luaY_parser(InputStream z, String name) throws IOException {
LexState lexstate = new LexState(this, z);
FuncState funcstate = new FuncState();
// lexstate.buff = buff;
lexstate.fs = funcstate;
lexstate.setinput(this, z.read(), z, (LuaString) LuaValue.valueOf(name) );
lexstate.setinput(this, z.read(), z, (LuaString) LuaValue.valueOf(name));
/* main func. is always vararg */
funcstate.f = new Prototype();
funcstate.f.source = (LuaString) LuaValue.valueOf(name);
lexstate.mainfunc(funcstate);
LuaC._assert (funcstate.prev == null);
LuaC._assert(funcstate.prev == null);
/* all scopes should be correctly finished */
LuaC._assert (lexstate.dyd == null
LuaC._assert(lexstate.dyd == null
|| (lexstate.dyd.n_actvar == 0 && lexstate.dyd.n_gt == 0 && lexstate.dyd.n_label == 0));
return funcstate.f;
}

View File

@@ -34,14 +34,14 @@ import org.luaj.vm2.LuaValue;
import org.luaj.vm2.Varargs;
/**
* Subclass of {@link LibFunction} which implements the lua basic library functions.
* Subclass of {@link LibFunction} which implements the lua basic library
* functions.
* <p>
* This contains all library functions listed as "basic functions" in the lua documentation for JME.
* The functions dofile and loadfile use the
* {@link Globals#finder} instance to find resource files.
* Since JME has no file system by default, {@link BaseLib} implements
* {@link ResourceFinder} using {@link Class#getResource(String)},
* which is the closest equivalent on JME.
* This contains all library functions listed as "basic functions" in the lua
* documentation for JME. The functions dofile and loadfile use the
* {@link Globals#finder} instance to find resource files. Since JME has no file
* system by default, {@link BaseLib} implements {@link ResourceFinder} using
* {@link Class#getResource(String)}, which is the closest equivalent on JME.
* The default loader chain in {@link PackageLib} will use these as well.
* <p>
* To use basic library functions that include a {@link ResourceFinder} based on
@@ -50,47 +50,60 @@ import org.luaj.vm2.Varargs;
* Typically, this library is included as part of a call to either
* {@link org.luaj.vm2.lib.jse.JsePlatform#standardGlobals()} or
* {@link org.luaj.vm2.lib.jme.JmePlatform#standardGlobals()}
* <pre> {@code
*
* <pre>
* {
* &#64;code
* Globals globals = JsePlatform.standardGlobals();
* globals.get("print").call(LuaValue.valueOf("hello, world"));
* } </pre>
* }
* </pre>
* <p>
* For special cases where the smallest possible footprint is desired,
* a minimal set of libraries could be loaded
* directly via {@link Globals#load(LuaValue)} using code such as:
* <pre> {@code
* For special cases where the smallest possible footprint is desired, a minimal
* set of libraries could be loaded directly via {@link Globals#load(LuaValue)}
* using code such as:
*
* <pre>
* {
* &#64;code
* Globals globals = new Globals();
* globals.load(new JseBaseLib());
* globals.get("print").call(LuaValue.valueOf("hello, world"));
* } </pre>
* Doing so will ensure the library is properly initialized
* and loaded into the globals table.
* }
* </pre>
*
* Doing so will ensure the library is properly initialized and loaded into the
* globals table.
* <p>
* This is a direct port of the corresponding library in C.
*
* @see org.luaj.vm2.lib.jse.JseBaseLib
* @see ResourceFinder
* @see Globals#finder
* @see LibFunction
* @see org.luaj.vm2.lib.jse.JsePlatform
* @see org.luaj.vm2.lib.jme.JmePlatform
* @see <a href="http://www.lua.org/manual/5.2/manual.html#6.1">Lua 5.2 Base Lib Reference</a>
* @see <a href="http://www.lua.org/manual/5.2/manual.html#6.1">Lua 5.2 Base Lib
* Reference</a>
*/
public class BaseLib extends TwoArgFunction implements ResourceFinder {
Globals globals;
/** Perform one-time initialization on the library by adding base functions
/**
* Perform one-time initialization on the library by adding base functions
* to the supplied environment, and returning it as the return value.
*
* @param modname the module name supplied if this is loaded via 'require'.
* @param env the environment to load into, which must be a Globals instance.
* @param env the environment to load into, which must be a Globals
* instance.
*/
public LuaValue call(LuaValue modname, LuaValue env) {
globals = env.checkglobals();
globals.finder = this;
globals.baselib = this;
env.set( "_G", env );
env.set( "_VERSION", Lua._VERSION );
env.set("_G", env);
env.set("_VERSION", Lua._VERSION);
env.set("assert", new _assert());
env.set("collectgarbage", new collectgarbage());
env.set("dofile", new dofile());
@@ -119,20 +132,20 @@ public class BaseLib extends TwoArgFunction implements ResourceFinder {
return env;
}
/** ResourceFinder implementation
/**
* ResourceFinder implementation
*
* Tries to open the file as a resource, which can work for JSE and JME.
*/
public InputStream findResource(String filename) {
return getClass().getResourceAsStream(filename.startsWith("/")? filename: "/"+filename);
return getClass().getResourceAsStream(filename.startsWith("/")? filename: "/" + filename);
}
// "assert", // ( v [,message] ) -> v, message | ERR
static final class _assert extends VarArgFunction {
public Varargs invoke(Varargs args) {
if ( !args.arg1().toboolean() )
error( args.narg()>1? args.optjstring(2,"assertion failed!"): "assertion failed!" );
if (!args.arg1().toboolean())
error(args.narg() > 1? args.optjstring(2, "assertion failed!"): "assertion failed!");
return args;
}
}
@@ -141,14 +154,14 @@ public class BaseLib extends TwoArgFunction implements ResourceFinder {
static final class collectgarbage extends VarArgFunction {
public Varargs invoke(Varargs args) {
String s = args.optjstring(1, "collect");
if ( "collect".equals(s) ) {
if ("collect".equals(s)) {
System.gc();
return ZERO;
} else if ( "count".equals(s) ) {
} else if ("count".equals(s)) {
Runtime rt = Runtime.getRuntime();
long used = rt.totalMemory() - rt.freeMemory();
long used = rt.totalMemory()-rt.freeMemory();
return varargsOf(valueOf(used/1024.), valueOf(used%1024));
} else if ( "step".equals(s) ) {
} else if ("step".equals(s)) {
System.gc();
return LuaValue.TRUE;
} else {
@@ -163,9 +176,8 @@ public class BaseLib extends TwoArgFunction implements ResourceFinder {
public Varargs invoke(Varargs args) {
args.argcheck(args.isstring(1) || args.isnil(1), 1, "filename must be string or nil");
String filename = args.isstring(1)? args.tojstring(1): null;
Varargs v = filename == null?
loadStream( globals.STDIN, "=stdin", "bt", globals ):
loadFile( args.checkjstring(1), "bt", globals );
Varargs v = filename == null? loadStream(globals.STDIN, "=stdin", "bt", globals)
: loadFile(args.checkjstring(1), "bt", globals);
return v.isnil(1)? error(v.tojstring(2)): v.arg1().invoke();
}
}
@@ -173,8 +185,10 @@ public class BaseLib extends TwoArgFunction implements ResourceFinder {
// "error", // ( message [,level] ) -> ERR
static final class error extends TwoArgFunction {
public LuaValue call(LuaValue arg1, LuaValue arg2) {
if (arg1.isnil()) throw new LuaError(NIL);
if (!arg1.isstring() || arg2.optint(1) == 0) throw new LuaError(arg1);
if (arg1.isnil())
throw new LuaError(NIL);
if (!arg1.isstring() || arg2.optint(1) == 0)
throw new LuaError(arg1);
throw new LuaError(arg1.tojstring(), arg2.optint(1));
}
}
@@ -184,23 +198,26 @@ public class BaseLib extends TwoArgFunction implements ResourceFinder {
public LuaValue call() {
return argerror(1, "value expected");
}
public LuaValue call(LuaValue arg) {
LuaValue mt = arg.getmetatable();
return mt!=null? mt.rawget(METATABLE).optvalue(mt): NIL;
return mt != null? mt.rawget(METATABLE).optvalue(mt): NIL;
}
}
// "load", // ( ld [, source [, mode [, env]]] ) -> chunk | nil, msg
final class load extends VarArgFunction {
public Varargs invoke(Varargs args) {
LuaValue ld = args.arg1();
if (!ld.isstring() && !ld.isfunction()) {
throw new LuaError("bad argument #1 to 'load' (string or function expected, got " + ld.typename() + ")");
throw new LuaError(
"bad argument #1 to 'load' (string or function expected, got " + ld.typename() + ")");
}
String source = args.optjstring(2, ld.isstring()? ld.tojstring(): "=(load)");
String mode = args.optjstring(3, "bt");
LuaValue env = args.optvalue(4, globals);
return loadStream(ld.isstring()? ld.strvalue().toInputStream():
new StringInputStream(ld.checkfunction()), source, mode, env);
return loadStream(ld.isstring()? ld.strvalue().toInputStream(): new StringInputStream(ld.checkfunction()),
source, mode, env);
}
}
@@ -211,9 +228,7 @@ public class BaseLib extends TwoArgFunction implements ResourceFinder {
String filename = args.isstring(1)? args.tojstring(1): null;
String mode = args.optjstring(2, "bt");
LuaValue env = args.optvalue(3, globals);
return filename == null?
loadStream( globals.STDIN, "=stdin", mode, env ):
loadFile( filename, mode, env );
return filename == null? loadStream(globals.STDIN, "=stdin", mode, env): loadFile(filename, mode, env);
}
}
@@ -225,12 +240,12 @@ public class BaseLib extends TwoArgFunction implements ResourceFinder {
globals.debuglib.onCall(this);
try {
return varargsOf(TRUE, func.invoke(args.subargs(2)));
} catch ( LuaError le ) {
} catch (LuaError le) {
final LuaValue m = le.getMessageObject();
return varargsOf(FALSE, m!=null? m: NIL);
} catch ( Exception e ) {
return varargsOf(FALSE, m != null? m: NIL);
} catch (Exception e) {
final String m = e.getMessage();
return varargsOf(FALSE, valueOf(m!=null? m: e.toString()));
return varargsOf(FALSE, valueOf(m != null? m: e.toString()));
} finally {
if (globals != null && globals.debuglib != null)
globals.debuglib.onReturn();
@@ -241,14 +256,17 @@ public class BaseLib extends TwoArgFunction implements ResourceFinder {
// "print", // (...) -> void
final class print extends VarArgFunction {
final BaseLib baselib;
print(BaseLib baselib) {
this.baselib = baselib;
}
public Varargs invoke(Varargs args) {
LuaValue tostring = globals.get("tostring");
for ( int i=1, n=args.narg(); i<=n; i++ ) {
if ( i>1 ) globals.STDOUT.print( '\t' );
LuaString s = tostring.call( args.arg(i) ).strvalue();
for (int i = 1, n = args.narg(); i <= n; i++) {
if (i > 1)
globals.STDOUT.print('\t');
LuaString s = tostring.call(args.arg(i)).strvalue();
globals.STDOUT.print(s.tojstring());
}
globals.STDOUT.print('\n');
@@ -256,15 +274,16 @@ public class BaseLib extends TwoArgFunction implements ResourceFinder {
}
}
// "rawequal", // (v1, v2) -> boolean
static final class rawequal extends LibFunction {
public LuaValue call() {
return argerror(1, "value expected");
}
public LuaValue call(LuaValue arg) {
return argerror(2, "value expected");
}
public LuaValue call(LuaValue arg1, LuaValue arg2) {
return valueOf(arg1.raweq(arg2));
}
@@ -275,12 +294,12 @@ public class BaseLib extends TwoArgFunction implements ResourceFinder {
public LuaValue call(LuaValue arg) {
return argerror(2, "value expected");
}
public LuaValue call(LuaValue arg1, LuaValue arg2) {
return arg1.checktable().rawget(arg2);
}
}
// "rawlen", // (v) -> value
static final class rawlen extends LibFunction {
public LuaValue call(LuaValue arg) {
@@ -291,14 +310,17 @@ public class BaseLib extends TwoArgFunction implements ResourceFinder {
// "rawset", // (table, index, value) -> table
static final class rawset extends TableLibFunction {
public LuaValue call(LuaValue table) {
return argerror(2,"value expected");
return argerror(2, "value expected");
}
public LuaValue call(LuaValue table, LuaValue index) {
return argerror(3,"value expected");
return argerror(3, "value expected");
}
public LuaValue call(LuaValue table, LuaValue index, LuaValue value) {
LuaTable t = table.checktable();
if (!index.isvalidkey()) argerror(2, "table index is nil");
if (!index.isvalidkey())
argerror(2, "table index is nil");
t.rawset(index, value);
return t;
}
@@ -308,23 +330,24 @@ public class BaseLib extends TwoArgFunction implements ResourceFinder {
static final class select extends VarArgFunction {
public Varargs invoke(Varargs args) {
int n = args.narg()-1;
if ( args.arg1().equals(valueOf("#")) )
if (args.arg1().equals(valueOf("#")))
return valueOf(n);
int i = args.checkint(1);
if ( i == 0 || i < -n )
argerror(1,"index out of range");
return args.subargs(i<0? n+i+2: i+1);
if (i == 0 || i < -n)
argerror(1, "index out of range");
return args.subargs(i < 0? n+i+2: i+1);
}
}
// "setmetatable", // (table, metatable) -> table
static final class setmetatable extends TableLibFunction {
public LuaValue call(LuaValue table) {
return argerror(2,"nil or table expected");
return argerror(2, "nil or table expected");
}
public LuaValue call(LuaValue table, LuaValue metatable) {
final LuaValue mt0 = table.checktable().getmetatable();
if ( mt0!=null && !mt0.rawget(METATABLE).isnil() )
if (mt0 != null && !mt0.rawget(METATABLE).isnil())
error("cannot change a protected metatable");
return table.setmetatable(metatable.isnil()? null: metatable.checktable());
}
@@ -335,11 +358,12 @@ public class BaseLib extends TwoArgFunction implements ResourceFinder {
public LuaValue call(LuaValue e) {
return e.tonumber();
}
public LuaValue call(LuaValue e, LuaValue base) {
if (base.isnil())
return e.tonumber();
final int b = base.checkint();
if ( b < 2 || b > 36 )
if (b < 2 || b > 36)
argerror(2, "base out of range");
return e.checkstring().tonumber(b);
}
@@ -349,10 +373,10 @@ public class BaseLib extends TwoArgFunction implements ResourceFinder {
static final class tostring extends LibFunction {
public LuaValue call(LuaValue arg) {
LuaValue h = arg.metatag(TOSTRING);
if ( ! h.isnil() )
if (!h.isnil())
return h.call(arg);
LuaValue v = arg.tostring();
if ( ! v.isnil() )
if (!v.isnil())
return v;
return valueOf(arg.tojstring());
}
@@ -376,12 +400,12 @@ public class BaseLib extends TwoArgFunction implements ResourceFinder {
globals.debuglib.onCall(this);
try {
return varargsOf(TRUE, args.arg1().invoke(args.subargs(3)));
} catch ( LuaError le ) {
} catch (LuaError le) {
final LuaValue m = le.getMessageObject();
return varargsOf(FALSE, m!=null? m: NIL);
} catch ( Exception e ) {
return varargsOf(FALSE, m != null? m: NIL);
} catch (Exception e) {
final String m = e.getMessage();
return varargsOf(FALSE, valueOf(m!=null? m: e.toString()));
return varargsOf(FALSE, valueOf(m != null? m: e.toString()));
} finally {
if (globals != null && globals.debuglib != null)
globals.debuglib.onReturn();
@@ -395,19 +419,22 @@ public class BaseLib extends TwoArgFunction implements ResourceFinder {
// "pairs" (t) -> iter-func, t, nil
static final class pairs extends VarArgFunction {
final next next;
pairs(next next) {
this.next = next;
}
public Varargs invoke(Varargs args) {
return varargsOf( next, args.checktable(1), NIL );
return varargsOf(next, args.checktable(1), NIL);
}
}
// // "ipairs", // (t) -> iter-func, t, 0
static final class ipairs extends VarArgFunction {
inext inext = new inext();
public Varargs invoke(Varargs args) {
return varargsOf( inext, args.checktable(1), ZERO );
return varargsOf(inext, args.checktable(1), ZERO);
}
}
@@ -427,20 +454,21 @@ public class BaseLib extends TwoArgFunction implements ResourceFinder {
/**
* Load from a named file, returning the chunk or nil,error of can't load
*
* @param env
* @param mode
* @return Varargs containing chunk, or NIL,error-text on error
*/
public Varargs loadFile(String filename, String mode, LuaValue env) {
InputStream is = globals.finder.findResource(filename);
if ( is == null )
return varargsOf(NIL, valueOf("cannot open "+filename+": No such file or directory"));
if (is == null)
return varargsOf(NIL, valueOf("cannot open " + filename + ": No such file or directory"));
try {
return loadStream(is, "@"+filename, mode, env);
return loadStream(is, "@" + filename, mode, env);
} finally {
try {
is.close();
} catch ( Exception e ) {
} catch (Exception e) {
e.printStackTrace();
}
}
@@ -448,28 +476,29 @@ public class BaseLib extends TwoArgFunction implements ResourceFinder {
public Varargs loadStream(InputStream is, String chunkname, String mode, LuaValue env) {
try {
if ( is == null )
return varargsOf(NIL, valueOf("not found: "+chunkname));
if (is == null)
return varargsOf(NIL, valueOf("not found: " + chunkname));
return globals.load(is, chunkname, mode, env);
} catch (Exception e) {
return varargsOf(NIL, valueOf(e.getMessage()));
}
}
private static class StringInputStream extends InputStream {
final LuaValue func;
byte[] bytes;
int offset, remaining = 0;
StringInputStream(LuaValue func) {
this.func = func;
}
public int read() throws IOException {
if ( remaining < 0 )
if (remaining < 0)
return -1;
if ( remaining == 0 ) {
if (remaining == 0) {
LuaValue s = func.call();
if ( s.isnil() )
if (s.isnil())
return remaining = -1;
LuaString ls = s.strvalue();
bytes = ls.m_bytes;
@@ -479,7 +508,7 @@ public class BaseLib extends TwoArgFunction implements ResourceFinder {
return -1;
}
--remaining;
return 0xFF&bytes[offset++];
return 0xFF & bytes[offset++];
}
}
}

View File

@@ -26,68 +26,86 @@ import org.luaj.vm2.LuaValue;
import org.luaj.vm2.Varargs;
/**
* Subclass of LibFunction that implements the Lua standard {@code bit32} library.
* Subclass of LibFunction that implements the Lua standard {@code bit32}
* library.
* <p>
* Typically, this library is included as part of a call to either
* {@link org.luaj.vm2.lib.jse.JsePlatform#standardGlobals()} or {@link org.luaj.vm2.lib.jme.JmePlatform#standardGlobals()}
* <pre> {@code
* {@link org.luaj.vm2.lib.jse.JsePlatform#standardGlobals()} or
* {@link org.luaj.vm2.lib.jme.JmePlatform#standardGlobals()}
*
* <pre>
* {
* &#64;code
* Globals globals = JsePlatform.standardGlobals();
* System.out.println( globals.get("bit32").get("bnot").call( LuaValue.valueOf(2) ) );
* } </pre>
* System.out.println(globals.get("bit32").get("bnot").call(LuaValue.valueOf(2)));
* }
* </pre>
* <p>
* To instantiate and use it directly,
* link it into your globals table via {@link LuaValue#load(LuaValue)} using code such as:
* <pre> {@code
* To instantiate and use it directly, link it into your globals table via
* {@link LuaValue#load(LuaValue)} using code such as:
*
* <pre>
* {
* &#64;code
* Globals globals = new Globals();
* globals.load(new JseBaseLib());
* globals.load(new PackageLib());
* globals.load(new Bit32Lib());
* System.out.println( globals.get("bit32").get("bnot").call( LuaValue.valueOf(2) ) );
* } </pre>
* System.out.println(globals.get("bit32").get("bnot").call(LuaValue.valueOf(2)));
* }
* </pre>
* <p>
* This has been implemented to match as closely as possible the behavior in the corresponding library in C.
* This has been implemented to match as closely as possible the behavior in the
* corresponding library in C.
*
* @see LibFunction
* @see org.luaj.vm2.lib.jse.JsePlatform
* @see org.luaj.vm2.lib.jme.JmePlatform
* @see <a href="http://www.lua.org/manual/5.2/manual.html#6.7">Lua 5.2 Bitwise Operation Lib Reference</a>
* @see <a href="http://www.lua.org/manual/5.2/manual.html#6.7">Lua 5.2 Bitwise
* Operation Lib Reference</a>
*/
public class Bit32Lib extends TwoArgFunction {
public Bit32Lib() {
}
/** Perform one-time initialization on the library by creating a table
* containing the library functions, adding that table to the supplied environment,
* adding the table to package.loaded, and returning table as the return value.
/**
* Perform one-time initialization on the library by creating a table
* containing the library functions, adding that table to the supplied
* environment, adding the table to package.loaded, and returning table as
* the return value.
*
* @param modname the module name supplied if this is loaded via 'require'.
* @param env the environment to load into, which must be a Globals instance.
* @param env the environment to load into, which must be a Globals
* instance.
*/
public LuaValue call(LuaValue modname, LuaValue env) {
LuaTable t = new LuaTable();
bind(t, Bit32LibV.class, new String[] {
"band", "bnot", "bor", "btest", "bxor", "extract", "replace"
});
bind(t, Bit32Lib2.class, new String[] {
"arshift", "lrotate", "lshift", "rrotate", "rshift"
});
bind(t, Bit32LibV.class, new String[] { "band", "bnot", "bor", "btest", "bxor", "extract", "replace" });
bind(t, Bit32Lib2.class, new String[] { "arshift", "lrotate", "lshift", "rrotate", "rshift" });
env.set("bit32", t);
if (!env.get("package").isnil()) env.get("package").get("loaded").set("bit32", t);
if (!env.get("package").isnil())
env.get("package").get("loaded").set("bit32", t);
return t;
}
static final class Bit32LibV extends VarArgFunction {
public Varargs invoke(Varargs args) {
switch ( opcode ) {
case 0: return Bit32Lib.band( args );
case 1: return Bit32Lib.bnot( args );
case 2: return Bit32Lib.bor( args );
case 3: return Bit32Lib.btest( args );
case 4: return Bit32Lib.bxor( args );
switch (opcode) {
case 0:
return Bit32Lib.band(args);
case 1:
return Bit32Lib.bnot(args);
case 2:
return Bit32Lib.bor(args);
case 3:
return Bit32Lib.btest(args);
case 4:
return Bit32Lib.bxor(args);
case 5:
return Bit32Lib.extract( args.checkint(1), args.checkint(2), args.optint(3, 1) );
return Bit32Lib.extract(args.checkint(1), args.checkint(2), args.optint(3, 1));
case 6:
return Bit32Lib.replace( args.checkint(1), args.checkint(2),
args.checkint(3), args.optint(4, 1) );
return Bit32Lib.replace(args.checkint(1), args.checkint(2), args.checkint(3), args.optint(4, 1));
}
return NIL;
}
@@ -96,12 +114,17 @@ public class Bit32Lib extends TwoArgFunction {
static final class Bit32Lib2 extends TwoArgFunction {
public LuaValue call(LuaValue arg1, LuaValue arg2) {
switch ( opcode ) {
case 0: return Bit32Lib.arshift(arg1.checkint(), arg2.checkint());
case 1: return Bit32Lib.lrotate(arg1.checkint(), arg2.checkint());
case 2: return Bit32Lib.lshift(arg1.checkint(), arg2.checkint());
case 3: return Bit32Lib.rrotate(arg1.checkint(), arg2.checkint());
case 4: return Bit32Lib.rshift(arg1.checkint(), arg2.checkint());
switch (opcode) {
case 0:
return Bit32Lib.arshift(arg1.checkint(), arg2.checkint());
case 1:
return Bit32Lib.lrotate(arg1.checkint(), arg2.checkint());
case 2:
return Bit32Lib.lshift(arg1.checkint(), arg2.checkint());
case 3:
return Bit32Lib.rrotate(arg1.checkint(), arg2.checkint());
case 4:
return Bit32Lib.rshift(arg1.checkint(), arg2.checkint());
}
return NIL;
}
@@ -110,9 +133,9 @@ public class Bit32Lib extends TwoArgFunction {
static LuaValue arshift(int x, int disp) {
if (disp >= 0) {
return bitsToValue(x >> disp);
return bitsToValue(x>>disp);
} else {
return bitsToValue(x << -disp);
return bitsToValue(x<<-disp);
}
}
@@ -120,9 +143,9 @@ public class Bit32Lib extends TwoArgFunction {
if (disp >= 32 || disp <= -32) {
return ZERO;
} else if (disp >= 0) {
return bitsToValue(x >>> disp);
return bitsToValue(x>>>disp);
} else {
return bitsToValue(x << -disp);
return bitsToValue(x<<-disp);
}
}
@@ -130,46 +153,46 @@ public class Bit32Lib extends TwoArgFunction {
if (disp >= 32 || disp <= -32) {
return ZERO;
} else if (disp >= 0) {
return bitsToValue(x << disp);
return bitsToValue(x<<disp);
} else {
return bitsToValue(x >>> -disp);
return bitsToValue(x>>>-disp);
}
}
static Varargs band( Varargs args ) {
static Varargs band(Varargs args) {
int result = -1;
for ( int i = 1; i <= args.narg(); i++ ) {
for (int i = 1; i <= args.narg(); i++) {
result &= args.checkint(i);
}
return bitsToValue( result );
return bitsToValue(result);
}
static Varargs bnot( Varargs args ) {
return bitsToValue( ~args.checkint(1) );
static Varargs bnot(Varargs args) {
return bitsToValue(~args.checkint(1));
}
static Varargs bor( Varargs args ) {
static Varargs bor(Varargs args) {
int result = 0;
for ( int i = 1; i <= args.narg(); i++ ) {
for (int i = 1; i <= args.narg(); i++) {
result |= args.checkint(i);
}
return bitsToValue( result );
return bitsToValue(result);
}
static Varargs btest( Varargs args ) {
static Varargs btest(Varargs args) {
int bits = -1;
for ( int i = 1; i <= args.narg(); i++ ) {
for (int i = 1; i <= args.narg(); i++) {
bits &= args.checkint(i);
}
return valueOf( bits != 0 );
return valueOf(bits != 0);
}
static Varargs bxor( Varargs args ) {
static Varargs bxor(Varargs args) {
int result = 0;
for ( int i = 1; i <= args.narg(); i++ ) {
for (int i = 1; i <= args.narg(); i++) {
result ^= args.checkint(i);
}
return bitsToValue( result );
return bitsToValue(result);
}
static LuaValue lrotate(int x, int disp) {
@@ -177,7 +200,7 @@ public class Bit32Lib extends TwoArgFunction {
return rrotate(x, -disp);
} else {
disp = disp & 31;
return bitsToValue((x << disp) | (x >>> (32 - disp)));
return bitsToValue((x<<disp) | (x>>>(32-disp)));
}
}
@@ -186,7 +209,7 @@ public class Bit32Lib extends TwoArgFunction {
return lrotate(x, -disp);
} else {
disp = disp & 31;
return bitsToValue((x >>> disp) | (x << (32 - disp)));
return bitsToValue((x>>>disp) | (x<<(32-disp)));
}
}
@@ -197,10 +220,10 @@ public class Bit32Lib extends TwoArgFunction {
if (width < 0) {
argerror(3, "width must be postive");
}
if (field + width > 32) {
if (field+width > 32) {
error("trying to access non-existent bits");
}
return bitsToValue((n >>> field) & (-1 >>> (32 - width)));
return bitsToValue((n>>>field) & (-1>>>(32-width)));
}
static LuaValue replace(int n, int v, int field, int width) {
@@ -210,15 +233,15 @@ public class Bit32Lib extends TwoArgFunction {
if (width < 0) {
argerror(4, "width must be postive");
}
if (field + width > 32) {
if (field+width > 32) {
error("trying to access non-existent bits");
}
int mask = (-1 >>> (32 - width)) << field;
n = (n & ~mask) | ((v << field) & mask);
int mask = (-1>>>(32-width))<<field;
n = (n & ~mask) | ((v<<field) & mask);
return bitsToValue(n);
}
private static LuaValue bitsToValue( int x ) {
return ( x < 0 ) ? valueOf((double) ((long) x & 0xFFFFFFFFL)) : valueOf(x);
private static LuaValue bitsToValue(int x) {
return (x < 0)? valueOf((double) ((long) x & 0xFFFFFFFFL)): valueOf(x);
}
}

View File

@@ -28,37 +28,48 @@ import org.luaj.vm2.LuaValue;
import org.luaj.vm2.Varargs;
/**
* Subclass of {@link LibFunction} which implements the lua standard {@code coroutine}
* library.
* Subclass of {@link LibFunction} which implements the lua standard
* {@code coroutine} library.
* <p>
* The coroutine library in luaj has the same behavior as the
* coroutine library in C, but is implemented using Java Threads to maintain
* the call state between invocations. Therefore it can be yielded from anywhere,
* similar to the "Coco" yield-from-anywhere patch available for C-based lua.
* However, coroutines that are yielded but never resumed to complete their execution
* may not be collected by the garbage collector.
* The coroutine library in luaj has the same behavior as the coroutine library
* in C, but is implemented using Java Threads to maintain the call state
* between invocations. Therefore it can be yielded from anywhere, similar to
* the "Coco" yield-from-anywhere patch available for C-based lua. However,
* coroutines that are yielded but never resumed to complete their execution may
* not be collected by the garbage collector.
* <p>
* Typically, this library is included as part of a call to either
* {@link org.luaj.vm2.lib.jse.JsePlatform#standardGlobals()} or {@link org.luaj.vm2.lib.jme.JmePlatform#standardGlobals()}
* <pre> {@code
* {@link org.luaj.vm2.lib.jse.JsePlatform#standardGlobals()} or
* {@link org.luaj.vm2.lib.jme.JmePlatform#standardGlobals()}
*
* <pre>
* {
* &#64;code
* Globals globals = JsePlatform.standardGlobals();
* System.out.println( globals.get("coroutine").get("running").call() );
* } </pre>
* System.out.println(globals.get("coroutine").get("running").call());
* }
* </pre>
* <p>
* To instantiate and use it directly,
* link it into your globals table via {@link LuaValue#load(LuaValue)} using code such as:
* <pre> {@code
* To instantiate and use it directly, link it into your globals table via
* {@link LuaValue#load(LuaValue)} using code such as:
*
* <pre>
* {
* &#64;code
* Globals globals = new Globals();
* globals.load(new JseBaseLib());
* globals.load(new PackageLib());
* globals.load(new CoroutineLib());
* System.out.println( globals.get("coroutine").get("running").call() );
* } </pre>
* System.out.println(globals.get("coroutine").get("running").call());
* }
* </pre>
* <p>
*
* @see LibFunction
* @see org.luaj.vm2.lib.jse.JsePlatform
* @see org.luaj.vm2.lib.jme.JmePlatform
* @see <a href="http://www.lua.org/manual/5.2/manual.html#6.2">Lua 5.2 Coroutine Lib Reference</a>
* @see <a href="http://www.lua.org/manual/5.2/manual.html#6.2">Lua 5.2
* Coroutine Lib Reference</a>
*/
public class CoroutineLib extends TwoArgFunction {
@@ -66,11 +77,15 @@ public class CoroutineLib extends TwoArgFunction {
Globals globals;
/** Perform one-time initialization on the library by creating a table
* containing the library functions, adding that table to the supplied environment,
* adding the table to package.loaded, and returning table as the return value.
/**
* Perform one-time initialization on the library by creating a table
* containing the library functions, adding that table to the supplied
* environment, adding the table to package.loaded, and returning table as
* the return value.
*
* @param modname the module name supplied if this is loaded via 'require'.
* @param env the environment to load into, which must be a Globals instance.
* @param env the environment to load into, which must be a Globals
* instance.
*/
public LuaValue call(LuaValue modname, LuaValue env) {
globals = env.checkglobals();
@@ -82,7 +97,8 @@ public class CoroutineLib extends TwoArgFunction {
coroutine.set("yield", new yield());
coroutine.set("wrap", new wrap());
env.set("coroutine", coroutine);
if (!env.get("package").isnil()) env.get("package").get("loaded").set("coroutine", coroutine);
if (!env.get("package").isnil())
env.get("package").get("loaded").set("coroutine", coroutine);
return coroutine;
}
@@ -95,7 +111,7 @@ public class CoroutineLib extends TwoArgFunction {
static final class resume extends VarArgFunction {
public Varargs invoke(Varargs args) {
final LuaThread t = args.checkthread(1);
return t.resume( args.subargs(2) );
return t.resume(args.subargs(2));
}
}
@@ -109,13 +125,13 @@ public class CoroutineLib extends TwoArgFunction {
static final class status extends LibFunction {
public LuaValue call(LuaValue t) {
LuaThread lt = t.checkthread();
return valueOf( lt.getStatus() );
return valueOf(lt.getStatus());
}
}
final class yield extends VarArgFunction {
public Varargs invoke(Varargs args) {
return globals.yield( args );
return globals.yield(args);
}
}
@@ -129,15 +145,17 @@ public class CoroutineLib extends TwoArgFunction {
static final class wrapper extends VarArgFunction {
final LuaThread luathread;
wrapper(LuaThread luathread) {
this.luathread = luathread;
}
public Varargs invoke(Varargs args) {
final Varargs result = luathread.resume(args);
if ( result.arg1().toboolean() ) {
if (result.arg1().toboolean()) {
return result.subargs(2);
} else {
return error( result.arg(2).tojstring() );
return error(result.arg(2).tojstring());
}
}
}

View File

@@ -39,49 +39,64 @@ import org.luaj.vm2.Prototype;
import org.luaj.vm2.Varargs;
/**
* Subclass of {@link LibFunction} which implements the lua standard {@code debug}
* library.
* Subclass of {@link LibFunction} which implements the lua standard
* {@code debug} library.
* <p>
* The debug library in luaj tries to emulate the behavior of the corresponding C-based lua library.
* To do this, it must maintain a separate stack of calls to {@link LuaClosure} and {@link LibFunction}
* instances.
* Especially when lua-to-java bytecode compiling is being used
* via a {@link org.luaj.vm2.Globals.Compiler} such as {@link org.luaj.vm2.luajc.LuaJC},
* this cannot be done in all cases.
* The debug library in luaj tries to emulate the behavior of the corresponding
* C-based lua library. To do this, it must maintain a separate stack of calls
* to {@link LuaClosure} and {@link LibFunction} instances. Especially when
* lua-to-java bytecode compiling is being used via a
* {@link org.luaj.vm2.Globals.Compiler} such as
* {@link org.luaj.vm2.luajc.LuaJC}, this cannot be done in all cases.
* <p>
* Typically, this library is included as part of a call to either
* {@link org.luaj.vm2.lib.jse.JsePlatform#debugGlobals()} or
* {@link org.luaj.vm2.lib.jme.JmePlatform#debugGlobals()}
* <pre> {@code
*
* <pre>
* {
* &#64;code
* Globals globals = JsePlatform.debugGlobals();
* System.out.println( globals.get("debug").get("traceback").call() );
* } </pre>
* System.out.println(globals.get("debug").get("traceback").call());
* }
* </pre>
* <p>
* To instantiate and use it directly,
* link it into your globals table via {@link LuaValue#load(LuaValue)} using code such as:
* <pre> {@code
* To instantiate and use it directly, link it into your globals table via
* {@link LuaValue#load(LuaValue)} using code such as:
*
* <pre>
* {
* &#64;code
* Globals globals = new Globals();
* globals.load(new JseBaseLib());
* globals.load(new PackageLib());
* globals.load(new DebugLib());
* System.out.println( globals.get("debug").get("traceback").call() );
* } </pre>
* System.out.println(globals.get("debug").get("traceback").call());
* }
* </pre>
* <p>
* This library exposes the entire state of lua code, and provides method to see and modify
* all underlying lua values within a Java VM so should not be exposed to client code
* in a shared server environment.
* This library exposes the entire state of lua code, and provides method to see
* and modify all underlying lua values within a Java VM so should not be
* exposed to client code in a shared server environment.
*
* @see LibFunction
* @see org.luaj.vm2.lib.jse.JsePlatform
* @see org.luaj.vm2.lib.jme.JmePlatform
* @see <a href="http://www.lua.org/manual/5.2/manual.html#6.10">Lua 5.2 Debug Lib Reference</a>
* @see <a href="http://www.lua.org/manual/5.2/manual.html#6.10">Lua 5.2 Debug
* Lib Reference</a>
*/
public class DebugLib extends TwoArgFunction {
public static boolean CALLS;
public static boolean TRACE;
static {
try { CALLS = (null != System.getProperty("CALLS")); } catch (Exception e) {}
try { TRACE = (null != System.getProperty("TRACE")); } catch (Exception e) {}
try {
CALLS = (null != System.getProperty("CALLS"));
} catch (Exception e) {
}
try {
TRACE = (null != System.getProperty("TRACE"));
} catch (Exception e) {
}
}
static final LuaString LUA = valueOf("Lua");
@@ -108,11 +123,15 @@ public class DebugLib extends TwoArgFunction {
Globals globals;
/** Perform one-time initialization on the library by creating a table
* containing the library functions, adding that table to the supplied environment,
* adding the table to package.loaded, and returning table as the return value.
/**
* Perform one-time initialization on the library by creating a table
* containing the library functions, adding that table to the supplied
* environment, adding the table to package.loaded, and returning table as
* the return value.
*
* @param modname the module name supplied if this is loaded via 'require'.
* @param env the environment to load into, which must be a Globals instance.
* @param env the environment to load into, which must be a Globals
* instance.
*/
public LuaValue call(LuaValue modname, LuaValue env) {
globals = env.checkglobals();
@@ -135,7 +154,8 @@ public class DebugLib extends TwoArgFunction {
debug.set("upvalueid", new upvalueid());
debug.set("upvaluejoin", new upvaluejoin());
env.set("debug", debug);
if (!env.get("package").isnil()) env.get("package").get("loaded").set("debug", debug);
if (!env.get("package").isnil())
env.get("package").get("loaded").set("debug", debug);
return debug;
}
@@ -149,19 +169,17 @@ public class DebugLib extends TwoArgFunction {
// debug.gethook ([thread])
final class gethook extends VarArgFunction {
public Varargs invoke(Varargs args) {
LuaThread t = args.narg() > 0 ? args.checkthread(1): globals.running;
LuaThread t = args.narg() > 0? args.checkthread(1): globals.running;
LuaThread.State s = t.state;
return varargsOf(
s.hookfunc != null? s.hookfunc: NIL,
valueOf((s.hookcall?"c":"")+(s.hookline?"l":"")+(s.hookrtrn?"r":"")),
valueOf(s.hookcount));
return varargsOf(s.hookfunc != null? s.hookfunc: NIL,
valueOf((s.hookcall? "c": "")+(s.hookline? "l": "")+(s.hookrtrn? "r": "")), valueOf(s.hookcount));
}
}
// debug.getinfo ([thread,] f [, what])
final class getinfo extends VarArgFunction {
public Varargs invoke(Varargs args) {
int a=1;
int a = 1;
LuaThread thread = args.isthread(a)? args.checkthread(a++): globals.running;
LuaValue func = args.arg(a++);
String what = args.optjstring(a++, "flnStu");
@@ -169,12 +187,12 @@ public class DebugLib extends TwoArgFunction {
// find the stack info
DebugLib.CallFrame frame;
if ( func.isnumber() ) {
if (func.isnumber()) {
frame = callstack.getCallFrame(func.toint());
if (frame == null)
return NONE;
func = frame.f;
} else if ( func.isfunction() ) {
} else if (func.isfunction()) {
frame = callstack.findCallFrame(func);
} else {
return argerror(a-2, "function or level");
@@ -191,7 +209,7 @@ public class DebugLib extends TwoArgFunction {
info.set(LASTLINEDEFINED, valueOf(ar.lastlinedefined));
}
if (what.indexOf('l') >= 0) {
info.set( CURRENTLINE, valueOf(ar.currentline) );
info.set(CURRENTLINE, valueOf(ar.currentline));
}
if (what.indexOf('u') >= 0) {
info.set(NUPS, valueOf(ar.nups));
@@ -199,7 +217,7 @@ public class DebugLib extends TwoArgFunction {
info.set(ISVARARG, ar.isvararg? ONE: ZERO);
}
if (what.indexOf('n') >= 0) {
info.set(NAME, LuaValue.valueOf(ar.name!=null? ar.name: "?"));
info.set(NAME, LuaValue.valueOf(ar.name != null? ar.name: "?"));
info.set(NAMEWHAT, LuaValue.valueOf(ar.namewhat));
}
if (what.indexOf('t') >= 0) {
@@ -209,13 +227,13 @@ public class DebugLib extends TwoArgFunction {
LuaTable lines = new LuaTable();
info.set(ACTIVELINES, lines);
DebugLib.CallFrame cf;
for (int l = 1; (cf=callstack.getCallFrame(l)) != null; ++l)
for (int l = 1; (cf = callstack.getCallFrame(l)) != null; ++l)
if (cf.f == func)
lines.insert(-1, valueOf(cf.currentline()));
}
if (what.indexOf('f') >= 0) {
if (func != null)
info.set( FUNC, func );
info.set(FUNC, func);
}
return info;
}
@@ -224,7 +242,7 @@ public class DebugLib extends TwoArgFunction {
// debug.getlocal ([thread,] f, local)
final class getlocal extends VarArgFunction {
public Varargs invoke(Varargs args) {
int a=1;
int a = 1;
LuaThread thread = args.isthread(a)? args.checkthread(a++): globals.running;
int level = args.checkint(a++);
int local = args.checkint(a++);
@@ -253,11 +271,11 @@ public class DebugLib extends TwoArgFunction {
public Varargs invoke(Varargs args) {
LuaValue func = args.checkfunction(1);
int up = args.checkint(2);
if ( func instanceof LuaClosure ) {
if (func instanceof LuaClosure) {
LuaClosure c = (LuaClosure) func;
LuaString name = findupvalue(c, up);
if ( name != null ) {
return varargsOf(name, c.upValues[up-1].getValue() );
if (name != null) {
return varargsOf(name, c.upValues[up-1].getValue());
}
}
return NIL;
@@ -271,21 +289,26 @@ public class DebugLib extends TwoArgFunction {
}
}
// debug.sethook ([thread,] hook, mask [, count])
final class sethook extends VarArgFunction {
public Varargs invoke(Varargs args) {
int a=1;
int a = 1;
LuaThread t = args.isthread(a)? args.checkthread(a++): globals.running;
LuaValue func = args.optfunction(a++, null);
String str = args.optjstring(a++,"");
int count = args.optint(a++,0);
boolean call=false,line=false,rtrn=false;
for ( int i=0; i<str.length(); i++ )
switch ( str.charAt(i) ) {
case 'c': call=true; break;
case 'l': line=true; break;
case 'r': rtrn=true; break;
String str = args.optjstring(a++, "");
int count = args.optint(a++, 0);
boolean call = false, line = false, rtrn = false;
for (int i = 0; i < str.length(); i++)
switch (str.charAt(i)) {
case 'c':
call = true;
break;
case 'l':
line = true;
break;
case 'r':
rtrn = true;
break;
}
LuaThread.State s = t.state;
s.hookfunc = func;
@@ -300,7 +323,7 @@ public class DebugLib extends TwoArgFunction {
// debug.setlocal ([thread,] level, local, value)
final class setlocal extends VarArgFunction {
public Varargs invoke(Varargs args) {
int a=1;
int a = 1;
LuaThread thread = args.isthread(a)? args.checkthread(a++): globals.running;
int level = args.checkint(a++);
int local = args.checkint(a++);
@@ -314,14 +337,27 @@ public class DebugLib extends TwoArgFunction {
static final class setmetatable extends TwoArgFunction {
public LuaValue call(LuaValue value, LuaValue table) {
LuaValue mt = table.opttable(null);
switch ( value.type() ) {
case TNIL: LuaNil.s_metatable = mt; break;
case TNUMBER: LuaNumber.s_metatable = mt; break;
case TBOOLEAN: LuaBoolean.s_metatable = mt; break;
case TSTRING: LuaString.s_metatable = mt; break;
case TFUNCTION: LuaFunction.s_metatable = mt; break;
case TTHREAD: LuaThread.s_metatable = mt; break;
default: value.setmetatable( mt );
switch (value.type()) {
case TNIL:
LuaNil.s_metatable = mt;
break;
case TNUMBER:
LuaNumber.s_metatable = mt;
break;
case TBOOLEAN:
LuaBoolean.s_metatable = mt;
break;
case TSTRING:
LuaString.s_metatable = mt;
break;
case TFUNCTION:
LuaFunction.s_metatable = mt;
break;
case TTHREAD:
LuaThread.s_metatable = mt;
break;
default:
value.setmetatable(mt);
}
return value;
}
@@ -333,10 +369,10 @@ public class DebugLib extends TwoArgFunction {
LuaValue func = args.checkfunction(1);
int up = args.checkint(2);
LuaValue value = args.arg(3);
if ( func instanceof LuaClosure ) {
if (func instanceof LuaClosure) {
LuaClosure c = (LuaClosure) func;
LuaString name = findupvalue(c, up);
if ( name != null ) {
if (name != null) {
c.upValues[up-1].setValue(value);
return name;
}
@@ -360,12 +396,12 @@ public class DebugLib extends TwoArgFunction {
// debug.traceback ([thread,] [message [, level]])
final class traceback extends VarArgFunction {
public Varargs invoke(Varargs args) {
int a=1;
int a = 1;
LuaThread thread = args.isthread(a)? args.checkthread(a++): globals.running;
String message = args.optjstring(a++, null);
int level = args.optint(a++,1);
int level = args.optint(a++, 1);
String tb = callstack(thread).traceback(level);
return valueOf(message!=null? message+"\n"+tb: tb);
return valueOf(message != null? message + "\n" + tb: tb);
}
}
@@ -374,9 +410,9 @@ public class DebugLib extends TwoArgFunction {
public Varargs invoke(Varargs args) {
LuaValue func = args.checkfunction(1);
int up = args.checkint(2);
if ( func instanceof LuaClosure ) {
if (func instanceof LuaClosure) {
LuaClosure c = (LuaClosure) func;
if ( c.upValues != null && up > 0 && up <= c.upValues.length ) {
if (c.upValues != null && up > 0 && up <= c.upValues.length) {
return valueOf(c.upValues[up-1].hashCode());
}
}
@@ -402,29 +438,35 @@ public class DebugLib extends TwoArgFunction {
public void onCall(LuaFunction f) {
LuaThread.State s = globals.running.state;
if (s.inhook) return;
if (s.inhook)
return;
callstack().onCall(f);
if (s.hookcall) callHook(s, CALL, NIL);
if (s.hookcall)
callHook(s, CALL, NIL);
}
public void onCall(LuaClosure c, Varargs varargs, LuaValue[] stack) {
LuaThread.State s = globals.running.state;
if (s.inhook) return;
if (s.inhook)
return;
callstack().onCall(c, varargs, stack);
if (s.hookcall) callHook(s, CALL, NIL);
if (s.hookcall)
callHook(s, CALL, NIL);
}
public void onInstruction(int pc, Varargs v, int top) {
LuaThread.State s = globals.running.state;
if (s.inhook) return;
if (s.inhook)
return;
callstack().onInstruction(pc, v, top);
if (s.hookfunc == null) return;
if (s.hookfunc == null)
return;
if (s.hookcount > 0)
if (++s.bytecodes % s.hookcount == 0)
if (++s.bytecodes%s.hookcount == 0)
callHook(s, COUNT, NIL);
if (s.hookline) {
int newline = callstack().currentline();
if ( newline != s.lastline ) {
if (newline != s.lastline) {
s.lastline = newline;
callHook(s, LINE, LuaValue.valueOf(newline));
}
@@ -433,9 +475,11 @@ public class DebugLib extends TwoArgFunction {
public void onReturn() {
LuaThread.State s = globals.running.state;
if (s.inhook) return;
if (s.inhook)
return;
callstack().onReturn();
if (s.hookrtrn) callHook(s, RETURN, NIL);
if (s.hookrtrn)
callHook(s, RETURN, NIL);
}
public String traceback(int level) {
@@ -447,7 +491,8 @@ public class DebugLib extends TwoArgFunction {
}
void callHook(LuaThread.State s, LuaValue type, LuaValue arg) {
if (s.inhook || s.hookfunc == null) return;
if (s.inhook || s.hookfunc == null)
return;
s.inhook = true;
try {
s.hookfunc.call(type, arg);
@@ -479,7 +524,7 @@ public class DebugLib extends TwoArgFunction {
int linedefined; /* (S) */
int lastlinedefined; /* (S) */
short nups; /* (u) number of upvalues */
short nparams;/* (u) number of parameters */
short nparams; /* (u) number of parameters */
boolean isvararg; /* (u) */
boolean istailcall; /* (t) */
String short_src; /* (S) */
@@ -488,10 +533,10 @@ public class DebugLib extends TwoArgFunction {
public void funcinfo(LuaFunction f) {
if (f.isclosure()) {
Prototype p = f.checkclosure().p;
this.source = p.source != null ? p.source.tojstring() : "=?";
this.source = p.source != null? p.source.tojstring(): "=?";
this.linedefined = p.linedefined;
this.lastlinedefined = p.lastlinedefined;
this.what = (this.linedefined == 0) ? "main" : "Lua";
this.what = (this.linedefined == 0)? "main": "Lua";
this.short_src = p.shortsource();
} else {
this.source = "=[Java]";
@@ -516,7 +561,7 @@ public class DebugLib extends TwoArgFunction {
private synchronized CallFrame pushcall() {
if (calls >= frame.length) {
int n = Math.max(4, frame.length * 3 / 2);
int n = Math.max(4, frame.length*3/2);
CallFrame[] f = new CallFrame[n];
System.arraycopy(frame, 0, f, 0, frame.length);
for (int i = frame.length; i < n; ++i)
@@ -548,32 +593,33 @@ public class DebugLib extends TwoArgFunction {
/**
* Get the traceback starting at a specific level.
*
* @param level
* @return String containing the traceback.
*/
synchronized String traceback(int level) {
StringBuffer sb = new StringBuffer();
sb.append( "stack traceback:" );
for (DebugLib.CallFrame c; (c = getCallFrame(level++)) != null; ) {
sb.append("stack traceback:");
for (DebugLib.CallFrame c; (c = getCallFrame(level++)) != null;) {
sb.append("\n\t");
sb.append( c.shortsource() );
sb.append( ':' );
sb.append(c.shortsource());
sb.append(':');
if (c.currentline() > 0)
sb.append( c.currentline()+":" );
sb.append( " in " );
sb.append(c.currentline() + ":");
sb.append(" in ");
DebugInfo ar = auxgetinfo("n", c.f, c);
if (c.linedefined() == 0)
sb.append("main chunk");
else if ( ar.name != null ) {
sb.append( "function '" );
sb.append( ar.name );
sb.append( '\'' );
else if (ar.name != null) {
sb.append("function '");
sb.append(ar.name);
sb.append('\'');
} else {
sb.append( "function <" );
sb.append( c.shortsource() );
sb.append( ':' );
sb.append( c.linedefined() );
sb.append( '>' );
sb.append("function <");
sb.append(c.shortsource());
sb.append(':');
sb.append(c.linedefined());
sb.append('>');
}
}
sb.append("\n\t[Java]: in ?");
@@ -593,7 +639,6 @@ public class DebugLib extends TwoArgFunction {
return null;
}
synchronized DebugInfo auxgetinfo(String what, LuaFunction f, CallFrame ci) {
DebugInfo ar = new DebugInfo();
for (int i = 0, n = what.length(); i < n; ++i) {
@@ -656,22 +701,27 @@ public class DebugLib extends TwoArgFunction {
Varargs v;
LuaValue[] stack;
CallFrame previous;
void set(LuaClosure function, Varargs varargs, LuaValue[] stack) {
this.f = function;
this.v = varargs;
this.stack = stack;
}
public String shortsource() {
return f.isclosure()? f.checkclosure().p.shortsource(): "[Java]";
}
void set(LuaFunction function) {
this.f = function;
}
void reset() {
this.f = null;
this.v = null;
this.stack = null;
}
void instr(int pc, Varargs v, int top) {
this.pc = pc;
this.v = v;
@@ -679,57 +729,68 @@ public class DebugLib extends TwoArgFunction {
if (TRACE)
Print.printState(f.checkclosure(), pc, stack, top, v);
}
Varargs getLocal(int i) {
LuaString name = getlocalname(i);
if ( i >= 1 && i <= stack.length && stack[i-1] != null )
return varargsOf( name == null ? NIL : name, stack[i-1] );
if (i >= 1 && i <= stack.length && stack[i-1] != null)
return varargsOf(name == null? NIL: name, stack[i-1]);
else
return NIL;
}
Varargs setLocal(int i, LuaValue value) {
LuaString name = getlocalname(i);
if ( i >= 1 && i <= stack.length && stack[i-1] != null ) {
if (i >= 1 && i <= stack.length && stack[i-1] != null) {
stack[i-1] = value;
return name == null ? NIL : name;
return name == null? NIL: name;
} else {
return NIL;
}
}
public int currentline() {
if ( !f.isclosure() ) return -1;
if (!f.isclosure())
return -1;
int[] li = f.checkclosure().p.lineinfo;
return li==null || pc<0 || pc>=li.length? -1: li[pc];
return li == null || pc < 0 || pc >= li.length? -1: li[pc];
}
String sourceline() {
if ( !f.isclosure() ) return f.tojstring();
if (!f.isclosure())
return f.tojstring();
return f.checkclosure().p.shortsource() + ":" + currentline();
}
int linedefined() {
return f.isclosure()? f.checkclosure().p.linedefined: -1;
}
LuaString getlocalname(int index) {
if ( !f.isclosure() ) return null;
if (!f.isclosure())
return null;
return f.checkclosure().p.getlocalname(index, pc);
}
}
static LuaString findupvalue(LuaClosure c, int up) {
if ( c.upValues != null && up > 0 && up <= c.upValues.length ) {
if ( c.p.upvalues != null && up <= c.p.upvalues.length )
if (c.upValues != null && up > 0 && up <= c.upValues.length) {
if (c.p.upvalues != null && up <= c.p.upvalues.length)
return c.p.upvalues[up-1].name;
else
return LuaString.valueOf( "."+up );
return LuaString.valueOf("." + up);
}
return null;
}
static void lua_assert(boolean x) {
if (!x) throw new RuntimeException("lua_assert failed");
if (!x)
throw new RuntimeException("lua_assert failed");
}
static class NameWhat {
final String name;
final String namewhat;
NameWhat(String name, String namewhat) {
this.name = name;
this.namewhat = namewhat;
@@ -753,33 +814,61 @@ public class DebugLib extends TwoArgFunction {
/* all other instructions can call only through metamethods */
case Lua.OP_SELF:
case Lua.OP_GETTABUP:
case Lua.OP_GETTABLE: tm = LuaValue.INDEX; break;
case Lua.OP_GETTABLE:
tm = LuaValue.INDEX;
break;
case Lua.OP_SETTABUP:
case Lua.OP_SETTABLE: tm = LuaValue.NEWINDEX; break;
case Lua.OP_EQ: tm = LuaValue.EQ; break;
case Lua.OP_ADD: tm = LuaValue.ADD; break;
case Lua.OP_SUB: tm = LuaValue.SUB; break;
case Lua.OP_MUL: tm = LuaValue.MUL; break;
case Lua.OP_DIV: tm = LuaValue.DIV; break;
case Lua.OP_MOD: tm = LuaValue.MOD; break;
case Lua.OP_POW: tm = LuaValue.POW; break;
case Lua.OP_UNM: tm = LuaValue.UNM; break;
case Lua.OP_LEN: tm = LuaValue.LEN; break;
case Lua.OP_LT: tm = LuaValue.LT; break;
case Lua.OP_LE: tm = LuaValue.LE; break;
case Lua.OP_CONCAT: tm = LuaValue.CONCAT; break;
case Lua.OP_SETTABLE:
tm = LuaValue.NEWINDEX;
break;
case Lua.OP_EQ:
tm = LuaValue.EQ;
break;
case Lua.OP_ADD:
tm = LuaValue.ADD;
break;
case Lua.OP_SUB:
tm = LuaValue.SUB;
break;
case Lua.OP_MUL:
tm = LuaValue.MUL;
break;
case Lua.OP_DIV:
tm = LuaValue.DIV;
break;
case Lua.OP_MOD:
tm = LuaValue.MOD;
break;
case Lua.OP_POW:
tm = LuaValue.POW;
break;
case Lua.OP_UNM:
tm = LuaValue.UNM;
break;
case Lua.OP_LEN:
tm = LuaValue.LEN;
break;
case Lua.OP_LT:
tm = LuaValue.LT;
break;
case Lua.OP_LE:
tm = LuaValue.LE;
break;
case Lua.OP_CONCAT:
tm = LuaValue.CONCAT;
break;
default:
return null; /* else no useful name can be found */
}
return new NameWhat( tm.tojstring(), "metamethod" );
return new NameWhat(tm.tojstring(), "metamethod");
}
// return NameWhat if found, null if not
public static NameWhat getobjname(Prototype p, int lastpc, int reg) {
int pc = lastpc; // currentpc(L, ci);
LuaString name = p.getlocalname(reg + 1, pc);
LuaString name = p.getlocalname(reg+1, pc);
if (name != null) /* is a local? */
return new NameWhat( name.tojstring(), "local" );
return new NameWhat(name.tojstring(), "local");
/* else try symbolic execution */
pc = findsetreg(p, lastpc, reg);
@@ -798,30 +887,29 @@ public class DebugLib extends TwoArgFunction {
int k = Lua.GETARG_C(i); /* key index */
int t = Lua.GETARG_B(i); /* table index */
LuaString vn = (Lua.GET_OPCODE(i) == Lua.OP_GETTABLE) /* name of indexed variable */
? p.getlocalname(t + 1, pc)
: (t < p.upvalues.length ? p.upvalues[t].name : QMARK);
? p.getlocalname(t+1, pc)
: (t < p.upvalues.length? p.upvalues[t].name: QMARK);
String jname = kname(p, pc, k);
return new NameWhat( jname, vn != null && vn.eq_b(ENV)? "global": "field" );
return new NameWhat(jname, vn != null && vn.eq_b(ENV)? "global": "field");
}
case Lua.OP_GETUPVAL: {
int u = Lua.GETARG_B(i); /* upvalue index */
name = u < p.upvalues.length ? p.upvalues[u].name : QMARK;
return name == null ? null : new NameWhat( name.tojstring(), "upvalue" );
name = u < p.upvalues.length? p.upvalues[u].name: QMARK;
return name == null? null: new NameWhat(name.tojstring(), "upvalue");
}
case Lua.OP_LOADK:
case Lua.OP_LOADKX: {
int b = (Lua.GET_OPCODE(i) == Lua.OP_LOADK) ? Lua.GETARG_Bx(i)
: Lua.GETARG_Ax(p.code[pc + 1]);
int b = (Lua.GET_OPCODE(i) == Lua.OP_LOADK)? Lua.GETARG_Bx(i): Lua.GETARG_Ax(p.code[pc+1]);
if (p.k[b].isstring()) {
name = p.k[b].strvalue();
return new NameWhat( name.tojstring(), "constant" );
return new NameWhat(name.tojstring(), "constant");
}
break;
}
case Lua.OP_SELF: {
int k = Lua.GETARG_C(i); /* key index */
String jname = kname(p, pc, k);
return new NameWhat( jname, "method" );
return new NameWhat(jname, "method");
}
default:
break;
@@ -849,7 +937,7 @@ public class DebugLib extends TwoArgFunction {
/*
** try to find last instruction before 'lastpc' that modified register 'reg'
*/
static int findsetreg (Prototype p, int lastpc, int reg) {
static int findsetreg(Prototype p, int lastpc, int reg) {
int pc;
int setreg = -1; /* keep last instruction that changed 'reg' */
for (pc = 0; pc < lastpc; pc++) {
@@ -859,33 +947,37 @@ public class DebugLib extends TwoArgFunction {
switch (op) {
case Lua.OP_LOADNIL: {
int b = Lua.GETARG_B(i);
if (a <= reg && reg <= a + b) /* set registers from 'a' to 'a+b' */
if (a <= reg && reg <= a+b) /* set registers from 'a' to 'a+b' */
setreg = pc;
break;
}
case Lua.OP_TFORCALL: {
if (reg >= a + 2) setreg = pc; /* affect all regs above its base */
if (reg >= a+2)
setreg = pc; /* affect all regs above its base */
break;
}
case Lua.OP_CALL:
case Lua.OP_TAILCALL: {
if (reg >= a) setreg = pc; /* affect all registers above base */
if (reg >= a)
setreg = pc; /* affect all registers above base */
break;
}
case Lua.OP_JMP: {
int b = Lua.GETARG_sBx(i);
int dest = pc + 1 + b;
int dest = pc+1+b;
/* jump is forward and do not skip `lastpc'? */
if (pc < dest && dest <= lastpc)
pc += b; /* do the jump */
break;
}
case Lua.OP_TEST: {
if (reg == a) setreg = pc; /* jumped code can change 'a' */
if (reg == a)
setreg = pc; /* jumped code can change 'a' */
break;
}
case Lua.OP_SETLIST: { // Lua.testAMode(Lua.OP_SETLIST) == false
if ( ((i>>14)&0x1ff) == 0 ) pc++; // if c == 0 then c stored in next op -> skip
if (((i>>14) & 0x1ff) == 0)
pc++; // if c == 0 then c stored in next op -> skip
break;
}
default:

View File

@@ -32,77 +32,100 @@ import org.luaj.vm2.LuaValue;
import org.luaj.vm2.Varargs;
/**
* Abstract base class extending {@link LibFunction} which implements the
* core of the lua standard {@code io} library.
* Abstract base class extending {@link LibFunction} which implements the core
* of the lua standard {@code io} library.
* <p>
* It contains the implementation of the io library support that is common to
* the JSE and JME platforms.
* In practice on of the concrete IOLib subclasses is chosen:
* {@link org.luaj.vm2.lib.jse.JseIoLib} for the JSE platform, and
* the JSE and JME platforms. In practice on of the concrete IOLib subclasses is
* chosen: {@link org.luaj.vm2.lib.jse.JseIoLib} for the JSE platform, and
* {@link org.luaj.vm2.lib.jme.JmeIoLib} for the JME platform.
* <p>
* The JSE implementation conforms almost completely to the C-based lua library,
* while the JME implementation follows closely except in the area of random-access files,
* which are difficult to support properly on JME.
* while the JME implementation follows closely except in the area of
* random-access files, which are difficult to support properly on JME.
* <p>
* Typically, this library is included as part of a call to either
* {@link org.luaj.vm2.lib.jse.JsePlatform#standardGlobals()} or {@link org.luaj.vm2.lib.jme.JmePlatform#standardGlobals()}
* <pre> {@code
* {@link org.luaj.vm2.lib.jse.JsePlatform#standardGlobals()} or
* {@link org.luaj.vm2.lib.jme.JmePlatform#standardGlobals()}
*
* <pre>
* {
* &#64;code
* Globals globals = JsePlatform.standardGlobals();
* globals.get("io").get("write").call(LuaValue.valueOf("hello, world\n"));
* } </pre>
* In this example the platform-specific {@link org.luaj.vm2.lib.jse.JseIoLib} library will be loaded, which will include
* the base functionality provided by this class, whereas the {@link org.luaj.vm2.lib.jse.JsePlatform} would load the
* {@link org.luaj.vm2.lib.jse.JseIoLib}.
* }
* </pre>
*
* In this example the platform-specific {@link org.luaj.vm2.lib.jse.JseIoLib}
* library will be loaded, which will include the base functionality provided by
* this class, whereas the {@link org.luaj.vm2.lib.jse.JsePlatform} would load
* the {@link org.luaj.vm2.lib.jse.JseIoLib}.
* <p>
* To instantiate and use it directly,
* link it into your globals table via {@link LuaValue#load(LuaValue)} using code such as:
* <pre> {@code
* To instantiate and use it directly, link it into your globals table via
* {@link LuaValue#load(LuaValue)} using code such as:
*
* <pre>
* {
* &#64;code
* Globals globals = new Globals();
* globals.load(new JseBaseLib());
* globals.load(new PackageLib());
* globals.load(new OsLib());
* globals.get("io").get("write").call(LuaValue.valueOf("hello, world\n"));
* } </pre>
* }
* </pre>
* <p>
* This has been implemented to match as closely as possible the behavior in the corresponding library in C.
* This has been implemented to match as closely as possible the behavior in the
* corresponding library in C.
*
* @see LibFunction
* @see org.luaj.vm2.lib.jse.JsePlatform
* @see org.luaj.vm2.lib.jme.JmePlatform
* @see org.luaj.vm2.lib.jse.JseIoLib
* @see org.luaj.vm2.lib.jme.JmeIoLib
* @see <a href="http://www.lua.org/manual/5.1/manual.html#5.7">http://www.lua.org/manual/5.1/manual.html#5.7</a>
* @see <a href=
* "http://www.lua.org/manual/5.1/manual.html#5.7">http://www.lua.org/manual/5.1/manual.html#5.7</a>
*/
abstract
public class IoLib extends TwoArgFunction {
abstract public class IoLib extends TwoArgFunction {
abstract protected class File extends LuaValue {
abstract public void write(LuaString string) throws IOException;
abstract
protected class File extends LuaValue{
abstract public void write( LuaString string ) throws IOException;
abstract public void flush() throws IOException;
abstract public boolean isstdfile();
abstract public void close() throws IOException;
abstract public boolean isclosed();
// returns new position
abstract public int seek(String option, int bytecount) throws IOException;
abstract public void setvbuf(String mode, int size);
// get length remaining to read
abstract public int remaining() throws IOException;
// peek ahead one character
abstract public int peek() throws IOException, EOFException;
// return char if read, -1 if eof, throw IOException on other exception
abstract public int read() throws IOException, EOFException;
// return number of bytes read if positive, false if eof, throw IOException on other exception
abstract public int read(byte[] bytes, int offset, int length) throws IOException;
public boolean eof() throws IOException {
try {
return peek() < 0;
} catch (EOFException e) { return true; }
} catch (EOFException e) {
return true;
}
}
// delegate method access to file methods table
public LuaValue get( LuaValue key ) {
public LuaValue get(LuaValue key) {
return filemethods.get(key);
}
@@ -110,6 +133,7 @@ public class IoLib extends TwoArgFunction {
public int type() {
return LuaValue.TUSERDATA;
}
public String typename() {
return "userdata";
}
@@ -123,7 +147,8 @@ public class IoLib extends TwoArgFunction {
if (!isclosed()) {
try {
close();
} catch (IOException ignore) {}
} catch (IOException ignore) {
}
}
}
}
@@ -139,6 +164,7 @@ public class IoLib extends TwoArgFunction {
/**
* Wrap the standard input.
*
* @return File
* @throws IOException
*/
@@ -146,6 +172,7 @@ public class IoLib extends TwoArgFunction {
/**
* Wrap the standard output.
*
* @return File
* @throws IOException
*/
@@ -153,6 +180,7 @@ public class IoLib extends TwoArgFunction {
/**
* Wrap the standard error output.
*
* @return File
* @throws IOException
*/
@@ -160,6 +188,7 @@ public class IoLib extends TwoArgFunction {
/**
* Open a file in a particular mode.
*
* @param filename
* @param readMode true if opening in read mode
* @param appendMode true if opening in append mode
@@ -168,10 +197,12 @@ public class IoLib extends TwoArgFunction {
* @return File object if successful
* @throws IOException if could not be opened
*/
abstract protected File openFile( String filename, boolean readMode, boolean appendMode, boolean updateMode, boolean binaryMode ) throws IOException;
abstract protected File openFile(String filename, boolean readMode, boolean appendMode, boolean updateMode,
boolean binaryMode) throws IOException;
/**
* Open a temporary file.
*
* @return File object if successful
* @throws IOException if could not be opened
*/
@@ -179,6 +210,7 @@ public class IoLib extends TwoArgFunction {
/**
* Start a new process and return a file for input or output
*
* @param prog the program to execute
* @param mode "r" to read, "w" to write
* @return File to read to or write from
@@ -219,29 +251,10 @@ public class IoLib extends TwoArgFunction {
private static final int IO_INDEX = 18;
private static final int LINES_ITER = 19;
public static final String[] IO_NAMES = {
"close",
"flush",
"input",
"lines",
"open",
"output",
"popen",
"read",
"tmpfile",
"type",
"write",
};
public static final String[] IO_NAMES = { "close", "flush", "input", "lines", "open", "output", "popen", "read",
"tmpfile", "type", "write", };
public static final String[] FILE_NAMES = {
"close",
"flush",
"lines",
"read",
"seek",
"setvbuf",
"write",
};
public static final String[] FILE_NAMES = { "close", "flush", "lines", "read", "seek", "setvbuf", "write", };
LuaTable filemethods;
@@ -252,31 +265,32 @@ public class IoLib extends TwoArgFunction {
// io lib functions
LuaTable t = new LuaTable();
bind(t, IoLibV.class, IO_NAMES );
bind(t, IoLibV.class, IO_NAMES);
// create file methods table
filemethods = new LuaTable();
bind(filemethods, IoLibV.class, FILE_NAMES, FILE_CLOSE );
bind(filemethods, IoLibV.class, FILE_NAMES, FILE_CLOSE);
// set up file metatable
LuaTable mt = new LuaTable();
bind(mt, IoLibV.class, new String[] { "__index" }, IO_INDEX );
t.setmetatable( mt );
bind(mt, IoLibV.class, new String[] { "__index" }, IO_INDEX);
t.setmetatable(mt);
// all functions link to library instance
setLibInstance( t );
setLibInstance( filemethods );
setLibInstance( mt );
setLibInstance(t);
setLibInstance(filemethods);
setLibInstance(mt);
// return the table
env.set("io", t);
if (!env.get("package").isnil()) env.get("package").get("loaded").set("io", t);
if (!env.get("package").isnil())
env.get("package").get("loaded").set("io", t);
return t;
}
private void setLibInstance(LuaTable t) {
LuaValue[] k = t.keys();
for ( int i=0, n=k.length; i<n; i++ )
for (int i = 0, n = k.length; i < n; i++)
((IoLibV) t.get(k[i])).iolib = this;
}
@@ -285,13 +299,16 @@ public class IoLib extends TwoArgFunction {
public IoLib iolib;
private boolean toclose;
private Varargs args;
public IoLibV() {
}
public IoLibV(File f, String name, int opcode, IoLib iolib, boolean toclose, Varargs args) {
this(f, name, opcode, iolib);
this.toclose = toclose;
this.args = args.dealias();
}
public IoLibV(File f, String name, int opcode, IoLib iolib) {
super();
this.f = f;
@@ -302,34 +319,54 @@ public class IoLib extends TwoArgFunction {
public Varargs invoke(Varargs args) {
try {
switch ( opcode ) {
case IO_FLUSH: return iolib._io_flush();
case IO_TMPFILE: return iolib._io_tmpfile();
case IO_CLOSE: return iolib._io_close(args.arg1());
case IO_INPUT: return iolib._io_input(args.arg1());
case IO_OUTPUT: return iolib._io_output(args.arg1());
case IO_TYPE: return iolib._io_type(args.arg1());
case IO_POPEN: return iolib._io_popen(args.checkjstring(1),args.optjstring(2,"r"));
case IO_OPEN: return iolib._io_open(args.checkjstring(1), args.optjstring(2,"r"));
case IO_LINES: return iolib._io_lines(args);
case IO_READ: return iolib._io_read(args);
case IO_WRITE: return iolib._io_write(args);
switch (opcode) {
case IO_FLUSH:
return iolib._io_flush();
case IO_TMPFILE:
return iolib._io_tmpfile();
case IO_CLOSE:
return iolib._io_close(args.arg1());
case IO_INPUT:
return iolib._io_input(args.arg1());
case IO_OUTPUT:
return iolib._io_output(args.arg1());
case IO_TYPE:
return iolib._io_type(args.arg1());
case IO_POPEN:
return iolib._io_popen(args.checkjstring(1), args.optjstring(2, "r"));
case IO_OPEN:
return iolib._io_open(args.checkjstring(1), args.optjstring(2, "r"));
case IO_LINES:
return iolib._io_lines(args);
case IO_READ:
return iolib._io_read(args);
case IO_WRITE:
return iolib._io_write(args);
case FILE_CLOSE: return iolib._file_close(args.arg1());
case FILE_FLUSH: return iolib._file_flush(args.arg1());
case FILE_SETVBUF: return iolib._file_setvbuf(args.arg1(),args.checkjstring(2),args.optint(3,8192));
case FILE_LINES: return iolib._file_lines(args);
case FILE_READ: return iolib._file_read(args.arg1(),args.subargs(2));
case FILE_SEEK: return iolib._file_seek(args.arg1(),args.optjstring(2,"cur"),args.optint(3,0));
case FILE_WRITE: return iolib._file_write(args.arg1(),args.subargs(2));
case FILE_CLOSE:
return iolib._file_close(args.arg1());
case FILE_FLUSH:
return iolib._file_flush(args.arg1());
case FILE_SETVBUF:
return iolib._file_setvbuf(args.arg1(), args.checkjstring(2), args.optint(3, 8192));
case FILE_LINES:
return iolib._file_lines(args);
case FILE_READ:
return iolib._file_read(args.arg1(), args.subargs(2));
case FILE_SEEK:
return iolib._file_seek(args.arg1(), args.optjstring(2, "cur"), args.optint(3, 0));
case FILE_WRITE:
return iolib._file_write(args.arg1(), args.subargs(2));
case IO_INDEX: return iolib._io_index(args.arg(2));
case LINES_ITER: return iolib._lines_iter(f, toclose, this.args);
case IO_INDEX:
return iolib._io_index(args.arg(2));
case LINES_ITER:
return iolib._lines_iter(f, toclose, this.args);
}
} catch ( IOException ioe ) {
} catch (IOException ioe) {
if (opcode == LINES_ITER) {
String s = ioe.getMessage();
error(s != null ? s : ioe.toString());
error(s != null? s: ioe.toString());
}
return errorresult(ioe);
}
@@ -338,7 +375,7 @@ public class IoLib extends TwoArgFunction {
}
private File input() {
return infile!=null? infile: (infile=ioopenfile(FTYPE_STDIN, "-","r"));
return infile != null? infile: (infile = ioopenfile(FTYPE_STDIN, "-", "r"));
}
// io.flush() -> bool
@@ -362,31 +399,28 @@ public class IoLib extends TwoArgFunction {
// io.input([file]) -> file
public Varargs _io_input(LuaValue file) {
infile = file.isnil()? input():
file.isstring()? ioopenfile(FTYPE_NAMED, file.checkjstring(),"r"):
checkfile(file);
infile = file.isnil()? input()
: file.isstring()? ioopenfile(FTYPE_NAMED, file.checkjstring(), "r"): checkfile(file);
return infile;
}
// io.output(filename) -> file
public Varargs _io_output(LuaValue filename) {
outfile = filename.isnil()? output():
filename.isstring()? ioopenfile(FTYPE_NAMED, filename.checkjstring(),"w"):
checkfile(filename);
outfile = filename.isnil()? output()
: filename.isstring()? ioopenfile(FTYPE_NAMED, filename.checkjstring(), "w"): checkfile(filename);
return outfile;
}
// io.type(obj) -> "file" | "closed file" | nil
public Varargs _io_type(LuaValue obj) {
File f = optfile(obj);
return f!=null?
f.isclosed()? CLOSED_FILE: FILE:
NIL;
return f != null? f.isclosed()? CLOSED_FILE: FILE: NIL;
}
// io.popen(prog, [mode]) -> file
public Varargs _io_popen(String prog, String mode) throws IOException {
if (!"r".equals(mode) && !"w".equals(mode)) argerror(2, "invalid value: '" + mode + "'; must be one of 'r' or 'w'");
if (!"r".equals(mode) && !"w".equals(mode))
argerror(2, "invalid value: '" + mode + "'; must be one of 'r' or 'w'");
return openProgram(prog, mode);
}
@@ -398,7 +432,7 @@ public class IoLib extends TwoArgFunction {
// io.lines(filename, ...) -> iterator
public Varargs _io_lines(Varargs args) {
String filename = args.optjstring(1, null);
File infile = filename==null? input(): ioopenfile(FTYPE_NAMED, filename,"r");
File infile = filename == null? input(): ioopenfile(FTYPE_NAMED, filename, "r");
checkopen(infile);
return lines(infile, filename != null, args.subargs(2));
}
@@ -406,13 +440,13 @@ public class IoLib extends TwoArgFunction {
// io.read(...) -> (...)
public Varargs _io_read(Varargs args) throws IOException {
checkopen(input());
return ioread(infile,args);
return ioread(infile, args);
}
// io.write(...) -> void
public Varargs _io_write(Varargs args) throws IOException {
checkopen(output());
return iowrite(outfile,args);
return iowrite(outfile, args);
}
// file:close() -> void
@@ -434,7 +468,7 @@ public class IoLib extends TwoArgFunction {
} else {
argerror(1, "invalid value: '" + mode + "'; must be one of 'no', 'full' or 'line'");
}
checkfile(file).setvbuf(mode,size);
checkfile(file).setvbuf(mode, size);
return LuaValue.TRUE;
}
@@ -445,7 +479,7 @@ public class IoLib extends TwoArgFunction {
// file:read(...) -> (...)
public Varargs _file_read(LuaValue file, Varargs subargs) throws IOException {
return ioread(checkfile(file),subargs);
return ioread(checkfile(file), subargs);
}
// file:seek([whence][,offset]) -> pos | nil,error
@@ -456,50 +490,51 @@ public class IoLib extends TwoArgFunction {
} else {
argerror(1, "invalid value: '" + whence + "'; must be one of 'set', 'cur' or 'end'");
}
return valueOf( checkfile(file).seek(whence,offset) );
return valueOf(checkfile(file).seek(whence, offset));
}
// file:write(...) -> void
public Varargs _file_write(LuaValue file, Varargs subargs) throws IOException {
return iowrite(checkfile(file),subargs);
return iowrite(checkfile(file), subargs);
}
// __index, returns a field
public Varargs _io_index(LuaValue v) {
return v.equals(STDOUT)?output():
v.equals(STDIN)? input():
v.equals(STDERR)? errput(): NIL;
return v.equals(STDOUT)? output(): v.equals(STDIN)? input(): v.equals(STDERR)? errput(): NIL;
}
// lines iterator(s,var) -> var'
public Varargs _lines_iter(LuaValue file, boolean toclose, Varargs args) throws IOException {
File f = optfile(file);
if ( f == null ) argerror(1, "not a file: " + file);
if ( f.isclosed() ) error("file is already closed");
if (f == null)
argerror(1, "not a file: " + file);
if (f.isclosed())
error("file is already closed");
Varargs ret = ioread(f, args);
if (toclose && ret.isnil(1) && f.eof()) f.close();
if (toclose && ret.isnil(1) && f.eof())
f.close();
return ret;
}
private File output() {
return outfile!=null? outfile: (outfile=ioopenfile(FTYPE_STDOUT,"-","w"));
return outfile != null? outfile: (outfile = ioopenfile(FTYPE_STDOUT, "-", "w"));
}
private File errput() {
return errfile!=null? errfile: (errfile=ioopenfile(FTYPE_STDERR,"-","w"));
return errfile != null? errfile: (errfile = ioopenfile(FTYPE_STDERR, "-", "w"));
}
private File ioopenfile(int filetype, String filename, String mode) {
try {
return rawopenfile(filetype, filename, mode);
} catch ( Exception e ) {
error("io error: "+e.getMessage());
} catch (Exception e) {
error("io error: " + e.getMessage());
return null;
}
}
private static Varargs ioclose(File f) throws IOException {
if ( f.isstdfile() )
if (f.isstdfile())
return errorresult("cannot close standard file");
else {
f.close();
@@ -513,7 +548,7 @@ public class IoLib extends TwoArgFunction {
static Varargs errorresult(Exception ioe) {
String s = ioe.getMessage();
return errorresult("io error: "+(s!=null? s: ioe.toString()));
return errorresult("io error: " + (s != null? s: ioe.toString()));
}
private static Varargs errorresult(String errortext) {
@@ -522,53 +557,62 @@ public class IoLib extends TwoArgFunction {
private Varargs lines(final File f, boolean toclose, Varargs args) {
try {
return new IoLibV(f,"lnext",LINES_ITER,this,toclose,args);
} catch ( Exception e ) {
return error("lines: "+e);
return new IoLibV(f, "lnext", LINES_ITER, this, toclose, args);
} catch (Exception e) {
return error("lines: " + e);
}
}
private static Varargs iowrite(File f, Varargs args) throws IOException {
for ( int i=1, n=args.narg(); i<=n; i++ )
f.write( args.checkstring(i) );
for (int i = 1, n = args.narg(); i <= n; i++)
f.write(args.checkstring(i));
return f;
}
private Varargs ioread(File f, Varargs args) throws IOException {
int i,n=args.narg();
if (n == 0) return freadline(f,false);
int i, n = args.narg();
if (n == 0)
return freadline(f, false);
LuaValue[] v = new LuaValue[n];
LuaValue ai,vi;
LuaValue ai, vi;
LuaString fmt;
for ( i=0; i<n; ) {
item: switch ( (ai = args.arg(i+1)).type() ) {
for (i = 0; i < n;) {
item: switch ((ai = args.arg(i+1)).type()) {
case LuaValue.TNUMBER:
vi = freadbytes(f,ai.toint());
vi = freadbytes(f, ai.toint());
break item;
case LuaValue.TSTRING:
fmt = ai.checkstring();
if ( fmt.m_length >= 2 && fmt.m_bytes[fmt.m_offset] == '*' ) {
switch ( fmt.m_bytes[fmt.m_offset+1] ) {
case 'n': vi = freadnumber(f); break item;
case 'l': vi = freadline(f,false); break item;
case 'L': vi = freadline(f,true); break item;
case 'a': vi = freadall(f); break item;
if (fmt.m_length >= 2 && fmt.m_bytes[fmt.m_offset] == '*') {
switch (fmt.m_bytes[fmt.m_offset+1]) {
case 'n':
vi = freadnumber(f);
break item;
case 'l':
vi = freadline(f, false);
break item;
case 'L':
vi = freadline(f, true);
break item;
case 'a':
vi = freadall(f);
break item;
}
}
default:
return argerror( i+1, "(invalid format)" );
return argerror(i+1, "(invalid format)");
}
if ( (v[i++] = vi).isnil() )
if ((v[i++] = vi).isnil())
break;
}
return i==0? NIL: varargsOf(v, 0, i);
return i == 0? NIL: varargsOf(v, 0, i);
}
private static File checkfile(LuaValue val) {
File f = optfile(val);
if ( f == null )
argerror(1,"file");
checkopen( f );
if (f == null)
argerror(1, "file");
checkopen(f);
return f;
}
@@ -577,7 +621,7 @@ public class IoLib extends TwoArgFunction {
}
private static File checkopen(File file) {
if ( file.isclosed() )
if (file.isclosed())
error("attempt to use a closed file");
return file;
}
@@ -586,99 +630,115 @@ public class IoLib extends TwoArgFunction {
int len = mode.length();
for (int i = 0; i < len; i++) { // [rwa][+]?b*
char ch = mode.charAt(i);
if (i == 0 && "rwa".indexOf(ch) >= 0) continue;
if (i == 1 && ch == '+') continue;
if (i >= 1 && ch == 'b') continue;
if (i == 0 && "rwa".indexOf(ch) >= 0)
continue;
if (i == 1 && ch == '+')
continue;
if (i >= 1 && ch == 'b')
continue;
len = -1;
break;
}
if (len <= 0) argerror(2, "invalid mode: '" + mode + "'");
if (len <= 0)
argerror(2, "invalid mode: '" + mode + "'");
switch (filetype) {
case FTYPE_STDIN: return wrapStdin();
case FTYPE_STDOUT: return wrapStdout();
case FTYPE_STDERR: return wrapStderr();
case FTYPE_STDIN:
return wrapStdin();
case FTYPE_STDOUT:
return wrapStdout();
case FTYPE_STDERR:
return wrapStderr();
}
boolean isreadmode = mode.startsWith("r");
boolean isappend = mode.startsWith("a");
boolean isupdate = mode.indexOf('+') > 0;
boolean isbinary = mode.endsWith("b");
return openFile( filename, isreadmode, isappend, isupdate, isbinary );
return openFile(filename, isreadmode, isappend, isupdate, isbinary);
}
// ------------- file reading utilitied ------------------
public static LuaValue freadbytes(File f, int count) throws IOException {
if (count == 0) return f.eof() ? NIL : EMPTYSTRING;
if (count == 0)
return f.eof()? NIL: EMPTYSTRING;
byte[] b = new byte[count];
int r;
if ( ( r = f.read(b,0,b.length) ) < 0 )
if ((r = f.read(b, 0, b.length)) < 0)
return NIL;
return LuaString.valueUsing(b, 0, r);
}
public static LuaValue freaduntil(File f,boolean lineonly,boolean withend) throws IOException {
public static LuaValue freaduntil(File f, boolean lineonly, boolean withend) throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
int c;
try {
if ( lineonly ) {
if (lineonly) {
loop: while ( (c = f.read()) >= 0 ) {
switch ( c ) {
case '\r': if (withend) baos.write(c); break;
case '\n': if (withend) baos.write(c); break loop;
default: baos.write(c); break;
switch (c) {
case '\r':
if (withend)
baos.write(c);
break;
case '\n':
if (withend)
baos.write(c);
break loop;
default:
baos.write(c);
break;
}
}
} else {
while ( (c = f.read()) >= 0 )
baos.write(c);
}
} catch ( EOFException e ) {
} catch (EOFException e) {
c = -1;
}
return ( c < 0 && baos.size() == 0 )?
(LuaValue) NIL:
(LuaValue) LuaString.valueUsing(baos.toByteArray());
return (c < 0 && baos.size() == 0)? (LuaValue) NIL: (LuaValue) LuaString.valueUsing(baos.toByteArray());
}
public static LuaValue freadline(File f,boolean withend) throws IOException {
return freaduntil(f,true,withend);
public static LuaValue freadline(File f, boolean withend) throws IOException {
return freaduntil(f, true, withend);
}
public static LuaValue freadall(File f) throws IOException {
int n = f.remaining();
if ( n >= 0 ) {
return n == 0 ? EMPTYSTRING : freadbytes(f, n);
if (n >= 0) {
return n == 0? EMPTYSTRING: freadbytes(f, n);
} else {
return freaduntil(f,false,false);
return freaduntil(f, false, false);
}
}
public static LuaValue freadnumber(File f) throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
freadchars(f," \t\r\n",null);
freadchars(f,"-+",baos);
freadchars(f, " \t\r\n", null);
freadchars(f, "-+", baos);
//freadchars(f,"0",baos);
//freadchars(f,"xX",baos);
freadchars(f,"0123456789",baos);
freadchars(f,".",baos);
freadchars(f,"0123456789",baos);
freadchars(f, "0123456789", baos);
freadchars(f, ".", baos);
freadchars(f, "0123456789", baos);
//freadchars(f,"eEfFgG",baos);
// freadchars(f,"+-",baos);
//freadchars(f,"0123456789",baos);
String s = baos.toString();
return s.length()>0? valueOf( Double.parseDouble(s) ): NIL;
return s.length() > 0? valueOf(Double.parseDouble(s)): NIL;
}
private static void freadchars(File f, String chars, ByteArrayOutputStream baos) throws IOException {
int c;
while ( true ) {
c = f.peek();
if ( chars.indexOf(c) < 0 ) {
if (chars.indexOf(c) < 0) {
return;
}
f.read();
if ( baos != null )
baos.write( c );
if (baos != null)
baos.write(c);
}
}
}

View File

@@ -29,20 +29,20 @@ import org.luaj.vm2.Varargs;
/**
* Subclass of {@link LuaFunction} common to Java functions exposed to lua.
* <p>
* To provide for common implementations in JME and JSE,
* library functions are typically grouped on one or more library classes
* and an opcode per library function is defined and used to key the switch
* to the correct function within the library.
* To provide for common implementations in JME and JSE, library functions are
* typically grouped on one or more library classes and an opcode per library
* function is defined and used to key the switch to the correct function within
* the library.
* <p>
* Since lua functions can be called with too few or too many arguments,
* and there are overloaded {@link LuaValue#call()} functions with varying
* number of arguments, a Java function exposed in lua needs to handle the
* argument fixup when a function is called with a number of arguments
* differs from that expected.
* Since lua functions can be called with too few or too many arguments, and
* there are overloaded {@link LuaValue#call()} functions with varying number of
* arguments, a Java function exposed in lua needs to handle the argument fixup
* when a function is called with a number of arguments differs from that
* expected.
* <p>
* To simplify the creation of library functions,
* there are 5 direct subclasses to handle common cases based on number of
* argument values and number of return return values.
* To simplify the creation of library functions, there are 5 direct subclasses
* to handle common cases based on number of argument values and number of
* return return values.
* <ul>
* <li>{@link ZeroArgFunction}</li>
* <li>{@link OneArgFunction}</li>
@@ -51,13 +51,15 @@ import org.luaj.vm2.Varargs;
* <li>{@link VarArgFunction}</li>
* </ul>
* <p>
* To be a Java library that can be loaded via {@code require}, it should have
* a public constructor that returns a {@link LuaValue} that, when executed,
* To be a Java library that can be loaded via {@code require}, it should have a
* public constructor that returns a {@link LuaValue} that, when executed,
* initializes the library.
* <p>
* For example, the following code will implement a library called "hyperbolic"
* with two functions, "sinh", and "cosh":
<pre> {@code
*
* <pre>
* {@code
* import org.luaj.vm2.LuaValue;
* import org.luaj.vm2.lib.*;
*
@@ -85,18 +87,22 @@ import org.luaj.vm2.Varargs;
* }
* }
*}
*}</pre>
* The default constructor is used to instantiate the library
* in response to {@code require 'hyperbolic'} statement,
* provided it is on Java&quot;s class path.
* This instance is then invoked with 2 arguments: the name supplied to require(),
* and the environment for this function. The library may ignore these, or use
* them to leave side effects in the global environment, for example.
* In the previous example, two functions are created, 'sinh', and 'cosh', and placed
* into a global table called 'hyperbolic' using the supplied 'env' argument.
*}
* </pre>
*
* The default constructor is used to instantiate the library in response to
* {@code require 'hyperbolic'} statement, provided it is on Java&quot;s class
* path. This instance is then invoked with 2 arguments: the name supplied to
* require(), and the environment for this function. The library may ignore
* these, or use them to leave side effects in the global environment, for
* example. In the previous example, two functions are created, 'sinh', and
* 'cosh', and placed into a global table called 'hyperbolic' using the supplied
* 'env' argument.
* <p>
* To test it, a script such as this can be used:
* <pre> {@code
*
* <pre>
* {@code
* local t = require('hyperbolic')
* print( 't', t )
* print( 'hyperbolic', hyperbolic )
@@ -105,30 +111,38 @@ import org.luaj.vm2.Varargs;
* end
* print( 'sinh(.5)', hyperbolic.sinh(.5) )
* print( 'cosh(.5)', hyperbolic.cosh(.5) )
* }</pre>
* }
* </pre>
* <p>
* It should produce something like:
* <pre> {@code
*
* <pre>
* {@code
* t table: 3dbbd23f
* hyperbolic table: 3dbbd23f
* k,v cosh function: 3dbbd128
* k,v sinh function: 3dbbd242
* sinh(.5) 0.5210953
* cosh(.5) 1.127626
* }</pre>
* }
* </pre>
* <p>
* See the source code in any of the library functions
* such as {@link BaseLib} or {@link TableLib} for other examples.
* See the source code in any of the library functions such as {@link BaseLib}
* or {@link TableLib} for other examples.
*/
abstract public class LibFunction extends LuaFunction {
/** User-defined opcode to differentiate between instances of the library function class.
/**
* User-defined opcode to differentiate between instances of the library
* function class.
* <p>
* Subclass will typicall switch on this value to provide the specific behavior for each function.
* Subclass will typicall switch on this value to provide the specific
* behavior for each function.
*/
protected int opcode;
/** The common name for this function, useful for debugging.
/**
* The common name for this function, useful for debugging.
* <p>
* Binding functions initialize this to the name to which it is bound.
*/
@@ -139,84 +153,105 @@ abstract public class LibFunction extends LuaFunction {
}
public String tojstring() {
return name != null ? "function: " + name : super.tojstring();
return name != null? "function: " + name: super.tojstring();
}
/**
* Bind a set of library functions.
* <p>
* An array of names is provided, and the first name is bound
* with opcode = 0, second with 1, etc.
* An array of names is provided, and the first name is bound with opcode =
* 0, second with 1, etc.
*
* @param env The environment to apply to each bound function
* @param factory the Class to instantiate for each bound function
* @param names array of String names, one for each function.
* @see #bind(LuaValue, Class, String[], int)
*/
protected void bind(LuaValue env, Class factory, String[] names ) {
bind( env, factory, names, 0 );
protected void bind(LuaValue env, Class factory, String[] names) {
bind(env, factory, names, 0);
}
/**
* Bind a set of library functions, with an offset
* <p>
* An array of names is provided, and the first name is bound
* with opcode = {@code firstopcode}, second with {@code firstopcode+1}, etc.
* An array of names is provided, and the first name is bound with opcode =
* {@code firstopcode}, second with {@code firstopcode+1}, etc.
*
* @param env The environment to apply to each bound function
* @param factory the Class to instantiate for each bound function
* @param names array of String names, one for each function.
* @param firstopcode the first opcode to use
* @see #bind(LuaValue, Class, String[])
*/
protected void bind(LuaValue env, Class factory, String[] names, int firstopcode ) {
protected void bind(LuaValue env, Class factory, String[] names, int firstopcode) {
try {
for ( int i=0, n=names.length; i<n; i++ ) {
for (int i = 0, n = names.length; i < n; i++) {
LibFunction f = (LibFunction) factory.newInstance();
f.opcode = firstopcode + i;
f.opcode = firstopcode+i;
f.name = names[i];
env.set(f.name, f);
}
} catch ( Exception e ) {
throw new LuaError( "bind failed: "+e );
} catch (Exception e) {
throw new LuaError("bind failed: " + e);
}
}
/** Java code generation utility to allocate storage for upvalue, leave it empty */
/**
* Java code generation utility to allocate storage for upvalue, leave it
* empty
*/
protected static LuaValue[] newupe() {
return new LuaValue[1];
}
/** Java code generation utility to allocate storage for upvalue, initialize with nil */
/**
* Java code generation utility to allocate storage for upvalue, initialize
* with nil
*/
protected static LuaValue[] newupn() {
return new LuaValue[] { NIL };
}
/** Java code generation utility to allocate storage for upvalue, initialize with value */
/**
* Java code generation utility to allocate storage for upvalue, initialize
* with value
*/
protected static LuaValue[] newupl(LuaValue v) {
return new LuaValue[] { v };
}
public LuaValue call() {
return argerror(1,"value expected");
return argerror(1, "value expected");
}
public LuaValue call(LuaValue a) {
return call();
}
public LuaValue call(LuaValue a, LuaValue b) {
return call(a);
}
public LuaValue call(LuaValue a, LuaValue b, LuaValue c) {
return call(a,b);
return call(a, b);
}
public LuaValue call(LuaValue a, LuaValue b, LuaValue c, LuaValue d) {
return call(a,b,c);
return call(a, b, c);
}
public Varargs invoke(Varargs args) {
switch(args.narg()) {
case 0: return call();
case 1: return call(args.arg1());
case 2: return call(args.arg1(),args.arg(2));
case 3: return call(args.arg1(),args.arg(2),args.arg(3));
default: return call(args.arg1(),args.arg(2),args.arg(3),args.arg(4));
switch (args.narg()) {
case 0:
return call();
case 1:
return call(args.arg1());
case 2:
return call(args.arg1(), args.arg(2));
case 3:
return call(args.arg1(), args.arg(2), args.arg(3));
default:
return call(args.arg1(), args.arg(2), args.arg(3), args.arg(4));
}
}
}

View File

@@ -29,13 +29,13 @@ import org.luaj.vm2.LuaValue;
import org.luaj.vm2.Varargs;
/**
* Subclass of {@link LibFunction} which implements the lua standard {@code math}
* library.
* Subclass of {@link LibFunction} which implements the lua standard
* {@code math} library.
* <p>
* It contains only the math library support that is possible on JME.
* For a more complete implementation based on math functions specific to JSE
* use {@link org.luaj.vm2.lib.jse.JseMathLib}.
* In Particular the following math functions are <b>not</b> implemented by this library:
* It contains only the math library support that is possible on JME. For a more
* complete implementation based on math functions specific to JSE use
* {@link org.luaj.vm2.lib.jse.JseMathLib}. In Particular the following math
* functions are <b>not</b> implemented by this library:
* <ul>
* <li>acos</li>
* <li>asin</li>
@@ -48,60 +48,81 @@ import org.luaj.vm2.Varargs;
* </ul>
* <p>
* The implementations of {@code exp()} and {@code pow()} are constructed by
* hand for JME, so will be slower and less accurate than when executed on the JSE platform.
* hand for JME, so will be slower and less accurate than when executed on the
* JSE platform.
* <p>
* Typically, this library is included as part of a call to either
* {@link org.luaj.vm2.lib.jse.JsePlatform#standardGlobals()} or
* {@link org.luaj.vm2.lib.jme.JmePlatform#standardGlobals()}
* <pre> {@code
*
* <pre>
* {
* &#64;code
* Globals globals = JsePlatform.standardGlobals();
* System.out.println( globals.get("math").get("sqrt").call( LuaValue.valueOf(2) ) );
* } </pre>
* When using {@link org.luaj.vm2.lib.jse.JsePlatform} as in this example,
* the subclass {@link org.luaj.vm2.lib.jse.JseMathLib} will
* be included, which also includes this base functionality.
* System.out.println(globals.get("math").get("sqrt").call(LuaValue.valueOf(2)));
* }
* </pre>
*
* When using {@link org.luaj.vm2.lib.jse.JsePlatform} as in this example, the
* subclass {@link org.luaj.vm2.lib.jse.JseMathLib} will be included, which also
* includes this base functionality.
* <p>
* To instantiate and use it directly,
* link it into your globals table via {@link LuaValue#load(LuaValue)} using code such as:
* <pre> {@code
* To instantiate and use it directly, link it into your globals table via
* {@link LuaValue#load(LuaValue)} using code such as:
*
* <pre>
* {
* &#64;code
* Globals globals = new Globals();
* globals.load(new JseBaseLib());
* globals.load(new PackageLib());
* globals.load(new MathLib());
* System.out.println( globals.get("math").get("sqrt").call( LuaValue.valueOf(2) ) );
* } </pre>
* Doing so will ensure the library is properly initialized
* and loaded into the globals table.
* System.out.println(globals.get("math").get("sqrt").call(LuaValue.valueOf(2)));
* }
* </pre>
*
* Doing so will ensure the library is properly initialized and loaded into the
* globals table.
* <p>
* This has been implemented to match as closely as possible the behavior in the corresponding library in C.
* This has been implemented to match as closely as possible the behavior in the
* corresponding library in C.
*
* @see LibFunction
* @see org.luaj.vm2.lib.jse.JsePlatform
* @see org.luaj.vm2.lib.jme.JmePlatform
* @see org.luaj.vm2.lib.jse.JseMathLib
* @see <a href="http://www.lua.org/manual/5.2/manual.html#6.6">Lua 5.2 Math Lib Reference</a>
* @see <a href="http://www.lua.org/manual/5.2/manual.html#6.6">Lua 5.2 Math Lib
* Reference</a>
*/
public class MathLib extends TwoArgFunction {
/** Pointer to the latest MathLib instance, used only to dispatch
* math.exp to tha correct platform math library.
/**
* Pointer to the latest MathLib instance, used only to dispatch math.exp to
* tha correct platform math library.
*/
public static MathLib MATHLIB = null;
/** Construct a MathLib, which can be initialized by calling it with a
/**
* Construct a MathLib, which can be initialized by calling it with a
* modname string, and a global environment table as arguments using
* {@link #call(LuaValue, LuaValue)}. */
* {@link #call(LuaValue, LuaValue)}.
*/
public MathLib() {
MATHLIB = this;
}
/** Perform one-time initialization on the library by creating a table
* containing the library functions, adding that table to the supplied environment,
* adding the table to package.loaded, and returning table as the return value.
/**
* Perform one-time initialization on the library by creating a table
* containing the library functions, adding that table to the supplied
* environment, adding the table to package.loaded, and returning table as
* the return value.
*
* @param modname the module name supplied if this is loaded via 'require'.
* @param env the environment to load into, typically a Globals instance.
* @param env the environment to load into, typically a Globals
* instance.
*/
public LuaValue call(LuaValue modname, LuaValue env) {
LuaTable math = new LuaTable(0,30);
LuaTable math = new LuaTable(0, 30);
math.set("abs", new abs());
math.set("ceil", new ceil());
math.set("cos", new cos());
@@ -110,12 +131,12 @@ public class MathLib extends TwoArgFunction {
math.set("floor", new floor());
math.set("fmod", new fmod());
math.set("frexp", new frexp());
math.set("huge", LuaDouble.POSINF );
math.set("huge", LuaDouble.POSINF);
math.set("ldexp", new ldexp());
math.set("max", new max());
math.set("min", new min());
math.set("modf", new modf());
math.set("pi", Math.PI );
math.set("pi", Math.PI);
math.set("pow", new pow());
random r;
math.set("random", r = new random());
@@ -125,7 +146,8 @@ public class MathLib extends TwoArgFunction {
math.set("sqrt", new sqrt());
math.set("tan", new tan());
env.set("math", math);
if (!env.get("package").isnil()) env.get("package").get("loaded").set("math", math);
if (!env.get("package").isnil())
env.get("package").get("loaded").set("math", math);
return math;
}
@@ -133,6 +155,7 @@ public class MathLib extends TwoArgFunction {
public LuaValue call(LuaValue arg) {
return valueOf(call(arg.checkdouble()));
}
abstract protected double call(double d);
}
@@ -140,43 +163,74 @@ public class MathLib extends TwoArgFunction {
public LuaValue call(LuaValue x, LuaValue y) {
return valueOf(call(x.checkdouble(), y.checkdouble()));
}
abstract protected double call(double x, double y);
}
static final class abs extends UnaryOp { protected double call(double d) { return Math.abs(d); } }
static final class ceil extends UnaryOp { protected double call(double d) { return Math.ceil(d); } }
static final class cos extends UnaryOp { protected double call(double d) { return Math.cos(d); } }
static final class deg extends UnaryOp { protected double call(double d) { return Math.toDegrees(d); } }
static final class floor extends UnaryOp { protected double call(double d) { return Math.floor(d); } }
static final class rad extends UnaryOp { protected double call(double d) { return Math.toRadians(d); } }
static final class sin extends UnaryOp { protected double call(double d) { return Math.sin(d); } }
static final class sqrt extends UnaryOp { protected double call(double d) { return Math.sqrt(d); } }
static final class tan extends UnaryOp { protected double call(double d) { return Math.tan(d); } }
static final class abs extends UnaryOp {
protected double call(double d) { return Math.abs(d); }
}
static final class ceil extends UnaryOp {
protected double call(double d) { return Math.ceil(d); }
}
static final class cos extends UnaryOp {
protected double call(double d) { return Math.cos(d); }
}
static final class deg extends UnaryOp {
protected double call(double d) { return Math.toDegrees(d); }
}
static final class floor extends UnaryOp {
protected double call(double d) { return Math.floor(d); }
}
static final class rad extends UnaryOp {
protected double call(double d) { return Math.toRadians(d); }
}
static final class sin extends UnaryOp {
protected double call(double d) { return Math.sin(d); }
}
static final class sqrt extends UnaryOp {
protected double call(double d) { return Math.sqrt(d); }
}
static final class tan extends UnaryOp {
protected double call(double d) { return Math.tan(d); }
}
static final class exp extends UnaryOp {
final MathLib mathlib;
exp(MathLib mathlib) {
this.mathlib = mathlib;
}
protected double call(double d) {
return mathlib.dpow_lib(Math.E,d);
return mathlib.dpow_lib(Math.E, d);
}
}
static final class fmod extends TwoArgFunction {
public LuaValue call(LuaValue xv, LuaValue yv) {
if (xv.islong() && yv.islong()) {
return valueOf(xv.tolong() % yv.tolong());
return valueOf(xv.tolong()%yv.tolong());
}
return valueOf(xv.checkdouble() % yv.checkdouble());
return valueOf(xv.checkdouble()%yv.checkdouble());
}
}
static final class ldexp extends BinaryOp {
protected double call(double x, double y) {
// This is the behavior on os-x, windows differs in rounding behavior.
return x * Double.longBitsToDouble((((long) y) + 1023) << 52);
return x*Double.longBitsToDouble((((long) y)+1023)<<52);
}
}
static final class pow extends BinaryOp {
protected double call(double x, double y) {
return MathLib.dpow_default(x, y);
@@ -186,20 +240,22 @@ public class MathLib extends TwoArgFunction {
static class frexp extends VarArgFunction {
public Varargs invoke(Varargs args) {
double x = args.checkdouble(1);
if ( x == 0 ) return varargsOf(ZERO,ZERO);
long bits = Double.doubleToLongBits( x );
double m = ((bits & (~(-1L<<52))) + (1L<<52)) * ((bits >= 0)? (.5 / (1L<<52)): (-.5 / (1L<<52)));
double e = (((int) (bits >> 52)) & 0x7ff) - 1022;
return varargsOf( valueOf(m), valueOf(e) );
if (x == 0)
return varargsOf(ZERO, ZERO);
long bits = Double.doubleToLongBits(x);
double m = ((bits & (~(-1L<<52)))+(1L<<52))*((bits >= 0)? (.5/(1L<<52)): (-.5/(1L<<52)));
double e = (((int) (bits>>52)) & 0x7ff)-1022;
return varargsOf(valueOf(m), valueOf(e));
}
}
static class max extends VarArgFunction {
public Varargs invoke(Varargs args) {
LuaValue m = args.checkvalue(1);
for ( int i=2,n=args.narg(); i<=n; ++i ) {
for (int i = 2, n = args.narg(); i <= n; ++i) {
LuaValue v = args.checkvalue(i);
if (m.lt_b(v)) m = v;
if (m.lt_b(v))
m = v;
}
return m;
}
@@ -208,9 +264,10 @@ public class MathLib extends TwoArgFunction {
static class min extends VarArgFunction {
public Varargs invoke(Varargs args) {
LuaValue m = args.checkvalue(1);
for ( int i=2,n=args.narg(); i<=n; ++i ) {
for (int i = 2, n = args.narg(); i <= n; ++i) {
LuaValue v = args.checkvalue(i);
if (v.lt_b(m)) m = v;
if (v.lt_b(m))
m = v;
}
return m;
}
@@ -220,40 +277,48 @@ public class MathLib extends TwoArgFunction {
public Varargs invoke(Varargs args) {
LuaValue n = args.arg1();
/* number is its own integer part, no fractional part */
if (n.islong()) return varargsOf(n, valueOf(0.0));
if (n.islong())
return varargsOf(n, valueOf(0.0));
double x = n.checkdouble();
/* integer part (rounds toward zero) */
double intPart = ( x > 0 ) ? Math.floor( x ) : Math.ceil( x );
double intPart = (x > 0)? Math.floor(x): Math.ceil(x);
/* fractional part (test needed for inf/-inf) */
double fracPart = x == intPart ? 0.0 : x - intPart;
return varargsOf( valueOf(intPart), valueOf(fracPart) );
double fracPart = x == intPart? 0.0: x-intPart;
return varargsOf(valueOf(intPart), valueOf(fracPart));
}
}
static class random extends LibFunction {
Random random = new Random();
public LuaValue call() {
return valueOf( random.nextDouble() );
return valueOf(random.nextDouble());
}
public LuaValue call(LuaValue a) {
int m = a.checkint();
if (m<1) argerror(1, "interval is empty");
return valueOf( 1 + random.nextInt(m) );
if (m < 1)
argerror(1, "interval is empty");
return valueOf(1+random.nextInt(m));
}
public LuaValue call(LuaValue a, LuaValue b) {
int m = a.checkint();
int n = b.checkint();
if (n<m) argerror(2, "interval is empty");
return valueOf( m + random.nextInt(n+1-m) );
if (n < m)
argerror(2, "interval is empty");
return valueOf(m+random.nextInt(n+1-m));
}
}
static class randomseed extends OneArgFunction {
final random random;
randomseed(random random) {
this.random = random;
}
public LuaValue call(LuaValue arg) {
long seed = arg.checklong();
random.random = new Random(seed);
@@ -261,42 +326,41 @@ public class MathLib extends TwoArgFunction {
}
}
/** compute power using installed math library, or default if there is no math library installed */
/**
* compute power using installed math library, or default if there is no
* math library installed
*/
public static LuaValue dpow(double a, double b) {
return LuaDouble.valueOf(
MATHLIB!=null?
MATHLIB.dpow_lib(a,b):
dpow_default(a,b) );
return LuaDouble.valueOf(MATHLIB != null? MATHLIB.dpow_lib(a, b): dpow_default(a, b));
}
public static double dpow_d(double a, double b) {
return MATHLIB!=null?
MATHLIB.dpow_lib(a,b):
dpow_default(a,b);
return MATHLIB != null? MATHLIB.dpow_lib(a, b): dpow_default(a, b);
}
/**
* Hook to override default dpow behavior with faster implementation.
*/
public double dpow_lib(double a, double b) {
return dpow_default(a,b);
return dpow_default(a, b);
}
/**
* Default JME version computes using longhand heuristics.
*/
protected static double dpow_default(double a, double b) {
if ( b < 0 )
return 1 / dpow_default( a, -b );
if (b < 0)
return 1/dpow_default(a, -b);
double p = 1;
int whole = (int) b;
for ( double v=a; whole > 0; whole>>=1, v*=v )
if ( (whole & 1) != 0 )
for (double v = a; whole > 0; whole >>= 1, v *= v)
if ((whole & 1) != 0)
p *= v;
if ( (b -= whole) > 0 ) {
int frac = (int) (0x10000 * b);
for ( ; (frac&0xffff)!=0; frac<<=1 ) {
if ((b -= whole) > 0) {
int frac = (int) (0x10000*b);
for (; (frac & 0xffff) != 0; frac <<= 1) {
a = Math.sqrt(a);
if ( (frac & 0x8000) != 0 )
if ((frac & 0x8000) != 0)
p *= a;
}
}

View File

@@ -24,21 +24,23 @@ package org.luaj.vm2.lib;
import org.luaj.vm2.LuaValue;
import org.luaj.vm2.Varargs;
/** Abstract base class for Java function implementations that take one argument and
* return one value.
/**
* Abstract base class for Java function implementations that take one argument
* and return one value.
* <p>
* Subclasses need only implement {@link LuaValue#call(LuaValue)} to complete this class,
* simplifying development.
* All other uses of {@link #call()}, {@link #invoke(Varargs)},etc,
* are routed through this method by this class,
* Subclasses need only implement {@link LuaValue#call(LuaValue)} to complete
* this class, simplifying development. All other uses of {@link #call()},
* {@link #invoke(Varargs)},etc, are routed through this method by this class,
* dropping or extending arguments with {@code nil} values as required.
* <p>
* If more than one argument are required, or no arguments are required,
* or variable argument or variable return values,
* then use one of the related function
* {@link ZeroArgFunction}, {@link TwoArgFunction}, {@link ThreeArgFunction}, or {@link VarArgFunction}.
* If more than one argument are required, or no arguments are required, or
* variable argument or variable return values, then use one of the related
* function {@link ZeroArgFunction}, {@link TwoArgFunction},
* {@link ThreeArgFunction}, or {@link VarArgFunction}.
* <p>
* See {@link LibFunction} for more information on implementation libraries and library functions.
* See {@link LibFunction} for more information on implementation libraries and
* library functions.
*
* @see #call(LuaValue)
* @see LibFunction
* @see ZeroArgFunction

View File

@@ -32,21 +32,21 @@ import org.luaj.vm2.LuaValue;
import org.luaj.vm2.Varargs;
/**
* Subclass of {@link LibFunction} which implements the standard lua {@code os} library.
* Subclass of {@link LibFunction} which implements the standard lua {@code os}
* library.
* <p>
* It is a usable base with simplified stub functions
* for library functions that cannot be implemented uniformly
* on Jse and Jme.
* It is a usable base with simplified stub functions for library functions that
* cannot be implemented uniformly on Jse and Jme.
* <p>
* This can be installed as-is on either platform, or extended
* and refined to be used in a complete Jse implementation.
* This can be installed as-is on either platform, or extended and refined to be
* used in a complete Jse implementation.
* <p>
* Because the nature of the {@code os} library is to encapsulate
* os-specific features, the behavior of these functions varies considerably
* from their counterparts in the C platform.
* Because the nature of the {@code os} library is to encapsulate os-specific
* features, the behavior of these functions varies considerably from their
* counterparts in the C platform.
* <p>
* The following functions have limited implementations of features
* that are not supported well on Jme:
* The following functions have limited implementations of features that are not
* supported well on Jme:
* <ul>
* <li>{@code execute()}</li>
* <li>{@code remove()}</li>
@@ -55,29 +55,42 @@ import org.luaj.vm2.Varargs;
* </ul>
* <p>
* Typically, this library is included as part of a call to either
* {@link org.luaj.vm2.lib.jse.JsePlatform#standardGlobals()} or {@link org.luaj.vm2.lib.jme.JmePlatform#standardGlobals()}
* <pre> {@code
* {@link org.luaj.vm2.lib.jse.JsePlatform#standardGlobals()} or
* {@link org.luaj.vm2.lib.jme.JmePlatform#standardGlobals()}
*
* <pre>
* {
* &#64;code
* Globals globals = JsePlatform.standardGlobals();
* System.out.println( globals.get("os").get("time").call() );
* } </pre>
* In this example the platform-specific {@link org.luaj.vm2.lib.jse.JseOsLib} library will be loaded, which will include
* the base functionality provided by this class.
* System.out.println(globals.get("os").get("time").call());
* }
* </pre>
*
* In this example the platform-specific {@link org.luaj.vm2.lib.jse.JseOsLib}
* library will be loaded, which will include the base functionality provided by
* this class.
* <p>
* To instantiate and use it directly,
* link it into your globals table via {@link LuaValue#load(LuaValue)} using code such as:
* <pre> {@code
* To instantiate and use it directly, link it into your globals table via
* {@link LuaValue#load(LuaValue)} using code such as:
*
* <pre>
* {
* &#64;code
* Globals globals = new Globals();
* globals.load(new JseBaseLib());
* globals.load(new PackageLib());
* globals.load(new OsLib());
* System.out.println( globals.get("os").get("time").call() );
* } </pre>
* System.out.println(globals.get("os").get("time").call());
* }
* </pre>
* <p>
*
* @see LibFunction
* @see org.luaj.vm2.lib.jse.JseOsLib
* @see org.luaj.vm2.lib.jse.JsePlatform
* @see org.luaj.vm2.lib.jme.JmePlatform
* @see <a href="http://www.lua.org/manual/5.1/manual.html#5.8">http://www.lua.org/manual/5.1/manual.html#5.8</a>
* @see <a href=
* "http://www.lua.org/manual/5.1/manual.html#5.8">http://www.lua.org/manual/5.1/manual.html#5.8</a>
*/
public class OsLib extends TwoArgFunction {
public static final String TMP_PREFIX = ".luaj";
@@ -95,19 +108,8 @@ public class OsLib extends TwoArgFunction {
private static final int TIME = 9;
private static final int TMPNAME = 10;
private static final String[] NAMES = {
"clock",
"date",
"difftime",
"execute",
"exit",
"getenv",
"remove",
"rename",
"setlocale",
"time",
"tmpname",
};
private static final String[] NAMES = { "clock", "date", "difftime", "execute", "exit", "getenv", "remove",
"rename", "setlocale", "time", "tmpname", };
private static final long t0 = System.currentTimeMillis();
private static long tmpnames = t0;
@@ -120,11 +122,15 @@ public class OsLib extends TwoArgFunction {
public OsLib() {
}
/** Perform one-time initialization on the library by creating a table
* containing the library functions, adding that table to the supplied environment,
* adding the table to package.loaded, and returning table as the return value.
/**
* Perform one-time initialization on the library by creating a table
* containing the library functions, adding that table to the supplied
* environment, adding the table to package.loaded, and returning table as
* the return value.
*
* @param modname the module name supplied if this is loaded via 'require'.
* @param env the environment to load into, typically a Globals instance.
* @param env the environment to load into, typically a Globals
* instance.
*/
public LuaValue call(LuaValue modname, LuaValue env) {
globals = env.checkglobals();
@@ -132,7 +138,8 @@ public class OsLib extends TwoArgFunction {
for (int i = 0; i < NAMES.length; ++i)
os.set(NAMES[i], new OsLibFunc(i, NAMES[i]));
env.set("os", os);
if (!env.get("package").isnil()) env.get("package").get("loaded").set("os", os);
if (!env.get("package").isnil())
env.get("package").get("loaded").set("os", os);
return os;
}
@@ -141,9 +148,10 @@ public class OsLib extends TwoArgFunction {
this.opcode = opcode;
this.name = name;
}
public Varargs invoke(Varargs args) {
try {
switch ( opcode ) {
switch (opcode) {
case CLOCK:
return valueOf(clock());
case DATE: {
@@ -151,7 +159,7 @@ public class OsLib extends TwoArgFunction {
double t = args.isnumber(2)? args.todouble(2): time(null);
if (s.equals("*t")) {
Calendar d = Calendar.getInstance();
d.setTime(new Date((long)(t*1000)));
d.setTime(new Date((long) (t*1000)));
LuaTable tbl = LuaValue.tableOf();
tbl.set("year", LuaValue.valueOf(d.get(Calendar.YEAR)));
tbl.set("month", LuaValue.valueOf(d.get(Calendar.MONTH)+1));
@@ -164,10 +172,10 @@ public class OsLib extends TwoArgFunction {
tbl.set("isdst", LuaValue.valueOf(isDaylightSavingsTime(d)));
return tbl;
}
return valueOf( date(s, t==-1? time(null): t) );
return valueOf(date(s, t == -1? time(null): t));
}
case DIFFTIME:
return valueOf(difftime(args.checkdouble(1),args.checkdouble(2)));
return valueOf(difftime(args.checkdouble(1), args.checkdouble(2)));
case EXECUTE:
return execute(args.optjstring(1, null));
case EXIT:
@@ -175,7 +183,7 @@ public class OsLib extends TwoArgFunction {
return NONE;
case GETENV: {
final String val = getenv(args.checkjstring(1));
return val!=null? valueOf(val): NIL;
return val != null? valueOf(val): NIL;
}
case REMOVE:
remove(args.checkjstring(1));
@@ -184,8 +192,8 @@ public class OsLib extends TwoArgFunction {
rename(args.checkjstring(1), args.checkjstring(2));
return LuaValue.TRUE;
case SETLOCALE: {
String s = setlocale(args.optjstring(1,null), args.optjstring(2, "all"));
return s!=null? valueOf(s): NIL;
String s = setlocale(args.optjstring(1, null), args.optjstring(2, "all"));
return s != null? valueOf(s): NIL;
}
case TIME:
return valueOf(time(args.opttable(1, null)));
@@ -193,78 +201,79 @@ public class OsLib extends TwoArgFunction {
return valueOf(tmpname());
}
return NONE;
} catch ( IOException e ) {
} catch (IOException e) {
return varargsOf(NIL, valueOf(e.getMessage()));
}
}
}
/**
* @return an approximation of the amount in seconds of CPU time used by
* the program. For luaj this simple returns the elapsed time since the
* @return an approximation of the amount in seconds of CPU time used by the
* program. For luaj this simple returns the elapsed time since the
* OsLib class was loaded.
*/
protected double clock() {
return (System.currentTimeMillis()-t0) / 1000.;
return (System.currentTimeMillis()-t0)/1000.;
}
/**
* Returns the number of seconds from time t1 to time t2.
* In POSIX, Windows, and some other systems, this value is exactly t2-t1.
* Returns the number of seconds from time t1 to time t2. In POSIX, Windows,
* and some other systems, this value is exactly t2-t1.
*
* @param t2
* @param t1
* @return diffeence in time values, in seconds
*/
protected double difftime(double t2, double t1) {
return t2 - t1;
return t2-t1;
}
/**
* If the time argument is present, this is the time to be formatted
* (see the os.time function for a description of this value).
* Otherwise, date formats the current time.
* If the time argument is present, this is the time to be formatted (see
* the os.time function for a description of this value). Otherwise, date
* formats the current time.
*
* Date returns the date as a string,
* formatted according to the same rules as ANSII strftime, but without
* support for %g, %G, or %V.
* Date returns the date as a string, formatted according to the same rules
* as ANSII strftime, but without support for %g, %G, or %V.
*
* When called without arguments, date returns a reasonable date and
* time representation that depends on the host system and on the
* current locale (that is, os.date() is equivalent to os.date("%c")).
* When called without arguments, date returns a reasonable date and time
* representation that depends on the host system and on the current locale
* (that is, os.date() is equivalent to os.date("%c")).
*
* @param format
* @param time time since epoch, or -1 if not supplied
* @return a LString or a LTable containing date and time,
* formatted according to the given string format.
* @return a LString or a LTable containing date and time, formatted
* according to the given string format.
*/
public String date(String format, double time) {
Calendar d = Calendar.getInstance();
d.setTime(new Date((long)(time*1000)));
d.setTime(new Date((long) (time*1000)));
if (format.startsWith("!")) {
time -= timeZoneOffset(d);
d.setTime(new Date((long)(time*1000)));
d.setTime(new Date((long) (time*1000)));
format = format.substring(1);
}
byte[] fmt = format.getBytes();
final int n = fmt.length;
Buffer result = new Buffer(n);
byte c;
for ( int i = 0; i < n; ) {
switch ( c = fmt[i++ ] ) {
for (int i = 0; i < n;) {
switch (c = fmt[i++]) {
case '\n':
result.append( "\n" );
result.append("\n");
break;
default:
result.append( c );
result.append(c);
break;
case '%':
if (i >= n) break;
switch ( c = fmt[i++ ] ) {
if (i >= n)
break;
switch (c = fmt[i++]) {
default:
LuaValue.argerror(1, "invalid conversion specifier '%"+c+"'");
LuaValue.argerror(1, "invalid conversion specifier '%" + c + "'");
break;
case '%':
result.append( (byte)'%' );
result.append((byte) '%');
break;
case 'a':
result.append(WeekdayNameAbbrev[d.get(Calendar.DAY_OF_WEEK)-1]);
@@ -292,7 +301,7 @@ public class OsLib extends TwoArgFunction {
break;
case 'j': { // day of year.
Calendar y0 = beginningOfYear(d);
int dayOfYear = (int) ((d.getTime().getTime() - y0.getTime().getTime()) / (24 * 3600L * 1000L));
int dayOfYear = (int) ((d.getTime().getTime()-y0.getTime().getTime())/(24*3600L*1000L));
result.append(String.valueOf(1001+dayOfYear).substring(1));
break;
}
@@ -330,11 +339,11 @@ public class OsLib extends TwoArgFunction {
result.append(String.valueOf(d.get(Calendar.YEAR)));
break;
case 'z': {
final int tzo = timeZoneOffset(d) / 60;
final int tzo = timeZoneOffset(d)/60;
final int a = Math.abs(tzo);
final String h = String.valueOf(100 + a / 60).substring(1);
final String m = String.valueOf(100 + a % 60).substring(1);
result.append((tzo>=0? "+": "-") + h + m);
final String h = String.valueOf(100+a/60).substring(1);
final String m = String.valueOf(100+a%60).substring(1);
result.append((tzo >= 0? "+": "-")+h+m);
break;
}
}
@@ -344,9 +353,12 @@ public class OsLib extends TwoArgFunction {
}
private static final String[] WeekdayNameAbbrev = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
private static final String[] WeekdayName = { "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" };
private static final String[] MonthNameAbbrev = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
private static final String[] MonthName = { "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" };
private static final String[] WeekdayName = { "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday",
"Friday", "Saturday" };
private static final String[] MonthNameAbbrev = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep",
"Oct", "Nov", "Dec" };
private static final String[] MonthName = { "January", "February", "March", "April", "May", "June", "July",
"August", "September", "October", "November", "December" };
private Calendar beginningOfYear(Calendar d) {
Calendar y0 = Calendar.getInstance();
@@ -362,39 +374,32 @@ public class OsLib extends TwoArgFunction {
private int weekNumber(Calendar d, int startDay) {
Calendar y0 = beginningOfYear(d);
y0.set(Calendar.DAY_OF_MONTH, 1 + (startDay + 8 - y0.get(Calendar.DAY_OF_WEEK)) % 7);
y0.set(Calendar.DAY_OF_MONTH, 1+(startDay+8-y0.get(Calendar.DAY_OF_WEEK))%7);
if (y0.after(d)) {
y0.set(Calendar.YEAR, y0.get(Calendar.YEAR) - 1);
y0.set(Calendar.DAY_OF_MONTH, 1 + (startDay + 8 - y0.get(Calendar.DAY_OF_WEEK)) % 7);
y0.set(Calendar.YEAR, y0.get(Calendar.YEAR)-1);
y0.set(Calendar.DAY_OF_MONTH, 1+(startDay+8-y0.get(Calendar.DAY_OF_WEEK))%7);
}
long dt = d.getTime().getTime() - y0.getTime().getTime();
return 1 + (int) (dt / (7L * 24L * 3600L * 1000L));
long dt = d.getTime().getTime()-y0.getTime().getTime();
return 1+(int) (dt/(7L*24L*3600L*1000L));
}
private int timeZoneOffset(Calendar d) {
int localStandarTimeMillis = (
d.get(Calendar.HOUR_OF_DAY) * 3600 +
d.get(Calendar.MINUTE) * 60 +
d.get(Calendar.SECOND)) * 1000;
return d.getTimeZone().getOffset(
1,
d.get(Calendar.YEAR),
d.get(Calendar.MONTH),
d.get(Calendar.DAY_OF_MONTH),
d.get(Calendar.DAY_OF_WEEK),
localStandarTimeMillis) / 1000;
int localStandarTimeMillis = (d.get(Calendar.HOUR_OF_DAY)*3600+d.get(Calendar.MINUTE)*60+d.get(Calendar.SECOND))
*1000;
return d.getTimeZone().getOffset(1, d.get(Calendar.YEAR), d.get(Calendar.MONTH), d.get(Calendar.DAY_OF_MONTH),
d.get(Calendar.DAY_OF_WEEK), localStandarTimeMillis)/1000;
}
private boolean isDaylightSavingsTime(Calendar d) {
return timeZoneOffset(d) != d.getTimeZone().getRawOffset() / 1000;
return timeZoneOffset(d) != d.getTimeZone().getRawOffset()/1000;
}
/**
* This function is equivalent to the C function system.
* It passes command to be executed by an operating system shell.
* It returns a status code, which is system-dependent.
* If command is absent, then it returns nonzero if a shell
* is available and zero otherwise.
* This function is equivalent to the C function system. It passes command
* to be executed by an operating system shell. It returns a status code,
* which is system-dependent. If command is absent, then it returns nonzero
* if a shell is available and zero otherwise.
*
* @param command command to pass to the system
*/
protected Varargs execute(String command) {
@@ -402,7 +407,9 @@ public class OsLib extends TwoArgFunction {
}
/**
* Calls the C function exit, with an optional code, to terminate the host program.
* Calls the C function exit, with an optional code, to terminate the host
* program.
*
* @param code
*/
protected void exit(int code) {
@@ -410,19 +417,19 @@ public class OsLib extends TwoArgFunction {
}
/**
* Returns the value of the process environment variable varname,
* or the System property value for varname,
* or null if the variable is not defined in either environment.
* Returns the value of the process environment variable varname, or the
* System property value for varname, or null if the variable is not defined
* in either environment.
*
* The default implementation, which is used by the JmePlatform,
* only queryies System.getProperty().
* The default implementation, which is used by the JmePlatform, only
* queryies System.getProperty().
*
* The JsePlatform overrides this behavior and returns the
* environment variable value using System.getenv() if it exists,
* or the System property value if it does not.
* The JsePlatform overrides this behavior and returns the environment
* variable value using System.getenv() if it exists, or the System property
* value if it does not.
*
* A SecurityException may be thrown if access is not allowed for 'varname'.
*
* A SecurityException may be thrown if access is not allowed
* for 'varname'.
* @param varname
* @return String value, or null if not defined
*/
@@ -431,57 +438,57 @@ public class OsLib extends TwoArgFunction {
}
/**
* Deletes the file or directory with the given name.
* Directories must be empty to be removed.
* If this function fails, it throws and IOException
* Deletes the file or directory with the given name. Directories must be
* empty to be removed. If this function fails, it throws and IOException
*
* @param filename
* @throws IOException if it fails
*/
protected void remove(String filename) throws IOException {
throw new IOException( "not implemented" );
throw new IOException("not implemented");
}
/**
* Renames file or directory named oldname to newname.
* If this function fails,it throws and IOException
* Renames file or directory named oldname to newname. If this function
* fails,it throws and IOException
*
* @param oldname old file name
* @param newname new file name
* @throws IOException if it fails
*/
protected void rename(String oldname, String newname) throws IOException {
throw new IOException( "not implemented" );
throw new IOException("not implemented");
}
/**
* Sets the current locale of the program. locale is a string specifying
* a locale; category is an optional string describing which category to change:
* "all", "collate", "ctype", "monetary", "numeric", or "time"; the default category
* is "all".
* Sets the current locale of the program. locale is a string specifying a
* locale; category is an optional string describing which category to
* change: "all", "collate", "ctype", "monetary", "numeric", or "time"; the
* default category is "all".
*
* If locale is the empty string, the current locale is set to an implementation-
* defined native locale. If locale is the string "C", the current locale is set
* to the standard C locale.
* If locale is the empty string, the current locale is set to an
* implementation- defined native locale. If locale is the string "C", the
* current locale is set to the standard C locale.
*
* When called with null as the first argument, this function only returns the
* name of the current locale for the given category.
* When called with null as the first argument, this function only returns
* the name of the current locale for the given category.
*
* @param locale
* @param category
* @return the name of the new locale, or null if the request
* cannot be honored.
* @return the name of the new locale, or null if the request cannot be
* honored.
*/
protected String setlocale(String locale, String category) {
return "C";
}
/**
* Returns the current time when called without arguments,
* or a time representing the date and time specified by the given table.
* This table must have fields year, month, and day,
* and may have fields hour, min, sec, and isdst
* (for a description of these fields, see the os.date function).
* Returns the current time when called without arguments, or a time
* representing the date and time specified by the given table. This table
* must have fields year, month, and day, and may have fields hour, min,
* sec, and isdst (for a description of these fields, see the os.date
* function).
*
* @param table
* @return long value for the time
*/
@@ -500,7 +507,7 @@ public class OsLib extends TwoArgFunction {
c.set(Calendar.MILLISECOND, 0);
d = c.getTime();
}
return d.getTime() / 1000.;
return d.getTime()/1000.;
}
/**
@@ -508,16 +515,16 @@ public class OsLib extends TwoArgFunction {
* The file must be explicitly opened before its use and explicitly removed
* when no longer needed.
*
* On some systems (POSIX), this function also creates a file with that name,
* to avoid security risks. (Someone else might create the file with wrong
* permissions in the time between getting the name and creating the file.)
* You still have to open the file to use it and to remove it (even if you
* do not use it).
* On some systems (POSIX), this function also creates a file with that
* name, to avoid security risks. (Someone else might create the file with
* wrong permissions in the time between getting the name and creating the
* file.) You still have to open the file to use it and to remove it (even
* if you do not use it).
*
* @return String filename to use
*/
protected String tmpname() {
synchronized ( OsLib.class ) {
synchronized (OsLib.class) {
return TMP_PREFIX+(tmpnames++)+TMP_SUFFIX;
}
}

View File

@@ -31,56 +31,73 @@ import org.luaj.vm2.LuaValue;
import org.luaj.vm2.Varargs;
/**
* Subclass of {@link LibFunction} which implements the lua standard package and module
* library functions.
* Subclass of {@link LibFunction} which implements the lua standard package and
* module library functions.
*
* <h3>Lua Environment Variables</h3>
* The following variables are available to lua scrips when this library has been loaded:
* <h3>Lua Environment Variables</h3> The following variables are available to
* lua scrips when this library has been loaded:
* <ul>
* <li><code>"package.loaded"</code> Lua table of loaded modules.
* <li><code>"package.path"</code> Search path for lua scripts.
* <li><code>"package.preload"</code> Lua table of uninitialized preload functions.
* <li><code>"package.searchers"</code> Lua table of functions that search for object to load.
* <li><code>"package.preload"</code> Lua table of uninitialized preload
* functions.
* <li><code>"package.searchers"</code> Lua table of functions that search for
* object to load.
* </ul>
*
* <h3>Java Environment Variables</h3>
* These Java environment variables affect the library behavior:
* <h3>Java Environment Variables</h3> These Java environment variables affect
* the library behavior:
* <ul>
* <li><code>"luaj.package.path"</code> Initial value for <code>"package.path"</code>. Default value is <code>"?.lua"</code>
* <li><code>"luaj.package.path"</code> Initial value for
* <code>"package.path"</code>. Default value is <code>"?.lua"</code>
* </ul>
*
* <h3>Loading</h3>
* Typically, this library is included as part of a call to either
* {@link org.luaj.vm2.lib.jse.JsePlatform#standardGlobals()} or {@link org.luaj.vm2.lib.jme.JmePlatform#standardGlobals()}
* <pre> {@code
* <h3>Loading</h3> Typically, this library is included as part of a call to
* either {@link org.luaj.vm2.lib.jse.JsePlatform#standardGlobals()} or
* {@link org.luaj.vm2.lib.jme.JmePlatform#standardGlobals()}
*
* <pre>
* {@code
* Globals globals = JsePlatform.standardGlobals();
* System.out.println( globals.get("require").call"foo") );
* } </pre>
* }
* </pre>
* <p>
* To instantiate and use it directly,
* link it into your globals table via {@link LuaValue#load(LuaValue)} using code such as:
* <pre> {@code
* To instantiate and use it directly, link it into your globals table via
* {@link LuaValue#load(LuaValue)} using code such as:
*
* <pre>
* {
* &#64;code
* Globals globals = new Globals();
* globals.load(new JseBaseLib());
* globals.load(new PackageLib());
* System.out.println( globals.get("require").call("foo") );
* } </pre>
* <h3>Limitations</h3>
* This library has been implemented to match as closely as possible the behavior in the corresponding library in C.
* However, the default filesystem search semantics are different and delegated to the bas library
* as outlined in the {@link BaseLib} and {@link org.luaj.vm2.lib.jse.JseBaseLib} documentation.
* System.out.println(globals.get("require").call("foo"));
* }
* </pre>
*
* <h3>Limitations</h3> This library has been implemented to match as closely as
* possible the behavior in the corresponding library in C. However, the default
* filesystem search semantics are different and delegated to the bas library as
* outlined in the {@link BaseLib} and {@link org.luaj.vm2.lib.jse.JseBaseLib}
* documentation.
* <p>
*
* @see LibFunction
* @see BaseLib
* @see org.luaj.vm2.lib.jse.JseBaseLib
* @see org.luaj.vm2.lib.jse.JsePlatform
* @see org.luaj.vm2.lib.jme.JmePlatform
* @see <a href="http://www.lua.org/manual/5.2/manual.html#6.3">Lua 5.2 Package Lib Reference</a>
* @see <a href="http://www.lua.org/manual/5.2/manual.html#6.3">Lua 5.2 Package
* Lib Reference</a>
*/
public class PackageLib extends TwoArgFunction {
/** The default value to use for package.path. This can be set with the system property
* <code>"luaj.package.path"</code>, and is <code>"?.lua"</code> by default. */
/**
* The default value to use for package.path. This can be set with the
* system property <code>"luaj.package.path"</code>, and is
* <code>"?.lua"</code> by default.
*/
public static final String DEFAULT_LUA_PATH;
static {
String path = null;
@@ -111,10 +128,16 @@ public class PackageLib extends TwoArgFunction {
/** Loader that loads from {@code preload} table if found there */
public preload_searcher preload_searcher;
/** Loader that loads as a lua script using the lua path currently in {@link path} */
/**
* Loader that loads as a lua script using the lua path currently in
* {@link path}
*/
public lua_searcher lua_searcher;
/** Loader that loads as a Java class. Class must have public constructor and be a LuaValue. */
/**
* Loader that loads as a Java class. Class must have public constructor and
* be a LuaValue.
*/
public java_searcher java_searcher;
private static final LuaString _SENTINEL = valueOf("\u0001");
@@ -123,12 +146,15 @@ public class PackageLib extends TwoArgFunction {
public PackageLib() {}
/** Perform one-time initialization on the library by adding package functions
* to the supplied environment, and returning it as the return value.
* It also creates the package.preload and package.loaded tables for use by
* other libraries.
/**
* Perform one-time initialization on the library by adding package
* functions to the supplied environment, and returning it as the return
* value. It also creates the package.preload and package.loaded tables for
* use by other libraries.
*
* @param modname the module name supplied if this is loaded via 'require'.
* @param env the environment to load into, typically a Globals instance.
* @param env the environment to load into, typically a Globals
* instance.
*/
public LuaValue call(LuaValue modname, LuaValue env) {
globals = env.checkglobals();
@@ -156,10 +182,11 @@ public class PackageLib extends TwoArgFunction {
package_.get(_LOADED).set(name, value);
}
/** Set the lua path used by this library instance to a new value.
* Merely sets the value of {@link path} to be used in subsequent searches. */
public void setLuaPath( String newLuaPath ) {
/**
* Set the lua path used by this library instance to a new value. Merely
* sets the value of {@link path} to be used in subsequent searches.
*/
public void setLuaPath(String newLuaPath) {
package_.set(_PATH, LuaValue.valueOf(newLuaPath));
}
@@ -172,38 +199,43 @@ public class PackageLib extends TwoArgFunction {
/**
* require (modname)
*
* Loads the given module. The function starts by looking into the package.loaded table
* to determine whether modname is already loaded. If it is, then require returns the value
* stored at package.loaded[modname]. Otherwise, it tries to find a loader for the module.
* Loads the given module. The function starts by looking into the
* package.loaded table to determine whether modname is already loaded. If
* it is, then require returns the value stored at package.loaded[modname].
* Otherwise, it tries to find a loader for the module.
*
* To find a loader, require is guided by the package.searchers sequence.
* By changing this sequence, we can change how require looks for a module.
* The following explanation is based on the default configuration for package.searchers.
* To find a loader, require is guided by the package.searchers sequence. By
* changing this sequence, we can change how require looks for a module. The
* following explanation is based on the default configuration for
* package.searchers.
*
* First require queries package.preload[modname]. If it has a value, this value
* (which should be a function) is the loader. Otherwise require searches for a Lua loader using
* the path stored in package.path. If that also fails, it searches for a Java loader using
* the classpath, using the public default constructor, and casting the instance to LuaFunction.
* First require queries package.preload[modname]. If it has a value, this
* value (which should be a function) is the loader. Otherwise require
* searches for a Lua loader using the path stored in package.path. If that
* also fails, it searches for a Java loader using the classpath, using the
* public default constructor, and casting the instance to LuaFunction.
*
* Once a loader is found, require calls the loader with two arguments: modname and an extra value
* dependent on how it got the loader. If the loader came from a file, this extra value is the file name.
* If the loader is a Java instance of LuaFunction, this extra value is the environment.
* If the loader returns any non-nil value, require assigns the returned value to package.loaded[modname].
* If the loader does not return a non-nil value and has not assigned any value to package.loaded[modname],
* then require assigns true to this entry.
* In any case, require returns the final value of package.loaded[modname].
* Once a loader is found, require calls the loader with two arguments:
* modname and an extra value dependent on how it got the loader. If the
* loader came from a file, this extra value is the file name. If the loader
* is a Java instance of LuaFunction, this extra value is the environment.
* If the loader returns any non-nil value, require assigns the returned
* value to package.loaded[modname]. If the loader does not return a non-nil
* value and has not assigned any value to package.loaded[modname], then
* require assigns true to this entry. In any case, require returns the
* final value of package.loaded[modname].
*
* If there is any error loading or running the module, or if it cannot find any loader for the module,
* then require raises an error.
* If there is any error loading or running the module, or if it cannot find
* any loader for the module, then require raises an error.
*/
public class require extends OneArgFunction {
public LuaValue call( LuaValue arg ) {
public LuaValue call(LuaValue arg) {
LuaString name = arg.checkstring();
LuaValue loaded = package_.get(_LOADED);
LuaValue result = loaded.get(name);
if ( result.toboolean() ) {
if ( result == _SENTINEL )
error("loop or previous error loading module '"+name+"'");
if (result.toboolean()) {
if (result == _SENTINEL)
error("loop or previous error loading module '" + name + "'");
return result;
}
@@ -211,33 +243,33 @@ public class PackageLib extends TwoArgFunction {
LuaTable tbl = package_.get(_SEARCHERS).checktable();
StringBuffer sb = new StringBuffer();
Varargs loader = null;
for ( int i=1; true; i++ ) {
for (int i = 1; true; i++) {
LuaValue searcher = tbl.get(i);
if ( searcher.isnil() ) {
error( "module '"+name+"' not found: "+name+sb );
if (searcher.isnil()) {
error("module '" + name + "' not found: " + name + sb);
}
/* call loader with module name as argument */
loader = searcher.invoke(name);
if ( loader.isfunction(1) )
if (loader.isfunction(1))
break;
if ( loader.isstring(1) )
sb.append( loader.tojstring(1) );
if (loader.isstring(1))
sb.append(loader.tojstring(1));
}
// load the module using the loader
loaded.set(name, _SENTINEL);
result = loader.arg1().call(name, loader.arg(2));
if ( ! result.isnil() )
loaded.set( name, result );
else if ( (result = loaded.get(name)) == _SENTINEL )
loaded.set( name, result = LuaValue.TRUE );
if (!result.isnil())
loaded.set(name, result);
else if ((result = loaded.get(name)) == _SENTINEL)
loaded.set(name, result = LuaValue.TRUE);
return result;
}
}
public static class loadlib extends VarArgFunction {
public Varargs invoke( Varargs args ) {
public Varargs invoke(Varargs args) {
args.checkstring(1);
return varargsOf(NIL, valueOf("dynamic libraries not enabled"), valueOf("absent"));
}
@@ -247,9 +279,7 @@ public class PackageLib extends TwoArgFunction {
public Varargs invoke(Varargs args) {
LuaString name = args.checkstring(1);
LuaValue val = package_.get(_PRELOAD).get(name);
return val.isnil()?
valueOf("\n\tno field package.preload['"+name+"']"):
val;
return val.isnil()? valueOf("\n\tno field package.preload['" + name + "']"): val;
}
}
@@ -259,7 +289,7 @@ public class PackageLib extends TwoArgFunction {
// get package path
LuaValue path = package_.get(_PATH);
if ( ! path.isstring() )
if (!path.isstring())
return valueOf("package.path is not a string");
// get the searchpath function.
@@ -272,11 +302,11 @@ public class PackageLib extends TwoArgFunction {
// Try to load the file.
v = globals.loadfile(filename.tojstring());
if ( v.arg1().isfunction() )
if (v.arg1().isfunction())
return LuaValue.varargsOf(v.arg1(), filename);
// report error
return varargsOf(NIL, valueOf("'"+filename+"': "+v.arg(2).tojstring()));
return varargsOf(NIL, valueOf("'" + filename + "': " + v.arg(2).tojstring()));
}
}
@@ -296,29 +326,32 @@ public class PackageLib extends TwoArgFunction {
// find next template
int b = e+1;
e = path.indexOf(';',b);
if ( e < 0 )
e = path.indexOf(';', b);
if (e < 0)
e = path.length();
String template = path.substring(b,e);
String template = path.substring(b, e);
// create filename
int q = template.indexOf('?');
String filename = template;
if ( q >= 0 ) {
filename = template.substring(0,q) + name + template.substring(q+1);
if (q >= 0) {
filename = template.substring(0, q)+name+template.substring(q+1);
}
// try opening the file
InputStream is = globals.finder.findResource(filename);
if (is != null) {
try { is.close(); } catch ( java.io.IOException ioe ) {}
try {
is.close();
} catch (java.io.IOException ioe) {
}
return valueOf(filename);
}
// report error
if ( sb == null )
if (sb == null)
sb = new StringBuffer();
sb.append( "\n\t"+filename );
sb.append("\n\t" + filename);
}
return varargsOf(NIL, valueOf(sb.toString()));
}
@@ -327,49 +360,47 @@ public class PackageLib extends TwoArgFunction {
public class java_searcher extends VarArgFunction {
public Varargs invoke(Varargs args) {
String name = args.checkjstring(1);
String classname = toClassname( name );
String classname = toClassname(name);
Class c = null;
LuaValue v = null;
try {
c = Class.forName(classname);
v = (LuaValue) c.newInstance();
if (v.isfunction())
((LuaFunction)v).initupvalue1(globals);
((LuaFunction) v).initupvalue1(globals);
return varargsOf(v, globals);
} catch ( ClassNotFoundException cnfe ) {
return valueOf("\n\tno class '"+classname+"'" );
} catch ( Exception e ) {
return valueOf("\n\tjava load failed on '"+classname+"', "+e );
} catch (ClassNotFoundException cnfe) {
return valueOf("\n\tno class '" + classname + "'");
} catch (Exception e) {
return valueOf("\n\tjava load failed on '" + classname + "', " + e);
}
}
}
/** Convert lua filename to valid class name */
public static final String toClassname( String filename ) {
int n=filename.length();
int j=n;
if ( filename.endsWith(".lua") )
public static final String toClassname(String filename) {
int n = filename.length();
int j = n;
if (filename.endsWith(".lua"))
j -= 4;
for ( int k=0; k<j; k++ ) {
for (int k = 0; k < j; k++) {
char c = filename.charAt(k);
if ( (!isClassnamePart(c)) || (c=='/') || (c=='\\') ) {
if ((!isClassnamePart(c)) || (c == '/') || (c == '\\')) {
StringBuffer sb = new StringBuffer(j);
for ( int i=0; i<j; i++ ) {
for (int i = 0; i < j; i++) {
c = filename.charAt(i);
sb.append(
(isClassnamePart(c))? c:
((c=='/') || (c=='\\'))? '.': '_' );
sb.append((isClassnamePart(c))? c: ((c == '/') || (c == '\\'))? '.': '_');
}
return sb.toString();
}
}
return n==j? filename: filename.substring(0,j);
return n == j? filename: filename.substring(0, j);
}
private static final boolean isClassnamePart(char c) {
if ( (c>='a'&&c<='z') || (c>='A'&&c<='Z') || (c>='0'&&c<='9') )
if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9'))
return true;
switch ( c ) {
switch (c) {
case '.':
case '$':
case '_':

View File

@@ -28,16 +28,17 @@ import org.luaj.vm2.Globals;
/**
* Interface for opening application resource files such as scripts sources.
* <p>
* This is used by required to load files that are part of
* the application, and implemented by BaseLib
* for both the Jme and Jse platforms.
* This is used by required to load files that are part of the application, and
* implemented by BaseLib for both the Jme and Jse platforms.
* <p>
* The Jme version of base lib {@link BaseLib}
* implements {@link Globals#finder} via {@link Class#getResourceAsStream(String)},
* while the Jse version {@link org.luaj.vm2.lib.jse.JseBaseLib} implements it using {@link java.io.File#File(String)}.
* The Jme version of base lib {@link BaseLib} implements {@link Globals#finder}
* via {@link Class#getResourceAsStream(String)}, while the Jse version
* {@link org.luaj.vm2.lib.jse.JseBaseLib} implements it using
* {@link java.io.File#File(String)}.
* <p>
* The io library does not use this API for file manipulation.
* <p>
*
* @see BaseLib
* @see Globals#finder
* @see org.luaj.vm2.lib.jse.JseBaseLib
@@ -55,5 +56,5 @@ public interface ResourceFinder {
* @param filename
* @return InputStream, or null if not found.
*/
public InputStream findResource( String filename );
public InputStream findResource(String filename);
}

File diff suppressed because it is too large Load Diff

View File

@@ -26,40 +26,56 @@ import org.luaj.vm2.LuaValue;
import org.luaj.vm2.Varargs;
/**
* Subclass of {@link LibFunction} which implements the lua standard {@code table}
* library.
* Subclass of {@link LibFunction} which implements the lua standard
* {@code table} library.
*
* <p>
* Typically, this library is included as part of a call to either
* {@link org.luaj.vm2.lib.jse.JsePlatform#standardGlobals()} or {@link org.luaj.vm2.lib.jme.JmePlatform#standardGlobals()}
* <pre> {@code
* {@link org.luaj.vm2.lib.jse.JsePlatform#standardGlobals()} or
* {@link org.luaj.vm2.lib.jme.JmePlatform#standardGlobals()}
*
* <pre>
* {
* &#64;code
* Globals globals = JsePlatform.standardGlobals();
* System.out.println( globals.get("table").get("length").call( LuaValue.tableOf() ) );
* } </pre>
* System.out.println(globals.get("table").get("length").call(LuaValue.tableOf()));
* }
* </pre>
* <p>
* To instantiate and use it directly,
* link it into your globals table via {@link LuaValue#load(LuaValue)} using code such as:
* <pre> {@code
* To instantiate and use it directly, link it into your globals table via
* {@link LuaValue#load(LuaValue)} using code such as:
*
* <pre>
* {
* &#64;code
* Globals globals = new Globals();
* globals.load(new JseBaseLib());
* globals.load(new PackageLib());
* globals.load(new TableLib());
* System.out.println( globals.get("table").get("length").call( LuaValue.tableOf() ) );
* } </pre>
* System.out.println(globals.get("table").get("length").call(LuaValue.tableOf()));
* }
* </pre>
* <p>
* This has been implemented to match as closely as possible the behavior in the corresponding library in C.
* This has been implemented to match as closely as possible the behavior in the
* corresponding library in C.
*
* @see LibFunction
* @see org.luaj.vm2.lib.jse.JsePlatform
* @see org.luaj.vm2.lib.jme.JmePlatform
* @see <a href="http://www.lua.org/manual/5.2/manual.html#6.5">Lua 5.2 Table Lib Reference</a>
* @see <a href="http://www.lua.org/manual/5.2/manual.html#6.5">Lua 5.2 Table
* Lib Reference</a>
*/
public class TableLib extends TwoArgFunction {
/** Perform one-time initialization on the library by creating a table
* containing the library functions, adding that table to the supplied environment,
* adding the table to package.loaded, and returning table as the return value.
/**
* Perform one-time initialization on the library by creating a table
* containing the library functions, adding that table to the supplied
* environment, adding the table to package.loaded, and returning table as
* the return value.
*
* @param modname the module name supplied if this is loaded via 'require'.
* @param env the environment to load into, typically a Globals instance.
* @param env the environment to load into, typically a Globals
* instance.
*/
public LuaValue call(LuaValue modname, LuaValue env) {
LuaTable table = new LuaTable();
@@ -70,23 +86,27 @@ public class TableLib extends TwoArgFunction {
table.set("sort", new sort());
table.set("unpack", new unpack());
env.set("table", table);
if (!env.get("package").isnil()) env.get("package").get("loaded").set("table", table);
if (!env.get("package").isnil())
env.get("package").get("loaded").set("table", table);
return NIL;
}
// "concat" (table [, sep [, i [, j]]]) -> string
static class concat extends TableLibFunction {
public LuaValue call(LuaValue list) {
return list.checktable().concat(EMPTYSTRING,1,list.length());
return list.checktable().concat(EMPTYSTRING, 1, list.length());
}
public LuaValue call(LuaValue list, LuaValue sep) {
return list.checktable().concat(sep.checkstring(),1,list.length());
return list.checktable().concat(sep.checkstring(), 1, list.length());
}
public LuaValue call(LuaValue list, LuaValue sep, LuaValue i) {
return list.checktable().concat(sep.checkstring(),i.checkint(),list.length());
return list.checktable().concat(sep.checkstring(), i.checkint(), list.length());
}
public LuaValue call(LuaValue list, LuaValue sep, LuaValue i, LuaValue j) {
return list.checktable().concat(sep.checkstring(),i.checkint(),j.checkint());
return list.checktable().concat(sep.checkstring(), i.checkint(), j.checkint());
}
}
@@ -96,14 +116,15 @@ public class TableLib extends TwoArgFunction {
switch (args.narg()) {
case 2: {
LuaTable table = args.checktable(1);
table.insert(table.length()+1,args.arg(2));
table.insert(table.length()+1, args.arg(2));
return NONE;
}
case 3: {
LuaTable table = args.checktable(1);
int pos = args.checkint(2);
int max = table.length() + 1;
if (pos < 1 || pos > max) argerror(2, "position out of bounds: " + pos + " not between 1 and " + max);
int max = table.length()+1;
if (pos < 1 || pos > max)
argerror(2, "position out of bounds: " + pos + " not between 1 and " + max);
table.insert(pos, args.arg(3));
return NONE;
}
@@ -129,8 +150,8 @@ public class TableLib extends TwoArgFunction {
LuaTable table = args.checktable(1);
int size = table.length();
int pos = args.optint(2, size);
if (pos != size && (pos < 1 || pos > size + 1)) {
argerror(2, "position out of bounds: " + pos + " not between 1 and " + (size + 1));
if (pos != size && (pos < 1 || pos > size+1)) {
argerror(2, "position out of bounds: " + pos + " not between 1 and " + (size+1));
}
return table.remove(pos);
}
@@ -139,19 +160,17 @@ public class TableLib extends TwoArgFunction {
// "sort" (table [, comp])
static class sort extends VarArgFunction {
public Varargs invoke(Varargs args) {
args.checktable(1).sort(
args.isnil(2)? NIL: args.checkfunction(2));
args.checktable(1).sort(args.isnil(2)? NIL: args.checkfunction(2));
return NONE;
}
}
// "unpack", // (list [,i [,j]]) -> result1, ...
static class unpack extends VarArgFunction {
public Varargs invoke(Varargs args) {
LuaTable t = args.checktable(1);
// do not waste resource for calc rawlen if arg3 is not nil
int len = args.arg(3).isnil() ? t.length() : 0;
int len = args.arg(3).isnil()? t.length(): 0;
return t.unpack(args.optint(2, 1), args.optint(3, len));
}
}

View File

@@ -24,21 +24,24 @@ package org.luaj.vm2.lib;
import org.luaj.vm2.LuaValue;
import org.luaj.vm2.Varargs;
/** Abstract base class for Java function implementations that take two arguments and
* return one value.
/**
* Abstract base class for Java function implementations that take two arguments
* and return one value.
* <p>
* Subclasses need only implement {@link LuaValue#call(LuaValue,LuaValue,LuaValue)} to complete this class,
* simplifying development.
* All other uses of {@link #call()}, {@link #invoke(Varargs)},etc,
* are routed through this method by this class,
* Subclasses need only implement
* {@link LuaValue#call(LuaValue,LuaValue,LuaValue)} to complete this class,
* simplifying development. All other uses of {@link #call()},
* {@link #invoke(Varargs)},etc, are routed through this method by this class,
* dropping or extending arguments with {@code nil} values as required.
* <p>
* If more or less than three arguments are required,
* or variable argument or variable return values,
* then use one of the related function
* {@link ZeroArgFunction}, {@link OneArgFunction}, {@link TwoArgFunction}, or {@link VarArgFunction}.
* If more or less than three arguments are required, or variable argument or
* variable return values, then use one of the related function
* {@link ZeroArgFunction}, {@link OneArgFunction}, {@link TwoArgFunction}, or
* {@link VarArgFunction}.
* <p>
* See {@link LibFunction} for more information on implementation libraries and library functions.
* See {@link LibFunction} for more information on implementation libraries and
* library functions.
*
* @see #call(LuaValue,LuaValue,LuaValue)
* @see LibFunction
* @see ZeroArgFunction
@@ -67,7 +70,7 @@ abstract public class ThreeArgFunction extends LibFunction {
}
public Varargs invoke(Varargs varargs) {
return call(varargs.arg1(),varargs.arg(2),varargs.arg(3));
return call(varargs.arg1(), varargs.arg(2), varargs.arg(3));
}
}

View File

@@ -24,21 +24,24 @@ package org.luaj.vm2.lib;
import org.luaj.vm2.LuaValue;
import org.luaj.vm2.Varargs;
/** Abstract base class for Java function implementations that take two arguments and
* return one value.
/**
* Abstract base class for Java function implementations that take two arguments
* and return one value.
* <p>
* Subclasses need only implement {@link LuaValue#call(LuaValue,LuaValue)} to complete this class,
* simplifying development.
* All other uses of {@link #call()}, {@link #invoke(Varargs)},etc,
* are routed through this method by this class,
* dropping or extending arguments with {@code nil} values as required.
* Subclasses need only implement {@link LuaValue#call(LuaValue,LuaValue)} to
* complete this class, simplifying development. All other uses of
* {@link #call()}, {@link #invoke(Varargs)},etc, are routed through this method
* by this class, dropping or extending arguments with {@code nil} values as
* required.
* <p>
* If more or less than two arguments are required,
* or variable argument or variable return values,
* then use one of the related function
* {@link ZeroArgFunction}, {@link OneArgFunction}, {@link ThreeArgFunction}, or {@link VarArgFunction}.
* If more or less than two arguments are required, or variable argument or
* variable return values, then use one of the related function
* {@link ZeroArgFunction}, {@link OneArgFunction}, {@link ThreeArgFunction}, or
* {@link VarArgFunction}.
* <p>
* See {@link LibFunction} for more information on implementation libraries and library functions.
* See {@link LibFunction} for more information on implementation libraries and
* library functions.
*
* @see #call(LuaValue,LuaValue)
* @see LibFunction
* @see ZeroArgFunction
@@ -67,7 +70,7 @@ abstract public class TwoArgFunction extends LibFunction {
}
public Varargs invoke(Varargs varargs) {
return call(varargs.arg1(),varargs.arg(2));
return call(varargs.arg1(), varargs.arg(2));
}
}

View File

@@ -24,20 +24,23 @@ package org.luaj.vm2.lib;
import org.luaj.vm2.LuaValue;
import org.luaj.vm2.Varargs;
/** Abstract base class for Java function implementations that takes varaiable arguments and
* returns multiple return values.
/**
* Abstract base class for Java function implementations that takes varaiable
* arguments and returns multiple return values.
* <p>
* Subclasses need only implement {@link LuaValue#invoke(Varargs)} to complete this class,
* simplifying development.
* All other uses of {@link #call(LuaValue)}, {@link #invoke()},etc,
* are routed through this method by this class,
* converting arguments to {@link Varargs} and
* dropping or extending return values with {@code nil} values as required.
* Subclasses need only implement {@link LuaValue#invoke(Varargs)} to complete
* this class, simplifying development. All other uses of
* {@link #call(LuaValue)}, {@link #invoke()},etc, are routed through this
* method by this class, converting arguments to {@link Varargs} and dropping or
* extending return values with {@code nil} values as required.
* <p>
* If between one and three arguments are required, and only one return value is returned,
* {@link ZeroArgFunction}, {@link OneArgFunction}, {@link TwoArgFunction}, or {@link ThreeArgFunction}.
* If between one and three arguments are required, and only one return value is
* returned, {@link ZeroArgFunction}, {@link OneArgFunction},
* {@link TwoArgFunction}, or {@link ThreeArgFunction}.
* <p>
* See {@link LibFunction} for more information on implementation libraries and library functions.
* See {@link LibFunction} for more information on implementation libraries and
* library functions.
*
* @see #invoke(Varargs)
* @see LibFunction
* @see ZeroArgFunction
@@ -59,18 +62,18 @@ abstract public class VarArgFunction extends LibFunction {
}
public LuaValue call(LuaValue arg1, LuaValue arg2) {
return invoke(varargsOf(arg1,arg2)).arg1();
return invoke(varargsOf(arg1, arg2)).arg1();
}
public LuaValue call(LuaValue arg1, LuaValue arg2, LuaValue arg3) {
return invoke(varargsOf(arg1,arg2,arg3)).arg1();
return invoke(varargsOf(arg1, arg2, arg3)).arg1();
}
/**
* Subclass responsibility.
* May not have expected behavior for tail calls.
* Should not be used if:
* - function has a possibility of returning a TailcallVarargs
* Subclass responsibility. May not have expected behavior for tail calls.
* Should not be used if: - function has a possibility of returning a
* TailcallVarargs
*
* @param args the arguments to the function call.
*/
public Varargs invoke(Varargs args) {

View File

@@ -24,19 +24,21 @@ package org.luaj.vm2.lib;
import org.luaj.vm2.LuaValue;
import org.luaj.vm2.Varargs;
/** Abstract base class for Java function implementations that take no arguments and
* return one value.
/**
* Abstract base class for Java function implementations that take no arguments
* and return one value.
* <p>
* Subclasses need only implement {@link LuaValue#call()} to complete this class,
* simplifying development.
* All other uses of {@link #call(LuaValue)}, {@link #invoke(Varargs)},etc,
* are routed through this method by this class.
* Subclasses need only implement {@link LuaValue#call()} to complete this
* class, simplifying development. All other uses of {@link #call(LuaValue)},
* {@link #invoke(Varargs)},etc, are routed through this method by this class.
* <p>
* If one or more arguments are required, or variable argument or variable return values,
* then use one of the related function
* {@link OneArgFunction}, {@link TwoArgFunction}, {@link ThreeArgFunction}, or {@link VarArgFunction}.
* If one or more arguments are required, or variable argument or variable
* return values, then use one of the related function {@link OneArgFunction},
* {@link TwoArgFunction}, {@link ThreeArgFunction}, or {@link VarArgFunction}.
* <p>
* See {@link LibFunction} for more information on implementation libraries and library functions.
* See {@link LibFunction} for more information on implementation libraries and
* library functions.
*
* @see #call()
* @see LibFunction
* @see OneArgFunction

View File

@@ -35,38 +35,51 @@ import org.luaj.vm2.lib.IoLib;
import org.luaj.vm2.lib.LibFunction;
/**
* Subclass of {@link IoLib} and therefore {@link LibFunction} which implements the lua standard {@code io}
* library for the JSE platform.
* Subclass of {@link IoLib} and therefore {@link LibFunction} which implements
* the lua standard {@code io} library for the JSE platform.
* <p>
* The implementation of the is based on CLDC 1.0 and StreamConnection.
* However, seek is not supported.
* The implementation of the is based on CLDC 1.0 and StreamConnection. However,
* seek is not supported.
* <p>
* Typically, this library is included as part of a call to
* {@link org.luaj.vm2.lib.jme.JmePlatform#standardGlobals()}
* <pre> {@code
*
* <pre>
* {
* &#64;code
* Globals globals = JmePlatform.standardGlobals();
* globals.get("io").get("write").call(LuaValue.valueOf("hello, world\n"));
* } </pre>
* }
* </pre>
* <p>
* For special cases where the smallest possible footprint is desired,
* a minimal set of libraries could be loaded
* directly via {@link Globals#load(LuaValue)} using code such as:
* <pre> {@code
* For special cases where the smallest possible footprint is desired, a minimal
* set of libraries could be loaded directly via {@link Globals#load(LuaValue)}
* using code such as:
*
* <pre>
* {
* &#64;code
* Globals globals = new Globals();
* globals.load(new JmeBaseLib());
* globals.load(new PackageLib());
* globals.load(new JmeIoLib());
* globals.get("io").get("write").call(LuaValue.valueOf("hello, world\n"));
* } </pre>
* <p>However, other libraries such as <em>MathLib</em> are not loaded in this case.
* }
* </pre>
* <p>
* This has been implemented to match as closely as possible the behavior in the corresponding library in C.
* However, other libraries such as <em>MathLib</em> are not loaded in this
* case.
* <p>
* This has been implemented to match as closely as possible the behavior in the
* corresponding library in C.
*
* @see LibFunction
* @see org.luaj.vm2.lib.jse.JsePlatform
* @see org.luaj.vm2.lib.jme.JmePlatform
* @see IoLib
* @see org.luaj.vm2.lib.jse.JseIoLib
* @see <a href="http://www.lua.org/manual/5.2/manual.html#6.8">Lua 5.2 I/O Lib Reference</a>
* @see <a href="http://www.lua.org/manual/5.2/manual.html#6.8">Lua 5.2 I/O Lib
* Reference</a>
*/
public class JmeIoLib extends IoLib {
@@ -82,13 +95,13 @@ public class JmeIoLib extends IoLib {
return new FileImpl(globals.STDERR);
}
protected File openFile( String filename, boolean readMode, boolean appendMode, boolean updateMode, boolean binaryMode ) throws IOException {
protected File openFile(String filename, boolean readMode, boolean appendMode, boolean updateMode,
boolean binaryMode) throws IOException {
String url = "file:///" + filename;
int mode = readMode? Connector.READ: Connector.READ_WRITE;
StreamConnection conn = (StreamConnection) Connector.open( url, mode );
File f = readMode?
new FileImpl(conn, conn.openInputStream(), null):
new FileImpl(conn, conn.openInputStream(), conn.openOutputStream());
StreamConnection conn = (StreamConnection) Connector.open(url, mode);
File f = readMode? new FileImpl(conn, conn.openInputStream(), null)
: new FileImpl(conn, conn.openInputStream(), conn.openOutputStream());
/*
if ( appendMode ) {
f.seek("end",0);
@@ -121,44 +134,54 @@ public class JmeIoLib extends IoLib {
private boolean closed = false;
private boolean nobuffer = false;
private int lookahead = -1;
private FileImpl( StreamConnection conn, InputStream is, OutputStream os ) {
private FileImpl(StreamConnection conn, InputStream is, OutputStream os) {
this.conn = conn;
this.is = is;
this.os = os;
}
private FileImpl( InputStream i ) {
this( null, i, null );
private FileImpl(InputStream i) {
this(null, i, null);
}
private FileImpl( OutputStream o ) {
this( null, null, o );
private FileImpl(OutputStream o) {
this(null, null, o);
}
public String tojstring() {
return "file ("+this.hashCode()+")";
return "file (" + this.hashCode() + ")";
}
public boolean isstdfile() {
return conn == null;
}
public void close() throws IOException {
closed = true;
if ( conn != null ) {
if (conn != null) {
conn.close();
}
}
public void flush() throws IOException {
if ( os != null )
if (os != null)
os.flush();
}
public void write(LuaString s) throws IOException {
if ( os != null )
os.write( s.m_bytes, s.m_offset, s.m_length );
if (os != null)
os.write(s.m_bytes, s.m_offset, s.m_length);
else
notimplemented();
if ( nobuffer )
if (nobuffer)
flush();
}
public boolean isclosed() {
return closed;
}
public int seek(String option, int pos) throws IOException {
/*
if ( conn != null ) {
@@ -177,6 +200,7 @@ public class JmeIoLib extends IoLib {
notimplemented();
return 0;
}
public void setvbuf(String mode, int size) {
nobuffer = "no".equals(mode);
}
@@ -188,19 +212,19 @@ public class JmeIoLib extends IoLib {
// peek ahead one character
public int peek() throws IOException {
if ( lookahead < 0 )
if (lookahead < 0)
lookahead = is.read();
return lookahead;
}
// return char if read, -1 if eof, throw IOException on other exception
public int read() throws IOException {
if ( lookahead >= 0 ) {
if (lookahead >= 0) {
int c = lookahead;
lookahead = -1;
return c;
}
if ( is != null )
if (is != null)
return is.read();
notimplemented();
return 0;
@@ -208,17 +232,17 @@ public class JmeIoLib extends IoLib {
// return number of bytes read if positive, -1 if eof, throws IOException
public int read(byte[] bytes, int offset, int length) throws IOException {
int n,i=0;
if (is!=null) {
if ( length > 0 && lookahead >= 0 ) {
int n, i = 0;
if (is != null) {
if (length > 0 && lookahead >= 0) {
bytes[offset] = (byte) lookahead;
lookahead = -1;
i += 1;
}
for ( ; i<length; ) {
for (; i < length;) {
n = is.read(bytes, offset+i, length-i);
if ( n < 0 )
return ( i > 0 ? i : -1 );
if (n < 0)
return (i > 0? i: -1);
i += n;
}
} else {

View File

@@ -37,40 +37,60 @@ import org.luaj.vm2.lib.ResourceFinder;
import org.luaj.vm2.lib.StringLib;
import org.luaj.vm2.lib.TableLib;
/** The {@link org.luaj.vm2.lib.jme.JmePlatform} class is a convenience class to standardize
* how globals tables are initialized for the JME platform.
/**
* The {@link org.luaj.vm2.lib.jme.JmePlatform} class is a convenience class to
* standardize how globals tables are initialized for the JME platform.
* <p>
* The JME platform, being limited, cannot implement all libraries in all aspects. The main limitations are
* The JME platform, being limited, cannot implement all libraries in all
* aspects. The main limitations are
* <ul>
* <li>Some math functions are not implemented, see {@link MathLib} for details</li>
* <li>Scripts are loaded via Class.getResourceAsStream(), see {@link BaseLib} for details</li>
* <li>OS functions execute(), remove(), rename(), and tmpname() vary, see {@link OsLib} for details</li>
* <li>I/O seek is not implemented, see {@link org.luaj.vm2.lib.jme.JmeIoLib} for details</li>
* <li>luajava is not available, see {@link org.luaj.vm2.lib.jse.LuajavaLib} for details</li>
* <li>Some math functions are not implemented, see {@link MathLib} for
* details</li>
* <li>Scripts are loaded via Class.getResourceAsStream(), see {@link BaseLib}
* for details</li>
* <li>OS functions execute(), remove(), rename(), and tmpname() vary, see
* {@link OsLib} for details</li>
* <li>I/O seek is not implemented, see {@link org.luaj.vm2.lib.jme.JmeIoLib}
* for details</li>
* <li>luajava is not available, see {@link org.luaj.vm2.lib.jse.LuajavaLib} for
* details</li>
* </ul>
* <p>
* It is used to allocate either a set of standard globals using
* {@link #standardGlobals()} or debug globals using {@link #debugGlobals()}
* <p>
* A simple example of initializing globals and using them from Java is:
* <pre> {@code
*
* <pre>
* {
* &#64;code
* Globals global = JmePlatform.standardGlobals();
* global.get("print").call(LuaValue.valueOf("hello, world"));
* } </pre>
* }
* </pre>
* <p>
* Once globals are created, a simple way to load and run a script is:
* <pre> {@code
*
* <pre>
* {@code
* LoadState.load( getClass().getResourceAsStream("main.lua"), "main.lua", globals ).call();
* } </pre>
* }
* </pre>
* <p>
* although {@code require} could also be used:
* <pre> {@code
*
* <pre>
* {@code
* globals.get("require").call(LuaValue.valueOf("main"));
* } </pre>
* For this to succeed, the file "main.lua" must be a resource in the class path.
* See {@link BaseLib} for details on finding scripts using {@link ResourceFinder}.
* }
* </pre>
*
* For this to succeed, the file "main.lua" must be a resource in the class
* path. See {@link BaseLib} for details on finding scripts using
* {@link ResourceFinder}.
* <p>
* The standard globals will contain all standard libraries in their JME flavors:
* The standard globals will contain all standard libraries in their JME
* flavors:
* <ul>
* <li>{@link Globals}</li>
* <li>{@link BaseLib}</li>
@@ -83,9 +103,11 @@ import org.luaj.vm2.lib.TableLib;
* <li>{@link org.luaj.vm2.lib.jme.JmeIoLib}</li>
* <li>{@link OsLib}</li>
* </ul>
* In addition, the {@link LuaC} compiler is installed so lua files may be loaded in their source form.
* In addition, the {@link LuaC} compiler is installed so lua files may be
* loaded in their source form.
* <p>
* The debug globals are simply the standard globals plus the {@code debug} library {@link DebugLib}.
* The debug globals are simply the standard globals plus the {@code debug}
* library {@link DebugLib}.
* <p>
* <p>
* The class ensures that initialization is done in the correct order.
@@ -119,9 +141,11 @@ public class JmePlatform {
return globals;
}
/** Create standard globals including the {@link DebugLib} library.
/**
* Create standard globals including the {@link DebugLib} library.
*
* @return Table of globals initialized with the standard JSE and debug libraries
* @return Table of globals initialized with the standard JSE and debug
* libraries
* @see #standardGlobals()
* @see org.luaj.vm2.lib.jse.JsePlatform
* @see org.luaj.vm2.lib.jme.JmePlatform

View File

@@ -1,3 +1,4 @@
/*******************************************************************************
* Copyright (c) 2009-2012 Luaj.org. All rights reserved.
*
@@ -38,26 +39,19 @@ import org.luaj.vm2.Varargs;
import org.luaj.vm2.lib.jse.JsePlatform;
import org.luaj.vm2.luajc.LuaJC;
/**
* lua command for use in JSE environments.
*/
public class lua {
private static final String version = Lua._VERSION + " Copyright (c) 2012 Luaj.org.org";
private static final String usage =
"usage: java -cp luaj-jse.jar lua [options] [script [args]].\n" +
"Available options are:\n" +
" -e stat execute string 'stat'\n" +
" -l name require library 'name'\n" +
" -i enter interactive mode after executing 'script'\n" +
" -v show version information\n" +
" -b use luajc bytecode-to-bytecode compiler (requires bcel on class path)\n" +
" -n nodebug - do not load debug library by default\n" +
" -p print the prototype\n" +
" -c enc use the supplied encoding 'enc' for input files\n" +
" -- stop handling options\n" +
" - execute stdin and stop handling options";
private static final String usage = "usage: java -cp luaj-jse.jar lua [options] [script [args]].\n"
+ "Available options are:\n" + " -e stat execute string 'stat'\n" + " -l name require library 'name'\n"
+ " -i enter interactive mode after executing 'script'\n" + " -v show version information\n"
+ " -b use luajc bytecode-to-bytecode compiler (requires bcel on class path)\n"
+ " -n nodebug - do not load debug library by default\n" + " -p print the prototype\n"
+ " -c enc use the supplied encoding 'enc' for input files\n" + " -- stop handling options\n"
+ " - execute stdin and stop handling options";
private static void usageExit() {
System.out.println(usage);
@@ -68,7 +62,7 @@ public class lua {
private static boolean print = false;
private static String encoding = null;
public static void main( String[] args ) throws IOException {
public static void main(String[] args) throws IOException {
// process args
boolean interactive = (args.length == 0);
@@ -79,17 +73,17 @@ public class lua {
Vector libs = null;
try {
// stateful argument processing
for ( int i=0; i<args.length; i++ ) {
if ( ! processing || ! args[i].startsWith("-") ) {
for (int i = 0; i < args.length; i++) {
if (!processing || !args[i].startsWith("-")) {
// input file - defer to last stage
break;
} else if ( args[i].length() <= 1 ) {
} else if (args[i].length() <= 1) {
// input file - defer to last stage
break;
} else {
switch ( args[i].charAt(1) ) {
switch (args[i].charAt(1)) {
case 'e':
if ( ++i >= args.length )
if (++i >= args.length)
usageExit();
// input script - defer to last stage
break;
@@ -97,10 +91,10 @@ public class lua {
luajc = true;
break;
case 'l':
if ( ++i >= args.length )
if (++i >= args.length)
usageExit();
libs = libs!=null? libs: new Vector();
libs.addElement( args[i] );
libs = libs != null? libs: new Vector();
libs.addElement(args[i]);
break;
case 'i':
interactive = true;
@@ -115,12 +109,12 @@ public class lua {
print = true;
break;
case 'c':
if ( ++i >= args.length )
if (++i >= args.length)
usageExit();
encoding = args[i];
break;
case '-':
if ( args[i].length() > 2 )
if (args[i].length() > 2)
usageExit();
processing = false;
break;
@@ -132,33 +126,34 @@ public class lua {
}
// echo version
if ( versioninfo )
if (versioninfo)
System.out.println(version);
// new lua state
globals = nodebug? JsePlatform.standardGlobals(): JsePlatform.debugGlobals();
if ( luajc ) LuaJC.install(globals);
for ( int i=0, n=libs!=null? libs.size(): 0; i<n; i++ )
loadLibrary( (String) libs.elementAt(i) );
if (luajc)
LuaJC.install(globals);
for (int i = 0, n = libs != null? libs.size(): 0; i < n; i++)
loadLibrary((String) libs.elementAt(i));
// input script processing
processing = true;
for ( int i=0; i<args.length; i++ ) {
if ( ! processing || ! args[i].startsWith("-") ) {
processScript( new FileInputStream(args[i]), args[i], args, i );
for (int i = 0; i < args.length; i++) {
if (!processing || !args[i].startsWith("-")) {
processScript(new FileInputStream(args[i]), args[i], args, i);
break;
} else if ( "-".equals( args[i] ) ) {
processScript( System.in, "=stdin", args, i );
} else if ("-".equals(args[i])) {
processScript(System.in, "=stdin", args, i);
break;
} else {
switch ( args[i].charAt(1) ) {
switch (args[i].charAt(1)) {
case 'l':
case 'c':
++i;
break;
case 'e':
++i;
processScript( new ByteArrayInputStream(args[i].getBytes()), "string", args, i );
processScript(new ByteArrayInputStream(args[i].getBytes()), "string", args, i);
break;
case '-':
processing = false;
@@ -167,48 +162,48 @@ public class lua {
}
}
if ( interactive )
if (interactive)
interactiveMode();
} catch ( IOException ioe ) {
System.err.println( ioe.toString() );
} catch (IOException ioe) {
System.err.println(ioe.toString());
System.exit(-2);
}
}
private static void loadLibrary( String libname ) throws IOException {
LuaValue slibname =LuaValue.valueOf(libname);
private static void loadLibrary(String libname) throws IOException {
LuaValue slibname = LuaValue.valueOf(libname);
try {
// load via plain require
globals.get("require").call(slibname);
} catch ( Exception e ) {
} catch (Exception e) {
try {
// load as java class
LuaValue v = (LuaValue) Class.forName(libname).newInstance();
v.call(slibname, globals);
} catch ( Exception f ) {
throw new IOException("loadLibrary("+libname+") failed: "+e+","+f );
} catch (Exception f) {
throw new IOException("loadLibrary(" + libname + ") failed: " + e + "," + f);
}
}
}
private static void processScript( InputStream script, String chunkname, String[] args, int firstarg ) throws IOException {
private static void processScript(InputStream script, String chunkname, String[] args, int firstarg)
throws IOException {
try {
LuaValue c;
try {
script = new BufferedInputStream(script);
c = encoding != null?
globals.load(new InputStreamReader(script, encoding), chunkname):
globals.load(script, chunkname, "bt", globals);
c = encoding != null? globals.load(new InputStreamReader(script, encoding), chunkname)
: globals.load(script, chunkname, "bt", globals);
} finally {
script.close();
}
if (print && c.isclosure())
Print.print(c.checkclosure().p);
Varargs scriptargs = setGlobalArg(chunkname, args, firstarg, globals);
c.invoke( scriptargs );
} catch ( Exception e ) {
e.printStackTrace( System.err );
c.invoke(scriptargs);
} catch (Exception e) {
e.printStackTrace(System.err);
}
}
@@ -216,23 +211,23 @@ public class lua {
if (args == null)
return LuaValue.NONE;
LuaTable arg = LuaValue.tableOf();
for ( int j=0; j<args.length; j++ )
arg.set( j-i, LuaValue.valueOf(args[j]) );
for (int j = 0; j < args.length; j++)
arg.set(j-i, LuaValue.valueOf(args[j]));
arg.set(0, LuaValue.valueOf(chunkname));
arg.set(-1, LuaValue.valueOf("luaj"));
globals.set("arg", arg);
return arg.unpack();
}
private static void interactiveMode( ) throws IOException {
BufferedReader reader = new BufferedReader( new InputStreamReader( System.in ) );
private static void interactiveMode() throws IOException {
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
while ( true ) {
System.out.print("> ");
System.out.flush();
String line = reader.readLine();
if ( line == null )
if (line == null)
return;
processScript( new ByteArrayInputStream(line.getBytes()), "=stdin", null, 0 );
processScript(new ByteArrayInputStream(line.getBytes()), "=stdin", null, 0);
}
}
}

View File

@@ -1,3 +1,4 @@
/*******************************************************************************
* Copyright (c) 2009 Luaj.org. All rights reserved.
*
@@ -35,26 +36,19 @@ import org.luaj.vm2.Prototype;
import org.luaj.vm2.compiler.DumpState;
import org.luaj.vm2.lib.jse.JsePlatform;
/**
* Compiler for lua files to lua bytecode.
*/
public class luac {
private static final String version = Lua._VERSION + "Copyright (C) 2009 luaj.org";
private static final String usage =
"usage: java -cp luaj-jse.jar luac [options] [filenames].\n" +
"Available options are:\n" +
" - process stdin\n" +
" -l list\n" +
" -o name output to file 'name' (default is \"luac.out\")\n" +
" -p parse only\n" +
" -s strip debug information\n" +
" -e little endian format for numbers\n" +
" -i<n> number format 'n', (n=0,1 or 4, default="+DumpState.NUMBER_FORMAT_DEFAULT+")\n" +
" -v show version information\n" +
" -c enc use the supplied encoding 'enc' for input files\n" +
" -- stop handling options\n";
private static final String usage = "usage: java -cp luaj-jse.jar luac [options] [filenames].\n"
+ "Available options are:\n" + " - process stdin\n" + " -l list\n"
+ " -o name output to file 'name' (default is \"luac.out\")\n" + " -p parse only\n"
+ " -s strip debug information\n" + " -e little endian format for numbers\n"
+ " -i<n> number format 'n', (n=0,1 or 4, default=" + DumpState.NUMBER_FORMAT_DEFAULT + ")\n"
+ " -v show version information\n" + " -c enc use the supplied encoding 'enc' for input files\n"
+ " -- stop handling options\n";
private static void usageExit() {
System.out.println(usage);
@@ -71,27 +65,27 @@ public class luac {
private boolean processing = true;
private String encoding = null;
public static void main( String[] args ) throws IOException {
new luac( args );
public static void main(String[] args) throws IOException {
new luac(args);
}
private luac( String[] args ) throws IOException {
private luac(String[] args) throws IOException {
// process args
try {
// get stateful args
for ( int i=0; i<args.length; i++ ) {
if ( ! processing || ! args[i].startsWith("-") ) {
for (int i = 0; i < args.length; i++) {
if (!processing || !args[i].startsWith("-")) {
// input file - defer to next stage
} else if ( args[i].length() <= 1 ) {
} else if (args[i].length() <= 1) {
// input file - defer to next stage
} else {
switch ( args[i].charAt(1) ) {
switch (args[i].charAt(1)) {
case 'l':
list = true;
break;
case 'o':
if ( ++i >= args.length )
if (++i >= args.length)
usageExit();
output = args[i];
break;
@@ -105,7 +99,7 @@ public class luac {
littleendian = true;
break;
case 'i':
if ( args[i].length() <= 2 )
if (args[i].length() <= 2)
usageExit();
numberformat = Integer.parseInt(args[i].substring(2));
break;
@@ -113,12 +107,12 @@ public class luac {
versioninfo = true;
break;
case 'c':
if ( ++i >= args.length )
if (++i >= args.length)
usageExit();
encoding = args[i];
break;
case '-':
if ( args[i].length() > 2 )
if (args[i].length() > 2)
usageExit();
processing = false;
break;
@@ -130,24 +124,24 @@ public class luac {
}
// echo version
if ( versioninfo )
if (versioninfo)
System.out.println(version);
// open output file
OutputStream fos = new FileOutputStream( output );
OutputStream fos = new FileOutputStream(output);
// process input files
try {
Globals globals = JsePlatform.standardGlobals();
processing = true;
for ( int i=0; i<args.length; i++ ) {
if ( ! processing || ! args[i].startsWith("-") ) {
String chunkname = args[i].substring(0,args[i].length()-4);
processScript( globals, new FileInputStream(args[i]), chunkname, fos );
} else if ( args[i].length() <= 1 ) {
processScript( globals, System.in, "=stdin", fos );
for (int i = 0; i < args.length; i++) {
if (!processing || !args[i].startsWith("-")) {
String chunkname = args[i].substring(0, args[i].length()-4);
processScript(globals, new FileInputStream(args[i]), chunkname, fos);
} else if (args[i].length() <= 1) {
processScript(globals, System.in, "=stdin", fos);
} else {
switch ( args[i].charAt(1) ) {
switch (args[i].charAt(1)) {
case 'o':
case 'c':
++i;
@@ -162,19 +156,20 @@ public class luac {
fos.close();
}
} catch ( IOException ioe ) {
System.err.println( ioe.toString() );
} catch (IOException ioe) {
System.err.println(ioe.toString());
System.exit(-2);
}
}
private void processScript( Globals globals, InputStream script, String chunkname, OutputStream out ) throws IOException {
private void processScript(Globals globals, InputStream script, String chunkname, OutputStream out)
throws IOException {
try {
// create the chunk
script = new BufferedInputStream(script);
Prototype chunk = encoding != null?
globals.compilePrototype(new InputStreamReader(script, encoding), chunkname):
globals.compilePrototype(script, chunkname);
Prototype chunk = encoding != null
? globals.compilePrototype(new InputStreamReader(script, encoding), chunkname)
: globals.compilePrototype(script, chunkname);
// list the chunk
if (list)
@@ -185,8 +180,8 @@ public class luac {
DumpState.dump(chunk, out, stripdebug, numberformat, littleendian);
}
} catch ( Exception e ) {
e.printStackTrace( System.err );
} catch (Exception e) {
e.printStackTrace(System.err);
} finally {
script.close();
}

View File

@@ -1,3 +1,4 @@
/*******************************************************************************
* Copyright (c) 2009-2012 Luaj.org. All rights reserved.
*
@@ -36,23 +37,18 @@ import org.luaj.vm2.lib.jse.JsePlatform;
import org.luaj.vm2.luajc.LuaJC;
/**
* Compiler for lua files to compile lua sources or lua binaries into java classes.
* Compiler for lua files to compile lua sources or lua binaries into java
* classes.
*/
public class luajc {
private static final String version = Lua._VERSION + " Copyright (C) 2012 luaj.org";
private static final String usage =
"usage: java -cp luaj-jse.jar,bcel-5.2.jar luajc [options] fileordir [, fileordir ...]\n" +
"Available options are:\n" +
" - process stdin\n" +
" -s src source directory\n" +
" -d dir destination directory\n" +
" -p pkg package prefix to apply to all classes\n" +
" -m generate main(String[]) function for JSE\n" +
" -r recursively compile all\n" +
" -l load classes to verify generated bytecode\n" +
" -c enc use the supplied encoding 'enc' for input files\n" +
" -v verbose\n";
private static final String usage = "usage: java -cp luaj-jse.jar,bcel-5.2.jar luajc [options] fileordir [, fileordir ...]\n"
+ "Available options are:\n" + " - process stdin\n" + " -s src source directory\n"
+ " -d dir destination directory\n" + " -p pkg package prefix to apply to all classes\n"
+ " -m generate main(String[]) function for JSE\n" + " -r recursively compile all\n"
+ " -l load classes to verify generated bytecode\n"
+ " -c enc use the supplied encoding 'enc' for input files\n" + " -v verbose\n";
private static void usageExit() {
System.out.println(usage);
@@ -70,28 +66,28 @@ public class luajc {
private List files = new ArrayList();
private Globals globals;
public static void main( String[] args ) throws IOException {
new luajc( args );
public static void main(String[] args) throws IOException {
new luajc(args);
}
private luajc( String[] args ) throws IOException {
private luajc(String[] args) throws IOException {
// process args
List seeds = new ArrayList ();
List seeds = new ArrayList();
// get stateful args
for ( int i=0; i<args.length; i++ ) {
if ( ! args[i].startsWith("-") ) {
for (int i = 0; i < args.length; i++) {
if (!args[i].startsWith("-")) {
seeds.add(args[i]);
} else {
switch ( args[i].charAt(1) ) {
switch (args[i].charAt(1)) {
case 's':
if ( ++i >= args.length )
if (++i >= args.length)
usageExit();
srcdir = args[i];
break;
case 'd':
if ( ++i >= args.length )
if (++i >= args.length)
usageExit();
destdir = args[i];
break;
@@ -99,7 +95,7 @@ public class luajc {
loadclasses = true;
break;
case 'p':
if ( ++i >= args.length )
if (++i >= args.length)
usageExit();
pkgprefix = args[i];
break;
@@ -110,7 +106,7 @@ public class luajc {
recurse = true;
break;
case 'c':
if ( ++i >= args.length )
if (++i >= args.length)
usageExit();
encoding = args[i];
break;
@@ -125,58 +121,59 @@ public class luajc {
}
// echo version
if ( verbose ) {
if (verbose) {
System.out.println(version);
System.out.println("srcdir: "+srcdir);
System.out.println("destdir: "+destdir);
System.out.println("files: "+seeds);
System.out.println("recurse: "+recurse);
System.out.println("srcdir: " + srcdir);
System.out.println("destdir: " + destdir);
System.out.println("files: " + seeds);
System.out.println("recurse: " + recurse);
}
// need at least one seed
if ( seeds.size() <= 0 ) {
if (seeds.size() <= 0) {
System.err.println(usage);
System.exit(-1);
}
// collect up files to process
for ( int i=0; i<seeds.size(); i++ )
collectFiles( srcdir+"/"+seeds.get(i) );
for (int i = 0; i < seeds.size(); i++)
collectFiles(srcdir + "/" + seeds.get(i));
// check for at least one file
if ( files.size() <= 0 ) {
System.err.println("no files found in "+seeds);
if (files.size() <= 0) {
System.err.println("no files found in " + seeds);
System.exit(-1);
}
// process input files
globals = JsePlatform.standardGlobals();
for ( int i=0,n=files.size(); i<n; i++ )
processFile( (InputFile) files.get(i) );
for (int i = 0, n = files.size(); i < n; i++)
processFile((InputFile) files.get(i));
}
private void collectFiles(String path) {
File f = new File(path);
if ( f.isDirectory() && recurse )
scandir(f,pkgprefix);
else if ( f.isFile() ) {
if (f.isDirectory() && recurse)
scandir(f, pkgprefix);
else if (f.isFile()) {
File dir = f.getAbsoluteFile().getParentFile();
if ( dir != null )
scanfile( dir, f, pkgprefix );
if (dir != null)
scanfile(dir, f, pkgprefix);
}
}
private void scandir(File dir, String javapackage) {
File[] f = dir.listFiles();
for ( int i=0; i<f.length; i++ )
scanfile( dir, f[i], javapackage );
for (int i = 0; i < f.length; i++)
scanfile(dir, f[i], javapackage);
}
private void scanfile(File dir, File f, String javapackage) {
if ( f.exists() ) {
if ( f.isDirectory() && recurse )
scandir( f, (javapackage!=null? javapackage+"."+f.getName(): f.getName()) );
else if ( f.isFile() && f.getName().endsWith(".lua") )
files.add( new InputFile(dir,f,javapackage) );
if (f.exists()) {
if (f.isDirectory() && recurse)
scandir(f, (javapackage != null? javapackage + "." + f.getName(): f.getName()));
else if (f.isFile() && f.getName().endsWith(".lua"))
files.add(new InputFile(dir, f, javapackage));
}
}
@@ -189,7 +186,7 @@ public class luajc {
public Class findClass(String classname) throws ClassNotFoundException {
byte[] bytes = (byte[]) t.get(classname);
if ( bytes != null )
if (bytes != null)
return defineClass(classname, bytes, 0, bytes.length);
return super.findClass(classname);
}
@@ -204,66 +201,68 @@ public class luajc {
public InputFile(File dir, File f, String javapackage) {
this.infile = f;
String subdir = javapackage!=null? javapackage.replace('.', '/'): null;
String outdirpath = subdir!=null? destdir+"/"+subdir: destdir;
String subdir = javapackage != null? javapackage.replace('.', '/'): null;
String outdirpath = subdir != null? destdir + "/" + subdir: destdir;
this.javapackage = javapackage;
this.srcfilename = (subdir!=null? subdir+"/": "")+infile.getName();
this.luachunkname = (subdir!=null? subdir+"/": "")+infile.getName().substring( 0, infile.getName().lastIndexOf('.') );
this.srcfilename = (subdir != null? subdir + "/": "")+infile.getName();
this.luachunkname = (subdir != null? subdir + "/": "")
+infile.getName().substring(0, infile.getName().lastIndexOf('.'));
this.infile = f;
this.outdir = new File(outdirpath);
}
}
private void processFile( InputFile inf ) {
private void processFile(InputFile inf) {
inf.outdir.mkdirs();
try {
if ( verbose )
System.out.println("chunk="+inf.luachunkname+" srcfile="+inf.srcfilename);
if (verbose)
System.out.println("chunk=" + inf.luachunkname + " srcfile=" + inf.srcfilename);
// create the chunk
FileInputStream fis = new FileInputStream( inf.infile );
final Hashtable t = encoding != null?
LuaJC.instance.compileAll( new InputStreamReader(fis, encoding), inf.luachunkname, inf.srcfilename, globals, genmain):
LuaJC.instance.compileAll( fis, inf.luachunkname, inf.srcfilename, globals, genmain);
FileInputStream fis = new FileInputStream(inf.infile);
final Hashtable t = encoding != null
? LuaJC.instance.compileAll(new InputStreamReader(fis, encoding), inf.luachunkname, inf.srcfilename,
globals, genmain)
: LuaJC.instance.compileAll(fis, inf.luachunkname, inf.srcfilename, globals, genmain);
fis.close();
// write out the chunk
for ( Enumeration e = t.keys(); e.hasMoreElements(); ) {
for (Enumeration e = t.keys(); e.hasMoreElements();) {
String key = (String) e.nextElement();
byte[] bytes = (byte[]) t.get(key);
if ( key.indexOf('/')>=0 ) {
String d = (destdir!=null? destdir+"/": "")+key.substring(0,key.lastIndexOf('/'));
if (key.indexOf('/') >= 0) {
String d = (destdir != null? destdir + "/": "")+key.substring(0, key.lastIndexOf('/'));
new File(d).mkdirs();
}
String destpath = (destdir!=null? destdir+"/": "") + key + ".class";
if ( verbose )
System.out.println( " "+destpath +" ("+bytes.length+" bytes)");
FileOutputStream fos = new FileOutputStream( destpath );
fos.write( bytes );
String destpath = (destdir != null? destdir + "/": "") + key + ".class";
if (verbose)
System.out.println(" " + destpath + " (" + bytes.length + " bytes)");
FileOutputStream fos = new FileOutputStream(destpath);
fos.write(bytes);
fos.close();
}
// try to load the files
if ( loadclasses ) {
if (loadclasses) {
ClassLoader loader = new LocalClassLoader(t);
for ( Enumeration e = t.keys(); e.hasMoreElements(); ) {
for (Enumeration e = t.keys(); e.hasMoreElements();) {
String classname = (String) e.nextElement();
try {
Class c = loader.loadClass(classname);
Object o = c.newInstance();
if ( verbose )
System.out.println(" loaded "+classname+" as "+o );
} catch ( Exception ex ) {
if (verbose)
System.out.println(" loaded " + classname + " as " + o);
} catch (Exception ex) {
System.out.flush();
System.err.println(" failed to load "+classname+": "+ex );
System.err.println(" failed to load " + classname + ": " + ex);
System.err.flush();
}
}
}
} catch ( Exception e ) {
System.err.println(" failed to load "+inf.srcfilename+": "+e );
e.printStackTrace( System.err );
} catch (Exception e) {
System.err.println(" failed to load " + inf.srcfilename + ": " + e);
e.printStackTrace(System.err);
System.err.flush();
}
}

View File

@@ -30,7 +30,7 @@ public class Block extends Stat {
public NameScope scope;
public void add(Stat s) {
if ( s == null )
if (s == null)
return;
stats.add(s);
}

View File

@@ -28,7 +28,7 @@ public class Chunk extends SyntaxElement {
this.block = b;
}
public void accept( Visitor visitor ) {
visitor.visit( this );
public void accept(Visitor visitor) {
visitor.visit(this);
}
}

View File

@@ -24,8 +24,7 @@ package org.luaj.vm2.ast;
import org.luaj.vm2.Lua;
import org.luaj.vm2.LuaValue;
abstract
public class Exp extends SyntaxElement {
abstract public class Exp extends SyntaxElement {
abstract public void accept(Visitor visitor);
public static Exp constant(LuaValue value) {
@@ -33,7 +32,7 @@ public class Exp extends SyntaxElement {
}
public static Exp numberconstant(String token) {
return new Constant( LuaValue.valueOf(token).tonumber() );
return new Constant(LuaValue.valueOf(token).tonumber());
}
public static Exp varargs() {
@@ -45,56 +44,75 @@ public class Exp extends SyntaxElement {
}
public static Exp unaryexp(int op, Exp rhs) {
if ( rhs instanceof BinopExp ) {
if (rhs instanceof BinopExp) {
BinopExp b = (BinopExp) rhs;
if ( precedence(op) > precedence(b.op) )
return binaryexp( unaryexp(op, b.lhs), b.op, b.rhs );
if (precedence(op) > precedence(b.op))
return binaryexp(unaryexp(op, b.lhs), b.op, b.rhs);
}
return new UnopExp(op, rhs);
}
public static Exp binaryexp(Exp lhs, int op, Exp rhs) {
if ( lhs instanceof UnopExp ) {
if (lhs instanceof UnopExp) {
UnopExp u = (UnopExp) lhs;
if ( precedence(op) > precedence(u.op) )
return unaryexp( u.op, binaryexp( u.rhs, op, rhs ) );
if (precedence(op) > precedence(u.op))
return unaryexp(u.op, binaryexp(u.rhs, op, rhs));
}
// TODO: cumulate string concatenations together
// TODO: constant folding
if ( lhs instanceof BinopExp ) {
if (lhs instanceof BinopExp) {
BinopExp b = (BinopExp) lhs;
if ( (precedence(op) > precedence(b.op)) ||
((precedence(op) == precedence(b.op)) && isrightassoc(op)) )
return binaryexp( b.lhs, b.op, binaryexp( b.rhs, op, rhs ) );
if ((precedence(op) > precedence(b.op)) || ((precedence(op) == precedence(b.op)) && isrightassoc(op)))
return binaryexp(b.lhs, b.op, binaryexp(b.rhs, op, rhs));
}
if ( rhs instanceof BinopExp ) {
if (rhs instanceof BinopExp) {
BinopExp b = (BinopExp) rhs;
if ( (precedence(op) > precedence(b.op)) ||
((precedence(op) == precedence(b.op)) && ! isrightassoc(op)) )
return binaryexp( binaryexp( lhs, op, b.lhs ), b.op, b.rhs );
if ((precedence(op) > precedence(b.op)) || ((precedence(op) == precedence(b.op)) && !isrightassoc(op)))
return binaryexp(binaryexp(lhs, op, b.lhs), b.op, b.rhs);
}
return new BinopExp(lhs, op, rhs);
}
static boolean isrightassoc(int op) {
switch ( op ) {
switch (op) {
case Lua.OP_CONCAT:
case Lua.OP_POW: return true;
default: return false;
case Lua.OP_POW:
return true;
default:
return false;
}
}
static int precedence(int op) {
switch ( op ) {
case Lua.OP_OR: return 0;
case Lua.OP_AND: return 1;
case Lua.OP_LT: case Lua.OP_GT: case Lua.OP_LE: case Lua.OP_GE: case Lua.OP_NEQ: case Lua.OP_EQ: return 2;
case Lua.OP_CONCAT: return 3;
case Lua.OP_ADD: case Lua.OP_SUB: return 4;
case Lua.OP_MUL: case Lua.OP_DIV: case Lua.OP_MOD: return 5;
case Lua.OP_NOT: case Lua.OP_UNM: case Lua.OP_LEN: return 6;
case Lua.OP_POW: return 7;
default: throw new IllegalStateException("precedence of bad op "+op);
switch (op) {
case Lua.OP_OR:
return 0;
case Lua.OP_AND:
return 1;
case Lua.OP_LT:
case Lua.OP_GT:
case Lua.OP_LE:
case Lua.OP_GE:
case Lua.OP_NEQ:
case Lua.OP_EQ:
return 2;
case Lua.OP_CONCAT:
return 3;
case Lua.OP_ADD:
case Lua.OP_SUB:
return 4;
case Lua.OP_MUL:
case Lua.OP_DIV:
case Lua.OP_MOD:
return 5;
case Lua.OP_NOT:
case Lua.OP_UNM:
case Lua.OP_LEN:
return 6;
case Lua.OP_POW:
return 7;
default:
throw new IllegalStateException("precedence of bad op " + op);
}
}
@@ -148,6 +166,7 @@ public class Exp extends SyntaxElement {
public boolean isvarexp() {
return false;
}
public boolean isfunccall() {
return false;
}
@@ -157,18 +176,22 @@ public class Exp extends SyntaxElement {
public boolean isvarexp() {
return true;
}
public void markHasAssignment() {
}
}
public static class NameExp extends VarExp {
public final Name name;
public NameExp(String name) {
this.name = new Name(name);
}
public void markHasAssignment() {
name.variable.hasassignments = true;
}
public void accept(Visitor visitor) {
visitor.visit(this);
}
@@ -176,6 +199,7 @@ public class Exp extends SyntaxElement {
public static class ParensExp extends PrimaryExp {
public final Exp exp;
public ParensExp(Exp exp) {
this.exp = exp;
}
@@ -188,6 +212,7 @@ public class Exp extends SyntaxElement {
public static class FieldExp extends VarExp {
public final PrimaryExp lhs;
public final Name name;
public FieldExp(PrimaryExp lhs, String name) {
this.lhs = lhs;
this.name = new Name(name);
@@ -201,6 +226,7 @@ public class Exp extends SyntaxElement {
public static class IndexExp extends VarExp {
public final PrimaryExp lhs;
public final Exp exp;
public IndexExp(PrimaryExp lhs, Exp exp) {
this.lhs = lhs;
this.exp = exp;
@@ -252,6 +278,7 @@ public class Exp extends SyntaxElement {
public static class Constant extends Exp {
public final LuaValue value;
public Constant(LuaValue value) {
this.value = value;
}
@@ -275,6 +302,7 @@ public class Exp extends SyntaxElement {
public static class UnopExp extends Exp {
public final int op;
public final Exp rhs;
public UnopExp(int op, Exp rhs) {
this.op = op;
this.rhs = rhs;
@@ -286,8 +314,9 @@ public class Exp extends SyntaxElement {
}
public static class BinopExp extends Exp {
public final Exp lhs,rhs;
public final Exp lhs, rhs;
public final int op;
public BinopExp(Exp lhs, int op, Exp rhs) {
this.lhs = lhs;
this.op = op;
@@ -301,6 +330,7 @@ public class Exp extends SyntaxElement {
public static class AnonFuncDef extends Exp {
public final FuncBody body;
public AnonFuncDef(FuncBody funcbody) {
this.body = funcbody;
}

View File

@@ -51,12 +51,12 @@ public class FuncArgs extends SyntaxElement {
public FuncArgs(LuaString string) {
this.exps = new ArrayList<Exp>();
this.exps.add( Exp.constant(string) );
this.exps.add(Exp.constant(string));
}
public FuncArgs(TableConstructor table) {
this.exps = new ArrayList<Exp>();
this.exps.add( table );
this.exps.add(table);
}
public void accept(Visitor visitor) {

View File

@@ -27,9 +27,10 @@ public class FuncBody extends SyntaxElement {
public NameScope scope;
public FuncBody(ParList parlist, Block block) {
this.parlist = parlist!=null? parlist: ParList.EMPTY_PARLIST;
this.parlist = parlist != null? parlist: ParList.EMPTY_PARLIST;
this.block = block;
}
public void accept(Visitor visitor) {
visitor.visit(this);
}

View File

@@ -36,12 +36,12 @@ public class FuncName extends SyntaxElement {
// optional final method name: "e"
public String method;
public FuncName( String name ) {
public FuncName(String name) {
this.name = new Name(name);
}
public void adddot(String dot) {
if ( dots == null )
if (dots == null)
dots = new ArrayList<String>();
dots.add(dot);
}

View File

@@ -21,10 +21,10 @@
******************************************************************************/
package org.luaj.vm2.ast;
public class Name {
public final String name;
public Variable variable;
public Name(String name) {
this.name = name;
}

View File

@@ -14,9 +14,9 @@ import org.luaj.vm2.ast.Stat.LocalFuncDef;
import org.luaj.vm2.ast.Stat.NumericFor;
/**
* Visitor that resolves names to scopes.
* Each Name is resolved to a NamedVarible, possibly in a NameScope
* if it is a local, or in no named scope if it is a global.
* Visitor that resolves names to scopes. Each Name is resolved to a
* NamedVarible, possibly in a NameScope if it is a local, or in no named scope
* if it is a global.
*/
public class NameResolver extends Visitor {
@@ -25,6 +25,7 @@ public class NameResolver extends Visitor {
private void pushScope() {
scope = new NameScope(scope);
}
private void popScope() {
scope = scope.outerScope;
}
@@ -63,7 +64,7 @@ public class NameResolver extends Visitor {
public void visit(GenericFor stat) {
pushScope();
stat.scope = scope;
defineLocalVars( stat.names );
defineLocalVars(stat.names);
super.visit(stat);
popScope();
}
@@ -81,7 +82,7 @@ public class NameResolver extends Visitor {
public void visit(Assign stat) {
super.visit(stat);
for ( int i=0, n=stat.vars.size(); i<n; i++ ) {
for (int i = 0, n = stat.vars.size(); i < n; i++) {
VarExp v = (VarExp) stat.vars.get(i);
v.markHasAssignment();
}
@@ -89,28 +90,28 @@ public class NameResolver extends Visitor {
public void visit(LocalAssign stat) {
visitExps(stat.values);
defineLocalVars( stat.names );
defineLocalVars(stat.names);
int n = stat.names.size();
int m = stat.values!=null? stat.values.size(): 0;
boolean isvarlist = m>0 && m<n && ((Exp)stat.values.get(m-1)).isvarargexp();
for ( int i=0; i<n && i<(isvarlist?m-1:m); i++ )
if ( stat.values.get(i) instanceof Constant )
((Name)stat.names.get(i)).variable.initialValue = ((Constant) stat.values.get(i)).value;
if ( !isvarlist )
for ( int i=m; i<n; i++ )
((Name)stat.names.get(i)).variable.initialValue = LuaValue.NIL;
int m = stat.values != null? stat.values.size(): 0;
boolean isvarlist = m > 0 && m < n && ((Exp) stat.values.get(m-1)).isvarargexp();
for (int i = 0; i < n && i < (isvarlist? m-1: m); i++)
if (stat.values.get(i) instanceof Constant)
((Name) stat.names.get(i)).variable.initialValue = ((Constant) stat.values.get(i)).value;
if (!isvarlist)
for (int i = m; i < n; i++)
((Name) stat.names.get(i)).variable.initialValue = LuaValue.NIL;
}
public void visit(ParList pars) {
if ( pars.names != null )
if (pars.names != null)
defineLocalVars(pars.names);
if ( pars.isvararg )
if (pars.isvararg)
scope.define("arg");
super.visit(pars);
}
protected void defineLocalVars(List<Name> names) {
for ( int i=0, n=names.size(); i<n; i++ )
for (int i = 0, n = names.size(); i < n; i++)
defineLocalVar((Name) names.get(i));
}
@@ -120,7 +121,7 @@ public class NameResolver extends Visitor {
protected Variable resolveNameReference(Name name) {
Variable v = scope.find(name.name);
if ( v.isLocal() && scope.functionNestingCount != v.definingScope.functionNestingCount )
if (v.isLocal() && scope.functionNestingCount != v.definingScope.functionNestingCount)
v.isupvalue = true;
return v;
}

View File

@@ -26,22 +26,18 @@ import java.util.HashSet;
import java.util.Map;
import java.util.Set;
public class NameScope {
private static final Set<String> LUA_KEYWORDS = new HashSet<String>();
static {
String[] k = new String[] {
"and", "break", "do", "else", "elseif", "end",
"false", "for", "function", "if", "in", "local",
"nil", "not", "or", "repeat", "return",
"then", "true", "until", "while" };
for ( int i=0; i<k.length; i++ )
LUA_KEYWORDS.add( k[i] );
String[] k = new String[] { "and", "break", "do", "else", "elseif", "end", "false", "for", "function", "if",
"in", "local", "nil", "not", "or", "repeat", "return", "then", "true", "until", "while" };
for (int i = 0; i < k.length; i++)
LUA_KEYWORDS.add(k[i]);
}
public final Map<String,Variable> namedVariables = new HashMap<String,Variable>();
public final Map<String, Variable> namedVariables = new HashMap<String, Variable>();
public final NameScope outerScope;
@@ -53,25 +49,31 @@ public class NameScope {
this.functionNestingCount = 0;
}
/** Construct name scope within another scope*/
/** Construct name scope within another scope */
public NameScope(NameScope outerScope) {
this.outerScope = outerScope;
this.functionNestingCount = outerScope!=null? outerScope.functionNestingCount: 0;
this.functionNestingCount = outerScope != null? outerScope.functionNestingCount: 0;
}
/** Look up a name. If it is a global name, then throw IllegalArgumentException. */
public Variable find( String name ) throws IllegalArgumentException {
/**
* Look up a name. If it is a global name, then throw
* IllegalArgumentException.
*/
public Variable find(String name) throws IllegalArgumentException {
validateIsNotKeyword(name);
for ( NameScope n = this; n!=null; n=n.outerScope )
if ( n.namedVariables.containsKey(name) )
return (Variable)n.namedVariables.get(name);
for (NameScope n = this; n != null; n = n.outerScope)
if (n.namedVariables.containsKey(name))
return (Variable) n.namedVariables.get(name);
Variable value = new Variable(name);
this.namedVariables.put(name, value);
return value;
}
/** Define a name in this scope. If it is a global name, then throw IllegalArgumentException. */
public Variable define( String name ) throws IllegalStateException, IllegalArgumentException {
/**
* Define a name in this scope. If it is a global name, then throw
* IllegalArgumentException.
*/
public Variable define(String name) throws IllegalStateException, IllegalArgumentException {
validateIsNotKeyword(name);
Variable value = new Variable(name, this);
this.namedVariables.put(name, value);
@@ -79,7 +81,7 @@ public class NameScope {
}
private void validateIsNotKeyword(String name) {
if ( LUA_KEYWORDS.contains(name) )
throw new IllegalArgumentException("name is a keyword: '"+name+"'");
if (LUA_KEYWORDS.contains(name))
throw new IllegalArgumentException("name is a keyword: '" + name + "'");
}
}

View File

@@ -26,7 +26,7 @@ import java.util.List;
public class ParList extends SyntaxElement {
public static final List<Name> EMPTY_NAMELIST = new ArrayList<Name>();
public static final ParList EMPTY_PARLIST = new ParList(EMPTY_NAMELIST,false);
public static final ParList EMPTY_PARLIST = new ParList(EMPTY_NAMELIST, false);
public final List<Name> names;
public final boolean isvararg;

View File

@@ -25,8 +25,7 @@ import java.util.List;
import org.luaj.vm2.ast.Exp.VarExp;
abstract
public class Stat extends SyntaxElement {
abstract public class Stat extends SyntaxElement {
public abstract void accept(Visitor visitor);
public static Stat block(Block block) {
@@ -50,7 +49,7 @@ public class Stat extends SyntaxElement {
}
public static Stat assignment(List<VarExp> vars, List<Exp> exps) {
return new Assign(vars,exps);
return new Assign(vars, exps);
}
public static Stat functioncall(Exp.FuncCall funccall) {
@@ -66,7 +65,7 @@ public class Stat extends SyntaxElement {
}
public static Stat functiondef(FuncName funcname, FuncBody funcbody) {
return new FuncDef( funcname, funcbody );
return new FuncDef(funcname, funcbody);
}
public static Stat forgeneric(List<Name> names, List<Exp> exps, Block block) {
@@ -77,7 +76,8 @@ public class Stat extends SyntaxElement {
return new LocalAssign(names, values);
}
public static Stat ifthenelse(Exp ifexp, Block ifblock, List<Exp> elseifexps, List<Block> elseifblocks, Block elseblock) {
public static Stat ifthenelse(Exp ifexp, Block ifblock, List<Exp> elseifexps, List<Block> elseifblocks,
Block elseblock) {
return new IfThenElse(ifexp, ifblock, elseifexps, elseifblocks, elseblock);
}
@@ -91,9 +91,11 @@ public class Stat extends SyntaxElement {
public static class Goto extends Stat {
public final String name;
public Goto(String name) {
this.name = name;
}
public void accept(Visitor visitor) {
visitor.visit(this);
}
@@ -101,9 +103,11 @@ public class Stat extends SyntaxElement {
public static class Label extends Stat {
public final String name;
public Label(String name) {
this.name = name;
}
public void accept(Visitor visitor) {
visitor.visit(this);
}
@@ -127,46 +131,51 @@ public class Stat extends SyntaxElement {
public static class WhileDo extends Stat {
public final Exp exp;
public final Block block;
public WhileDo( Exp exp, Block block ) {
public WhileDo(Exp exp, Block block) {
this.exp = exp;
this.block = block;
}
public void accept(Visitor visitor) {
visitor.visit( this );
visitor.visit(this);
}
}
public static class RepeatUntil extends Stat {
public final Block block;
public final Exp exp;
public RepeatUntil( Block block, Exp exp ) {
public RepeatUntil(Block block, Exp exp) {
this.block = block;
this.exp = exp;
}
public void accept(Visitor visitor) {
visitor.visit( this );
visitor.visit(this);
}
}
public static class Break extends Stat {
public void accept(Visitor visitor) {
visitor.visit( this );
visitor.visit(this);
}
}
public static class Return extends Stat {
public final List<Exp> values;
public Return(List<Exp> values) {
this.values = values;
}
public void accept(Visitor visitor) {
visitor.visit( this );
visitor.visit(this);
}
public int nreturns() {
int n = values!=null? values.size(): 0;
if ( n>0 && ((Exp)values.get(n-1)).isvarargexp() )
int n = values != null? values.size(): 0;
if (n > 0 && ((Exp) values.get(n-1)).isvarargexp())
n = -1;
return n;
}
@@ -174,38 +183,41 @@ public class Stat extends SyntaxElement {
public static class FuncCallStat extends Stat {
public final Exp.FuncCall funccall;
public FuncCallStat(Exp.FuncCall funccall) {
this.funccall = funccall;
}
public void accept(Visitor visitor) {
visitor.visit( this );
visitor.visit(this);
}
}
public static class LocalFuncDef extends Stat {
public final Name name;
public final FuncBody body;
public LocalFuncDef(String name, FuncBody body) {
this.name = new Name(name);
this.body = body;
}
public void accept(Visitor visitor) {
visitor.visit( this );
visitor.visit(this);
}
}
public static class FuncDef extends Stat {
public final FuncName name;
public final FuncBody body;
public FuncDef(FuncName name, FuncBody body) {
this.name = name;
this.body = body;
}
public void accept(Visitor visitor) {
visitor.visit( this );
visitor.visit(this);
}
}
@@ -214,6 +226,7 @@ public class Stat extends SyntaxElement {
public List<Exp> exps;
public Block block;
public NameScope scope;
public GenericFor(List<Name> names, List<Exp> exps, Block block) {
this.names = names;
this.exps = exps;
@@ -221,15 +234,16 @@ public class Stat extends SyntaxElement {
}
public void accept(Visitor visitor) {
visitor.visit( this );
visitor.visit(this);
}
}
public static class NumericFor extends Stat {
public final Name name;
public final Exp initial,limit,step;
public final Exp initial, limit, step;
public final Block block;
public NameScope scope;
public NumericFor(String name, Exp initial, Exp limit, Exp step, Block block) {
this.name = new Name(name);
this.initial = initial;
@@ -239,20 +253,21 @@ public class Stat extends SyntaxElement {
}
public void accept(Visitor visitor) {
visitor.visit( this );
visitor.visit(this);
}
}
public static class LocalAssign extends Stat {
public final List<Name> names;
public final List<Exp> values;
public LocalAssign(List<Name> names, List<Exp> values) {
this.names = names;
this.values = values;
}
public void accept(Visitor visitor) {
visitor.visit( this );
visitor.visit(this);
}
}
@@ -262,8 +277,8 @@ public class Stat extends SyntaxElement {
public final List<Exp> elseifexps;
public final List<Block> elseifblocks;
public final Block elseblock;
public IfThenElse(Exp ifexp, Block ifblock, List<Exp> elseifexps,
List<Block> elseifblocks, Block elseblock) {
public IfThenElse(Exp ifexp, Block ifblock, List<Exp> elseifexps, List<Block> elseifblocks, Block elseblock) {
this.ifexp = ifexp;
this.ifblock = ifblock;
this.elseifexps = elseifexps;
@@ -272,7 +287,7 @@ public class Stat extends SyntaxElement {
}
public void accept(Visitor visitor) {
visitor.visit( this );
visitor.visit(this);
}
}
}

View File

@@ -44,12 +44,12 @@ public class Str {
public static LuaString longString(String image) {
int i = image.indexOf('[', image.indexOf('[')+1)+1;
String s = image.substring(i,image.length()-i);
String s = image.substring(i, image.length()-i);
byte[] b = iso88591bytes(s);
return LuaString.valueUsing(b);
}
public static byte[] iso88591bytes( String s ) {
public static byte[] iso88591bytes(String s) {
try {
return s.getBytes("ISO8859-1");
} catch (UnsupportedEncodingException e) {
@@ -61,31 +61,61 @@ public class Str {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
char[] c = s.toCharArray();
int n = c.length;
for ( int i=0; i<n; i++ ) {
if ( c[i] == '\\' && i<n ) {
switch ( c[++i] ) {
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
int d=(int) (c[i++]-'0');
for ( int j=0; i<n && j<2 && c[i]>='0' && c[i]<='9'; i++, j++ )
d = d * 10 + (int) (c[i]-'0');
baos.write( (byte) d );
for (int i = 0; i < n; i++) {
if (c[i] == '\\' && i < n) {
switch (c[++i]) {
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
int d = (int) (c[i++]-'0');
for (int j = 0; i < n && j < 2 && c[i] >= '0' && c[i] <= '9'; i++, j++)
d = d*10+(int) (c[i]-'0');
baos.write((byte) d);
--i;
continue;
case 'a': baos.write( (byte) 7 ); continue;
case 'b': baos.write( (byte) '\b' ); continue;
case 'f': baos.write( (byte) '\f' ); continue;
case 'n': baos.write( (byte) '\n' ); continue;
case 'r': baos.write( (byte) '\r' ); continue;
case 't': baos.write( (byte) '\t' ); continue;
case 'v': baos.write( (byte) 11 ); continue;
case '"': baos.write( (byte) '"' ); continue;
case '\'': baos.write( (byte) '\'' ); continue;
case '\\': baos.write( (byte) '\\' ); continue;
default: baos.write( (byte) c[i] ); break;
case 'a':
baos.write((byte) 7);
continue;
case 'b':
baos.write((byte) '\b');
continue;
case 'f':
baos.write((byte) '\f');
continue;
case 'n':
baos.write((byte) '\n');
continue;
case 'r':
baos.write((byte) '\r');
continue;
case 't':
baos.write((byte) '\t');
continue;
case 'v':
baos.write((byte) 11);
continue;
case '"':
baos.write((byte) '"');
continue;
case '\'':
baos.write((byte) '\'');
continue;
case '\\':
baos.write((byte) '\\');
continue;
default:
baos.write((byte) c[i]);
break;
}
} else {
baos.write( (byte) c[i] );
baos.write((byte) c[i]);
}
}
return baos.toByteArray();

View File

@@ -21,7 +21,8 @@
******************************************************************************/
package org.luaj.vm2.ast;
/** Base class for syntax elements of the parse tree that appear in source files.
/**
* Base class for syntax elements of the parse tree that appear in source files.
* The LuaParser class will fill these values out during parsing for use in
* syntax highlighting, for example.
*/

View File

@@ -23,8 +23,9 @@ package org.luaj.vm2.ast;
import org.luaj.vm2.LuaValue;
/** Variable is created lua name scopes, and is a named, lua variable that
* either refers to a lua local, global, or upvalue storage location.
/**
* Variable is created lua name scopes, and is a named, lua variable that either
* refers to a lua local, global, or upvalue storage location.
*/
public class Variable {
@@ -40,7 +41,10 @@ public class Variable {
/** true if there are assignments made to this variable */
public boolean hasassignments;
/** When hasassignments == false, and the initial value is a constant, this is the initial value */
/**
* When hasassignments == false, and the initial value is a constant, this
* is the initial value
*/
public LuaValue initialValue;
/** Global is named variable not associated with a defining scope */
@@ -48,15 +52,14 @@ public class Variable {
this.name = name;
this.definingScope = null;
}
public Variable(String name, NameScope definingScope) {
/** Local variable is defined in a particular scope. */
this.name = name;
this.definingScope = definingScope;
}
public boolean isLocal() {
return this.definingScope != null;
}
public boolean isConstant() {
return ! hasassignments && initialValue != null;
}
public boolean isLocal() { return this.definingScope != null; }
public boolean isConstant() { return !hasassignments && initialValue != null; }
}

View File

@@ -29,152 +29,189 @@ abstract public class Visitor {
public void visit(Chunk chunk) {
chunk.block.accept(this);
};
public void visit(Block block) {
visit(block.scope);
if ( block.stats != null )
for ( int i=0, n=block.stats.size(); i<n; i++ )
((Stat)block.stats.get(i)).accept(this);
if (block.stats != null)
for (int i = 0, n = block.stats.size(); i < n; i++)
((Stat) block.stats.get(i)).accept(this);
};
public void visit(Stat.Assign stat) {
visitVars(stat.vars);
visitExps(stat.exps);
}
public void visit(Stat.Break breakstat) {
}
public void visit(Stat.FuncCallStat stat) {
stat.funccall.accept(this);
}
public void visit(Stat.FuncDef stat) {
stat.body.accept(this);
}
public void visit(Stat.GenericFor stat) {
visit(stat.scope);
visitNames(stat.names);
visitExps(stat.exps);
stat.block.accept(this);
}
public void visit(Stat.IfThenElse stat) {
stat.ifexp.accept(this);
stat.ifblock.accept(this);
if ( stat.elseifblocks != null )
for ( int i=0, n=stat.elseifblocks.size(); i<n; i++ ) {
((Exp)stat.elseifexps.get(i)).accept(this);
((Block)stat.elseifblocks.get(i)).accept(this);
if (stat.elseifblocks != null)
for (int i = 0, n = stat.elseifblocks.size(); i < n; i++) {
((Exp) stat.elseifexps.get(i)).accept(this);
((Block) stat.elseifblocks.get(i)).accept(this);
}
if ( stat.elseblock != null )
visit( stat.elseblock );
if (stat.elseblock != null)
visit(stat.elseblock);
}
public void visit(Stat.LocalAssign stat) {
visitNames(stat.names);
visitExps(stat.values);
}
public void visit(Stat.LocalFuncDef stat) {
visit(stat.name);
stat.body.accept(this);
}
public void visit(Stat.NumericFor stat) {
visit(stat.scope);
visit(stat.name);
stat.initial.accept(this);
stat.limit.accept(this);
if ( stat.step != null )
if (stat.step != null)
stat.step.accept(this);
stat.block.accept(this);
}
public void visit(Stat.RepeatUntil stat) {
stat.block.accept(this);
stat.exp.accept(this);
}
public void visit(Stat.Return stat) {
visitExps(stat.values);
}
public void visit(Stat.WhileDo stat) {
stat.exp.accept(this);
stat.block.accept(this);
}
public void visit(FuncBody body) {
visit(body.scope);
body.parlist.accept(this);
body.block.accept(this);
}
public void visit(FuncArgs args) {
visitExps(args.exps);
}
public void visit(TableField field) {
if ( field.name != null )
visit( field.name );
if ( field.index != null )
if (field.name != null)
visit(field.name);
if (field.index != null)
field.index.accept(this);
field.rhs.accept(this);
}
public void visit(Exp.AnonFuncDef exp) {
exp.body.accept(this);
}
public void visit(Exp.BinopExp exp) {
exp.lhs.accept(this);
exp.rhs.accept(this);
}
public void visit(Exp.Constant exp) {
}
public void visit(Exp.FieldExp exp) {
exp.lhs.accept(this);
visit(exp.name);
}
public void visit(Exp.FuncCall exp) {
exp.lhs.accept(this);
exp.args.accept(this);
}
public void visit(Exp.IndexExp exp) {
exp.lhs.accept(this);
exp.exp.accept(this);
}
public void visit(Exp.MethodCall exp) {
exp.lhs.accept(this);
visit(exp.name);
exp.args.accept(this);
}
public void visit(Exp.NameExp exp) {
visit(exp.name);
}
public void visit(Exp.ParensExp exp) {
exp.exp.accept(this);
}
public void visit(Exp.UnopExp exp) {
exp.rhs.accept(this);
}
public void visit(Exp.VarargsExp exp) {
}
public void visit(ParList pars) {
visitNames(pars.names);
}
public void visit(TableConstructor table) {
if( table.fields != null)
for ( int i=0, n=table.fields.size(); i<n; i++ )
((TableField)table.fields.get(i)).accept(this);
if (table.fields != null)
for (int i = 0, n = table.fields.size(); i < n; i++)
((TableField) table.fields.get(i)).accept(this);
}
public void visitVars(List<VarExp> vars) {
if ( vars != null )
for ( int i=0, n=vars.size(); i<n; i++ )
((Exp.VarExp)vars.get(i)).accept(this);
if (vars != null)
for (int i = 0, n = vars.size(); i < n; i++)
((Exp.VarExp) vars.get(i)).accept(this);
}
public void visitExps(List<Exp> exps) {
if ( exps != null )
for ( int i=0, n=exps.size(); i<n; i++ )
((Exp)exps.get(i)).accept(this);
if (exps != null)
for (int i = 0, n = exps.size(); i < n; i++)
((Exp) exps.get(i)).accept(this);
}
public void visitNames(List<Name> names) {
if ( names != null )
for ( int i=0, n=names.size(); i<n; i++ )
if (names != null)
for (int i = 0, n = names.size(); i < n; i++)
visit((Name) names.get(i));
}
public void visit(Name name) {
}
public void visit(String name) {
}
public void visit(NameScope scope) {
}
public void visit(Stat.Goto gotostat) {
}
public void visit(Stat.Label label) {
}
}

View File

@@ -37,8 +37,8 @@ import org.luaj.vm2.LuaValue;
* This class is primarily used by the {@link org.luaj.vm2.lib.jse.LuajavaLib},
* but can also be used directly when working with Java/lua bindings.
* <p>
* To coerce scalar types, the various, generally the {@code valueOf(type)} methods
* on {@link LuaValue} may be used:
* To coerce scalar types, the various, generally the {@code valueOf(type)}
* methods on {@link LuaValue} may be used:
* <ul>
* <li>{@link LuaValue#valueOf(boolean)}</li>
* <li>{@link LuaValue#valueOf(byte[])}</li>
@@ -47,17 +47,17 @@ import org.luaj.vm2.LuaValue;
* <li>{@link LuaValue#valueOf(String)}</li>
* </ul>
* <p>
* To coerce arrays of objects and lists, the {@code listOf(..)} and {@code tableOf(...)} methods
* on {@link LuaValue} may be used:
* To coerce arrays of objects and lists, the {@code listOf(..)} and
* {@code tableOf(...)} methods on {@link LuaValue} may be used:
* <ul>
* <li>{@link LuaValue#listOf(LuaValue[])}</li>
* <li>{@link LuaValue#listOf(LuaValue[], org.luaj.vm2.Varargs)}</li>
* <li>{@link LuaValue#tableOf(LuaValue[])}</li>
* <li>{@link LuaValue#tableOf(LuaValue[], LuaValue[], org.luaj.vm2.Varargs)}</li>
* </ul>
* The method {@link CoerceJavaToLua#coerce(Object)} looks as the type and dimesioning
* of the argument and tries to guess the best fit for corrsponding lua scalar,
* table, or table of tables.
* The method {@link CoerceJavaToLua#coerce(Object)} looks as the type and
* dimesioning of the argument and tries to guess the best fit for corrsponding
* lua scalar, table, or table of tables.
*
* @see CoerceJavaToLua#coerce(Object)
* @see org.luaj.vm2.lib.jse.LuajavaLib
@@ -65,51 +65,51 @@ import org.luaj.vm2.LuaValue;
public class CoerceJavaToLua {
static interface Coercion {
public LuaValue coerce( Object javaValue );
public LuaValue coerce(Object javaValue);
};
private static final class BoolCoercion implements Coercion {
public LuaValue coerce( Object javaValue ) {
public LuaValue coerce(Object javaValue) {
Boolean b = (Boolean) javaValue;
return b.booleanValue()? LuaValue.TRUE: LuaValue.FALSE;
}
}
private static final class IntCoercion implements Coercion {
public LuaValue coerce( Object javaValue ) {
public LuaValue coerce(Object javaValue) {
Number n = (Number) javaValue;
return LuaInteger.valueOf( n.intValue() );
return LuaInteger.valueOf(n.intValue());
}
}
private static final class CharCoercion implements Coercion {
public LuaValue coerce( Object javaValue ) {
public LuaValue coerce(Object javaValue) {
Character c = (Character) javaValue;
return LuaInteger.valueOf( c.charValue() );
return LuaInteger.valueOf(c.charValue());
}
}
private static final class DoubleCoercion implements Coercion {
public LuaValue coerce( Object javaValue ) {
public LuaValue coerce(Object javaValue) {
Number n = (Number) javaValue;
return LuaDouble.valueOf( n.doubleValue() );
return LuaDouble.valueOf(n.doubleValue());
}
}
private static final class StringCoercion implements Coercion {
public LuaValue coerce( Object javaValue ) {
return LuaString.valueOf( javaValue.toString() );
public LuaValue coerce(Object javaValue) {
return LuaString.valueOf(javaValue.toString());
}
}
private static final class BytesCoercion implements Coercion {
public LuaValue coerce( Object javaValue ) {
public LuaValue coerce(Object javaValue) {
return LuaValue.valueOf((byte[]) javaValue);
}
}
private static final class ClassCoercion implements Coercion {
public LuaValue coerce( Object javaValue ) {
public LuaValue coerce(Object javaValue) {
return JavaClass.forClass((Class) javaValue);
}
}
@@ -128,44 +128,44 @@ public class CoerceJavaToLua {
}
private static final class LuaCoercion implements Coercion {
public LuaValue coerce( Object javaValue ) {
public LuaValue coerce(Object javaValue) {
return (LuaValue) javaValue;
}
}
static final Map COERCIONS = Collections.synchronizedMap(new HashMap());
static {
Coercion boolCoercion = new BoolCoercion() ;
Coercion intCoercion = new IntCoercion() ;
Coercion charCoercion = new CharCoercion() ;
Coercion doubleCoercion = new DoubleCoercion() ;
Coercion stringCoercion = new StringCoercion() ;
Coercion bytesCoercion = new BytesCoercion() ;
Coercion classCoercion = new ClassCoercion() ;
COERCIONS.put( Boolean.class, boolCoercion );
COERCIONS.put( Byte.class, intCoercion );
COERCIONS.put( Character.class, charCoercion );
COERCIONS.put( Short.class, intCoercion );
COERCIONS.put( Integer.class, intCoercion );
COERCIONS.put( Long.class, doubleCoercion );
COERCIONS.put( Float.class, doubleCoercion );
COERCIONS.put( Double.class, doubleCoercion );
COERCIONS.put( String.class, stringCoercion );
COERCIONS.put( byte[].class, bytesCoercion );
COERCIONS.put( Class.class, classCoercion );
Coercion boolCoercion = new BoolCoercion();
Coercion intCoercion = new IntCoercion();
Coercion charCoercion = new CharCoercion();
Coercion doubleCoercion = new DoubleCoercion();
Coercion stringCoercion = new StringCoercion();
Coercion bytesCoercion = new BytesCoercion();
Coercion classCoercion = new ClassCoercion();
COERCIONS.put(Boolean.class, boolCoercion);
COERCIONS.put(Byte.class, intCoercion);
COERCIONS.put(Character.class, charCoercion);
COERCIONS.put(Short.class, intCoercion);
COERCIONS.put(Integer.class, intCoercion);
COERCIONS.put(Long.class, doubleCoercion);
COERCIONS.put(Float.class, doubleCoercion);
COERCIONS.put(Double.class, doubleCoercion);
COERCIONS.put(String.class, stringCoercion);
COERCIONS.put(byte[].class, bytesCoercion);
COERCIONS.put(Class.class, classCoercion);
}
/**
* Coerse a Java object to a corresponding lua value.
* <p>
* Integral types {@code boolean}, {@code byte}, {@code char}, and {@code int}
* will become {@link LuaInteger};
* {@code long}, {@code float}, and {@code double} will become {@link LuaDouble};
* {@code String} and {@code byte[]} will become {@link LuaString};
* types inheriting from {@link LuaValue} will be returned without coercion;
* other types will become {@link LuaUserdata}.
* Integral types {@code boolean}, {@code byte}, {@code char}, and
* {@code int} will become {@link LuaInteger}; {@code long}, {@code float},
* and {@code double} will become {@link LuaDouble}; {@code String} and
* {@code byte[]} will become {@link LuaString}; types inheriting from
* {@link LuaValue} will be returned without coercion; other types will
* become {@link LuaUserdata}.
*
* @param o Java object needing conversion
* @return {@link LuaValue} corresponding to the supplied Java value.
* @see LuaValue
@@ -175,15 +175,13 @@ public class CoerceJavaToLua {
* @see LuaUserdata
*/
public static LuaValue coerce(Object o) {
if ( o == null )
if (o == null)
return LuaValue.NIL;
Class clazz = o.getClass();
Coercion c = (Coercion) COERCIONS.get( clazz );
if ( c == null ) {
c = clazz.isArray()? arrayCoercion:
o instanceof LuaValue ? luaCoercion:
instanceCoercion;
COERCIONS.put( clazz, c );
Coercion c = (Coercion) COERCIONS.get(clazz);
if (c == null) {
c = clazz.isArray()? arrayCoercion: o instanceof LuaValue? luaCoercion: instanceCoercion;
COERCIONS.put(clazz, c);
}
return c.coerce(o);
}
@@ -192,5 +190,5 @@ public class CoerceJavaToLua {
static final Coercion arrayCoercion = new ArrayCoercion();
static final Coercion luaCoercion = new LuaCoercion() ;
static final Coercion luaCoercion = new LuaCoercion();
}

View File

@@ -36,8 +36,8 @@ import org.luaj.vm2.LuaValue;
* This class is primarily used by the {@link org.luaj.vm2.lib.jse.LuajavaLib},
* but can also be used directly when working with Java/lua bindings.
* <p>
* To coerce to specific Java values, generally the {@code toType()} methods
* on {@link LuaValue} may be used:
* To coerce to specific Java values, generally the {@code toType()} methods on
* {@link LuaValue} may be used:
* <ul>
* <li>{@link LuaValue#toboolean()}</li>
* <li>{@link LuaValue#tobyte()}</li>
@@ -51,8 +51,8 @@ import org.luaj.vm2.LuaValue;
* <li>{@link LuaValue#touserdata(Class)}</li>
* </ul>
* <p>
* For data in lua tables, the various methods on {@link LuaTable} can be used directly
* to convert data to something more useful.
* For data in lua tables, the various methods on {@link LuaTable} can be used
* directly to convert data to something more useful.
*
* @see org.luaj.vm2.lib.jse.LuajavaLib
* @see CoerceJavaToLua
@@ -64,15 +64,18 @@ public class CoerceLuaToJava {
static int SCORE_UNCOERCIBLE = 0x10000;
static interface Coercion {
public int score( LuaValue value );
public Object coerce( LuaValue value );
public int score(LuaValue value);
public Object coerce(LuaValue value);
};
/**
* Coerce a LuaValue value to a specified java class
*
* @param value LuaValue to coerce
* @param clazz Class to coerce into
* @return Object of type clazz (or a subclass) with the corresponding value.
* @return Object of type clazz (or a subclass) with the corresponding
* value.
*/
public static Object coerce(LuaValue value, Class clazz) {
return getCoercion(clazz).coerce(value);
@@ -84,8 +87,9 @@ public class CoerceLuaToJava {
public String toString() {
return "BoolCoercion()";
}
public int score( LuaValue value ) {
switch ( value.type() ) {
public int score(LuaValue value) {
switch (value.type()) {
case LuaValue.TBOOLEAN:
return 0;
}
@@ -107,65 +111,75 @@ public class CoerceLuaToJava {
static final int TARGET_TYPE_DOUBLE = 6;
static final String[] TYPE_NAMES = { "byte", "char", "short", "int", "long", "float", "double" };
final int targetType;
public String toString() {
return "NumericCoercion("+TYPE_NAMES[targetType]+")";
return "NumericCoercion(" + TYPE_NAMES[targetType] + ")";
}
NumericCoercion(int targetType) {
this.targetType = targetType;
}
public int score( LuaValue value ) {
public int score(LuaValue value) {
int fromStringPenalty = 0;
if ( value.type() == LuaValue.TSTRING ) {
if (value.type() == LuaValue.TSTRING) {
value = value.tonumber();
if ( value.isnil() ) {
if (value.isnil()) {
return SCORE_UNCOERCIBLE;
}
fromStringPenalty = 4;
}
if ( value.isint() ) {
switch ( targetType ) {
if (value.isint()) {
switch (targetType) {
case TARGET_TYPE_BYTE: {
int i = value.toint();
return fromStringPenalty + ((i==(byte)i)? 0: SCORE_WRONG_TYPE);
return fromStringPenalty+((i == (byte) i)? 0: SCORE_WRONG_TYPE);
}
case TARGET_TYPE_CHAR: {
int i = value.toint();
return fromStringPenalty + ((i==(byte)i)? 1: (i==(char)i)? 0: SCORE_WRONG_TYPE);
return fromStringPenalty+((i == (byte) i)? 1: (i == (char) i)? 0: SCORE_WRONG_TYPE);
}
case TARGET_TYPE_SHORT: {
int i = value.toint();
return fromStringPenalty +
((i==(byte)i)? 1: (i==(short)i)? 0: SCORE_WRONG_TYPE);
return fromStringPenalty+((i == (byte) i)? 1: (i == (short) i)? 0: SCORE_WRONG_TYPE);
}
case TARGET_TYPE_INT: {
int i = value.toint();
return fromStringPenalty +
((i==(byte)i)? 2: ((i==(char)i) || (i==(short)i))? 1: 0);
return fromStringPenalty+((i == (byte) i)? 2: ((i == (char) i) || (i == (short) i))? 1: 0);
}
case TARGET_TYPE_FLOAT: return fromStringPenalty + 1;
case TARGET_TYPE_LONG: return fromStringPenalty + 1;
case TARGET_TYPE_DOUBLE: return fromStringPenalty + 2;
default: return SCORE_WRONG_TYPE;
case TARGET_TYPE_FLOAT:
return fromStringPenalty+1;
case TARGET_TYPE_LONG:
return fromStringPenalty+1;
case TARGET_TYPE_DOUBLE:
return fromStringPenalty+2;
default:
return SCORE_WRONG_TYPE;
}
} else if ( value.isnumber() ) {
switch ( targetType ) {
case TARGET_TYPE_BYTE: return SCORE_WRONG_TYPE;
case TARGET_TYPE_CHAR: return SCORE_WRONG_TYPE;
case TARGET_TYPE_SHORT: return SCORE_WRONG_TYPE;
case TARGET_TYPE_INT: return SCORE_WRONG_TYPE;
} else if (value.isnumber()) {
switch (targetType) {
case TARGET_TYPE_BYTE:
return SCORE_WRONG_TYPE;
case TARGET_TYPE_CHAR:
return SCORE_WRONG_TYPE;
case TARGET_TYPE_SHORT:
return SCORE_WRONG_TYPE;
case TARGET_TYPE_INT:
return SCORE_WRONG_TYPE;
case TARGET_TYPE_LONG: {
double d = value.todouble();
return fromStringPenalty + ((d==(long)d)? 0: SCORE_WRONG_TYPE);
return fromStringPenalty+((d == (long) d)? 0: SCORE_WRONG_TYPE);
}
case TARGET_TYPE_FLOAT: {
double d = value.todouble();
return fromStringPenalty + ((d==(float)d)? 0: SCORE_WRONG_TYPE);
return fromStringPenalty+((d == (float) d)? 0: SCORE_WRONG_TYPE);
}
case TARGET_TYPE_DOUBLE: {
double d = value.todouble();
return fromStringPenalty + (((d==(long)d) || (d==(float)d))? 1: 0);
return fromStringPenalty+(((d == (long) d) || (d == (float) d))? 1: 0);
}
default: return SCORE_WRONG_TYPE;
default:
return SCORE_WRONG_TYPE;
}
} else {
return SCORE_UNCOERCIBLE;
@@ -173,15 +187,23 @@ public class CoerceLuaToJava {
}
public Object coerce(LuaValue value) {
switch ( targetType ) {
case TARGET_TYPE_BYTE: return new Byte( (byte) value.toint() );
case TARGET_TYPE_CHAR: return new Character( (char) value.toint() );
case TARGET_TYPE_SHORT: return new Short( (short) value.toint() );
case TARGET_TYPE_INT: return new Integer( (int) value.toint() );
case TARGET_TYPE_LONG: return new Long( (long) value.todouble() );
case TARGET_TYPE_FLOAT: return new Float( (float) value.todouble() );
case TARGET_TYPE_DOUBLE: return new Double( (double) value.todouble() );
default: return null;
switch (targetType) {
case TARGET_TYPE_BYTE:
return new Byte((byte) value.toint());
case TARGET_TYPE_CHAR:
return new Character((char) value.toint());
case TARGET_TYPE_SHORT:
return new Short((short) value.toint());
case TARGET_TYPE_INT:
return new Integer((int) value.toint());
case TARGET_TYPE_LONG:
return new Long((long) value.todouble());
case TARGET_TYPE_FLOAT:
return new Float((float) value.todouble());
case TARGET_TYPE_DOUBLE:
return new Double((double) value.todouble());
default:
return null;
}
}
}
@@ -190,28 +212,31 @@ public class CoerceLuaToJava {
public static final int TARGET_TYPE_STRING = 0;
public static final int TARGET_TYPE_BYTES = 1;
final int targetType;
public StringCoercion(int targetType) {
this.targetType = targetType;
}
public String toString() {
return "StringCoercion("+(targetType==TARGET_TYPE_STRING? "String": "byte[]")+")";
return "StringCoercion(" + (targetType == TARGET_TYPE_STRING? "String": "byte[]") + ")";
}
public int score(LuaValue value) {
switch ( value.type() ) {
switch (value.type()) {
case LuaValue.TSTRING:
return value.checkstring().isValidUtf8()?
(targetType==TARGET_TYPE_STRING? 0: 1):
(targetType==TARGET_TYPE_BYTES? 0: SCORE_WRONG_TYPE);
return value.checkstring().isValidUtf8()? (targetType == TARGET_TYPE_STRING? 0: 1)
: (targetType == TARGET_TYPE_BYTES? 0: SCORE_WRONG_TYPE);
case LuaValue.TNIL:
return SCORE_NULL_VALUE;
default:
return targetType == TARGET_TYPE_STRING? SCORE_WRONG_TYPE: SCORE_UNCOERCIBLE;
}
}
public Object coerce(LuaValue value) {
if ( value.isnil() )
if (value.isnil())
return null;
if ( targetType == TARGET_TYPE_STRING )
if (targetType == TARGET_TYPE_STRING)
return value.tojstring();
LuaString s = value.checkstring();
byte[] b = new byte[s.m_length];
@@ -223,31 +248,35 @@ public class CoerceLuaToJava {
static final class ArrayCoercion implements Coercion {
final Class componentType;
final Coercion componentCoercion;
public ArrayCoercion(Class componentType) {
this.componentType = componentType;
this.componentCoercion = getCoercion(componentType);
}
public String toString() {
return "ArrayCoercion("+componentType.getName()+")";
return "ArrayCoercion(" + componentType.getName() + ")";
}
public int score(LuaValue value) {
switch ( value.type() ) {
switch (value.type()) {
case LuaValue.TTABLE:
return value.length()==0? 0: componentCoercion.score( value.get(1) );
return value.length() == 0? 0: componentCoercion.score(value.get(1));
case LuaValue.TUSERDATA:
return inheritanceLevels( componentType, value.touserdata().getClass().getComponentType() );
return inheritanceLevels(componentType, value.touserdata().getClass().getComponentType());
case LuaValue.TNIL:
return SCORE_NULL_VALUE;
default:
return SCORE_UNCOERCIBLE;
}
}
public Object coerce(LuaValue value) {
switch ( value.type() ) {
switch (value.type()) {
case LuaValue.TTABLE: {
int n = value.length();
Object a = Array.newInstance(componentType, n);
for ( int i=0; i<n; i++ )
for (int i = 0; i < n; i++)
Array.set(a, i, componentCoercion.coerce(value.get(i+1)));
return a;
}
@@ -264,51 +293,56 @@ public class CoerceLuaToJava {
/**
* Determine levels of inheritance between a base class and a subclass
*
* @param baseclass base class to look for
* @param subclass class from which to start looking
* @return number of inheritance levels between subclass and baseclass,
* or SCORE_UNCOERCIBLE if not a subclass
* @return number of inheritance levels between subclass and baseclass, or
* SCORE_UNCOERCIBLE if not a subclass
*/
static final int inheritanceLevels( Class baseclass, Class subclass ) {
if ( subclass == null )
static final int inheritanceLevels(Class baseclass, Class subclass) {
if (subclass == null)
return SCORE_UNCOERCIBLE;
if ( baseclass == subclass )
if (baseclass == subclass)
return 0;
int min = Math.min( SCORE_UNCOERCIBLE, inheritanceLevels( baseclass, subclass.getSuperclass() ) + 1 );
int min = Math.min(SCORE_UNCOERCIBLE, inheritanceLevels(baseclass, subclass.getSuperclass())+1);
Class[] ifaces = subclass.getInterfaces();
for ( int i=0; i<ifaces.length; i++ )
min = Math.min(min, inheritanceLevels(baseclass, ifaces[i]) + 1 );
for (int i = 0; i < ifaces.length; i++)
min = Math.min(min, inheritanceLevels(baseclass, ifaces[i])+1);
return min;
}
static final class ObjectCoercion implements Coercion {
final Class targetType;
ObjectCoercion(Class targetType) {
this.targetType = targetType;
}
public String toString() {
return "ObjectCoercion("+targetType.getName()+")";
return "ObjectCoercion(" + targetType.getName() + ")";
}
public int score(LuaValue value) {
switch ( value.type() ) {
switch (value.type()) {
case LuaValue.TNUMBER:
return inheritanceLevels( targetType, value.isint()? Integer.class: Double.class );
return inheritanceLevels(targetType, value.isint()? Integer.class: Double.class);
case LuaValue.TBOOLEAN:
return inheritanceLevels( targetType, Boolean.class );
return inheritanceLevels(targetType, Boolean.class);
case LuaValue.TSTRING:
return inheritanceLevels( targetType, String.class );
return inheritanceLevels(targetType, String.class);
case LuaValue.TUSERDATA:
return inheritanceLevels( targetType, value.touserdata().getClass() );
return inheritanceLevels(targetType, value.touserdata().getClass());
case LuaValue.TNIL:
return SCORE_NULL_VALUE;
default:
return inheritanceLevels( targetType, value.getClass() );
return inheritanceLevels(targetType, value.getClass());
}
}
public Object coerce(LuaValue value) {
switch ( value.type() ) {
switch (value.type()) {
case LuaValue.TNUMBER:
return value.isint()? (Object)new Integer(value.toint()): (Object)new Double(value.todouble());
return value.isint()? (Object) new Integer(value.toint()): (Object) new Double(value.todouble());
case LuaValue.TBOOLEAN:
return value.toboolean()? Boolean.TRUE: Boolean.FALSE;
case LuaValue.TSTRING:
@@ -335,38 +369,38 @@ public class CoerceLuaToJava {
Coercion stringCoercion = new StringCoercion(StringCoercion.TARGET_TYPE_STRING);
Coercion bytesCoercion = new StringCoercion(StringCoercion.TARGET_TYPE_BYTES);
COERCIONS.put( Boolean.TYPE, boolCoercion );
COERCIONS.put( Boolean.class, boolCoercion );
COERCIONS.put( Byte.TYPE, byteCoercion );
COERCIONS.put( Byte.class, byteCoercion );
COERCIONS.put( Character.TYPE, charCoercion );
COERCIONS.put( Character.class, charCoercion );
COERCIONS.put( Short.TYPE, shortCoercion );
COERCIONS.put( Short.class, shortCoercion );
COERCIONS.put( Integer.TYPE, intCoercion );
COERCIONS.put( Integer.class, intCoercion );
COERCIONS.put( Long.TYPE, longCoercion );
COERCIONS.put( Long.class, longCoercion );
COERCIONS.put( Float.TYPE, floatCoercion );
COERCIONS.put( Float.class, floatCoercion );
COERCIONS.put( Double.TYPE, doubleCoercion );
COERCIONS.put( Double.class, doubleCoercion );
COERCIONS.put( String.class, stringCoercion );
COERCIONS.put( byte[].class, bytesCoercion );
COERCIONS.put(Boolean.TYPE, boolCoercion);
COERCIONS.put(Boolean.class, boolCoercion);
COERCIONS.put(Byte.TYPE, byteCoercion);
COERCIONS.put(Byte.class, byteCoercion);
COERCIONS.put(Character.TYPE, charCoercion);
COERCIONS.put(Character.class, charCoercion);
COERCIONS.put(Short.TYPE, shortCoercion);
COERCIONS.put(Short.class, shortCoercion);
COERCIONS.put(Integer.TYPE, intCoercion);
COERCIONS.put(Integer.class, intCoercion);
COERCIONS.put(Long.TYPE, longCoercion);
COERCIONS.put(Long.class, longCoercion);
COERCIONS.put(Float.TYPE, floatCoercion);
COERCIONS.put(Float.class, floatCoercion);
COERCIONS.put(Double.TYPE, doubleCoercion);
COERCIONS.put(Double.class, doubleCoercion);
COERCIONS.put(String.class, stringCoercion);
COERCIONS.put(byte[].class, bytesCoercion);
}
static Coercion getCoercion(Class c) {
Coercion co = (Coercion) COERCIONS.get( c );
if ( co != null ) {
Coercion co = (Coercion) COERCIONS.get(c);
if (co != null) {
return co;
}
if ( c.isArray() ) {
if (c.isArray()) {
Class typ = c.getComponentType();
co = new ArrayCoercion(c.getComponentType());
} else {
co = new ObjectCoercion(c);
}
COERCIONS.put( c, co );
COERCIONS.put(c, co);
return co;
}
}

View File

@@ -33,9 +33,9 @@ import org.luaj.vm2.lib.OneArgFunction;
* <p>
* Can get elements by their integer key index, as well as the length.
* <p>
* This class is not used directly.
* It is returned by calls to {@link CoerceJavaToLua#coerce(Object)}
* when an array is supplied.
* This class is not used directly. It is returned by calls to
* {@link CoerceJavaToLua#coerce(Object)} when an array is supplied.
*
* @see CoerceJavaToLua
* @see CoerceLuaToJava
*/
@@ -43,7 +43,7 @@ class JavaArray extends LuaUserdata {
private static final class LenFunction extends OneArgFunction {
public LuaValue call(LuaValue u) {
return LuaValue.valueOf(Array.getLength(((LuaUserdata)u).m_instance));
return LuaValue.valueOf(Array.getLength(((LuaUserdata) u).m_instance));
}
}
@@ -61,26 +61,25 @@ class JavaArray extends LuaUserdata {
}
public LuaValue get(LuaValue key) {
if ( key.equals(LENGTH) )
if (key.equals(LENGTH))
return valueOf(Array.getLength(m_instance));
if ( key.isint() ) {
int i = key.toint() - 1;
return i>=0 && i<Array.getLength(m_instance)?
CoerceJavaToLua.coerce(Array.get(m_instance,key.toint()-1)):
NIL;
if (key.isint()) {
int i = key.toint()-1;
return i >= 0 && i < Array.getLength(m_instance)
? CoerceJavaToLua.coerce(Array.get(m_instance, key.toint()-1))
: NIL;
}
return super.get(key);
}
public void set(LuaValue key, LuaValue value) {
if ( key.isint() ) {
int i = key.toint() - 1;
if ( i>=0 && i<Array.getLength(m_instance) )
Array.set(m_instance,i,CoerceLuaToJava.coerce(value, m_instance.getClass().getComponentType()));
else if ( m_metatable==null || ! settable(this,key,value) )
if (key.isint()) {
int i = key.toint()-1;
if (i >= 0 && i < Array.getLength(m_instance))
Array.set(m_instance, i, CoerceLuaToJava.coerce(value, m_instance.getClass().getComponentType()));
else if (m_metatable == null || !settable(this, key, value))
error("array index out of bounds");
}
else
} else
super.set(key, value);
}
}

View File

@@ -40,9 +40,9 @@ import org.luaj.vm2.LuaValue;
* <p>
* Will respond to get() and set() by returning field values, or java methods.
* <p>
* This class is not used directly.
* It is returned by calls to {@link CoerceJavaToLua#coerce(Object)}
* when a Class is supplied.
* This class is not used directly. It is returned by calls to
* {@link CoerceJavaToLua#coerce(Object)} when a Class is supplied.
*
* @see CoerceJavaToLua
* @see CoerceLuaToJava
*/
@@ -58,8 +58,8 @@ class JavaClass extends JavaInstance implements CoerceJavaToLua.Coercion {
static JavaClass forClass(Class c) {
JavaClass j = (JavaClass) classes.get(c);
if ( j == null )
classes.put( c, j = new JavaClass(c) );
if (j == null)
classes.put(c, j = new JavaClass(c));
return j;
}
@@ -73,12 +73,12 @@ class JavaClass extends JavaInstance implements CoerceJavaToLua.Coercion {
}
Field getField(LuaValue key) {
if ( fields == null ) {
if (fields == null) {
Map m = new HashMap();
Field[] f = ((Class)m_instance).getFields();
for ( int i=0; i<f.length; i++ ) {
Field[] f = ((Class) m_instance).getFields();
for (int i = 0; i < f.length; i++) {
Field fi = f[i];
if ( Modifier.isPublic(fi.getModifiers()) ) {
if (Modifier.isPublic(fi.getModifiers())) {
m.put(LuaValue.valueOf(fi.getName()), fi);
try {
if (!fi.isAccessible())
@@ -93,39 +93,43 @@ class JavaClass extends JavaInstance implements CoerceJavaToLua.Coercion {
}
LuaValue getMethod(LuaValue key) {
if ( methods == null ) {
if (methods == null) {
Map namedlists = new HashMap();
Method[] m = ((Class)m_instance).getMethods();
for ( int i=0; i<m.length; i++ ) {
Method[] m = ((Class) m_instance).getMethods();
for (int i = 0; i < m.length; i++) {
Method mi = m[i];
if ( Modifier.isPublic( mi.getModifiers()) ) {
if (Modifier.isPublic(mi.getModifiers())) {
String name = mi.getName();
List list = (List) namedlists.get(name);
if ( list == null )
if (list == null)
namedlists.put(name, list = new ArrayList());
list.add( JavaMethod.forMethod(mi) );
list.add(JavaMethod.forMethod(mi));
}
}
Map map = new HashMap();
Constructor[] c = ((Class)m_instance).getConstructors();
Constructor[] c = ((Class) m_instance).getConstructors();
List list = new ArrayList();
for ( int i=0; i<c.length; i++ )
if ( Modifier.isPublic(c[i].getModifiers()) )
list.add( JavaConstructor.forConstructor(c[i]) );
switch ( list.size() ) {
case 0: break;
case 1: map.put(NEW, list.get(0)); break;
default: map.put(NEW, JavaConstructor.forConstructors( (JavaConstructor[])list.toArray(new JavaConstructor[list.size()]) ) ); break;
for (int i = 0; i < c.length; i++)
if (Modifier.isPublic(c[i].getModifiers()))
list.add(JavaConstructor.forConstructor(c[i]));
switch (list.size()) {
case 0:
break;
case 1:
map.put(NEW, list.get(0));
break;
default:
map.put(NEW, JavaConstructor
.forConstructors((JavaConstructor[]) list.toArray(new JavaConstructor[list.size()])));
break;
}
for ( Iterator it=namedlists.entrySet().iterator(); it.hasNext(); ) {
for (Iterator it = namedlists.entrySet().iterator(); it.hasNext();) {
Entry e = (Entry) it.next();
String name = (String) e.getKey();
List methods = (List) e.getValue();
map.put( LuaValue.valueOf(name),
methods.size()==1?
methods.get(0):
JavaMethod.forMethods( (JavaMethod[])methods.toArray(new JavaMethod[methods.size()])) );
map.put(LuaValue.valueOf(name), methods.size() == 1? methods.get(0)
: JavaMethod.forMethods((JavaMethod[]) methods.toArray(new JavaMethod[methods.size()])));
}
methods = map;
}
@@ -133,10 +137,10 @@ class JavaClass extends JavaInstance implements CoerceJavaToLua.Coercion {
}
Class getInnerClass(LuaValue key) {
if ( innerclasses == null ) {
if (innerclasses == null) {
Map m = new HashMap();
Class[] c = ((Class)m_instance).getClasses();
for ( int i=0; i<c.length; i++ ) {
Class[] c = ((Class) m_instance).getClasses();
for (int i = 0; i < c.length; i++) {
Class ci = c[i];
String name = ci.getName();
String stub = name.substring(Math.max(name.lastIndexOf('$'), name.lastIndexOf('.'))+1);
@@ -147,7 +151,5 @@ class JavaClass extends JavaInstance implements CoerceJavaToLua.Coercion {
return (Class) innerclasses.get(key);
}
public LuaValue getConstructor() {
return getMethod(NEW);
}
public LuaValue getConstructor() { return getMethod(NEW); }
}

View File

@@ -35,12 +35,12 @@ import org.luaj.vm2.lib.VarArgFunction;
/**
* LuaValue that represents a particular public Java constructor.
* <p>
* May be called with arguments to return a JavaInstance
* created by calling the constructor.
* May be called with arguments to return a JavaInstance created by calling the
* constructor.
* <p>
* This class is not used directly.
* It is returned by calls to {@link JavaClass#new(LuaValue key)}
* when the value of key is "new".
* This class is not used directly. It is returned by calls to
* {@link JavaClass#new(LuaValue key)} when the value of key is "new".
*
* @see CoerceJavaToLua
* @see CoerceLuaToJava
*/
@@ -50,8 +50,8 @@ class JavaConstructor extends JavaMember {
static JavaConstructor forConstructor(Constructor c) {
JavaConstructor j = (JavaConstructor) constructors.get(c);
if ( j == null )
constructors.put( c, j = new JavaConstructor(c) );
if (j == null)
constructors.put(c, j = new JavaConstructor(c));
return j;
}
@@ -62,18 +62,18 @@ class JavaConstructor extends JavaMember {
final Constructor constructor;
private JavaConstructor(Constructor c) {
super( c.getParameterTypes(), c.getModifiers() );
super(c.getParameterTypes(), c.getModifiers());
this.constructor = c;
}
public Varargs invoke(Varargs args) {
Object[] a = convertArgs(args);
try {
return CoerceJavaToLua.coerce( constructor.newInstance(a) );
return CoerceJavaToLua.coerce(constructor.newInstance(a));
} catch (InvocationTargetException e) {
throw new LuaError(e.getTargetException());
} catch (Exception e) {
return LuaValue.error("coercion error "+e);
return LuaValue.error("coercion error " + e);
}
}
@@ -82,12 +82,13 @@ class JavaConstructor extends JavaMember {
* <p>
* On invocation, will pick the best method from the list, and invoke it.
* <p>
* This class is not used directly.
* It is returned by calls to calls to {@link JavaClass#get(LuaValue key)}
* when key is "new" and there is more than one public constructor.
* This class is not used directly. It is returned by calls to calls to
* {@link JavaClass#get(LuaValue key)} when key is "new" and there is more
* than one public constructor.
*/
static class Overload extends VarArgFunction {
final JavaConstructor[] constructors;
public Overload(JavaConstructor[] c) {
this.constructors = c;
}
@@ -95,18 +96,18 @@ class JavaConstructor extends JavaMember {
public Varargs invoke(Varargs args) {
JavaConstructor best = null;
int score = CoerceLuaToJava.SCORE_UNCOERCIBLE;
for ( int i=0; i<constructors.length; i++ ) {
for (int i = 0; i < constructors.length; i++) {
int s = constructors[i].score(args);
if ( s < score ) {
if (s < score) {
score = s;
best = constructors[i];
if ( score == 0 )
if (score == 0)
break;
}
}
// any match?
if ( best == null )
if (best == null)
LuaValue.error("no coercible public method");
// invoke it

View File

@@ -32,9 +32,9 @@ import org.luaj.vm2.LuaValue;
* <p>
* Will respond to get() and set() by returning field values or methods.
* <p>
* This class is not used directly.
* It is returned by calls to {@link CoerceJavaToLua#coerce(Object)}
* when a subclass of Object is supplied.
* This class is not used directly. It is returned by calls to
* {@link CoerceJavaToLua#coerce(Object)} when a subclass of Object is supplied.
*
* @see CoerceJavaToLua
* @see CoerceLuaToJava
*/
@@ -47,29 +47,29 @@ class JavaInstance extends LuaUserdata {
}
public LuaValue get(LuaValue key) {
if ( jclass == null )
if (jclass == null)
jclass = JavaClass.forClass(m_instance.getClass());
Field f = jclass.getField(key);
if ( f != null )
if (f != null)
try {
return CoerceJavaToLua.coerce(f.get(m_instance));
} catch (Exception e) {
throw new LuaError(e);
}
LuaValue m = jclass.getMethod(key);
if ( m != null )
if (m != null)
return m;
Class c = jclass.getInnerClass(key);
if ( c != null )
if (c != null)
return JavaClass.forClass(c);
return super.get(key);
}
public void set(LuaValue key, LuaValue value) {
if ( jclass == null )
if (jclass == null)
jclass = JavaClass.forClass(m_instance.getClass());
Field f = jclass.getField(key);
if ( f != null )
if (f != null)
try {
f.set(m_instance, CoerceLuaToJava.coerce(value, f.getType()));
return;

View File

@@ -28,18 +28,18 @@ import org.luaj.vm2.lib.jse.CoerceLuaToJava.Coercion;
/**
* Java method or constructor.
* <p>
* Primarily handles argument coercion for parameter lists including scoring of compatibility and
* java varargs handling.
* Primarily handles argument coercion for parameter lists including scoring of
* compatibility and java varargs handling.
* <p>
* This class is not used directly.
* It is an abstract base class for {@link JavaConstructor} and {@link JavaMethod}.
* This class is not used directly. It is an abstract base class for
* {@link JavaConstructor} and {@link JavaMethod}.
*
* @see JavaConstructor
* @see JavaMethod
* @see CoerceJavaToLua
* @see CoerceLuaToJava
*/
abstract
class JavaMember extends VarArgFunction {
abstract class JavaMember extends VarArgFunction {
static final int METHOD_MODIFIERS_VARARGS = 0x80;
@@ -49,35 +49,35 @@ class JavaMember extends VarArgFunction {
protected JavaMember(Class[] params, int modifiers) {
boolean isvarargs = ((modifiers & METHOD_MODIFIERS_VARARGS) != 0);
fixedargs = new CoerceLuaToJava.Coercion[isvarargs? params.length-1: params.length];
for ( int i=0; i<fixedargs.length; i++ )
fixedargs[i] = CoerceLuaToJava.getCoercion( params[i] );
varargs = isvarargs? CoerceLuaToJava.getCoercion( params[params.length-1] ): null;
for (int i = 0; i < fixedargs.length; i++)
fixedargs[i] = CoerceLuaToJava.getCoercion(params[i]);
varargs = isvarargs? CoerceLuaToJava.getCoercion(params[params.length-1]): null;
}
int score(Varargs args) {
int n = args.narg();
int s = n>fixedargs.length? CoerceLuaToJava.SCORE_WRONG_TYPE * (n-fixedargs.length): 0;
for ( int j=0; j<fixedargs.length; j++ )
s += fixedargs[j].score( args.arg(j+1) );
if ( varargs != null )
for ( int k=fixedargs.length; k<n; k++ )
s += varargs.score( args.arg(k+1) );
int s = n > fixedargs.length? CoerceLuaToJava.SCORE_WRONG_TYPE*(n-fixedargs.length): 0;
for (int j = 0; j < fixedargs.length; j++)
s += fixedargs[j].score(args.arg(j+1));
if (varargs != null)
for (int k = fixedargs.length; k < n; k++)
s += varargs.score(args.arg(k+1));
return s;
}
protected Object[] convertArgs(Varargs args) {
Object[] a;
if ( varargs == null ) {
if (varargs == null) {
a = new Object[fixedargs.length];
for ( int i=0; i<a.length; i++ )
a[i] = fixedargs[i].coerce( args.arg(i+1) );
for (int i = 0; i < a.length; i++)
a[i] = fixedargs[i].coerce(args.arg(i+1));
} else {
int n = Math.max(fixedargs.length,args.narg());
int n = Math.max(fixedargs.length, args.narg());
a = new Object[n];
for ( int i=0; i<fixedargs.length; i++ )
a[i] = fixedargs[i].coerce( args.arg(i+1) );
for ( int i=fixedargs.length; i<n; i++ )
a[i] = varargs.coerce( args.arg(i+1) );
for (int i = 0; i < fixedargs.length; i++)
a[i] = fixedargs[i].coerce(args.arg(i+1));
for (int i = fixedargs.length; i < n; i++)
a[i] = varargs.coerce(args.arg(i+1));
}
return a;
}

View File

@@ -37,9 +37,9 @@ import org.luaj.vm2.Varargs;
* <p>
* Can be invoked via call(LuaValue...) and related methods.
* <p>
* This class is not used directly.
* It is returned by calls to calls to {@link JavaInstance#get(LuaValue key)}
* when a method is named.
* This class is not used directly. It is returned by calls to calls to
* {@link JavaInstance#get(LuaValue key)} when a method is named.
*
* @see CoerceJavaToLua
* @see CoerceLuaToJava
*/
@@ -49,8 +49,8 @@ class JavaMethod extends JavaMember {
static JavaMethod forMethod(Method m) {
JavaMethod j = (JavaMethod) methods.get(m);
if ( j == null )
methods.put( m, j = new JavaMethod(m) );
if (j == null)
methods.put(m, j = new JavaMethod(m));
return j;
}
@@ -61,7 +61,7 @@ class JavaMethod extends JavaMember {
final Method method;
private JavaMethod(Method m) {
super( m.getParameterTypes(), m.getModifiers() );
super(m.getParameterTypes(), m.getModifiers());
this.method = m;
try {
if (!m.isAccessible())
@@ -93,11 +93,11 @@ class JavaMethod extends JavaMember {
LuaValue invokeMethod(Object instance, Varargs args) {
Object[] a = convertArgs(args);
try {
return CoerceJavaToLua.coerce( method.invoke(instance, a) );
return CoerceJavaToLua.coerce(method.invoke(instance, a));
} catch (InvocationTargetException e) {
throw new LuaError(e.getTargetException());
} catch (Exception e) {
return LuaValue.error("coercion error "+e);
return LuaValue.error("coercion error " + e);
}
}
@@ -106,9 +106,9 @@ class JavaMethod extends JavaMember {
* <p>
* On invocation, will pick the best method from the list, and invoke it.
* <p>
* This class is not used directly.
* It is returned by calls to calls to {@link JavaInstance#get(LuaValue key)}
* when an overloaded method is named.
* This class is not used directly. It is returned by calls to calls to
* {@link JavaInstance#get(LuaValue key)} when an overloaded method is
* named.
*/
static class Overload extends LuaFunction {
@@ -141,18 +141,18 @@ class JavaMethod extends JavaMember {
private LuaValue invokeBestMethod(Object instance, Varargs args) {
JavaMethod best = null;
int score = CoerceLuaToJava.SCORE_UNCOERCIBLE;
for ( int i=0; i<methods.length; i++ ) {
for (int i = 0; i < methods.length; i++) {
int s = methods[i].score(args);
if ( s < score ) {
if (s < score) {
score = s;
best = methods[i];
if ( score == 0 )
if (score == 0)
break;
}
}
// any match?
if ( best == null )
if (best == null)
LuaValue.error("no coercible public method");
// invoke it

View File

@@ -34,33 +34,46 @@ import org.luaj.vm2.lib.LibFunction;
import org.luaj.vm2.lib.ResourceFinder;
/**
* Subclass of {@link BaseLib} and {@link LibFunction} which implements the lua basic library functions
* and provides a directory based {@link ResourceFinder} as the {@link Globals#finder}.
* Subclass of {@link BaseLib} and {@link LibFunction} which implements the lua
* basic library functions and provides a directory based {@link ResourceFinder}
* as the {@link Globals#finder}.
* <p>
* Since JME has no file system by default, {@link BaseLib} implements
* {@link ResourceFinder} using {@link Class#getResource(String)}.
* The {@link org.luaj.vm2.lib.jse.JseBaseLib} implements {@link Globals#finder} by scanning the current directory
* first, then falling back to {@link Class#getResource(String)} if that fails.
* Otherwise, the behavior is the same as that of {@link BaseLib}.
* {@link ResourceFinder} using {@link Class#getResource(String)}. The
* {@link org.luaj.vm2.lib.jse.JseBaseLib} implements {@link Globals#finder} by
* scanning the current directory first, then falling back to
* {@link Class#getResource(String)} if that fails. Otherwise, the behavior is
* the same as that of {@link BaseLib}.
* <p>
* Typically, this library is included as part of a call to
* {@link org.luaj.vm2.lib.jse.JsePlatform#standardGlobals()}
* <pre> {@code
*
* <pre>
* {
* &#64;code
* Globals globals = JsePlatform.standardGlobals();
* globals.get("print").call(LuaValue.valueOf("hello, world"));
* } </pre>
* }
* </pre>
* <p>
* For special cases where the smallest possible footprint is desired,
* a minimal set of libraries could be loaded
* directly via {@link Globals#load(LuaValue)} using code such as:
* <pre> {@code
* For special cases where the smallest possible footprint is desired, a minimal
* set of libraries could be loaded directly via {@link Globals#load(LuaValue)}
* using code such as:
*
* <pre>
* {
* &#64;code
* Globals globals = new Globals();
* globals.load(new JseBaseLib());
* globals.get("print").call(LuaValue.valueOf("hello, world"));
* } </pre>
* <p>However, other libraries such as <em>PackageLib</em> are not loaded in this case.
* }
* </pre>
* <p>
* However, other libraries such as <em>PackageLib</em> are not loaded in this
* case.
* <p>
* This is a direct port of the corresponding library in C.
*
* @see Globals
* @see BaseLib
* @see ResourceFinder
@@ -68,18 +81,24 @@ import org.luaj.vm2.lib.ResourceFinder;
* @see LibFunction
* @see org.luaj.vm2.lib.jse.JsePlatform
* @see org.luaj.vm2.lib.jme.JmePlatform
* @see <a href="http://www.lua.org/manual/5.2/manual.html#6.1">Lua 5.2 Base Lib Reference</a>
* @see <a href="http://www.lua.org/manual/5.2/manual.html#6.1">Lua 5.2 Base Lib
* Reference</a>
*/
public class JseBaseLib extends org.luaj.vm2.lib.BaseLib {
/** Perform one-time initialization on the library by creating a table
* containing the library functions, adding that table to the supplied environment,
* adding the table to package.loaded, and returning table as the return value.
* <P>Specifically, extend the library loading to set the default value for {@link Globals#STDIN}
/**
* Perform one-time initialization on the library by creating a table
* containing the library functions, adding that table to the supplied
* environment, adding the table to package.loaded, and returning table as
* the return value.
* <P>
* Specifically, extend the library loading to set the default value for
* {@link Globals#STDIN}
*
* @param modname the module name supplied if this is loaded via 'require'.
* @param env the environment to load into, which must be a Globals instance.
* @param env the environment to load into, which must be a Globals
* instance.
*/
public LuaValue call(LuaValue modname, LuaValue env) {
super.call(modname, env);
@@ -87,10 +106,9 @@ public class JseBaseLib extends org.luaj.vm2.lib.BaseLib {
return env;
}
/**
* Try to open a file in the current working directory,
* or fall back to base opener if not found.
* Try to open a file in the current working directory, or fall back to base
* opener if not found.
*
* This implementation attempts to open the file using new File(filename).
* It falls back to the base implementation that looks it up as a resource
@@ -104,13 +122,12 @@ public class JseBaseLib extends org.luaj.vm2.lib.BaseLib {
*/
public InputStream findResource(String filename) {
File f = new File(filename);
if ( ! f.exists() )
if (!f.exists())
return super.findResource(filename);
try {
return new BufferedInputStream(new FileInputStream(f));
} catch ( IOException ioe ) {
} catch (IOException ioe) {
return null;
}
}
}

View File

@@ -37,37 +37,50 @@ import org.luaj.vm2.lib.IoLib;
import org.luaj.vm2.lib.LibFunction;
/**
* Subclass of {@link IoLib} and therefore {@link LibFunction} which implements the lua standard {@code io}
* library for the JSE platform.
* Subclass of {@link IoLib} and therefore {@link LibFunction} which implements
* the lua standard {@code io} library for the JSE platform.
* <p>
* It uses RandomAccessFile to implement seek on files.
* <p>
* Typically, this library is included as part of a call to
* {@link org.luaj.vm2.lib.jse.JsePlatform#standardGlobals()}
* <pre> {@code
*
* <pre>
* {
* &#64;code
* Globals globals = JsePlatform.standardGlobals();
* globals.get("io").get("write").call(LuaValue.valueOf("hello, world\n"));
* } </pre>
* }
* </pre>
* <p>
* For special cases where the smallest possible footprint is desired,
* a minimal set of libraries could be loaded
* directly via {@link Globals#load(LuaValue)} using code such as:
* <pre> {@code
* For special cases where the smallest possible footprint is desired, a minimal
* set of libraries could be loaded directly via {@link Globals#load(LuaValue)}
* using code such as:
*
* <pre>
* {
* &#64;code
* Globals globals = new Globals();
* globals.load(new JseBaseLib());
* globals.load(new PackageLib());
* globals.load(new JseIoLib());
* globals.get("io").get("write").call(LuaValue.valueOf("hello, world\n"));
* } </pre>
* <p>However, other libraries such as <em>MathLib</em> are not loaded in this case.
* }
* </pre>
* <p>
* This has been implemented to match as closely as possible the behavior in the corresponding library in C.
* However, other libraries such as <em>MathLib</em> are not loaded in this
* case.
* <p>
* This has been implemented to match as closely as possible the behavior in the
* corresponding library in C.
*
* @see LibFunction
* @see org.luaj.vm2.lib.jse.JsePlatform
* @see org.luaj.vm2.lib.jme.JmePlatform
* @see IoLib
* @see org.luaj.vm2.lib.jme.JmeIoLib
* @see <a href="http://www.lua.org/manual/5.2/manual.html#6.8">Lua 5.2 I/O Lib Reference</a>
* @see <a href="http://www.lua.org/manual/5.2/manual.html#6.8">Lua 5.2 I/O Lib
* Reference</a>
*/
public class JseIoLib extends IoLib {
@@ -83,89 +96,98 @@ public class JseIoLib extends IoLib {
return new StdoutFile(FTYPE_STDERR);
}
protected File openFile( String filename, boolean readMode, boolean appendMode, boolean updateMode, boolean binaryMode ) throws IOException {
RandomAccessFile f = new RandomAccessFile(filename,readMode? "r": "rw");
if ( appendMode ) {
protected File openFile(String filename, boolean readMode, boolean appendMode, boolean updateMode,
boolean binaryMode) throws IOException {
RandomAccessFile f = new RandomAccessFile(filename, readMode? "r": "rw");
if (appendMode) {
f.seek(f.length());
} else {
if ( ! readMode )
if (!readMode)
f.setLength(0);
}
return new FileImpl( f );
return new FileImpl(f);
}
protected File openProgram(String prog, String mode) throws IOException {
final Process p = Runtime.getRuntime().exec(prog);
return "w".equals(mode)?
new FileImpl( p.getOutputStream() ):
new FileImpl( p.getInputStream() );
return "w".equals(mode)? new FileImpl(p.getOutputStream()): new FileImpl(p.getInputStream());
}
protected File tmpFile() throws IOException {
java.io.File f = java.io.File.createTempFile(".luaj","bin");
java.io.File f = java.io.File.createTempFile(".luaj", "bin");
f.deleteOnExit();
return new FileImpl( new RandomAccessFile(f,"rw") );
return new FileImpl(new RandomAccessFile(f, "rw"));
}
private static void notimplemented() {
throw new LuaError("not implemented");
}
private final class FileImpl extends File {
private final RandomAccessFile file;
private final InputStream is;
private final OutputStream os;
private boolean closed = false;
private boolean nobuffer = false;
private FileImpl( RandomAccessFile file, InputStream is, OutputStream os ) {
private FileImpl(RandomAccessFile file, InputStream is, OutputStream os) {
this.file = file;
this.is = is!=null? is.markSupported()? is: new BufferedInputStream(is): null;
this.is = is != null? is.markSupported()? is: new BufferedInputStream(is): null;
this.os = os;
}
private FileImpl( RandomAccessFile f ) {
this( f, null, null );
private FileImpl(RandomAccessFile f) {
this(f, null, null);
}
private FileImpl( InputStream i ) {
this( null, i, null );
private FileImpl(InputStream i) {
this(null, i, null);
}
private FileImpl( OutputStream o ) {
this( null, null, o );
private FileImpl(OutputStream o) {
this(null, null, o);
}
public String tojstring() {
return "file (" + (this.closed ? "closed" : String.valueOf(this.hashCode())) + ")";
return "file (" + (this.closed? "closed": String.valueOf(this.hashCode())) + ")";
}
public boolean isstdfile() {
return file == null;
}
public void close() throws IOException {
closed = true;
if ( file != null ) {
if (file != null) {
file.close();
}
}
public void flush() throws IOException {
if ( os != null )
if (os != null)
os.flush();
}
public void write(LuaString s) throws IOException {
if ( os != null )
os.write( s.m_bytes, s.m_offset, s.m_length );
else if ( file != null )
file.write( s.m_bytes, s.m_offset, s.m_length );
if (os != null)
os.write(s.m_bytes, s.m_offset, s.m_length);
else if (file != null)
file.write(s.m_bytes, s.m_offset, s.m_length);
else
notimplemented();
if ( nobuffer )
if (nobuffer)
flush();
}
public boolean isclosed() {
return closed;
}
public int seek(String option, int pos) throws IOException {
if ( file != null ) {
if ( "set".equals(option) ) {
if (file != null) {
if ("set".equals(option)) {
file.seek(pos);
} else if ( "end".equals(option) ) {
} else if ("end".equals(option)) {
file.seek(file.length()+pos);
} else {
file.seek(file.getFilePointer()+pos);
@@ -175,23 +197,24 @@ public class JseIoLib extends IoLib {
notimplemented();
return 0;
}
public void setvbuf(String mode, int size) {
nobuffer = "no".equals(mode);
}
// get length remaining to read
public int remaining() throws IOException {
return file!=null? (int) (file.length()-file.getFilePointer()): -1;
return file != null? (int) (file.length()-file.getFilePointer()): -1;
}
// peek ahead one character
public int peek() throws IOException {
if ( is != null ) {
if (is != null) {
is.mark(1);
int c = is.read();
is.reset();
return c;
} else if ( file != null ) {
} else if (file != null) {
long fp = file.getFilePointer();
int c = file.read();
file.seek(fp);
@@ -203,9 +226,9 @@ public class JseIoLib extends IoLib {
// return char if read, -1 if eof, throw IOException on other exception
public int read() throws IOException {
if ( is != null )
if (is != null)
return is.read();
else if ( file != null ) {
else if (file != null) {
return file.read();
}
notimplemented();
@@ -214,9 +237,9 @@ public class JseIoLib extends IoLib {
// return number of bytes read if positive, -1 if eof, throws IOException
public int read(byte[] bytes, int offset, int length) throws IOException {
if (file!=null) {
if (file != null) {
return file.read(bytes, offset, length);
} else if (is!=null) {
} else if (is != null) {
return is.read(bytes, offset, length);
} else {
notimplemented();
@@ -233,14 +256,10 @@ public class JseIoLib extends IoLib {
}
public String tojstring() {
return "file ("+this.hashCode()+")";
return "file (" + this.hashCode() + ")";
}
private final PrintStream getPrintStream() {
return file_type == FTYPE_STDERR?
globals.STDERR:
globals.STDOUT;
}
private final PrintStream getPrintStream() { return file_type == FTYPE_STDERR? globals.STDERR: globals.STDOUT; }
public void write(LuaString string) throws IOException {
getPrintStream().write(string.m_bytes, string.m_offset, string.m_length);
@@ -281,8 +300,7 @@ public class JseIoLib extends IoLib {
return 0;
}
public int read(byte[] bytes, int offset, int length)
throws IOException {
public int read(byte[] bytes, int offset, int length) throws IOException {
return 0;
}
}
@@ -292,7 +310,7 @@ public class JseIoLib extends IoLib {
}
public String tojstring() {
return "file ("+this.hashCode()+")";
return "file (" + this.hashCode() + ")";
}
public void write(LuaString string) throws IOException {
@@ -335,8 +353,7 @@ public class JseIoLib extends IoLib {
return globals.STDIN.read();
}
public int read(byte[] bytes, int offset, int length)
throws IOException {
public int read(byte[] bytes, int offset, int length) throws IOException {
return globals.STDIN.read(bytes, offset, length);
}
}

View File

@@ -27,50 +27,68 @@ import org.luaj.vm2.lib.LibFunction;
import org.luaj.vm2.lib.TwoArgFunction;
/**
* Subclass of {@link LibFunction} which implements the lua standard {@code math}
* library.
* Subclass of {@link LibFunction} which implements the lua standard
* {@code math} library.
* <p>
* It contains all lua math functions, including those not available on the JME platform.
* See {@link org.luaj.vm2.lib.MathLib} for the exception list.
* It contains all lua math functions, including those not available on the JME
* platform. See {@link org.luaj.vm2.lib.MathLib} for the exception list.
* <p>
* Typically, this library is included as part of a call to
* {@link org.luaj.vm2.lib.jse.JsePlatform#standardGlobals()}
* <pre> {@code
*
* <pre>
* {
* &#64;code
* Globals globals = JsePlatform.standardGlobals();
* System.out.println( globals.get("math").get("sqrt").call( LuaValue.valueOf(2) ) );
* } </pre>
* System.out.println(globals.get("math").get("sqrt").call(LuaValue.valueOf(2)));
* }
* </pre>
* <p>
* For special cases where the smallest possible footprint is desired,
* a minimal set of libraries could be loaded
* directly via {@link Globals#load(LuaValue)} using code such as:
* <pre> {@code
* For special cases where the smallest possible footprint is desired, a minimal
* set of libraries could be loaded directly via {@link Globals#load(LuaValue)}
* using code such as:
*
* <pre>
* {
* &#64;code
* Globals globals = new Globals();
* globals.load(new JseBaseLib());
* globals.load(new PackageLib());
* globals.load(new JseMathLib());
* System.out.println( globals.get("math").get("sqrt").call( LuaValue.valueOf(2) ) );
* } </pre>
* <p>However, other libraries such as <em>CoroutineLib</em> are not loaded in this case.
* System.out.println(globals.get("math").get("sqrt").call(LuaValue.valueOf(2)));
* }
* </pre>
* <p>
* This has been implemented to match as closely as possible the behavior in the corresponding library in C.
* However, other libraries such as <em>CoroutineLib</em> are not loaded in this
* case.
* <p>
* This has been implemented to match as closely as possible the behavior in the
* corresponding library in C.
*
* @see LibFunction
* @see org.luaj.vm2.lib.jse.JsePlatform
* @see org.luaj.vm2.lib.jme.JmePlatform
* @see org.luaj.vm2.lib.jse.JseMathLib
* @see <a href="http://www.lua.org/manual/5.2/manual.html#6.6">Lua 5.2 Math Lib Reference</a>
* @see <a href="http://www.lua.org/manual/5.2/manual.html#6.6">Lua 5.2 Math Lib
* Reference</a>
*/
public class JseMathLib extends org.luaj.vm2.lib.MathLib {
public JseMathLib() {}
/** Perform one-time initialization on the library by creating a table
* containing the library functions, adding that table to the supplied environment,
* adding the table to package.loaded, and returning table as the return value.
* <P>Specifically, adds all library functions that can be implemented directly
* in JSE but not JME: acos, asin, atan, atan2, cosh, exp, log, pow, sinh, and tanh.
/**
* Perform one-time initialization on the library by creating a table
* containing the library functions, adding that table to the supplied
* environment, adding the table to package.loaded, and returning table as
* the return value.
* <P>
* Specifically, adds all library functions that can be implemented directly
* in JSE but not JME: acos, asin, atan, atan2, cosh, exp, log, pow, sinh,
* and tanh.
*
* @param modname the module name supplied if this is loaded via 'require'.
* @param env the environment to load into, which must be a Globals instance.
* @param env the environment to load into, which must be a Globals
* instance.
*/
public LuaValue call(LuaValue modname, LuaValue env) {
super.call(modname, env);
@@ -89,32 +107,53 @@ public class JseMathLib extends org.luaj.vm2.lib.MathLib {
return math;
}
static final class acos extends UnaryOp { protected double call(double d) { return Math.acos(d); } }
static final class asin extends UnaryOp { protected double call(double d) { return Math.asin(d); } }
static final class acos extends UnaryOp {
protected double call(double d) { return Math.acos(d); }
}
static final class asin extends UnaryOp {
protected double call(double d) { return Math.asin(d); }
}
static final class atan2 extends TwoArgFunction {
public LuaValue call(LuaValue x, LuaValue y) {
return valueOf(Math.atan2(x.checkdouble(), y.optdouble(1)));
}
}
static final class cosh extends UnaryOp { protected double call(double d) { return Math.cosh(d); } }
static final class exp extends UnaryOp { protected double call(double d) { return Math.exp(d); } }
static final class cosh extends UnaryOp {
protected double call(double d) { return Math.cosh(d); }
}
static final class exp extends UnaryOp {
protected double call(double d) { return Math.exp(d); }
}
static final class log extends TwoArgFunction {
public LuaValue call(LuaValue x, LuaValue base) {
double nat = Math.log(x.checkdouble());
double b = base.optdouble(Math.E);
if (b != Math.E) nat /= Math.log(b);
if (b != Math.E)
nat /= Math.log(b);
return valueOf(nat);
}
}
static final class pow extends BinaryOp { protected double call(double x, double y) { return Math.pow(x, y); } }
static final class sinh extends UnaryOp { protected double call(double d) { return Math.sinh(d); } }
static final class tanh extends UnaryOp { protected double call(double d) { return Math.tanh(d); } }
static final class pow extends BinaryOp {
protected double call(double x, double y) { return Math.pow(x, y); }
}
static final class sinh extends UnaryOp {
protected double call(double d) { return Math.sinh(d); }
}
static final class tanh extends UnaryOp {
protected double call(double d) { return Math.tanh(d); }
}
/** Faster, better version of pow() used by arithmetic operator ^ */
public double dpow_lib(double a, double b) {
return Math.pow(a, b);
}
}

View File

@@ -31,10 +31,11 @@ import org.luaj.vm2.lib.LibFunction;
import org.luaj.vm2.lib.OsLib;
/**
* Subclass of {@link LibFunction} which implements the standard lua {@code os} library.
* Subclass of {@link LibFunction} which implements the standard lua {@code os}
* library.
* <p>
* This contains more complete implementations of the following functions
* using features that are specific to JSE:
* This contains more complete implementations of the following functions using
* features that are specific to JSE:
* <ul>
* <li>{@code execute()}</li>
* <li>{@code remove()}</li>
@@ -42,34 +43,46 @@ import org.luaj.vm2.lib.OsLib;
* <li>{@code tmpname()}</li>
* </ul>
* <p>
* Because the nature of the {@code os} library is to encapsulate
* os-specific features, the behavior of these functions varies considerably
* from their counterparts in the C platform.
* Because the nature of the {@code os} library is to encapsulate os-specific
* features, the behavior of these functions varies considerably from their
* counterparts in the C platform.
* <p>
* Typically, this library is included as part of a call to
* {@link org.luaj.vm2.lib.jse.JsePlatform#standardGlobals()}
* <pre> {@code
*
* <pre>
* {
* &#64;code
* Globals globals = JsePlatform.standardGlobals();
* System.out.println( globals.get("os").get("time").call() );
* } </pre>
* System.out.println(globals.get("os").get("time").call());
* }
* </pre>
* <p>
* For special cases where the smallest possible footprint is desired,
* a minimal set of libraries could be loaded
* directly via {@link Globals#load(LuaValue)} using code such as:
* <pre> {@code
* For special cases where the smallest possible footprint is desired, a minimal
* set of libraries could be loaded directly via {@link Globals#load(LuaValue)}
* using code such as:
*
* <pre>
* {
* &#64;code
* Globals globals = new Globals();
* globals.load(new JseBaseLib());
* globals.load(new PackageLib());
* globals.load(new JseOsLib());
* System.out.println( globals.get("os").get("time").call() );
* } </pre>
* <p>However, other libraries such as <em>MathLib</em> are not loaded in this case.
* System.out.println(globals.get("os").get("time").call());
* }
* </pre>
* <p>
* However, other libraries such as <em>MathLib</em> are not loaded in this
* case.
* <p>
*
* @see LibFunction
* @see OsLib
* @see org.luaj.vm2.lib.jse.JsePlatform
* @see org.luaj.vm2.lib.jme.JmePlatform
* @see <a href="http://www.lua.org/manual/5.2/manual.html#6.9">Lua 5.2 OS Lib Reference</a>
* @see <a href="http://www.lua.org/manual/5.2/manual.html#6.9">Lua 5.2 OS Lib
* Reference</a>
*/
public class JseOsLib extends org.luaj.vm2.lib.OsLib {
@@ -88,7 +101,7 @@ public class JseOsLib extends org.luaj.vm2.lib.OsLib {
protected String getenv(String varname) {
String s = System.getenv(varname);
return s != null? s : System.getProperty(varname);
return s != null? s: System.getProperty(varname);
}
protected Varargs execute(String command) {
@@ -109,25 +122,25 @@ public class JseOsLib extends org.luaj.vm2.lib.OsLib {
protected void remove(String filename) throws IOException {
File f = new File(filename);
if ( ! f.exists() )
if (!f.exists())
throw new IOException("No such file or directory");
if ( ! f.delete() )
if (!f.delete())
throw new IOException("Failed to delete");
}
protected void rename(String oldname, String newname) throws IOException {
File f = new File(oldname);
if ( ! f.exists() )
if (!f.exists())
throw new IOException("No such file or directory");
if ( ! f.renameTo(new File(newname)) )
if (!f.renameTo(new File(newname)))
throw new IOException("Failed to rename");
}
protected String tmpname() {
try {
java.io.File f = java.io.File.createTempFile(TMP_PREFIX ,TMP_SUFFIX);
java.io.File f = java.io.File.createTempFile(TMP_PREFIX, TMP_SUFFIX);
return f.getAbsolutePath();
} catch ( IOException ioe ) {
} catch (IOException ioe) {
return super.tmpname();
}
}

View File

@@ -34,31 +34,45 @@ import org.luaj.vm2.lib.ResourceFinder;
import org.luaj.vm2.lib.StringLib;
import org.luaj.vm2.lib.TableLib;
/** The {@link org.luaj.vm2.lib.jse.JsePlatform} class is a convenience class to standardize
* how globals tables are initialized for the JSE platform.
/**
* The {@link org.luaj.vm2.lib.jse.JsePlatform} class is a convenience class to
* standardize how globals tables are initialized for the JSE platform.
* <p>
* It is used to allocate either a set of standard globals using
* {@link #standardGlobals()} or debug globals using {@link #debugGlobals()}
* <p>
* A simple example of initializing globals and using them from Java is:
* <pre> {@code
*
* <pre>
* {
* &#64;code
* Globals globals = JsePlatform.standardGlobals();
* globals.get("print").call(LuaValue.valueOf("hello, world"));
* } </pre>
* }
* </pre>
* <p>
* Once globals are created, a simple way to load and run a script is:
* <pre> {@code
*
* <pre>
* {@code
* globals.load( new FileInputStream("main.lua"), "main.lua" ).call();
* } </pre>
* }
* </pre>
* <p>
* although {@code require} could also be used:
* <pre> {@code
*
* <pre>
* {@code
* globals.get("require").call(LuaValue.valueOf("main"));
* } </pre>
* For this to succeed, the file "main.lua" must be in the current directory or a resource.
* See {@link org.luaj.vm2.lib.jse.JseBaseLib} for details on finding scripts using {@link ResourceFinder}.
* }
* </pre>
*
* For this to succeed, the file "main.lua" must be in the current directory or
* a resource. See {@link org.luaj.vm2.lib.jse.JseBaseLib} for details on
* finding scripts using {@link ResourceFinder}.
* <p>
* The standard globals will contain all standard libraries plus {@code luajava}:
* The standard globals will contain all standard libraries plus
* {@code luajava}:
* <ul>
* <li>{@link Globals}</li>
* <li>{@link org.luaj.vm2.lib.jse.JseBaseLib}</li>
@@ -72,9 +86,11 @@ import org.luaj.vm2.lib.TableLib;
* <li>{@link org.luaj.vm2.lib.jse.JseOsLib}</li>
* <li>{@link org.luaj.vm2.lib.jse.LuajavaLib}</li>
* </ul>
* In addition, the {@link LuaC} compiler is installed so lua files may be loaded in their source form.
* In addition, the {@link LuaC} compiler is installed so lua files may be
* loaded in their source form.
* <p>
* The debug globals are simply the standard globals plus the {@code debug} library {@link DebugLib}.
* The debug globals are simply the standard globals plus the {@code debug}
* library {@link DebugLib}.
* <p>
* The class ensures that initialization is done in the correct order.
*
@@ -108,9 +124,11 @@ public class JsePlatform {
return globals;
}
/** Create standard globals including the {@link DebugLib} library.
/**
* Create standard globals including the {@link DebugLib} library.
*
* @return Table of globals initialized with the standard JSE and debug libraries
* @return Table of globals initialized with the standard JSE and debug
* libraries
* @see #standardGlobals()
* @see org.luaj.vm2.lib.jse.JsePlatform
* @see org.luaj.vm2.lib.jme.JmePlatform
@@ -122,10 +140,11 @@ public class JsePlatform {
return globals;
}
/** Simple wrapper for invoking a lua function with command line arguments.
* The supplied function is first given a new Globals object as its environment
* then the program is run with arguments.
/**
* Simple wrapper for invoking a lua function with command line arguments.
* The supplied function is first given a new Globals object as its
* environment then the program is run with arguments.
*
* @return {@link Varargs} containing any values returned by mainChunk.
*/
public static Varargs luaMain(LuaValue mainChunk, String[] args) {

View File

@@ -25,19 +25,25 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
/** Analog of Process that pipes input and output to client-specified streams.
/**
* Analog of Process that pipes input and output to client-specified streams.
*/
public class JseProcess {
final Process process;
final Thread input,output,error;
final Thread input, output, error;
/** Construct a process around a command, with specified streams to redirect input and output to.
/**
* Construct a process around a command, with specified streams to redirect
* input and output to.
*
* @param cmd The command to execute, including arguments, if any
* @param stdin Optional InputStream to read from as process input, or null if input is not needed.
* @param stdout Optional OutputStream to copy process output to, or null if output is ignored.
* @param stderr Optinoal OutputStream to copy process stderr output to, or null if output is ignored.
* @param stdin Optional InputStream to read from as process input, or null
* if input is not needed.
* @param stdout Optional OutputStream to copy process output to, or null if
* output is ignored.
* @param stderr Optinoal OutputStream to copy process stderr output to, or
* null if output is ignored.
* @throws IOException If the system process could not be created.
* @see Process
*/
@@ -45,12 +51,17 @@ public class JseProcess {
this(Runtime.getRuntime().exec(cmd), stdin, stdout, stderr);
}
/** Construct a process around a command, with specified streams to redirect input and output to.
/**
* Construct a process around a command, with specified streams to redirect
* input and output to.
*
* @param cmd The command to execute, including arguments, if any
* @param stdin Optional InputStream to read from as process input, or null if input is not needed.
* @param stdout Optional OutputStream to copy process output to, or null if output is ignored.
* @param stderr Optinoal OutputStream to copy process stderr output to, or null if output is ignored.
* @param stdin Optional InputStream to read from as process input, or null
* if input is not needed.
* @param stdout Optional OutputStream to copy process output to, or null if
* output is ignored.
* @param stderr Optinoal OutputStream to copy process stderr output to, or
* null if output is ignored.
* @throws IOException If the system process could not be created.
* @see Process
*/
@@ -70,7 +81,9 @@ public class JseProcess {
return process.exitValue();
}
/** Wait for the process to complete, and all pending output to finish.
/**
* Wait for the process to complete, and all pending output to finish.
*
* @return The exit status.
* @throws InterruptedException
*/
@@ -87,8 +100,7 @@ public class JseProcess {
}
/** Create a thread to copy bytes from input to output. */
private Thread copyBytes(final InputStream input,
final OutputStream output, final InputStream ownedInput,
private Thread copyBytes(final InputStream input, final OutputStream output, final InputStream ownedInput,
final OutputStream ownedOutput) {
Thread t = (new CopyThread(output, ownedOutput, ownedInput, input));
t.start();
@@ -101,8 +113,7 @@ public class JseProcess {
private final InputStream ownedInput;
private final InputStream input;
private CopyThread(OutputStream output, OutputStream ownedOutput,
InputStream ownedInput, InputStream input) {
private CopyThread(OutputStream output, OutputStream ownedOutput, InputStream ownedInput, InputStream input) {
this.output = output;
this.ownedOutput = ownedOutput;
this.ownedInput = ownedInput;
@@ -114,7 +125,7 @@ public class JseProcess {
byte[] buf = new byte[1024];
int r;
try {
while ((r = input.read(buf)) >= 0) {
while ( (r = input.read(buf)) >= 0 ) {
output.write(buf, 0, r);
}
} finally {

View File

@@ -30,7 +30,7 @@ public class JseStringLib extends org.luaj.vm2.lib.StringLib {
protected String format(String src, double x) {
String out;
try {
out = String.format(src, new Object[] {Double.valueOf(x)});
out = String.format(src, new Object[] { Double.valueOf(x) });
} catch (Throwable e) {
out = super.format(src, x);
}

View File

@@ -21,7 +21,6 @@
******************************************************************************/
package org.luaj.vm2.lib.jse;
import java.lang.reflect.Array;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
@@ -38,40 +37,51 @@ import org.luaj.vm2.lib.LibFunction;
import org.luaj.vm2.lib.VarArgFunction;
/**
* Subclass of {@link LibFunction} which implements the features of the luajava package.
* Subclass of {@link LibFunction} which implements the features of the luajava
* package.
* <p>
* Luajava is an approach to mixing lua and java using simple functions that bind
* java classes and methods to lua dynamically. The API is documented on the
* <a href="http://www.keplerproject.org/luajava/">luajava</a> documentation pages.
* Luajava is an approach to mixing lua and java using simple functions that
* bind java classes and methods to lua dynamically. The API is documented on
* the <a href="http://www.keplerproject.org/luajava/">luajava</a> documentation
* pages.
*
* <p>
* Typically, this library is included as part of a call to
* {@link org.luaj.vm2.lib.jse.JsePlatform#standardGlobals()}
* <pre> {@code
*
* <pre>
* {
* &#64;code
* Globals globals = JsePlatform.standardGlobals();
* System.out.println( globals.get("luajava").get("bindClass").call( LuaValue.valueOf("java.lang.System") ).invokeMethod("currentTimeMillis") );
* } </pre>
* System.out.println(globals.get("luajava").get("bindClass").call(LuaValue.valueOf("java.lang.System"))
* .invokeMethod("currentTimeMillis"));
* }
* </pre>
* <p>
* To instantiate and use it directly,
* link it into your globals table via {@link Globals#load} using code such as:
* <pre> {@code
* To instantiate and use it directly, link it into your globals table via
* {@link Globals#load} using code such as:
*
* <pre>
* {
* &#64;code
* Globals globals = new Globals();
* globals.load(new JseBaseLib());
* globals.load(new PackageLib());
* globals.load(new LuajavaLib());
* globals.load(
* "sys = luajava.bindClass('java.lang.System')\n"+
* "print ( sys:currentTimeMillis() )\n", "main.lua" ).call();
* } </pre>
* globals.load("sys = luajava.bindClass('java.lang.System')\n" + "print ( sys:currentTimeMillis() )\n", "main.lua")
* .call();
* }
* </pre>
* <p>
*
* The {@code luajava} library is available
* on all JSE platforms via the call to {@link org.luaj.vm2.lib.jse.JsePlatform#standardGlobals()}
* and the luajava api's are simply invoked from lua.
* Because it makes extensive use of Java's reflection API, it is not available
* on JME, but can be used in Android applications.
* The {@code luajava} library is available on all JSE platforms via the call to
* {@link org.luaj.vm2.lib.jse.JsePlatform#standardGlobals()} and the luajava
* api's are simply invoked from lua. Because it makes extensive use of Java's
* reflection API, it is not available on JME, but can be used in Android
* applications.
* <p>
* This has been implemented to match as closely as possible the behavior in the corresponding library in C.
* This has been implemented to match as closely as possible the behavior in the
* corresponding library in C.
*
* @see LibFunction
* @see org.luaj.vm2.lib.jse.JsePlatform
@@ -79,7 +89,8 @@ import org.luaj.vm2.lib.VarArgFunction;
* @see LuaC
* @see CoerceJavaToLua
* @see CoerceLuaToJava
* @see <a href="http://www.keplerproject.org/luajava/manual.html#luareference">http://www.keplerproject.org/luajava/manual.html#luareference</a>
* @see <a href=
* "http://www.keplerproject.org/luajava/manual.html#luareference">http://www.keplerproject.org/luajava/manual.html#luareference</a>
*/
public class LuajavaLib extends VarArgFunction {
@@ -90,13 +101,7 @@ public class LuajavaLib extends VarArgFunction {
static final int CREATEPROXY = 4;
static final int LOADLIB = 5;
static final String[] NAMES = {
"bindClass",
"newInstance",
"new",
"createProxy",
"loadLib",
};
static final String[] NAMES = { "bindClass", "newInstance", "new", "createProxy", "loadLib", };
static final int METHOD_MODIFIERS_VARARGS = 0x80;
@@ -105,14 +110,15 @@ public class LuajavaLib extends VarArgFunction {
public Varargs invoke(Varargs args) {
try {
switch ( opcode ) {
switch (opcode) {
case INIT: {
// LuaValue modname = args.arg1();
LuaValue env = args.arg(2);
LuaTable t = new LuaTable();
bind( t, this.getClass(), NAMES, BINDCLASS );
bind(t, this.getClass(), NAMES, BINDCLASS);
env.set("luajava", t);
if (!env.get("package").isnil()) env.get("package").get("loaded").set("luajava", t);
if (!env.get("package").isnil())
env.get("package").get("loaded").set("luajava", t);
return t;
}
case BINDCLASS: {
@@ -123,20 +129,21 @@ public class LuajavaLib extends VarArgFunction {
case NEW: {
// get constructor
final LuaValue c = args.checkvalue(1);
final Class clazz = (opcode==NEWINSTANCE? classForName(c.tojstring()): (Class) c.checkuserdata(Class.class));
final Class clazz = (opcode == NEWINSTANCE? classForName(c.tojstring())
: (Class) c.checkuserdata(Class.class));
final Varargs consargs = args.subargs(2);
return JavaClass.forClass(clazz).getConstructor().invoke(consargs);
}
case CREATEPROXY: {
final int niface = args.narg()-1;
if ( niface <= 0 )
if (niface <= 0)
throw new LuaError("no interfaces");
final LuaValue lobj = args.checktable(niface+1);
// get the interfaces
final Class[] ifaces = new Class[niface];
for ( int i=0; i<niface; i++ )
for (int i = 0; i < niface; i++)
ifaces[i] = classForName(args.checkjstring(i+1));
// create the invocation handler
@@ -146,7 +153,7 @@ public class LuajavaLib extends VarArgFunction {
Object proxy = Proxy.newProxyInstance(getClass().getClassLoader(), ifaces, handler);
// return the proxy
return LuaValue.userdataOf( proxy );
return LuaValue.userdataOf(proxy);
}
case LOADLIB: {
// get constructor
@@ -155,14 +162,14 @@ public class LuajavaLib extends VarArgFunction {
Class clazz = classForName(classname);
Method method = clazz.getMethod(methodname, new Class[] {});
Object result = method.invoke(clazz, new Object[] {});
if ( result instanceof LuaValue ) {
if (result instanceof LuaValue) {
return (LuaValue) result;
} else {
return NIL;
}
}
default:
throw new LuaError("not yet supported: "+this);
throw new LuaError("not yet supported: " + this);
}
} catch (LuaError e) {
throw e;
@@ -188,22 +195,22 @@ public class LuajavaLib extends VarArgFunction {
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
String name = method.getName();
LuaValue func = lobj.get(name);
if ( func.isnil() )
if (func.isnil())
return null;
boolean isvarargs = ((method.getModifiers() & METHOD_MODIFIERS_VARARGS) != 0);
int n = args!=null? args.length: 0;
int n = args != null? args.length: 0;
LuaValue[] v;
if ( isvarargs ) {
if (isvarargs) {
Object o = args[--n];
int m = Array.getLength( o );
int m = Array.getLength(o);
v = new LuaValue[n+m];
for ( int i=0; i<n; i++ )
for (int i = 0; i < n; i++)
v[i] = CoerceJavaToLua.coerce(args[i]);
for ( int i=0; i<m; i++ )
v[i+n] = CoerceJavaToLua.coerce(Array.get(o,i));
for (int i = 0; i < m; i++)
v[i+n] = CoerceJavaToLua.coerce(Array.get(o, i));
} else {
v = new LuaValue[n];
for ( int i=0; i<n; i++ )
for (int i = 0; i < n; i++)
v[i] = CoerceJavaToLua.coerce(args[i]);
}
LuaValue result = func.invoke(v).arg1();

View File

@@ -9,7 +9,7 @@ import org.luaj.vm2.Lua;
import org.luaj.vm2.Prototype;
public class BasicBlock {
int pc0,pc1; // range of program counter values for the block
int pc0, pc1; // range of program counter values for the block
BasicBlock[] prev; // previous basic blocks (0-n of these)
BasicBlock[] next; // next basic blocks (0, 1, or 2 of these)
boolean islive; // true if this block is used
@@ -20,22 +20,20 @@ public class BasicBlock {
public String toString() {
StringBuffer sb = new StringBuffer();
sb.append( (pc0+1)+"-"+(pc1+1)
+(prev!=null? " prv: "+str(prev,1): "")
+(next!=null? " nxt: "+str(next,0): "")
+"\n" );
sb.append((pc0+1) + "-" + (pc1+1) + (prev != null? " prv: " + str(prev, 1): "")
+ (next != null? " nxt: " + str(next, 0): "") + "\n");
return sb.toString();
}
private String str(BasicBlock[] b, int p) {
if ( b == null )
if (b == null)
return "";
StringBuffer sb = new StringBuffer();
sb.append("(");
for ( int i=0, n=b.length; i<n; i++ ) {
if ( i > 0 )
sb.append( "," );
sb.append( String.valueOf( p==1? b[i].pc1+1: b[i].pc0+1 ) );
for (int i = 0, n = b.length; i < n; i++) {
if (i > 0)
sb.append(",");
sb.append(String.valueOf(p == 1? b[i].pc1+1: b[i].pc0+1));
}
sb.append(")");
return sb.toString();
@@ -54,12 +52,12 @@ public class BasicBlock {
// create basic blocks
final BasicBlock[] blocks = new BasicBlock[n];
for ( int i=0; i<n; i++ ) {
for (int i = 0; i < n; i++) {
isbeg[i] = true;
BasicBlock b = new BasicBlock(p,i);
BasicBlock b = new BasicBlock(p, i);
blocks[i] = b;
while ( !isend[i] && i+1<n && !isbeg[i+1] )
blocks[b.pc1=++i] = b;
while ( !isend[i] && i+1 < n && !isbeg[i+1] )
blocks[b.pc1 = ++i] = b;
}
// count previous, next
@@ -68,7 +66,7 @@ public class BasicBlock {
visitBranches(p, new CountPrevNextVistor(isbeg, nnext, nprev));
// allocate and cross-reference
visitBranches( p, new AllocAndXRefVisitor(isbeg, nnext, nprev, blocks));
visitBranches(p, new AllocAndXRefVisitor(isbeg, nnext, nprev, blocks));
return blocks;
}
@@ -77,8 +75,7 @@ public class BasicBlock {
private final int[] nprev;
private final BasicBlock[] blocks;
private AllocAndXRefVisitor(boolean[] isbeg, int[] nnext, int[] nprev,
BasicBlock[] blocks) {
private AllocAndXRefVisitor(boolean[] isbeg, int[] nnext, int[] nprev, BasicBlock[] blocks) {
super(isbeg);
this.nnext = nnext;
this.nprev = nprev;
@@ -86,8 +83,10 @@ public class BasicBlock {
}
public void visitBranch(int pc0, int pc1) {
if ( blocks[pc0].next == null ) blocks[pc0].next = new BasicBlock[nnext[pc0]];
if ( blocks[pc1].prev == null ) blocks[pc1].prev = new BasicBlock[nprev[pc1]];
if (blocks[pc0].next == null)
blocks[pc0].next = new BasicBlock[nnext[pc0]];
if (blocks[pc1].prev == null)
blocks[pc1].prev = new BasicBlock[nprev[pc1]];
blocks[pc0].next[--nnext[pc0]] = blocks[pc1];
blocks[pc1].prev[--nprev[pc1]] = blocks[pc0];
}
@@ -129,82 +128,85 @@ public class BasicBlock {
abstract public static class BranchVisitor {
final boolean[] isbeg;
public BranchVisitor(boolean[] isbeg) {
this.isbeg = isbeg;
}
public void visitBranch( int frompc, int topc ) {}
public void visitReturn( int atpc ) {}
public void visitBranch(int frompc, int topc) {}
public void visitReturn(int atpc) {}
}
public static void visitBranches( Prototype p, BranchVisitor visitor ) {
int sbx,j,c;
public static void visitBranches(Prototype p, BranchVisitor visitor) {
int sbx, j, c;
int[] code = p.code;
int n = code.length;
for ( int i=0; i<n; i++ ) {
for (int i = 0; i < n; i++) {
int ins = code[i];
switch ( Lua.GET_OPCODE( ins ) ) {
switch (Lua.GET_OPCODE(ins)) {
case Lua.OP_LOADBOOL:
if ( 0 == Lua.GETARG_C(ins) )
if (0 == Lua.GETARG_C(ins))
break;
if ( Lua.GET_OPCODE(code[i+1]) == Lua.OP_JMP )
throw new IllegalArgumentException("OP_LOADBOOL followed by jump at "+i);
visitor.visitBranch( i, i+2 );
if (Lua.GET_OPCODE(code[i+1]) == Lua.OP_JMP)
throw new IllegalArgumentException("OP_LOADBOOL followed by jump at " + i);
visitor.visitBranch(i, i+2);
continue;
case Lua.OP_EQ:
case Lua.OP_LT:
case Lua.OP_LE:
case Lua.OP_TEST:
case Lua.OP_TESTSET:
if ( Lua.GET_OPCODE(code[i+1]) != Lua.OP_JMP )
throw new IllegalArgumentException("test not followed by jump at "+i);
if (Lua.GET_OPCODE(code[i+1]) != Lua.OP_JMP)
throw new IllegalArgumentException("test not followed by jump at " + i);
sbx = Lua.GETARG_sBx(code[i+1]);
++i;
j = i + sbx + 1;
visitor.visitBranch( i, j );
visitor.visitBranch( i, i+1 );
j = i+sbx+1;
visitor.visitBranch(i, j);
visitor.visitBranch(i, i+1);
continue;
case Lua.OP_TFORLOOP:
case Lua.OP_FORLOOP:
sbx = Lua.GETARG_sBx(ins);
j = i + sbx + 1;
visitor.visitBranch( i, j );
visitor.visitBranch( i, i+1 );
j = i+sbx+1;
visitor.visitBranch(i, j);
visitor.visitBranch(i, i+1);
continue;
case Lua.OP_JMP:
case Lua.OP_FORPREP:
sbx = Lua.GETARG_sBx(ins);
j = i + sbx + 1;
visitor.visitBranch( i, j );
j = i+sbx+1;
visitor.visitBranch(i, j);
continue;
case Lua.OP_TAILCALL:
case Lua.OP_RETURN:
visitor.visitReturn( i );
visitor.visitReturn(i);
continue;
}
if ( i+1<n && visitor.isbeg[i+1] )
visitor.visitBranch( i, i+1 );
if (i+1 < n && visitor.isbeg[i+1])
visitor.visitBranch(i, i+1);
}
}
public static BasicBlock[] findLiveBlocks(BasicBlock[] blocks) {
// add reachable blocks
Vector next = new Vector ();
next.addElement( blocks[0] );
while ( ! next.isEmpty() ) {
Vector next = new Vector();
next.addElement(blocks[0]);
while ( !next.isEmpty() ) {
BasicBlock b = (BasicBlock) next.elementAt(0);
next.removeElementAt(0);
if ( ! b.islive ) {
if (!b.islive) {
b.islive = true;
for ( int i=0, n=b.next!=null? b.next.length: 0; i<n; i++ )
if ( ! b.next[i].islive )
next.addElement( b.next[i] );
for (int i = 0, n = b.next != null? b.next.length: 0; i < n; i++)
if (!b.next[i].islive)
next.addElement(b.next[i]);
}
}
// create list in natural order
Vector list = new Vector();
for ( int i=0; i<blocks.length; i=blocks[i].pc1+1 )
if ( blocks[i].islive )
for (int i = 0; i < blocks.length; i = blocks[i].pc1+1)
if (blocks[i].islive)
list.addElement(blocks[i]);
// convert to array

View File

@@ -89,10 +89,9 @@ public class JavaBuilder {
private static final ObjectType TYPE_BUFFER = new ObjectType(STR_BUFFER);
private static final ObjectType TYPE_STRING = new ObjectType(STR_STRING);
private static final ArrayType TYPE_LOCALUPVALUE = new ArrayType( TYPE_LUAVALUE, 1 );
private static final ArrayType TYPE_CHARARRAY = new ArrayType( Type.CHAR, 1 );
private static final ArrayType TYPE_STRINGARRAY = new ArrayType( TYPE_STRING, 1 );
private static final ArrayType TYPE_LOCALUPVALUE = new ArrayType(TYPE_LUAVALUE, 1);
private static final ArrayType TYPE_CHARARRAY = new ArrayType(Type.CHAR, 1);
private static final ArrayType TYPE_STRINGARRAY = new ArrayType(TYPE_STRING, 1);
private static final String STR_FUNCV = VarArgFunction.class.getName();
private static final String STR_FUNC0 = ZeroArgFunction.class.getName();
@@ -110,8 +109,9 @@ public class JavaBuilder {
private static final Type[] ARG_TYPES_INT_VARARGS = { Type.INT, TYPE_VARARGS };
private static final Type[] ARG_TYPES_LUAVALUE_VARARGS = { TYPE_LUAVALUE, TYPE_VARARGS };
private static final Type[] ARG_TYPES_LUAVALUE_LUAVALUE_VARARGS = { TYPE_LUAVALUE, TYPE_LUAVALUE, TYPE_VARARGS };
private static final Type[] ARG_TYPES_LUAVALUEARRAY = { new ArrayType( TYPE_LUAVALUE, 1 ) };
private static final Type[] ARG_TYPES_LUAVALUEARRAY_VARARGS = { new ArrayType( TYPE_LUAVALUE, 1 ), TYPE_VARARGS };
private static final Type[] ARG_TYPES_LUAVALUEARRAY = { new ArrayType(TYPE_LUAVALUE, 1) };
private static final Type[] ARG_TYPES_LUAVALUEARRAY_VARARGS = { new ArrayType(TYPE_LUAVALUE, 1),
TYPE_VARARGS };
private static final Type[] ARG_TYPES_LUAVALUE_LUAVALUE_LUAVALUE = { TYPE_LUAVALUE, TYPE_LUAVALUE, TYPE_LUAVALUE };
private static final Type[] ARG_TYPES_VARARGS = { TYPE_VARARGS };
private static final Type[] ARG_TYPES_LUAVALUE_LUAVALUE = { TYPE_LUAVALUE, TYPE_LUAVALUE };
@@ -123,13 +123,14 @@ public class JavaBuilder {
// names, arg types for main prototype classes
private static final String[] SUPER_NAME_N = { STR_FUNC0, STR_FUNC1, STR_FUNC2, STR_FUNC3, STR_FUNCV, };
private static final ObjectType[] RETURN_TYPE_N = { TYPE_LUAVALUE, TYPE_LUAVALUE, TYPE_LUAVALUE, TYPE_LUAVALUE, TYPE_VARARGS, };
private static final Type[][] ARG_TYPES_N = { ARG_TYPES_NONE, ARG_TYPES_LUAVALUE, ARG_TYPES_LUAVALUE_LUAVALUE, ARG_TYPES_LUAVALUE_LUAVALUE_LUAVALUE, ARG_TYPES_VARARGS, };
private static final String[][] ARG_NAMES_N = { {}, {"arg"}, {"arg1","arg2"}, {"arg1","arg2","arg3"}, {"args"}, };
private static final ObjectType[] RETURN_TYPE_N = { TYPE_LUAVALUE, TYPE_LUAVALUE, TYPE_LUAVALUE, TYPE_LUAVALUE,
TYPE_VARARGS, };
private static final Type[][] ARG_TYPES_N = { ARG_TYPES_NONE, ARG_TYPES_LUAVALUE, ARG_TYPES_LUAVALUE_LUAVALUE,
ARG_TYPES_LUAVALUE_LUAVALUE_LUAVALUE, ARG_TYPES_VARARGS, };
private static final String[][] ARG_NAMES_N = { {}, { "arg" }, { "arg1", "arg2" }, { "arg1", "arg2", "arg3" },
{ "args" }, };
private static final String[] METH_NAME_N = { "call", "call", "call", "call", "onInvoke", };
// varable naming
private static final String PREFIX_CONSTANT = "k";
private static final String PREFIX_UPVALUE = "u";
@@ -174,21 +175,21 @@ public class JavaBuilder {
// what class to inherit from
superclassType = p.numparams;
if ( p.is_vararg != 0 || superclassType >= SUPERTYPE_VARARGS )
if (p.is_vararg != 0 || superclassType >= SUPERTYPE_VARARGS)
superclassType = SUPERTYPE_VARARGS;
for ( int i=0, n=p.code.length; i<n; i++ ) {
for (int i = 0, n = p.code.length; i < n; i++) {
int inst = p.code[i];
int o = Lua.GET_OPCODE(inst);
if ( (o == Lua.OP_TAILCALL) ||
((o == Lua.OP_RETURN) && (Lua.GETARG_B(inst) < 1 || Lua.GETARG_B(inst) > 2)) ) {
if ((o == Lua.OP_TAILCALL)
|| ((o == Lua.OP_RETURN) && (Lua.GETARG_B(inst) < 1 || Lua.GETARG_B(inst) > 2))) {
superclassType = SUPERTYPE_VARARGS;
break;
}
}
// create class generator
cg = new ClassGen(classname, SUPER_NAME_N[superclassType], filename,
Constants.ACC_PUBLIC | Constants.ACC_SUPER, null);
cg = new ClassGen(classname, SUPER_NAME_N[superclassType], filename, Constants.ACC_PUBLIC | Constants.ACC_SUPER,
null);
cp = cg.getConstantPool(); // cg creates constant pool
// main instruction lists
@@ -197,20 +198,19 @@ public class JavaBuilder {
main = new InstructionList();
// create the fields
for ( int i=0; i<p.upvalues.length; i++ ) {
boolean isrw = pi.isReadWriteUpvalue( pi.upvals[i] );
for (int i = 0; i < p.upvalues.length; i++) {
boolean isrw = pi.isReadWriteUpvalue(pi.upvals[i]);
Type uptype = isrw? (Type) TYPE_LOCALUPVALUE: (Type) TYPE_LUAVALUE;
FieldGen fg = new FieldGen(0, uptype, upvalueName(i), cp);
cg.addField(fg.getField());
}
// create the method
mg = new MethodGen( Constants.ACC_PUBLIC | Constants.ACC_FINAL, // access flags
mg = new MethodGen(Constants.ACC_PUBLIC | Constants.ACC_FINAL, // access flags
RETURN_TYPE_N[superclassType], // return type
ARG_TYPES_N[superclassType], // argument types
ARG_NAMES_N[superclassType], // arg names
METH_NAME_N[superclassType],
STR_LUAVALUE, // method, defining class
METH_NAME_N[superclassType], STR_LUAVALUE, // method, defining class
main, cp);
// initialize the values in the slots
@@ -227,24 +227,25 @@ public class JavaBuilder {
public void initializeSlots() {
int slot = 0;
createUpvalues(-1, 0, p.maxstacksize);
if ( superclassType == SUPERTYPE_VARARGS ) {
for ( slot=0; slot<p.numparams; slot++ ) {
if ( pi.isInitialValueUsed(slot) ) {
if (superclassType == SUPERTYPE_VARARGS) {
for (slot = 0; slot < p.numparams; slot++) {
if (pi.isInitialValueUsed(slot)) {
append(new ALOAD(1));
append(new PUSH(cp, slot+1));
append(factory.createInvoke(STR_VARARGS, "arg", TYPE_LUAVALUE, ARG_TYPES_INT, Constants.INVOKEVIRTUAL));
append(factory.createInvoke(STR_VARARGS, "arg", TYPE_LUAVALUE, ARG_TYPES_INT,
Constants.INVOKEVIRTUAL));
storeLocal(-1, slot);
}
}
append(new ALOAD(1));
append(new PUSH(cp, 1 + p.numparams));
append(new PUSH(cp, 1+p.numparams));
append(factory.createInvoke(STR_VARARGS, "subargs", TYPE_VARARGS, ARG_TYPES_INT, Constants.INVOKEVIRTUAL));
append(new ASTORE(1));
} else {
// fixed arg function between 0 and 3 arguments
for ( slot=0; slot<p.numparams; slot++ ) {
this.plainSlotVars.put( Integer.valueOf(slot), Integer.valueOf(1+slot) );
if ( pi.isUpvalueCreate(-1, slot) ) {
for (slot = 0; slot < p.numparams; slot++) {
this.plainSlotVars.put(Integer.valueOf(slot), Integer.valueOf(1+slot));
if (pi.isUpvalueCreate(-1, slot)) {
append(new ALOAD(1+slot));
storeLocal(-1, slot);
}
@@ -253,8 +254,8 @@ public class JavaBuilder {
// nil parameters
// TODO: remove this for lua 5.2, not needed
for ( ; slot<p.maxstacksize; slot++ ) {
if ( pi.isInitialValueUsed(slot) ) {
for (; slot < p.maxstacksize; slot++) {
if (pi.isInitialValueUsed(slot)) {
loadNil();
storeLocal(-1, slot);
}
@@ -264,9 +265,8 @@ public class JavaBuilder {
public byte[] completeClass(boolean genmain) {
// add class initializer
if ( ! init.isEmpty() ) {
MethodGen mg = new MethodGen(Constants.ACC_STATIC, Type.VOID,
ARG_TYPES_NONE, new String[] {}, "<clinit>",
if (!init.isEmpty()) {
MethodGen mg = new MethodGen(Constants.ACC_STATIC, Type.VOID, ARG_TYPES_NONE, new String[] {}, "<clinit>",
cg.getClassName(), init, cg.getConstantPool());
init.append(InstructionConstants.RETURN);
mg.setMaxStack();
@@ -285,18 +285,18 @@ public class JavaBuilder {
// add initupvalue1(LuaValue env) to initialize environment for main chunk
if (p.upvalues.length == 1 && superclassType == SUPERTYPE_VARARGS) {
MethodGen mg = new MethodGen( Constants.ACC_PUBLIC | Constants.ACC_FINAL, // access flags
MethodGen mg = new MethodGen(Constants.ACC_PUBLIC | Constants.ACC_FINAL, // access flags
Type.VOID, // return type
ARG_TYPES_LUAVALUE, // argument types
new String[] { "env" }, // arg names
"initupvalue1",
STR_LUAVALUE, // method, defining class
"initupvalue1", STR_LUAVALUE, // method, defining class
main, cp);
boolean isrw = pi.isReadWriteUpvalue( pi.upvals[0] );
boolean isrw = pi.isReadWriteUpvalue(pi.upvals[0]);
append(InstructionConstants.THIS);
append(new ALOAD(1));
if ( isrw ) {
append(factory.createInvoke(classname, "newupl", TYPE_LOCALUPVALUE, ARG_TYPES_LUAVALUE, Constants.INVOKESTATIC));
if (isrw) {
append(factory.createInvoke(classname, "newupl", TYPE_LOCALUPVALUE, ARG_TYPES_LUAVALUE,
Constants.INVOKESTATIC));
append(factory.createFieldAccess(classname, upvalueName(0), TYPE_LOCALUPVALUE, Constants.PUTFIELD));
} else {
append(factory.createFieldAccess(classname, upvalueName(0), TYPE_LUAVALUE, Constants.PUTFIELD));
@@ -309,32 +309,32 @@ public class JavaBuilder {
// add main function so class is invokable from the java command line
if (genmain) {
MethodGen mg = new MethodGen( Constants.ACC_PUBLIC | Constants.ACC_STATIC, // access flags
MethodGen mg = new MethodGen(Constants.ACC_PUBLIC | Constants.ACC_STATIC, // access flags
Type.VOID, // return type
ARG_TYPES_STRINGARRAY, // argument types
new String[] { "arg" }, // arg names
"main",
classname, // method, defining class
"main", classname, // method, defining class
main, cp);
append(factory.createNew(classname));
append(InstructionConstants.DUP);
append(factory.createInvoke(classname, Constants.CONSTRUCTOR_NAME, Type.VOID, ARG_TYPES_NONE, Constants.INVOKESPECIAL));
append(factory.createInvoke(classname, Constants.CONSTRUCTOR_NAME, Type.VOID, ARG_TYPES_NONE,
Constants.INVOKESPECIAL));
append(new ALOAD(0));
append(factory.createInvoke(STR_JSEPLATFORM, "luaMain", Type.VOID, ARG_TYPES_LUAVALUE_STRINGARRAY, Constants.INVOKESTATIC));
append(factory.createInvoke(STR_JSEPLATFORM, "luaMain", Type.VOID, ARG_TYPES_LUAVALUE_STRINGARRAY,
Constants.INVOKESTATIC));
append(InstructionConstants.RETURN);
mg.setMaxStack();
cg.addMethod(mg.getMethod());
main.dispose();
}
// convert to class bytes
try {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
cg.getJavaClass().dump(baos);
return baos.toByteArray();
} catch ( IOException ioe ) {
throw new RuntimeException("JavaClass.dump() threw "+ioe);
} catch (IOException ioe) {
throw new RuntimeException("JavaClass.dump() threw " + ioe);
}
}
@@ -359,13 +359,14 @@ public class JavaBuilder {
append(factory.createFieldAccess(STR_LUAVALUE, field, TYPE_LUABOOLEAN, Constants.GETSTATIC));
}
private Map<Integer,Integer> plainSlotVars = new HashMap<Integer,Integer>();
private Map<Integer,Integer> upvalueSlotVars = new HashMap<Integer,Integer>();
private Map<Integer,LocalVariableGen> localVarGenBySlot = new HashMap<Integer,LocalVariableGen>();
private int findSlot( int slot, Map<Integer,Integer> map, String prefix, Type type ) {
private Map<Integer, Integer> plainSlotVars = new HashMap<Integer, Integer>();
private Map<Integer, Integer> upvalueSlotVars = new HashMap<Integer, Integer>();
private Map<Integer, LocalVariableGen> localVarGenBySlot = new HashMap<Integer, LocalVariableGen>();
private int findSlot(int slot, Map<Integer, Integer> map, String prefix, Type type) {
Integer islot = Integer.valueOf(slot);
if ( map.containsKey(islot) )
return ((Integer)map.get(islot)).intValue();
if (map.containsKey(islot))
return ((Integer) map.get(islot)).intValue();
String name = prefix+slot;
LocalVariableGen local = mg.addLocalVariable(name, type, null, null);
int index = local.getIndex();
@@ -373,15 +374,15 @@ public class JavaBuilder {
localVarGenBySlot.put(islot, local);
return index;
}
private int findSlotIndex( int slot, boolean isupvalue ) {
return isupvalue?
findSlot( slot, upvalueSlotVars, PREFIX_UPVALUE_SLOT, TYPE_LOCALUPVALUE ):
findSlot( slot, plainSlotVars, PREFIX_PLAIN_SLOT, TYPE_LUAVALUE );
private int findSlotIndex(int slot, boolean isupvalue) {
return isupvalue? findSlot(slot, upvalueSlotVars, PREFIX_UPVALUE_SLOT, TYPE_LOCALUPVALUE)
: findSlot(slot, plainSlotVars, PREFIX_PLAIN_SLOT, TYPE_LUAVALUE);
}
public void loadLocal(int pc, int slot) {
boolean isupval = pi.isUpvalueRefer(pc, slot);
int index = findSlotIndex( slot, isupval );
int index = findSlotIndex(slot, isupval);
append(new ALOAD(index));
if (isupval) {
append(new PUSH(cp, 0));
@@ -391,11 +392,12 @@ public class JavaBuilder {
public void storeLocal(int pc, int slot) {
boolean isupval = pi.isUpvalueAssign(pc, slot);
int index = findSlotIndex( slot, isupval );
int index = findSlotIndex(slot, isupval);
if (isupval) {
boolean isupcreate = pi.isUpvalueCreate(pc, slot);
if ( isupcreate ) {
append(factory.createInvoke(classname, "newupe", TYPE_LOCALUPVALUE, ARG_TYPES_NONE, Constants.INVOKESTATIC));
if (isupcreate) {
append(factory.createInvoke(classname, "newupe", TYPE_LOCALUPVALUE, ARG_TYPES_NONE,
Constants.INVOKESTATIC));
append(InstructionConstants.DUP);
append(new ASTORE(index));
} else {
@@ -411,12 +413,13 @@ public class JavaBuilder {
}
public void createUpvalues(int pc, int firstslot, int numslots) {
for ( int i=0; i<numslots; i++ ) {
int slot = firstslot + i;
for (int i = 0; i < numslots; i++) {
int slot = firstslot+i;
boolean isupcreate = pi.isUpvalueCreate(pc, slot);
if ( isupcreate ) {
int index = findSlotIndex( slot, true );
append(factory.createInvoke(classname, "newupn", TYPE_LOCALUPVALUE, ARG_TYPES_NONE, Constants.INVOKESTATIC));
if (isupcreate) {
int index = findSlotIndex(slot, true);
append(factory.createInvoke(classname, "newupn", TYPE_LOCALUPVALUE, ARG_TYPES_NONE,
Constants.INVOKESTATIC));
append(new ASTORE(index));
}
}
@@ -424,11 +427,12 @@ public class JavaBuilder {
public void convertToUpvalue(int pc, int slot) {
boolean isupassign = pi.isUpvalueAssign(pc, slot);
if ( isupassign ) {
int index = findSlotIndex( slot, false );
if (isupassign) {
int index = findSlotIndex(slot, false);
append(new ALOAD(index));
append(factory.createInvoke(classname, "newupl", TYPE_LOCALUPVALUE, ARG_TYPES_LUAVALUE, Constants.INVOKESTATIC));
int upindex = findSlotIndex( slot, true );
append(factory.createInvoke(classname, "newupl", TYPE_LOCALUPVALUE, ARG_TYPES_LUAVALUE,
Constants.INVOKESTATIC));
int upindex = findSlotIndex(slot, true);
append(new ASTORE(upindex));
}
}
@@ -438,11 +442,11 @@ public class JavaBuilder {
}
public void loadUpvalue(int upindex) {
boolean isrw = pi.isReadWriteUpvalue( pi.upvals[upindex] );
boolean isrw = pi.isReadWriteUpvalue(pi.upvals[upindex]);
append(InstructionConstants.THIS);
if ( isrw ) {
if (isrw) {
append(factory.createFieldAccess(classname, upvalueName(upindex), TYPE_LOCALUPVALUE, Constants.GETFIELD));
append(new PUSH(cp,0));
append(new PUSH(cp, 0));
append(InstructionConstants.AALOAD);
} else {
append(factory.createFieldAccess(classname, upvalueName(upindex), TYPE_LUAVALUE, Constants.GETFIELD));
@@ -450,11 +454,11 @@ public class JavaBuilder {
}
public void storeUpvalue(int pc, int upindex, int slot) {
boolean isrw = pi.isReadWriteUpvalue( pi.upvals[upindex] );
boolean isrw = pi.isReadWriteUpvalue(pi.upvals[upindex]);
append(InstructionConstants.THIS);
if ( isrw ) {
if (isrw) {
append(factory.createFieldAccess(classname, upvalueName(upindex), TYPE_LOCALUPVALUE, Constants.GETFIELD));
append(new PUSH(cp,0));
append(new PUSH(cp, 0));
loadLocal(pc, slot);
append(InstructionConstants.AASTORE);
} else {
@@ -463,8 +467,7 @@ public class JavaBuilder {
}
}
public void newTable( int b, int c ) {
public void newTable(int b, int c) {
append(new PUSH(cp, b));
append(new PUSH(cp, c));
append(factory.createInvoke(STR_LUAVALUE, "tableOf", TYPE_LUATABLE, ARG_TYPES_INT_INT, Constants.INVOKESTATIC));
@@ -480,7 +483,7 @@ public class JavaBuilder {
}
public void arg(int argindex) {
if ( argindex == 1 ) {
if (argindex == 1) {
append(factory.createInvoke(STR_VARARGS, "arg1", TYPE_LUAVALUE, ARG_TYPES_NONE, Constants.INVOKEVIRTUAL));
} else {
append(new PUSH(cp, argindex));
@@ -489,7 +492,7 @@ public class JavaBuilder {
}
private int getVarresultIndex() {
if ( varresult == null )
if (varresult == null)
varresult = mg.addLocalVariable(NAME_VARRESULT, TYPE_VARARGS, null, null);
return varresult.getIndex();
}
@@ -512,16 +515,23 @@ public class JavaBuilder {
}
public void setTable() {
append(factory.createInvoke(STR_LUAVALUE, "set", Type.VOID, ARG_TYPES_LUAVALUE_LUAVALUE, Constants.INVOKEVIRTUAL));
append(
factory.createInvoke(STR_LUAVALUE, "set", Type.VOID, ARG_TYPES_LUAVALUE_LUAVALUE, Constants.INVOKEVIRTUAL));
}
public void unaryop(int o) {
String op;
switch (o) {
default:
case Lua.OP_UNM: op = "neg"; break;
case Lua.OP_NOT: op = "not"; break;
case Lua.OP_LEN: op = "len"; break;
case Lua.OP_UNM:
op = "neg";
break;
case Lua.OP_NOT:
op = "not";
break;
case Lua.OP_LEN:
op = "len";
break;
}
append(factory.createInvoke(STR_LUAVALUE, op, TYPE_LUAVALUE, Type.NO_ARGS, Constants.INVOKEVIRTUAL));
}
@@ -530,12 +540,24 @@ public class JavaBuilder {
String op;
switch (o) {
default:
case Lua.OP_ADD: op = "add"; break;
case Lua.OP_SUB: op = "sub"; break;
case Lua.OP_MUL: op = "mul"; break;
case Lua.OP_DIV: op = "div"; break;
case Lua.OP_MOD: op = "mod"; break;
case Lua.OP_POW: op = "pow"; break;
case Lua.OP_ADD:
op = "add";
break;
case Lua.OP_SUB:
op = "sub";
break;
case Lua.OP_MUL:
op = "mul";
break;
case Lua.OP_DIV:
op = "div";
break;
case Lua.OP_MOD:
op = "mod";
break;
case Lua.OP_POW:
op = "pow";
break;
}
append(factory.createInvoke(STR_LUAVALUE, op, TYPE_LUAVALUE, ARG_TYPES_LUAVALUE, Constants.INVOKEVIRTUAL));
}
@@ -544,9 +566,15 @@ public class JavaBuilder {
String op;
switch (o) {
default:
case Lua.OP_EQ: op = "eq_b"; break;
case Lua.OP_LT: op = "lt_b"; break;
case Lua.OP_LE: op = "lteq_b"; break;
case Lua.OP_EQ:
op = "eq_b";
break;
case Lua.OP_LT:
op = "lt_b";
break;
case Lua.OP_LE:
op = "lteq_b";
break;
}
append(factory.createInvoke(STR_LUAVALUE, op, Type.BOOLEAN, ARG_TYPES_LUAVALUE, Constants.INVOKEVIRTUAL));
}
@@ -568,13 +596,14 @@ public class JavaBuilder {
}
public void testForLoop() {
append(factory.createInvoke(STR_LUAVALUE, "testfor_b", Type.BOOLEAN, ARG_TYPES_LUAVALUE_LUAVALUE, Constants.INVOKEVIRTUAL));
append(factory.createInvoke(STR_LUAVALUE, "testfor_b", Type.BOOLEAN, ARG_TYPES_LUAVALUE_LUAVALUE,
Constants.INVOKEVIRTUAL));
}
public void loadArrayArgs(int pc, int firstslot, int nargs) {
append(new PUSH(cp, nargs));
append(new ANEWARRAY(cp.addClass(STR_LUAVALUE)));
for ( int i=0; i<nargs; i++ ) {
for (int i = 0; i < nargs; i++) {
append(InstructionConstants.DUP);
append(new PUSH(cp, i));
loadLocal(pc, firstslot++);
@@ -583,56 +612,94 @@ public class JavaBuilder {
}
public void newVarargs(int pc, int firstslot, int nargs) {
switch ( nargs ) {
case 0: loadNone();
switch (nargs) {
case 0:
loadNone();
break;
case 1: loadLocal(pc, firstslot);
case 1:
loadLocal(pc, firstslot);
break;
case 2: loadLocal(pc, firstslot); loadLocal(pc, firstslot+1);
append(factory.createInvoke(STR_LUAVALUE, "varargsOf", TYPE_VARARGS, ARG_TYPES_LUAVALUE_VARARGS, Constants.INVOKESTATIC));
case 2:
loadLocal(pc, firstslot);
loadLocal(pc, firstslot+1);
append(factory.createInvoke(STR_LUAVALUE, "varargsOf", TYPE_VARARGS, ARG_TYPES_LUAVALUE_VARARGS,
Constants.INVOKESTATIC));
break;
case 3: loadLocal(pc, firstslot); loadLocal(pc, firstslot+1); loadLocal(pc, firstslot+2);
append(factory.createInvoke(STR_LUAVALUE, "varargsOf", TYPE_VARARGS, ARG_TYPES_LUAVALUE_LUAVALUE_VARARGS, Constants.INVOKESTATIC));
case 3:
loadLocal(pc, firstslot);
loadLocal(pc, firstslot+1);
loadLocal(pc, firstslot+2);
append(factory.createInvoke(STR_LUAVALUE, "varargsOf", TYPE_VARARGS, ARG_TYPES_LUAVALUE_LUAVALUE_VARARGS,
Constants.INVOKESTATIC));
break;
default:
loadArrayArgs(pc, firstslot, nargs);
append(factory.createInvoke(STR_LUAVALUE, "varargsOf", TYPE_VARARGS, ARG_TYPES_LUAVALUEARRAY, Constants.INVOKESTATIC));
append(factory.createInvoke(STR_LUAVALUE, "varargsOf", TYPE_VARARGS, ARG_TYPES_LUAVALUEARRAY,
Constants.INVOKESTATIC));
break;
}
}
public void newVarargsVarresult(int pc, int firstslot, int nslots) {
loadArrayArgs(pc, firstslot, nslots );
loadArrayArgs(pc, firstslot, nslots);
loadVarresult();
append(factory.createInvoke(STR_LUAVALUE, "varargsOf", TYPE_VARARGS, ARG_TYPES_LUAVALUEARRAY_VARARGS, Constants.INVOKESTATIC));
append(factory.createInvoke(STR_LUAVALUE, "varargsOf", TYPE_VARARGS, ARG_TYPES_LUAVALUEARRAY_VARARGS,
Constants.INVOKESTATIC));
}
public void call(int nargs) {
switch ( nargs ) {
case 0: append(factory.createInvoke(STR_LUAVALUE, "call", TYPE_LUAVALUE, ARG_TYPES_NONE, Constants.INVOKEVIRTUAL)); break;
case 1: append(factory.createInvoke(STR_LUAVALUE, "call", TYPE_LUAVALUE, ARG_TYPES_LUAVALUE, Constants.INVOKEVIRTUAL)); break;
case 2: append(factory.createInvoke(STR_LUAVALUE, "call", TYPE_LUAVALUE, ARG_TYPES_LUAVALUE_LUAVALUE, Constants.INVOKEVIRTUAL)); break;
case 3: append(factory.createInvoke(STR_LUAVALUE, "call", TYPE_LUAVALUE, ARG_TYPES_LUAVALUE_LUAVALUE_LUAVALUE, Constants.INVOKEVIRTUAL)); break;
default: throw new IllegalArgumentException("can't call with "+nargs+" args");
switch (nargs) {
case 0:
append(factory.createInvoke(STR_LUAVALUE, "call", TYPE_LUAVALUE, ARG_TYPES_NONE, Constants.INVOKEVIRTUAL));
break;
case 1:
append(
factory.createInvoke(STR_LUAVALUE, "call", TYPE_LUAVALUE, ARG_TYPES_LUAVALUE, Constants.INVOKEVIRTUAL));
break;
case 2:
append(factory.createInvoke(STR_LUAVALUE, "call", TYPE_LUAVALUE, ARG_TYPES_LUAVALUE_LUAVALUE,
Constants.INVOKEVIRTUAL));
break;
case 3:
append(factory.createInvoke(STR_LUAVALUE, "call", TYPE_LUAVALUE, ARG_TYPES_LUAVALUE_LUAVALUE_LUAVALUE,
Constants.INVOKEVIRTUAL));
break;
default:
throw new IllegalArgumentException("can't call with " + nargs + " args");
}
}
public void newTailcallVarargs() {
append(factory.createInvoke(STR_LUAVALUE, "tailcallOf", TYPE_VARARGS, ARG_TYPES_LUAVALUE_VARARGS, Constants.INVOKESTATIC));
append(factory.createInvoke(STR_LUAVALUE, "tailcallOf", TYPE_VARARGS, ARG_TYPES_LUAVALUE_VARARGS,
Constants.INVOKESTATIC));
}
public void invoke(int nargs) {
switch ( nargs ) {
case -1: append(factory.createInvoke(STR_LUAVALUE, "invoke", TYPE_VARARGS, ARG_TYPES_VARARGS, Constants.INVOKEVIRTUAL)); break;
case 0: append(factory.createInvoke(STR_LUAVALUE, "invoke", TYPE_VARARGS, ARG_TYPES_NONE, Constants.INVOKEVIRTUAL)); break;
case 1: append(factory.createInvoke(STR_LUAVALUE, "invoke", TYPE_VARARGS, ARG_TYPES_VARARGS, Constants.INVOKEVIRTUAL)); break;
case 2: append(factory.createInvoke(STR_LUAVALUE, "invoke", TYPE_VARARGS, ARG_TYPES_LUAVALUE_VARARGS, Constants.INVOKEVIRTUAL)); break;
case 3: append(factory.createInvoke(STR_LUAVALUE, "invoke", TYPE_VARARGS, ARG_TYPES_LUAVALUE_LUAVALUE_VARARGS, Constants.INVOKEVIRTUAL)); break;
default: throw new IllegalArgumentException("can't invoke with "+nargs+" args");
switch (nargs) {
case -1:
append(
factory.createInvoke(STR_LUAVALUE, "invoke", TYPE_VARARGS, ARG_TYPES_VARARGS, Constants.INVOKEVIRTUAL));
break;
case 0:
append(factory.createInvoke(STR_LUAVALUE, "invoke", TYPE_VARARGS, ARG_TYPES_NONE, Constants.INVOKEVIRTUAL));
break;
case 1:
append(
factory.createInvoke(STR_LUAVALUE, "invoke", TYPE_VARARGS, ARG_TYPES_VARARGS, Constants.INVOKEVIRTUAL));
break;
case 2:
append(factory.createInvoke(STR_LUAVALUE, "invoke", TYPE_VARARGS, ARG_TYPES_LUAVALUE_VARARGS,
Constants.INVOKEVIRTUAL));
break;
case 3:
append(factory.createInvoke(STR_LUAVALUE, "invoke", TYPE_VARARGS, ARG_TYPES_LUAVALUE_LUAVALUE_VARARGS,
Constants.INVOKEVIRTUAL));
break;
default:
throw new IllegalArgumentException("can't invoke with " + nargs + " args");
}
}
// ------------------------ closures ------------------------
public void closureCreate(String protoname) {
@@ -642,7 +709,7 @@ public class JavaBuilder {
}
public void closureInitUpvalueFromUpvalue(String protoname, int newup, int upindex) {
boolean isrw = pi.isReadWriteUpvalue( pi.upvals[upindex] );
boolean isrw = pi.isReadWriteUpvalue(pi.upvals[upindex]);
Type uptype = isrw? (Type) TYPE_LOCALUPVALUE: (Type) TYPE_LUAVALUE;
String srcname = upvalueName(upindex);
String destname = upvalueName(newup);
@@ -652,86 +719,78 @@ public class JavaBuilder {
}
public void closureInitUpvalueFromLocal(String protoname, int newup, int pc, int srcslot) {
boolean isrw = pi.isReadWriteUpvalue( pi.vars[srcslot][pc].upvalue );
boolean isrw = pi.isReadWriteUpvalue(pi.vars[srcslot][pc].upvalue);
Type uptype = isrw? (Type) TYPE_LOCALUPVALUE: (Type) TYPE_LUAVALUE;
String destname = upvalueName(newup);
int index = findSlotIndex( srcslot, isrw );
int index = findSlotIndex(srcslot, isrw);
append(new ALOAD(index));
append(factory.createFieldAccess(protoname, destname, uptype, Constants.PUTFIELD));
}
private Map<LuaValue,String> constants = new HashMap<LuaValue,String>();
private Map<LuaValue, String> constants = new HashMap<LuaValue, String>();
public void loadConstant(LuaValue value) {
switch ( value.type() ) {
switch (value.type()) {
case LuaValue.TNIL:
loadNil();
break;
case LuaValue.TBOOLEAN:
loadBoolean( value.toboolean() );
loadBoolean(value.toboolean());
break;
case LuaValue.TNUMBER:
case LuaValue.TSTRING:
String name = (String) constants.get(value);
if ( name == null ) {
name = value.type() == LuaValue.TNUMBER?
value.isinttype()?
createLuaIntegerField(value.checkint()):
createLuaDoubleField(value.checkdouble()):
createLuaStringField(value.checkstring());
if (name == null) {
name = value.type() == LuaValue.TNUMBER? value.isinttype()? createLuaIntegerField(value.checkint())
: createLuaDoubleField(value.checkdouble()): createLuaStringField(value.checkstring());
constants.put(value, name);
}
append(factory.createGetStatic(classname, name, TYPE_LUAVALUE));
break;
default:
throw new IllegalArgumentException("bad constant type: "+value.type());
throw new IllegalArgumentException("bad constant type: " + value.type());
}
}
private String createLuaIntegerField(int value) {
String name = PREFIX_CONSTANT+constants.size();
FieldGen fg = new FieldGen(Constants.ACC_STATIC | Constants.ACC_FINAL,
TYPE_LUAVALUE, name, cp);
FieldGen fg = new FieldGen(Constants.ACC_STATIC | Constants.ACC_FINAL, TYPE_LUAVALUE, name, cp);
cg.addField(fg.getField());
init.append(new PUSH(cp, value));
init.append(factory.createInvoke(STR_LUAVALUE, "valueOf",
TYPE_LUAINTEGER, ARG_TYPES_INT, Constants.INVOKESTATIC));
init.append(
factory.createInvoke(STR_LUAVALUE, "valueOf", TYPE_LUAINTEGER, ARG_TYPES_INT, Constants.INVOKESTATIC));
init.append(factory.createPutStatic(classname, name, TYPE_LUAVALUE));
return name;
}
private String createLuaDoubleField(double value) {
String name = PREFIX_CONSTANT+constants.size();
FieldGen fg = new FieldGen(Constants.ACC_STATIC | Constants.ACC_FINAL,
TYPE_LUAVALUE, name, cp);
FieldGen fg = new FieldGen(Constants.ACC_STATIC | Constants.ACC_FINAL, TYPE_LUAVALUE, name, cp);
cg.addField(fg.getField());
init.append(new PUSH(cp, value));
init.append(factory.createInvoke(STR_LUAVALUE, "valueOf",
TYPE_LUANUMBER, ARG_TYPES_DOUBLE, Constants.INVOKESTATIC));
init.append(
factory.createInvoke(STR_LUAVALUE, "valueOf", TYPE_LUANUMBER, ARG_TYPES_DOUBLE, Constants.INVOKESTATIC));
init.append(factory.createPutStatic(classname, name, TYPE_LUAVALUE));
return name;
}
private String createLuaStringField(LuaString value) {
String name = PREFIX_CONSTANT+constants.size();
FieldGen fg = new FieldGen(Constants.ACC_STATIC | Constants.ACC_FINAL,
TYPE_LUAVALUE, name, cp);
FieldGen fg = new FieldGen(Constants.ACC_STATIC | Constants.ACC_FINAL, TYPE_LUAVALUE, name, cp);
cg.addField(fg.getField());
LuaString ls = value.checkstring();
if ( ls.isValidUtf8() ) {
if (ls.isValidUtf8()) {
init.append(new PUSH(cp, value.tojstring()));
init.append(factory.createInvoke(STR_LUASTRING, "valueOf",
TYPE_LUASTRING, ARG_TYPES_STRING, Constants.INVOKESTATIC));
init.append(factory.createInvoke(STR_LUASTRING, "valueOf", TYPE_LUASTRING, ARG_TYPES_STRING,
Constants.INVOKESTATIC));
} else {
char[] c = new char[ls.m_length];
for ( int j=0; j<ls.m_length; j++ )
for (int j = 0; j < ls.m_length; j++)
c[j] = (char) (0xff & (int) (ls.m_bytes[ls.m_offset+j]));
init.append(new PUSH(cp, new String(c)));
init.append(factory.createInvoke(STR_STRING, "toCharArray",
TYPE_CHARARRAY, Type.NO_ARGS,
Constants.INVOKEVIRTUAL));
init.append(factory.createInvoke(STR_LUASTRING, "valueOf",
TYPE_LUASTRING, ARG_TYPES_CHARARRAY,
init.append(
factory.createInvoke(STR_STRING, "toCharArray", TYPE_CHARARRAY, Type.NO_ARGS, Constants.INVOKEVIRTUAL));
init.append(factory.createInvoke(STR_LUASTRING, "valueOf", TYPE_LUASTRING, ARG_TYPES_CHARARRAY,
Constants.INVOKESTATIC));
}
init.append(factory.createPutStatic(classname, name, TYPE_LUAVALUE));
@@ -743,32 +802,37 @@ public class JavaBuilder {
public static final int BRANCH_IFNE = 2;
public static final int BRANCH_IFEQ = 3;
public void addBranch( int pc, int branchType, int targetpc ) {
switch ( branchType ) {
public void addBranch(int pc, int branchType, int targetpc) {
switch (branchType) {
default:
case BRANCH_GOTO: branches[pc] = new GOTO(null); break;
case BRANCH_IFNE: branches[pc] = new IFNE(null); break;
case BRANCH_IFEQ: branches[pc] = new IFEQ(null); break;
case BRANCH_GOTO:
branches[pc] = new GOTO(null);
break;
case BRANCH_IFNE:
branches[pc] = new IFNE(null);
break;
case BRANCH_IFEQ:
branches[pc] = new IFEQ(null);
break;
}
targets[pc] = targetpc;
append(branches[pc]);
}
private void append( Instruction i ) {
conditionalSetBeginningOfLua( main.append(i) );
private void append(Instruction i) {
conditionalSetBeginningOfLua(main.append(i));
}
private void append( CompoundInstruction i ) {
conditionalSetBeginningOfLua( main.append(i) );
private void append(CompoundInstruction i) {
conditionalSetBeginningOfLua(main.append(i));
}
private void append( BranchInstruction i ) {
conditionalSetBeginningOfLua( main.append(i) );
private void append(BranchInstruction i) {
conditionalSetBeginningOfLua(main.append(i));
}
private void conditionalSetBeginningOfLua(InstructionHandle ih) {
if ( beginningOfLuaInstruction == null )
if (beginningOfLuaInstruction == null)
beginningOfLuaInstruction = ih;
}
@@ -784,7 +848,7 @@ public class JavaBuilder {
Integer islot = Integer.valueOf(slot);
if (localVarGenBySlot.containsKey(islot)) {
name = name.replaceAll("[^a-zA-Z0-9]", "_");
LocalVariableGen l = (LocalVariableGen)localVarGenBySlot.get(islot);
LocalVariableGen l = (LocalVariableGen) localVarGenBySlot.get(islot);
l.setEnd(lastInstrHandles[end_pc-1]);
if (start_pc > 1)
l.setStart(lastInstrHandles[start_pc-2]);
@@ -796,33 +860,37 @@ public class JavaBuilder {
int nc = p.code.length;
for (int pc = 0; pc < nc; pc++) {
if (branches[pc] != null) {
int t=targets[pc];
while ( t<branchDestHandles.length && branchDestHandles[t] == null )
int t = targets[pc];
while ( t < branchDestHandles.length && branchDestHandles[t] == null )
t++;
if ( t>= branchDestHandles.length )
throw new IllegalArgumentException("no target at or after "+targets[pc]+" op="+Lua.GET_OPCODE(p.code[targets[pc]]));
if (t >= branchDestHandles.length)
throw new IllegalArgumentException(
"no target at or after " + targets[pc] + " op=" + Lua.GET_OPCODE(p.code[targets[pc]]));
branches[pc].setTarget(branchDestHandles[t]);
}
}
}
public void setlistStack(int pc, int a0, int index0, int nvals) {
for ( int i=0; i<nvals; i++ ) {
for (int i = 0; i < nvals; i++) {
dup();
append(new PUSH(cp, index0+i));
loadLocal( pc, a0+i );
append(factory.createInvoke(STR_LUAVALUE, "rawset", Type.VOID, ARG_TYPES_INT_LUAVALUE, Constants.INVOKEVIRTUAL));
loadLocal(pc, a0+i);
append(factory.createInvoke(STR_LUAVALUE, "rawset", Type.VOID, ARG_TYPES_INT_LUAVALUE,
Constants.INVOKEVIRTUAL));
}
}
public void setlistVarargs(int index0, int vresultbase) {
append(new PUSH(cp, index0));
loadVarresult();
append(factory.createInvoke(STR_LUAVALUE, "rawsetlist", Type.VOID, ARG_TYPES_INT_VARARGS, Constants.INVOKEVIRTUAL));
append(factory.createInvoke(STR_LUAVALUE, "rawsetlist", Type.VOID, ARG_TYPES_INT_VARARGS,
Constants.INVOKEVIRTUAL));
}
public void concatvalue() {
append(factory.createInvoke(STR_LUAVALUE, "concat", TYPE_LUAVALUE, ARG_TYPES_LUAVALUE, Constants.INVOKEVIRTUAL));
append(
factory.createInvoke(STR_LUAVALUE, "concat", TYPE_LUAVALUE, ARG_TYPES_LUAVALUE, Constants.INVOKEVIRTUAL));
}
public void concatbuffer() {

View File

@@ -27,9 +27,7 @@ import org.luaj.vm2.Prototype;
import org.luaj.vm2.Upvaldesc;
/**
* TODO:
* propogate constants
* loader can find inner classes
* TODO: propogate constants loader can find inner classes
*/
public class JavaGen {
@@ -37,11 +35,11 @@ public class JavaGen {
public final byte[] bytecode;
public final JavaGen[] inners;
public JavaGen( Prototype p, String classname, String filename, boolean genmain ) {
this( new ProtoInfo(p,classname), classname, filename, genmain );
public JavaGen(Prototype p, String classname, String filename, boolean genmain) {
this(new ProtoInfo(p, classname), classname, filename, genmain);
}
private JavaGen( ProtoInfo pi, String classname, String filename, boolean genmain ) {
private JavaGen(ProtoInfo pi, String classname, String filename, boolean genmain) {
this.classname = classname;
// build this class
@@ -54,10 +52,10 @@ public class JavaGen {
this.bytecode = builder.completeClass(genmain);
// build sub-prototypes
if ( pi.subprotos != null ) {
if (pi.subprotos != null) {
int n = pi.subprotos.length;
inners = new JavaGen[n];
for ( int i=0; i<n; i++ )
for (int i = 0; i < n; i++)
inners[i] = new JavaGen(pi.subprotos[i], pi.subprotos[i].name, filename, false);
} else {
inners = null;
@@ -68,18 +66,18 @@ public class JavaGen {
Prototype p = pi.prototype;
int vresultbase = -1;
for ( int bi=0; bi<pi.blocklist.length; bi++ ) {
for (int bi = 0; bi < pi.blocklist.length; bi++) {
BasicBlock b0 = pi.blocklist[bi];
// convert upvalues that are phi-variables
for ( int slot=0; slot<p.maxstacksize; slot++ ) {
for (int slot = 0; slot < p.maxstacksize; slot++) {
int pc = b0.pc0;
boolean c = pi.isUpvalueCreate(pc, slot);
if ( c && pi.vars[slot][pc].isPhiVar() )
if (c && pi.vars[slot][pc].isPhiVar())
builder.convertToUpvalue(pc, slot);
}
for ( int pc=b0.pc0; pc<=b0.pc1; pc++ ) {
for (int pc = b0.pc0; pc <= b0.pc1; pc++) {
final int pc0 = pc; // closure changes pc
final int ins = p.code[pc];
@@ -91,73 +89,73 @@ public class JavaGen {
int sbx = Lua.GETARG_sBx(ins);
int c = Lua.GETARG_C(ins);
switch ( o ) {
switch (o) {
case Lua.OP_GETUPVAL: /* A B R(A):= UpValue[B] */
builder.loadUpvalue( b );
builder.storeLocal( pc, a );
builder.loadUpvalue(b);
builder.storeLocal(pc, a);
break;
case Lua.OP_SETUPVAL: /* A B UpValue[B]:= R(A) */
builder.storeUpvalue( pc, b, a );
builder.storeUpvalue(pc, b, a);
break;
case Lua.OP_NEWTABLE: /* A B C R(A):= {} (size = B,C) */
builder.newTable( b, c );
builder.storeLocal( pc, a );
builder.newTable(b, c);
builder.storeLocal(pc, a);
break;
case Lua.OP_MOVE:/* A B R(A):= R(B) */
builder.loadLocal( pc, b );
builder.storeLocal( pc, a );
builder.loadLocal(pc, b);
builder.storeLocal(pc, a);
break;
case Lua.OP_UNM: /* A B R(A):= -R(B) */
case Lua.OP_NOT: /* A B R(A):= not R(B) */
case Lua.OP_LEN: /* A B R(A):= length of R(B) */
builder.loadLocal( pc, b );
builder.unaryop( o );
builder.storeLocal( pc, a );
builder.loadLocal(pc, b);
builder.unaryop(o);
builder.storeLocal(pc, a);
break;
case Lua.OP_LOADK:/* A Bx R(A):= Kst(Bx) */
builder.loadConstant( p.k[bx] );
builder.storeLocal( pc, a );
builder.loadConstant(p.k[bx]);
builder.storeLocal(pc, a);
break;
case Lua.OP_LOADNIL: /* A B R(A):= ...:= R(A+B):= nil */
builder.loadNil();
for ( ; b>=0; a++, b-- ) {
if ( b > 0 )
for (; b >= 0; a++, b--) {
if (b > 0)
builder.dup();
builder.storeLocal( pc, a );
builder.storeLocal(pc, a);
}
break;
case Lua.OP_GETTABUP: /* A B C R(A) := UpValue[B][RK(C)] */
builder.loadUpvalue( b );
loadLocalOrConstant( p, builder, pc, c );
builder.loadUpvalue(b);
loadLocalOrConstant(p, builder, pc, c);
builder.getTable();
builder.storeLocal( pc, a );
builder.storeLocal(pc, a);
break;
case Lua.OP_GETTABLE: /* A B C R(A):= R(B)[RK(C)] */
builder.loadLocal( pc, b );
loadLocalOrConstant( p, builder, pc, c );
builder.loadLocal(pc, b);
loadLocalOrConstant(p, builder, pc, c);
builder.getTable();
builder.storeLocal( pc, a );
builder.storeLocal(pc, a);
break;
case Lua.OP_SETTABUP: /* A B C UpValue[A][RK(B)] := RK(C) */
builder.loadUpvalue( a );
loadLocalOrConstant( p, builder, pc, b );
loadLocalOrConstant( p, builder, pc, c );
builder.loadUpvalue(a);
loadLocalOrConstant(p, builder, pc, b);
loadLocalOrConstant(p, builder, pc, c);
builder.setTable();
break;
case Lua.OP_SETTABLE: /* A B C R(A)[RK(B)]:= RK(C) */
builder.loadLocal( pc, a );
loadLocalOrConstant( p, builder, pc, b );
loadLocalOrConstant( p, builder, pc, c );
builder.loadLocal(pc, a);
loadLocalOrConstant(p, builder, pc, b);
loadLocalOrConstant(p, builder, pc, c);
builder.setTable();
break;
@@ -167,27 +165,27 @@ public class JavaGen {
case Lua.OP_DIV: /* A B C R(A):= RK(B) / RK(C) */
case Lua.OP_MOD: /* A B C R(A):= RK(B) % RK(C) */
case Lua.OP_POW: /* A B C R(A):= RK(B) ^ RK(C) */
loadLocalOrConstant( p, builder, pc, b );
loadLocalOrConstant( p, builder, pc, c );
builder.binaryop( o );
builder.storeLocal( pc, a );
loadLocalOrConstant(p, builder, pc, b);
loadLocalOrConstant(p, builder, pc, c);
builder.binaryop(o);
builder.storeLocal(pc, a);
break;
case Lua.OP_SELF: /* A B C R(A+1):= R(B): R(A):= R(B)[RK(C)] */
builder.loadLocal(pc,b);
builder.loadLocal(pc, b);
builder.dup();
builder.storeLocal(pc, a+1);
loadLocalOrConstant( p, builder, pc, c );
loadLocalOrConstant(p, builder, pc, c);
builder.getTable();
builder.storeLocal(pc, a);
break;
case Lua.OP_CONCAT: /* A B C R(A):= R(B).. ... ..R(C) */
for ( int k=b; k<=c; k++ )
for (int k = b; k <= c; k++)
builder.loadLocal(pc, k);
if ( c > b+1 ) {
if (c > b+1) {
builder.tobuffer();
for ( int k=c; --k>=b; )
for (int k = c; --k >= b;)
builder.concatbuffer();
builder.tovalue();
} else {
@@ -197,9 +195,9 @@ public class JavaGen {
break;
case Lua.OP_LOADBOOL:/* A B C R(A):= (Bool)B: if (C) pc++ */
builder.loadBoolean( b!=0 );
builder.storeLocal( pc, a );
if ( c!=0 )
builder.loadBoolean(b != 0);
builder.storeLocal(pc, a);
if (c != 0)
builder.addBranch(pc, JavaBuilder.BRANCH_GOTO, pc+2);
break;
@@ -215,24 +213,24 @@ public class JavaGen {
case Lua.OP_EQ: /* A B C if ((RK(B) == RK(C)) ~= A) then pc++ */
case Lua.OP_LT: /* A B C if ((RK(B) < RK(C)) ~= A) then pc++ */
case Lua.OP_LE: /* A B C if ((RK(B) <= RK(C)) ~= A) then pc++ */
loadLocalOrConstant( p, builder, pc, b );
loadLocalOrConstant( p, builder, pc, c );
loadLocalOrConstant(p, builder, pc, b);
loadLocalOrConstant(p, builder, pc, c);
builder.compareop(o);
builder.addBranch(pc, (a!=0? JavaBuilder.BRANCH_IFEQ: JavaBuilder.BRANCH_IFNE), pc+2);
builder.addBranch(pc, (a != 0? JavaBuilder.BRANCH_IFEQ: JavaBuilder.BRANCH_IFNE), pc+2);
break;
case Lua.OP_TEST: /* A C if not (R(A) <=> C) then pc++ */
builder.loadLocal( pc, a );
builder.loadLocal(pc, a);
builder.toBoolean();
builder.addBranch(pc, (c!=0? JavaBuilder.BRANCH_IFEQ: JavaBuilder.BRANCH_IFNE), pc+2);
builder.addBranch(pc, (c != 0? JavaBuilder.BRANCH_IFEQ: JavaBuilder.BRANCH_IFNE), pc+2);
break;
case Lua.OP_TESTSET: /* A B C if (R(B) <=> C) then R(A):= R(B) else pc++ */
builder.loadLocal( pc, b );
builder.loadLocal(pc, b);
builder.toBoolean();
builder.addBranch(pc, (c!=0? JavaBuilder.BRANCH_IFEQ: JavaBuilder.BRANCH_IFNE), pc+2);
builder.loadLocal( pc, b );
builder.storeLocal( pc, a );
builder.addBranch(pc, (c != 0? JavaBuilder.BRANCH_IFEQ: JavaBuilder.BRANCH_IFNE), pc+2);
builder.loadLocal(pc, b);
builder.storeLocal(pc, a);
break;
case Lua.OP_CALL: { /* A B C R(A), ... ,R(A+C-2):= R(A)(R(A+1), ... ,R(A+B-1)) */
@@ -241,44 +239,47 @@ public class JavaGen {
builder.loadLocal(pc, a);
// load args
int narg = b - 1;
switch ( narg ) {
case 0: case 1: case 2: case 3:
for ( int i=1; i<b; i++ )
int narg = b-1;
switch (narg) {
case 0:
case 1:
case 2:
case 3:
for (int i = 1; i < b; i++)
builder.loadLocal(pc, a+i);
break;
default: // fixed arg count > 3
builder.newVarargs( pc, a+1, b-1 );
builder.newVarargs(pc, a+1, b-1);
narg = -1;
break;
case -1: // prev vararg result
loadVarargResults( builder, pc, a+1, vresultbase );
loadVarargResults(builder, pc, a+1, vresultbase);
narg = -1;
break;
}
// call or invoke
boolean useinvoke = narg<0 || c<1 || c>2;
if ( useinvoke )
boolean useinvoke = narg < 0 || c < 1 || c > 2;
if (useinvoke)
builder.invoke(narg);
else
builder.call(narg);
// handle results
switch ( c ) {
switch (c) {
case 1:
builder.pop();
break;
case 2:
if ( useinvoke )
builder.arg( 1 );
if (useinvoke)
builder.arg(1);
builder.storeLocal(pc, a);
break;
default: // fixed result count - unpack args
for ( int i=1; i<c; i++ ) {
if ( i+1 < c )
for (int i = 1; i < c; i++) {
if (i+1 < c)
builder.dup();
builder.arg( i );
builder.arg(i);
builder.storeLocal(pc, a+i-1);
}
break;
@@ -296,7 +297,7 @@ public class JavaGen {
builder.loadLocal(pc, a);
// load args
switch ( b ) {
switch (b) {
case 1:
builder.loadNone();
break;
@@ -304,10 +305,10 @@ public class JavaGen {
builder.loadLocal(pc, a+1);
break;
default: // fixed arg count > 1
builder.newVarargs( pc, a+1, b-1 );
builder.newVarargs(pc, a+1, b-1);
break;
case 0: // prev vararg result
loadVarargResults( builder, pc, a+1, vresultbase );
loadVarargResults(builder, pc, a+1, vresultbase);
break;
}
builder.newTailcallVarargs();
@@ -315,14 +316,22 @@ public class JavaGen {
break;
case Lua.OP_RETURN: /* A B return R(A), ... ,R(A+B-2) (see note) */
if ( c == 1 ) {
if (c == 1) {
builder.loadNone();
} else {
switch ( b ) {
case 0: loadVarargResults( builder, pc, a, vresultbase ); break;
case 1: builder.loadNone(); break;
case 2: builder.loadLocal(pc, a); break;
default: builder.newVarargs(pc, a, b-1); break;
switch (b) {
case 0:
loadVarargResults(builder, pc, a, vresultbase);
break;
case 1:
builder.loadNone();
break;
case 2:
builder.loadLocal(pc, a);
break;
default:
builder.newVarargs(pc, a, b-1);
break;
}
}
builder.areturn();
@@ -331,7 +340,7 @@ public class JavaGen {
case Lua.OP_FORPREP: /* A sBx R(A)-=R(A+2): pc+=sBx */
builder.loadLocal(pc, a);
builder.loadLocal(pc, a+2);
builder.binaryop( Lua.OP_SUB );
builder.binaryop(Lua.OP_SUB);
builder.storeLocal(pc, a);
builder.addBranch(pc, JavaBuilder.BRANCH_GOTO, pc+1+sbx);
break;
@@ -339,7 +348,7 @@ public class JavaGen {
case Lua.OP_FORLOOP: /* A sBx R(A)+=R(A+2): if R(A) <?= R(A+1) then { pc+=sBx: R(A+3)=R(A) }*/
builder.loadLocal(pc, a);
builder.loadLocal(pc, a+2);
builder.binaryop( Lua.OP_ADD );
builder.binaryop(Lua.OP_ADD);
builder.dup();
builder.dup();
builder.storeLocal(pc, a);
@@ -355,10 +364,10 @@ public class JavaGen {
builder.loadLocal(pc, a+1);
builder.loadLocal(pc, a+2);
builder.invoke(2);
for ( int i=1; i<=c; i++ ) {
if ( i < c )
for (int i = 1; i <= c; i++) {
if (i < c)
builder.dup();
builder.arg( i );
builder.arg(i);
builder.storeLocal(pc, a+2+i);
}
break;
@@ -372,17 +381,17 @@ public class JavaGen {
break;
case Lua.OP_SETLIST: /* A B C R(A)[(C-1)*FPF+i]:= R(A+i), 1 <= i <= B */
int index0 = (c-1)*Lua.LFIELDS_PER_FLUSH + 1;
builder.loadLocal( pc, a );
if ( b == 0 ) {
int nstack = vresultbase - (a+1);
if ( nstack > 0 ) {
builder.setlistStack( pc, a+1, index0, nstack );
int index0 = (c-1)*Lua.LFIELDS_PER_FLUSH+1;
builder.loadLocal(pc, a);
if (b == 0) {
int nstack = vresultbase-(a+1);
if (nstack > 0) {
builder.setlistStack(pc, a+1, index0, nstack);
index0 += nstack;
}
builder.setlistVarargs( index0, vresultbase );
builder.setlistVarargs(index0, vresultbase);
} else {
builder.setlistStack( pc, a+1, index0, b );
builder.setlistStack(pc, a+1, index0, b);
builder.pop();
}
break;
@@ -392,29 +401,29 @@ public class JavaGen {
Prototype newp = p.p[bx];
int nup = newp.upvalues.length;
String protoname = pi.subprotos[bx].name;
builder.closureCreate( protoname );
if ( nup > 0 )
builder.closureCreate(protoname);
if (nup > 0)
builder.dup();
builder.storeLocal( pc, a );
for ( int up=0; up<nup; ++up ) {
if ( up+1 < nup )
builder.storeLocal(pc, a);
for (int up = 0; up < nup; ++up) {
if (up+1 < nup)
builder.dup();
Upvaldesc u = newp.upvalues[up];
if (u.instack)
builder.closureInitUpvalueFromLocal( protoname, up, pc, u.idx );
builder.closureInitUpvalueFromLocal(protoname, up, pc, u.idx);
else
builder.closureInitUpvalueFromUpvalue( protoname, up, u.idx );
builder.closureInitUpvalueFromUpvalue(protoname, up, u.idx);
}
break;
}
case Lua.OP_VARARG: /* A B R(A), R(A+1), ..., R(A+B-1) = vararg */
if ( b == 0 ) {
if (b == 0) {
builder.loadVarargs();
builder.storeVarresult();
vresultbase = a;
} else {
for ( int i=1; i<b; ++a, ++i ) {
builder.loadVarargs( i );
for (int i = 1; i < b; ++a, ++i) {
builder.loadVarargs(i);
builder.storeLocal(pc, a);
}
}
@@ -422,16 +431,16 @@ public class JavaGen {
}
// let builder process branch instructions
builder.onEndOfLuaInstruction( pc0, line );
builder.onEndOfLuaInstruction(pc0, line);
}
}
}
private void loadVarargResults(JavaBuilder builder, int pc, int a, int vresultbase) {
if ( vresultbase <= a ) {
if (vresultbase <= a) {
builder.loadVarresult();
builder.subargs( a+1-vresultbase );
} else if ( vresultbase == a ) {
builder.subargs(a+1-vresultbase);
} else if (vresultbase == a) {
builder.loadVarresult();
} else {
builder.newVarargsVarresult(pc, a, vresultbase-a);
@@ -439,9 +448,9 @@ public class JavaGen {
}
private void loadLocalOrConstant(Prototype p, JavaBuilder builder, int pc, int borc) {
if ( borc<=0xff )
builder.loadLocal( pc, borc );
if (borc <= 0xff)
builder.loadLocal(pc, borc);
else
builder.loadConstant( p.k[borc&0xff] );
builder.loadConstant(p.k[borc & 0xff]);
}
}

View File

@@ -8,64 +8,64 @@ import org.luaj.vm2.LuaValue;
import org.luaj.vm2.Prototype;
/*******************************************************************************
* Copyright (c) 2010 Luaj.org. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
******************************************************************************/
* Copyright (c) 2010 Luaj.org. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
******************************************************************************/
public class JavaLoader extends ClassLoader {
private Map<String,byte[]> unloaded = new HashMap<String,byte[]>();
private Map<String, byte[]> unloaded = new HashMap<String, byte[]>();
public JavaLoader() {
}
public LuaFunction load( Prototype p, String classname, String filename, LuaValue env ) {
JavaGen jg = new JavaGen( p, classname, filename, false );
return load( jg, env );
public LuaFunction load(Prototype p, String classname, String filename, LuaValue env) {
JavaGen jg = new JavaGen(p, classname, filename, false);
return load(jg, env);
}
public LuaFunction load( JavaGen jg, LuaValue env ) {
include( jg );
return load( jg.classname, env );
public LuaFunction load(JavaGen jg, LuaValue env) {
include(jg);
return load(jg.classname, env);
}
public LuaFunction load(String classname, LuaValue env) {
try {
Class c = loadClass( classname );
Class c = loadClass(classname);
LuaFunction v = (LuaFunction) c.newInstance();
v.initupvalue1(env);
return v;
} catch ( Exception e ) {
} catch (Exception e) {
e.printStackTrace();
throw new IllegalStateException("bad class gen: "+e);
throw new IllegalStateException("bad class gen: " + e);
}
}
public void include( JavaGen jg ) {
unloaded.put( jg.classname, jg.bytecode );
for ( int i=0, n=jg.inners!=null? jg.inners.length: 0; i<n; i++ )
include( jg.inners[i] );
public void include(JavaGen jg) {
unloaded.put(jg.classname, jg.bytecode);
for (int i = 0, n = jg.inners != null? jg.inners.length: 0; i < n; i++)
include(jg.inners[i]);
}
public Class findClass(String classname) throws ClassNotFoundException {
byte[] bytes = (byte[]) unloaded.get(classname);
if ( bytes != null )
if (bytes != null)
return defineClass(classname, bytes, 0, bytes.length);
return super.findClass(classname);
}

View File

@@ -38,20 +38,22 @@ import org.luaj.vm2.compiler.LuaC;
* lua-to-java-bytecode compiling.
* <p>
* By default, when using {@link org.luaj.vm2.lib.jse.JsePlatform} or
* {@link org.luaj.vm2.lib.jme.JmePlatform}
* to construct globals, the plain compiler {@link LuaC} is installed and lua code
* will only be compiled into lua bytecode and execute as {@link LuaClosure}.
* {@link org.luaj.vm2.lib.jme.JmePlatform} to construct globals, the plain
* compiler {@link LuaC} is installed and lua code will only be compiled into
* lua bytecode and execute as {@link LuaClosure}.
* <p>
* To override the default compiling behavior with {@link LuaJC}
* lua-to-java bytecode compiler, install it before undumping code,
* for example:
* <pre> {@code
* To override the default compiling behavior with {@link LuaJC} lua-to-java
* bytecode compiler, install it before undumping code, for example:
*
* <pre>
* {@code
* LuaValue globals = JsePlatform.standardGlobals();
* LuaJC.install(globals);
* LuaValue chunk = globals.load( "print('hello, world'), "main.lua");
* System.out.println(chunk.isclosure()); // Will be false when LuaJC is working.
* chunk.call();
* } </pre>
* }
* </pre>
* <p>
* This requires the bcel library to be on the class path to work as expected.
* If the library is not found, the default {@link LuaC} lua-to-lua-bytecode
@@ -67,8 +69,8 @@ public class LuaJC implements Globals.Loader {
public static final LuaJC instance = new LuaJC();
/**
* Install the compiler as the main Globals.Loader to use in a set of globals.
* Will fall back to the LuaC prototype compiler.
* Install the compiler as the main Globals.Loader to use in a set of
* globals. Will fall back to the LuaC prototype compiler.
*/
public static final void install(Globals G) {
G.loader = instance;
@@ -76,57 +78,62 @@ public class LuaJC implements Globals.Loader {
protected LuaJC() {}
public Hashtable compileAll(InputStream script, String chunkname, String filename, Globals globals, boolean genmain) throws IOException {
final String classname = toStandardJavaClassName( chunkname );
public Hashtable compileAll(InputStream script, String chunkname, String filename, Globals globals, boolean genmain)
throws IOException {
final String classname = toStandardJavaClassName(chunkname);
final Prototype p = globals.loadPrototype(script, classname, "bt");
return compileProtoAndSubProtos(p, classname, filename, genmain);
}
public Hashtable compileAll(Reader script, String chunkname, String filename, Globals globals, boolean genmain) throws IOException {
final String classname = toStandardJavaClassName( chunkname );
public Hashtable compileAll(Reader script, String chunkname, String filename, Globals globals, boolean genmain)
throws IOException {
final String classname = toStandardJavaClassName(chunkname);
final Prototype p = globals.compilePrototype(script, classname);
return compileProtoAndSubProtos(p, classname, filename, genmain);
}
private Hashtable compileProtoAndSubProtos(Prototype p, String classname, String filename, boolean genmain) throws IOException {
final String luaname = toStandardLuaFileName( filename );
private Hashtable compileProtoAndSubProtos(Prototype p, String classname, String filename, boolean genmain)
throws IOException {
final String luaname = toStandardLuaFileName(filename);
final Hashtable h = new Hashtable();
final JavaGen gen = new JavaGen(p, classname, luaname, genmain);
insert( h, gen );
insert(h, gen);
return h;
}
private void insert(Hashtable h, JavaGen gen) {
h.put(gen.classname, gen.bytecode);
for ( int i=0, n=gen.inners!=null? gen.inners.length: 0; i<n; i++ )
for (int i = 0, n = gen.inners != null? gen.inners.length: 0; i < n; i++)
insert(h, gen.inners[i]);
}
public LuaFunction load(Prototype p, String name, LuaValue globals) throws IOException {
String luaname = toStandardLuaFileName( name );
String classname = toStandardJavaClassName( luaname );
String luaname = toStandardLuaFileName(name);
String classname = toStandardJavaClassName(luaname);
JavaLoader loader = new JavaLoader();
return loader.load(p, classname, luaname, globals);
}
private static String toStandardJavaClassName( String luachunkname ) {
String stub = toStub( luachunkname );
private static String toStandardJavaClassName(String luachunkname) {
String stub = toStub(luachunkname);
StringBuffer classname = new StringBuffer();
for (int i = 0, n = stub.length(); i < n; ++i) {
final char c = stub.charAt(i);
classname.append((((i == 0) && Character.isJavaIdentifierStart(c)) || ((i > 0) && Character.isJavaIdentifierPart(c)))? c: '_');
classname.append(
(((i == 0) && Character.isJavaIdentifierStart(c)) || ((i > 0) && Character.isJavaIdentifierPart(c)))? c
: '_');
}
return classname.toString();
}
private static String toStandardLuaFileName( String luachunkname ) {
String stub = toStub( luachunkname );
String filename = stub.replace('.','/')+".lua";
private static String toStandardLuaFileName(String luachunkname) {
String stub = toStub(luachunkname);
String filename = stub.replace('.', '/') + ".lua";
return filename.startsWith("@")? filename.substring(1): filename;
}
private static String toStub( String s ) {
String stub = s.endsWith(".lua")? s.substring(0,s.length()-4): s;
private static String toStub(String s) {
String stub = s.endsWith(".lua")? s.substring(0, s.length()-4): s;
return stub;
}
}

View File

@@ -28,14 +28,14 @@ public class ProtoInfo {
// A main chunk proto info.
public ProtoInfo(Prototype p, String name) {
// For the outer chunk, we have one upvalue which is the environment.
this(p,name,null);
this(p, name, null);
}
private ProtoInfo(Prototype p, String name, UpvalInfo[] u) {
this.name = name;
this.prototype = p;
this.upvals = u != null? u: new UpvalInfo[] { new UpvalInfo(this) };
this.subprotos = p.p!=null&&p.p.length>0? new ProtoInfo[p.p.length]: null;
this.subprotos = p.p != null && p.p.length > 0? new ProtoInfo[p.p.length]: null;
// find basic blocks
this.blocks = BasicBlock.findBasicBlocks(p);
@@ -43,7 +43,7 @@ public class ProtoInfo {
// params are inputs to first block
this.params = new VarInfo[p.maxstacksize];
for ( int slot=0; slot<p.maxstacksize; slot++ ) {
for (int slot = 0; slot < p.maxstacksize; slot++) {
VarInfo v = VarInfo.PARAM(slot);
params[slot] = v;
}
@@ -61,34 +61,36 @@ public class ProtoInfo {
StringBuffer sb = new StringBuffer();
// prototpye name
sb.append( "proto '"+name+"'\n" );
sb.append("proto '" + name + "'\n");
// upvalues from outer scopes
for ( int i=0, n=(upvals!=null? upvals.length: 0); i<n; i++ )
sb.append( " up["+i+"]: "+upvals[i]+"\n" );
for (int i = 0, n = (upvals != null? upvals.length: 0); i < n; i++)
sb.append(" up[" + i + "]: " + upvals[i] + "\n");
// basic blocks
for ( int i=0; i<blocklist.length; i++ ) {
for (int i = 0; i < blocklist.length; i++) {
BasicBlock b = blocklist[i];
int pc0 = b.pc0;
sb.append( " block "+b.toString() );
appendOpenUps( sb, -1 );
sb.append(" block " + b.toString());
appendOpenUps(sb, -1);
// instructions
for ( int pc=pc0; pc<=b.pc1; pc++ ) {
for (int pc = pc0; pc <= b.pc1; pc++) {
// open upvalue storage
appendOpenUps( sb, pc );
appendOpenUps(sb, pc);
// opcode
sb.append( " " );
for ( int j=0; j<prototype.maxstacksize; j++ ) {
sb.append(" ");
for (int j = 0; j < prototype.maxstacksize; j++) {
VarInfo v = vars[j][pc];
String u = (v==null? "": v.upvalue!=null? !v.upvalue.rw? "[C] ": (v.allocupvalue&&v.pc==pc? "[*] ": "[] "): " ");
String s = v==null? "null ": String.valueOf(v);
sb.append( s+u);
String u = (v == null? ""
: v.upvalue != null? !v.upvalue.rw? "[C] ": (v.allocupvalue && v.pc == pc? "[*] ": "[] ")
: " ");
String s = v == null? "null ": String.valueOf(v);
sb.append(s+u);
}
sb.append( " " );
sb.append(" ");
ByteArrayOutputStream baos = new ByteArrayOutputStream();
PrintStream ops = Print.ps;
Print.ps = new PrintStream(baos);
@@ -98,24 +100,24 @@ public class ProtoInfo {
Print.ps.close();
Print.ps = ops;
}
sb.append( baos.toString() );
sb.append( "\n" );
sb.append(baos.toString());
sb.append("\n");
}
}
// nested functions
for ( int i=0, n=subprotos!=null? subprotos.length: 0; i<n; i++ ) {
sb.append( subprotos[i].toString() );
for (int i = 0, n = subprotos != null? subprotos.length: 0; i < n; i++) {
sb.append(subprotos[i].toString());
}
return sb.toString();
}
private void appendOpenUps(StringBuffer sb, int pc) {
for ( int j=0; j<prototype.maxstacksize; j++ ) {
VarInfo v = (pc<0? params[j]: vars[j][pc]);
if ( v != null && v.pc == pc && v.allocupvalue ) {
sb.append( " open: "+v.upvalue+"\n" );
for (int j = 0; j < prototype.maxstacksize; j++) {
VarInfo v = (pc < 0? params[j]: vars[j][pc]);
if (v != null && v.pc == pc && v.allocupvalue) {
sb.append(" open: " + v.upvalue + "\n");
}
}
}
@@ -126,52 +128,52 @@ public class ProtoInfo {
int n = prototype.code.length;
int m = prototype.maxstacksize;
VarInfo[][] v = new VarInfo[m][];
for ( int i=0; i<v.length; i++ )
for (int i = 0; i < v.length; i++)
v[i] = new VarInfo[n];
// process instructions
for ( int bi=0; bi<blocklist.length; bi++ ) {
for (int bi = 0; bi < blocklist.length; bi++) {
BasicBlock b0 = blocklist[bi];
// input from previous blocks
int nprev = b0.prev!=null? b0.prev.length: 0;
for ( int slot=0; slot<m; slot++ ) {
int nprev = b0.prev != null? b0.prev.length: 0;
for (int slot = 0; slot < m; slot++) {
VarInfo var = null;
if ( nprev == 0 )
if (nprev == 0)
var = params[slot];
else if ( nprev == 1 )
else if (nprev == 1)
var = v[slot][b0.prev[0].pc1];
else {
for ( int i=0; i<nprev; i++ ) {
for (int i = 0; i < nprev; i++) {
BasicBlock bp = b0.prev[i];
if ( v[slot][bp.pc1] == VarInfo.INVALID )
if (v[slot][bp.pc1] == VarInfo.INVALID)
var = VarInfo.INVALID;
}
}
if ( var == null )
if (var == null)
var = VarInfo.PHI(this, slot, b0.pc0);
v[slot][b0.pc0] = var;
}
// process instructions for this basic block
for ( int pc=b0.pc0; pc<=b0.pc1; pc++ ) {
for (int pc = b0.pc0; pc <= b0.pc1; pc++) {
// propogate previous values except at block boundaries
if ( pc > b0.pc0 )
propogateVars( v, pc-1, pc );
if (pc > b0.pc0)
propogateVars(v, pc-1, pc);
int a,b,c;
int a, b, c;
int ins = prototype.code[pc];
int op = Lua.GET_OPCODE(ins);
// account for assignments, references and invalidations
switch ( op ) {
switch (op) {
case Lua.OP_LOADK:/* A Bx R(A) := Kst(Bx) */
case Lua.OP_LOADBOOL:/* A B C R(A) := (Bool)B; if (C) pc++ */
case Lua.OP_GETUPVAL: /* A B R(A) := UpValue[B] */
case Lua.OP_NEWTABLE: /* A B C R(A) := {} (size = B,C) */
a = Lua.GETARG_A( ins );
v[a][pc] = new VarInfo(a,pc);
a = Lua.GETARG_A(ins);
v[a][pc] = new VarInfo(a, pc);
break;
case Lua.OP_MOVE:/* A B R(A) := R(B) */
@@ -179,10 +181,10 @@ public class ProtoInfo {
case Lua.OP_NOT: /* A B R(A) := not R(B) */
case Lua.OP_LEN: /* A B R(A) := length of R(B) */
case Lua.OP_TESTSET: /* A B C if (R(B) <=> C) then R(A) := R(B) else pc++ */
a = Lua.GETARG_A( ins );
b = Lua.GETARG_B( ins );
a = Lua.GETARG_A(ins);
b = Lua.GETARG_B(ins);
v[b][pc].isreferenced = true;
v[a][pc] = new VarInfo(a,pc);
v[a][pc] = new VarInfo(a, pc);
break;
case Lua.OP_ADD: /* A B C R(A) := RK(B) + RK(C) */
@@ -191,189 +193,200 @@ public class ProtoInfo {
case Lua.OP_DIV: /* A B C R(A) := RK(B) / RK(C) */
case Lua.OP_MOD: /* A B C R(A) := RK(B) % RK(C) */
case Lua.OP_POW: /* A B C R(A) := RK(B) ^ RK(C) */
a = Lua.GETARG_A( ins );
b = Lua.GETARG_B( ins );
c = Lua.GETARG_C( ins );
if (!Lua.ISK(b)) v[b][pc].isreferenced = true;
if (!Lua.ISK(c)) v[c][pc].isreferenced = true;
v[a][pc] = new VarInfo(a,pc);
a = Lua.GETARG_A(ins);
b = Lua.GETARG_B(ins);
c = Lua.GETARG_C(ins);
if (!Lua.ISK(b))
v[b][pc].isreferenced = true;
if (!Lua.ISK(c))
v[c][pc].isreferenced = true;
v[a][pc] = new VarInfo(a, pc);
break;
case Lua.OP_SETTABLE: /* A B C R(A)[RK(B)]:= RK(C) */
a = Lua.GETARG_A( ins );
b = Lua.GETARG_B( ins );
c = Lua.GETARG_C( ins );
a = Lua.GETARG_A(ins);
b = Lua.GETARG_B(ins);
c = Lua.GETARG_C(ins);
v[a][pc].isreferenced = true;
if (!Lua.ISK(b)) v[b][pc].isreferenced = true;
if (!Lua.ISK(c)) v[c][pc].isreferenced = true;
if (!Lua.ISK(b))
v[b][pc].isreferenced = true;
if (!Lua.ISK(c))
v[c][pc].isreferenced = true;
break;
case Lua.OP_SETTABUP: /* A B C UpValue[A][RK(B)] := RK(C) */
b = Lua.GETARG_B( ins );
c = Lua.GETARG_C( ins );
if (!Lua.ISK(b)) v[b][pc].isreferenced = true;
if (!Lua.ISK(c)) v[c][pc].isreferenced = true;
b = Lua.GETARG_B(ins);
c = Lua.GETARG_C(ins);
if (!Lua.ISK(b))
v[b][pc].isreferenced = true;
if (!Lua.ISK(c))
v[c][pc].isreferenced = true;
break;
case Lua.OP_CONCAT: /* A B C R(A) := R(B).. ... ..R(C) */
a = Lua.GETARG_A( ins );
b = Lua.GETARG_B( ins );
c = Lua.GETARG_C( ins );
for ( ; b<=c; b++ )
a = Lua.GETARG_A(ins);
b = Lua.GETARG_B(ins);
c = Lua.GETARG_C(ins);
for (; b <= c; b++)
v[b][pc].isreferenced = true;
v[a][pc] = new VarInfo(a,pc);
v[a][pc] = new VarInfo(a, pc);
break;
case Lua.OP_FORPREP: /* A sBx R(A)-=R(A+2); pc+=sBx */
a = Lua.GETARG_A( ins );
a = Lua.GETARG_A(ins);
v[a+2][pc].isreferenced = true;
v[a][pc] = new VarInfo(a,pc);
v[a][pc] = new VarInfo(a, pc);
break;
case Lua.OP_GETTABLE: /* A B C R(A) := R(B)[RK(C)] */
a = Lua.GETARG_A( ins );
b = Lua.GETARG_B( ins );
c = Lua.GETARG_C( ins );
a = Lua.GETARG_A(ins);
b = Lua.GETARG_B(ins);
c = Lua.GETARG_C(ins);
v[b][pc].isreferenced = true;
if (!Lua.ISK(c)) v[c][pc].isreferenced = true;
v[a][pc] = new VarInfo(a,pc);
if (!Lua.ISK(c))
v[c][pc].isreferenced = true;
v[a][pc] = new VarInfo(a, pc);
break;
case Lua.OP_GETTABUP: /* A B C R(A) := UpValue[B][RK(C)] */
a = Lua.GETARG_A( ins );
c = Lua.GETARG_C( ins );
if (!Lua.ISK(c)) v[c][pc].isreferenced = true;
v[a][pc] = new VarInfo(a,pc);
a = Lua.GETARG_A(ins);
c = Lua.GETARG_C(ins);
if (!Lua.ISK(c))
v[c][pc].isreferenced = true;
v[a][pc] = new VarInfo(a, pc);
break;
case Lua.OP_SELF: /* A B C R(A+1) := R(B); R(A) := R(B)[RK(C)] */
a = Lua.GETARG_A( ins );
b = Lua.GETARG_B( ins );
c = Lua.GETARG_C( ins );
a = Lua.GETARG_A(ins);
b = Lua.GETARG_B(ins);
c = Lua.GETARG_C(ins);
v[b][pc].isreferenced = true;
if (!Lua.ISK(c)) v[c][pc].isreferenced = true;
v[a][pc] = new VarInfo(a,pc);
v[a+1][pc] = new VarInfo(a+1,pc);
if (!Lua.ISK(c))
v[c][pc].isreferenced = true;
v[a][pc] = new VarInfo(a, pc);
v[a+1][pc] = new VarInfo(a+1, pc);
break;
case Lua.OP_FORLOOP: /* A sBx R(A)+=R(A+2);
if R(A) <?= R(A+1) then { pc+=sBx; R(A+3)=R(A) }*/
a = Lua.GETARG_A( ins );
a = Lua.GETARG_A(ins);
v[a][pc].isreferenced = true;
v[a+2][pc].isreferenced = true;
v[a][pc] = new VarInfo(a,pc);
v[a][pc] = new VarInfo(a, pc);
v[a][pc].isreferenced = true;
v[a+1][pc].isreferenced = true;
v[a+3][pc] = new VarInfo(a+3,pc);
v[a+3][pc] = new VarInfo(a+3, pc);
break;
case Lua.OP_LOADNIL: /* A B R(A) := ... := R(A+B) := nil */
a = Lua.GETARG_A( ins );
b = Lua.GETARG_B( ins );
for ( ; b-->=0; a++ )
v[a][pc] = new VarInfo(a,pc);
a = Lua.GETARG_A(ins);
b = Lua.GETARG_B(ins);
for (; b-- >= 0; a++)
v[a][pc] = new VarInfo(a, pc);
break;
case Lua.OP_VARARG: /* A B R(A), R(A+1), ..., R(A+B-1) = vararg */
a = Lua.GETARG_A( ins );
b = Lua.GETARG_B( ins );
for ( int j=1; j<b; j++, a++ )
v[a][pc] = new VarInfo(a,pc);
if ( b == 0 )
for ( ; a<m; a++ )
a = Lua.GETARG_A(ins);
b = Lua.GETARG_B(ins);
for (int j = 1; j < b; j++, a++)
v[a][pc] = new VarInfo(a, pc);
if (b == 0)
for (; a < m; a++)
v[a][pc] = VarInfo.INVALID;
break;
case Lua.OP_CALL: /* A B C R(A), ... ,R(A+C-2) := R(A)(R(A+1), ... ,R(A+B-1)) */
a = Lua.GETARG_A( ins );
b = Lua.GETARG_B( ins );
c = Lua.GETARG_C( ins );
a = Lua.GETARG_A(ins);
b = Lua.GETARG_B(ins);
c = Lua.GETARG_C(ins);
v[a][pc].isreferenced = true;
v[a][pc].isreferenced = true;
for ( int i=1; i<=b-1; i++ )
for (int i = 1; i <= b-1; i++)
v[a+i][pc].isreferenced = true;
for ( int j=0; j<=c-2; j++, a++ )
v[a][pc] = new VarInfo(a,pc);
for ( ; a<m; a++ )
for (int j = 0; j <= c-2; j++, a++)
v[a][pc] = new VarInfo(a, pc);
for (; a < m; a++)
v[a][pc] = VarInfo.INVALID;
break;
case Lua.OP_TFORCALL: /* A C R(A+3), ... ,R(A+2+C) := R(A)(R(A+1), R(A+2)); */
a = Lua.GETARG_A( ins );
c = Lua.GETARG_C( ins );
a = Lua.GETARG_A(ins);
c = Lua.GETARG_C(ins);
v[a++][pc].isreferenced = true;
v[a++][pc].isreferenced = true;
v[a++][pc].isreferenced = true;
for ( int j=0; j<c; j++, a++ )
v[a][pc] = new VarInfo(a,pc);
for ( ; a<m; a++ )
for (int j = 0; j < c; j++, a++)
v[a][pc] = new VarInfo(a, pc);
for (; a < m; a++)
v[a][pc] = VarInfo.INVALID;
break;
case Lua.OP_TFORLOOP: /* A sBx if R(A+1) ~= nil then { R(A)=R(A+1); pc += sBx */
a = Lua.GETARG_A( ins );
a = Lua.GETARG_A(ins);
v[a+1][pc].isreferenced = true;
v[a][pc] = new VarInfo(a,pc);
v[a][pc] = new VarInfo(a, pc);
break;
case Lua.OP_TAILCALL: /* A B C return R(A)(R(A+1), ... ,R(A+B-1)) */
a = Lua.GETARG_A( ins );
b = Lua.GETARG_B( ins );
a = Lua.GETARG_A(ins);
b = Lua.GETARG_B(ins);
v[a][pc].isreferenced = true;
for ( int i=1; i<=b-1; i++ )
for (int i = 1; i <= b-1; i++)
v[a+i][pc].isreferenced = true;
break;
case Lua.OP_RETURN: /* A B return R(A), ... ,R(A+B-2) (see note) */
a = Lua.GETARG_A( ins );
b = Lua.GETARG_B( ins );
for ( int i=0; i<=b-2; i++ )
a = Lua.GETARG_A(ins);
b = Lua.GETARG_B(ins);
for (int i = 0; i <= b-2; i++)
v[a+i][pc].isreferenced = true;
break;
case Lua.OP_CLOSURE: { /* A Bx R(A) := closure(KPROTO[Bx], R(A), ... ,R(A+n)) */
a = Lua.GETARG_A( ins );
b = Lua.GETARG_Bx( ins );
a = Lua.GETARG_A(ins);
b = Lua.GETARG_Bx(ins);
Upvaldesc[] upvalues = prototype.p[b].upvalues;
for (int k = 0, nups = upvalues.length; k < nups; ++k)
if (upvalues[k].instack)
v[upvalues[k].idx][pc].isreferenced = true;
v[a][pc] = new VarInfo(a,pc);
v[a][pc] = new VarInfo(a, pc);
break;
}
case Lua.OP_SETLIST: /* A B C R(A)[(C-1)*FPF+i]:= R(A+i), 1 <= i <= B */
a = Lua.GETARG_A( ins );
b = Lua.GETARG_B( ins );
a = Lua.GETARG_A(ins);
b = Lua.GETARG_B(ins);
v[a][pc].isreferenced = true;
for ( int i=1; i<=b; i++ )
for (int i = 1; i <= b; i++)
v[a+i][pc].isreferenced = true;
break;
case Lua.OP_SETUPVAL: /* A B UpValue[B]:= R(A) */
case Lua.OP_TEST: /* A C if not (R(A) <=> C) then pc++ */
a = Lua.GETARG_A( ins );
a = Lua.GETARG_A(ins);
v[a][pc].isreferenced = true;
break;
case Lua.OP_EQ: /* A B C if ((RK(B) == RK(C)) ~= A) then pc++ */
case Lua.OP_LT: /* A B C if ((RK(B) < RK(C)) ~= A) then pc++ */
case Lua.OP_LE: /* A B C if ((RK(B) <= RK(C)) ~= A) then pc++ */
b = Lua.GETARG_B( ins );
c = Lua.GETARG_C( ins );
if (!Lua.ISK(b)) v[b][pc].isreferenced = true;
if (!Lua.ISK(c)) v[c][pc].isreferenced = true;
b = Lua.GETARG_B(ins);
c = Lua.GETARG_C(ins);
if (!Lua.ISK(b))
v[b][pc].isreferenced = true;
if (!Lua.ISK(c))
v[c][pc].isreferenced = true;
break;
case Lua.OP_JMP: /* sBx pc+=sBx */
a = Lua.GETARG_A( ins );
a = Lua.GETARG_A(ins);
if (a > 0)
for ( --a; a<m; a++ )
for (--a; a < m; a++)
v[a][pc] = VarInfo.INVALID;
break;
default:
throw new IllegalStateException("unhandled opcode: "+ins);
throw new IllegalStateException("unhandled opcode: " + ins);
}
}
}
@@ -381,30 +394,30 @@ public class ProtoInfo {
}
private static void propogateVars(VarInfo[][] v, int pcfrom, int pcto) {
for ( int j=0, m=v.length; j<m; j++ )
for (int j = 0, m = v.length; j < m; j++)
v[j][pcto] = v[j][pcfrom];
}
private void replaceTrivialPhiVariables() {
for ( int i=0; i<blocklist.length; i++ ) {
for (int i = 0; i < blocklist.length; i++) {
BasicBlock b0 = blocklist[i];
for ( int slot=0; slot<prototype.maxstacksize; slot++ ) {
for (int slot = 0; slot < prototype.maxstacksize; slot++) {
VarInfo vold = vars[slot][b0.pc0];
VarInfo vnew = vold.resolvePhiVariableValues();
if ( vnew != null )
substituteVariable( slot, vold, vnew );
if (vnew != null)
substituteVariable(slot, vold, vnew);
}
}
}
private void substituteVariable(int slot, VarInfo vold, VarInfo vnew) {
for ( int i=0, n=prototype.code.length; i<n; i++ )
replaceAll( vars[slot], vars[slot].length, vold, vnew );
for (int i = 0, n = prototype.code.length; i < n; i++)
replaceAll(vars[slot], vars[slot].length, vold, vnew);
}
private void replaceAll(VarInfo[] v, int n, VarInfo vold, VarInfo vnew) {
for ( int i=0; i<n; i++ )
if ( v[i] == vold )
for (int i = 0; i < n; i++)
if (v[i] == vold)
v[i] = vnew;
}
@@ -414,53 +427,54 @@ public class ProtoInfo {
// propogate to inner prototypes
String[] names = findInnerprotoNames();
for ( int pc=0; pc<n; pc++ ) {
if ( Lua.GET_OPCODE(code[pc]) == Lua.OP_CLOSURE ) {
for (int pc = 0; pc < n; pc++) {
if (Lua.GET_OPCODE(code[pc]) == Lua.OP_CLOSURE) {
int bx = Lua.GETARG_Bx(code[pc]);
Prototype newp = prototype.p[bx];
UpvalInfo[] newu = new UpvalInfo[newp.upvalues.length];
String newname = name + "$" + names[bx];
for ( int j=0; j<newp.upvalues.length; ++j ) {
for (int j = 0; j < newp.upvalues.length; ++j) {
Upvaldesc u = newp.upvalues[j];
newu[j] = u.instack? findOpenUp(pc,u.idx) : upvals[u.idx];
newu[j] = u.instack? findOpenUp(pc, u.idx): upvals[u.idx];
}
subprotos[bx] = new ProtoInfo(newp, newname, newu);
}
}
// mark all upvalues that are written locally as read/write
for ( int pc=0; pc<n; pc++ ) {
if ( Lua.GET_OPCODE(code[pc]) == Lua.OP_SETUPVAL )
for (int pc = 0; pc < n; pc++) {
if (Lua.GET_OPCODE(code[pc]) == Lua.OP_SETUPVAL)
upvals[Lua.GETARG_B(code[pc])].rw = true;
}
}
private UpvalInfo findOpenUp(int pc, int slot) {
if ( openups[slot] == null )
if (openups[slot] == null)
openups[slot] = new UpvalInfo[prototype.code.length];
if ( openups[slot][pc] != null )
if (openups[slot][pc] != null)
return openups[slot][pc];
UpvalInfo u = new UpvalInfo(this, pc, slot);
for ( int i=0, n=prototype.code.length; i<n; ++i )
if ( vars[slot][i] != null && vars[slot][i].upvalue == u )
for (int i = 0, n = prototype.code.length; i < n; ++i)
if (vars[slot][i] != null && vars[slot][i].upvalue == u)
openups[slot][i] = u;
return u;
}
public boolean isUpvalueAssign(int pc, int slot) {
VarInfo v = pc<0? params[slot]: vars[slot][pc];
VarInfo v = pc < 0? params[slot]: vars[slot][pc];
return v != null && v.upvalue != null && v.upvalue.rw;
}
public boolean isUpvalueCreate(int pc, int slot) {
VarInfo v = pc<0? params[slot]: vars[slot][pc];
VarInfo v = pc < 0? params[slot]: vars[slot][pc];
return v != null && v.upvalue != null && v.upvalue.rw && v.allocupvalue && pc == v.pc;
}
public boolean isUpvalueRefer(int pc, int slot) {
// special case when both refer and assign in same instruction
if ( pc > 0 && vars[slot][pc] != null && vars[slot][pc].pc == pc && vars[slot][pc-1] != null )
if (pc > 0 && vars[slot][pc] != null && vars[slot][pc].pc == pc && vars[slot][pc-1] != null)
pc -= 1;
VarInfo v = pc<0? params[slot]: vars[slot][pc];
VarInfo v = pc < 0? params[slot]: vars[slot][pc];
return v != null && v.upvalue != null && v.upvalue.rw;
}
@@ -481,8 +495,8 @@ public class ProtoInfo {
Hashtable used = new Hashtable();
int[] code = prototype.code;
int n = code.length;
for ( int pc=0; pc<n; pc++ ) {
if ( Lua.GET_OPCODE(code[pc]) == Lua.OP_CLOSURE ) {
for (int pc = 0; pc < n; pc++) {
if (Lua.GET_OPCODE(code[pc]) == Lua.OP_CLOSURE) {
int bx = Lua.GETARG_Bx(code[pc]);
String name = null;
final int i = code[pc+1];
@@ -491,7 +505,7 @@ public class ProtoInfo {
case Lua.OP_SETTABUP: {
final int b = Lua.GETARG_B(i);
if (Lua.ISK(b))
name = prototype.k[b&0x0ff].tojstring();
name = prototype.k[b & 0x0ff].tojstring();
break;
}
case Lua.OP_SETUPVAL: {
@@ -513,8 +527,8 @@ public class ProtoInfo {
String basename = name;
int count = 1;
do {
name = basename + '$' + count++;
} while (used.containsKey(name));
name = basename+'$'+count++;
} while ( used.containsKey(name) );
}
used.put(name, Boolean.TRUE);
names[bx] = name;
@@ -527,7 +541,7 @@ public class ProtoInfo {
final int n = s.length();
StringBuffer sb = new StringBuffer(n);
for (int i = 0; i < n; ++i)
sb.append( Character.isJavaIdentifierPart(s.charAt(i)) ? s.charAt(i): '_' );
sb.append(Character.isJavaIdentifierPart(s.charAt(i))? s.charAt(i): '_');
return sb.toString();
}

View File

@@ -26,30 +26,30 @@ public class UpvalInfo {
this.slot = slot;
this.nvars = 0;
this.var = null;
includeVarAndPosteriorVars( pi.vars[slot][pc] );
for ( int i=0; i<nvars; i++ )
var[i].allocupvalue = testIsAllocUpvalue( var[i] );
includeVarAndPosteriorVars(pi.vars[slot][pc]);
for (int i = 0; i < nvars; i++)
var[i].allocupvalue = testIsAllocUpvalue(var[i]);
this.rw = nvars > 1;
}
private boolean includeVarAndPosteriorVars( VarInfo var ) {
if ( var == null || var == VarInfo.INVALID )
private boolean includeVarAndPosteriorVars(VarInfo var) {
if (var == null || var == VarInfo.INVALID)
return false;
if ( var.upvalue == this )
if (var.upvalue == this)
return true;
var.upvalue = this;
appendVar( var );
if ( isLoopVariable( var ) )
appendVar(var);
if (isLoopVariable(var))
return false;
boolean loopDetected = includePosteriorVarsCheckLoops( var );
if ( loopDetected )
includePriorVarsIgnoreLoops( var );
boolean loopDetected = includePosteriorVarsCheckLoops(var);
if (loopDetected)
includePriorVarsIgnoreLoops(var);
return loopDetected;
}
private boolean isLoopVariable(VarInfo var) {
if ( var.pc >= 0 ) {
switch ( Lua.GET_OPCODE(pi.prototype.code[var.pc]) ) {
if (var.pc >= 0) {
switch (Lua.GET_OPCODE(pi.prototype.code[var.pc])) {
case Lua.OP_TFORLOOP:
case Lua.OP_FORLOOP:
return true;
@@ -58,25 +58,25 @@ public class UpvalInfo {
return false;
}
private boolean includePosteriorVarsCheckLoops( VarInfo prior ) {
private boolean includePosteriorVarsCheckLoops(VarInfo prior) {
boolean loopDetected = false;
for ( int i=0, n=pi.blocklist.length; i<n; i++ ) {
for (int i = 0, n = pi.blocklist.length; i < n; i++) {
BasicBlock b = pi.blocklist[i];
VarInfo v = pi.vars[slot][b.pc1];
if ( v == prior ) {
for ( int j=0, m=b.next!=null? b.next.length: 0; j<m; j++ ) {
if (v == prior) {
for (int j = 0, m = b.next != null? b.next.length: 0; j < m; j++) {
BasicBlock b1 = b.next[j];
VarInfo v1 = pi.vars[slot][b1.pc0];
if ( v1 != prior ) {
loopDetected |= includeVarAndPosteriorVars( v1 );
if ( v1.isPhiVar() )
includePriorVarsIgnoreLoops( v1 );
if (v1 != prior) {
loopDetected |= includeVarAndPosteriorVars(v1);
if (v1.isPhiVar())
includePriorVarsIgnoreLoops(v1);
}
}
} else {
for ( int pc=b.pc1-1; pc>=b.pc0; pc-- ) {
if ( pi.vars[slot][pc] == prior ) {
loopDetected |= includeVarAndPosteriorVars( pi.vars[slot][pc+1] );
for (int pc = b.pc1-1; pc >= b.pc0; pc--) {
if (pi.vars[slot][pc] == prior) {
loopDetected |= includeVarAndPosteriorVars(pi.vars[slot][pc+1]);
break;
}
}
@@ -86,20 +86,20 @@ public class UpvalInfo {
}
private void includePriorVarsIgnoreLoops(VarInfo poster) {
for ( int i=0, n=pi.blocklist.length; i<n; i++ ) {
for (int i = 0, n = pi.blocklist.length; i < n; i++) {
BasicBlock b = pi.blocklist[i];
VarInfo v = pi.vars[slot][b.pc0];
if ( v == poster ) {
for ( int j=0, m=b.prev!=null? b.prev.length: 0; j<m; j++ ) {
if (v == poster) {
for (int j = 0, m = b.prev != null? b.prev.length: 0; j < m; j++) {
BasicBlock b0 = b.prev[j];
VarInfo v0 = pi.vars[slot][b0.pc1];
if ( v0 != poster )
includeVarAndPosteriorVars( v0 );
if (v0 != poster)
includeVarAndPosteriorVars(v0);
}
} else {
for ( int pc=b.pc0+1; pc<=b.pc1; pc++ ) {
if ( pi.vars[slot][pc] == poster ) {
includeVarAndPosteriorVars( pi.vars[slot][pc-1] );
for (int pc = b.pc0+1; pc <= b.pc1; pc++) {
if (pi.vars[slot][pc] == poster) {
includeVarAndPosteriorVars(pi.vars[slot][pc-1]);
break;
}
}
@@ -108,9 +108,9 @@ public class UpvalInfo {
}
private void appendVar(VarInfo v) {
if ( nvars == 0 ) {
if (nvars == 0) {
var = new VarInfo[1];
} else if ( nvars+1 >= var.length ) {
} else if (nvars+1 >= var.length) {
VarInfo[] s = var;
var = new VarInfo[nvars*2+1];
System.arraycopy(s, 0, var, 0, nvars);
@@ -120,30 +120,30 @@ public class UpvalInfo {
public String toString() {
StringBuffer sb = new StringBuffer();
sb.append( pi.name );
for ( int i=0; i<nvars; i++ ) {
sb.append( i>0? ",": " " );
sb.append( String.valueOf(var[i]));
sb.append(pi.name);
for (int i = 0; i < nvars; i++) {
sb.append(i > 0? ",": " ");
sb.append(String.valueOf(var[i]));
}
if ( rw )
sb.append( "(rw)" );
if (rw)
sb.append("(rw)");
return sb.toString();
}
private boolean testIsAllocUpvalue(VarInfo v) {
if ( v.pc < 0 )
if (v.pc < 0)
return true;
BasicBlock b = pi.blocks[v.pc];
if ( v.pc > b.pc0 )
if (v.pc > b.pc0)
return pi.vars[slot][v.pc-1].upvalue != this;
if ( b.prev == null ) {
if (b.prev == null) {
v = pi.params[slot];
if ( v != null && v.upvalue != this )
if (v != null && v.upvalue != this)
return true;
} else {
for ( int i=0, n=b.prev.length; i<n; i++ ) {
for (int i = 0, n = b.prev.length; i < n; i++) {
v = pi.vars[slot][b.prev[i].pc1];
if ( v != null && v.upvalue != this )
if (v != null && v.upvalue != this)
return true;
}
}

View File

@@ -38,14 +38,16 @@ public class VarInfo {
}
public String toString() {
return slot < 0 ? "x.x" : (slot + "." + pc);
return slot < 0? "x.x": (slot + "." + pc);
}
/** Return replacement variable if there is exactly one value possible,
/**
* Return replacement variable if there is exactly one value possible,
* otherwise compute entire collection of variables and return null.
* Computes the list of aall variable values, and saves it for the future.
*
* @return new Variable to replace with if there is only one value, or null to leave alone.
* @return new Variable to replace with if there is only one value, or null
* to leave alone.
*/
public VarInfo resolvePhiVariableValues() {
return null;
@@ -55,9 +57,7 @@ public class VarInfo {
vars.add(this);
}
public boolean isPhiVar() {
return false;
}
public boolean isPhiVar() { return false; }
private static final class ParamVarInfo extends VarInfo {
private ParamVarInfo(int slot, int pc) {
@@ -88,17 +88,15 @@ public class VarInfo {
this.pi = pi;
}
public boolean isPhiVar() {
return true;
}
public boolean isPhiVar() { return true; }
public String toString() {
StringBuffer sb = new StringBuffer();
sb.append( super.toString() );
sb.append(super.toString());
sb.append("={");
for (int i=0, n=(values!=null? values.length : 0); i<n; i++) {
if ( i>0 )
sb.append( "," );
for (int i = 0, n = (values != null? values.length: 0); i < n; i++) {
if (i > 0)
sb.append(",");
sb.append(String.valueOf(values[i]));
}
sb.append("}");
@@ -119,7 +117,7 @@ public class VarInfo {
return v;
}
this.values = new VarInfo[n];
for ( int i=0; i<n; i++ ) {
for (int i = 0; i < n; i++) {
this.values[i] = (VarInfo) it.next();
this.values[i].isreferenced |= this.isreferenced;
}
@@ -128,14 +126,14 @@ public class VarInfo {
protected void collectUniqueValues(Set visitedBlocks, Set vars) {
BasicBlock b = pi.blocks[pc];
if ( pc == 0 )
if (pc == 0)
vars.add(pi.params[slot]);
for (int i = 0, n = b.prev != null ? b.prev.length : 0; i < n; i++) {
for (int i = 0, n = b.prev != null? b.prev.length: 0; i < n; i++) {
BasicBlock bp = b.prev[i];
if (!visitedBlocks.contains(bp)) {
visitedBlocks.add(bp);
VarInfo v = pi.vars[slot][bp.pc1];
if ( v != null )
if (v != null)
v.collectUniqueValues(visitedBlocks, vars);
}
}

View File

@@ -37,9 +37,9 @@ import org.luaj.vm2.lib.jse.CoerceJavaToLua;
* <p>
* This engine requires the types of the Bindings and ScriptContext to be
* compatible with the engine. For creating new client context use
* ScriptEngine.createContext() which will return {@link LuajContext},
* and for client bindings use the default engine scoped bindings or
* construct a {@link LuajBindings} directly.
* ScriptEngine.createContext() which will return {@link LuajContext}, and for
* client bindings use the default engine scoped bindings or construct a
* {@link LuajBindings} directly.
*/
public class LuaScriptEngine extends AbstractScriptEngine implements ScriptEngine, Compilable {
@@ -85,13 +85,13 @@ public class LuaScriptEngine extends AbstractScriptEngine implements ScriptEngin
final Globals g = context.globals;
final LuaFunction f = g.load(script, "script").checkfunction();
return new LuajCompiledScript(f, g);
} catch ( LuaError lee ) {
throw new ScriptException(lee.getMessage() );
} catch (LuaError lee) {
throw new ScriptException(lee.getMessage());
} finally {
is.close();
}
} catch ( Exception e ) {
throw new ScriptException("eval threw "+e.toString());
} catch (Exception e) {
throw new ScriptException("eval threw " + e.toString());
}
}
@@ -116,34 +116,28 @@ public class LuaScriptEngine extends AbstractScriptEngine implements ScriptEngin
}
@Override
public Object eval(String script, ScriptContext context)
throws ScriptException {
public Object eval(String script, ScriptContext context) throws ScriptException {
return eval(new StringReader(script), context);
}
@Override
public Object eval(Reader reader, ScriptContext context)
throws ScriptException {
public Object eval(Reader reader, ScriptContext context) throws ScriptException {
return compile(reader).eval(context);
}
@Override
public ScriptEngineFactory getFactory() {
return myFactory;
}
public ScriptEngineFactory getFactory() { return myFactory; }
class LuajCompiledScript extends CompiledScript {
final LuaFunction function;
final Globals compiling_globals;
LuajCompiledScript(LuaFunction function, Globals compiling_globals) {
this.function = function;
this.compiling_globals = compiling_globals;
}
public ScriptEngine getEngine() {
return LuaScriptEngine.this;
}
public ScriptEngine getEngine() { return LuaScriptEngine.this; }
public Object eval() throws ScriptException {
return eval(getContext());
@@ -186,17 +180,17 @@ public class LuaScriptEngine extends AbstractScriptEngine implements ScriptEngin
}
public int read() throws IOException {
if ( n > 0 )
if (n > 0)
return buf[--n];
int c = r.read();
if ( c < 0x80 )
if (c < 0x80)
return c;
n = 0;
if ( c < 0x800 ) {
buf[n++] = (0x80 | ( c & 0x3f));
if (c < 0x800) {
buf[n++] = (0x80 | (c & 0x3f));
return (0xC0 | ((c>>6) & 0x1f));
} else {
buf[n++] = (0x80 | ( c & 0x3f));
buf[n++] = (0x80 | (c & 0x3f));
buf[n++] = (0x80 | ((c>>6) & 0x3f));
return (0xE0 | ((c>>12) & 0x0f));
}
@@ -233,31 +227,36 @@ public class LuaScriptEngine extends AbstractScriptEngine implements ScriptEngin
}
static private LuaValue toLua(Object javaValue) {
return javaValue == null? LuaValue.NIL:
javaValue instanceof LuaValue? (LuaValue) javaValue:
CoerceJavaToLua.coerce(javaValue);
return javaValue == null? LuaValue.NIL
: javaValue instanceof LuaValue? (LuaValue) javaValue: CoerceJavaToLua.coerce(javaValue);
}
static private Object toJava(LuaValue luajValue) {
switch ( luajValue.type() ) {
case LuaValue.TNIL: return null;
case LuaValue.TSTRING: return luajValue.tojstring();
case LuaValue.TUSERDATA: return luajValue.checkuserdata(Object.class);
case LuaValue.TNUMBER: return luajValue.isinttype()?
(Object) new Integer(luajValue.toint()):
(Object) new Double(luajValue.todouble());
default: return luajValue;
switch (luajValue.type()) {
case LuaValue.TNIL:
return null;
case LuaValue.TSTRING:
return luajValue.tojstring();
case LuaValue.TUSERDATA:
return luajValue.checkuserdata(Object.class);
case LuaValue.TNUMBER:
return luajValue.isinttype()? (Object) new Integer(luajValue.toint())
: (Object) new Double(luajValue.todouble());
default:
return luajValue;
}
}
static private Object toJava(Varargs v) {
final int n = v.narg();
switch (n) {
case 0: return null;
case 1: return toJava(v.arg1());
case 0:
return null;
case 1:
return toJava(v.arg1());
default:
Object[] o = new Object[n];
for (int i=0; i<n; ++i)
for (int i = 0; i < n; ++i)
o[i] = toJava(v.arg(i+1));
return o;
}

View File

@@ -30,25 +30,16 @@ import javax.script.ScriptEngineFactory;
/**
* Jsr 223 scripting engine factory.
*
* Exposes metadata to support the lua language, and constructs
* instances of LuaScriptEngine to handl lua scripts.
* Exposes metadata to support the lua language, and constructs instances of
* LuaScriptEngine to handl lua scripts.
*/
public class LuaScriptEngineFactory implements ScriptEngineFactory {
private static final String [] EXTENSIONS = {
"lua",
".lua",
};
private static final String[] EXTENSIONS = { "lua", ".lua", };
private static final String [] MIMETYPES = {
"text/lua",
"application/lua"
};
private static final String[] MIMETYPES = { "text/lua", "application/lua" };
private static final String [] NAMES = {
"lua",
"luaj",
};
private static final String[] NAMES = { "lua", "luaj", };
private List<String> extensions;
private List<String> mimeTypes;
@@ -60,33 +51,19 @@ public class LuaScriptEngineFactory implements ScriptEngineFactory {
names = Arrays.asList(NAMES);
}
public String getEngineName() {
return getScriptEngine().get(ScriptEngine.ENGINE).toString();
}
public String getEngineName() { return getScriptEngine().get(ScriptEngine.ENGINE).toString(); }
public String getEngineVersion() {
return getScriptEngine().get(ScriptEngine.ENGINE_VERSION).toString();
}
public String getEngineVersion() { return getScriptEngine().get(ScriptEngine.ENGINE_VERSION).toString(); }
public List<String> getExtensions() {
return extensions;
}
public List<String> getExtensions() { return extensions; }
public List<String> getMimeTypes() {
return mimeTypes;
}
public List<String> getMimeTypes() { return mimeTypes; }
public List<String> getNames() {
return names;
}
public List<String> getNames() { return names; }
public String getLanguageName() {
return getScriptEngine().get(ScriptEngine.LANGUAGE).toString();
}
public String getLanguageName() { return getScriptEngine().get(ScriptEngine.LANGUAGE).toString(); }
public String getLanguageVersion() {
return getScriptEngine().get(ScriptEngine.LANGUAGE_VERSION).toString();
}
public String getLanguageVersion() { return getScriptEngine().get(ScriptEngine.LANGUAGE_VERSION).toString(); }
public Object getParameter(String key) {
return getScriptEngine().get(key).toString();
@@ -110,7 +87,7 @@ public class LuaScriptEngineFactory implements ScriptEngineFactory {
return "print(" + toDisplay + ")";
}
public String getProgram(String ... statements) {
public String getProgram(String... statements) {
StringBuffer sb = new StringBuffer();
int len = statements.length;
for (int i = 0; i < len; i++) {
@@ -122,7 +99,5 @@ public class LuaScriptEngineFactory implements ScriptEngineFactory {
return sb.toString();
}
public ScriptEngine getScriptEngine() {
return new LuaScriptEngine();
}
public ScriptEngine getScriptEngine() { return new LuaScriptEngine(); }
}

View File

@@ -36,8 +36,8 @@ import org.luaj.vm2.lib.jse.JsePlatform;
import org.luaj.vm2.luajc.LuaJC;
/**
* Context for LuaScriptEngine execution which maintains its own Globals,
* and manages the input and output redirection.
* Context for LuaScriptEngine execution which maintains its own Globals, and
* manages the input and output redirection.
*/
public class LuajContext extends SimpleScriptContext implements ScriptContext {
@@ -51,37 +51,34 @@ public class LuajContext extends SimpleScriptContext implements ScriptContext {
/** The initial value of globals.STDERR */
private final PrintStream stderr;
/** Construct a LuajContext with its own globals which may
* be debug globals depending on the value of the system
* property 'org.luaj.debug'
/**
* Construct a LuajContext with its own globals which may be debug globals
* depending on the value of the system property 'org.luaj.debug'
* <p>
* If the system property 'org.luaj.debug' is set, the globals
* created will be a debug globals that includes the debug
* library. This may provide better stack traces, but may
* have negative impact on performance.
* If the system property 'org.luaj.debug' is set, the globals created will
* be a debug globals that includes the debug library. This may provide
* better stack traces, but may have negative impact on performance.
*/
public LuajContext() {
this("true".equals(System.getProperty("org.luaj.debug")),
"true".equals(System.getProperty("org.luaj.luajc")));
this("true".equals(System.getProperty("org.luaj.debug")), "true".equals(System.getProperty("org.luaj.luajc")));
}
/** Construct a LuajContext with its own globals, which
* which optionally are debug globals, and optionally use the
* luajc direct lua to java bytecode compiler.
/**
* Construct a LuajContext with its own globals, which which optionally are
* debug globals, and optionally use the luajc direct lua to java bytecode
* compiler.
* <p>
* If createDebugGlobals is set, the globals
* created will be a debug globals that includes the debug
* library. This may provide better stack traces, but may
* have negative impact on performance.
* @param createDebugGlobals true to create debug globals,
* false for standard globals.
* @param useLuaJCCompiler true to use the luajc compiler,
* reqwuires bcel to be on the class path.
* If createDebugGlobals is set, the globals created will be a debug globals
* that includes the debug library. This may provide better stack traces,
* but may have negative impact on performance.
*
* @param createDebugGlobals true to create debug globals, false for
* standard globals.
* @param useLuaJCCompiler true to use the luajc compiler, reqwuires bcel
* to be on the class path.
*/
public LuajContext(boolean createDebugGlobals, boolean useLuaJCCompiler) {
globals = createDebugGlobals?
JsePlatform.debugGlobals():
JsePlatform.standardGlobals();
globals = createDebugGlobals? JsePlatform.debugGlobals(): JsePlatform.standardGlobals();
if (useLuaJCCompiler)
LuaJC.install(globals);
stdin = globals.STDIN;
@@ -91,42 +88,40 @@ public class LuajContext extends SimpleScriptContext implements ScriptContext {
@Override
public void setErrorWriter(Writer writer) {
globals.STDERR = writer != null?
new PrintStream(new WriterOutputStream(writer)):
stderr;
globals.STDERR = writer != null? new PrintStream(new WriterOutputStream(writer)): stderr;
}
@Override
public void setReader(Reader reader) {
globals.STDIN = reader != null?
new ReaderInputStream(reader):
stdin;
}
public void setReader(Reader reader) { globals.STDIN = reader != null? new ReaderInputStream(reader): stdin; }
@Override
public void setWriter(Writer writer) {
globals.STDOUT = writer != null?
new PrintStream(new WriterOutputStream(writer), true):
stdout;
globals.STDOUT = writer != null? new PrintStream(new WriterOutputStream(writer), true): stdout;
}
static final class WriterOutputStream extends OutputStream {
final Writer w;
WriterOutputStream(Writer w) {
this.w = w;
}
public void write(int b) throws IOException {
w.write(new String(new byte[] {(byte)b}));
w.write(new String(new byte[] { (byte) b }));
}
public void write(byte[] b, int o, int l) throws IOException {
w.write(new String(b, o, l));
}
public void write(byte[] b) throws IOException {
w.write(new String(b));
}
public void close() throws IOException {
w.close();
}
public void flush() throws IOException {
w.flush();
}
@@ -134,9 +129,11 @@ public class LuajContext extends SimpleScriptContext implements ScriptContext {
static final class ReaderInputStream extends InputStream {
final Reader r;
ReaderInputStream(Reader r) {
this.r = r;
}
public int read() throws IOException {
return r.read();
}

View File

@@ -31,13 +31,13 @@ import org.luaj.vm2.lib.jse.CoerceJavaToLua;
import org.luaj.vm2.lib.jse.JsePlatform;
/**
* Default {@link Launcher} instance that creates standard globals
* and runs the supplied scripts with chunk name 'main'.
* Default {@link Launcher} instance that creates standard globals and runs the
* supplied scripts with chunk name 'main'.
* <P>
* Arguments are coerced into lua using {@link CoerceJavaToLua#coerce(Object)}.
* <P>
* Return values with simple types are coerced into Java simple types.
* Tables, threads, and functions are returned as lua objects.
* Return values with simple types are coerced into Java simple types. Tables,
* threads, and functions are returned as lua objects.
*
* @see Launcher
* @see LuajClassLoader
@@ -57,7 +57,9 @@ public class DefaultLauncher implements Launcher {
return launchChunk(g.load(script, "main"), arg);
}
/** Launches the script with chunk name 'main' and loading using modes 'bt' */
/**
* Launches the script with chunk name 'main' and loading using modes 'bt'
*/
public Object[] launch(InputStream script, Object[] arg) {
return launchChunk(g.load(script, "main", "bt", g), arg);
}

Some files were not shown because too many files have changed in this diff Show More