[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,6 +66,7 @@ public final class Buffer {
/**
* Create buffer with specified initial capacity
*
* @param initialCapacity the initial capacity
*/
public Buffer(int initialCapacity) {
@@ -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,6 +110,7 @@ public final class Buffer {
/**
* Convert the buffer to a {@link LuaString}
*
* @return the value as a {@link LuaString}
*/
public final LuaString tostring() {
@@ -114,6 +120,7 @@ public final class Buffer {
/**
* 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,6 +138,7 @@ public final class Buffer {
/**
* Append a single byte to the buffer.
*
* @return {@code this} to allow call chaining
*/
public final Buffer append(byte b) {
@@ -140,6 +149,7 @@ public final class Buffer {
/**
* Append a {@link LuaValue} to the buffer.
*
* @return {@code this} to allow call chaining
*/
public final Buffer append(LuaValue val) {
@@ -149,6 +159,7 @@ public final class Buffer {
/**
* Append a {@link LuaString} to the buffer.
*
* @return {@code this} to allow call chaining
*/
public final Buffer append(LuaString str) {
@@ -160,8 +171,9 @@ public final class Buffer {
}
/**
* 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)
*/
@@ -174,34 +186,46 @@ public final class Buffer {
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);
}
/** 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());
}
/** 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) {
@@ -214,9 +238,13 @@ public final class Buffer {
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) {
@@ -233,7 +261,9 @@ public final class Buffer {
}
}
/** 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
*/

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>
* }
* </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>
* }
* </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,24 +191,39 @@ 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.
@@ -186,69 +236,96 @@ public class Globals extends LuaTable {
}
}
/** 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);
@@ -260,12 +337,16 @@ public class Globals extends LuaTable {
}
}
/** 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) {
@@ -286,17 +367,21 @@ public class Globals extends LuaTable {
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,16 +409,20 @@ 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;
}
public int read(char[] cbuf, int off, int len) throws IOException {
int j = 0;
for (; j < len && i < n; ++j, ++i)
@@ -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++]);
}
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);
i += k;
return k;
}
public int available() throws IOException {
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,29 +504,36 @@ 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);
if (n < 0)
@@ -436,9 +548,11 @@ 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;
@@ -448,9 +562,11 @@ public class Globals extends LuaTable {
b = dest;
}
}
public boolean markSupported() {
return true;
}
public synchronized void reset() throws IOException {
i = 0;
}

View File

@@ -25,7 +25,6 @@ import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStream;
/**
* Class to undump compiled lua bytecode into a {@link Prototype} instances.
* <p>
@@ -34,47 +33,63 @@ import java.io.InputStream;
* 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
* 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.
* }
* </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}.
* {@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
* 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>
* }
* </pre>
*
* The {@link LoadState}'s default undumper {@link #instance}
* may be used directly to undump these bytes:
* <pre> {@code
* 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>
* }
* </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 Globals.Compiler
* @see Globals.Undumper
@@ -87,16 +102,25 @@ import java.io.InputStream;
*/
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,22 +186,28 @@ 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]);
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 {
@@ -191,14 +222,16 @@ public class LoadState {
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]);
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 {
@@ -213,7 +246,9 @@ public class LoadState {
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 {
@@ -227,8 +262,10 @@ public class LoadState {
/**
* 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) {
@@ -252,6 +289,7 @@ public class LoadState {
/**
* Load a number from a binary chunk
*
* @return the {@link LuaValue} loaded
* @throws IOException if an i/o exception occurs
*/
@@ -265,6 +303,7 @@ public class LoadState {
/**
* Load a list of constants from a binary chunk
*
* @param f the function prototype
* @throws IOException if an i/o exception occurs
*/
@@ -301,7 +340,6 @@ public class LoadState {
f.p = protos;
}
void loadUpvalues(Prototype f) throws IOException {
int n = loadInt();
f.upvalues = n > 0? new Upvaldesc[n]: NOUPVALDESCS;
@@ -314,6 +352,7 @@ 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
*/
@@ -336,6 +375,7 @@ public class LoadState {
/**
* 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 {
@@ -383,17 +424,19 @@ public class LoadState {
}
/**
* 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]
if (stream.read() != LUA_SIGNATURE[0] || stream.read() != LUA_SIGNATURE[1] || stream.read() != LUA_SIGNATURE[2]
|| stream.read() != LUA_SIGNATURE[3])
return null;
@@ -416,6 +459,7 @@ public class LoadState {
/**
* Construct a source name from a supplied chunk name
*
* @param name String name that appears in the chunk
* @return source file name
*/
@@ -435,8 +479,7 @@ public class LoadState {
}
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

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,14 +53,12 @@ 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.
*/
@@ -132,7 +129,6 @@ public class Lua {
return ((i>>POS_Bx) & MAXARG_Bx)-MAXARG_sBx;
}
/*
** Macros to operate RK indices
*/
@@ -157,20 +153,17 @@ public class Lua {
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
*/
@@ -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,15 +317,19 @@ 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;
}
public static int getCMode(int m) {
return (luaP_opmodes[m]>>2) & 3;
}
public static boolean testAMode(int m) {
return 0 != (luaP_opmodes[m] & (1<<6));
}
public static boolean testTMode(int m) {
return 0 != (luaP_opmodes[m] & (1<<7));
}

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
@@ -75,6 +75,7 @@ public final class LuaBoolean extends LuaValue {
/**
* Return the boolean value for this boolean
*
* @return value as a Java boolean
*/
public boolean booleanValue() {

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>
@@ -75,6 +87,7 @@ import org.luaj.vm2.lib.DebugLib.CallFrame;
* <li>{@link LuaValue#invokemethod(String,Varargs)}</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.
*/
@@ -112,7 +128,6 @@ public class LuaClosure extends LuaFunction {
}
}
public boolean isclosure() {
return true;
}
@@ -144,27 +159,46 @@ public class LuaClosure extends LuaFunction {
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();
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();
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();
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();
}
}
@@ -221,8 +255,8 @@ 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;
@@ -251,7 +285,8 @@ public class LuaClosure extends LuaFunction {
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,7 +294,8 @@ 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) */
@@ -272,27 +308,33 @@ public class LuaClosure extends LuaFunction {
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,8 +351,7 @@ 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;
{
c = (i>>14) & 0x1ff; {
if (c > b+1) {
Buffer sb = stack[c].buffer();
while ( --c >= b )
@@ -334,17 +375,20 @@ 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;
@@ -363,21 +407,42 @@ public class LuaClosure extends LuaFunction {
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;
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
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) {
v.copyto(stack, a, c-1);
@@ -391,14 +456,17 @@ public class LuaClosure extends LuaFunction {
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]));
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);
}
@@ -406,9 +474,12 @@ public class LuaClosure extends LuaFunction {
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];
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);
}
@@ -528,15 +599,15 @@ 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 {
@@ -594,5 +665,4 @@ public class LuaClosure extends LuaFunction {
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
@@ -94,16 +98,25 @@ 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 long optlong(long defval) { return (long) v; }
public LuaInteger checkinteger() { return LuaInteger.valueOf((int) (long) v); }
@@ -116,68 +129,102 @@ public class LuaDouble extends LuaNumber {
// 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); }
// 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; }
// 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); }
/** Divide two double numbers according to lua math, and return a {@link LuaValue} result.
/**
* 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;
}
/** 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;
}
/** 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);
}
@@ -187,15 +234,19 @@ public class LuaDouble extends LuaNumber {
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;
}
@@ -207,28 +258,55 @@ public class LuaDouble extends LuaNumber {
// 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(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(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
@@ -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,20 +65,25 @@ 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;
}
/** 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) {
@@ -98,7 +103,9 @@ public class LuaError extends RuntimeException {
}
/**
* 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
*/
@@ -108,8 +115,9 @@ public class LuaError extends RuntimeException {
}
/**
* 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) {
@@ -118,13 +126,9 @@ public class LuaError extends RuntimeException {
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++;
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
@@ -53,7 +53,9 @@ public class LuaInteger extends LuaNumber {
};
// 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() {
@@ -138,63 +151,116 @@ public class LuaInteger extends LuaNumber {
// 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); }
// 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; }
// 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); }
// 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(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(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
@@ -203,15 +269,19 @@ public class LuaInteger extends LuaNumber {
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));
}

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); }
}

View File

@@ -21,7 +21,6 @@
******************************************************************************/
package org.luaj.vm2;
import java.io.ByteArrayInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
@@ -33,27 +32,27 @@ import org.luaj.vm2.lib.MathLib;
/**
* Subclass of {@link LuaValue} for representing lua strings.
* <p>
* Because lua string values are more nearly sequences of bytes than
* sequences of characters or unicode code points, the {@link LuaString}
* implementation holds the string value in an internal byte array.
* Because lua string values are more nearly sequences of bytes than sequences
* of characters or unicode code points, the {@link LuaString} implementation
* holds the string value in an internal byte array.
* <p>
* {@link LuaString} values are not considered mutable once constructed,
* so multiple {@link LuaString} values can chare a single byte array.
* {@link LuaString} values are not considered mutable once constructed, so
* multiple {@link LuaString} values can chare a single byte array.
* <p>
* Currently {@link LuaString}s are pooled via a centrally managed weak table.
* To ensure that as many string values as possible take advantage of this,
* Constructors are not exposed directly. As with number, booleans, and nil,
* instance construction should be via {@link LuaValue#valueOf(byte[])} or similar API.
* instance construction should be via {@link LuaValue#valueOf(byte[])} or
* similar API.
* <p>
* Because of this pooling, users of LuaString <em>must not directly alter the
* bytes in a LuaString</em>, or undefined behavior will result.
* <p>
* When Java Strings are used to initialize {@link LuaString} data, the UTF8 encoding is assumed.
* The functions
* {@link #lengthAsUtf8(char[])},
* When Java Strings are used to initialize {@link LuaString} data, the UTF8
* encoding is assumed. The functions {@link #lengthAsUtf8(char[])},
* {@link #encodeToUtf8(char[], int, byte[], int)}, and
* {@link #decodeAsUtf8(byte[], int, int)}
* are used to convert back and forth between UTF8 byte arrays and character arrays.
* {@link #decodeAsUtf8(byte[], int, int)} are used to convert back and forth
* between UTF8 byte arrays and character arrays.
*
* @see LuaValue
* @see LuaValue#valueOf(String)
@@ -61,18 +60,22 @@ import org.luaj.vm2.lib.MathLib;
*/
public class LuaString extends LuaValue {
/** The singleton instance for string metatables that forwards to the string functions.
* Typically, this is set to the string metatable as a side effect of loading the string
* library, and is read-write to provide flexible behavior by default. When used in a
* server environment where there may be roge scripts, this should be replaced with a
* read-only table since it is shared across all lua code in this Java VM.
/**
* The singleton instance for string metatables that forwards to the string
* functions. Typically, this is set to the string metatable as a side
* effect of loading the string library, and is read-write to provide
* flexible behavior by default. When used in a server environment where
* there may be roge scripts, this should be replaced with a read-only table
* since it is shared across all lua code in this Java VM.
*/
public static LuaValue s_metatable;
/** The bytes for the string. These <em><b>must not be mutated directly</b></em> because
* the backing may be shared by multiple LuaStrings, and the hash code is
* computed only at construction time.
* It is exposed only for performance and legacy reasons. */
/**
* The bytes for the string. These <em><b>must not be mutated
* directly</b></em> because the backing may be shared by multiple
* LuaStrings, and the hash code is computed only at construction time. It
* is exposed only for performance and legacy reasons.
*/
public final byte[] m_bytes;
/** The offset into the byte array, 0 means start at the first byte */
@@ -84,31 +87,39 @@ public class LuaString extends LuaValue {
/** The hashcode for this string. Computed at construct time. */
private final int m_hashcode;
/** Size of cache of recent short strings. This is the maximum number of LuaStrings that
* will be retained in the cache of recent short strings. Exposed to package for testing. */
/**
* Size of cache of recent short strings. This is the maximum number of
* LuaStrings that will be retained in the cache of recent short strings.
* Exposed to package for testing.
*/
static final int RECENT_STRINGS_CACHE_SIZE = 128;
/** Maximum length of a string to be considered for recent short strings caching.
* This effectively limits the total memory that can be spent on the recent strings cache,
* because no LuaString whose backing exceeds this length will be put into the cache.
* Exposed to package for testing. */
/**
* Maximum length of a string to be considered for recent short strings
* caching. This effectively limits the total memory that can be spent on
* the recent strings cache, because no LuaString whose backing exceeds this
* length will be put into the cache. Exposed to package for testing.
*/
static final int RECENT_STRINGS_MAX_LENGTH = 32;
/** Simple cache of recently created strings that are short.
* This is simply a list of strings, indexed by their hash codes modulo the cache size
* that have been recently constructed. If a string is being constructed frequently
* from different contexts, it will generally show up as a cache hit and resolve
* to the same value. */
/**
* Simple cache of recently created strings that are short. This is simply a
* list of strings, indexed by their hash codes modulo the cache size that
* have been recently constructed. If a string is being constructed
* frequently from different contexts, it will generally show up as a cache
* hit and resolve to the same value.
*/
private static final class RecentShortStrings {
private static final LuaString recent_short_strings[] =
new LuaString[RECENT_STRINGS_CACHE_SIZE];
private static final LuaString recent_short_strings[] = new LuaString[RECENT_STRINGS_CACHE_SIZE];
}
/**
* Get a {@link LuaString} instance whose bytes match
* the supplied Java String using the UTF8 encoding.
* Get a {@link LuaString} instance whose bytes match the supplied Java
* String using the UTF8 encoding.
*
* @param string Java String containing characters to encode as UTF8
* @return {@link LuaString} with UTF8 bytes corresponding to the supplied String
* @return {@link LuaString} with UTF8 bytes corresponding to the supplied
* String
*/
public static LuaString valueOf(String string) {
char[] c = string.toCharArray();
@@ -117,13 +128,16 @@ public class LuaString extends LuaValue {
return valueUsing(b, 0, b.length);
}
/** Construct a {@link LuaString} for a portion of a byte array.
/**
* Construct a {@link LuaString} for a portion of a byte array.
* <p>
* The array is first be used as the backing for this object, so clients must not change contents.
* If the supplied value for 'len' is more than half the length of the container, the
* supplied byte array will be used as the backing, otherwise the bytes will be copied to a
* new byte array, and cache lookup may be performed.
* The array is first be used as the backing for this object, so clients
* must not change contents. If the supplied value for 'len' is more than
* half the length of the container, the supplied byte array will be used as
* the backing, otherwise the bytes will be copied to a new byte array, and
* cache lookup may be performed.
* <p>
*
* @param bytes byte buffer
* @param off offset into the byte buffer
* @param len length of the byte buffer
@@ -135,7 +149,8 @@ public class LuaString extends LuaValue {
final int hash = hashCode(bytes, off, len);
final int bucket = hash & (RECENT_STRINGS_CACHE_SIZE-1);
final LuaString t = RecentShortStrings.recent_short_strings[bucket];
if (t != null && t.m_hashcode == hash && t.byteseq(bytes, off, len)) return t;
if (t != null && t.m_hashcode == hash && t.byteseq(bytes, off, len))
return t;
final LuaString s = valueFromCopy(bytes, off, len);
RecentShortStrings.recent_short_strings[bucket] = s;
return s;
@@ -148,15 +163,18 @@ public class LuaString extends LuaValue {
return new LuaString(copy, 0, len);
}
/** Construct a {@link LuaString} around, possibly using the the supplied
/**
* Construct a {@link LuaString} around, possibly using the the supplied
* byte array as the backing store.
* <p>
* The caller must ensure that the array is not mutated after the call.
* However, if the string is short enough the short-string cache is checked
* for a match which may be used instead of the supplied byte array.
* <p>
*
* @param bytes byte buffer
* @return {@link LuaString} wrapping the byte buffer, or an equivalent string.
* @return {@link LuaString} wrapping the byte buffer, or an equivalent
* string.
*/
static public LuaString valueUsing(byte[] bytes, int off, int len) {
if (bytes.length > RECENT_STRINGS_MAX_LENGTH)
@@ -164,30 +182,43 @@ public class LuaString extends LuaValue {
final int hash = hashCode(bytes, off, len);
final int bucket = hash & (RECENT_STRINGS_CACHE_SIZE-1);
final LuaString t = RecentShortStrings.recent_short_strings[bucket];
if (t != null && t.m_hashcode == hash && t.byteseq(bytes, off, len)) return t;
if (t != null && t.m_hashcode == hash && t.byteseq(bytes, off, len))
return t;
final LuaString s = new LuaString(bytes, off, len);
RecentShortStrings.recent_short_strings[bucket] = s;
return s;
}
/** Construct a {@link LuaString} using the supplied characters as byte values.
/**
* Construct a {@link LuaString} using the supplied characters as byte
* values.
* <p>
* Only the low-order 8-bits of each character are used, the remainder is ignored.
* Only the low-order 8-bits of each character are used, the remainder is
* ignored.
* <p>
* This is most useful for constructing byte sequences that do not conform to UTF8.
* @param bytes array of char, whose values are truncated at 8-bits each and put into a byte array.
* This is most useful for constructing byte sequences that do not conform
* to UTF8.
*
* @param bytes array of char, whose values are truncated at 8-bits each and
* put into a byte array.
* @return {@link LuaString} wrapping a copy of the byte buffer
*/
public static LuaString valueOf(char[] bytes) {
return valueOf(bytes, 0, bytes.length);
}
/** Construct a {@link LuaString} using the supplied characters as byte values.
/**
* Construct a {@link LuaString} using the supplied characters as byte
* values.
* <p>
* Only the low-order 8-bits of each character are used, the remainder is ignored.
* Only the low-order 8-bits of each character are used, the remainder is
* ignored.
* <p>
* This is most useful for constructing byte sequences that do not conform to UTF8.
* @param bytes array of char, whose values are truncated at 8-bits each and put into a byte array.
* This is most useful for constructing byte sequences that do not conform
* to UTF8.
*
* @param bytes array of char, whose values are truncated at 8-bits each and
* put into a byte array.
* @return {@link LuaString} wrapping a copy of the byte buffer
*/
public static LuaString valueOf(char[] bytes, int off, int len) {
@@ -197,11 +228,14 @@ public class LuaString extends LuaValue {
return valueUsing(b, 0, len);
}
/** Construct a {@link LuaString} for all the bytes in a byte array.
/**
* Construct a {@link LuaString} for all the bytes in a byte array.
* <p>
* The LuaString returned will either be a new LuaString containing a copy
* of the bytes array, or be an existing LuaString used already having the same value.
* of the bytes array, or be an existing LuaString used already having the
* same value.
* <p>
*
* @param bytes byte buffer
* @return {@link LuaString} wrapping the byte buffer
*/
@@ -209,14 +243,16 @@ public class LuaString extends LuaValue {
return valueOf(bytes, 0, bytes.length);
}
/** Construct a {@link LuaString} for all the bytes in a byte array, possibly using
* the supplied array as the backing store.
/**
* Construct a {@link LuaString} for all the bytes in a byte array, possibly
* using the supplied array as the backing store.
* <p>
* The LuaString returned will either be a new LuaString containing the byte array,
* or be an existing LuaString used already having the same value.
* The LuaString returned will either be a new LuaString containing the byte
* array, or be an existing LuaString used already having the same value.
* <p>
* The caller must not mutate the contents of the byte array after this call, as
* it may be used elsewhere due to recent short string caching.
* The caller must not mutate the contents of the byte array after this
* call, as it may be used elsewhere due to recent short string caching.
*
* @param bytes byte buffer
* @return {@link LuaString} wrapping the byte buffer
*/
@@ -224,10 +260,14 @@ public class LuaString extends LuaValue {
return valueUsing(bytes, 0, bytes.length);
}
/** Construct a {@link LuaString} around a byte array without copying the contents.
/**
* Construct a {@link LuaString} around a byte array without copying the
* contents.
* <p>
* The array is used directly after this is called, so clients must not change contents.
* The array is used directly after this is called, so clients must not
* change contents.
* <p>
*
* @param bytes byte buffer
* @param offset offset into the byte buffer
* @param length length of the byte buffer
@@ -264,52 +304,118 @@ public class LuaString extends LuaValue {
public LuaValue neg() { double d = scannumber(); return Double.isNaN(d)? super.neg(): valueOf(-d); }
// basic binary arithmetic
public LuaValue add( LuaValue rhs ) { double d = scannumber(); return Double.isNaN(d)? arithmt(ADD,rhs): rhs.add(d); }
public LuaValue add(LuaValue rhs) {
double d = scannumber();
return Double.isNaN(d)? arithmt(ADD, rhs): rhs.add(d);
}
public LuaValue add(double rhs) { return valueOf(checkarith()+rhs); }
public LuaValue add(int rhs) { return valueOf(checkarith()+rhs); }
public LuaValue sub( LuaValue rhs ) { double d = scannumber(); return Double.isNaN(d)? arithmt(SUB,rhs): rhs.subFrom(d); }
public LuaValue sub(LuaValue rhs) {
double d = scannumber();
return Double.isNaN(d)? arithmt(SUB, rhs): rhs.subFrom(d);
}
public LuaValue sub(double rhs) { return valueOf(checkarith()-rhs); }
public LuaValue sub(int rhs) { return valueOf(checkarith()-rhs); }
public LuaValue subFrom(double lhs) { return valueOf(lhs-checkarith()); }
public LuaValue mul( LuaValue rhs ) { double d = scannumber(); return Double.isNaN(d)? arithmt(MUL,rhs): rhs.mul(d); }
public LuaValue mul(LuaValue rhs) {
double d = scannumber();
return Double.isNaN(d)? arithmt(MUL, rhs): rhs.mul(d);
}
public LuaValue mul(double rhs) { return valueOf(checkarith()*rhs); }
public LuaValue mul(int rhs) { return valueOf(checkarith()*rhs); }
public LuaValue pow( LuaValue rhs ) { double d = scannumber(); return Double.isNaN(d)? arithmt(POW,rhs): rhs.powWith(d); }
public LuaValue pow(LuaValue rhs) {
double d = scannumber();
return Double.isNaN(d)? arithmt(POW, rhs): rhs.powWith(d);
}
public LuaValue pow(double rhs) { return MathLib.dpow(checkarith(), rhs); }
public LuaValue pow(int rhs) { return MathLib.dpow(checkarith(), rhs); }
public LuaValue powWith(double lhs) { return MathLib.dpow(lhs, checkarith()); }
public LuaValue powWith(int lhs) { return MathLib.dpow(lhs, checkarith()); }
public LuaValue div( LuaValue rhs ) { double d = scannumber(); return Double.isNaN(d)? arithmt(DIV,rhs): rhs.divInto(d); }
public LuaValue div(LuaValue rhs) {
double d = scannumber();
return Double.isNaN(d)? arithmt(DIV, rhs): rhs.divInto(d);
}
public LuaValue div(double rhs) { return LuaDouble.ddiv(checkarith(), rhs); }
public LuaValue div(int rhs) { return LuaDouble.ddiv(checkarith(), rhs); }
public LuaValue divInto(double lhs) { return LuaDouble.ddiv(lhs, checkarith()); }
public LuaValue mod( LuaValue rhs ) { double d = scannumber(); return Double.isNaN(d)? arithmt(MOD,rhs): rhs.modFrom(d); }
public LuaValue mod(LuaValue rhs) {
double d = scannumber();
return Double.isNaN(d)? arithmt(MOD, rhs): rhs.modFrom(d);
}
public LuaValue mod(double rhs) { return LuaDouble.dmod(checkarith(), rhs); }
public LuaValue mod(int rhs) { return LuaDouble.dmod(checkarith(), rhs); }
public LuaValue modFrom(double lhs) { return LuaDouble.dmod(lhs, checkarith()); }
// relational operators, these only work with other strings
public LuaValue lt( LuaValue rhs ) { return rhs.isstring() ? (rhs.strcmp(this)>0? LuaValue.TRUE: FALSE) : super.lt(rhs); }
public LuaValue lt(LuaValue rhs) {
return rhs.isstring()? (rhs.strcmp(this) > 0? LuaValue.TRUE: FALSE): super.lt(rhs);
}
public boolean lt_b(LuaValue rhs) { return rhs.isstring()? rhs.strcmp(this) > 0: super.lt_b(rhs); }
public boolean lt_b(int rhs) { typerror("attempt to compare string with number"); return false; }
public boolean lt_b(double rhs) { typerror("attempt to compare string with number"); return false; }
public LuaValue lteq( LuaValue rhs ) { return rhs.isstring() ? (rhs.strcmp(this)>=0? LuaValue.TRUE: FALSE) : super.lteq(rhs); }
public LuaValue lteq(LuaValue rhs) {
return rhs.isstring()? (rhs.strcmp(this) >= 0? LuaValue.TRUE: FALSE): super.lteq(rhs);
}
public boolean lteq_b(LuaValue rhs) { return rhs.isstring()? rhs.strcmp(this) >= 0: super.lteq_b(rhs); }
public boolean lteq_b(int rhs) { typerror("attempt to compare string with number"); return false; }
public boolean lteq_b(double rhs) { typerror("attempt to compare string with number"); return false; }
public LuaValue gt( LuaValue rhs ) { return rhs.isstring() ? (rhs.strcmp(this)<0? LuaValue.TRUE: FALSE) : super.gt(rhs); }
public LuaValue gt(LuaValue rhs) {
return rhs.isstring()? (rhs.strcmp(this) < 0? LuaValue.TRUE: FALSE): super.gt(rhs);
}
public boolean gt_b(LuaValue rhs) { return rhs.isstring()? rhs.strcmp(this) < 0: super.gt_b(rhs); }
public boolean gt_b(int rhs) { typerror("attempt to compare string with number"); return false; }
public boolean gt_b(double rhs) { typerror("attempt to compare string with number"); return false; }
public LuaValue gteq( LuaValue rhs ) { return rhs.isstring() ? (rhs.strcmp(this)<=0? LuaValue.TRUE: FALSE) : super.gteq(rhs); }
public LuaValue gteq(LuaValue rhs) {
return rhs.isstring()? (rhs.strcmp(this) <= 0? LuaValue.TRUE: FALSE): super.gteq(rhs);
}
public boolean gteq_b(LuaValue rhs) { return rhs.isstring()? rhs.strcmp(this) <= 0: super.gteq_b(rhs); }
public boolean gteq_b(int rhs) { typerror("attempt to compare string with number"); return false; }
public boolean gteq_b(double rhs) { typerror("attempt to compare string with number"); return false; }
// concatenation
public LuaValue concat(LuaValue rhs) { return rhs.concatTo(this); }
public Buffer concat(Buffer rhs) { return rhs.concatTo(this); }
public LuaValue concatTo(LuaNumber lhs) { return concatTo(lhs.strvalue()); }
public LuaValue concatTo(LuaString lhs) {
byte[] b = new byte[lhs.m_length+this.m_length];
System.arraycopy(lhs.m_bytes, lhs.m_offset, b, 0, lhs.m_length);
@@ -319,6 +425,7 @@ public class LuaString extends LuaValue {
// string comparison
public int strcmp(LuaValue lhs) { return -lhs.strcmp(this); }
public int strcmp(LuaString rhs) {
for (int i = 0, j = 0; i < m_length && j < rhs.m_length; ++i, ++j) {
if (m_bytes[m_offset+i] != rhs.m_bytes[rhs.m_offset+j]) {
@@ -339,21 +446,26 @@ public class LuaString extends LuaValue {
public int checkint() {
return (int) (long) checkdouble();
}
public LuaInteger checkinteger() {
return valueOf(checkint());
}
public long checklong() {
return (long) checkdouble();
}
public double checkdouble() {
double d = scannumber();
if (Double.isNaN(d))
argerror("number");
return d;
}
public LuaNumber checknumber() {
return valueOf(checkdouble());
}
public LuaNumber checknumber(String msg) {
double d = scannumber();
if (Double.isNaN(d))
@@ -383,11 +495,17 @@ public class LuaString extends LuaValue {
}
public byte tobyte() { return (byte) toint(); }
public char tochar() { return (char) toint(); }
public double todouble() { double d = scannumber(); return Double.isNaN(d)? 0: d; }
public float tofloat() { return (float) todouble(); }
public int toint() { return (int) tolong(); }
public long tolong() { return (long) todouble(); }
public short toshort() { return (short) toint(); }
public double optdouble(double defval) {
@@ -426,29 +544,35 @@ public class LuaString extends LuaValue {
return this;
}
/** Take a substring using Java zero-based indexes for begin and end or range.
/**
* Take a substring using Java zero-based indexes for begin and end or
* range.
*
* @param beginIndex The zero-based index of the first character to include.
* @param endIndex The zero-based index of position after the last character.
* @param endIndex The zero-based index of position after the last
* character.
* @return LuaString which is a substring whose first character is at offset
* beginIndex and extending for (endIndex - beginIndex ) characters.
*/
public LuaString substring(int beginIndex, int endIndex) {
final int off = m_offset+beginIndex;
final int len = endIndex-beginIndex;
return len >= m_length / 2?
valueUsing(m_bytes, off, len):
valueOf(m_bytes, off, len);
return len >= m_length/2? valueUsing(m_bytes, off, len): valueOf(m_bytes, off, len);
}
public int hashCode() {
return m_hashcode;
}
/** Compute the hash code of a sequence of bytes within a byte array using
* lua's rules for string hashes. For long strings, not all bytes are hashed.
/**
* Compute the hash code of a sequence of bytes within a byte array using
* lua's rules for string hashes. For long strings, not all bytes are
* hashed.
*
* @param bytes byte array containing the bytes.
* @param offset offset into the hash for the first byte.
* @param length number of bytes starting with offset that are part of the string.
* @param length number of bytes starting with offset that are part of the
* string.
* @return hash for the string defined by bytes, offset, and length.
*/
public static int hashCode(byte[] bytes, int offset, int length) {
@@ -469,6 +593,7 @@ public class LuaString extends LuaValue {
// equality w/ metatable processing
public LuaValue eq(LuaValue val) { return val.raweq(this)? TRUE: FALSE; }
public boolean eq_b(LuaValue val) { return val.raweq(this); }
// equality w/o metatable processing
@@ -495,7 +620,10 @@ public class LuaString extends LuaValue {
return equals(a.m_bytes, a.m_offset+i, b.m_bytes, b.m_offset+j, n);
}
/** Return true if the bytes in the supplied range match this LuaStrings bytes. */
/**
* Return true if the bytes in the supplied range match this LuaStrings
* bytes.
*/
private boolean byteseq(byte[] bytes, int off, int len) {
return (m_length == len && equals(m_bytes, m_offset, bytes, off, len));
}
@@ -543,9 +671,11 @@ public class LuaString extends LuaValue {
return this;
}
/** Convert value to an input stream.
/**
* Convert value to an input stream.
*
* @return {@link InputStream} whose data matches the bytes in this {@link LuaString}
* @return {@link InputStream} whose data matches the bytes in this
* {@link LuaString}
*/
public InputStream toInputStream() {
return new ByteArrayInputStream(m_bytes, m_offset, m_length);
@@ -553,6 +683,7 @@ public class LuaString extends LuaValue {
/**
* Copy the bytes of the string into the given byte array.
*
* @param strOffset offset from which to copy
* @param bytes destination byte array
* @param arrayOffset offset in destination
@@ -562,9 +693,13 @@ public class LuaString extends LuaValue {
System.arraycopy(m_bytes, m_offset+strOffset, bytes, arrayOffset, len);
}
/** Java version of strpbrk - find index of any byte that in an accept string.
/**
* Java version of strpbrk - find index of any byte that in an accept
* string.
*
* @param accept {@link LuaString} containing characters to look for.
* @return index of first match in the {@code accept} string, or -1 if not found.
* @return index of first match in the {@code accept} string, or -1 if not
* found.
*/
public int indexOfAny(LuaString accept) {
final int ilimit = m_offset+m_length;
@@ -581,6 +716,7 @@ public class LuaString extends LuaValue {
/**
* Find the index of a byte starting at a point in this string
*
* @param b the byte to look for
* @param start the first index in the string
* @return index of first match found, or -1 if not found.
@@ -595,6 +731,7 @@ public class LuaString extends LuaValue {
/**
* Find the index of a string starting at a point in this string
*
* @param s the string to search for
* @param start the first index in the string
* @return index of first match found, or -1 if not found.
@@ -611,6 +748,7 @@ public class LuaString extends LuaValue {
/**
* Find the last index of a string in this string
*
* @param s the string to search for
* @return index of last match found, or -1 if not found.
*/
@@ -624,14 +762,14 @@ public class LuaString extends LuaValue {
return -1;
}
/**
* Convert to Java String interpreting as utf8 characters.
*
* @param bytes byte array in UTF8 encoding to convert
* @param offset starting index in byte array
* @param length number of bytes to convert
* @return Java String corresponding to the value of bytes interpreted using UTF8
* @return Java String corresponding to the value of bytes interpreted using
* UTF8
* @see #lengthAsUtf8(char[])
* @see #encodeToUtf8(char[], int, byte[], int)
* @see #isValidUtf8()
@@ -640,22 +778,24 @@ public class LuaString extends LuaValue {
int i, j, n, b;
for (i = offset, j = offset+length, n = 0; i < j; ++n) {
switch (0xE0 & bytes[i++]) {
case 0xE0: ++i;
case 0xC0: ++i;
case 0xE0:
++i;
case 0xC0:
++i;
}
}
char[] chars = new char[n];
for (i = offset, j = offset+length, n = 0; i < j;) {
chars[n++] = (char) (
((b=bytes[i++])>=0||i>=j)? b:
(b<-32||i+1>=j)? (((b&0x3f) << 6) | (bytes[i++]&0x3f)):
(((b&0xf) << 12) | ((bytes[i++]&0x3f)<<6) | (bytes[i++]&0x3f)));
chars[n++] = (char) (((b = bytes[i++]) >= 0 || i >= j)? b
: (b < -32 || i+1 >= j)? (((b & 0x3f)<<6) | (bytes[i++] & 0x3f))
: (((b & 0xf)<<12) | ((bytes[i++] & 0x3f)<<6) | (bytes[i++] & 0x3f)));
}
return new String(chars);
}
/**
* Count the number of bytes required to encode the string as UTF-8.
*
* @param chars Array of unicode characters to be encoded as UTF-8
* @return count of bytes needed to encode using UTF-8
* @see #encodeToUtf8(char[], int, byte[], int)
@@ -675,8 +815,9 @@ public class LuaString extends LuaValue {
* Encode the given Java string as UTF-8 bytes, writing the result to bytes
* starting at offset.
* <p>
* The string should be measured first with lengthAsUtf8
* to make sure the given byte array is large enough.
* The string should be measured first with lengthAsUtf8 to make sure the
* given byte array is large enough.
*
* @param chars Array of unicode characters to be encoded as UTF-8
* @param nchars Number of characters in the array to convert.
* @param bytes byte array to hold the result
@@ -704,7 +845,9 @@ public class LuaString extends LuaValue {
return j-off;
}
/** Check that a byte sequence is valid UTF-8
/**
* Check that a byte sequence is valid UTF-8
*
* @return true if it is valid UTF-8, otherwise false
* @see #lengthAsUtf8(char[])
* @see #encodeToUtf8(char[], int, byte[], int)
@@ -713,14 +856,12 @@ public class LuaString extends LuaValue {
public boolean isValidUtf8() {
for (int i = m_offset, j = m_offset+m_length; i < j;) {
int c = m_bytes[i++];
if ( c >= 0 ) continue;
if ( ((c & 0xE0) == 0xC0)
&& i<j
&& (m_bytes[i++] & 0xC0) == 0x80) continue;
if ( ((c & 0xF0) == 0xE0)
&& i+1<j
&& (m_bytes[i++] & 0xC0) == 0x80
&& (m_bytes[i++] & 0xC0) == 0x80) continue;
if (c >= 0)
continue;
if (((c & 0xE0) == 0xC0) && i < j && (m_bytes[i++] & 0xC0) == 0x80)
continue;
if (((c & 0xF0) == 0xE0) && i+1 < j && (m_bytes[i++] & 0xC0) == 0x80 && (m_bytes[i++] & 0xC0) == 0x80)
continue;
return false;
}
return true;
@@ -729,9 +870,11 @@ public class LuaString extends LuaValue {
// --------------------- number conversion -----------------------
/**
* convert to a number using baee 10 or base 16 if it starts with '0x',
* or NIL if it can't be converted
* @return IntValue, DoubleValue, or NIL depending on the content of the string.
* convert to a number using baee 10 or base 16 if it starts with '0x', or
* NIL if it can't be converted
*
* @return IntValue, DoubleValue, or NIL depending on the content of the
* string.
* @see LuaValue#tonumber()
*/
public LuaValue tonumber() {
@@ -740,9 +883,12 @@ public class LuaString extends LuaValue {
}
/**
* convert to a number using a supplied base, or NIL if it can't be converted
* convert to a number using a supplied base, or NIL if it can't be
* converted
*
* @param base the base to use, such as 10
* @return IntValue, DoubleValue, or NIL depending on the content of the string.
* @return IntValue, DoubleValue, or NIL depending on the content of the
* string.
* @see LuaValue#tonumber()
*/
public LuaValue tonumber(int base) {
@@ -751,14 +897,17 @@ public class LuaString extends LuaValue {
}
/**
* Convert to a number in base 10, or base 16 if the string starts with '0x',
* or return Double.NaN if it cannot be converted to a number.
* Convert to a number in base 10, or base 16 if the string starts with
* '0x', or return Double.NaN if it cannot be converted to a number.
*
* @return double value if conversion is valid, or Double.NaN if not
*/
public double scannumber() {
int i = m_offset, j = m_offset+m_length;
while ( i<j && m_bytes[i]==' ' ) ++i;
while ( i<j && m_bytes[j-1]==' ' ) --j;
while ( i < j && m_bytes[i] == ' ' )
++i;
while ( i < j && m_bytes[j-1] == ' ' )
--j;
if (i >= j)
return Double.NaN;
if (m_bytes[i] == '0' && i+1 < j && (m_bytes[i+1] == 'x' || m_bytes[i+1] == 'X'))
@@ -769,6 +918,7 @@ public class LuaString extends LuaValue {
/**
* Convert to a number in a base, or return Double.NaN if not a number.
*
* @param base the base to use between 2 and 36
* @return double value if conversion is valid, or Double.NaN if not
*/
@@ -776,8 +926,10 @@ public class LuaString extends LuaValue {
if (base < 2 || base > 36)
return Double.NaN;
int i = m_offset, j = m_offset+m_length;
while ( i<j && m_bytes[i]==' ' ) ++i;
while ( i<j && m_bytes[j-1]==' ' ) --j;
while ( i < j && m_bytes[i] == ' ' )
++i;
while ( i < j && m_bytes[j-1] == ' ' )
--j;
if (i >= j)
return Double.NaN;
return scanlong(base, i, j);
@@ -785,18 +937,18 @@ public class LuaString extends LuaValue {
/**
* Scan and convert a long value, or return Double.NaN if not found.
*
* @param base the base to use, such as 10
* @param start the index to start searching from
* @param end the first index beyond the search range
* @return double value if conversion is valid,
* or Double.NaN if not
* @return double value if conversion is valid, or Double.NaN if not
*/
private double scanlong(int base, int start, int end) {
long x = 0;
boolean neg = (m_bytes[start] == '-');
for (int i = (neg? start+1: start); i < end; i++) {
int digit = m_bytes[i] - (base<=10||(m_bytes[i]>='0'&&m_bytes[i]<='9')? '0':
m_bytes[i]>='A'&&m_bytes[i]<='Z'? ('A'-10): ('a'-10));
int digit = m_bytes[i]-(base <= 10 || (m_bytes[i] >= '0' && m_bytes[i] <= '9')? '0'
: m_bytes[i] >= 'A' && m_bytes[i] <= 'Z'? ('A'-10): ('a'-10));
if (digit < 0 || digit >= base)
return Double.NaN;
x = x*base+digit;
@@ -808,21 +960,31 @@ public class LuaString extends LuaValue {
/**
* Scan and convert a double value, or return Double.NaN if not a double.
*
* @param start the index to start searching from
* @param end the first index beyond the search range
* @return double value if conversion is valid,
* or Double.NaN if not
* @return double value if conversion is valid, or Double.NaN if not
*/
private double scandouble(int start, int end) {
if ( end>start+64 ) end=start+64;
if (end > start+64)
end = start+64;
for (int i = start; i < end; i++) {
switch (m_bytes[i]) {
case '-':
case '+':
case '.':
case 'e': case 'E':
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
case 'e':
case 'E':
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
break;
default:
return Double.NaN;
@@ -839,8 +1001,9 @@ public class LuaString extends LuaValue {
}
/**
* Print the bytes of the LuaString to a PrintStream as if it were
* an ASCII string, quoting and escaping control characters.
* Print the bytes of the LuaString to a PrintStream as if it were an ASCII
* string, quoting and escaping control characters.
*
* @param ps PrintStream to print to.
*/
public void printToStream(PrintStream ps) {

View File

@@ -27,25 +27,27 @@ import java.util.Vector;
/**
* Subclass of {@link LuaValue} for representing lua tables.
* <p>
* Almost all API's implemented in {@link LuaTable} are defined and documented in {@link LuaValue}.
* Almost all API's implemented in {@link LuaTable} are defined and documented
* in {@link LuaValue}.
* <p>
* If a table is needed, the one of the type-checking functions can be used such as
* {@link #istable()},
* {@link #checktable()}, or
* {@link #opttable(LuaTable)}
* If a table is needed, the one of the type-checking functions can be used such
* as {@link #istable()}, {@link #checktable()}, or {@link #opttable(LuaTable)}
* <p>
* The main table operations are defined on {@link LuaValue}
* for getting and setting values with and without metatag processing:
* The main table operations are defined on {@link LuaValue} for getting and
* setting values with and without metatag processing:
* <ul>
* <li>{@link #get(LuaValue)}</li>
* <li>{@link #set(LuaValue,LuaValue)}</li>
* <li>{@link #rawget(LuaValue)}</li>
* <li>{@link #rawset(LuaValue,LuaValue)}</li>
* <li>plus overloads such as {@link #get(String)}, {@link #get(int)}, and so on</li>
* <li>plus overloads such as {@link #get(String)}, {@link #get(int)}, and so
* on</li>
* </ul>
* <p>
* To iterate over key-value pairs from Java, use
* <pre> {@code
*
* <pre>
* {@code
* LuaValue k = LuaValue.NIL;
* while ( true ) {
* Varargs n = table.next(k);
@@ -53,11 +55,12 @@ import java.util.Vector;
* break;
* LuaValue v = n.arg(2)
* process( k, v )
* }}</pre>
* }}
* </pre>
*
* <p>
* As with other types, {@link LuaTable} instances should be constructed via one of the table constructor
* methods on {@link LuaValue}:
* As with other types, {@link LuaTable} instances should be constructed via one
* of the table constructor methods on {@link LuaValue}:
* <ul>
* <li>{@link LuaValue#tableOf()} empty table</li>
* <li>{@link LuaValue#tableOf(int, int)} table with capacity</li>
@@ -65,9 +68,12 @@ import java.util.Vector;
* <li>{@link LuaValue#listOf(LuaValue[], Varargs)} initialize array part</li>
* <li>{@link LuaValue#tableOf(LuaValue[])} initialize named hash part</li>
* <li>{@link LuaValue#tableOf(Varargs, int)} initialize named hash part</li>
* <li>{@link LuaValue#tableOf(LuaValue[], LuaValue[])} initialize array and named parts</li>
* <li>{@link LuaValue#tableOf(LuaValue[], LuaValue[], Varargs)} initialize array and named parts</li>
* <li>{@link LuaValue#tableOf(LuaValue[], LuaValue[])} initialize array and
* named parts</li>
* <li>{@link LuaValue#tableOf(LuaValue[], LuaValue[], Varargs)} initialize
* array and named parts</li>
* </ul>
*
* @see LuaValue
*/
public class LuaTable extends LuaValue implements Metatable {
@@ -94,6 +100,7 @@ public class LuaTable extends LuaValue implements Metatable {
/**
* Construct table with preset capacity.
*
* @param narray capacity of array part
* @param nhash capacity of hash part
*/
@@ -103,7 +110,9 @@ public class LuaTable extends LuaValue implements Metatable {
/**
* Construct table with named and unnamed parts.
* @param named Named elements in order {@code key-a, value-a, key-b, value-b, ... }
*
* @param named Named elements in order
* {@code key-a, value-a, key-b, value-b, ... }
* @param unnamed Unnamed elements in order {@code value-1, value-2, ... }
* @param lastarg Additional unnamed values beyond {@code unnamed.length}
*/
@@ -124,6 +133,7 @@ public class LuaTable extends LuaValue implements Metatable {
/**
* Construct table of unnamed elements.
*
* @param varargs Unnamed elements in order {@code value-1, value-2, ... }
*/
public LuaTable(Varargs varargs) {
@@ -132,8 +142,10 @@ public class LuaTable extends LuaValue implements Metatable {
/**
* Construct table of unnamed elements.
*
* @param varargs Unnamed elements in order {@code value-1, value-2, ... }
* @param firstarg the index in varargs of the first argument to include in the table
* @param firstarg the index in varargs of the first argument to include in
* the table
*/
public LuaTable(Varargs varargs, int firstarg) {
int nskip = firstarg-1;
@@ -187,19 +199,19 @@ public class LuaTable extends LuaValue implements Metatable {
/**
* Get the length of the array part of the table.
* @return length of the array part, does not relate to count of objects in the table.
*
* @return length of the array part, does not relate to count of objects in
* the table.
*/
protected int getArrayLength() {
return array.length;
}
protected int getArrayLength() { return array.length; }
/**
* Get the length of the hash part of the table.
* @return length of the hash part, does not relate to count of objects in the table.
*
* @return length of the hash part, does not relate to count of objects in
* the table.
*/
protected int getHashLength() {
return hash.length;
}
protected int getHashLength() { return hash.length; }
public LuaValue getmetatable() {
return (m_metatable != null)? m_metatable.toLuaValue(): null;
@@ -209,8 +221,8 @@ public class LuaTable extends LuaValue implements Metatable {
boolean hadWeakKeys = m_metatable != null && m_metatable.useWeakKeys();
boolean hadWeakValues = m_metatable != null && m_metatable.useWeakValues();
m_metatable = metatableOf(metatable);
if ( ( hadWeakKeys != ( m_metatable != null && m_metatable.useWeakKeys() )) ||
( hadWeakValues != ( m_metatable != null && m_metatable.useWeakValues() ))) {
if ((hadWeakKeys != (m_metatable != null && m_metatable.useWeakKeys()))
|| (hadWeakValues != (m_metatable != null && m_metatable.useWeakValues()))) {
// force a rehash
rehash(0);
}
@@ -239,8 +251,7 @@ public class LuaTable extends LuaValue implements Metatable {
if (key.isinttype()) {
int ikey = key.toint();
if (ikey > 0 && ikey <= array.length) {
LuaValue v = m_metatable == null
? array[ikey-1] : m_metatable.arrayget(array, ikey-1);
LuaValue v = m_metatable == null? array[ikey-1]: m_metatable.arrayget(array, ikey-1);
return v != null? v: NIL;
}
}
@@ -286,14 +297,14 @@ public class LuaTable extends LuaValue implements Metatable {
/** Set an array element */
private boolean arrayset(int key, LuaValue value) {
if (key > 0 && key <= array.length) {
array[key - 1] = value.isnil() ? null :
(m_metatable != null ? m_metatable.wrap(value) : value);
array[key-1] = value.isnil()? null: (m_metatable != null? m_metatable.wrap(value): value);
return true;
}
return false;
}
/** Remove the element at a position in a list-table
/**
* Remove the element at a position in a list-table
*
* @param pos the position to remove
* @return The removed item, or {@link #NONE} if not removed
@@ -312,7 +323,8 @@ public class LuaTable extends LuaValue implements Metatable {
return v.isnil()? NONE: v;
}
/** Insert an element at a position in a list-table
/**
* Insert an element at a position in a list-table
*
* @param pos the position to remove
* @param value The value to insert
@@ -327,7 +339,8 @@ public class LuaTable extends LuaValue implements Metatable {
}
}
/** Concatenate the contents of a table efficiently, using {@link Buffer}
/**
* Concatenate the contents of a table efficiently, using {@link Buffer}
*
* @param sep {@link LuaString} separater to apply between elements
* @param i the first element index
@@ -349,7 +362,8 @@ public class LuaTable extends LuaValue implements Metatable {
public int length() {
if (m_metatable != null) {
LuaValue len = len();
if (!len.isint()) throw new LuaError("table length is not an integer: " + len);
if (!len.isint())
throw new LuaError("table length is not an integer: " + len);
return len.toint();
}
return rawlen();
@@ -381,6 +395,7 @@ public class LuaTable extends LuaValue implements Metatable {
/**
* Get the next element after a particular key in the table
*
* @return key,value or nil
*/
public Varargs next(LuaValue key) {
@@ -441,8 +456,9 @@ public class LuaTable extends LuaValue implements Metatable {
}
/**
* Get the next element after a particular key in the
* contiguous array part of a table
* Get the next element after a particular key in the contiguous array part
* of a table
*
* @return key,value or none
*/
public Varargs inext(LuaValue key) {
@@ -453,6 +469,7 @@ public class LuaTable extends LuaValue implements Metatable {
/**
* Set a hashtable value
*
* @param key key to set
* @param value value to set
*/
@@ -472,8 +489,7 @@ public class LuaTable extends LuaValue implements Metatable {
}
}
if (checkLoadFactor()) {
if ( (m_metatable == null || !m_metatable.useWeakValues())
&& key.isinttype() && key.toint() > 0 ) {
if ((m_metatable == null || !m_metatable.useWeakValues()) && key.isinttype() && key.toint() > 0) {
// a rehash might make room in the array portion for this key.
rehash(key.toint());
if (arrayset(key.toint(), value))
@@ -483,9 +499,7 @@ public class LuaTable extends LuaValue implements Metatable {
}
index = hashSlot(key);
}
Slot entry = ( m_metatable != null )
? m_metatable.entry( key, value )
: defaultEntry( key, value );
Slot entry = (m_metatable != null)? m_metatable.entry(key, value): defaultEntry(key, value);
hash[index] = (hash[index] != null)? hash[index].add(entry): entry;
++hashEntries;
}
@@ -501,8 +515,10 @@ public class LuaTable extends LuaValue implements Metatable {
/**
* Find the hashtable slot index to use.
*
* @param key the key to look for
* @param hashMask N-1 where N is the number of hash slots (must be power of 2)
* @param hashMask N-1 where N is the number of hash slots (must be power of
* 2)
* @return the slot index
*/
public static int hashSlot(LuaValue key, int hashMask) {
@@ -520,6 +536,7 @@ public class LuaTable extends LuaValue implements Metatable {
/**
* Find the hashtable slot to use
*
* @param key key to look for
* @return slot to use
*/
@@ -614,22 +631,53 @@ public class LuaTable extends LuaValue implements Metatable {
x >>>= 4;
}
switch (x) {
case 0x0: return 0;
case 0x1: lg += 1; break;
case 0x2: lg += 2; break;
case 0x3: lg += 2; break;
case 0x4: lg += 3; break;
case 0x5: lg += 3; break;
case 0x6: lg += 3; break;
case 0x7: lg += 3; break;
case 0x8: lg += 4; break;
case 0x9: lg += 4; break;
case 0xA: lg += 4; break;
case 0xB: lg += 4; break;
case 0xC: lg += 4; break;
case 0xD: lg += 4; break;
case 0xE: lg += 4; break;
case 0xF: lg += 4; break;
case 0x0:
return 0;
case 0x1:
lg += 1;
break;
case 0x2:
lg += 2;
break;
case 0x3:
lg += 2;
break;
case 0x4:
lg += 3;
break;
case 0x5:
lg += 3;
break;
case 0x6:
lg += 3;
break;
case 0x7:
lg += 3;
break;
case 0x8:
lg += 4;
break;
case 0x9:
lg += 4;
break;
case 0xA:
lg += 4;
break;
case 0xB:
lg += 4;
break;
case 0xC:
lg += 4;
break;
case 0xD:
lg += 4;
break;
case 0xE:
lg += 4;
break;
case 0xF:
lg += 4;
break;
}
return lg;
}
@@ -693,17 +741,14 @@ public class LuaTable extends LuaValue implements Metatable {
newArray = array;
}
final int newHashSize = hashEntries - movingToArray
+ ((newKey < 0 || newKey > newArraySize) ? 1 : 0); // Make room for the new entry
final int newHashSize = hashEntries-movingToArray+((newKey < 0 || newKey > newArraySize)? 1: 0); // Make room for the new entry
final int oldCapacity = oldHash.length;
final int newCapacity;
final int newHashMask;
if (newHashSize > 0) {
// round up to next power of 2.
newCapacity = ( newHashSize < MIN_HASH_CAPACITY )
? MIN_HASH_CAPACITY
: 1 << log2(newHashSize);
newCapacity = (newHashSize < MIN_HASH_CAPACITY)? MIN_HASH_CAPACITY: 1<<log2(newHashSize);
newHashMask = newCapacity-1;
newHash = new Slot[newCapacity];
} else {
@@ -740,8 +785,7 @@ public class LuaTable extends LuaValue implements Metatable {
} else {
newEntry = defaultEntry(valueOf(i), v);
}
newHash[ slot ] = ( newHash[slot] != null )
? newHash[slot].add( newEntry ) : newEntry;
newHash[slot] = (newHash[slot] != null)? newHash[slot].add(newEntry): newEntry;
}
}
@@ -782,11 +826,14 @@ public class LuaTable extends LuaValue implements Metatable {
//
// Only sorts the contiguous array part.
//
/** Sort the table using a comparator.
/**
* Sort the table using a comparator.
*
* @param comparator {@link LuaValue} to be called to compare elements.
*/
public void sort(LuaValue comparator) {
if (len().tolong() >= (long)Integer.MAX_VALUE) throw new LuaError("array too big: " + len().tolong());
if (len().tolong() >= (long) Integer.MAX_VALUE)
throw new LuaError("array too big: " + len().tolong());
if (m_metatable != null && m_metatable.useWeakValues()) {
dropWeakArrayValues();
}
@@ -836,10 +883,12 @@ public class LuaTable extends LuaValue implements Metatable {
}
}
/** This may be deprecated in a future release.
* It is recommended to count via iteration over next() instead
/**
* This may be deprecated in a future release. It is recommended to count
* via iteration over next() instead
*
* @return count of keys in the table
* */
*/
public int keyCount() {
LuaValue k = LuaValue.NIL;
for (int i = 0; true; i++) {
@@ -849,10 +898,12 @@ public class LuaTable extends LuaValue implements Metatable {
}
}
/** This may be deprecated in a future release.
* It is recommended to use next() instead
/**
* This may be deprecated in a future release. It is recommended to use
* next() instead
*
* @return array of keys in the table
* */
*/
public LuaValue[] keys() {
Vector l = new Vector();
LuaValue k = LuaValue.NIL;
@@ -869,9 +920,12 @@ public class LuaTable extends LuaValue implements Metatable {
// equality w/ metatable processing
public LuaValue eq(LuaValue val) { return eq_b(val)? TRUE: FALSE; }
public boolean eq_b(LuaValue val) {
if ( this == val ) return true;
if ( m_metatable == null || !val.istable() ) return false;
if (this == val)
return true;
if (m_metatable == null || !val.istable())
return false;
LuaValue valmt = val.getmetatable();
return valmt != null && LuaValue.eqmtcall(this, m_metatable.toLuaValue(), val, valmt);
}
@@ -888,16 +942,22 @@ public class LuaTable extends LuaValue implements Metatable {
/** Unpack the elements from i to j inclusive */
public Varargs unpack(int i, int j) {
if (j < i) return NONE;
if (j < i)
return NONE;
int count = j-i;
if (count < 0) throw new LuaError("too many results to unpack: greater " + Integer.MAX_VALUE); // integer overflow
if (count < 0)
throw new LuaError("too many results to unpack: greater " + Integer.MAX_VALUE); // integer overflow
int max = 0x00ffffff;
if (count >= max) throw new LuaError("too many results to unpack: " + count + " (max is " + max + ')');
if (count >= max)
throw new LuaError("too many results to unpack: " + count + " (max is " + max + ')');
int n = j+1-i;
switch (n) {
case 0: return NONE;
case 1: return get(i);
case 2: return varargsOf(get(i), get(i+1));
case 0:
return NONE;
case 1:
return get(i);
case 2:
return varargsOf(get(i), get(i+1));
default:
if (n < 0)
return NONE;
@@ -1076,9 +1136,13 @@ public class LuaTable extends LuaValue implements Metatable {
*/
static abstract class Entry extends Varargs implements StrongSlot {
public abstract LuaValue key();
public abstract LuaValue value();
abstract Entry set(LuaValue value);
public abstract boolean keyeq(LuaValue key);
public abstract int keyindex(int hashMask);
public int arraykey(int max) {
@@ -1087,8 +1151,10 @@ public class LuaTable extends LuaValue implements Metatable {
public LuaValue arg(int i) {
switch (i) {
case 1: return key();
case 2: return value();
case 1:
return key();
case 2:
return value();
}
return NIL;
}
@@ -1110,8 +1176,10 @@ public class LuaTable extends LuaValue implements Metatable {
public Varargs subargs(int start) {
switch (start) {
case 1: return this;
case 2: return value();
case 1:
return this;
case 2:
return value();
}
return NONE;
}
@@ -1216,7 +1284,8 @@ public class LuaTable extends LuaValue implements Metatable {
}
/**
* Entry class used with numeric values, but only when the key is not an integer.
* Entry class used with numeric values, but only when the key is not an
* integer.
*/
private static class NumberValueEntry extends Entry {
private double value;
@@ -1256,8 +1325,8 @@ public class LuaTable extends LuaValue implements Metatable {
}
/**
* A Slot whose value has been set to nil. The key is kept in a weak reference so that
* it can be found by next().
* A Slot whose value has been set to nil. The key is kept in a weak
* reference so that it can be found by next().
*/
private static class DeadSlot implements Slot {

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);
}
@@ -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 {

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());
@@ -106,21 +110,26 @@ public class LuaUserdata extends LuaValue {
// 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;
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);
}
// equality w/o metatable processing
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;
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

@@ -44,8 +44,8 @@ interface Metatable {
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,50 +37,10 @@ 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) {
@@ -133,8 +94,11 @@ public class Print extends Lua {
return;
}
switch (v.type()) {
case LuaValue.TSTRING: printString( ps, (LuaString) v ); break;
default: ps.print( v.tojstring() );
case LuaValue.TSTRING:
printString(ps, (LuaString) v);
break;
default:
ps.print(v.tojstring());
}
}
@@ -150,6 +114,7 @@ public class Print extends Lua {
/**
* Print the code in a prototype
*
* @param f the {@link Prototype}
*/
public static void printCode(Prototype f) {
@@ -163,6 +128,7 @@ 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
@@ -173,6 +139,7 @@ public class Print extends Lua {
/**
* 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
@@ -334,13 +301,10 @@ public class Print extends Lua {
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");
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) {
@@ -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.
@@ -409,6 +376,7 @@ public class Print extends Lua {
private static String id(Prototype f) {
return "Proto";
}
private void _assert(boolean b) {
if (!b)
throw new NullPointerException("_assert failed");
@@ -416,6 +384,7 @@ public class Print extends Lua {
/**
* 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}
@@ -443,12 +412,12 @@ public class Print extends Lua {
LuaValue v = stack[i];
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());

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>
* }
* </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
@@ -117,7 +149,8 @@ public class Prototype {
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

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;

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,6 +35,7 @@ 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
*/
@@ -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

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.
@@ -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
*/
@@ -301,8 +302,10 @@ public class WeakTable implements Metatable {
/**
* 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()) {
@@ -319,6 +322,7 @@ 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)
@@ -333,7 +337,9 @@ public class WeakTable implements Metatable {
return (LuaValue) ref;
}
/** Internal class to implement weak values.
/**
* Internal class to implement weak values.
*
* @see WeakTable
*/
static class WeakValue extends LuaValue {
@@ -368,7 +374,9 @@ public class WeakTable implements Metatable {
}
}
/** Internal class to implement weak userdata values.
/**
* Internal class to implement weak userdata values.
*
* @see WeakTable
*/
static final class WeakUserdata extends WeakValue {

View File

@@ -44,21 +44,15 @@ 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");
@@ -93,21 +87,15 @@ public class Constants extends Lua {
}
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

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 */
@@ -272,13 +290,17 @@ 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 {
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:

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,7 +64,6 @@ public class FuncState extends Constants {
FuncState() {
}
// =============================================================
// from lcode.h
// =============================================================
@@ -86,7 +84,6 @@ public class FuncState extends Constants {
setreturns(e, LUA_MULTRET);
}
// =============================================================
// from lparser.c
// =============================================================
@@ -96,14 +93,12 @@ public class FuncState extends Constants {
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);
@@ -111,9 +106,8 @@ public class FuncState extends Constants {
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);
}
@@ -129,7 +123,6 @@ public class FuncState extends Constants {
getlocvar(--nactvar).endpc = pc;
}
int searchupvalue(LuaString name) {
int i;
Upvaldesc[] up = f.upvalues;
@@ -256,21 +249,22 @@ public class FuncState extends Constants {
}
void lastlistfield(ConsControl cc) {
if (cc.tostore == 0) return;
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
// =============================================================
@@ -282,8 +276,7 @@ public class FuncState extends Constants {
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? */
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)
@@ -298,7 +291,6 @@ public class FuncState extends Constants {
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;
@@ -325,7 +317,6 @@ public class FuncState extends Constants {
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 */
@@ -347,7 +337,6 @@ public class FuncState extends Constants {
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])))
@@ -356,7 +345,6 @@ public class FuncState extends Constants {
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,7 +372,6 @@ 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);
@@ -420,8 +406,8 @@ public class FuncState extends Constants {
level++; /* argument is +1 to reserve 0 as non-op */
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;
}
@@ -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();
@@ -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: {
@@ -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);
@@ -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
@@ -742,9 +726,8 @@ 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);
@@ -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);
@@ -1004,7 +986,6 @@ public class FuncState extends Constants {
}
}
void posfix(int op, expdesc e1, expdesc e2, int line) {
switch (op) {
case LexState.OPR_AND: {
@@ -1025,8 +1006,7 @@ public class FuncState extends Constants {
}
case LexState.OPR_CONCAT: {
this.exp2val(e2);
if (e2.k == LexState.VRELOCABLE
&& GET_OPCODE(this.getcode(e2)) == OP_CONCAT) {
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);
@@ -1079,12 +1059,10 @@ public class FuncState extends Constants {
}
}
void fixline(int line) {
this.f.lineinfo[this.pc-1] = line;
}
int code(int instruction, int line) {
Prototype f = this.f;
this.dischargejpc(); /* `pc' will change */
@@ -1094,13 +1072,11 @@ public class FuncState extends Constants {
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);
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);
@@ -1108,7 +1084,6 @@ public class FuncState extends Constants {
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);

View File

@@ -24,13 +24,16 @@ package org.luaj.vm2.compiler;
class InstructionPtr {
final int[] code;
final 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;
}

View File

@@ -35,7 +35,6 @@ import org.luaj.vm2.Prototype;
import org.luaj.vm2.compiler.FuncState.BlockCnt;
import org.luaj.vm2.lib.MathLib;
public class LexState extends Constants {
protected static final String RESERVED_LOCAL_VAR_FOR_CONTROL = "(for control)";
@@ -46,14 +45,9 @@ public class LexState extends Constants {
protected static final String RESERVED_LOCAL_VAR_FOR_INDEX = "(for index)";
// keywords array
protected static final String[] RESERVED_LOCAL_VAR_KEYWORDS = new String[] {
RESERVED_LOCAL_VAR_FOR_CONTROL,
RESERVED_LOCAL_VAR_FOR_GENERATOR,
RESERVED_LOCAL_VAR_FOR_INDEX,
RESERVED_LOCAL_VAR_FOR_LIMIT,
RESERVED_LOCAL_VAR_FOR_STATE,
RESERVED_LOCAL_VAR_FOR_STEP
};
protected static final String[] RESERVED_LOCAL_VAR_KEYWORDS = new String[] { RESERVED_LOCAL_VAR_FOR_CONTROL,
RESERVED_LOCAL_VAR_FOR_GENERATOR, RESERVED_LOCAL_VAR_FOR_INDEX, RESERVED_LOCAL_VAR_FOR_LIMIT,
RESERVED_LOCAL_VAR_FOR_STATE, RESERVED_LOCAL_VAR_FOR_STEP };
private static final Hashtable RESERVED_LOCAL_VAR_KEYWORDS_TABLE = new Hashtable();
static {
for (int i = 0; i < RESERVED_LOCAL_VAR_KEYWORDS.length; i++)
@@ -66,6 +60,7 @@ public class LexState extends Constants {
private static final int LUAI_MAXCCALLS = 200;
private static final String LUA_QS(String s) { return "'" + s + "'"; }
private static final String LUA_QL(Object o) { return LUA_QS(String.valueOf(o)); }
private static final int LUA_COMPAT_LSTR = 1; // 1 for compatibility, 2 for old behavior
@@ -84,24 +79,15 @@ public class LexState extends Constants {
/*
** grep "ORDER OPR" if you change these enums
*/
static final int
OPR_ADD=0, OPR_SUB=1, OPR_MUL=2, OPR_DIV=3, OPR_MOD=4, OPR_POW=5,
OPR_CONCAT=6,
OPR_NE=7, OPR_EQ=8,
OPR_LT=9, OPR_LE=10, OPR_GT=11, OPR_GE=12,
OPR_AND=13, OPR_OR=14,
static final int OPR_ADD = 0, OPR_SUB = 1, OPR_MUL = 2, OPR_DIV = 3, OPR_MOD = 4, OPR_POW = 5, OPR_CONCAT = 6,
OPR_NE = 7, OPR_EQ = 8, OPR_LT = 9, OPR_LE = 10, OPR_GT = 11, OPR_GE = 12, OPR_AND = 13, OPR_OR = 14,
OPR_NOBINOPR = 15;
static final int
OPR_MINUS=0, OPR_NOT=1, OPR_LEN=2, OPR_NOUNOPR=3;
static final int OPR_MINUS = 0, OPR_NOT = 1, OPR_LEN = 2, OPR_NOUNOPR = 3;
/* exp kind */
static final int
VVOID = 0, /* no value */
VNIL = 1,
VTRUE = 2,
VFALSE = 3,
VK = 4, /* info = index of constant in `k' */
static final int VVOID = 0, /* no value */
VNIL = 1, VTRUE = 2, VFALSE = 3, VK = 4, /* info = index of constant in `k' */
VKNUM = 5, /* nval = numerical value */
VNONRELOC = 6, /* info = result register */
VLOCAL = 7, /* info = local register */
@@ -121,6 +107,7 @@ public class LexState extends Constants {
private static class Token {
int token;
final SemInfo seminfo = new SemInfo();
public void set(Token other) {
this.token = other.token;
this.seminfo.r = other.seminfo.r;
@@ -144,24 +131,19 @@ public class LexState extends Constants {
byte decpoint; /* locale decimal point */
/* ORDER RESERVED */
final static String luaX_tokens [] = {
"and", "break", "do", "else", "elseif",
"end", "false", "for", "function", "goto", "if",
"in", "local", "nil", "not", "or", "repeat",
"return", "then", "true", "until", "while",
"..", "...", "==", ">=", "<=", "~=",
"::", "<eos>", "<number>", "<name>", "<string>", "<eof>",
};
final static String luaX_tokens[] = { "and", "break", "do", "else", "elseif", "end", "false", "for", "function",
"goto", "if", "in", "local", "nil", "not", "or", "repeat", "return", "then", "true", "until", "while", "..",
"...", "==", ">=", "<=", "~=", "::", "<eos>", "<number>", "<name>", "<string>", "<eof>", };
final static int
/* terminal symbols denoted by reserved words */
TK_AND=257, TK_BREAK=258, TK_DO=259, TK_ELSE=260, TK_ELSEIF=261,
TK_END=262, TK_FALSE=263, TK_FOR=264, TK_FUNCTION=265, TK_GOTO=266, TK_IF=267,
TK_IN=268, TK_LOCAL=269, TK_NIL=270, TK_NOT=271, TK_OR=272, TK_REPEAT=273,
TK_RETURN=274, TK_THEN=275, TK_TRUE=276, TK_UNTIL=277, TK_WHILE=278,
TK_AND = 257, TK_BREAK = 258, TK_DO = 259, TK_ELSE = 260, TK_ELSEIF = 261, TK_END = 262, TK_FALSE = 263,
TK_FOR = 264, TK_FUNCTION = 265, TK_GOTO = 266, TK_IF = 267, TK_IN = 268, TK_LOCAL = 269, TK_NIL = 270,
TK_NOT = 271, TK_OR = 272, TK_REPEAT = 273, TK_RETURN = 274, TK_THEN = 275, TK_TRUE = 276, TK_UNTIL = 277,
TK_WHILE = 278,
/* other terminal symbols */
TK_CONCAT=279, TK_DOTS=280, TK_EQ=281, TK_GE=282, TK_LE=283, TK_NE=284,
TK_DBCOLON=285, TK_EOS=286, TK_NUMBER=287, TK_NAME=288, TK_STRING=289;
TK_CONCAT = 279, TK_DOTS = 280, TK_EQ = 281, TK_GE = 282, TK_LE = 283, TK_NE = 284, TK_DBCOLON = 285,
TK_EOS = 286, TK_NUMBER = 287, TK_NAME = 288, TK_STRING = 289;
final static int FIRST_RESERVED = TK_AND;
final static int NUM_RESERVED = TK_WHILE+1-FIRST_RESERVED;
@@ -175,16 +157,12 @@ public class LexState extends Constants {
}
private boolean isalnum(int c) {
return (c >= '0' && c <= '9')
|| (c >= 'a' && c <= 'z')
|| (c >= 'A' && c <= 'Z')
|| (c == '_');
return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c == '_');
// return Character.isLetterOrDigit(c);
}
private boolean isalpha(int c) {
return (c >= 'a' && c <= 'z')
|| (c >= 'A' && c <= 'Z');
return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
}
private boolean isdigit(int c) {
@@ -192,16 +170,13 @@ public class LexState extends Constants {
}
private boolean isxdigit(int c) {
return (c >= '0' && c <= '9')
|| (c >= 'a' && c <= 'f')
|| (c >= 'A' && c <= 'F');
return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F');
}
private boolean isspace(int c) {
return (c >= 0 && c <= ' ');
}
public LexState(LuaC.CompileState state, InputStream stream) {
this.z = stream;
this.buff = new char[32];
@@ -232,12 +207,10 @@ public class LexState extends Constants {
buff[nbuff++] = (char) c;
}
String token2str(int token) {
if (token < FIRST_RESERVED) {
return iscntrl(token)?
L.pushfstring( "char("+((int)token)+")" ):
L.pushfstring( String.valueOf( (char) token ) );
return iscntrl(token)? L.pushfstring("char(" + ((int) token) + ")")
: L.pushfstring(String.valueOf((char) token));
} else {
return luaX_tokens[token-FIRST_RESERVED];
}
@@ -310,15 +283,12 @@ public class LexState extends Constants {
nextChar();
}
/*
** =======================================================
** LEXICAL ANALYZER
** =======================================================
*/
boolean check_next(String set) {
if (set.indexOf(current) < 0)
return false;
@@ -437,8 +407,7 @@ public class LexState extends Constants {
for (boolean endloop = false; !endloop;) {
switch (current) {
case EOZ:
lexerror((seminfo != null) ? "unfinished long string"
: "unfinished long comment", TK_EOS);
lexerror((seminfo != null)? "unfinished long string": "unfinished long comment", TK_EOS);
break; /* to avoid warnings */
case '[': {
if (skip_sep() == sep) {
@@ -546,8 +515,10 @@ public class LexState extends Constants {
case 'z': { /* zap following span of spaces */
nextChar(); /* skip the 'z' */
while ( isspace(current) ) {
if (currIsNewline()) inclinenumber();
else nextChar();
if (currIsNewline())
inclinenumber();
else
nextChar();
}
continue;
}
@@ -690,8 +661,16 @@ public class LexState extends Constants {
return TK_NUMBER;
}
}
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9': {
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9': {
read_numeral(seminfo);
return TK_NUMBER;
}
@@ -740,7 +719,6 @@ public class LexState extends Constants {
// from lcode.h
// =============================================================
// =============================================================
// from lparser.c
// =============================================================
@@ -755,22 +733,25 @@ public class LexState extends Constants {
static class expdesc {
int k; // expkind, from enumerated list, above
static class U { // originally a union
short ind_idx; // index (R/K)
short ind_t; // table(register or upvalue)
short ind_vt; // whether 't' is register (VLOCAL) or (UPVALUE)
private LuaValue _nval;
int info;
public void setNval(LuaValue r) {
_nval = r;
}
public void setNval(LuaValue r) { _nval = r; }
public LuaValue nval() {
return (_nval == null? LuaInteger.valueOf(info): _nval);
}
};
final U u = new U();
final IntPtr t = new IntPtr(); /* patch list of `exit when true' */
final IntPtr f = new IntPtr(); /* patch list of `exit when false' */
void init(int k, int i) {
this.f.i = NO_JUMP;
this.t.i = NO_JUMP;
@@ -798,22 +779,22 @@ public class LexState extends Constants {
}
}
/* description of active local variable */
static class Vardesc {
final short idx; /* variable index in stack */
Vardesc(int idx) {
this.idx = (short) idx;
}
};
/* description of pending goto statements and label statements */
static class Labeldesc {
LuaString name; /* label identifier */
int pc; /* position in code */
int line; /* line where it appeared */
short nactvar; /* local level where it appears in current block */
public Labeldesc(LuaString name, int pc, int line, short nactvar) {
this.name = name;
this.pc = pc;
@@ -822,7 +803,6 @@ public class LexState extends Constants {
}
};
/* dynamic structures used by the parser */
static class Dyndata {
Vardesc[] actvar; /* list of active local variables */
@@ -833,7 +813,6 @@ public class LexState extends Constants {
int n_label = 0;
};
boolean hasmultret(int k) {
return ((k) == VCALL || (k) == VVARARG);
}
@@ -885,14 +864,12 @@ public class LexState extends Constants {
syntaxerror(msg);
}
void check_match(int what, int who, int where) {
if (!testnext(what)) {
if (where == linenumber)
error_expected(what);
else {
syntaxerror(L.pushfstring(LUA_QS(token2str(what))
+ " expected " + "(to close " + LUA_QS(token2str(who))
syntaxerror(L.pushfstring(LUA_QS(token2str(what)) + " expected " + "(to close " + LUA_QS(token2str(who))
+ " at line " + where + ")"));
}
}
@@ -914,7 +891,6 @@ public class LexState extends Constants {
codestring(e, str_checkname());
}
int registerlocalvar(LuaString varname) {
FuncState fs = this.fs;
Prototype f = fs.f;
@@ -1003,8 +979,7 @@ public class LexState extends Constants {
_assert(gt.name.eq_b(label.name));
if (gt.nactvar < label.nactvar) {
LuaString vname = fs.getlocvar(gt.nactvar).varname;
String msg = L.pushfstring("<goto " + gt.name + "> at line "
+ gt.line + " jumps into the scope of local '"
String msg = L.pushfstring("<goto " + gt.name + "> at line " + gt.line + " jumps into the scope of local '"
+ vname.tojstring() + "'");
semerror(msg);
}
@@ -1026,8 +1001,7 @@ public class LexState extends Constants {
for (i = bl.firstlabel; i < dyd.n_label; i++) {
Labeldesc lb = dyd.label[i];
if (lb.name.eq_b(gt.name)) { /* correct label? */
if (gt.nactvar > lb.nactvar &&
(bl.upval || dyd.n_label > bl.firstlabel))
if (gt.nactvar > lb.nactvar && (bl.upval || dyd.n_label > bl.firstlabel))
fs.patchclose(gt.pc, lb.nactvar);
closegoto(g, lb); /* close it */
return true;
@@ -1057,7 +1031,6 @@ public class LexState extends Constants {
}
}
/*
** create a label named "break" to resolve break statements
*/
@@ -1072,8 +1045,8 @@ public class LexState extends Constants {
** message when label name is a reserved word (which can only be 'break')
*/
void undefgoto(Labeldesc gt) {
String msg = L.pushfstring(isReservedKeyword(gt.name.tojstring())
? "<"+gt.name+"> at line "+gt.line+" not inside a loop"
String msg = L.pushfstring(
isReservedKeyword(gt.name.tojstring())? "<" + gt.name + "> at line " + gt.line + " not inside a loop"
: "no visible label '" + gt.name + "' for <goto> at line " + gt.line);
semerror(msg);
}
@@ -1153,14 +1126,12 @@ public class LexState extends Constants {
this.checknext(']');
}
/*
** {======================================================================
** Rules for Constructors
** =======================================================================
*/
static class ConsControl {
expdesc v = new expdesc(); /* last list item read */
expdesc t; /* table descriptor */
@@ -1169,7 +1140,6 @@ public class LexState extends Constants {
int tostore; /* number of array elements pending to be stored */
};
void recfield(ConsControl cc) {
/* recfield -> (NAME | `['exp1`]') = exp1 */
FuncState fs = this.fs;
@@ -1198,7 +1168,6 @@ public class LexState extends Constants {
cc.tostore++;
}
void constructor(expdesc t) {
/* constructor -> ?? */
FuncState fs = this.fs;
@@ -1253,11 +1222,12 @@ public class LexState extends Constants {
x = (x+1)>>1;
e++;
}
if (x < 8) return x;
else return ((e+1) << 3) | (((int)x) - 8);
if (x < 8)
return x;
else
return ((e+1)<<3) | (((int) x)-8);
}
/* }====================================================================== */
void parlist() {
@@ -1279,7 +1249,8 @@ public class LexState extends Constants {
f.is_vararg = 1;
break;
}
default: this.syntaxerror("<name> or " + LUA_QL("...") + " expected");
default:
this.syntaxerror("<name> or " + LUA_QL("...") + " expected");
}
} while ( (f.is_vararg == 0) && this.testnext(',') );
}
@@ -1288,7 +1259,6 @@ public class LexState extends Constants {
fs.reserveregs(fs.nactvar); /* reserve register for parameters */
}
void body(expdesc e, boolean needself, int line) {
/* body -> `(' parlist `)' chunk END */
FuncState new_fs = new FuncState();
@@ -1322,7 +1292,6 @@ public class LexState extends Constants {
return n;
}
void funcargs(expdesc f, int line) {
FuncState fs = this.fs;
expdesc args = new expdesc();
@@ -1368,7 +1337,6 @@ public class LexState extends Constants {
* (unless changed) one result */
}
/*
** {======================================================================
** Expression parsing
@@ -1397,7 +1365,6 @@ public class LexState extends Constants {
}
}
void suffixedexp(expdesc v) {
/* suffixedexp ->
primaryexp { '.' NAME | '[' exp ']' | ':' NAME funcargs | funcargs } */
@@ -1437,7 +1404,6 @@ public class LexState extends Constants {
}
}
void simpleexp(expdesc v) {
/*
* simpleexp -> NUMBER | STRING | NIL | true | false | ... | constructor |
@@ -1467,8 +1433,7 @@ public class LexState extends Constants {
}
case TK_DOTS: { /* vararg */
FuncState fs = this.fs;
this.check_condition(fs.f.is_vararg!=0, "cannot use " + LUA_QL("...")
+ " outside a vararg function");
this.check_condition(fs.f.is_vararg != 0, "cannot use " + LUA_QL("...") + " outside a vararg function");
v.init(VVARARG, fs.codeABC(Lua.OP_VARARG, 0, 1, 0));
break;
}
@@ -1489,7 +1454,6 @@ public class LexState extends Constants {
this.next();
}
int getunopr(int op) {
switch (op) {
case TK_NOT:
@@ -1503,7 +1467,6 @@ public class LexState extends Constants {
}
}
int getbinopr(int op) {
switch (op) {
case '+':
@@ -1553,7 +1516,8 @@ public class LexState extends Constants {
};
static Priority[] priority = { /* ORDER OPR */
new Priority(6, 6), new Priority(6, 6), new Priority(7, 7), new Priority(7, 7), new Priority(7, 7), /* `+' `-' `/' `%' */
new Priority(6, 6), new Priority(6, 6), new Priority(7, 7), new Priority(7, 7),
new Priority(7, 7), /* `+' `-' `/' `%' */
new Priority(10, 9), new Priority(5, 4), /* power and concat (right associative) */
new Priority(3, 3), new Priority(3, 3), /* equality and inequality */
new Priority(3, 3), new Priority(3, 3), new Priority(3, 3), new Priority(3, 3), /* order */
@@ -1562,7 +1526,6 @@ public class LexState extends Constants {
static final int UNARY_PRIORITY = 8; /* priority for unary operators */
/*
** subexpr -> (simpleexp | unop subexpr) { binop subexpr }
** where `binop' is any binary operator with a priority higher than `limit'
@@ -1601,26 +1564,26 @@ public class LexState extends Constants {
/* }==================================================================== */
/*
** {======================================================================
** Rules for Statements
** =======================================================================
*/
boolean block_follow(boolean withuntil) {
switch (t.token) {
case TK_ELSE: case TK_ELSEIF: case TK_END: case TK_EOS:
case TK_ELSE:
case TK_ELSEIF:
case TK_END:
case TK_EOS:
return true;
case TK_UNTIL:
return withuntil;
default: return false;
default:
return false;
}
}
void block() {
/* block -> chunk */
FuncState fs = this.fs;
@@ -1630,7 +1593,6 @@ public class LexState extends Constants {
fs.leaveblock();
}
/*
** structure to chain all variables in the left-hand side of an
** assignment
@@ -1641,7 +1603,6 @@ public class LexState extends Constants {
expdesc v = new expdesc();
};
/*
** check whether, in an assignment to a local variable, the local variable
** is needed in a previous assignment (to a table). If so, save original
@@ -1675,11 +1636,9 @@ public class LexState extends Constants {
}
}
void assignment(LHS_assign lh, int nvars) {
expdesc e = new expdesc();
this.check_condition(VLOCAL <= lh.v.k && lh.v.k <= VINDEXED,
"syntax error");
this.check_condition(VLOCAL <= lh.v.k && lh.v.k <= VINDEXED, "syntax error");
if (this.testnext(',')) { /* assignment -> `,' primaryexp assignment */
LHS_assign nv = new LHS_assign();
nv.prev = lh;
@@ -1687,8 +1646,7 @@ public class LexState extends Constants {
if (nv.v.k != VINDEXED)
this.check_conflict(lh, nv.v);
this.assignment(nv, nvars+1);
}
else { /* assignment . `=' explist1 */
} else { /* assignment . `=' explist1 */
int nexps;
this.checknext('=');
nexps = this.explist(e);
@@ -1696,8 +1654,7 @@ public class LexState extends Constants {
this.adjust_assign(nvars, nexps, e);
if (nexps > nvars)
this.fs.freereg -= nexps-nvars; /* remove extra values */
}
else {
} else {
fs.setoneret(e); /* close last expression */
fs.storevar(lh.v, e);
return; /* avoid default */
@@ -1707,7 +1664,6 @@ public class LexState extends Constants {
fs.storevar(lh.v, e);
}
int cond() {
/* cond -> exp */
expdesc v = new expdesc();
@@ -1734,14 +1690,12 @@ public class LexState extends Constants {
findlabel(g); /* close it if label already defined */
}
/* skip no-op statements */
void skipnoopstat() {
while ( t.token == ';' || t.token == TK_DBCOLON )
statement();
}
void labelstat(LuaString label, int line) {
/* label -> '::' NAME '::' */
int l; /* index of new label being created */
@@ -1757,7 +1711,6 @@ public class LexState extends Constants {
findgotos(dyd.label[l]);
}
void whilestat(int line) {
/* whilestat -> WHILE cond DO block END */
FuncState fs = this.fs;
@@ -1797,7 +1750,6 @@ public class LexState extends Constants {
fs.leaveblock(); /* finish loop */
}
int exp1() {
expdesc e = new expdesc();
int k;
@@ -1807,7 +1759,6 @@ public class LexState extends Constants {
return k;
}
void forbody(int base, int line, int nvars, boolean isnum) {
/* forbody -> DO block */
BlockCnt bl = new BlockCnt();
@@ -1833,7 +1784,6 @@ public class LexState extends Constants {
fs.fixline(line);
}
void fornum(LuaString varname, int line) {
/* fornum -> NAME = exp1,exp1[,exp1] forbody */
FuncState fs = this.fs;
@@ -1855,7 +1805,6 @@ public class LexState extends Constants {
this.forbody(base, line, 1, true);
}
void forlist(LuaString indexname) {
/* forlist -> NAME {,NAME} IN explist1 forbody */
FuncState fs = this.fs;
@@ -1880,7 +1829,6 @@ public class LexState extends Constants {
this.forbody(base, line, nvars-3, false);
}
void forstat(int line) {
/* forstat -> FOR (fornum | forlist) END */
FuncState fs = this.fs;
@@ -1904,7 +1852,6 @@ public class LexState extends Constants {
fs.leaveblock(); /* loop scope (`break' jumps to this point) */
}
void test_then_block(IntPtr escapelist) {
/* test_then_block -> [IF | ELSEIF] cond THEN block */
expdesc v = new expdesc();
@@ -1936,7 +1883,6 @@ public class LexState extends Constants {
fs.patchtohere(jf);
}
void ifstat(int line) {
IntPtr escapelist = new IntPtr(NO_JUMP); /* exit list for finished parts */
test_then_block(escapelist); /* IF cond THEN block */
@@ -1958,7 +1904,6 @@ public class LexState extends Constants {
fs.getlocvar(fs.nactvar-1).startpc = fs.pc;
}
void localstat() {
/* stat -> LOCAL NAME {`,' NAME} [`=' explist1] */
int nvars = 0;
@@ -1978,7 +1923,6 @@ public class LexState extends Constants {
this.adjustlocalvars(nvars);
}
boolean funcname(expdesc v) {
/* funcname -> NAME {field} [`:' NAME] */
boolean ismethod = false;
@@ -1992,7 +1936,6 @@ public class LexState extends Constants {
return ismethod;
}
void funcstat(int line) {
/* funcstat -> FUNCTION funcname body */
boolean needself;
@@ -2005,7 +1948,6 @@ public class LexState extends Constants {
fs.fixline(line); /* definition `happens' in the first line */
}
void exprstat() {
/* stat -> func | assignment */
FuncState fs = this.fs;
@@ -2014,8 +1956,7 @@ public class LexState extends Constants {
if (t.token == '=' || t.token == ',') { /* stat -> assignment ? */
v.prev = null;
assignment(v, 1);
}
else { /* stat -> func */
} else { /* stat -> func */
check_condition(v.v.k == VCALL, "syntax error");
SETARG_C(fs.getcodePtr(v.v), 1); /* call statement uses no results */
}
@@ -2114,8 +2055,7 @@ public class LexState extends Constants {
break;
}
}
_assert(fs.f.maxstacksize >= fs.freereg
&& fs.freereg >= fs.nactvar);
_assert(fs.f.maxstacksize >= fs.freereg && fs.freereg >= fs.nactvar);
fs.freereg = fs.nactvar; /* free registers */
leavelevel();
}

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>
* }
* </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,6 +126,7 @@ 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 */

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,40 +50,53 @@ 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();
@@ -119,7 +132,8 @@ 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.
*/
@@ -127,7 +141,6 @@ public class BaseLib extends TwoArgFunction implements ResourceFinder {
return getClass().getResourceAsStream(filename.startsWith("/")? filename: "/" + filename);
}
// "assert", // ( v [,message] ) -> v, message | ERR
static final class _assert extends VarArgFunction {
public Varargs invoke(Varargs args) {
@@ -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;
}
}
// "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);
}
}
@@ -241,13 +256,16 @@ 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' );
if (i > 1)
globals.STDOUT.print('\t');
LuaString s = tostring.call(args.arg(i)).strvalue();
globals.STDOUT.print(s.tojstring());
}
@@ -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) {
@@ -293,12 +312,15 @@ public class BaseLib extends TwoArgFunction implements ResourceFinder {
public LuaValue call(LuaValue table) {
return argerror(2, "value expected");
}
public LuaValue call(LuaValue table, LuaValue index) {
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;
}
@@ -322,6 +344,7 @@ public class BaseLib extends TwoArgFunction implements ResourceFinder {
public LuaValue call(LuaValue table) {
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())
@@ -335,6 +358,7 @@ 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();
@@ -395,9 +419,11 @@ 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);
}
@@ -406,6 +432,7 @@ public class BaseLib extends TwoArgFunction implements ResourceFinder {
// // "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);
}
@@ -427,6 +454,7 @@ 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
@@ -456,14 +484,15 @@ public class BaseLib extends TwoArgFunction implements ResourceFinder {
}
}
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)
return -1;

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>
* }
* </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>
* }
* </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 );
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));
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;
}
@@ -97,11 +115,16 @@ public class Bit32Lib 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());
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;
}

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>
* }
* </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>
* }
* </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;
}
@@ -129,9 +145,11 @@ 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()) {

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>
* }
* </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>
* }
* </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;
}
@@ -151,10 +171,8 @@ public class DebugLib extends TwoArgFunction {
public Varargs invoke(Varargs args) {
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));
}
}
@@ -271,7 +289,6 @@ public class DebugLib extends TwoArgFunction {
}
}
// debug.sethook ([thread,] hook, mask [, count])
final class sethook extends VarArgFunction {
public Varargs invoke(Varargs args) {
@@ -283,9 +300,15 @@ public class DebugLib extends TwoArgFunction {
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;
case 'c':
call = true;
break;
case 'l':
line = true;
break;
case 'r':
rtrn = true;
break;
}
LuaThread.State s = t.state;
s.hookfunc = func;
@@ -315,13 +338,26 @@ public class DebugLib 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 );
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;
}
@@ -402,23 +438,29 @@ 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)
callHook(s, COUNT, NIL);
@@ -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);
@@ -548,6 +593,7 @@ public class DebugLib extends TwoArgFunction {
/**
* Get the traceback starting at a specific level.
*
* @param level
* @return String containing the traceback.
*/
@@ -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,6 +729,7 @@ 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)
@@ -686,6 +737,7 @@ public class DebugLib extends TwoArgFunction {
else
return NIL;
}
Varargs setLocal(int i, LuaValue value) {
LuaString name = getlocalname(i);
if (i >= 1 && i <= stack.length && stack[i-1] != null) {
@@ -695,20 +747,27 @@ public class DebugLib extends TwoArgFunction {
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];
}
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);
}
}
@@ -724,12 +783,14 @@ public class DebugLib extends TwoArgFunction {
}
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,21 +814,49 @@ 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 */
}
@@ -810,8 +899,7 @@ public class DebugLib extends TwoArgFunction {
}
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");
@@ -864,12 +952,14 @@ public class DebugLib extends TwoArgFunction {
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: {
@@ -881,11 +971,13 @@ public class DebugLib extends TwoArgFunction {
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,73 +32,96 @@ 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 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
@@ -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;
@@ -270,7 +283,8 @@ public class IoLib extends TwoArgFunction {
// 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;
}
@@ -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;
@@ -303,28 +320,48 @@ 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);
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) {
if (opcode == LINES_ITER) {
@@ -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);
}
@@ -466,18 +500,19 @@ public class IoLib extends TwoArgFunction {
// __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;
}
@@ -536,7 +571,8 @@ public class IoLib extends TwoArgFunction {
private Varargs ioread(File f, Varargs args) throws IOException {
int i, n = args.narg();
if (n == 0) return freadline(f,false);
if (n == 0)
return freadline(f, false);
LuaValue[] v = new LuaValue[n];
LuaValue ai, vi;
LuaString fmt;
@@ -549,10 +585,18 @@ public class IoLib extends TwoArgFunction {
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;
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:
@@ -586,18 +630,25 @@ 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");
@@ -606,17 +657,18 @@ public class IoLib extends TwoArgFunction {
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)
return NIL;
return LuaString.valueUsing(b, 0, r);
}
public static LuaValue freaduntil(File f, boolean lineonly, boolean withend) throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
int c;
@@ -624,9 +676,17 @@ public class IoLib extends TwoArgFunction {
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;
case '\r':
if (withend)
baos.write(c);
break;
case '\n':
if (withend)
baos.write(c);
break loop;
default:
baos.write(c);
break;
}
}
} else {
@@ -636,13 +696,13 @@ public class IoLib extends TwoArgFunction {
} 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 freadall(File f) throws IOException {
int n = f.remaining();
if (n >= 0) {
@@ -651,6 +711,7 @@ public class IoLib extends TwoArgFunction {
return freaduntil(f, false, false);
}
}
public static LuaValue freadnumber(File f) throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
freadchars(f, " \t\r\n", null);
@@ -666,6 +727,7 @@ public class IoLib extends TwoArgFunction {
String s = baos.toString();
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 ) {
@@ -679,6 +741,4 @@ public class IoLib extends TwoArgFunction {
}
}
}

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.
*/
@@ -145,8 +159,9 @@ abstract public class LibFunction extends LuaFunction {
/**
* 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.
@@ -159,8 +174,9 @@ abstract public class LibFunction extends LuaFunction {
/**
* 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.
@@ -180,17 +196,26 @@ abstract public class LibFunction extends LuaFunction {
}
}
/** 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 };
}
@@ -198,25 +223,35 @@ abstract public class LibFunction extends LuaFunction {
public LuaValue call() {
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);
}
public LuaValue call(LuaValue a, LuaValue b, LuaValue c, LuaValue d) {
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));
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,57 +48,78 @@ 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.
* }
* </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.
* }
* </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);
@@ -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,24 +163,53 @@ 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);
}
@@ -171,12 +223,14 @@ public class MathLib extends TwoArgFunction {
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);
}
}
static final class pow extends BinaryOp {
protected double call(double x, double y) {
return MathLib.dpow_default(x, y);
@@ -186,7 +240,8 @@ 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);
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;
@@ -199,7 +254,8 @@ public class MathLib extends TwoArgFunction {
LuaValue m = args.checkvalue(1);
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;
}
@@ -210,7 +266,8 @@ public class MathLib extends TwoArgFunction {
LuaValue m = args.checkvalue(1);
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,7 +277,8 @@ 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);
@@ -232,18 +290,23 @@ public class MathLib extends TwoArgFunction {
static class random extends LibFunction {
Random random = new Random();
public LuaValue call() {
return valueOf(random.nextDouble());
}
public LuaValue call(LuaValue a) {
int m = a.checkint();
if (m<1) argerror(1, "interval is empty");
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");
if (n < m)
argerror(2, "interval is empty");
return valueOf(m+random.nextInt(n+1-m));
}
@@ -251,9 +314,11 @@ public class MathLib extends TwoArgFunction {
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,17 +326,16 @@ 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);
}
/**

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.
* }
* </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>
* }
* </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,6 +148,7 @@ public class OsLib extends TwoArgFunction {
this.opcode = opcode;
this.name = name;
}
public Varargs invoke(Varargs args) {
try {
switch (opcode) {
@@ -200,8 +208,8 @@ public class OsLib extends TwoArgFunction {
}
/**
* @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() {
@@ -209,8 +217,9 @@ public class OsLib extends TwoArgFunction {
}
/**
* 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
@@ -220,22 +229,21 @@ public class OsLib extends TwoArgFunction {
}
/**
* 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();
@@ -258,7 +266,8 @@ public class OsLib extends TwoArgFunction {
result.append(c);
break;
case '%':
if (i >= n) break;
if (i >= n)
break;
switch (c = fmt[i++]) {
default:
LuaValue.argerror(1, "invalid conversion specifier '%" + c + "'");
@@ -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();
@@ -372,17 +384,10 @@ public class OsLib extends TwoArgFunction {
}
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) {
@@ -390,11 +395,11 @@ public class OsLib extends TwoArgFunction {
}
/**
* 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,9 +438,8 @@ 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
@@ -443,8 +449,8 @@ public class OsLib extends TwoArgFunction {
}
/**
* 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
@@ -455,33 +461,34 @@ public class OsLib extends TwoArgFunction {
}
/**
* 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
*/
@@ -508,11 +515,11 @@ 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
*/

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.
* }
* </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,9 +182,10 @@ 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. */
/**
* 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,29 +199,34 @@ 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) {
@@ -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;
}
}
@@ -311,7 +341,10 @@ public class PackageLib extends TwoArgFunction {
// 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);
}
@@ -356,9 +389,7 @@ public class PackageLib extends TwoArgFunction {
StringBuffer sb = new StringBuffer(j);
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();
}

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

View File

@@ -33,53 +33,70 @@ import org.luaj.vm2.Varargs;
import org.luaj.vm2.compiler.DumpState;
/**
* Subclass of {@link LibFunction} which implements the lua standard {@code string}
* library.
* Subclass of {@link LibFunction} which implements the lua standard
* {@code string} 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("string").get("upper").call(LuaValue.valueOf("abcde")));
* } </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());
* globals.load(new JseStringLib());
* System.out.println(globals.get("string").get("upper").call(LuaValue.valueOf("abcde")));
* } </pre>
* }
* </pre>
* <p>
* This is a direct port of 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.4">Lua 5.2 String Lib Reference</a>
* @see <a href="http://www.lua.org/manual/5.2/manual.html#6.4">Lua 5.2 String
* Lib Reference</a>
*/
public class StringLib extends TwoArgFunction {
/** Construct a StringLib, which can be initialized by calling it with a
/**
* Construct a StringLib, 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 StringLib() {
}
/** 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.
* Creates a metatable that uses __INDEX to fall back on itself to support string
* method operations.
* If the shared strings metatable instance is null, will set the metatable as
* the global shared metatable for strings.
/**
* 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. Creates a metatable that uses __INDEX to fall back on
* itself to support string method operations. If the shared strings
* metatable instance is null, will set the metatable as the global shared
* metatable for strings.
* <P>
* All tables and metatables are read-write by default so if this will be used in
* a server environment, sandboxing should be used. In particular, the
* {@link LuaString#s_metatable} table should probably be made read-only.
* All tables and metatables are read-write by default so if this will be
* used in a server environment, sandboxing should be used. In particular,
* the {@link LuaString#s_metatable} table should probably be made
* read-only.
*
* @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 string = new LuaTable();
@@ -99,7 +116,8 @@ public class StringLib extends TwoArgFunction {
string.set("upper", new upper());
env.set("string", string);
if (!env.get("package").isnil()) env.get("package").get("loaded").set("string", string);
if (!env.get("package").isnil())
env.get("package").get("loaded").set("string", string);
if (LuaString.s_metatable == null) {
LuaString.s_metatable = LuaValue.tableOf(new LuaValue[] { INDEX, string });
}
@@ -109,9 +127,8 @@ public class StringLib extends TwoArgFunction {
/**
* string.byte (s [, i [, j]])
*
* Returns the internal numerical codes of the
* characters s[i], s[i+1], ..., s[j]. The default value for i is 1; the
* default value for j is i.
* Returns the internal numerical codes of the characters s[i], s[i+1], ...,
* s[j]. The default value for i is 1; the default value for j is i.
*
* Note that numerical codes are not necessarily portable across platforms.
*
@@ -124,9 +141,12 @@ public class StringLib extends TwoArgFunction {
int posi = posrelat(args.optint(2, 1), l);
int pose = posrelat(args.optint(3, posi), l);
int n, i;
if (posi <= 0) posi = 1;
if (pose > l) pose = l;
if (posi > pose) return NONE; /* empty interval; return no values */
if (posi <= 0)
posi = 1;
if (pose > l)
pose = l;
if (posi > pose)
return NONE; /* empty interval; return no values */
n = (int) (pose-posi+1);
if (posi+n <= pose) /* overflow? */
error("string slice too long");
@@ -140,9 +160,9 @@ public class StringLib extends TwoArgFunction {
/**
* string.char (...)
*
* Receives zero or more integers. Returns a string with length equal
* to the number of arguments, in which each character has the internal
* numerical code equal to its corresponding argument.
* Receives zero or more integers. Returns a string with length equal to the
* number of arguments, in which each character has the internal numerical
* code equal to its corresponding argument.
*
* Note that numerical codes are not necessarily portable across platforms.
*
@@ -154,7 +174,8 @@ public class StringLib extends TwoArgFunction {
byte[] bytes = new byte[n];
for (int i = 0, a = 1; i < n; i++, a++) {
int c = args.checkint(a);
if (c<0 || c>=256) argerror(a, "invalid value for string.char [0; 255]: " + c);
if (c < 0 || c >= 256)
argerror(a, "invalid value for string.char [0; 255]: " + c);
bytes[i] = (byte) c;
}
return LuaString.valueUsing(bytes);
@@ -164,11 +185,11 @@ public class StringLib extends TwoArgFunction {
/**
* string.dump (function[, stripDebug])
*
* Returns a string containing a binary representation of the given function,
* so that a later loadstring on this string returns a copy of the function.
* function must be a Lua function without upvalues.
* Boolean param stripDebug - true to strip debugging info, false otherwise.
* The default value for stripDebug is true.
* Returns a string containing a binary representation of the given
* function, so that a later loadstring on this string returns a copy of the
* function. function must be a Lua function without upvalues. Boolean param
* stripDebug - true to strip debugging info, false otherwise. The default
* value for stripDebug is true.
*
* TODO: port dumping code as optional add-on
*/
@@ -188,18 +209,17 @@ public class StringLib extends TwoArgFunction {
/**
* string.find (s, pattern [, init [, plain]])
*
* Looks for the first match of pattern in the string s.
* If it finds a match, then find returns the indices of s
* where this occurrence starts and ends; otherwise, it returns nil.
* A third, optional numerical argument init specifies where to start the search;
* its default value is 1 and may be negative. A value of true as a fourth,
* optional argument plain turns off the pattern matching facilities,
* so the function does a plain "find substring" operation,
* with no characters in pattern being considered "magic".
* Note that if plain is given, then init must be given as well.
* Looks for the first match of pattern in the string s. If it finds a
* match, then find returns the indices of s where this occurrence starts
* and ends; otherwise, it returns nil. A third, optional numerical argument
* init specifies where to start the search; its default value is 1 and may
* be negative. A value of true as a fourth, optional argument plain turns
* off the pattern matching facilities, so the function does a plain "find
* substring" operation, with no characters in pattern being considered
* "magic". Note that if plain is given, then init must be given as well.
*
* If the pattern has captures, then in a successful match the captured values
* are also returned, after the two indices.
* If the pattern has captures, then in a successful match the captured
* values are also returned, after the two indices.
*/
static final class find extends VarArgFunction {
public Varargs invoke(Varargs args) {
@@ -211,21 +231,20 @@ public class StringLib extends TwoArgFunction {
* string.format (formatstring, ...)
*
* Returns a formatted version of its variable number of arguments following
* the description given in its first argument (which must be a string).
* The format string follows the same rules as the printf family of standard C functions.
* The only differences are that the options/modifiers *, l, L, n, p, and h are not supported
* and that there is an extra option, q. The q option formats a string in a form suitable
* to be safely read back by the Lua interpreter: the string is written between double quotes,
* and all double quotes, newlines, embedded zeros, and backslashes in the string are correctly
* escaped when written. For instance, the call
* the description given in its first argument (which must be a string). The
* format string follows the same rules as the printf family of standard C
* functions. The only differences are that the options/modifiers *, l, L,
* n, p, and h are not supported and that there is an extra option, q. The q
* option formats a string in a form suitable to be safely read back by the
* Lua interpreter: the string is written between double quotes, and all
* double quotes, newlines, embedded zeros, and backslashes in the string
* are correctly escaped when written. For instance, the call
* string.format('%q', 'a string with "quotes" and \n new line')
*
* will produce the string:
* "a string with \"quotes\" and \
* new line"
* will produce the string: "a string with \"quotes\" and \ new line"
*
* The options c, d, E, e, f, g, G, i, o, u, X, and x all expect a number as argument,
* whereas q and s expect a string.
* The options c, d, E, e, f, g, G, i, o, u, X, and x all expect a number as
* argument, whereas q and s expect a string.
*
* This function does not accept string values containing embedded zeros,
* except as arguments to the q option.
@@ -286,7 +305,8 @@ public class StringLib extends TwoArgFunction {
} else {
fdsc.format(result, s);
}
} break;
}
break;
default:
error("invalid option '%" + (char) fdsc.conversion + "' to 'format'");
break;
@@ -305,7 +325,9 @@ public class StringLib extends TwoArgFunction {
buf.append((byte) '"');
for (int i = 0, n = s.length(); i < n; i++) {
switch (c = s.luaByte(i)) {
case '"': case '\\': case '\n':
case '"':
case '\\':
case '\n':
buf.append((byte) '\\');
buf.append((byte) c);
break;
@@ -354,12 +376,24 @@ public class StringLib extends TwoArgFunction {
boolean moreFlags = true;
while ( moreFlags ) {
switch (c = ((p < n)? strfrmt.luaByte(p++): 0)) {
case '-': leftAdjust = true; break;
case '+': explicitPlus = true; break;
case ' ': space = true; break;
case '#': alternateForm = true; break;
case '0': zeroPad = true; break;
default: moreFlags = false; break;
case '-':
leftAdjust = true;
break;
case '+':
explicitPlus = true;
break;
case ' ':
space = true;
break;
case '#':
alternateForm = true;
break;
case '0':
zeroPad = true;
break;
default:
moreFlags = false;
break;
}
}
if (p-start > MAX_FLAGS)
@@ -494,26 +528,20 @@ public class StringLib extends TwoArgFunction {
/**
* string.gmatch (s, pattern)
*
* Returns an iterator function that, each time it is called, returns the next captures
* from pattern over string s. If pattern specifies no captures, then the
* whole match is produced in each call.
* Returns an iterator function that, each time it is called, returns the
* next captures from pattern over string s. If pattern specifies no
* captures, then the whole match is produced in each call.
*
* As an example, the following loop
* s = "hello world from Lua"
* for w in string.gmatch(s, "%a+") do
* print(w)
* end
* As an example, the following loop s = "hello world from Lua" for w in
* string.gmatch(s, "%a+") do print(w) end
*
* will iterate over all the words from string s, printing one per line.
* The next example collects all pairs key=value from the given string into a table:
* t = {}
* s = "from=world, to=Lua"
* for k, v in string.gmatch(s, "(%w+)=(%w+)") do
* t[k] = v
* end
* will iterate over all the words from string s, printing one per line. The
* next example collects all pairs key=value from the given string into a
* table: t = {} s = "from=world, to=Lua" for k, v in string.gmatch(s,
* "(%w+)=(%w+)") do t[k] = v end
*
* For this function, a '^' at the start of a pattern does not work as an anchor,
* as this would prevent the iteration.
* For this function, a '^' at the start of a pattern does not work as an
* anchor, as this would prevent the iteration.
*/
static final class gmatch extends VarArgFunction {
public Varargs invoke(Varargs args) {
@@ -528,12 +556,14 @@ public class StringLib extends TwoArgFunction {
private final MatchState ms;
private int soffset;
private int lastmatch;
public GMatchAux(Varargs args, LuaString src, LuaString pat) {
this.srclen = src.length();
this.ms = new MatchState(args, src, pat);
this.soffset = 0;
this.lastmatch = -1;
}
public Varargs invoke(Varargs args) {
for (; soffset <= srclen; soffset++) {
ms.reset();
@@ -548,51 +578,50 @@ public class StringLib extends TwoArgFunction {
}
}
/**
* string.gsub (s, pattern, repl [, n])
* Returns a copy of s in which all (or the first n, if given) occurrences of the
* pattern have been replaced by a replacement string specified by repl, which
* may be a string, a table, or a function. gsub also returns, as its second value,
* the total number of matches that occurred.
* string.gsub (s, pattern, repl [, n]) Returns a copy of s in which all (or
* the first n, if given) occurrences of the pattern have been replaced by a
* replacement string specified by repl, which may be a string, a table, or
* a function. gsub also returns, as its second value, the total number of
* matches that occurred.
*
* If repl is a string, then its value is used for replacement.
* The character % works as an escape character: any sequence in repl of the form %n,
* with n between 1 and 9, stands for the value of the n-th captured substring (see below).
* The sequence %0 stands for the whole match. The sequence %% stands for a single %.
* If repl is a string, then its value is used for replacement. The
* character % works as an escape character: any sequence in repl of the
* form %n, with n between 1 and 9, stands for the value of the n-th
* captured substring (see below). The sequence %0 stands for the whole
* match. The sequence %% stands for a single %.
*
* If repl is a table, then the table is queried for every match, using the first capture
* as the key; if the pattern specifies no captures, then the whole match is used as the key.
* If repl is a table, then the table is queried for every match, using the
* first capture as the key; if the pattern specifies no captures, then the
* whole match is used as the key.
*
* If repl is a function, then this function is called every time a match occurs,
* with all captured substrings passed as arguments, in order; if the pattern specifies
* no captures, then the whole match is passed as a sole argument.
* If repl is a function, then this function is called every time a match
* occurs, with all captured substrings passed as arguments, in order; if
* the pattern specifies no captures, then the whole match is passed as a
* sole argument.
*
* If the value returned by the table query or by the function call is a string or a number,
* then it is used as the replacement string; otherwise, if it is false or nil,
* then there is no replacement (that is, the original match is kept in the string).
* If the value returned by the table query or by the function call is a
* string or a number, then it is used as the replacement string; otherwise,
* if it is false or nil, then there is no replacement (that is, the
* original match is kept in the string).
*
* Here are some examples:
* x = string.gsub("hello world", "(%w+)", "%1 %1")
* Here are some examples: x = string.gsub("hello world", "(%w+)", "%1 %1")
* --> x="hello hello world world"
*
* x = string.gsub("hello world", "%w+", "%0 %0", 1)
* --> x="hello hello world"
* x = string.gsub("hello world", "%w+", "%0 %0", 1) --> x="hello hello
* world"
*
* x = string.gsub("hello world from Lua", "(%w+)%s*(%w+)", "%2 %1")
* --> x="world hello Lua from"
* x = string.gsub("hello world from Lua", "(%w+)%s*(%w+)", "%2 %1") -->
* x="world hello Lua from"
*
* x = string.gsub("home = $HOME, user = $USER", "%$(%w+)", os.getenv)
* --> x="home = /home/roberto, user = roberto"
* x = string.gsub("home = $HOME, user = $USER", "%$(%w+)", os.getenv) -->
* x="home = /home/roberto, user = roberto"
*
* x = string.gsub("4+5 = $return 4+5$", "%$(.-)%$", function (s)
* return loadstring(s)()
* end)
* --> x="4+5 = 9"
* x = string.gsub("4+5 = $return 4+5$", "%$(.-)%$", function (s) return
* loadstring(s)() end) --> x="4+5 = 9"
*
* local t = {name="lua", version="5.1"}
* x = string.gsub("$name-$version.tar.gz", "%$(%w+)", t)
* --> x="lua-5.1.tar.gz"
* local t = {name="lua", version="5.1"} x =
* string.gsub("$name-$version.tar.gz", "%$(%w+)", t) --> x="lua-5.1.tar.gz"
*/
static final class gsub extends VarArgFunction {
public Varargs invoke(Varargs args) {
@@ -616,11 +645,12 @@ public class StringLib extends TwoArgFunction {
n++;
ms.add_value(lbuf, soffset, res, repl); /* add replacement to buffer */
soffset = lastmatch = res;
}
else if ( soffset < srclen ) /* otherwise, skip one character */
} else if (soffset < srclen) /* otherwise, skip one character */
lbuf.append((byte) src.luaByte(soffset++));
else break; /* end of subject */
if ( anchor ) break;
else
break; /* end of subject */
if (anchor)
break;
}
lbuf.append(src.substring(soffset, srclen));
return varargsOf(lbuf.tostring(), valueOf(n));
@@ -630,8 +660,8 @@ public class StringLib extends TwoArgFunction {
/**
* string.len (s)
*
* Receives a string and returns its length. The empty string "" has length 0.
* Embedded zeros are counted, so "a\000bc\000" has length 5.
* Receives a string and returns its length. The empty string "" has length
* 0. Embedded zeros are counted, so "a\000bc\000" has length 5.
*/
static final class len extends OneArgFunction {
public LuaValue call(LuaValue arg) {
@@ -642,9 +672,10 @@ public class StringLib extends TwoArgFunction {
/**
* string.lower (s)
*
* Receives a string and returns a copy of this string with all uppercase letters
* changed to lowercase. All other characters are left unchanged.
* The definition of what an uppercase letter is depends on the current locale.
* Receives a string and returns a copy of this string with all uppercase
* letters changed to lowercase. All other characters are left unchanged.
* The definition of what an uppercase letter is depends on the current
* locale.
*/
static final class lower extends OneArgFunction {
public LuaValue call(LuaValue arg) {
@@ -704,13 +735,11 @@ public class StringLib extends TwoArgFunction {
/**
* string.sub (s, i [, j])
*
* Returns the substring of s that starts at i and continues until j;
* i and j may be negative. If j is absent, then it is assumed to be equal to -1
* Returns the substring of s that starts at i and continues until j; i and
* j may be negative. If j is absent, then it is assumed to be equal to -1
* (which is the same as the string length). In particular, the call
* string.sub(s,1,j)
* returns a prefix of s with length j, and
* string.sub(s, -i)
* returns a suffix of s with length i.
* string.sub(s,1,j) returns a prefix of s with length j, and string.sub(s,
* -i) returns a suffix of s with length i.
*/
static final class sub extends VarArgFunction {
public Varargs invoke(Varargs args) {
@@ -736,9 +765,10 @@ public class StringLib extends TwoArgFunction {
/**
* string.upper (s)
*
* Receives a string and returns a copy of this string with all lowercase letters
* changed to uppercase. All other characters are left unchanged.
* The definition of what a lowercase letter is depends on the current locale.
* Receives a string and returns a copy of this string with all lowercase
* letters changed to uppercase. All other characters are left unchanged.
* The definition of what a lowercase letter is depends on the current
* locale.
*/
static final class upper extends OneArgFunction {
public LuaValue call(LuaValue arg) {
@@ -824,10 +854,9 @@ public class StringLib extends TwoArgFunction {
for (int i = 0; i < 128; ++i) {
final char c = (char) i;
CHAR_TABLE[i] = (byte)( ( Character.isDigit( c ) ? MASK_DIGIT : 0 ) |
( Character.isLowerCase( c ) ? MASK_LOWERCASE : 0 ) |
( Character.isUpperCase( c ) ? MASK_UPPERCASE : 0 ) |
( ( c < ' ' || c == 0x7F ) ? MASK_CONTROL : 0 ) );
CHAR_TABLE[i] = (byte) ((Character.isDigit(c)? MASK_DIGIT: 0)
| (Character.isLowerCase(c)? MASK_LOWERCASE: 0) | (Character.isUpperCase(c)? MASK_UPPERCASE: 0)
| ((c < ' ' || c == 0x7F)? MASK_CONTROL: 0));
if ((c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F') || (c >= '0' && c <= '9')) {
CHAR_TABLE[i] |= MASK_HEXDIGIT;
}
@@ -881,12 +910,11 @@ public class StringLib extends TwoArgFunction {
++i; // skip ESC
b = (byte) (i < l? news.luaByte(i): 0);
if (!Character.isDigit((char) b)) {
if (b != L_ESC) error( "invalid use of '" + (char)L_ESC +
"' in replacement string: after '" + (char)L_ESC +
"' must be '0'-'9' or '" + (char)L_ESC +
"', but found " + (i < l ? "symbol '" + (char)b + "' with code " + b +
" at pos " + (i + 1) :
"end of string"));
if (b != L_ESC)
error("invalid use of '" + (char) L_ESC + "' in replacement string: after '" + (char) L_ESC
+ "' must be '0'-'9' or '" + (char) L_ESC + "', but found "
+ (i < l? "symbol '" + (char) b + "' with code " + b + " at pos " + (i+1)
: "end of string"));
lbuf.append(b);
} else if (b == '0') {
lbuf.append(s.substring(soff, e));
@@ -929,8 +957,10 @@ public class StringLib extends TwoArgFunction {
Varargs push_captures(boolean wholeMatch, int soff, int end) {
int nlevels = (this.level == 0 && wholeMatch)? 1: this.level;
switch (nlevels) {
case 0: return NONE;
case 1: return push_onecapture( 0, soff, end );
case 0:
return NONE;
case 1:
return push_onecapture(0, soff, end);
}
LuaValue[] v = new LuaValue[nlevels];
for (int i = 0; i < nlevels; ++i)
@@ -985,7 +1015,8 @@ public class StringLib extends TwoArgFunction {
return poffset+1;
case '[':
if ( poffset != p.length() && p.luaByte( poffset ) == '^' ) poffset++;
if (poffset != p.length() && p.luaByte(poffset) == '^')
poffset++;
do {
if (poffset == p.length()) {
error("malformed pattern (missing ']')");
@@ -1005,18 +1036,41 @@ public class StringLib extends TwoArgFunction {
boolean res;
switch (lcl) {
case 'a': res = ( cdata & MASK_ALPHA ) != 0; break;
case 'd': res = ( cdata & MASK_DIGIT ) != 0; break;
case 'l': res = ( cdata & MASK_LOWERCASE ) != 0; break;
case 'u': res = ( cdata & MASK_UPPERCASE ) != 0; break;
case 'c': res = ( cdata & MASK_CONTROL ) != 0; break;
case 'p': res = ( cdata & MASK_PUNCT ) != 0; break;
case 's': res = ( cdata & MASK_SPACE ) != 0; break;
case 'g': res = ( cdata & ( MASK_ALPHA | MASK_DIGIT | MASK_PUNCT ) ) != 0; break;
case 'w': res = ( cdata & ( MASK_ALPHA | MASK_DIGIT ) ) != 0; break;
case 'x': res = ( cdata & MASK_HEXDIGIT ) != 0; break;
case 'z': res = ( c == 0 ); break; /* deprecated option */
default: return cl == c;
case 'a':
res = (cdata & MASK_ALPHA) != 0;
break;
case 'd':
res = (cdata & MASK_DIGIT) != 0;
break;
case 'l':
res = (cdata & MASK_LOWERCASE) != 0;
break;
case 'u':
res = (cdata & MASK_UPPERCASE) != 0;
break;
case 'c':
res = (cdata & MASK_CONTROL) != 0;
break;
case 'p':
res = (cdata & MASK_PUNCT) != 0;
break;
case 's':
res = (cdata & MASK_SPACE) != 0;
break;
case 'g':
res = (cdata & (MASK_ALPHA | MASK_DIGIT | MASK_PUNCT)) != 0;
break;
case 'w':
res = (cdata & (MASK_ALPHA | MASK_DIGIT)) != 0;
break;
case 'x':
res = (cdata & MASK_HEXDIGIT) != 0;
break;
case 'z':
res = (c == 0);
break; /* deprecated option */
default:
return cl == c;
}
return (lcl == cl)? res: !res;
}
@@ -1032,23 +1086,26 @@ public class StringLib extends TwoArgFunction {
poff++;
if (match_class(c, p.luaByte(poff)))
return sig;
}
else if ( ( p.luaByte( poff + 1 ) == '-' ) && ( poff + 2 < ec ) ) {
} else if ((p.luaByte(poff+1) == '-') && (poff+2 < ec)) {
poff += 2;
if (p.luaByte(poff-2) <= c && c <= p.luaByte(poff))
return sig;
}
else if ( p.luaByte( poff ) == c ) return sig;
} else if (p.luaByte(poff) == c)
return sig;
}
return !sig;
}
boolean singlematch(int c, int poff, int ep) {
switch (p.luaByte(poff)) {
case '.': return true;
case L_ESC: return match_class( c, p.luaByte( poff + 1 ) );
case '[': return matchbracketclass( c, poff, ep - 1 );
default: return p.luaByte( poff ) == c;
case '.':
return true;
case L_ESC:
return match_class(c, p.luaByte(poff+1));
case '[':
return matchbracketclass(c, poff, ep-1);
default:
return p.luaByte(poff) == c;
}
}
@@ -1057,7 +1114,8 @@ public class StringLib extends TwoArgFunction {
* where match ends, otherwise returns -1.
*/
int match(int soffset, int poffset) {
if (matchdepth-- == 0) error("pattern too complex");
if (matchdepth-- == 0)
error("pattern too complex");
try {
while ( true ) {
// Check if we are at the end of the pattern -
@@ -1079,7 +1137,8 @@ public class StringLib extends TwoArgFunction {
switch (p.luaByte(poffset+1)) {
case 'b':
soffset = matchbalance(soffset, poffset+2);
if ( soffset == -1 ) return -1;
if (soffset == -1)
return -1;
poffset += 4;
continue;
case 'f': {
@@ -1090,8 +1149,7 @@ public class StringLib extends TwoArgFunction {
int ep = classend(poffset);
int previous = (soffset == 0)? '\0': s.luaByte(soffset-1);
int next = (soffset == s.length())? '\0': s.luaByte(soffset);
if ( matchbracketclass( previous, poffset, ep - 1 ) ||
!matchbracketclass( next, poffset, ep - 1 ) )
if (matchbracketclass(previous, poffset, ep-1) || !matchbracketclass(next, poffset, ep-1))
return -1;
poffset = ep;
continue;
@@ -1142,8 +1200,7 @@ public class StringLib extends TwoArgFunction {
int max_expand(int soff, int poff, int ep) {
int i = 0;
while ( soff + i < s.length() &&
singlematch( s.luaByte( soff + i ), poff, ep ) )
while ( soff+i < s.length() && singlematch(s.luaByte(soff+i), poff, ep) )
i++;
while ( i >= 0 ) {
int res = match(soff+i, ep+1);
@@ -1161,7 +1218,8 @@ public class StringLib extends TwoArgFunction {
return res;
else if (soff < s.length() && singlematch(s.luaByte(soff), poff, ep))
soff++;
else return -1;
else
return -1;
}
}
@@ -1191,8 +1249,7 @@ public class StringLib extends TwoArgFunction {
int match_capture(int soff, int l) {
l = check_capture(l);
int len = clen[l];
if ( ( s.length() - soff ) >= len &&
LuaString.equals( s, cinit[l], s, soff, len ) )
if ((s.length()-soff) >= len && LuaString.equals(s, cinit[l], s, soff, len))
return soff+len;
else
return -1;
@@ -1213,9 +1270,10 @@ public class StringLib extends TwoArgFunction {
int cont = 1;
while ( ++soff < slen ) {
if (s.luaByte(soff) == e) {
if ( --cont == 0 ) return soff + 1;
}
else if ( s.luaByte( soff ) == b ) cont++;
if (--cont == 0)
return soff+1;
} else if (s.luaByte(soff) == b)
cont++;
}
return -1;
}

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>
* }
* </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>
* }
* </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,7 +86,8 @@ 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;
}
@@ -79,12 +96,15 @@ public class TableLib extends TwoArgFunction {
public LuaValue call(LuaValue list) {
return list.checktable().concat(EMPTYSTRING, 1, list.length());
}
public LuaValue call(LuaValue list, LuaValue sep) {
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());
}
public LuaValue call(LuaValue list, LuaValue sep, LuaValue i, LuaValue j) {
return list.checktable().concat(sep.checkstring(), i.checkint(), j.checkint());
}
@@ -103,7 +123,8 @@ public class TableLib extends TwoArgFunction {
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);
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;
}
@@ -139,13 +160,11 @@ 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) {

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

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

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
@@ -67,10 +70,10 @@ abstract public class VarArgFunction extends LibFunction {
}
/**
* 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());
File f = readMode? new FileImpl(conn, conn.openInputStream(), null)
: new FileImpl(conn, conn.openInputStream(), conn.openOutputStream());
/*
if ( appendMode ) {
f.seek("end",0);
@@ -121,33 +134,41 @@ 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) {
this.conn = conn;
this.is = is;
this.os = os;
}
private FileImpl(InputStream i) {
this(null, i, null);
}
private FileImpl(OutputStream o) {
this(null, null, o);
}
public String tojstring() {
return "file (" + this.hashCode() + ")";
}
public boolean isstdfile() {
return conn == null;
}
public void close() throws IOException {
closed = true;
if (conn != null) {
conn.close();
}
}
public void flush() throws IOException {
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);
@@ -156,9 +177,11 @@ public class JmeIoLib extends IoLib {
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);
}

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);
@@ -137,7 +131,8 @@ public class lua {
// new lua state
globals = nodebug? JsePlatform.standardGlobals(): JsePlatform.debugGlobals();
if ( luajc ) LuaJC.install(globals);
if (luajc)
LuaJC.install(globals);
for (int i = 0, n = libs != null? libs.size(): 0; i < n; i++)
loadLibrary((String) libs.elementAt(i));
@@ -192,14 +187,14 @@ public class lua {
}
}
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();
}

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);
@@ -168,13 +162,14 @@ public class luac {
}
}
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)

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);
@@ -165,6 +161,7 @@ public class luajc {
scanfile(dir, f, pkgprefix);
}
}
private void scandir(File dir, String javapackage) {
File[] f = dir.listFiles();
for (int i = 0; i < f.length; i++)
@@ -208,7 +205,8 @@ public class luajc {
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.luachunkname = (subdir != null? subdir + "/": "")
+infile.getName().substring(0, infile.getName().lastIndexOf('.'));
this.infile = f;
this.outdir = new File(outdirpath);
}
@@ -222,9 +220,10 @@ public class luajc {
// 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);
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

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) {
@@ -63,14 +62,12 @@ public class Exp extends SyntaxElement {
// TODO: constant folding
if (lhs instanceof BinopExp) {
BinopExp b = (BinopExp) lhs;
if ( (precedence(op) > precedence(b.op)) ||
((precedence(op) == precedence(b.op)) && isrightassoc(op)) )
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) {
BinopExp b = (BinopExp) rhs;
if ( (precedence(op) > precedence(b.op)) ||
((precedence(op) == precedence(b.op)) && ! isrightassoc(op)) )
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);
@@ -79,22 +76,43 @@ public class Exp extends SyntaxElement {
static boolean isrightassoc(int 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);
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;
@@ -288,6 +316,7 @@ public class Exp extends SyntaxElement {
public static class BinopExp extends Exp {
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

@@ -30,6 +30,7 @@ public class FuncBody extends SyntaxElement {
this.parlist = parlist != null? parlist: ParList.EMPTY_PARLIST;
this.block = block;
}
public void accept(Visitor visitor) {
visitor.visit(this);
}

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;
}

View File

@@ -26,17 +26,13 @@ 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" };
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]);
}
@@ -59,7 +55,10 @@ public class NameScope {
this.functionNestingCount = outerScope != null? outerScope.functionNestingCount: 0;
}
/** Look up a name. If it is a global name, then throw 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)
@@ -70,7 +69,10 @@ public class NameScope {
return value;
}
/** Define a name in this scope. If it is a global name, then throw 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);

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) {
@@ -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,10 +131,12 @@ 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) {
this.exp = exp;
this.block = block;
}
public void accept(Visitor visitor) {
visitor.visit(this);
}
@@ -139,10 +145,12 @@ public class Stat extends SyntaxElement {
public static class RepeatUntil extends Stat {
public final Block block;
public final Exp exp;
public RepeatUntil(Block block, Exp exp) {
this.block = block;
this.exp = exp;
}
public void accept(Visitor visitor) {
visitor.visit(this);
}
@@ -156,6 +164,7 @@ public class Stat extends SyntaxElement {
public static class Return extends Stat {
public final List<Exp> values;
public Return(List<Exp> values) {
this.values = values;
}
@@ -174,6 +183,7 @@ public class Stat extends SyntaxElement {
public static class FuncCallStat extends Stat {
public final Exp.FuncCall funccall;
public FuncCallStat(Exp.FuncCall funccall) {
this.funccall = funccall;
}
@@ -186,6 +196,7 @@ public class Stat extends SyntaxElement {
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;
@@ -199,6 +210,7 @@ public class Stat extends SyntaxElement {
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;
@@ -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;
@@ -230,6 +243,7 @@ public class Stat extends SyntaxElement {
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;
@@ -246,6 +260,7 @@ public class Stat extends SyntaxElement {
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;
@@ -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;

View File

@@ -64,25 +64,55 @@ public class Str {
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':
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]);

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,30 +29,37 @@ 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);
};
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);
@@ -64,14 +71,17 @@ abstract public class Visitor {
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);
@@ -81,25 +91,31 @@ abstract public class Visitor {
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);
@@ -107,74 +123,95 @@ abstract public class Visitor {
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);
}
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);
}
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);
}
public void visitNames(List<Name> names) {
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
@@ -133,7 +133,6 @@ public class CoerceJavaToLua {
}
}
static final Map COERCIONS = Collections.synchronizedMap(new HashMap());
static {
@@ -160,12 +159,13 @@ public class CoerceJavaToLua {
/**
* 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
@@ -180,9 +180,7 @@ public class CoerceJavaToLua {
Class clazz = o.getClass();
Coercion c = (Coercion) COERCIONS.get(clazz);
if (c == null) {
c = clazz.isArray()? arrayCoercion:
o instanceof LuaValue ? luaCoercion:
instanceCoercion;
c = clazz.isArray()? arrayCoercion: o instanceof LuaValue? luaCoercion: instanceCoercion;
COERCIONS.put(clazz, c);
}
return c.coerce(o);

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
@@ -65,14 +65,17 @@ public class CoerceLuaToJava {
static interface Coercion {
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,6 +87,7 @@ public class CoerceLuaToJava {
public String toString() {
return "BoolCoercion()";
}
public int score(LuaValue value) {
switch (value.type()) {
case LuaValue.TBOOLEAN:
@@ -107,12 +111,15 @@ 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] + ")";
}
NumericCoercion(int targetType) {
this.targetType = targetType;
}
public int score(LuaValue value) {
int fromStringPenalty = 0;
if (value.type() == LuaValue.TSTRING) {
@@ -134,25 +141,31 @@ public class CoerceLuaToJava {
}
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;
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);
@@ -165,7 +178,8 @@ public class CoerceLuaToJava {
double d = value.todouble();
return fromStringPenalty+(((d == (long) d) || (d == (float) d))? 1: 0);
}
default: return SCORE_WRONG_TYPE;
default:
return SCORE_WRONG_TYPE;
}
} else {
return SCORE_UNCOERCIBLE;
@@ -174,14 +188,22 @@ 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;
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,24 +212,27 @@ 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[]") + ")";
}
public int score(LuaValue value) {
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())
return null;
@@ -223,13 +248,16 @@ 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() + ")";
}
public int score(LuaValue value) {
switch (value.type()) {
case LuaValue.TTABLE:
@@ -242,6 +270,7 @@ public class CoerceLuaToJava {
return SCORE_UNCOERCIBLE;
}
}
public Object coerce(LuaValue value) {
switch (value.type()) {
case LuaValue.TTABLE: {
@@ -264,10 +293,11 @@ 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)
@@ -283,12 +313,15 @@ public class CoerceLuaToJava {
static final class ObjectCoercion implements Coercion {
final Class targetType;
ObjectCoercion(Class targetType) {
this.targetType = targetType;
}
public String toString() {
return "ObjectCoercion(" + targetType.getName() + ")";
}
public int score(LuaValue value) {
switch (value.type()) {
case LuaValue.TNUMBER:
@@ -305,6 +338,7 @@ public class CoerceLuaToJava {
return inheritanceLevels(targetType, value.getClass());
}
}
public Object coerce(LuaValue value) {
switch (value.type()) {
case LuaValue.TNUMBER:

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
*/
@@ -65,9 +65,9 @@ class JavaArray extends LuaUserdata {
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;
return i >= 0 && i < Array.getLength(m_instance)
? CoerceJavaToLua.coerce(Array.get(m_instance, key.toint()-1))
: NIL;
}
return super.get(key);
}
@@ -79,8 +79,7 @@ class JavaArray extends LuaUserdata {
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
*/
@@ -113,19 +113,23 @@ class JavaClass extends JavaInstance implements CoerceJavaToLua.Coercion {
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;
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();) {
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;
}
@@ -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
*/
@@ -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;
}

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
*/

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;

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
*/
@@ -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 {

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
@@ -113,4 +131,3 @@ public class JseBaseLib extends org.luaj.vm2.lib.BaseLib {
}
}
}

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,7 +96,8 @@ 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 {
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());
@@ -96,9 +110,7 @@ public class JseIoLib extends IoLib {
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 {
@@ -111,43 +123,51 @@ public class JseIoLib extends IoLib {
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) {
this.file = file;
this.is = is != null? is.markSupported()? is: new BufferedInputStream(is): null;
this.os = os;
}
private FileImpl(RandomAccessFile f) {
this(f, null, null);
}
private FileImpl(InputStream i) {
this(null, i, null);
}
private FileImpl(OutputStream o) {
this(null, null, o);
}
public String tojstring() {
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) {
file.close();
}
}
public void flush() throws IOException {
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);
@@ -158,9 +178,11 @@ public class JseIoLib extends IoLib {
if (nobuffer)
flush();
}
public boolean isclosed() {
return closed;
}
public int seek(String option, int pos) throws IOException {
if (file != null) {
if ("set".equals(option)) {
@@ -175,6 +197,7 @@ public class JseIoLib extends IoLib {
notimplemented();
return 0;
}
public void setvbuf(String mode, int size) {
nobuffer = "no".equals(mode);
}
@@ -236,11 +259,7 @@ public class JseIoLib extends IoLib {
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;
}
}
@@ -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>
* }
* </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.
* }
* </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>
* }
* </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.
* }
* </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 {

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;
/** 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;

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;
@@ -112,7 +117,8 @@ public class LuajavaLib extends VarArgFunction {
LuaTable t = new LuaTable();
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,7 +129,8 @@ 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);
}

View File

@@ -20,10 +20,8 @@ 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();
}
@@ -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,10 +128,13 @@ 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) {}
}

View File

@@ -93,7 +93,6 @@ public class JavaBuilder {
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();
private static final String STR_FUNC1 = OneArgFunction.class.getName();
@@ -111,7 +110,8 @@ public class JavaBuilder {
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_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";
@@ -179,16 +180,16 @@ public class JavaBuilder {
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
@@ -209,8 +210,7 @@ public class JavaBuilder {
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
@@ -232,7 +232,8 @@ public class JavaBuilder {
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);
}
}
@@ -265,8 +266,7 @@ public class JavaBuilder {
// add class initializer
if (!init.isEmpty()) {
MethodGen mg = new MethodGen(Constants.ACC_STATIC, Type.VOID,
ARG_TYPES_NONE, new String[] {}, "<clinit>",
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();
@@ -289,14 +289,14 @@ public class JavaBuilder {
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]);
append(InstructionConstants.THIS);
append(new ALOAD(1));
if (isrw) {
append(factory.createInvoke(classname, "newupl", TYPE_LOCALUPVALUE, ARG_TYPES_LUAVALUE, Constants.INVOKESTATIC));
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));
@@ -313,21 +313,21 @@ public class JavaBuilder {
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();
@@ -362,6 +362,7 @@ public class JavaBuilder {
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))
@@ -373,10 +374,10 @@ 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 );
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) {
@@ -395,7 +396,8 @@ public class JavaBuilder {
if (isupval) {
boolean isupcreate = pi.isUpvalueCreate(pc, slot);
if (isupcreate) {
append(factory.createInvoke(classname, "newupe", TYPE_LOCALUPVALUE, ARG_TYPES_NONE, Constants.INVOKESTATIC));
append(factory.createInvoke(classname, "newupe", TYPE_LOCALUPVALUE, ARG_TYPES_NONE,
Constants.INVOKESTATIC));
append(InstructionConstants.DUP);
append(new ASTORE(index));
} else {
@@ -416,7 +418,8 @@ public class JavaBuilder {
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));
append(factory.createInvoke(classname, "newupn", TYPE_LOCALUPVALUE, ARG_TYPES_NONE,
Constants.INVOKESTATIC));
append(new ASTORE(index));
}
}
@@ -427,7 +430,8 @@ public class JavaBuilder {
if (isupassign) {
int index = findSlotIndex(slot, false);
append(new ALOAD(index));
append(factory.createInvoke(classname, "newupl", TYPE_LOCALUPVALUE, ARG_TYPES_LUAVALUE, Constants.INVOKESTATIC));
append(factory.createInvoke(classname, "newupl", TYPE_LOCALUPVALUE, ARG_TYPES_LUAVALUE,
Constants.INVOKESTATIC));
int upindex = findSlotIndex(slot, true);
append(new ASTORE(upindex));
}
@@ -463,7 +467,6 @@ public class JavaBuilder {
}
}
public void newTable(int b, int c) {
append(new PUSH(cp, b));
append(new PUSH(cp, c));
@@ -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,7 +596,8 @@ 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) {
@@ -584,19 +613,29 @@ public class JavaBuilder {
public void newVarargs(int pc, int firstslot, int nargs) {
switch (nargs) {
case 0: loadNone();
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;
}
}
@@ -604,35 +643,63 @@ public class JavaBuilder {
public void newVarargsVarresult(int pc, int firstslot, int 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");
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");
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) {
@@ -674,11 +741,8 @@ public class JavaBuilder {
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());
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));
@@ -690,48 +754,43 @@ public class JavaBuilder {
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()) {
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++)
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));
@@ -746,15 +805,20 @@ public class JavaBuilder {
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));
}
@@ -800,7 +864,8 @@ public class JavaBuilder {
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]]));
throw new IllegalArgumentException(
"no target at or after " + targets[pc] + " op=" + Lua.GET_OPCODE(p.code[targets[pc]]));
branches[pc].setTarget(branchDestHandles[t]);
}
}
@@ -811,18 +876,21 @@ public class JavaBuilder {
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));
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 {
@@ -243,7 +241,10 @@ public class JavaGen {
// load args
int narg = b-1;
switch (narg) {
case 0: case 1: case 2: case 3:
case 0:
case 1:
case 2:
case 3:
for (int i = 1; i < b; i++)
builder.loadLocal(pc, a+i);
break;
@@ -319,10 +320,18 @@ public class JavaGen {
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;
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();

View File

@@ -25,8 +25,8 @@ import org.luaj.vm2.Prototype;
* 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.
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
******************************************************************************/
public class JavaLoader extends ClassLoader {

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,19 +78,22 @@ public class LuaJC implements Globals.Loader {
protected LuaJC() {}
public Hashtable compileAll(InputStream script, String chunkname, String filename, Globals globals, boolean genmain) throws IOException {
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 {
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 {
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);
@@ -114,7 +119,9 @@ public class LuaJC implements Globals.Loader {
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();
}

View File

@@ -84,7 +84,9 @@ public class ProtoInfo {
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 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);
}
@@ -194,8 +196,10 @@ public class ProtoInfo {
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;
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;
@@ -204,15 +208,19 @@ public class ProtoInfo {
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;
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) */
@@ -235,14 +243,16 @@ public class ProtoInfo {
b = Lua.GETARG_B(ins);
c = Lua.GETARG_C(ins);
v[b][pc].isreferenced = true;
if (!Lua.ISK(c)) v[c][pc].isreferenced = true;
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;
if (!Lua.ISK(c))
v[c][pc].isreferenced = true;
v[a][pc] = new VarInfo(a, pc);
break;
@@ -251,7 +261,8 @@ public class ProtoInfo {
b = Lua.GETARG_B(ins);
c = Lua.GETARG_C(ins);
v[b][pc].isreferenced = true;
if (!Lua.ISK(c)) v[c][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);
break;
@@ -361,8 +372,10 @@ public class ProtoInfo {
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;
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 */
@@ -434,6 +447,7 @@ public class ProtoInfo {
upvals[Lua.GETARG_B(code[pc])].rw = true;
}
}
private UpvalInfo findOpenUp(int pc, int slot) {
if (openups[slot] == null)
openups[slot] = new UpvalInfo[prototype.code.length];

View File

@@ -41,11 +41,13 @@ public class VarInfo {
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,9 +88,7 @@ public class VarInfo {
this.pi = pi;
}
public boolean isPhiVar() {
return true;
}
public boolean isPhiVar() { return true; }
public String toString() {
StringBuffer sb = new StringBuffer();

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 {
@@ -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());
@@ -233,28 +227,33 @@ 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;
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)

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();
@@ -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 }));
}
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);
}

View File

@@ -24,15 +24,18 @@ package org.luaj.vm2.server;
import java.io.InputStream;
import java.io.Reader;
/** Interface to launch lua scripts using the {@link LuajClassLoader}.
/**
* Interface to launch lua scripts using the {@link LuajClassLoader}.
* <P>
* <em>Note: This class is experimental and subject to change in future versions.</em>
* <em>Note: This class is experimental and subject to change in future
* versions.</em>
* <P>
* This interface is purposely genericized to defer class loading so that
* luaj classes can come from the class loader.
* This interface is purposely genericized to defer class loading so that luaj
* classes can come from the class loader.
* <P>
* The implementation should be acquired using {@link LuajClassLoader#NewLauncher()}
* or {@link LuajClassLoader#NewLauncher(Class)} which ensure that the classes are
* The implementation should be acquired using
* {@link LuajClassLoader#NewLauncher()} or
* {@link LuajClassLoader#NewLauncher(Class)} which ensure that the classes are
* loaded to give each Launcher instance a pristine set of Globals, including
* the shared metatables.
*
@@ -44,7 +47,8 @@ import java.io.Reader;
*/
public interface Launcher {
/** Launch a script contained in a String.
/**
* Launch a script contained in a String.
*
* @param script The script contents.
* @param arg Optional arguments supplied to the script.
@@ -52,7 +56,8 @@ public interface Launcher {
*/
public Object[] launch(String script, Object[] arg);
/** Launch a script from an InputStream.
/**
* Launch a script from an InputStream.
*
* @param script The script as an InputStream.
* @param arg Optional arguments supplied to the script.
@@ -60,7 +65,8 @@ public interface Launcher {
*/
public Object[] launch(InputStream script, Object[] arg);
/** Launch a script from a Reader.
/**
* Launch a script from a Reader.
*
* @param script The script as a Reader.
* @param arg Optional arguments supplied to the script.

View File

@@ -30,14 +30,14 @@ import java.util.Map;
* Class loader that can be used to launch a lua script in a Java VM that has a
* unique set of classes for org.luaj classes.
* <P>
* <em>Note: This class is experimental and subject to change in future versions.</em>
* <em>Note: This class is experimental and subject to change in future
* versions.</em>
* <P>
* By using a custom class loader per script, it allows the script to have
* its own set of globals, including static values such as shared metatables
* that cannot access lua values from other scripts because their classes are
* loaded from different class loaders. Thus normally unsafe libraries such
* as luajava can be exposed to scripts in a server environment using these
* techniques.
* By using a custom class loader per script, it allows the script to have its
* own set of globals, including static values such as shared metatables that
* cannot access lua values from other scripts because their classes are loaded
* from different class loaders. Thus normally unsafe libraries such as luajava
* can be exposed to scripts in a server environment using these techniques.
* <P>
* All classes in the package "org.luaj.vm2." are considered user classes, and
* loaded into this class loader from their bytes in the class path. Other
@@ -61,10 +61,14 @@ import java.util.Map;
*/
public class LuajClassLoader extends ClassLoader {
/** String describing the luaj packages to consider part of the user classes */
/**
* String describing the luaj packages to consider part of the user classes
*/
static final String luajPackageRoot = "org.luaj.vm2.";
/** String describing the Launcher interface to be considered a system class */
/**
* String describing the Launcher interface to be considered a system class
*/
static final String launcherInterfaceRoot = Launcher.class.getName();
/** Local cache of classes loaded by this loader. */
@@ -75,54 +79,52 @@ public class LuajClassLoader extends ClassLoader {
* its own {@link LuajClassLoader} using the default implementation class
* {@link DefaultLauncher}.
* <P>
* The {@link Launcher} that is returned will be a pristine luaj vm
* whose classes are loaded into this loader including static variables
* such as shared metatables, and should not be able to directly access
* variables from other Launcher instances.
* The {@link Launcher} that is returned will be a pristine luaj vm whose
* classes are loaded into this loader including static variables such as
* shared metatables, and should not be able to directly access variables
* from other Launcher instances.
*
* @return {@link Launcher} instance that can be used to launch scripts.
* @throws InstantiationException
* @throws IllegalAccessException
* @throws ClassNotFoundException
*/
public static Launcher NewLauncher() throws InstantiationException,
IllegalAccessException, ClassNotFoundException {
public static Launcher NewLauncher() throws InstantiationException, IllegalAccessException, ClassNotFoundException {
return NewLauncher(DefaultLauncher.class);
}
/**
* Construct a {@link Launcher} instance that will load classes in
* its own {@link LuajClassLoader} using a user-supplied implementation class
* that implements {@link Launcher}.
* Construct a {@link Launcher} instance that will load classes in its own
* {@link LuajClassLoader} using a user-supplied implementation class that
* implements {@link Launcher}.
* <P>
* The {@link Launcher} that is returned will be a pristine luaj vm
* whose classes are loaded into this loader including static variables
* such as shared metatables, and should not be able to directly access
* variables from other Launcher instances.
* The {@link Launcher} that is returned will be a pristine luaj vm whose
* classes are loaded into this loader including static variables such as
* shared metatables, and should not be able to directly access variables
* from other Launcher instances.
*
* @return instance of type 'launcher_class' that can be used to launch scripts.
* @return instance of type 'launcher_class' that can be used to launch
* scripts.
* @throws InstantiationException
* @throws IllegalAccessException
* @throws ClassNotFoundException
*/
public static Launcher NewLauncher(Class<? extends Launcher> launcher_class)
throws InstantiationException, IllegalAccessException,
ClassNotFoundException {
throws InstantiationException, IllegalAccessException, ClassNotFoundException {
final LuajClassLoader loader = new LuajClassLoader();
final Object instance = loader.loadAsUserClass(launcher_class.getName())
.newInstance();
final Object instance = loader.loadAsUserClass(launcher_class.getName()).newInstance();
return (Launcher) instance;
}
/**
* Test if a class name should be considered a user class and loaded
* by this loader, or a system class and loaded by the system loader.
* Test if a class name should be considered a user class and loaded by this
* loader, or a system class and loaded by the system loader.
*
* @param classname Class name to test.
* @return true if this should be loaded into this class loader.
*/
public static boolean isUserClass(String classname) {
return classname.startsWith(luajPackageRoot)
&& !classname.startsWith(launcherInterfaceRoot);
return classname.startsWith(luajPackageRoot) && !classname.startsWith(launcherInterfaceRoot);
}
public Class<?> loadClass(String classname) throws ClassNotFoundException {
@@ -143,13 +145,11 @@ public class LuajClassLoader extends ClassLoader {
for (int n = 0; (n = is.read(b)) >= 0;)
baos.write(b, 0, n);
byte[] bytes = baos.toByteArray();
Class<?> result = super.defineClass(classname, bytes, 0,
bytes.length);
Class<?> result = super.defineClass(classname, bytes, 0, bytes.length);
classes.put(classname, result);
return result;
} catch (java.io.IOException e) {
throw new ClassNotFoundException("Read failed: " + classname
+ ": " + e);
throw new ClassNotFoundException("Read failed: " + classname + ": " + e);
}
}
throw new ClassNotFoundException("Not found: " + classname);

View File

@@ -31,17 +31,9 @@ import org.luaj.vm2.lib.jse.JsePlatform;
public class TestLuaJ {
// create the script
public static String name = "script";
public static String script =
"function r(q,...)\n"+
" local a=arg\n"+
" return a and a[2]\n"+
"end\n" +
"function s(q,...)\n"+
" local a=arg\n"+
" local b=...\n"+
" return a and a[2],b\n"+
"end\n" +
"print( r(111,222,333),s(111,222,333) )";
public static String script = "function r(q,...)\n" + " local a=arg\n" + " return a and a[2]\n" + "end\n"
+ "function s(q,...)\n" + " local a=arg\n" + " local b=...\n" + " return a and a[2],b\n" + "end\n"
+ "print( r(111,222,333),s(111,222,333) )";
public static void main(String[] args) throws Exception {
System.out.println(script);

View File

@@ -87,11 +87,8 @@ public class TestLuaJC {
String key = (String) e.nextElement();
byte[] bytes = (byte[]) t.get(key);
String destpath = (destdir != null? destdir + "/": "") + key + ".class";
System.out.println(
"chunk "+filename+
" from "+filename+
" written to "+destpath
+" length="+bytes.length+" bytes");
System.out.println("chunk " + filename + " from " + filename + " written to " + destpath + " length="
+ bytes.length + " bytes");
FileOutputStream fos = new FileOutputStream(destpath);
fos.write(bytes);
fos.close();

View File

@@ -27,7 +27,6 @@ import junit.framework.TestCase;
import org.luaj.vm2.Globals.BufferedStream;
public class BufferedStreamTest extends TestCase {
public BufferedStreamTest() {}

View File

@@ -28,8 +28,8 @@ import org.luaj.vm2.luajc.LuaJC;
/**
* Compatibility tests for the Luaj VM
*
* Results are compared for exact match with
* the installed C-based lua environment.
* Results are compared for exact match with the installed C-based lua
* environment.
*/
public class CompatibiltyTest extends TestSuite {
@@ -37,6 +37,7 @@ public class CompatibiltyTest extends TestSuite {
abstract protected static class CompatibiltyTestSuite extends ScriptDrivenTest {
LuaValue savedStringMetatable;
protected CompatibiltyTestSuite(PlatformType platform) {
super(platform, dir);
}
@@ -57,23 +58,36 @@ public class CompatibiltyTest extends TestSuite {
}
public void testBaseLib() { runTest("baselib"); }
public void testCoroutineLib() { runTest("coroutinelib"); }
public void testDebugLib() { runTest("debuglib"); }
public void testErrors() { runTest("errors"); }
public void testFunctions() { runTest("functions"); }
public void testIoLib() { runTest("iolib"); }
public void testManyUpvals() { runTest("manyupvals"); }
public void testMathLib() { runTest("mathlib"); }
public void testMetatags() { runTest("metatags"); }
public void testOsLib() { runTest("oslib"); }
public void testStringLib() { runTest("stringlib"); }
public void testTableLib() { runTest("tablelib"); }
public void testTailcalls() { runTest("tailcalls"); }
public void testUpvalues() { runTest("upvalues"); }
public void testVm() { runTest("vm"); }
}
public static TestSuite suite() {
TestSuite suite = new TestSuite("Compatibility Tests");
suite.addTest(new TestSuite(JseCompatibilityTest.class, "JSE Compatibility Tests"));
@@ -86,29 +100,35 @@ public class CompatibiltyTest extends TestSuite {
public JmeCompatibilityTest() {
super(ScriptDrivenTest.PlatformType.JME);
}
protected void setUp() throws Exception {
System.setProperty("JME", "true");
super.setUp();
}
}
public static class JseCompatibilityTest extends CompatibiltyTestSuite {
public JseCompatibilityTest() {
super(ScriptDrivenTest.PlatformType.JSE);
}
protected void setUp() throws Exception {
super.setUp();
System.setProperty("JME", "false");
}
}
public static class LuaJCCompatibilityTest extends CompatibiltyTestSuite {
public LuaJCCompatibilityTest() {
super(ScriptDrivenTest.PlatformType.LUAJIT);
}
protected void setUp() throws Exception {
super.setUp();
System.setProperty("JME", "false");
LuaJC.install(globals);
}
// not supported on this platform - don't test
public void testDebugLib() {}
}

View File

@@ -24,12 +24,11 @@ package org.luaj.vm2;
import java.io.IOException;
import java.io.InputStream;
/**
* Test argument type check errors
*
* Results are compared for exact match with
* the installed C-based lua environment.
* Results are compared for exact match with the installed C-based lua
* environment.
*/
public class ErrorsTest extends ScriptDrivenTest {
@@ -51,13 +50,21 @@ public class ErrorsTest extends ScriptDrivenTest {
};
runTest("baselibargs");
}
public void testCoroutineLibArgs() { runTest("coroutinelibargs"); }
public void testDebugLibArgs() { runTest("debuglibargs"); }
public void testIoLibArgs() { runTest("iolibargs"); }
public void testMathLibArgs() { runTest("mathlibargs"); }
public void testModuleLibArgs() { runTest("modulelibargs"); }
public void testOperators() { runTest("operators"); }
public void testStringLibArgs() { runTest("stringlibargs"); }
public void testTableLibArgs() { runTest("tablelibargs"); }
}

View File

@@ -31,8 +31,8 @@ import org.luaj.vm2.lib.jse.JsePlatform;
import org.luaj.vm2.luajc.LuaJC;
/**
* Test compilation of various fragments that have
* caused problems for jit compiling during development.
* Test compilation of various fragments that have caused problems for jit
* compiling during development.
*
*/
public class FragmentsTest extends TestSuite {
@@ -43,9 +43,11 @@ public class FragmentsTest extends TestSuite {
public static class JseFragmentsTest extends FragmentsTestCase {
public JseFragmentsTest() { super(TEST_TYPE_LUAC); }
}
public static class LuaJCFragmentsTest extends FragmentsTestCase {
public LuaJCFragmentsTest() { super(TEST_TYPE_LUAJC); }
}
public static TestSuite suite() {
TestSuite suite = new TestSuite("Compiler Fragments Tests");
suite.addTest(new TestSuite(JseFragmentsTest.class, "JSE Fragments Tests"));
@@ -90,522 +92,309 @@ public class FragmentsTest extends TestSuite {
}
public void testFirstArgNilExtended() {
runFragment( LuaValue.NIL,
"function f1(a) print( 'f1:', a ) return a end\n" +
"b = f1()\n" +
"return b" );
runFragment(LuaValue.NIL, "function f1(a) print( 'f1:', a ) return a end\n" + "b = f1()\n" + "return b");
}
public void testSimpleForloop() {
runFragment(LuaValue.valueOf(77),
"for n,p in ipairs({77}) do\n"+
" print('n,p',n,p)\n"+
" return p\n"+
"end\n");
"for n,p in ipairs({77}) do\n" + " print('n,p',n,p)\n" + " return p\n" + "end\n");
}
public void testForloopParamUpvalues() {
runFragment( LuaValue.varargsOf(new LuaValue[] {
LuaValue.valueOf(77),
LuaValue.valueOf(1) } ),
"for n,p in ipairs({77}) do\n"+
" print('n,p',n,p)\n"+
" foo = function()\n"+
" return p,n\n"+
" end\n"+
" return foo()\n"+
"end\n");
runFragment(LuaValue.varargsOf(new LuaValue[] { LuaValue.valueOf(77), LuaValue.valueOf(1) }),
"for n,p in ipairs({77}) do\n" + " print('n,p',n,p)\n" + " foo = function()\n" + " return p,n\n"
+ " end\n" + " return foo()\n" + "end\n");
}
public void testArgVarargsUseBoth() {
runFragment( LuaValue.varargsOf( new LuaValue[] {
LuaValue.valueOf("a"),
LuaValue.valueOf("b"),
LuaValue.valueOf("c")}),
"function v(arg,...)\n" +
" return arg,...\n" +
"end\n" +
"return v('a','b','c')\n" );
runFragment(
LuaValue
.varargsOf(new LuaValue[] { LuaValue.valueOf("a"), LuaValue.valueOf("b"), LuaValue.valueOf("c") }),
"function v(arg,...)\n" + " return arg,...\n" + "end\n" + "return v('a','b','c')\n");
}
public void testArgParamUseNone() {
runFragment(LuaValue.valueOf("string"),
"function v(arg,...)\n" +
" return type(arg)\n" +
"end\n" +
"return v('abc')\n" );
"function v(arg,...)\n" + " return type(arg)\n" + "end\n" + "return v('abc')\n");
}
public void testSetlistVarargs() {
runFragment(LuaValue.valueOf("abc"),
"local f = function() return 'abc' end\n" +
"local g = { f() }\n" +
"return g[1]\n" );
"local f = function() return 'abc' end\n" + "local g = { f() }\n" + "return g[1]\n");
}
public void testSelfOp() {
runFragment( LuaValue.valueOf("bcd"),
"local s = 'abcde'\n"+
"return s:sub(2,4)\n" );
runFragment(LuaValue.valueOf("bcd"), "local s = 'abcde'\n" + "return s:sub(2,4)\n");
}
public void testSetListWithOffsetAndVarargs() {
runFragment( LuaValue.valueOf(1003),
"local bar = {1000, math.sqrt(9)}\n"+
"return bar[1]+bar[2]\n" );
runFragment(LuaValue.valueOf(1003), "local bar = {1000, math.sqrt(9)}\n" + "return bar[1]+bar[2]\n");
}
public void testMultiAssign() {
// arargs evaluations are all done before assignments
runFragment( LuaValue.varargsOf(new LuaValue[]{
LuaValue.valueOf(111),
LuaValue.valueOf(111),
LuaValue.valueOf(111)}),
"a,b,c = 1,10,100\n" +
"a,b,c = a+b+c, a+b+c, a+b+c\n" +
"return a,b,c\n" );
runFragment(
LuaValue
.varargsOf(new LuaValue[] { LuaValue.valueOf(111), LuaValue.valueOf(111), LuaValue.valueOf(111) }),
"a,b,c = 1,10,100\n" + "a,b,c = a+b+c, a+b+c, a+b+c\n" + "return a,b,c\n");
}
public void testUpvalues() {
runFragment(LuaValue.valueOf(999),
"local a = function(x)\n" +
" return function(y)\n" +
" return x + y\n" +
" end\n" +
"end\n" +
"local b = a(222)\n" +
"local c = b(777)\n" +
"print( 'c=', c )\n" +
"return c\n" );
"local a = function(x)\n" + " return function(y)\n" + " return x + y\n" + " end\n" + "end\n"
+ "local b = a(222)\n" + "local c = b(777)\n" + "print( 'c=', c )\n" + "return c\n");
}
public void testNonAsciiStringLiterals() {
runFragment( LuaValue.valueOf("7,8,12,10,9,11,133,222"),
"local a='\\a\\b\\f\\n\\t\\v\\133\\222'\n"+
"local t={string.byte(a,1,#a)}\n"+
"return table.concat(t,',')\n" );
runFragment(LuaValue.valueOf("7,8,12,10,9,11,133,222"), "local a='\\a\\b\\f\\n\\t\\v\\133\\222'\n"
+ "local t={string.byte(a,1,#a)}\n" + "return table.concat(t,',')\n");
}
public void testControlCharStringLiterals() {
runFragment( LuaValue.valueOf("97,0,98,18,99,18,100,18,48,101"),
"local a='a\\0b\\18c\\018d\\0180e'\n"+
"local t={string.byte(a,1,#a)}\n"+
"return table.concat(t,',')\n" );
runFragment(LuaValue.valueOf("97,0,98,18,99,18,100,18,48,101"), "local a='a\\0b\\18c\\018d\\0180e'\n"
+ "local t={string.byte(a,1,#a)}\n" + "return table.concat(t,',')\n");
}
public void testLoopVarNames() {
runFragment(LuaValue.valueOf(" 234,1,aa 234,2,bb"),
"local w = ''\n"+
"function t()\n"+
" for f,var in ipairs({'aa','bb'}) do\n"+
" local s = 234\n"+
" w = w..' '..s..','..f..','..var\n"+
" end\n"+
"end\n" +
"t()\n" +
"return w\n" );
"local w = ''\n" + "function t()\n" + " for f,var in ipairs({'aa','bb'}) do\n" + " local s = 234\n"
+ " w = w..' '..s..','..f..','..var\n" + " end\n" + "end\n" + "t()\n" + "return w\n");
}
public void testForLoops() {
runFragment(LuaValue.valueOf("12345 357 963"),
"local s,t,u = '','',''\n"+
"for m=1,5 do\n"+
" s = s..m\n"+
"end\n"+
"for m=3,7,2 do\n"+
" t = t..m\n"+
"end\n"+
"for m=9,3,-3 do\n"+
" u = u..m\n"+
"end\n"+
"return s..' '..t..' '..u\n" );
"local s,t,u = '','',''\n" + "for m=1,5 do\n" + " s = s..m\n" + "end\n" + "for m=3,7,2 do\n"
+ " t = t..m\n" + "end\n" + "for m=9,3,-3 do\n" + " u = u..m\n" + "end\n"
+ "return s..' '..t..' '..u\n");
}
public void testLocalFunctionDeclarations() {
runFragment(LuaValue.varargsOf(LuaValue.valueOf("function"), LuaValue.valueOf("nil")),
"local function aaa()\n"+
" return type(aaa)\n"+
"end\n"+
"local bbb = function()\n"+
" return type(bbb)\n"+
"end\n"+
"return aaa(),bbb()\n" );
"local function aaa()\n" + " return type(aaa)\n" + "end\n" + "local bbb = function()\n"
+ " return type(bbb)\n" + "end\n" + "return aaa(),bbb()\n");
}
public void testNilsInTableConstructor() {
runFragment(LuaValue.valueOf("1=111 2=222 3=333 "),
"local t = { 111, 222, 333, nil, nil }\n"+
"local s = ''\n"+
"for i,v in ipairs(t) do \n" +
" s=s..tostring(i)..'='..tostring(v)..' '\n" +
"end\n"+
"return s\n" );
"local t = { 111, 222, 333, nil, nil }\n" + "local s = ''\n" + "for i,v in ipairs(t) do \n"
+ " s=s..tostring(i)..'='..tostring(v)..' '\n" + "end\n" + "return s\n");
}
public void testUnreachableCode() {
runFragment(LuaValue.valueOf(66),
"local function foo(x) return x * 2 end\n" +
"local function bar(x, y)\n" +
" if x==y then\n" +
" return y\n" +
" else\n" +
" return foo(x)\n" +
" end\n" +
"end\n" +
"return bar(33,44)\n" );
"local function foo(x) return x * 2 end\n" + "local function bar(x, y)\n" + " if x==y then\n"
+ " return y\n" + " else\n" + " return foo(x)\n" + " end\n" + "end\n"
+ "return bar(33,44)\n");
}
public void testVarargsWithParameters() {
runFragment(LuaValue.valueOf(222),
"local func = function(t,...)\n"+
" return (...)\n"+
"end\n"+
"return func(111,222,333)\n" );
"local func = function(t,...)\n" + " return (...)\n" + "end\n" + "return func(111,222,333)\n");
}
public void testNoReturnValuesPlainCall() {
runFragment( LuaValue.TRUE,
"local testtable = {}\n"+
"return pcall( function() testtable[1]=2 end )\n" );
runFragment(LuaValue.TRUE, "local testtable = {}\n" + "return pcall( function() testtable[1]=2 end )\n");
}
public void testVarargsInTableConstructor() {
runFragment( LuaValue.valueOf(222),
"local function foo() return 111,222,333 end\n"+
"local t = {'a','b',c='c',foo()}\n"+
"return t[4]\n" );
runFragment(LuaValue.valueOf(222), "local function foo() return 111,222,333 end\n"
+ "local t = {'a','b',c='c',foo()}\n" + "return t[4]\n");
}
public void testVarargsInFirstArg() {
runFragment( LuaValue.valueOf(123),
"function aaa(x) return x end\n" +
"function bbb(y) return y end\n" +
"function ccc(z) return z end\n" +
"return ccc( aaa(bbb(123)), aaa(456) )\n" );
runFragment(LuaValue.valueOf(123), "function aaa(x) return x end\n" + "function bbb(y) return y end\n"
+ "function ccc(z) return z end\n" + "return ccc( aaa(bbb(123)), aaa(456) )\n");
}
public void testSetUpvalueTableInitializer() {
runFragment( LuaValue.valueOf("b"),
"local aliases = {a='b'}\n" +
"local foo = function()\n" +
" return aliases\n" +
"end\n" +
"return foo().a\n" );
runFragment(LuaValue.valueOf("b"), "local aliases = {a='b'}\n" + "local foo = function()\n"
+ " return aliases\n" + "end\n" + "return foo().a\n");
}
public void testLoadNilUpvalue() {
runFragment( LuaValue.NIL,
"tostring = function() end\n" +
"local pc \n" +
"local pcall = function(...)\n" +
" pc(...)\n" +
"end\n" +
"return NIL\n" );
runFragment(LuaValue.NIL, "tostring = function() end\n" + "local pc \n" + "local pcall = function(...)\n"
+ " pc(...)\n" + "end\n" + "return NIL\n");
}
public void testUpvalueClosure() {
runFragment( LuaValue.NIL,
"print()\n"+
"local function f2() end\n"+
"local function f3()\n"+
" return f3\n"+
"end\n" +
"return NIL\n" );
runFragment(LuaValue.NIL, "print()\n" + "local function f2() end\n" + "local function f3()\n"
+ " return f3\n" + "end\n" + "return NIL\n");
}
public void testUninitializedUpvalue() {
runFragment( LuaValue.NIL,
"local f\n"+
"do\n"+
" function g()\n"+
" print(f())\n"+
" end\n"+
"end\n" +
"return NIL\n" );
runFragment(LuaValue.NIL, "local f\n" + "do\n" + " function g()\n" + " print(f())\n" + " end\n"
+ "end\n" + "return NIL\n");
}
public void testTestOpUpvalues() {
runFragment(LuaValue.varargsOf(LuaValue.valueOf(1), LuaValue.valueOf(2), LuaValue.valueOf(3)),
"print( nil and 'T' or 'F' )\n"+
"local a,b,c = 1,2,3\n"+
"function foo()\n"+
" return a,b,c\n"+
"end\n" +
"return foo()\n" );
"print( nil and 'T' or 'F' )\n" + "local a,b,c = 1,2,3\n" + "function foo()\n" + " return a,b,c\n"
+ "end\n" + "return foo()\n");
}
public void testTestSimpleBinops() {
runFragment( LuaValue.varargsOf(new LuaValue[] {
LuaValue.FALSE, LuaValue.FALSE, LuaValue.TRUE, LuaValue.TRUE, LuaValue.FALSE }),
"local a,b,c = 2,-2.5,0\n" +
"return (a==c), (b==c), (a==a), (a>c), (b>0)\n" );
runFragment(
LuaValue.varargsOf(
new LuaValue[] { LuaValue.FALSE, LuaValue.FALSE, LuaValue.TRUE, LuaValue.TRUE, LuaValue.FALSE }),
"local a,b,c = 2,-2.5,0\n" + "return (a==c), (b==c), (a==a), (a>c), (b>0)\n");
}
public void testNumericForUpvalues() {
runFragment( LuaValue.valueOf(8),
"for i = 3,4 do\n"+
" i = i + 5\n"+
" local a = function()\n"+
" return i\n"+
" end\n" +
" return a()\n"+
"end\n");
runFragment(LuaValue.valueOf(8), "for i = 3,4 do\n" + " i = i + 5\n" + " local a = function()\n"
+ " return i\n" + " end\n" + " return a()\n" + "end\n");
}
public void testNumericForUpvalues2() {
runFragment(LuaValue.valueOf("222 222"),
"local t = {}\n"+
"local template = [[123 456]]\n"+
"for i = 1,2 do\n"+
" t[i] = template:gsub('%d', function(s)\n"+
" return i\n"+
" end)\n"+
"end\n" +
"return t[2]\n");
"local t = {}\n" + "local template = [[123 456]]\n" + "for i = 1,2 do\n"
+ " t[i] = template:gsub('%d', function(s)\n" + " return i\n" + " end)\n" + "end\n"
+ "return t[2]\n");
}
public void testReturnUpvalue() {
runFragment( LuaValue.varargsOf(new LuaValue[] { LuaValue.ONE, LuaValue.valueOf(5), }),
"local a = 1\n"+
"local b\n"+
"function c()\n"+
" b=5\n" +
" return a\n"+
"end\n"+
"return c(),b\n" );
runFragment(LuaValue.varargsOf(new LuaValue[] { LuaValue.ONE, LuaValue.valueOf(5), }), "local a = 1\n"
+ "local b\n" + "function c()\n" + " b=5\n" + " return a\n" + "end\n" + "return c(),b\n");
}
public void testUninitializedAroundBranch() {
runFragment(LuaValue.valueOf(333),
"local state\n"+
"if _G then\n"+
" state = 333\n"+
"end\n"+
"return state\n" );
"local state\n" + "if _G then\n" + " state = 333\n" + "end\n" + "return state\n");
}
public void testLoadedNilUpvalue() {
runFragment( LuaValue.NIL,
"local a = print()\n"+
"local b = c and { d = e }\n"+
"local f\n"+
"local function g()\n"+
" return f\n"+
"end\n" +
"return g()\n" );
runFragment(LuaValue.NIL, "local a = print()\n" + "local b = c and { d = e }\n" + "local f\n"
+ "local function g()\n" + " return f\n" + "end\n" + "return g()\n");
}
public void testUpvalueInFirstSlot() {
runFragment( LuaValue.valueOf("foo"),
"local p = {'foo'}\n"+
"bar = function()\n"+
" return p \n"+
"end\n"+
"for i,key in ipairs(p) do\n"+
" print()\n"+
"end\n" +
"return bar()[1]");
runFragment(LuaValue.valueOf("foo"), "local p = {'foo'}\n" + "bar = function()\n" + " return p \n"
+ "end\n" + "for i,key in ipairs(p) do\n" + " print()\n" + "end\n" + "return bar()[1]");
}
public void testReadOnlyAndReadWriteUpvalues() {
runFragment(LuaValue.varargsOf(new LuaValue[] { LuaValue.valueOf(333), LuaValue.valueOf(222) }),
"local a = 111\n" +
"local b = 222\n" +
"local c = function()\n"+
" a = a + b\n" +
" return a,b\n"+
"end\n" +
"return c()\n" );
"local a = 111\n" + "local b = 222\n" + "local c = function()\n" + " a = a + b\n"
+ " return a,b\n" + "end\n" + "return c()\n");
}
public void testNestedUpvalues() {
runFragment( LuaValue.varargsOf( new LuaValue[] { LuaValue.valueOf(5), LuaValue.valueOf(8), LuaValue.valueOf(9) } ),
"local x = 3\n"+
"local y = 5\n"+
"local function f()\n"+
" return y\n"+
"end\n"+
"local function g(x1, y1)\n"+
" x = x1\n"+
" y = y1\n" +
" return x,y\n"+
"end\n"+
"return f(), g(8,9)\n"+
"\n" );
runFragment(
LuaValue.varargsOf(new LuaValue[] { LuaValue.valueOf(5), LuaValue.valueOf(8), LuaValue.valueOf(9) }),
"local x = 3\n" + "local y = 5\n" + "local function f()\n" + " return y\n" + "end\n"
+ "local function g(x1, y1)\n" + " x = x1\n" + " y = y1\n" + " return x,y\n" + "end\n"
+ "return f(), g(8,9)\n" + "\n");
}
public void testLoadBool() {
runFragment( LuaValue.NONE,
"print( type(foo)=='string' )\n"+
"local a,b\n"+
"if print() then\n"+
" b = function()\n"+
" return a\n"+
" end\n"+
"end\n" );
runFragment(LuaValue.NONE, "print( type(foo)=='string' )\n" + "local a,b\n" + "if print() then\n"
+ " b = function()\n" + " return a\n" + " end\n" + "end\n");
}
public void testBasicForLoop() {
runFragment( LuaValue.valueOf(2),
"local data\n"+
"for i = 1, 2 do\n"+
" data = i\n"+
"end\n"+
"local bar = function()\n"+
" return data\n"+
"end\n" +
"return bar()\n" );
runFragment(LuaValue.valueOf(2), "local data\n" + "for i = 1, 2 do\n" + " data = i\n" + "end\n"
+ "local bar = function()\n" + " return data\n" + "end\n" + "return bar()\n");
}
public void testGenericForMultipleValues() {
runFragment(LuaValue.varargsOf(LuaValue.valueOf(3), LuaValue.valueOf(2), LuaValue.valueOf(1)),
"local iter = function() return 1,2,3,4 end\n" +
"local foo = function() return iter,5 end\n" +
"for a,b,c in foo() do\n" +
" return c,b,a\n" +
"end\n" );
"local iter = function() return 1,2,3,4 end\n" + "local foo = function() return iter,5 end\n"
+ "for a,b,c in foo() do\n" + " return c,b,a\n" + "end\n");
}
public void testPhiUpvalue() {
runFragment( LuaValue.valueOf(6),
"local a = foo or 0\n"+
"local function b(c)\n"+
" if c > a then a = c end\n" +
" return a\n"+
"end\n" +
"b(6)\n" +
"return a\n" );
runFragment(LuaValue.valueOf(6), "local a = foo or 0\n" + "local function b(c)\n"
+ " if c > a then a = c end\n" + " return a\n" + "end\n" + "b(6)\n" + "return a\n");
}
public void testAssignReferUpvalues() {
runFragment( LuaValue.valueOf(123),
"local entity = 234\n" +
"local function c()\n" +
" return entity\n" +
"end\n" +
"entity = (a == b) and 123\n" +
"if entity then\n" +
" return entity\n" +
"end\n" );
runFragment(LuaValue.valueOf(123), "local entity = 234\n" + "local function c()\n" + " return entity\n"
+ "end\n" + "entity = (a == b) and 123\n" + "if entity then\n" + " return entity\n" + "end\n");
}
public void testSimpleRepeatUntil() {
runFragment(LuaValue.valueOf(5),
"local a\n"+
"local w\n"+
"repeat\n"+
" a = w\n"+
"until not a\n" +
"return 5\n" );
"local a\n" + "local w\n" + "repeat\n" + " a = w\n" + "until not a\n" + "return 5\n");
}
public void testLoopVarUpvalues() {
runFragment(LuaValue.valueOf("b"),
"local env = {}\n" +
"for a,b in pairs(_G) do\n" +
" c = function()\n" +
" return b\n" +
" end\n" +
"end\n" +
"local e = env\n" +
"local f = {a='b'}\n" +
"for k,v in pairs(f) do\n" +
" return env[k] or v\n" +
"end\n");
"local env = {}\n" + "for a,b in pairs(_G) do\n" + " c = function()\n" + " return b\n"
+ " end\n" + "end\n" + "local e = env\n" + "local f = {a='b'}\n" + "for k,v in pairs(f) do\n"
+ " return env[k] or v\n" + "end\n");
}
public void testPhiVarUpvalue() {
runFragment( LuaValue.valueOf(2),
"local a = 1\n"+
"local function b()\n"+
" a = a + 1\n"+
" return function() end\n"+
"end\n"+
"for i in b() do\n"+
" a = 3\n"+
"end\n" +
"return a\n");
runFragment(LuaValue.valueOf(2), "local a = 1\n" + "local function b()\n" + " a = a + 1\n"
+ " return function() end\n" + "end\n" + "for i in b() do\n" + " a = 3\n" + "end\n" + "return a\n");
}
public void testUpvaluesInElseClauses() {
runFragment(LuaValue.valueOf(111),
"if a then\n" +
" foo(bar)\n" +
"elseif _G then\n" +
" local x = 111\n" +
" if d then\n" +
" foo(bar)\n" +
" else\n" +
" local y = function()\n" +
" return x\n" +
" end\n" +
" return y()\n" +
" end\n" +
"end\n");
"if a then\n" + " foo(bar)\n" + "elseif _G then\n" + " local x = 111\n" + " if d then\n"
+ " foo(bar)\n" + " else\n" + " local y = function()\n" + " return x\n"
+ " end\n" + " return y()\n" + " end\n" + "end\n");
}
public void testUpvalueInDoBlock() {
runFragment( LuaValue.NONE, "do\n"+
" local x = 10\n"+
" function g()\n"+
" return x\n"+
" end\n"+
"end\n"+
"g()\n");
runFragment(LuaValue.NONE,
"do\n" + " local x = 10\n" + " function g()\n" + " return x\n" + " end\n" + "end\n" + "g()\n");
}
public void testNullError() {
runFragment( LuaValue.varargsOf(LuaValue.FALSE, LuaValue.NIL),
"return pcall(error)\n");
runFragment(LuaValue.varargsOf(LuaValue.FALSE, LuaValue.NIL), "return pcall(error)\n");
}
public void testFindWithOffset() {
runFragment(LuaValue.varargsOf(LuaValue.valueOf(8), LuaValue.valueOf(5)),
"string = \"abcdef:ghi\"\n" +
"substring = string:sub(3)\n" +
"idx = substring:find(\":\")\n" +
"return #substring, idx\n");
runFragment(LuaValue.varargsOf(LuaValue.valueOf(8), LuaValue.valueOf(5)), "string = \"abcdef:ghi\"\n"
+ "substring = string:sub(3)\n" + "idx = substring:find(\":\")\n" + "return #substring, idx\n");
}
public void testErrorArgIsString() {
runFragment(LuaValue.varargsOf(LuaValue.valueOf("string"), LuaValue.valueOf("c")),
"a,b = pcall(error, 'c'); return type(b), b\n");
}
public void testErrorArgIsNil() {
runFragment(LuaValue.varargsOf(LuaValue.valueOf("nil"), LuaValue.NIL),
"a,b = pcall(error); return type(b), b\n");
}
public void testErrorArgIsTable() {
runFragment(LuaValue.varargsOf(LuaValue.valueOf("table"), LuaValue.valueOf("d")),
"a,b = pcall(error, {c='d'}); return type(b), b.c\n");
}
public void testErrorArgIsNumber() {
runFragment(LuaValue.varargsOf(LuaValue.valueOf("string"), LuaValue.valueOf("1")),
"a,b = pcall(error, 1); return type(b), b\n");
}
public void testErrorArgIsBool() {
runFragment(LuaValue.varargsOf(LuaValue.valueOf("boolean"), LuaValue.TRUE),
"a,b = pcall(error, true); return type(b), b\n");
}
public void testBalancedMatchOnEmptyString() {
runFragment(LuaValue.NIL, "return (\"\"):match(\"%b''\")\n");
}
public void testReturnValueForTableRemove() {
runFragment(LuaValue.NONE, "return table.remove({ })");
}
public void testTypeOfTableRemoveReturnValue() {
runFragment(LuaValue.valueOf("nil"), "local k = table.remove({ }) return type(k)");
}
public void testVarargBugReport() {
runFragment(LuaValue.varargsOf(new LuaValue[] {
LuaValue.valueOf(1), LuaValue.valueOf(2), LuaValue.valueOf(3) }),
"local i = function(...) return ... end\n"
+ "local v1, v2, v3 = i(1, 2, 3)\n"
+ "return v1, v2, v3");
runFragment(
LuaValue.varargsOf(new LuaValue[] { LuaValue.valueOf(1), LuaValue.valueOf(2), LuaValue.valueOf(3) }),
"local i = function(...) return ... end\n" + "local v1, v2, v3 = i(1, 2, 3)\n" + "return v1, v2, v3");
}
}

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