[NOTHING CHANGED] Assorted fixes #48

Closed
asiekierka wants to merge 61 commits from asiekierka/master into master
413 changed files with 51328 additions and 22440 deletions

View File

@@ -1,19 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" path="src/core"/>
<classpathentry excluding="org/luaj/vm2/luajc/antlr/|org/luaj/vm2/luajc/lst/|org/luaj/vm2/luajc/JavaCodeGenerator.java" kind="src" path="src/jse"/>
<classpathentry kind="src" path="src/jme"/>
<classpathentry kind="src" path="test/java"/>
<classpathentry kind="src" path="test/junit"/>
<classpathentry kind="src" path="test/lua"/>
<classpathentry kind="src" path="examples/jse"/>
<classpathentry kind="src" path="examples/jme"/>
<classpathentry kind="src" path="examples/lua"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
<classpathentry kind="con" path="org.eclipse.jdt.junit.JUNIT_CONTAINER/3"/>
<classpathentry kind="lib" path="lib/midpapi20.jar"/>
<classpathentry kind="lib" path="lib/cldcapi11.jar"/>
<classpathentry kind="lib" path="lib/bcel-5.2.jar"/>
<classpathentry kind="var" path="JRE_LIB"/>
<classpathentry kind="output" path="bin"/>
</classpath>

17
.gitignore vendored
View File

@@ -1,15 +1,4 @@
bin/
target/ target/
build/ .classpath
lib/ .project
jit/ .settings/
*.ser
*.gz
*.jar
*.lua
*.out
*.tar
*.txt
*.zip
docs
*.0

138
.ide/cleanup.xml Normal file
View File

@@ -0,0 +1,138 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<profiles version="2">
<profile kind="CleanUpProfile" name="Default" version="2">
<setting id="cleanup.array_with_curly" value="true"/>
<setting id="cleanup.use_autoboxing" value="true"/>
<setting id="cleanup.always_use_this_for_non_static_method_access" value="false"/>
<setting id="cleanup.remove_trailing_whitespaces_ignore_empty" value="false"/>
<setting id="cleanup.primitive_comparison" value="false"/>
<setting id="cleanup.system_property_file_encoding" value="true"/>
<setting id="cleanup.format_source_code_changes_only" value="false"/>
<setting id="cleanup.remove_redundant_semicolons" value="true"/>
<setting id="cleanup.qualify_static_member_accesses_through_subtypes_with_declaring_class" value="true"/>
<setting id="cleanup.useless_continue" value="true"/>
<setting id="cleanup.remove_redundant_type_arguments" value="true"/>
<setting id="cleanup.remove_unused_imports" value="true"/>
<setting id="cleanup.break_loop" value="false"/>
<setting id="cleanup.pull_up_assignment" value="false"/>
<setting id="cleanup.stringbuilder" value="false"/>
<setting id="cleanup.no_super" value="true"/>
<setting id="cleanup.arrays_fill" value="false"/>
<setting id="cleanup.use_lambda" value="true"/>
<setting id="cleanup.operand_factorization" value="false"/>
<setting id="cleanup.simplify_lambda_expression_and_method_ref" value="true"/>
<setting id="cleanup.always_use_blocks" value="true"/>
<setting id="cleanup.sort_members_all" value="false"/>
<setting id="cleanup.system_property_path_separator" value="true"/>
<setting id="cleanup.instanceof" value="false"/>
<setting id="cleanup.add_missing_annotations" value="true"/>
<setting id="cleanup.precompile_regex" value="false"/>
<setting id="cleanup.always_use_this_for_non_static_field_access" value="false"/>
<setting id="cleanup.boolean_literal" value="true"/>
<setting id="cleanup.always_use_parentheses_in_expressions" value="false"/>
<setting id="cleanup.sort_members" value="false"/>
<setting id="cleanup.remove_unused_local_variables" value="false"/>
<setting id="cleanup.add_missing_deprecated_annotations" value="true"/>
<setting id="cleanup.no_string_creation" value="true"/>
<setting id="cleanup.use_unboxing" value="false"/>
<setting id="cleanup.use_blocks_only_for_return_and_throw" value="false"/>
<setting id="cleanup.standard_comparison" value="false"/>
<setting id="cleanup.if_condition" value="true"/>
<setting id="cleanup.system_property_line_separator" value="true"/>
<setting id="cleanup.remove_trailing_whitespaces" value="true"/>
<setting id="cleanup.map_cloning" value="true"/>
<setting id="cleanup.add_serial_version_id" value="false"/>
<setting id="cleanup.try_with_resource" value="true"/>
<setting id="cleanup.use_this_for_non_static_method_access" value="false"/>
<setting id="cleanup.use_this_for_non_static_method_access_only_if_necessary" value="true"/>
<setting id="cleanup.single_used_field" value="false"/>
<setting id="cleanup.reduce_indentation" value="false"/>
<setting id="cleanup.primitive_parsing" value="false"/>
<setting id="cleanup.make_local_variable_final" value="false"/>
<setting id="cleanup.add_missing_methods" value="false"/>
<setting id="cleanup.qualify_static_member_accesses_with_declaring_class" value="true"/>
<setting id="cleanup.add_missing_override_annotations" value="true"/>
<setting id="cleanup.use_blocks" value="false"/>
<setting id="cleanup.multi_catch" value="true"/>
<setting id="cleanup.pull_out_if_from_if_else" value="true"/>
<setting id="cleanup.collection_cloning" value="true"/>
<setting id="cleanup.convert_to_enhanced_for_loop_if_loop_var_used" value="true"/>
<setting id="cleanup.make_variable_declarations_final" value="true"/>
<setting id="cleanup.redundant_comparator" value="false"/>
<setting id="cleanup.remove_unused_private_types" value="true"/>
<setting id="cleanup.system_property_boolean" value="true"/>
<setting id="cleanup.qualify_static_method_accesses_with_declaring_class" value="false"/>
<setting id="cleanup.organize_imports" value="true"/>
<setting id="cleanup.lazy_logical_operator" value="true"/>
<setting id="cleanup.bitwise_conditional_expression" value="false"/>
<setting id="cleanup.use_directly_map_method" value="false"/>
<setting id="cleanup.add_all" value="false"/>
<setting id="cleanup.system_property_file_separator" value="true"/>
<setting id="cleanup.qualify_static_field_accesses_with_declaring_class" value="false"/>
<setting id="cleanup.add_generated_serial_version_id" value="false"/>
<setting id="cleanup.controlflow_merge" value="false"/>
<setting id="cleanup.primitive_serialization" value="false"/>
<setting id="cleanup.comparing_on_criteria" value="true"/>
<setting id="cleanup.comparison_statement" value="true"/>
<setting id="cleanup.extract_increment" value="false"/>
<setting id="cleanup.insert_inferred_type_arguments" value="false"/>
<setting id="cleanup.make_private_fields_final" value="true"/>
<setting id="cleanup.useless_return" value="true"/>
<setting id="cleanup.instanceof_keyword" value="true"/>
<setting id="cleanup.use_this_for_non_static_field_access_only_if_necessary" value="true"/>
<setting id="cleanup.remove_trailing_whitespaces_all" value="true"/>
<setting id="cleanup.one_if_rather_than_duplicate_blocks_that_fall_through" value="true"/>
<setting id="cleanup.valueof_rather_than_instantiation" value="true"/>
<setting id="cleanup.plain_replacement" value="false"/>
<setting id="cleanup.remove_unnecessary_array_creation" value="true"/>
<setting id="cleanup.remove_private_constructors" value="true"/>
<setting id="cleanup.make_parameters_final" value="false"/>
<setting id="cleanup.substring" value="false"/>
<setting id="cleanup.ternary_operator" value="false"/>
<setting id="cleanup.merge_conditional_blocks" value="false"/>
<setting id="cleanup.return_expression" value="true"/>
<setting id="cleanup.system_property" value="true"/>
<setting id="cleanup.unlooped_while" value="true"/>
<setting id="cleanup.convert_to_enhanced_for_loop" value="true"/>
<setting id="cleanup.remove_unused_private_fields" value="true"/>
<setting id="cleanup.never_use_blocks" value="false"/>
<setting id="cleanup.remove_redundant_modifiers" value="true"/>
<setting id="cleanup.unreachable_block" value="false"/>
<setting id="cleanup.redundant_falling_through_block_end" value="false"/>
<setting id="cleanup.switch" value="false"/>
<setting id="cleanup.number_suffix" value="true"/>
<setting id="cleanup.remove_unnecessary_nls_tags" value="true"/>
<setting id="cleanup.convert_to_switch_expressions" value="false"/>
<setting id="cleanup.use_this_for_non_static_field_access" value="false"/>
<setting id="cleanup.static_inner_class" value="false"/>
<setting id="cleanup.use_string_is_blank" value="true"/>
<setting id="cleanup.add_missing_nls_tags" value="false"/>
<setting id="cleanup.qualify_static_member_accesses_through_instances_with_declaring_class" value="true"/>
<setting id="cleanup.remove_unnecessary_casts" value="true"/>
<setting id="cleanup.objects_equals" value="false"/>
<setting id="cleanup.convert_functional_interfaces" value="true"/>
<setting id="cleanup.format_source_code" value="true"/>
<setting id="cleanup.else_if" value="false"/>
<setting id="cleanup.boolean_value_rather_than_comparison" value="true"/>
<setting id="cleanup.add_default_serial_version_id" value="true"/>
<setting id="cleanup.remove_unused_private_methods" value="true"/>
<setting id="cleanup.make_type_abstract_if_missing_method" value="false"/>
<setting id="cleanup.join" value="false"/>
<setting id="cleanup.embedded_if" value="false"/>
<setting id="cleanup.use_anonymous_class_creation" value="false"/>
<setting id="cleanup.invert_equals" value="false"/>
<setting id="cleanup.add_missing_override_annotations_interface_methods" value="true"/>
<setting id="cleanup.remove_unused_private_members" value="false"/>
<setting id="cleanup.strictly_equal_or_different" value="true"/>
<setting id="cleanup.never_use_parentheses_in_expressions" value="true"/>
<setting id="cleanup.push_down_negation" value="false"/>
<setting id="cleanup.evaluate_nullable" value="false"/>
<setting id="cleanup.use_parentheses_in_expressions" value="true"/>
<setting id="cleanup.hash" value="false"/>
<setting id="cleanup.double_negation" value="true"/>
<setting id="cleanup.overridden_assignment" value="true"/>
<setting id="cleanup.primitive_rather_than_wrapper" value="true"/>
<setting id="cleanup.correct_indentation" value="false"/>
<setting id="cleanup.use_var" value="false"/>
</profile>
</profiles>

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

@@ -1,17 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>luaj-vm</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.jdt.core.javanature</nature>
</natures>
</projectDescription>

View File

@@ -858,37 +858,30 @@ An example skelton maven pom file for a skeleton project is in
<h2>Building the jars</h2> <h2>Building the jars</h2>
An ant file is included in the root directory which builds the libraries by default. Build the jars with maven.
<pre>
mvn clean verify
</pre>
<p> <p>
Other targets exist for creating distribution file an measuring code coverage of unit tests.
<h2>Unit tests</h2> <h2>Unit tests</h2>
<p> <p>
The main luaj JUnit tests are organized into a JUnit 3 suite: All unit tests are executed during the build.
<pre>
test/junit/org/luaj/vm2/AllTests.lua
</pre>
<p> <p>
Unit test scripts can be found in these locations Test scripts can be found in these locations
<pre> <pre>
test/lua/*.lua luaj-test/src/test/resources
test/lua/errors/*.lua
test/lua/perf/*.lua
test/lua/luaj3.0.2-tests.zip
</pre> </pre>
Executon is included in the build of luaj-test.
<h2>Code coverage</h2> <h2>Code coverage</h2>
<p> <p>
A build script for running unit tests and producing code coverage statistics is in The maven build creates the coverage report in the luaj-test/target/site folder
<pre> during the verify phase.
<a href="build-coverage.xml">build-coverage.xml</a>
</pre>
It relies on the cobertura code coverage library.
<h1>8 - <a name="8">Downloads</a></h1> <h1>8 - <a name="8">Downloads</a></h1>

View File

@@ -1,108 +0,0 @@
<!-- And build script to compile lua scripts into runnable jar files using the "luajc"
lua to java bytecode compiler.
Each source file is converted into a runnable jar file that takes arguments from the command line.
For example, the program test/lua/perf/binarytrees.lua is converted to a jar that can be run with
java -jar binarytrees.jar 15
-->
<project default="all">
<import file="build.xml"/>
<import file="build-libs.xml"/>
<available file="luaj-jse-${version}.jar" property="luaj.lib.exists"/>
<!-- this may need to be changed when building on mac -->
<property name="rt.jar" value="${java.home}/lib/rt.jar"/>
<target name="luaj-lib" unless="luaj.lib.exists">
<antcall target="jar-jse"/>
</target>
<macrodef name="perftest">
<attribute name="cmd"/>
<sequential>
<echo level="info">------ @{cmd}</echo>
<exec executable="bash">
<arg value="-c"/>
<arg value="time @{cmd}"/>
</exec>
</sequential>
</macrodef>
<macrodef name="buildappjar">
<attribute name="luaprog"/>
<attribute name="arg" default=""/>
<attribute name="srcdir" default="test/lua/perf"/>
<sequential>
<echo level="info">=========== @{srcdir}/@{luaprog} =============</echo>
<delete dir="build/@{luaprog}"/>
<mkdir dir="build/@{luaprog}/class"/>
<java classname="luajc">
<classpath>
<pathelement path="luaj-jse-${version}.jar"/>
<pathelement path="lib/bcel-5.2.jar"/>
</classpath>
<arg value="-s"/>
<arg path="@{srcdir}"/>
<arg value="-d"/>
<arg path="build/@{luaprog}/class"/>
<arg value="-m"/>
<arg value="-v"/>
<arg value="@{luaprog}.lua"/>
</java>
<jar destfile="build/@{luaprog}.jar">
<fileset dir="build/@{luaprog}/class"/>
<zipfileset includes="org/luaj/vm2/*.class,org/luaj/vm2/lib/*.class,org/luaj/vm2/lib/jse/*.class,org/luaj/vm2/compiler/*.class" src="luaj-jse-${version}.jar" />
<manifest>
<attribute name="Main-Class" value="@{luaprog}" />
</manifest>
</jar>
<unjar src="build/@{luaprog}.jar" dest="build/@{luaprog}/unjarred"/>
<perftest cmd="java -jar build/@{luaprog}.jar @{arg}"/>
<!-- The following can be adapted to produce an optimized jar.
<taskdef resource="proguard/ant/task.properties" classpath="lib/proguard.jar" />
<proguard>
-injars build/@{luaprog}.jar
-outjars build/@{luaprog}-opt.jar
-libraryjars ${rt.jar}
-overloadaggressively
-repackageclasses ''
-allowaccessmodification
-printmapping build/@{luaprog}.map
-keep public class @{luaprog} {
public static void main(java.lang.String[]);
}
</proguard>
<unjar src="build/@{luaprog}-opt.jar" dest="build/@{luaprog}/unjarred-opt"/>
<perftest cmd="java -jar build/@{luaprog}-opt.jar @{arg}"/>
-->
</sequential>
</macrodef>
<target name="binarytrees" depends="luaj-lib,proguard-lib">
<buildappjar luaprog="binarytrees" arg="15"/>
</target>
<target name="fannkuch" depends="luaj-lib,proguard-lib">
<buildappjar luaprog="fannkuch" arg="10"/>
</target>
<target name="nbody" depends="luaj-lib,proguard-lib">
<buildappjar luaprog="nbody" arg="1000000"/>
</target>
<target name="nsieve" depends="luaj-lib,proguard-lib">
<buildappjar luaprog="nsieve" arg="8"/>
</target>
<target name="swingapp" depends="luaj-lib,proguard-lib">
<buildappjar luaprog="swingapp" srcdir="examples/lua"/>
</target>
<target name="allappjars" depends="binarytrees,fannkuch,nbody,nsieve,swingapp"/>
<target name="all" depends="allappjars"/>
</project>

View File

@@ -1,116 +0,0 @@
<?xml version="1.0"?>
<project name="sample" default="main" basedir=".">
<property file="version.properties"/>
<!-- find libs -->
<import file="build-libs.xml"/>
<!-- main java class -->
<property name="java.dir" value="examples/jse"/>
<property name="java.name" value="SampleApplet"/>
<!-- main script -->
<property name="script.dir" value="examples/lua"/>
<property name="script.name" value="swingapplet"/>
<property name="image.name" value="logo.gif"/>
<!-- location of luaj jar -->
<property name="libs.dir" value="lib"/>
<property name="luaj.jar" value="${libs.dir}/luaj-jse-${version}.jar"/>
<!-- location of build results -->
<property name="build.dir" value="build/applet"/>
<target name="clean">
<delete failonerror="false" dir="${build.dir}"/>
</target>
<target name="dirs">
<mkdir dir="build/applet/classes"/>
</target>
<target name="classes" depends="dirs">
<copy todir="${build.dir}">
<fileset dir="${script.dir}" includes="${script.name}.lua,${image.name}"/>
</copy>
<javac destdir="${build.dir}/classes" source="1.4" target="1.4"
classpath="${luaj.jar}" srcdir="${java.dir}" includes="${java.name}.java"/>
</target>
<target name="manifest" depends="dirs">
<manifest file="${build.dir}/MANIFEST.MF">
<attribute name="Permissions" value="sandbox"/>
<attribute name="Main-class" value="${java.name}"/>
</manifest>
</target>
<target name="jar" depends="classes,manifest">
<jar destfile="${build.dir}/${script.name}.jar"
manifest="${build.dir}/MANIFEST.MF">
<fileset dir="${build.dir}" includes="*.lua"/>
<fileset dir="${build.dir}/classes"/>
<zipfileset
src="${luaj.jar}"
excludes="**/script/*,**/luajc/**,**/parser/**,**/ast/**,lua*"/>
</jar>
</target>
<target name="obf" depends="jar,proguard-lib">
<taskdef resource="proguard/ant/task.properties" classpath="lib/proguard.jar" />
<copy file="${build.dir}/${script.name}.jar"
tofile="${build.dir}/${script.name}-unobfuscated.jar"/>
<proguard>
-injars ${build.dir}/${script.name}-unobfuscated.jar
-outjars ${build.dir}/${script.name}.jar
-libraryjars ${java.home}/lib/rt.jar
-overloadaggressively
-repackageclasses ''
-allowaccessmodification
-printmapping ${build.dir}/mapping.txt
-keep public class * extends java.applet.Applet
-target 1.4
</proguard>
</target>
<target name="sign" depends="obf">
<signjar jar="${build.dir}/${script.name}.jar"
alias="${sign.alias}"
storepass="${sign.storepass}"
keypass="${sign.keypass}"
keystore="${sign.keystore}" />
</target>
<target name="html" depends="dirs">
<echoxml file="build/applet/LuajSampleApplet.html">
<html>
<head><title>Luaj Sample Applet</title></head>
<body>
<h1>Luaj Sample Applet</h1>
Requires browser that supports applets.
${script.name}
<applet archive='${script.name}.jar'
code='${java.name}.class'
width='800'
height='640' >
<param name='luaj.script' value='${script.name}.lua'/>
<param name="java_version" value="1.4+"/>
</applet>
</body>
</html>
</echoxml>
</target>
<target name="run" depends="jar,html">
<exec executable="open" spawn="true">
<arg value="-a Firefox"/>
<arg path="build/applet/LuajSampleApplet.html"/>
</exec>
</target>
<target name="all" depends="clean,sign,html,run"/>
<target name="main" depends="sign,html"/>
</project>

View File

@@ -1,119 +0,0 @@
<project default="all" xmlns:artifact="antlib:org.apache.maven.artifact.ant">
<!--
Run code coverage for unit tests on the luaj vm and libraries.
-->
<property name="classes.dir" value="build/classes-debug" />
<property name="instrumented.dir" value="build/instrumented" />
<property name="reports.xml.dir" value="build/reports-junit-xml" />
<property name="reports.html.dir" value="build/reports-junit-html" />
<property name="coverage.xml.dir" value="build/reports-coverage-xml" />
<property name="coverage.html.dir" value="build/reports-coverage-html" />
<property name="cobertura.serfile" value="cobertura.ser" />
<property name="cobertura.logfile" value="cobertura.log" />
<artifact:dependencies filesetId="cobutura.fileset">
<dependency groupId="net.sourceforge.cobertura" artifactId="cobertura" version="1.9.4.1"/>
<dependency groupId="junit" artifactId="junit" version="3.8.1"/>
</artifact:dependencies>
<path id="cobertura.classpath">
<fileset refid="cobutura.fileset" />
</path>
<taskdef classpathref="cobertura.classpath" resource="tasks.properties" />
<import file="wtk.xml"/>
<property environment="env"/>
<target name="clean" description="Remove all files created by the build/test process.">
<delete dir="${classes.dir}" failonerror="yes"/>
<delete dir="${instrumented.dir}" failonerror="yes"/>
<delete file="${cobertura.logfile}" />
<delete file="${cobertura.serfile}" />
</target>
<target name="init">
<ant antfile="build.xml" target="bcel-lib"/>
<ant antfile="build.xml" target="luaj1-lib"/>
<mkdir dir="${classes.dir}" />
<mkdir dir="${instrumented.dir}" />
<mkdir dir="${reports.xml.dir}" />
<mkdir dir="${reports.html.dir}" />
<mkdir dir="${coverage.xml.dir}" />
<mkdir dir="${coverage.html.dir}" />
</target>
<target name="compile" depends="init,wtk-or-fail">
<javac destdir="${classes.dir}" debug="yes" target="1.5">
<classpath refid="cobertura.classpath" />
<classpath refid="wtk-libs" />
<classpath path="lib/bcel-5.2.jar" />
<src path="src/core"/>
<src path="src/jme"/>
<src path="src/jse"/>
<src path="test/junit"/>
</javac>
</target>
<target name="instrument" depends="compile">
<delete file="${cobertura.serfile}"/>
<delete dir="${instrumented.dir}" failonerror="no"/>
<cobertura-instrument datafile="${cobertura.serfile}" todir="${instrumented.dir}">
<fileset dir="${classes.dir}">
<include name="org/luaj/vm2/*.class" />
<include name="org/luaj/vm2/lib/*.class" />
<include name="org/luaj/vm2/lib/jse/*.class" />
<include name="org/luaj/vm2/lib/jme/*.class" />
<include name="org/luaj/vm2/compiler/*.class" />
<include name="org/luaj/vm2/luajc/*.class" />
<include name="org/luaj/vm2/lua2java/*.class" />
<include name="org/luaj/vm2/parser/*.class" />
<include name="org/luaj/vm2/ast/*.class" />
<exclude name="**/*Test*.class" />
</fileset>
</cobertura-instrument>
</target>
<target name="test">
<junit fork="yes" dir="${basedir}" showoutput="yes">
<sysproperty key="net.sourceforge.cobertura.serfile"
file="${basedir}/${cobertura.serfile}" />
<classpath location="${instrumented.dir}" />
<classpath location="${classes.dir}" />
<classpath refid="cobertura.classpath" />
<classpath location="test/lua" />
<classpath location="test/junit/org/luaj/vm2/compiler" />
<classpath location="test/junit/org/luaj/vm2/vm1" />
<classpath path="lib/bcel-5.2.jar" />
<formatter type="xml" />
<batchtest todir="${reports.xml.dir}">
<fileset dir="test/junit">
<include name="org/luaj/vm2/AllTests.java" />
</fileset>
</batchtest>
</junit>
<junitreport todir="${reports.xml.dir}">
<fileset dir="${reports.xml.dir}">
<include name="TEST-*.xml" />
</fileset>
<report format="frames" todir="${reports.html.dir}" />
</junitreport>
</target>
<target name="report">
<cobertura-report datafile="${cobertura.serfile}" destdir="${coverage.xml.dir}" format="xml" />
<cobertura-report datafile="${cobertura.serfile}" destdir="${coverage.html.dir}">
<fileset dir="src/core"/>
<fileset dir="src/jse"/>
<fileset dir="src/jme"/>
</cobertura-report>
</target>
<target name="coverage" depends="clean,init,compile,instrument,test,report"/>
<target name="all" depends="coverage" />
</project>

View File

@@ -1,56 +0,0 @@
<project default="all-libs">
<available file="lib/midpapi20.jar" property="midpapi.lib.exists"/>
<available file="lib/bcel-5.2.jar" property="bcel.lib.exists"/>
<available file="lib/javacc.jar" property="javacc.lib.exists"/>
<available file="lib/proguard.jar" property="proguard.lib.exists"/>
<available file="lib/antenna-bin-1.2.0-beta.jar" property="antenna.lib.exists"/>
<available file="lib/junit.jar" property="junit.lib.exists"/>
<available file="lib/cobertura.jar" property="cobertura.lib.exists"/>
<available file="lib/microemulator.jar" property="microemulator.lib.exists"/>
<macrodef name="download">
<attribute name="zipname"/>
<attribute name="jars" default="**/*.jar"/>
<sequential>
<mkdir dir="lib"/>
<get src="http://luaj.sourceforge.net/lib/@{zipname}.tar.gz"
dest="lib/@{zipname}.tar.gz"/>
<gunzip src="lib/@{zipname}.tar.gz" dest="lib/@{zipname}.tar"/>
<untar src="lib/@{zipname}.tar" dest="lib" overwrite="true">
<patternset>
<include name="@{jars}"/>
</patternset>
<mapper type="flatten"/>
</untar>
</sequential>
</macrodef>
<target name="wtk-libs" unless="midpapi.lib.exists">
<download zipname="wtk-2.5.2-api"/>
</target>
<target name="bcel-lib" unless="bcel.lib.exists">
<download zipname="/bcel-5.2"/>
</target>
<target name="javacc-lib" unless="javacc.lib.exists">
<download zipname="javacc-5.0"/>
</target>
<target name="proguard-lib" unless="proguard.lib.exists">
<download zipname="proguard4.6"/>
</target>
<target name="antenna-lib" unless="antenna.lib.exists">
<download zipname="antenna-bin-1.2.0-beta"/>
</target>
<target name="junit-lib" unless="junit.lib.exists">
<download zipname="junit-3.8.2"/>
</target>
<target name="cobertura-lib" unless="cobertura.lib.exists">
<download zipname="cobertura-1.9.4.1-bin"/>
</target>
<target name="microemulator-lib" unless="microemulator.lib.exists">
<download zipname="microemulator-2.0.4" jars="**/microemulator.jar"/>
</target>
<target name="all-libs" depends="wtk-libs,bcel-lib,javacc-lib,proguard-lib,antenna-lib,junit-lib,cobertura-lib"/>
</project>

View File

@@ -1,176 +0,0 @@
<project default="usage">
<!-- Ant file to deploy to maven once the distribution is released on sourceforge.
-->
<property file="version.properties"/>
<macrodef name="write_pom">
<attribute name="platform"/>
<attribute name="snapshot" default=""/>
<sequential>
<mkdir dir="build/maven-${version}"/>
<echo file="build/maven-${version}/luaj-@{platform}-${version}@{snapshot}.pom"><![CDATA[<project>
<modelVersion>4.0.0</modelVersion>
<groupId>org.luaj</groupId>
<artifactId>luaj-]]>@{platform}<![CDATA[</artifactId>
<version>]]>${version}@{snapshot}<![CDATA[</version>
<packaging>jar</packaging>
<name>luaj-]]>@{platform}<![CDATA[</name>
<description>Luaj ]]>${version}<![CDATA[ for the ]]>@{platform}<![CDATA[ platform</description>
<url>http://sourceforge.net/projects/luaj/</url>
<licenses>
<license>
<name>MIT License</name>
<url>http://luaj.sourceforge.net/license.txt</url>
<distribution>repo</distribution>
</license>
</licenses>
<developers>
<developer>
<id>jrosebor</id>
<name>James Roseborough</name>
<email>jim.roseborough@luaj.org</email>
<timezone>-8</timezone>
<roles></roles>
</developer>
<developer>
<id>ifarmer</id>
<name>Ian Farmer</name>
<email>ian.farmer@luaj.org</email>
<timezone>-8</timezone>
<roles></roles>
</developer>
</developers>
<scm>
<url>http://luaj.cvs.sourceforge.net/viewvc/luaj/luaj-vm/</url>
</scm>
</project>
]]></echo>
</sequential>
</macrodef>
<macrodef name="prepare_files">
<attribute name="platform"/>
<attribute name="snapshot" default=""/>
<sequential>
<mkdir dir="build/maven-${version}"/>
<write_pom platform="@{platform}" snapshot="@{snapshot}"/>
<copy file="luaj-${version}.zip" todir="build/maven-${version}"/>
<unzip src="build/maven-${version}/luaj-${version}.zip" dest="build/maven-${version}"/>
<copy file="build/maven-${version}/luaj-${version}/lib/luaj-@{platform}-${version}.jar" todir="build/maven-${version}"/>
<!-- make a -sources file -->
<mkdir dir="build/maven-${version}/sources-@{platform}"/>
<copy todir="build/maven-${version}/sources-@{platform}">
<fileset dir="build/maven-${version}/luaj-${version}/src/core"/>
<fileset dir="build/maven-${version}/luaj-${version}/src/@{platform}"/>
<filterchain>
<tokenfilter><replacestring from='"Luaj 0.0"' to='"Luaj-@{platform} ${version}"'/></tokenfilter>
</filterchain>
</copy>
<zip destfile="build/maven-${version}/luaj-@{platform}-${version}-sources.jar"
basedir="build/maven-${version}/sources-@{platform}"/>
<!-- make a -javadoc file -->
<mkdir dir="build/maven-${version}/javadoc-@{platform}"/>
<javadoc defaultexcludes="yes"
destdir="build/maven-${version}/javadoc-@{platform}"
author="true"
version="true"
use="true"
windowtitle="Luaj API">
<fileset dir="build/maven-${version}/sources-@{platform}">
<include name="org/luaj/vm/*.java"/>
<include name="org/luaj/vm2/*.java"/>
<include name="org/luaj/vm2/server/*.java"/>
<include name="**/LuaC.java"/>
<include name="**/LuaJC.java"/>
<include name="**/lib/*/*.java"/>
</fileset>
<doctitle><![CDATA[<h1>Luaj API</h1>]]></doctitle>
<bottom><![CDATA[<i>Copyright &#169; 2007-2015 Luaj.org. All Rights Reserved.</i>]]></bottom>
<tag name="todo" scope="all" description="To do:"/>
<link offline="true" href="http://sourceforge.net/projects/luaj/" packagelistLoc="C:\tmp"/>
<link href="http://sourceforge.net/projects/luaj/"/>
</javadoc>
<zip destfile="build/maven-${version}/luaj-@{platform}-${version}-javadoc.jar"
basedir="build/maven-${version}/javadoc-@{platform}"/>
</sequential>
</macrodef>
<macrodef name="shapshot_files">
<attribute name="platform"/>
<sequential>
<exec executable="mvn">
<arg value="deploy:deploy-file"/>
<arg value="-Durl=https://oss.sonatype.org/content/repositories/snapshots"/>
<arg value="-DrepositoryId=nexus-releases"/>
<arg value="-DpomFile=build/maven-${version}/luaj-@{platform}-${version}-SNAPSHOT.pom"/>
<arg value="-Dfile=build/maven-${version}/luaj-@{platform}-${version}.jar"/>
<arg value="-Dsources=build/maven-${version}/luaj-@{platform}-${version}-sources.jar"/>
<arg value="-Djavadoc=build/maven-${version}/luaj-@{platform}-${version}-javadoc.jar"/>
</exec>
</sequential>
</macrodef>
<macrodef name="sign_and_deploy">
<attribute name="platform"/>
<sequential>
<exec executable="mvn">
<arg value="gpg:sign-and-deploy-file"/>
<arg value="-Durl=http://oss.sonatype.org/service/local/staging/deploy/maven2"/>
<arg value="-DrepositoryId=nexus-releases"/>
<arg value="-DpomFile=build/maven-${version}/luaj-@{platform}-${version}.pom"/>
<arg value="-Dfile=build/maven-${version}/luaj-@{platform}-${version}.jar"/>
<arg value="-Dsources=build/maven-${version}/luaj-@{platform}-${version}-sources.jar"/>
<arg value="-Djavadoc=build/maven-${version}/luaj-@{platform}-${version}-javadoc.jar"/>
</exec>
</sequential>
</macrodef>
<macrodef name="prepare_and_install">
<attribute name="platform"/>
<sequential>
<prepare_files platform="@{platform}"/>
<exec executable="mvn">
<arg value="install:install-file"/>
<arg value="-Dfile=build/maven-${version}/luaj-@{platform}-${version}.jar"/>
<arg value="-DpomFile=build/maven-${version}/luaj-@{platform}-${version}.pom"/>
</exec>
</sequential>
</macrodef>
<macrodef name="prepare_and_snapshot">
<attribute name="platform"/>
<sequential>
<prepare_files platform="@{platform}" snapshot="-SNAPSHOT"/>
<shapshot_files platform="@{platform}"/>
</sequential>
</macrodef>
<macrodef name="prepare_and_deploy">
<attribute name="platform"/>
<sequential>
<prepare_files platform="@{platform}"/>
<sign_and_deploy platform="@{platform}"/>
</sequential>
</macrodef>
<target name="install">
<prepare_and_install platform="jse"/>
<prepare_and_install platform="jme"/>
</target>
<target name="snapshot">
<prepare_and_snapshot platform="jse"/>
<prepare_and_snapshot platform="jme"/>
</target>
<target name="deploy">
<prepare_and_deploy platform="jse"/>
<prepare_and_deploy platform="jme"/>
</target>
<target name="usage">
<echo level="info">Usage: ant [-Dversion=${version}] -f build-maven.xml [install | shapshot | deploy]</echo>
</target>
</project>

View File

@@ -1,113 +0,0 @@
<?xml version="1.0"?>
<project name="sample" default="all" basedir=".">
<property file="version.properties"/>
<!-- find libs -->
<import file="build-libs.xml"/>
<!-- main script -->
<property name="script.name" value="hello"/>
<property name="script.dir" value="examples/lua"/>
<target name="clean">
<delete failonerror="false" dir="build"/>
</target>
<target name="dirs">
<mkdir dir="build"/>
<mkdir dir="build/tool"/>
<mkdir dir="build/classes"/>
</target>
<target name="tools" depends="dirs,bcel-lib,wtk-libs,microemulator-lib">
<javac destdir="build/tool" classpath="lib/bcel-5.2.jar">
<src path="src/core"/>
<src path="src/jse"/>
</javac>
</target>
<!-- compile script into lua bytecode -->
<target name="luac" depends="tools">
<java classname="luac" classpath="build/tool">
<arg line="-o build/classes/${script.name}.lua"/>
<arg line="${script.dir}/${script.name}.lua"/>
</java>
</target>
<!-- compile script into java bytecode -->
<target name="luajc" depends="tools,wtk-libs">
<java classname="luajc" classpath="build/tool:lib/bcel-5.2.jar">
<arg line="-verbose"/>
<arg line="-srcdir ${script.dir}"/>
<arg line="-destdir build/classes"/>
<arg line="${script.name}.lua"/>
</java>
</target>
<target name="classes" depends="dirs,wtk-libs">
<mkdir dir="build/midlet/src"/>
<copy todir="build/midlet/src">
<fileset dir="src/core"/>
<fileset dir="src/jme"/>
<fileset dir="examples/jme"/>
<filterchain>
<tokenfilter><replacestring from='"Luaj 0.0"' to='"Luaj-jme ${version}"'/></tokenfilter>
</filterchain>
</copy>
<path id="wtk-libs">
<pathelement path="lib/cldcapi11.jar"/>
<pathelement path="lib/midpapi20.jar"/>
<pathelement path="lib/mmapi.jar"/>
</path>
<javac destdir="build/classes" encoding="utf-8" source="1.3" target="1.2" bootclasspathref="wtk-libs"
srcdir="build/midlet/src"/>
</target>
<target name="jar" depends="luajc,classes">
<jar destfile="build/sample-plain.jar"
basedir="build/classes"/>
</target>
<target name="obf" depends="jar,proguard-lib">
<taskdef resource="proguard/ant/task.properties" classpath="lib/proguard.jar" />
<proguard>
-injars build/sample-plain.jar
-outjars build/sample.jar
-libraryjars lib/midpapi20.jar
-libraryjars lib/cldcapi11.jar
-overloadaggressively
-repackageclasses ''
-microedition
-keep public class SampleMIDlet
-keep public class * extends org.luaj.vm2.LuaValue
</proguard>
</target>
<target name="jad" depends="obf">
<length file="build/sample.jar" property="sample.jar.length" />
<echo level="info">Jar file length is ${sample.jar.length}</echo>
<manifest file="build/sample.jad">
<attribute name="Built-By" value="luaj-${version}"/>
<attribute name="MIDlet-Name" value="Luaj ${script.name}"/>
<attribute name="MIDlet-Version" value="${version}"/>
<attribute name="MIDlet-Vendor" value="luaj.org"/>
<attribute name="MIDlet-Description" value="Luaj Sample Midlet"/>
<attribute name="MIDlet-1" value="${script.name}-${version}, , SampleMIDlet"/>
<attribute name="MIDlet-Jar-URL" value="sample.jar"/>
<attribute name="MIDlet-Jar-Size" value="${sample.jar.length}"/>
<attribute name="script" value="${script.name}"/>
</manifest>
</target>
<target name="package" depends="jad,jar,obf"/>
<target name="run" depends="jad,jar,obf,microemulator-lib">
<java jar="lib/microemulator.jar" fork="true">
<arg path="build/sample.jad"/>
</java>
</target>
<target name="all" depends="clean,package,run"/>
</project>

View File

@@ -1,68 +0,0 @@
<project default="all">
<import file="build.xml"/>
<property name="lua.command" value="lua"/>
<available file="luaj-jse-${version}.jar" property="luaj.lib.exists"/>
<available file="lib/jill-1.0.1.jar" property="jill.lib.exists"/>
<available file="lib/kahlua.jar" property="kahlua.lib.exists"/>
<available file="lib/mochalua-1.0.jar" property="mochalua.lib.exists"/>
<target name="luaj-lib" unless="luaj.lib.exists">
<antcall target="jar-jse"/>
</target>
<target name="jill-lib" unless="jill.lib.exists">
<mkdir dir="lib"/>
<get src="http://jillcode.googlecode.com/files/jill-1.0.1.zip"
dest="lib/jill-1.0.1.zip"/>
<unzip src="lib/jill-1.0.1.zip" dest="lib" overwrite="true"/>
<ant dir="lib/jill-1.0.1" target="compile"/>
<jar destfile="lib/jill-1.0.1.jar" basedir="lib/jill-1.0.1/compiled"/>
</target>
<target name="kahlua-lib" unless="kahlua.lib.exists">
<get src="http://kahlua.googlecode.com/files/kahlua.jar"
dest="lib/kahlua.jar"/>
</target>
<target name="mochalua-lib" unless="mochalua.lib.exists">
<get src="http://mochalua.googlecode.com/files/Mochalua%201.0.jar"
dest="lib/mochalua-1.0.jar"/>
</target>
<target name="perf-libs" depends="luaj-lib,bcel-lib,jill-lib,kahlua-lib,mochalua-lib"/>
<macrodef name="perftest">
<attribute name="program" default="lua"/>
<attribute name="luaprog" default="fannkuch.lua 10"/>
<attribute name="basedir" default="test/lua/perf/"/>
<sequential>
<echo level="info">------ @{program} @{luaprog}</echo>
<exec executable="bash">
<arg value="-c"/>
<arg value="time @{program} @{basedir}@{luaprog}"/>
</exec>
</sequential>
</macrodef>
<macrodef name="testcase">
<attribute name="luaprog" default="fannkuch.lua 10"/>
<sequential>
<echo level="info">=========== @{luaprog} =============</echo>
<perftest program="java -version" luaprog="" basedir=""/>
<perftest program="${lua.command}" luaprog="@{luaprog}"/>
<perftest program="java -cp luaj-jse-${version}.jar lua -n" luaprog="@{luaprog}"/>
<perftest program="java -cp luaj-jse-${version}.jar${path.separator}lib/bcel-5.2.jar lua -b" luaprog="@{luaprog}"/>
</sequential>
</macrodef>
<target name="alltests">
<testcase luaprog="binarytrees.lua 15"/>
<testcase luaprog="fannkuch.lua 10"/>
<testcase luaprog="nbody.lua 1000000"/>
<testcase luaprog="nsieve.lua 9"/>
</target>
<target name="all" depends="alltests"/>
</project>

212
build.xml
View File

@@ -1,212 +0,0 @@
<project default="all">
<property file="version.properties"/>
<property name="jar.name.jme" value="luaj-jme-${version}.jar"/>
<property name="jar.name.jse" value="luaj-jse-${version}.jar"/>
<property name="jar.name.sources" value="luaj-sources-${version}.jar"/>
<target name="clean-build">
<delete dir="build"/>
</target>
<target name="clean" depends="clean-build">
<delete>
<fileset dir="." includes="luaj-*.jar"/>
</delete>
<delete dir="examples/android/bin"/>
<delete dir="examples/android/build"/>
<delete dir="examples/android/gen"/>
<delete dir="examples/android/libs"/>
<delete dir="examples/maven/target"/>
</target>
<import file="build-libs.xml"/>
<target name="parser" depends="javacc-lib">
<java classname="javacc" classpath="lib/javacc.jar">
<arg line="grammar/LuaParser.jj"/>
</java>
</target>
<target name="plain-parser" depends="javacc-lib">
<java dir="src/jse" fork="true" classname="javacc" classpath="lib/javacc.jar">
<arg line="../../grammar/Lua52.jj"/>
</java>
</target>
<target name="compile" depends="wtk-libs,bcel-lib">
<delete dir="build/jme/src"/>
<delete dir="build/jse/src"/>
<mkdir dir="build/jme/src"/>
<mkdir dir="build/jse/src"/>
<mkdir dir="build/jme/classes"/>
<mkdir dir="build/jse/classes"/>
<copy todir="build/jme/src">
<fileset dir="src/core"/>
<fileset dir="src/jme"/>
<filterchain>
<tokenfilter><replacestring from='"Luaj 0.0"' to='"Luaj-jme ${version}"'/></tokenfilter>
</filterchain>
</copy>
<copy todir="build/jse/src">
<fileset dir="src/core"/>
<filterchain>
<tokenfilter><replacestring from='"Luaj 0.0"' to='"Luaj-jse ${version}"'/></tokenfilter>
</filterchain>
</copy>
<copy todir="build/jse/src">
<fileset dir="src/jse"/>
<filterchain>
<tokenfilter><replacestring from='&lt;String&gt;' to=''/></tokenfilter>
<tokenfilter><replacestring from='&lt;Stat&gt;' to=''/></tokenfilter>
<tokenfilter><replacestring from='&lt;Exp&gt;' to=''/></tokenfilter>
<tokenfilter><replacestring from='&lt;Name&gt;' to=''/></tokenfilter>
<tokenfilter><replacestring from='&lt;Block&gt;' to=''/></tokenfilter>
<tokenfilter><replacestring from='&lt;TableField&gt;' to=''/></tokenfilter>
<tokenfilter><replacestring from='&lt;VarExp&gt;' to=''/></tokenfilter>
<tokenfilter><replacestring from='&lt;Exp.VarExp&gt;' to=''/></tokenfilter>
<tokenfilter><replacestring from='&lt;Object,String&gt;' to=''/></tokenfilter>
<tokenfilter><replacestring from='&lt;Double,String&gt;' to=''/></tokenfilter>
<tokenfilter><replacestring from='&lt;Integer,Integer&gt;' to=''/></tokenfilter>
<tokenfilter><replacestring from='&lt;Integer,LocalVariableGen&gt;' to=''/></tokenfilter>
<tokenfilter><replacestring from='&lt;Exp,Integer&gt;' to=''/></tokenfilter>
<tokenfilter><replacestring from='&lt;String,byte[]&gt;' to=''/></tokenfilter>
<tokenfilter><replacestring from='&lt;String,Variable&gt;' to=''/></tokenfilter>
<tokenfilter><replacestring from='&lt;LuaValue,String&gt;' to=''/></tokenfilter>
<tokenfilter><replacestring from='&lt;LuaString,String&gt;' to=''/></tokenfilter>
</filterchain>
</copy>
<path id="wtk-libs">
<pathelement path="lib/cldcapi11.jar"/>
<pathelement path="lib/midpapi20.jar"/>
<pathelement path="lib/mmapi.jar"/>
</path>
<javac destdir="build/jme/classes" encoding="utf-8" source="1.3" target="1.2" bootclasspathref="wtk-libs"
debug="on"
srcdir="build/jme/src"/>
<javac destdir="build/jse/classes" encoding="utf-8" source="1.3" target="1.3"
classpath="lib/bcel-5.2.jar"
debug="on"
srcdir="build/jse/src"
excludes="**/script/*,**/Lua2Java*,**/server/*,lua*"/>
<javac destdir="build/jse/classes" encoding="utf-8" source="1.5" target="1.5"
classpath="build/jse/classes"
debug="on"
srcdir="build/jse/src"
includes="**/script/*,**/Lua2Java*,**/server/*"/>
<javac destdir="build/jse/classes" encoding="utf-8" source="1.3" target="1.3"
classpath="build/jse/classes"
debug="on"
srcdir="build/jse/src"
includes="lua*"/>
</target>
<target name="jar-jme" depends="compile">
<jar destfile="${jar.name.jme}" basedir="build/jme/classes"/>
</target>
<target name="jar-jse" depends="compile">
<jar destfile="${jar.name.jse}">
<fileset dir="build/jse/classes"/>
<fileset dir="src/jse/">
<include name="META-INF/services/**"/>
</fileset>
</jar>
</target>
<target name="jar-jse-sources" depends="compile">
<jar destfile="${jar.name.sources}">
<fileset dir="build/jme/src"/>
<fileset dir="build/jse/src"/>
</jar>
</target>
<target name="doc">
<delete dir="docs/api"/>
<mkdir dir="docs/api"/>
<javadoc defaultexcludes="yes"
destdir="docs/api"
author="true"
version="true"
use="true"
windowtitle="Luaj API">
<fileset dir="src/core" defaultexcludes="yes" includes="org/luaj/vm2/*.java,org/luaj/vm2/compiler/LuaC.java,org/luaj/vm2/lib/*.java"/>
<fileset dir="src/jse" defaultexcludes="yes" includes="org/luaj/vm2/lib/jse/*.java,org/luaj/vm2/luajc/LuaJC.java,org/luaj/vm2/server/*.java"/>
<fileset dir="src/jme" defaultexcludes="yes" includes="org/luaj/vm2/lib/jme/*.java"/>
<doctitle><![CDATA[<h1>Luaj API</h1>]]></doctitle>
<bottom><![CDATA[<i>Copyright &#169; 2007-2015 Luaj.org. All Rights Reserved.</i>]]></bottom>
<tag name="todo" scope="all" description="To do:"/>
<group title="Core VM" packages="org.luaj.vm.*"/>
<link offline="true" href="http://sourceforge.net/projects/luaj/" packagelistLoc="C:\tmp"/>
<link href="http://sourceforge.net/projects/luaj/"/>
</javadoc>
</target>
<target name="dist" depends="all,doc">
<delete dir="build/luaj-${version}"/>
<mkdir dir="build/luaj-${version}/src"/>
<mkdir dir="build/luaj-${version}/lib"/>
<copy todir="build/luaj-${version}/src">
<fileset dir="src">
<exclude name="src/test/**"/>
<exclude name="**/antlr/**"/>
<exclude name="**/lst/**"/>
<exclude name="**/JavaCodeGenerator.java"/>
<exclude name="**/LuaJCompiler.java"/>
</fileset>
</copy>
<copy todir="build/luaj-${version}/test">
<fileset dir="test"/>
</copy>
<copy todir="build/luaj-${version}/examples">
<fileset dir="examples">
<include name="android/*.*"/>
<include name="android/assets/**"/>
<include name="android/res/**"/>
<include name="android/src/**"/>
<include name="jme/*.java"/>
<include name="jse/*.java"/>
<include name="lua/*.*"/>
<include name="maven/pom.xml"/>
<include name="maven/src/**"/>
</fileset>
</copy>
<copy todir="build/luaj-${version}/lib">
<fileset dir=".">
<include name="*-${version}.jar"/>
</fileset>
</copy>
<copy todir="build/luaj-${version}">
<fileset dir=".">
<include name="build.xml"/>
<include name="build-libs.xml"/>
<include name="build-coverage.xml"/>
<include name="version.properties"/>
<include name="wtk.xml"/>
<include name="README.html"/>
<include name="names.csv"/>
<include name=".classpath"/>
<include name=".project"/>
</fileset>
</copy>
<copy todir="build/luaj-${version}/docs">
<fileset dir="docs"/>
</copy>
<zip destfile="luaj-${version}.zip"
basedir="build" includes="luaj-${version}/**"/>
</target>
<target name="mvn_install" depends="jar-jse">
<exec executable="mvn">
<arg value="install:install-file"/>
<arg value="-Dfile=${jar.name.jse}"/>
<arg value="-DgroupId=org.luaj"/>
<arg value="-DartifactId=luaj-jse"/>
<arg value="-Dversion=${version}"/>
<arg value="-Dpackaging=jar"/>
</exec>
</target>
<target name="all" depends="clean,jar-jme,jar-jse,jar-jse-sources"/>
</project>

25
luaj-core/pom.xml Normal file
View File

@@ -0,0 +1,25 @@
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.luaj</groupId>
<artifactId>luaj-parent</artifactId>
<version>3.0-SNAPSHOT</version>
</parent>
<artifactId>luaj-core</artifactId>
<name>luaj-core</name>
<description>Core code for LuaJ</description>
<dependencies>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>

View File

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

View File

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

View File

@@ -25,7 +25,6 @@ import java.io.DataInputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
/** /**
* Class to undump compiled lua bytecode into a {@link Prototype} instances. * Class to undump compiled lua bytecode into a {@link Prototype} instances.
* <p> * <p>
@@ -34,47 +33,63 @@ import java.io.InputStream;
* using either the C-based lua compiler, or luaj's * using either the C-based lua compiler, or luaj's
* {@link org.luaj.vm2.compiler.LuaC} compiler. * {@link org.luaj.vm2.compiler.LuaC} compiler.
* <p> * <p>
* The canonical method to load and execute code is done * The canonical method to load and execute code is done indirectly using the
* indirectly using the Globals: * Globals:
* <pre> {@code *
* <pre>
* {
* &#64;code
* Globals globals = JsePlatform.standardGlobals(); * Globals globals = JsePlatform.standardGlobals();
* LuaValue chunk = globasl.load("print('hello, world')", "main.lua"); * LuaValue chunk = globasl.load("print('hello, world')", "main.lua");
* chunk.call(); * chunk.call();
* } </pre> * }
* This should work regardless of which {@link Globals.Compiler} or {@link Globals.Undumper} * </pre>
* have been installed. *
* This should work regardless of which {@link Globals.Compiler} or
* {@link Globals.Undumper} have been installed.
* <p> * <p>
* By default, when using {@link org.luaj.vm2.lib.jse.JsePlatform} or * By default, when using {@link org.luaj.vm2.lib.jse.JsePlatform} or
* {@link org.luaj.vm2.lib.jme.JmePlatform} * {@link org.luaj.vm2.lib.jme.JmePlatform} to construct globals, the
* to construct globals, the {@link LoadState} default undumper is installed * {@link LoadState} default undumper is installed as the default
* as the default {@link Globals.Undumper}. * {@link Globals.Undumper}.
* <p> * <p>
* *
* A lua binary file is created via the {@link org.luaj.vm2.compiler.DumpState} class * A lua binary file is created via the {@link org.luaj.vm2.compiler.DumpState}
: * class :
* <pre> {@code *
* <pre>
* {
* &#64;code
* Globals globals = JsePlatform.standardGlobals(); * Globals globals = JsePlatform.standardGlobals();
* Prototype p = globals.compilePrototype(new StringReader("print('hello, world')"), "main.lua"); * Prototype p = globals.compilePrototype(new StringReader("print('hello, world')"), "main.lua");
* ByteArrayOutputStream o = new ByteArrayOutputStream(); * ByteArrayOutputStream o = new ByteArrayOutputStream();
* org.luaj.vm2.compiler.DumpState.dump(p, o, false); * org.luaj.vm2.compiler.DumpState.dump(p, o, false);
* byte[] lua_binary_file_bytes = o.toByteArray(); * byte[] lua_binary_file_bytes = o.toByteArray();
* } </pre> * }
* </pre>
* *
* The {@link LoadState}'s default undumper {@link #instance} * The {@link LoadState}'s default undumper {@link #instance} may be used
* may be used directly to undump these bytes: * directly to undump these bytes:
* <pre> {@code *
* <pre>
* {@code
* Prototypep = LoadState.instance.undump(new ByteArrayInputStream(lua_binary_file_bytes), "main.lua"); * Prototypep = LoadState.instance.undump(new ByteArrayInputStream(lua_binary_file_bytes), "main.lua");
* LuaClosure c = new LuaClosure(p, globals); * LuaClosure c = new LuaClosure(p, globals);
* c.call(); * c.call();
* } </pre> * }
* </pre>
* *
* *
* More commonly, the {@link Globals.Undumper} may be used to undump them: * 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"); * Prototype p = globals.loadPrototype(new ByteArrayInputStream(lua_binary_file_bytes), "main.lua", "b");
* LuaClosure c = new LuaClosure(p, globals); * LuaClosure c = new LuaClosure(p, globals);
* c.call(); * c.call();
* } </pre> * }
* </pre>
* *
* @see Globals.Compiler * @see Globals.Compiler
* @see Globals.Undumper * @see Globals.Undumper
@@ -87,21 +102,30 @@ import java.io.InputStream;
*/ */
public class LoadState { 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(); 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; public static final int NUMBER_FORMAT_FLOATS_OR_DOUBLES = 0;
/** format corresponding to non-number-patched lua, all numbers are ints */ /** format corresponding to non-number-patched lua, all numbers are ints */
public static final int NUMBER_FORMAT_INTS_ONLY = 1; 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; public static final int NUMBER_FORMAT_NUM_PATCH_INT32 = 4;
// type constants // type constants
public static final int LUA_TINT = (-2); public static final int LUA_TINT = -2;
public static final int LUA_TNONE = (-1); public static final int LUA_TNONE = -1;
public static final int LUA_TNIL = 0; public static final int LUA_TNIL = 0;
public static final int LUA_TBOOLEAN = 1; public static final int LUA_TBOOLEAN = 1;
public static final int LUA_TLIGHTUSERDATA = 2; public static final int LUA_TLIGHTUSERDATA = 2;
@@ -113,7 +137,10 @@ public class LoadState {
public static final int LUA_TTHREAD = 8; public static final int LUA_TTHREAD = 8;
public static final int LUA_TVALUE = 9; 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; public static String encoding = null;
/** Signature byte indicating the file is a compiled binary chunk */ /** Signature byte indicating the file is a compiled binary chunk */
@@ -122,11 +149,9 @@ public class LoadState {
/** Data to catch conversion errors */ /** Data to catch conversion errors */
public static final byte[] LUAC_TAIL = { (byte) 0x19, (byte) 0x93, '\r', '\n', (byte) 0x1a, '\n', }; public static final byte[] LUAC_TAIL = { (byte) 0x19, (byte) 0x93, '\r', '\n', (byte) 0x1a, '\n', };
/** Name for compiled chunks */ /** Name for compiled chunks */
public static final String SOURCE_BINARY_STRING = "binary string"; public static final String SOURCE_BINARY_STRING = "binary string";
/** for header of binary files -- this is Lua 5.2 */ /** for header of binary files -- this is Lua 5.2 */
public static final int LUAC_VERSION = 0x52; public static final int LUAC_VERSION = 0x52;
@@ -161,22 +186,28 @@ public class LoadState {
/** Read buffer */ /** Read buffer */
private byte[] buf = new byte[512]; 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) { public static void install(Globals globals) {
globals.undumper = instance; 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. * @return the int value laoded.
**/ **/
int loadInt() throws IOException { int loadInt() throws IOException {
is.readFully(buf, 0, 4); is.readFully(buf, 0, 4);
return luacLittleEndian? return luacLittleEndian? buf[3]<<24 | (0xff & buf[2])<<16 | (0xff & buf[1])<<8 | 0xff & buf[0]
(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];
(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. * @return the array of int values laoded.
**/ **/
int[] loadIntArray() throws IOException { int[] loadIntArray() throws IOException {
@@ -191,14 +222,15 @@ public class LoadState {
is.readFully(buf, 0, m); is.readFully(buf, 0, m);
int[] array = new int[n]; int[] array = new int[n];
for (int i = 0, j = 0; i < n; ++i, j += 4) for (int i = 0, j = 0; i < n; ++i, j += 4)
array[i] = luacLittleEndian? array[i] = luacLittleEndian? buf[j+3]<<24 | (0xff & buf[j+2])<<16 | (0xff & buf[j+1])<<8 | 0xff & buf[j+0]
(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];
(buf[j+0] << 24) | ((0xff & buf[j+1]) << 16) | ((0xff & buf[j+2]) << 8) | (0xff & buf[j+3]);
return array; return array;
} }
/** Load a long value from the input stream /**
* Load a long value from the input stream
*
* @return the long value laoded. * @return the long value laoded.
**/ **/
long loadInt64() throws IOException { long loadInt64() throws IOException {
@@ -210,10 +242,12 @@ public class LoadState {
b = loadInt(); b = loadInt();
a = loadInt(); a = loadInt();
} }
return (((long)b)<<32) | (((long)a)&0xffffffffL); return (long) b<<32 | 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. * @return the {@link LuaString} value laoded.
**/ **/
LuaString loadString() throws IOException { LuaString loadString() throws IOException {
@@ -227,23 +261,25 @@ public class LoadState {
/** /**
* Convert bits in a long value to a {@link LuaValue}. * Convert bits in a long value to a {@link LuaValue}.
*
* @param bits long value containing the bits * @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) { public static LuaValue longBitsToLuaNumber(long bits) {
if ( ( bits & ( ( 1L << 63 ) - 1 ) ) == 0L ) { if ((bits & (1L<<63)-1) == 0L) {
return LuaValue.ZERO; return LuaValue.ZERO;
} }
int e = (int)((bits >> 52) & 0x7ffL) - 1023; int e = (int) (bits>>52 & 0x7ffL)-1023;
if (e >= 0 && e < 31) { if (e >= 0 && e < 31) {
long f = bits & 0xFFFFFFFFFFFFFL; long f = bits & 0xFFFFFFFFFFFFFL;
int shift = 52-e; int shift = 52-e;
long intPrecMask = (1L<<shift)-1; long intPrecMask = (1L<<shift)-1;
if ((f & intPrecMask) == 0) { if ((f & intPrecMask) == 0) {
int intValue = (int)( f >> shift ) | ( 1 << e ); int intValue = (int) (f>>shift) | 1<<e;
return LuaInteger.valueOf( ( ( bits >> 63 ) != 0 ) ? -intValue : intValue ); return LuaInteger.valueOf(bits>>63 != 0? -intValue: intValue);
} }
} }
@@ -252,6 +288,7 @@ public class LoadState {
/** /**
* Load a number from a binary chunk * Load a number from a binary chunk
*
* @return the {@link LuaValue} loaded * @return the {@link LuaValue} loaded
* @throws IOException if an i/o exception occurs * @throws IOException if an i/o exception occurs
*/ */
@@ -265,6 +302,7 @@ public class LoadState {
/** /**
* Load a list of constants from a binary chunk * Load a list of constants from a binary chunk
*
* @param f the function prototype * @param f the function prototype
* @throws IOException if an i/o exception occurs * @throws IOException if an i/o exception occurs
*/ */
@@ -277,7 +315,7 @@ public class LoadState {
values[i] = LuaValue.NIL; values[i] = LuaValue.NIL;
break; break;
case LUA_TBOOLEAN: case LUA_TBOOLEAN:
values[i] = (0 != is.readUnsignedByte()? LuaValue.TRUE: LuaValue.FALSE); values[i] = 0 != is.readUnsignedByte()? LuaValue.TRUE: LuaValue.FALSE;
break; break;
case LUA_TINT: case LUA_TINT:
values[i] = LuaInteger.valueOf(loadInt()); values[i] = LuaInteger.valueOf(loadInt());
@@ -301,19 +339,19 @@ public class LoadState {
f.p = protos; f.p = protos;
} }
void loadUpvalues(Prototype f) throws IOException { void loadUpvalues(Prototype f) throws IOException {
int n = loadInt(); int n = loadInt();
f.upvalues = n > 0? new Upvaldesc[n]: NOUPVALDESCS; f.upvalues = n > 0? new Upvaldesc[n]: NOUPVALDESCS;
for (int i = 0; i < n; i++) { for (int i = 0; i < n; i++) {
boolean instack = is.readByte() != 0; boolean instack = is.readByte() != 0;
int idx = ((int) is.readByte()) & 0xff; int idx = is.readByte() & 0xff;
f.upvalues[i] = new Upvaldesc(null, instack, idx); f.upvalues[i] = new Upvaldesc(null, instack, idx);
} }
} }
/** /**
* Load the debug info for a function prototype * Load the debug info for a function prototype
*
* @param f the function Prototype * @param f the function Prototype
* @throws IOException if there is an i/o exception * @throws IOException if there is an i/o exception
*/ */
@@ -336,6 +374,7 @@ public class LoadState {
/** /**
* Load a function prototype from the input stream * Load a function prototype from the input stream
*
* @param p name of the source * @param p name of the source
* @return {@link Prototype} instance that was loaded * @return {@link Prototype} instance that was loaded
* @throws IOException * @throws IOException
@@ -366,12 +405,13 @@ public class LoadState {
/** /**
* Load the lua chunk header values. * Load the lua chunk header values.
*
* @throws IOException if an i/o exception occurs. * @throws IOException if an i/o exception occurs.
*/ */
public void loadHeader() throws IOException { public void loadHeader() throws IOException {
luacVersion = is.readByte(); luacVersion = is.readByte();
luacFormat = is.readByte(); luacFormat = is.readByte();
luacLittleEndian = (0 != is.readByte()); luacLittleEndian = 0 != is.readByte();
luacSizeofInt = is.readByte(); luacSizeofInt = is.readByte();
luacSizeofSizeT = is.readByte(); luacSizeofSizeT = is.readByte();
luacSizeofInstruction = is.readByte(); luacSizeofInstruction = is.readByte();
@@ -383,17 +423,19 @@ public class LoadState {
} }
/** /**
* Load input stream as a lua binary chunk if the first 4 bytes are the lua binary signature. * Load input stream as a lua binary chunk if the first 4 bytes are the lua
* @param stream InputStream to read, after having read the first byte already * binary signature.
*
* @param stream InputStream to read, after having read the first byte
* already
* @param chunkname Name to apply to the loaded chunk * @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 * @throws IOException if an IOException occurs
*/ */
public static Prototype undump(InputStream stream, String chunkname) throws IOException { public static Prototype undump(InputStream stream, String chunkname) throws IOException {
// check rest of signature // check rest of signature
if ( stream.read() != LUA_SIGNATURE[0] if (stream.read() != LUA_SIGNATURE[0] || stream.read() != LUA_SIGNATURE[1] || stream.read() != LUA_SIGNATURE[2]
|| stream.read() != LUA_SIGNATURE[1]
|| stream.read() != LUA_SIGNATURE[2]
|| stream.read() != LUA_SIGNATURE[3]) || stream.read() != LUA_SIGNATURE[3])
return null; return null;
@@ -416,6 +458,7 @@ public class LoadState {
/** /**
* Construct a source name from a supplied chunk name * Construct a source name from a supplied chunk name
*
* @param name String name that appears in the chunk * @param name String name that appears in the chunk
* @return source file name * @return source file name
*/ */
@@ -435,8 +478,8 @@ public class LoadState {
} }
private static final class GlobalsUndumper implements Globals.Undumper { private static final class GlobalsUndumper implements Globals.Undumper {
public Prototype undump(InputStream stream, String chunkname) @Override
throws IOException { public Prototype undump(InputStream stream, String chunkname) throws IOException {
return LoadState.undump(stream, chunkname); return LoadState.undump(stream, chunkname);
} }
} }

View File

@@ -22,7 +22,8 @@
package org.luaj.vm2; 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 { public class LocVars {
/** The local variable name */ /** The local variable name */
@@ -36,6 +37,7 @@ public class LocVars {
/** /**
* Construct a LocVars instance. * Construct a LocVars instance.
*
* @param varname The local variable name * @param varname The local variable name
* @param startpc The instruction offset when the variable comes into scope * @param startpc The instruction offset when the variable comes into scope
* @param endpc The instruction offset when the variable goes out of scope * @param endpc The instruction offset when the variable goes out of scope

View File

@@ -21,12 +21,11 @@
******************************************************************************/ ******************************************************************************/
package org.luaj.vm2; package org.luaj.vm2;
/** /**
* Constants for lua limits and opcodes. * Constants for lua limits and opcodes.
* <p> * <p>
* This is a direct translation of C lua distribution header file constants * This is a direct translation of C lua distribution header file constants for
* for bytecode creation and processing. * bytecode creation and processing.
*/ */
public class Lua { public class Lua {
/** version is supplied by ant build task */ /** version is supplied by ant build task */
@@ -54,46 +53,44 @@ public class Lua {
unsigned argument. unsigned argument.
===========================================================================*/ ===========================================================================*/
/* basic instruction format */ /* basic instruction format */
public static final int iABC = 0; public static final int iABC = 0;
public static final int iABx = 1; public static final int iABx = 1;
public static final int iAsBx = 2; public static final int iAsBx = 2;
public static final int iAx = 3; public static final int iAx = 3;
/* /*
** size and position of opcode arguments. ** size and position of opcode arguments.
*/ */
public static final int SIZE_C = 9; public static final int SIZE_C = 9;
public static final int SIZE_B = 9; public static final int SIZE_B = 9;
public static final int SIZE_Bx = (SIZE_C + SIZE_B); public static final int SIZE_Bx = SIZE_C+SIZE_B;
public static final int SIZE_A = 8; public static final int SIZE_A = 8;
public static final int SIZE_Ax = (SIZE_C + SIZE_B + SIZE_A); public static final int SIZE_Ax = SIZE_C+SIZE_B+SIZE_A;
public static final int SIZE_OP = 6; public static final int SIZE_OP = 6;
public static final int POS_OP = 0; public static final int POS_OP = 0;
public static final int POS_A = (POS_OP + SIZE_OP); public static final int POS_A = POS_OP+SIZE_OP;
public static final int POS_C = (POS_A + SIZE_A); public static final int POS_C = POS_A+SIZE_A;
public static final int POS_B = (POS_C + SIZE_C); public static final int POS_B = POS_C+SIZE_C;
public static final int POS_Bx = POS_C; public static final int POS_Bx = POS_C;
public static final int POS_Ax = POS_A; public static final int POS_Ax = POS_A;
public static final int MAX_OP = ((1<<SIZE_OP)-1); public static final int MAX_OP = (1<<SIZE_OP)-1;
public static final int MAXARG_A = ((1<<SIZE_A)-1); public static final int MAXARG_A = (1<<SIZE_A)-1;
public static final int MAXARG_B = ((1<<SIZE_B)-1); public static final int MAXARG_B = (1<<SIZE_B)-1;
public static final int MAXARG_C = ((1<<SIZE_C)-1); public static final int MAXARG_C = (1<<SIZE_C)-1;
public static final int MAXARG_Bx = ((1<<SIZE_Bx)-1); public static final int MAXARG_Bx = (1<<SIZE_Bx)-1;
public static final int MAXARG_sBx = (MAXARG_Bx>>1); /* `sBx' is signed */ public static final int MAXARG_sBx = MAXARG_Bx>>1; /* `sBx' is signed */
public static final int MAXARG_Ax = ((1<<SIZE_Ax)-1); public static final int MAXARG_Ax = (1<<SIZE_Ax)-1;
public static final int MASK_OP = ((1<<SIZE_OP)-1)<<POS_OP; public static final int MASK_OP = (1<<SIZE_OP)-1<<POS_OP;
public static final int MASK_A = ((1<<SIZE_A)-1)<<POS_A; public static final int MASK_A = (1<<SIZE_A)-1<<POS_A;
public static final int MASK_B = ((1<<SIZE_B)-1)<<POS_B; public static final int MASK_B = (1<<SIZE_B)-1<<POS_B;
public static final int MASK_C = ((1<<SIZE_C)-1)<<POS_C; public static final int MASK_C = (1<<SIZE_C)-1<<POS_C;
public static final int MASK_Bx = ((1<<SIZE_Bx)-1)<<POS_Bx; public static final int MASK_Bx = (1<<SIZE_Bx)-1<<POS_Bx;
public static final int MASK_Ax = ((1<<SIZE_Ax)-1)<<POS_Ax; public static final int MASK_Ax = (1<<SIZE_Ax)-1<<POS_Ax;
public static final int MASK_NOT_OP = ~MASK_OP; public static final int MASK_NOT_OP = ~MASK_OP;
public static final int MASK_NOT_A = ~MASK_A; public static final int MASK_NOT_A = ~MASK_A;
@@ -105,72 +102,68 @@ public class Lua {
** the following macros help to manipulate instructions ** the following macros help to manipulate instructions
*/ */
public static int GET_OPCODE(int i) { public static int GET_OPCODE(int i) {
return (i >> POS_OP) & MAX_OP; return i>>POS_OP & MAX_OP;
} }
public static int GETARG_A(int i) { public static int GETARG_A(int i) {
return (i >> POS_A) & MAXARG_A; return i>>POS_A & MAXARG_A;
} }
public static int GETARG_Ax(int i) { public static int GETARG_Ax(int i) {
return (i >> POS_Ax) & MAXARG_Ax; return i>>POS_Ax & MAXARG_Ax;
} }
public static int GETARG_B(int i) { public static int GETARG_B(int i) {
return (i >> POS_B) & MAXARG_B; return i>>POS_B & MAXARG_B;
} }
public static int GETARG_C(int i) { public static int GETARG_C(int i) {
return (i >> POS_C) & MAXARG_C; return i>>POS_C & MAXARG_C;
} }
public static int GETARG_Bx(int i) { public static int GETARG_Bx(int i) {
return (i >> POS_Bx) & MAXARG_Bx; return i>>POS_Bx & MAXARG_Bx;
} }
public static int GETARG_sBx(int i) { public static int GETARG_sBx(int i) {
return ((i >> POS_Bx) & MAXARG_Bx) - MAXARG_sBx; return (i>>POS_Bx & MAXARG_Bx)-MAXARG_sBx;
} }
/* /*
** Macros to operate RK indices ** Macros to operate RK indices
*/ */
/** this bit 1 means constant (0 means register) */ /** this bit 1 means constant (0 means register) */
public static final int BITRK = (1 << (SIZE_B - 1)); public static final int BITRK = 1<<SIZE_B-1;
/** test whether value is a constant */ /** test whether value is a constant */
public static boolean ISK(int x) { public static boolean ISK(int x) {
return 0 != ((x) & BITRK); return 0 != (x & BITRK);
} }
/** gets the index of the constant */ /** gets the index of the constant */
public static int INDEXK(int r) { public static int INDEXK(int r) {
return ((int)(r) & ~BITRK); return r & ~BITRK;
} }
public static final int MAXINDEXRK = (BITRK - 1); public static final int MAXINDEXRK = BITRK-1;
/** code a constant index as a RK value */ /** code a constant index as a RK value */
public static int RKASK(int x) { public static int RKASK(int x) {
return ((x) | BITRK); return x | BITRK;
} }
/** /**
** invalid register that fits in 8 bits ** invalid register that fits in 8 bits
*/ */
public static final int NO_REG = MAXARG_A; public static final int NO_REG = MAXARG_A;
/* /*
** R(x) - register ** R(x) - register
** Kst(x) - constant (in constant table) ** Kst(x) - constant (in constant table)
** RK(x) == if ISK(x) then Kst(INDEXK(x)) else R(x) ** RK(x) == if ISK(x) then Kst(INDEXK(x)) else R(x)
*/ */
/* /*
** grep "ORDER OP" if you change these enums ** 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 (*) All `skips' (pc++) assume that next instruction is a jump
===========================================================================*/ ===========================================================================*/
/* /*
** masks for instruction properties. The format is: ** masks for instruction properties. The format is:
** bits 0-1: op mode ** bits 0-1: op mode
@@ -280,62 +272,66 @@ public class Lua {
public static final int[] luaP_opmodes = { public static final int[] luaP_opmodes = {
/* T A B C mode opcode */ /* T A B C mode opcode */
(0<<7) | (1<<6) | (OpArgR<<4) | (OpArgN<<2) | (iABC), /* OP_MOVE */ 0<<7 | 1<<6 | OpArgR<<4 | OpArgN<<2 | iABC, /* OP_MOVE */
(0<<7) | (1<<6) | (OpArgK<<4) | (OpArgN<<2) | (iABx), /* OP_LOADK */ 0<<7 | 1<<6 | OpArgK<<4 | OpArgN<<2 | iABx, /* OP_LOADK */
(0<<7) | (1<<6) | (OpArgN<<4) | (OpArgN<<2) | (iABx), /* OP_LOADKX */ 0<<7 | 1<<6 | OpArgN<<4 | OpArgN<<2 | iABx, /* OP_LOADKX */
(0<<7) | (1<<6) | (OpArgU<<4) | (OpArgU<<2) | (iABC), /* OP_LOADBOOL */ 0<<7 | 1<<6 | OpArgU<<4 | OpArgU<<2 | iABC, /* OP_LOADBOOL */
(0<<7) | (1<<6) | (OpArgU<<4) | (OpArgN<<2) | (iABC), /* OP_LOADNIL */ 0<<7 | 1<<6 | OpArgU<<4 | OpArgN<<2 | iABC, /* OP_LOADNIL */
(0<<7) | (1<<6) | (OpArgU<<4) | (OpArgN<<2) | (iABC), /* OP_GETUPVAL */ 0<<7 | 1<<6 | OpArgU<<4 | OpArgN<<2 | iABC, /* OP_GETUPVAL */
(0<<7) | (1<<6) | (OpArgU<<4) | (OpArgK<<2) | (iABC), /* OP_GETTABUP */ 0<<7 | 1<<6 | OpArgU<<4 | OpArgK<<2 | iABC, /* OP_GETTABUP */
(0<<7) | (1<<6) | (OpArgR<<4) | (OpArgK<<2) | (iABC), /* OP_GETTABLE */ 0<<7 | 1<<6 | OpArgR<<4 | OpArgK<<2 | iABC, /* OP_GETTABLE */
(0<<7) | (0<<6) | (OpArgK<<4) | (OpArgK<<2) | (iABC), /* OP_SETTABUP */ 0<<7 | 0<<6 | OpArgK<<4 | OpArgK<<2 | iABC, /* OP_SETTABUP */
(0<<7) | (0<<6) | (OpArgU<<4) | (OpArgN<<2) | (iABC), /* OP_SETUPVAL */ 0<<7 | 0<<6 | OpArgU<<4 | OpArgN<<2 | iABC, /* OP_SETUPVAL */
(0<<7) | (0<<6) | (OpArgK<<4) | (OpArgK<<2) | (iABC), /* OP_SETTABLE */ 0<<7 | 0<<6 | OpArgK<<4 | OpArgK<<2 | iABC, /* OP_SETTABLE */
(0<<7) | (1<<6) | (OpArgU<<4) | (OpArgU<<2) | (iABC), /* OP_NEWTABLE */ 0<<7 | 1<<6 | OpArgU<<4 | OpArgU<<2 | iABC, /* OP_NEWTABLE */
(0<<7) | (1<<6) | (OpArgR<<4) | (OpArgK<<2) | (iABC), /* OP_SELF */ 0<<7 | 1<<6 | OpArgR<<4 | OpArgK<<2 | iABC, /* OP_SELF */
(0<<7) | (1<<6) | (OpArgK<<4) | (OpArgK<<2) | (iABC), /* OP_ADD */ 0<<7 | 1<<6 | OpArgK<<4 | OpArgK<<2 | iABC, /* OP_ADD */
(0<<7) | (1<<6) | (OpArgK<<4) | (OpArgK<<2) | (iABC), /* OP_SUB */ 0<<7 | 1<<6 | OpArgK<<4 | OpArgK<<2 | iABC, /* OP_SUB */
(0<<7) | (1<<6) | (OpArgK<<4) | (OpArgK<<2) | (iABC), /* OP_MUL */ 0<<7 | 1<<6 | OpArgK<<4 | OpArgK<<2 | iABC, /* OP_MUL */
(0<<7) | (1<<6) | (OpArgK<<4) | (OpArgK<<2) | (iABC), /* OP_DIV */ 0<<7 | 1<<6 | OpArgK<<4 | OpArgK<<2 | iABC, /* OP_DIV */
(0<<7) | (1<<6) | (OpArgK<<4) | (OpArgK<<2) | (iABC), /* OP_MOD */ 0<<7 | 1<<6 | OpArgK<<4 | OpArgK<<2 | iABC, /* OP_MOD */
(0<<7) | (1<<6) | (OpArgK<<4) | (OpArgK<<2) | (iABC), /* OP_POW */ 0<<7 | 1<<6 | OpArgK<<4 | OpArgK<<2 | iABC, /* OP_POW */
(0<<7) | (1<<6) | (OpArgR<<4) | (OpArgN<<2) | (iABC), /* OP_UNM */ 0<<7 | 1<<6 | OpArgR<<4 | OpArgN<<2 | iABC, /* OP_UNM */
(0<<7) | (1<<6) | (OpArgR<<4) | (OpArgN<<2) | (iABC), /* OP_NOT */ 0<<7 | 1<<6 | OpArgR<<4 | OpArgN<<2 | iABC, /* OP_NOT */
(0<<7) | (1<<6) | (OpArgR<<4) | (OpArgN<<2) | (iABC), /* OP_LEN */ 0<<7 | 1<<6 | OpArgR<<4 | OpArgN<<2 | iABC, /* OP_LEN */
(0<<7) | (1<<6) | (OpArgR<<4) | (OpArgR<<2) | (iABC), /* OP_CONCAT */ 0<<7 | 1<<6 | OpArgR<<4 | OpArgR<<2 | iABC, /* OP_CONCAT */
(0<<7) | (0<<6) | (OpArgR<<4) | (OpArgN<<2) | (iAsBx), /* OP_JMP */ 0<<7 | 0<<6 | OpArgR<<4 | OpArgN<<2 | iAsBx, /* OP_JMP */
(1<<7) | (0<<6) | (OpArgK<<4) | (OpArgK<<2) | (iABC), /* OP_EQ */ 1<<7 | 0<<6 | OpArgK<<4 | OpArgK<<2 | iABC, /* OP_EQ */
(1<<7) | (0<<6) | (OpArgK<<4) | (OpArgK<<2) | (iABC), /* OP_LT */ 1<<7 | 0<<6 | OpArgK<<4 | OpArgK<<2 | iABC, /* OP_LT */
(1<<7) | (0<<6) | (OpArgK<<4) | (OpArgK<<2) | (iABC), /* OP_LE */ 1<<7 | 0<<6 | OpArgK<<4 | OpArgK<<2 | iABC, /* OP_LE */
(1<<7) | (0<<6) | (OpArgN<<4) | (OpArgU<<2) | (iABC), /* OP_TEST */ 1<<7 | 0<<6 | OpArgN<<4 | OpArgU<<2 | iABC, /* OP_TEST */
(1<<7) | (1<<6) | (OpArgR<<4) | (OpArgU<<2) | (iABC), /* OP_TESTSET */ 1<<7 | 1<<6 | OpArgR<<4 | OpArgU<<2 | iABC, /* OP_TESTSET */
(0<<7) | (1<<6) | (OpArgU<<4) | (OpArgU<<2) | (iABC), /* OP_CALL */ 0<<7 | 1<<6 | OpArgU<<4 | OpArgU<<2 | iABC, /* OP_CALL */
(0<<7) | (1<<6) | (OpArgU<<4) | (OpArgU<<2) | (iABC), /* OP_TAILCALL */ 0<<7 | 1<<6 | OpArgU<<4 | OpArgU<<2 | iABC, /* OP_TAILCALL */
(0<<7) | (0<<6) | (OpArgU<<4) | (OpArgN<<2) | (iABC), /* OP_RETURN */ 0<<7 | 0<<6 | OpArgU<<4 | OpArgN<<2 | iABC, /* OP_RETURN */
(0<<7) | (1<<6) | (OpArgR<<4) | (OpArgN<<2) | (iAsBx), /* OP_FORLOOP */ 0<<7 | 1<<6 | OpArgR<<4 | OpArgN<<2 | iAsBx, /* OP_FORLOOP */
(0<<7) | (1<<6) | (OpArgR<<4) | (OpArgN<<2) | (iAsBx), /* OP_FORPREP */ 0<<7 | 1<<6 | OpArgR<<4 | OpArgN<<2 | iAsBx, /* OP_FORPREP */
(0<<7) | (0<<6) | (OpArgN<<4) | (OpArgU<<2) | (iABC), /* OP_TFORCALL */ 0<<7 | 0<<6 | OpArgN<<4 | OpArgU<<2 | iABC, /* OP_TFORCALL */
(1<<7) | (1<<6) | (OpArgR<<4) | (OpArgN<<2) | (iAsBx), /* OP_TFORLOOP */ 1<<7 | 1<<6 | OpArgR<<4 | OpArgN<<2 | iAsBx, /* OP_TFORLOOP */
(0<<7) | (0<<6) | (OpArgU<<4) | (OpArgU<<2) | (iABC), /* OP_SETLIST */ 0<<7 | 0<<6 | OpArgU<<4 | OpArgU<<2 | iABC, /* OP_SETLIST */
(0<<7) | (1<<6) | (OpArgU<<4) | (OpArgN<<2) | (iABx), /* OP_CLOSURE */ 0<<7 | 1<<6 | OpArgU<<4 | OpArgN<<2 | iABx, /* OP_CLOSURE */
(0<<7) | (1<<6) | (OpArgU<<4) | (OpArgN<<2) | (iABC), /* OP_VARARG */ 0<<7 | 1<<6 | OpArgU<<4 | OpArgN<<2 | iABC, /* OP_VARARG */
(0<<7) | (0<<6) | (OpArgU<<4) | (OpArgU<<2) | (iAx), /* OP_EXTRAARG */ 0<<7 | 0<<6 | OpArgU<<4 | OpArgU<<2 | iAx, /* OP_EXTRAARG */
}; };
public static int getOpMode(int m) { public static int getOpMode(int m) {
return luaP_opmodes[m] & 3; return luaP_opmodes[m] & 3;
} }
public static int getBMode(int m) { public static int getBMode(int m) {
return (luaP_opmodes[m] >> 4) & 3; return luaP_opmodes[m]>>4 & 3;
} }
public static int getCMode(int m) { public static int getCMode(int m) {
return (luaP_opmodes[m] >> 2) & 3; return luaP_opmodes[m]>>2 & 3;
} }
public static boolean testAMode(int m) { public static boolean testAMode(int m) {
return 0 != (luaP_opmodes[m] & (1 << 6)); return 0 != (luaP_opmodes[m] & 1<<6);
} }
public static boolean testTMode(int m) { public static boolean testTMode(int m) {
return 0 != (luaP_opmodes[m] & (1 << 7)); return 0 != (luaP_opmodes[m] & 1<<7);
} }
/* number of list items to accumulate before a SETLIST instruction */ /* number of list items to accumulate before a SETLIST instruction */

View File

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

View File

@@ -26,44 +26,56 @@ import org.luaj.vm2.lib.DebugLib.CallFrame;
/** /**
* Extension of {@link LuaFunction} which executes lua bytecode. * Extension of {@link LuaFunction} which executes lua bytecode.
* <p> * <p>
* A {@link LuaClosure} is a combination of a {@link Prototype} * A {@link LuaClosure} is a combination of a {@link Prototype} and a
* and a {@link LuaValue} to use as an environment for execution. * {@link LuaValue} to use as an environment for execution. Normally the
* Normally the {@link LuaValue} is a {@link Globals} in which case the environment * {@link LuaValue} is a {@link Globals} in which case the environment will
* will contain standard lua libraries. * contain standard lua libraries.
* *
* <p> * <p>
* There are three main ways {@link LuaClosure} instances are created: * There are three main ways {@link LuaClosure} instances are created:
* <ul> * <ul>
* <li>Construct an instance using {@link #LuaClosure(Prototype, LuaValue)}</li> * <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>Construct it indirectly by loading a chunk via
* <li>Execute the lua bytecode {@link Lua#OP_CLOSURE} as part of bytecode processing * {@link Globals#load(java.io.Reader, String)}
* <li>Execute the lua bytecode {@link Lua#OP_CLOSURE} as part of bytecode
* processing
* </ul> * </ul>
* <p> * <p>
* To construct it directly, the {@link Prototype} is typically created via a compiler such as * To construct it directly, the {@link Prototype} is typically created via a
* {@link org.luaj.vm2.compiler.LuaC}: * compiler such as {@link org.luaj.vm2.compiler.LuaC}:
* <pre> {@code *
* <pre>
* {
* &#64;code
* String script = "print( 'hello, world' )"; * String script = "print( 'hello, world' )";
* InputStream is = new ByteArrayInputStream(script.getBytes()); * InputStream is = new ByteArrayInputStream(script.getBytes());
* Prototype p = LuaC.instance.compile(is, "script"); * Prototype p = LuaC.instance.compile(is, "script");
* LuaValue globals = JsePlatform.standardGlobals(); * LuaValue globals = JsePlatform.standardGlobals();
* LuaClosure f = new LuaClosure(p, globals); * LuaClosure f = new LuaClosure(p, globals);
* f.call(); * f.call();
* }</pre> * }
* </pre>
* <p> * <p>
* To construct it indirectly, the {@link Globals#load(java.io.Reader, String)} method may be used: * To construct it indirectly, the {@link Globals#load(java.io.Reader, String)}
* <pre> {@code * method may be used:
*
* <pre>
* {
* &#64;code
* Globals globals = JsePlatform.standardGlobals(); * Globals globals = JsePlatform.standardGlobals();
* LuaFunction f = globals.load(new StringReader(script), "script"); * LuaFunction f = globals.load(new StringReader(script), "script");
* LuaClosure c = f.checkclosure(); // This may fail if LuaJC is installed. * LuaClosure c = f.checkclosure(); // This may fail if LuaJC is installed.
* c.call(); * c.call();
* }</pre> * }
* </pre>
* <p> * <p>
* In this example, the "checkclosure()" may fail if direct lua-to-java-bytecode * 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 * compiling using LuaJC is installed, because no LuaClosure is created in that
* and the value returned is a {@link LuaFunction} but not a {@link LuaClosure}. * case and the value returned is a {@link LuaFunction} but not a
* {@link LuaClosure}.
* <p> * <p>
* Since a {@link LuaClosure} is a {@link LuaFunction} which is a {@link LuaValue}, * Since a {@link LuaClosure} is a {@link LuaFunction} which is a
* all the value operations can be used directly such as: * {@link LuaValue}, all the value operations can be used directly such as:
* <ul> * <ul>
* <li>{@link LuaValue#call()}</li> * <li>{@link LuaValue#call()}</li>
* <li>{@link LuaValue#call(LuaValue)}</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>{@link LuaValue#invokemethod(String,Varargs)}</li>
* <li>...</li> * <li>...</li>
* </ul> * </ul>
*
* @see LuaValue * @see LuaValue
* @see LuaFunction * @see LuaFunction
* @see LuaValue#isclosure() * @see LuaValue#isclosure()
@@ -84,7 +97,7 @@ import org.luaj.vm2.lib.DebugLib.CallFrame;
* @see Globals#compiler * @see Globals#compiler
*/ */
public class LuaClosure extends LuaFunction { public class LuaClosure extends LuaFunction {
private static final UpValue[] NOUPVALUES = new UpValue[0]; private static final UpValue[] NOUPVALUES = {};
public final Prototype p; public final Prototype p;
@@ -92,8 +105,11 @@ public class LuaClosure extends LuaFunction {
final Globals globals; 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 p the Prototype to construct this Closure for.
* @param env the environment to associate with the closure. * @param env the environment to associate with the closure.
*/ */
@@ -103,6 +119,7 @@ public class LuaClosure extends LuaFunction {
globals = env instanceof Globals? (Globals) env: null; globals = env instanceof Globals? (Globals) env: null;
} }
@Override
public void initupvalue1(LuaValue env) { public void initupvalue1(LuaValue env) {
if (p.upvalues == null || p.upvalues.length == 0) if (p.upvalues == null || p.upvalues.length == 0)
this.upValues = NOUPVALUES; this.upValues = NOUPVALUES;
@@ -112,19 +129,22 @@ public class LuaClosure extends LuaFunction {
} }
} }
@Override
public boolean isclosure() { public boolean isclosure() {
return true; return true;
} }
@Override
public LuaClosure optclosure(LuaClosure defval) { public LuaClosure optclosure(LuaClosure defval) {
return this; return this;
} }
@Override
public LuaClosure checkclosure() { public LuaClosure checkclosure() {
return this; return this;
} }
@Override
public String tojstring() { public String tojstring() {
return "function: " + p.toString(); return "function: " + p.toString();
} }
@@ -136,42 +156,67 @@ public class LuaClosure extends LuaFunction {
return stack; return stack;
} }
@Override
public final LuaValue call() { public final LuaValue call() {
LuaValue[] stack = getNewStack(); LuaValue[] stack = getNewStack();
return execute(stack, NONE).arg1(); return execute(stack, NONE).arg1();
} }
@Override
public final LuaValue call(LuaValue arg) { public final LuaValue call(LuaValue arg) {
LuaValue[] stack = getNewStack(); LuaValue[] stack = getNewStack();
switch (p.numparams) { switch (p.numparams) {
default: stack[0]=arg; return execute(stack,NONE).arg1(); default:
case 0: return execute(stack,arg).arg1(); stack[0] = arg;
return execute(stack, NONE).arg1();
case 0:
return execute(stack, arg).arg1();
} }
} }
@Override
public final LuaValue call(LuaValue arg1, LuaValue arg2) { public final LuaValue call(LuaValue arg1, LuaValue arg2) {
LuaValue[] stack = getNewStack(); LuaValue[] stack = getNewStack();
switch (p.numparams) { switch (p.numparams) {
default: stack[0]=arg1; stack[1]=arg2; return execute(stack,NONE).arg1(); default:
case 1: stack[0]=arg1; return execute(stack,arg2).arg1(); stack[0] = arg1;
case 0: return execute(stack,p.is_vararg!=0? varargsOf(arg1,arg2): NONE).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();
} }
} }
@Override
public final LuaValue call(LuaValue arg1, LuaValue arg2, LuaValue arg3) { public final LuaValue call(LuaValue arg1, LuaValue arg2, LuaValue arg3) {
LuaValue[] stack = getNewStack(); LuaValue[] stack = getNewStack();
switch (p.numparams) { switch (p.numparams) {
default: stack[0]=arg1; stack[1]=arg2; stack[2]=arg3; return execute(stack,NONE).arg1(); default:
case 2: stack[0]=arg1; stack[1]=arg2; return execute(stack,arg3).arg1(); stack[0] = arg1;
case 1: stack[0]=arg1; return execute(stack,p.is_vararg!=0? varargsOf(arg2,arg3): NONE).arg1(); stack[1] = arg2;
case 0: return execute(stack,p.is_vararg!=0? varargsOf(arg1,arg2,arg3): NONE).arg1(); 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();
} }
} }
@Override
public final Varargs invoke(Varargs varargs) { public final Varargs invoke(Varargs varargs) {
return onInvoke(varargs).eval(); return onInvoke(varargs).eval();
} }
@Override
public final Varargs onInvoke(Varargs varargs) { public final Varargs onInvoke(Varargs varargs) {
LuaValue[] stack = getNewStack(); LuaValue[] stack = getNewStack();
for (int i = 0; i < p.numparams; i++) for (int i = 0; i < p.numparams; i++)
@@ -203,7 +248,7 @@ public class LuaClosure extends LuaFunction {
// pull out instruction // pull out instruction
i = code[pc]; i = code[pc];
a = ((i>>6) & 0xff); a = i>>6 & 0xff;
// process the op code // process the op code
switch (i & 0x3f) { switch (i & 0x3f) {
@@ -221,15 +266,15 @@ public class LuaClosure extends LuaFunction {
i = code[pc]; i = code[pc];
if ((i & 0x3f) != Lua.OP_EXTRAARG) { if ((i & 0x3f) != Lua.OP_EXTRAARG) {
int op = i & 0x3f; int op = i & 0x3f;
throw new LuaError("OP_EXTRAARG expected after OP_LOADKX, got " + throw new LuaError("OP_EXTRAARG expected after OP_LOADKX, got "
(op < Print.OPNAMES.length - 1 ? Print.OPNAMES[op] : "UNKNOWN_OP_" + op)); + (op < Print.OPNAMES.length-1? Print.OPNAMES[op]: "UNKNOWN_OP_" + op));
} }
stack[a] = k[i>>>6]; stack[a] = k[i>>>6];
continue; continue;
case Lua.OP_LOADBOOL:/* A B C R(A):= (Bool)B: if (C) pc++ */ case Lua.OP_LOADBOOL:/* A B C R(A):= (Bool)B: if (C) pc++ */
stack[a] = (i>>>23!=0)? LuaValue.TRUE: LuaValue.FALSE; stack[a] = i>>>23 != 0? LuaValue.TRUE: LuaValue.FALSE;
if ((i&(0x1ff<<14)) != 0) if ((i & 0x1ff<<14) != 0)
++pc; /* skip next instruction (if C) */ ++pc; /* skip next instruction (if C) */
continue; continue;
@@ -243,15 +288,16 @@ public class LuaClosure extends LuaFunction {
continue; continue;
case Lua.OP_GETTABUP: /* A B C R(A) := UpValue[B][RK(C)] */ case Lua.OP_GETTABUP: /* A B C R(A) := UpValue[B][RK(C)] */
stack[a] = upValues[i>>>23].getValue().get((c=(i>>14)&0x1ff)>0xff? k[c&0x0ff]: stack[c]); stack[a] = upValues[i>>>23].getValue().get((c = i>>14 & 0x1ff) > 0xff? k[c & 0x0ff]: stack[c]);
continue; continue;
case Lua.OP_GETTABLE: /* A B C R(A):= R(B)[RK(C)] */ case Lua.OP_GETTABLE: /* A B C R(A):= R(B)[RK(C)] */
stack[a] = stack[i>>>23].get((c=(i>>14)&0x1ff)>0xff? k[c&0x0ff]: stack[c]); stack[a] = stack[i>>>23].get((c = i>>14 & 0x1ff) > 0xff? k[c & 0x0ff]: stack[c]);
continue; continue;
case Lua.OP_SETTABUP: /* A B C UpValue[A][RK(B)] := RK(C) */ 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; continue;
case Lua.OP_SETUPVAL: /* A B UpValue[B]:= R(A) */ case Lua.OP_SETUPVAL: /* A B UpValue[B]:= R(A) */
@@ -259,40 +305,47 @@ public class LuaClosure extends LuaFunction {
continue; continue;
case Lua.OP_SETTABLE: /* A B C R(A)[RK(B)]:= RK(C) */ 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; continue;
case Lua.OP_NEWTABLE: /* A B C R(A):= {} (size = B,C) */ case Lua.OP_NEWTABLE: /* A B C R(A):= {} (size = B,C) */
stack[a] = new LuaTable(i>>>23,(i>>14)&0x1ff); stack[a] = new LuaTable(i>>>23, i>>14 & 0x1ff);
continue; continue;
case Lua.OP_SELF: /* A B C R(A+1):= R(B): R(A):= R(B)[RK(C)] */ case Lua.OP_SELF: /* A B C R(A+1):= R(B): R(A):= R(B)[RK(C)] */
stack[a+1] = (o = stack[i>>>23]); stack[a+1] = o = stack[i>>>23];
stack[a] = o.get((c=(i>>14)&0x1ff)>0xff? k[c&0x0ff]: stack[c]); stack[a] = o.get((c = i>>14 & 0x1ff) > 0xff? k[c & 0x0ff]: stack[c]);
continue; continue;
case Lua.OP_ADD: /* A B C R(A):= RK(B) + RK(C) */ 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; continue;
case Lua.OP_SUB: /* A B C R(A):= RK(B) - RK(C) */ 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; continue;
case Lua.OP_MUL: /* A B C R(A):= RK(B) * RK(C) */ 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; continue;
case Lua.OP_DIV: /* A B C R(A):= RK(B) / RK(C) */ 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; continue;
case Lua.OP_MOD: /* A B C R(A):= RK(B) % RK(C) */ 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; continue;
case Lua.OP_POW: /* A B C R(A):= RK(B) ^ RK(C) */ 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; continue;
case Lua.OP_UNM: /* A B R(A):= -R(B) */ case Lua.OP_UNM: /* A B R(A):= -R(B) */
@@ -309,8 +362,7 @@ public class LuaClosure extends LuaFunction {
case Lua.OP_CONCAT: /* A B C R(A):= R(B).. ... ..R(C) */ case Lua.OP_CONCAT: /* A B C R(A):= R(B).. ... ..R(C) */
b = i>>>23; b = i>>>23;
c = (i>>14)&0x1ff; c = i>>14 & 0x1ff; {
{
if (c > b+1) { if (c > b+1) {
Buffer sb = stack[c].buffer(); Buffer sb = stack[c].buffer();
while ( --c >= b ) while ( --c >= b )
@@ -334,28 +386,31 @@ public class LuaClosure extends LuaFunction {
continue; continue;
case Lua.OP_EQ: /* A B C if ((RK(B) == RK(C)) ~= A) then pc++ */ 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; ++pc;
continue; continue;
case Lua.OP_LT: /* A B C if ((RK(B) < RK(C)) ~= A) then pc++ */ case Lua.OP_LT: /* A B C if ((RK(B) < RK(C)) ~= A) then pc++ */
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; ++pc;
continue; continue;
case Lua.OP_LE: /* A B C if ((RK(B) <= RK(C)) ~= A) then pc++ */ case Lua.OP_LE: /* A B C if ((RK(B) <= RK(C)) ~= A) then pc++ */
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; ++pc;
continue; continue;
case Lua.OP_TEST: /* A C if not (R(A) <=> C) then pc++ */ case Lua.OP_TEST: /* A C if not (R(A) <=> C) then pc++ */
if ( stack[a].toboolean() != ((i&(0x1ff<<14))!=0) ) if (stack[a].toboolean() != ((i & 0x1ff<<14) != 0))
++pc; ++pc;
continue; continue;
case Lua.OP_TESTSET: /* A B C if (R(B) <=> C) then R(A):= R(B) else pc++ */ case Lua.OP_TESTSET: /* A B C if (R(B) <=> C) then R(A):= R(B) else pc++ */
/* note: doc appears to be reversed */ /* note: doc appears to be reversed */
if ( (o=stack[i>>>23]).toboolean() != ((i&(0x1ff<<14))!=0) ) if ((o = stack[i>>>23]).toboolean() != ((i & 0x1ff<<14) != 0))
++pc; ++pc;
else else
stack[a] = o; // TODO: should be sBx? stack[a] = o; // TODO: should be sBx?
@@ -363,21 +418,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)) */ 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)) { 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 1<<Lua.POS_B | 0<<Lua.POS_C:
case (2<<Lua.POS_B) | (0<<Lua.POS_C): v=stack[a].invoke(stack[a+1]); top=a+v.narg(); continue; v = stack[a].invoke(NONE);
case (1<<Lua.POS_B) | (1<<Lua.POS_C): stack[a].call(); continue; top = a+v.narg();
case (2<<Lua.POS_B) | (1<<Lua.POS_C): stack[a].call(stack[a+1]); continue; continue;
case (3<<Lua.POS_B) | (1<<Lua.POS_C): stack[a].call(stack[a+1],stack[a+2]); continue; case 2<<Lua.POS_B | 0<<Lua.POS_C:
case (4<<Lua.POS_B) | (1<<Lua.POS_C): stack[a].call(stack[a+1],stack[a+2],stack[a+3]); continue; v = stack[a].invoke(stack[a+1]);
case (1<<Lua.POS_B) | (2<<Lua.POS_C): stack[a] = stack[a].call(); continue; top = a+v.narg();
case (2<<Lua.POS_B) | (2<<Lua.POS_C): stack[a] = stack[a].call(stack[a+1]); continue; continue;
case (3<<Lua.POS_B) | (2<<Lua.POS_C): stack[a] = stack[a].call(stack[a+1],stack[a+2]); continue; case 1<<Lua.POS_B | 1<<Lua.POS_C:
case (4<<Lua.POS_B) | (2<<Lua.POS_C): stack[a] = stack[a].call(stack[a+1],stack[a+2],stack[a+3]); continue; 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: default:
b = i>>>23; b = i>>>23;
c = (i>>14)&0x1ff; c = i>>14 & 0x1ff;
v = stack[a].invoke(b>0? v = stack[a].invoke(b > 0? varargsOf(stack, a+1, b-1): // exact arg count
varargsOf(stack, a+1, b-1): // exact arg count
varargsOf(stack, a+1, top-v.narg()-(a+1), v)); // from prev top varargsOf(stack, a+1, top-v.narg()-(a+1), v)); // from prev top
if (c > 0) { if (c > 0) {
v.copyto(stack, a, c-1); v.copyto(stack, a, c-1);
@@ -391,14 +467,17 @@ public class LuaClosure extends LuaFunction {
case Lua.OP_TAILCALL: /* A B C return R(A)(R(A+1), ... ,R(A+B-1)) */ case Lua.OP_TAILCALL: /* A B C return R(A)(R(A+1), ... ,R(A+B-1)) */
switch (i & Lua.MASK_B) { switch (i & Lua.MASK_B) {
case (1<<Lua.POS_B): return new TailcallVarargs(stack[a], NONE); case 1<<Lua.POS_B:
case (2<<Lua.POS_B): return new TailcallVarargs(stack[a], stack[a+1]); return new TailcallVarargs(stack[a], NONE);
case (3<<Lua.POS_B): return new TailcallVarargs(stack[a], varargsOf(stack[a+1],stack[a+2])); case 2<<Lua.POS_B:
case (4<<Lua.POS_B): return new TailcallVarargs(stack[a], varargsOf(stack[a+1],stack[a+2],stack[a+3])); 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: default:
b = i>>>23; b = i>>>23;
v = b>0? v = b > 0? varargsOf(stack, a+1, b-1): // exact arg count
varargsOf(stack,a+1,b-1): // exact arg count
varargsOf(stack, a+1, top-v.narg()-(a+1), v); // from prev top varargsOf(stack, a+1, top-v.narg()-(a+1), v); // from prev top
return new TailcallVarargs(stack[a], v); return new TailcallVarargs(stack[a], v);
} }
@@ -406,9 +485,12 @@ public class LuaClosure extends LuaFunction {
case Lua.OP_RETURN: /* A B return R(A), ... ,R(A+B-2) (see note) */ case Lua.OP_RETURN: /* A B return R(A), ... ,R(A+B-2) (see note) */
b = i>>>23; b = i>>>23;
switch (b) { switch (b) {
case 0: return varargsOf(stack, a, top-v.narg()-a, v); case 0:
case 1: return NONE; return varargsOf(stack, a, top-v.narg()-a, v);
case 2: return stack[a]; case 1:
return NONE;
case 2:
return stack[a];
default: default:
return varargsOf(stack, a, b-1); return varargsOf(stack, a, b-1);
} }
@@ -440,7 +522,7 @@ public class LuaClosure extends LuaFunction {
case Lua.OP_TFORCALL: /* A C R(A+3), ... ,R(A+2+C) := R(A)(R(A+1), R(A+2)); */ case Lua.OP_TFORCALL: /* A C R(A+3), ... ,R(A+2+C) := R(A)(R(A+1), R(A+2)); */
v = stack[a].invoke(varargsOf(stack[a+1], stack[a+2])); v = stack[a].invoke(varargsOf(stack[a+1], stack[a+2]));
c = (i>>14) & 0x1ff; c = i>>14 & 0x1ff;
while ( --c >= 0 ) while ( --c >= 0 )
stack[a+3+c] = v.arg(c+1); stack[a+3+c] = v.arg(c+1);
v = NONE; v = NONE;
@@ -455,7 +537,7 @@ public class LuaClosure extends LuaFunction {
case Lua.OP_SETLIST: /* A B C R(A)[(C-1)*FPF+i]:= R(A+i), 1 <= i <= B */ case Lua.OP_SETLIST: /* A B C R(A)[(C-1)*FPF+i]:= R(A+i), 1 <= i <= B */
{ {
if ( (c=(i>>14)&0x1ff) == 0 ) if ((c = i>>14 & 0x1ff) == 0)
c = code[++pc]; c = code[++pc];
int offset = (c-1)*Lua.LFIELDS_PER_FLUSH; int offset = (c-1)*Lua.LFIELDS_PER_FLUSH;
o = stack[a]; o = stack[a];
@@ -528,15 +610,15 @@ public class LuaClosure extends LuaFunction {
/** /**
* Run the error hook if there is one * Run the error hook if there is one
*
* @param msg the message to use in error hook processing. * @param msg the message to use in error hook processing.
* */ */
String errorHook(String msg, int level) { String errorHook(String msg, int level) {
if (globals == null ) return msg; if (globals == null)
return msg;
final LuaThread r = globals.running; final LuaThread r = globals.running;
if (r.errorfunc == null) if (r.errorfunc == null)
return globals.debuglib != null? return globals.debuglib != null? msg + "\n" + globals.debuglib.traceback(level): msg;
msg + "\n" + globals.debuglib.traceback(level):
msg;
final LuaValue e = r.errorfunc; final LuaValue e = r.errorfunc;
r.errorfunc = null; r.errorfunc = null;
try { try {
@@ -590,9 +672,9 @@ public class LuaClosure extends LuaFunction {
upValues[i].setValue(v); upValues[i].setValue(v);
} }
@Override
public String name() { public String name() {
return "<" + p.shortsource() + ":" + p.linedefined + ">"; return "<" + p.shortsource() + ":" + p.linedefined + ">";
} }
} }

View File

@@ -21,6 +21,7 @@
******************************************************************************/ ******************************************************************************/
package org.luaj.vm2; package org.luaj.vm2;
import org.luaj.vm2.compat.JavaCompat;
import org.luaj.vm2.lib.MathLib; import org.luaj.vm2.lib.MathLib;
/** /**
@@ -33,8 +34,8 @@ import org.luaj.vm2.lib.MathLib;
* <p> * <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> * <p>
* However the constants {@link #NAN}, {@link #POSINF}, {@link #NEGINF}, * However the constants {@link #NAN}, {@link #NEGNAN}, {@link #POSINF}, {@link #NEGINF},
* {@link #JSTR_NAN}, {@link #JSTR_POSINF}, and {@link #JSTR_NEGINF} may be useful * {@link #JSTR_NAN}, {@link #JSTR_NEGNAN}, {@link #JSTR_POSINF}, and {@link #JSTR_NEGINF} may be useful
* when dealing with Nan or Infinite values. * when dealing with Nan or Infinite values.
* <p> * <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
@@ -56,6 +57,9 @@ public class LuaDouble extends LuaNumber {
/** Constant LuaDouble representing NaN (not a number) */ /** Constant LuaDouble representing NaN (not a number) */
public static final LuaDouble NAN = new LuaDouble( Double.NaN ); public static final LuaDouble NAN = new LuaDouble( Double.NaN );
/** Constant LuaDouble representing negative NaN (not a number) */
public static final LuaDouble NEGNAN = new LuaDouble( -Double.NaN );
/** Constant LuaDouble representing positive infinity */ /** Constant LuaDouble representing positive infinity */
public static final LuaDouble POSINF = new LuaDouble( Double.POSITIVE_INFINITY ); public static final LuaDouble POSINF = new LuaDouble( Double.POSITIVE_INFINITY );
@@ -65,6 +69,9 @@ public class LuaDouble extends LuaNumber {
/** Constant String representation for NaN (not a number), "nan" */ /** Constant String representation for NaN (not a number), "nan" */
public static final String JSTR_NAN = "nan"; public static final String JSTR_NAN = "nan";
/** Constant String representation for negative NaN (not a number), "-nan" */
public static final String JSTR_NEGNAN = "-nan";
/** Constant String representation for positive infinity, "inf" */ /** Constant String representation for positive infinity, "inf" */
public static final String JSTR_POSINF = "inf"; public static final String JSTR_POSINF = "inf";
@@ -235,17 +242,13 @@ public class LuaDouble extends LuaNumber {
public int strcmp( LuaString rhs ) { typerror("attempt to compare number with string"); return 0; } public int strcmp( LuaString rhs ) { typerror("attempt to compare number with string"); return 0; }
public String tojstring() { public String tojstring() {
/* if ( v == 0.0 ) // never occurs on J2ME
if ( v == 0.0 ) { // never occurs in J2me return (JavaCompat.INSTANCE.doubleToRawLongBits(v)<0? "-0": "0");
long bits = Double.doubleToLongBits( v );
return ( bits >> 63 == 0 ) ? "0" : "-0";
}
*/
long l = (long) v; long l = (long) v;
if ( l == v ) if ( l == v )
return Long.toString(l); return Long.toString(l);
if ( Double.isNaN(v) ) if ( Double.isNaN(v) )
return JSTR_NAN; return (JavaCompat.INSTANCE.doubleToRawLongBits(v)<0? JSTR_NEGNAN: JSTR_NAN);
if ( Double.isInfinite(v) ) if ( Double.isInfinite(v) )
return (v<0? JSTR_NEGINF: JSTR_POSINF); return (v<0? JSTR_NEGINF: JSTR_POSINF);
return Float.toString((float)v); return Float.toString((float)v);

View File

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

View File

@@ -21,71 +21,86 @@
******************************************************************************/ ******************************************************************************/
package org.luaj.vm2; package org.luaj.vm2;
/** /**
* Base class for functions implemented in Java. * Base class for functions implemented in Java.
* <p> * <p>
* Direct subclass include {@link org.luaj.vm2.lib.LibFunction} * Direct subclass include {@link org.luaj.vm2.lib.LibFunction} which is the
* which is the base class for * base class for all built-in library functions coded in Java, and
* all built-in library functions coded in Java, * {@link LuaClosure}, which represents a lua closure whose bytecode is
* and {@link LuaClosure}, which represents a lua closure * interpreted when the function is invoked.
* whose bytecode is interpreted when the function is invoked. *
* @see LuaValue * @see LuaValue
* @see LuaClosure * @see LuaClosure
* @see org.luaj.vm2.lib.LibFunction * @see org.luaj.vm2.lib.LibFunction
*/ */
abstract abstract public class LuaFunction extends LuaValue {
public class LuaFunction extends LuaValue {
/** Shared static metatable for all functions and closures. */ /** Shared static metatable for all functions and closures. */
public static LuaValue s_metatable; public static LuaValue s_metatable;
@Override
public int type() { public int type() {
return TFUNCTION; return TFUNCTION;
} }
@Override
public String typename() { public String typename() {
return "function"; return "function";
} }
@Override
public boolean isfunction() { public boolean isfunction() {
return true; return true;
} }
@Override
public LuaFunction checkfunction() { public LuaFunction checkfunction() {
return this; return this;
} }
@Override
public LuaFunction optfunction(LuaFunction defval) { public LuaFunction optfunction(LuaFunction defval) {
return this; return this;
} }
@Override
public LuaValue getmetatable() { public LuaValue getmetatable() {
return s_metatable; return s_metatable;
} }
@Override
public String tojstring() { public String tojstring() {
return "function: " + classnamestub(); return "function: " + classnamestub();
} }
@Override
public LuaString strvalue() { public LuaString strvalue() {
return valueOf(tojstring()); 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 ($). * Return the last part of the class name, to be used as a function name in
* If the first character is '_', it is skipped. * 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() { public String classnamestub() {
String s = getClass().getName(); String s = getClass().getName();
int offset = Math.max(s.lastIndexOf('.'), s.lastIndexOf('$'))+1; int offset = Math.max(s.lastIndexOf('.'), s.lastIndexOf('$'))+1;
if (s.charAt(offset) == '_') offset++; if (s.charAt(offset) == '_')
offset++;
return s.substring(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 a human-readable name for this function. Returns the last part of
* @return common name for this function. */ * 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() { public String name() {
return classnamestub(); return classnamestub();
} }

View File

@@ -0,0 +1,372 @@
/*******************************************************************************
* Copyright (c) 2009 Luaj.org. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
******************************************************************************/
package org.luaj.vm2;
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.
* <p>
* There are no API's specific to LuaInteger that are useful beyond what is
* already exposed in {@link LuaValue}.
*
* @see LuaValue
* @see LuaNumber
* @see LuaDouble
* @see LuaValue#valueOf(int)
* @see LuaValue#valueOf(double)
*/
public class LuaInteger extends LuaNumber {
private static final LuaInteger[] intValues = new LuaInteger[512];
static {
for (int i = 0; i < 512; i++)
intValues[i] = new LuaInteger(i-256);
}
public static LuaInteger valueOf(int i) {
return i <= 255 && i >= -256? intValues[i+256]: new LuaInteger(i);
}
// TODO consider moving this to LuaValue
/**
* 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)
* @see LuaValue#valueOf(double)
*/
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);
}
/** The value being held by this instance. */
public final int v;
/**
* Package protected constructor.
*
* @see LuaValue#valueOf(int)
**/
LuaInteger(int i) {
this.v = i;
}
@Override
public boolean isint() { return true; }
@Override
public boolean isinttype() { return true; }
@Override
public boolean islong() { return true; }
@Override
public byte tobyte() { return (byte) v; }
@Override
public char tochar() { return (char) v; }
@Override
public double todouble() { return v; }
@Override
public float tofloat() { return v; }
@Override
public int toint() { return v; }
@Override
public long tolong() { return v; }
@Override
public short toshort() { return (short) v; }
@Override
public double optdouble(double defval) { return v; }
@Override
public int optint(int defval) { return v; }
@Override
public LuaInteger optinteger(LuaInteger defval) { return this; }
@Override
public long optlong(long defval) { return v; }
@Override
public String tojstring() {
return Integer.toString(v);
}
@Override
public LuaString strvalue() {
return LuaString.valueOf(Integer.toString(v));
}
@Override
public LuaString optstring(LuaString defval) {
return LuaString.valueOf(Integer.toString(v));
}
@Override
public LuaValue tostring() {
return LuaString.valueOf(Integer.toString(v));
}
@Override
public String optjstring(String defval) {
return Integer.toString(v);
}
@Override
public LuaInteger checkinteger() {
return this;
}
@Override
public boolean isstring() {
return true;
}
@Override
public int hashCode() {
return v;
}
public static int hashCode(int x) {
return x;
}
// unary operators
@Override
public LuaValue neg() { return valueOf(-(long) v); }
// object equality, used for key comparison
@Override
public boolean equals(Object o) { return o instanceof LuaInteger? ((LuaInteger) o).v == v: false; }
// equality w/ metatable processing
@Override
public LuaValue eq(LuaValue val) { return val.raweq(v)? TRUE: FALSE; }
@Override
public boolean eq_b(LuaValue val) { return val.raweq(v); }
// equality w/o metatable processing
@Override
public boolean raweq(LuaValue val) { return val.raweq(v); }
@Override
public boolean raweq(double val) { return v == val; }
@Override
public boolean raweq(int val) { return v == val; }
// arithmetic operators
@Override
public LuaValue add(LuaValue rhs) { return rhs.add(v); }
@Override
public LuaValue add(double lhs) { return LuaDouble.valueOf(lhs+v); }
@Override
public LuaValue add(int lhs) { return LuaInteger.valueOf(lhs+(long) v); }
@Override
public LuaValue sub(LuaValue rhs) { return rhs.subFrom(v); }
@Override
public LuaValue sub(double rhs) { return LuaDouble.valueOf(v-rhs); }
@Override
public LuaValue sub(int rhs) { return LuaValue.valueOf(v-rhs); }
@Override
public LuaValue subFrom(double lhs) { return LuaDouble.valueOf(lhs-v); }
@Override
public LuaValue subFrom(int lhs) { return LuaInteger.valueOf(lhs-(long) v); }
@Override
public LuaValue mul(LuaValue rhs) { return rhs.mul(v); }
@Override
public LuaValue mul(double lhs) { return LuaDouble.valueOf(lhs*v); }
@Override
public LuaValue mul(int lhs) { return LuaInteger.valueOf(lhs*(long) v); }
@Override
public LuaValue pow(LuaValue rhs) { return rhs.powWith(v); }
@Override
public LuaValue pow(double rhs) { return MathLib.dpow(v, rhs); }
@Override
public LuaValue pow(int rhs) { return MathLib.dpow(v, rhs); }
@Override
public LuaValue powWith(double lhs) { return MathLib.dpow(lhs, v); }
@Override
public LuaValue powWith(int lhs) { return MathLib.dpow(lhs, v); }
@Override
public LuaValue div(LuaValue rhs) { return rhs.divInto(v); }
@Override
public LuaValue div(double rhs) { return LuaDouble.ddiv(v, rhs); }
@Override
public LuaValue div(int rhs) { return LuaDouble.ddiv(v, rhs); }
@Override
public LuaValue divInto(double lhs) { return LuaDouble.ddiv(lhs, v); }
@Override
public LuaValue mod(LuaValue rhs) { return rhs.modFrom(v); }
@Override
public LuaValue mod(double rhs) { return LuaDouble.dmod(v, rhs); }
@Override
public LuaValue mod(int rhs) { return LuaDouble.dmod(v, rhs); }
@Override
public LuaValue modFrom(double lhs) { return LuaDouble.dmod(lhs, v); }
// relational operators
@Override
public LuaValue lt(LuaValue rhs) { return rhs instanceof LuaNumber? rhs.gt_b(v)? TRUE: FALSE: super.lt(rhs); }
@Override
public LuaValue lt(double rhs) { return v < rhs? TRUE: FALSE; }
@Override
public LuaValue lt(int rhs) { return v < rhs? TRUE: FALSE; }
@Override
public boolean lt_b(LuaValue rhs) { return rhs instanceof LuaNumber? rhs.gt_b(v): super.lt_b(rhs); }
@Override
public boolean lt_b(int rhs) { return v < rhs; }
@Override
public boolean lt_b(double rhs) { return v < rhs; }
@Override
public LuaValue lteq(LuaValue rhs) {
return rhs instanceof LuaNumber? rhs.gteq_b(v)? TRUE: FALSE: super.lteq(rhs);
}
@Override
public LuaValue lteq(double rhs) { return v <= rhs? TRUE: FALSE; }
@Override
public LuaValue lteq(int rhs) { return v <= rhs? TRUE: FALSE; }
@Override
public boolean lteq_b(LuaValue rhs) { return rhs instanceof LuaNumber? rhs.gteq_b(v): super.lteq_b(rhs); }
@Override
public boolean lteq_b(int rhs) { return v <= rhs; }
@Override
public boolean lteq_b(double rhs) { return v <= rhs; }
@Override
public LuaValue gt(LuaValue rhs) { return rhs instanceof LuaNumber? rhs.lt_b(v)? TRUE: FALSE: super.gt(rhs); }
@Override
public LuaValue gt(double rhs) { return v > rhs? TRUE: FALSE; }
@Override
public LuaValue gt(int rhs) { return v > rhs? TRUE: FALSE; }
@Override
public boolean gt_b(LuaValue rhs) { return rhs instanceof LuaNumber? rhs.lt_b(v): super.gt_b(rhs); }
@Override
public boolean gt_b(int rhs) { return v > rhs; }
@Override
public boolean gt_b(double rhs) { return v > rhs; }
@Override
public LuaValue gteq(LuaValue rhs) {
return rhs instanceof LuaNumber? rhs.lteq_b(v)? TRUE: FALSE: super.gteq(rhs);
}
@Override
public LuaValue gteq(double rhs) { return v >= rhs? TRUE: FALSE; }
@Override
public LuaValue gteq(int rhs) { return v >= rhs? TRUE: FALSE; }
@Override
public boolean gteq_b(LuaValue rhs) { return rhs instanceof LuaNumber? rhs.lteq_b(v): super.gteq_b(rhs); }
@Override
public boolean gteq_b(int rhs) { return v >= rhs; }
@Override
public boolean gteq_b(double rhs) { return v >= rhs; }
// string comparison
@Override
public int strcmp(LuaString rhs) { typerror("attempt to compare number with string"); return 0; }
@Override
public int checkint() {
return v;
}
@Override
public long checklong() {
return v;
}
@Override
public double checkdouble() {
return v;
}
@Override
public String checkjstring() {
return String.valueOf(v);
}
@Override
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} * Class to encapsulate behavior of the singleton instance {@code nil}
* <p> * <p>
* There will be one instance of this class, {@link LuaValue#NIL}, * There will be one instance of this class, {@link LuaValue#NIL}, per Java
* per Java virtual machine. * virtual machine. However, the {@link Varargs} instance {@link LuaValue#NONE}
* However, the {@link Varargs} instance {@link LuaValue#NONE} * which is the empty list, is also considered treated as a nil value by
* which is the empty list, * default.
* is also considered treated as a nil value by default.
* <p> * <p>
* Although it is possible to test for nil using Java == operator, * Although it is possible to test for nil using Java == operator, the
* the recommended approach is to use the method {@link LuaValue#isnil()} * recommended approach is to use the method {@link LuaValue#isnil()} instead.
* instead. By using that any ambiguities between * By using that any ambiguities between {@link LuaValue#NIL} and
* {@link LuaValue#NIL} and {@link LuaValue#NONE} are avoided. * {@link LuaValue#NONE} are avoided.
*
* @see LuaValue * @see LuaValue
* @see LuaValue#NIL * @see LuaValue#NIL
*/ */
@@ -45,64 +45,104 @@ public class LuaNil extends LuaValue {
LuaNil() {} LuaNil() {}
@Override
public int type() { public int type() {
return LuaValue.TNIL; return LuaValue.TNIL;
} }
@Override
public String toString() { public String toString() {
return "nil"; return "nil";
} }
@Override
public String typename() { public String typename() {
return "nil"; return "nil";
} }
@Override
public String tojstring() { public String tojstring() {
return "nil"; return "nil";
} }
@Override
public LuaValue not() { public LuaValue not() {
return LuaValue.TRUE; return LuaValue.TRUE;
} }
@Override
public boolean toboolean() { public boolean toboolean() {
return false; return false;
} }
@Override
public boolean isnil() { public boolean isnil() {
return true; return true;
} }
@Override
public LuaValue getmetatable() { public LuaValue getmetatable() {
return s_metatable; return s_metatable;
} }
@Override
public boolean equals(Object o) { public boolean equals(Object o) {
return o instanceof LuaNil; return o instanceof LuaNil;
} }
@Override
public LuaValue checknotnil() { public LuaValue checknotnil() {
return argerror("value"); return argerror("value");
} }
@Override
public boolean isvalidkey() { public boolean isvalidkey() {
return false; return false;
} }
// optional argument conversions - nil alwas falls badk to default value // optional argument conversions - nil alwas falls badk to default value
@Override
public boolean optboolean(boolean defval) { return defval; } public boolean optboolean(boolean defval) { return defval; }
@Override
public LuaClosure optclosure(LuaClosure defval) { return defval; } public LuaClosure optclosure(LuaClosure defval) { return defval; }
@Override
public double optdouble(double defval) { return defval; } public double optdouble(double defval) { return defval; }
@Override
public LuaFunction optfunction(LuaFunction defval) { return defval; } public LuaFunction optfunction(LuaFunction defval) { return defval; }
@Override
public int optint(int defval) { return defval; } public int optint(int defval) { return defval; }
@Override
public LuaInteger optinteger(LuaInteger defval) { return defval; } public LuaInteger optinteger(LuaInteger defval) { return defval; }
@Override
public long optlong(long defval) { return defval; } public long optlong(long defval) { return defval; }
@Override
public LuaNumber optnumber(LuaNumber defval) { return defval; } public LuaNumber optnumber(LuaNumber defval) { return defval; }
@Override
public LuaTable opttable(LuaTable defval) { return defval; } public LuaTable opttable(LuaTable defval) { return defval; }
@Override
public LuaThread optthread(LuaThread defval) { return defval; } public LuaThread optthread(LuaThread defval) { return defval; }
@Override
public String optjstring(String defval) { return defval; } public String optjstring(String defval) { return defval; }
@Override
public LuaString optstring(LuaString defval) { return defval; } public LuaString optstring(LuaString defval) { return defval; }
@Override
public Object optuserdata(Object defval) { return defval; } public Object optuserdata(Object defval) { return defval; }
@Override
public Object optuserdata(Class c, Object defval) { return defval; } public Object optuserdata(Class c, Object defval) { return defval; }
@Override
public LuaValue optvalue(LuaValue defval) { return defval; } public LuaValue optvalue(LuaValue defval) { return defval; }
} }

View File

@@ -24,58 +24,74 @@ package org.luaj.vm2;
/** /**
* Base class for representing numbers as lua values directly. * Base class for representing numbers as lua values directly.
* <p> * <p>
* The main subclasses are {@link LuaInteger} which holds values that fit in a java int, * The main subclasses are {@link LuaInteger} which holds values that fit in a
* and {@link LuaDouble} which holds all other number values. * java int, and {@link LuaDouble} which holds all other number values.
*
* @see LuaInteger * @see LuaInteger
* @see LuaDouble * @see LuaDouble
* @see LuaValue * @see LuaValue
* *
*/ */
abstract abstract public class LuaNumber extends LuaValue {
public class LuaNumber extends LuaValue {
/** Shared static metatable for all number values represented in lua. */ /** Shared static metatable for all number values represented in lua. */
public static LuaValue s_metatable; public static LuaValue s_metatable;
@Override
public int type() { public int type() {
return TNUMBER; return TNUMBER;
} }
@Override
public String typename() { public String typename() {
return "number"; return "number";
} }
@Override
public LuaNumber checknumber() { public LuaNumber checknumber() {
return this; return this;
} }
@Override
public LuaNumber checknumber(String errmsg) { public LuaNumber checknumber(String errmsg) {
return this; return this;
} }
@Override
public LuaNumber optnumber(LuaNumber defval) { public LuaNumber optnumber(LuaNumber defval) {
return this; return this;
} }
@Override
public LuaValue tonumber() { public LuaValue tonumber() {
return this; return this;
} }
@Override
public boolean isnumber() { public boolean isnumber() {
return true; return true;
} }
@Override
public boolean isstring() { public boolean isstring() {
return true; return true;
} }
@Override
public LuaValue getmetatable() { public LuaValue getmetatable() {
return s_metatable; return s_metatable;
} }
@Override
public LuaValue concat(LuaValue rhs) { return rhs.concatTo(this); } public LuaValue concat(LuaValue rhs) { return rhs.concatTo(this); }
@Override
public Buffer concat(Buffer rhs) { return rhs.concatTo(this); } public Buffer concat(Buffer rhs) { return rhs.concatTo(this); }
@Override
public LuaValue concatTo(LuaNumber lhs) { return strvalue().concatTo(lhs.strvalue()); } public LuaValue concatTo(LuaNumber lhs) { return strvalue().concatTo(lhs.strvalue()); }
@Override
public LuaValue concatTo(LuaString lhs) { return strvalue().concatTo(lhs); } public LuaValue concatTo(LuaString lhs) { return strvalue().concatTo(lhs); }
} }

View File

@@ -639,9 +639,15 @@ public class LuaString extends LuaValue {
public static String decodeAsUtf8(byte[] bytes, int offset, int length) { public static String decodeAsUtf8(byte[] bytes, int offset, int length) {
int i,j,n,b; int i,j,n,b;
for ( i=offset,j=offset+length,n=0; i<j; ++n ) { for ( i=offset,j=offset+length,n=0; i<j; ++n ) {
switch ( 0xE0 & bytes[i++] ) { byte v = bytes[i++];
case 0xE0: ++i; if ((v & 0xC0) == 0xC0) {
case 0xC0: ++i; ++i;
if ((v & 0xE0) == 0xE0) {
++i;
if ((v & 0xF0) == 0xF0) {
++i;
}
}
} }
} }
char[] chars=new char[n]; char[] chars=new char[n];
@@ -665,9 +671,22 @@ public class LuaString extends LuaValue {
public static int lengthAsUtf8(char[] chars) { public static int lengthAsUtf8(char[] chars) {
int i, b; int i, b;
char c; char c;
for ( i=b=chars.length; --i>=0; ) for (i = 0, b = 0; i < chars.length; i++) {
if ( (c=chars[i]) >=0x80 ) if ((c = chars[i]) < 0x80 || (c >= 0xdc00 && c < 0xe000)) {
b += (c>=0x800)? 2: 1; b += 1;
} else if (c < 0x800) {
b += 2;
} else if (c >= 0xd800 && c < 0xdc00) {
if (i + 1 < chars.length && chars[i+1] >= 0xdc00 && chars[i+1] < 0xe000) {
b += 4;
i++;
} else {
b += 1;
}
} else {
b += 3;
}
}
return b; return b;
} }
@@ -693,10 +712,22 @@ public class LuaString extends LuaValue {
if ((c = chars[i]) < 0x80) { if ((c = chars[i]) < 0x80) {
bytes[j++] = (byte) c; bytes[j++] = (byte) c;
} else if (c < 0x800) { } else if (c < 0x800) {
bytes[j++] = (byte) (0xC0 | ((c>>6) & 0x1f)); bytes[j++] = (byte) (0xC0 | ((c >> 6)));
bytes[j++] = (byte) (0x80 | (c & 0x3f)); bytes[j++] = (byte) (0x80 | (c & 0x3f));
} else if (c >= 0xd800 && c < 0xdc00) {
if (i + 1 < nchars && chars[i+1] >= 0xdc00 && chars[i+1] < 0xe000) {
int uc = 0x10000 + (((c & 0x3ff) << 10) | (chars[++i] & 0x3ff));
bytes[j++] = (byte) (0xF0 | ((uc >> 18)));
bytes[j++] = (byte) (0x80 | ((uc >> 12) & 0x3f));
bytes[j++] = (byte) (0x80 | ((uc >> 6) & 0x3f));
bytes[j++] = (byte) (0x80 | (uc & 0x3f));
} else { } else {
bytes[j++] = (byte) (0xE0 | ((c>>12) & 0x0f)); bytes[j++] = (byte) '?';
}
} else if (c >= 0xdc00 && c < 0xe000) {
bytes[j++] = (byte) '?';
} else {
bytes[j++] = (byte) (0xE0 | ((c >> 12)));
bytes[j++] = (byte) (0x80 | ((c >> 6) & 0x3f)); bytes[j++] = (byte) (0x80 | ((c >> 6) & 0x3f));
bytes[j++] = (byte) (0x80 | (c & 0x3f)); bytes[j++] = (byte) (0x80 | (c & 0x3f));
} }
@@ -713,14 +744,14 @@ public class LuaString extends LuaValue {
public boolean isValidUtf8() { public boolean isValidUtf8() {
for (int i = m_offset, j = m_offset + m_length; i < j;) { for (int i = m_offset, j = m_offset + m_length; i < j;) {
int c = m_bytes[i++]; int c = m_bytes[i++];
if ( c >= 0 ) continue; if (c >= 0)
if ( ((c & 0xE0) == 0xC0) continue;
&& i<j if (((c & 0xE0) == 0xC0) && i < j && (m_bytes[i++] & 0xC0) == 0x80)
&& (m_bytes[i++] & 0xC0) == 0x80) continue; continue;
if ( ((c & 0xF0) == 0xE0) if (((c & 0xF0) == 0xE0) && i + 1 < j && (m_bytes[i++] & 0xC0) == 0x80 && (m_bytes[i++] & 0xC0) == 0x80)
&& i+1<j continue;
&& (m_bytes[i++] & 0xC0) == 0x80 if (((c & 0xF8) == 0xF0) && i + 2 < j && (m_bytes[i++] & 0xC0) == 0x80 && (m_bytes[i++] & 0xC0) == 0x80 && (m_bytes[i++] & 0xC0) == 0x80)
&& (m_bytes[i++] & 0xC0) == 0x80) continue; continue;
return false; return false;
} }
return true; return true;
@@ -750,6 +781,22 @@ public class LuaString extends LuaValue {
return Double.isNaN(d)? NIL: valueOf(d); return Double.isNaN(d)? NIL: valueOf(d);
} }
private boolean isspace(byte c) {
return c == ' ' || (c >= '\t' && c <= '\r');
}
private boolean isdigit(byte c) {
return (c >= '0' && c <= '9');
}
private boolean isxdigit(byte c) {
return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F');
}
private int hexvalue(byte c) {
return c <= '9' ? c - '0' : c <= 'F' ? c + 10 - 'A' : c + 10 - 'a';
}
/** /**
* Convert to a number in base 10, or base 16 if the string starts with '0x', * 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. * or return Double.NaN if it cannot be converted to a number.
@@ -757,14 +804,63 @@ public class LuaString extends LuaValue {
*/ */
public double scannumber() { public double scannumber() {
int i = m_offset, j = m_offset + m_length; int i = m_offset, j = m_offset + m_length;
while ( i<j && m_bytes[i]==' ' ) ++i; while (i < j && isspace(m_bytes[i]))
while ( i<j && m_bytes[j-1]==' ' ) --j; ++i;
while (i < j && isspace(m_bytes[j - 1]))
--j;
if (i >= j) if (i >= j)
return Double.NaN; return Double.NaN;
if ( m_bytes[i]=='0' && i+1<j && (m_bytes[i+1]=='x'||m_bytes[i+1]=='X')) if (indexOf((byte) 'x', i - m_offset) != -1 || indexOf((byte) 'X', i - m_offset) != -1)
return scanlong(16, i+2, j); return strx2number(i, j);
double l = scanlong(10, i, j); return scandouble(i, j);
return Double.isNaN(l)? scandouble(i,j): l; }
private double strx2number(int start, int end) {
double sgn = (m_bytes[start] == '-') ? -1.0 : 1.0;
if (sgn == -1.0 || m_bytes[start] == '+')
++start;
if (start + 2 >= end)
return Double.NaN;
if (m_bytes[start++] != '0')
return Double.NaN;
if (m_bytes[start] != 'x' && m_bytes[start] != 'X')
return Double.NaN;
++start;
double m = 0;
int e = 0;
boolean i = isxdigit(m_bytes[start]);
while (start < end && isxdigit(m_bytes[start]))
m = (m * 16) + hexvalue(m_bytes[start++]);
if (start < end && m_bytes[start] == '.') {
++start;
while (start < end && isxdigit(m_bytes[start])) {
m = (m * 16) + hexvalue(m_bytes[start++]);
e -= 4;
}
}
if (!i && e == 0)
return Double.NaN;
if (start < end && (m_bytes[start] == 'p' || m_bytes[start] == 'P')) {
++start;
int exp1 = 0;
boolean neg1 = false;
if (start < end) {
if (m_bytes[start] == '-')
neg1 = true;
if (neg1 || m_bytes[start] == '+')
++start;
}
if (start >= end || !isdigit(m_bytes[start]))
return Double.NaN;
while (start < end && isdigit(m_bytes[start]))
exp1 = exp1 * 10 + m_bytes[start++] - '0';
if (neg1)
exp1 = -exp1;
e += exp1;
}
if (start != end)
return Double.NaN;
return sgn * m * MathLib.dpow_d(2.0, e);
} }
/** /**
@@ -776,8 +872,8 @@ public class LuaString extends LuaValue {
if ( base < 2 || base > 36 ) if ( base < 2 || base > 36 )
return Double.NaN; return Double.NaN;
int i=m_offset,j=m_offset+m_length; int i=m_offset,j=m_offset+m_length;
while ( i<j && m_bytes[i]==' ' ) ++i; while ( i<j && isspace(m_bytes[i]) ) ++i;
while ( i<j && m_bytes[j-1]==' ' ) --j; while ( i<j && isspace(m_bytes[j-1]) ) --j;
if ( i>=j ) if ( i>=j )
return Double.NaN; return Double.NaN;
return scanlong( base, i, j ); return scanlong( base, i, j );
@@ -794,7 +890,8 @@ public class LuaString extends LuaValue {
private double scanlong( int base, int start, int end ) { private double scanlong( int base, int start, int end ) {
long x = 0; long x = 0;
boolean neg = (m_bytes[start] == '-'); boolean neg = (m_bytes[start] == '-');
for ( int i=(neg?start+1:start); i<end; i++ ) { if (neg || m_bytes[start] == '+') start++;
for ( int i=start; i<end; i++ ) {
int digit = m_bytes[i] - (base<=10||(m_bytes[i]>='0'&&m_bytes[i]<='9')? '0': 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)); m_bytes[i]>='A'&&m_bytes[i]<='Z'? ('A'-10): ('a'-10));
if ( digit < 0 || digit >= base ) if ( digit < 0 || digit >= base )

View File

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

View File

@@ -21,7 +21,6 @@
******************************************************************************/ ******************************************************************************/
package org.luaj.vm2; package org.luaj.vm2;
public class LuaUserdata extends LuaValue { public class LuaUserdata extends LuaValue {
public Object m_instance; public Object m_instance;
@@ -36,18 +35,22 @@ public class LuaUserdata extends LuaValue {
m_metatable = metatable; m_metatable = metatable;
} }
@Override
public String tojstring() { public String tojstring() {
return String.valueOf(m_instance); return String.valueOf(m_instance);
} }
@Override
public int type() { public int type() {
return LuaValue.TUSERDATA; return LuaValue.TUSERDATA;
} }
@Override
public String typename() { public String typename() {
return "userdata"; return "userdata";
} }
@Override
public int hashCode() { public int hashCode() {
return m_instance.hashCode(); return m_instance.hashCode();
} }
@@ -56,45 +59,63 @@ public class LuaUserdata extends LuaValue {
return m_instance; return m_instance;
} }
@Override
public boolean isuserdata() { return true; } public boolean isuserdata() { return true; }
@Override
public boolean isuserdata(Class c) { return c.isAssignableFrom(m_instance.getClass()); } public boolean isuserdata(Class c) { return c.isAssignableFrom(m_instance.getClass()); }
@Override
public Object touserdata() { return m_instance; } public Object touserdata() { return m_instance; }
@Override
public Object touserdata(Class c) { return c.isAssignableFrom(m_instance.getClass())? m_instance: null; } public Object touserdata(Class c) { return c.isAssignableFrom(m_instance.getClass())? m_instance: null; }
@Override
public Object optuserdata(Object defval) { return m_instance; } public Object optuserdata(Object defval) { return m_instance; }
@Override
public Object optuserdata(Class c, Object defval) { public Object optuserdata(Class c, Object defval) {
if (!c.isAssignableFrom(m_instance.getClass())) if (!c.isAssignableFrom(m_instance.getClass()))
typerror(c.getName()); typerror(c.getName());
return m_instance; return m_instance;
} }
@Override
public LuaValue getmetatable() { public LuaValue getmetatable() {
return m_metatable; return m_metatable;
} }
@Override
public LuaValue setmetatable(LuaValue metatable) { public LuaValue setmetatable(LuaValue metatable) {
this.m_metatable = metatable; this.m_metatable = metatable;
return this; return this;
} }
@Override
public Object checkuserdata() { public Object checkuserdata() {
return m_instance; return m_instance;
} }
@Override
public Object checkuserdata(Class c) { public Object checkuserdata(Class c) {
if (c.isAssignableFrom(m_instance.getClass())) if (c.isAssignableFrom(m_instance.getClass()))
return m_instance; return m_instance;
return typerror(c.getName()); return typerror(c.getName());
} }
@Override
public LuaValue get(LuaValue key) { public LuaValue get(LuaValue key) {
return m_metatable != null? gettable(this, key): NIL; return m_metatable != null? gettable(this, key): NIL;
} }
@Override
public void set(LuaValue key, LuaValue value) { public void set(LuaValue key, LuaValue value) {
if (m_metatable == null || !settable(this, key, value)) if (m_metatable == null || !settable(this, key, value))
error("cannot set " + key + " for userdata"); error("cannot set " + key + " for userdata");
} }
@Override
public boolean equals(Object val) { public boolean equals(Object val) {
if (this == val) if (this == val)
return true; return true;
@@ -105,22 +126,31 @@ public class LuaUserdata extends LuaValue {
} }
// equality w/ metatable processing // equality w/ metatable processing
@Override
public LuaValue eq(LuaValue val) { return eq_b(val)? TRUE: FALSE; } public LuaValue eq(LuaValue val) { return eq_b(val)? TRUE: FALSE; }
@Override
public boolean eq_b(LuaValue val) { public boolean eq_b(LuaValue val) {
if ( val.raweq(this) ) return true; if (val.raweq(this))
if ( m_metatable == null || !val.isuserdata() ) return false; return true;
if (m_metatable == null || !val.isuserdata())
return false;
LuaValue valmt = val.getmetatable(); LuaValue valmt = val.getmetatable();
return valmt != null && LuaValue.eqmtcall(this, m_metatable, val, valmt); return valmt != null && LuaValue.eqmtcall(this, m_metatable, val, valmt);
} }
// equality w/o metatable processing // equality w/o metatable processing
@Override
public boolean raweq(LuaValue val) { return val.raweq(this); } public boolean raweq(LuaValue val) { return val.raweq(this); }
@Override
public boolean raweq(LuaUserdata val) { public boolean raweq(LuaUserdata val) {
return this == val || (m_metatable == val.m_metatable && m_instance.equals(val.m_instance)); return this == val || m_metatable == val.m_metatable && m_instance.equals(val.m_instance);
} }
// __eq metatag processing // __eq metatag processing
public boolean eqmt(LuaValue val) { 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;
} }
} }

View File

@@ -99,7 +99,7 @@ package org.luaj.vm2;
* {@link #INDEX}, {@link #NEWINDEX}, {@link #CALL}, {@link #MODE}, {@link #METATABLE}, * {@link #INDEX}, {@link #NEWINDEX}, {@link #CALL}, {@link #MODE}, {@link #METATABLE},
* {@link #ADD}, {@link #SUB}, {@link #DIV}, {@link #MUL}, {@link #POW}, * {@link #ADD}, {@link #SUB}, {@link #DIV}, {@link #MUL}, {@link #POW},
* {@link #MOD}, {@link #UNM}, {@link #LEN}, {@link #EQ}, {@link #LT}, * {@link #MOD}, {@link #UNM}, {@link #LEN}, {@link #EQ}, {@link #LT},
* {@link #LE}, {@link #TOSTRING}, and {@link #CONCAT}. * {@link #LE}, {@link #TOSTRING}, {@link #CONCAT}, {@link PAIRS} and {@link IPAIRS}.
* *
* @see org.luaj.vm2.lib.jse.JsePlatform * @see org.luaj.vm2.lib.jse.JsePlatform
* @see org.luaj.vm2.lib.jme.JmePlatform * @see org.luaj.vm2.lib.jme.JmePlatform
@@ -243,6 +243,12 @@ public class LuaValue extends Varargs {
/** LuaString constant with value "__concat" for use as metatag */ /** LuaString constant with value "__concat" for use as metatag */
public static final LuaString CONCAT = valueOf("__concat"); public static final LuaString CONCAT = valueOf("__concat");
/** LuaString constant with value "__pairs" for use as metatag */
public static final LuaString PAIRS = valueOf("__pairs");
/** LuaString constant with value "__ipairs" for use as metatag */
public static final LuaString IPAIRS = valueOf("__ipairs");
/** LuaString constant with value "" */ /** LuaString constant with value "" */
public static final LuaString EMPTYSTRING = valueOf(""); public static final LuaString EMPTYSTRING = valueOf("");
@@ -529,7 +535,7 @@ public class LuaValue extends Varargs {
* @see #isstring() * @see #isstring()
* @see #TSTRING * @see #TSTRING
*/ */
public String tojstring() { return typename() + ": " + Integer.toHexString(hashCode()); } public String tojstring() { return typename() + ": 0x" + Integer.toHexString(hashCode()); }
/** Convert to userdata instance, or null. /** Convert to userdata instance, or null.
* @return userdata instance if userdata, or null if not {@link LuaUserdata} * @return userdata instance if userdata, or null if not {@link LuaUserdata}
@@ -625,7 +631,7 @@ public class LuaValue extends Varargs {
* @see #isclosure() * @see #isclosure()
* @see #TFUNCTION * @see #TFUNCTION
*/ */
public LuaClosure optclosure(LuaClosure defval) { argerror("closure"); return null; } public LuaClosure optclosure(LuaClosure defval) { argerror("function"); return null; }
/** Check that optional argument is a number or string convertible to number and return as double /** Check that optional argument is a number or string convertible to number and return as double
* @param defval double to return if {@code this} is nil or none * @param defval double to return if {@code this} is nil or none
@@ -737,7 +743,7 @@ public class LuaValue extends Varargs {
* @see #toString() * @see #toString()
* @see #TSTRING * @see #TSTRING
*/ */
public String optjstring(String defval) { argerror("String"); return null; } public String optjstring(String defval) { argerror("string"); return null; }
/** Check that optional argument is a string or number and return as {@link LuaString} /** Check that optional argument is a string or number and return as {@link LuaString}
* @param defval {@link LuaString} to return if {@code this} is nil or none * @param defval {@link LuaString} to return if {@code this} is nil or none
@@ -888,7 +894,7 @@ public class LuaValue extends Varargs {
* @see #optint(int) * @see #optint(int)
* @see #TNUMBER * @see #TNUMBER
*/ */
public int checkint() { argerror("int"); return 0; } public int checkint() { argerror("number"); return 0; }
/** Check that the value is numeric, and convert and cast value to int, or throw {@link LuaError} if not numeric /** Check that the value is numeric, and convert and cast value to int, or throw {@link LuaError} if not numeric
* <p> * <p>
@@ -1053,7 +1059,7 @@ public class LuaValue extends Varargs {
* @param expected String naming the type that was expected * @param expected String naming the type that was expected
* @throws LuaError in all cases * @throws LuaError in all cases
*/ */
protected LuaValue argerror(String expected) { throw new LuaError("bad argument: "+expected+" expected, got "+typename()); } protected LuaValue argerror(String expected) { throw new LuaError("bad argument ("+expected+" expected, got "+typename()+")"); }
/** /**
* Throw a {@link LuaError} indicating an invalid argument was supplied to a function * Throw a {@link LuaError} indicating an invalid argument was supplied to a function
@@ -2985,7 +2991,7 @@ public class LuaValue extends Varargs {
return h.call(this, op1); return h.call(this, op1);
if (LuaValue.LE.raweq(tag) && (!(h = metatag(LT)).isnil() || !(h = op1.metatag(LT)).isnil())) if (LuaValue.LE.raweq(tag) && (!(h = metatag(LT)).isnil() || !(h = op1.metatag(LT)).isnil()))
return h.call(op1, this).not(); return h.call(op1, this).not();
return error("attempt to compare "+tag+" on "+typename()+" and "+op1.typename()); return error("bad argument: attempt to compare "+tag+" on "+typename()+" and "+op1.typename());
} }
/** Perform string comparison with another value /** Perform string comparison with another value

View File

@@ -29,23 +29,23 @@ import org.luaj.vm2.LuaTable.Slot;
interface Metatable { interface Metatable {
/** Return whether or not this table's keys are weak. */ /** Return whether or not this table's keys are weak. */
public boolean useWeakKeys(); boolean useWeakKeys();
/** Return whether or not this table's values are weak. */ /** Return whether or not this table's values are weak. */
public boolean useWeakValues(); boolean useWeakValues();
/** Return this metatable as a LuaValue. */ /** Return this metatable as a LuaValue. */
public LuaValue toLuaValue(); LuaValue toLuaValue();
/** Return an instance of Slot appropriate for the given key and value. */ /** Return an instance of Slot appropriate for the given key and value. */
public Slot entry( LuaValue key, LuaValue value ); Slot entry(LuaValue key, LuaValue value);
/** Returns the given value wrapped in a weak reference if appropriate. */ /** Returns the given value wrapped in a weak reference if appropriate. */
public LuaValue wrap( LuaValue value ); LuaValue wrap(LuaValue value);
/** /**
* Returns the value at the given index in the array, or null if it is a weak reference that * Returns the value at the given index in the array, or null if it is a
* has been dropped. * weak reference that has been dropped.
*/ */
public LuaValue arrayget(LuaValue[] array, int index); LuaValue arrayget(LuaValue[] array, int index);
} }

View File

@@ -10,26 +10,32 @@ class NonTableMetatable implements Metatable {
this.value = value; this.value = value;
} }
@Override
public boolean useWeakKeys() { public boolean useWeakKeys() {
return false; return false;
} }
@Override
public boolean useWeakValues() { public boolean useWeakValues() {
return false; return false;
} }
@Override
public LuaValue toLuaValue() { public LuaValue toLuaValue() {
return value; return value;
} }
@Override
public Slot entry(LuaValue key, LuaValue value) { public Slot entry(LuaValue key, LuaValue value) {
return LuaTable.defaultEntry(key, value); return LuaTable.defaultEntry(key, value);
} }
@Override
public LuaValue wrap(LuaValue value) { public LuaValue wrap(LuaValue value) {
return value; return value;
} }
@Override
public LuaValue arrayget(LuaValue[] array, int index) { public LuaValue arrayget(LuaValue[] array, int index) {
return array[index]; return array[index];
} }

View File

@@ -29,7 +29,8 @@ package org.luaj.vm2;
* {@link LuaThread} being used as a coroutine that could not possibly be * {@link LuaThread} being used as a coroutine that could not possibly be
* resumed again because there are no more references to the LuaThread with * resumed again because there are no more references to the LuaThread with
* which it is associated. Rather than locking up resources forever, this error * 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> * <p>
* Java code mixed with the luaj vm should not catch this error because it may * 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 * 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. * Debug helper class to pretty-print lua bytecodes.
*
* @see Prototype * @see Prototype
* @see LuaClosure * @see LuaClosure
*/ */
@@ -36,50 +37,10 @@ public class Print extends Lua {
public static PrintStream ps = System.out; public static PrintStream ps = System.out;
/** String names for each lua opcode value. */ /** String names for each lua opcode value. */
public static final String[] OPNAMES = { public static final String[] OPNAMES = { "MOVE", "LOADK", "LOADKX", "LOADBOOL", "LOADNIL", "GETUPVAL", "GETTABUP",
"MOVE", "GETTABLE", "SETTABUP", "SETUPVAL", "SETTABLE", "NEWTABLE", "SELF", "ADD", "SUB", "MUL", "DIV", "MOD",
"LOADK", "POW", "UNM", "NOT", "LEN", "CONCAT", "JMP", "EQ", "LT", "LE", "TEST", "TESTSET", "CALL", "TAILCALL",
"LOADKX", "RETURN", "FORLOOP", "FORPREP", "TFORCALL", "TFORLOOP", "SETLIST", "CLOSURE", "VARARG", "EXTRAARG", null, };
"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) { static void printString(PrintStream ps, final LuaString s) {
@@ -133,8 +94,11 @@ public class Print extends Lua {
return; return;
} }
switch (v.type()) { switch (v.type()) {
case LuaValue.TSTRING: printString( ps, (LuaString) v ); break; case LuaValue.TSTRING:
default: ps.print( v.tojstring() ); 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 * Print the code in a prototype
*
* @param f the {@link Prototype} * @param f the {@link Prototype}
*/ */
public static void printCode(Prototype f) { public static void printCode(Prototype f) {
@@ -163,6 +128,7 @@ public class Print extends Lua {
/** /**
* Print an opcode in a prototype * Print an opcode in a prototype
*
* @param f the {@link Prototype} * @param f the {@link Prototype}
* @param pc the program counter to look up and print * @param pc the program counter to look up and print
* @return pc same as above or changed * @return pc same as above or changed
@@ -173,6 +139,7 @@ public class Print extends Lua {
/** /**
* Print an opcode in a prototype * Print an opcode in a prototype
*
* @param ps the {@link PrintStream} to print to * @param ps the {@link PrintStream} to print to
* @param f the {@link Prototype} * @param f the {@link Prototype}
* @param pc the program counter to look up and print * @param pc the program counter to look up and print
@@ -201,15 +168,15 @@ public class Print extends Lua {
case iABC: case iABC:
ps.print(a); ps.print(a);
if (getBMode(o) != OpArgN) if (getBMode(o) != OpArgN)
ps.print(" "+(ISK(b) ? (-1 - INDEXK(b)) : b)); ps.print(" " + (ISK(b)? -1-INDEXK(b): b));
if (getCMode(o) != OpArgN) if (getCMode(o) != OpArgN)
ps.print(" "+(ISK(c) ? (-1 - INDEXK(c)) : c)); ps.print(" " + (ISK(c)? -1-INDEXK(c): c));
break; break;
case iABx: case iABx:
if (getBMode(o) == OpArgK) { if (getBMode(o) == OpArgK) {
ps.print(a + " " + (-1-bx)); ps.print(a + " " + (-1-bx));
} else { } else {
ps.print(a + " " + (bx)); ps.print(a + " " + bx);
} }
break; break;
case iAsBx: case iAsBx:
@@ -307,9 +274,9 @@ public class Print extends Lua {
break; break;
case OP_SETLIST: case OP_SETLIST:
if (c == 0) if (c == 0)
ps.print(" ; " + ((int) code[++pc]) + " (stored in the next OP)"); ps.print(" ; " + code[++pc] + " (stored in the next OP)");
else else
ps.print(" ; " + ((int) c)); ps.print(" ; " + c);
break; break;
case OP_VARARG: case OP_VARARG:
ps.print(" ; is_vararg=" + f.is_vararg); ps.print(" ; is_vararg=" + f.is_vararg);
@@ -333,14 +300,11 @@ public class Print extends Lua {
s = "(bstring)"; s = "(bstring)";
else else
s = "(string)"; s = "(string)";
String a = (f.linedefined == 0) ? "main" : "function"; String a = f.linedefined == 0? "main": "function";
ps.print("\n%" + a + " <" + s + ":" + f.linedefined + "," ps.print("\n%" + a + " <" + s + ":" + f.linedefined + "," + f.lastlinedefined + "> (" + f.code.length
+ f.lastlinedefined + "> (" + f.code.length + " instructions, " + " instructions, " + f.code.length*4 + " bytes at " + id(f) + ")\n");
+ f.code.length * 4 + " bytes at " + id(f) + ")\n"); ps.print(f.numparams + " param, " + f.maxstacksize + " slot, " + f.upvalues.length + " upvalue, ");
ps.print(f.numparams + " param, " + f.maxstacksize + " slot, " ps.print(f.locvars.length + " local, " + f.k.length + " constant, " + f.p.length + " function\n");
+ f.upvalues.length + " upvalue, ");
ps.print(f.locvars.length + " local, " + f.k.length
+ " constant, " + f.p.length + " function\n");
} }
static void printConstants(Prototype f) { static void printConstants(Prototype f) {
@@ -357,7 +321,8 @@ public class Print extends Lua {
int i, n = f.locvars.length; int i, n = f.locvars.length;
ps.print("locals (" + n + ") for " + id(f) + ":\n"); ps.print("locals (" + n + ") for " + id(f) + ":\n");
for (i = 0; i < n; i++) { 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. * @param prototype Prototype to print.
*/ */
@@ -377,7 +343,8 @@ public class Print extends Lua {
printFunction(prototype, true); 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 prototype Prototype to print.
* @param full true to print all fields, false to print short form. * @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) { private static String id(Prototype f) {
return "Proto"; return "Proto";
} }
private void _assert(boolean b) { private void _assert(boolean b) {
if (!b) if (!b)
throw new NullPointerException("_assert failed"); 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 * Print the state of a {@link LuaClosure} that is being executed
*
* @param cl the {@link LuaClosure} * @param cl the {@link LuaClosure}
* @param pc the program counter * @param pc the program counter
* @param stack the stack of {@link LuaValue} * @param stack the stack of {@link LuaValue}
@@ -443,12 +412,12 @@ public class Print extends Lua {
LuaValue v = stack[i]; LuaValue v = stack[i];
if (v == null) if (v == null)
ps.print(STRING_FOR_NULL); ps.print(STRING_FOR_NULL);
else switch ( v.type() ) { else
switch (v.type()) {
case LuaValue.TSTRING: case LuaValue.TSTRING:
LuaString s = v.checkstring(); LuaString s = v.checkstring();
ps.print( s.length() < 48? ps.print(s.length() < 48? s.tojstring()
s.tojstring(): : s.substring(0, 32).tojstring() + "...+" + (s.length()-32) + "b");
s.substring(0, 32).tojstring()+"...+"+(s.length()-32)+"b");
break; break;
case LuaValue.TFUNCTION: case LuaValue.TFUNCTION:
ps.print(v.tojstring()); ps.print(v.tojstring());

View File

@@ -0,0 +1,180 @@
/*******************************************************************************
* Copyright (c) 2009-2011 Luaj.org. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
******************************************************************************/
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.
*
* <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>
* {
* &#64;code
* Globals globals = JsePlatform.standardGlobals();
* globals.load(new StringReader("print 'hello'"), "main.lua").call();
* }
* </pre>
*
* <p>
* To create a {@link Prototype} directly, a compiler such as
* {@link org.luaj.vm2.compiler.LuaC} may be used:
*
* <pre>
* {
* &#64;code
* InputStream is = new ByteArrayInputStream("print('hello,world')".getBytes());
* Prototype p = LuaC.instance.compile(is, "script");
* }
* </pre>
*
* 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>
*
* 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>
*
* 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>
*
* 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>
*
* To simplify the debugging of prototype values, the contents may be printed
* using {@link Print#print}:
*
* <pre>
* {@code
* Print.print(p);
* }
* </pre>
* <p>
*
* @see LuaClosure
* @see Globals
* @see Globals#undumper
* @see Globals#compiler
* @see Print#print
*/
public class Prototype {
/* constants used by the function */
public LuaValue[] k;
public int[] code;
/* functions defined inside the function */
public Prototype[] p;
/* map from opcodes to source lines */
public int[] lineinfo;
/* information about local variables */
public LocVars[] locvars;
/* upvalue information */
public Upvaldesc[] upvalues;
public LuaString source;
public int linedefined;
public int lastlinedefined;
public int numparams;
public int is_vararg;
public int maxstacksize;
private static final Upvaldesc[] NOUPVALUES = {};
private static final Prototype[] NOSUBPROTOS = {};
public Prototype() {
p = NOSUBPROTOS;
upvalues = NOUPVALUES;
}
public Prototype(int n_upvalues) {
p = NOSUBPROTOS;
upvalues = new Upvaldesc[n_upvalues];
}
@Override
public String toString() {
return source + ":" + linedefined + "-" + lastlinedefined;
}
/**
* Get the name of a local variable.
*
* @param number the local variable number to look up
* @param pc the program counter
* @return the name, or null if not found
*/
public LuaString getlocalname(int number, int pc) {
int i;
for (i = 0; i < locvars.length && locvars[i].startpc <= pc; i++) {
if (pc < locvars[i].endpc) { /* is variable active? */
number--;
if (number == 0)
return locvars[i].varname;
}
}
return null; /* not found */
}
public String shortsource() {
String name = source.tojstring();
if (name.startsWith("@") || name.startsWith("="))
name = name.substring(1);
else if (name.startsWith("\033"))
name = "binary string";
return name;
}
}

View File

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

View File

@@ -21,9 +21,10 @@
******************************************************************************/ ******************************************************************************/
package org.luaj.vm2; package org.luaj.vm2;
/**
/** Upvalue used with Closure formulation * Upvalue used with Closure formulation
* <p> * <p>
*
* @see LuaClosure * @see LuaClosure
* @see Prototype * @see Prototype
*/ */
@@ -34,6 +35,7 @@ public final class UpValue {
/** /**
* Create an upvalue relative to a stack * Create an upvalue relative to a stack
*
* @param stack the stack * @param stack the stack
* @param index the index on the stack for the upvalue * @param index the index on the stack for the upvalue
*/ */
@@ -42,12 +44,14 @@ public final class UpValue {
this.index = index; this.index = index;
} }
@Override
public String toString() { public String toString() {
return index + "/" + array.length + " " + array[index]; return index + "/" + array.length + " " + array[index];
} }
/** /**
* Convert this upvalue to a Java String * Convert this upvalue to a Java String
*
* @return the Java String for this upvalue. * @return the Java String for this upvalue.
* @see LuaValue#tojstring() * @see LuaValue#tojstring()
*/ */
@@ -57,24 +61,22 @@ public final class UpValue {
/** /**
* Get the value of the upvalue * Get the value of the upvalue
*
* @return the {@link LuaValue} for this upvalue * @return the {@link LuaValue} for this upvalue
*/ */
public final LuaValue getValue() { public LuaValue getValue() { return array[index]; }
return array[index];
}
/** /**
* Set the value of the upvalue * Set the value of the upvalue
*
* @param value the {@link LuaValue} to set it to * @param value the {@link LuaValue} to set it to
*/ */
public final void setValue( LuaValue value ) { public void setValue(LuaValue value) { array[index] = value; }
array[index] = value;
}
/** /**
* Close this upvalue so it is no longer on the stack * Close this upvalue so it is no longer on the stack
*/ */
public final void close() { public void close() {
LuaValue[] old = array; LuaValue[] old = array;
array = new LuaValue[] { old[index] }; array = new LuaValue[] { old[index] };
old[index] = null; old[index] = null;

View File

@@ -38,6 +38,7 @@ public class Upvaldesc {
this.idx = (short) idx; this.idx = (short) idx;
} }
@Override
public String toString() { public String toString() {
return idx+(instack? " instack ": " closed ")+String.valueOf(name); return idx+(instack? " instack ": " closed ")+String.valueOf(name);
} }

View File

@@ -29,16 +29,16 @@ import org.luaj.vm2.LuaTable.StrongSlot;
/** /**
* Subclass of {@link LuaTable} that provides weak key and weak value semantics. * Subclass of {@link LuaTable} that provides weak key and weak value semantics.
* <p> * <p>
* Normally these are not created directly, but indirectly when changing the mode * Normally these are not created directly, but indirectly when changing the
* of a {@link LuaTable} as lua script executes. * mode of a {@link LuaTable} as lua script executes.
* <p> * <p>
* However, calling the constructors directly when weak tables are required from * However, calling the constructors directly when weak tables are required from
* Java will reduce overhead. * Java will reduce overhead.
*/ */
public class WeakTable implements Metatable { public class WeakTable implements Metatable {
private boolean weakkeys, weakvalues; private final boolean weakkeys, weakvalues;
private LuaValue backing; private final LuaValue backing;
public static LuaTable make(boolean weakkeys, boolean weakvalues) { public static LuaTable make(boolean weakkeys, boolean weakvalues) {
LuaString mode; LuaString mode;
@@ -49,16 +49,17 @@ public class WeakTable implements Metatable {
} else if (weakvalues) { } else if (weakvalues) {
mode = LuaString.valueOf("v"); mode = LuaString.valueOf("v");
} else { } else {
return LuaTable.tableOf(); return LuaValue.tableOf();
} }
LuaTable table = LuaTable.tableOf(); LuaTable table = LuaValue.tableOf();
LuaTable mt = LuaTable.tableOf(new LuaValue[] { LuaValue.MODE, mode }); LuaTable mt = LuaValue.tableOf(new LuaValue[] { LuaValue.MODE, mode });
table.setmetatable(mt); table.setmetatable(mt);
return table; return table;
} }
/** /**
* Construct a table with weak keys, weak values, or both * Construct a table with weak keys, weak values, or both
*
* @param weakkeys true to let the table have weak keys * @param weakkeys true to let the table have weak keys
* @param weakvalues true to let the table have weak values * @param weakvalues true to let the table have weak values
*/ */
@@ -68,18 +69,22 @@ public class WeakTable implements Metatable {
this.backing = backing; this.backing = backing;
} }
@Override
public boolean useWeakKeys() { public boolean useWeakKeys() {
return weakkeys; return weakkeys;
} }
@Override
public boolean useWeakValues() { public boolean useWeakValues() {
return weakvalues; return weakvalues;
} }
@Override
public LuaValue toLuaValue() { public LuaValue toLuaValue() {
return backing; return backing;
} }
@Override
public Slot entry(LuaValue key, LuaValue value) { public Slot entry(LuaValue key, LuaValue value) {
value = value.strongvalue(); value = value.strongvalue();
if (value == null) if (value == null)
@@ -109,10 +114,12 @@ public class WeakTable implements Metatable {
this.next = next; this.next = next;
} }
@Override
public abstract int keyindex(int hashMask); public abstract int keyindex(int hashMask);
public abstract Slot set(LuaValue value); public abstract Slot set(LuaValue value);
@Override
public StrongSlot first() { public StrongSlot first() {
LuaValue key = strongkey(); LuaValue key = strongkey();
LuaValue value = strongvalue(); LuaValue value = strongvalue();
@@ -125,25 +132,30 @@ public class WeakTable implements Metatable {
} }
} }
@Override
public StrongSlot find(LuaValue key) { public StrongSlot find(LuaValue key) {
StrongSlot first = first(); StrongSlot first = first();
return ( first != null ) ? first.find( key ) : null; return first != null? first.find(key): null;
} }
@Override
public boolean keyeq(LuaValue key) { public boolean keyeq(LuaValue key) {
StrongSlot first = first(); StrongSlot first = first();
return ( first != null ) && first.keyeq( key ); return first != null && first.keyeq(key);
} }
@Override
public Slot rest() { public Slot rest() {
return next; return next;
} }
@Override
public int arraykey(int max) { public int arraykey(int max) {
// Integer keys can never be weak. // Integer keys can never be weak.
return 0; return 0;
} }
@Override
public Slot set(StrongSlot target, LuaValue value) { public Slot set(StrongSlot target, LuaValue value) {
LuaValue key = strongkey(); LuaValue key = strongkey();
if (key != null && target.find(key) != null) { if (key != null && target.find(key) != null) {
@@ -158,8 +170,9 @@ public class WeakTable implements Metatable {
} }
} }
@Override
public Slot add(Slot entry) { public Slot add(Slot entry) {
next = ( next != null ) ? next.add( entry ) : entry; next = next != null? next.add(entry): entry;
if (strongkey() != null && strongvalue() != null) { if (strongkey() != null && strongvalue() != null) {
return this; return this;
} else { } else {
@@ -167,6 +180,7 @@ public class WeakTable implements Metatable {
} }
} }
@Override
public Slot remove(StrongSlot target) { public Slot remove(StrongSlot target) {
LuaValue key = strongkey(); LuaValue key = strongkey();
if (key == null) { if (key == null) {
@@ -180,6 +194,7 @@ public class WeakTable implements Metatable {
} }
} }
@Override
public Slot relink(Slot rest) { public Slot relink(Slot rest) {
if (strongkey() != null && strongvalue() != null) { if (strongkey() != null && strongvalue() != null) {
if (rest == null && this.next == null) { if (rest == null && this.next == null) {
@@ -217,19 +232,23 @@ public class WeakTable implements Metatable {
this.keyhash = copyFrom.keyhash; this.keyhash = copyFrom.keyhash;
} }
@Override
public int keyindex(int mask) { public int keyindex(int mask) {
return LuaTable.hashmod(keyhash, mask); return LuaTable.hashmod(keyhash, mask);
} }
@Override
public Slot set(LuaValue value) { public Slot set(LuaValue value) {
this.value = value; this.value = value;
return this; return this;
} }
@Override
public LuaValue strongkey() { public LuaValue strongkey() {
return strengthen(key); return strengthen(key);
} }
@Override
protected WeakSlot copy(Slot rest) { protected WeakSlot copy(Slot rest) {
return new WeakKeySlot(this, rest); return new WeakKeySlot(this, rest);
} }
@@ -245,19 +264,23 @@ public class WeakTable implements Metatable {
super(copyFrom.key, copyFrom.value, next); super(copyFrom.key, copyFrom.value, next);
} }
@Override
public int keyindex(int mask) { public int keyindex(int mask) {
return LuaTable.hashSlot(strongkey(), mask); return LuaTable.hashSlot(strongkey(), mask);
} }
@Override
public Slot set(LuaValue value) { public Slot set(LuaValue value) {
this.value = weaken(value); this.value = weaken(value);
return this; return this;
} }
@Override
public LuaValue strongvalue() { public LuaValue strongvalue() {
return strengthen(value); return strengthen(value);
} }
@Override
protected WeakSlot copy(Slot next) { protected WeakSlot copy(Slot next) {
return new WeakValueSlot(this, next); return new WeakValueSlot(this, next);
} }
@@ -277,23 +300,28 @@ public class WeakTable implements Metatable {
keyhash = copyFrom.keyhash; keyhash = copyFrom.keyhash;
} }
@Override
public int keyindex(int hashMask) { public int keyindex(int hashMask) {
return LuaTable.hashmod(keyhash, hashMask); return LuaTable.hashmod(keyhash, hashMask);
} }
@Override
public Slot set(LuaValue value) { public Slot set(LuaValue value) {
this.value = weaken(value); this.value = weaken(value);
return this; return this;
} }
@Override
public LuaValue strongkey() { public LuaValue strongkey() {
return strengthen(key); return strengthen(key);
} }
@Override
public LuaValue strongvalue() { public LuaValue strongvalue() {
return strengthen(value); return strengthen(value);
} }
@Override
protected WeakSlot copy(Slot next) { protected WeakSlot copy(Slot next) {
return new WeakKeyAndValueSlot(this, next); return new WeakKeyAndValueSlot(this, next);
} }
@@ -301,8 +329,10 @@ public class WeakTable implements Metatable {
/** /**
* Self-sent message to convert a value to its weak counterpart * Self-sent message to convert a value to its weak counterpart
*
* @param value value to convert * @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) { protected static LuaValue weaken(LuaValue value) {
switch (value.type()) { switch (value.type()) {
@@ -319,6 +349,7 @@ public class WeakTable implements Metatable {
/** /**
* Unwrap a LuaValue from a WeakReference and/or WeakUserdata. * Unwrap a LuaValue from a WeakReference and/or WeakUserdata.
*
* @param ref reference to convert * @param ref reference to convert
* @return LuaValue or null * @return LuaValue or null
* @see #weaken(LuaValue) * @see #weaken(LuaValue)
@@ -333,7 +364,9 @@ public class WeakTable implements Metatable {
return (LuaValue) ref; return (LuaValue) ref;
} }
/** Internal class to implement weak values. /**
* Internal class to implement weak values.
*
* @see WeakTable * @see WeakTable
*/ */
static class WeakValue extends LuaValue { static class WeakValue extends LuaValue {
@@ -343,32 +376,39 @@ public class WeakTable implements Metatable {
ref = new WeakReference(value); ref = new WeakReference(value);
} }
@Override
public int type() { public int type() {
illegal("type", "weak value"); illegal("type", "weak value");
return 0; return 0;
} }
@Override
public String typename() { public String typename() {
illegal("typename", "weak value"); illegal("typename", "weak value");
return null; return null;
} }
@Override
public String toString() { public String toString() {
return "weak<" + ref.get() + ">"; return "weak<" + ref.get() + ">";
} }
@Override
public LuaValue strongvalue() { public LuaValue strongvalue() {
Object o = ref.get(); Object o = ref.get();
return (LuaValue) o; return (LuaValue) o;
} }
@Override
public boolean raweq(LuaValue rhs) { public boolean raweq(LuaValue rhs) {
Object o = ref.get(); Object o = ref.get();
return o != null && rhs.raweq((LuaValue) o); return o != null && rhs.raweq((LuaValue) o);
} }
} }
/** Internal class to implement weak userdata values. /**
* Internal class to implement weak userdata values.
*
* @see WeakTable * @see WeakTable
*/ */
static final class WeakUserdata extends WeakValue { static final class WeakUserdata extends WeakValue {
@@ -381,6 +421,7 @@ public class WeakTable implements Metatable {
mt = value.getmetatable(); mt = value.getmetatable();
} }
@Override
public LuaValue strongvalue() { public LuaValue strongvalue() {
Object u = ref.get(); Object u = ref.get();
if (u != null) if (u != null)
@@ -396,10 +437,12 @@ public class WeakTable implements Metatable {
} }
} }
@Override
public LuaValue wrap(LuaValue value) { public LuaValue wrap(LuaValue value) {
return weakvalues? weaken(value): value; return weakvalues? weaken(value): value;
} }
@Override
public LuaValue arrayget(LuaValue[] array, int index) { public LuaValue arrayget(LuaValue[] array, int index) {
LuaValue value = array[index]; LuaValue value = array[index];
if (value != null) { if (value != null) {

View File

@@ -0,0 +1,19 @@
package org.luaj.vm2.compat;
public class JavaCompat {
public static final JavaCompat INSTANCE;
static {
JavaCompat instance;
try {
instance = (JavaCompat) Class.forName("org.luaj.vm2.lib.jse.JavaCompatJSE").newInstance();
} catch (Throwable t) {
instance = new JavaCompat();
}
INSTANCE = instance;
}
public long doubleToRawLongBits(double x) {
return Double.doubleToLongBits(x);
}
}

View File

@@ -44,48 +44,42 @@ public class Constants extends Lua {
static final int LUAI_MAXVARS = 200; static final int LUAI_MAXVARS = 200;
static final int NO_REG = MAXARG_A; static final int NO_REG = MAXARG_A;
/* OpMode - basic instruction format */ /* OpMode - basic instruction format */
static final int static final int iABC = 0, iABx = 1, iAsBx = 2;
iABC = 0,
iABx = 1,
iAsBx = 2;
/* OpArgMask */ /* OpArgMask */
static final int static final int OpArgN = 0, /* argument is not used */
OpArgN = 0, /* argument is not used */
OpArgU = 1, /* argument is used */ OpArgU = 1, /* argument is used */
OpArgR = 2, /* argument is a register or a jump offset */ OpArgR = 2, /* argument is a register or a jump offset */
OpArgK = 3; /* argument is a constant or register/constant */ OpArgK = 3; /* argument is a constant or register/constant */
protected static void _assert(boolean b) { protected static void _assert(boolean b) {
if (!b) if (!b)
throw new LuaError("compiler assert failed"); throw new LuaError("compiler assert failed");
} }
static void SET_OPCODE(InstructionPtr i, int o) { static void SET_OPCODE(InstructionPtr i, int o) {
i.set( ( i.get() & (MASK_NOT_OP)) | ((o << POS_OP) & MASK_OP) ); i.set(i.get() & MASK_NOT_OP | o<<POS_OP & MASK_OP);
} }
static void SETARG_A(int[] code, int index, int u) { static void SETARG_A(int[] code, int index, int u) {
code[index] = (code[index] & (MASK_NOT_A)) | ((u << POS_A) & MASK_A); code[index] = code[index] & MASK_NOT_A | u<<POS_A & MASK_A;
} }
static void SETARG_A(InstructionPtr i, int u) { static void SETARG_A(InstructionPtr i, int u) {
i.set( ( i.get() & (MASK_NOT_A)) | ((u << POS_A) & MASK_A) ); i.set(i.get() & MASK_NOT_A | u<<POS_A & MASK_A);
} }
static void SETARG_B(InstructionPtr i, int u) { static void SETARG_B(InstructionPtr i, int u) {
i.set( ( i.get() & (MASK_NOT_B)) | ((u << POS_B) & MASK_B) ); i.set(i.get() & MASK_NOT_B | u<<POS_B & MASK_B);
} }
static void SETARG_C(InstructionPtr i, int u) { static void SETARG_C(InstructionPtr i, int u) {
i.set( ( i.get() & (MASK_NOT_C)) | ((u << POS_C) & MASK_C) ); i.set(i.get() & MASK_NOT_C | u<<POS_C & MASK_C);
} }
static void SETARG_Bx(InstructionPtr i, int u) { static void SETARG_Bx(InstructionPtr i, int u) {
i.set( ( i.get() & (MASK_NOT_Bx)) | ((u << POS_Bx) & MASK_Bx) ); i.set(i.get() & MASK_NOT_Bx | u<<POS_Bx & MASK_Bx);
} }
static void SETARG_sBx(InstructionPtr i, int u) { static void SETARG_sBx(InstructionPtr i, int u) {
@@ -93,21 +87,15 @@ public class Constants extends Lua {
} }
static int CREATE_ABC(int o, int a, int b, int c) { static int CREATE_ABC(int o, int a, int b, int c) {
return ((o << POS_OP) & MASK_OP) | return o<<POS_OP & MASK_OP | a<<POS_A & MASK_A | b<<POS_B & MASK_B | c<<POS_C & MASK_C;
((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) { static int CREATE_ABx(int o, int a, int bc) {
return ((o << POS_OP) & MASK_OP) | return o<<POS_OP & MASK_OP | a<<POS_A & MASK_A | bc<<POS_Bx & MASK_Bx;
((a << POS_A) & MASK_A) |
((bc << POS_Bx) & MASK_Bx) ;
} }
static int CREATE_Ax(int o, int a) { static int CREATE_Ax(int o, int a) {
return ((o << POS_OP) & MASK_OP) | return o<<POS_OP & MASK_OP | a<<POS_Ax & MASK_Ax;
((a << POS_Ax) & MASK_Ax) ;
} }
// vector reallocation // vector reallocation

View File

@@ -32,35 +32,47 @@ import org.luaj.vm2.LuaString;
import org.luaj.vm2.LuaValue; import org.luaj.vm2.LuaValue;
import org.luaj.vm2.Prototype; 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> * <p>
* Generally, this class is not used directly, but rather indirectly via a command * Generally, this class is not used directly, but rather indirectly via a
* line interface tool such as {@link luac}. * command line interface tool such as {@link luac}.
* <p> * <p>
* A lua binary file is created via {@link DumpState#dump}: * A lua binary file is created via {@link DumpState#dump}:
* <pre> {@code *
* <pre>
* {
* &#64;code
* Globals globals = JsePlatform.standardGlobals(); * Globals globals = JsePlatform.standardGlobals();
* Prototype p = globals.compilePrototype(new StringReader("print('hello, world')"), "main.lua"); * Prototype p = globals.compilePrototype(new StringReader("print('hello, world')"), "main.lua");
* ByteArrayOutputStream o = new ByteArrayOutputStream(); * ByteArrayOutputStream o = new ByteArrayOutputStream();
* DumpState.dump(p, o, false); * DumpState.dump(p, o, false);
* byte[] lua_binary_file_bytes = o.toByteArray(); * byte[] lua_binary_file_bytes = o.toByteArray();
* } </pre> * }
* </pre>
* *
* The {@link LoadState} may be used directly to undump these bytes: * 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"); * Prototypep = LoadState.instance.undump(new ByteArrayInputStream(lua_binary_file_bytes), "main.lua");
* LuaClosure c = new LuaClosure(p, globals); * LuaClosure c = new LuaClosure(p, globals);
* c.call(); * c.call();
* } </pre> * }
* </pre>
* *
* *
* More commonly, the {@link Globals#undumper} may be used to undump them: * 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"); * Prototype p = globals.loadPrototype(new ByteArrayInputStream(lua_binary_file_bytes), "main.lua", "b");
* LuaClosure c = new LuaClosure(p, globals); * LuaClosure c = new LuaClosure(p, globals);
* c.call(); * c.call();
* } </pre> * }
* </pre>
* *
* @see luac * @see luac
* @see LoadState * @see LoadState
@@ -72,13 +84,19 @@ public class DumpState {
/** set true to allow integer compilation */ /** set true to allow integer compilation */
public static boolean ALLOW_INTEGER_CASTING = false; 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; public static final int NUMBER_FORMAT_FLOATS_OR_DOUBLES = 0;
/** format corresponding to non-number-patched lua, all numbers are ints */ /** format corresponding to non-number-patched lua, all numbers are ints */
public static final int NUMBER_FORMAT_INTS_ONLY = 1; 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; public static final int NUMBER_FORMAT_NUM_PATCH_INT32 = 4;
/** default number format */ /** default number format */
@@ -113,9 +131,9 @@ public class DumpState {
void dumpInt(int x) throws IOException { void dumpInt(int x) throws IOException {
if (IS_LITTLE_ENDIAN) { if (IS_LITTLE_ENDIAN) {
writer.writeByte(x & 0xff); writer.writeByte(x & 0xff);
writer.writeByte((x>>8)&0xff); writer.writeByte(x>>8 & 0xff);
writer.writeByte((x>>16)&0xff); writer.writeByte(x>>16 & 0xff);
writer.writeByte((x>>24)&0xff); writer.writeByte(x>>24 & 0xff);
} else { } else {
writer.writeInt(x); writer.writeInt(x);
} }
@@ -272,13 +290,17 @@ public class DumpState {
* @param f the function to dump * @param f the function to dump
* @param w the output stream to dump to * @param w the output stream to dump to
* @param stripDebug true to strip debugging info, false otherwise * @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 numberFormat one of NUMBER_FORMAT_FLOATS_OR_DOUBLES,
* @param littleendian true to use little endian for numbers, false for big endian * 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 * @return 0 if dump succeeds
* @throws IOException * @throws IOException
* @throws IllegalArgumentException if the number format it not supported * @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) { switch (numberFormat) {
case NUMBER_FORMAT_FLOATS_OR_DOUBLES: case NUMBER_FORMAT_FLOATS_OR_DOUBLES:
case NUMBER_FORMAT_INTS_ONLY: case NUMBER_FORMAT_INTS_ONLY:
@@ -290,7 +312,7 @@ public class DumpState {
DumpState D = new DumpState(w, stripDebug); DumpState D = new DumpState(w, stripDebug);
D.IS_LITTLE_ENDIAN = littleendian; D.IS_LITTLE_ENDIAN = littleendian;
D.NUMBER_FORMAT = numberFormat; D.NUMBER_FORMAT = numberFormat;
D.SIZEOF_LUA_NUMBER = (numberFormat==NUMBER_FORMAT_INTS_ONLY? 4: 8); D.SIZEOF_LUA_NUMBER = numberFormat == NUMBER_FORMAT_INTS_ONLY? 4: 8;
D.dumpHeader(); D.dumpHeader();
D.dumpFunction(f); D.dumpFunction(f);
return D.status; return D.status;

View File

@@ -34,7 +34,6 @@ import org.luaj.vm2.Upvaldesc;
import org.luaj.vm2.compiler.LexState.ConsControl; import org.luaj.vm2.compiler.LexState.ConsControl;
import org.luaj.vm2.compiler.LexState.expdesc; import org.luaj.vm2.compiler.LexState.expdesc;
public class FuncState extends Constants { public class FuncState extends Constants {
static class BlockCnt { static class BlockCnt {
@@ -44,7 +43,7 @@ public class FuncState extends Constants {
short nactvar; /* # active locals outside the breakable structure */ short nactvar; /* # active locals outside the breakable structure */
boolean upval; /* true if some variable in the block is an upvalue */ boolean upval; /* true if some variable in the block is an upvalue */
boolean isloop; /* true if `block' is a loop */ boolean isloop; /* true if `block' is a loop */
}; }
Prototype f; /* current function header */ Prototype f; /* current function header */
Hashtable h; /* table to find (and reuse) elements in `k' */ Hashtable h; /* table to find (and reuse) elements in `k' */
@@ -65,7 +64,6 @@ public class FuncState extends Constants {
FuncState() { FuncState() {
} }
// ============================================================= // =============================================================
// from lcode.h // from lcode.h
// ============================================================= // =============================================================
@@ -86,7 +84,6 @@ public class FuncState extends Constants {
setreturns(e, LUA_MULTRET); setreturns(e, LUA_MULTRET);
} }
// ============================================================= // =============================================================
// from lparser.c // from lparser.c
// ============================================================= // =============================================================
@@ -96,14 +93,12 @@ public class FuncState extends Constants {
int i; int i;
for (i = bl.firstlabel; i < ll_n; i++) { for (i = bl.firstlabel; i < ll_n; i++) {
if (label.eq_b(ll[i].name)) { if (label.eq_b(ll[i].name)) {
String msg = ls.L.pushfstring( String msg = ls.L.pushfstring("label '" + label + " already defined on line " + ll[i].line);
"label '" + label + " already defined on line " + ll[i].line);
ls.semerror(msg); ls.semerror(msg);
} }
} }
} }
void checklimit(int v, int l, String msg) { void checklimit(int v, int l, String msg) {
if (v > l) if (v > l)
errorlimit(l, msg); errorlimit(l, msg);
@@ -111,9 +106,8 @@ public class FuncState extends Constants {
void errorlimit(int limit, String what) { void errorlimit(int limit, String what) {
// TODO: report message logic. // TODO: report message logic.
String msg = (f.linedefined == 0) ? String msg = f.linedefined == 0? ls.L.pushfstring("main function has more than " + limit + " " + what)
ls.L.pushfstring("main function has more than "+limit+" "+what) : : ls.L.pushfstring("function at line " + f.linedefined + " has more than " + limit + " " + what);
ls.L.pushfstring("function at line "+f.linedefined+" has more than "+limit+" "+what);
ls.lexerror(msg, 0); ls.lexerror(msg, 0);
} }
@@ -124,12 +118,11 @@ public class FuncState extends Constants {
} }
void removevars(int tolevel) { void removevars(int tolevel) {
ls.dyd.n_actvar -= (nactvar - tolevel); ls.dyd.n_actvar -= nactvar-tolevel;
while ( nactvar > tolevel ) while ( nactvar > tolevel )
getlocvar(--nactvar).endpc = pc; getlocvar(--nactvar).endpc = pc;
} }
int searchupvalue(LuaString name) { int searchupvalue(LuaString name) {
int i; int i;
Upvaldesc[] up = f.upvalues; Upvaldesc[] up = f.upvalues;
@@ -252,25 +245,26 @@ public class FuncState extends Constants {
} }
boolean hasmultret(int k) { boolean hasmultret(int k) {
return ((k) == LexState.VCALL || (k) == LexState.VVARARG); return k == LexState.VCALL || k == LexState.VVARARG;
} }
void lastlistfield(ConsControl cc) { void lastlistfield(ConsControl cc) {
if (cc.tostore == 0) return; if (cc.tostore == 0)
return;
if (hasmultret(cc.v.k)) { if (hasmultret(cc.v.k)) {
this.setmultret(cc.v); this.setmultret(cc.v);
this.setlist(cc.t.u.info, cc.na, LUA_MULTRET); this.setlist(cc.t.u.info, cc.na, LUA_MULTRET);
cc.na--; /** do not count last expression (unknown number of elements) */ cc.na--; /**
} * do not count last expression (unknown number of
else { * elements)
*/
} else {
if (cc.v.k != LexState.VVOID) if (cc.v.k != LexState.VVOID)
this.exp2nextreg(cc.v); this.exp2nextreg(cc.v);
this.setlist(cc.t.u.info, cc.na, cc.tostore); this.setlist(cc.t.u.info, cc.na, cc.tostore);
} }
} }
// ============================================================= // =============================================================
// from lcode.c // from lcode.c
// ============================================================= // =============================================================
@@ -282,8 +276,7 @@ public class FuncState extends Constants {
if (GET_OPCODE(previous_code) == OP_LOADNIL) { if (GET_OPCODE(previous_code) == OP_LOADNIL) {
int pfrom = GETARG_A(previous_code); int pfrom = GETARG_A(previous_code);
int pl = pfrom+GETARG_B(previous_code); int pl = pfrom+GETARG_B(previous_code);
if ((pfrom <= from && from <= pl + 1) if (pfrom <= from && from <= pl+1 || from <= pfrom && pfrom <= l+1) { /* can connect both? */
|| (from <= pfrom && pfrom <= l + 1)) { /* can connect both? */
if (pfrom < from) if (pfrom < from)
from = pfrom; /* from = min(from, pfrom) */ from = pfrom; /* from = min(from, pfrom) */
if (pl > l) if (pl > l)
@@ -298,7 +291,6 @@ public class FuncState extends Constants {
this.codeABC(OP_LOADNIL, from, n-1, 0); this.codeABC(OP_LOADNIL, from, n-1, 0);
} }
int jump() { int jump() {
int jpc = this.jpc.i; /* save list of jumps to here */ int jpc = this.jpc.i; /* save list of jumps to here */
this.jpc.i = LexState.NO_JUMP; this.jpc.i = LexState.NO_JUMP;
@@ -325,7 +317,6 @@ public class FuncState extends Constants {
SETARG_sBx(jmp, offset); SETARG_sBx(jmp, offset);
} }
/* /*
* * returns current `pc' and marks it as a jump target (to avoid wrong * * * returns current `pc' and marks it as a jump target (to avoid wrong *
* optimizations with consecutive instructions not in the same basic block). * optimizations with consecutive instructions not in the same basic block).
@@ -335,7 +326,6 @@ public class FuncState extends Constants {
return this.pc; return this.pc;
} }
int getjump(int pc) { int getjump(int pc) {
int offset = GETARG_sBx(this.f.code[pc]); int offset = GETARG_sBx(this.f.code[pc]);
/* point to itself represents end of list */ /* point to itself represents end of list */
@@ -344,10 +334,9 @@ public class FuncState extends Constants {
return LexState.NO_JUMP; return LexState.NO_JUMP;
else else
/* turn offset into absolute position */ /* turn offset into absolute position */
return (pc + 1) + offset; return pc+1+offset;
} }
InstructionPtr getjumpcontrol(int pc) { InstructionPtr getjumpcontrol(int pc) {
InstructionPtr pi = new InstructionPtr(this.f.code, pc); InstructionPtr pi = new InstructionPtr(this.f.code, pc);
if (pc >= 1 && testTMode(GET_OPCODE(pi.code[pi.idx-1]))) if (pc >= 1 && testTMode(GET_OPCODE(pi.code[pi.idx-1])))
@@ -356,7 +345,6 @@ public class FuncState extends Constants {
return pi; return pi;
} }
/* /*
* * check whether list has any jump that do not produce a value * (or * * check whether list has any jump that do not produce a value * (or
* produce an inverted value) * produce an inverted value)
@@ -370,7 +358,6 @@ public class FuncState extends Constants {
return false; /* not found */ return false; /* not found */
} }
boolean patchtestreg(int node, int reg) { boolean patchtestreg(int node, int reg) {
InstructionPtr i = this.getjumpcontrol(node); InstructionPtr i = this.getjumpcontrol(node);
if (GET_OPCODE(i.get()) != OP_TESTSET) if (GET_OPCODE(i.get()) != OP_TESTSET)
@@ -385,7 +372,6 @@ public class FuncState extends Constants {
return true; return true;
} }
void removevalues(int list) { void removevalues(int list) {
for (; list != LexState.NO_JUMP; list = this.getjump(list)) for (; list != LexState.NO_JUMP; list = this.getjump(list))
this.patchtestreg(list, NO_REG); this.patchtestreg(list, NO_REG);
@@ -420,8 +406,8 @@ public class FuncState extends Constants {
level++; /* argument is +1 to reserve 0 as non-op */ level++; /* argument is +1 to reserve 0 as non-op */
while ( list != LexState.NO_JUMP ) { while ( list != LexState.NO_JUMP ) {
int next = getjump(list); int next = getjump(list);
_assert(GET_OPCODE(f.code[list]) == OP_JMP _assert(
&& (GETARG_A(f.code[list]) == 0 || GETARG_A(f.code[list]) >= level)); 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); SETARG_A(f.code, list, level);
list = next; list = next;
} }
@@ -472,6 +458,7 @@ public class FuncState extends Constants {
if (e.k == LexState.VNONRELOC) if (e.k == LexState.VNONRELOC)
this.freereg(e.u.info); this.freereg(e.u.info);
} }
int addk(LuaValue v) { int addk(LuaValue v) {
if (this.h == null) { if (this.h == null) {
this.h = new Hashtable(); this.h = new Hashtable();
@@ -479,7 +466,7 @@ public class FuncState extends Constants {
return ((Integer) h.get(v)).intValue(); return ((Integer) h.get(v)).intValue();
} }
final int idx = this.nk; final int idx = this.nk;
this.h.put(v, new Integer(idx)); this.h.put(v, Integer.valueOf(idx));
final Prototype f = this.f; final Prototype f = this.f;
if (f.k == null || nk+1 >= f.k.length) if (f.k == null || nk+1 >= f.k.length)
f.k = realloc(f.k, nk*2+1); f.k = realloc(f.k, nk*2+1);
@@ -495,14 +482,14 @@ public class FuncState extends Constants {
if (r instanceof LuaDouble) { if (r instanceof LuaDouble) {
double d = r.todouble(); double d = r.todouble();
int i = (int) d; int i = (int) d;
if ( d == (double) i ) if (d == i)
r = LuaInteger.valueOf(i); r = LuaInteger.valueOf(i);
} }
return this.addk(r); return this.addk(r);
} }
int boolK(boolean b) { int boolK(boolean b) {
return this.addk((b ? LuaValue.TRUE : LuaValue.FALSE)); return this.addk(b? LuaValue.TRUE: LuaValue.FALSE);
} }
int nilK() { int nilK() {
@@ -575,8 +562,7 @@ public class FuncState extends Constants {
} }
case LexState.VFALSE: case LexState.VFALSE:
case LexState.VTRUE: { case LexState.VTRUE: {
this.codeABC(OP_LOADBOOL, reg, (e.k == LexState.VTRUE ? 1 : 0), this.codeABC(OP_LOADBOOL, reg, e.k == LexState.VTRUE? 1: 0, 0);
0);
break; break;
} }
case LexState.VK: { 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_f = LexState.NO_JUMP; /* position of an eventual LOAD false */
int p_t = LexState.NO_JUMP; /* position of an eventual LOAD true */ 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)) { if (this.need_value(e.t.i) || this.need_value(e.f.i)) {
int fj = (e.k == LexState.VJMP) ? LexState.NO_JUMP : this int fj = e.k == LexState.VJMP? LexState.NO_JUMP: this.jump();
.jump();
p_f = this.code_label(reg, 0, 1); p_f = this.code_label(reg, 0, 1);
p_t = this.code_label(reg, 1, 0); p_t = this.code_label(reg, 1, 0);
this.patchtohere(fj); this.patchtohere(fj);
@@ -677,8 +662,7 @@ public class FuncState extends Constants {
case LexState.VFALSE: case LexState.VFALSE:
case LexState.VNIL: { case LexState.VNIL: {
if (this.nk <= MAXINDEXRK) { /* constant fit in RK operand? */ if (this.nk <= MAXINDEXRK) { /* constant fit in RK operand? */
e.u.info = (e.k == LexState.VNIL) ? this.nilK() e.u.info = e.k == LexState.VNIL? this.nilK(): this.boolK(e.k == LexState.VTRUE);
: this.boolK((e.k == LexState.VTRUE));
e.k = LexState.VK; e.k = LexState.VK;
return RKASK(e.u.info); return RKASK(e.u.info);
} else } else
@@ -715,7 +699,7 @@ public class FuncState extends Constants {
break; break;
} }
case LexState.VINDEXED: { case LexState.VINDEXED: {
int op = (var.u.ind_vt == LexState.VLOCAL) ? OP_SETTABLE : OP_SETTABUP; int op = var.u.ind_vt == LexState.VLOCAL? OP_SETTABLE: OP_SETTABUP;
int e = this.exp2RK(ex); int e = this.exp2RK(ex);
this.codeABC(op, var.u.ind_t, var.u.ind_idx, e); this.codeABC(op, var.u.ind_t, var.u.ind_idx, e);
break; break;
@@ -742,12 +726,11 @@ public class FuncState extends Constants {
void invertjump(expdesc e) { void invertjump(expdesc e) {
InstructionPtr pc = this.getjumpcontrol(e.u.info); InstructionPtr pc = this.getjumpcontrol(e.u.info);
_assert (testTMode(GET_OPCODE(pc.get())) _assert(testTMode(GET_OPCODE(pc.get())) && GET_OPCODE(pc.get()) != OP_TESTSET
&& GET_OPCODE(pc.get()) != OP_TESTSET && Lua && Lua.GET_OPCODE(pc.get()) != OP_TEST);
.GET_OPCODE(pc.get()) != OP_TEST);
// SETARG_A(pc, !(GETARG_A(pc.get()))); // SETARG_A(pc, !(GETARG_A(pc.get())));
int a = GETARG_A(pc.get()); int a = GETARG_A(pc.get());
int nota = (a!=0? 0: 1); int nota = a != 0? 0: 1;
SETARG_A(pc, nota); SETARG_A(pc, nota);
} }
@@ -756,7 +739,7 @@ public class FuncState extends Constants {
int ie = this.getcode(e); int ie = this.getcode(e);
if (GET_OPCODE(ie) == OP_NOT) { if (GET_OPCODE(ie) == OP_NOT) {
this.pc--; /* remove previous OP_NOT */ this.pc--; /* remove previous OP_NOT */
return this.condjump(OP_TEST, GETARG_B(ie), 0, (cond!=0? 0: 1)); return this.condjump(OP_TEST, GETARG_B(ie), 0, cond != 0? 0: 1);
} }
/* else go through */ /* else go through */
} }
@@ -855,14 +838,14 @@ public class FuncState extends Constants {
} }
static boolean vkisinreg(int k) { static boolean vkisinreg(int k) {
return ((k) == LexState.VNONRELOC || (k) == LexState.VLOCAL); return k == LexState.VNONRELOC || k == LexState.VLOCAL;
} }
void indexed(expdesc t, expdesc k) { void indexed(expdesc t, expdesc k) {
t.u.ind_t = (short) t.u.info; t.u.ind_t = (short) t.u.info;
t.u.ind_idx = (short) this.exp2RK(k); t.u.ind_idx = (short) this.exp2RK(k);
LuaC._assert(t.k == LexState.VUPVAL || vkisinreg(t.k)); Constants._assert(t.k == LexState.VUPVAL || vkisinreg(t.k));
t.u.ind_vt = (short) ((t.k == LexState.VUPVAL) ? LexState.VUPVAL : LexState.VLOCAL); t.u.ind_vt = (short) (t.k == LexState.VUPVAL? LexState.VUPVAL: LexState.VLOCAL);
t.k = LexState.VINDEXED; t.k = LexState.VINDEXED;
} }
@@ -912,11 +895,9 @@ public class FuncState extends Constants {
} }
void codearith(int op, expdesc e1, expdesc e2, int line) { void codearith(int op, expdesc e1, expdesc e2, int line) {
if (constfolding(op, e1, e2)) if (constfolding(op, e1, e2)) {
return; } else {
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); int o1 = this.exp2RK(e1);
if (o1 > o2) { if (o1 > o2) {
this.freeexp(e1); this.freeexp(e1);
@@ -1004,7 +985,6 @@ public class FuncState extends Constants {
} }
} }
void posfix(int op, expdesc e1, expdesc e2, int line) { void posfix(int op, expdesc e1, expdesc e2, int line) {
switch (op) { switch (op) {
case LexState.OPR_AND: { case LexState.OPR_AND: {
@@ -1025,8 +1005,7 @@ public class FuncState extends Constants {
} }
case LexState.OPR_CONCAT: { case LexState.OPR_CONCAT: {
this.exp2val(e2); this.exp2val(e2);
if (e2.k == LexState.VRELOCABLE if (e2.k == LexState.VRELOCABLE && GET_OPCODE(this.getcode(e2)) == OP_CONCAT) {
&& GET_OPCODE(this.getcode(e2)) == OP_CONCAT) {
_assert(e1.u.info == GETARG_B(this.getcode(e2))-1); _assert(e1.u.info == GETARG_B(this.getcode(e2))-1);
this.freeexp(e1); this.freeexp(e1);
SETARG_B(this.getcodePtr(e2), e1.u.info); SETARG_B(this.getcodePtr(e2), e1.u.info);
@@ -1079,28 +1058,24 @@ public class FuncState extends Constants {
} }
} }
void fixline(int line) { void fixline(int line) {
this.f.lineinfo[this.pc-1] = line; this.f.lineinfo[this.pc-1] = line;
} }
int code(int instruction, int line) { int code(int instruction, int line) {
Prototype f = this.f; Prototype f = this.f;
this.dischargejpc(); /* `pc' will change */ this.dischargejpc(); /* `pc' will change */
/* put new instruction in code array */ /* put new instruction in code array */
if (f.code == null || this.pc+1 > f.code.length) if (f.code == null || this.pc+1 > f.code.length)
f.code = LuaC.realloc(f.code, this.pc * 2 + 1); f.code = Constants.realloc(f.code, this.pc*2+1);
f.code[this.pc] = instruction; f.code[this.pc] = instruction;
/* save corresponding line information */ /* save corresponding line information */
if (f.lineinfo == null || this.pc+1 > f.lineinfo.length) if (f.lineinfo == null || this.pc+1 > f.lineinfo.length)
f.lineinfo = LuaC.realloc(f.lineinfo, f.lineinfo = Constants.realloc(f.lineinfo, this.pc*2+1);
this.pc * 2 + 1);
f.lineinfo[this.pc] = line; f.lineinfo[this.pc] = line;
return this.pc++; return this.pc++;
} }
int codeABC(int o, int a, int b, int c) { int codeABC(int o, int a, int b, int c) {
_assert(getOpMode(o) == iABC); _assert(getOpMode(o) == iABC);
_assert(getBMode(o) != OpArgN || b == 0); _assert(getBMode(o) != OpArgN || b == 0);
@@ -1108,7 +1083,6 @@ public class FuncState extends Constants {
return this.code(CREATE_ABC(o, a, b, c), this.ls.lastline); return this.code(CREATE_ABC(o, a, b, c), this.ls.lastline);
} }
int codeABx(int o, int a, int bc) { int codeABx(int o, int a, int bc) {
_assert(getOpMode(o) == iABx || getOpMode(o) == iAsBx); _assert(getOpMode(o) == iABx || getOpMode(o) == iAsBx);
_assert(getCMode(o) == OpArgN); _assert(getCMode(o) == OpArgN);
@@ -1133,7 +1107,7 @@ public class FuncState extends Constants {
void setlist(int base, int nelems, int tostore) { void setlist(int base, int nelems, int tostore) {
int c = (nelems-1)/LFIELDS_PER_FLUSH+1; int c = (nelems-1)/LFIELDS_PER_FLUSH+1;
int b = (tostore == LUA_MULTRET) ? 0 : tostore; int b = tostore == LUA_MULTRET? 0: tostore;
_assert(tostore != 0); _assert(tostore != 0);
if (c <= MAXARG_C) if (c <= MAXARG_C)
this.codeABC(OP_SETLIST, base, b, c); this.codeABC(OP_SETLIST, base, b, c);

View File

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

View File

@@ -23,8 +23,10 @@ package org.luaj.vm2.compiler;
public class IntPtr { public class IntPtr {
int i; int i;
IntPtr() { IntPtr() {
} }
IntPtr(int value) { IntPtr(int value) {
this.i = 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.compiler.FuncState.BlockCnt;
import org.luaj.vm2.lib.MathLib; import org.luaj.vm2.lib.MathLib;
public class LexState extends Constants { public class LexState extends Constants {
protected static final String RESERVED_LOCAL_VAR_FOR_CONTROL = "(for control)"; protected static final String RESERVED_LOCAL_VAR_FOR_CONTROL = "(for control)";
@@ -46,26 +45,22 @@ public class LexState extends Constants {
protected static final String RESERVED_LOCAL_VAR_FOR_INDEX = "(for index)"; protected static final String RESERVED_LOCAL_VAR_FOR_INDEX = "(for index)";
// keywords array // keywords array
protected static final String[] RESERVED_LOCAL_VAR_KEYWORDS = new String[] { protected static final String[] RESERVED_LOCAL_VAR_KEYWORDS = { RESERVED_LOCAL_VAR_FOR_CONTROL,
RESERVED_LOCAL_VAR_FOR_CONTROL, RESERVED_LOCAL_VAR_FOR_GENERATOR, RESERVED_LOCAL_VAR_FOR_INDEX, RESERVED_LOCAL_VAR_FOR_LIMIT,
RESERVED_LOCAL_VAR_FOR_GENERATOR, RESERVED_LOCAL_VAR_FOR_STATE, RESERVED_LOCAL_VAR_FOR_STEP };
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(); private static final Hashtable RESERVED_LOCAL_VAR_KEYWORDS_TABLE = new Hashtable();
static { static {
for ( int i=0; i<RESERVED_LOCAL_VAR_KEYWORDS.length; i++ ) for (String element : RESERVED_LOCAL_VAR_KEYWORDS)
RESERVED_LOCAL_VAR_KEYWORDS_TABLE.put( RESERVED_LOCAL_VAR_KEYWORDS[i], Boolean.TRUE ); RESERVED_LOCAL_VAR_KEYWORDS_TABLE.put(element, Boolean.TRUE);
} }
private static final int EOZ = (-1); private static final int EOZ = -1;
private static final int MAX_INT = Integer.MAX_VALUE-2; private static final int MAX_INT = Integer.MAX_VALUE-2;
private static final int UCHAR_MAX = 255; // TODO, convert to unicode CHAR_MAX? private static final int UCHAR_MAX = 255; // TODO, convert to unicode CHAR_MAX?
private static final int LUAI_MAXCCALLS = 200; private static final int LUAI_MAXCCALLS = 200;
private static final String LUA_QS(String s) { return "'" + s + "'"; } 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 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 private static final int LUA_COMPAT_LSTR = 1; // 1 for compatibility, 2 for old behavior
@@ -79,29 +74,20 @@ public class LexState extends Constants {
** Marks the end of a patch list. It is an invalid value both as an absolute ** Marks the end of a patch list. It is an invalid value both as an absolute
** address, and as a list link (would link an element to itself). ** address, and as a list link (would link an element to itself).
*/ */
static final int NO_JUMP = (-1); static final int NO_JUMP = -1;
/* /*
** grep "ORDER OPR" if you change these enums ** grep "ORDER OPR" if you change these enums
*/ */
static final int 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_ADD=0, OPR_SUB=1, OPR_MUL=2, OPR_DIV=3, OPR_MOD=4, OPR_POW=5, 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_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; OPR_NOBINOPR = 15;
static final int static final int OPR_MINUS = 0, OPR_NOT = 1, OPR_LEN = 2, OPR_NOUNOPR = 3;
OPR_MINUS=0, OPR_NOT=1, OPR_LEN=2, OPR_NOUNOPR=3;
/* exp kind */ /* exp kind */
static final int static final int VVOID = 0, /* no value */
VVOID = 0, /* no value */ VNIL = 1, VTRUE = 2, VFALSE = 3, VK = 4, /* info = index of constant in `k' */
VNIL = 1,
VTRUE = 2,
VFALSE = 3,
VK = 4, /* info = index of constant in `k' */
VKNUM = 5, /* nval = numerical value */ VKNUM = 5, /* nval = numerical value */
VNONRELOC = 6, /* info = result register */ VNONRELOC = 6, /* info = result register */
VLOCAL = 7, /* info = local register */ VLOCAL = 7, /* info = local register */
@@ -116,17 +102,18 @@ public class LexState extends Constants {
private static class SemInfo { private static class SemInfo {
LuaValue r; LuaValue r;
LuaString ts; LuaString ts;
}; }
private static class Token { private static class Token {
int token; int token;
final SemInfo seminfo = new SemInfo(); final SemInfo seminfo = new SemInfo();
public void set(Token other) { public void set(Token other) {
this.token = other.token; this.token = other.token;
this.seminfo.r = other.seminfo.r; this.seminfo.r = other.seminfo.r;
this.seminfo.ts = other.seminfo.ts; this.seminfo.ts = other.seminfo.ts;
} }
}; }
int current; /* current character (charint) */ int current; /* current character (charint) */
int linenumber; /* input line counter */ int linenumber; /* input line counter */
@@ -150,18 +137,18 @@ public class LexState extends Constants {
"in", "local", "nil", "not", "or", "repeat", "in", "local", "nil", "not", "or", "repeat",
"return", "then", "true", "until", "while", "return", "then", "true", "until", "while",
"..", "...", "==", ">=", "<=", "~=", "..", "...", "==", ">=", "<=", "~=",
"::", "<eos>", "<number>", "<name>", "<string>", "<eof>", "::", "<eof>", "<number>", "<name>", "<string>"
}; };
final static int final static int
/* terminal symbols denoted by reserved words */ /* terminal symbols denoted by reserved words */
TK_AND=257, TK_BREAK=258, TK_DO=259, TK_ELSE=260, TK_ELSEIF=261, TK_AND = 257, TK_BREAK = 258, TK_DO = 259, TK_ELSE = 260, TK_ELSEIF = 261, TK_END = 262, TK_FALSE = 263,
TK_END=262, TK_FALSE=263, TK_FOR=264, TK_FUNCTION=265, TK_GOTO=266, TK_IF=267, TK_FOR = 264, TK_FUNCTION = 265, TK_GOTO = 266, TK_IF = 267, TK_IN = 268, TK_LOCAL = 269, TK_NIL = 270,
TK_IN=268, TK_LOCAL=269, TK_NIL=270, TK_NOT=271, TK_OR=272, TK_REPEAT=273, TK_NOT = 271, TK_OR = 272, TK_REPEAT = 273, TK_RETURN = 274, TK_THEN = 275, TK_TRUE = 276, TK_UNTIL = 277,
TK_RETURN=274, TK_THEN=275, TK_TRUE=276, TK_UNTIL=277, TK_WHILE=278, TK_WHILE = 278,
/* other terminal symbols */ /* other terminal symbols */
TK_CONCAT=279, TK_DOTS=280, TK_EQ=281, TK_GE=282, TK_LE=283, TK_NE=284, 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_DBCOLON=285, TK_EOF=286, TK_NUMBER=287, TK_NAME=288, TK_STRING=289;
final static int FIRST_RESERVED = TK_AND; final static int FIRST_RESERVED = TK_AND;
final static int NUM_RESERVED = TK_WHILE+1-FIRST_RESERVED; final static int NUM_RESERVED = TK_WHILE+1-FIRST_RESERVED;
@@ -169,39 +156,32 @@ public class LexState extends Constants {
final static Hashtable RESERVED = new Hashtable(); final static Hashtable RESERVED = new Hashtable();
static { static {
for (int i = 0; i < NUM_RESERVED; i++) { for (int i = 0; i < NUM_RESERVED; i++) {
LuaString ts = (LuaString) LuaValue.valueOf( luaX_tokens[i] ); LuaString ts = LuaValue.valueOf(luaX_tokens[i]);
RESERVED.put(ts, new Integer(FIRST_RESERVED+i)); RESERVED.put(ts, Integer.valueOf(FIRST_RESERVED+i));
} }
} }
private boolean isalnum(int c) { private boolean isalnum(int c) {
return (c >= '0' && c <= '9') return c >= '0' && c <= '9' || c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z' || c == '_';
|| (c >= 'a' && c <= 'z')
|| (c >= 'A' && c <= 'Z')
|| (c == '_');
// return Character.isLetterOrDigit(c); // return Character.isLetterOrDigit(c);
} }
private boolean isalpha(int c) { private boolean isalpha(int c) {
return (c >= 'a' && c <= 'z') return c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z';
|| (c >= 'A' && c <= 'Z');
} }
private boolean isdigit(int c) { private boolean isdigit(int c) {
return (c >= '0' && c <= '9'); return c >= '0' && c <= '9';
} }
private boolean isxdigit(int c) { private boolean isxdigit(int c) {
return (c >= '0' && c <= '9') return c >= '0' && c <= '9' || c >= 'a' && c <= 'f' || c >= 'A' && c <= 'F';
|| (c >= 'a' && c <= 'f')
|| (c >= 'A' && c <= 'F');
} }
private boolean isspace(int c) { private boolean isspace(int c) {
return (c >= 0 && c <= ' '); return c >= 0 && c <= ' ';
} }
public LexState(LuaC.CompileState state, InputStream stream) { public LexState(LuaC.CompileState state, InputStream stream) {
this.z = stream; this.z = stream;
this.buff = new char[32]; this.buff = new char[32];
@@ -232,12 +212,9 @@ public class LexState extends Constants {
buff[nbuff++] = (char) c; buff[nbuff++] = (char) c;
} }
String token2str(int token) { String token2str(int token) {
if (token < FIRST_RESERVED) { if (token < FIRST_RESERVED) {
return iscntrl(token)? return iscntrl(token)? L.pushfstring("char(" + token + ")"): L.pushfstring(String.valueOf((char) token));
L.pushfstring( "char("+((int)token)+")" ):
L.pushfstring( String.valueOf( (char) token ) );
} else { } else {
return luaX_tokens[token-FIRST_RESERVED]; return luaX_tokens[token-FIRST_RESERVED];
} }
@@ -292,7 +269,7 @@ public class LexState extends Constants {
void setinput(LuaC.CompileState L, int firstByte, InputStream z, LuaString source) { void setinput(LuaC.CompileState L, int firstByte, InputStream z, LuaString source) {
this.decpoint = '.'; this.decpoint = '.';
this.L = L; this.L = L;
this.lookahead.token = TK_EOS; /* no look-ahead token */ this.lookahead.token = TK_EOF; /* no look-ahead token */
this.z = z; this.z = z;
this.fs = null; this.fs = null;
this.linenumber = 1; this.linenumber = 1;
@@ -310,15 +287,12 @@ public class LexState extends Constants {
nextChar(); nextChar();
} }
/* /*
** ======================================================= ** =======================================================
** LEXICAL ANALYZER ** LEXICAL ANALYZER
** ======================================================= ** =======================================================
*/ */
boolean check_next(String set) { boolean check_next(String set) {
if (set.indexOf(current) < 0) if (set.indexOf(current) < 0)
return false; return false;
@@ -329,7 +303,7 @@ public class LexState extends Constants {
void buffreplace(char from, char to) { void buffreplace(char from, char to) {
int n = nbuff; int n = nbuff;
char[] p = buff; char[] p = buff;
while ((--n) >= 0) while ( --n >= 0 )
if (p[n] == from) if (p[n] == from)
p[n] = to; p[n] = to;
} }
@@ -346,11 +320,7 @@ public class LexState extends Constants {
++s; ++s;
} }
/* Check for "0x" */ /* Check for "0x" */
if (s + 2 >= c.length ) if (s+2 >= c.length || c[s++] != '0' || c[s] != 'x' && c[s] != 'X')
return LuaValue.ZERO;
if (c[s++] != '0')
return LuaValue.ZERO;
if (c[s] != 'x' && c[s] != 'X')
return LuaValue.ZERO; return LuaValue.ZERO;
++s; ++s;
@@ -358,11 +328,11 @@ public class LexState extends Constants {
double m = 0; double m = 0;
int e = 0; int e = 0;
while ( s < c.length && isxdigit(c[s]) ) while ( s < c.length && isxdigit(c[s]) )
m = (m * 16) + hexvalue(c[s++]); m = m*16+hexvalue(c[s++]);
if (s < c.length && c[s] == '.') { if (s < c.length && c[s] == '.') {
++s; // skip dot ++s; // skip dot
while ( s < c.length && isxdigit(c[s]) ) { while ( s < c.length && isxdigit(c[s]) ) {
m = (m * 16) + hexvalue(c[s++]); m = m*16+hexvalue(c[s++]);
e -= 4; // Each fractional part shifts right by 2^4 e -= 4; // Each fractional part shifts right by 2^4
} }
} }
@@ -426,7 +396,7 @@ public class LexState extends Constants {
save_and_next(); save_and_next();
count++; count++;
} }
return (current == s) ? count : (-count) - 1; return current == s? count: (-count)-1;
} }
void read_long_string(SemInfo seminfo, int sep) { void read_long_string(SemInfo seminfo, int sep) {
@@ -438,7 +408,7 @@ public class LexState extends Constants {
switch (current) { switch (current) {
case EOZ: case EOZ:
lexerror((seminfo != null) ? "unfinished long string" lexerror((seminfo != null) ? "unfinished long string"
: "unfinished long comment", TK_EOS); : "unfinished long comment", TK_EOF);
break; /* to avoid warnings */ break; /* to avoid warnings */
case '[': { case '[': {
if (skip_sep() == sep) { if (skip_sep() == sep) {
@@ -493,7 +463,7 @@ public class LexState extends Constants {
nextChar(); nextChar();
int c2 = current; int c2 = current;
if (!isxdigit(c1) || !isxdigit(c2)) if (!isxdigit(c1) || !isxdigit(c2))
lexerror("hexadecimal digit expected 'x"+((char)c1)+((char)c2), TK_STRING); lexerror("hexadecimal digit expected 'x" + (char) c1 + (char) c2, TK_STRING);
return (hexvalue(c1)<<4)+hexvalue(c2); return (hexvalue(c1)<<4)+hexvalue(c2);
} }
@@ -502,7 +472,7 @@ public class LexState extends Constants {
while ( current != del ) { while ( current != del ) {
switch (current) { switch (current) {
case EOZ: case EOZ:
lexerror("unfinished string", TK_EOS); lexerror("unfinished string", TK_EOF);
continue; /* to avoid warnings */ continue; /* to avoid warnings */
case '\n': case '\n':
case '\r': case '\r':
@@ -546,8 +516,10 @@ public class LexState extends Constants {
case 'z': { /* zap following span of spaces */ case 'z': { /* zap following span of spaces */
nextChar(); /* skip the 'z' */ nextChar(); /* skip the 'z' */
while ( isspace(current) ) { while ( isspace(current) ) {
if (currIsNewline()) inclinenumber(); if (currIsNewline())
else nextChar(); inclinenumber();
else
nextChar();
} }
continue; continue;
} }
@@ -558,7 +530,7 @@ public class LexState extends Constants {
int i = 0; int i = 0;
c = 0; c = 0;
do { do {
c = 10 * c + (current - '0'); c = 10*c+current-'0';
nextChar(); nextChar();
} while ( ++i < 3 && isdigit(current) ); } while ( ++i < 3 && isdigit(current) );
if (c > UCHAR_MAX) if (c > UCHAR_MAX)
@@ -696,7 +668,7 @@ public class LexState extends Constants {
return TK_NUMBER; return TK_NUMBER;
} }
case EOZ: { case EOZ: {
return TK_EOS; return TK_EOF;
} }
default: { default: {
if (isalpha(current) || current == '_') { if (isalpha(current) || current == '_') {
@@ -724,15 +696,15 @@ public class LexState extends Constants {
void next() { void next() {
lastline = linenumber; lastline = linenumber;
if (lookahead.token != TK_EOS) { /* is there a look-ahead token? */ if (lookahead.token != TK_EOF) { /* is there a look-ahead token? */
t.set( lookahead ); /* use this one */ t.set( lookahead ); /* use this one */
lookahead.token = TK_EOS; /* and discharge it */ lookahead.token = TK_EOF; /* and discharge it */
} else } else
t.token = llex(t.seminfo); /* read next token */ t.token = llex(t.seminfo); /* read next token */
} }
void lookahead() { void lookahead() {
_assert (lookahead.token == TK_EOS); _assert (lookahead.token == TK_EOF);
lookahead.token = llex(lookahead.seminfo); lookahead.token = llex(lookahead.seminfo);
} }
@@ -740,37 +712,39 @@ public class LexState extends Constants {
// from lcode.h // from lcode.h
// ============================================================= // =============================================================
// ============================================================= // =============================================================
// from lparser.c // from lparser.c
// ============================================================= // =============================================================
static final boolean vkisvar(final int k) { static final boolean vkisvar(final int k) {
return (VLOCAL <= (k) && (k) <= VINDEXED); return VLOCAL <= k && k <= VINDEXED;
} }
static final boolean vkisinreg(final int k) { static final boolean vkisinreg(final int k) {
return ((k) == VNONRELOC || (k) == VLOCAL); return k == VNONRELOC || k == VLOCAL;
} }
static class expdesc { static class expdesc {
int k; // expkind, from enumerated list, above int k; // expkind, from enumerated list, above
static class U { // originally a union static class U { // originally a union
short ind_idx; // index (R/K) short ind_idx; // index (R/K)
short ind_t; // table(register or upvalue) short ind_t; // table(register or upvalue)
short ind_vt; // whether 't' is register (VLOCAL) or (UPVALUE) short ind_vt; // whether 't' is register (VLOCAL) or (UPVALUE)
private LuaValue _nval; private LuaValue _nval;
int info; int info;
public void setNval(LuaValue r) {
_nval = r; public void setNval(LuaValue r) { _nval = r; }
}
public LuaValue nval() { public LuaValue nval() {
return (_nval == null? LuaInteger.valueOf(info): _nval); return _nval == null? LuaInteger.valueOf(info): _nval;
} }
}; }
final U u = new U(); final U u = new U();
final IntPtr t = new IntPtr(); /* patch list of `exit when true' */ final IntPtr t = new IntPtr(); /* patch list of `exit when true' */
final IntPtr f = new IntPtr(); /* patch list of `exit when false' */ final IntPtr f = new IntPtr(); /* patch list of `exit when false' */
void init(int k, int i) { void init(int k, int i) {
this.f.i = NO_JUMP; this.f.i = NO_JUMP;
this.t.i = NO_JUMP; this.t.i = NO_JUMP;
@@ -779,11 +753,11 @@ public class LexState extends Constants {
} }
boolean hasjumps() { boolean hasjumps() {
return (t.i != f.i); return t.i != f.i;
} }
boolean isnumeral() { boolean isnumeral() {
return (k == VKNUM && t.i == NO_JUMP && f.i == NO_JUMP); return k == VKNUM && t.i == NO_JUMP && f.i == NO_JUMP;
} }
public void setvalue(expdesc other) { public void setvalue(expdesc other) {
@@ -798,15 +772,14 @@ public class LexState extends Constants {
} }
} }
/* description of active local variable */ /* description of active local variable */
static class Vardesc { static class Vardesc {
final short idx; /* variable index in stack */ final short idx; /* variable index in stack */
Vardesc(int idx) { Vardesc(int idx) {
this.idx = (short) idx; this.idx = (short) idx;
} }
}; }
/* description of pending goto statements and label statements */ /* description of pending goto statements and label statements */
static class Labeldesc { static class Labeldesc {
@@ -814,14 +787,14 @@ public class LexState extends Constants {
int pc; /* position in code */ int pc; /* position in code */
int line; /* line where it appeared */ int line; /* line where it appeared */
short nactvar; /* local level where it appears in current block */ short nactvar; /* local level where it appears in current block */
public Labeldesc(LuaString name, int pc, int line, short nactvar) { public Labeldesc(LuaString name, int pc, int line, short nactvar) {
this.name = name; this.name = name;
this.pc = pc; this.pc = pc;
this.line = line; this.line = line;
this.nactvar = nactvar; this.nactvar = nactvar;
} }
}; }
/* dynamic structures used by the parser */ /* dynamic structures used by the parser */
static class Dyndata { static class Dyndata {
@@ -831,11 +804,10 @@ public class LexState extends Constants {
int n_gt = 0; int n_gt = 0;
Labeldesc[] label; /* list of active labels */ Labeldesc[] label; /* list of active labels */
int n_label = 0; int n_label = 0;
}; }
boolean hasmultret(int k) { boolean hasmultret(int k) {
return ((k) == VCALL || (k) == VVARARG); return k == VCALL || k == VVARARG;
} }
/*---------------------------------------------------------------------- /*----------------------------------------------------------------------
@@ -843,8 +815,8 @@ public class LexState extends Constants {
------------------------------------------------------------------------*/ ------------------------------------------------------------------------*/
void anchor_token () { void anchor_token () {
/* last token from outer function must be EOS */ /* last token from outer function must be EOF */
_assert(fs != null || t.token == TK_EOS); _assert(fs != null || t.token == TK_EOF);
if (t.token == TK_NAME || t.token == TK_STRING) { if (t.token == TK_NAME || t.token == TK_STRING) {
LuaString ts = t.seminfo.ts; LuaString ts = t.seminfo.ts;
// TODO: is this necessary? // TODO: is this necessary?
@@ -881,18 +853,16 @@ public class LexState extends Constants {
} }
void check_condition(boolean c, String msg) { void check_condition(boolean c, String msg) {
if (!(c)) if (!c)
syntaxerror(msg); syntaxerror(msg);
} }
void check_match(int what, int who, int where) { void check_match(int what, int who, int where) {
if (!testnext(what)) { if (!testnext(what)) {
if (where == linenumber) if (where == linenumber)
error_expected(what); error_expected(what);
else { else {
syntaxerror(L.pushfstring(LUA_QS(token2str(what)) syntaxerror(L.pushfstring(LUA_QS(token2str(what)) + " expected " + "(to close " + LUA_QS(token2str(who))
+ " expected " + "(to close " + LUA_QS(token2str(who))
+ " at line " + where + ")")); + " at line " + where + ")"));
} }
} }
@@ -914,7 +884,6 @@ public class LexState extends Constants {
codestring(e, str_checkname()); codestring(e, str_checkname());
} }
int registerlocalvar(LuaString varname) { int registerlocalvar(LuaString varname) {
FuncState fs = this.fs; FuncState fs = this.fs;
Prototype f = fs.f; Prototype f = fs.f;
@@ -926,7 +895,7 @@ public class LexState extends Constants {
void new_localvar(LuaString name) { void new_localvar(LuaString name) {
int reg = registerlocalvar(name); int reg = registerlocalvar(name);
fs.checklimit(dyd.n_actvar + 1, FuncState.LUAI_MAXVARS, "local variables"); fs.checklimit(dyd.n_actvar+1, Constants.LUAI_MAXVARS, "local variables");
if (dyd.actvar == null || dyd.n_actvar+1 > dyd.actvar.length) if (dyd.actvar == null || dyd.n_actvar+1 > dyd.actvar.length)
dyd.actvar = realloc(dyd.actvar, Math.max(1, dyd.n_actvar*2)); dyd.actvar = realloc(dyd.actvar, Math.max(1, dyd.n_actvar*2));
dyd.actvar[dyd.n_actvar++] = new Vardesc(reg); dyd.actvar[dyd.n_actvar++] = new Vardesc(reg);
@@ -1003,8 +972,7 @@ public class LexState extends Constants {
_assert(gt.name.eq_b(label.name)); _assert(gt.name.eq_b(label.name));
if (gt.nactvar < label.nactvar) { if (gt.nactvar < label.nactvar) {
LuaString vname = fs.getlocvar(gt.nactvar).varname; LuaString vname = fs.getlocvar(gt.nactvar).varname;
String msg = L.pushfstring("<goto " + gt.name + "> at line " String msg = L.pushfstring("<goto " + gt.name + "> at line " + gt.line + " jumps into the scope of local '"
+ gt.line + " jumps into the scope of local '"
+ vname.tojstring() + "'"); + vname.tojstring() + "'");
semerror(msg); semerror(msg);
} }
@@ -1026,8 +994,7 @@ public class LexState extends Constants {
for (i = bl.firstlabel; i < dyd.n_label; i++) { for (i = bl.firstlabel; i < dyd.n_label; i++) {
Labeldesc lb = dyd.label[i]; Labeldesc lb = dyd.label[i];
if (lb.name.eq_b(gt.name)) { /* correct label? */ if (lb.name.eq_b(gt.name)) { /* correct label? */
if (gt.nactvar > lb.nactvar && if (gt.nactvar > lb.nactvar && (bl.upval || dyd.n_label > bl.firstlabel))
(bl.upval || dyd.n_label > bl.firstlabel))
fs.patchclose(gt.pc, lb.nactvar); fs.patchclose(gt.pc, lb.nactvar);
closegoto(g, lb); /* close it */ closegoto(g, lb); /* close it */
return true; return true;
@@ -1057,7 +1024,6 @@ public class LexState extends Constants {
} }
} }
/* /*
** create a label named "break" to resolve break statements ** create a label named "break" to resolve break statements
*/ */
@@ -1072,8 +1038,8 @@ public class LexState extends Constants {
** message when label name is a reserved word (which can only be 'break') ** message when label name is a reserved word (which can only be 'break')
*/ */
void undefgoto(Labeldesc gt) { void undefgoto(Labeldesc gt) {
String msg = L.pushfstring(isReservedKeyword(gt.name.tojstring()) String msg = L.pushfstring(
? "<"+gt.name+"> at line "+gt.line+" not inside a loop" 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); : "no visible label '" + gt.name + "' for <goto> at line " + gt.line);
semerror(msg); semerror(msg);
} }
@@ -1153,22 +1119,19 @@ public class LexState extends Constants {
this.checknext(']'); this.checknext(']');
} }
/* /*
** {====================================================================== ** {======================================================================
** Rules for Constructors ** Rules for Constructors
** ======================================================================= ** =======================================================================
*/ */
static class ConsControl { static class ConsControl {
expdesc v = new expdesc(); /* last list item read */ expdesc v = new expdesc(); /* last list item read */
expdesc t; /* table descriptor */ expdesc t; /* table descriptor */
int nh; /* total number of `record' elements */ int nh; /* total number of `record' elements */
int na; /* total number of array elements */ int na; /* total number of array elements */
int tostore; /* number of array elements pending to be stored */ int tostore; /* number of array elements pending to be stored */
}; }
void recfield(ConsControl cc) { void recfield(ConsControl cc) {
/* recfield -> (NAME | `['exp1`]') = exp1 */ /* recfield -> (NAME | `['exp1`]') = exp1 */
@@ -1198,7 +1161,6 @@ public class LexState extends Constants {
cc.tostore++; cc.tostore++;
} }
void constructor(expdesc t) { void constructor(expdesc t) {
/* constructor -> ?? */ /* constructor -> ?? */
FuncState fs = this.fs; FuncState fs = this.fs;
@@ -1250,14 +1212,15 @@ public class LexState extends Constants {
static int luaO_int2fb(int x) { static int luaO_int2fb(int x) {
int e = 0; /* expoent */ int e = 0; /* expoent */
while ( x >= 16 ) { while ( x >= 16 ) {
x = (x+1) >> 1; x = x+1>>1;
e++; e++;
} }
if (x < 8) return x; if (x < 8)
else return ((e+1) << 3) | (((int)x) - 8); return x;
else
return e+1<<3 | x-8;
} }
/* }====================================================================== */ /* }====================================================================== */
void parlist() { void parlist() {
@@ -1279,16 +1242,16 @@ public class LexState extends Constants {
f.is_vararg = 1; f.is_vararg = 1;
break; break;
} }
default: this.syntaxerror("<name> or " + LUA_QL("...") + " expected"); default:
this.syntaxerror("<name> or " + LUA_QL("...") + " expected");
} }
} while ((f.is_vararg==0) && this.testnext(',')); } while ( f.is_vararg == 0 && this.testnext(',') );
} }
this.adjustlocalvars(nparams); this.adjustlocalvars(nparams);
f.numparams = fs.nactvar; f.numparams = fs.nactvar;
fs.reserveregs(fs.nactvar); /* reserve register for parameters */ fs.reserveregs(fs.nactvar); /* reserve register for parameters */
} }
void body(expdesc e, boolean needself, int line) { void body(expdesc e, boolean needself, int line) {
/* body -> `(' parlist `)' chunk END */ /* body -> `(' parlist `)' chunk END */
FuncState new_fs = new FuncState(); FuncState new_fs = new FuncState();
@@ -1322,7 +1285,6 @@ public class LexState extends Constants {
return n; return n;
} }
void funcargs(expdesc f, int line) { void funcargs(expdesc f, int line) {
FuncState fs = this.fs; FuncState fs = this.fs;
expdesc args = new expdesc(); expdesc args = new expdesc();
@@ -1368,7 +1330,6 @@ public class LexState extends Constants {
* (unless changed) one result */ * (unless changed) one result */
} }
/* /*
** {====================================================================== ** {======================================================================
** Expression parsing ** Expression parsing
@@ -1391,13 +1352,11 @@ public class LexState extends Constants {
return; return;
} }
default: { default: {
this.syntaxerror("unexpected symbol " + t.token + " (" + ((char) t.token) + ")"); this.syntaxerror("unexpected symbol " + t.token + " (" + (char) t.token + ")");
return;
} }
} }
} }
void suffixedexp(expdesc v) { void suffixedexp(expdesc v) {
/* suffixedexp -> /* suffixedexp ->
primaryexp { '.' NAME | '[' exp ']' | ':' NAME funcargs | funcargs } */ primaryexp { '.' NAME | '[' exp ']' | ':' NAME funcargs | funcargs } */
@@ -1437,7 +1396,6 @@ public class LexState extends Constants {
} }
} }
void simpleexp(expdesc v) { void simpleexp(expdesc v) {
/* /*
* simpleexp -> NUMBER | STRING | NIL | true | false | ... | constructor | * simpleexp -> NUMBER | STRING | NIL | true | false | ... | constructor |
@@ -1467,8 +1425,7 @@ public class LexState extends Constants {
} }
case TK_DOTS: { /* vararg */ case TK_DOTS: { /* vararg */
FuncState fs = this.fs; FuncState fs = this.fs;
this.check_condition(fs.f.is_vararg!=0, "cannot use " + LUA_QL("...") this.check_condition(fs.f.is_vararg != 0, "cannot use " + LUA_QL("...") + " outside a vararg function");
+ " outside a vararg function");
v.init(VVARARG, fs.codeABC(Lua.OP_VARARG, 0, 1, 0)); v.init(VVARARG, fs.codeABC(Lua.OP_VARARG, 0, 1, 0));
break; break;
} }
@@ -1489,7 +1446,6 @@ public class LexState extends Constants {
this.next(); this.next();
} }
int getunopr(int op) { int getunopr(int op) {
switch (op) { switch (op) {
case TK_NOT: case TK_NOT:
@@ -1503,7 +1459,6 @@ public class LexState extends Constants {
} }
} }
int getbinopr(int op) { int getbinopr(int op) {
switch (op) { switch (op) {
case '+': case '+':
@@ -1550,10 +1505,11 @@ public class LexState extends Constants {
left = (byte) i; left = (byte) i;
right = (byte) j; right = (byte) j;
} }
}; }
static Priority[] priority = { /* ORDER OPR */ 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(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), /* equality and inequality */
new Priority(3, 3), new Priority(3, 3), new Priority(3, 3), new Priority(3, 3), /* order */ new Priority(3, 3), new Priority(3, 3), new Priority(3, 3), new Priority(3, 3), /* order */
@@ -1562,7 +1518,6 @@ public class LexState extends Constants {
static final int UNARY_PRIORITY = 8; /* priority for unary operators */ static final int UNARY_PRIORITY = 8; /* priority for unary operators */
/* /*
** subexpr -> (simpleexp | unop subexpr) { binop subexpr } ** subexpr -> (simpleexp | unop subexpr) { binop subexpr }
** where `binop' is any binary operator with a priority higher than `limit' ** where `binop' is any binary operator with a priority higher than `limit'
@@ -1601,18 +1556,15 @@ public class LexState extends Constants {
/* }==================================================================== */ /* }==================================================================== */
/* /*
** {====================================================================== ** {======================================================================
** Rules for Statements ** Rules for Statements
** ======================================================================= ** =======================================================================
*/ */
boolean block_follow(boolean withuntil) { boolean block_follow(boolean withuntil) {
switch (t.token) { 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_EOF:
return true; return true;
case TK_UNTIL: case TK_UNTIL:
return withuntil; return withuntil;
@@ -1620,7 +1572,6 @@ public class LexState extends Constants {
} }
} }
void block() { void block() {
/* block -> chunk */ /* block -> chunk */
FuncState fs = this.fs; FuncState fs = this.fs;
@@ -1630,7 +1581,6 @@ public class LexState extends Constants {
fs.leaveblock(); fs.leaveblock();
} }
/* /*
** structure to chain all variables in the left-hand side of an ** structure to chain all variables in the left-hand side of an
** assignment ** assignment
@@ -1639,8 +1589,7 @@ public class LexState extends Constants {
LHS_assign prev; LHS_assign prev;
/* variable (global, local, upvalue, or indexed) */ /* variable (global, local, upvalue, or indexed) */
expdesc v = new expdesc(); expdesc v = new expdesc();
}; }
/* /*
** check whether, in an assignment to a local variable, the local variable ** check whether, in an assignment to a local variable, the local variable
@@ -1650,7 +1599,7 @@ public class LexState extends Constants {
*/ */
void check_conflict(LHS_assign lh, expdesc v) { void check_conflict(LHS_assign lh, expdesc v) {
FuncState fs = this.fs; FuncState fs = this.fs;
short extra = (short) fs.freereg; /* eventual position to save local variable */ short extra = fs.freereg; /* eventual position to save local variable */
boolean conflict = false; boolean conflict = false;
for (; lh != null; lh = lh.prev) { for (; lh != null; lh = lh.prev) {
if (lh.v.k == VINDEXED) { if (lh.v.k == VINDEXED) {
@@ -1669,17 +1618,15 @@ public class LexState extends Constants {
} }
if (conflict) { if (conflict) {
/* copy upvalue/local value to a temporary (in position 'extra') */ /* copy upvalue/local value to a temporary (in position 'extra') */
int op = (v.k == VLOCAL) ? Lua.OP_MOVE : Lua.OP_GETUPVAL; int op = v.k == VLOCAL? Lua.OP_MOVE: Lua.OP_GETUPVAL;
fs.codeABC(op, extra, v.u.info, 0); fs.codeABC(op, extra, v.u.info, 0);
fs.reserveregs(1); fs.reserveregs(1);
} }
} }
void assignment(LHS_assign lh, int nvars) { void assignment(LHS_assign lh, int nvars) {
expdesc e = new expdesc(); expdesc e = new expdesc();
this.check_condition(VLOCAL <= lh.v.k && lh.v.k <= VINDEXED, this.check_condition(VLOCAL <= lh.v.k && lh.v.k <= VINDEXED, "syntax error");
"syntax error");
if (this.testnext(',')) { /* assignment -> `,' primaryexp assignment */ if (this.testnext(',')) { /* assignment -> `,' primaryexp assignment */
LHS_assign nv = new LHS_assign(); LHS_assign nv = new LHS_assign();
nv.prev = lh; nv.prev = lh;
@@ -1687,8 +1634,7 @@ public class LexState extends Constants {
if (nv.v.k != VINDEXED) if (nv.v.k != VINDEXED)
this.check_conflict(lh, nv.v); this.check_conflict(lh, nv.v);
this.assignment(nv, nvars+1); this.assignment(nv, nvars+1);
} } else { /* assignment . `=' explist1 */
else { /* assignment . `=' explist1 */
int nexps; int nexps;
this.checknext('='); this.checknext('=');
nexps = this.explist(e); nexps = this.explist(e);
@@ -1696,8 +1642,7 @@ public class LexState extends Constants {
this.adjust_assign(nvars, nexps, e); this.adjust_assign(nvars, nexps, e);
if (nexps > nvars) if (nexps > nvars)
this.fs.freereg -= nexps-nvars; /* remove extra values */ this.fs.freereg -= nexps-nvars; /* remove extra values */
} } else {
else {
fs.setoneret(e); /* close last expression */ fs.setoneret(e); /* close last expression */
fs.storevar(lh.v, e); fs.storevar(lh.v, e);
return; /* avoid default */ return; /* avoid default */
@@ -1707,7 +1652,6 @@ public class LexState extends Constants {
fs.storevar(lh.v, e); fs.storevar(lh.v, e);
} }
int cond() { int cond() {
/* cond -> exp */ /* cond -> exp */
expdesc v = new expdesc(); expdesc v = new expdesc();
@@ -1734,14 +1678,12 @@ public class LexState extends Constants {
findlabel(g); /* close it if label already defined */ findlabel(g); /* close it if label already defined */
} }
/* skip no-op statements */ /* skip no-op statements */
void skipnoopstat() { void skipnoopstat() {
while ( t.token == ';' || t.token == TK_DBCOLON ) while ( t.token == ';' || t.token == TK_DBCOLON )
statement(); statement();
} }
void labelstat(LuaString label, int line) { void labelstat(LuaString label, int line) {
/* label -> '::' NAME '::' */ /* label -> '::' NAME '::' */
int l; /* index of new label being created */ int l; /* index of new label being created */
@@ -1757,7 +1699,6 @@ public class LexState extends Constants {
findgotos(dyd.label[l]); findgotos(dyd.label[l]);
} }
void whilestat(int line) { void whilestat(int line) {
/* whilestat -> WHILE cond DO block END */ /* whilestat -> WHILE cond DO block END */
FuncState fs = this.fs; FuncState fs = this.fs;
@@ -1797,7 +1738,6 @@ public class LexState extends Constants {
fs.leaveblock(); /* finish loop */ fs.leaveblock(); /* finish loop */
} }
int exp1() { int exp1() {
expdesc e = new expdesc(); expdesc e = new expdesc();
int k; int k;
@@ -1807,7 +1747,6 @@ public class LexState extends Constants {
return k; return k;
} }
void forbody(int base, int line, int nvars, boolean isnum) { void forbody(int base, int line, int nvars, boolean isnum) {
/* forbody -> DO block */ /* forbody -> DO block */
BlockCnt bl = new BlockCnt(); BlockCnt bl = new BlockCnt();
@@ -1833,7 +1772,6 @@ public class LexState extends Constants {
fs.fixline(line); fs.fixline(line);
} }
void fornum(LuaString varname, int line) { void fornum(LuaString varname, int line) {
/* fornum -> NAME = exp1,exp1[,exp1] forbody */ /* fornum -> NAME = exp1,exp1[,exp1] forbody */
FuncState fs = this.fs; FuncState fs = this.fs;
@@ -1855,7 +1793,6 @@ public class LexState extends Constants {
this.forbody(base, line, 1, true); this.forbody(base, line, 1, true);
} }
void forlist(LuaString indexname) { void forlist(LuaString indexname) {
/* forlist -> NAME {,NAME} IN explist1 forbody */ /* forlist -> NAME {,NAME} IN explist1 forbody */
FuncState fs = this.fs; FuncState fs = this.fs;
@@ -1880,7 +1817,6 @@ public class LexState extends Constants {
this.forbody(base, line, nvars-3, false); this.forbody(base, line, nvars-3, false);
} }
void forstat(int line) { void forstat(int line) {
/* forstat -> FOR (fornum | forlist) END */ /* forstat -> FOR (fornum | forlist) END */
FuncState fs = this.fs; FuncState fs = this.fs;
@@ -1904,7 +1840,6 @@ public class LexState extends Constants {
fs.leaveblock(); /* loop scope (`break' jumps to this point) */ fs.leaveblock(); /* loop scope (`break' jumps to this point) */
} }
void test_then_block(IntPtr escapelist) { void test_then_block(IntPtr escapelist) {
/* test_then_block -> [IF | ELSEIF] cond THEN block */ /* test_then_block -> [IF | ELSEIF] cond THEN block */
expdesc v = new expdesc(); expdesc v = new expdesc();
@@ -1936,7 +1871,6 @@ public class LexState extends Constants {
fs.patchtohere(jf); fs.patchtohere(jf);
} }
void ifstat(int line) { void ifstat(int line) {
IntPtr escapelist = new IntPtr(NO_JUMP); /* exit list for finished parts */ IntPtr escapelist = new IntPtr(NO_JUMP); /* exit list for finished parts */
test_then_block(escapelist); /* IF cond THEN block */ test_then_block(escapelist); /* IF cond THEN block */
@@ -1958,7 +1892,6 @@ public class LexState extends Constants {
fs.getlocvar(fs.nactvar-1).startpc = fs.pc; fs.getlocvar(fs.nactvar-1).startpc = fs.pc;
} }
void localstat() { void localstat() {
/* stat -> LOCAL NAME {`,' NAME} [`=' explist1] */ /* stat -> LOCAL NAME {`,' NAME} [`=' explist1] */
int nvars = 0; int nvars = 0;
@@ -1978,7 +1911,6 @@ public class LexState extends Constants {
this.adjustlocalvars(nvars); this.adjustlocalvars(nvars);
} }
boolean funcname(expdesc v) { boolean funcname(expdesc v) {
/* funcname -> NAME {field} [`:' NAME] */ /* funcname -> NAME {field} [`:' NAME] */
boolean ismethod = false; boolean ismethod = false;
@@ -1992,7 +1924,6 @@ public class LexState extends Constants {
return ismethod; return ismethod;
} }
void funcstat(int line) { void funcstat(int line) {
/* funcstat -> FUNCTION funcname body */ /* funcstat -> FUNCTION funcname body */
boolean needself; boolean needself;
@@ -2005,7 +1936,6 @@ public class LexState extends Constants {
fs.fixline(line); /* definition `happens' in the first line */ fs.fixline(line); /* definition `happens' in the first line */
} }
void exprstat() { void exprstat() {
/* stat -> func | assignment */ /* stat -> func | assignment */
FuncState fs = this.fs; FuncState fs = this.fs;
@@ -2014,8 +1944,7 @@ public class LexState extends Constants {
if (t.token == '=' || t.token == ',') { /* stat -> assignment ? */ if (t.token == '=' || t.token == ',') { /* stat -> assignment ? */
v.prev = null; v.prev = null;
assignment(v, 1); assignment(v, 1);
} } else { /* stat -> func */
else { /* stat -> func */
check_condition(v.v.k == VCALL, "syntax error"); check_condition(v.v.k == VCALL, "syntax error");
SETARG_C(fs.getcodePtr(v.v), 1); /* call statement uses no results */ SETARG_C(fs.getcodePtr(v.v), 1); /* call statement uses no results */
} }
@@ -2114,8 +2043,7 @@ public class LexState extends Constants {
break; break;
} }
} }
_assert(fs.f.maxstacksize >= fs.freereg _assert(fs.f.maxstacksize >= fs.freereg && fs.freereg >= fs.nactvar);
&& fs.freereg >= fs.nactvar);
fs.freereg = fs.nactvar; /* free registers */ fs.freereg = fs.nactvar; /* free registers */
leavelevel(); leavelevel();
} }
@@ -2144,7 +2072,7 @@ public class LexState extends Constants {
fs.newupvalue(envn, v); /* ...set environment upvalue */ fs.newupvalue(envn, v); /* ...set environment upvalue */
next(); /* read first token */ next(); /* read first token */
statlist(); /* parse main body */ statlist(); /* parse main body */
check(TK_EOS); check(TK_EOF);
close_func(); close_func();
} }

View File

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

View File

@@ -34,14 +34,14 @@ import org.luaj.vm2.LuaValue;
import org.luaj.vm2.Varargs; 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> * <p>
* This contains all library functions listed as "basic functions" in the lua documentation for JME. * This contains all library functions listed as "basic functions" in the lua
* The functions dofile and loadfile use the * documentation for JME. The functions dofile and loadfile use the
* {@link Globals#finder} instance to find resource files. * {@link Globals#finder} instance to find resource files. Since JME has no file
* Since JME has no file system by default, {@link BaseLib} implements * system by default, {@link BaseLib} implements {@link ResourceFinder} using
* {@link ResourceFinder} using {@link Class#getResource(String)}, * {@link Class#getResource(String)}, which is the closest equivalent on JME.
* which is the closest equivalent on JME.
* The default loader chain in {@link PackageLib} will use these as well. * The default loader chain in {@link PackageLib} will use these as well.
* <p> * <p>
* To use basic library functions that include a {@link ResourceFinder} based on * To use basic library functions that include a {@link ResourceFinder} based on
@@ -50,41 +50,55 @@ import org.luaj.vm2.Varargs;
* Typically, this library is included as part of a call to either * 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.jse.JsePlatform#standardGlobals()} or
* {@link org.luaj.vm2.lib.jme.JmePlatform#standardGlobals()} * {@link org.luaj.vm2.lib.jme.JmePlatform#standardGlobals()}
* <pre> {@code *
* <pre>
* {
* &#64;code
* Globals globals = JsePlatform.standardGlobals(); * Globals globals = JsePlatform.standardGlobals();
* globals.get("print").call(LuaValue.valueOf("hello, world")); * globals.get("print").call(LuaValue.valueOf("hello, world"));
* } </pre> * }
* </pre>
* <p> * <p>
* For special cases where the smallest possible footprint is desired, * For special cases where the smallest possible footprint is desired, a minimal
* a minimal set of libraries could be loaded * set of libraries could be loaded directly via {@link Globals#load(LuaValue)}
* directly via {@link Globals#load(LuaValue)} using code such as: * using code such as:
* <pre> {@code *
* <pre>
* {
* &#64;code
* Globals globals = new Globals(); * Globals globals = new Globals();
* globals.load(new JseBaseLib()); * globals.load(new JseBaseLib());
* globals.get("print").call(LuaValue.valueOf("hello, world")); * globals.get("print").call(LuaValue.valueOf("hello, world"));
* } </pre> * }
* Doing so will ensure the library is properly initialized * </pre>
* and loaded into the globals table. *
* Doing so will ensure the library is properly initialized and loaded into the
* globals table.
* <p> * <p>
* This is a direct port of the corresponding library in C. * This is a direct port of the corresponding library in C.
*
* @see org.luaj.vm2.lib.jse.JseBaseLib * @see org.luaj.vm2.lib.jse.JseBaseLib
* @see ResourceFinder * @see ResourceFinder
* @see Globals#finder * @see Globals#finder
* @see LibFunction * @see LibFunction
* @see org.luaj.vm2.lib.jse.JsePlatform * @see org.luaj.vm2.lib.jse.JsePlatform
* @see org.luaj.vm2.lib.jme.JmePlatform * @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 { public class BaseLib extends TwoArgFunction implements ResourceFinder {
Globals globals; 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. * to the supplied environment, and returning it as the return value.
*
* @param modname the module name supplied if this is loaded via 'require'. * @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.
*/ */
@Override
public LuaValue call(LuaValue modname, LuaValue env) { public LuaValue call(LuaValue modname, LuaValue env) {
globals = env.checkglobals(); globals = env.checkglobals();
globals.finder = this; globals.finder = this;
@@ -113,8 +127,8 @@ public class BaseLib extends TwoArgFunction implements ResourceFinder {
next next; next next;
env.set("next", next = new next()); env.set("next", next = new next());
env.set("pairs", new pairs(next)); env.set("pairs", new pairsbase(PAIRS, NIL, next));
env.set("ipairs", new ipairs()); env.set("ipairs", new pairsbase(IPAIRS, ZERO, new inext()));
return env; return env;
} }
@@ -206,6 +220,7 @@ public class BaseLib extends TwoArgFunction implements ResourceFinder {
// "loadfile", // ( [filename [, mode [, env]]] ) -> chunk | nil, msg // "loadfile", // ( [filename [, mode [, env]]] ) -> chunk | nil, msg
final class loadfile extends VarArgFunction { final class loadfile extends VarArgFunction {
@Override
public Varargs invoke(Varargs args) { public Varargs invoke(Varargs args) {
args.argcheck(args.isstring(1) || args.isnil(1), 1, "filename must be string or nil"); args.argcheck(args.isstring(1) || args.isnil(1), 1, "filename must be string or nil");
String filename = args.isstring(1)? args.tojstring(1): null; String filename = args.isstring(1)? args.tojstring(1): null;
@@ -219,6 +234,7 @@ public class BaseLib extends TwoArgFunction implements ResourceFinder {
// "pcall", // (f, arg1, ...) -> status, result1, ... // "pcall", // (f, arg1, ...) -> status, result1, ...
final class pcall extends VarArgFunction { final class pcall extends VarArgFunction {
@Override
public Varargs invoke(Varargs args) { public Varargs invoke(Varargs args) {
LuaValue func = args.checkvalue(1); LuaValue func = args.checkvalue(1);
if (globals != null && globals.debuglib != null) if (globals != null && globals.debuglib != null)
@@ -244,6 +260,8 @@ public class BaseLib extends TwoArgFunction implements ResourceFinder {
print(BaseLib baselib) { print(BaseLib baselib) {
this.baselib = baselib; this.baselib = baselib;
} }
@Override
public Varargs invoke(Varargs args) { public Varargs invoke(Varargs args) {
LuaValue tostring = globals.get("tostring"); LuaValue tostring = globals.get("tostring");
for ( int i=1, n=args.narg(); i<=n; i++ ) { for ( int i=1, n=args.narg(); i<=n; i++ ) {
@@ -256,7 +274,6 @@ public class BaseLib extends TwoArgFunction implements ResourceFinder {
} }
} }
// "rawequal", // (v1, v2) -> boolean // "rawequal", // (v1, v2) -> boolean
static final class rawequal extends LibFunction { static final class rawequal extends LibFunction {
public LuaValue call() { public LuaValue call() {
@@ -272,6 +289,9 @@ public class BaseLib extends TwoArgFunction implements ResourceFinder {
// "rawget", // (table, index) -> value // "rawget", // (table, index) -> value
static final class rawget extends TableLibFunction { static final class rawget extends TableLibFunction {
public LuaValue call() {
return argerror(1, "value expected");
}
public LuaValue call(LuaValue arg) { public LuaValue call(LuaValue arg) {
return argerror(2, "value expected"); return argerror(2, "value expected");
} }
@@ -349,8 +369,11 @@ public class BaseLib extends TwoArgFunction implements ResourceFinder {
static final class tostring extends LibFunction { static final class tostring extends LibFunction {
public LuaValue call(LuaValue arg) { public LuaValue call(LuaValue arg) {
LuaValue h = arg.metatag(TOSTRING); LuaValue h = arg.metatag(TOSTRING);
if ( ! h.isnil() ) if ( ! h.isnil() ) {
return h.call(arg); LuaValue v = h.call(arg);
LuaValue vs = v.tostring();
return !vs.isnil() ? vs : v;
}
LuaValue v = arg.tostring(); LuaValue v = arg.tostring();
if ( ! v.isnil() ) if ( ! v.isnil() )
return v; return v;
@@ -360,6 +383,7 @@ public class BaseLib extends TwoArgFunction implements ResourceFinder {
// "type", // (v) -> value // "type", // (v) -> value
static final class type extends LibFunction { static final class type extends LibFunction {
@Override
public LuaValue call(LuaValue arg) { public LuaValue call(LuaValue arg) {
return valueOf(arg.typename()); return valueOf(arg.typename());
} }
@@ -367,6 +391,7 @@ public class BaseLib extends TwoArgFunction implements ResourceFinder {
// "xpcall", // (f, err) -> result1, ... // "xpcall", // (f, err) -> result1, ...
final class xpcall extends VarArgFunction { final class xpcall extends VarArgFunction {
@Override
public Varargs invoke(Varargs args) { public Varargs invoke(Varargs args) {
final LuaThread t = globals.running; final LuaThread t = globals.running;
final LuaValue preverror = t.errorfunc; final LuaValue preverror = t.errorfunc;
@@ -392,22 +417,25 @@ public class BaseLib extends TwoArgFunction implements ResourceFinder {
} }
} }
// "pairs" (t) -> iter-func, t, nil // pairsbase, // (t) -> iter-func, t, initial
static final class pairs extends VarArgFunction { static final class pairsbase extends VarArgFunction {
final next next; final LuaString method;
pairs(next next) { final LuaValue initial;
this.next = next; final VarArgFunction iter;
}
public Varargs invoke(Varargs args) { pairsbase(LuaString method, LuaValue initial, VarArgFunction iter) {
return varargsOf( next, args.checktable(1), NIL ); this.method = method;
} this.initial = initial;
this.iter = iter;
} }
// // "ipairs", // (t) -> iter-func, t, 0
static final class ipairs extends VarArgFunction {
inext inext = new inext();
public Varargs invoke(Varargs args) { public Varargs invoke(Varargs args) {
return varargsOf( inext, args.checktable(1), ZERO ); LuaValue arg = args.arg1();
LuaValue t = arg.metatag(method);
if (!t.isnil())
// TODO: This can return more than 3 results.
return t.invoke(args.isvalue(1) ? arg : t);
return varargsOf(iter, args.checktable(1), initial);
} }
} }
@@ -420,6 +448,7 @@ public class BaseLib extends TwoArgFunction implements ResourceFinder {
// "inext" ( table, [int-index] ) -> next-index, next-value // "inext" ( table, [int-index] ) -> next-index, next-value
static final class inext extends VarArgFunction { static final class inext extends VarArgFunction {
@Override
public Varargs invoke(Varargs args) { public Varargs invoke(Varargs args) {
return args.checktable(1).inext(args.arg(2)); return args.checktable(1).inext(args.arg(2));
} }
@@ -456,7 +485,6 @@ public class BaseLib extends TwoArgFunction implements ResourceFinder {
} }
} }
private static class StringInputStream extends InputStream { private static class StringInputStream extends InputStream {
final LuaValue func; final LuaValue func;
byte[] bytes; byte[] bytes;

View File

@@ -26,68 +26,88 @@ import org.luaj.vm2.LuaValue;
import org.luaj.vm2.Varargs; 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> * <p>
* Typically, this library is included as part of a call to either * 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()} * {@link org.luaj.vm2.lib.jse.JsePlatform#standardGlobals()} or
* <pre> {@code * {@link org.luaj.vm2.lib.jme.JmePlatform#standardGlobals()}
*
* <pre>
* {
* &#64;code
* Globals globals = JsePlatform.standardGlobals(); * Globals globals = JsePlatform.standardGlobals();
* System.out.println(globals.get("bit32").get("bnot").call(LuaValue.valueOf(2))); * System.out.println(globals.get("bit32").get("bnot").call(LuaValue.valueOf(2)));
* } </pre> * }
* </pre>
* <p> * <p>
* To instantiate and use it directly, * To instantiate and use it directly, link it into your globals table via
* link it into your globals table via {@link LuaValue#load(LuaValue)} using code such as: * {@link LuaValue#load(LuaValue)} using code such as:
* <pre> {@code *
* <pre>
* {
* &#64;code
* Globals globals = new Globals(); * Globals globals = new Globals();
* globals.load(new JseBaseLib()); * globals.load(new JseBaseLib());
* globals.load(new PackageLib()); * globals.load(new PackageLib());
* globals.load(new Bit32Lib()); * globals.load(new Bit32Lib());
* System.out.println(globals.get("bit32").get("bnot").call(LuaValue.valueOf(2))); * System.out.println(globals.get("bit32").get("bnot").call(LuaValue.valueOf(2)));
* } </pre> * }
* </pre>
* <p> * <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 LibFunction
* @see org.luaj.vm2.lib.jse.JsePlatform * @see org.luaj.vm2.lib.jse.JsePlatform
* @see org.luaj.vm2.lib.jme.JmePlatform * @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 class Bit32Lib extends TwoArgFunction {
public Bit32Lib() { public Bit32Lib() {
} }
/** Perform one-time initialization on the library by creating a table /**
* containing the library functions, adding that table to the supplied environment, * Perform one-time initialization on the library by creating a table
* adding the table to package.loaded, and returning table as the return value. * 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 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.
*/ */
@Override
public LuaValue call(LuaValue modname, LuaValue env) { public LuaValue call(LuaValue modname, LuaValue env) {
LuaTable t = new LuaTable(); LuaTable t = new LuaTable();
bind(t, Bit32LibV.class, new String[] { bind(t, Bit32LibV.class, new String[] { "band", "bnot", "bor", "btest", "bxor", "extract", "replace" });
"band", "bnot", "bor", "btest", "bxor", "extract", "replace" bind(t, Bit32Lib2.class, new String[] { "arshift", "lrotate", "lshift", "rrotate", "rshift" });
});
bind(t, Bit32Lib2.class, new String[] {
"arshift", "lrotate", "lshift", "rrotate", "rshift"
});
env.set("bit32", t); 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; return t;
} }
static final class Bit32LibV extends VarArgFunction { static final class Bit32LibV extends VarArgFunction {
@Override
public Varargs invoke(Varargs args) { public Varargs invoke(Varargs args) {
switch (opcode) { switch (opcode) {
case 0: return Bit32Lib.band( args ); case 0:
case 1: return Bit32Lib.bnot( args ); return Bit32Lib.band(args);
case 2: return Bit32Lib.bor( args ); case 1:
case 3: return Bit32Lib.btest( args ); return Bit32Lib.bnot(args);
case 4: return Bit32Lib.bxor( args ); case 2:
return Bit32Lib.bor(args);
case 3:
return Bit32Lib.btest(args);
case 4:
return Bit32Lib.bxor(args);
case 5: case 5:
return Bit32Lib.extract(args.checkint(1), args.checkint(2), args.optint(3, 1)); return Bit32Lib.extract(args.checkint(1), args.checkint(2), args.optint(3, 1));
case 6: case 6:
return Bit32Lib.replace( args.checkint(1), args.checkint(2), return Bit32Lib.replace(args.checkint(1), args.checkint(2), args.checkint(3), args.optint(4, 1));
args.checkint(3), args.optint(4, 1) );
} }
return NIL; return NIL;
} }
@@ -95,13 +115,19 @@ public class Bit32Lib extends TwoArgFunction {
static final class Bit32Lib2 extends TwoArgFunction { static final class Bit32Lib2 extends TwoArgFunction {
@Override
public LuaValue call(LuaValue arg1, LuaValue arg2) { public LuaValue call(LuaValue arg1, LuaValue arg2) {
switch (opcode) { switch (opcode) {
case 0: return Bit32Lib.arshift(arg1.checkint(), arg2.checkint()); case 0:
case 1: return Bit32Lib.lrotate(arg1.checkint(), arg2.checkint()); return Bit32Lib.arshift(arg1.checkint(), arg2.checkint());
case 2: return Bit32Lib.lshift(arg1.checkint(), arg2.checkint()); case 1:
case 3: return Bit32Lib.rrotate(arg1.checkint(), arg2.checkint()); return Bit32Lib.lrotate(arg1.checkint(), arg2.checkint());
case 4: return Bit32Lib.rshift(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; return NIL;
} }
@@ -177,7 +203,7 @@ public class Bit32Lib extends TwoArgFunction {
return rrotate(x, -disp); return rrotate(x, -disp);
} else { } else {
disp = disp & 31; disp = disp & 31;
return bitsToValue((x << disp) | (x >>> (32 - disp))); return bitsToValue(x<<disp | x>>>32-disp);
} }
} }
@@ -186,7 +212,7 @@ public class Bit32Lib extends TwoArgFunction {
return lrotate(x, -disp); return lrotate(x, -disp);
} else { } else {
disp = disp & 31; disp = disp & 31;
return bitsToValue((x >>> disp) | (x << (32 - disp))); return bitsToValue(x>>>disp | x<<32-disp);
} }
} }
@@ -200,7 +226,7 @@ public class Bit32Lib extends TwoArgFunction {
if (field+width > 32) { if (field+width > 32) {
error("trying to access non-existent bits"); error("trying to access non-existent bits");
} }
return bitsToValue((n >>> field) & (-1 >>> (32 - width))); return bitsToValue(n>>>field & -1>>>32-width);
} }
static LuaValue replace(int n, int v, int field, int width) { static LuaValue replace(int n, int v, int field, int width) {
@@ -213,12 +239,12 @@ public class Bit32Lib extends TwoArgFunction {
if (field+width > 32) { if (field+width > 32) {
error("trying to access non-existent bits"); error("trying to access non-existent bits");
} }
int mask = (-1 >>> (32 - width)) << field; int mask = -1>>>32-width<<field;
n = (n & ~mask) | ((v << field) & mask); n = n & ~mask | v<<field & mask;
return bitsToValue(n); return bitsToValue(n);
} }
private static LuaValue bitsToValue(int x) { private static LuaValue bitsToValue(int x) {
return ( x < 0 ) ? valueOf((double) ((long) x & 0xFFFFFFFFL)) : valueOf(x); return x < 0? valueOf(x & 0xFFFFFFFFL): valueOf(x);
} }
} }

View File

@@ -28,37 +28,48 @@ import org.luaj.vm2.LuaValue;
import org.luaj.vm2.Varargs; import org.luaj.vm2.Varargs;
/** /**
* Subclass of {@link LibFunction} which implements the lua standard {@code coroutine} * Subclass of {@link LibFunction} which implements the lua standard
* library. * {@code coroutine} library.
* <p> * <p>
* The coroutine library in luaj has the same behavior as the * The coroutine library in luaj has the same behavior as the coroutine library
* coroutine library in C, but is implemented using Java Threads to maintain * in C, but is implemented using Java Threads to maintain the call state
* the call state between invocations. Therefore it can be yielded from anywhere, * between invocations. Therefore it can be yielded from anywhere, similar to
* similar to the "Coco" yield-from-anywhere patch available for C-based lua. * the "Coco" yield-from-anywhere patch available for C-based lua. However,
* However, coroutines that are yielded but never resumed to complete their execution * coroutines that are yielded but never resumed to complete their execution may
* may not be collected by the garbage collector. * not be collected by the garbage collector.
* <p> * <p>
* Typically, this library is included as part of a call to either * 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()} * {@link org.luaj.vm2.lib.jse.JsePlatform#standardGlobals()} or
* <pre> {@code * {@link org.luaj.vm2.lib.jme.JmePlatform#standardGlobals()}
*
* <pre>
* {
* &#64;code
* Globals globals = JsePlatform.standardGlobals(); * Globals globals = JsePlatform.standardGlobals();
* System.out.println(globals.get("coroutine").get("running").call()); * System.out.println(globals.get("coroutine").get("running").call());
* } </pre> * }
* </pre>
* <p> * <p>
* To instantiate and use it directly, * To instantiate and use it directly, link it into your globals table via
* link it into your globals table via {@link LuaValue#load(LuaValue)} using code such as: * {@link LuaValue#load(LuaValue)} using code such as:
* <pre> {@code *
* <pre>
* {
* &#64;code
* Globals globals = new Globals(); * Globals globals = new Globals();
* globals.load(new JseBaseLib()); * globals.load(new JseBaseLib());
* globals.load(new PackageLib()); * globals.load(new PackageLib());
* globals.load(new CoroutineLib()); * globals.load(new CoroutineLib());
* System.out.println(globals.get("coroutine").get("running").call()); * System.out.println(globals.get("coroutine").get("running").call());
* } </pre> * }
* </pre>
* <p> * <p>
*
* @see LibFunction * @see LibFunction
* @see org.luaj.vm2.lib.jse.JsePlatform * @see org.luaj.vm2.lib.jse.JsePlatform
* @see org.luaj.vm2.lib.jme.JmePlatform * @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 { public class CoroutineLib extends TwoArgFunction {
@@ -66,12 +77,17 @@ public class CoroutineLib extends TwoArgFunction {
Globals globals; Globals globals;
/** Perform one-time initialization on the library by creating a table /**
* containing the library functions, adding that table to the supplied environment, * Perform one-time initialization on the library by creating a table
* adding the table to package.loaded, and returning table as the return value. * 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 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.
*/ */
@Override
public LuaValue call(LuaValue modname, LuaValue env) { public LuaValue call(LuaValue modname, LuaValue env) {
globals = env.checkglobals(); globals = env.checkglobals();
LuaTable coroutine = new LuaTable(); LuaTable coroutine = new LuaTable();
@@ -82,17 +98,20 @@ public class CoroutineLib extends TwoArgFunction {
coroutine.set("yield", new yield()); coroutine.set("yield", new yield());
coroutine.set("wrap", new wrap()); coroutine.set("wrap", new wrap());
env.set("coroutine", coroutine); 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; return coroutine;
} }
final class create extends LibFunction { final class create extends LibFunction {
@Override
public LuaValue call(LuaValue f) { public LuaValue call(LuaValue f) {
return new LuaThread(globals, f.checkfunction()); return new LuaThread(globals, f.checkfunction());
} }
} }
static final class resume extends VarArgFunction { static final class resume extends VarArgFunction {
@Override
public Varargs invoke(Varargs args) { public Varargs invoke(Varargs args) {
final LuaThread t = args.checkthread(1); final LuaThread t = args.checkthread(1);
return t.resume(args.subargs(2)); return t.resume(args.subargs(2));
@@ -100,6 +119,7 @@ public class CoroutineLib extends TwoArgFunction {
} }
final class running extends VarArgFunction { final class running extends VarArgFunction {
@Override
public Varargs invoke(Varargs args) { public Varargs invoke(Varargs args) {
final LuaThread r = globals.running; final LuaThread r = globals.running;
return varargsOf(r, valueOf(r.isMainThread())); return varargsOf(r, valueOf(r.isMainThread()));
@@ -107,6 +127,7 @@ public class CoroutineLib extends TwoArgFunction {
} }
static final class status extends LibFunction { static final class status extends LibFunction {
@Override
public LuaValue call(LuaValue t) { public LuaValue call(LuaValue t) {
LuaThread lt = t.checkthread(); LuaThread lt = t.checkthread();
return valueOf(lt.getStatus()); return valueOf(lt.getStatus());
@@ -114,12 +135,14 @@ public class CoroutineLib extends TwoArgFunction {
} }
final class yield extends VarArgFunction { final class yield extends VarArgFunction {
@Override
public Varargs invoke(Varargs args) { public Varargs invoke(Varargs args) {
return globals.yield(args); return globals.yield(args);
} }
} }
final class wrap extends LibFunction { final class wrap extends LibFunction {
@Override
public LuaValue call(LuaValue f) { public LuaValue call(LuaValue f) {
final LuaValue func = f.checkfunction(); final LuaValue func = f.checkfunction();
final LuaThread thread = new LuaThread(globals, func); final LuaThread thread = new LuaThread(globals, func);
@@ -129,9 +152,12 @@ public class CoroutineLib extends TwoArgFunction {
static final class wrapper extends VarArgFunction { static final class wrapper extends VarArgFunction {
final LuaThread luathread; final LuaThread luathread;
wrapper(LuaThread luathread) { wrapper(LuaThread luathread) {
this.luathread = luathread; this.luathread = luathread;
} }
@Override
public Varargs invoke(Varargs args) { public Varargs invoke(Varargs args) {
final Varargs result = luathread.resume(args); final Varargs result = luathread.resume(args);
if (result.arg1().toboolean()) { if (result.arg1().toboolean()) {

View File

@@ -39,49 +39,64 @@ import org.luaj.vm2.Prototype;
import org.luaj.vm2.Varargs; import org.luaj.vm2.Varargs;
/** /**
* Subclass of {@link LibFunction} which implements the lua standard {@code debug} * Subclass of {@link LibFunction} which implements the lua standard
* library. * {@code debug} library.
* <p> * <p>
* The debug library in luaj tries to emulate the behavior of the corresponding C-based lua library. * The debug library in luaj tries to emulate the behavior of the corresponding
* To do this, it must maintain a separate stack of calls to {@link LuaClosure} and {@link LibFunction} * C-based lua library. To do this, it must maintain a separate stack of calls
* instances. * to {@link LuaClosure} and {@link LibFunction} instances. Especially when
* Especially when lua-to-java bytecode compiling is being used * lua-to-java bytecode compiling is being used via a
* via a {@link org.luaj.vm2.Globals.Compiler} such as {@link org.luaj.vm2.luajc.LuaJC}, * {@link org.luaj.vm2.Globals.Compiler} such as
* this cannot be done in all cases. * {@link org.luaj.vm2.luajc.LuaJC}, this cannot be done in all cases.
* <p> * <p>
* Typically, this library is included as part of a call to either * 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.jse.JsePlatform#debugGlobals()} or
* {@link org.luaj.vm2.lib.jme.JmePlatform#debugGlobals()} * {@link org.luaj.vm2.lib.jme.JmePlatform#debugGlobals()}
* <pre> {@code *
* <pre>
* {
* &#64;code
* Globals globals = JsePlatform.debugGlobals(); * Globals globals = JsePlatform.debugGlobals();
* System.out.println(globals.get("debug").get("traceback").call()); * System.out.println(globals.get("debug").get("traceback").call());
* } </pre> * }
* </pre>
* <p> * <p>
* To instantiate and use it directly, * To instantiate and use it directly, link it into your globals table via
* link it into your globals table via {@link LuaValue#load(LuaValue)} using code such as: * {@link LuaValue#load(LuaValue)} using code such as:
* <pre> {@code *
* <pre>
* {
* &#64;code
* Globals globals = new Globals(); * Globals globals = new Globals();
* globals.load(new JseBaseLib()); * globals.load(new JseBaseLib());
* globals.load(new PackageLib()); * globals.load(new PackageLib());
* globals.load(new DebugLib()); * globals.load(new DebugLib());
* System.out.println(globals.get("debug").get("traceback").call()); * System.out.println(globals.get("debug").get("traceback").call());
* } </pre> * }
* </pre>
* <p> * <p>
* This library exposes the entire state of lua code, and provides method to see and modify * This library exposes the entire state of lua code, and provides method to see
* all underlying lua values within a Java VM so should not be exposed to client code * and modify all underlying lua values within a Java VM so should not be
* in a shared server environment. * exposed to client code in a shared server environment.
* *
* @see LibFunction * @see LibFunction
* @see org.luaj.vm2.lib.jse.JsePlatform * @see org.luaj.vm2.lib.jse.JsePlatform
* @see org.luaj.vm2.lib.jme.JmePlatform * @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 class DebugLib extends TwoArgFunction {
public static boolean CALLS; public static boolean CALLS;
public static boolean TRACE; public static boolean TRACE;
static { static {
try { CALLS = (null != System.getProperty("CALLS")); } catch (Exception e) {} try {
try { TRACE = (null != System.getProperty("TRACE")); } catch (Exception e) {} CALLS = null != System.getProperty("CALLS");
} catch (Exception e) {
}
try {
TRACE = null != System.getProperty("TRACE");
} catch (Exception e) {
}
} }
static final LuaString LUA = valueOf("Lua"); static final LuaString LUA = valueOf("Lua");
@@ -108,12 +123,17 @@ public class DebugLib extends TwoArgFunction {
Globals globals; Globals globals;
/** Perform one-time initialization on the library by creating a table /**
* containing the library functions, adding that table to the supplied environment, * Perform one-time initialization on the library by creating a table
* adding the table to package.loaded, and returning table as the return value. * 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 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.
*/ */
@Override
public LuaValue call(LuaValue modname, LuaValue env) { public LuaValue call(LuaValue modname, LuaValue env) {
globals = env.checkglobals(); globals = env.checkglobals();
globals.debuglib = this; globals.debuglib = this;
@@ -135,12 +155,14 @@ public class DebugLib extends TwoArgFunction {
debug.set("upvalueid", new upvalueid()); debug.set("upvalueid", new upvalueid());
debug.set("upvaluejoin", new upvaluejoin()); debug.set("upvaluejoin", new upvaluejoin());
env.set("debug", debug); 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; return debug;
} }
// debug.debug() // debug.debug()
static final class debug extends ZeroArgFunction { static final class debug extends ZeroArgFunction {
@Override
public LuaValue call() { public LuaValue call() {
return NONE; return NONE;
} }
@@ -148,18 +170,18 @@ public class DebugLib extends TwoArgFunction {
// debug.gethook ([thread]) // debug.gethook ([thread])
final class gethook extends VarArgFunction { final class gethook extends VarArgFunction {
@Override
public Varargs invoke(Varargs args) { public Varargs invoke(Varargs args) {
LuaThread t = args.narg() > 0? args.checkthread(1): globals.running; LuaThread t = args.narg() > 0? args.checkthread(1): globals.running;
LuaThread.State s = t.state; LuaThread.State s = t.state;
return varargsOf( return varargsOf(s.hookfunc != null? s.hookfunc: NIL,
s.hookfunc != null? s.hookfunc: NIL, valueOf((s.hookcall? "c": "")+(s.hookline? "l": "")+(s.hookrtrn? "r": "")), valueOf(s.hookcount));
valueOf((s.hookcall?"c":"")+(s.hookline?"l":"")+(s.hookrtrn?"r":"")),
valueOf(s.hookcount));
} }
} }
// debug.getinfo ([thread,] f [, what]) // debug.getinfo ([thread,] f [, what])
final class getinfo extends VarArgFunction { final class getinfo extends VarArgFunction {
@Override
public Varargs invoke(Varargs args) { public Varargs invoke(Varargs args) {
int a = 1; int a = 1;
LuaThread thread = args.isthread(a)? args.checkthread(a++): globals.running; LuaThread thread = args.isthread(a)? args.checkthread(a++): globals.running;
@@ -223,18 +245,27 @@ public class DebugLib extends TwoArgFunction {
// debug.getlocal ([thread,] f, local) // debug.getlocal ([thread,] f, local)
final class getlocal extends VarArgFunction { final class getlocal extends VarArgFunction {
@Override
public Varargs invoke(Varargs args) { public Varargs invoke(Varargs args) {
int a = 1; int a = 1;
LuaThread thread = args.isthread(a)? args.checkthread(a++): globals.running; LuaThread thread = args.isthread(a)? args.checkthread(a++): globals.running;
int level = args.checkint(a++); LuaValue func = args.arg(a++);
int local = args.checkint(a++); int local = args.checkint(a);
CallFrame f = callstack(thread).getCallFrame(level);
return f != null? f.getLocal(local): NONE; if (func.isfunction())
return func.checkclosure().p.getlocalname(local, 0);
// find the stack info
DebugLib.CallFrame frame = callstack(thread).getCallFrame(func.checkint());
if (frame == null)
return argerror(a, "level out of range");
return frame.getLocal(local);
} }
} }
// debug.getmetatable (value) // debug.getmetatable (value)
static final class getmetatable extends LibFunction { static final class getmetatable extends LibFunction {
@Override
public LuaValue call(LuaValue v) { public LuaValue call(LuaValue v) {
LuaValue mt = v.getmetatable(); LuaValue mt = v.getmetatable();
return mt != null? mt: NIL; return mt != null? mt: NIL;
@@ -243,6 +274,7 @@ public class DebugLib extends TwoArgFunction {
// debug.getregistry () // debug.getregistry ()
final class getregistry extends ZeroArgFunction { final class getregistry extends ZeroArgFunction {
@Override
public LuaValue call() { public LuaValue call() {
return globals; return globals;
} }
@@ -250,6 +282,7 @@ public class DebugLib extends TwoArgFunction {
// debug.getupvalue (f, up) // debug.getupvalue (f, up)
static final class getupvalue extends VarArgFunction { static final class getupvalue extends VarArgFunction {
@Override
public Varargs invoke(Varargs args) { public Varargs invoke(Varargs args) {
LuaValue func = args.checkfunction(1); LuaValue func = args.checkfunction(1);
int up = args.checkint(2); int up = args.checkint(2);
@@ -266,14 +299,15 @@ public class DebugLib extends TwoArgFunction {
// debug.getuservalue (u) // debug.getuservalue (u)
static final class getuservalue extends LibFunction { static final class getuservalue extends LibFunction {
@Override
public LuaValue call(LuaValue u) { public LuaValue call(LuaValue u) {
return u.isuserdata()? u: NIL; return u.isuserdata()? u: NIL;
} }
} }
// debug.sethook ([thread,] hook, mask [, count]) // debug.sethook ([thread,] hook, mask [, count])
final class sethook extends VarArgFunction { final class sethook extends VarArgFunction {
@Override
public Varargs invoke(Varargs args) { public Varargs invoke(Varargs args) {
int a = 1; int a = 1;
LuaThread t = args.isthread(a)? args.checkthread(a++): globals.running; LuaThread t = args.isthread(a)? args.checkthread(a++): globals.running;
@@ -283,9 +317,15 @@ public class DebugLib extends TwoArgFunction {
boolean call = false, line = false, rtrn = false; boolean call = false, line = false, rtrn = false;
for (int i = 0; i < str.length(); i++) for (int i = 0; i < str.length(); i++)
switch (str.charAt(i)) { switch (str.charAt(i)) {
case 'c': call=true; break; case 'c':
case 'l': line=true; break; call = true;
case 'r': rtrn=true; break; break;
case 'l':
line = true;
break;
case 'r':
rtrn = true;
break;
} }
LuaThread.State s = t.state; LuaThread.State s = t.state;
s.hookfunc = func; s.hookfunc = func;
@@ -299,6 +339,7 @@ public class DebugLib extends TwoArgFunction {
// debug.setlocal ([thread,] level, local, value) // debug.setlocal ([thread,] level, local, value)
final class setlocal extends VarArgFunction { final class setlocal extends VarArgFunction {
@Override
public Varargs invoke(Varargs args) { public Varargs invoke(Varargs args) {
int a = 1; int a = 1;
LuaThread thread = args.isthread(a)? args.checkthread(a++): globals.running; LuaThread thread = args.isthread(a)? args.checkthread(a++): globals.running;
@@ -312,16 +353,30 @@ public class DebugLib extends TwoArgFunction {
// debug.setmetatable (value, table) // debug.setmetatable (value, table)
static final class setmetatable extends TwoArgFunction { static final class setmetatable extends TwoArgFunction {
@Override
public LuaValue call(LuaValue value, LuaValue table) { public LuaValue call(LuaValue value, LuaValue table) {
LuaValue mt = table.opttable(null); LuaValue mt = table.opttable(null);
switch (value.type()) { switch (value.type()) {
case TNIL: LuaNil.s_metatable = mt; break; case TNIL:
case TNUMBER: LuaNumber.s_metatable = mt; break; LuaNil.s_metatable = mt;
case TBOOLEAN: LuaBoolean.s_metatable = mt; break; break;
case TSTRING: LuaString.s_metatable = mt; break; case TNUMBER:
case TFUNCTION: LuaFunction.s_metatable = mt; break; LuaNumber.s_metatable = mt;
case TTHREAD: LuaThread.s_metatable = mt; break; break;
default: value.setmetatable( mt ); 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; return value;
} }
@@ -329,10 +384,11 @@ public class DebugLib extends TwoArgFunction {
// debug.setupvalue (f, up, value) // debug.setupvalue (f, up, value)
static final class setupvalue extends VarArgFunction { static final class setupvalue extends VarArgFunction {
@Override
public Varargs invoke(Varargs args) { public Varargs invoke(Varargs args) {
LuaValue func = args.checkfunction(1); LuaValue value = args.checkvalue(3);
int up = args.checkint(2); int up = args.checkint(2);
LuaValue value = args.arg(3); LuaValue func = args.checkfunction(1);
if (func instanceof LuaClosure) { if (func instanceof LuaClosure) {
LuaClosure c = (LuaClosure) func; LuaClosure c = (LuaClosure) func;
LuaString name = findupvalue(c, up); LuaString name = findupvalue(c, up);
@@ -347,6 +403,7 @@ public class DebugLib extends TwoArgFunction {
// debug.setuservalue (udata, value) // debug.setuservalue (udata, value)
static final class setuservalue extends VarArgFunction { static final class setuservalue extends VarArgFunction {
@Override
public Varargs invoke(Varargs args) { public Varargs invoke(Varargs args) {
Object o = args.checkuserdata(1); Object o = args.checkuserdata(1);
LuaValue v = args.checkvalue(2); LuaValue v = args.checkvalue(2);
@@ -359,6 +416,7 @@ public class DebugLib extends TwoArgFunction {
// debug.traceback ([thread,] [message [, level]]) // debug.traceback ([thread,] [message [, level]])
final class traceback extends VarArgFunction { final class traceback extends VarArgFunction {
@Override
public Varargs invoke(Varargs args) { public Varargs invoke(Varargs args) {
int a = 1; int a = 1;
LuaThread thread = args.isthread(a)? args.checkthread(a++): globals.running; LuaThread thread = args.isthread(a)? args.checkthread(a++): globals.running;
@@ -371,9 +429,10 @@ public class DebugLib extends TwoArgFunction {
// debug.upvalueid (f, n) // debug.upvalueid (f, n)
static final class upvalueid extends VarArgFunction { static final class upvalueid extends VarArgFunction {
@Override
public Varargs invoke(Varargs args) { public Varargs invoke(Varargs args) {
LuaValue func = args.checkfunction(1);
int up = args.checkint(2); int up = args.checkint(2);
LuaValue func = args.checkfunction(1);
if (func instanceof LuaClosure) { if (func instanceof LuaClosure) {
LuaClosure c = (LuaClosure) func; LuaClosure c = (LuaClosure) func;
if (c.upValues != null && up > 0 && up <= c.upValues.length) { if (c.upValues != null && up > 0 && up <= c.upValues.length) {
@@ -386,11 +445,12 @@ public class DebugLib extends TwoArgFunction {
// debug.upvaluejoin (f1, n1, f2, n2) // debug.upvaluejoin (f1, n1, f2, n2)
static final class upvaluejoin extends VarArgFunction { static final class upvaluejoin extends VarArgFunction {
@Override
public Varargs invoke(Varargs args) { public Varargs invoke(Varargs args) {
LuaClosure f1 = args.checkclosure(1);
int n1 = args.checkint(2); int n1 = args.checkint(2);
LuaClosure f2 = args.checkclosure(3); LuaClosure f1 = args.checkclosure(1);
int n2 = args.checkint(4); int n2 = args.checkint(4);
LuaClosure f2 = args.checkclosure(3);
if (n1 < 1 || n1 > f1.upValues.length) if (n1 < 1 || n1 > f1.upValues.length)
argerror("index out of range"); argerror("index out of range");
if (n2 < 1 || n2 > f2.upValues.length) if (n2 < 1 || n2 > f2.upValues.length)
@@ -402,23 +462,29 @@ public class DebugLib extends TwoArgFunction {
public void onCall(LuaFunction f) { public void onCall(LuaFunction f) {
LuaThread.State s = globals.running.state; LuaThread.State s = globals.running.state;
if (s.inhook) return; if (s.inhook)
return;
callstack().onCall(f); 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) { public void onCall(LuaClosure c, Varargs varargs, LuaValue[] stack) {
LuaThread.State s = globals.running.state; LuaThread.State s = globals.running.state;
if (s.inhook) return; if (s.inhook)
return;
callstack().onCall(c, varargs, stack); 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) { public void onInstruction(int pc, Varargs v, int top) {
LuaThread.State s = globals.running.state; LuaThread.State s = globals.running.state;
if (s.inhook) return; if (s.inhook)
return;
callstack().onInstruction(pc, v, top); callstack().onInstruction(pc, v, top);
if (s.hookfunc == null) return; if (s.hookfunc == null)
return;
if (s.hookcount > 0) if (s.hookcount > 0)
if (++s.bytecodes%s.hookcount == 0) if (++s.bytecodes%s.hookcount == 0)
callHook(s, COUNT, NIL); callHook(s, COUNT, NIL);
@@ -433,9 +499,11 @@ public class DebugLib extends TwoArgFunction {
public void onReturn() { public void onReturn() {
LuaThread.State s = globals.running.state; LuaThread.State s = globals.running.state;
if (s.inhook) return; if (s.inhook)
return;
callstack().onReturn(); callstack().onReturn();
if (s.hookrtrn) callHook(s, RETURN, NIL); if (s.hookrtrn)
callHook(s, RETURN, NIL);
} }
public String traceback(int level) { public String traceback(int level) {
@@ -447,7 +515,8 @@ public class DebugLib extends TwoArgFunction {
} }
void callHook(LuaThread.State s, LuaValue type, LuaValue arg) { 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; s.inhook = true;
try { try {
s.hookfunc.call(type, arg); s.hookfunc.call(type, arg);
@@ -491,7 +560,7 @@ public class DebugLib extends TwoArgFunction {
this.source = p.source != null? p.source.tojstring(): "=?"; this.source = p.source != null? p.source.tojstring(): "=?";
this.linedefined = p.linedefined; this.linedefined = p.linedefined;
this.lastlinedefined = p.lastlinedefined; this.lastlinedefined = p.lastlinedefined;
this.what = (this.linedefined == 0) ? "main" : "Lua"; this.what = this.linedefined == 0? "main": "Lua";
this.short_src = p.shortsource(); this.short_src = p.shortsource();
} else { } else {
this.source = "=[Java]"; this.source = "=[Java]";
@@ -548,6 +617,7 @@ public class DebugLib extends TwoArgFunction {
/** /**
* Get the traceback starting at a specific level. * Get the traceback starting at a specific level.
*
* @param level * @param level
* @return String containing the traceback. * @return String containing the traceback.
*/ */
@@ -593,7 +663,6 @@ public class DebugLib extends TwoArgFunction {
return null; return null;
} }
synchronized DebugInfo auxgetinfo(String what, LuaFunction f, CallFrame ci) { synchronized DebugInfo auxgetinfo(String what, LuaFunction f, CallFrame ci) {
DebugInfo ar = new DebugInfo(); DebugInfo ar = new DebugInfo();
for (int i = 0, n = what.length(); i < n; ++i) { for (int i = 0, n = what.length(); i < n; ++i) {
@@ -650,28 +719,35 @@ public class DebugLib extends TwoArgFunction {
} }
public static class CallFrame { public static class CallFrame {
static final LuaValue[] EMPTY = {};
LuaFunction f; LuaFunction f;
int pc; int pc;
int top; int top;
Varargs v; Varargs v;
LuaValue[] stack; LuaValue[] stack = EMPTY;
CallFrame previous; CallFrame previous;
void set(LuaClosure function, Varargs varargs, LuaValue[] stack) { void set(LuaClosure function, Varargs varargs, LuaValue[] stack) {
this.f = function; this.f = function;
this.v = varargs; this.v = varargs;
this.stack = stack; this.stack = stack;
} }
public String shortsource() { public String shortsource() {
return f.isclosure()? f.checkclosure().p.shortsource(): "[Java]"; return f.isclosure()? f.checkclosure().p.shortsource(): "[Java]";
} }
void set(LuaFunction function) { void set(LuaFunction function) {
this.f = function; this.f = function;
} }
void reset() { void reset() {
this.f = null; this.f = null;
this.v = null; this.v = null;
this.stack = null; this.stack = EMPTY;
} }
void instr(int pc, Varargs v, int top) { void instr(int pc, Varargs v, int top) {
this.pc = pc; this.pc = pc;
this.v = v; this.v = v;
@@ -679,6 +755,7 @@ public class DebugLib extends TwoArgFunction {
if (TRACE) if (TRACE)
Print.printState(f.checkclosure(), pc, stack, top, v); Print.printState(f.checkclosure(), pc, stack, top, v);
} }
Varargs getLocal(int i) { Varargs getLocal(int i) {
LuaString name = getlocalname(i); LuaString name = getlocalname(i);
if (i >= 1 && i <= stack.length && stack[i-1] != null) if (i >= 1 && i <= stack.length && stack[i-1] != null)
@@ -686,6 +763,7 @@ public class DebugLib extends TwoArgFunction {
else else
return NIL; return NIL;
} }
Varargs setLocal(int i, LuaValue value) { Varargs setLocal(int i, LuaValue value) {
LuaString name = getlocalname(i); LuaString name = getlocalname(i);
if (i >= 1 && i <= stack.length && stack[i-1] != null) { if (i >= 1 && i <= stack.length && stack[i-1] != null) {
@@ -695,20 +773,27 @@ public class DebugLib extends TwoArgFunction {
return NIL; return NIL;
} }
} }
public int currentline() { public int currentline() {
if ( !f.isclosure() ) return -1; if (!f.isclosure())
return -1;
int[] li = f.checkclosure().p.lineinfo; int[] li = f.checkclosure().p.lineinfo;
return li == null || pc < 0 || pc >= li.length? -1: li[pc]; return li == null || pc < 0 || pc >= li.length? -1: li[pc];
} }
String sourceline() { String sourceline() {
if ( !f.isclosure() ) return f.tojstring(); if (!f.isclosure())
return f.tojstring();
return f.checkclosure().p.shortsource() + ":" + currentline(); return f.checkclosure().p.shortsource() + ":" + currentline();
} }
int linedefined() { int linedefined() {
return f.isclosure()? f.checkclosure().p.linedefined: -1; return f.isclosure()? f.checkclosure().p.linedefined: -1;
} }
LuaString getlocalname(int index) { LuaString getlocalname(int index) {
if ( !f.isclosure() ) return null; if (!f.isclosure())
return null;
return f.checkclosure().p.getlocalname(index, pc); return f.checkclosure().p.getlocalname(index, pc);
} }
} }
@@ -724,12 +809,14 @@ public class DebugLib extends TwoArgFunction {
} }
static void lua_assert(boolean x) { 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 { static class NameWhat {
final String name; final String name;
final String namewhat; final String namewhat;
NameWhat(String name, String namewhat) { NameWhat(String name, String namewhat) {
this.name = name; this.name = name;
this.namewhat = namewhat; this.namewhat = namewhat;
@@ -753,21 +840,49 @@ public class DebugLib extends TwoArgFunction {
/* all other instructions can call only through metamethods */ /* all other instructions can call only through metamethods */
case Lua.OP_SELF: case Lua.OP_SELF:
case Lua.OP_GETTABUP: 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_SETTABUP:
case Lua.OP_SETTABLE: tm = LuaValue.NEWINDEX; break; case Lua.OP_SETTABLE:
case Lua.OP_EQ: tm = LuaValue.EQ; break; tm = LuaValue.NEWINDEX;
case Lua.OP_ADD: tm = LuaValue.ADD; break; break;
case Lua.OP_SUB: tm = LuaValue.SUB; break; case Lua.OP_EQ:
case Lua.OP_MUL: tm = LuaValue.MUL; break; tm = LuaValue.EQ;
case Lua.OP_DIV: tm = LuaValue.DIV; break; break;
case Lua.OP_MOD: tm = LuaValue.MOD; break; case Lua.OP_ADD:
case Lua.OP_POW: tm = LuaValue.POW; break; tm = LuaValue.ADD;
case Lua.OP_UNM: tm = LuaValue.UNM; break; break;
case Lua.OP_LEN: tm = LuaValue.LEN; break; case Lua.OP_SUB:
case Lua.OP_LT: tm = LuaValue.LT; break; tm = LuaValue.SUB;
case Lua.OP_LE: tm = LuaValue.LE; break; break;
case Lua.OP_CONCAT: tm = LuaValue.CONCAT; 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: default:
return null; /* else no useful name can be found */ return null; /* else no useful name can be found */
} }
@@ -797,9 +912,9 @@ public class DebugLib extends TwoArgFunction {
case Lua.OP_GETTABLE: { case Lua.OP_GETTABLE: {
int k = Lua.GETARG_C(i); /* key index */ int k = Lua.GETARG_C(i); /* key index */
int t = Lua.GETARG_B(i); /* table index */ int t = Lua.GETARG_B(i); /* table index */
LuaString vn = (Lua.GET_OPCODE(i) == Lua.OP_GETTABLE) /* name of indexed variable */ LuaString vn = Lua.GET_OPCODE(i) == Lua.OP_GETTABLE /* name of indexed variable */
? p.getlocalname(t+1, pc) ? p.getlocalname(t+1, pc)
: (t < p.upvalues.length ? p.upvalues[t].name : QMARK); : t < p.upvalues.length? p.upvalues[t].name: QMARK;
String jname = kname(p, pc, k); String jname = kname(p, pc, k);
return new NameWhat(jname, vn != null && vn.eq_b(ENV)? "global": "field"); return new NameWhat(jname, vn != null && vn.eq_b(ENV)? "global": "field");
} }
@@ -810,8 +925,7 @@ public class DebugLib extends TwoArgFunction {
} }
case Lua.OP_LOADK: case Lua.OP_LOADK:
case Lua.OP_LOADKX: { case Lua.OP_LOADKX: {
int b = (Lua.GET_OPCODE(i) == Lua.OP_LOADK) ? Lua.GETARG_Bx(i) int b = Lua.GET_OPCODE(i) == Lua.OP_LOADK? Lua.GETARG_Bx(i): Lua.GETARG_Ax(p.code[pc+1]);
: Lua.GETARG_Ax(p.code[pc + 1]);
if (p.k[b].isstring()) { if (p.k[b].isstring()) {
name = p.k[b].strvalue(); name = p.k[b].strvalue();
return new NameWhat(name.tojstring(), "constant"); return new NameWhat(name.tojstring(), "constant");
@@ -864,12 +978,14 @@ public class DebugLib extends TwoArgFunction {
break; break;
} }
case Lua.OP_TFORCALL: { 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; break;
} }
case Lua.OP_CALL: case Lua.OP_CALL:
case Lua.OP_TAILCALL: { 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; break;
} }
case Lua.OP_JMP: { case Lua.OP_JMP: {
@@ -881,11 +997,13 @@ public class DebugLib extends TwoArgFunction {
break; break;
} }
case Lua.OP_TEST: { 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; break;
} }
case Lua.OP_SETLIST: { // Lua.testAMode(Lua.OP_SETLIST) == false 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; break;
} }
default: default:

View File

@@ -32,98 +32,128 @@ import org.luaj.vm2.LuaValue;
import org.luaj.vm2.Varargs; import org.luaj.vm2.Varargs;
/** /**
* Abstract base class extending {@link LibFunction} which implements the * Abstract base class extending {@link LibFunction} which implements the core
* core of the lua standard {@code io} library. * of the lua standard {@code io} library.
* <p> * <p>
* It contains the implementation of the io library support that is common to * It contains the implementation of the io library support that is common to
* the JSE and JME platforms. * the JSE and JME platforms. In practice on of the concrete IOLib subclasses is
* In practice on of the concrete IOLib subclasses is chosen: * chosen: {@link org.luaj.vm2.lib.jse.JseIoLib} for the JSE platform, and
* {@link org.luaj.vm2.lib.jse.JseIoLib} for the JSE platform, and
* {@link org.luaj.vm2.lib.jme.JmeIoLib} for the JME platform. * {@link org.luaj.vm2.lib.jme.JmeIoLib} for the JME platform.
* <p> * <p>
* The JSE implementation conforms almost completely to the C-based lua library, * 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, * while the JME implementation follows closely except in the area of
* which are difficult to support properly on JME. * random-access files, which are difficult to support properly on JME.
* <p> * <p>
* Typically, this library is included as part of a call to either * 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()} * {@link org.luaj.vm2.lib.jse.JsePlatform#standardGlobals()} or
* <pre> {@code * {@link org.luaj.vm2.lib.jme.JmePlatform#standardGlobals()}
*
* <pre>
* {
* &#64;code
* Globals globals = JsePlatform.standardGlobals(); * Globals globals = JsePlatform.standardGlobals();
* globals.get("io").get("write").call(LuaValue.valueOf("hello, world\n")); * 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 * </pre>
* 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}. * 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> * <p>
* To instantiate and use it directly, * To instantiate and use it directly, link it into your globals table via
* link it into your globals table via {@link LuaValue#load(LuaValue)} using code such as: * {@link LuaValue#load(LuaValue)} using code such as:
* <pre> {@code *
* <pre>
* {
* &#64;code
* Globals globals = new Globals(); * Globals globals = new Globals();
* globals.load(new JseBaseLib()); * globals.load(new JseBaseLib());
* globals.load(new PackageLib()); * globals.load(new PackageLib());
* globals.load(new OsLib()); * globals.load(new OsLib());
* globals.get("io").get("write").call(LuaValue.valueOf("hello, world\n")); * globals.get("io").get("write").call(LuaValue.valueOf("hello, world\n"));
* } </pre> * }
* </pre>
* <p> * <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 LibFunction
* @see org.luaj.vm2.lib.jse.JsePlatform * @see org.luaj.vm2.lib.jse.JsePlatform
* @see org.luaj.vm2.lib.jme.JmePlatform * @see org.luaj.vm2.lib.jme.JmePlatform
* @see org.luaj.vm2.lib.jse.JseIoLib * @see org.luaj.vm2.lib.jse.JseIoLib
* @see org.luaj.vm2.lib.jme.JmeIoLib * @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 abstract class IoLib extends TwoArgFunction {
public class IoLib extends TwoArgFunction {
protected abstract class File extends LuaValue {
public abstract void write(LuaString string) throws IOException;
public abstract void flush() throws IOException;
public abstract boolean isstdfile();
public abstract void close() throws IOException;
public abstract boolean isclosed();
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 // returns new position
abstract public int seek(String option, int bytecount) throws IOException; public abstract int seek(String option, int bytecount) throws IOException;
abstract public void setvbuf(String mode, int size);
public abstract void setvbuf(String mode, int size);
// get length remaining to read // get length remaining to read
abstract public int remaining() throws IOException; public abstract int remaining() throws IOException;
// peek ahead one character // peek ahead one character
abstract public int peek() throws IOException, EOFException; public abstract int peek() throws IOException, EOFException;
// return char if read, -1 if eof, throw IOException on other exception // return char if read, -1 if eof, throw IOException on other exception
abstract public int read() throws IOException, EOFException; public abstract int read() throws IOException, EOFException;
// return number of bytes read if positive, false if eof, throw IOException on other exception // 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 abstract int read(byte[] bytes, int offset, int length) throws IOException;
public boolean eof() throws IOException { public boolean eof() throws IOException {
try { try {
return peek() < 0; return peek() < 0;
} catch (EOFException e) { return true; } } catch (EOFException e) {
return true;
}
} }
// delegate method access to file methods table // delegate method access to file methods table
@Override
public LuaValue get(LuaValue key) { public LuaValue get(LuaValue key) {
return filemethods.get(key); return filemethods.get(key);
} }
// essentially a userdata instance // essentially a userdata instance
@Override
public int type() { public int type() {
return LuaValue.TUSERDATA; return LuaValue.TUSERDATA;
} }
@Override
public String typename() { public String typename() {
return "userdata"; return "userdata";
} }
// displays as "file" type // displays as "file" type
@Override
public String tojstring() { public String tojstring() {
return "file: " + Integer.toHexString(hashCode()); return "file: " + Integer.toHexString(hashCode());
} }
@Override
public void finalize() { public void finalize() {
if (!isclosed()) { if (!isclosed()) {
try { try {
close(); close();
} catch (IOException ignore) {} } catch (IOException ignore) {
}
} }
} }
} }
@@ -139,6 +169,7 @@ public class IoLib extends TwoArgFunction {
/** /**
* Wrap the standard input. * Wrap the standard input.
*
* @return File * @return File
* @throws IOException * @throws IOException
*/ */
@@ -146,6 +177,7 @@ public class IoLib extends TwoArgFunction {
/** /**
* Wrap the standard output. * Wrap the standard output.
*
* @return File * @return File
* @throws IOException * @throws IOException
*/ */
@@ -153,6 +185,7 @@ public class IoLib extends TwoArgFunction {
/** /**
* Wrap the standard error output. * Wrap the standard error output.
*
* @return File * @return File
* @throws IOException * @throws IOException
*/ */
@@ -160,6 +193,7 @@ public class IoLib extends TwoArgFunction {
/** /**
* Open a file in a particular mode. * Open a file in a particular mode.
*
* @param filename * @param filename
* @param readMode true if opening in read mode * @param readMode true if opening in read mode
* @param appendMode true if opening in append mode * @param appendMode true if opening in append mode
@@ -168,10 +202,12 @@ public class IoLib extends TwoArgFunction {
* @return File object if successful * @return File object if successful
* @throws IOException if could not be opened * @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. * Open a temporary file.
*
* @return File object if successful * @return File object if successful
* @throws IOException if could not be opened * @throws IOException if could not be opened
*/ */
@@ -179,6 +215,7 @@ public class IoLib extends TwoArgFunction {
/** /**
* Start a new process and return a file for input or output * Start a new process and return a file for input or output
*
* @param prog the program to execute * @param prog the program to execute
* @param mode "r" to read, "w" to write * @param mode "r" to read, "w" to write
* @return File to read to or write from * @return File to read to or write from
@@ -219,34 +256,16 @@ public class IoLib extends TwoArgFunction {
private static final int IO_INDEX = 18; private static final int IO_INDEX = 18;
private static final int LINES_ITER = 19; private static final int LINES_ITER = 19;
public static final String[] IO_NAMES = { public static final String[] IO_NAMES = { "close", "flush", "input", "lines", "open", "output", "popen", "read",
"close", "tmpfile", "type", "write", };
"flush",
"input",
"lines",
"open",
"output",
"popen",
"read",
"tmpfile",
"type",
"write",
};
public static final String[] FILE_NAMES = { public static final String[] FILE_NAMES = { "close", "flush", "lines", "read", "seek", "setvbuf", "write", };
"close",
"flush",
"lines",
"read",
"seek",
"setvbuf",
"write",
};
LuaTable filemethods; LuaTable filemethods;
protected Globals globals; protected Globals globals;
@Override
public LuaValue call(LuaValue modname, LuaValue env) { public LuaValue call(LuaValue modname, LuaValue env) {
globals = env.checkglobals(); globals = env.checkglobals();
@@ -270,7 +289,8 @@ public class IoLib extends TwoArgFunction {
// return the table // return the table
env.set("io", t); 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; return t;
} }
@@ -285,46 +305,69 @@ public class IoLib extends TwoArgFunction {
public IoLib iolib; public IoLib iolib;
private boolean toclose; private boolean toclose;
private Varargs args; private Varargs args;
public IoLibV() { public IoLibV() {
} }
public IoLibV(File f, String name, int opcode, IoLib iolib, boolean toclose, Varargs args) { public IoLibV(File f, String name, int opcode, IoLib iolib, boolean toclose, Varargs args) {
this(f, name, opcode, iolib); this(f, name, opcode, iolib);
this.toclose = toclose; this.toclose = toclose;
this.args = args.dealias(); this.args = args.dealias();
} }
public IoLibV(File f, String name, int opcode, IoLib iolib) { public IoLibV(File f, String name, int opcode, IoLib iolib) {
super();
this.f = f; this.f = f;
this.name = name; this.name = name;
this.opcode = opcode; this.opcode = opcode;
this.iolib = iolib; this.iolib = iolib;
} }
@Override
public Varargs invoke(Varargs args) { public Varargs invoke(Varargs args) {
try { try {
switch (opcode) { switch (opcode) {
case IO_FLUSH: return iolib._io_flush(); case IO_FLUSH:
case IO_TMPFILE: return iolib._io_tmpfile(); return iolib._io_flush();
case IO_CLOSE: return iolib._io_close(args.arg1()); case IO_TMPFILE:
case IO_INPUT: return iolib._io_input(args.arg1()); return iolib._io_tmpfile();
case IO_OUTPUT: return iolib._io_output(args.arg1()); case IO_CLOSE:
case IO_TYPE: return iolib._io_type(args.arg1()); return iolib._io_close(args.arg1());
case IO_POPEN: return iolib._io_popen(args.checkjstring(1),args.optjstring(2,"r")); case IO_INPUT:
case IO_OPEN: return iolib._io_open(args.checkjstring(1), args.optjstring(2,"r")); return iolib._io_input(args.arg1());
case IO_LINES: return iolib._io_lines(args); case IO_OUTPUT:
case IO_READ: return iolib._io_read(args); return iolib._io_output(args.arg1());
case IO_WRITE: return iolib._io_write(args); 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_CLOSE:
case FILE_FLUSH: return iolib._file_flush(args.arg1()); return iolib._file_close(args.arg1());
case FILE_SETVBUF: return iolib._file_setvbuf(args.arg1(),args.checkjstring(2),args.optint(3,8192)); case FILE_FLUSH:
case FILE_LINES: return iolib._file_lines(args); return iolib._file_flush(args.arg1());
case FILE_READ: return iolib._file_read(args.arg1(),args.subargs(2)); case FILE_SETVBUF:
case FILE_SEEK: return iolib._file_seek(args.arg1(),args.optjstring(2,"cur"),args.optint(3,0)); return iolib._file_setvbuf(args.arg1(), args.checkjstring(2), args.optint(3, 8192));
case FILE_WRITE: return iolib._file_write(args.arg1(),args.subargs(2)); 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 IO_INDEX:
case LINES_ITER: return iolib._lines_iter(f, toclose, this.args); return iolib._io_index(args.arg(2));
case LINES_ITER:
return iolib._lines_iter(f, toclose, this.args);
} }
} catch (IOException ioe) { } catch (IOException ioe) {
if (opcode == LINES_ITER) { if (opcode == LINES_ITER) {
@@ -362,31 +405,28 @@ public class IoLib extends TwoArgFunction {
// io.input([file]) -> file // io.input([file]) -> file
public Varargs _io_input(LuaValue file) { public Varargs _io_input(LuaValue file) {
infile = file.isnil()? input(): infile = file.isnil()? input()
file.isstring()? ioopenfile(FTYPE_NAMED, file.checkjstring(),"r"): : file.isstring()? ioopenfile(FTYPE_NAMED, file.checkjstring(), "r"): checkfile(file);
checkfile(file);
return infile; return infile;
} }
// io.output(filename) -> file // io.output(filename) -> file
public Varargs _io_output(LuaValue filename) { public Varargs _io_output(LuaValue filename) {
outfile = filename.isnil()? output(): outfile = filename.isnil()? output()
filename.isstring()? ioopenfile(FTYPE_NAMED, filename.checkjstring(),"w"): : filename.isstring()? ioopenfile(FTYPE_NAMED, filename.checkjstring(), "w"): checkfile(filename);
checkfile(filename);
return outfile; return outfile;
} }
// io.type(obj) -> "file" | "closed file" | nil // io.type(obj) -> "file" | "closed file" | nil
public Varargs _io_type(LuaValue obj) { public Varargs _io_type(LuaValue obj) {
File f = optfile(obj); File f = optfile(obj);
return f!=null? return f != null? f.isclosed()? CLOSED_FILE: FILE: NIL;
f.isclosed()? CLOSED_FILE: FILE:
NIL;
} }
// io.popen(prog, [mode]) -> file // io.popen(prog, [mode]) -> file
public Varargs _io_popen(String prog, String mode) throws IOException { 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); return openProgram(prog, mode);
} }
@@ -466,18 +506,19 @@ public class IoLib extends TwoArgFunction {
// __index, returns a field // __index, returns a field
public Varargs _io_index(LuaValue v) { public Varargs _io_index(LuaValue v) {
return v.equals(STDOUT)?output(): return v.equals(STDOUT)? output(): v.equals(STDIN)? input(): v.equals(STDERR)? errput(): NIL;
v.equals(STDIN)? input():
v.equals(STDERR)? errput(): NIL;
} }
// lines iterator(s,var) -> var' // lines iterator(s,var) -> var'
public Varargs _lines_iter(LuaValue file, boolean toclose, Varargs args) throws IOException { public Varargs _lines_iter(LuaValue file, boolean toclose, Varargs args) throws IOException {
File f = optfile(file); File f = optfile(file);
if ( f == null ) argerror(1, "not a file: " + file); if (f == null)
if ( f.isclosed() ) error("file is already closed"); argerror(1, "not a file: " + file);
if (f.isclosed())
error("file is already closed");
Varargs ret = ioread(f, args); 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; return ret;
} }
@@ -536,7 +577,8 @@ public class IoLib extends TwoArgFunction {
private Varargs ioread(File f, Varargs args) throws IOException { private Varargs ioread(File f, Varargs args) throws IOException {
int i, n = args.narg(); 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[] v = new LuaValue[n];
LuaValue ai, vi; LuaValue ai, vi;
LuaString fmt; LuaString fmt;
@@ -549,10 +591,18 @@ public class IoLib extends TwoArgFunction {
fmt = ai.checkstring(); fmt = ai.checkstring();
if (fmt.m_length >= 2 && fmt.m_bytes[fmt.m_offset] == '*') { if (fmt.m_length >= 2 && fmt.m_bytes[fmt.m_offset] == '*') {
switch (fmt.m_bytes[fmt.m_offset+1]) { switch (fmt.m_bytes[fmt.m_offset+1]) {
case 'n': vi = freadnumber(f); break item; case 'n':
case 'l': vi = freadline(f,false); break item; vi = freadnumber(f);
case 'L': vi = freadline(f,true); break item; break item;
case 'a': vi = freadall(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: default:
@@ -586,18 +636,23 @@ public class IoLib extends TwoArgFunction {
int len = mode.length(); int len = mode.length();
for (int i = 0; i < len; i++) { // [rwa][+]?b* for (int i = 0; i < len; i++) { // [rwa][+]?b*
char ch = mode.charAt(i); char ch = mode.charAt(i);
if (i == 0 && "rwa".indexOf(ch) >= 0) continue; if ((i == 0 && "rwa".indexOf(ch) >= 0) || (i == 1 && ch == '+'))
if (i == 1 && ch == '+') continue; continue;
if (i >= 1 && ch == 'b') continue; if (i >= 1 && ch == 'b')
continue;
len = -1; len = -1;
break; break;
} }
if (len <= 0) argerror(2, "invalid mode: '" + mode + "'"); if (len <= 0)
argerror(2, "invalid mode: '" + mode + "'");
switch (filetype) { switch (filetype) {
case FTYPE_STDIN: return wrapStdin(); case FTYPE_STDIN:
case FTYPE_STDOUT: return wrapStdout(); return wrapStdin();
case FTYPE_STDERR: return wrapStderr(); case FTYPE_STDOUT:
return wrapStdout();
case FTYPE_STDERR:
return wrapStderr();
} }
boolean isreadmode = mode.startsWith("r"); boolean isreadmode = mode.startsWith("r");
boolean isappend = mode.startsWith("a"); boolean isappend = mode.startsWith("a");
@@ -606,17 +661,18 @@ public class IoLib extends TwoArgFunction {
return openFile(filename, isreadmode, isappend, isupdate, isbinary); return openFile(filename, isreadmode, isappend, isupdate, isbinary);
} }
// ------------- file reading utilitied ------------------ // ------------- file reading utilitied ------------------
public static LuaValue freadbytes(File f, int count) throws IOException { 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]; byte[] b = new byte[count];
int r; int r;
if ((r = f.read(b, 0, b.length)) < 0) if ((r = f.read(b, 0, b.length)) < 0)
return NIL; return NIL;
return LuaString.valueUsing(b, 0, r); return LuaString.valueUsing(b, 0, r);
} }
public static LuaValue freaduntil(File f, boolean lineonly, boolean withend) throws IOException { public static LuaValue freaduntil(File f, boolean lineonly, boolean withend) throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream(); ByteArrayOutputStream baos = new ByteArrayOutputStream();
int c; int c;
@@ -624,9 +680,17 @@ public class IoLib extends TwoArgFunction {
if (lineonly) { if (lineonly) {
loop: while ( (c = f.read()) >= 0 ) { loop: while ( (c = f.read()) >= 0 ) {
switch (c) { switch (c) {
case '\r': if (withend) baos.write(c); break; case '\r':
case '\n': if (withend) baos.write(c); break loop; if (withend)
default: baos.write(c); break; baos.write(c);
break;
case '\n':
if (withend)
baos.write(c);
break loop;
default:
baos.write(c);
break;
} }
} }
} else { } else {
@@ -636,13 +700,13 @@ public class IoLib extends TwoArgFunction {
} catch (EOFException e) { } catch (EOFException e) {
c = -1; c = -1;
} }
return ( c < 0 && baos.size() == 0 )? return (c < 0 && baos.size() == 0)? (LuaValue) NIL: (LuaValue) LuaString.valueUsing(baos.toByteArray());
(LuaValue) NIL:
(LuaValue) LuaString.valueUsing(baos.toByteArray());
} }
public static LuaValue freadline(File f, boolean withend) throws IOException { public static LuaValue freadline(File f, boolean withend) throws IOException {
return freaduntil(f, true, withend); return freaduntil(f, true, withend);
} }
public static LuaValue freadall(File f) throws IOException { public static LuaValue freadall(File f) throws IOException {
int n = f.remaining(); int n = f.remaining();
if (n >= 0) { if (n >= 0) {
@@ -651,6 +715,7 @@ public class IoLib extends TwoArgFunction {
return freaduntil(f, false, false); return freaduntil(f, false, false);
} }
} }
public static LuaValue freadnumber(File f) throws IOException { public static LuaValue freadnumber(File f) throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream(); ByteArrayOutputStream baos = new ByteArrayOutputStream();
freadchars(f, " \t\r\n", null); freadchars(f, " \t\r\n", null);
@@ -666,6 +731,7 @@ public class IoLib extends TwoArgFunction {
String s = baos.toString(); String s = baos.toString();
return s.length() > 0? valueOf(Double.parseDouble(s)): NIL; return s.length() > 0? valueOf(Double.parseDouble(s)): NIL;
} }
private static void freadchars(File f, String chars, ByteArrayOutputStream baos) throws IOException { private static void freadchars(File f, String chars, ByteArrayOutputStream baos) throws IOException {
int c; int c;
while ( true ) { while ( true ) {
@@ -679,6 +745,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. * Subclass of {@link LuaFunction} common to Java functions exposed to lua.
* <p> * <p>
* To provide for common implementations in JME and JSE, * To provide for common implementations in JME and JSE, library functions are
* library functions are typically grouped on one or more library classes * typically grouped on one or more library classes and an opcode per library
* and an opcode per library function is defined and used to key the switch * function is defined and used to key the switch to the correct function within
* to the correct function within the library. * the library.
* <p> * <p>
* Since lua functions can be called with too few or too many arguments, * Since lua functions can be called with too few or too many arguments, and
* and there are overloaded {@link LuaValue#call()} functions with varying * there are overloaded {@link LuaValue#call()} functions with varying number of
* number of arguments, a Java function exposed in lua needs to handle the * arguments, a Java function exposed in lua needs to handle the argument fixup
* argument fixup when a function is called with a number of arguments * when a function is called with a number of arguments differs from that
* differs from that expected. * expected.
* <p> * <p>
* To simplify the creation of library functions, * To simplify the creation of library functions, there are 5 direct subclasses
* there are 5 direct subclasses to handle common cases based on number of * to handle common cases based on number of argument values and number of
* argument values and number of return return values. * return return values.
* <ul> * <ul>
* <li>{@link ZeroArgFunction}</li> * <li>{@link ZeroArgFunction}</li>
* <li>{@link OneArgFunction}</li> * <li>{@link OneArgFunction}</li>
@@ -51,13 +51,15 @@ import org.luaj.vm2.Varargs;
* <li>{@link VarArgFunction}</li> * <li>{@link VarArgFunction}</li>
* </ul> * </ul>
* <p> * <p>
* To be a Java library that can be loaded via {@code require}, it should have * To be a Java library that can be loaded via {@code require}, it should have a
* a public constructor that returns a {@link LuaValue} that, when executed, * public constructor that returns a {@link LuaValue} that, when executed,
* initializes the library. * initializes the library.
* <p> * <p>
* For example, the following code will implement a library called "hyperbolic" * For example, the following code will implement a library called "hyperbolic"
* with two functions, "sinh", and "cosh": * with two functions, "sinh", and "cosh":
<pre> {@code *
* <pre>
* {@code
* import org.luaj.vm2.LuaValue; * import org.luaj.vm2.LuaValue;
* import org.luaj.vm2.lib.*; * import org.luaj.vm2.lib.*;
* *
@@ -85,18 +87,22 @@ import org.luaj.vm2.Varargs;
* } * }
* } * }
*} *}
*}</pre> *}
* The default constructor is used to instantiate the library * </pre>
* in response to {@code require 'hyperbolic'} statement, *
* provided it is on Java&quot;s class path. * The default constructor is used to instantiate the library in response to
* This instance is then invoked with 2 arguments: the name supplied to require(), * {@code require 'hyperbolic'} statement, provided it is on Java&quot;s class
* and the environment for this function. The library may ignore these, or use * path. This instance is then invoked with 2 arguments: the name supplied to
* them to leave side effects in the global environment, for example. * require(), and the environment for this function. The library may ignore
* In the previous example, two functions are created, 'sinh', and 'cosh', and placed * these, or use them to leave side effects in the global environment, for
* into a global table called 'hyperbolic' using the supplied 'env' argument. * 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> * <p>
* To test it, a script such as this can be used: * To test it, a script such as this can be used:
* <pre> {@code *
* <pre>
* {@code
* local t = require('hyperbolic') * local t = require('hyperbolic')
* print( 't', t ) * print( 't', t )
* print( 'hyperbolic', hyperbolic ) * print( 'hyperbolic', hyperbolic )
@@ -105,30 +111,38 @@ import org.luaj.vm2.Varargs;
* end * end
* print( 'sinh(.5)', hyperbolic.sinh(.5) ) * print( 'sinh(.5)', hyperbolic.sinh(.5) )
* print( 'cosh(.5)', hyperbolic.cosh(.5) ) * print( 'cosh(.5)', hyperbolic.cosh(.5) )
* }</pre> * }
* </pre>
* <p> * <p>
* It should produce something like: * It should produce something like:
* <pre> {@code *
* <pre>
* {@code
* t table: 3dbbd23f * t table: 3dbbd23f
* hyperbolic table: 3dbbd23f * hyperbolic table: 3dbbd23f
* k,v cosh function: 3dbbd128 * k,v cosh function: 3dbbd128
* k,v sinh function: 3dbbd242 * k,v sinh function: 3dbbd242
* sinh(.5) 0.5210953 * sinh(.5) 0.5210953
* cosh(.5) 1.127626 * cosh(.5) 1.127626
* }</pre> * }
* </pre>
* <p> * <p>
* See the source code in any of the library functions * See the source code in any of the library functions such as {@link BaseLib}
* such as {@link BaseLib} or {@link TableLib} for other examples. * or {@link TableLib} for other examples.
*/ */
abstract public class LibFunction extends LuaFunction { 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> * <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; protected int opcode;
/** The common name for this function, useful for debugging. /**
* The common name for this function, useful for debugging.
* <p> * <p>
* Binding functions initialize this to the name to which it is bound. * Binding functions initialize this to the name to which it is bound.
*/ */
@@ -138,6 +152,7 @@ abstract public class LibFunction extends LuaFunction {
protected LibFunction() { protected LibFunction() {
} }
@Override
public String tojstring() { public String tojstring() {
return name != null? "function: " + name: super.tojstring(); return name != null? "function: " + name: super.tojstring();
} }
@@ -145,8 +160,9 @@ abstract public class LibFunction extends LuaFunction {
/** /**
* Bind a set of library functions. * Bind a set of library functions.
* <p> * <p>
* An array of names is provided, and the first name is bound * An array of names is provided, and the first name is bound with opcode =
* with opcode = 0, second with 1, etc. * 0, second with 1, etc.
*
* @param env The environment to apply to each bound function * @param env The environment to apply to each bound function
* @param factory the Class to instantiate for each bound function * @param factory the Class to instantiate for each bound function
* @param names array of String names, one for each function. * @param names array of String names, one for each function.
@@ -159,8 +175,9 @@ abstract public class LibFunction extends LuaFunction {
/** /**
* Bind a set of library functions, with an offset * Bind a set of library functions, with an offset
* <p> * <p>
* An array of names is provided, and the first name is bound * An array of names is provided, and the first name is bound with opcode =
* with opcode = {@code firstopcode}, second with {@code firstopcode+1}, etc. * {@code firstopcode}, second with {@code firstopcode+1}, etc.
*
* @param env The environment to apply to each bound function * @param env The environment to apply to each bound function
* @param factory the Class to instantiate for each bound function * @param factory the Class to instantiate for each bound function
* @param names array of String names, one for each function. * @param names array of String names, one for each function.
@@ -180,43 +197,67 @@ 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() { protected static LuaValue[] newupe() {
return new LuaValue[1]; 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() { protected static LuaValue[] newupn() {
return new LuaValue[] { NIL }; 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) { protected static LuaValue[] newupl(LuaValue v) {
return new LuaValue[] { v }; return new LuaValue[] { v };
} }
@Override
public LuaValue call() { public LuaValue call() {
return argerror(1, "value expected"); return argerror(1, "value expected");
} }
@Override
public LuaValue call(LuaValue a) { public LuaValue call(LuaValue a) {
return call(); return call();
} }
@Override
public LuaValue call(LuaValue a, LuaValue b) { public LuaValue call(LuaValue a, LuaValue b) {
return call(a); return call(a);
} }
@Override
public LuaValue call(LuaValue a, LuaValue b, LuaValue c) { public LuaValue call(LuaValue a, LuaValue b, LuaValue c) {
return call(a, b); return call(a, b);
} }
public LuaValue call(LuaValue a, LuaValue b, LuaValue c, LuaValue d) { public LuaValue call(LuaValue a, LuaValue b, LuaValue c, LuaValue d) {
return call(a, b, c); return call(a, b, c);
} }
@Override
public Varargs invoke(Varargs args) { public Varargs invoke(Varargs args) {
switch (args.narg()) { switch (args.narg()) {
case 0: return call(); case 0:
case 1: return call(args.arg1()); return call();
case 2: return call(args.arg1(),args.arg(2)); case 1:
case 3: return call(args.arg1(),args.arg(2),args.arg(3)); return call(args.arg1());
default: return call(args.arg1(),args.arg(2),args.arg(3),args.arg(4)); 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; import org.luaj.vm2.Varargs;
/** /**
* Subclass of {@link LibFunction} which implements the lua standard {@code math} * Subclass of {@link LibFunction} which implements the lua standard
* library. * {@code math} library.
* <p> * <p>
* It contains only the math library support that is possible on JME. * It contains only the math library support that is possible on JME. For a more
* For a more complete implementation based on math functions specific to JSE * complete implementation based on math functions specific to JSE use
* use {@link org.luaj.vm2.lib.jse.JseMathLib}. * {@link org.luaj.vm2.lib.jse.JseMathLib}. In Particular the following math
* In Particular the following math functions are <b>not</b> implemented by this library: * functions are <b>not</b> implemented by this library:
* <ul> * <ul>
* <li>acos</li> * <li>acos</li>
* <li>asin</li> * <li>asin</li>
@@ -48,58 +48,80 @@ import org.luaj.vm2.Varargs;
* </ul> * </ul>
* <p> * <p>
* The implementations of {@code exp()} and {@code pow()} are constructed by * 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> * <p>
* Typically, this library is included as part of a call to either * 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.jse.JsePlatform#standardGlobals()} or
* {@link org.luaj.vm2.lib.jme.JmePlatform#standardGlobals()} * {@link org.luaj.vm2.lib.jme.JmePlatform#standardGlobals()}
* <pre> {@code *
* <pre>
* {
* &#64;code
* Globals globals = JsePlatform.standardGlobals(); * Globals globals = JsePlatform.standardGlobals();
* System.out.println(globals.get("math").get("sqrt").call(LuaValue.valueOf(2))); * 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, * </pre>
* the subclass {@link org.luaj.vm2.lib.jse.JseMathLib} will *
* be included, which also includes this base functionality. * 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> * <p>
* To instantiate and use it directly, * To instantiate and use it directly, link it into your globals table via
* link it into your globals table via {@link LuaValue#load(LuaValue)} using code such as: * {@link LuaValue#load(LuaValue)} using code such as:
* <pre> {@code *
* <pre>
* {
* &#64;code
* Globals globals = new Globals(); * Globals globals = new Globals();
* globals.load(new JseBaseLib()); * globals.load(new JseBaseLib());
* globals.load(new PackageLib()); * globals.load(new PackageLib());
* globals.load(new MathLib()); * globals.load(new MathLib());
* System.out.println(globals.get("math").get("sqrt").call(LuaValue.valueOf(2))); * System.out.println(globals.get("math").get("sqrt").call(LuaValue.valueOf(2)));
* } </pre> * }
* Doing so will ensure the library is properly initialized * </pre>
* and loaded into the globals table. *
* Doing so will ensure the library is properly initialized and loaded into the
* globals table.
* <p> * <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 LibFunction
* @see org.luaj.vm2.lib.jse.JsePlatform * @see org.luaj.vm2.lib.jse.JsePlatform
* @see org.luaj.vm2.lib.jme.JmePlatform * @see org.luaj.vm2.lib.jme.JmePlatform
* @see org.luaj.vm2.lib.jse.JseMathLib * @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 { 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; 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 * modname string, and a global environment table as arguments using
* {@link #call(LuaValue, LuaValue)}. */ * {@link #call(LuaValue, LuaValue)}.
*/
public MathLib() { public MathLib() {
MATHLIB = this; MATHLIB = this;
} }
/** Perform one-time initialization on the library by creating a table /**
* containing the library functions, adding that table to the supplied environment, * Perform one-time initialization on the library by creating a table
* adding the table to package.loaded, and returning table as the return value. * 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 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.
*/ */
@Override
public LuaValue call(LuaValue modname, LuaValue env) { public LuaValue call(LuaValue modname, LuaValue env) {
LuaTable math = new LuaTable(0, 30); LuaTable math = new LuaTable(0, 30);
math.set("abs", new abs()); math.set("abs", new abs());
@@ -125,105 +147,163 @@ public class MathLib extends TwoArgFunction {
math.set("sqrt", new sqrt()); math.set("sqrt", new sqrt());
math.set("tan", new tan()); math.set("tan", new tan());
env.set("math", math); 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; return math;
} }
abstract protected static class UnaryOp extends OneArgFunction { abstract protected static class UnaryOp extends OneArgFunction {
@Override
public LuaValue call(LuaValue arg) { public LuaValue call(LuaValue arg) {
return valueOf(call(arg.checkdouble())); return valueOf(call(arg.checkdouble()));
} }
abstract protected double call(double d); abstract protected double call(double d);
} }
abstract protected static class BinaryOp extends TwoArgFunction { abstract protected static class BinaryOp extends TwoArgFunction {
@Override
public LuaValue call(LuaValue x, LuaValue y) { public LuaValue call(LuaValue x, LuaValue y) {
return valueOf(call(x.checkdouble(), y.checkdouble())); return valueOf(call(x.checkdouble(), y.checkdouble()));
} }
abstract protected double call(double x, double y); 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 abs extends UnaryOp {
static final class ceil extends UnaryOp { protected double call(double d) { return Math.ceil(d); } } @Override
static final class cos extends UnaryOp { protected double call(double d) { return Math.cos(d); } } protected double call(double d) { return Math.abs(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 ceil extends UnaryOp {
static final class sin extends UnaryOp { protected double call(double d) { return Math.sin(d); } } @Override
static final class sqrt extends UnaryOp { protected double call(double d) { return Math.sqrt(d); } } protected double call(double d) { return Math.ceil(d); }
static final class tan extends UnaryOp { protected double call(double d) { return Math.tan(d); } } }
static final class cos extends UnaryOp {
@Override
protected double call(double d) { return Math.cos(d); }
}
static final class deg extends UnaryOp {
@Override
protected double call(double d) { return Math.toDegrees(d); }
}
static final class floor extends UnaryOp {
@Override
protected double call(double d) { return Math.floor(d); }
}
static final class rad extends UnaryOp {
@Override
protected double call(double d) { return Math.toRadians(d); }
}
static final class sin extends UnaryOp {
@Override
protected double call(double d) { return Math.sin(d); }
}
static final class sqrt extends UnaryOp {
@Override
protected double call(double d) { return Math.sqrt(d); }
}
static final class tan extends UnaryOp {
@Override
protected double call(double d) { return Math.tan(d); }
}
static final class exp extends UnaryOp { static final class exp extends UnaryOp {
final MathLib mathlib; final MathLib mathlib;
exp(MathLib mathlib) { exp(MathLib mathlib) {
this.mathlib = mathlib; this.mathlib = mathlib;
} }
@Override
protected double call(double d) { protected double call(double d) {
return mathlib.dpow_lib(Math.E, d); return mathlib.dpow_lib(Math.E, d);
} }
} }
static final class fmod extends TwoArgFunction { static final class fmod extends TwoArgFunction {
@Override
public LuaValue call(LuaValue xv, LuaValue yv) { public LuaValue call(LuaValue xv, LuaValue yv) {
if (yv.checkdouble() == 0.0d)
return LuaDouble.NAN;
if (xv.islong() && yv.islong()) { if (xv.islong() && yv.islong()) {
return valueOf(xv.tolong()%yv.tolong()); return valueOf(xv.tolong()%yv.tolong());
} }
return valueOf(xv.checkdouble()%yv.checkdouble()); return valueOf(xv.checkdouble()%yv.checkdouble());
} }
} }
static final class ldexp extends BinaryOp { static final class ldexp extends BinaryOp {
@Override
protected double call(double x, double y) { protected double call(double x, double y) {
// This is the behavior on os-x, windows differs in rounding behavior. // This is the behavior on os-x, windows differs in rounding behavior.
return x * Double.longBitsToDouble((((long) y) + 1023) << 52); return x*Double.longBitsToDouble((long) y+1023<<52);
} }
} }
static final class pow extends BinaryOp { static final class pow extends BinaryOp {
@Override
protected double call(double x, double y) { protected double call(double x, double y) {
return MathLib.dpow_default(x, y); return MathLib.dpow_default(x, y);
} }
} }
static class frexp extends VarArgFunction { static class frexp extends VarArgFunction {
@Override
public Varargs invoke(Varargs args) { public Varargs invoke(Varargs args) {
double x = args.checkdouble(1); double x = args.checkdouble(1);
if ( x == 0 ) return varargsOf(ZERO,ZERO); if (x == 0)
return varargsOf(ZERO, ZERO);
long bits = Double.doubleToLongBits(x); long bits = Double.doubleToLongBits(x);
double m = ((bits & (~(-1L<<52))) + (1L<<52)) * ((bits >= 0)? (.5 / (1L<<52)): (-.5 / (1L<<52))); double m = ((bits & ~(-1L<<52))+(1L<<52))*(bits >= 0? .5/(1L<<52): -.5/(1L<<52));
double e = (((int) (bits >> 52)) & 0x7ff) - 1022; double e = ((int) (bits>>52) & 0x7ff)-1022;
return varargsOf(valueOf(m), valueOf(e)); return varargsOf(valueOf(m), valueOf(e));
} }
} }
static class max extends VarArgFunction { static class max extends VarArgFunction {
@Override
public Varargs invoke(Varargs args) { public Varargs invoke(Varargs args) {
LuaValue m = args.checkvalue(1); LuaValue m = args.checknumber(1);
for (int i = 2, n = args.narg(); i <= n; ++i) { for (int i = 2, n = args.narg(); i <= n; ++i) {
LuaValue v = args.checkvalue(i); LuaValue v = args.checknumber(i);
if (m.lt_b(v)) m = v; if (m.lt_b(v))
m = v;
} }
return m; return m;
} }
} }
static class min extends VarArgFunction { static class min extends VarArgFunction {
@Override
public Varargs invoke(Varargs args) { public Varargs invoke(Varargs args) {
LuaValue m = args.checkvalue(1); LuaValue m = args.checknumber(1);
for (int i = 2, n = args.narg(); i <= n; ++i) { for (int i = 2, n = args.narg(); i <= n; ++i) {
LuaValue v = args.checkvalue(i); LuaValue v = args.checknumber(i);
if (v.lt_b(m)) m = v; if (v.lt_b(m))
m = v;
} }
return m; return m;
} }
} }
static class modf extends VarArgFunction { static class modf extends VarArgFunction {
@Override
public Varargs invoke(Varargs args) { public Varargs invoke(Varargs args) {
LuaValue n = args.arg1(); LuaValue n = args.arg1();
/* number is its own integer part, no fractional part */ /* number is its own integer part, no fractional part */
if (n.islong()) return varargsOf(n, valueOf(0.0)); if (n.islong())
return varargsOf(n.tonumber(), valueOf(0.0));
double x = n.checkdouble(); double x = n.checkdouble();
/* integer part (rounds toward zero) */ /* integer part (rounds toward zero) */
double intPart = ( x > 0 ) ? Math.floor( x ) : Math.ceil( x ); double intPart = x > 0? Math.floor(x): Math.ceil(x);
/* fractional part (test needed for inf/-inf) */ /* fractional part (test needed for inf/-inf) */
double fracPart = x == intPart? 0.0: x-intPart; double fracPart = x == intPart? 0.0: x-intPart;
return varargsOf(valueOf(intPart), valueOf(fracPart)); return varargsOf(valueOf(intPart), valueOf(fracPart));
@@ -232,18 +312,26 @@ public class MathLib extends TwoArgFunction {
static class random extends LibFunction { static class random extends LibFunction {
Random random = new Random(); Random random = new Random();
@Override
public LuaValue call() { public LuaValue call() {
return valueOf(random.nextDouble()); return valueOf(random.nextDouble());
} }
@Override
public LuaValue call(LuaValue a) { public LuaValue call(LuaValue a) {
int m = a.checkint(); 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)); return valueOf(1+random.nextInt(m));
} }
@Override
public LuaValue call(LuaValue a, LuaValue b) { public LuaValue call(LuaValue a, LuaValue b) {
int m = a.checkint(); int m = a.checkint();
int n = b.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)); return valueOf(m+random.nextInt(n+1-m));
} }
@@ -251,9 +339,12 @@ public class MathLib extends TwoArgFunction {
static class randomseed extends OneArgFunction { static class randomseed extends OneArgFunction {
final random random; final random random;
randomseed(random random) { randomseed(random random) {
this.random = random; this.random = random;
} }
@Override
public LuaValue call(LuaValue arg) { public LuaValue call(LuaValue arg) {
long seed = arg.checklong(); long seed = arg.checklong();
random.random = new Random(seed); random.random = new Random(seed);
@@ -261,17 +352,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) { public static LuaValue dpow(double a, double b) {
return LuaDouble.valueOf( return LuaDouble.valueOf(MATHLIB != null? MATHLIB.dpow_lib(a, b): dpow_default(a, b));
MATHLIB!=null?
MATHLIB.dpow_lib(a,b):
dpow_default(a,b) );
} }
public static double dpow_d(double a, double b) { public static double dpow_d(double a, double b) {
return MATHLIB!=null? return MATHLIB != null? MATHLIB.dpow_lib(a, b): dpow_default(a, b);
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.LuaValue;
import org.luaj.vm2.Varargs; 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> * <p>
* Subclasses need only implement {@link LuaValue#call(LuaValue)} to complete this class, * Subclasses need only implement {@link LuaValue#call(LuaValue)} to complete
* simplifying development. * this class, simplifying development. All other uses of {@link #call()},
* All other uses of {@link #call()}, {@link #invoke(Varargs)},etc, * {@link #invoke(Varargs)},etc, are routed through this method by this class,
* are routed through this method by this class,
* dropping or extending arguments with {@code nil} values as required. * dropping or extending arguments with {@code nil} values as required.
* <p> * <p>
* If more than one argument are required, or no arguments are required, * If more than one argument are required, or no arguments are required, or
* or variable argument or variable return values, * variable argument or variable return values, then use one of the related
* then use one of the related function * function {@link ZeroArgFunction}, {@link TwoArgFunction},
* {@link ZeroArgFunction}, {@link TwoArgFunction}, {@link ThreeArgFunction}, or {@link VarArgFunction}. * {@link ThreeArgFunction}, or {@link VarArgFunction}.
* <p> * <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 #call(LuaValue)
* @see LibFunction * @see LibFunction
* @see ZeroArgFunction * @see ZeroArgFunction
@@ -48,24 +50,29 @@ import org.luaj.vm2.Varargs;
*/ */
abstract public class OneArgFunction extends LibFunction { abstract public class OneArgFunction extends LibFunction {
@Override
abstract public LuaValue call(LuaValue arg); abstract public LuaValue call(LuaValue arg);
/** Default constructor */ /** Default constructor */
public OneArgFunction() { public OneArgFunction() {
} }
@Override
public final LuaValue call() { public final LuaValue call() {
return call(NIL); return call(NIL);
} }
@Override
public final LuaValue call(LuaValue arg1, LuaValue arg2) { public final LuaValue call(LuaValue arg1, LuaValue arg2) {
return call(arg1); return call(arg1);
} }
@Override
public LuaValue call(LuaValue arg1, LuaValue arg2, LuaValue arg3) { public LuaValue call(LuaValue arg1, LuaValue arg2, LuaValue arg3) {
return call(arg1); return call(arg1);
} }
@Override
public Varargs invoke(Varargs varargs) { public Varargs invoke(Varargs varargs) {
return call(varargs.arg1()); return call(varargs.arg1());
} }

View File

@@ -0,0 +1,522 @@
/*******************************************************************************
* Copyright (c) 2009 Luaj.org. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
******************************************************************************/
package org.luaj.vm2.lib;
import java.io.IOException;
import java.time.format.TextStyle;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import org.luaj.vm2.Buffer;
import org.luaj.vm2.Globals;
import org.luaj.vm2.LuaTable;
import org.luaj.vm2.LuaValue;
import org.luaj.vm2.Varargs;
/**
* 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.
* <p>
* 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.
* <p>
* The following functions have limited implementations of features that are not
* supported well on Jme:
* <ul>
* <li>{@code execute()}</li>
* <li>{@code remove()}</li>
* <li>{@code rename()}</li>
* <li>{@code tmpname()}</li>
* </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>
* {
* &#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.
* <p>
* 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>
* <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>
*/
public class OsLib extends TwoArgFunction {
public static final String TMP_PREFIX = ".luaj";
public static final String TMP_SUFFIX = "tmp";
private static final int CLOCK = 0;
private static final int DATE = 1;
private static final int DIFFTIME = 2;
private static final int EXECUTE = 3;
private static final int EXIT = 4;
private static final int GETENV = 5;
private static final int REMOVE = 6;
private static final int RENAME = 7;
private static final int SETLOCALE = 8;
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 long t0 = System.currentTimeMillis();
private static long tmpnames = t0;
protected Globals globals;
/**
* Create and OsLib instance.
*/
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.
*
* @param modname the module name supplied if this is loaded via 'require'.
* @param env the environment to load into, typically a Globals
* instance.
*/
@Override
public LuaValue call(LuaValue modname, LuaValue env) {
globals = env.checkglobals();
LuaTable os = new LuaTable();
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);
return os;
}
class OsLibFunc extends VarArgFunction {
public OsLibFunc(int opcode, String name) {
this.opcode = opcode;
this.name = name;
}
@Override
public Varargs invoke(Varargs args) {
try {
switch (opcode) {
case CLOCK:
return valueOf(clock());
case DATE: {
String s = args.optjstring(1, "%c");
long t = args.isnumber(2)? args.tolong(2): time(null);
if (s.equals("*t")) {
Calendar d = Calendar.getInstance();
d.setTime(new Date(t*1000));
LuaTable tbl = LuaValue.tableOf();
tbl.set("year", LuaValue.valueOf(d.get(Calendar.YEAR)));
tbl.set("month", LuaValue.valueOf(d.get(Calendar.MONTH)+1));
tbl.set("day", LuaValue.valueOf(d.get(Calendar.DAY_OF_MONTH)));
tbl.set("hour", LuaValue.valueOf(d.get(Calendar.HOUR_OF_DAY)));
tbl.set("min", LuaValue.valueOf(d.get(Calendar.MINUTE)));
tbl.set("sec", LuaValue.valueOf(d.get(Calendar.SECOND)));
tbl.set("wday", LuaValue.valueOf(d.get(Calendar.DAY_OF_WEEK)));
tbl.set("yday", LuaValue.valueOf(d.get(0x6))); // Day of year
tbl.set("isdst", LuaValue.valueOf(isDaylightSavingsTime(d)));
return tbl;
}
return valueOf(date(s, t == -1? time(null): t));
}
case DIFFTIME:
return valueOf(difftime(args.checkdouble(1), args.checkdouble(2)));
case EXECUTE:
return execute(args.optjstring(1, null));
case EXIT:
exit(args.optint(1, 0));
return NONE;
case GETENV: {
final String val = getenv(args.checkjstring(1));
return val != null? valueOf(val): NIL;
}
case REMOVE:
remove(args.checkjstring(1));
return LuaValue.TRUE;
case RENAME:
rename(args.checkjstring(1), args.checkjstring(2));
return LuaValue.TRUE;
case SETLOCALE: {
String s = setlocale(args.optjstring(1, null), args.optjstring(2, "all"));
return s != null? valueOf(s): NIL;
}
case TIME:
return valueOf(time(args.opttable(1, null)));
case TMPNAME:
return valueOf(tmpname());
}
return NONE;
} catch (IOException e) {
return varargsOf(NIL, valueOf(e.getMessage()));
}
}
}
/**
* @return an approximation of the amount in seconds of CPU time used by the
* program. For luaj this simple returns the elapsed time since the
* OsLib class was loaded.
*/
protected double clock() {
return (System.currentTimeMillis()-t0)/1000.;
}
/**
* Returns the number of seconds from time t1 to time t2. In POSIX, Windows,
* and some other systems, this value is exactly t2-t1.
*
* @param t2
* @param t1
* @return diffeence in time values, in seconds
*/
protected double difftime(double t2, double t1) {
return t2-t1;
}
/**
* If the time argument is present, this is the time to be formatted (see
* the os.time function for a description of this value). Otherwise, date
* formats the current time.
*
* 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")).
*
* @param format
* @param timeInSec 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.
*/
private static String date(String format, long timeInSec) {
Calendar d = Calendar.getInstance();
d.setTime(new Date(timeInSec*1000));
if (format.startsWith("!")) {
timeInSec -= timeZoneOffset(d);
d.setTime(new Date(timeInSec*1000));
format = format.substring(1);
}
byte[] fmt = format.getBytes();
final int n = fmt.length;
Buffer result = new Buffer(n);
for (int i = 0; i < n; i++) {
byte c = fmt[i];
switch (c) {
case '\n':
result.append("\n");
break;
case '%':
if (++i >= n)
break;
String conv = Character.toString((char) fmt[i]);
if (CONVERTERS.containsKey(conv)) {
result.append(CONVERTERS.get(conv).convert(d));
} else {
LuaValue.argerror(1, "invalid conversion specifier '%" + conv + "'");
}
break;
default:
result.append(c);
break;
}
}
return result.tojstring();
}
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 interface DateConversion {
public String convert(Calendar d);
}
private static final Map<String, DateConversion> CONVERTERS = new HashMap<>();
static {
CONVERTERS.put("%", d -> "%");
CONVERTERS.put("a", d -> WeekdayNameAbbrev[d.get(Calendar.DAY_OF_WEEK)-1]);
CONVERTERS.put("A", d -> WeekdayName[d.get(Calendar.DAY_OF_WEEK)-1]);
CONVERTERS.put("b", d -> MonthNameAbbrev[d.get(Calendar.MONTH)]);
CONVERTERS.put("B", d -> MonthName[d.get(Calendar.MONTH)]);
CONVERTERS.put("c", d -> date("%a %b %e %H:%M:%S %Y", d.getTimeInMillis()/1000L));
CONVERTERS.put("C", d -> String.valueOf(d.get(Calendar.YEAR)).substring(0, 2));
CONVERTERS.put("d", d -> String.valueOf(100+d.get(Calendar.DAY_OF_MONTH)).substring(1));
CONVERTERS.put("D", d -> date("%m/%d/%y", d.getTimeInMillis()/1000L));
CONVERTERS.put("e", d -> String.format("%2d", d.get(Calendar.DAY_OF_MONTH)));
CONVERTERS.put("F", d -> date("%Y-%m-%d", d.getTimeInMillis()/1000L));
CONVERTERS.put("g", d -> String.valueOf(d.get(Calendar.YEAR)).substring(2));
CONVERTERS.put("G", d -> String.valueOf(d.get(Calendar.YEAR)));
CONVERTERS.put("h", d -> MonthNameAbbrev[d.get(Calendar.MONTH)]);
CONVERTERS.put("H", d -> String.valueOf(100+d.get(Calendar.HOUR_OF_DAY)).substring(1));
CONVERTERS.put("I", d -> String.valueOf(100+d.get(Calendar.HOUR_OF_DAY)%12).substring(1));
// day of year
CONVERTERS.put("j", d -> {
Calendar y0 = beginningOfYear(d);
int dayOfYear = (int) ((d.getTimeInMillis()-y0.getTimeInMillis())/(24*3600L*1000L));
return String.valueOf(1001+dayOfYear).substring(1);
});
CONVERTERS.put("m", d -> String.valueOf(101+d.get(Calendar.MONTH)).substring(1));
CONVERTERS.put("M", d -> String.valueOf(100+d.get(Calendar.MINUTE)).substring(1));
CONVERTERS.put("n", d -> "\n");
CONVERTERS.put("p", d -> d.get(Calendar.HOUR_OF_DAY) < 12? "AM": "PM");
CONVERTERS.put("r", d -> date("%I:%M:%S %p", d.getTimeInMillis()/1000L));
CONVERTERS.put("R", d -> date("%H:%M", d.getTimeInMillis()/1000L));
CONVERTERS.put("S", d -> String.valueOf(100+d.get(Calendar.SECOND)).substring(1));
CONVERTERS.put("t", d -> "\t");
CONVERTERS.put("T", d -> date("%H:%M:%S", d.getTimeInMillis()/1000L));
CONVERTERS.put("u", d -> String.valueOf((d.get(Calendar.DAY_OF_WEEK)+6)%7));
CONVERTERS.put("U", d -> String.valueOf(weekNumber(d, 0)));
CONVERTERS.put("V", d -> String.valueOf(weekNumber(d, 0)));
CONVERTERS.put("w", d -> String.valueOf((d.get(Calendar.DAY_OF_WEEK)+6)%7));
CONVERTERS.put("W", d -> String.valueOf(weekNumber(d, 1)));
CONVERTERS.put("x", d -> date("%m/%d/%y", d.getTimeInMillis()/1000L));
CONVERTERS.put("X", d -> date("%H:%M:%S", d.getTimeInMillis()/1000L));
CONVERTERS.put("y", d -> String.valueOf(d.get(Calendar.YEAR)).substring(2));
CONVERTERS.put("Y", d -> String.valueOf(d.get(Calendar.YEAR)));
CONVERTERS.put("z", d -> {
final int tzo = timeZoneOffset(d)/60;
final int a = Math.abs(tzo);
final String h = String.valueOf(100+a/60).substring(1);
final String m = String.valueOf(100+a%60).substring(1);
return (tzo >= 0? "+": "-")+h+m;
});
CONVERTERS.put("Z", d -> d.getTimeZone().toZoneId().getDisplayName(TextStyle.SHORT, Locale.getDefault()));
}
private static Calendar beginningOfYear(Calendar d) {
Calendar y0 = Calendar.getInstance();
y0.setTime(d.getTime());
y0.set(Calendar.MONTH, 0);
y0.set(Calendar.DAY_OF_MONTH, 1);
y0.set(Calendar.HOUR_OF_DAY, 0);
y0.set(Calendar.MINUTE, 0);
y0.set(Calendar.SECOND, 0);
y0.set(Calendar.MILLISECOND, 0);
return y0;
}
private static int weekNumber(Calendar d, int startDay) {
Calendar y0 = beginningOfYear(d);
y0.set(Calendar.DAY_OF_MONTH, 1+(startDay+8-y0.get(Calendar.DAY_OF_WEEK))%7);
if (y0.after(d)) {
y0.set(Calendar.YEAR, y0.get(Calendar.YEAR)-1);
y0.set(Calendar.DAY_OF_MONTH, 1+(startDay+8-y0.get(Calendar.DAY_OF_WEEK))%7);
}
long dt = d.getTime().getTime()-y0.getTime().getTime();
return 1+(int) (dt/(7L*24L*3600L*1000L));
}
private static 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;
}
private boolean isDaylightSavingsTime(Calendar d) {
return timeZoneOffset(d) != d.getTimeZone().getRawOffset()/1000;
}
/**
* This function is equivalent to the C function system. It passes command
* to be executed by an operating system shell. It returns a status code,
* which is system-dependent. If command is absent, then it returns nonzero
* if a shell is available and zero otherwise.
*
* @param command command to pass to the system
*/
protected Varargs execute(String command) {
return varargsOf(NIL, valueOf("exit"), ONE);
}
/**
* Calls the C function exit, with an optional code, to terminate the host
* program.
*
* @param code
*/
protected void exit(int code) {
System.exit(code);
}
/**
* 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 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'.
*
* @param varname
* @return String value, or null if not defined
*/
protected String getenv(String varname) {
return System.getProperty(varname);
}
/**
* Deletes the file or directory with the given name. Directories must be
* empty to be removed. If this function fails, it throws and IOException
*
* @param filename
* @throws IOException if it fails
*/
protected void remove(String filename) throws IOException {
throw new IOException("not implemented");
}
/**
* Renames file or directory named oldname to newname. If this function
* fails,it throws and IOException
*
* @param oldname old file name
* @param newname new file name
* @throws IOException if it fails
*/
protected void rename(String oldname, String newname) throws IOException {
throw new IOException("not implemented");
}
/**
* 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.
*
* 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.
*/
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).
*
* @param table
* @return long value for the time
*/
protected long time(LuaTable table) {
java.util.Date d;
if (table == null) {
d = new java.util.Date();
} else {
Calendar c = Calendar.getInstance();
c.set(Calendar.YEAR, table.get("year").checkint());
c.set(Calendar.MONTH, table.get("month").checkint()-1);
c.set(Calendar.DAY_OF_MONTH, table.get("day").checkint());
c.set(Calendar.HOUR_OF_DAY, table.get("hour").optint(12));
c.set(Calendar.MINUTE, table.get("min").optint(0));
c.set(Calendar.SECOND, table.get("sec").optint(0));
c.set(Calendar.MILLISECOND, 0);
d = c.getTime();
}
return d.getTime()/1000L;
}
/**
* Returns a string with a file name that can be used for a temporary file.
* 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).
*
* @return String filename to use
*/
protected String tmpname() {
synchronized (OsLib.class) {
return TMP_PREFIX+tmpnames+++TMP_SUFFIX;
}
}
}

View File

@@ -22,6 +22,7 @@
package org.luaj.vm2.lib; package org.luaj.vm2.lib;
import java.io.InputStream; import java.io.InputStream;
import java.nio.file.FileSystems;
import org.luaj.vm2.Globals; import org.luaj.vm2.Globals;
import org.luaj.vm2.LuaFunction; import org.luaj.vm2.LuaFunction;
@@ -31,56 +32,73 @@ import org.luaj.vm2.LuaValue;
import org.luaj.vm2.Varargs; import org.luaj.vm2.Varargs;
/** /**
* Subclass of {@link LibFunction} which implements the lua standard package and module * Subclass of {@link LibFunction} which implements the lua standard package and
* library functions. * module library functions.
* *
* <h3>Lua Environment Variables</h3> * <h3>Lua Environment Variables</h3> The following variables are available to
* The following variables are available to lua scrips when this library has been loaded: * lua scrips when this library has been loaded:
* <ul> * <ul>
* <li><code>"package.loaded"</code> Lua table of loaded modules. * <li><code>"package.loaded"</code> Lua table of loaded modules.
* <li><code>"package.path"</code> Search path for lua scripts. * <li><code>"package.path"</code> Search path for lua scripts.
* <li><code>"package.preload"</code> Lua table of uninitialized preload functions. * <li><code>"package.preload"</code> Lua table of uninitialized preload
* <li><code>"package.searchers"</code> Lua table of functions that search for object to load. * functions.
* <li><code>"package.searchers"</code> Lua table of functions that search for
* object to load.
* </ul> * </ul>
* *
* <h3>Java Environment Variables</h3> * <h3>Java Environment Variables</h3> These Java environment variables affect
* These Java environment variables affect the library behavior: * the library behavior:
* <ul> * <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> * </ul>
* *
* <h3>Loading</h3> * <h3>Loading</h3> Typically, this library is included as part of a call to
* Typically, this library is included as part of a call to either * either {@link org.luaj.vm2.lib.jse.JsePlatform#standardGlobals()} or
* {@link org.luaj.vm2.lib.jse.JsePlatform#standardGlobals()} or {@link org.luaj.vm2.lib.jme.JmePlatform#standardGlobals()} * {@link org.luaj.vm2.lib.jme.JmePlatform#standardGlobals()}
* <pre> {@code *
* <pre>
* {@code
* Globals globals = JsePlatform.standardGlobals(); * Globals globals = JsePlatform.standardGlobals();
* System.out.println( globals.get("require").call"foo") ); * System.out.println( globals.get("require").call"foo") );
* } </pre> * }
* </pre>
* <p> * <p>
* To instantiate and use it directly, * To instantiate and use it directly, link it into your globals table via
* link it into your globals table via {@link LuaValue#load(LuaValue)} using code such as: * {@link LuaValue#load(LuaValue)} using code such as:
* <pre> {@code *
* <pre>
* {
* &#64;code
* Globals globals = new Globals(); * Globals globals = new Globals();
* globals.load(new JseBaseLib()); * globals.load(new JseBaseLib());
* globals.load(new PackageLib()); * globals.load(new PackageLib());
* System.out.println(globals.get("require").call("foo")); * System.out.println(globals.get("require").call("foo"));
* } </pre> * }
* <h3>Limitations</h3> * </pre>
* 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 * <h3>Limitations</h3> This library has been implemented to match as closely as
* as outlined in the {@link BaseLib} and {@link org.luaj.vm2.lib.jse.JseBaseLib} documentation. * 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> * <p>
*
* @see LibFunction * @see LibFunction
* @see BaseLib * @see BaseLib
* @see org.luaj.vm2.lib.jse.JseBaseLib * @see org.luaj.vm2.lib.jse.JseBaseLib
* @see org.luaj.vm2.lib.jse.JsePlatform * @see org.luaj.vm2.lib.jse.JsePlatform
* @see org.luaj.vm2.lib.jme.JmePlatform * @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 { 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; public static final String DEFAULT_LUA_PATH;
static { static {
String path = null; String path = null;
@@ -101,6 +119,7 @@ public class PackageLib extends TwoArgFunction {
static final LuaString _PATH = valueOf("path"); static final LuaString _PATH = valueOf("path");
static final LuaString _SEARCHPATH = valueOf("searchpath"); static final LuaString _SEARCHPATH = valueOf("searchpath");
static final LuaString _SEARCHERS = valueOf("searchers"); static final LuaString _SEARCHERS = valueOf("searchers");
static final LuaString _SEEALL = valueOf("seeall");
/** The globals that were used to load this library. */ /** The globals that were used to load this library. */
Globals globals; Globals globals;
@@ -111,25 +130,35 @@ public class PackageLib extends TwoArgFunction {
/** Loader that loads from {@code preload} table if found there */ /** Loader that loads from {@code preload} table if found there */
public preload_searcher preload_searcher; 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; 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; public java_searcher java_searcher;
private static final LuaString _SENTINEL = valueOf("\u0001"); private static final LuaString _SENTINEL = valueOf("\u0001");
private static final String FILE_SEP = System.getProperty("file.separator"); private static final String FILE_SEP = FileSystems.getDefault().getSeparator();
public PackageLib() {} public PackageLib() {}
/** Perform one-time initialization on the library by adding package functions /**
* to the supplied environment, and returning it as the return value. * Perform one-time initialization on the library by adding package
* It also creates the package.preload and package.loaded tables for use by * functions to the supplied environment, and returning it as the return
* other libraries. * 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 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.
*/ */
@Override
public LuaValue call(LuaValue modname, LuaValue env) { public LuaValue call(LuaValue modname, LuaValue env) {
globals = env.checkglobals(); globals = env.checkglobals();
globals.set("require", new require()); globals.set("require", new require());
@@ -139,6 +168,7 @@ public class PackageLib extends TwoArgFunction {
package_.set(_PATH, LuaValue.valueOf(DEFAULT_LUA_PATH)); package_.set(_PATH, LuaValue.valueOf(DEFAULT_LUA_PATH));
package_.set(_LOADLIB, new loadlib()); package_.set(_LOADLIB, new loadlib());
package_.set(_SEARCHPATH, new searchpath()); package_.set(_SEARCHPATH, new searchpath());
package_.set(_SEEALL, new seeall());
LuaTable searchers = new LuaTable(); LuaTable searchers = new LuaTable();
searchers.set(1, preload_searcher = new preload_searcher()); searchers.set(1, preload_searcher = new preload_searcher());
searchers.set(2, lua_searcher = new lua_searcher()); searchers.set(2, lua_searcher = new lua_searcher());
@@ -156,13 +186,15 @@ public class PackageLib extends TwoArgFunction {
package_.get(_LOADED).set(name, value); package_.get(_LOADED).set(name, value);
} }
/**
/** Set the lua path used by this library instance to a new value. * Set the lua path used by this library instance to a new value. Merely
* Merely sets the value of {@link path} to be used in subsequent searches. */ * sets the value of {@link path} to be used in subsequent searches.
*/
public void setLuaPath(String newLuaPath) { public void setLuaPath(String newLuaPath) {
package_.set(_PATH, LuaValue.valueOf(newLuaPath)); package_.set(_PATH, LuaValue.valueOf(newLuaPath));
} }
@Override
public String tojstring() { public String tojstring() {
return "package"; return "package";
} }
@@ -172,31 +204,37 @@ public class PackageLib extends TwoArgFunction {
/** /**
* require (modname) * require (modname)
* *
* Loads the given module. The function starts by looking into the package.loaded table * Loads the given module. The function starts by looking into the
* to determine whether modname is already loaded. If it is, then require returns the value * package.loaded table to determine whether modname is already loaded. If
* stored at package.loaded[modname]. Otherwise, it tries to find a loader for the module. * 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. * To find a loader, require is guided by the package.searchers sequence. By
* By changing this sequence, we can change how require looks for a module. * changing this sequence, we can change how require looks for a module. The
* The following explanation is based on the default configuration for package.searchers. * following explanation is based on the default configuration for
* package.searchers.
* *
* First require queries package.preload[modname]. If it has a value, this value * First require queries package.preload[modname]. If it has a value, this
* (which should be a function) is the loader. Otherwise require searches for a Lua loader using * value (which should be a function) is the loader. Otherwise require
* the path stored in package.path. If that also fails, it searches for a Java loader using * searches for a Lua loader using the path stored in package.path. If that
* the classpath, using the public default constructor, and casting the instance to LuaFunction. * 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 * Once a loader is found, require calls the loader with two arguments:
* dependent on how it got the loader. If the loader came from a file, this extra value is the file name. * modname and an extra value dependent on how it got the loader. If the
* If the loader is a Java instance of LuaFunction, this extra value is the environment. * loader came from a file, this extra value is the file name. If the loader
* If the loader returns any non-nil value, require assigns the returned value to package.loaded[modname]. * is a Java instance of LuaFunction, this extra value is the environment.
* If the loader does not return a non-nil value and has not assigned any value to package.loaded[modname], * If the loader returns any non-nil value, require assigns the returned
* then require assigns true to this entry. * value to package.loaded[modname]. If the loader does not return a non-nil
* In any case, require returns the final value of package.loaded[modname]. * 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, * If there is any error loading or running the module, or if it cannot find
* then require raises an error. * any loader for the module, then require raises an error.
*/ */
public class require extends OneArgFunction { public class require extends OneArgFunction {
@Override
public LuaValue call(LuaValue arg) { public LuaValue call(LuaValue arg) {
LuaString name = arg.checkstring(); LuaString name = arg.checkstring();
LuaValue loaded = package_.get(_LOADED); LuaValue loaded = package_.get(_LOADED);
@@ -237,6 +275,7 @@ public class PackageLib extends TwoArgFunction {
} }
public static class loadlib extends VarArgFunction { public static class loadlib extends VarArgFunction {
@Override
public Varargs invoke(Varargs args) { public Varargs invoke(Varargs args) {
args.checkstring(1); args.checkstring(1);
return varargsOf(NIL, valueOf("dynamic libraries not enabled"), valueOf("absent")); return varargsOf(NIL, valueOf("dynamic libraries not enabled"), valueOf("absent"));
@@ -244,16 +283,16 @@ public class PackageLib extends TwoArgFunction {
} }
public class preload_searcher extends VarArgFunction { public class preload_searcher extends VarArgFunction {
@Override
public Varargs invoke(Varargs args) { public Varargs invoke(Varargs args) {
LuaString name = args.checkstring(1); LuaString name = args.checkstring(1);
LuaValue val = package_.get(_PRELOAD).get(name); LuaValue val = package_.get(_PRELOAD).get(name);
return val.isnil()? return val.isnil()? valueOf("\n\tno field package.preload['" + name + "']"): val;
valueOf("\n\tno field package.preload['"+name+"']"):
val;
} }
} }
public class lua_searcher extends VarArgFunction { public class lua_searcher extends VarArgFunction {
@Override
public Varargs invoke(Varargs args) { public Varargs invoke(Varargs args) {
LuaString name = args.checkstring(1); LuaString name = args.checkstring(1);
@@ -281,6 +320,7 @@ public class PackageLib extends TwoArgFunction {
} }
public class searchpath extends VarArgFunction { public class searchpath extends VarArgFunction {
@Override
public Varargs invoke(Varargs args) { public Varargs invoke(Varargs args) {
String name = args.checkjstring(1); String name = args.checkjstring(1);
String path = args.checkjstring(2); String path = args.checkjstring(2);
@@ -311,7 +351,10 @@ public class PackageLib extends TwoArgFunction {
// try opening the file // try opening the file
InputStream is = globals.finder.findResource(filename); InputStream is = globals.finder.findResource(filename);
if (is != null) { if (is != null) {
try { is.close(); } catch ( java.io.IOException ioe ) {} try {
is.close();
} catch (java.io.IOException ioe) {
}
return valueOf(filename); return valueOf(filename);
} }
@@ -324,7 +367,18 @@ public class PackageLib extends TwoArgFunction {
} }
} }
public class seeall extends OneArgFunction {
@Override
public LuaValue call(LuaValue arg) {
LuaTable mt = new LuaTable();
mt.set(LuaValue.INDEX, globals);
arg.checktable().setmetatable(mt);
return LuaValue.NONE;
}
}
public class java_searcher extends VarArgFunction { public class java_searcher extends VarArgFunction {
@Override
public Varargs invoke(Varargs args) { public Varargs invoke(Varargs args) {
String name = args.checkjstring(1); String name = args.checkjstring(1);
String classname = toClassname(name); String classname = toClassname(name);
@@ -352,13 +406,11 @@ public class PackageLib extends TwoArgFunction {
j -= 4; j -= 4;
for (int k = 0; k < j; k++) { for (int k = 0; k < j; k++) {
char c = filename.charAt(k); char c = filename.charAt(k);
if ( (!isClassnamePart(c)) || (c=='/') || (c=='\\') ) { if (!isClassnamePart(c) || c == '/' || c == '\\') {
StringBuffer sb = new StringBuffer(j); StringBuffer sb = new StringBuffer(j);
for (int i = 0; i < j; i++) { for (int i = 0; i < j; i++) {
c = filename.charAt(i); c = filename.charAt(i);
sb.append( sb.append(isClassnamePart(c)? c: c == '/' || c == '\\'? '.': '_');
(isClassnamePart(c))? c:
((c=='/') || (c=='\\'))? '.': '_' );
} }
return sb.toString(); return sb.toString();
} }
@@ -367,7 +419,7 @@ public class PackageLib extends TwoArgFunction {
} }
private static final boolean isClassnamePart(char c) { private static final boolean isClassnamePart(char c) {
if ( (c>='a'&&c<='z') || (c>='A'&&c<='Z') || (c>='0'&&c<='9') ) if (c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z' || c >= '0' && c <= '9')
return true; return true;
switch (c) { switch (c) {
case '.': case '.':

View File

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

View File

@@ -24,12 +24,8 @@ package org.luaj.vm2.lib;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.IOException; import java.io.IOException;
import org.luaj.vm2.Buffer; import org.luaj.vm2.*;
import org.luaj.vm2.LuaClosure; import org.luaj.vm2.compat.JavaCompat;
import org.luaj.vm2.LuaString;
import org.luaj.vm2.LuaTable;
import org.luaj.vm2.LuaValue;
import org.luaj.vm2.Varargs;
import org.luaj.vm2.compiler.DumpState; import org.luaj.vm2.compiler.DumpState;
/** /**
@@ -274,16 +270,63 @@ public class StringLib extends TwoArgFunction {
case 'f': case 'f':
case 'g': case 'g':
case 'G': case 'G':
case 'a':
case 'A':
double j = args.checkdouble(arg);
if (Double.isNaN(j) || Double.isInfinite(j)) {
String nprefix = "";
if (JavaCompat.INSTANCE.doubleToRawLongBits(j) < 0)
nprefix = "-";
else if (fdsc.explicitPlus)
nprefix = "+";
else if (fdsc.space)
nprefix = " ";
String bstr = Double.isNaN(j) ? LuaDouble.JSTR_NAN : LuaDouble.JSTR_POSINF;
if (fdsc.conversion == 'E' || fdsc.conversion == 'G')
bstr = bstr.toUpperCase();
fdsc.precision = -1;
fdsc.zeroPad = false;
fdsc.format(result, valueOf(nprefix + bstr));
} else if ((fdsc.conversion == 'g' || fdsc.conversion == 'G') && fdsc.precision == -1) {
//TODO: This gives a slightly different format but is better than nothing
String nprefix = "";
if (j >= 0) {
if (fdsc.explicitPlus)
nprefix = "+";
else if (fdsc.space)
nprefix = " ";
}
String bstr = Double.toString(j);
if (fdsc.conversion == 'G')
bstr = bstr.toUpperCase();
else
bstr = bstr.toLowerCase();
fdsc.format(result, valueOf(nprefix + bstr));
} else
fdsc.format(result, args.checkdouble(arg)); fdsc.format(result, args.checkdouble(arg));
break; break;
case 'q': case 'q':
addquoted( result, args.checkstring( arg ) ); addquoted( result, args.checkstring( arg ) );
break; break;
case 's': { case 's': {
LuaString s = args.checkstring( arg ); LuaValue argv = args.checkvalue( arg );
LuaString s;
LuaValue h = argv.metatag(TOSTRING);
if ( ! h.isnil() ) {
LuaValue v = h.call(argv).tostring();
return !v.isnil() ? v : StringLib.valueOf("(null)");
} else {
LuaValue v = argv.tostring();
if ( ! v.isnil() ) {
s = v.checkstring();
} else {
s = StringLib.valueOf(argv.tojstring());
}
}
if ( fdsc.precision == -1 && s.length() >= 100 ) { if ( fdsc.precision == -1 && s.length() >= 100 ) {
result.append( s ); result.append( s );
} else { } else {
fdsc.zeroPad = false;
fdsc.format( result, s ); fdsc.format( result, s );
} }
} break; } break;
@@ -375,8 +418,8 @@ public class StringLib extends TwoArgFunction {
} }
} }
precision = -1;
if ( c == '.' ) { if ( c == '.' ) {
precision = 0;
c = ( (p < n) ? strfrmt.luaByte( p++ ) : 0 ); c = ( (p < n) ? strfrmt.luaByte( p++ ) : 0 );
if ( Character.isDigit( (char) c ) ) { if ( Character.isDigit( (char) c ) ) {
precision = c - '0'; precision = c - '0';
@@ -386,20 +429,32 @@ public class StringLib extends TwoArgFunction {
c = ( (p < n) ? strfrmt.luaByte( p++ ) : 0 ); c = ( (p < n) ? strfrmt.luaByte( p++ ) : 0 );
} }
} }
} } else
precision = -1;
if ( Character.isDigit( (char) c ) ) if ( Character.isDigit( (char) c ) )
error("invalid format (width or precision too long)"); error("invalid format (width or precision too long)");
if ( width == -1 ) {
// default width overrides '-' and '0'
leftAdjust = false;
zeroPad = false;
} else
zeroPad &= !leftAdjust; // '-' overrides '0' zeroPad &= !leftAdjust; // '-' overrides '0'
space &= !explicitPlus; // '+' overrides ' '
conversion = c; conversion = c;
length = p - start; length = p - start;
src = strfrmt.substring(start - 1, p).tojstring(); src = strfrmt.substring(start - 1, p).tojstring();
} }
public void format(Buffer buf, byte c) { public void format(Buffer buf, byte c) {
// TODO: not clear that any of width, precision, or flags apply here. if (!leftAdjust)
pad(buf, ' ', width - 1);
buf.append(c); buf.append(c);
if (leftAdjust)
pad(buf, ' ', width - 1);
} }
public void format(Buffer buf, long number) { public void format(Buffer buf, long number) {
@@ -430,9 +485,11 @@ public class StringLib extends TwoArgFunction {
int ndigits = minwidth; int ndigits = minwidth;
int nzeros; int nzeros;
boolean allowPlusSpace = conversion == 'd' || conversion == 'i';
if ( number < 0 ) { if ( number < 0 ) {
ndigits--; ndigits--;
} else if ( explicitPlus || space ) { } else if ( allowPlusSpace && (explicitPlus || space) ) {
minwidth++; minwidth++;
} }
@@ -454,12 +511,26 @@ public class StringLib extends TwoArgFunction {
buf.append( (byte)'-' ); buf.append( (byte)'-' );
digits = digits.substring( 1 ); digits = digits.substring( 1 );
} }
} else if ( explicitPlus ) { } else if ( allowPlusSpace && explicitPlus ) {
buf.append( (byte)'+' ); buf.append( (byte)'+' );
} else if ( space ) { } else if ( allowPlusSpace && space ) {
buf.append( (byte)' ' ); buf.append( (byte)' ' );
} }
if (alternateForm) {
switch (conversion) {
case 'o':
buf.append((byte) '0');
break;
case 'x':
buf.append("0x");
break;
case 'X':
buf.append("0X");
break;
}
}
if ( nzeros > 0 ) if ( nzeros > 0 )
pad( buf, '0', nzeros ); pad( buf, '0', nzeros );
@@ -470,14 +541,40 @@ public class StringLib extends TwoArgFunction {
} }
public void format(Buffer buf, double x) { public void format(Buffer buf, double x) {
buf.append( StringLib.this.format(src, x) ); // TODO: Java does not support alternateForm with 'g'
String sFormat = "%";
if (leftAdjust)
sFormat += ("-");
if (explicitPlus)
sFormat += ("+");
if (space)
sFormat += (" ");
if (alternateForm && conversion != 'g' && conversion != 'G')
sFormat += ("#");
if (zeroPad)
sFormat += ("0");
if (width != -1)
sFormat += (width);
if (precision != -1)
sFormat += (".") + (precision);
sFormat += ((char) conversion);
buf.append( StringLib.this.format(sFormat, x) );
} }
public void format(Buffer buf, LuaString s) { public void format(Buffer buf, LuaString s) {
int nullindex = s.indexOf( (byte)'\0', 0 ); int nullindex = s.indexOf( (byte)'\0', 0 );
if ( nullindex != -1 ) if ( nullindex != -1 )
s = s.substring( 0, nullindex ); s = s.substring( 0, nullindex );
int newLength = precision == -1 ? s.length() : Math.min(precision, s.length());
if (!leftAdjust)
pad(buf, zeroPad ? '0' : ' ', width - newLength);
buf.append(s); buf.append(s);
if (leftAdjust)
pad(buf, ' ', width - newLength);
} }
public final void pad(Buffer buf, char c, int n) { public final void pad(Buffer buf, char c, int n) {
@@ -602,6 +699,8 @@ public class StringLib extends TwoArgFunction {
int lastmatch = -1; /* end of last match */ int lastmatch = -1; /* end of last match */
LuaValue repl = args.arg( 3 ); LuaValue repl = args.arg( 3 );
int max_s = args.optint( 4, srclen + 1 ); int max_s = args.optint( 4, srclen + 1 );
if (max_s < 0)
max_s = srclen+1;
final boolean anchor = p.length() > 0 && p.charAt( 0 ) == '^'; final boolean anchor = p.length() > 0 && p.charAt( 0 ) == '^';
Buffer lbuf = new Buffer( srclen ); Buffer lbuf = new Buffer( srclen );
@@ -668,19 +767,32 @@ public class StringLib extends TwoArgFunction {
} }
/** /**
* string.rep (s, n) * string.rep (s, n [, sep])
* *
* Returns a string that is the concatenation of n copies of the string s. * Returns a string that is the concatenation of n copies of the string s
* separated by the string sep. The default value for sep is the empty
* string (that is, no separator).
*/ */
static final class rep extends VarArgFunction { static final class rep extends VarArgFunction {
public Varargs invoke(Varargs args) { public Varargs invoke(Varargs args) {
LuaString s = args.checkstring(1); LuaString s = args.checkstring(1);
int n = args.checkint(2); int n = args.checkint(2);
final byte[] bytes = new byte[ s.length() * n ]; LuaString sep = args.optstring(3, EMPTYSTRING);
if (n <= 0)
return EMPTYSTRING;
int len = s.length(); int len = s.length();
for ( int offset = 0; offset < bytes.length; offset += len ) { int lsep = sep.length();
final byte[] bytes = new byte[len * n + lsep * (n - 1)];
int offset = 0;
while (n-- > 1) {
s.copyInto(0, bytes, offset, len); s.copyInto(0, bytes, offset, len);
offset += len;
if (lsep > 0) {
sep.copyInto(0, bytes, offset, lsep);
offset += lsep;
} }
}
s.copyInto(0, bytes, offset, len);
return LuaString.valueUsing(bytes); return LuaString.valueUsing(bytes);
} }
} }

View File

@@ -26,41 +26,58 @@ import org.luaj.vm2.LuaValue;
import org.luaj.vm2.Varargs; import org.luaj.vm2.Varargs;
/** /**
* Subclass of {@link LibFunction} which implements the lua standard {@code table} * Subclass of {@link LibFunction} which implements the lua standard
* library. * {@code table} library.
* *
* <p> * <p>
* Typically, this library is included as part of a call to either * 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()} * {@link org.luaj.vm2.lib.jse.JsePlatform#standardGlobals()} or
* <pre> {@code * {@link org.luaj.vm2.lib.jme.JmePlatform#standardGlobals()}
*
* <pre>
* {
* &#64;code
* Globals globals = JsePlatform.standardGlobals(); * Globals globals = JsePlatform.standardGlobals();
* System.out.println(globals.get("table").get("length").call(LuaValue.tableOf())); * System.out.println(globals.get("table").get("length").call(LuaValue.tableOf()));
* } </pre> * }
* </pre>
* <p> * <p>
* To instantiate and use it directly, * To instantiate and use it directly, link it into your globals table via
* link it into your globals table via {@link LuaValue#load(LuaValue)} using code such as: * {@link LuaValue#load(LuaValue)} using code such as:
* <pre> {@code *
* <pre>
* {
* &#64;code
* Globals globals = new Globals(); * Globals globals = new Globals();
* globals.load(new JseBaseLib()); * globals.load(new JseBaseLib());
* globals.load(new PackageLib()); * globals.load(new PackageLib());
* globals.load(new TableLib()); * globals.load(new TableLib());
* System.out.println(globals.get("table").get("length").call(LuaValue.tableOf())); * System.out.println(globals.get("table").get("length").call(LuaValue.tableOf()));
* } </pre> * }
* </pre>
* <p> * <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 LibFunction
* @see org.luaj.vm2.lib.jse.JsePlatform * @see org.luaj.vm2.lib.jse.JsePlatform
* @see org.luaj.vm2.lib.jme.JmePlatform * @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 { 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, * Perform one-time initialization on the library by creating a table
* adding the table to package.loaded, and returning table as the return value. * 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 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.
*/ */
@Override
public LuaValue call(LuaValue modname, LuaValue env) { public LuaValue call(LuaValue modname, LuaValue env) {
LuaTable table = new LuaTable(); LuaTable table = new LuaTable();
table.set("concat", new concat()); table.set("concat", new concat());
@@ -70,21 +87,29 @@ public class TableLib extends TwoArgFunction {
table.set("sort", new sort()); table.set("sort", new sort());
table.set("unpack", new unpack()); table.set("unpack", new unpack());
env.set("table", table); 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; return NIL;
} }
// "concat" (table [, sep [, i [, j]]]) -> string // "concat" (table [, sep [, i [, j]]]) -> string
static class concat extends TableLibFunction { static class concat extends TableLibFunction {
@Override
public LuaValue call(LuaValue list) { public LuaValue call(LuaValue list) {
return list.checktable().concat(EMPTYSTRING, 1, list.length()); return list.checktable().concat(EMPTYSTRING, 1, list.length());
} }
@Override
public LuaValue call(LuaValue list, LuaValue sep) { public LuaValue call(LuaValue list, LuaValue sep) {
return list.checktable().concat(sep.checkstring(), 1, list.length()); return list.checktable().concat(sep.checkstring(), 1, list.length());
} }
@Override
public LuaValue call(LuaValue list, LuaValue sep, LuaValue i) { public LuaValue call(LuaValue list, LuaValue sep, LuaValue i) {
return list.checktable().concat(sep.checkstring(), i.checkint(), list.length()); return list.checktable().concat(sep.checkstring(), i.checkint(), list.length());
} }
@Override
public LuaValue call(LuaValue list, LuaValue sep, LuaValue i, LuaValue j) { public LuaValue call(LuaValue list, LuaValue sep, LuaValue i, LuaValue j) {
return list.checktable().concat(sep.checkstring(), i.checkint(), j.checkint()); return list.checktable().concat(sep.checkstring(), i.checkint(), j.checkint());
} }
@@ -92,6 +117,7 @@ public class TableLib extends TwoArgFunction {
// "insert" (table, [pos,] value) // "insert" (table, [pos,] value)
static class insert extends VarArgFunction { static class insert extends VarArgFunction {
@Override
public Varargs invoke(Varargs args) { public Varargs invoke(Varargs args) {
switch (args.narg()) { switch (args.narg()) {
case 2: { case 2: {
@@ -103,7 +129,8 @@ public class TableLib extends TwoArgFunction {
LuaTable table = args.checktable(1); LuaTable table = args.checktable(1);
int pos = args.checkint(2); int pos = args.checkint(2);
int max = table.length()+1; 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)); table.insert(pos, args.arg(3));
return NONE; return NONE;
} }
@@ -116,6 +143,7 @@ public class TableLib extends TwoArgFunction {
// "pack" (...) -> table // "pack" (...) -> table
static class pack extends VarArgFunction { static class pack extends VarArgFunction {
@Override
public Varargs invoke(Varargs args) { public Varargs invoke(Varargs args) {
LuaValue t = tableOf(args, 1); LuaValue t = tableOf(args, 1);
t.set("n", args.narg()); t.set("n", args.narg());
@@ -125,6 +153,7 @@ public class TableLib extends TwoArgFunction {
// "remove" (table [, pos]) -> removed-ele // "remove" (table [, pos]) -> removed-ele
static class remove extends VarArgFunction { static class remove extends VarArgFunction {
@Override
public Varargs invoke(Varargs args) { public Varargs invoke(Varargs args) {
LuaTable table = args.checktable(1); LuaTable table = args.checktable(1);
int size = table.length(); int size = table.length();
@@ -138,16 +167,16 @@ public class TableLib extends TwoArgFunction {
// "sort" (table [, comp]) // "sort" (table [, comp])
static class sort extends VarArgFunction { static class sort extends VarArgFunction {
@Override
public Varargs invoke(Varargs args) { public Varargs invoke(Varargs args) {
args.checktable(1).sort( args.checktable(1).sort(args.isnil(2)? NIL: args.checkfunction(2));
args.isnil(2)? NIL: args.checkfunction(2));
return NONE; return NONE;
} }
} }
// "unpack", // (list [,i [,j]]) -> result1, ... // "unpack", // (list [,i [,j]]) -> result1, ...
static class unpack extends VarArgFunction { static class unpack extends VarArgFunction {
@Override
public Varargs invoke(Varargs args) { public Varargs invoke(Varargs args) {
LuaTable t = args.checktable(1); LuaTable t = args.checktable(1);
// do not waste resource for calc rawlen if arg3 is not nil // do not waste resource for calc rawlen if arg3 is not nil

View File

@@ -3,6 +3,7 @@ package org.luaj.vm2.lib;
import org.luaj.vm2.LuaValue; import org.luaj.vm2.LuaValue;
class TableLibFunction extends LibFunction { class TableLibFunction extends LibFunction {
@Override
public LuaValue call() { public LuaValue call() {
return argerror(1, "table expected, got no value"); return argerror(1, "table expected, got no value");
} }

View File

@@ -24,21 +24,24 @@ package org.luaj.vm2.lib;
import org.luaj.vm2.LuaValue; import org.luaj.vm2.LuaValue;
import org.luaj.vm2.Varargs; 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> * <p>
* Subclasses need only implement {@link LuaValue#call(LuaValue,LuaValue,LuaValue)} to complete this class, * Subclasses need only implement
* simplifying development. * {@link LuaValue#call(LuaValue,LuaValue,LuaValue)} to complete this class,
* All other uses of {@link #call()}, {@link #invoke(Varargs)},etc, * simplifying development. All other uses of {@link #call()},
* are routed through this method by this class, * {@link #invoke(Varargs)},etc, are routed through this method by this class,
* dropping or extending arguments with {@code nil} values as required. * dropping or extending arguments with {@code nil} values as required.
* <p> * <p>
* If more or less than three arguments are required, * If more or less than three arguments are required, or variable argument or
* or variable argument or variable return values, * variable return values, then use one of the related function
* then use one of the related function * {@link ZeroArgFunction}, {@link OneArgFunction}, {@link TwoArgFunction}, or
* {@link ZeroArgFunction}, {@link OneArgFunction}, {@link TwoArgFunction}, or {@link VarArgFunction}. * {@link VarArgFunction}.
* <p> * <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 #call(LuaValue,LuaValue,LuaValue)
* @see LibFunction * @see LibFunction
* @see ZeroArgFunction * @see ZeroArgFunction
@@ -48,24 +51,29 @@ import org.luaj.vm2.Varargs;
*/ */
abstract public class ThreeArgFunction extends LibFunction { abstract public class ThreeArgFunction extends LibFunction {
@Override
abstract public LuaValue call(LuaValue arg1, LuaValue arg2, LuaValue arg3); abstract public LuaValue call(LuaValue arg1, LuaValue arg2, LuaValue arg3);
/** Default constructor */ /** Default constructor */
public ThreeArgFunction() { public ThreeArgFunction() {
} }
@Override
public final LuaValue call() { public final LuaValue call() {
return call(NIL, NIL, NIL); return call(NIL, NIL, NIL);
} }
@Override
public final LuaValue call(LuaValue arg) { public final LuaValue call(LuaValue arg) {
return call(arg, NIL, NIL); return call(arg, NIL, NIL);
} }
@Override
public LuaValue call(LuaValue arg1, LuaValue arg2) { public LuaValue call(LuaValue arg1, LuaValue arg2) {
return call(arg1, arg2, NIL); return call(arg1, arg2, NIL);
} }
@Override
public Varargs invoke(Varargs varargs) { public Varargs invoke(Varargs varargs) {
return call(varargs.arg1(), varargs.arg(2), varargs.arg(3)); return call(varargs.arg1(), varargs.arg(2), varargs.arg(3));
} }

View File

@@ -24,21 +24,24 @@ package org.luaj.vm2.lib;
import org.luaj.vm2.LuaValue; import org.luaj.vm2.LuaValue;
import org.luaj.vm2.Varargs; 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> * <p>
* Subclasses need only implement {@link LuaValue#call(LuaValue,LuaValue)} to complete this class, * Subclasses need only implement {@link LuaValue#call(LuaValue,LuaValue)} to
* simplifying development. * complete this class, simplifying development. All other uses of
* All other uses of {@link #call()}, {@link #invoke(Varargs)},etc, * {@link #call()}, {@link #invoke(Varargs)},etc, are routed through this method
* are routed through this method by this class, * by this class, dropping or extending arguments with {@code nil} values as
* dropping or extending arguments with {@code nil} values as required. * required.
* <p> * <p>
* If more or less than two arguments are required, * If more or less than two arguments are required, or variable argument or
* or variable argument or variable return values, * variable return values, then use one of the related function
* then use one of the related function * {@link ZeroArgFunction}, {@link OneArgFunction}, {@link ThreeArgFunction}, or
* {@link ZeroArgFunction}, {@link OneArgFunction}, {@link ThreeArgFunction}, or {@link VarArgFunction}. * {@link VarArgFunction}.
* <p> * <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 #call(LuaValue,LuaValue)
* @see LibFunction * @see LibFunction
* @see ZeroArgFunction * @see ZeroArgFunction
@@ -48,24 +51,29 @@ import org.luaj.vm2.Varargs;
*/ */
abstract public class TwoArgFunction extends LibFunction { abstract public class TwoArgFunction extends LibFunction {
@Override
abstract public LuaValue call(LuaValue arg1, LuaValue arg2); abstract public LuaValue call(LuaValue arg1, LuaValue arg2);
/** Default constructor */ /** Default constructor */
public TwoArgFunction() { public TwoArgFunction() {
} }
@Override
public final LuaValue call() { public final LuaValue call() {
return call(NIL, NIL); return call(NIL, NIL);
} }
@Override
public final LuaValue call(LuaValue arg) { public final LuaValue call(LuaValue arg) {
return call(arg, NIL); return call(arg, NIL);
} }
@Override
public LuaValue call(LuaValue arg1, LuaValue arg2, LuaValue arg3) { public LuaValue call(LuaValue arg1, LuaValue arg2, LuaValue arg3) {
return call(arg1, arg2); return call(arg1, arg2);
} }
@Override
public Varargs invoke(Varargs varargs) { public Varargs invoke(Varargs varargs) {
return call(varargs.arg1(), varargs.arg(2)); return call(varargs.arg1(), varargs.arg(2));
} }

View File

@@ -24,20 +24,23 @@ package org.luaj.vm2.lib;
import org.luaj.vm2.LuaValue; import org.luaj.vm2.LuaValue;
import org.luaj.vm2.Varargs; 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> * <p>
* Subclasses need only implement {@link LuaValue#invoke(Varargs)} to complete this class, * Subclasses need only implement {@link LuaValue#invoke(Varargs)} to complete
* simplifying development. * this class, simplifying development. All other uses of
* All other uses of {@link #call(LuaValue)}, {@link #invoke()},etc, * {@link #call(LuaValue)}, {@link #invoke()},etc, are routed through this
* are routed through this method by this class, * method by this class, converting arguments to {@link Varargs} and dropping or
* converting arguments to {@link Varargs} and * extending return values with {@code nil} values as required.
* dropping or extending return values with {@code nil} values as required.
* <p> * <p>
* If between one and three arguments are required, and only one return value is returned, * If between one and three arguments are required, and only one return value is
* {@link ZeroArgFunction}, {@link OneArgFunction}, {@link TwoArgFunction}, or {@link ThreeArgFunction}. * returned, {@link ZeroArgFunction}, {@link OneArgFunction},
* {@link TwoArgFunction}, or {@link ThreeArgFunction}.
* <p> * <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 #invoke(Varargs)
* @see LibFunction * @see LibFunction
* @see ZeroArgFunction * @see ZeroArgFunction
@@ -50,33 +53,39 @@ abstract public class VarArgFunction extends LibFunction {
public VarArgFunction() { public VarArgFunction() {
} }
@Override
public LuaValue call() { public LuaValue call() {
return invoke(NONE).arg1(); return invoke(NONE).arg1();
} }
@Override
public LuaValue call(LuaValue arg) { public LuaValue call(LuaValue arg) {
return invoke(arg).arg1(); return invoke(arg).arg1();
} }
@Override
public LuaValue call(LuaValue arg1, LuaValue arg2) { public LuaValue call(LuaValue arg1, LuaValue arg2) {
return invoke(varargsOf(arg1, arg2)).arg1(); return invoke(varargsOf(arg1, arg2)).arg1();
} }
@Override
public LuaValue call(LuaValue arg1, LuaValue arg2, LuaValue arg3) { public LuaValue call(LuaValue arg1, LuaValue arg2, LuaValue arg3) {
return invoke(varargsOf(arg1, arg2, arg3)).arg1(); return invoke(varargsOf(arg1, arg2, arg3)).arg1();
} }
/** /**
* Subclass responsibility. * Subclass responsibility. May not have expected behavior for tail calls.
* May not have expected behavior for tail calls. * Should not be used if: - function has a possibility of returning a
* Should not be used if: * TailcallVarargs
* - function has a possibility of returning a TailcallVarargs *
* @param args the arguments to the function call. * @param args the arguments to the function call.
*/ */
@Override
public Varargs invoke(Varargs args) { public Varargs invoke(Varargs args) {
return onInvoke(args).eval(); return onInvoke(args).eval();
} }
@Override
public Varargs onInvoke(Varargs args) { public Varargs onInvoke(Varargs args) {
return invoke(args); return invoke(args);
} }

View File

@@ -24,19 +24,21 @@ package org.luaj.vm2.lib;
import org.luaj.vm2.LuaValue; import org.luaj.vm2.LuaValue;
import org.luaj.vm2.Varargs; 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> * <p>
* Subclasses need only implement {@link LuaValue#call()} to complete this class, * Subclasses need only implement {@link LuaValue#call()} to complete this
* simplifying development. * class, simplifying development. All other uses of {@link #call(LuaValue)},
* All other uses of {@link #call(LuaValue)}, {@link #invoke(Varargs)},etc, * {@link #invoke(Varargs)},etc, are routed through this method by this class.
* are routed through this method by this class.
* <p> * <p>
* If one or more arguments are required, or variable argument or variable return values, * If one or more arguments are required, or variable argument or variable
* then use one of the related function * return values, then use one of the related function {@link OneArgFunction},
* {@link OneArgFunction}, {@link TwoArgFunction}, {@link ThreeArgFunction}, or {@link VarArgFunction}. * {@link TwoArgFunction}, {@link ThreeArgFunction}, or {@link VarArgFunction}.
* <p> * <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 #call()
* @see LibFunction * @see LibFunction
* @see OneArgFunction * @see OneArgFunction
@@ -46,24 +48,29 @@ import org.luaj.vm2.Varargs;
*/ */
abstract public class ZeroArgFunction extends LibFunction { abstract public class ZeroArgFunction extends LibFunction {
@Override
abstract public LuaValue call(); abstract public LuaValue call();
/** Default constructor */ /** Default constructor */
public ZeroArgFunction() { public ZeroArgFunction() {
} }
@Override
public LuaValue call(LuaValue arg) { public LuaValue call(LuaValue arg) {
return call(); return call();
} }
@Override
public LuaValue call(LuaValue arg1, LuaValue arg2) { public LuaValue call(LuaValue arg1, LuaValue arg2) {
return call(); return call();
} }
@Override
public LuaValue call(LuaValue arg1, LuaValue arg2, LuaValue arg3) { public LuaValue call(LuaValue arg1, LuaValue arg2, LuaValue arg3) {
return call(); return call();
} }
@Override
public Varargs invoke(Varargs varargs) { public Varargs invoke(Varargs varargs) {
return call(); return call();
} }

View File

@@ -21,33 +21,29 @@
******************************************************************************/ ******************************************************************************/
package org.luaj.vm2; package org.luaj.vm2;
import static org.junit.jupiter.api.Assertions.assertEquals;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import junit.framework.TestCase; import org.junit.jupiter.api.Test;
import org.luaj.vm2.Globals.BufferedStream; import org.luaj.vm2.Globals.BufferedStream;
class BufferedStreamTest {
public class BufferedStreamTest extends TestCase {
public BufferedStreamTest() {}
private BufferedStream NewBufferedStream(int buflen, String contents) { private BufferedStream NewBufferedStream(int buflen, String contents) {
return new BufferedStream(buflen, new ByteArrayInputStream(contents.getBytes())); return new BufferedStream(buflen, new ByteArrayInputStream(contents.getBytes()));
} }
protected void setUp() throws Exception { @Test
super.setUp(); void testReadEmptyStream() throws java.io.IOException {
}
public void testReadEmptyStream() throws java.io.IOException {
BufferedStream bs = NewBufferedStream(4, ""); BufferedStream bs = NewBufferedStream(4, "");
assertEquals(-1, bs.read()); assertEquals(-1, bs.read());
assertEquals(-1, bs.read(new byte[10])); assertEquals(-1, bs.read(new byte[10]));
assertEquals(-1, bs.read(new byte[10], 0, 10)); assertEquals(-1, bs.read(new byte[10], 0, 10));
} }
public void testReadByte() throws java.io.IOException { @Test
void testReadByte() throws java.io.IOException {
BufferedStream bs = NewBufferedStream(2, "abc"); BufferedStream bs = NewBufferedStream(2, "abc");
assertEquals('a', bs.read()); assertEquals('a', bs.read());
assertEquals('b', bs.read()); assertEquals('b', bs.read());
@@ -55,7 +51,8 @@ public class BufferedStreamTest extends TestCase {
assertEquals(-1, bs.read()); assertEquals(-1, bs.read());
} }
public void testReadByteArray() throws java.io.IOException { @Test
void testReadByteArray() throws java.io.IOException {
byte[] array = new byte[3]; byte[] array = new byte[3];
BufferedStream bs = NewBufferedStream(4, "abcdef"); BufferedStream bs = NewBufferedStream(4, "abcdef");
assertEquals(3, bs.read(array)); assertEquals(3, bs.read(array));
@@ -67,7 +64,8 @@ public class BufferedStreamTest extends TestCase {
assertEquals(-1, bs.read()); assertEquals(-1, bs.read());
} }
public void testReadByteArrayOffsetLength() throws java.io.IOException { @Test
void testReadByteArrayOffsetLength() throws java.io.IOException {
byte[] array = new byte[10]; byte[] array = new byte[10];
BufferedStream bs = NewBufferedStream(8, "abcdefghijklmn"); BufferedStream bs = NewBufferedStream(8, "abcdefghijklmn");
assertEquals(4, bs.read(array, 0, 4)); assertEquals(4, bs.read(array, 0, 4));
@@ -79,7 +77,8 @@ public class BufferedStreamTest extends TestCase {
assertEquals(-1, bs.read()); assertEquals(-1, bs.read());
} }
public void testMarkOffsetBeginningOfStream() throws java.io.IOException { @Test
void testMarkOffsetBeginningOfStream() throws java.io.IOException {
byte[] array = new byte[4]; byte[] array = new byte[4];
BufferedStream bs = NewBufferedStream(8, "abcdefghijkl"); BufferedStream bs = NewBufferedStream(8, "abcdefghijkl");
assertEquals(true, bs.markSupported()); assertEquals(true, bs.markSupported());
@@ -96,7 +95,8 @@ public class BufferedStreamTest extends TestCase {
assertEquals(-1, bs.read()); assertEquals(-1, bs.read());
} }
public void testMarkOffsetMiddleOfStream() throws java.io.IOException { @Test
void testMarkOffsetMiddleOfStream() throws java.io.IOException {
byte[] array = new byte[4]; byte[] array = new byte[4];
BufferedStream bs = NewBufferedStream(8, "abcdefghijkl"); BufferedStream bs = NewBufferedStream(8, "abcdefghijkl");
assertEquals(true, bs.markSupported()); assertEquals(true, bs.markSupported());

View File

@@ -0,0 +1,135 @@
/*******************************************************************************
* Copyright (c) 2009 Luaj.org. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
******************************************************************************/
package org.luaj.vm2;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.fail;
import java.lang.reflect.InvocationTargetException;
import org.junit.jupiter.api.Test;
import org.luaj.vm2.TypeTest.MyData;
import org.luaj.vm2.lib.ZeroArgFunction;
class LuaOperationsTest {
private final int sampleint = 77;
private final long samplelong = 123400000000L;
private final double sampledouble = 55.25;
private final String samplestringstring = "abcdef";
private final String samplestringint = String.valueOf(sampleint);
private final String samplestringlong = String.valueOf(samplelong);
private final String samplestringdouble = String.valueOf(sampledouble);
private final Object sampleobject = new Object();
private final MyData sampledata = new MyData();
private final LuaValue somenil = LuaValue.NIL;
private final LuaValue sometrue = LuaValue.TRUE;
private final LuaValue somefalse = LuaValue.FALSE;
private final LuaValue zero = LuaValue.ZERO;
private final LuaValue intint = LuaValue.valueOf(sampleint);
private final LuaValue longdouble = LuaValue.valueOf(samplelong);
private final LuaValue doubledouble = LuaValue.valueOf(sampledouble);
private final LuaValue stringstring = LuaValue.valueOf(samplestringstring);
private final LuaValue stringint = LuaValue.valueOf(samplestringint);
private final LuaValue stringlong = LuaValue.valueOf(samplestringlong);
private final LuaValue stringdouble = LuaValue.valueOf(samplestringdouble);
private final LuaTable table = LuaValue
.listOf(new LuaValue[] { LuaValue.valueOf("aaa"), LuaValue.valueOf("bbb") });
private final LuaValue somefunc = new ZeroArgFunction() {
@Override
public LuaValue call() { return NONE; }
};
private final LuaThread thread = new LuaThread(new Globals(), somefunc);
private final Prototype proto = new Prototype(1);
private final LuaClosure someclosure = new LuaClosure(proto, table);
private final LuaUserdata userdataobj = LuaValue.userdataOf(sampleobject);
private final LuaUserdata userdatacls = LuaValue.userdataOf(sampledata);
private void throwsLuaError(String methodName, Object obj) {
try {
LuaValue.class.getMethod(methodName).invoke(obj);
fail("failed to throw LuaError as required");
} catch (InvocationTargetException e) {
if (!(e.getTargetException() instanceof LuaError))
fail("not a LuaError: " + e.getTargetException());
return; // pass
} catch (Exception e) {
fail("bad exception: " + e);
}
}
private void throwsLuaError(String methodName, Object obj, Object arg) {
try {
LuaValue.class.getMethod(methodName, LuaValue.class).invoke(obj, arg);
fail("failed to throw LuaError as required");
} catch (InvocationTargetException e) {
if (!(e.getTargetException() instanceof LuaError))
fail("not a LuaError: " + e.getTargetException());
return; // pass
} catch (Exception e) {
fail("bad exception: " + e);
}
}
@Test
void testLen() {
throwsLuaError("len", somenil);
throwsLuaError("len", sometrue);
throwsLuaError("len", somefalse);
throwsLuaError("len", zero);
throwsLuaError("len", intint);
throwsLuaError("len", longdouble);
throwsLuaError("len", doubledouble);
assertEquals(LuaInteger.valueOf(samplestringstring.length()), stringstring.len());
assertEquals(LuaInteger.valueOf(samplestringint.length()), stringint.len());
assertEquals(LuaInteger.valueOf(samplestringlong.length()), stringlong.len());
assertEquals(LuaInteger.valueOf(samplestringdouble.length()), stringdouble.len());
assertEquals(LuaInteger.valueOf(2), table.len());
throwsLuaError("len", somefunc);
throwsLuaError("len", thread);
throwsLuaError("len", someclosure);
throwsLuaError("len", userdataobj);
throwsLuaError("len", userdatacls);
}
@Test
void testLength() {
throwsLuaError("length", somenil);
throwsLuaError("length", sometrue);
throwsLuaError("length", somefalse);
throwsLuaError("length", zero);
throwsLuaError("length", intint);
throwsLuaError("length", longdouble);
throwsLuaError("length", doubledouble);
assertEquals(samplestringstring.length(), stringstring.length());
assertEquals(samplestringint.length(), stringint.length());
assertEquals(samplestringlong.length(), stringlong.length());
assertEquals(samplestringdouble.length(), stringdouble.length());
assertEquals(2, table.length());
throwsLuaError("length", somefunc);
throwsLuaError("length", thread);
throwsLuaError("length", someclosure);
throwsLuaError("length", userdataobj);
throwsLuaError("length", userdatacls);
}
}

View File

@@ -0,0 +1,372 @@
/*******************************************************************************
* Copyright (c) 2009 Luaj.org. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
******************************************************************************/
package org.luaj.vm2;
import static org.junit.jupiter.api.Assertions.assertEquals;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.luaj.vm2.TypeTest.MyData;
import org.luaj.vm2.lib.StringLib;
import org.luaj.vm2.lib.ThreeArgFunction;
import org.luaj.vm2.lib.TwoArgFunction;
import org.luaj.vm2.lib.ZeroArgFunction;
class MetatableTest {
private final String samplestring = "abcdef";
private final Object sampleobject = new Object();
private final MyData sampledata = new MyData();
private final LuaValue string = LuaValue.valueOf(samplestring);
private final LuaTable table = LuaValue.tableOf();
private final LuaFunction function = new ZeroArgFunction() {
@Override
public LuaValue call() { return NONE; }
};
private final LuaThread thread = new LuaThread(new Globals(), function);
private final LuaClosure closure = new LuaClosure(new Prototype(), new LuaTable());
private final LuaUserdata userdata = LuaValue.userdataOf(sampleobject);
private final LuaUserdata userdatamt = LuaValue.userdataOf(sampledata, table);
@BeforeEach
protected void setUp() throws Exception {
// needed for metatable ops to work on strings
new StringLib();
}
@AfterEach
protected void tearDown() throws Exception {
LuaBoolean.s_metatable = null;
LuaFunction.s_metatable = null;
LuaNil.s_metatable = null;
LuaNumber.s_metatable = null;
// LuaString.s_metatable = null;
LuaThread.s_metatable = null;
}
@Test
void testGetMetatable() {
assertEquals(null, LuaValue.NIL.getmetatable());
assertEquals(null, LuaValue.TRUE.getmetatable());
assertEquals(null, LuaValue.ONE.getmetatable());
// assertEquals( null, string.getmetatable() );
assertEquals(null, table.getmetatable());
assertEquals(null, function.getmetatable());
assertEquals(null, thread.getmetatable());
assertEquals(null, closure.getmetatable());
assertEquals(null, userdata.getmetatable());
assertEquals(table, userdatamt.getmetatable());
}
@Test
void testSetMetatable() {
LuaValue mt = LuaValue.tableOf();
assertEquals(null, table.getmetatable());
assertEquals(null, userdata.getmetatable());
assertEquals(table, userdatamt.getmetatable());
assertEquals(table, table.setmetatable(mt));
assertEquals(userdata, userdata.setmetatable(mt));
assertEquals(userdatamt, userdatamt.setmetatable(mt));
assertEquals(mt, table.getmetatable());
assertEquals(mt, userdata.getmetatable());
assertEquals(mt, userdatamt.getmetatable());
// these all get metatable behind-the-scenes
assertEquals(null, LuaValue.NIL.getmetatable());
assertEquals(null, LuaValue.TRUE.getmetatable());
assertEquals(null, LuaValue.ONE.getmetatable());
// assertEquals( null, string.getmetatable() );
assertEquals(null, function.getmetatable());
assertEquals(null, thread.getmetatable());
assertEquals(null, closure.getmetatable());
LuaNil.s_metatable = mt;
assertEquals(mt, LuaValue.NIL.getmetatable());
assertEquals(null, LuaValue.TRUE.getmetatable());
assertEquals(null, LuaValue.ONE.getmetatable());
// assertEquals( null, string.getmetatable() );
assertEquals(null, function.getmetatable());
assertEquals(null, thread.getmetatable());
assertEquals(null, closure.getmetatable());
LuaBoolean.s_metatable = mt;
assertEquals(mt, LuaValue.TRUE.getmetatable());
assertEquals(null, LuaValue.ONE.getmetatable());
// assertEquals( null, string.getmetatable() );
assertEquals(null, function.getmetatable());
assertEquals(null, thread.getmetatable());
assertEquals(null, closure.getmetatable());
LuaNumber.s_metatable = mt;
assertEquals(mt, LuaValue.ONE.getmetatable());
assertEquals(mt, LuaValue.valueOf(1.25).getmetatable());
// assertEquals( null, string.getmetatable() );
assertEquals(null, function.getmetatable());
assertEquals(null, thread.getmetatable());
assertEquals(null, closure.getmetatable());
// LuaString.s_metatable = mt;
// assertEquals( mt, string.getmetatable() );
assertEquals(null, function.getmetatable());
assertEquals(null, thread.getmetatable());
assertEquals(null, closure.getmetatable());
LuaFunction.s_metatable = mt;
assertEquals(mt, function.getmetatable());
assertEquals(null, thread.getmetatable());
LuaThread.s_metatable = mt;
assertEquals(mt, thread.getmetatable());
}
@Test
void testMetatableIndex() {
assertEquals(table, table.setmetatable(null));
assertEquals(userdata, userdata.setmetatable(null));
assertEquals(userdatamt, userdatamt.setmetatable(null));
assertEquals(LuaValue.NIL, table.get(1));
assertEquals(LuaValue.NIL, userdata.get(1));
assertEquals(LuaValue.NIL, userdatamt.get(1));
// empty metatable
LuaValue mt = LuaValue.tableOf();
assertEquals(table, table.setmetatable(mt));
assertEquals(userdata, userdata.setmetatable(mt));
LuaBoolean.s_metatable = mt;
LuaFunction.s_metatable = mt;
LuaNil.s_metatable = mt;
LuaNumber.s_metatable = mt;
// LuaString.s_metatable = mt;
LuaThread.s_metatable = mt;
assertEquals(mt, table.getmetatable());
assertEquals(mt, userdata.getmetatable());
assertEquals(mt, LuaValue.NIL.getmetatable());
assertEquals(mt, LuaValue.TRUE.getmetatable());
assertEquals(mt, LuaValue.ONE.getmetatable());
// assertEquals( StringLib.instance, string.getmetatable() );
assertEquals(mt, function.getmetatable());
assertEquals(mt, thread.getmetatable());
// plain metatable
LuaValue abc = LuaValue.valueOf("abc");
mt.set(LuaValue.INDEX, LuaValue.listOf(new LuaValue[] { abc }));
assertEquals(abc, table.get(1));
assertEquals(abc, userdata.get(1));
assertEquals(abc, LuaValue.NIL.get(1));
assertEquals(abc, LuaValue.TRUE.get(1));
assertEquals(abc, LuaValue.ONE.get(1));
// assertEquals( abc, string.get(1) );
assertEquals(abc, function.get(1));
assertEquals(abc, thread.get(1));
// plain metatable
mt.set(LuaValue.INDEX, new TwoArgFunction() {
@Override
public LuaValue call(LuaValue arg1, LuaValue arg2) {
return LuaValue.valueOf(arg1.typename() + "[" + arg2.tojstring() + "]=xyz");
}
});
assertEquals("table[1]=xyz", table.get(1).tojstring());
assertEquals("userdata[1]=xyz", userdata.get(1).tojstring());
assertEquals("nil[1]=xyz", LuaValue.NIL.get(1).tojstring());
assertEquals("boolean[1]=xyz", LuaValue.TRUE.get(1).tojstring());
assertEquals("number[1]=xyz", LuaValue.ONE.get(1).tojstring());
// assertEquals( "string[1]=xyz", string.get(1).tojstring() );
assertEquals("function[1]=xyz", function.get(1).tojstring());
assertEquals("thread[1]=xyz", thread.get(1).tojstring());
}
@Test
void testMetatableNewIndex() {
// empty metatable
LuaValue mt = LuaValue.tableOf();
assertEquals(table, table.setmetatable(mt));
assertEquals(userdata, userdata.setmetatable(mt));
LuaBoolean.s_metatable = mt;
LuaFunction.s_metatable = mt;
LuaNil.s_metatable = mt;
LuaNumber.s_metatable = mt;
// LuaString.s_metatable = mt;
LuaThread.s_metatable = mt;
// plain metatable
final LuaValue fallback = LuaValue.tableOf();
LuaValue abc = LuaValue.valueOf("abc");
mt.set(LuaValue.NEWINDEX, fallback);
table.set(2, abc);
userdata.set(3, abc);
LuaValue.NIL.set(4, abc);
LuaValue.TRUE.set(5, abc);
LuaValue.ONE.set(6, abc);
// string.set(7,abc);
function.set(8, abc);
thread.set(9, abc);
assertEquals(abc, fallback.get(2));
assertEquals(abc, fallback.get(3));
assertEquals(abc, fallback.get(4));
assertEquals(abc, fallback.get(5));
assertEquals(abc, fallback.get(6));
// assertEquals( abc, StringLib.instance.get(7) );
assertEquals(abc, fallback.get(8));
assertEquals(abc, fallback.get(9));
// metatable with function call
mt.set(LuaValue.NEWINDEX, new ThreeArgFunction() {
@Override
public LuaValue call(LuaValue arg1, LuaValue arg2, LuaValue arg3) {
fallback.rawset(arg2, LuaValue.valueOf("via-func-" + arg3));
return NONE;
}
});
table.set(12, abc);
userdata.set(13, abc);
LuaValue.NIL.set(14, abc);
LuaValue.TRUE.set(15, abc);
LuaValue.ONE.set(16, abc);
// string.set(17,abc);
function.set(18, abc);
thread.set(19, abc);
LuaValue via = LuaValue.valueOf("via-func-abc");
assertEquals(via, fallback.get(12));
assertEquals(via, fallback.get(13));
assertEquals(via, fallback.get(14));
assertEquals(via, fallback.get(15));
assertEquals(via, fallback.get(16));
// assertEquals( via, StringLib.instance.get(17) );
assertEquals(via, fallback.get(18));
assertEquals(via, fallback.get(19));
}
private void checkTable(LuaValue t, LuaValue aa, LuaValue bb, LuaValue cc, LuaValue dd, LuaValue ee, LuaValue ff,
LuaValue gg, LuaValue ra, LuaValue rb, LuaValue rc, LuaValue rd, LuaValue re, LuaValue rf, LuaValue rg) {
assertEquals(aa, t.get("aa"));
assertEquals(bb, t.get("bb"));
assertEquals(cc, t.get("cc"));
assertEquals(dd, t.get("dd"));
assertEquals(ee, t.get("ee"));
assertEquals(ff, t.get("ff"));
assertEquals(gg, t.get("gg"));
assertEquals(ra, t.rawget("aa"));
assertEquals(rb, t.rawget("bb"));
assertEquals(rc, t.rawget("cc"));
assertEquals(rd, t.rawget("dd"));
assertEquals(re, t.rawget("ee"));
assertEquals(rf, t.rawget("ff"));
assertEquals(rg, t.rawget("gg"));
}
private LuaValue makeTable(String key1, String val1, String key2, String val2) {
return LuaValue.tableOf(new LuaValue[] { LuaValue.valueOf(key1), LuaValue.valueOf(val1), LuaValue.valueOf(key2),
LuaValue.valueOf(val2), });
}
@Test
void testRawsetMetatableSet() {
// set up tables
LuaValue m = makeTable("aa", "aaa", "bb", "bbb");
m.set(LuaValue.INDEX, m);
m.set(LuaValue.NEWINDEX, m);
LuaValue s = makeTable("cc", "ccc", "dd", "ddd");
LuaValue t = makeTable("cc", "ccc", "dd", "ddd");
t.setmetatable(m);
LuaValue aaa = LuaValue.valueOf("aaa");
LuaValue bbb = LuaValue.valueOf("bbb");
LuaValue ccc = LuaValue.valueOf("ccc");
LuaValue ddd = LuaValue.valueOf("ddd");
LuaValue ppp = LuaValue.valueOf("ppp");
LuaValue qqq = LuaValue.valueOf("qqq");
LuaValue rrr = LuaValue.valueOf("rrr");
LuaValue sss = LuaValue.valueOf("sss");
LuaValue ttt = LuaValue.valueOf("ttt");
LuaValue www = LuaValue.valueOf("www");
LuaValue xxx = LuaValue.valueOf("xxx");
LuaValue yyy = LuaValue.valueOf("yyy");
LuaValue zzz = LuaValue.valueOf("zzz");
LuaValue nil = LuaValue.NIL;
// check initial values
// values via "bet()" values via "rawget()"
checkTable(s, nil, nil, ccc, ddd, nil, nil, nil, nil, nil, ccc, ddd, nil, nil, nil);
checkTable(t, aaa, bbb, ccc, ddd, nil, nil, nil, nil, nil, ccc, ddd, nil, nil, nil);
checkTable(m, aaa, bbb, nil, nil, nil, nil, nil, aaa, bbb, nil, nil, nil, nil, nil);
// rawset()
s.rawset("aa", www);
checkTable(s, www, nil, ccc, ddd, nil, nil, nil, www, nil, ccc, ddd, nil, nil, nil);
checkTable(t, aaa, bbb, ccc, ddd, nil, nil, nil, nil, nil, ccc, ddd, nil, nil, nil);
checkTable(m, aaa, bbb, nil, nil, nil, nil, nil, aaa, bbb, nil, nil, nil, nil, nil);
s.rawset("cc", xxx);
checkTable(s, www, nil, xxx, ddd, nil, nil, nil, www, nil, xxx, ddd, nil, nil, nil);
checkTable(t, aaa, bbb, ccc, ddd, nil, nil, nil, nil, nil, ccc, ddd, nil, nil, nil);
checkTable(m, aaa, bbb, nil, nil, nil, nil, nil, aaa, bbb, nil, nil, nil, nil, nil);
t.rawset("bb", yyy);
checkTable(s, www, nil, xxx, ddd, nil, nil, nil, www, nil, xxx, ddd, nil, nil, nil);
checkTable(t, aaa, yyy, ccc, ddd, nil, nil, nil, nil, yyy, ccc, ddd, nil, nil, nil);
checkTable(m, aaa, bbb, nil, nil, nil, nil, nil, aaa, bbb, nil, nil, nil, nil, nil);
t.rawset("dd", zzz);
checkTable(s, www, nil, xxx, ddd, nil, nil, nil, www, nil, xxx, ddd, nil, nil, nil);
checkTable(t, aaa, yyy, ccc, zzz, nil, nil, nil, nil, yyy, ccc, zzz, nil, nil, nil);
checkTable(m, aaa, bbb, nil, nil, nil, nil, nil, aaa, bbb, nil, nil, nil, nil, nil);
// set() invoking metatables
s.set("ee", ppp);
checkTable(s, www, nil, xxx, ddd, ppp, nil, nil, www, nil, xxx, ddd, ppp, nil, nil);
checkTable(t, aaa, yyy, ccc, zzz, nil, nil, nil, nil, yyy, ccc, zzz, nil, nil, nil);
checkTable(m, aaa, bbb, nil, nil, nil, nil, nil, aaa, bbb, nil, nil, nil, nil, nil);
s.set("cc", qqq);
checkTable(s, www, nil, qqq, ddd, ppp, nil, nil, www, nil, qqq, ddd, ppp, nil, nil);
checkTable(t, aaa, yyy, ccc, zzz, nil, nil, nil, nil, yyy, ccc, zzz, nil, nil, nil);
checkTable(m, aaa, bbb, nil, nil, nil, nil, nil, aaa, bbb, nil, nil, nil, nil, nil);
t.set("ff", rrr);
checkTable(s, www, nil, qqq, ddd, ppp, nil, nil, www, nil, qqq, ddd, ppp, nil, nil);
checkTable(t, aaa, yyy, ccc, zzz, nil, rrr, nil, nil, yyy, ccc, zzz, nil, nil, nil);
checkTable(m, aaa, bbb, nil, nil, nil, rrr, nil, aaa, bbb, nil, nil, nil, rrr, nil);
t.set("dd", sss);
checkTable(s, www, nil, qqq, ddd, ppp, nil, nil, www, nil, qqq, ddd, ppp, nil, nil);
checkTable(t, aaa, yyy, ccc, sss, nil, rrr, nil, nil, yyy, ccc, sss, nil, nil, nil);
checkTable(m, aaa, bbb, nil, nil, nil, rrr, nil, aaa, bbb, nil, nil, nil, rrr, nil);
m.set("gg", ttt);
checkTable(s, www, nil, qqq, ddd, ppp, nil, nil, www, nil, qqq, ddd, ppp, nil, nil);
checkTable(t, aaa, yyy, ccc, sss, nil, rrr, ttt, nil, yyy, ccc, sss, nil, nil, nil);
checkTable(m, aaa, bbb, nil, nil, nil, rrr, ttt, aaa, bbb, nil, nil, nil, rrr, ttt);
// make s fall back to t
s.setmetatable(LuaValue.tableOf(new LuaValue[] { LuaValue.INDEX, t, LuaValue.NEWINDEX, t }));
checkTable(s, www, yyy, qqq, ddd, ppp, rrr, ttt, www, nil, qqq, ddd, ppp, nil, nil);
checkTable(t, aaa, yyy, ccc, sss, nil, rrr, ttt, nil, yyy, ccc, sss, nil, nil, nil);
checkTable(m, aaa, bbb, nil, nil, nil, rrr, ttt, aaa, bbb, nil, nil, nil, rrr, ttt);
s.set("aa", www);
checkTable(s, www, yyy, qqq, ddd, ppp, rrr, ttt, www, nil, qqq, ddd, ppp, nil, nil);
checkTable(t, aaa, yyy, ccc, sss, nil, rrr, ttt, nil, yyy, ccc, sss, nil, nil, nil);
checkTable(m, aaa, bbb, nil, nil, nil, rrr, ttt, aaa, bbb, nil, nil, nil, rrr, ttt);
s.set("bb", zzz);
checkTable(s, www, zzz, qqq, ddd, ppp, rrr, ttt, www, nil, qqq, ddd, ppp, nil, nil);
checkTable(t, aaa, zzz, ccc, sss, nil, rrr, ttt, nil, zzz, ccc, sss, nil, nil, nil);
checkTable(m, aaa, bbb, nil, nil, nil, rrr, ttt, aaa, bbb, nil, nil, nil, rrr, ttt);
s.set("ee", xxx);
checkTable(s, www, zzz, qqq, ddd, xxx, rrr, ttt, www, nil, qqq, ddd, xxx, nil, nil);
checkTable(t, aaa, zzz, ccc, sss, nil, rrr, ttt, nil, zzz, ccc, sss, nil, nil, nil);
checkTable(m, aaa, bbb, nil, nil, nil, rrr, ttt, aaa, bbb, nil, nil, nil, rrr, ttt);
s.set("ff", yyy);
checkTable(s, www, zzz, qqq, ddd, xxx, yyy, ttt, www, nil, qqq, ddd, xxx, nil, nil);
checkTable(t, aaa, zzz, ccc, sss, nil, yyy, ttt, nil, zzz, ccc, sss, nil, nil, nil);
checkTable(m, aaa, bbb, nil, nil, nil, yyy, ttt, aaa, bbb, nil, nil, nil, yyy, ttt);
}
}

View File

@@ -1,20 +1,21 @@
package org.luaj.vm2; package org.luaj.vm2;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotSame;
import static org.junit.jupiter.api.Assertions.assertSame;
import static org.junit.jupiter.api.Assertions.assertTrue;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.UnsupportedEncodingException; import java.io.UnsupportedEncodingException;
import junit.framework.TestCase; import org.junit.jupiter.api.Test;
import org.luaj.vm2.lib.jse.JsePlatform; class StringTest {
public class StringTest extends TestCase { @Test
void testToInputStream() throws IOException {
protected void setUp() throws Exception {
JsePlatform.standardGlobals();
}
public void testToInputStream() throws IOException {
LuaString str = LuaString.valueOf("Hello"); LuaString str = LuaString.valueOf("Hello");
InputStream is = str.toInputStream(); InputStream is = str.toInputStream();
@@ -53,7 +54,6 @@ public class StringTest extends TestCase {
assertEquals('e', is.read()); assertEquals('e', is.read());
} }
private static final String userFriendly(String s) { private static final String userFriendly(String s) {
StringBuffer sb = new StringBuffer(); StringBuffer sb = new StringBuffer();
for (int i = 0, n = s.length(); i < n; i++) { for (int i = 0, n = s.length(); i < n; i++) {
@@ -67,7 +67,8 @@ public class StringTest extends TestCase {
return sb.toString(); return sb.toString();
} }
public void testUtf820482051() throws UnsupportedEncodingException { @Test
void testUtf820482051() throws UnsupportedEncodingException {
int i = 2048; int i = 2048;
char[] c = { (char) (i+0), (char) (i+1), (char) (i+2), (char) (i+3) }; char[] c = { (char) (i+0), (char) (i+1), (char) (i+2), (char) (i+3) };
String before = new String(c) + " " + i + "-" + (i+4); String before = new String(c) + " " + i + "-" + (i+4);
@@ -76,8 +77,10 @@ public class StringTest extends TestCase {
assertEquals(userFriendly(before), userFriendly(after)); assertEquals(userFriendly(before), userFriendly(after));
} }
public void testUtf8() { @Test
void testUtf8() {
for (int i = 4; i < 0xffff; i += 4) { for (int i = 4; i < 0xffff; i += 4) {
if (i == 0xd800) i = 0xe000;
char[] c = { (char) (i+0), (char) (i+1), (char) (i+2), (char) (i+3) }; char[] c = { (char) (i+0), (char) (i+1), (char) (i+2), (char) (i+3) };
String before = new String(c) + " " + i + "-" + (i+4); String before = new String(c) + " " + i + "-" + (i+4);
LuaString ls = LuaString.valueOf(before); LuaString ls = LuaString.valueOf(before);
@@ -91,8 +94,10 @@ public class StringTest extends TestCase {
assertEquals(userFriendly(before), userFriendly(after)); assertEquals(userFriendly(before), userFriendly(after));
} }
public void testSpotCheckUtf8() throws UnsupportedEncodingException { @Test
byte[] bytes = {(byte)194,(byte)160,(byte)194,(byte)161,(byte)194,(byte)162,(byte)194,(byte)163,(byte)194,(byte)164}; void testSpotCheckUtf8() throws UnsupportedEncodingException {
byte[] bytes = { (byte) 194, (byte) 160, (byte) 194, (byte) 161, (byte) 194, (byte) 162, (byte) 194, (byte) 163,
(byte) 194, (byte) 164 };
String expected = new String(bytes, "UTF8"); String expected = new String(bytes, "UTF8");
String actual = LuaString.valueOf(bytes).tojstring(); String actual = LuaString.valueOf(bytes).tojstring();
char[] d = actual.toCharArray(); char[] d = actual.toCharArray();
@@ -104,7 +109,8 @@ public class StringTest extends TestCase {
assertEquals(expected, actual); assertEquals(expected, actual);
} }
public void testNullTerminated() { @Test
void testNullTerminated() {
char[] c = { 'a', 'b', 'c', '\0', 'd', 'e', 'f' }; char[] c = { 'a', 'b', 'c', '\0', 'd', 'e', 'f' };
String before = new String(c); String before = new String(c);
LuaString ls = LuaString.valueOf(before); LuaString ls = LuaString.valueOf(before);
@@ -112,7 +118,8 @@ public class StringTest extends TestCase {
assertEquals(userFriendly("abc\0def"), userFriendly(after)); assertEquals(userFriendly("abc\0def"), userFriendly(after));
} }
public void testRecentStringsCacheDifferentHashcodes() { @Test
void testRecentStringsCacheDifferentHashcodes() {
final byte[] abc = { 'a', 'b', 'c' }; final byte[] abc = { 'a', 'b', 'c' };
final byte[] xyz = { 'x', 'y', 'z' }; final byte[] xyz = { 'x', 'y', 'z' };
final LuaString abc1 = LuaString.valueOf(abc); final LuaString abc1 = LuaString.valueOf(abc);
@@ -125,7 +132,8 @@ public class StringTest extends TestCase {
assertSame(xyz1, xyz2); assertSame(xyz1, xyz2);
} }
public void testRecentStringsCacheHashCollisionCacheHit() { @Test
void testRecentStringsCacheHashCollisionCacheHit() {
final byte[] abc = { 'a', 'b', 'c' }; final byte[] abc = { 'a', 'b', 'c' };
final byte[] lyz = { 'l', 'y', 'z' }; // chosen to have hash collision with 'abc' final byte[] lyz = { 'l', 'y', 'z' }; // chosen to have hash collision with 'abc'
final LuaString abc1 = LuaString.valueOf(abc); final LuaString abc1 = LuaString.valueOf(abc);
@@ -140,7 +148,8 @@ public class StringTest extends TestCase {
assertSame(lyz1, lyz2); assertSame(lyz1, lyz2);
} }
public void testRecentStringsCacheHashCollisionCacheMiss() { @Test
void testRecentStringsCacheHashCollisionCacheMiss() {
final byte[] abc = { 'a', 'b', 'c' }; final byte[] abc = { 'a', 'b', 'c' };
final byte[] lyz = { 'l', 'y', 'z' }; // chosen to have hash collision with 'abc' final byte[] lyz = { 'l', 'y', 'z' }; // chosen to have hash collision with 'abc'
final LuaString abc1 = LuaString.valueOf(abc); final LuaString abc1 = LuaString.valueOf(abc);
@@ -155,7 +164,8 @@ public class StringTest extends TestCase {
assertNotSame(lyz1, lyz2); assertNotSame(lyz1, lyz2);
} }
public void testRecentStringsLongStrings() { @Test
void testRecentStringsLongStrings() {
byte[] abc = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ".getBytes(); byte[] abc = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ".getBytes();
assertTrue(abc.length > LuaString.RECENT_STRINGS_MAX_LENGTH); assertTrue(abc.length > LuaString.RECENT_STRINGS_MAX_LENGTH);
LuaString abc1 = LuaString.valueOf(abc); LuaString abc1 = LuaString.valueOf(abc);
@@ -163,7 +173,8 @@ public class StringTest extends TestCase {
assertNotSame(abc1, abc2); assertNotSame(abc1, abc2);
} }
public void testRecentStringsUsingJavaStrings() { @Test
void testRecentStringsUsingJavaStrings() {
final String abc = "abc"; final String abc = "abc";
final String lyz = "lyz"; // chosen to have hash collision with 'abc' final String lyz = "lyz"; // chosen to have hash collision with 'abc'
final String xyz = "xyz"; final String xyz = "xyz";
@@ -193,7 +204,8 @@ public class StringTest extends TestCase {
assertSame(xyz3, xyz4); // because hashes do not collide assertSame(xyz3, xyz4); // because hashes do not collide
} }
public void testLongSubstringGetsOldBacking() { @Test
void testLongSubstringGetsOldBacking() {
LuaString src = LuaString.valueOf("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"); LuaString src = LuaString.valueOf("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ");
LuaString sub1 = src.substring(10, 40); LuaString sub1 = src.substring(10, 40);
assertSame(src.m_bytes, sub1.m_bytes); assertSame(src.m_bytes, sub1.m_bytes);
@@ -201,7 +213,8 @@ public class StringTest extends TestCase {
assertEquals(sub1.m_length, 30); assertEquals(sub1.m_length, 30);
} }
public void testShortSubstringGetsNewBacking() { @Test
void testShortSubstringGetsNewBacking() {
LuaString src = LuaString.valueOf("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"); LuaString src = LuaString.valueOf("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ");
LuaString sub1 = src.substring(10, 20); LuaString sub1 = src.substring(10, 20);
LuaString sub2 = src.substring(10, 20); LuaString sub2 = src.substring(10, 20);
@@ -211,10 +224,10 @@ public class StringTest extends TestCase {
assertFalse(src.m_bytes == sub1.m_bytes); assertFalse(src.m_bytes == sub1.m_bytes);
} }
public void testShortSubstringOfVeryLongStringGetsNewBacking() { @Test
LuaString src = LuaString.valueOf( void testShortSubstringOfVeryLongStringGetsNewBacking() {
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" + LuaString src = LuaString.valueOf("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" ); + "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ");
LuaString sub1 = src.substring(10, 50); LuaString sub1 = src.substring(10, 50);
LuaString sub2 = src.substring(10, 50); LuaString sub2 = src.substring(10, 50);
assertEquals(sub1.m_offset, 0); assertEquals(sub1.m_offset, 0);
@@ -223,7 +236,8 @@ public class StringTest extends TestCase {
assertFalse(src.m_bytes == sub1.m_bytes); assertFalse(src.m_bytes == sub1.m_bytes);
} }
public void testIndexOfByteInSubstring() { @Test
void testIndexOfByteInSubstring() {
LuaString str = LuaString.valueOf("abcdef:ghi"); LuaString str = LuaString.valueOf("abcdef:ghi");
LuaString sub = str.substring(2, 10); LuaString sub = str.substring(2, 10);
assertEquals(10, str.m_length); assertEquals(10, str.m_length);
@@ -256,7 +270,8 @@ public class StringTest extends TestCase {
assertEquals(-1, sub.indexOf((byte) 'z', 7)); assertEquals(-1, sub.indexOf((byte) 'z', 7));
} }
public void testIndexOfPatternInSubstring() { @Test
void testIndexOfPatternInSubstring() {
LuaString str = LuaString.valueOf("abcdef:ghi"); LuaString str = LuaString.valueOf("abcdef:ghi");
LuaString sub = str.substring(2, 10); LuaString sub = str.substring(2, 10);
assertEquals(10, str.m_length); assertEquals(10, str.m_length);
@@ -293,7 +308,8 @@ public class StringTest extends TestCase {
assertEquals(-1, sub.indexOf(xyz, 7)); assertEquals(-1, sub.indexOf(xyz, 7));
} }
public void testLastIndexOfPatternInSubstring() { @Test
void testLastIndexOfPatternInSubstring() {
LuaString str = LuaString.valueOf("abcdef:ghi"); LuaString str = LuaString.valueOf("abcdef:ghi");
LuaString sub = str.substring(2, 10); LuaString sub = str.substring(2, 10);
assertEquals(10, str.m_length); assertEquals(10, str.m_length);
@@ -314,7 +330,8 @@ public class StringTest extends TestCase {
assertEquals(-1, sub.lastIndexOf(xyz)); assertEquals(-1, sub.lastIndexOf(xyz));
} }
public void testIndexOfAnyInSubstring() { @Test
void testIndexOfAnyInSubstring() {
LuaString str = LuaString.valueOf("abcdef:ghi"); LuaString str = LuaString.valueOf("abcdef:ghi");
LuaString sub = str.substring(2, 10); LuaString sub = str.substring(2, 10);
assertEquals(10, str.m_length); assertEquals(10, str.m_length);
@@ -349,33 +366,4 @@ public class StringTest extends TestCase {
assertEquals(1, sub.indexOfAny(CdEFGHIJ)); assertEquals(1, sub.indexOfAny(CdEFGHIJ));
assertEquals(-1, sub.indexOfAny(EFGHIJKL)); assertEquals(-1, sub.indexOfAny(EFGHIJKL));
} }
public void testMatchShortPatterns() {
LuaValue[] args = { LuaString.valueOf("%bxy") };
LuaString _ = LuaString.valueOf("");
LuaString a = LuaString.valueOf("a");
LuaString ax = LuaString.valueOf("ax");
LuaString axb = LuaString.valueOf("axb");
LuaString axby = LuaString.valueOf("axby");
LuaString xbya = LuaString.valueOf("xbya");
LuaString bya = LuaString.valueOf("bya");
LuaString xby = LuaString.valueOf("xby");
LuaString axbya = LuaString.valueOf("axbya");
LuaValue nil = LuaValue.NIL;
assertEquals(nil, _.invokemethod("match", args));
assertEquals(nil, a.invokemethod("match", args));
assertEquals(nil, ax.invokemethod("match", args));
assertEquals(nil, axb.invokemethod("match", args));
assertEquals(xby, axby.invokemethod("match", args));
assertEquals(xby, xbya.invokemethod("match", args));
assertEquals(nil, bya.invokemethod("match", args));
assertEquals(xby, xby.invokemethod("match", args));
assertEquals(xby, axbya.invokemethod("match", args));
assertEquals(xby, axbya.substring(0,4).invokemethod("match", args));
assertEquals(nil, axbya.substring(0,3).invokemethod("match", args));
assertEquals(xby, axbya.substring(1,5).invokemethod("match", args));
assertEquals(nil, axbya.substring(2,5).invokemethod("match", args));
}
} }

View File

@@ -0,0 +1,325 @@
/*******************************************************************************
* Copyright (c) 2009 Luaj.org. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
******************************************************************************/
package org.luaj.vm2;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
import org.junit.jupiter.api.Test;
import org.luaj.vm2.lib.TwoArgFunction;
/**
* Tests for tables used as lists.
*/
public class TableHashTest {
protected LuaTable new_Table() {
return new LuaTable();
}
protected LuaTable new_Table(int n, int m) {
return new LuaTable(n, m);
}
@Test
void testSetRemove() {
LuaTable t = new_Table();
assertEquals(0, t.getHashLength());
assertEquals(0, t.length());
assertEquals(0, t.keyCount());
String[] keys = { "abc", "def", "ghi", "jkl", "mno", "pqr", "stu", "wxy", "z01", "cd", "ef", "g", "hi", "jk",
"lm", "no", "pq", "rs", };
int[] capacities = { 0, 2, 2, 4, 4, 8, 8, 8, 8, 16, 16, 16, 16, 16, 16, 16, 16, 32, 32, 32 };
for (int i = 0; i < keys.length; ++i) {
assertEquals(capacities[i], t.getHashLength());
String si = "Test Value! " + i;
t.set(keys[i], si);
assertEquals(0, t.length());
assertEquals(i+1, t.keyCount());
}
assertEquals(capacities[keys.length], t.getHashLength());
for (int i = 0; i < keys.length; ++i) {
LuaValue vi = LuaString.valueOf("Test Value! " + i);
assertEquals(vi, t.get(keys[i]));
assertEquals(vi, t.get(LuaString.valueOf(keys[i])));
assertEquals(vi, t.rawget(keys[i]));
assertEquals(vi, t.rawget(keys[i]));
}
// replace with new values
for (int i = 0; i < keys.length; ++i) {
t.set(keys[i], LuaString.valueOf("Replacement Value! " + i));
assertEquals(0, t.length());
assertEquals(keys.length, t.keyCount());
assertEquals(capacities[keys.length], t.getHashLength());
}
for (int i = 0; i < keys.length; ++i) {
LuaValue vi = LuaString.valueOf("Replacement Value! " + i);
assertEquals(vi, t.get(keys[i]));
}
// remove
for (int i = 0; i < keys.length; ++i) {
t.set(keys[i], LuaValue.NIL);
assertEquals(0, t.length());
assertEquals(keys.length-i-1, t.keyCount());
if (i < keys.length-1)
assertEquals(capacities[keys.length], t.getHashLength());
else
assertTrue(0 <= t.getHashLength());
}
for (int i = 0; i < keys.length; ++i) {
assertEquals(LuaValue.NIL, t.get(keys[i]));
}
}
@Test
void testIndexMetatag() {
LuaTable t = new_Table();
LuaTable mt = new_Table();
LuaTable fb = new_Table();
// set basic values
t.set("ppp", "abc");
t.set(123, "def");
mt.set(LuaValue.INDEX, fb);
fb.set("qqq", "ghi");
fb.set(456, "jkl");
// check before setting metatable
assertEquals("abc", t.get("ppp").tojstring());
assertEquals("def", t.get(123).tojstring());
assertEquals("nil", t.get("qqq").tojstring());
assertEquals("nil", t.get(456).tojstring());
assertEquals("nil", fb.get("ppp").tojstring());
assertEquals("nil", fb.get(123).tojstring());
assertEquals("ghi", fb.get("qqq").tojstring());
assertEquals("jkl", fb.get(456).tojstring());
assertEquals("nil", mt.get("ppp").tojstring());
assertEquals("nil", mt.get(123).tojstring());
assertEquals("nil", mt.get("qqq").tojstring());
assertEquals("nil", mt.get(456).tojstring());
// check before setting metatable
t.setmetatable(mt);
assertEquals(mt, t.getmetatable());
assertEquals("abc", t.get("ppp").tojstring());
assertEquals("def", t.get(123).tojstring());
assertEquals("ghi", t.get("qqq").tojstring());
assertEquals("jkl", t.get(456).tojstring());
assertEquals("nil", fb.get("ppp").tojstring());
assertEquals("nil", fb.get(123).tojstring());
assertEquals("ghi", fb.get("qqq").tojstring());
assertEquals("jkl", fb.get(456).tojstring());
assertEquals("nil", mt.get("ppp").tojstring());
assertEquals("nil", mt.get(123).tojstring());
assertEquals("nil", mt.get("qqq").tojstring());
assertEquals("nil", mt.get(456).tojstring());
// set metatable to metatable without values
t.setmetatable(fb);
assertEquals("abc", t.get("ppp").tojstring());
assertEquals("def", t.get(123).tojstring());
assertEquals("nil", t.get("qqq").tojstring());
assertEquals("nil", t.get(456).tojstring());
// set metatable to null
t.setmetatable(null);
assertEquals("abc", t.get("ppp").tojstring());
assertEquals("def", t.get(123).tojstring());
assertEquals("nil", t.get("qqq").tojstring());
assertEquals("nil", t.get(456).tojstring());
}
@Test
void testIndexFunction() {
final LuaTable t = new_Table();
final LuaTable mt = new_Table();
final TwoArgFunction fb = new TwoArgFunction() {
@Override
public LuaValue call(LuaValue tbl, LuaValue key) {
assertEquals(tbl, t);
return valueOf("from mt: " + key);
}
};
// set basic values
t.set("ppp", "abc");
t.set(123, "def");
mt.set(LuaValue.INDEX, fb);
// check before setting metatable
assertEquals("abc", t.get("ppp").tojstring());
assertEquals("def", t.get(123).tojstring());
assertEquals("nil", t.get("qqq").tojstring());
assertEquals("nil", t.get(456).tojstring());
// check before setting metatable
t.setmetatable(mt);
assertEquals(mt, t.getmetatable());
assertEquals("abc", t.get("ppp").tojstring());
assertEquals("def", t.get(123).tojstring());
assertEquals("from mt: qqq", t.get("qqq").tojstring());
assertEquals("from mt: 456", t.get(456).tojstring());
// use raw set
t.rawset("qqq", "alt-qqq");
t.rawset(456, "alt-456");
assertEquals("abc", t.get("ppp").tojstring());
assertEquals("def", t.get(123).tojstring());
assertEquals("alt-qqq", t.get("qqq").tojstring());
assertEquals("alt-456", t.get(456).tojstring());
// remove using raw set
t.rawset("qqq", LuaValue.NIL);
t.rawset(456, LuaValue.NIL);
assertEquals("abc", t.get("ppp").tojstring());
assertEquals("def", t.get(123).tojstring());
assertEquals("from mt: qqq", t.get("qqq").tojstring());
assertEquals("from mt: 456", t.get(456).tojstring());
// set metatable to null
t.setmetatable(null);
assertEquals("abc", t.get("ppp").tojstring());
assertEquals("def", t.get(123).tojstring());
assertEquals("nil", t.get("qqq").tojstring());
assertEquals("nil", t.get(456).tojstring());
}
@Test
void testNext() {
final LuaTable t = new_Table();
assertEquals(LuaValue.NIL, t.next(LuaValue.NIL));
// insert array elements
t.set(1, "one");
assertEquals(LuaValue.valueOf(1), t.next(LuaValue.NIL).arg(1));
assertEquals(LuaValue.valueOf("one"), t.next(LuaValue.NIL).arg(2));
assertEquals(LuaValue.NIL, t.next(LuaValue.ONE));
t.set(2, "two");
assertEquals(LuaValue.valueOf(1), t.next(LuaValue.NIL).arg(1));
assertEquals(LuaValue.valueOf("one"), t.next(LuaValue.NIL).arg(2));
assertEquals(LuaValue.valueOf(2), t.next(LuaValue.ONE).arg(1));
assertEquals(LuaValue.valueOf("two"), t.next(LuaValue.ONE).arg(2));
assertEquals(LuaValue.NIL, t.next(LuaValue.valueOf(2)));
// insert hash elements
t.set("aa", "aaa");
assertEquals(LuaValue.valueOf(1), t.next(LuaValue.NIL).arg(1));
assertEquals(LuaValue.valueOf("one"), t.next(LuaValue.NIL).arg(2));
assertEquals(LuaValue.valueOf(2), t.next(LuaValue.ONE).arg(1));
assertEquals(LuaValue.valueOf("two"), t.next(LuaValue.ONE).arg(2));
assertEquals(LuaValue.valueOf("aa"), t.next(LuaValue.valueOf(2)).arg(1));
assertEquals(LuaValue.valueOf("aaa"), t.next(LuaValue.valueOf(2)).arg(2));
assertEquals(LuaValue.NIL, t.next(LuaValue.valueOf("aa")));
t.set("bb", "bbb");
assertEquals(LuaValue.valueOf(1), t.next(LuaValue.NIL).arg(1));
assertEquals(LuaValue.valueOf("one"), t.next(LuaValue.NIL).arg(2));
assertEquals(LuaValue.valueOf(2), t.next(LuaValue.ONE).arg(1));
assertEquals(LuaValue.valueOf("two"), t.next(LuaValue.ONE).arg(2));
assertEquals(LuaValue.valueOf("aa"), t.next(LuaValue.valueOf(2)).arg(1));
assertEquals(LuaValue.valueOf("aaa"), t.next(LuaValue.valueOf(2)).arg(2));
assertEquals(LuaValue.valueOf("bb"), t.next(LuaValue.valueOf("aa")).arg(1));
assertEquals(LuaValue.valueOf("bbb"), t.next(LuaValue.valueOf("aa")).arg(2));
assertEquals(LuaValue.NIL, t.next(LuaValue.valueOf("bb")));
}
@Test
void testLoopWithRemoval() {
final LuaTable t = new_Table();
t.set(LuaValue.valueOf(1), LuaValue.valueOf("1"));
t.set(LuaValue.valueOf(3), LuaValue.valueOf("3"));
t.set(LuaValue.valueOf(8), LuaValue.valueOf("4"));
t.set(LuaValue.valueOf(17), LuaValue.valueOf("5"));
t.set(LuaValue.valueOf(26), LuaValue.valueOf("6"));
t.set(LuaValue.valueOf(35), LuaValue.valueOf("7"));
t.set(LuaValue.valueOf(42), LuaValue.valueOf("8"));
t.set(LuaValue.valueOf(60), LuaValue.valueOf("10"));
t.set(LuaValue.valueOf(63), LuaValue.valueOf("11"));
Varargs entry = t.next(LuaValue.NIL);
while ( !entry.isnil(1) ) {
LuaValue k = entry.arg1();
LuaValue v = entry.arg(2);
if ((k.toint() & 1) == 0) {
t.set(k, LuaValue.NIL);
}
entry = t.next(k);
}
int numEntries = 0;
entry = t.next(LuaValue.NIL);
while ( !entry.isnil(1) ) {
LuaValue k = entry.arg1();
// Only odd keys should remain
assertTrue((k.toint() & 1) == 1);
numEntries++;
entry = t.next(k);
}
assertEquals(5, numEntries);
}
@Test
void testLoopWithRemovalAndSet() {
final LuaTable t = new_Table();
t.set(LuaValue.valueOf(1), LuaValue.valueOf("1"));
t.set(LuaValue.valueOf(3), LuaValue.valueOf("3"));
t.set(LuaValue.valueOf(8), LuaValue.valueOf("4"));
t.set(LuaValue.valueOf(17), LuaValue.valueOf("5"));
t.set(LuaValue.valueOf(26), LuaValue.valueOf("6"));
t.set(LuaValue.valueOf(35), LuaValue.valueOf("7"));
t.set(LuaValue.valueOf(42), LuaValue.valueOf("8"));
t.set(LuaValue.valueOf(60), LuaValue.valueOf("10"));
t.set(LuaValue.valueOf(63), LuaValue.valueOf("11"));
Varargs entry = t.next(LuaValue.NIL);
Varargs entry2 = entry;
while ( !entry.isnil(1) ) {
LuaValue k = entry.arg1();
LuaValue v = entry.arg(2);
if ((k.toint() & 1) == 0) {
t.set(k, LuaValue.NIL);
} else {
t.set(k, v.tonumber());
entry2 = t.next(entry2.arg1());
}
entry = t.next(k);
}
int numEntries = 0;
entry = t.next(LuaValue.NIL);
while ( !entry.isnil(1) ) {
LuaValue k = entry.arg1();
// Only odd keys should remain
assertTrue((k.toint() & 1) == 1);
assertTrue(entry.arg(2).type() == LuaValue.TNUMBER);
numEntries++;
entry = t.next(k);
}
assertEquals(5, numEntries);
}
}

View File

@@ -0,0 +1,437 @@
/*******************************************************************************
* Copyright (c) 2009 Luaj.org. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
******************************************************************************/
package org.luaj.vm2;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotSame;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.fail;
import java.util.ArrayList;
import java.util.List;
import java.util.Vector;
import org.junit.jupiter.api.Test;
class TableTest {
protected LuaTable new_Table() {
return new LuaTable();
}
protected LuaTable new_Table(int n, int m) {
return new LuaTable(n, m);
}
private int keyCount(LuaTable t) {
return keys(t).length;
}
private LuaValue[] keys(LuaTable t) {
ArrayList<LuaValue> l = new ArrayList<LuaValue>();
LuaValue k = LuaValue.NIL;
while ( true ) {
Varargs n = t.next(k);
if ((k = n.arg1()).isnil())
break;
l.add(k);
}
return l.toArray(new LuaValue[t.length()]);
}
@Test
void testInOrderIntegerKeyInsertion() {
LuaTable t = new_Table();
for (int i = 1; i <= 32; ++i) {
t.set(i, LuaValue.valueOf("Test Value! " + i));
}
// Ensure all keys are still there.
for (int i = 1; i <= 32; ++i) {
assertEquals("Test Value! " + i, t.get(i).tojstring());
}
// Ensure capacities make sense
assertEquals(0, t.getHashLength());
assertTrue(t.getArrayLength() >= 32);
assertTrue(t.getArrayLength() <= 64);
}
@Test
void testRekeyCount() {
LuaTable t = new_Table();
// NOTE: This order of insertion is important.
t.set(3, LuaInteger.valueOf(3));
t.set(1, LuaInteger.valueOf(1));
t.set(5, LuaInteger.valueOf(5));
t.set(4, LuaInteger.valueOf(4));
t.set(6, LuaInteger.valueOf(6));
t.set(2, LuaInteger.valueOf(2));
for (int i = 1; i < 6; ++i) {
assertEquals(LuaInteger.valueOf(i), t.get(i));
}
assertTrue(t.getArrayLength() >= 3);
assertTrue(t.getArrayLength() <= 12);
assertTrue(t.getHashLength() <= 3);
}
@Test
void testOutOfOrderIntegerKeyInsertion() {
LuaTable t = new_Table();
for (int i = 32; i > 0; --i) {
t.set(i, LuaValue.valueOf("Test Value! " + i));
}
// Ensure all keys are still there.
for (int i = 1; i <= 32; ++i) {
assertEquals("Test Value! " + i, t.get(i).tojstring());
}
// Ensure capacities make sense
assertEquals(32, t.getArrayLength());
assertEquals(0, t.getHashLength());
}
@Test
void testStringAndIntegerKeys() {
LuaTable t = new_Table();
for (int i = 0; i < 10; ++i) {
LuaString str = LuaValue.valueOf(String.valueOf(i));
t.set(i, str);
t.set(str, LuaInteger.valueOf(i));
}
assertTrue(t.getArrayLength() >= 8); // 1, 2, ..., 9
assertTrue(t.getArrayLength() <= 16);
assertTrue(t.getHashLength() >= 11); // 0, "0", "1", ..., "9"
assertTrue(t.getHashLength() <= 33);
LuaValue[] keys = keys(t);
int intKeys = 0;
int stringKeys = 0;
assertEquals(20, keys.length);
for (int i = 0; i < keys.length; ++i) {
LuaValue k = keys[i];
if (k instanceof LuaInteger) {
final int ik = k.toint();
assertTrue(ik >= 0 && ik < 10);
final int mask = 1<<ik;
assertTrue((intKeys & mask) == 0);
intKeys |= mask;
} else if (k instanceof LuaString) {
final int ik = Integer.parseInt(k.strvalue().tojstring());
assertEquals(String.valueOf(ik), k.strvalue().tojstring());
assertTrue(ik >= 0 && ik < 10);
final int mask = 1<<ik;
assertTrue((stringKeys & mask) == 0, "Key \"" + ik + "\" found more than once");
stringKeys |= mask;
} else {
fail("Unexpected type of key found");
}
}
assertEquals(0x03FF, intKeys);
assertEquals(0x03FF, stringKeys);
}
@Test
void testBadInitialCapacity() {
LuaTable t = new_Table(0, 1);
t.set("test", LuaValue.valueOf("foo"));
t.set("explode", LuaValue.valueOf("explode"));
assertEquals(2, keyCount(t));
}
@Test
void testRemove0() {
LuaTable t = new_Table(2, 0);
t.set(1, LuaValue.valueOf("foo"));
t.set(2, LuaValue.valueOf("bah"));
assertNotSame(LuaValue.NIL, t.get(1));
assertNotSame(LuaValue.NIL, t.get(2));
assertEquals(LuaValue.NIL, t.get(3));
t.set(1, LuaValue.NIL);
t.set(2, LuaValue.NIL);
t.set(3, LuaValue.NIL);
assertEquals(LuaValue.NIL, t.get(1));
assertEquals(LuaValue.NIL, t.get(2));
assertEquals(LuaValue.NIL, t.get(3));
}
@Test
void testRemove1() {
LuaTable t = new_Table(0, 1);
t.set("test", LuaValue.valueOf("foo"));
t.set("explode", LuaValue.NIL);
t.set(42, LuaValue.NIL);
t.set(new_Table(), LuaValue.NIL);
t.set("test", LuaValue.NIL);
assertEquals(0, keyCount(t));
t.set(10, LuaInteger.valueOf(5));
t.set(10, LuaValue.NIL);
assertEquals(0, keyCount(t));
}
@Test
void testRemove2() {
LuaTable t = new_Table(0, 1);
t.set("test", LuaValue.valueOf("foo"));
t.set("string", LuaInteger.valueOf(10));
assertEquals(2, keyCount(t));
t.set("string", LuaValue.NIL);
t.set("three", LuaValue.valueOf(3.14));
assertEquals(2, keyCount(t));
t.set("test", LuaValue.NIL);
assertEquals(1, keyCount(t));
t.set(10, LuaInteger.valueOf(5));
assertEquals(2, keyCount(t));
t.set(10, LuaValue.NIL);
assertEquals(1, keyCount(t));
t.set("three", LuaValue.NIL);
assertEquals(0, keyCount(t));
}
@Test
void testShrinkNonPowerOfTwoArray() {
LuaTable t = new_Table(6, 2);
t.set(1, "one");
t.set(2, "two");
t.set(3, "three");
t.set(4, "four");
t.set(5, "five");
t.set(6, "six");
t.set("aa", "aaa");
t.set("bb", "bbb");
t.set(3, LuaValue.NIL);
t.set(4, LuaValue.NIL);
t.set(6, LuaValue.NIL);
t.set("cc", "ccc");
t.set("dd", "ddd");
assertEquals(4, t.getArrayLength());
assertTrue(t.getHashLength() < 10);
assertEquals(5, t.hashEntries);
assertEquals("one", t.get(1).tojstring());
assertEquals("two", t.get(2).tojstring());
assertEquals(LuaValue.NIL, t.get(3));
assertEquals(LuaValue.NIL, t.get(4));
assertEquals("five", t.get(5).tojstring());
assertEquals(LuaValue.NIL, t.get(6));
assertEquals("aaa", t.get("aa").tojstring());
assertEquals("bbb", t.get("bb").tojstring());
assertEquals("ccc", t.get("cc").tojstring());
assertEquals("ddd", t.get("dd").tojstring());
}
@Test
void testInOrderLuaLength() {
LuaTable t = new_Table();
for (int i = 1; i <= 32; ++i) {
t.set(i, LuaValue.valueOf("Test Value! " + i));
assertEquals(i, t.length());
}
}
@Test
void testOutOfOrderLuaLength() {
LuaTable t = new_Table();
for (int j = 8; j < 32; j += 8) {
for (int i = j; i > 0; --i) {
t.set(i, LuaValue.valueOf("Test Value! " + i));
}
assertEquals(j, t.length());
}
}
@Test
void testStringKeysLuaLength() {
LuaTable t = new_Table();
for (int i = 1; i <= 32; ++i) {
t.set("str-" + i, LuaValue.valueOf("String Key Test Value! " + i));
assertEquals(0, t.length());
}
}
@Test
void testMixedKeysLuaLength() {
LuaTable t = new_Table();
for (int i = 1; i <= 32; ++i) {
t.set("str-" + i, LuaValue.valueOf("String Key Test Value! " + i));
t.set(i, LuaValue.valueOf("Int Key Test Value! " + i));
assertEquals(i, t.length());
}
}
private static final void compareLists(LuaTable t, Vector<LuaString> v) {
int n = v.size();
assertEquals(v.size(), t.length());
for (int j = 0; j < n; j++) {
LuaString vj = v.elementAt(j);
String tj = t.get(j+1).tojstring();
assertEquals(vj.tojstring(), tj);
}
}
@Test
void testInsertBeginningOfList() {
LuaTable t = new_Table();
Vector<LuaString> v = new Vector<>();
for (int i = 1; i <= 32; ++i) {
LuaString test = LuaValue.valueOf("Test Value! " + i);
t.insert(1, test);
v.insertElementAt(test, 0);
compareLists(t, v);
}
}
@Test
void testInsertEndOfList() {
LuaTable t = new_Table();
Vector<LuaString> v = new Vector<>();
for (int i = 1; i <= 32; ++i) {
LuaString test = LuaValue.valueOf("Test Value! " + i);
t.insert(0, test);
v.insertElementAt(test, v.size());
compareLists(t, v);
}
}
@Test
void testInsertMiddleOfList() {
LuaTable t = new_Table();
Vector<LuaString> v = new Vector<>();
for (int i = 1; i <= 32; ++i) {
LuaString test = LuaValue.valueOf("Test Value! " + i);
int m = i/2;
t.insert(m+1, test);
v.insertElementAt(test, m);
compareLists(t, v);
}
}
private static final void prefillLists(LuaTable t, Vector<LuaString> v) {
for (int i = 1; i <= 32; ++i) {
LuaString test = LuaValue.valueOf("Test Value! " + i);
t.insert(0, test);
v.insertElementAt(test, v.size());
}
}
@Test
void testRemoveBeginningOfList() {
LuaTable t = new_Table();
Vector<LuaString> v = new Vector<>();
prefillLists(t, v);
for (int i = 1; i <= 32; ++i) {
t.remove(1);
v.removeElementAt(0);
compareLists(t, v);
}
}
@Test
void testRemoveEndOfList() {
LuaTable t = new_Table();
Vector<LuaString> v = new Vector<>();
prefillLists(t, v);
for (int i = 1; i <= 32; ++i) {
t.remove(0);
v.removeElementAt(v.size()-1);
compareLists(t, v);
}
}
@Test
void testRemoveMiddleOfList() {
LuaTable t = new_Table();
Vector<LuaString> v = new Vector<>();
prefillLists(t, v);
for (int i = 1; i <= 32; ++i) {
int m = v.size()/2;
t.remove(m+1);
v.removeElementAt(m);
compareLists(t, v);
}
}
@Test
void testRemoveWhileIterating() {
LuaTable t = LuaValue.tableOf(
new LuaValue[] { LuaValue.valueOf("a"), LuaValue.valueOf("aa"), LuaValue.valueOf("b"),
LuaValue.valueOf("bb"), LuaValue.valueOf("c"), LuaValue.valueOf("cc"), LuaValue.valueOf("d"),
LuaValue.valueOf("dd"), LuaValue.valueOf("e"), LuaValue.valueOf("ee"), },
new LuaValue[] { LuaValue.valueOf("11"), LuaValue.valueOf("22"), LuaValue.valueOf("33"),
LuaValue.valueOf("44"), LuaValue.valueOf("55"), });
// Find expected order after removal.
List<String> expected = new ArrayList<>();
Varargs n;
int i;
for (n = t.next(LuaValue.NIL), i = 0; !n.arg1().isnil(); n = t.next(n.arg1()), ++i) {
if (i%2 == 0)
expected.add(n.arg1() + "=" + n.arg(2));
}
// Remove every other key while iterating over the table.
for (n = t.next(LuaValue.NIL), i = 0; !n.arg1().isnil(); n = t.next(n.arg1()), ++i) {
if (i%2 != 0)
t.set(n.arg1(), LuaValue.NIL);
}
// Iterate over remaining table, and form list of entries still in table.
List<String> actual = new ArrayList<>();
for (n = t.next(LuaValue.NIL); !n.arg1().isnil(); n = t.next(n.arg1())) {
actual.add(n.arg1() + "=" + n.arg(2));
}
assertEquals(expected, actual);
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -21,12 +21,15 @@
******************************************************************************/ ******************************************************************************/
package org.luaj.vm2; package org.luaj.vm2;
import junit.framework.TestCase; import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.fail;
import org.junit.jupiter.api.Test;
/** /**
* Tests of basic unary and binary operators on main value types. * Tests of basic unary and binary operators on main value types.
*/ */
public class VarargsTest extends TestCase { class VarargsTest {
static LuaValue A = LuaValue.valueOf("a"); static LuaValue A = LuaValue.valueOf("a");
static LuaValue B = LuaValue.valueOf("b"); static LuaValue B = LuaValue.valueOf("b");
@@ -57,7 +60,7 @@ public class VarargsTest extends TestCase {
static Varargs FG_alt = new Varargs.PairVarargs(F, G); static Varargs FG_alt = new Varargs.PairVarargs(F, G);
static Varargs NONE = LuaValue.NONE; static Varargs NONE = LuaValue.NONE;
static void expectEquals(Varargs x, Varargs y) { private void expectEquals(Varargs x, Varargs y) {
assertEquals(x.narg(), y.narg()); assertEquals(x.narg(), y.narg());
assertEquals(x.arg1(), y.arg1()); assertEquals(x.arg1(), y.arg1());
assertEquals(x.arg(0), y.arg(0)); assertEquals(x.arg(0), y.arg(0));
@@ -68,7 +71,8 @@ public class VarargsTest extends TestCase {
assertEquals(x.arg(i), y.arg(i)); assertEquals(x.arg(i), y.arg(i));
} }
public void testSanity() { @Test
void testSanity() {
expectEquals(A_G, A_G); expectEquals(A_G, A_G);
expectEquals(A_G_alt, A_G_alt); expectEquals(A_G_alt, A_G_alt);
expectEquals(A_G, A_G_alt); expectEquals(A_G, A_G_alt);
@@ -86,7 +90,8 @@ public class VarargsTest extends TestCase {
expectEquals(NIL, NIL); expectEquals(NIL, NIL);
} }
public void testNegativeIndices() { @Test
void testNegativeIndices() {
expectNegSubargsError(A_G); expectNegSubargsError(A_G);
expectNegSubargsError(A_G_alt); expectNegSubargsError(A_G_alt);
expectNegSubargsError(B_E); expectNegSubargsError(B_E);
@@ -106,7 +111,7 @@ public class VarargsTest extends TestCase {
expectNegSubargsError(NIL); expectNegSubargsError(NIL);
} }
static void standardTestsA_G(Varargs a_g) { private void standardTestsA_G(Varargs a_g) {
expectEquals(A_G, a_g); expectEquals(A_G, a_g);
expectEquals(A_G, a_g.subargs(1)); expectEquals(A_G, a_g.subargs(1));
expectEquals(C_G, a_g.subargs(3).subargs(1)); expectEquals(C_G, a_g.subargs(3).subargs(1));
@@ -121,7 +126,7 @@ public class VarargsTest extends TestCase {
standardTestsC_G(A_G.subargs(3)); standardTestsC_G(A_G.subargs(3));
} }
static void standardTestsC_G(Varargs c_g) { private void standardTestsC_G(Varargs c_g) {
expectEquals(C_G, c_g.subargs(1)); expectEquals(C_G, c_g.subargs(1));
expectEquals(E_G, c_g.subargs(3)); expectEquals(E_G, c_g.subargs(3));
expectEquals(E_G, c_g.subargs(3).subargs(1)); expectEquals(E_G, c_g.subargs(3).subargs(1));
@@ -134,7 +139,7 @@ public class VarargsTest extends TestCase {
standardTestsE_G(c_g.subargs(3)); standardTestsE_G(c_g.subargs(3));
} }
static void standardTestsE_G(Varargs e_g) { private void standardTestsE_G(Varargs e_g) {
expectEquals(E_G, e_g.subargs(1)); expectEquals(E_G, e_g.subargs(1));
expectEquals(FG, e_g.subargs(2)); expectEquals(FG, e_g.subargs(2));
expectEquals(FG, e_g.subargs(2).subargs(1)); expectEquals(FG, e_g.subargs(2).subargs(1));
@@ -145,7 +150,7 @@ public class VarargsTest extends TestCase {
standardTestsFG(e_g.subargs(2)); standardTestsFG(e_g.subargs(2));
} }
static void standardTestsFG(Varargs fg) { private void standardTestsFG(Varargs fg) {
expectEquals(FG, fg.subargs(1)); expectEquals(FG, fg.subargs(1));
expectEquals(G, fg.subargs(2)); expectEquals(G, fg.subargs(2));
expectEquals(G, fg.subargs(2).subargs(1)); expectEquals(G, fg.subargs(2).subargs(1));
@@ -153,12 +158,13 @@ public class VarargsTest extends TestCase {
expectEquals(NONE, fg.subargs(3).subargs(1)); expectEquals(NONE, fg.subargs(3).subargs(1));
} }
static void standardTestsNone(Varargs none) { private void standardTestsNone(Varargs none) {
expectEquals(NONE, none.subargs(1)); expectEquals(NONE, none.subargs(1));
expectEquals(NONE, none.subargs(2)); expectEquals(NONE, none.subargs(2));
} }
public void testVarargsSubargs() { @Test
void testVarargsSubargs() {
standardTestsA_G(A_G); standardTestsA_G(A_G);
standardTestsA_G(A_G_alt); standardTestsA_G(A_G_alt);
standardTestsC_G(C_G); standardTestsC_G(C_G);
@@ -170,7 +176,8 @@ public class VarargsTest extends TestCase {
standardTestsNone(NONE); standardTestsNone(NONE);
} }
public void testVarargsMore() { @Test
void testVarargsMore() {
Varargs a_g; Varargs a_g;
a_g = LuaValue.varargsOf(new LuaValue[] { A, }, LuaValue.varargsOf(new LuaValue[] { B, C, D, E, F, G })); a_g = LuaValue.varargsOf(new LuaValue[] { A, }, LuaValue.varargsOf(new LuaValue[] { B, C, D, E, F, G }));
standardTestsA_G(a_g); standardTestsA_G(a_g);
@@ -186,17 +193,15 @@ public class VarargsTest extends TestCase {
standardTestsA_G(a_g); standardTestsA_G(a_g);
} }
public void testPairVarargsMore() { @Test
Varargs a_g = new Varargs.PairVarargs(A, void testPairVarargsMore() {
new Varargs.PairVarargs(B, Varargs a_g = new Varargs.PairVarargs(A, new Varargs.PairVarargs(B, new Varargs.PairVarargs(C,
new Varargs.PairVarargs(C, new Varargs.PairVarargs(D, new Varargs.PairVarargs(E, new Varargs.PairVarargs(F, G))))));
new Varargs.PairVarargs(D,
new Varargs.PairVarargs(E,
new Varargs.PairVarargs(F, G))))));
standardTestsA_G(a_g); standardTestsA_G(a_g);
} }
public void testArrayPartMore() { @Test
void testArrayPartMore() {
Varargs a_g; Varargs a_g;
a_g = new Varargs.ArrayPartVarargs(Z_H_array, 1, 1, new Varargs.ArrayPartVarargs(Z_H_array, 2, 6)); a_g = new Varargs.ArrayPartVarargs(Z_H_array, 1, 1, new Varargs.ArrayPartVarargs(Z_H_array, 2, 6));
standardTestsA_G(a_g); standardTestsA_G(a_g);
@@ -212,7 +217,7 @@ public class VarargsTest extends TestCase {
standardTestsA_G(a_g); standardTestsA_G(a_g);
} }
static void expectNegSubargsError(Varargs v) { private void expectNegSubargsError(Varargs v) {
String expected_msg = "bad argument #1: start must be > 0"; String expected_msg = "bad argument #1: start must be > 0";
try { try {
v.subargs(0); v.subargs(0);

View File

@@ -0,0 +1,262 @@
/*******************************************************************************
* Copyright (c) 2009 Luaj.org. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
******************************************************************************/
package org.luaj.vm2;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
import java.lang.ref.WeakReference;
import org.junit.jupiter.api.Test;
class WeakTableTest {
@Test
void testWeakValuesTable() {
LuaTable t = WeakTable.make(false, true);
Object obj = new Object();
LuaTable tableValue = new LuaTable();
LuaString stringValue = LuaString.valueOf("this is a test");
LuaTable tableValue2 = new LuaTable();
t.set("table", tableValue);
t.set("userdata", LuaValue.userdataOf(obj, null));
t.set("string", stringValue);
t.set("string2", LuaValue.valueOf("another string"));
t.set(1, tableValue2);
assertTrue(t.getHashLength() >= 4, "table must have at least 4 elements");
// TODO fix assert
// assertTrue(t.getArrayLength() >= 1, "array part must have 1 element");
// check that table can be used to get elements
assertEquals(tableValue, t.get("table"));
assertEquals(stringValue, t.get("string"));
assertEquals(obj, t.get("userdata").checkuserdata());
assertEquals(tableValue2, t.get(1));
// nothing should be collected, since we have strong references here
collectGarbage();
// check that elements are still there
assertEquals(tableValue, t.get("table"));
assertEquals(stringValue, t.get("string"));
assertEquals(obj, t.get("userdata").checkuserdata());
assertEquals(tableValue2, t.get(1));
// drop our strong references
obj = null;
tableValue = null;
tableValue2 = null;
stringValue = null;
// Garbage collection should cause weak entries to be dropped.
collectGarbage();
// check that they are dropped
assertEquals(LuaValue.NIL, t.get("table"));
assertEquals(LuaValue.NIL, t.get("userdata"));
assertEquals(LuaValue.NIL, t.get(1));
assertFalse(t.get("string").isnil(), "strings should not be in weak references");
}
@Test
void testWeakKeysTable() {
LuaTable t = WeakTable.make(true, false);
LuaValue key = LuaValue.userdataOf(new MyData(111));
LuaValue val = LuaValue.userdataOf(new MyData(222));
// set up the table
t.set(key, val);
assertEquals(val, t.get(key));
System.gc();
assertEquals(val, t.get(key));
// drop key and value references, replace them with new ones
WeakReference<LuaValue> origkey = new WeakReference<>(key);
WeakReference<LuaValue> origval = new WeakReference<>(val);
key = LuaValue.userdataOf(new MyData(111));
val = LuaValue.userdataOf(new MyData(222));
// new key and value should be interchangeable (feature of this test class)
assertEquals(key, origkey.get());
assertEquals(val, origval.get());
assertEquals(val, t.get(key));
assertEquals(val, t.get(origkey.get()));
assertEquals(origval.get(), t.get(key));
// value should not be reachable after gc
collectGarbage();
assertEquals(null, origkey.get());
assertEquals(LuaValue.NIL, t.get(key));
collectGarbage();
assertEquals(null, origval.get());
}
@Test
void testNext() {
LuaTable t = WeakTable.make(true, true);
LuaValue key = LuaValue.userdataOf(new MyData(111));
LuaValue val = LuaValue.userdataOf(new MyData(222));
LuaValue key2 = LuaValue.userdataOf(new MyData(333));
LuaValue val2 = LuaValue.userdataOf(new MyData(444));
LuaValue key3 = LuaValue.userdataOf(new MyData(555));
LuaValue val3 = LuaValue.userdataOf(new MyData(666));
// set up the table
t.set(key, val);
t.set(key2, val2);
t.set(key3, val3);
// forget one of the keys
key2 = null;
val2 = null;
collectGarbage();
// table should have 2 entries
int size = 0;
for (LuaValue k = t.next(LuaValue.NIL).arg1(); !k.isnil(); k = t.next(k).arg1()) {
size++;
}
assertEquals(2, size);
}
@Test
void testWeakKeysValuesTable() {
LuaTable t = WeakTable.make(true, true);
LuaValue key = LuaValue.userdataOf(new MyData(111));
LuaValue val = LuaValue.userdataOf(new MyData(222));
LuaValue key2 = LuaValue.userdataOf(new MyData(333));
LuaValue val2 = LuaValue.userdataOf(new MyData(444));
LuaValue key3 = LuaValue.userdataOf(new MyData(555));
LuaValue val3 = LuaValue.userdataOf(new MyData(666));
// set up the table
t.set(key, val);
t.set(key2, val2);
t.set(key3, val3);
assertEquals(val, t.get(key));
assertEquals(val2, t.get(key2));
assertEquals(val3, t.get(key3));
System.gc();
assertEquals(val, t.get(key));
assertEquals(val2, t.get(key2));
assertEquals(val3, t.get(key3));
// drop key and value references, replace them with new ones
WeakReference<LuaValue> origkey = new WeakReference<>(key);
WeakReference<LuaValue> origval = new WeakReference<>(val);
WeakReference<LuaValue> origkey2 = new WeakReference<>(key2);
WeakReference<LuaValue> origval2 = new WeakReference<>(val2);
WeakReference<LuaValue> origkey3 = new WeakReference<>(key3);
WeakReference<LuaValue> origval3 = new WeakReference<>(val3);
key = LuaValue.userdataOf(new MyData(111));
val = LuaValue.userdataOf(new MyData(222));
key2 = LuaValue.userdataOf(new MyData(333));
// don't drop val2, or key3
val3 = LuaValue.userdataOf(new MyData(666));
// no values should be reachable after gc
collectGarbage();
assertEquals(null, origkey.get());
assertEquals(null, origval.get());
assertEquals(null, origkey2.get());
assertEquals(null, origval3.get());
assertEquals(LuaValue.NIL, t.get(key));
assertEquals(LuaValue.NIL, t.get(key2));
assertEquals(LuaValue.NIL, t.get(key3));
// all originals should be gone after gc, then access
val2 = null;
key3 = null;
collectGarbage();
assertEquals(null, origval2.get());
assertEquals(null, origkey3.get());
}
@Test
void testReplace() {
LuaTable t = WeakTable.make(true, true);
LuaValue key = LuaValue.userdataOf(new MyData(111));
LuaValue val = LuaValue.userdataOf(new MyData(222));
LuaValue key2 = LuaValue.userdataOf(new MyData(333));
LuaValue val2 = LuaValue.userdataOf(new MyData(444));
LuaValue key3 = LuaValue.userdataOf(new MyData(555));
LuaValue val3 = LuaValue.userdataOf(new MyData(666));
// set up the table
t.set(key, val);
t.set(key2, val2);
t.set(key3, val3);
LuaValue val4 = LuaValue.userdataOf(new MyData(777));
t.set(key2, val4);
// table should have 3 entries
int size = 0;
for (LuaValue k = t.next(LuaValue.NIL).arg1(); !k.isnil() && size < 1000; k = t.next(k).arg1()) {
size++;
}
assertEquals(3, size);
}
public static class MyData {
public final int value;
public MyData(int value) {
this.value = value;
}
@Override
public int hashCode() {
return value;
}
@Override
public boolean equals(Object o) {
return (o instanceof MyData) && ((MyData) o).value == value;
}
@Override
public String toString() {
return "mydata-" + value;
}
}
static void collectGarbage() {
Runtime rt = Runtime.getRuntime();
rt.gc();
try {
Thread.sleep(20);
rt.gc();
Thread.sleep(20);
} catch (Exception e) {
e.printStackTrace();
}
rt.gc();
}
}

BIN
luaj-jme-3.0.2.jar Normal file

Binary file not shown.

39
luaj-jme/pom.xml Normal file
View File

@@ -0,0 +1,39 @@
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.luaj</groupId>
<artifactId>luaj-parent</artifactId>
<version>3.0-SNAPSHOT</version>
</parent>
<artifactId>luaj-jme</artifactId>
<name>luaj-jme</name>
<description>LuaJ for Java ME</description>
<dependencies>
<dependency>
<groupId>org.luaj</groupId>
<artifactId>luaj-core</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.apache.bcel</groupId>
<artifactId>bcel</artifactId>
</dependency>
<dependency>
<groupId>com.github.mcpat.apistubs</groupId>
<artifactId>cldc-1.1-stub</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>

View File

@@ -35,60 +35,76 @@ import org.luaj.vm2.lib.IoLib;
import org.luaj.vm2.lib.LibFunction; import org.luaj.vm2.lib.LibFunction;
/** /**
* Subclass of {@link IoLib} and therefore {@link LibFunction} which implements the lua standard {@code io} * Subclass of {@link IoLib} and therefore {@link LibFunction} which implements
* library for the JSE platform. * the lua standard {@code io} library for the JSE platform.
* <p> * <p>
* The implementation of the is based on CLDC 1.0 and StreamConnection. * The implementation of the is based on CLDC 1.0 and StreamConnection. However,
* However, seek is not supported. * seek is not supported.
* <p> * <p>
* Typically, this library is included as part of a call to * Typically, this library is included as part of a call to
* {@link org.luaj.vm2.lib.jme.JmePlatform#standardGlobals()} * {@link org.luaj.vm2.lib.jme.JmePlatform#standardGlobals()}
* <pre> {@code *
* <pre>
* {
* &#64;code
* Globals globals = JmePlatform.standardGlobals(); * Globals globals = JmePlatform.standardGlobals();
* globals.get("io").get("write").call(LuaValue.valueOf("hello, world\n")); * globals.get("io").get("write").call(LuaValue.valueOf("hello, world\n"));
* } </pre> * }
* </pre>
* <p> * <p>
* For special cases where the smallest possible footprint is desired, * For special cases where the smallest possible footprint is desired, a minimal
* a minimal set of libraries could be loaded * set of libraries could be loaded directly via {@link Globals#load(LuaValue)}
* directly via {@link Globals#load(LuaValue)} using code such as: * using code such as:
* <pre> {@code *
* <pre>
* {
* &#64;code
* Globals globals = new Globals(); * Globals globals = new Globals();
* globals.load(new JmeBaseLib()); * globals.load(new JmeBaseLib());
* globals.load(new PackageLib()); * globals.load(new PackageLib());
* globals.load(new JmeIoLib()); * globals.load(new JmeIoLib());
* globals.get("io").get("write").call(LuaValue.valueOf("hello, world\n")); * 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> * <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 LibFunction
* @see org.luaj.vm2.lib.jse.JsePlatform * @see org.luaj.vm2.lib.jse.JsePlatform
* @see org.luaj.vm2.lib.jme.JmePlatform * @see org.luaj.vm2.lib.jme.JmePlatform
* @see IoLib * @see IoLib
* @see org.luaj.vm2.lib.jse.JseIoLib * @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 { public class JmeIoLib extends IoLib {
@Override
protected File wrapStdin() throws IOException { protected File wrapStdin() throws IOException {
return new FileImpl(globals.STDIN); return new FileImpl(globals.STDIN);
} }
@Override
protected File wrapStdout() throws IOException { protected File wrapStdout() throws IOException {
return new FileImpl(globals.STDOUT); return new FileImpl(globals.STDOUT);
} }
@Override
protected File wrapStderr() throws IOException { protected File wrapStderr() throws IOException {
return new FileImpl(globals.STDERR); return new FileImpl(globals.STDERR);
} }
protected File openFile( String filename, boolean readMode, boolean appendMode, boolean updateMode, boolean binaryMode ) throws IOException { @Override
protected File openFile(String filename, boolean readMode, boolean appendMode, boolean updateMode,
boolean binaryMode) throws IOException {
String url = "file:///" + filename; String url = "file:///" + filename;
int mode = readMode? Connector.READ: Connector.READ_WRITE; int mode = readMode? Connector.READ: Connector.READ_WRITE;
StreamConnection conn = (StreamConnection) Connector.open(url, mode); StreamConnection conn = (StreamConnection) Connector.open(url, mode);
File f = readMode?
new FileImpl(conn, conn.openInputStream(), null):
new FileImpl(conn, conn.openInputStream(), conn.openOutputStream());
/* /*
if ( appendMode ) { if ( appendMode ) {
f.seek("end",0); f.seek("end",0);
@@ -97,18 +113,21 @@ public class JmeIoLib extends IoLib {
conn.truncate(0); conn.truncate(0);
} }
*/ */
return f; return readMode? new FileImpl(conn, conn.openInputStream(), null)
: new FileImpl(conn, conn.openInputStream(), conn.openOutputStream());
} }
private static void notimplemented() throws IOException { private static void notimplemented() throws IOException {
throw new IOException("not implemented"); throw new IOException("not implemented");
} }
@Override
protected File openProgram(String prog, String mode) throws IOException { protected File openProgram(String prog, String mode) throws IOException {
notimplemented(); notimplemented();
return null; return null;
} }
@Override
protected File tmpFile() throws IOException { protected File tmpFile() throws IOException {
notimplemented(); notimplemented();
return null; return null;
@@ -121,33 +140,46 @@ public class JmeIoLib extends IoLib {
private boolean closed = false; private boolean closed = false;
private boolean nobuffer = false; private boolean nobuffer = false;
private int lookahead = -1; private int lookahead = -1;
private FileImpl(StreamConnection conn, InputStream is, OutputStream os) { private FileImpl(StreamConnection conn, InputStream is, OutputStream os) {
this.conn = conn; this.conn = conn;
this.is = is; this.is = is;
this.os = os; this.os = os;
} }
private FileImpl(InputStream i) { private FileImpl(InputStream i) {
this(null, i, null); this(null, i, null);
} }
private FileImpl(OutputStream o) { private FileImpl(OutputStream o) {
this(null, null, o); this(null, null, o);
} }
@Override
public String tojstring() { public String tojstring() {
return "file (" + this.hashCode() + ")"; return "file (" + this.hashCode() + ")";
} }
@Override
public boolean isstdfile() { public boolean isstdfile() {
return conn == null; return conn == null;
} }
@Override
public void close() throws IOException { public void close() throws IOException {
closed = true; closed = true;
if (conn != null) { if (conn != null) {
conn.close(); conn.close();
} }
} }
@Override
public void flush() throws IOException { public void flush() throws IOException {
if (os != null) if (os != null)
os.flush(); os.flush();
} }
@Override
public void write(LuaString s) throws IOException { public void write(LuaString s) throws IOException {
if (os != null) if (os != null)
os.write(s.m_bytes, s.m_offset, s.m_length); os.write(s.m_bytes, s.m_offset, s.m_length);
@@ -156,9 +188,13 @@ public class JmeIoLib extends IoLib {
if (nobuffer) if (nobuffer)
flush(); flush();
} }
@Override
public boolean isclosed() { public boolean isclosed() {
return closed; return closed;
} }
@Override
public int seek(String option, int pos) throws IOException { public int seek(String option, int pos) throws IOException {
/* /*
if ( conn != null ) { if ( conn != null ) {
@@ -177,16 +213,20 @@ public class JmeIoLib extends IoLib {
notimplemented(); notimplemented();
return 0; return 0;
} }
@Override
public void setvbuf(String mode, int size) { public void setvbuf(String mode, int size) {
nobuffer = "no".equals(mode); nobuffer = "no".equals(mode);
} }
// get length remaining to read // get length remaining to read
@Override
public int remaining() throws IOException { public int remaining() throws IOException {
return -1; return -1;
} }
// peek ahead one character // peek ahead one character
@Override
public int peek() throws IOException { public int peek() throws IOException {
if (lookahead < 0) if (lookahead < 0)
lookahead = is.read(); lookahead = is.read();
@@ -194,6 +234,7 @@ public class JmeIoLib extends IoLib {
} }
// return char if read, -1 if eof, throw IOException on other exception // return char if read, -1 if eof, throw IOException on other exception
@Override
public int read() throws IOException { public int read() throws IOException {
if (lookahead >= 0) { if (lookahead >= 0) {
int c = lookahead; int c = lookahead;
@@ -207,6 +248,7 @@ public class JmeIoLib extends IoLib {
} }
// return number of bytes read if positive, -1 if eof, throws IOException // return number of bytes read if positive, -1 if eof, throws IOException
@Override
public int read(byte[] bytes, int offset, int length) throws IOException { public int read(byte[] bytes, int offset, int length) throws IOException {
int n, i = 0; int n, i = 0;
if (is != null) { if (is != null) {
@@ -218,7 +260,7 @@ public class JmeIoLib extends IoLib {
for (; i < length;) { for (; i < length;) {
n = is.read(bytes, offset+i, length-i); n = is.read(bytes, offset+i, length-i);
if (n < 0) if (n < 0)
return ( i > 0 ? i : -1 ); return i > 0? i: -1;
i += n; i += n;
} }
} else { } else {

View File

@@ -23,8 +23,6 @@ package org.luaj.vm2.lib.jme;
import org.luaj.vm2.Globals; import org.luaj.vm2.Globals;
import org.luaj.vm2.LoadState; import org.luaj.vm2.LoadState;
import org.luaj.vm2.LuaThread;
import org.luaj.vm2.LuaValue;
import org.luaj.vm2.compiler.LuaC; import org.luaj.vm2.compiler.LuaC;
import org.luaj.vm2.lib.BaseLib; import org.luaj.vm2.lib.BaseLib;
import org.luaj.vm2.lib.Bit32Lib; import org.luaj.vm2.lib.Bit32Lib;
@@ -37,40 +35,60 @@ import org.luaj.vm2.lib.ResourceFinder;
import org.luaj.vm2.lib.StringLib; import org.luaj.vm2.lib.StringLib;
import org.luaj.vm2.lib.TableLib; 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> * <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> * <ul>
* <li>Some math functions are not implemented, see {@link MathLib} for details</li> * <li>Some math functions are not implemented, see {@link MathLib} for
* <li>Scripts are loaded via Class.getResourceAsStream(), see {@link BaseLib} for details</li> * details</li>
* <li>OS functions execute(), remove(), rename(), and tmpname() vary, see {@link OsLib} for details</li> * <li>Scripts are loaded via Class.getResourceAsStream(), see {@link BaseLib}
* <li>I/O seek is not implemented, see {@link org.luaj.vm2.lib.jme.JmeIoLib} for details</li> * for details</li>
* <li>luajava is not available, see {@link org.luaj.vm2.lib.jse.LuajavaLib} 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> * </ul>
* <p> * <p>
* It is used to allocate either a set of standard globals using * It is used to allocate either a set of standard globals using
* {@link #standardGlobals()} or debug globals using {@link #debugGlobals()} * {@link #standardGlobals()} or debug globals using {@link #debugGlobals()}
* <p> * <p>
* A simple example of initializing globals and using them from Java is: * A simple example of initializing globals and using them from Java is:
* <pre> {@code *
* <pre>
* {
* &#64;code
* Globals global = JmePlatform.standardGlobals(); * Globals global = JmePlatform.standardGlobals();
* global.get("print").call(LuaValue.valueOf("hello, world")); * global.get("print").call(LuaValue.valueOf("hello, world"));
* } </pre> * }
* </pre>
* <p> * <p>
* Once globals are created, a simple way to load and run a script is: * 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(); * LoadState.load( getClass().getResourceAsStream("main.lua"), "main.lua", globals ).call();
* } </pre> * }
* </pre>
* <p> * <p>
* although {@code require} could also be used: * although {@code require} could also be used:
* <pre> {@code *
* <pre>
* {@code
* globals.get("require").call(LuaValue.valueOf("main")); * globals.get("require").call(LuaValue.valueOf("main"));
* } </pre> * }
* For this to succeed, the file "main.lua" must be a resource in the class path. * </pre>
* See {@link BaseLib} for details on finding scripts using {@link ResourceFinder}. *
* 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> * <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> * <ul>
* <li>{@link Globals}</li> * <li>{@link Globals}</li>
* <li>{@link BaseLib}</li> * <li>{@link BaseLib}</li>
@@ -83,9 +101,11 @@ import org.luaj.vm2.lib.TableLib;
* <li>{@link org.luaj.vm2.lib.jme.JmeIoLib}</li> * <li>{@link org.luaj.vm2.lib.jme.JmeIoLib}</li>
* <li>{@link OsLib}</li> * <li>{@link OsLib}</li>
* </ul> * </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> * <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>
* <p> * <p>
* The class ensures that initialization is done in the correct order. * The class ensures that initialization is done in the correct order.
@@ -119,9 +139,11 @@ public class JmePlatform {
return globals; 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 #standardGlobals()
* @see org.luaj.vm2.lib.jse.JsePlatform * @see org.luaj.vm2.lib.jse.JsePlatform
* @see org.luaj.vm2.lib.jme.JmePlatform * @see org.luaj.vm2.lib.jme.JmePlatform

View File

View File

@@ -0,0 +1,136 @@
package org.luaj.vm2.lib.jme;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.luaj.vm2.LuaValue;
class OsLibTest {
LuaValue jme_lib;
double time;
@BeforeEach
public void setUp() {
jme_lib = JmePlatform.standardGlobals().get("os");
time = 998571302000L/1000.0;
}
void test(String format, String expected) {
String actual = jme_lib.get("date").call(LuaValue.valueOf(format), LuaValue.valueOf(time)).tojstring();
assertEquals(expected, actual);
}
@Test
void testStringDateChars() { test("foo", "foo"); }
@Test
void testStringDate_a() { test("%a", "Thu"); }
@Test
void testStringDate_A() { test("%A", "Thursday"); }
@Test
void testStringDate_b() { test("%b", "Aug"); }
@Test
void testStringDate_B() { test("%B", "August"); }
@Test
void testStringDate_c() { test("%c", "Thu Aug 23 14:55:02 2001"); }
@Test
void testStringDate_d() { test("%d", "23"); }
@Test
void testStringDate_H() { test("%H", "14"); }
@Test
void testStringDate_I() { test("%I", "02"); }
@Test
void testStringDate_j() { test("%j", "235"); }
@Test
void testStringDate_m() { test("%m", "08"); }
@Test
void testStringDate_M() { test("%M", "55"); }
@Test
void testStringDate_p() { test("%p", "PM"); }
@Test
void testStringDate_S() { test("%S", "02"); }
@Test
void testStringDate_U() { test("%U", "33"); }
@Test
void testStringDate_w() { test("%w", "4"); }
@Test
void testStringDate_W() { test("%W", "34"); }
@Test
void testStringDate_x() { test("%x", "08/23/01"); }
@Test
void testStringDate_X() { test("%X", "14:55:02"); }
@Test
void testStringDate_y() { test("%y", "01"); }
@Test
void testStringDate_Y() { test("%Y", "2001"); }
@Test
void testStringDate_Pct() { test("%%", "%"); }
static final double DAY = 24.*3600.;
@Test
void testStringDate_UW_neg4() { time -= 4*DAY; test("%c %U %W", "Sun Aug 19 14:55:02 2001 33 33"); }
@Test
void testStringDate_UW_neg3() { time -= 3*DAY; test("%c %U %W", "Mon Aug 20 14:55:02 2001 33 34"); }
@Test
void testStringDate_UW_neg2() { time -= 2*DAY; test("%c %U %W", "Tue Aug 21 14:55:02 2001 33 34"); }
@Test
void testStringDate_UW_neg1() { time -= DAY; test("%c %U %W", "Wed Aug 22 14:55:02 2001 33 34"); }
@Test
void testStringDate_UW_pos0() { time += 0; test("%c %U %W", "Thu Aug 23 14:55:02 2001 33 34"); }
@Test
void testStringDate_UW_pos1() { time += DAY; test("%c %U %W", "Fri Aug 24 14:55:02 2001 33 34"); }
@Test
void testStringDate_UW_pos2() { time += 2*DAY; test("%c %U %W", "Sat Aug 25 14:55:02 2001 33 34"); }
@Test
void testStringDate_UW_pos3() { time += 3*DAY; test("%c %U %W", "Sun Aug 26 14:55:02 2001 34 34"); }
@Test
void testStringDate_UW_pos4() { time += 4*DAY; test("%c %U %W", "Mon Aug 27 14:55:02 2001 34 35"); }
@Test
void testJseOsGetenvForEnvVariables() {
LuaValue USER = LuaValue.valueOf("USER");
LuaValue jme_user = jme_lib.get("getenv").call(USER);
assertTrue(jme_user.isnil());
System.out.println("User: " + jme_user);
}
void testJseOsGetenvForSystemProperties() {
// System.setProperty("test.key.foo", "test.value.bar");
LuaValue key = LuaValue.valueOf("test.key.foo");
LuaValue value = LuaValue.valueOf("test.value.bar");
LuaValue jme_value = jme_lib.get("getenv").call(key);
assertEquals(value, jme_value);
}
}

View File

BIN
luaj-jse-3.0.2.jar Normal file

Binary file not shown.

77
luaj-jse/pom.xml Normal file
View File

@@ -0,0 +1,77 @@
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.luaj</groupId>
<artifactId>luaj-parent</artifactId>
<version>3.0-SNAPSHOT</version>
</parent>
<artifactId>luaj-jse</artifactId>
<name>luaj-jse</name>
<description>LuaJ for Java SE</description>
<dependencies>
<dependency>
<groupId>org.luaj</groupId>
<artifactId>luaj-core</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.apache.bcel</groupId>
<artifactId>bcel</artifactId>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>com.helger.maven</groupId>
<artifactId>ph-javacc-maven-plugin</artifactId>
<executions>
<execution>
<id>generate-grammar</id>
<phase>generate-sources</phase>
<goals>
<goal>javacc</goal>
</goals>
<configuration>
<jdkVersion>1.8</jdkVersion>
<javadocFriendlyComments>true</javadocFriendlyComments>
<packageName>org.luaj.vm2.parser</packageName>
<sourceDirectory>src/main/javacc</sourceDirectory>
<outputDirectory>${project.build.directory}/generated-sources/javacc</outputDirectory>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId>
<executions>
<execution>
<id>add-source</id>
<phase>generate-sources</phase>
<goals>
<goal>add-source</goal>
</goals>
<configuration>
<sources>
<source>${project.build.directory}/generated-sources/javacc</source>
</sources>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

View File

@@ -1,3 +1,4 @@
/******************************************************************************* /*******************************************************************************
* Copyright (c) 2009-2012 Luaj.org. All rights reserved. * 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.lib.jse.JsePlatform;
import org.luaj.vm2.luajc.LuaJC; import org.luaj.vm2.luajc.LuaJC;
/** /**
* lua command for use in JSE environments. * lua command for use in JSE environments.
*/ */
public class lua { public class lua {
private static final String version = Lua._VERSION + " Copyright (c) 2012 Luaj.org.org"; private static final String version = Lua._VERSION + " Copyright (c) 2012 Luaj.org.org";
private static final String usage = private static final String usage = "usage: java -cp luaj-jse.jar lua [options] [script [args]].\n"
"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"
"Available options are:\n" + + " -i enter interactive mode after executing 'script'\n" + " -v show version information\n"
" -e stat execute string 'stat'\n" + + " -b use luajc bytecode-to-bytecode compiler (requires bcel on class path)\n"
" -l name require library 'name'\n" + + " -n nodebug - do not load debug library by default\n" + " -p print the prototype\n"
" -i enter interactive mode after executing 'script'\n" + + " -c enc use the supplied encoding 'enc' for input files\n" + " -- stop handling options\n"
" -v show version information\n" + + " - execute stdin and stop handling options";
" -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() { private static void usageExit() {
System.out.println(usage); System.out.println(usage);
@@ -71,7 +65,7 @@ public class lua {
public static void main(String[] args) throws IOException { public static void main(String[] args) throws IOException {
// process args // process args
boolean interactive = (args.length == 0); boolean interactive = args.length == 0;
boolean versioninfo = false; boolean versioninfo = false;
boolean processing = true; boolean processing = true;
boolean nodebug = false; boolean nodebug = false;
@@ -137,7 +131,8 @@ public class lua {
// new lua state // new lua state
globals = nodebug? JsePlatform.standardGlobals(): JsePlatform.debugGlobals(); 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++) for (int i = 0, n = libs != null? libs.size(): 0; i < n; i++)
loadLibrary((String) libs.elementAt(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 { try {
LuaValue c; LuaValue c;
try { try {
script = new BufferedInputStream(script); script = new BufferedInputStream(script);
c = encoding != null? c = encoding != null? globals.load(new InputStreamReader(script, encoding), chunkname)
globals.load(new InputStreamReader(script, encoding), chunkname): : globals.load(script, chunkname, "bt", globals);
globals.load(script, chunkname, "bt", globals);
} finally { } finally {
script.close(); script.close();
} }

View File

@@ -1,3 +1,4 @@
/******************************************************************************* /*******************************************************************************
* Copyright (c) 2009 Luaj.org. All rights reserved. * 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.compiler.DumpState;
import org.luaj.vm2.lib.jse.JsePlatform; import org.luaj.vm2.lib.jse.JsePlatform;
/** /**
* Compiler for lua files to lua bytecode. * Compiler for lua files to lua bytecode.
*/ */
public class luac { public class luac {
private static final String version = Lua._VERSION + "Copyright (C) 2009 luaj.org"; private static final String version = Lua._VERSION + "Copyright (C) 2009 luaj.org";
private static final String usage = private static final String usage = "usage: java -cp luaj-jse.jar luac [options] [filenames].\n"
"usage: java -cp luaj-jse.jar luac [options] [filenames].\n" + + "Available options are:\n" + " - process stdin\n" + " -l list\n"
"Available options are:\n" + + " -o name output to file 'name' (default is \"luac.out\")\n" + " -p parse only\n"
" - process stdin\n" + + " -s strip debug information\n" + " -e little endian format for numbers\n"
" -l list\n" + + " -i<n> number format 'n', (n=0,1 or 4, default=" + DumpState.NUMBER_FORMAT_DEFAULT + ")\n"
" -o name output to file 'name' (default is \"luac.out\")\n" + + " -v show version information\n" + " -c enc use the supplied encoding 'enc' for input files\n"
" -p parse only\n" + + " -- stop handling options\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() { private static void usageExit() {
System.out.println(usage); System.out.println(usage);
@@ -134,10 +128,8 @@ public class luac {
System.out.println(version); System.out.println(version);
// open output file // open output file
OutputStream fos = new FileOutputStream( output );
// process input files // process input files
try { try (OutputStream fos = new FileOutputStream(output)) {
Globals globals = JsePlatform.standardGlobals(); Globals globals = JsePlatform.standardGlobals();
processing = true; processing = true;
for (int i = 0; i < args.length; i++) { for (int i = 0; i < args.length; i++) {
@@ -158,8 +150,6 @@ public class luac {
} }
} }
} }
} finally {
fos.close();
} }
} catch (IOException ioe) { } catch (IOException ioe) {
@@ -168,13 +158,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 { try {
// create the chunk // create the chunk
script = new BufferedInputStream(script); script = new BufferedInputStream(script);
Prototype chunk = encoding != null? Prototype chunk = encoding != null
globals.compilePrototype(new InputStreamReader(script, encoding), chunkname): ? globals.compilePrototype(new InputStreamReader(script, encoding), chunkname)
globals.compilePrototype(script, chunkname); : globals.compilePrototype(script, chunkname);
// list the chunk // list the chunk
if (list) if (list)

View File

@@ -0,0 +1,270 @@
/*******************************************************************************
* Copyright (c) 2009-2012 Luaj.org. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
******************************************************************************/
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.List;
import org.luaj.vm2.Globals;
import org.luaj.vm2.Lua;
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.
*/
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 void usageExit() {
System.out.println(usage);
System.exit(-1);
}
private String srcdir = ".";
private String destdir = ".";
private boolean genmain = false;
private boolean recurse = false;
private boolean verbose = false;
private boolean loadclasses = false;
private String encoding = null;
private String pkgprefix = null;
private final List files = new ArrayList();
private final Globals globals;
public static void main(String[] args) throws IOException {
new luajc(args);
}
private luajc(String[] args) throws IOException {
// process args
List seeds = new ArrayList();
// get stateful args
for (int i = 0; i < args.length; i++) {
if (!args[i].startsWith("-")) {
seeds.add(args[i]);
} else {
switch (args[i].charAt(1)) {
case 's':
if (++i >= args.length)
usageExit();
srcdir = args[i];
break;
case 'd':
if (++i >= args.length)
usageExit();
destdir = args[i];
break;
case 'l':
loadclasses = true;
break;
case 'p':
if (++i >= args.length)
usageExit();
pkgprefix = args[i];
break;
case 'm':
genmain = true;
break;
case 'r':
recurse = true;
break;
case 'c':
if (++i >= args.length)
usageExit();
encoding = args[i];
break;
case 'v':
verbose = true;
break;
default:
usageExit();
break;
}
}
}
// echo version
if (verbose) {
System.out.println(version);
System.out.println("srcdir: " + srcdir);
System.out.println("destdir: " + destdir);
System.out.println("files: " + seeds);
System.out.println("recurse: " + recurse);
}
// need at least one seed
if (seeds.size() <= 0) {
System.err.println(usage);
System.exit(-1);
}
// collect up files to process
for (Object seed : seeds)
collectFiles(srcdir + "/" + seed);
// check for at least one file
if (files.size() <= 0) {
System.err.println("no files found in " + seeds);
System.exit(-1);
}
// process input files
globals = JsePlatform.standardGlobals();
for (Object file : files)
processFile((InputFile) file);
}
private void collectFiles(String path) {
File f = new File(path);
if (f.isDirectory() && recurse)
scandir(f, pkgprefix);
else if (f.isFile()) {
File dir = f.getAbsoluteFile().getParentFile();
if (dir != null)
scanfile(dir, f, pkgprefix);
}
}
private void scandir(File dir, String javapackage) {
File[] f = dir.listFiles();
for (File element : f)
scanfile(dir, element, javapackage);
}
private void scanfile(File dir, File f, String javapackage) {
if (f.exists()) {
if (f.isDirectory() && recurse)
scandir(f, javapackage != null? javapackage + "." + f.getName(): f.getName());
else if (f.isFile() && f.getName().endsWith(".lua"))
files.add(new InputFile(dir, f, javapackage));
}
}
private static final class LocalClassLoader extends ClassLoader {
private final Hashtable t;
private LocalClassLoader(Hashtable t) {
this.t = t;
}
@Override
public Class findClass(String classname) throws ClassNotFoundException {
byte[] bytes = (byte[]) t.get(classname);
if (bytes != null)
return defineClass(classname, bytes, 0, bytes.length);
return super.findClass(classname);
}
}
class InputFile {
public String luachunkname;
public String srcfilename;
public File infile;
public File outdir;
public String javapackage;
public InputFile(File dir, File f, String javapackage) {
this.infile = f;
String subdir = javapackage != null? javapackage.replace('.', '/'): null;
String outdirpath = subdir != null? destdir + "/" + subdir: destdir;
this.javapackage = javapackage;
this.srcfilename = (subdir != null? subdir + "/": "")+infile.getName();
this.luachunkname = (subdir != null? subdir + "/": "")
+infile.getName().substring(0, infile.getName().lastIndexOf('.'));
this.infile = f;
this.outdir = new File(outdirpath);
}
}
private void processFile(InputFile inf) {
inf.outdir.mkdirs();
try {
if (verbose)
System.out.println("chunk=" + inf.luachunkname + " srcfile=" + inf.srcfilename);
// create the chunk
FileInputStream fis = new FileInputStream(inf.infile);
final Hashtable t = encoding != null
? LuaJC.instance.compileAll(new InputStreamReader(fis, encoding), inf.luachunkname, inf.srcfilename,
globals, genmain)
: LuaJC.instance.compileAll(fis, inf.luachunkname, inf.srcfilename, globals, genmain);
fis.close();
// write out the chunk
for (Enumeration e = t.keys(); e.hasMoreElements();) {
String key = (String) e.nextElement();
byte[] bytes = (byte[]) t.get(key);
if (key.indexOf('/') >= 0) {
String d = (destdir != null? destdir + "/": "")+key.substring(0, key.lastIndexOf('/'));
new File(d).mkdirs();
}
String destpath = (destdir != null? destdir + "/": "") + key + ".class";
if (verbose)
System.out.println(" " + destpath + " (" + bytes.length + " bytes)");
FileOutputStream fos = new FileOutputStream(destpath);
fos.write(bytes);
fos.close();
}
// try to load the files
if (loadclasses) {
ClassLoader loader = new LocalClassLoader(t);
for (Enumeration e = t.keys(); e.hasMoreElements();) {
String classname = (String) e.nextElement();
try {
Class c = loader.loadClass(classname);
Object o = c.newInstance();
if (verbose)
System.out.println(" loaded " + classname + " as " + o);
} catch (Exception ex) {
System.out.flush();
System.err.println(" failed to load " + classname + ": " + ex);
System.err.flush();
}
}
}
} catch (Exception e) {
System.err.println(" failed to load " + inf.srcfilename + ": " + e);
e.printStackTrace(System.err);
System.err.flush();
}
}
}

View File

@@ -26,7 +26,7 @@ import java.util.List;
public class Block extends Stat { public class Block extends Stat {
public List<Stat> stats = new ArrayList<Stat>(); public List<Stat> stats = new ArrayList<>();
public NameScope scope; public NameScope scope;
public void add(Stat s) { public void add(Stat s) {
@@ -35,6 +35,7 @@ public class Block extends Stat {
stats.add(s); stats.add(s);
} }
@Override
public void accept(Visitor visitor) { public void accept(Visitor visitor) {
visitor.visit(this); visitor.visit(this);
} }

View File

@@ -24,8 +24,7 @@ package org.luaj.vm2.ast;
import org.luaj.vm2.Lua; import org.luaj.vm2.Lua;
import org.luaj.vm2.LuaValue; import org.luaj.vm2.LuaValue;
abstract abstract public class Exp extends SyntaxElement {
public class Exp extends SyntaxElement {
abstract public void accept(Visitor visitor); abstract public void accept(Visitor visitor);
public static Exp constant(LuaValue value) { public static Exp constant(LuaValue value) {
@@ -63,14 +62,12 @@ public class Exp extends SyntaxElement {
// TODO: constant folding // TODO: constant folding
if (lhs instanceof BinopExp) { if (lhs instanceof BinopExp) {
BinopExp b = (BinopExp) lhs; BinopExp b = (BinopExp) lhs;
if ( (precedence(op) > precedence(b.op)) || if (precedence(op) > precedence(b.op) || precedence(op) == precedence(b.op) && isrightassoc(op))
((precedence(op) == precedence(b.op)) && isrightassoc(op)) )
return binaryexp(b.lhs, b.op, binaryexp(b.rhs, op, rhs)); return binaryexp(b.lhs, b.op, binaryexp(b.rhs, op, rhs));
} }
if (rhs instanceof BinopExp) { if (rhs instanceof BinopExp) {
BinopExp b = (BinopExp) rhs; BinopExp b = (BinopExp) rhs;
if ( (precedence(op) > precedence(b.op)) || if (precedence(op) > precedence(b.op) || precedence(op) == precedence(b.op) && !isrightassoc(op))
((precedence(op) == precedence(b.op)) && ! isrightassoc(op)) )
return binaryexp(binaryexp(lhs, op, b.lhs), b.op, b.rhs); return binaryexp(binaryexp(lhs, op, b.lhs), b.op, b.rhs);
} }
return new BinopExp(lhs, op, rhs); return new BinopExp(lhs, op, rhs);
@@ -79,22 +76,43 @@ public class Exp extends SyntaxElement {
static boolean isrightassoc(int op) { static boolean isrightassoc(int op) {
switch (op) { switch (op) {
case Lua.OP_CONCAT: case Lua.OP_CONCAT:
case Lua.OP_POW: return true; case Lua.OP_POW:
default: return false; return true;
default:
return false;
} }
} }
static int precedence(int op) { static int precedence(int op) {
switch (op) { switch (op) {
case Lua.OP_OR: return 0; case Lua.OP_OR:
case Lua.OP_AND: return 1; return 0;
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_AND:
case Lua.OP_CONCAT: return 3; return 1;
case Lua.OP_ADD: case Lua.OP_SUB: return 4; case Lua.OP_LT:
case Lua.OP_MUL: case Lua.OP_DIV: case Lua.OP_MOD: return 5; case Lua.OP_GT:
case Lua.OP_NOT: case Lua.OP_UNM: case Lua.OP_LEN: return 6; case Lua.OP_LE:
case Lua.OP_POW: return 7; case Lua.OP_GE:
default: throw new IllegalStateException("precedence of bad op "+op); 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);
} }
} }
@@ -145,30 +163,40 @@ public class Exp extends SyntaxElement {
} }
abstract public static class PrimaryExp extends Exp { abstract public static class PrimaryExp extends Exp {
@Override
public boolean isvarexp() { public boolean isvarexp() {
return false; return false;
} }
@Override
public boolean isfunccall() { public boolean isfunccall() {
return false; return false;
} }
} }
abstract public static class VarExp extends PrimaryExp { abstract public static class VarExp extends PrimaryExp {
@Override
public boolean isvarexp() { public boolean isvarexp() {
return true; return true;
} }
public void markHasAssignment() { public void markHasAssignment() {
} }
} }
public static class NameExp extends VarExp { public static class NameExp extends VarExp {
public final Name name; public final Name name;
public NameExp(String name) { public NameExp(String name) {
this.name = new Name(name); this.name = new Name(name);
} }
@Override
public void markHasAssignment() { public void markHasAssignment() {
name.variable.hasassignments = true; name.variable.hasassignments = true;
} }
@Override
public void accept(Visitor visitor) { public void accept(Visitor visitor) {
visitor.visit(this); visitor.visit(this);
} }
@@ -176,10 +204,12 @@ public class Exp extends SyntaxElement {
public static class ParensExp extends PrimaryExp { public static class ParensExp extends PrimaryExp {
public final Exp exp; public final Exp exp;
public ParensExp(Exp exp) { public ParensExp(Exp exp) {
this.exp = exp; this.exp = exp;
} }
@Override
public void accept(Visitor visitor) { public void accept(Visitor visitor) {
visitor.visit(this); visitor.visit(this);
} }
@@ -188,11 +218,13 @@ public class Exp extends SyntaxElement {
public static class FieldExp extends VarExp { public static class FieldExp extends VarExp {
public final PrimaryExp lhs; public final PrimaryExp lhs;
public final Name name; public final Name name;
public FieldExp(PrimaryExp lhs, String name) { public FieldExp(PrimaryExp lhs, String name) {
this.lhs = lhs; this.lhs = lhs;
this.name = new Name(name); this.name = new Name(name);
} }
@Override
public void accept(Visitor visitor) { public void accept(Visitor visitor) {
visitor.visit(this); visitor.visit(this);
} }
@@ -201,11 +233,13 @@ public class Exp extends SyntaxElement {
public static class IndexExp extends VarExp { public static class IndexExp extends VarExp {
public final PrimaryExp lhs; public final PrimaryExp lhs;
public final Exp exp; public final Exp exp;
public IndexExp(PrimaryExp lhs, Exp exp) { public IndexExp(PrimaryExp lhs, Exp exp) {
this.lhs = lhs; this.lhs = lhs;
this.exp = exp; this.exp = exp;
} }
@Override
public void accept(Visitor visitor) { public void accept(Visitor visitor) {
visitor.visit(this); visitor.visit(this);
} }
@@ -220,14 +254,17 @@ public class Exp extends SyntaxElement {
this.args = args; this.args = args;
} }
@Override
public boolean isfunccall() { public boolean isfunccall() {
return true; return true;
} }
@Override
public void accept(Visitor visitor) { public void accept(Visitor visitor) {
visitor.visit(this); visitor.visit(this);
} }
@Override
public boolean isvarargexp() { public boolean isvarargexp() {
return true; return true;
} }
@@ -241,10 +278,12 @@ public class Exp extends SyntaxElement {
this.name = new String(name); this.name = new String(name);
} }
@Override
public boolean isfunccall() { public boolean isfunccall() {
return true; return true;
} }
@Override
public void accept(Visitor visitor) { public void accept(Visitor visitor) {
visitor.visit(this); visitor.visit(this);
} }
@@ -252,10 +291,12 @@ public class Exp extends SyntaxElement {
public static class Constant extends Exp { public static class Constant extends Exp {
public final LuaValue value; public final LuaValue value;
public Constant(LuaValue value) { public Constant(LuaValue value) {
this.value = value; this.value = value;
} }
@Override
public void accept(Visitor visitor) { public void accept(Visitor visitor) {
visitor.visit(this); visitor.visit(this);
} }
@@ -263,10 +304,12 @@ public class Exp extends SyntaxElement {
public static class VarargsExp extends Exp { public static class VarargsExp extends Exp {
@Override
public void accept(Visitor visitor) { public void accept(Visitor visitor) {
visitor.visit(this); visitor.visit(this);
} }
@Override
public boolean isvarargexp() { public boolean isvarargexp() {
return true; return true;
} }
@@ -275,11 +318,13 @@ public class Exp extends SyntaxElement {
public static class UnopExp extends Exp { public static class UnopExp extends Exp {
public final int op; public final int op;
public final Exp rhs; public final Exp rhs;
public UnopExp(int op, Exp rhs) { public UnopExp(int op, Exp rhs) {
this.op = op; this.op = op;
this.rhs = rhs; this.rhs = rhs;
} }
@Override
public void accept(Visitor visitor) { public void accept(Visitor visitor) {
visitor.visit(this); visitor.visit(this);
} }
@@ -288,12 +333,14 @@ public class Exp extends SyntaxElement {
public static class BinopExp extends Exp { public static class BinopExp extends Exp {
public final Exp lhs, rhs; public final Exp lhs, rhs;
public final int op; public final int op;
public BinopExp(Exp lhs, int op, Exp rhs) { public BinopExp(Exp lhs, int op, Exp rhs) {
this.lhs = lhs; this.lhs = lhs;
this.op = op; this.op = op;
this.rhs = rhs; this.rhs = rhs;
} }
@Override
public void accept(Visitor visitor) { public void accept(Visitor visitor) {
visitor.visit(this); visitor.visit(this);
} }
@@ -301,10 +348,12 @@ public class Exp extends SyntaxElement {
public static class AnonFuncDef extends Exp { public static class AnonFuncDef extends Exp {
public final FuncBody body; public final FuncBody body;
public AnonFuncDef(FuncBody funcbody) { public AnonFuncDef(FuncBody funcbody) {
this.body = funcbody; this.body = funcbody;
} }
@Override
public void accept(Visitor visitor) { public void accept(Visitor visitor) {
visitor.visit(this); visitor.visit(this);
} }

View File

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

View File

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

View File

@@ -42,7 +42,7 @@ public class FuncName extends SyntaxElement {
public void adddot(String dot) { public void adddot(String dot) {
if (dots == null) if (dots == null)
dots = new ArrayList<String>(); dots = new ArrayList<>();
dots.add(dot); dots.add(dot);
} }

View File

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

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