Compare commits
203 Commits
v3.0.1
...
asiekierka
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ac261965a8 | ||
|
|
342d940b5e | ||
|
|
a3507cf771 | ||
|
|
0775cc6c59 | ||
|
|
f87e3726a4 | ||
|
|
a4d95841e4 | ||
|
|
c8c2c29d62 | ||
|
|
67962d4cc3 | ||
|
|
9a65948e26 | ||
|
|
66130964c6 | ||
|
|
abe14ca995 | ||
|
|
30a3a472bc | ||
|
|
e87d9ceee4 | ||
|
|
3e9ae5c524 | ||
|
|
ddba10c180 | ||
|
|
39e9be0a2d | ||
|
|
b1322640ca | ||
|
|
99bd46876e | ||
|
|
23ae7cdc06 | ||
|
|
942dc4afa3 | ||
|
|
11ec746838 | ||
|
|
b8b951b7c9 | ||
|
|
1f9a874979 | ||
|
|
b121b65151 | ||
|
|
5851e6994a | ||
|
|
5984ec6097 | ||
|
|
4802623aa3 | ||
|
|
2fdcf5e2ac | ||
|
|
560a4694e4 | ||
|
|
6b9dece367 | ||
|
|
179062493d | ||
|
|
f81bc1e174 | ||
|
|
bf23883492 | ||
|
|
5465eff841 | ||
|
|
ddc7531845 | ||
|
|
58a4dec882 | ||
|
|
f91cc9a509 | ||
|
|
9792fcb018 | ||
|
|
1a6de4a227 | ||
|
|
1833c57d4d | ||
|
|
e7e6190f9c | ||
|
|
3c266bcc98 | ||
|
|
d2a92c07d3 | ||
|
|
a58147ddfa | ||
|
|
74e5ef6f36 | ||
|
|
a9d475bbbf | ||
|
|
daf3da94e3 | ||
|
|
30e60a883e | ||
|
|
27edcc9a92 | ||
|
|
d6737c0bb3 | ||
|
|
d201bc3012 | ||
|
|
ca64666242 | ||
|
|
725cf89b6f | ||
|
|
da0b06555a | ||
|
|
ee2d5284e7 | ||
|
|
0f0ec4bf7b | ||
|
|
5813d56f89 | ||
|
|
8c42c4712b | ||
|
|
6bc8fd6b1b | ||
|
|
bf663878cb | ||
|
|
e120008f9b | ||
|
|
9a20aa8077 | ||
|
|
99f21b6277 | ||
|
|
53bd4bf71f | ||
|
|
b57eb247ba | ||
|
|
05e82f1c3f | ||
|
|
9b2f0a2805 | ||
|
|
ef8175050b | ||
|
|
0d2aa6cc54 | ||
|
|
fe7bd07450 | ||
|
|
f0e9348ae2 | ||
|
|
22e7a8c620 | ||
|
|
c8461b8128 | ||
|
|
3a6c382570 | ||
|
|
4db34780b7 | ||
|
|
ac3475deee | ||
|
|
af35c4d89e | ||
|
|
c71f277697 | ||
|
|
5fe0a3950d | ||
|
|
169202362e | ||
|
|
5609d8c92b | ||
|
|
dbab0aed01 | ||
|
|
f8d7731b56 | ||
|
|
2f5aa594bd | ||
|
|
edfe1a5fde | ||
|
|
6efb6f000e | ||
|
|
f3b8a1eddc | ||
|
|
20eca5760d | ||
|
|
3613bc0862 | ||
|
|
6985980572 | ||
|
|
60d130cecc | ||
|
|
b705eb05f4 | ||
|
|
d0bb0409a3 | ||
|
|
db58e1808b | ||
|
|
e2ede7f91c | ||
|
|
a50deaa75c | ||
|
|
f9f78b81da | ||
|
|
984fa30bf6 | ||
|
|
65beda4c2b | ||
|
|
934a8fc57b | ||
|
|
832ec739ea | ||
|
|
8345bee6b4 | ||
|
|
83f2e1d96a | ||
|
|
14745ba76a | ||
|
|
c62ba1f22e | ||
|
|
868928779f | ||
|
|
f383c27728 | ||
|
|
e7b11110a3 | ||
|
|
0fa27c3783 | ||
|
|
72a71e5a65 | ||
|
|
6031d6b479 | ||
|
|
a071b04b8f | ||
|
|
11b29f92c1 | ||
|
|
c666a507ab | ||
|
|
5026b5ac1e | ||
|
|
6ba28727d2 | ||
|
|
0707e71c6c | ||
|
|
43f937470f | ||
|
|
5d3f2eb72c | ||
|
|
244eb4b1a1 | ||
|
|
626664a0fe | ||
|
|
2bccb4670e | ||
|
|
89acb5bcb5 | ||
|
|
c69585332b | ||
|
|
c9fa0f27c7 | ||
|
|
af4cfe5e00 | ||
|
|
c1834733c1 | ||
|
|
10f88d2c31 | ||
|
|
6d2deb4cb6 | ||
|
|
5f52729fc9 | ||
|
|
e6736857b6 | ||
|
|
5c5176727a | ||
|
|
7721380e20 | ||
|
|
16aa199d40 | ||
|
|
177fe4e09f | ||
|
|
a7c8a408ce | ||
|
|
84b0dd171e | ||
|
|
898208365d | ||
|
|
ffb686556f | ||
|
|
6694c375c9 | ||
|
|
e70eb5edc2 | ||
|
|
9688d3c5fc | ||
|
|
6f5af581e8 | ||
|
|
870aee2cae | ||
|
|
c2ec9edf39 | ||
|
|
cfb3aaca61 | ||
|
|
4105cebf1e | ||
|
|
339f004eb7 | ||
|
|
05a604645d | ||
|
|
63ead7aac7 | ||
|
|
c9ba2d4bb1 | ||
|
|
92cee0812d | ||
|
|
e61e5694fa | ||
|
|
47f8d6e6fc | ||
|
|
14ac4bb7f9 | ||
|
|
b8aaaafb68 | ||
|
|
88a557033b | ||
|
|
24a8559ceb | ||
|
|
028e03e4bc | ||
|
|
5c1f7d2ab2 | ||
|
|
9db1254160 | ||
|
|
f899c709ff | ||
|
|
9c9e193cc4 | ||
|
|
e9db487d97 | ||
|
|
c6fe5d3ed3 | ||
|
|
52ab872d08 | ||
|
|
5d3041c6be | ||
|
|
8d544729a8 | ||
|
|
bd57dddef0 | ||
|
|
d509e21cc6 | ||
|
|
5b67841232 | ||
|
|
bd4dac18ff | ||
|
|
e02a82ef8d | ||
|
|
70a5086097 | ||
|
|
ad20f939b1 | ||
|
|
e7058bcd6a | ||
|
|
00c7e266ba | ||
|
|
e75c5e2fca | ||
|
|
ed46675a25 | ||
|
|
8fbca25dce | ||
|
|
d0ed5b80e5 | ||
|
|
9b77084109 | ||
|
|
4f410fba6e | ||
|
|
f164c1cd28 | ||
|
|
63ca0f94af | ||
|
|
5bd9827af1 | ||
|
|
0a5cccc50f | ||
|
|
12aded74ca | ||
|
|
48dd90f6d7 | ||
|
|
6333d9acf7 | ||
|
|
d61ed707ef | ||
|
|
1e521d8900 | ||
|
|
bf8ef8d1a9 | ||
|
|
69498dbb7c | ||
|
|
4cc5f4270d | ||
|
|
75fa98d13f | ||
|
|
a627a868d5 | ||
|
|
f073919f64 | ||
|
|
27a1dcdd11 | ||
|
|
b459724103 | ||
|
|
3d22990e3c | ||
|
|
194b776317 | ||
|
|
828e4be019 |
19
.classpath
19
.classpath
@@ -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
17
.gitignore
vendored
@@ -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
138
.ide/cleanup.xml
Normal 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
390
.ide/formatter.xml
Normal 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>
|
||||||
17
.project
17
.project
@@ -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>
|
|
||||||
21
LICENSE
Normal file
21
LICENSE
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2007 LuaJ. 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.
|
||||||
@@ -1,27 +1,24 @@
|
|||||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
# This is a fork!
|
||||||
<html>
|
<div style="border: 1px dotted red; margin: 1.em 0.5em; font-weight: bold; color: red;">
|
||||||
|
This repository has been forked from the original CVS sources of Luaj.
|
||||||
|
The commit history has been converted to make sure that the original work of
|
||||||
|
James Roseborough and Ian Farmer is not lost.
|
||||||
|
Unfortunately, I was not able to contact either James or Ian to hand over
|
||||||
|
ownership of the Github organization/repo as I have originally intended to.
|
||||||
|
The community however seems interested enough to continue work on the original
|
||||||
|
sources and therefore I have decided to make sure that any useful pull requests
|
||||||
|
that may add some value to the original code base shall be merged in from now
|
||||||
|
on.<br>
|
||||||
|
-- Benjamin P. Jung, Jan. 26th 2018
|
||||||
|
</div>
|
||||||
|
|
||||||
<head>
|
<h1>Getting Started with LuaJ</h1>
|
||||||
<title>Getting Started with LuaJ</title>
|
James Roseborough, Ian Farmer, Version 3.0.2
|
||||||
<link rel="stylesheet" type="text/css" href="http://www.lua.org/lua.css">
|
|
||||||
<META HTTP-EQUIV="content-type" CONTENT="text/html; charset=iso-8859-1">
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body>
|
|
||||||
|
|
||||||
<hr>
|
|
||||||
<h1>
|
|
||||||
<a href="README.html"><img src="http://sourceforge.net/dbimage.php?id=196139" alt="" border="0"></a>
|
|
||||||
|
|
||||||
Getting Started with LuaJ
|
|
||||||
|
|
||||||
</h1>
|
|
||||||
James Roseborough, Ian Farmer, Version 3.0.1
|
|
||||||
<p>
|
<p>
|
||||||
<small>
|
<small>
|
||||||
Copyright © 2009-2014 Luaj.org.
|
Copyright © 2009-2014 Luaj.org.
|
||||||
Freely available under the terms of the
|
Freely available under the terms of the
|
||||||
<a href="http://sourceforge.net/dbimage.php?id=196142">Luaj license</a>.
|
<a href="LICENSE">Luaj license</a>.
|
||||||
</small>
|
</small>
|
||||||
<hr>
|
<hr>
|
||||||
<p>
|
<p>
|
||||||
@@ -120,7 +117,7 @@ in comparison with the standard C distribution.
|
|||||||
<td>16.794</td>
|
<td>16.794</td>
|
||||||
<td>11.274</td>
|
<td>11.274</td>
|
||||||
<td>Java</td>
|
<td>Java</td>
|
||||||
<td>java -cp luaj-jse-3.0.1.jar;bcel-5.2.jar lua <b>-b</b> fannkuch.lua 10</td></tr>
|
<td>java -cp luaj-jse-3.0.2.jar;bcel-5.2.jar lua <b>-b</b> fannkuch.lua 10</td></tr>
|
||||||
<tr valign="top">
|
<tr valign="top">
|
||||||
<td></td>
|
<td></td>
|
||||||
<td></td>
|
<td></td>
|
||||||
@@ -130,7 +127,7 @@ in comparison with the standard C distribution.
|
|||||||
<td>36.894</td>
|
<td>36.894</td>
|
||||||
<td>15.163</td>
|
<td>15.163</td>
|
||||||
<td></td>
|
<td></td>
|
||||||
<td>java -cp luaj-jse-3.0.1.jar lua -n fannkuch.lua 10</td></tr>
|
<td>java -cp luaj-jse-3.0.2.jar lua -n fannkuch.lua 10</td></tr>
|
||||||
<tr valign="top">
|
<tr valign="top">
|
||||||
<td>lua</td>
|
<td>lua</td>
|
||||||
<td>5.1.4</td>
|
<td>5.1.4</td>
|
||||||
@@ -186,7 +183,7 @@ It is also faster than Java-lua implementations Jill, Kahlua, and Mochalua for a
|
|||||||
From the main distribution directory line type:
|
From the main distribution directory line type:
|
||||||
|
|
||||||
<pre>
|
<pre>
|
||||||
java -cp lib/luaj-jse-3.0.1.jar lua examples/lua/hello.lua
|
java -cp luaj-jse-3.0.2.jar lua examples/lua/hello.lua
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
@@ -198,7 +195,7 @@ You should see the following output:
|
|||||||
To see how luaj can be used to acccess most Java API's including swing, try:
|
To see how luaj can be used to acccess most Java API's including swing, try:
|
||||||
|
|
||||||
<pre>
|
<pre>
|
||||||
java -cp lib/luaj-jse-3.0.1.jar lua examples/lua/swingapp.lua
|
java -cp luaj-jse-3.0.2.jar lua examples/lua/swingapp.lua
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
@@ -213,8 +210,8 @@ Links to sources:<pre>
|
|||||||
From the main distribution directory line type:
|
From the main distribution directory line type:
|
||||||
|
|
||||||
<pre>
|
<pre>
|
||||||
java -cp lib/luaj-jse-3.0.1.jar luac examples/lua/hello.lua
|
java -cp luaj-jse-3.0.2.jar luac examples/lua/hello.lua
|
||||||
java -cp lib/luaj-jse-3.0.1.jar lua luac.out
|
java -cp luaj-jse-3.0.2.jar lua luac.out
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
@@ -228,8 +225,8 @@ Luaj can compile lua sources or binaries directly to java bytecode if the bcel l
|
|||||||
|
|
||||||
<pre>
|
<pre>
|
||||||
ant bcel-lib
|
ant bcel-lib
|
||||||
java -cp "lib/luaj-jse-3.0.1.jar;lib/bcel-5.2.jar" luajc -s examples/lua -d . hello.lua
|
java -cp "luaj-jse-3.0.2.jar;lib/bcel-5.2.jar" luajc -s examples/lua -d . hello.lua
|
||||||
java -cp "lib/luaj-jse-3.0.1.jar;." lua -l hello
|
java -cp "luaj-jse-3.0.2.jar;." lua -l hello
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
@@ -240,7 +237,7 @@ but the compiled classes must be in the class path at runtime, unless runtime ji
|
|||||||
<p>
|
<p>
|
||||||
Lua scripts can also be run directly in this mode without precompiling using the <em>lua</em> command with the <b><em>-b</em></b> option and providing the <em>bcel</em> library in the class path:
|
Lua scripts can also be run directly in this mode without precompiling using the <em>lua</em> command with the <b><em>-b</em></b> option and providing the <em>bcel</em> library in the class path:
|
||||||
<pre>
|
<pre>
|
||||||
java -cp "lib/luaj-jse-3.0.1.jar;lib/bcel-5.2.jar" lua -b examples/lua/hello.lua
|
java -cp "luaj-jse-3.0.2.jar;lib/bcel-5.2.jar" lua -b examples/lua/hello.lua
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
|
|
||||||
@@ -284,7 +281,7 @@ A simple example may be found in
|
|||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
You must include the library <b>lib/luaj-jse-3.0.1.jar</b> in your class path.
|
You must include the library <b>luaj-jse-3.0.2.jar</b> in your class path.
|
||||||
|
|
||||||
<h2>Run a script in a MIDlet</h2>
|
<h2>Run a script in a MIDlet</h2>
|
||||||
|
|
||||||
@@ -311,7 +308,7 @@ A simple example may be found in
|
|||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
You must include the library <b>lib/luaj-jme-3.0.1.jar</b> in your midlet jar.
|
You must include the library <b>luaj-jme-3.0.2.jar</b> in your midlet jar.
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
An ant script to build and run the midlet is in
|
An ant script to build and run the midlet is in
|
||||||
@@ -341,7 +338,7 @@ You can also look up the engine by language "lua" or mimetypes "text/lua" or "ap
|
|||||||
All standard aspects of script engines including compiled statements are supported.
|
All standard aspects of script engines including compiled statements are supported.
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
You must include the library <b>lib/luaj-jse-3.0.1.jar</b> in your class path.
|
You must include the library <b>luaj-jse-3.0.2.jar</b> in your class path.
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
A working example may be found in
|
A working example may be found in
|
||||||
@@ -352,8 +349,8 @@ A working example may be found in
|
|||||||
To compile and run it using Java 1.6 or higher:
|
To compile and run it using Java 1.6 or higher:
|
||||||
|
|
||||||
<pre>
|
<pre>
|
||||||
javac -cp lib/luaj-jse-3.0.1.jar examples/jse/ScriptEngineSample.java
|
javac -cp luaj-jse-3.0.2.jar examples/jse/ScriptEngineSample.java
|
||||||
java -cp "lib/luaj-jse-3.0.1.jar;examples/jse" ScriptEngineSample
|
java -cp "luaj-jse-3.0.2.jar;examples/jse" ScriptEngineSample
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
<h2>Excluding the lua bytecode compiler</h2>
|
<h2>Excluding the lua bytecode compiler</h2>
|
||||||
@@ -415,7 +412,7 @@ and the math operations include all those supported by Java SE.
|
|||||||
Android applications should use the JsePlatform, and can include the <a href="#luajava">Luajava</a> library
|
Android applications should use the JsePlatform, and can include the <a href="#luajava">Luajava</a> library
|
||||||
to simplify access to underlying Android APIs.
|
to simplify access to underlying Android APIs.
|
||||||
A specialized Globals.finder should be provided to find scripts and data for loading.
|
A specialized Globals.finder should be provided to find scripts and data for loading.
|
||||||
See <a href="examples/android/src/android/LuajView">examples/android/src/android/LuajView</a>
|
See <a href="examples/android/src/android/LuajView.java">examples/android/src/android/LuajView.java</a>
|
||||||
for an example that loads from the "res" Android project directory.
|
for an example that loads from the "res" Android project directory.
|
||||||
The ant build script is <a href="examples/android/build.xml">examples/android/build.xml</a>.
|
The ant build script is <a href="examples/android/build.xml">examples/android/build.xml</a>.
|
||||||
|
|
||||||
@@ -593,7 +590,7 @@ The following lua script will open a swing frame on Java SE:
|
|||||||
See a longer sample in <em>examples/lua/swingapp.lua</em> for details, including a simple animation loop, rendering graphics, mouse and key handling, and image loading.
|
See a longer sample in <em>examples/lua/swingapp.lua</em> for details, including a simple animation loop, rendering graphics, mouse and key handling, and image loading.
|
||||||
Or try running it using:
|
Or try running it using:
|
||||||
<pre>
|
<pre>
|
||||||
java -cp lib/luaj-jse-3.0.1.jar lua examples/lua/swingapp.lua
|
java -cp luaj-jse-3.0.2.jar lua examples/lua/swingapp.lua
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
@@ -842,7 +839,7 @@ For JSE projects, add this dependency for the luaj-jse jar:
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.luaj</groupId>
|
<groupId>org.luaj</groupId>
|
||||||
<artifactId>luaj-jse</artifactId>
|
<artifactId>luaj-jse</artifactId>
|
||||||
<version>3.0.1</version>
|
<version>3.0.2</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
</pre>
|
</pre>
|
||||||
while for JME projects, use the luaj-jme jar:
|
while for JME projects, use the luaj-jme jar:
|
||||||
@@ -850,7 +847,7 @@ while for JME projects, use the luaj-jme jar:
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.luaj</groupId>
|
<groupId>org.luaj</groupId>
|
||||||
<artifactId>luaj-jme</artifactId>
|
<artifactId>luaj-jme</artifactId>
|
||||||
<version>3.0.1</version>
|
<version>3.0.2</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
@@ -861,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.1-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>
|
||||||
|
|
||||||
@@ -930,7 +920,7 @@ Files are no longer hosted at LuaForge.
|
|||||||
<li>Enhance javadoc, put it <a href="docs/api/index.html">in distribution</a>
|
<li>Enhance javadoc, put it <a href="docs/api/index.html">in distribution</a>
|
||||||
and at <a href="http://luaj.sourceforge.net/api/2.0/index.html">http://luaj.sourceforge.net/api/2.0/</a></li>
|
and at <a href="http://luaj.sourceforge.net/api/2.0/index.html">http://luaj.sourceforge.net/api/2.0/</a></li>
|
||||||
<li>Major refactor of luajava type coercion logic, improve method selection.</li>
|
<li>Major refactor of luajava type coercion logic, improve method selection.</li>
|
||||||
<li>Add lib/luaj-sources-2.0.2.jar for easier integration into an IDE such as Netbeans </li>
|
<li>Add luaj-sources-2.0.2.jar for easier integration into an IDE such as Netbeans </li>
|
||||||
|
|
||||||
<tr valign="top"><td> <b>2.0.3</b></td><td><ul>
|
<tr valign="top"><td> <b>2.0.3</b></td><td><ul>
|
||||||
<li>Improve coroutine state logic including let unreferenced coroutines be garbage collected </li>
|
<li>Improve coroutine state logic including let unreferenced coroutines be garbage collected </li>
|
||||||
@@ -1017,6 +1007,11 @@ and at <a href="http://luaj.sourceforge.net/api/2.0/index.html">http://luaj.sour
|
|||||||
<li>Move online docs to <a href="http://luaj.org/luaj/3.0/api/index.html">http://luaj.org/luaj/3.0/api/</a></li>
|
<li>Move online docs to <a href="http://luaj.org/luaj/3.0/api/index.html">http://luaj.org/luaj/3.0/api/</a></li>
|
||||||
<li>Fix os.time() conversions for pm times.</li>
|
<li>Fix os.time() conversions for pm times.</li>
|
||||||
|
|
||||||
|
<tr valign="top"><td> <b>3.0.2</b></td><td><ul>
|
||||||
|
<li>Fix JsePlatform.luaMain() to provide an "arg" table in the chunk's environment.</li>
|
||||||
|
<li>Let JsePlatform.luaMain() return values returned by the main chunk.</li>
|
||||||
|
<li>Add synchronization to CoerceJavaToLua.COERCIONS map.</li>
|
||||||
|
|
||||||
</ul></td></tr>
|
</ul></td></tr>
|
||||||
</table></td></tr></table>
|
</table></td></tr></table>
|
||||||
|
|
||||||
108
build-app.xml
108
build-app.xml
@@ -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>
|
|
||||||
116
build-applet.xml
116
build-applet.xml
@@ -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>
|
|
||||||
@@ -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>
|
|
||||||
@@ -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>
|
|
||||||
176
build-maven.xml
176
build-maven.xml
@@ -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 © 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>
|
|
||||||
113
build-midlet.xml
113
build-midlet.xml
@@ -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>
|
|
||||||
@@ -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>
|
|
||||||
208
build.xml
208
build.xml
@@ -1,208 +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='<String>' to=''/></tokenfilter>
|
|
||||||
<tokenfilter><replacestring from='<Stat>' to=''/></tokenfilter>
|
|
||||||
<tokenfilter><replacestring from='<Exp>' to=''/></tokenfilter>
|
|
||||||
<tokenfilter><replacestring from='<Name>' to=''/></tokenfilter>
|
|
||||||
<tokenfilter><replacestring from='<Block>' to=''/></tokenfilter>
|
|
||||||
<tokenfilter><replacestring from='<TableField>' to=''/></tokenfilter>
|
|
||||||
<tokenfilter><replacestring from='<VarExp>' to=''/></tokenfilter>
|
|
||||||
<tokenfilter><replacestring from='<Exp.VarExp>' to=''/></tokenfilter>
|
|
||||||
<tokenfilter><replacestring from='<Object,String>' to=''/></tokenfilter>
|
|
||||||
<tokenfilter><replacestring from='<Double,String>' to=''/></tokenfilter>
|
|
||||||
<tokenfilter><replacestring from='<Integer,Integer>' to=''/></tokenfilter>
|
|
||||||
<tokenfilter><replacestring from='<Integer,LocalVariableGen>' to=''/></tokenfilter>
|
|
||||||
<tokenfilter><replacestring from='<Exp,Integer>' to=''/></tokenfilter>
|
|
||||||
<tokenfilter><replacestring from='<String,byte[]>' to=''/></tokenfilter>
|
|
||||||
<tokenfilter><replacestring from='<String,Variable>' to=''/></tokenfilter>
|
|
||||||
<tokenfilter><replacestring from='<LuaValue,String>' to=''/></tokenfilter>
|
|
||||||
<tokenfilter><replacestring from='<LuaString,String>' 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"
|
|
||||||
srcdir="build/jme/src"/>
|
|
||||||
<javac destdir="build/jse/classes" encoding="utf-8" source="1.3" target="1.3"
|
|
||||||
classpath="lib/bcel-5.2.jar"
|
|
||||||
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"
|
|
||||||
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"
|
|
||||||
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 © 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>
|
|
||||||
@@ -11,13 +11,13 @@ import org.luaj.vm2.lib.Bit32Lib;
|
|||||||
import org.luaj.vm2.lib.CoroutineLib;
|
import org.luaj.vm2.lib.CoroutineLib;
|
||||||
import org.luaj.vm2.lib.PackageLib;
|
import org.luaj.vm2.lib.PackageLib;
|
||||||
import org.luaj.vm2.lib.ResourceFinder;
|
import org.luaj.vm2.lib.ResourceFinder;
|
||||||
import org.luaj.vm2.lib.StringLib;
|
|
||||||
import org.luaj.vm2.lib.TableLib;
|
import org.luaj.vm2.lib.TableLib;
|
||||||
import org.luaj.vm2.lib.jse.CoerceJavaToLua;
|
import org.luaj.vm2.lib.jse.CoerceJavaToLua;
|
||||||
import org.luaj.vm2.lib.jse.JseBaseLib;
|
import org.luaj.vm2.lib.jse.JseBaseLib;
|
||||||
import org.luaj.vm2.lib.jse.JseIoLib;
|
import org.luaj.vm2.lib.jse.JseIoLib;
|
||||||
import org.luaj.vm2.lib.jse.JseMathLib;
|
import org.luaj.vm2.lib.jse.JseMathLib;
|
||||||
import org.luaj.vm2.lib.jse.JseOsLib;
|
import org.luaj.vm2.lib.jse.JseOsLib;
|
||||||
|
import org.luaj.vm2.lib.jse.JseStringLib;
|
||||||
import org.luaj.vm2.lib.jse.LuajavaLib;
|
import org.luaj.vm2.lib.jse.LuajavaLib;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -76,7 +76,7 @@ public class SampleApplet extends Applet implements ResourceFinder {
|
|||||||
globals.load(new PackageLib());
|
globals.load(new PackageLib());
|
||||||
globals.load(new Bit32Lib());
|
globals.load(new Bit32Lib());
|
||||||
globals.load(new TableLib());
|
globals.load(new TableLib());
|
||||||
globals.load(new StringLib());
|
globals.load(new JseStringLib());
|
||||||
globals.load(new CoroutineLib());
|
globals.load(new CoroutineLib());
|
||||||
globals.load(new JseMathLib());
|
globals.load(new JseMathLib());
|
||||||
globals.load(new JseIoLib());
|
globals.load(new JseIoLib());
|
||||||
|
|||||||
@@ -1,7 +1,21 @@
|
|||||||
import org.luaj.vm2.*;
|
import org.luaj.vm2.Globals;
|
||||||
|
import org.luaj.vm2.LoadState;
|
||||||
|
import org.luaj.vm2.LuaBoolean;
|
||||||
|
import org.luaj.vm2.LuaString;
|
||||||
|
import org.luaj.vm2.LuaTable;
|
||||||
|
import org.luaj.vm2.LuaThread;
|
||||||
|
import org.luaj.vm2.LuaValue;
|
||||||
|
import org.luaj.vm2.Varargs;
|
||||||
import org.luaj.vm2.compiler.LuaC;
|
import org.luaj.vm2.compiler.LuaC;
|
||||||
import org.luaj.vm2.lib.*;
|
import org.luaj.vm2.lib.Bit32Lib;
|
||||||
import org.luaj.vm2.lib.jse.*;
|
import org.luaj.vm2.lib.DebugLib;
|
||||||
|
import org.luaj.vm2.lib.PackageLib;
|
||||||
|
import org.luaj.vm2.lib.TableLib;
|
||||||
|
import org.luaj.vm2.lib.TwoArgFunction;
|
||||||
|
import org.luaj.vm2.lib.ZeroArgFunction;
|
||||||
|
import org.luaj.vm2.lib.jse.JseBaseLib;
|
||||||
|
import org.luaj.vm2.lib.jse.JseMathLib;
|
||||||
|
import org.luaj.vm2.lib.jse.JseStringLib;
|
||||||
|
|
||||||
/** Simple program that illustrates basic sand-boxing of client scripts
|
/** Simple program that illustrates basic sand-boxing of client scripts
|
||||||
* in a server environment.
|
* in a server environment.
|
||||||
@@ -29,7 +43,7 @@ public class SampleSandboxed {
|
|||||||
server_globals = new Globals();
|
server_globals = new Globals();
|
||||||
server_globals.load(new JseBaseLib());
|
server_globals.load(new JseBaseLib());
|
||||||
server_globals.load(new PackageLib());
|
server_globals.load(new PackageLib());
|
||||||
server_globals.load(new StringLib());
|
server_globals.load(new JseStringLib());
|
||||||
|
|
||||||
// To load scripts, we occasionally need a math library in addition to compiler support.
|
// To load scripts, we occasionally need a math library in addition to compiler support.
|
||||||
// To limit scripts using the debug library, they must be closures, so we only install LuaC.
|
// To limit scripts using the debug library, they must be closures, so we only install LuaC.
|
||||||
@@ -82,7 +96,7 @@ public class SampleSandboxed {
|
|||||||
user_globals.load(new PackageLib());
|
user_globals.load(new PackageLib());
|
||||||
user_globals.load(new Bit32Lib());
|
user_globals.load(new Bit32Lib());
|
||||||
user_globals.load(new TableLib());
|
user_globals.load(new TableLib());
|
||||||
user_globals.load(new StringLib());
|
user_globals.load(new JseStringLib());
|
||||||
user_globals.load(new JseMathLib());
|
user_globals.load(new JseMathLib());
|
||||||
|
|
||||||
// This library is dangerous as it gives unfettered access to the
|
// This library is dangerous as it gives unfettered access to the
|
||||||
|
|||||||
25
luaj-core/pom.xml
Normal file
25
luaj-core/pom.xml
Normal 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>
|
||||||
@@ -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,10 +66,11 @@ 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) {
|
||||||
bytes = new byte[ initialCapacity ];
|
bytes = new byte[initialCapacity];
|
||||||
length = 0;
|
length = 0;
|
||||||
offset = 0;
|
offset = 0;
|
||||||
value = null;
|
value = null;
|
||||||
@@ -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,125 +129,149 @@ 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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);
|
||||||
length += n;
|
length += n;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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);
|
||||||
LuaString.encodeToUtf8( c, c.length, bytes, offset + length );
|
LuaString.encodeToUtf8(c, c.length, bytes, offset+length);
|
||||||
length += n;
|
length += n;
|
||||||
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) {
|
||||||
int n = s.m_length;
|
int n = s.m_length;
|
||||||
makeroom( n, 0 );
|
makeroom(n, 0);
|
||||||
System.arraycopy( s.m_bytes, s.m_offset, bytes, offset-n, n );
|
System.arraycopy(s.m_bytes, s.m_offset, bytes, offset-n, n);
|
||||||
offset -= n;
|
offset -= n;
|
||||||
length += n;
|
length += n;
|
||||||
value = null;
|
value = null;
|
||||||
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;
|
||||||
length = s.m_length;
|
length = s.m_length;
|
||||||
offset = nbefore;
|
offset = nbefore;
|
||||||
bytes = new byte[nbefore+length+nafter];
|
bytes = new byte[nbefore+length+nafter];
|
||||||
System.arraycopy(s.m_bytes, s.m_offset, bytes, offset, length);
|
System.arraycopy(s.m_bytes, s.m_offset, bytes, offset, length);
|
||||||
} else if ( offset+length+nafter > bytes.length || offset<nbefore ) {
|
} else if (offset+length+nafter > bytes.length || offset < nbefore) {
|
||||||
int n = nbefore+length+nafter;
|
int n = nbefore+length+nafter;
|
||||||
int m = n<32? 32: n<length*2? length*2: n;
|
int m = n < 32? 32: n < length*2? length*2: n;
|
||||||
realloc( m, nbefore==0? 0: m-length-nafter );
|
realloc(m, nbefore == 0? 0: m-length-nafter);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Reallocate the internal storage for the buffer
|
/**
|
||||||
|
* Reallocate the internal storage for the buffer
|
||||||
|
*
|
||||||
* @param newSize the size of the buffer to use
|
* @param 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);
|
||||||
bytes = newBytes;
|
bytes = newBytes;
|
||||||
offset = newOffset;
|
offset = newOffset;
|
||||||
}
|
}
|
||||||
@@ -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>
|
||||||
|
* {
|
||||||
|
* @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>
|
||||||
|
* {
|
||||||
|
* @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,99 +191,142 @@ 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.
|
||||||
*/
|
*/
|
||||||
public LuaValue loadfile(String filename) {
|
public LuaValue loadfile(String filename) {
|
||||||
try {
|
try {
|
||||||
return load(finder.findResource(filename), "@"+filename, "bt", this);
|
return load(finder.findResource(filename), "@" + filename, "bt", this);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
return error("load "+filename+": "+e);
|
return error("load " + filename + ": " + e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Convenience function to load a string value as a script. Must be lua source.
|
/**
|
||||||
* @param script Contents of a lua script, such as "print 'hello, world.'"
|
* Convenience function to load a string value as a script. Must be lua
|
||||||
|
* source.
|
||||||
|
*
|
||||||
|
* @param script Contents of a lua script, such as "print 'hello,
|
||||||
|
* world.'"
|
||||||
* @param chunkname Name that will be used within the chunk as the source.
|
* @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);
|
||||||
@@ -256,16 +334,20 @@ public class Globals extends LuaTable {
|
|||||||
} catch (LuaError l) {
|
} catch (LuaError l) {
|
||||||
throw l;
|
throw l;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
return error("load "+chunkname+": "+e);
|
return error("load " + chunkname + ": " + e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Load lua source or lua binary from an input stream into a Prototype.
|
/**
|
||||||
* The InputStream is either a binary lua chunk starting with the lua binary chunk signature,
|
* 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) {
|
||||||
@@ -282,21 +364,25 @@ public class Globals extends LuaTable {
|
|||||||
if (mode.indexOf('t') >= 0) {
|
if (mode.indexOf('t') >= 0) {
|
||||||
return compilePrototype(is, chunkname);
|
return compilePrototype(is, chunkname);
|
||||||
}
|
}
|
||||||
error("Failed to load prototype "+chunkname+" using mode '"+mode+"'");
|
error("Failed to load prototype " + chunkname + " using mode '" + mode + "'");
|
||||||
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,21 +410,28 @@ 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)
|
||||||
cbuf[off+j] = s.charAt(i);
|
cbuf[off+j] = s.charAt(i);
|
||||||
return j > 0 || len == 0 ? j : -1;
|
return j > 0 || len == 0? j: -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -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,31 +514,40 @@ 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)
|
||||||
return -1;
|
return -1;
|
||||||
if (n == 0) {
|
if (n == 0) {
|
||||||
@@ -436,21 +560,29 @@ 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;
|
||||||
System.arraycopy(b, i, dest, 0, j - i);
|
System.arraycopy(b, i, dest, 0, j-i);
|
||||||
j -= i;
|
j -= i;
|
||||||
i = 0;
|
i = 0;
|
||||||
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;
|
||||||
}
|
}
|
||||||
486
luaj-core/src/main/java/org/luaj/vm2/LoadState.java
Normal file
486
luaj-core/src/main/java/org/luaj/vm2/LoadState.java
Normal file
@@ -0,0 +1,486 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* 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 java.io.DataInputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class to undump compiled lua bytecode into a {@link Prototype} instances.
|
||||||
|
* <p>
|
||||||
|
* The {@link LoadState} class provides the default {@link Globals.Undumper}
|
||||||
|
* which is used to undump a string of bytes that represent a lua binary file
|
||||||
|
* using either the C-based lua compiler, or luaj's
|
||||||
|
* {@link org.luaj.vm2.compiler.LuaC} compiler.
|
||||||
|
* <p>
|
||||||
|
* The canonical method to load and execute code is done indirectly using the
|
||||||
|
* Globals:
|
||||||
|
*
|
||||||
|
* <pre>
|
||||||
|
* {
|
||||||
|
* @code
|
||||||
|
* Globals globals = JsePlatform.standardGlobals();
|
||||||
|
* LuaValue chunk = globasl.load("print('hello, world')", "main.lua");
|
||||||
|
* chunk.call();
|
||||||
|
* }
|
||||||
|
* </pre>
|
||||||
|
*
|
||||||
|
* This should work regardless of which {@link Globals.Compiler} or
|
||||||
|
* {@link Globals.Undumper} have been installed.
|
||||||
|
* <p>
|
||||||
|
* By default, when using {@link org.luaj.vm2.lib.jse.JsePlatform} or
|
||||||
|
* {@link org.luaj.vm2.lib.jme.JmePlatform} to construct globals, the
|
||||||
|
* {@link LoadState} default undumper is installed as the default
|
||||||
|
* {@link Globals.Undumper}.
|
||||||
|
* <p>
|
||||||
|
*
|
||||||
|
* A lua binary file is created via the {@link org.luaj.vm2.compiler.DumpState}
|
||||||
|
* class :
|
||||||
|
*
|
||||||
|
* <pre>
|
||||||
|
* {
|
||||||
|
* @code
|
||||||
|
* Globals globals = JsePlatform.standardGlobals();
|
||||||
|
* Prototype p = globals.compilePrototype(new StringReader("print('hello, world')"), "main.lua");
|
||||||
|
* ByteArrayOutputStream o = new ByteArrayOutputStream();
|
||||||
|
* org.luaj.vm2.compiler.DumpState.dump(p, o, false);
|
||||||
|
* byte[] lua_binary_file_bytes = o.toByteArray();
|
||||||
|
* }
|
||||||
|
* </pre>
|
||||||
|
*
|
||||||
|
* The {@link LoadState}'s default undumper {@link #instance} may be used
|
||||||
|
* directly to undump these bytes:
|
||||||
|
*
|
||||||
|
* <pre>
|
||||||
|
* {@code
|
||||||
|
* Prototypep = LoadState.instance.undump(new ByteArrayInputStream(lua_binary_file_bytes), "main.lua");
|
||||||
|
* LuaClosure c = new LuaClosure(p, globals);
|
||||||
|
* c.call();
|
||||||
|
* }
|
||||||
|
* </pre>
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* More commonly, the {@link Globals.Undumper} may be used to undump them:
|
||||||
|
*
|
||||||
|
* <pre>
|
||||||
|
* {
|
||||||
|
* @code
|
||||||
|
* Prototype p = globals.loadPrototype(new ByteArrayInputStream(lua_binary_file_bytes), "main.lua", "b");
|
||||||
|
* LuaClosure c = new LuaClosure(p, globals);
|
||||||
|
* c.call();
|
||||||
|
* }
|
||||||
|
* </pre>
|
||||||
|
*
|
||||||
|
* @see Globals.Compiler
|
||||||
|
* @see Globals.Undumper
|
||||||
|
* @see LuaClosure
|
||||||
|
* @see LuaFunction
|
||||||
|
* @see org.luaj.vm2.compiler.LuaC
|
||||||
|
* @see org.luaj.vm2.luajc.LuaJC
|
||||||
|
* @see Globals#compiler
|
||||||
|
* @see Globals#load(InputStream, String, LuaValue)
|
||||||
|
*/
|
||||||
|
public class LoadState {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shared instance of Globals.Undumper to use loading prototypes from binary
|
||||||
|
* lua files
|
||||||
|
*/
|
||||||
|
public static final Globals.Undumper instance = new GlobalsUndumper();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* format corresponding to non-number-patched lua, all numbers are floats or
|
||||||
|
* doubles
|
||||||
|
*/
|
||||||
|
public static final int NUMBER_FORMAT_FLOATS_OR_DOUBLES = 0;
|
||||||
|
|
||||||
|
/** format corresponding to non-number-patched lua, all numbers are ints */
|
||||||
|
public static final int NUMBER_FORMAT_INTS_ONLY = 1;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* format corresponding to number-patched lua, all numbers are 32-bit (4
|
||||||
|
* byte) ints
|
||||||
|
*/
|
||||||
|
public static final int NUMBER_FORMAT_NUM_PATCH_INT32 = 4;
|
||||||
|
|
||||||
|
// type constants
|
||||||
|
public static final int LUA_TINT = -2;
|
||||||
|
public static final int LUA_TNONE = -1;
|
||||||
|
public static final int LUA_TNIL = 0;
|
||||||
|
public static final int LUA_TBOOLEAN = 1;
|
||||||
|
public static final int LUA_TLIGHTUSERDATA = 2;
|
||||||
|
public static final int LUA_TNUMBER = 3;
|
||||||
|
public static final int LUA_TSTRING = 4;
|
||||||
|
public static final int LUA_TTABLE = 5;
|
||||||
|
public static final int LUA_TFUNCTION = 6;
|
||||||
|
public static final int LUA_TUSERDATA = 7;
|
||||||
|
public static final int LUA_TTHREAD = 8;
|
||||||
|
public static final int LUA_TVALUE = 9;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The character encoding to use for file encoding. Null means the default
|
||||||
|
* encoding
|
||||||
|
*/
|
||||||
|
public static String encoding = null;
|
||||||
|
|
||||||
|
/** Signature byte indicating the file is a compiled binary chunk */
|
||||||
|
public static final byte[] LUA_SIGNATURE = { '\033', 'L', 'u', 'a' };
|
||||||
|
|
||||||
|
/** Data to catch conversion errors */
|
||||||
|
public static final byte[] LUAC_TAIL = { (byte) 0x19, (byte) 0x93, '\r', '\n', (byte) 0x1a, '\n', };
|
||||||
|
|
||||||
|
/** Name for compiled chunks */
|
||||||
|
public static final String SOURCE_BINARY_STRING = "binary string";
|
||||||
|
|
||||||
|
/** for header of binary files -- this is Lua 5.2 */
|
||||||
|
public static final int LUAC_VERSION = 0x52;
|
||||||
|
|
||||||
|
/** for header of binary files -- this is the official format */
|
||||||
|
public static final int LUAC_FORMAT = 0;
|
||||||
|
|
||||||
|
/** size of header of binary files */
|
||||||
|
public static final int LUAC_HEADERSIZE = 12;
|
||||||
|
|
||||||
|
// values read from the header
|
||||||
|
private int luacVersion;
|
||||||
|
private int luacFormat;
|
||||||
|
private boolean luacLittleEndian;
|
||||||
|
private int luacSizeofInt;
|
||||||
|
private int luacSizeofSizeT;
|
||||||
|
private int luacSizeofInstruction;
|
||||||
|
private int luacSizeofLuaNumber;
|
||||||
|
private int luacNumberFormat;
|
||||||
|
|
||||||
|
/** input stream from which we are loading */
|
||||||
|
public final DataInputStream is;
|
||||||
|
|
||||||
|
/** Name of what is being loaded? */
|
||||||
|
String name;
|
||||||
|
|
||||||
|
private static final LuaValue[] NOVALUES = {};
|
||||||
|
private static final Prototype[] NOPROTOS = {};
|
||||||
|
private static final LocVars[] NOLOCVARS = {};
|
||||||
|
private static final Upvaldesc[] NOUPVALDESCS = {};
|
||||||
|
private static final int[] NOINTS = {};
|
||||||
|
|
||||||
|
/** Read buffer */
|
||||||
|
private byte[] buf = new byte[512];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Install this class as the standard Globals.Undumper for the supplied
|
||||||
|
* Globals
|
||||||
|
*/
|
||||||
|
public static void install(Globals globals) {
|
||||||
|
globals.undumper = instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load a 4-byte int value from the input stream
|
||||||
|
*
|
||||||
|
* @return the int value laoded.
|
||||||
|
**/
|
||||||
|
int loadInt() throws IOException {
|
||||||
|
is.readFully(buf, 0, 4);
|
||||||
|
return luacLittleEndian? buf[3]<<24 | (0xff & buf[2])<<16 | (0xff & buf[1])<<8 | 0xff & buf[0]
|
||||||
|
: buf[0]<<24 | (0xff & buf[1])<<16 | (0xff & buf[2])<<8 | 0xff & buf[3];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load an array of int values from the input stream
|
||||||
|
*
|
||||||
|
* @return the array of int values laoded.
|
||||||
|
**/
|
||||||
|
int[] loadIntArray() throws IOException {
|
||||||
|
int n = loadInt();
|
||||||
|
if (n == 0)
|
||||||
|
return NOINTS;
|
||||||
|
|
||||||
|
// read all data at once
|
||||||
|
int m = n<<2;
|
||||||
|
if (buf.length < m)
|
||||||
|
buf = new byte[m];
|
||||||
|
is.readFully(buf, 0, m);
|
||||||
|
int[] array = new int[n];
|
||||||
|
for (int i = 0, j = 0; i < n; ++i, j += 4)
|
||||||
|
array[i] = luacLittleEndian? buf[j+3]<<24 | (0xff & buf[j+2])<<16 | (0xff & buf[j+1])<<8 | 0xff & buf[j+0]
|
||||||
|
: buf[j+0]<<24 | (0xff & buf[j+1])<<16 | (0xff & buf[j+2])<<8 | 0xff & buf[j+3];
|
||||||
|
|
||||||
|
return array;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load a long value from the input stream
|
||||||
|
*
|
||||||
|
* @return the long value laoded.
|
||||||
|
**/
|
||||||
|
long loadInt64() throws IOException {
|
||||||
|
int a, b;
|
||||||
|
if (this.luacLittleEndian) {
|
||||||
|
a = loadInt();
|
||||||
|
b = loadInt();
|
||||||
|
} else {
|
||||||
|
b = loadInt();
|
||||||
|
a = loadInt();
|
||||||
|
}
|
||||||
|
return (long) b<<32 | a & 0xffffffffL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load a lua strin gvalue from the input stream
|
||||||
|
*
|
||||||
|
* @return the {@link LuaString} value laoded.
|
||||||
|
**/
|
||||||
|
LuaString loadString() throws IOException {
|
||||||
|
int size = this.luacSizeofSizeT == 8? (int) loadInt64(): loadInt();
|
||||||
|
if (size == 0)
|
||||||
|
return null;
|
||||||
|
byte[] bytes = new byte[size];
|
||||||
|
is.readFully(bytes, 0, size);
|
||||||
|
return LuaString.valueUsing(bytes, 0, bytes.length-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert bits in a long value to a {@link LuaValue}.
|
||||||
|
*
|
||||||
|
* @param bits long value containing the bits
|
||||||
|
* @return {@link LuaInteger} or {@link LuaDouble} whose value corresponds
|
||||||
|
* to the bits provided.
|
||||||
|
*/
|
||||||
|
public static LuaValue longBitsToLuaNumber(long bits) {
|
||||||
|
if ((bits & (1L<<63)-1) == 0L) {
|
||||||
|
return LuaValue.ZERO;
|
||||||
|
}
|
||||||
|
|
||||||
|
int e = (int) (bits>>52 & 0x7ffL)-1023;
|
||||||
|
|
||||||
|
if (e >= 0 && e < 31) {
|
||||||
|
long f = bits & 0xFFFFFFFFFFFFFL;
|
||||||
|
int shift = 52-e;
|
||||||
|
long intPrecMask = (1L<<shift)-1;
|
||||||
|
if ((f & intPrecMask) == 0) {
|
||||||
|
int intValue = (int) (f>>shift) | 1<<e;
|
||||||
|
return LuaInteger.valueOf(bits>>63 != 0? -intValue: intValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return LuaValue.valueOf(Double.longBitsToDouble(bits));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load a number from a binary chunk
|
||||||
|
*
|
||||||
|
* @return the {@link LuaValue} loaded
|
||||||
|
* @throws IOException if an i/o exception occurs
|
||||||
|
*/
|
||||||
|
LuaValue loadNumber() throws IOException {
|
||||||
|
if (luacNumberFormat == NUMBER_FORMAT_INTS_ONLY) {
|
||||||
|
return LuaInteger.valueOf(loadInt());
|
||||||
|
} else {
|
||||||
|
return longBitsToLuaNumber(loadInt64());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load a list of constants from a binary chunk
|
||||||
|
*
|
||||||
|
* @param f the function prototype
|
||||||
|
* @throws IOException if an i/o exception occurs
|
||||||
|
*/
|
||||||
|
void loadConstants(Prototype f) throws IOException {
|
||||||
|
int n = loadInt();
|
||||||
|
LuaValue[] values = n > 0? new LuaValue[n]: NOVALUES;
|
||||||
|
for (int i = 0; i < n; i++) {
|
||||||
|
switch (is.readByte()) {
|
||||||
|
case LUA_TNIL:
|
||||||
|
values[i] = LuaValue.NIL;
|
||||||
|
break;
|
||||||
|
case LUA_TBOOLEAN:
|
||||||
|
values[i] = 0 != is.readUnsignedByte()? LuaValue.TRUE: LuaValue.FALSE;
|
||||||
|
break;
|
||||||
|
case LUA_TINT:
|
||||||
|
values[i] = LuaInteger.valueOf(loadInt());
|
||||||
|
break;
|
||||||
|
case LUA_TNUMBER:
|
||||||
|
values[i] = loadNumber();
|
||||||
|
break;
|
||||||
|
case LUA_TSTRING:
|
||||||
|
values[i] = loadString();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new IllegalStateException("bad constant");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
f.k = values;
|
||||||
|
|
||||||
|
n = loadInt();
|
||||||
|
Prototype[] protos = n > 0? new Prototype[n]: NOPROTOS;
|
||||||
|
for (int i = 0; i < n; i++)
|
||||||
|
protos[i] = loadFunction(f.source);
|
||||||
|
f.p = protos;
|
||||||
|
}
|
||||||
|
|
||||||
|
void loadUpvalues(Prototype f) throws IOException {
|
||||||
|
int n = loadInt();
|
||||||
|
f.upvalues = n > 0? new Upvaldesc[n]: NOUPVALDESCS;
|
||||||
|
for (int i = 0; i < n; i++) {
|
||||||
|
boolean instack = is.readByte() != 0;
|
||||||
|
int idx = is.readByte() & 0xff;
|
||||||
|
f.upvalues[i] = new Upvaldesc(null, instack, idx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load the debug info for a function prototype
|
||||||
|
*
|
||||||
|
* @param f the function Prototype
|
||||||
|
* @throws IOException if there is an i/o exception
|
||||||
|
*/
|
||||||
|
void loadDebug(Prototype f) throws IOException {
|
||||||
|
f.source = loadString();
|
||||||
|
f.lineinfo = loadIntArray();
|
||||||
|
int n = loadInt();
|
||||||
|
f.locvars = n > 0? new LocVars[n]: NOLOCVARS;
|
||||||
|
for (int i = 0; i < n; i++) {
|
||||||
|
LuaString varname = loadString();
|
||||||
|
int startpc = loadInt();
|
||||||
|
int endpc = loadInt();
|
||||||
|
f.locvars[i] = new LocVars(varname, startpc, endpc);
|
||||||
|
}
|
||||||
|
|
||||||
|
n = loadInt();
|
||||||
|
for (int i = 0; i < n; i++)
|
||||||
|
f.upvalues[i].name = loadString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load a function prototype from the input stream
|
||||||
|
*
|
||||||
|
* @param p name of the source
|
||||||
|
* @return {@link Prototype} instance that was loaded
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
public Prototype loadFunction(LuaString p) throws IOException {
|
||||||
|
Prototype f = new Prototype();
|
||||||
|
//// this.L.push(f);
|
||||||
|
// f.source = loadString();
|
||||||
|
// if ( f.source == null )
|
||||||
|
// f.source = p;
|
||||||
|
f.linedefined = loadInt();
|
||||||
|
f.lastlinedefined = loadInt();
|
||||||
|
f.numparams = is.readUnsignedByte();
|
||||||
|
f.is_vararg = is.readUnsignedByte();
|
||||||
|
f.maxstacksize = is.readUnsignedByte();
|
||||||
|
f.code = loadIntArray();
|
||||||
|
loadConstants(f);
|
||||||
|
loadUpvalues(f);
|
||||||
|
loadDebug(f);
|
||||||
|
|
||||||
|
// TODO: add check here, for debugging purposes, I believe
|
||||||
|
// see ldebug.c
|
||||||
|
// IF (!luaG_checkcode(f), "bad code");
|
||||||
|
|
||||||
|
// this.L.pop();
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load the lua chunk header values.
|
||||||
|
*
|
||||||
|
* @throws IOException if an i/o exception occurs.
|
||||||
|
*/
|
||||||
|
public void loadHeader() throws IOException {
|
||||||
|
luacVersion = is.readByte();
|
||||||
|
luacFormat = is.readByte();
|
||||||
|
luacLittleEndian = 0 != is.readByte();
|
||||||
|
luacSizeofInt = is.readByte();
|
||||||
|
luacSizeofSizeT = is.readByte();
|
||||||
|
luacSizeofInstruction = is.readByte();
|
||||||
|
luacSizeofLuaNumber = is.readByte();
|
||||||
|
luacNumberFormat = is.readByte();
|
||||||
|
for (int i = 0; i < LUAC_TAIL.length; ++i)
|
||||||
|
if (is.readByte() != LUAC_TAIL[i])
|
||||||
|
throw new LuaError("Unexpeted byte in luac tail of header, index=" + i);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load input stream as a lua binary chunk if the first 4 bytes are the lua
|
||||||
|
* binary signature.
|
||||||
|
*
|
||||||
|
* @param stream InputStream to read, after having read the first byte
|
||||||
|
* already
|
||||||
|
* @param chunkname Name to apply to the loaded chunk
|
||||||
|
* @return {@link Prototype} that was loaded, or null if the first 4 bytes
|
||||||
|
* were not the lua signature.
|
||||||
|
* @throws IOException if an IOException occurs
|
||||||
|
*/
|
||||||
|
public static Prototype undump(InputStream stream, String chunkname) throws IOException {
|
||||||
|
// check rest of signature
|
||||||
|
if (stream.read() != LUA_SIGNATURE[0] || stream.read() != LUA_SIGNATURE[1] || stream.read() != LUA_SIGNATURE[2]
|
||||||
|
|| stream.read() != LUA_SIGNATURE[3])
|
||||||
|
return null;
|
||||||
|
|
||||||
|
// load file as a compiled chunk
|
||||||
|
String sname = getSourceName(chunkname);
|
||||||
|
LoadState s = new LoadState(stream, sname);
|
||||||
|
s.loadHeader();
|
||||||
|
|
||||||
|
// check format
|
||||||
|
switch (s.luacNumberFormat) {
|
||||||
|
case NUMBER_FORMAT_FLOATS_OR_DOUBLES:
|
||||||
|
case NUMBER_FORMAT_INTS_ONLY:
|
||||||
|
case NUMBER_FORMAT_NUM_PATCH_INT32:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new LuaError("unsupported int size");
|
||||||
|
}
|
||||||
|
return s.loadFunction(LuaString.valueOf(sname));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct a source name from a supplied chunk name
|
||||||
|
*
|
||||||
|
* @param name String name that appears in the chunk
|
||||||
|
* @return source file name
|
||||||
|
*/
|
||||||
|
public static String getSourceName(String name) {
|
||||||
|
String sname = name;
|
||||||
|
if (name.startsWith("@") || name.startsWith("="))
|
||||||
|
sname = name.substring(1);
|
||||||
|
else if (name.startsWith("\033"))
|
||||||
|
sname = SOURCE_BINARY_STRING;
|
||||||
|
return sname;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Private constructor for create a load state */
|
||||||
|
private LoadState(InputStream stream, String name) {
|
||||||
|
this.name = name;
|
||||||
|
this.is = new DataInputStream(stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final class GlobalsUndumper implements Globals.Undumper {
|
||||||
|
@Override
|
||||||
|
public Prototype undump(InputStream stream, String chunkname) throws IOException {
|
||||||
|
return LoadState.undump(stream, chunkname);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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
|
||||||
@@ -47,6 +49,6 @@ public class LocVars {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public String tojstring() {
|
public String tojstring() {
|
||||||
return varname+" "+startpc+"-"+endpc;
|
return varname + " " + startpc + "-" + endpc;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
357
luaj-core/src/main/java/org/luaj/vm2/Lua.java
Normal file
357
luaj-core/src/main/java/org/luaj/vm2/Lua.java
Normal file
@@ -0,0 +1,357 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constants for lua limits and opcodes.
|
||||||
|
* <p>
|
||||||
|
* This is a direct translation of C lua distribution header file constants for
|
||||||
|
* bytecode creation and processing.
|
||||||
|
*/
|
||||||
|
public class Lua {
|
||||||
|
/** version is supplied by ant build task */
|
||||||
|
public static final String _VERSION = "Luaj 0.0";
|
||||||
|
|
||||||
|
/** use return values from previous op */
|
||||||
|
public static final int LUA_MULTRET = -1;
|
||||||
|
|
||||||
|
// from lopcodes.h
|
||||||
|
|
||||||
|
/*===========================================================================
|
||||||
|
We assume that instructions are unsigned numbers.
|
||||||
|
All instructions have an opcode in the first 6 bits.
|
||||||
|
Instructions can have the following fields:
|
||||||
|
`A' : 8 bits
|
||||||
|
`B' : 9 bits
|
||||||
|
`C' : 9 bits
|
||||||
|
`Bx' : 18 bits (`B' and `C' together)
|
||||||
|
`sBx' : signed Bx
|
||||||
|
|
||||||
|
A signed argument is represented in excess K; that is, the number
|
||||||
|
value is the unsigned value minus K. K is exactly the maximum value
|
||||||
|
for that argument (so that -max is represented by 0, and +max is
|
||||||
|
represented by 2*max), which is half the maximum for the corresponding
|
||||||
|
unsigned argument.
|
||||||
|
===========================================================================*/
|
||||||
|
|
||||||
|
/* basic instruction format */
|
||||||
|
public static final int iABC = 0;
|
||||||
|
public static final int iABx = 1;
|
||||||
|
public static final int iAsBx = 2;
|
||||||
|
public static final int iAx = 3;
|
||||||
|
|
||||||
|
/*
|
||||||
|
** size and position of opcode arguments.
|
||||||
|
*/
|
||||||
|
public static final int SIZE_C = 9;
|
||||||
|
public static final int SIZE_B = 9;
|
||||||
|
public static final int SIZE_Bx = SIZE_C+SIZE_B;
|
||||||
|
public static final int SIZE_A = 8;
|
||||||
|
public static final int SIZE_Ax = SIZE_C+SIZE_B+SIZE_A;
|
||||||
|
|
||||||
|
public static final int SIZE_OP = 6;
|
||||||
|
|
||||||
|
public static final int POS_OP = 0;
|
||||||
|
public static final int POS_A = POS_OP+SIZE_OP;
|
||||||
|
public static final int POS_C = POS_A+SIZE_A;
|
||||||
|
public static final int POS_B = POS_C+SIZE_C;
|
||||||
|
public static final int POS_Bx = POS_C;
|
||||||
|
public static final int POS_Ax = POS_A;
|
||||||
|
|
||||||
|
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_B = (1<<SIZE_B)-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_sBx = MAXARG_Bx>>1; /* `sBx' is signed */
|
||||||
|
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_A = (1<<SIZE_A)-1<<POS_A;
|
||||||
|
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_Bx = (1<<SIZE_Bx)-1<<POS_Bx;
|
||||||
|
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_A = ~MASK_A;
|
||||||
|
public static final int MASK_NOT_B = ~MASK_B;
|
||||||
|
public static final int MASK_NOT_C = ~MASK_C;
|
||||||
|
public static final int MASK_NOT_Bx = ~MASK_Bx;
|
||||||
|
|
||||||
|
/*
|
||||||
|
** the following macros help to manipulate instructions
|
||||||
|
*/
|
||||||
|
public static int GET_OPCODE(int i) {
|
||||||
|
return i>>POS_OP & MAX_OP;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int GETARG_A(int i) {
|
||||||
|
return i>>POS_A & MAXARG_A;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int GETARG_Ax(int i) {
|
||||||
|
return i>>POS_Ax & MAXARG_Ax;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int GETARG_B(int i) {
|
||||||
|
return i>>POS_B & MAXARG_B;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int GETARG_C(int i) {
|
||||||
|
return i>>POS_C & MAXARG_C;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int GETARG_Bx(int i) {
|
||||||
|
return i>>POS_Bx & MAXARG_Bx;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int GETARG_sBx(int i) {
|
||||||
|
return (i>>POS_Bx & MAXARG_Bx)-MAXARG_sBx;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Macros to operate RK indices
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** this bit 1 means constant (0 means register) */
|
||||||
|
public static final int BITRK = 1<<SIZE_B-1;
|
||||||
|
|
||||||
|
/** test whether value is a constant */
|
||||||
|
public static boolean ISK(int x) {
|
||||||
|
return 0 != (x & BITRK);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** gets the index of the constant */
|
||||||
|
public static int INDEXK(int r) {
|
||||||
|
return r & ~BITRK;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final int MAXINDEXRK = BITRK-1;
|
||||||
|
|
||||||
|
/** code a constant index as a RK value */
|
||||||
|
public static int RKASK(int x) {
|
||||||
|
return x | BITRK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
** invalid register that fits in 8 bits
|
||||||
|
*/
|
||||||
|
public static final int NO_REG = MAXARG_A;
|
||||||
|
|
||||||
|
/*
|
||||||
|
** R(x) - register
|
||||||
|
** Kst(x) - constant (in constant table)
|
||||||
|
** RK(x) == if ISK(x) then Kst(INDEXK(x)) else R(x)
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
** grep "ORDER OP" if you change these enums
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*----------------------------------------------------------------------
|
||||||
|
name args description
|
||||||
|
------------------------------------------------------------------------*/
|
||||||
|
public static final int OP_MOVE = 0; /* A B R(A) := R(B) */
|
||||||
|
public static final int OP_LOADK = 1; /* A Bx R(A) := Kst(Bx) */
|
||||||
|
public static final int OP_LOADKX = 2; /* A R(A) := Kst(extra arg) */
|
||||||
|
public static final int OP_LOADBOOL = 3; /* A B C R(A) := (Bool)B; if (C) pc++ */
|
||||||
|
public static final int OP_LOADNIL = 4; /* A B R(A) := ... := R(A+B) := nil */
|
||||||
|
public static final int OP_GETUPVAL = 5; /* A B R(A) := UpValue[B] */
|
||||||
|
|
||||||
|
public static final int OP_GETTABUP = 6; /* A B C R(A) := UpValue[B][RK(C)] */
|
||||||
|
public static final int OP_GETTABLE = 7; /* A B C R(A) := R(B)[RK(C)] */
|
||||||
|
|
||||||
|
public static final int OP_SETTABUP = 8; /* A B C UpValue[A][RK(B)] := RK(C) */
|
||||||
|
public static final int OP_SETUPVAL = 9; /* A B UpValue[B] := R(A) */
|
||||||
|
public static final int OP_SETTABLE = 10; /* A B C R(A)[RK(B)] := RK(C) */
|
||||||
|
|
||||||
|
public static final int OP_NEWTABLE = 11; /* A B C R(A) := {} (size = B,C) */
|
||||||
|
|
||||||
|
public static final int OP_SELF = 12; /* A B C R(A+1) := R(B); R(A) := R(B)[RK(C)] */
|
||||||
|
|
||||||
|
public static final int OP_ADD = 13; /* A B C R(A) := RK(B) + RK(C) */
|
||||||
|
public static final int OP_SUB = 14; /* A B C R(A) := RK(B) - RK(C) */
|
||||||
|
public static final int OP_MUL = 15; /* A B C R(A) := RK(B) * RK(C) */
|
||||||
|
public static final int OP_DIV = 16; /* A B C R(A) := RK(B) / RK(C) */
|
||||||
|
public static final int OP_MOD = 17; /* A B C R(A) := RK(B) % RK(C) */
|
||||||
|
public static final int OP_POW = 18; /* A B C R(A) := RK(B) ^ RK(C) */
|
||||||
|
public static final int OP_UNM = 19; /* A B R(A) := -R(B) */
|
||||||
|
public static final int OP_NOT = 20; /* A B R(A) := not R(B) */
|
||||||
|
public static final int OP_LEN = 21; /* A B R(A) := length of R(B) */
|
||||||
|
|
||||||
|
public static final int OP_CONCAT = 22; /* A B C R(A) := R(B).. ... ..R(C) */
|
||||||
|
|
||||||
|
public static final int OP_JMP = 23; /* A sBx pc+=sBx; if (A) close all upvalues >= R(A - 1) */
|
||||||
|
public static final int OP_EQ = 24; /* A B C if ((RK(B) == RK(C)) ~= A) then pc++ */
|
||||||
|
public static final int OP_LT = 25; /* A B C if ((RK(B) < RK(C)) ~= A) then pc++ */
|
||||||
|
public static final int OP_LE = 26; /* A B C if ((RK(B) <= RK(C)) ~= A) then pc++ */
|
||||||
|
|
||||||
|
public static final int OP_TEST = 27; /* A C if not (R(A) <=> C) then pc++ */
|
||||||
|
public static final int OP_TESTSET = 28; /* A B C if (R(B) <=> C) then R(A) := R(B) else pc++ */
|
||||||
|
|
||||||
|
public static final int OP_CALL = 29; /* A B C R(A), ... ,R(A+C-2) := R(A)(R(A+1), ... ,R(A+B-1)) */
|
||||||
|
public static final int OP_TAILCALL = 30; /* A B C return R(A)(R(A+1), ... ,R(A+B-1)) */
|
||||||
|
public static final int OP_RETURN = 31; /* A B return R(A), ... ,R(A+B-2) (see note) */
|
||||||
|
|
||||||
|
public static final int OP_FORLOOP = 32; /* A sBx R(A)+=R(A+2);
|
||||||
|
if R(A) <?= R(A+1) then { pc+=sBx; R(A+3)=R(A) }*/
|
||||||
|
public static final int OP_FORPREP = 33; /* A sBx R(A)-=R(A+2); pc+=sBx */
|
||||||
|
|
||||||
|
public static final int OP_TFORCALL = 34; /* A C R(A+3), ... ,R(A+2+C) := R(A)(R(A+1), R(A+2)); */
|
||||||
|
public static final int OP_TFORLOOP = 35; /* A sBx if R(A+1) ~= nil then { R(A)=R(A+1); pc += sBx } */
|
||||||
|
public static final int OP_SETLIST = 36; /* A B C R(A)[(C-1)*FPF+i] := R(A+i), 1 <= i <= B */
|
||||||
|
|
||||||
|
public static final int OP_CLOSURE = 37; /* A Bx R(A) := closure(KPROTO[Bx], R(A), ... ,R(A+n)) */
|
||||||
|
|
||||||
|
public static final int OP_VARARG = 38; /* A B R(A), R(A+1), ..., R(A+B-1) = vararg */
|
||||||
|
|
||||||
|
public static final int OP_EXTRAARG = 39; /* Ax extra (larger) argument for previous opcode */
|
||||||
|
|
||||||
|
public static final int NUM_OPCODES = OP_EXTRAARG+1;
|
||||||
|
|
||||||
|
/* pseudo-opcodes used in parsing only. */
|
||||||
|
public static final int OP_GT = 63; // >
|
||||||
|
public static final int OP_GE = 62; // >=
|
||||||
|
public static final int OP_NEQ = 61; // ~=
|
||||||
|
public static final int OP_AND = 60; // and
|
||||||
|
public static final int OP_OR = 59; // or
|
||||||
|
|
||||||
|
/*===========================================================================
|
||||||
|
Notes:
|
||||||
|
(*) In OP_CALL, if (B == 0) then B = top. C is the number of returns - 1,
|
||||||
|
and can be 0: OP_CALL then sets `top' to last_result+1, so
|
||||||
|
next open instruction (OP_CALL, OP_RETURN, OP_SETLIST) may use `top'.
|
||||||
|
|
||||||
|
(*) In OP_VARARG, if (B == 0) then use actual number of varargs and
|
||||||
|
set top (like in OP_CALL with C == 0).
|
||||||
|
|
||||||
|
(*) In OP_RETURN, if (B == 0) then return up to `top'
|
||||||
|
|
||||||
|
(*) In OP_SETLIST, if (B == 0) then B = `top';
|
||||||
|
if (C == 0) then next `instruction' is real C
|
||||||
|
|
||||||
|
(*) For comparisons, A specifies what condition the test should accept
|
||||||
|
(true or false).
|
||||||
|
|
||||||
|
(*) All `skips' (pc++) assume that next instruction is a jump
|
||||||
|
===========================================================================*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
** masks for instruction properties. The format is:
|
||||||
|
** bits 0-1: op mode
|
||||||
|
** bits 2-3: C arg mode
|
||||||
|
** bits 4-5: B arg mode
|
||||||
|
** bit 6: instruction set register A
|
||||||
|
** bit 7: operator is a test
|
||||||
|
*/
|
||||||
|
|
||||||
|
public static final int OpArgN = 0; /* argument is not used */
|
||||||
|
public static final int OpArgU = 1; /* argument is used */
|
||||||
|
public static final int OpArgR = 2; /* argument is a register or a jump offset */
|
||||||
|
public static final int OpArgK = 3; /* argument is a constant or register/constant */
|
||||||
|
|
||||||
|
public static final int[] luaP_opmodes = {
|
||||||
|
/* T A B C mode opcode */
|
||||||
|
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 | OpArgN<<4 | OpArgN<<2 | iABx, /* OP_LOADKX */
|
||||||
|
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_GETUPVAL */
|
||||||
|
0<<7 | 1<<6 | OpArgU<<4 | OpArgK<<2 | iABC, /* OP_GETTABUP */
|
||||||
|
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 | OpArgU<<4 | OpArgN<<2 | iABC, /* OP_SETUPVAL */
|
||||||
|
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 | 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_SUB */
|
||||||
|
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_MOD */
|
||||||
|
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_NOT */
|
||||||
|
0<<7 | 1<<6 | OpArgR<<4 | OpArgN<<2 | iABC, /* OP_LEN */
|
||||||
|
0<<7 | 1<<6 | OpArgR<<4 | OpArgR<<2 | iABC, /* OP_CONCAT */
|
||||||
|
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_LT */
|
||||||
|
1<<7 | 0<<6 | OpArgK<<4 | OpArgK<<2 | iABC, /* OP_LE */
|
||||||
|
1<<7 | 0<<6 | OpArgN<<4 | OpArgU<<2 | iABC, /* OP_TEST */
|
||||||
|
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_TAILCALL */
|
||||||
|
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_FORPREP */
|
||||||
|
0<<7 | 0<<6 | OpArgN<<4 | OpArgU<<2 | iABC, /* OP_TFORCALL */
|
||||||
|
1<<7 | 1<<6 | OpArgR<<4 | OpArgN<<2 | iAsBx, /* OP_TFORLOOP */
|
||||||
|
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 | iABC, /* OP_VARARG */
|
||||||
|
0<<7 | 0<<6 | OpArgU<<4 | OpArgU<<2 | iAx, /* OP_EXTRAARG */
|
||||||
|
};
|
||||||
|
|
||||||
|
public static int getOpMode(int m) {
|
||||||
|
return luaP_opmodes[m] & 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int getBMode(int m) {
|
||||||
|
return luaP_opmodes[m]>>4 & 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int getCMode(int m) {
|
||||||
|
return luaP_opmodes[m]>>2 & 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean testAMode(int m) {
|
||||||
|
return 0 != (luaP_opmodes[m] & 1<<6);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean testTMode(int m) {
|
||||||
|
return 0 != (luaP_opmodes[m] & 1<<7);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* number of list items to accumulate before a SETLIST instruction */
|
||||||
|
public static final int LFIELDS_PER_FLUSH = 50;
|
||||||
|
|
||||||
|
private static final int MAXSRC = 80;
|
||||||
|
|
||||||
|
public static String chunkid(String source) {
|
||||||
|
if (source.startsWith("="))
|
||||||
|
return source.substring(1);
|
||||||
|
String end = "";
|
||||||
|
if (source.startsWith("@")) {
|
||||||
|
source = source.substring(1);
|
||||||
|
} else {
|
||||||
|
source = "[string \"" + source;
|
||||||
|
end = "\"]";
|
||||||
|
}
|
||||||
|
int n = source.length()+end.length();
|
||||||
|
if (n > MAXSRC)
|
||||||
|
source = source.substring(0, MAXSRC-end.length()-3) + "...";
|
||||||
|
return source+end;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
}
|
}
|
||||||
680
luaj-core/src/main/java/org/luaj/vm2/LuaClosure.java
Normal file
680
luaj-core/src/main/java/org/luaj/vm2/LuaClosure.java
Normal file
@@ -0,0 +1,680 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* 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.DebugLib.CallFrame;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extension of {@link LuaFunction} which executes lua bytecode.
|
||||||
|
* <p>
|
||||||
|
* A {@link LuaClosure} is a combination of a {@link Prototype} and a
|
||||||
|
* {@link LuaValue} to use as an environment for execution. Normally the
|
||||||
|
* {@link LuaValue} is a {@link Globals} in which case the environment will
|
||||||
|
* contain standard lua libraries.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* There are three main ways {@link LuaClosure} instances are created:
|
||||||
|
* <ul>
|
||||||
|
* <li>Construct an instance using {@link #LuaClosure(Prototype, LuaValue)}</li>
|
||||||
|
* <li>Construct it indirectly by loading a chunk via
|
||||||
|
* {@link Globals#load(java.io.Reader, String)}
|
||||||
|
* <li>Execute the lua bytecode {@link Lua#OP_CLOSURE} as part of bytecode
|
||||||
|
* processing
|
||||||
|
* </ul>
|
||||||
|
* <p>
|
||||||
|
* To construct it directly, the {@link Prototype} is typically created via a
|
||||||
|
* compiler such as {@link org.luaj.vm2.compiler.LuaC}:
|
||||||
|
*
|
||||||
|
* <pre>
|
||||||
|
* {
|
||||||
|
* @code
|
||||||
|
* String script = "print( 'hello, world' )";
|
||||||
|
* InputStream is = new ByteArrayInputStream(script.getBytes());
|
||||||
|
* Prototype p = LuaC.instance.compile(is, "script");
|
||||||
|
* LuaValue globals = JsePlatform.standardGlobals();
|
||||||
|
* LuaClosure f = new LuaClosure(p, globals);
|
||||||
|
* f.call();
|
||||||
|
* }
|
||||||
|
* </pre>
|
||||||
|
* <p>
|
||||||
|
* To construct it indirectly, the {@link Globals#load(java.io.Reader, String)}
|
||||||
|
* method may be used:
|
||||||
|
*
|
||||||
|
* <pre>
|
||||||
|
* {
|
||||||
|
* @code
|
||||||
|
* Globals globals = JsePlatform.standardGlobals();
|
||||||
|
* LuaFunction f = globals.load(new StringReader(script), "script");
|
||||||
|
* LuaClosure c = f.checkclosure(); // This may fail if LuaJC is installed.
|
||||||
|
* c.call();
|
||||||
|
* }
|
||||||
|
* </pre>
|
||||||
|
* <p>
|
||||||
|
* In this example, the "checkclosure()" may fail if direct lua-to-java-bytecode
|
||||||
|
* compiling using LuaJC is installed, because no LuaClosure is created in that
|
||||||
|
* case and the value returned is a {@link LuaFunction} but not a
|
||||||
|
* {@link LuaClosure}.
|
||||||
|
* <p>
|
||||||
|
* Since a {@link LuaClosure} is a {@link LuaFunction} which is a
|
||||||
|
* {@link LuaValue}, all the value operations can be used directly such as:
|
||||||
|
* <ul>
|
||||||
|
* <li>{@link LuaValue#call()}</li>
|
||||||
|
* <li>{@link LuaValue#call(LuaValue)}</li>
|
||||||
|
* <li>{@link LuaValue#invoke()}</li>
|
||||||
|
* <li>{@link LuaValue#invoke(Varargs)}</li>
|
||||||
|
* <li>{@link LuaValue#method(String)}</li>
|
||||||
|
* <li>{@link LuaValue#method(String,LuaValue)}</li>
|
||||||
|
* <li>{@link LuaValue#invokemethod(String)}</li>
|
||||||
|
* <li>{@link LuaValue#invokemethod(String,Varargs)}</li>
|
||||||
|
* <li>...</li>
|
||||||
|
* </ul>
|
||||||
|
*
|
||||||
|
* @see LuaValue
|
||||||
|
* @see LuaFunction
|
||||||
|
* @see LuaValue#isclosure()
|
||||||
|
* @see LuaValue#checkclosure()
|
||||||
|
* @see LuaValue#optclosure(LuaClosure)
|
||||||
|
* @see LoadState
|
||||||
|
* @see Globals#compiler
|
||||||
|
*/
|
||||||
|
public class LuaClosure extends LuaFunction {
|
||||||
|
private static final UpValue[] NOUPVALUES = {};
|
||||||
|
|
||||||
|
public final Prototype p;
|
||||||
|
|
||||||
|
public UpValue[] upValues;
|
||||||
|
|
||||||
|
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.
|
||||||
|
*
|
||||||
|
* @param p the Prototype to construct this Closure for.
|
||||||
|
* @param env the environment to associate with the closure.
|
||||||
|
*/
|
||||||
|
public LuaClosure(Prototype p, LuaValue env) {
|
||||||
|
this.p = p;
|
||||||
|
this.initupvalue1(env);
|
||||||
|
globals = env instanceof Globals? (Globals) env: null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void initupvalue1(LuaValue env) {
|
||||||
|
if (p.upvalues == null || p.upvalues.length == 0)
|
||||||
|
this.upValues = NOUPVALUES;
|
||||||
|
else {
|
||||||
|
this.upValues = new UpValue[p.upvalues.length];
|
||||||
|
this.upValues[0] = new UpValue(new LuaValue[] { env }, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isclosure() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public LuaClosure optclosure(LuaClosure defval) {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public LuaClosure checkclosure() {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String tojstring() {
|
||||||
|
return "function: " + p.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
private LuaValue[] getNewStack() {
|
||||||
|
int max = p.maxstacksize;
|
||||||
|
LuaValue[] stack = new LuaValue[max];
|
||||||
|
System.arraycopy(NILS, 0, stack, 0, max);
|
||||||
|
return stack;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final LuaValue call() {
|
||||||
|
LuaValue[] stack = getNewStack();
|
||||||
|
return execute(stack, NONE).arg1();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final LuaValue call(LuaValue arg) {
|
||||||
|
LuaValue[] stack = getNewStack();
|
||||||
|
switch (p.numparams) {
|
||||||
|
default:
|
||||||
|
stack[0] = arg;
|
||||||
|
return execute(stack, NONE).arg1();
|
||||||
|
case 0:
|
||||||
|
return execute(stack, arg).arg1();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final LuaValue call(LuaValue arg1, LuaValue arg2) {
|
||||||
|
LuaValue[] stack = getNewStack();
|
||||||
|
switch (p.numparams) {
|
||||||
|
default:
|
||||||
|
stack[0] = arg1;
|
||||||
|
stack[1] = arg2;
|
||||||
|
return execute(stack, NONE).arg1();
|
||||||
|
case 1:
|
||||||
|
stack[0] = arg1;
|
||||||
|
return execute(stack, arg2).arg1();
|
||||||
|
case 0:
|
||||||
|
return execute(stack, p.is_vararg != 0? varargsOf(arg1, arg2): NONE).arg1();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final LuaValue call(LuaValue arg1, LuaValue arg2, LuaValue arg3) {
|
||||||
|
LuaValue[] stack = getNewStack();
|
||||||
|
switch (p.numparams) {
|
||||||
|
default:
|
||||||
|
stack[0] = arg1;
|
||||||
|
stack[1] = arg2;
|
||||||
|
stack[2] = arg3;
|
||||||
|
return execute(stack, NONE).arg1();
|
||||||
|
case 2:
|
||||||
|
stack[0] = arg1;
|
||||||
|
stack[1] = arg2;
|
||||||
|
return execute(stack, arg3).arg1();
|
||||||
|
case 1:
|
||||||
|
stack[0] = arg1;
|
||||||
|
return execute(stack, p.is_vararg != 0? varargsOf(arg2, arg3): NONE).arg1();
|
||||||
|
case 0:
|
||||||
|
return execute(stack, p.is_vararg != 0? varargsOf(arg1, arg2, arg3): NONE).arg1();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final Varargs invoke(Varargs varargs) {
|
||||||
|
return onInvoke(varargs).eval();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final Varargs onInvoke(Varargs varargs) {
|
||||||
|
LuaValue[] stack = getNewStack();
|
||||||
|
for (int i = 0; i < p.numparams; i++)
|
||||||
|
stack[i] = varargs.arg(i+1);
|
||||||
|
return execute(stack, p.is_vararg != 0? varargs.subargs(p.numparams+1): NONE);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Varargs execute(LuaValue[] stack, Varargs varargs) {
|
||||||
|
// loop through instructions
|
||||||
|
int i, a, b, c, pc = 0, top = 0;
|
||||||
|
LuaValue o;
|
||||||
|
Varargs v = NONE;
|
||||||
|
int[] code = p.code;
|
||||||
|
LuaValue[] k = p.k;
|
||||||
|
|
||||||
|
// upvalues are only possible when closures create closures
|
||||||
|
// TODO: use linked list.
|
||||||
|
UpValue[] openups = p.p.length > 0? new UpValue[stack.length]: null;
|
||||||
|
|
||||||
|
// allow for debug hooks
|
||||||
|
if (globals != null && globals.debuglib != null)
|
||||||
|
globals.debuglib.onCall(this, varargs, stack);
|
||||||
|
|
||||||
|
// process instructions
|
||||||
|
try {
|
||||||
|
for (; true; ++pc) {
|
||||||
|
if (globals != null && globals.debuglib != null)
|
||||||
|
globals.debuglib.onInstruction(pc, v, top);
|
||||||
|
|
||||||
|
// pull out instruction
|
||||||
|
i = code[pc];
|
||||||
|
a = i>>6 & 0xff;
|
||||||
|
|
||||||
|
// process the op code
|
||||||
|
switch (i & 0x3f) {
|
||||||
|
|
||||||
|
case Lua.OP_MOVE:/* A B R(A):= R(B) */
|
||||||
|
stack[a] = stack[i>>>23];
|
||||||
|
continue;
|
||||||
|
|
||||||
|
case Lua.OP_LOADK:/* A Bx R(A):= Kst(Bx) */
|
||||||
|
stack[a] = k[i>>>14];
|
||||||
|
continue;
|
||||||
|
|
||||||
|
case Lua.OP_LOADKX:/* A R(A) := Kst(extra arg) */
|
||||||
|
++pc;
|
||||||
|
i = code[pc];
|
||||||
|
if ((i & 0x3f) != Lua.OP_EXTRAARG) {
|
||||||
|
int op = i & 0x3f;
|
||||||
|
throw new LuaError("OP_EXTRAARG expected after OP_LOADKX, got "
|
||||||
|
+ (op < Print.OPNAMES.length-1? Print.OPNAMES[op]: "UNKNOWN_OP_" + op));
|
||||||
|
}
|
||||||
|
stack[a] = k[i>>>6];
|
||||||
|
continue;
|
||||||
|
|
||||||
|
case Lua.OP_LOADBOOL:/* A B C R(A):= (Bool)B: if (C) pc++ */
|
||||||
|
stack[a] = i>>>23 != 0? LuaValue.TRUE: LuaValue.FALSE;
|
||||||
|
if ((i & 0x1ff<<14) != 0)
|
||||||
|
++pc; /* skip next instruction (if C) */
|
||||||
|
continue;
|
||||||
|
|
||||||
|
case Lua.OP_LOADNIL: /* A B R(A):= ...:= R(A+B):= nil */
|
||||||
|
for (b = i>>>23; b-- >= 0;)
|
||||||
|
stack[a++] = LuaValue.NIL;
|
||||||
|
continue;
|
||||||
|
|
||||||
|
case Lua.OP_GETUPVAL: /* A B R(A):= UpValue[B] */
|
||||||
|
stack[a] = upValues[i>>>23].getValue();
|
||||||
|
continue;
|
||||||
|
|
||||||
|
case Lua.OP_GETTABUP: /* A B C R(A) := UpValue[B][RK(C)] */
|
||||||
|
stack[a] = upValues[i>>>23].getValue().get((c = i>>14 & 0x1ff) > 0xff? k[c & 0x0ff]: stack[c]);
|
||||||
|
continue;
|
||||||
|
|
||||||
|
case Lua.OP_GETTABLE: /* A B C R(A):= R(B)[RK(C)] */
|
||||||
|
stack[a] = stack[i>>>23].get((c = i>>14 & 0x1ff) > 0xff? k[c & 0x0ff]: stack[c]);
|
||||||
|
continue;
|
||||||
|
|
||||||
|
case Lua.OP_SETTABUP: /* A B C UpValue[A][RK(B)] := RK(C) */
|
||||||
|
upValues[a].getValue().set((b = i>>>23) > 0xff? k[b & 0x0ff]: stack[b],
|
||||||
|
(c = i>>14 & 0x1ff) > 0xff? k[c & 0x0ff]: stack[c]);
|
||||||
|
continue;
|
||||||
|
|
||||||
|
case Lua.OP_SETUPVAL: /* A B UpValue[B]:= R(A) */
|
||||||
|
upValues[i>>>23].setValue(stack[a]);
|
||||||
|
continue;
|
||||||
|
|
||||||
|
case Lua.OP_SETTABLE: /* A B C R(A)[RK(B)]:= RK(C) */
|
||||||
|
stack[a].set((b = i>>>23) > 0xff? k[b & 0x0ff]: stack[b],
|
||||||
|
(c = i>>14 & 0x1ff) > 0xff? k[c & 0x0ff]: stack[c]);
|
||||||
|
continue;
|
||||||
|
|
||||||
|
case Lua.OP_NEWTABLE: /* A B C R(A):= {} (size = B,C) */
|
||||||
|
stack[a] = new LuaTable(i>>>23, i>>14 & 0x1ff);
|
||||||
|
continue;
|
||||||
|
|
||||||
|
case Lua.OP_SELF: /* A B C R(A+1):= R(B): R(A):= R(B)[RK(C)] */
|
||||||
|
stack[a+1] = o = stack[i>>>23];
|
||||||
|
stack[a] = o.get((c = i>>14 & 0x1ff) > 0xff? k[c & 0x0ff]: stack[c]);
|
||||||
|
continue;
|
||||||
|
|
||||||
|
case Lua.OP_ADD: /* A B C R(A):= RK(B) + RK(C) */
|
||||||
|
stack[a] = ((b = i>>>23) > 0xff? k[b & 0x0ff]: stack[b])
|
||||||
|
.add((c = i>>14 & 0x1ff) > 0xff? k[c & 0x0ff]: stack[c]);
|
||||||
|
continue;
|
||||||
|
|
||||||
|
case Lua.OP_SUB: /* A B C R(A):= RK(B) - RK(C) */
|
||||||
|
stack[a] = ((b = i>>>23) > 0xff? k[b & 0x0ff]: stack[b])
|
||||||
|
.sub((c = i>>14 & 0x1ff) > 0xff? k[c & 0x0ff]: stack[c]);
|
||||||
|
continue;
|
||||||
|
|
||||||
|
case Lua.OP_MUL: /* A B C R(A):= RK(B) * RK(C) */
|
||||||
|
stack[a] = ((b = i>>>23) > 0xff? k[b & 0x0ff]: stack[b])
|
||||||
|
.mul((c = i>>14 & 0x1ff) > 0xff? k[c & 0x0ff]: stack[c]);
|
||||||
|
continue;
|
||||||
|
|
||||||
|
case Lua.OP_DIV: /* A B C R(A):= RK(B) / RK(C) */
|
||||||
|
stack[a] = ((b = i>>>23) > 0xff? k[b & 0x0ff]: stack[b])
|
||||||
|
.div((c = i>>14 & 0x1ff) > 0xff? k[c & 0x0ff]: stack[c]);
|
||||||
|
continue;
|
||||||
|
|
||||||
|
case Lua.OP_MOD: /* A B C R(A):= RK(B) % RK(C) */
|
||||||
|
stack[a] = ((b = i>>>23) > 0xff? k[b & 0x0ff]: stack[b])
|
||||||
|
.mod((c = i>>14 & 0x1ff) > 0xff? k[c & 0x0ff]: stack[c]);
|
||||||
|
continue;
|
||||||
|
|
||||||
|
case Lua.OP_POW: /* A B C R(A):= RK(B) ^ RK(C) */
|
||||||
|
stack[a] = ((b = i>>>23) > 0xff? k[b & 0x0ff]: stack[b])
|
||||||
|
.pow((c = i>>14 & 0x1ff) > 0xff? k[c & 0x0ff]: stack[c]);
|
||||||
|
continue;
|
||||||
|
|
||||||
|
case Lua.OP_UNM: /* A B R(A):= -R(B) */
|
||||||
|
stack[a] = stack[i>>>23].neg();
|
||||||
|
continue;
|
||||||
|
|
||||||
|
case Lua.OP_NOT: /* A B R(A):= not R(B) */
|
||||||
|
stack[a] = stack[i>>>23].not();
|
||||||
|
continue;
|
||||||
|
|
||||||
|
case Lua.OP_LEN: /* A B R(A):= length of R(B) */
|
||||||
|
stack[a] = stack[i>>>23].len();
|
||||||
|
continue;
|
||||||
|
|
||||||
|
case Lua.OP_CONCAT: /* A B C R(A):= R(B).. ... ..R(C) */
|
||||||
|
b = i>>>23;
|
||||||
|
c = i>>14 & 0x1ff; {
|
||||||
|
if (c > b+1) {
|
||||||
|
Buffer sb = stack[c].buffer();
|
||||||
|
while ( --c >= b )
|
||||||
|
sb.concatTo(stack[c]);
|
||||||
|
stack[a] = sb.value();
|
||||||
|
} else {
|
||||||
|
stack[a] = stack[c-1].concat(stack[c]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
|
||||||
|
case Lua.OP_JMP: /* A sBx pc+=sBx; if (A) close all upvalues >= R(A - 1) */
|
||||||
|
pc += (i>>>14)-0x1ffff;
|
||||||
|
if (a > 0) {
|
||||||
|
for (--a, b = openups.length; --b >= 0;)
|
||||||
|
if (openups[b] != null && openups[b].index >= a) {
|
||||||
|
openups[b].close();
|
||||||
|
openups[b] = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
|
||||||
|
case Lua.OP_EQ: /* A B C if ((RK(B) == RK(C)) ~= A) then pc++ */
|
||||||
|
if (((b = i>>>23) > 0xff? k[b & 0x0ff]: stack[b])
|
||||||
|
.eq_b((c = i>>14 & 0x1ff) > 0xff? k[c & 0x0ff]: stack[c]) != (a != 0))
|
||||||
|
++pc;
|
||||||
|
continue;
|
||||||
|
|
||||||
|
case Lua.OP_LT: /* A B C if ((RK(B) < RK(C)) ~= A) then pc++ */
|
||||||
|
if (((b = i>>>23) > 0xff? k[b & 0x0ff]: stack[b])
|
||||||
|
.lt_b((c = i>>14 & 0x1ff) > 0xff? k[c & 0x0ff]: stack[c]) != (a != 0))
|
||||||
|
++pc;
|
||||||
|
continue;
|
||||||
|
|
||||||
|
case Lua.OP_LE: /* A B C if ((RK(B) <= RK(C)) ~= A) then pc++ */
|
||||||
|
if (((b = i>>>23) > 0xff? k[b & 0x0ff]: stack[b])
|
||||||
|
.lteq_b((c = i>>14 & 0x1ff) > 0xff? k[c & 0x0ff]: stack[c]) != (a != 0))
|
||||||
|
++pc;
|
||||||
|
continue;
|
||||||
|
|
||||||
|
case Lua.OP_TEST: /* A C if not (R(A) <=> C) then pc++ */
|
||||||
|
if (stack[a].toboolean() != ((i & 0x1ff<<14) != 0))
|
||||||
|
++pc;
|
||||||
|
continue;
|
||||||
|
|
||||||
|
case Lua.OP_TESTSET: /* A B C if (R(B) <=> C) then R(A):= R(B) else pc++ */
|
||||||
|
/* note: doc appears to be reversed */
|
||||||
|
if ((o = stack[i>>>23]).toboolean() != ((i & 0x1ff<<14) != 0))
|
||||||
|
++pc;
|
||||||
|
else
|
||||||
|
stack[a] = o; // TODO: should be sBx?
|
||||||
|
continue;
|
||||||
|
|
||||||
|
case Lua.OP_CALL: /* A B C R(A), ... ,R(A+C-2):= R(A)(R(A+1), ... ,R(A+B-1)) */
|
||||||
|
switch (i & (Lua.MASK_B | Lua.MASK_C)) {
|
||||||
|
case 1<<Lua.POS_B | 0<<Lua.POS_C:
|
||||||
|
v = stack[a].invoke(NONE);
|
||||||
|
top = a+v.narg();
|
||||||
|
continue;
|
||||||
|
case 2<<Lua.POS_B | 0<<Lua.POS_C:
|
||||||
|
v = stack[a].invoke(stack[a+1]);
|
||||||
|
top = a+v.narg();
|
||||||
|
continue;
|
||||||
|
case 1<<Lua.POS_B | 1<<Lua.POS_C:
|
||||||
|
stack[a].call();
|
||||||
|
continue;
|
||||||
|
case 2<<Lua.POS_B | 1<<Lua.POS_C:
|
||||||
|
stack[a].call(stack[a+1]);
|
||||||
|
continue;
|
||||||
|
case 3<<Lua.POS_B | 1<<Lua.POS_C:
|
||||||
|
stack[a].call(stack[a+1], stack[a+2]);
|
||||||
|
continue;
|
||||||
|
case 4<<Lua.POS_B | 1<<Lua.POS_C:
|
||||||
|
stack[a].call(stack[a+1], stack[a+2], stack[a+3]);
|
||||||
|
continue;
|
||||||
|
case 1<<Lua.POS_B | 2<<Lua.POS_C:
|
||||||
|
stack[a] = stack[a].call();
|
||||||
|
continue;
|
||||||
|
case 2<<Lua.POS_B | 2<<Lua.POS_C:
|
||||||
|
stack[a] = stack[a].call(stack[a+1]);
|
||||||
|
continue;
|
||||||
|
case 3<<Lua.POS_B | 2<<Lua.POS_C:
|
||||||
|
stack[a] = stack[a].call(stack[a+1], stack[a+2]);
|
||||||
|
continue;
|
||||||
|
case 4<<Lua.POS_B | 2<<Lua.POS_C:
|
||||||
|
stack[a] = stack[a].call(stack[a+1], stack[a+2], stack[a+3]);
|
||||||
|
continue;
|
||||||
|
default:
|
||||||
|
b = i>>>23;
|
||||||
|
c = i>>14 & 0x1ff;
|
||||||
|
v = stack[a].invoke(b > 0? varargsOf(stack, a+1, b-1): // exact arg count
|
||||||
|
varargsOf(stack, a+1, top-v.narg()-(a+1), v)); // from prev top
|
||||||
|
if (c > 0) {
|
||||||
|
v.copyto(stack, a, c-1);
|
||||||
|
v = NONE;
|
||||||
|
} else {
|
||||||
|
top = a+v.narg();
|
||||||
|
v = v.dealias();
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
case Lua.OP_TAILCALL: /* A B C return R(A)(R(A+1), ... ,R(A+B-1)) */
|
||||||
|
switch (i & Lua.MASK_B) {
|
||||||
|
case 1<<Lua.POS_B:
|
||||||
|
return new TailcallVarargs(stack[a], NONE);
|
||||||
|
case 2<<Lua.POS_B:
|
||||||
|
return new TailcallVarargs(stack[a], stack[a+1]);
|
||||||
|
case 3<<Lua.POS_B:
|
||||||
|
return new TailcallVarargs(stack[a], varargsOf(stack[a+1], stack[a+2]));
|
||||||
|
case 4<<Lua.POS_B:
|
||||||
|
return new TailcallVarargs(stack[a], varargsOf(stack[a+1], stack[a+2], stack[a+3]));
|
||||||
|
default:
|
||||||
|
b = i>>>23;
|
||||||
|
v = b > 0? varargsOf(stack, a+1, b-1): // exact arg count
|
||||||
|
varargsOf(stack, a+1, top-v.narg()-(a+1), v); // from prev top
|
||||||
|
return new TailcallVarargs(stack[a], v);
|
||||||
|
}
|
||||||
|
|
||||||
|
case Lua.OP_RETURN: /* A B return R(A), ... ,R(A+B-2) (see note) */
|
||||||
|
b = i>>>23;
|
||||||
|
switch (b) {
|
||||||
|
case 0:
|
||||||
|
return varargsOf(stack, a, top-v.narg()-a, v);
|
||||||
|
case 1:
|
||||||
|
return NONE;
|
||||||
|
case 2:
|
||||||
|
return stack[a];
|
||||||
|
default:
|
||||||
|
return varargsOf(stack, a, b-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
case Lua.OP_FORLOOP: /* A sBx R(A)+=R(A+2): if R(A) <?= R(A+1) then { pc+=sBx: R(A+3)=R(A) }*/
|
||||||
|
{
|
||||||
|
LuaValue limit = stack[a+1];
|
||||||
|
LuaValue step = stack[a+2];
|
||||||
|
LuaValue idx = stack[a].add(step);
|
||||||
|
if (step.gt_b(0)? idx.lteq_b(limit): idx.gteq_b(limit)) {
|
||||||
|
stack[a] = idx;
|
||||||
|
stack[a+3] = idx;
|
||||||
|
pc += (i>>>14)-0x1ffff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
|
||||||
|
case Lua.OP_FORPREP: /* A sBx R(A)-=R(A+2): pc+=sBx */
|
||||||
|
{
|
||||||
|
LuaValue init = stack[a].checknumber("'for' initial value must be a number");
|
||||||
|
LuaValue limit = stack[a+1].checknumber("'for' limit must be a number");
|
||||||
|
LuaValue step = stack[a+2].checknumber("'for' step must be a number");
|
||||||
|
stack[a] = init.sub(step);
|
||||||
|
stack[a+1] = limit;
|
||||||
|
stack[a+2] = step;
|
||||||
|
pc += (i>>>14)-0x1ffff;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
|
||||||
|
case Lua.OP_TFORCALL: /* A C R(A+3), ... ,R(A+2+C) := R(A)(R(A+1), R(A+2)); */
|
||||||
|
v = stack[a].invoke(varargsOf(stack[a+1], stack[a+2]));
|
||||||
|
c = i>>14 & 0x1ff;
|
||||||
|
while ( --c >= 0 )
|
||||||
|
stack[a+3+c] = v.arg(c+1);
|
||||||
|
v = NONE;
|
||||||
|
continue;
|
||||||
|
|
||||||
|
case Lua.OP_TFORLOOP: /* A sBx if R(A+1) ~= nil then { R(A)=R(A+1); pc += sBx */
|
||||||
|
if (!stack[a+1].isnil()) { /* continue loop? */
|
||||||
|
stack[a] = stack[a+1]; /* save control varible. */
|
||||||
|
pc += (i>>>14)-0x1ffff;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
|
||||||
|
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)
|
||||||
|
c = code[++pc];
|
||||||
|
int offset = (c-1)*Lua.LFIELDS_PER_FLUSH;
|
||||||
|
o = stack[a];
|
||||||
|
if ((b = i>>>23) == 0) {
|
||||||
|
b = top-a-1;
|
||||||
|
int m = b-v.narg();
|
||||||
|
int j = 1;
|
||||||
|
for (; j <= m; j++)
|
||||||
|
o.set(offset+j, stack[a+j]);
|
||||||
|
for (; j <= b; j++)
|
||||||
|
o.set(offset+j, v.arg(j-m));
|
||||||
|
} else {
|
||||||
|
o.presize(offset+b);
|
||||||
|
for (int j = 1; j <= b; j++)
|
||||||
|
o.set(offset+j, stack[a+j]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
|
||||||
|
case Lua.OP_CLOSURE: /* A Bx R(A):= closure(KPROTO[Bx]) */
|
||||||
|
{
|
||||||
|
Prototype newp = p.p[i>>>14];
|
||||||
|
LuaClosure ncl = new LuaClosure(newp, globals);
|
||||||
|
Upvaldesc[] uv = newp.upvalues;
|
||||||
|
for (int j = 0, nup = uv.length; j < nup; ++j) {
|
||||||
|
if (uv[j].instack) /* upvalue refes to local variable? */
|
||||||
|
ncl.upValues[j] = findupval(stack, uv[j].idx, openups);
|
||||||
|
else /* get upvalue from enclosing function */
|
||||||
|
ncl.upValues[j] = upValues[uv[j].idx];
|
||||||
|
}
|
||||||
|
stack[a] = ncl;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
|
||||||
|
case Lua.OP_VARARG: /* A B R(A), R(A+1), ..., R(A+B-1) = vararg */
|
||||||
|
b = i>>>23;
|
||||||
|
if (b == 0) {
|
||||||
|
top = a+(b = varargs.narg());
|
||||||
|
v = varargs;
|
||||||
|
} else {
|
||||||
|
for (int j = 1; j < b; ++j)
|
||||||
|
stack[a+j-1] = varargs.arg(j);
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
|
||||||
|
case Lua.OP_EXTRAARG:
|
||||||
|
throw new java.lang.IllegalArgumentException("Uexecutable opcode: OP_EXTRAARG");
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw new java.lang.IllegalArgumentException("Illegal opcode: " + (i & 0x3f));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (LuaError le) {
|
||||||
|
if (le.traceback == null)
|
||||||
|
processErrorHooks(le, p, pc);
|
||||||
|
throw le;
|
||||||
|
} catch (Exception e) {
|
||||||
|
LuaError le = new LuaError(e);
|
||||||
|
processErrorHooks(le, p, pc);
|
||||||
|
throw le;
|
||||||
|
} finally {
|
||||||
|
if (openups != null)
|
||||||
|
for (int u = openups.length; --u >= 0;)
|
||||||
|
if (openups[u] != null)
|
||||||
|
openups[u].close();
|
||||||
|
if (globals != null && globals.debuglib != null)
|
||||||
|
globals.debuglib.onReturn();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Run the error hook if there is one
|
||||||
|
*
|
||||||
|
* @param msg the message to use in error hook processing.
|
||||||
|
*/
|
||||||
|
String errorHook(String msg, int level) {
|
||||||
|
if (globals == null)
|
||||||
|
return msg;
|
||||||
|
final LuaThread r = globals.running;
|
||||||
|
if (r.errorfunc == null)
|
||||||
|
return globals.debuglib != null? msg + "\n" + globals.debuglib.traceback(level): msg;
|
||||||
|
final LuaValue e = r.errorfunc;
|
||||||
|
r.errorfunc = null;
|
||||||
|
try {
|
||||||
|
return e.call(LuaValue.valueOf(msg)).tojstring();
|
||||||
|
} catch (Throwable t) {
|
||||||
|
return "error in error handling";
|
||||||
|
} finally {
|
||||||
|
r.errorfunc = e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void processErrorHooks(LuaError le, Prototype p, int pc) {
|
||||||
|
String file = "?";
|
||||||
|
int line = -1;
|
||||||
|
{
|
||||||
|
CallFrame frame = null;
|
||||||
|
if (globals != null && globals.debuglib != null) {
|
||||||
|
frame = globals.debuglib.getCallFrame(le.level);
|
||||||
|
if (frame != null) {
|
||||||
|
String src = frame.shortsource();
|
||||||
|
file = src != null? src: "?";
|
||||||
|
line = frame.currentline();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (frame == null) {
|
||||||
|
file = p.source != null? p.source.tojstring(): "?";
|
||||||
|
line = p.lineinfo != null && pc >= 0 && pc < p.lineinfo.length? p.lineinfo[pc]: -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
le.fileline = file + ": " + line;
|
||||||
|
le.traceback = errorHook(le.getMessage(), le.level);
|
||||||
|
}
|
||||||
|
|
||||||
|
private UpValue findupval(LuaValue[] stack, short idx, UpValue[] openups) {
|
||||||
|
final int n = openups.length;
|
||||||
|
for (int i = 0; i < n; ++i)
|
||||||
|
if (openups[i] != null && openups[i].index == idx)
|
||||||
|
return openups[i];
|
||||||
|
for (int i = 0; i < n; ++i)
|
||||||
|
if (openups[i] == null)
|
||||||
|
return openups[i] = new UpValue(stack, idx);
|
||||||
|
error("No space for upvalue");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected LuaValue getUpvalue(int i) {
|
||||||
|
return upValues[i].getValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void setUpvalue(int i, LuaValue v) {
|
||||||
|
upValues[i].setValue(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String name() {
|
||||||
|
return "<" + p.shortsource() + ":" + p.linedefined + ">";
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -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";
|
||||||
|
|
||||||
@@ -177,7 +184,14 @@ public class LuaDouble extends LuaNumber {
|
|||||||
* @see #dmod_d(double, double)
|
* @see #dmod_d(double, double)
|
||||||
*/
|
*/
|
||||||
public static LuaValue dmod(double lhs, double rhs) {
|
public static LuaValue dmod(double lhs, double rhs) {
|
||||||
return rhs!=0? valueOf( lhs-rhs*Math.floor(lhs/rhs) ): NAN;
|
if (rhs == 0 || lhs == Double.POSITIVE_INFINITY || lhs == Double.NEGATIVE_INFINITY) return NAN;
|
||||||
|
if (rhs == Double.POSITIVE_INFINITY) {
|
||||||
|
return lhs < 0 ? POSINF : valueOf(lhs);
|
||||||
|
}
|
||||||
|
if (rhs == Double.NEGATIVE_INFINITY) {
|
||||||
|
return lhs > 0 ? NEGINF : valueOf(lhs);
|
||||||
|
}
|
||||||
|
return valueOf( lhs-rhs*Math.floor(lhs/rhs) );
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Take modulo for double numbers according to lua math, and return a double result.
|
/** Take modulo for double numbers according to lua math, and return a double result.
|
||||||
@@ -188,32 +202,39 @@ public class LuaDouble extends LuaNumber {
|
|||||||
* @see #dmod(double, double)
|
* @see #dmod(double, double)
|
||||||
*/
|
*/
|
||||||
public static double dmod_d(double lhs, double rhs) {
|
public static double dmod_d(double lhs, double rhs) {
|
||||||
return rhs!=0? lhs-rhs*Math.floor(lhs/rhs): Double.NaN;
|
if (rhs == 0 || lhs == Double.POSITIVE_INFINITY || lhs == Double.NEGATIVE_INFINITY) return Double.NaN;
|
||||||
|
if (rhs == Double.POSITIVE_INFINITY) {
|
||||||
|
return lhs < 0 ? Double.POSITIVE_INFINITY : lhs;
|
||||||
|
}
|
||||||
|
if (rhs == Double.NEGATIVE_INFINITY) {
|
||||||
|
return lhs > 0 ? Double.NEGATIVE_INFINITY : lhs;
|
||||||
|
}
|
||||||
|
return lhs-rhs*Math.floor(lhs/rhs);
|
||||||
}
|
}
|
||||||
|
|
||||||
// relational operators
|
// relational operators
|
||||||
public LuaValue lt( LuaValue rhs ) { return rhs.gt_b(v)? LuaValue.TRUE: FALSE; }
|
public LuaValue lt( LuaValue rhs ) { return rhs instanceof LuaNumber ? (rhs.gt_b(v)? TRUE: FALSE) : super.lt(rhs); }
|
||||||
public LuaValue lt( double rhs ) { return v < rhs? TRUE: FALSE; }
|
public LuaValue lt( double rhs ) { return v < rhs? TRUE: FALSE; }
|
||||||
public LuaValue lt( int rhs ) { return v < rhs? TRUE: FALSE; }
|
public LuaValue lt( int rhs ) { return v < rhs? TRUE: FALSE; }
|
||||||
public boolean lt_b( LuaValue rhs ) { return rhs.gt_b(v); }
|
public boolean lt_b( LuaValue rhs ) { return rhs instanceof LuaNumber ? rhs.gt_b(v) : super.lt_b(rhs); }
|
||||||
public boolean lt_b( int rhs ) { return v < rhs; }
|
public boolean lt_b( int rhs ) { return v < rhs; }
|
||||||
public boolean lt_b( double rhs ) { return v < rhs; }
|
public boolean lt_b( double rhs ) { return v < rhs; }
|
||||||
public LuaValue lteq( LuaValue rhs ) { return rhs.gteq_b(v)? LuaValue.TRUE: FALSE; }
|
public LuaValue lteq( LuaValue rhs ) { return rhs instanceof LuaNumber ? (rhs.gteq_b(v)? TRUE: FALSE) : super.lteq(rhs); }
|
||||||
public LuaValue lteq( double rhs ) { return v <= rhs? TRUE: FALSE; }
|
public LuaValue lteq( double rhs ) { return v <= rhs? TRUE: FALSE; }
|
||||||
public LuaValue lteq( int rhs ) { return v <= rhs? TRUE: FALSE; }
|
public LuaValue lteq( int rhs ) { return v <= rhs? TRUE: FALSE; }
|
||||||
public boolean lteq_b( LuaValue rhs ) { return rhs.gteq_b(v); }
|
public boolean lteq_b( LuaValue rhs ) { return rhs instanceof LuaNumber ? rhs.gteq_b(v) : super.lteq_b(rhs); }
|
||||||
public boolean lteq_b( int rhs ) { return v <= rhs; }
|
public boolean lteq_b( int rhs ) { return v <= rhs; }
|
||||||
public boolean lteq_b( double rhs ) { return v <= rhs; }
|
public boolean lteq_b( double rhs ) { return v <= rhs; }
|
||||||
public LuaValue gt( LuaValue rhs ) { return rhs.lt_b(v)? LuaValue.TRUE: FALSE; }
|
public LuaValue gt( LuaValue rhs ) { return rhs instanceof LuaNumber ? (rhs.lt_b(v)? TRUE: FALSE) : super.gt(rhs); }
|
||||||
public LuaValue gt( double rhs ) { return v > rhs? TRUE: FALSE; }
|
public LuaValue gt( double rhs ) { return v > rhs? TRUE: FALSE; }
|
||||||
public LuaValue gt( int rhs ) { return v > rhs? TRUE: FALSE; }
|
public LuaValue gt( int rhs ) { return v > rhs? TRUE: FALSE; }
|
||||||
public boolean gt_b( LuaValue rhs ) { return rhs.lt_b(v); }
|
public boolean gt_b( LuaValue rhs ) { return rhs instanceof LuaNumber ? rhs.lt_b(v) : super.gt_b(rhs); }
|
||||||
public boolean gt_b( int rhs ) { return v > rhs; }
|
public boolean gt_b( int rhs ) { return v > rhs; }
|
||||||
public boolean gt_b( double rhs ) { return v > rhs; }
|
public boolean gt_b( double rhs ) { return v > rhs; }
|
||||||
public LuaValue gteq( LuaValue rhs ) { return rhs.lteq_b(v)? LuaValue.TRUE: FALSE; }
|
public LuaValue gteq( LuaValue rhs ) { return rhs instanceof LuaNumber ? (rhs.lteq_b(v)? TRUE: FALSE) : super.gteq(rhs); }
|
||||||
public LuaValue gteq( double rhs ) { return v >= rhs? TRUE: FALSE; }
|
public LuaValue gteq( double rhs ) { return v >= rhs? TRUE: FALSE; }
|
||||||
public LuaValue gteq( int rhs ) { return v >= rhs? TRUE: FALSE; }
|
public LuaValue gteq( int rhs ) { return v >= rhs? TRUE: FALSE; }
|
||||||
public boolean gteq_b( LuaValue rhs ) { return rhs.lteq_b(v); }
|
public boolean gteq_b( LuaValue rhs ) { return rhs instanceof LuaNumber ? rhs.lteq_b(v) : super.gteq_b(rhs); }
|
||||||
public boolean gteq_b( int rhs ) { return v >= rhs; }
|
public boolean gteq_b( int rhs ) { return v >= rhs; }
|
||||||
public boolean gteq_b( double rhs ) { return v >= rhs; }
|
public boolean gteq_b( double rhs ) { return v >= rhs; }
|
||||||
|
|
||||||
@@ -221,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);
|
||||||
@@ -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,28 +62,33 @@ 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) {
|
||||||
super( "vm error: "+cause );
|
super("vm error: " + cause);
|
||||||
this.cause = cause;
|
this.cause = cause;
|
||||||
this.level = 1;
|
this.level = 1;
|
||||||
}
|
}
|
||||||
@@ -93,38 +99,38 @@ public class LuaError extends RuntimeException {
|
|||||||
* @param message message to supply
|
* @param message message to supply
|
||||||
*/
|
*/
|
||||||
public LuaError(String message) {
|
public LuaError(String message) {
|
||||||
super( message );
|
super(message);
|
||||||
this.level = 1;
|
this.level = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Construct a LuaError with a message, and level to draw line number information from.
|
* Construct a LuaError with a message, and level to draw line number
|
||||||
|
* information from.
|
||||||
|
*
|
||||||
* @param message message to supply
|
* @param 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
|
||||||
*/
|
*/
|
||||||
public LuaError(String message, int level) {
|
public LuaError(String message, int level) {
|
||||||
super( message );
|
super(message);
|
||||||
this.level = level;
|
this.level = level;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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) {
|
||||||
super( message_object.tojstring() );
|
super(message_object.tojstring());
|
||||||
this.object = message_object;
|
this.object = message_object;
|
||||||
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; }
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -21,68 +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
|
||||||
|
* 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();
|
||||||
return s.substring(Math.max(s.lastIndexOf('.'),s.lastIndexOf('$'))+1);
|
int offset = Math.max(s.lastIndexOf('.'), s.lastIndexOf('$'))+1;
|
||||||
|
if (s.charAt(offset) == '_')
|
||||||
|
offset++;
|
||||||
|
return s.substring(offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Return a human-readable name for this function. Returns the last part of the class name by default.
|
/**
|
||||||
* Is overridden by LuaClosure to return the source file and line, and by LibFunctions to return the name.
|
* Return 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();
|
||||||
}
|
}
|
||||||
372
luaj-core/src/main/java/org/luaj/vm2/LuaInteger.java
Normal file
372
luaj-core/src/main/java/org/luaj/vm2/LuaInteger.java
Normal 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));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -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; }
|
||||||
}
|
}
|
||||||
@@ -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); }
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -144,7 +144,7 @@ public class LuaString extends LuaValue {
|
|||||||
/** Construct a new LuaString using a copy of the bytes array supplied */
|
/** Construct a new LuaString using a copy of the bytes array supplied */
|
||||||
private static LuaString valueFromCopy(byte[] bytes, int off, int len) {
|
private static LuaString valueFromCopy(byte[] bytes, int off, int len) {
|
||||||
final byte[] copy = new byte[len];
|
final byte[] copy = new byte[len];
|
||||||
for (int i=0; i<len; ++i) copy[i] = bytes[off+i];
|
System.arraycopy(bytes, off, copy, 0, len);
|
||||||
return new LuaString(copy, 0, len);
|
return new LuaString(copy, 0, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -289,20 +289,20 @@ public class LuaString extends LuaValue {
|
|||||||
public LuaValue modFrom( double lhs ) { return LuaDouble.dmod(lhs, checkarith()); }
|
public LuaValue modFrom( double lhs ) { return LuaDouble.dmod(lhs, checkarith()); }
|
||||||
|
|
||||||
// relational operators, these only work with other strings
|
// relational operators, these only work with other strings
|
||||||
public LuaValue lt( LuaValue rhs ) { return rhs.strcmp(this)>0? LuaValue.TRUE: FALSE; }
|
public LuaValue lt( LuaValue rhs ) { return rhs.isstring() ? (rhs.strcmp(this)>0? LuaValue.TRUE: FALSE) : super.lt(rhs); }
|
||||||
public boolean lt_b( LuaValue rhs ) { return rhs.strcmp(this)>0; }
|
public boolean lt_b( LuaValue rhs ) { return rhs.isstring() ? rhs.strcmp(this)>0 : super.lt_b(rhs); }
|
||||||
public boolean lt_b( int rhs ) { typerror("attempt to compare string with number"); return false; }
|
public boolean lt_b( int rhs ) { typerror("attempt to compare string with number"); return false; }
|
||||||
public boolean lt_b( double rhs ) { typerror("attempt to compare string with number"); return false; }
|
public boolean lt_b( double rhs ) { typerror("attempt to compare string with number"); return false; }
|
||||||
public LuaValue lteq( LuaValue rhs ) { return rhs.strcmp(this)>=0? LuaValue.TRUE: FALSE; }
|
public LuaValue lteq( LuaValue rhs ) { return rhs.isstring() ? (rhs.strcmp(this)>=0? LuaValue.TRUE: FALSE) : super.lteq(rhs); }
|
||||||
public boolean lteq_b( LuaValue rhs ) { return rhs.strcmp(this)>=0; }
|
public boolean lteq_b( LuaValue rhs ) { return rhs.isstring() ? rhs.strcmp(this)>=0 : super.lteq_b(rhs); }
|
||||||
public boolean lteq_b( int rhs ) { typerror("attempt to compare string with number"); return false; }
|
public boolean lteq_b( int rhs ) { typerror("attempt to compare string with number"); return false; }
|
||||||
public boolean lteq_b( double rhs ) { typerror("attempt to compare string with number"); return false; }
|
public boolean lteq_b( double rhs ) { typerror("attempt to compare string with number"); return false; }
|
||||||
public LuaValue gt( LuaValue rhs ) { return rhs.strcmp(this)<0? LuaValue.TRUE: FALSE; }
|
public LuaValue gt( LuaValue rhs ) { return rhs.isstring() ? (rhs.strcmp(this)<0? LuaValue.TRUE: FALSE) : super.gt(rhs); }
|
||||||
public boolean gt_b( LuaValue rhs ) { return rhs.strcmp(this)<0; }
|
public boolean gt_b( LuaValue rhs ) { return rhs.isstring() ? rhs.strcmp(this)<0 : super.gt_b(rhs); }
|
||||||
public boolean gt_b( int rhs ) { typerror("attempt to compare string with number"); return false; }
|
public boolean gt_b( int rhs ) { typerror("attempt to compare string with number"); return false; }
|
||||||
public boolean gt_b( double rhs ) { typerror("attempt to compare string with number"); return false; }
|
public boolean gt_b( double rhs ) { typerror("attempt to compare string with number"); return false; }
|
||||||
public LuaValue gteq( LuaValue rhs ) { return rhs.strcmp(this)<=0? LuaValue.TRUE: FALSE; }
|
public LuaValue gteq( LuaValue rhs ) { return rhs.isstring() ? (rhs.strcmp(this)<=0? LuaValue.TRUE: FALSE) : super.gteq(rhs); }
|
||||||
public boolean gteq_b( LuaValue rhs ) { return rhs.strcmp(this)<=0; }
|
public boolean gteq_b( LuaValue rhs ) { return rhs.isstring() ? rhs.strcmp(this)<=0 : super.gteq_b(rhs); }
|
||||||
public boolean gteq_b( int rhs ) { typerror("attempt to compare string with number"); return false; }
|
public boolean gteq_b( int rhs ) { typerror("attempt to compare string with number"); return false; }
|
||||||
public boolean gteq_b( double rhs ) { typerror("attempt to compare string with number"); return false; }
|
public boolean gteq_b( double rhs ) { typerror("attempt to compare string with number"); return false; }
|
||||||
|
|
||||||
@@ -391,23 +391,23 @@ public class LuaString extends LuaValue {
|
|||||||
public short toshort() { return (short) toint(); }
|
public short toshort() { return (short) toint(); }
|
||||||
|
|
||||||
public double optdouble(double defval) {
|
public double optdouble(double defval) {
|
||||||
return checknumber().checkdouble();
|
return checkdouble();
|
||||||
}
|
}
|
||||||
|
|
||||||
public int optint(int defval) {
|
public int optint(int defval) {
|
||||||
return checknumber().checkint();
|
return checkint();
|
||||||
}
|
}
|
||||||
|
|
||||||
public LuaInteger optinteger(LuaInteger defval) {
|
public LuaInteger optinteger(LuaInteger defval) {
|
||||||
return checknumber().checkinteger();
|
return checkinteger();
|
||||||
}
|
}
|
||||||
|
|
||||||
public long optlong(long defval) {
|
public long optlong(long defval) {
|
||||||
return checknumber().checklong();
|
return checklong();
|
||||||
}
|
}
|
||||||
|
|
||||||
public LuaNumber optnumber(LuaNumber defval) {
|
public LuaNumber optnumber(LuaNumber defval) {
|
||||||
return checknumber().checknumber();
|
return checknumber();
|
||||||
}
|
}
|
||||||
|
|
||||||
public LuaString optstring(LuaString defval) {
|
public LuaString optstring(LuaString defval) {
|
||||||
@@ -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];
|
||||||
@@ -663,11 +669,24 @@ public class LuaString extends LuaValue {
|
|||||||
* @see #isValidUtf8()
|
* @see #isValidUtf8()
|
||||||
*/
|
*/
|
||||||
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -689,16 +708,28 @@ public class LuaString extends LuaValue {
|
|||||||
public static int encodeToUtf8(char[] chars, int nchars, byte[] bytes, int off) {
|
public static int encodeToUtf8(char[] chars, int nchars, byte[] bytes, int off) {
|
||||||
char c;
|
char c;
|
||||||
int j = off;
|
int j = off;
|
||||||
for ( int i=0; i<nchars; i++ ) {
|
for (int i = 0; i < nchars; i++) {
|
||||||
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) '?';
|
||||||
bytes[j++] = (byte) (0x80 | ((c>>6) & 0x3f));
|
}
|
||||||
bytes[j++] = (byte) (0x80 | ( c & 0x3f));
|
} 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 & 0x3f));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return j - off;
|
return j - off;
|
||||||
@@ -711,16 +742,16 @@ public class LuaString extends LuaValue {
|
|||||||
* @see #decodeAsUtf8(byte[], int, int)
|
* @see #decodeAsUtf8(byte[], int, int)
|
||||||
*/
|
*/
|
||||||
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,21 +781,86 @@ 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.
|
||||||
* @return double value if conversion is valid, or Double.NaN if not
|
* @return double value if conversion is valid, or Double.NaN if not
|
||||||
*/
|
*/
|
||||||
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;
|
||||||
if ( i>=j )
|
while (i < j && isspace(m_bytes[j - 1]))
|
||||||
|
--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 )
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -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;
|
||||||
@@ -211,7 +211,7 @@ public class LuaThread extends LuaValue {
|
|||||||
this.args = args;
|
this.args = args;
|
||||||
if (this.status == STATUS_INITIAL) {
|
if (this.status == STATUS_INITIAL) {
|
||||||
this.status = STATUS_RUNNING;
|
this.status = STATUS_RUNNING;
|
||||||
new Thread(this, "Coroutine-"+(++coroutine_count)).start();
|
new Thread(this, "Coroutine-" + (++coroutine_count)).start();
|
||||||
} else {
|
} else {
|
||||||
this.notify();
|
this.notify();
|
||||||
}
|
}
|
||||||
@@ -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 {
|
||||||
@@ -230,7 +229,7 @@ public class LuaThread extends LuaValue {
|
|||||||
this.error = null;
|
this.error = null;
|
||||||
globals.running = previous_thread;
|
globals.running = previous_thread;
|
||||||
if (previous_thread != null)
|
if (previous_thread != null)
|
||||||
globals.running.state.status =STATUS_RUNNING;
|
globals.running.state.status = STATUS_RUNNING;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -245,7 +244,7 @@ public class LuaThread extends LuaValue {
|
|||||||
this.status = STATUS_DEAD;
|
this.status = STATUS_DEAD;
|
||||||
throw new OrphanedThread();
|
throw new OrphanedThread();
|
||||||
}
|
}
|
||||||
} while (this.status == STATUS_SUSPENDED);
|
} while ( this.status == STATUS_SUSPENDED );
|
||||||
return this.args;
|
return this.args;
|
||||||
} catch (InterruptedException ie) {
|
} catch (InterruptedException ie) {
|
||||||
this.status = STATUS_DEAD;
|
this.status = STATUS_DEAD;
|
||||||
@@ -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,71 +59,98 @@ 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());
|
||||||
}
|
}
|
||||||
|
|
||||||
public LuaValue get( LuaValue key ) {
|
@Override
|
||||||
return m_metatable!=null? gettable(this,key): NIL;
|
public LuaValue get(LuaValue key) {
|
||||||
|
return m_metatable != null? gettable(this, key): NIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void set( LuaValue key, LuaValue value ) {
|
@Override
|
||||||
if ( m_metatable==null || ! settable(this,key,value) )
|
public void set(LuaValue key, LuaValue value) {
|
||||||
error( "cannot set "+key+" for userdata" );
|
if (m_metatable == null || !settable(this, key, value))
|
||||||
|
error("cannot set " + key + " for userdata");
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean equals( Object val ) {
|
@Override
|
||||||
if ( this == val )
|
public boolean equals(Object val) {
|
||||||
|
if (this == val)
|
||||||
return true;
|
return true;
|
||||||
if ( ! (val instanceof LuaUserdata) )
|
if (!(val instanceof LuaUserdata))
|
||||||
return false;
|
return false;
|
||||||
LuaUserdata u = (LuaUserdata) val;
|
LuaUserdata u = (LuaUserdata) val;
|
||||||
return m_instance.equals(u.m_instance);
|
return m_instance.equals(u.m_instance);
|
||||||
}
|
}
|
||||||
|
|
||||||
// equality w/ metatable processing
|
// equality w/ metatable processing
|
||||||
public LuaValue eq( LuaValue val ) { return eq_b(val)? TRUE: FALSE; }
|
@Override
|
||||||
public boolean eq_b( LuaValue val ) {
|
public LuaValue eq(LuaValue val) { return eq_b(val)? TRUE: FALSE; }
|
||||||
if ( val.raweq(this) ) return true;
|
|
||||||
if ( m_metatable == null || !val.isuserdata() ) return false;
|
@Override
|
||||||
|
public boolean eq_b(LuaValue val) {
|
||||||
|
if (val.raweq(this))
|
||||||
|
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
|
||||||
public boolean raweq( LuaValue val ) { return val.raweq(this); }
|
@Override
|
||||||
public boolean raweq( LuaUserdata val ) {
|
public boolean raweq(LuaValue val) { return val.raweq(this); }
|
||||||
return this == val || (m_metatable == val.m_metatable && m_instance.equals(val.m_instance));
|
|
||||||
|
@Override
|
||||||
|
public boolean raweq(LuaUserdata val) {
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -21,8 +21,6 @@
|
|||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
package org.luaj.vm2;
|
package org.luaj.vm2;
|
||||||
|
|
||||||
import org.luaj.vm2.Varargs;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Base class for all concrete lua type values.
|
* Base class for all concrete lua type values.
|
||||||
* <p>
|
* <p>
|
||||||
@@ -101,7 +99,7 @@ import org.luaj.vm2.Varargs;
|
|||||||
* {@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
|
||||||
@@ -245,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("");
|
||||||
|
|
||||||
@@ -531,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}
|
||||||
@@ -627,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
|
||||||
@@ -643,7 +647,7 @@ public class LuaValue extends Varargs {
|
|||||||
* @see #isnumber()
|
* @see #isnumber()
|
||||||
* @see #TNUMBER
|
* @see #TNUMBER
|
||||||
*/
|
*/
|
||||||
public double optdouble(double defval) { argerror("double"); return 0; }
|
public double optdouble(double defval) { argerror("number"); return 0; }
|
||||||
|
|
||||||
/** Check that optional argument is a function and return as {@link LuaFunction}
|
/** Check that optional argument is a function and return as {@link LuaFunction}
|
||||||
* <p>
|
* <p>
|
||||||
@@ -739,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
|
||||||
@@ -855,7 +859,7 @@ public class LuaValue extends Varargs {
|
|||||||
* @see #optdouble(double)
|
* @see #optdouble(double)
|
||||||
* @see #TNUMBER
|
* @see #TNUMBER
|
||||||
*/
|
*/
|
||||||
public double checkdouble() { argerror("double"); return 0; }
|
public double checkdouble() { argerror("number"); return 0; }
|
||||||
|
|
||||||
/** Check that the value is a function , or throw {@link LuaError} if not
|
/** Check that the value is a function , or throw {@link LuaError} if not
|
||||||
* <p>
|
* <p>
|
||||||
@@ -890,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>
|
||||||
@@ -1055,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
|
||||||
@@ -2045,7 +2049,7 @@ public class LuaValue extends Varargs {
|
|||||||
* @see #eqmtcall(LuaValue, LuaValue, LuaValue, LuaValue)
|
* @see #eqmtcall(LuaValue, LuaValue, LuaValue, LuaValue)
|
||||||
* @see #EQ
|
* @see #EQ
|
||||||
*/
|
*/
|
||||||
public LuaValue eq( LuaValue val ) { return this == val? TRUE: FALSE; }
|
public LuaValue eq( LuaValue val ) { return eq_b(val)? TRUE: FALSE; }
|
||||||
|
|
||||||
/** Equals: Perform equality comparison with another value
|
/** Equals: Perform equality comparison with another value
|
||||||
* including metatag processing using {@link #EQ},
|
* including metatag processing using {@link #EQ},
|
||||||
@@ -2987,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
|
||||||
@@ -3143,7 +3147,7 @@ public class LuaValue extends Varargs {
|
|||||||
* @return {@link LuaString} corresponding to the value if a string or number
|
* @return {@link LuaString} corresponding to the value if a string or number
|
||||||
* @throws LuaError if not a string or number
|
* @throws LuaError if not a string or number
|
||||||
*/
|
*/
|
||||||
public LuaString strvalue() { typerror("strValue"); return null; }
|
public LuaString strvalue() { typerror("string or number"); return null; }
|
||||||
|
|
||||||
/** Return this value as a strong reference, or null if it was weak and is no longer referenced.
|
/** Return this value as a strong reference, or null if it was weak and is no longer referenced.
|
||||||
* @return {@link LuaValue} referred to, or null if it was weak and is no longer referenced.
|
* @return {@link LuaValue} referred to, or null if it was weak and is no longer referenced.
|
||||||
@@ -3298,7 +3302,7 @@ public class LuaValue extends Varargs {
|
|||||||
if ((!res.isnil()) || (tm = t.metatag(INDEX)).isnil())
|
if ((!res.isnil()) || (tm = t.metatag(INDEX)).isnil())
|
||||||
return res;
|
return res;
|
||||||
} else if ((tm = t.metatag(INDEX)).isnil())
|
} else if ((tm = t.metatag(INDEX)).isnil())
|
||||||
t.indexerror();
|
t.indexerror(key.tojstring());
|
||||||
if (tm.isfunction())
|
if (tm.isfunction())
|
||||||
return tm.call(t, key);
|
return tm.call(t, key);
|
||||||
t = tm;
|
t = tm;
|
||||||
@@ -3326,7 +3330,7 @@ public class LuaValue extends Varargs {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
} else if ((tm = t.metatag(NEWINDEX)).isnil())
|
} else if ((tm = t.metatag(NEWINDEX)).isnil())
|
||||||
t.typerror("index");
|
throw new LuaError("table expected for set index ('" + key + "') value, got " + t.typename());
|
||||||
if (tm.isfunction()) {
|
if (tm.isfunction()) {
|
||||||
tm.call(t, key, value);
|
tm.call(t, key, value);
|
||||||
return true;
|
return true;
|
||||||
@@ -3362,7 +3366,7 @@ public class LuaValue extends Varargs {
|
|||||||
protected LuaValue checkmetatag(LuaValue tag, String reason) {
|
protected LuaValue checkmetatag(LuaValue tag, String reason) {
|
||||||
LuaValue h = this.metatag(tag);
|
LuaValue h = this.metatag(tag);
|
||||||
if ( h.isnil() )
|
if ( h.isnil() )
|
||||||
throw new LuaError(reason+typename());
|
throw new LuaError(reason + "a " + typename() + " value");
|
||||||
return h;
|
return h;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3389,8 +3393,8 @@ public class LuaValue extends Varargs {
|
|||||||
/** Throw {@link LuaError} indicating index was attempted on illegal type
|
/** Throw {@link LuaError} indicating index was attempted on illegal type
|
||||||
* @throws LuaError when called.
|
* @throws LuaError when called.
|
||||||
*/
|
*/
|
||||||
private void indexerror() {
|
private void indexerror(String key) {
|
||||||
error( "attempt to index ? (a "+typename()+" value)" );
|
error( "attempt to index ? (a "+typename()+" value) with key '" + key + "'" );
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Construct a {@link Varargs} around an array of {@link LuaValue}s.
|
/** Construct a {@link Varargs} around an array of {@link LuaValue}s.
|
||||||
@@ -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);
|
||||||
}
|
}
|
||||||
@@ -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];
|
||||||
}
|
}
|
||||||
@@ -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
|
||||||
445
luaj-core/src/main/java/org/luaj/vm2/Print.java
Normal file
445
luaj-core/src/main/java/org/luaj/vm2/Print.java
Normal file
@@ -0,0 +1,445 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* 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 java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.PrintStream;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Debug helper class to pretty-print lua bytecodes.
|
||||||
|
*
|
||||||
|
* @see Prototype
|
||||||
|
* @see LuaClosure
|
||||||
|
*/
|
||||||
|
public class Print extends Lua {
|
||||||
|
|
||||||
|
/** opcode names */
|
||||||
|
private static final String STRING_FOR_NULL = "null";
|
||||||
|
public static PrintStream ps = System.out;
|
||||||
|
|
||||||
|
/** String names for each lua opcode value. */
|
||||||
|
public static final String[] OPNAMES = { "MOVE", "LOADK", "LOADKX", "LOADBOOL", "LOADNIL", "GETUPVAL", "GETTABUP",
|
||||||
|
"GETTABLE", "SETTABUP", "SETUPVAL", "SETTABLE", "NEWTABLE", "SELF", "ADD", "SUB", "MUL", "DIV", "MOD",
|
||||||
|
"POW", "UNM", "NOT", "LEN", "CONCAT", "JMP", "EQ", "LT", "LE", "TEST", "TESTSET", "CALL", "TAILCALL",
|
||||||
|
"RETURN", "FORLOOP", "FORPREP", "TFORCALL", "TFORLOOP", "SETLIST", "CLOSURE", "VARARG", "EXTRAARG", null, };
|
||||||
|
|
||||||
|
static void printString(PrintStream ps, final LuaString s) {
|
||||||
|
|
||||||
|
ps.print('"');
|
||||||
|
for (int i = 0, n = s.m_length; i < n; i++) {
|
||||||
|
int c = s.m_bytes[s.m_offset+i];
|
||||||
|
if (c >= ' ' && c <= '~' && c != '\"' && c != '\\')
|
||||||
|
ps.print((char) c);
|
||||||
|
else {
|
||||||
|
switch (c) {
|
||||||
|
case '"':
|
||||||
|
ps.print("\\\"");
|
||||||
|
break;
|
||||||
|
case '\\':
|
||||||
|
ps.print("\\\\");
|
||||||
|
break;
|
||||||
|
case 0x0007: /* bell */
|
||||||
|
ps.print("\\a");
|
||||||
|
break;
|
||||||
|
case '\b': /* backspace */
|
||||||
|
ps.print("\\b");
|
||||||
|
break;
|
||||||
|
case '\f': /* form feed */
|
||||||
|
ps.print("\\f");
|
||||||
|
break;
|
||||||
|
case '\t': /* tab */
|
||||||
|
ps.print("\\t");
|
||||||
|
break;
|
||||||
|
case '\r': /* carriage return */
|
||||||
|
ps.print("\\r");
|
||||||
|
break;
|
||||||
|
case '\n': /* newline */
|
||||||
|
ps.print("\\n");
|
||||||
|
break;
|
||||||
|
case 0x000B: /* vertical tab */
|
||||||
|
ps.print("\\v");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ps.print('\\');
|
||||||
|
ps.print(Integer.toString(1000+0xff & c).substring(1));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ps.print('"');
|
||||||
|
}
|
||||||
|
|
||||||
|
static void printValue(PrintStream ps, LuaValue v) {
|
||||||
|
if (v == null) {
|
||||||
|
ps.print("null");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
switch (v.type()) {
|
||||||
|
case LuaValue.TSTRING:
|
||||||
|
printString(ps, (LuaString) v);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ps.print(v.tojstring());
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void printConstant(PrintStream ps, Prototype f, int i) {
|
||||||
|
printValue(ps, i < f.k.length? f.k[i]: LuaValue.valueOf("UNKNOWN_CONST_" + i));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void printUpvalue(PrintStream ps, Upvaldesc u) {
|
||||||
|
ps.print(u.idx + " ");
|
||||||
|
printValue(ps, u.name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Print the code in a prototype
|
||||||
|
*
|
||||||
|
* @param f the {@link Prototype}
|
||||||
|
*/
|
||||||
|
public static void printCode(Prototype f) {
|
||||||
|
int[] code = f.code;
|
||||||
|
int pc, n = code.length;
|
||||||
|
for (pc = 0; pc < n; pc++) {
|
||||||
|
pc = printOpCode(f, pc);
|
||||||
|
ps.println();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Print an opcode in a prototype
|
||||||
|
*
|
||||||
|
* @param f the {@link Prototype}
|
||||||
|
* @param pc the program counter to look up and print
|
||||||
|
* @return pc same as above or changed
|
||||||
|
*/
|
||||||
|
public static int printOpCode(Prototype f, int pc) {
|
||||||
|
return printOpCode(ps, f, pc);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Print an opcode in a prototype
|
||||||
|
*
|
||||||
|
* @param ps the {@link PrintStream} to print to
|
||||||
|
* @param f the {@link Prototype}
|
||||||
|
* @param pc the program counter to look up and print
|
||||||
|
* @return pc same as above or changed
|
||||||
|
*/
|
||||||
|
public static int printOpCode(PrintStream ps, Prototype f, int pc) {
|
||||||
|
int[] code = f.code;
|
||||||
|
int i = code[pc];
|
||||||
|
int o = GET_OPCODE(i);
|
||||||
|
int a = GETARG_A(i);
|
||||||
|
int b = GETARG_B(i);
|
||||||
|
int c = GETARG_C(i);
|
||||||
|
int bx = GETARG_Bx(i);
|
||||||
|
int sbx = GETARG_sBx(i);
|
||||||
|
int line = getline(f, pc);
|
||||||
|
ps.print(" " + (pc+1) + " ");
|
||||||
|
if (line > 0)
|
||||||
|
ps.print("[" + line + "] ");
|
||||||
|
else
|
||||||
|
ps.print("[-] ");
|
||||||
|
if (o >= OPNAMES.length-1) {
|
||||||
|
ps.print("UNKNOWN_OP_" + o + " ");
|
||||||
|
} else {
|
||||||
|
ps.print(OPNAMES[o] + " ");
|
||||||
|
switch (getOpMode(o)) {
|
||||||
|
case iABC:
|
||||||
|
ps.print(a);
|
||||||
|
if (getBMode(o) != OpArgN)
|
||||||
|
ps.print(" " + (ISK(b)? -1-INDEXK(b): b));
|
||||||
|
if (getCMode(o) != OpArgN)
|
||||||
|
ps.print(" " + (ISK(c)? -1-INDEXK(c): c));
|
||||||
|
break;
|
||||||
|
case iABx:
|
||||||
|
if (getBMode(o) == OpArgK) {
|
||||||
|
ps.print(a + " " + (-1-bx));
|
||||||
|
} else {
|
||||||
|
ps.print(a + " " + bx);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case iAsBx:
|
||||||
|
if (o == OP_JMP)
|
||||||
|
ps.print(sbx);
|
||||||
|
else
|
||||||
|
ps.print(a + " " + sbx);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
switch (o) {
|
||||||
|
case OP_LOADK:
|
||||||
|
ps.print(" ; ");
|
||||||
|
printConstant(ps, f, bx);
|
||||||
|
break;
|
||||||
|
case OP_GETUPVAL:
|
||||||
|
case OP_SETUPVAL:
|
||||||
|
ps.print(" ; ");
|
||||||
|
if (b < f.upvalues.length) {
|
||||||
|
printUpvalue(ps, f.upvalues[b]);
|
||||||
|
} else {
|
||||||
|
ps.print("UNKNOWN_UPVALUE_" + b);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case OP_GETTABUP:
|
||||||
|
ps.print(" ; ");
|
||||||
|
if (b < f.upvalues.length) {
|
||||||
|
printUpvalue(ps, f.upvalues[b]);
|
||||||
|
} else {
|
||||||
|
ps.print("UNKNOWN_UPVALUE_" + b);
|
||||||
|
}
|
||||||
|
ps.print(" ");
|
||||||
|
if (ISK(c))
|
||||||
|
printConstant(ps, f, INDEXK(c));
|
||||||
|
else
|
||||||
|
ps.print("-");
|
||||||
|
break;
|
||||||
|
case OP_SETTABUP:
|
||||||
|
ps.print(" ; ");
|
||||||
|
if (a < f.upvalues.length) {
|
||||||
|
printUpvalue(ps, f.upvalues[a]);
|
||||||
|
} else {
|
||||||
|
ps.print("UNKNOWN_UPVALUE_" + a);
|
||||||
|
}
|
||||||
|
ps.print(" ");
|
||||||
|
if (ISK(b))
|
||||||
|
printConstant(ps, f, INDEXK(b));
|
||||||
|
else
|
||||||
|
ps.print("-");
|
||||||
|
ps.print(" ");
|
||||||
|
if (ISK(c))
|
||||||
|
printConstant(ps, f, INDEXK(c));
|
||||||
|
else
|
||||||
|
ps.print("-");
|
||||||
|
break;
|
||||||
|
case OP_GETTABLE:
|
||||||
|
case OP_SELF:
|
||||||
|
if (ISK(c)) {
|
||||||
|
ps.print(" ; ");
|
||||||
|
printConstant(ps, f, INDEXK(c));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case OP_SETTABLE:
|
||||||
|
case OP_ADD:
|
||||||
|
case OP_SUB:
|
||||||
|
case OP_MUL:
|
||||||
|
case OP_DIV:
|
||||||
|
case OP_POW:
|
||||||
|
case OP_EQ:
|
||||||
|
case OP_LT:
|
||||||
|
case OP_LE:
|
||||||
|
if (ISK(b) || ISK(c)) {
|
||||||
|
ps.print(" ; ");
|
||||||
|
if (ISK(b))
|
||||||
|
printConstant(ps, f, INDEXK(b));
|
||||||
|
else
|
||||||
|
ps.print("-");
|
||||||
|
ps.print(" ");
|
||||||
|
if (ISK(c))
|
||||||
|
printConstant(ps, f, INDEXK(c));
|
||||||
|
else
|
||||||
|
ps.print("-");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case OP_JMP:
|
||||||
|
case OP_FORLOOP:
|
||||||
|
case OP_FORPREP:
|
||||||
|
ps.print(" ; to " + (sbx+pc+2));
|
||||||
|
break;
|
||||||
|
case OP_CLOSURE:
|
||||||
|
if (bx < f.p.length) {
|
||||||
|
ps.print(" ; " + f.p[bx].getClass().getName());
|
||||||
|
} else {
|
||||||
|
ps.print(" ; UNKNOWN_PROTYPE_" + bx);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case OP_SETLIST:
|
||||||
|
if (c == 0)
|
||||||
|
ps.print(" ; " + code[++pc] + " (stored in the next OP)");
|
||||||
|
else
|
||||||
|
ps.print(" ; " + c);
|
||||||
|
break;
|
||||||
|
case OP_VARARG:
|
||||||
|
ps.print(" ; is_vararg=" + f.is_vararg);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return pc;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int getline(Prototype f, int pc) {
|
||||||
|
return pc > 0 && f.lineinfo != null && pc < f.lineinfo.length? f.lineinfo[pc]: -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void printHeader(Prototype f) {
|
||||||
|
String s = String.valueOf(f.source);
|
||||||
|
if (s.startsWith("@") || s.startsWith("="))
|
||||||
|
s = s.substring(1);
|
||||||
|
else if ("\033Lua".equals(s))
|
||||||
|
s = "(bstring)";
|
||||||
|
else
|
||||||
|
s = "(string)";
|
||||||
|
String a = f.linedefined == 0? "main": "function";
|
||||||
|
ps.print("\n%" + a + " <" + s + ":" + f.linedefined + "," + f.lastlinedefined + "> (" + f.code.length
|
||||||
|
+ " instructions, " + f.code.length*4 + " bytes at " + id(f) + ")\n");
|
||||||
|
ps.print(f.numparams + " param, " + f.maxstacksize + " slot, " + f.upvalues.length + " upvalue, ");
|
||||||
|
ps.print(f.locvars.length + " local, " + f.k.length + " constant, " + f.p.length + " function\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void printConstants(Prototype f) {
|
||||||
|
int i, n = f.k.length;
|
||||||
|
ps.print("constants (" + n + ") for " + id(f) + ":\n");
|
||||||
|
for (i = 0; i < n; i++) {
|
||||||
|
ps.print(" " + (i+1) + " ");
|
||||||
|
printValue(ps, f.k[i]);
|
||||||
|
ps.print("\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void printLocals(Prototype f) {
|
||||||
|
int i, n = f.locvars.length;
|
||||||
|
ps.print("locals (" + n + ") for " + id(f) + ":\n");
|
||||||
|
for (i = 0; i < n; i++) {
|
||||||
|
ps.println(
|
||||||
|
" " + i + " " + f.locvars[i].varname + " " + (f.locvars[i].startpc+1) + " " + (f.locvars[i].endpc+1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void printUpValues(Prototype f) {
|
||||||
|
int i, n = f.upvalues.length;
|
||||||
|
ps.print("upvalues (" + n + ") for " + id(f) + ":\n");
|
||||||
|
for (i = 0; i < n; i++) {
|
||||||
|
ps.print(" " + i + " " + f.upvalues[i] + "\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pretty-prints contents of a Prototype.
|
||||||
|
*
|
||||||
|
* @param prototype Prototype to print.
|
||||||
|
*/
|
||||||
|
public static void print(Prototype prototype) {
|
||||||
|
printFunction(prototype, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pretty-prints contents of a Prototype in short or long form.
|
||||||
|
*
|
||||||
|
* @param prototype Prototype to print.
|
||||||
|
* @param full true to print all fields, false to print short form.
|
||||||
|
*/
|
||||||
|
public static void printFunction(Prototype prototype, boolean full) {
|
||||||
|
int i, n = prototype.p.length;
|
||||||
|
printHeader(prototype);
|
||||||
|
printCode(prototype);
|
||||||
|
if (full) {
|
||||||
|
printConstants(prototype);
|
||||||
|
printLocals(prototype);
|
||||||
|
printUpValues(prototype);
|
||||||
|
}
|
||||||
|
for (i = 0; i < n; i++)
|
||||||
|
printFunction(prototype.p[i], full);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void format(String s, int maxcols) {
|
||||||
|
int n = s.length();
|
||||||
|
if (n > maxcols)
|
||||||
|
ps.print(s.substring(0, maxcols));
|
||||||
|
else {
|
||||||
|
ps.print(s);
|
||||||
|
for (int i = maxcols-n; --i >= 0;)
|
||||||
|
ps.print(' ');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String id(Prototype f) {
|
||||||
|
return "Proto";
|
||||||
|
}
|
||||||
|
|
||||||
|
private void _assert(boolean b) {
|
||||||
|
if (!b)
|
||||||
|
throw new NullPointerException("_assert failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Print the state of a {@link LuaClosure} that is being executed
|
||||||
|
*
|
||||||
|
* @param cl the {@link LuaClosure}
|
||||||
|
* @param pc the program counter
|
||||||
|
* @param stack the stack of {@link LuaValue}
|
||||||
|
* @param top the top of the stack
|
||||||
|
* @param varargs any {@link Varargs} value that may apply
|
||||||
|
*/
|
||||||
|
public static void printState(LuaClosure cl, int pc, LuaValue[] stack, int top, Varargs varargs) {
|
||||||
|
// print opcode into buffer
|
||||||
|
PrintStream previous = ps;
|
||||||
|
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||||
|
ps = new PrintStream(baos);
|
||||||
|
printOpCode(cl.p, pc);
|
||||||
|
ps.flush();
|
||||||
|
ps.close();
|
||||||
|
ps = previous;
|
||||||
|
format(baos.toString(), 50);
|
||||||
|
printStack(stack, top, varargs);
|
||||||
|
ps.println();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void printStack(LuaValue[] stack, int top, Varargs varargs) {
|
||||||
|
// print stack
|
||||||
|
ps.print('[');
|
||||||
|
for (int i = 0; i < stack.length; i++) {
|
||||||
|
LuaValue v = stack[i];
|
||||||
|
if (v == null)
|
||||||
|
ps.print(STRING_FOR_NULL);
|
||||||
|
else
|
||||||
|
switch (v.type()) {
|
||||||
|
case LuaValue.TSTRING:
|
||||||
|
LuaString s = v.checkstring();
|
||||||
|
ps.print(s.length() < 48? s.tojstring()
|
||||||
|
: s.substring(0, 32).tojstring() + "...+" + (s.length()-32) + "b");
|
||||||
|
break;
|
||||||
|
case LuaValue.TFUNCTION:
|
||||||
|
ps.print(v.tojstring());
|
||||||
|
break;
|
||||||
|
case LuaValue.TUSERDATA:
|
||||||
|
Object o = v.touserdata();
|
||||||
|
if (o != null) {
|
||||||
|
String n = o.getClass().getName();
|
||||||
|
n = n.substring(n.lastIndexOf('.')+1);
|
||||||
|
ps.print(n + ": " + Integer.toHexString(o.hashCode()));
|
||||||
|
} else {
|
||||||
|
ps.print(v.toString());
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ps.print(v.tojstring());
|
||||||
|
}
|
||||||
|
if (i+1 == top)
|
||||||
|
ps.print(']');
|
||||||
|
ps.print(" | ");
|
||||||
|
}
|
||||||
|
ps.print(varargs);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
180
luaj-core/src/main/java/org/luaj/vm2/Prototype.java
Normal file
180
luaj-core/src/main/java/org/luaj/vm2/Prototype.java
Normal 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>
|
||||||
|
* {
|
||||||
|
* @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>
|
||||||
|
* {
|
||||||
|
* @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>
|
||||||
|
* {
|
||||||
|
* @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>
|
||||||
|
* {
|
||||||
|
* @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>
|
||||||
|
* {
|
||||||
|
* @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>
|
||||||
|
* {
|
||||||
|
* @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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
public LuaValue arg( int i ) {
|
@Override
|
||||||
if ( result == null )
|
public LuaValue arg(int i) {
|
||||||
|
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();
|
||||||
@@ -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,20 +35,23 @@ 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
|
||||||
*/
|
*/
|
||||||
public UpValue( LuaValue[] stack, int index) {
|
public UpValue(LuaValue[] stack, int index) {
|
||||||
this.array = stack;
|
this.array = stack;
|
||||||
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;
|
||||||
@@ -38,7 +38,8 @@ 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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -29,36 +29,37 @@ 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;
|
||||||
if ( weakkeys && weakvalues ) {
|
if (weakkeys && weakvalues) {
|
||||||
mode = LuaString.valueOf("kv");
|
mode = LuaString.valueOf("kv");
|
||||||
} else if ( weakkeys ) {
|
} else if (weakkeys) {
|
||||||
mode = LuaString.valueOf("k");
|
mode = LuaString.valueOf("k");
|
||||||
} 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,33 +69,37 @@ 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)
|
||||||
return null;
|
return null;
|
||||||
if ( weakkeys && !( key.isnumber() || key.isstring() || key.isboolean() )) {
|
if (weakkeys && !(key.isnumber() || key.isstring() || key.isboolean())) {
|
||||||
if ( weakvalues && !( value.isnumber() || value.isstring() || value.isboolean() )) {
|
if (weakvalues && !(value.isnumber() || value.isstring() || value.isboolean())) {
|
||||||
return new WeakKeyAndValueSlot( key, value, null );
|
return new WeakKeyAndValueSlot(key, value, null);
|
||||||
} else {
|
} else {
|
||||||
return new WeakKeySlot( key, value, null );
|
return new WeakKeySlot(key, value, null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ( weakvalues && ! (value.isnumber() || value.isstring() || value.isboolean() )) {
|
if (weakvalues && !(value.isnumber() || value.isstring() || value.isboolean())) {
|
||||||
return new WeakValueSlot( key, value, null );
|
return new WeakValueSlot(key, value, null);
|
||||||
}
|
}
|
||||||
return LuaTable.defaultEntry( key, value );
|
return LuaTable.defaultEntry(key, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static abstract class WeakSlot implements Slot {
|
public static abstract class WeakSlot implements Slot {
|
||||||
@@ -109,14 +114,16 @@ public class WeakTable implements Metatable {
|
|||||||
this.next = next;
|
this.next = next;
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract int keyindex( int hashMask );
|
@Override
|
||||||
|
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();
|
||||||
if ( key != null && value != null ) {
|
if (key != null && value != null) {
|
||||||
return new LuaTable.NormalEntry(key, value);
|
return new LuaTable.NormalEntry(key, value);
|
||||||
} else {
|
} else {
|
||||||
this.key = null;
|
this.key = null;
|
||||||
@@ -125,67 +132,75 @@ 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) {
|
||||||
return set( value );
|
return set(value);
|
||||||
} else if ( key != null ) {
|
} else if (key != null) {
|
||||||
// Our key is still good.
|
// Our key is still good.
|
||||||
next = next.set( target, value );
|
next = next.set(target, value);
|
||||||
return this;
|
return this;
|
||||||
} else {
|
} else {
|
||||||
// our key was dropped, remove ourselves from the chain.
|
// our key was dropped, remove ourselves from the chain.
|
||||||
return next.set( target, value );
|
return next.set(target, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Slot add( Slot entry ) {
|
@Override
|
||||||
next = ( next != null ) ? next.add( entry ) : entry;
|
public Slot add(Slot entry) {
|
||||||
if ( strongkey() != null && strongvalue() != null ) {
|
next = next != null? next.add(entry): entry;
|
||||||
|
if (strongkey() != null && strongvalue() != null) {
|
||||||
return this;
|
return this;
|
||||||
} else {
|
} else {
|
||||||
return next;
|
return next;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Slot remove( StrongSlot target ) {
|
@Override
|
||||||
|
public Slot remove(StrongSlot target) {
|
||||||
LuaValue key = strongkey();
|
LuaValue key = strongkey();
|
||||||
if ( key == null ) {
|
if (key == null) {
|
||||||
return next.remove( target );
|
return next.remove(target);
|
||||||
} else if ( target.keyeq( key ) ) {
|
} else if (target.keyeq(key)) {
|
||||||
this.value = null;
|
this.value = null;
|
||||||
return this;
|
return this;
|
||||||
} else {
|
} else {
|
||||||
next = next.remove( target );
|
next = next.remove(target);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Slot relink( Slot rest ) {
|
@Override
|
||||||
if ( strongkey() != null && strongvalue() != null ) {
|
public Slot relink(Slot rest) {
|
||||||
if ( rest == null && this.next == null ) {
|
if (strongkey() != null && strongvalue() != null) {
|
||||||
|
if (rest == null && this.next == null) {
|
||||||
return this;
|
return this;
|
||||||
} else {
|
} else {
|
||||||
return copy( rest );
|
return copy(rest);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return rest;
|
return rest;
|
||||||
@@ -200,66 +215,74 @@ public class WeakTable implements Metatable {
|
|||||||
return (LuaValue) value;
|
return (LuaValue) value;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract WeakSlot copy( Slot next );
|
protected abstract WeakSlot copy(Slot next);
|
||||||
}
|
}
|
||||||
|
|
||||||
static class WeakKeySlot extends WeakSlot {
|
static class WeakKeySlot extends WeakSlot {
|
||||||
|
|
||||||
private final int keyhash;
|
private final int keyhash;
|
||||||
|
|
||||||
protected WeakKeySlot( LuaValue key, LuaValue value, Slot next ) {
|
protected WeakKeySlot(LuaValue key, LuaValue value, Slot next) {
|
||||||
super(weaken(key), value, next);
|
super(weaken(key), value, next);
|
||||||
keyhash = key.hashCode();
|
keyhash = key.hashCode();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected WeakKeySlot( WeakKeySlot copyFrom, Slot next ) {
|
protected WeakKeySlot(WeakKeySlot copyFrom, Slot next) {
|
||||||
super( copyFrom.key, copyFrom.value, next );
|
super(copyFrom.key, copyFrom.value, next);
|
||||||
this.keyhash = copyFrom.keyhash;
|
this.keyhash = copyFrom.keyhash;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int keyindex( int mask ) {
|
@Override
|
||||||
return LuaTable.hashmod( keyhash, mask );
|
public int keyindex(int 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected WeakSlot copy( Slot rest ) {
|
@Override
|
||||||
return new WeakKeySlot( this, rest );
|
protected WeakSlot copy(Slot rest) {
|
||||||
|
return new WeakKeySlot(this, rest);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static class WeakValueSlot extends WeakSlot {
|
static class WeakValueSlot extends WeakSlot {
|
||||||
|
|
||||||
protected WeakValueSlot( LuaValue key, LuaValue value, Slot next ) {
|
protected WeakValueSlot(LuaValue key, LuaValue value, Slot next) {
|
||||||
super( key, weaken(value), next);
|
super(key, weaken(value), next);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected WeakValueSlot( WeakValueSlot copyFrom, Slot next ) {
|
protected WeakValueSlot(WeakValueSlot copyFrom, Slot next) {
|
||||||
super( copyFrom.key, copyFrom.value, next );
|
super(copyFrom.key, copyFrom.value, next);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int keyindex( int mask ) {
|
@Override
|
||||||
return LuaTable.hashSlot( strongkey(), mask );
|
public int keyindex(int 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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -267,45 +290,52 @@ public class WeakTable implements Metatable {
|
|||||||
|
|
||||||
private final int keyhash;
|
private final int keyhash;
|
||||||
|
|
||||||
protected WeakKeyAndValueSlot( LuaValue key, LuaValue value, Slot next ) {
|
protected WeakKeyAndValueSlot(LuaValue key, LuaValue value, Slot next) {
|
||||||
super( weaken(key), weaken(value), next );
|
super(weaken(key), weaken(value), next);
|
||||||
keyhash = key.hashCode();
|
keyhash = key.hashCode();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected WeakKeyAndValueSlot(WeakKeyAndValueSlot copyFrom, Slot next) {
|
protected WeakKeyAndValueSlot(WeakKeyAndValueSlot copyFrom, Slot next) {
|
||||||
super( copyFrom.key, copyFrom.value, next );
|
super(copyFrom.key, copyFrom.value, next);
|
||||||
keyhash = copyFrom.keyhash;
|
keyhash = copyFrom.keyhash;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int keyindex( int hashMask ) {
|
@Override
|
||||||
return LuaTable.hashmod( keyhash, hashMask );
|
public int keyindex(int 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected WeakSlot copy( Slot next ) {
|
@Override
|
||||||
return new WeakKeyAndValueSlot( this, next );
|
protected WeakSlot copy(Slot next) {
|
||||||
|
return new WeakKeyAndValueSlot(this, next);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Self-sent message to convert a value to its weak counterpart
|
* 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()) {
|
||||||
case LuaValue.TFUNCTION:
|
case LuaValue.TFUNCTION:
|
||||||
case LuaValue.TTHREAD:
|
case LuaValue.TTHREAD:
|
||||||
case LuaValue.TTABLE:
|
case LuaValue.TTABLE:
|
||||||
@@ -319,21 +349,24 @@ 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)
|
||||||
*/
|
*/
|
||||||
protected static LuaValue strengthen(Object ref) {
|
protected static LuaValue strengthen(Object ref) {
|
||||||
if ( ref instanceof WeakReference ) {
|
if (ref instanceof WeakReference) {
|
||||||
ref = ((WeakReference) ref).get();
|
ref = ((WeakReference) ref).get();
|
||||||
}
|
}
|
||||||
if ( ref instanceof WeakValue ) {
|
if (ref instanceof WeakValue) {
|
||||||
return ((WeakValue) ref).strongvalue();
|
return ((WeakValue) ref).strongvalue();
|
||||||
}
|
}
|
||||||
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,13 +421,14 @@ 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)
|
||||||
return (LuaValue) u;
|
return (LuaValue) u;
|
||||||
Object o = ob.get();
|
Object o = ob.get();
|
||||||
if ( o != null ) {
|
if (o != null) {
|
||||||
LuaValue ud = LuaValue.userdataOf(o,mt);
|
LuaValue ud = LuaValue.userdataOf(o, mt);
|
||||||
ref = new WeakReference(ud);
|
ref = new WeakReference(ud);
|
||||||
return ud;
|
return ud;
|
||||||
} else {
|
} else {
|
||||||
@@ -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) {
|
||||||
19
luaj-core/src/main/java/org/luaj/vm2/compat/JavaCompat.java
Normal file
19
luaj-core/src/main/java/org/luaj/vm2/compat/JavaCompat.java
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -44,140 +44,133 @@ 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) {
|
||||||
SETARG_Bx( i, u + MAXARG_sBx );
|
SETARG_Bx(i, u+MAXARG_sBx);
|
||||||
}
|
}
|
||||||
|
|
||||||
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) {
|
||||||
|
return o<<POS_OP & MASK_OP | a<<POS_Ax & MASK_Ax;
|
||||||
}
|
}
|
||||||
|
|
||||||
// vector reallocation
|
// vector reallocation
|
||||||
|
|
||||||
static LuaValue[] realloc(LuaValue[] v, int n) {
|
static LuaValue[] realloc(LuaValue[] v, int n) {
|
||||||
LuaValue[] a = new LuaValue[n];
|
LuaValue[] a = new LuaValue[n];
|
||||||
if ( v != null )
|
if (v != null)
|
||||||
System.arraycopy(v, 0, a, 0, Math.min(v.length,n));
|
System.arraycopy(v, 0, a, 0, Math.min(v.length, n));
|
||||||
return a;
|
return a;
|
||||||
}
|
}
|
||||||
|
|
||||||
static Prototype[] realloc(Prototype[] v, int n) {
|
static Prototype[] realloc(Prototype[] v, int n) {
|
||||||
Prototype[] a = new Prototype[n];
|
Prototype[] a = new Prototype[n];
|
||||||
if ( v != null )
|
if (v != null)
|
||||||
System.arraycopy(v, 0, a, 0, Math.min(v.length,n));
|
System.arraycopy(v, 0, a, 0, Math.min(v.length, n));
|
||||||
return a;
|
return a;
|
||||||
}
|
}
|
||||||
|
|
||||||
static LuaString[] realloc(LuaString[] v, int n) {
|
static LuaString[] realloc(LuaString[] v, int n) {
|
||||||
LuaString[] a = new LuaString[n];
|
LuaString[] a = new LuaString[n];
|
||||||
if ( v != null )
|
if (v != null)
|
||||||
System.arraycopy(v, 0, a, 0, Math.min(v.length,n));
|
System.arraycopy(v, 0, a, 0, Math.min(v.length, n));
|
||||||
return a;
|
return a;
|
||||||
}
|
}
|
||||||
|
|
||||||
static LocVars[] realloc(LocVars[] v, int n) {
|
static LocVars[] realloc(LocVars[] v, int n) {
|
||||||
LocVars[] a = new LocVars[n];
|
LocVars[] a = new LocVars[n];
|
||||||
if ( v != null )
|
if (v != null)
|
||||||
System.arraycopy(v, 0, a, 0, Math.min(v.length,n));
|
System.arraycopy(v, 0, a, 0, Math.min(v.length, n));
|
||||||
return a;
|
return a;
|
||||||
}
|
}
|
||||||
|
|
||||||
static Upvaldesc[] realloc(Upvaldesc[] v, int n) {
|
static Upvaldesc[] realloc(Upvaldesc[] v, int n) {
|
||||||
Upvaldesc[] a = new Upvaldesc[n];
|
Upvaldesc[] a = new Upvaldesc[n];
|
||||||
if ( v != null )
|
if (v != null)
|
||||||
System.arraycopy(v, 0, a, 0, Math.min(v.length,n));
|
System.arraycopy(v, 0, a, 0, Math.min(v.length, n));
|
||||||
return a;
|
return a;
|
||||||
}
|
}
|
||||||
|
|
||||||
static LexState.Vardesc[] realloc(LexState.Vardesc[] v, int n) {
|
static LexState.Vardesc[] realloc(LexState.Vardesc[] v, int n) {
|
||||||
LexState.Vardesc[] a = new LexState.Vardesc[n];
|
LexState.Vardesc[] a = new LexState.Vardesc[n];
|
||||||
if ( v != null )
|
if (v != null)
|
||||||
System.arraycopy(v, 0, a, 0, Math.min(v.length,n));
|
System.arraycopy(v, 0, a, 0, Math.min(v.length, n));
|
||||||
return a;
|
return a;
|
||||||
}
|
}
|
||||||
|
|
||||||
static LexState.Labeldesc[] grow(LexState.Labeldesc[] v, int min_n) {
|
static LexState.Labeldesc[] grow(LexState.Labeldesc[] v, int min_n) {
|
||||||
return v == null ? new LexState.Labeldesc[2] : v.length < min_n ? realloc(v, v.length*2) : v;
|
return v == null? new LexState.Labeldesc[2]: v.length < min_n? realloc(v, v.length*2): v;
|
||||||
}
|
}
|
||||||
|
|
||||||
static LexState.Labeldesc[] realloc(LexState.Labeldesc[] v, int n) {
|
static LexState.Labeldesc[] realloc(LexState.Labeldesc[] v, int n) {
|
||||||
LexState.Labeldesc[] a = new LexState.Labeldesc[n];
|
LexState.Labeldesc[] a = new LexState.Labeldesc[n];
|
||||||
if ( v != null )
|
if (v != null)
|
||||||
System.arraycopy(v, 0, a, 0, Math.min(v.length,n));
|
System.arraycopy(v, 0, a, 0, Math.min(v.length, n));
|
||||||
return a;
|
return a;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int[] realloc(int[] v, int n) {
|
static int[] realloc(int[] v, int n) {
|
||||||
int[] a = new int[n];
|
int[] a = new int[n];
|
||||||
if ( v != null )
|
if (v != null)
|
||||||
System.arraycopy(v, 0, a, 0, Math.min(v.length,n));
|
System.arraycopy(v, 0, a, 0, Math.min(v.length, n));
|
||||||
return a;
|
return a;
|
||||||
}
|
}
|
||||||
|
|
||||||
static byte[] realloc(byte[] v, int n) {
|
static byte[] realloc(byte[] v, int n) {
|
||||||
byte[] a = new byte[n];
|
byte[] a = new byte[n];
|
||||||
if ( v != null )
|
if (v != null)
|
||||||
System.arraycopy(v, 0, a, 0, Math.min(v.length,n));
|
System.arraycopy(v, 0, a, 0, Math.min(v.length, n));
|
||||||
return a;
|
return a;
|
||||||
}
|
}
|
||||||
|
|
||||||
static char[] realloc(char[] v, int n) {
|
static char[] realloc(char[] v, int n) {
|
||||||
char[] a = new char[n];
|
char[] a = new char[n];
|
||||||
if ( v != null )
|
if (v != null)
|
||||||
System.arraycopy(v, 0, a, 0, Math.min(v.length,n));
|
System.arraycopy(v, 0, a, 0, Math.min(v.length, n));
|
||||||
return a;
|
return a;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -28,39 +28,51 @@ import java.io.OutputStream;
|
|||||||
import org.luaj.vm2.Globals;
|
import org.luaj.vm2.Globals;
|
||||||
import org.luaj.vm2.LoadState;
|
import org.luaj.vm2.LoadState;
|
||||||
import org.luaj.vm2.LocVars;
|
import org.luaj.vm2.LocVars;
|
||||||
import org.luaj.vm2.Prototype;
|
|
||||||
import org.luaj.vm2.LuaString;
|
import org.luaj.vm2.LuaString;
|
||||||
import org.luaj.vm2.LuaValue;
|
import org.luaj.vm2.LuaValue;
|
||||||
|
import org.luaj.vm2.Prototype;
|
||||||
|
|
||||||
|
/**
|
||||||
/** Class to dump a {@link Prototype} into an output stream, as part of compiling.
|
* Class to dump a {@link Prototype} into an output stream, as part of
|
||||||
|
* compiling.
|
||||||
* <p>
|
* <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>
|
||||||
|
* {
|
||||||
|
* @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>
|
||||||
|
* {
|
||||||
|
* @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,20 +84,26 @@ 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 */
|
||||||
public static final int NUMBER_FORMAT_DEFAULT = NUMBER_FORMAT_FLOATS_OR_DOUBLES;
|
public static final int NUMBER_FORMAT_DEFAULT = NUMBER_FORMAT_FLOATS_OR_DOUBLES;
|
||||||
|
|
||||||
// header fields
|
// header fields
|
||||||
private boolean IS_LITTLE_ENDIAN = false;
|
private boolean IS_LITTLE_ENDIAN = true;
|
||||||
private int NUMBER_FORMAT = NUMBER_FORMAT_DEFAULT;
|
private int NUMBER_FORMAT = NUMBER_FORMAT_DEFAULT;
|
||||||
private int SIZEOF_LUA_NUMBER = 8;
|
private int SIZEOF_LUA_NUMBER = 8;
|
||||||
private static final int SIZEOF_INT = 4;
|
private static final int SIZEOF_INT = 4;
|
||||||
@@ -97,7 +115,7 @@ public class DumpState {
|
|||||||
int status;
|
int status;
|
||||||
|
|
||||||
public DumpState(OutputStream w, boolean strip) {
|
public DumpState(OutputStream w, boolean strip) {
|
||||||
this.writer = new DataOutputStream( w );
|
this.writer = new DataOutputStream(w);
|
||||||
this.strip = strip;
|
this.strip = strip;
|
||||||
this.status = 0;
|
this.status = 0;
|
||||||
}
|
}
|
||||||
@@ -107,15 +125,15 @@ public class DumpState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void dumpChar(int b) throws IOException {
|
void dumpChar(int b) throws IOException {
|
||||||
writer.write( b );
|
writer.write(b);
|
||||||
}
|
}
|
||||||
|
|
||||||
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);
|
||||||
}
|
}
|
||||||
@@ -123,27 +141,27 @@ public class DumpState {
|
|||||||
|
|
||||||
void dumpString(LuaString s) throws IOException {
|
void dumpString(LuaString s) throws IOException {
|
||||||
final int len = s.len().toint();
|
final int len = s.len().toint();
|
||||||
dumpInt( len+1 );
|
dumpInt(len+1);
|
||||||
s.write( writer, 0, len );
|
s.write(writer, 0, len);
|
||||||
writer.write( 0 );
|
writer.write(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void dumpDouble(double d) throws IOException {
|
void dumpDouble(double d) throws IOException {
|
||||||
long l = Double.doubleToLongBits(d);
|
long l = Double.doubleToLongBits(d);
|
||||||
if ( IS_LITTLE_ENDIAN ) {
|
if (IS_LITTLE_ENDIAN) {
|
||||||
dumpInt( (int) l );
|
dumpInt((int) l);
|
||||||
dumpInt( (int) (l>>32) );
|
dumpInt((int) (l>>32));
|
||||||
} else {
|
} else {
|
||||||
writer.writeLong(l);
|
writer.writeLong(l);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void dumpCode( final Prototype f ) throws IOException {
|
void dumpCode(final Prototype f) throws IOException {
|
||||||
final int[] code = f.code;
|
final int[] code = f.code;
|
||||||
int n = code.length;
|
int n = code.length;
|
||||||
dumpInt( n );
|
dumpInt(n);
|
||||||
for ( int i=0; i<n; i++ )
|
for (int i = 0; i < n; i++)
|
||||||
dumpInt( code[i] );
|
dumpInt(code[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
void dumpConstants(final Prototype f) throws IOException {
|
void dumpConstants(final Prototype f) throws IOException {
|
||||||
@@ -152,13 +170,13 @@ public class DumpState {
|
|||||||
dumpInt(n);
|
dumpInt(n);
|
||||||
for (i = 0; i < n; i++) {
|
for (i = 0; i < n; i++) {
|
||||||
final LuaValue o = k[i];
|
final LuaValue o = k[i];
|
||||||
switch ( o.type() ) {
|
switch (o.type()) {
|
||||||
case LuaValue.TNIL:
|
case LuaValue.TNIL:
|
||||||
writer.write(LuaValue.TNIL);
|
writer.write(LuaValue.TNIL);
|
||||||
break;
|
break;
|
||||||
case LuaValue.TBOOLEAN:
|
case LuaValue.TBOOLEAN:
|
||||||
writer.write(LuaValue.TBOOLEAN);
|
writer.write(LuaValue.TBOOLEAN);
|
||||||
dumpChar(o.toboolean() ? 1 : 0);
|
dumpChar(o.toboolean()? 1: 0);
|
||||||
break;
|
break;
|
||||||
case LuaValue.TNUMBER:
|
case LuaValue.TNUMBER:
|
||||||
switch (NUMBER_FORMAT) {
|
switch (NUMBER_FORMAT) {
|
||||||
@@ -167,13 +185,13 @@ public class DumpState {
|
|||||||
dumpDouble(o.todouble());
|
dumpDouble(o.todouble());
|
||||||
break;
|
break;
|
||||||
case NUMBER_FORMAT_INTS_ONLY:
|
case NUMBER_FORMAT_INTS_ONLY:
|
||||||
if ( ! ALLOW_INTEGER_CASTING && ! o.isint() )
|
if (!ALLOW_INTEGER_CASTING && !o.isint())
|
||||||
throw new java.lang.IllegalArgumentException("not an integer: "+o);
|
throw new java.lang.IllegalArgumentException("not an integer: " + o);
|
||||||
writer.write(LuaValue.TNUMBER);
|
writer.write(LuaValue.TNUMBER);
|
||||||
dumpInt(o.toint());
|
dumpInt(o.toint());
|
||||||
break;
|
break;
|
||||||
case NUMBER_FORMAT_NUM_PATCH_INT32:
|
case NUMBER_FORMAT_NUM_PATCH_INT32:
|
||||||
if ( o.isint() ) {
|
if (o.isint()) {
|
||||||
writer.write(LuaValue.TINT);
|
writer.write(LuaValue.TINT);
|
||||||
dumpInt(o.toint());
|
dumpInt(o.toint());
|
||||||
} else {
|
} else {
|
||||||
@@ -182,12 +200,12 @@ public class DumpState {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new IllegalArgumentException("number format not supported: "+NUMBER_FORMAT);
|
throw new IllegalArgumentException("number format not supported: " + NUMBER_FORMAT);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case LuaValue.TSTRING:
|
case LuaValue.TSTRING:
|
||||||
writer.write(LuaValue.TSTRING);
|
writer.write(LuaValue.TSTRING);
|
||||||
dumpString((LuaString)o);
|
dumpString((LuaString) o);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new IllegalArgumentException("bad type for " + o);
|
throw new IllegalArgumentException("bad type for " + o);
|
||||||
@@ -203,7 +221,7 @@ public class DumpState {
|
|||||||
int n = f.upvalues.length;
|
int n = f.upvalues.length;
|
||||||
dumpInt(n);
|
dumpInt(n);
|
||||||
for (int i = 0; i < n; i++) {
|
for (int i = 0; i < n; i++) {
|
||||||
writer.writeByte(f.upvalues[i].instack ? 1 : 0);
|
writer.writeByte(f.upvalues[i].instack? 1: 0);
|
||||||
writer.writeByte(f.upvalues[i].idx);
|
writer.writeByte(f.upvalues[i].idx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -214,11 +232,11 @@ public class DumpState {
|
|||||||
dumpInt(0);
|
dumpInt(0);
|
||||||
else
|
else
|
||||||
dumpString(f.source);
|
dumpString(f.source);
|
||||||
n = strip ? 0 : f.lineinfo.length;
|
n = strip? 0: f.lineinfo.length;
|
||||||
dumpInt(n);
|
dumpInt(n);
|
||||||
for (i = 0; i < n; i++)
|
for (i = 0; i < n; i++)
|
||||||
dumpInt(f.lineinfo[i]);
|
dumpInt(f.lineinfo[i]);
|
||||||
n = strip ? 0 : f.locvars.length;
|
n = strip? 0: f.locvars.length;
|
||||||
dumpInt(n);
|
dumpInt(n);
|
||||||
for (i = 0; i < n; i++) {
|
for (i = 0; i < n; i++) {
|
||||||
LocVars lvi = f.locvars[i];
|
LocVars lvi = f.locvars[i];
|
||||||
@@ -226,7 +244,7 @@ public class DumpState {
|
|||||||
dumpInt(lvi.startpc);
|
dumpInt(lvi.startpc);
|
||||||
dumpInt(lvi.endpc);
|
dumpInt(lvi.endpc);
|
||||||
}
|
}
|
||||||
n = strip ? 0 : f.upvalues.length;
|
n = strip? 0: f.upvalues.length;
|
||||||
dumpInt(n);
|
dumpInt(n);
|
||||||
for (i = 0; i < n; i++)
|
for (i = 0; i < n; i++)
|
||||||
dumpString(f.upvalues[i].name);
|
dumpString(f.upvalues[i].name);
|
||||||
@@ -245,23 +263,23 @@ public class DumpState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void dumpHeader() throws IOException {
|
void dumpHeader() throws IOException {
|
||||||
writer.write( LoadState.LUA_SIGNATURE );
|
writer.write(LoadState.LUA_SIGNATURE);
|
||||||
writer.write( LoadState.LUAC_VERSION );
|
writer.write(LoadState.LUAC_VERSION);
|
||||||
writer.write( LoadState.LUAC_FORMAT );
|
writer.write(LoadState.LUAC_FORMAT);
|
||||||
writer.write( IS_LITTLE_ENDIAN? 1: 0 );
|
writer.write(IS_LITTLE_ENDIAN? 1: 0);
|
||||||
writer.write( SIZEOF_INT );
|
writer.write(SIZEOF_INT);
|
||||||
writer.write( SIZEOF_SIZET );
|
writer.write(SIZEOF_SIZET);
|
||||||
writer.write( SIZEOF_INSTRUCTION );
|
writer.write(SIZEOF_INSTRUCTION);
|
||||||
writer.write( SIZEOF_LUA_NUMBER );
|
writer.write(SIZEOF_LUA_NUMBER);
|
||||||
writer.write( NUMBER_FORMAT );
|
writer.write(NUMBER_FORMAT);
|
||||||
writer.write( LoadState.LUAC_TAIL );
|
writer.write(LoadState.LUAC_TAIL);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** dump Lua function as precompiled chunk
|
** dump Lua function as precompiled chunk
|
||||||
*/
|
*/
|
||||||
public static int dump( Prototype f, OutputStream w, boolean strip ) throws IOException {
|
public static int dump(Prototype f, OutputStream w, boolean strip) throws IOException {
|
||||||
DumpState D = new DumpState(w,strip);
|
DumpState D = new DumpState(w, strip);
|
||||||
D.dumpHeader();
|
D.dumpHeader();
|
||||||
D.dumpFunction(f);
|
D.dumpFunction(f);
|
||||||
return D.status;
|
return D.status;
|
||||||
@@ -272,25 +290,29 @@ 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)
|
||||||
switch ( numberFormat ) {
|
throws IOException {
|
||||||
|
switch (numberFormat) {
|
||||||
case NUMBER_FORMAT_FLOATS_OR_DOUBLES:
|
case NUMBER_FORMAT_FLOATS_OR_DOUBLES:
|
||||||
case NUMBER_FORMAT_INTS_ONLY:
|
case NUMBER_FORMAT_INTS_ONLY:
|
||||||
case NUMBER_FORMAT_NUM_PATCH_INT32:
|
case NUMBER_FORMAT_NUM_PATCH_INT32:
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new IllegalArgumentException("number format not supported: "+numberFormat);
|
throw new IllegalArgumentException("number format not supported: " + numberFormat);
|
||||||
}
|
}
|
||||||
DumpState D = new DumpState(w,stripDebug);
|
DumpState D = new DumpState(w, stripDebug);
|
||||||
D.IS_LITTLE_ENDIAN = littleendian;
|
D.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;
|
||||||
@@ -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,13 +43,12 @@ 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' */
|
||||||
FuncState prev; /* enclosing function */
|
FuncState prev; /* enclosing function */
|
||||||
LexState ls; /* lexical state */
|
LexState ls; /* lexical state */
|
||||||
LuaC.CompileState L; /* compiler being invoked */
|
|
||||||
BlockCnt bl; /* chain of current blocks */
|
BlockCnt bl; /* chain of current blocks */
|
||||||
int pc; /* next position to code (equivalent to `ncode') */
|
int pc; /* next position to code (equivalent to `ncode') */
|
||||||
int lasttarget; /* `pc' of last `jump target' */
|
int lasttarget; /* `pc' of last `jump target' */
|
||||||
@@ -66,13 +64,12 @@ public class FuncState extends Constants {
|
|||||||
FuncState() {
|
FuncState() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// =============================================================
|
// =============================================================
|
||||||
// from lcode.h
|
// from lcode.h
|
||||||
// =============================================================
|
// =============================================================
|
||||||
|
|
||||||
InstructionPtr getcodePtr(expdesc e) {
|
InstructionPtr getcodePtr(expdesc e) {
|
||||||
return new InstructionPtr( f.code, e.u.info );
|
return new InstructionPtr(f.code, e.u.info);
|
||||||
}
|
}
|
||||||
|
|
||||||
int getcode(expdesc e) {
|
int getcode(expdesc e) {
|
||||||
@@ -80,58 +77,53 @@ public class FuncState extends Constants {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int codeAsBx(int o, int A, int sBx) {
|
int codeAsBx(int o, int A, int sBx) {
|
||||||
return codeABx(o,A,sBx+MAXARG_sBx);
|
return codeABx(o, A, sBx+MAXARG_sBx);
|
||||||
}
|
}
|
||||||
|
|
||||||
void setmultret(expdesc e) {
|
void setmultret(expdesc e) {
|
||||||
setreturns(e, LUA_MULTRET);
|
setreturns(e, LUA_MULTRET);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// =============================================================
|
// =============================================================
|
||||||
// from lparser.c
|
// from lparser.c
|
||||||
// =============================================================
|
// =============================================================
|
||||||
|
|
||||||
/* check for repeated labels on the same block */
|
/* check for repeated labels on the same block */
|
||||||
void checkrepeated (LexState.Labeldesc[] ll, int ll_n, LuaString label) {
|
void checkrepeated(LexState.Labeldesc[] ll, int ll_n, LuaString label) {
|
||||||
int i;
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
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)
|
||||||
L.pushfstring("main function has more than "+limit+" "+what) :
|
: ls.L.pushfstring("function at line " + f.linedefined + " has more than " + limit + " " + what);
|
||||||
L.pushfstring("function at line "+f.linedefined+" has more than "+limit+" "+what);
|
|
||||||
ls.lexerror(msg, 0);
|
ls.lexerror(msg, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
LocVars getlocvar(int i) {
|
LocVars getlocvar(int i) {
|
||||||
int idx = ls.dyd.actvar[firstlocal + i].idx;
|
int idx = ls.dyd.actvar[firstlocal+i].idx;
|
||||||
_assert(idx < nlocvars);
|
_assert(idx < nlocvars);
|
||||||
return f.locvars[idx];
|
return f.locvars[idx];
|
||||||
}
|
}
|
||||||
|
|
||||||
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;
|
||||||
for (i = 0; i < nups; i++)
|
for (i = 0; i < nups; i++)
|
||||||
@@ -140,17 +132,17 @@ public class FuncState extends Constants {
|
|||||||
return -1; /* not found */
|
return -1; /* not found */
|
||||||
}
|
}
|
||||||
|
|
||||||
int newupvalue (LuaString name, expdesc v) {
|
int newupvalue(LuaString name, expdesc v) {
|
||||||
checklimit(nups + 1, LUAI_MAXUPVAL, "upvalues");
|
checklimit(nups+1, LUAI_MAXUPVAL, "upvalues");
|
||||||
if (f.upvalues == null || nups + 1 > f.upvalues.length)
|
if (f.upvalues == null || nups+1 > f.upvalues.length)
|
||||||
f.upvalues = realloc( f.upvalues, nups > 0 ? nups*2 : 1 );
|
f.upvalues = realloc(f.upvalues, nups > 0? nups*2: 1);
|
||||||
f.upvalues[nups] = new Upvaldesc(name, v.k == LexState.VLOCAL, v.u.info);
|
f.upvalues[nups] = new Upvaldesc(name, v.k == LexState.VLOCAL, v.u.info);
|
||||||
return nups++;
|
return nups++;
|
||||||
}
|
}
|
||||||
|
|
||||||
int searchvar(LuaString n) {
|
int searchvar(LuaString n) {
|
||||||
int i;
|
int i;
|
||||||
for (i = nactvar - 1; i >= 0; i--) {
|
for (i = nactvar-1; i >= 0; i--) {
|
||||||
if (n.eq_b(getlocvar(i).varname))
|
if (n.eq_b(getlocvar(i).varname))
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
@@ -159,7 +151,7 @@ public class FuncState extends Constants {
|
|||||||
|
|
||||||
void markupval(int level) {
|
void markupval(int level) {
|
||||||
BlockCnt bl = this.bl;
|
BlockCnt bl = this.bl;
|
||||||
while (bl.nactvar > level)
|
while ( bl.nactvar > level )
|
||||||
bl = bl.previous;
|
bl = bl.previous;
|
||||||
bl.upval = true;
|
bl.upval = true;
|
||||||
}
|
}
|
||||||
@@ -197,7 +189,7 @@ public class FuncState extends Constants {
|
|||||||
final LexState.Labeldesc[] gl = ls.dyd.gt;
|
final LexState.Labeldesc[] gl = ls.dyd.gt;
|
||||||
/* correct pending gotos to current block and try to close it
|
/* correct pending gotos to current block and try to close it
|
||||||
with visible labels */
|
with visible labels */
|
||||||
while (i < ls.dyd.n_gt) {
|
while ( i < ls.dyd.n_gt ) {
|
||||||
LexState.Labeldesc gt = gl[i];
|
LexState.Labeldesc gt = gl[i];
|
||||||
if (gt.nactvar > bl.nactvar) {
|
if (gt.nactvar > bl.nactvar) {
|
||||||
if (bl.upval)
|
if (bl.upval)
|
||||||
@@ -209,7 +201,7 @@ public class FuncState extends Constants {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void enterblock (BlockCnt bl, boolean isloop) {
|
void enterblock(BlockCnt bl, boolean isloop) {
|
||||||
bl.isloop = isloop;
|
bl.isloop = isloop;
|
||||||
bl.nactvar = nactvar;
|
bl.nactvar = nactvar;
|
||||||
bl.firstlabel = (short) ls.dyd.n_label;
|
bl.firstlabel = (short) ls.dyd.n_label;
|
||||||
@@ -253,53 +245,52 @@ 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
|
||||||
// =============================================================
|
// =============================================================
|
||||||
|
|
||||||
void nil(int from, int n) {
|
void nil(int from, int n) {
|
||||||
int l = from + n - 1; /* last register to set nil */
|
int l = from+n-1; /* last register to set nil */
|
||||||
if (this.pc > this.lasttarget && pc > 0) { /* no jumps to current position? */
|
if (this.pc > this.lasttarget && pc > 0) { /* no jumps to current position? */
|
||||||
final int previous_code = f.code[pc - 1];
|
final int previous_code = f.code[pc-1];
|
||||||
if (GET_OPCODE(previous_code) == OP_LOADNIL) {
|
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)
|
||||||
l = pl; /* l = max(l, pl) */
|
l = pl; /* l = max(l, pl) */
|
||||||
InstructionPtr previous = new InstructionPtr(this.f.code, this.pc - 1);
|
InstructionPtr previous = new InstructionPtr(this.f.code, this.pc-1);
|
||||||
SETARG_A(previous, from);
|
SETARG_A(previous, from);
|
||||||
SETARG_B(previous, l - from);
|
SETARG_B(previous, l-from);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} /* else go through */
|
} /* else go through */
|
||||||
}
|
}
|
||||||
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;
|
||||||
@@ -309,24 +300,23 @@ public class FuncState extends Constants {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void ret(int first, int nret) {
|
void ret(int first, int nret) {
|
||||||
this.codeABC(OP_RETURN, first, nret + 1, 0);
|
this.codeABC(OP_RETURN, first, nret+1, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
int condjump(int /* OpCode */op, int A, int B, int C) {
|
int condjump(int /* OpCode */ op, int A, int B, int C) {
|
||||||
this.codeABC(op, A, B, C);
|
this.codeABC(op, A, B, C);
|
||||||
return this.jump();
|
return this.jump();
|
||||||
}
|
}
|
||||||
|
|
||||||
void fixjump(int pc, int dest) {
|
void fixjump(int pc, int dest) {
|
||||||
InstructionPtr jmp = new InstructionPtr(this.f.code, pc);
|
InstructionPtr jmp = new InstructionPtr(this.f.code, pc);
|
||||||
int offset = dest - (pc + 1);
|
int offset = dest-(pc+1);
|
||||||
_assert (dest != LexState.NO_JUMP);
|
_assert(dest != LexState.NO_JUMP);
|
||||||
if (Math.abs(offset) > MAXARG_sBx)
|
if (Math.abs(offset) > MAXARG_sBx)
|
||||||
ls.syntaxerror("control structure too long");
|
ls.syntaxerror("control structure too long");
|
||||||
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).
|
||||||
@@ -336,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 */
|
||||||
@@ -345,19 +334,17 @@ 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])))
|
||||||
return new InstructionPtr(pi.code, pi.idx - 1);
|
return new InstructionPtr(pi.code, pi.idx-1);
|
||||||
else
|
else
|
||||||
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)
|
||||||
@@ -371,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)
|
||||||
@@ -386,14 +372,13 @@ 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
void patchlistaux(int list, int vtarget, int reg, int dtarget) {
|
void patchlistaux(int list, int vtarget, int reg, int dtarget) {
|
||||||
while (list != LexState.NO_JUMP) {
|
while ( list != LexState.NO_JUMP ) {
|
||||||
int next = this.getjump(list);
|
int next = this.getjump(list);
|
||||||
if (this.patchtestreg(list, reg))
|
if (this.patchtestreg(list, reg))
|
||||||
this.fixjump(list, vtarget);
|
this.fixjump(list, vtarget);
|
||||||
@@ -412,17 +397,17 @@ public class FuncState extends Constants {
|
|||||||
if (target == this.pc)
|
if (target == this.pc)
|
||||||
this.patchtohere(list);
|
this.patchtohere(list);
|
||||||
else {
|
else {
|
||||||
_assert (target < this.pc);
|
_assert(target < this.pc);
|
||||||
this.patchlistaux(list, target, NO_REG, target);
|
this.patchlistaux(list, target, NO_REG, target);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void patchclose(int list, int level) {
|
void patchclose(int list, int level) {
|
||||||
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;
|
||||||
}
|
}
|
||||||
@@ -441,7 +426,7 @@ public class FuncState extends Constants {
|
|||||||
else {
|
else {
|
||||||
int list = l1.i;
|
int list = l1.i;
|
||||||
int next;
|
int next;
|
||||||
while ((next = this.getjump(list)) != LexState.NO_JUMP)
|
while ( (next = this.getjump(list)) != LexState.NO_JUMP )
|
||||||
/* find last element */
|
/* find last element */
|
||||||
list = next;
|
list = next;
|
||||||
this.fixjump(list, l2);
|
this.fixjump(list, l2);
|
||||||
@@ -449,7 +434,7 @@ public class FuncState extends Constants {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void checkstack(int n) {
|
void checkstack(int n) {
|
||||||
int newstack = this.freereg + n;
|
int newstack = this.freereg+n;
|
||||||
if (newstack > this.f.maxstacksize) {
|
if (newstack > this.f.maxstacksize) {
|
||||||
if (newstack >= MAXSTACK)
|
if (newstack >= MAXSTACK)
|
||||||
ls.syntaxerror("function or expression too complex");
|
ls.syntaxerror("function or expression too complex");
|
||||||
@@ -465,7 +450,7 @@ public class FuncState extends Constants {
|
|||||||
void freereg(int reg) {
|
void freereg(int reg) {
|
||||||
if (!ISK(reg) && reg >= this.nactvar) {
|
if (!ISK(reg) && reg >= this.nactvar) {
|
||||||
this.freereg--;
|
this.freereg--;
|
||||||
_assert (reg == this.freereg);
|
_assert(reg == this.freereg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -473,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();
|
||||||
@@ -480,10 +466,10 @@ 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);
|
||||||
f.k[this.nk++] = v;
|
f.k[this.nk++] = v;
|
||||||
return idx;
|
return idx;
|
||||||
}
|
}
|
||||||
@@ -493,17 +479,17 @@ public class FuncState extends Constants {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int numberK(LuaValue r) {
|
int numberK(LuaValue r) {
|
||||||
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() {
|
||||||
@@ -512,9 +498,9 @@ public class FuncState extends Constants {
|
|||||||
|
|
||||||
void setreturns(expdesc e, int nresults) {
|
void setreturns(expdesc e, int nresults) {
|
||||||
if (e.k == LexState.VCALL) { /* expression is an open function call? */
|
if (e.k == LexState.VCALL) { /* expression is an open function call? */
|
||||||
SETARG_C(this.getcodePtr(e), nresults + 1);
|
SETARG_C(this.getcodePtr(e), nresults+1);
|
||||||
} else if (e.k == LexState.VVARARG) {
|
} else if (e.k == LexState.VVARARG) {
|
||||||
SETARG_B(this.getcodePtr(e), nresults + 1);
|
SETARG_B(this.getcodePtr(e), nresults+1);
|
||||||
SETARG_A(this.getcodePtr(e), this.freereg);
|
SETARG_A(this.getcodePtr(e), this.freereg);
|
||||||
this.reserveregs(1);
|
this.reserveregs(1);
|
||||||
}
|
}
|
||||||
@@ -576,16 +562,15 @@ 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: {
|
||||||
this.codeABx(OP_LOADK, reg, e.u.info);
|
this.codeK(reg, e.u.info);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case LexState.VKNUM: {
|
case LexState.VKNUM: {
|
||||||
this.codeABx(OP_LOADK, reg, this.numberK(e.u.nval()));
|
this.codeK(reg, this.numberK(e.u.nval()));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case LexState.VRELOCABLE: {
|
case LexState.VRELOCABLE: {
|
||||||
@@ -599,7 +584,7 @@ public class FuncState extends Constants {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default: {
|
default: {
|
||||||
_assert (e.k == LexState.VVOID || e.k == LexState.VJMP);
|
_assert(e.k == LexState.VVOID || e.k == LexState.VJMP);
|
||||||
return; /* nothing to do... */
|
return; /* nothing to do... */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -610,7 +595,7 @@ public class FuncState extends Constants {
|
|||||||
void discharge2anyreg(expdesc e) {
|
void discharge2anyreg(expdesc e) {
|
||||||
if (e.k != LexState.VNONRELOC) {
|
if (e.k != LexState.VNONRELOC) {
|
||||||
this.reserveregs(1);
|
this.reserveregs(1);
|
||||||
this.discharge2reg(e, this.freereg - 1);
|
this.discharge2reg(e, this.freereg-1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -623,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);
|
||||||
@@ -642,7 +626,7 @@ public class FuncState extends Constants {
|
|||||||
this.dischargevars(e);
|
this.dischargevars(e);
|
||||||
this.freeexp(e);
|
this.freeexp(e);
|
||||||
this.reserveregs(1);
|
this.reserveregs(1);
|
||||||
this.exp2reg(e, this.freereg - 1);
|
this.exp2reg(e, this.freereg-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
int exp2anyreg(expdesc e) {
|
int exp2anyreg(expdesc e) {
|
||||||
@@ -659,7 +643,7 @@ public class FuncState extends Constants {
|
|||||||
return e.u.info;
|
return e.u.info;
|
||||||
}
|
}
|
||||||
|
|
||||||
void exp2anyregup (expdesc e) {
|
void exp2anyregup(expdesc e) {
|
||||||
if (e.k != LexState.VUPVAL || e.hasjumps())
|
if (e.k != LexState.VUPVAL || e.hasjumps())
|
||||||
exp2anyreg(e);
|
exp2anyreg(e);
|
||||||
}
|
}
|
||||||
@@ -678,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
|
||||||
@@ -716,13 +699,13 @@ 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;
|
||||||
}
|
}
|
||||||
default: {
|
default: {
|
||||||
_assert (false); /* invalid var kind to store */
|
_assert(false); /* invalid var kind to store */
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -743,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);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -757,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 */
|
||||||
}
|
}
|
||||||
@@ -841,7 +823,7 @@ public class FuncState extends Constants {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default: {
|
default: {
|
||||||
_assert (false); /* cannot happen */
|
_assert(false); /* cannot happen */
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -856,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;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -902,22 +884,20 @@ public class FuncState extends Constants {
|
|||||||
// break;
|
// break;
|
||||||
return false; /* no constant folding for 'len' */
|
return false; /* no constant folding for 'len' */
|
||||||
default:
|
default:
|
||||||
_assert (false);
|
_assert(false);
|
||||||
r = null;
|
r = null;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if ( Double.isNaN(r.todouble()) )
|
if (Double.isNaN(r.todouble()))
|
||||||
return false; /* do not attempt to produce NaN */
|
return false; /* do not attempt to produce NaN */
|
||||||
e1.u.setNval( r );
|
e1.u.setNval(r);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
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);
|
||||||
@@ -932,7 +912,7 @@ public class FuncState extends Constants {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void codecomp(int /* OpCode */op, int cond, expdesc e1, expdesc e2) {
|
void codecomp(int /* OpCode */ op, int cond, expdesc e1, expdesc e2) {
|
||||||
int o1 = this.exp2RK(e1);
|
int o1 = this.exp2RK(e1);
|
||||||
int o2 = this.exp2RK(e2);
|
int o2 = this.exp2RK(e2);
|
||||||
this.freeexp(e2);
|
this.freeexp(e2);
|
||||||
@@ -948,7 +928,7 @@ public class FuncState extends Constants {
|
|||||||
e1.k = LexState.VJMP;
|
e1.k = LexState.VJMP;
|
||||||
}
|
}
|
||||||
|
|
||||||
void prefix(int /* UnOpr */op, expdesc e, int line) {
|
void prefix(int /* UnOpr */ op, expdesc e, int line) {
|
||||||
expdesc e2 = new expdesc();
|
expdesc e2 = new expdesc();
|
||||||
e2.init(LexState.VKNUM, 0);
|
e2.init(LexState.VKNUM, 0);
|
||||||
switch (op) {
|
switch (op) {
|
||||||
@@ -970,11 +950,11 @@ public class FuncState extends Constants {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
_assert (false);
|
_assert(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void infix(int /* BinOpr */op, expdesc v) {
|
void infix(int /* BinOpr */ op, expdesc v) {
|
||||||
switch (op) {
|
switch (op) {
|
||||||
case LexState.OPR_AND: {
|
case LexState.OPR_AND: {
|
||||||
this.goiftrue(v);
|
this.goiftrue(v);
|
||||||
@@ -1005,11 +985,10 @@ 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: {
|
||||||
_assert (e1.t.i == LexState.NO_JUMP); /* list must be closed */
|
_assert(e1.t.i == LexState.NO_JUMP); /* list must be closed */
|
||||||
this.dischargevars(e2);
|
this.dischargevars(e2);
|
||||||
this.concat(e2.f, e1.f.i);
|
this.concat(e2.f, e1.f.i);
|
||||||
// *e1 = *e2;
|
// *e1 = *e2;
|
||||||
@@ -1017,7 +996,7 @@ public class FuncState extends Constants {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case LexState.OPR_OR: {
|
case LexState.OPR_OR: {
|
||||||
_assert (e1.f.i == LexState.NO_JUMP); /* list must be closed */
|
_assert(e1.f.i == LexState.NO_JUMP); /* list must be closed */
|
||||||
this.dischargevars(e2);
|
this.dischargevars(e2);
|
||||||
this.concat(e2.t, e1.t.i);
|
this.concat(e2.t, e1.t.i);
|
||||||
// *e1 = *e2;
|
// *e1 = *e2;
|
||||||
@@ -1026,9 +1005,8 @@ 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);
|
||||||
e1.k = LexState.VRELOCABLE;
|
e1.k = LexState.VRELOCABLE;
|
||||||
@@ -1076,59 +1054,68 @@ public class FuncState extends Constants {
|
|||||||
this.codecomp(OP_LE, 0, e1, e2);
|
this.codecomp(OP_LE, 0, e1, e2);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
_assert (false);
|
_assert(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
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);
|
||||||
_assert (getCMode(o) != OpArgN || c == 0);
|
_assert(getCMode(o) != OpArgN || c == 0);
|
||||||
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);
|
||||||
_assert (bc >= 0 && bc <= Lua.MAXARG_Bx);
|
_assert(bc >= 0 && bc <= Lua.MAXARG_Bx);
|
||||||
return this.code(CREATE_ABx(o, a, bc), this.ls.lastline);
|
return this.code(CREATE_ABx(o, a, bc), this.ls.lastline);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int codeextraarg(int a) {
|
||||||
|
_assert(a <= MAXARG_Ax);
|
||||||
|
return this.code(CREATE_Ax(OP_EXTRAARG, a), this.ls.lastline);
|
||||||
|
}
|
||||||
|
|
||||||
|
int codeK(int reg, int k) {
|
||||||
|
if (k <= MAXARG_Bx)
|
||||||
|
return codeABx(OP_LOADK, reg, k);
|
||||||
|
else {
|
||||||
|
int p = codeABx(OP_LOADKX, reg, 0);
|
||||||
|
codeextraarg(k);
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
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);
|
||||||
else {
|
else {
|
||||||
this.codeABC(OP_SETLIST, base, b, 0);
|
this.codeABC(OP_SETLIST, base, b, 0);
|
||||||
this.code(c, this.ls.lastline);
|
this.code(c, this.ls.lastline);
|
||||||
}
|
}
|
||||||
this.freereg = (short) (base + 1); /* free registers with list values */
|
this.freereg = (short) (base+1); /* free registers with list values */
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -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;
|
||||||
}
|
}
|
||||||
@@ -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;
|
||||||
}
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -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>
|
||||||
|
* {
|
||||||
|
* @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,48 +97,56 @@ 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 */
|
||||||
private Prototype luaY_parser(InputStream z, String name) throws IOException{
|
Prototype luaY_parser(InputStream z, String name) throws IOException {
|
||||||
LexState lexstate = new LexState(this, z);
|
LexState lexstate = new LexState(this, z);
|
||||||
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -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,47 +50,61 @@ 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>
|
||||||
|
* {
|
||||||
|
* @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>
|
||||||
|
* {
|
||||||
|
* @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;
|
||||||
globals.baselib = this;
|
globals.baselib = this;
|
||||||
env.set( "_G", env );
|
env.set("_G", env);
|
||||||
env.set( "_VERSION", Lua._VERSION );
|
env.set("_VERSION", Lua._VERSION);
|
||||||
env.set("assert", new _assert());
|
env.set("assert", new _assert());
|
||||||
env.set("collectgarbage", new collectgarbage());
|
env.set("collectgarbage", new collectgarbage());
|
||||||
env.set("dofile", new dofile());
|
env.set("dofile", new dofile());
|
||||||
@@ -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;
|
||||||
}
|
}
|
||||||
@@ -152,7 +166,7 @@ public class BaseLib extends TwoArgFunction implements ResourceFinder {
|
|||||||
System.gc();
|
System.gc();
|
||||||
return LuaValue.TRUE;
|
return LuaValue.TRUE;
|
||||||
} else {
|
} else {
|
||||||
this.argerror("gc op");
|
argerror(1, "invalid option '" + s + "'");
|
||||||
}
|
}
|
||||||
return NIL;
|
return NIL;
|
||||||
}
|
}
|
||||||
@@ -173,16 +187,16 @@ public class BaseLib extends TwoArgFunction implements ResourceFinder {
|
|||||||
// "error", // ( message [,level] ) -> ERR
|
// "error", // ( message [,level] ) -> ERR
|
||||||
static final class error extends TwoArgFunction {
|
static final class error extends TwoArgFunction {
|
||||||
public LuaValue call(LuaValue arg1, LuaValue arg2) {
|
public LuaValue call(LuaValue arg1, LuaValue arg2) {
|
||||||
throw arg1.isnil()? new LuaError(null, arg2.optint(1)):
|
if (arg1.isnil()) throw new LuaError(NIL);
|
||||||
arg1.isstring()? new LuaError(arg1.tojstring(), arg2.optint(1)):
|
if (!arg1.isstring() || arg2.optint(1) == 0) throw new LuaError(arg1);
|
||||||
new LuaError(arg1);
|
throw new LuaError(arg1.tojstring(), arg2.optint(1));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// "getmetatable", // ( object ) -> table
|
// "getmetatable", // ( object ) -> table
|
||||||
static final class getmetatable extends LibFunction {
|
static final class getmetatable extends LibFunction {
|
||||||
public LuaValue call() {
|
public LuaValue call() {
|
||||||
return argerror(1, "value");
|
return argerror(1, "value expected");
|
||||||
}
|
}
|
||||||
public LuaValue call(LuaValue arg) {
|
public LuaValue call(LuaValue arg) {
|
||||||
LuaValue mt = arg.getmetatable();
|
LuaValue mt = arg.getmetatable();
|
||||||
@@ -193,7 +207,9 @@ public class BaseLib extends TwoArgFunction implements ResourceFinder {
|
|||||||
final class load extends VarArgFunction {
|
final class load extends VarArgFunction {
|
||||||
public Varargs invoke(Varargs args) {
|
public Varargs invoke(Varargs args) {
|
||||||
LuaValue ld = args.arg1();
|
LuaValue ld = args.arg1();
|
||||||
args.argcheck(ld.isstring() || ld.isfunction(), 1, "ld must be string or function");
|
if (!ld.isstring() && !ld.isfunction()) {
|
||||||
|
throw new LuaError("bad argument #1 to 'load' (string or function expected, got " + ld.typename() + ")");
|
||||||
|
}
|
||||||
String source = args.optjstring(2, ld.isstring()? ld.tojstring(): "=(load)");
|
String source = args.optjstring(2, ld.isstring()? ld.tojstring(): "=(load)");
|
||||||
String mode = args.optjstring(3, "bt");
|
String mode = args.optjstring(3, "bt");
|
||||||
LuaValue env = args.optvalue(4, globals);
|
LuaValue env = args.optvalue(4, globals);
|
||||||
@@ -204,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;
|
||||||
@@ -217,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)
|
||||||
@@ -242,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++ ) {
|
||||||
@@ -249,19 +269,18 @@ public class BaseLib extends TwoArgFunction implements ResourceFinder {
|
|||||||
LuaString s = tostring.call( args.arg(i) ).strvalue();
|
LuaString s = tostring.call( args.arg(i) ).strvalue();
|
||||||
globals.STDOUT.print(s.tojstring());
|
globals.STDOUT.print(s.tojstring());
|
||||||
}
|
}
|
||||||
globals.STDOUT.println();
|
globals.STDOUT.print('\n');
|
||||||
return NONE;
|
return NONE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// "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() {
|
||||||
return argerror(1, "value");
|
return argerror(1, "value expected");
|
||||||
}
|
}
|
||||||
public LuaValue call(LuaValue arg) {
|
public LuaValue call(LuaValue arg) {
|
||||||
return argerror(2, "value");
|
return argerror(2, "value expected");
|
||||||
}
|
}
|
||||||
public LuaValue call(LuaValue arg1, LuaValue arg2) {
|
public LuaValue call(LuaValue arg1, LuaValue arg2) {
|
||||||
return valueOf(arg1.raweq(arg2));
|
return valueOf(arg1.raweq(arg2));
|
||||||
@@ -269,12 +288,12 @@ public class BaseLib extends TwoArgFunction implements ResourceFinder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// "rawget", // (table, index) -> value
|
// "rawget", // (table, index) -> value
|
||||||
static final class rawget extends LibFunction {
|
static final class rawget extends TableLibFunction {
|
||||||
public LuaValue call() {
|
public LuaValue call() {
|
||||||
return argerror(1, "value");
|
return argerror(1, "value expected");
|
||||||
}
|
}
|
||||||
public LuaValue call(LuaValue arg) {
|
public LuaValue call(LuaValue arg) {
|
||||||
return argerror(2, "value");
|
return argerror(2, "value expected");
|
||||||
}
|
}
|
||||||
public LuaValue call(LuaValue arg1, LuaValue arg2) {
|
public LuaValue call(LuaValue arg1, LuaValue arg2) {
|
||||||
return arg1.checktable().rawget(arg2);
|
return arg1.checktable().rawget(arg2);
|
||||||
@@ -290,16 +309,17 @@ public class BaseLib extends TwoArgFunction implements ResourceFinder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// "rawset", // (table, index, value) -> table
|
// "rawset", // (table, index, value) -> table
|
||||||
static final class rawset extends LibFunction {
|
static final class rawset extends TableLibFunction {
|
||||||
public LuaValue call(LuaValue table) {
|
public LuaValue call(LuaValue table) {
|
||||||
return argerror(2,"value");
|
return argerror(2,"value expected");
|
||||||
}
|
}
|
||||||
public LuaValue call(LuaValue table, LuaValue index) {
|
public LuaValue call(LuaValue table, LuaValue index) {
|
||||||
return argerror(3,"value");
|
return argerror(3,"value expected");
|
||||||
}
|
}
|
||||||
public LuaValue call(LuaValue table, LuaValue index, LuaValue value) {
|
public LuaValue call(LuaValue table, LuaValue index, LuaValue value) {
|
||||||
LuaTable t = table.checktable();
|
LuaTable t = table.checktable();
|
||||||
t.rawset(index.checknotnil(), value);
|
if (!index.isvalidkey()) argerror(2, "table index is nil");
|
||||||
|
t.rawset(index, value);
|
||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -318,9 +338,9 @@ public class BaseLib extends TwoArgFunction implements ResourceFinder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// "setmetatable", // (table, metatable) -> table
|
// "setmetatable", // (table, metatable) -> table
|
||||||
static final class setmetatable extends LibFunction {
|
static final class setmetatable extends TableLibFunction {
|
||||||
public LuaValue call(LuaValue table) {
|
public LuaValue call(LuaValue table) {
|
||||||
return argerror(2,"value");
|
return argerror(2,"nil or table expected");
|
||||||
}
|
}
|
||||||
public LuaValue call(LuaValue table, LuaValue metatable) {
|
public LuaValue call(LuaValue table, LuaValue metatable) {
|
||||||
final LuaValue mt0 = table.checktable().getmetatable();
|
final LuaValue mt0 = table.checktable().getmetatable();
|
||||||
@@ -339,7 +359,7 @@ public class BaseLib extends TwoArgFunction implements ResourceFinder {
|
|||||||
if (base.isnil())
|
if (base.isnil())
|
||||||
return e.tonumber();
|
return e.tonumber();
|
||||||
final int b = base.checkint();
|
final int b = base.checkint();
|
||||||
if ( b < 2 || b > 36 )
|
if (b < 2 || b > 36)
|
||||||
argerror(2, "base out of range");
|
argerror(2, "base out of range");
|
||||||
return e.checkstring().tonumber(b);
|
return e.checkstring().tonumber(b);
|
||||||
}
|
}
|
||||||
@@ -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;
|
||||||
@@ -465,10 +493,12 @@ public class BaseLib extends TwoArgFunction implements ResourceFinder {
|
|||||||
this.func = func;
|
this.func = func;
|
||||||
}
|
}
|
||||||
public int read() throws IOException {
|
public int read() throws IOException {
|
||||||
if ( remaining <= 0 ) {
|
if ( remaining < 0 )
|
||||||
|
return -1;
|
||||||
|
if ( remaining == 0 ) {
|
||||||
LuaValue s = func.call();
|
LuaValue s = func.call();
|
||||||
if ( s.isnil() )
|
if ( s.isnil() )
|
||||||
return -1;
|
return remaining = -1;
|
||||||
LuaString ls = s.strvalue();
|
LuaString ls = s.strvalue();
|
||||||
bytes = ls.m_bytes;
|
bytes = ls.m_bytes;
|
||||||
offset = ls.m_offset;
|
offset = ls.m_offset;
|
||||||
@@ -477,7 +507,7 @@ public class BaseLib extends TwoArgFunction implements ResourceFinder {
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
--remaining;
|
--remaining;
|
||||||
return bytes[offset++];
|
return 0xFF & bytes[offset++];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -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>
|
||||||
|
* {
|
||||||
|
* @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>
|
||||||
|
* {
|
||||||
|
* @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);
|
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;
|
||||||
}
|
}
|
||||||
@@ -110,9 +136,9 @@ public class Bit32Lib extends TwoArgFunction {
|
|||||||
|
|
||||||
static LuaValue arshift(int x, int disp) {
|
static LuaValue arshift(int x, int disp) {
|
||||||
if (disp >= 0) {
|
if (disp >= 0) {
|
||||||
return bitsToValue(x >> disp);
|
return bitsToValue(x>>disp);
|
||||||
} else {
|
} else {
|
||||||
return bitsToValue(x << -disp);
|
return bitsToValue(x<<-disp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -120,9 +146,9 @@ public class Bit32Lib extends TwoArgFunction {
|
|||||||
if (disp >= 32 || disp <= -32) {
|
if (disp >= 32 || disp <= -32) {
|
||||||
return ZERO;
|
return ZERO;
|
||||||
} else if (disp >= 0) {
|
} else if (disp >= 0) {
|
||||||
return bitsToValue(x >>> disp);
|
return bitsToValue(x>>>disp);
|
||||||
} else {
|
} else {
|
||||||
return bitsToValue(x << -disp);
|
return bitsToValue(x<<-disp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -130,46 +156,46 @@ public class Bit32Lib extends TwoArgFunction {
|
|||||||
if (disp >= 32 || disp <= -32) {
|
if (disp >= 32 || disp <= -32) {
|
||||||
return ZERO;
|
return ZERO;
|
||||||
} else if (disp >= 0) {
|
} else if (disp >= 0) {
|
||||||
return bitsToValue(x << disp);
|
return bitsToValue(x<<disp);
|
||||||
} else {
|
} else {
|
||||||
return bitsToValue(x >>> -disp);
|
return bitsToValue(x>>>-disp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static Varargs band( Varargs args ) {
|
static Varargs band(Varargs args) {
|
||||||
int result = -1;
|
int result = -1;
|
||||||
for ( int i = 1; i <= args.narg(); i++ ) {
|
for (int i = 1; i <= args.narg(); i++) {
|
||||||
result &= args.checkint(i);
|
result &= args.checkint(i);
|
||||||
}
|
}
|
||||||
return bitsToValue( result );
|
return bitsToValue(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
static Varargs bnot( Varargs args ) {
|
static Varargs bnot(Varargs args) {
|
||||||
return bitsToValue( ~args.checkint(1) );
|
return bitsToValue(~args.checkint(1));
|
||||||
}
|
}
|
||||||
|
|
||||||
static Varargs bor( Varargs args ) {
|
static Varargs bor(Varargs args) {
|
||||||
int result = 0;
|
int result = 0;
|
||||||
for ( int i = 1; i <= args.narg(); i++ ) {
|
for (int i = 1; i <= args.narg(); i++) {
|
||||||
result |= args.checkint(i);
|
result |= args.checkint(i);
|
||||||
}
|
}
|
||||||
return bitsToValue( result );
|
return bitsToValue(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
static Varargs btest( Varargs args ) {
|
static Varargs btest(Varargs args) {
|
||||||
int bits = -1;
|
int bits = -1;
|
||||||
for ( int i = 1; i <= args.narg(); i++ ) {
|
for (int i = 1; i <= args.narg(); i++) {
|
||||||
bits &= args.checkint(i);
|
bits &= args.checkint(i);
|
||||||
}
|
}
|
||||||
return valueOf( bits != 0 );
|
return valueOf(bits != 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static Varargs bxor( Varargs args ) {
|
static Varargs bxor(Varargs args) {
|
||||||
int result = 0;
|
int result = 0;
|
||||||
for ( int i = 1; i <= args.narg(); i++ ) {
|
for (int i = 1; i <= args.narg(); i++) {
|
||||||
result ^= args.checkint(i);
|
result ^= args.checkint(i);
|
||||||
}
|
}
|
||||||
return bitsToValue( result );
|
return bitsToValue(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
static LuaValue lrotate(int x, int disp) {
|
static LuaValue lrotate(int x, int disp) {
|
||||||
@@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -197,10 +223,10 @@ public class Bit32Lib extends TwoArgFunction {
|
|||||||
if (width < 0) {
|
if (width < 0) {
|
||||||
argerror(3, "width must be postive");
|
argerror(3, "width must be postive");
|
||||||
}
|
}
|
||||||
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) {
|
||||||
@@ -210,15 +236,15 @@ public class Bit32Lib extends TwoArgFunction {
|
|||||||
if (width < 0) {
|
if (width < 0) {
|
||||||
argerror(4, "width must be postive");
|
argerror(4, "width must be postive");
|
||||||
}
|
}
|
||||||
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -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>
|
||||||
|
* {
|
||||||
|
* @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>
|
||||||
|
* {
|
||||||
|
* @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,24 +98,28 @@ 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);
|
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());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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,19 +127,22 @@ 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());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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);
|
||||||
@@ -127,17 +150,20 @@ public class CoroutineLib extends TwoArgFunction {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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()) {
|
||||||
return result.subargs(2);
|
return result.subargs(2);
|
||||||
} else {
|
} else {
|
||||||
return error( result.arg(2).tojstring() );
|
return error(result.arg(2).tojstring());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -39,81 +39,101 @@ 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>
|
||||||
|
* {
|
||||||
|
* @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>
|
||||||
|
* {
|
||||||
|
* @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) {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final LuaString LUA = valueOf("Lua");
|
static final LuaString LUA = valueOf("Lua");
|
||||||
private static final LuaString QMARK = valueOf("?");
|
private static final LuaString QMARK = valueOf("?");
|
||||||
private static final LuaString CALL = valueOf("call");
|
private static final LuaString CALL = valueOf("call");
|
||||||
private static final LuaString LINE = valueOf("line");
|
private static final LuaString LINE = valueOf("line");
|
||||||
private static final LuaString COUNT = valueOf("count");
|
private static final LuaString COUNT = valueOf("count");
|
||||||
private static final LuaString RETURN = valueOf("return");
|
private static final LuaString RETURN = valueOf("return");
|
||||||
|
|
||||||
private static final LuaString FUNC = valueOf("func");
|
static final LuaString FUNC = valueOf("func");
|
||||||
private static final LuaString ISTAILCALL = valueOf("istailcall");
|
static final LuaString ISTAILCALL = valueOf("istailcall");
|
||||||
private static final LuaString ISVARARG = valueOf("isvararg");
|
static final LuaString ISVARARG = valueOf("isvararg");
|
||||||
private static final LuaString NUPS = valueOf("nups");
|
static final LuaString NUPS = valueOf("nups");
|
||||||
private static final LuaString NPARAMS = valueOf("nparams");
|
static final LuaString NPARAMS = valueOf("nparams");
|
||||||
private static final LuaString NAME = valueOf("name");
|
static final LuaString NAME = valueOf("name");
|
||||||
private static final LuaString NAMEWHAT = valueOf("namewhat");
|
static final LuaString NAMEWHAT = valueOf("namewhat");
|
||||||
private static final LuaString WHAT = valueOf("what");
|
static final LuaString WHAT = valueOf("what");
|
||||||
private static final LuaString SOURCE = valueOf("source");
|
static final LuaString SOURCE = valueOf("source");
|
||||||
private static final LuaString SHORT_SRC = valueOf("short_src");
|
static final LuaString SHORT_SRC = valueOf("short_src");
|
||||||
private static final LuaString LINEDEFINED = valueOf("linedefined");
|
static final LuaString LINEDEFINED = valueOf("linedefined");
|
||||||
private static final LuaString LASTLINEDEFINED = valueOf("lastlinedefined");
|
static final LuaString LASTLINEDEFINED = valueOf("lastlinedefined");
|
||||||
private static final LuaString CURRENTLINE = valueOf("currentline");
|
static final LuaString CURRENTLINE = valueOf("currentline");
|
||||||
private static final LuaString ACTIVELINES = valueOf("activelines");
|
static final LuaString ACTIVELINES = valueOf("activelines");
|
||||||
|
|
||||||
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);
|
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,20 +170,20 @@ 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;
|
||||||
LuaValue func = args.arg(a++);
|
LuaValue func = args.arg(a++);
|
||||||
String what = args.optjstring(a++, "flnStu");
|
String what = args.optjstring(a++, "flnStu");
|
||||||
@@ -169,12 +191,12 @@ public class DebugLib extends TwoArgFunction {
|
|||||||
|
|
||||||
// find the stack info
|
// find the stack info
|
||||||
DebugLib.CallFrame frame;
|
DebugLib.CallFrame frame;
|
||||||
if ( func.isnumber() ) {
|
if (func.isnumber()) {
|
||||||
frame = callstack.getCallFrame(func.toint());
|
frame = callstack.getCallFrame(func.toint());
|
||||||
if (frame == null)
|
if (frame == null)
|
||||||
return NONE;
|
return NONE;
|
||||||
func = frame.f;
|
func = frame.f;
|
||||||
} else if ( func.isfunction() ) {
|
} else if (func.isfunction()) {
|
||||||
frame = callstack.findCallFrame(func);
|
frame = callstack.findCallFrame(func);
|
||||||
} else {
|
} else {
|
||||||
return argerror(a-2, "function or level");
|
return argerror(a-2, "function or level");
|
||||||
@@ -191,7 +213,7 @@ public class DebugLib extends TwoArgFunction {
|
|||||||
info.set(LASTLINEDEFINED, valueOf(ar.lastlinedefined));
|
info.set(LASTLINEDEFINED, valueOf(ar.lastlinedefined));
|
||||||
}
|
}
|
||||||
if (what.indexOf('l') >= 0) {
|
if (what.indexOf('l') >= 0) {
|
||||||
info.set( CURRENTLINE, valueOf(ar.currentline) );
|
info.set(CURRENTLINE, valueOf(ar.currentline));
|
||||||
}
|
}
|
||||||
if (what.indexOf('u') >= 0) {
|
if (what.indexOf('u') >= 0) {
|
||||||
info.set(NUPS, valueOf(ar.nups));
|
info.set(NUPS, valueOf(ar.nups));
|
||||||
@@ -199,7 +221,7 @@ public class DebugLib extends TwoArgFunction {
|
|||||||
info.set(ISVARARG, ar.isvararg? ONE: ZERO);
|
info.set(ISVARARG, ar.isvararg? ONE: ZERO);
|
||||||
}
|
}
|
||||||
if (what.indexOf('n') >= 0) {
|
if (what.indexOf('n') >= 0) {
|
||||||
info.set(NAME, LuaValue.valueOf(ar.name!=null? ar.name: "?"));
|
info.set(NAME, LuaValue.valueOf(ar.name != null? ar.name: "?"));
|
||||||
info.set(NAMEWHAT, LuaValue.valueOf(ar.namewhat));
|
info.set(NAMEWHAT, LuaValue.valueOf(ar.namewhat));
|
||||||
}
|
}
|
||||||
if (what.indexOf('t') >= 0) {
|
if (what.indexOf('t') >= 0) {
|
||||||
@@ -209,13 +231,13 @@ public class DebugLib extends TwoArgFunction {
|
|||||||
LuaTable lines = new LuaTable();
|
LuaTable lines = new LuaTable();
|
||||||
info.set(ACTIVELINES, lines);
|
info.set(ACTIVELINES, lines);
|
||||||
DebugLib.CallFrame cf;
|
DebugLib.CallFrame cf;
|
||||||
for (int l = 1; (cf=callstack.getCallFrame(l)) != null; ++l)
|
for (int l = 1; (cf = callstack.getCallFrame(l)) != null; ++l)
|
||||||
if (cf.f == func)
|
if (cf.f == func)
|
||||||
lines.insert(-1, valueOf(cf.currentline()));
|
lines.insert(-1, valueOf(cf.currentline()));
|
||||||
}
|
}
|
||||||
if (what.indexOf('f') >= 0) {
|
if (what.indexOf('f') >= 0) {
|
||||||
if (func != null)
|
if (func != null)
|
||||||
info.set( FUNC, func );
|
info.set(FUNC, func);
|
||||||
}
|
}
|
||||||
return info;
|
return info;
|
||||||
}
|
}
|
||||||
@@ -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)
|
||||||
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,14 +282,15 @@ 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);
|
||||||
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);
|
||||||
if ( name != null ) {
|
if (name != null) {
|
||||||
return varargsOf(name, c.upValues[up-1].getValue() );
|
return varargsOf(name, c.upValues[up-1].getValue());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return NIL;
|
return NIL;
|
||||||
@@ -266,26 +299,33 @@ 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;
|
||||||
LuaValue func = args.optfunction(a++, null);
|
LuaValue func = args.optfunction(a++, null);
|
||||||
String str = args.optjstring(a++,"");
|
String str = args.optjstring(a++, "");
|
||||||
int count = args.optint(a++,0);
|
int count = args.optint(a++, 0);
|
||||||
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,8 +339,9 @@ 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;
|
||||||
int level = args.checkint(a++);
|
int level = args.checkint(a++);
|
||||||
int local = args.checkint(a++);
|
int local = args.checkint(a++);
|
||||||
@@ -311,32 +352,47 @@ public class DebugLib extends TwoArgFunction {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// debug.setmetatable (value, table)
|
// debug.setmetatable (value, table)
|
||||||
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// debug.setupvalue (f, up, value)
|
// debug.setupvalue (f, up, value)
|
||||||
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);
|
||||||
if ( name != null ) {
|
if (name != null) {
|
||||||
c.upValues[up-1].setValue(value);
|
c.upValues[up-1].setValue(value);
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
@@ -346,7 +402,8 @@ public class DebugLib extends TwoArgFunction {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// debug.setuservalue (udata, value)
|
// debug.setuservalue (udata, value)
|
||||||
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,24 +416,26 @@ 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;
|
||||||
String message = args.optjstring(a++, null);
|
String message = args.optjstring(a++, null);
|
||||||
int level = args.optint(a++,1);
|
int level = args.optint(a++, 1);
|
||||||
String tb = callstack(thread).traceback(level);
|
String tb = callstack(thread).traceback(level);
|
||||||
return valueOf(message!=null? message+"\n"+tb: tb);
|
return valueOf(message != null? message + "\n" + tb: tb);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// debug.upvalueid (f, n)
|
// debug.upvalueid (f, n)
|
||||||
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);
|
||||||
if ( func instanceof LuaClosure ) {
|
LuaValue func = args.checkfunction(1);
|
||||||
|
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) {
|
||||||
return valueOf(c.upValues[up-1].hashCode());
|
return valueOf(c.upValues[up-1].hashCode());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -385,12 +444,13 @@ public class DebugLib extends TwoArgFunction {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// debug.upvaluejoin (f1, n1, f2, n2)
|
// debug.upvaluejoin (f1, n1, f2, n2)
|
||||||
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,29 +462,35 @@ 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);
|
||||||
if (s.hookline) {
|
if (s.hookline) {
|
||||||
int newline = callstack().currentline();
|
int newline = callstack().currentline();
|
||||||
if ( newline != s.lastline ) {
|
if (newline != s.lastline) {
|
||||||
s.lastline = newline;
|
s.lastline = newline;
|
||||||
callHook(s, LINE, LuaValue.valueOf(newline));
|
callHook(s, LINE, LuaValue.valueOf(newline));
|
||||||
}
|
}
|
||||||
@@ -433,17 +499,24 @@ 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) {
|
||||||
return callstack().traceback(level);
|
return callstack().traceback(level);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public CallFrame getCallFrame(int level) {
|
||||||
|
return callstack().getCallFrame(level);
|
||||||
|
}
|
||||||
|
|
||||||
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);
|
||||||
@@ -475,7 +548,7 @@ public class DebugLib extends TwoArgFunction {
|
|||||||
int linedefined; /* (S) */
|
int linedefined; /* (S) */
|
||||||
int lastlinedefined; /* (S) */
|
int lastlinedefined; /* (S) */
|
||||||
short nups; /* (u) number of upvalues */
|
short nups; /* (u) number of upvalues */
|
||||||
short nparams;/* (u) number of parameters */
|
short nparams; /* (u) number of parameters */
|
||||||
boolean isvararg; /* (u) */
|
boolean isvararg; /* (u) */
|
||||||
boolean istailcall; /* (t) */
|
boolean istailcall; /* (t) */
|
||||||
String short_src; /* (S) */
|
String short_src; /* (S) */
|
||||||
@@ -484,10 +557,10 @@ public class DebugLib extends TwoArgFunction {
|
|||||||
public void funcinfo(LuaFunction f) {
|
public void funcinfo(LuaFunction f) {
|
||||||
if (f.isclosure()) {
|
if (f.isclosure()) {
|
||||||
Prototype p = f.checkclosure().p;
|
Prototype p = f.checkclosure().p;
|
||||||
this.source = p.source != null ? p.source.tojstring() : "=?";
|
this.source = p.source != null? p.source.tojstring(): "=?";
|
||||||
this.linedefined = p.linedefined;
|
this.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]";
|
||||||
@@ -512,7 +585,7 @@ public class DebugLib extends TwoArgFunction {
|
|||||||
|
|
||||||
private synchronized CallFrame pushcall() {
|
private synchronized CallFrame pushcall() {
|
||||||
if (calls >= frame.length) {
|
if (calls >= frame.length) {
|
||||||
int n = Math.max(4, frame.length * 3 / 2);
|
int n = Math.max(4, frame.length*3/2);
|
||||||
CallFrame[] f = new CallFrame[n];
|
CallFrame[] f = new CallFrame[n];
|
||||||
System.arraycopy(frame, 0, f, 0, frame.length);
|
System.arraycopy(frame, 0, f, 0, frame.length);
|
||||||
for (int i = frame.length; i < n; ++i)
|
for (int i = frame.length; i < n; ++i)
|
||||||
@@ -544,28 +617,33 @@ 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.
|
||||||
*/
|
*/
|
||||||
synchronized String traceback(int level) {
|
synchronized String traceback(int level) {
|
||||||
StringBuffer sb = new StringBuffer();
|
StringBuffer sb = new StringBuffer();
|
||||||
sb.append( "stack traceback:" );
|
sb.append("stack traceback:");
|
||||||
for (DebugLib.CallFrame c; (c = getCallFrame(level++)) != null; ) {
|
for (DebugLib.CallFrame c; (c = getCallFrame(level++)) != null;) {
|
||||||
sb.append("\n\t");
|
sb.append("\n\t");
|
||||||
sb.append( c.shortsource() );
|
sb.append(c.shortsource());
|
||||||
sb.append( ':' );
|
sb.append(':');
|
||||||
if (c.currentline() > 0)
|
if (c.currentline() > 0)
|
||||||
sb.append( c.currentline()+":" );
|
sb.append(c.currentline() + ":");
|
||||||
sb.append( " in " );
|
sb.append(" in ");
|
||||||
DebugInfo ar = auxgetinfo("n", c.f, c);
|
DebugInfo ar = auxgetinfo("n", c.f, c);
|
||||||
if (c.linedefined() == 0)
|
if (c.linedefined() == 0)
|
||||||
sb.append("main chunk");
|
sb.append("main chunk");
|
||||||
else if ( ar.name != null ) {
|
else if (ar.name != null) {
|
||||||
sb.append( "function '" );
|
sb.append("function '");
|
||||||
sb.append( ar.name );
|
sb.append(ar.name);
|
||||||
sb.append( '\'' );
|
sb.append('\'');
|
||||||
} else {
|
} else {
|
||||||
sb.append( "function <"+c.shortsource()+":"+c.linedefined()+">" );
|
sb.append("function <");
|
||||||
|
sb.append(c.shortsource());
|
||||||
|
sb.append(':');
|
||||||
|
sb.append(c.linedefined());
|
||||||
|
sb.append('>');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
sb.append("\n\t[Java]: in ?");
|
sb.append("\n\t[Java]: in ?");
|
||||||
@@ -585,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) {
|
||||||
@@ -641,29 +718,36 @@ public class DebugLib extends TwoArgFunction {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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;
|
||||||
@@ -671,57 +755,68 @@ 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 ( name != null )
|
if (i >= 1 && i <= stack.length && stack[i-1] != null)
|
||||||
return varargsOf( name, stack[i-1] );
|
return varargsOf(name == null? NIL: name, stack[i-1]);
|
||||||
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 ( name != null ) {
|
if (i >= 1 && i <= stack.length && stack[i-1] != null) {
|
||||||
stack[i-1] = value;
|
stack[i-1] = value;
|
||||||
return name;
|
return name == null? NIL: name;
|
||||||
} else {
|
} else {
|
||||||
return NIL;
|
return NIL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
int currentline() {
|
|
||||||
if ( !f.isclosure() ) return -1;
|
public int currentline() {
|
||||||
|
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();
|
||||||
}
|
}
|
||||||
private 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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static LuaString findupvalue(LuaClosure c, int up) {
|
static LuaString findupvalue(LuaClosure c, int up) {
|
||||||
if ( c.upValues != null && up > 0 && up <= c.upValues.length ) {
|
if (c.upValues != null && up > 0 && up <= c.upValues.length) {
|
||||||
if ( c.p.upvalues != null && up <= c.p.upvalues.length )
|
if (c.p.upvalues != null && up <= c.p.upvalues.length)
|
||||||
return c.p.upvalues[up-1].name;
|
return c.p.upvalues[up-1].name;
|
||||||
else
|
else
|
||||||
return LuaString.valueOf( "."+up );
|
return LuaString.valueOf("." + up);
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
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;
|
||||||
@@ -745,33 +840,61 @@ 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 */
|
||||||
}
|
}
|
||||||
return new NameWhat( tm.tojstring(), "metamethod" );
|
return new NameWhat(tm.tojstring(), "metamethod");
|
||||||
}
|
}
|
||||||
|
|
||||||
// return NameWhat if found, null if not
|
// return NameWhat if found, null if not
|
||||||
public static NameWhat getobjname(Prototype p, int lastpc, int reg) {
|
public static NameWhat getobjname(Prototype p, int lastpc, int reg) {
|
||||||
int pc = lastpc; // currentpc(L, ci);
|
int pc = lastpc; // currentpc(L, ci);
|
||||||
LuaString name = p.getlocalname(reg + 1, pc);
|
LuaString name = p.getlocalname(reg+1, pc);
|
||||||
if (name != null) /* is a local? */
|
if (name != null) /* is a local? */
|
||||||
return new NameWhat( name.tojstring(), "local" );
|
return new NameWhat(name.tojstring(), "local");
|
||||||
|
|
||||||
/* else try symbolic execution */
|
/* else try symbolic execution */
|
||||||
pc = findsetreg(p, lastpc, reg);
|
pc = findsetreg(p, lastpc, reg);
|
||||||
@@ -789,31 +912,30 @@ 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;
|
||||||
name = kname(p, k);
|
String jname = kname(p, pc, k);
|
||||||
return new NameWhat( name.tojstring(), vn != null && vn.eq_b(ENV)? "global": "field" );
|
return new NameWhat(jname, vn != null && vn.eq_b(ENV)? "global": "field");
|
||||||
}
|
}
|
||||||
case Lua.OP_GETUPVAL: {
|
case Lua.OP_GETUPVAL: {
|
||||||
int u = Lua.GETARG_B(i); /* upvalue index */
|
int u = Lua.GETARG_B(i); /* upvalue index */
|
||||||
name = u < p.upvalues.length ? p.upvalues[u].name : QMARK;
|
name = u < p.upvalues.length? p.upvalues[u].name: QMARK;
|
||||||
return new NameWhat( name.tojstring(), "upvalue" );
|
return name == null? null: new NameWhat(name.tojstring(), "upvalue");
|
||||||
}
|
}
|
||||||
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");
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Lua.OP_SELF: {
|
case Lua.OP_SELF: {
|
||||||
int k = Lua.GETARG_C(i); /* key index */
|
int k = Lua.GETARG_C(i); /* key index */
|
||||||
name = kname(p, k);
|
String jname = kname(p, pc, k);
|
||||||
return new NameWhat( name.tojstring(), "method" );
|
return new NameWhat(jname, "method");
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
@@ -822,17 +944,26 @@ public class DebugLib extends TwoArgFunction {
|
|||||||
return null; /* no useful name found */
|
return null; /* no useful name found */
|
||||||
}
|
}
|
||||||
|
|
||||||
static LuaString kname(Prototype p, int c) {
|
static String kname(Prototype p, int pc, int c) {
|
||||||
if (Lua.ISK(c) && p.k[Lua.INDEXK(c)].isstring())
|
if (Lua.ISK(c)) { /* is 'c' a constant? */
|
||||||
return p.k[Lua.INDEXK(c)].strvalue();
|
LuaValue k = p.k[Lua.INDEXK(c)];
|
||||||
else
|
if (k.isstring()) { /* literal constant? */
|
||||||
return QMARK;
|
return k.tojstring(); /* it is its own name */
|
||||||
|
} /* else no reasonable name found */
|
||||||
|
} else { /* 'c' is a register */
|
||||||
|
NameWhat what = getobjname(p, pc, c); /* search for 'c' */
|
||||||
|
if (what != null && "constant".equals(what.namewhat)) { /* found a constant name? */
|
||||||
|
return what.name; /* 'name' already filled */
|
||||||
|
}
|
||||||
|
/* else no reasonable name found */
|
||||||
|
}
|
||||||
|
return "?"; /* no reasonable name found */
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** try to find last instruction before 'lastpc' that modified register 'reg'
|
** try to find last instruction before 'lastpc' that modified register 'reg'
|
||||||
*/
|
*/
|
||||||
static int findsetreg (Prototype p, int lastpc, int reg) {
|
static int findsetreg(Prototype p, int lastpc, int reg) {
|
||||||
int pc;
|
int pc;
|
||||||
int setreg = -1; /* keep last instruction that changed 'reg' */
|
int setreg = -1; /* keep last instruction that changed 'reg' */
|
||||||
for (pc = 0; pc < lastpc; pc++) {
|
for (pc = 0; pc < lastpc; pc++) {
|
||||||
@@ -842,29 +973,37 @@ public class DebugLib extends TwoArgFunction {
|
|||||||
switch (op) {
|
switch (op) {
|
||||||
case Lua.OP_LOADNIL: {
|
case Lua.OP_LOADNIL: {
|
||||||
int b = Lua.GETARG_B(i);
|
int b = Lua.GETARG_B(i);
|
||||||
if (a <= reg && reg <= a + b) /* set registers from 'a' to 'a+b' */
|
if (a <= reg && reg <= a+b) /* set registers from 'a' to 'a+b' */
|
||||||
setreg = pc;
|
setreg = pc;
|
||||||
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: {
|
||||||
int b = Lua.GETARG_sBx(i);
|
int b = Lua.GETARG_sBx(i);
|
||||||
int dest = pc + 1 + b;
|
int dest = pc+1+b;
|
||||||
/* jump is forward and do not skip `lastpc'? */
|
/* jump is forward and do not skip `lastpc'? */
|
||||||
if (pc < dest && dest <= lastpc)
|
if (pc < dest && dest <= lastpc)
|
||||||
pc += b; /* do the jump */
|
pc += b; /* do the jump */
|
||||||
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;
|
||||||
|
}
|
||||||
|
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
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
748
luaj-core/src/main/java/org/luaj/vm2/lib/IoLib.java
Normal file
748
luaj-core/src/main/java/org/luaj/vm2/lib/IoLib.java
Normal file
@@ -0,0 +1,748 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* 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.lib;
|
||||||
|
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.EOFException;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import org.luaj.vm2.Globals;
|
||||||
|
import org.luaj.vm2.LuaString;
|
||||||
|
import org.luaj.vm2.LuaTable;
|
||||||
|
import org.luaj.vm2.LuaValue;
|
||||||
|
import org.luaj.vm2.Varargs;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Abstract base class extending {@link LibFunction} which implements the core
|
||||||
|
* of the lua standard {@code io} library.
|
||||||
|
* <p>
|
||||||
|
* It contains the implementation of the io library support that is common to
|
||||||
|
* the JSE and JME platforms. In practice on of the concrete IOLib subclasses is
|
||||||
|
* chosen: {@link org.luaj.vm2.lib.jse.JseIoLib} for the JSE platform, and
|
||||||
|
* {@link org.luaj.vm2.lib.jme.JmeIoLib} for the JME platform.
|
||||||
|
* <p>
|
||||||
|
* The JSE implementation conforms almost completely to the C-based lua library,
|
||||||
|
* while the JME implementation follows closely except in the area of
|
||||||
|
* random-access files, which are difficult to support properly on JME.
|
||||||
|
* <p>
|
||||||
|
* Typically, this library is included as part of a call to either
|
||||||
|
* {@link org.luaj.vm2.lib.jse.JsePlatform#standardGlobals()} or
|
||||||
|
* {@link org.luaj.vm2.lib.jme.JmePlatform#standardGlobals()}
|
||||||
|
*
|
||||||
|
* <pre>
|
||||||
|
* {
|
||||||
|
* @code
|
||||||
|
* Globals globals = JsePlatform.standardGlobals();
|
||||||
|
* globals.get("io").get("write").call(LuaValue.valueOf("hello, world\n"));
|
||||||
|
* }
|
||||||
|
* </pre>
|
||||||
|
*
|
||||||
|
* In this example the platform-specific {@link org.luaj.vm2.lib.jse.JseIoLib}
|
||||||
|
* library will be loaded, which will include the base functionality provided by
|
||||||
|
* this class, whereas the {@link org.luaj.vm2.lib.jse.JsePlatform} would load
|
||||||
|
* the {@link org.luaj.vm2.lib.jse.JseIoLib}.
|
||||||
|
* <p>
|
||||||
|
* To instantiate and use it directly, link it into your globals table via
|
||||||
|
* {@link LuaValue#load(LuaValue)} using code such as:
|
||||||
|
*
|
||||||
|
* <pre>
|
||||||
|
* {
|
||||||
|
* @code
|
||||||
|
* Globals globals = new Globals();
|
||||||
|
* globals.load(new JseBaseLib());
|
||||||
|
* globals.load(new PackageLib());
|
||||||
|
* globals.load(new OsLib());
|
||||||
|
* globals.get("io").get("write").call(LuaValue.valueOf("hello, world\n"));
|
||||||
|
* }
|
||||||
|
* </pre>
|
||||||
|
* <p>
|
||||||
|
* This has been implemented to match as closely as possible the behavior in the
|
||||||
|
* corresponding library in C.
|
||||||
|
*
|
||||||
|
* @see LibFunction
|
||||||
|
* @see org.luaj.vm2.lib.jse.JsePlatform
|
||||||
|
* @see org.luaj.vm2.lib.jme.JmePlatform
|
||||||
|
* @see org.luaj.vm2.lib.jse.JseIoLib
|
||||||
|
* @see org.luaj.vm2.lib.jme.JmeIoLib
|
||||||
|
* @see <a href=
|
||||||
|
* "http://www.lua.org/manual/5.1/manual.html#5.7">http://www.lua.org/manual/5.1/manual.html#5.7</a>
|
||||||
|
*/
|
||||||
|
public abstract 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();
|
||||||
|
|
||||||
|
// returns new position
|
||||||
|
public abstract int seek(String option, int bytecount) throws IOException;
|
||||||
|
|
||||||
|
public abstract void setvbuf(String mode, int size);
|
||||||
|
|
||||||
|
// get length remaining to read
|
||||||
|
public abstract int remaining() throws IOException;
|
||||||
|
|
||||||
|
// peek ahead one character
|
||||||
|
public abstract int peek() throws IOException, EOFException;
|
||||||
|
|
||||||
|
// return char if read, -1 if eof, throw IOException on other exception
|
||||||
|
public abstract int read() throws IOException, EOFException;
|
||||||
|
|
||||||
|
// return number of bytes read if positive, false if eof, throw IOException on other exception
|
||||||
|
public abstract int read(byte[] bytes, int offset, int length) throws IOException;
|
||||||
|
|
||||||
|
public boolean eof() throws IOException {
|
||||||
|
try {
|
||||||
|
return peek() < 0;
|
||||||
|
} catch (EOFException e) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// delegate method access to file methods table
|
||||||
|
@Override
|
||||||
|
public LuaValue get(LuaValue key) {
|
||||||
|
return filemethods.get(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
// essentially a userdata instance
|
||||||
|
@Override
|
||||||
|
public int type() {
|
||||||
|
return LuaValue.TUSERDATA;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String typename() {
|
||||||
|
return "userdata";
|
||||||
|
}
|
||||||
|
|
||||||
|
// displays as "file" type
|
||||||
|
@Override
|
||||||
|
public String tojstring() {
|
||||||
|
return "file: " + Integer.toHexString(hashCode());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void finalize() {
|
||||||
|
if (!isclosed()) {
|
||||||
|
try {
|
||||||
|
close();
|
||||||
|
} catch (IOException ignore) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Enumerated value representing stdin */
|
||||||
|
protected static final int FTYPE_STDIN = 0;
|
||||||
|
/** Enumerated value representing stdout */
|
||||||
|
protected static final int FTYPE_STDOUT = 1;
|
||||||
|
/** Enumerated value representing stderr */
|
||||||
|
protected static final int FTYPE_STDERR = 2;
|
||||||
|
/** Enumerated value representing a file type for a named file */
|
||||||
|
protected static final int FTYPE_NAMED = 3;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wrap the standard input.
|
||||||
|
*
|
||||||
|
* @return File
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
abstract protected File wrapStdin() throws IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wrap the standard output.
|
||||||
|
*
|
||||||
|
* @return File
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
abstract protected File wrapStdout() throws IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wrap the standard error output.
|
||||||
|
*
|
||||||
|
* @return File
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
abstract protected File wrapStderr() throws IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Open a file in a particular mode.
|
||||||
|
*
|
||||||
|
* @param filename
|
||||||
|
* @param readMode true if opening in read mode
|
||||||
|
* @param appendMode true if opening in append mode
|
||||||
|
* @param updateMode true if opening in update mode
|
||||||
|
* @param binaryMode true if opening in binary mode
|
||||||
|
* @return File object if successful
|
||||||
|
* @throws IOException if could not be opened
|
||||||
|
*/
|
||||||
|
abstract protected File openFile(String filename, boolean readMode, boolean appendMode, boolean updateMode,
|
||||||
|
boolean binaryMode) throws IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Open a temporary file.
|
||||||
|
*
|
||||||
|
* @return File object if successful
|
||||||
|
* @throws IOException if could not be opened
|
||||||
|
*/
|
||||||
|
abstract protected File tmpFile() throws IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Start a new process and return a file for input or output
|
||||||
|
*
|
||||||
|
* @param prog the program to execute
|
||||||
|
* @param mode "r" to read, "w" to write
|
||||||
|
* @return File to read to or write from
|
||||||
|
* @throws IOException if an i/o exception occurs
|
||||||
|
*/
|
||||||
|
abstract protected File openProgram(String prog, String mode) throws IOException;
|
||||||
|
|
||||||
|
private File infile = null;
|
||||||
|
private File outfile = null;
|
||||||
|
private File errfile = null;
|
||||||
|
|
||||||
|
private static final LuaValue STDIN = valueOf("stdin");
|
||||||
|
private static final LuaValue STDOUT = valueOf("stdout");
|
||||||
|
private static final LuaValue STDERR = valueOf("stderr");
|
||||||
|
private static final LuaValue FILE = valueOf("file");
|
||||||
|
private static final LuaValue CLOSED_FILE = valueOf("closed file");
|
||||||
|
|
||||||
|
private static final int IO_CLOSE = 0;
|
||||||
|
private static final int IO_FLUSH = 1;
|
||||||
|
private static final int IO_INPUT = 2;
|
||||||
|
private static final int IO_LINES = 3;
|
||||||
|
private static final int IO_OPEN = 4;
|
||||||
|
private static final int IO_OUTPUT = 5;
|
||||||
|
private static final int IO_POPEN = 6;
|
||||||
|
private static final int IO_READ = 7;
|
||||||
|
private static final int IO_TMPFILE = 8;
|
||||||
|
private static final int IO_TYPE = 9;
|
||||||
|
private static final int IO_WRITE = 10;
|
||||||
|
|
||||||
|
private static final int FILE_CLOSE = 11;
|
||||||
|
private static final int FILE_FLUSH = 12;
|
||||||
|
private static final int FILE_LINES = 13;
|
||||||
|
private static final int FILE_READ = 14;
|
||||||
|
private static final int FILE_SEEK = 15;
|
||||||
|
private static final int FILE_SETVBUF = 16;
|
||||||
|
private static final int FILE_WRITE = 17;
|
||||||
|
|
||||||
|
private static final int IO_INDEX = 18;
|
||||||
|
private static final int LINES_ITER = 19;
|
||||||
|
|
||||||
|
public static final String[] IO_NAMES = { "close", "flush", "input", "lines", "open", "output", "popen", "read",
|
||||||
|
"tmpfile", "type", "write", };
|
||||||
|
|
||||||
|
public static final String[] FILE_NAMES = { "close", "flush", "lines", "read", "seek", "setvbuf", "write", };
|
||||||
|
|
||||||
|
LuaTable filemethods;
|
||||||
|
|
||||||
|
protected Globals globals;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public LuaValue call(LuaValue modname, LuaValue env) {
|
||||||
|
globals = env.checkglobals();
|
||||||
|
|
||||||
|
// io lib functions
|
||||||
|
LuaTable t = new LuaTable();
|
||||||
|
bind(t, IoLibV.class, IO_NAMES);
|
||||||
|
|
||||||
|
// create file methods table
|
||||||
|
filemethods = new LuaTable();
|
||||||
|
bind(filemethods, IoLibV.class, FILE_NAMES, FILE_CLOSE);
|
||||||
|
|
||||||
|
// set up file metatable
|
||||||
|
LuaTable mt = new LuaTable();
|
||||||
|
bind(mt, IoLibV.class, new String[] { "__index" }, IO_INDEX);
|
||||||
|
t.setmetatable(mt);
|
||||||
|
|
||||||
|
// all functions link to library instance
|
||||||
|
setLibInstance(t);
|
||||||
|
setLibInstance(filemethods);
|
||||||
|
setLibInstance(mt);
|
||||||
|
|
||||||
|
// return the table
|
||||||
|
env.set("io", t);
|
||||||
|
if (!env.get("package").isnil())
|
||||||
|
env.get("package").get("loaded").set("io", t);
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setLibInstance(LuaTable t) {
|
||||||
|
LuaValue[] k = t.keys();
|
||||||
|
for (int i = 0, n = k.length; i < n; i++)
|
||||||
|
((IoLibV) t.get(k[i])).iolib = this;
|
||||||
|
}
|
||||||
|
|
||||||
|
static final class IoLibV extends VarArgFunction {
|
||||||
|
private File f;
|
||||||
|
public IoLib iolib;
|
||||||
|
private boolean toclose;
|
||||||
|
private Varargs args;
|
||||||
|
|
||||||
|
public IoLibV() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public IoLibV(File f, String name, int opcode, IoLib iolib, boolean toclose, Varargs args) {
|
||||||
|
this(f, name, opcode, iolib);
|
||||||
|
this.toclose = toclose;
|
||||||
|
this.args = args.dealias();
|
||||||
|
}
|
||||||
|
|
||||||
|
public IoLibV(File f, String name, int opcode, IoLib iolib) {
|
||||||
|
this.f = f;
|
||||||
|
this.name = name;
|
||||||
|
this.opcode = opcode;
|
||||||
|
this.iolib = iolib;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Varargs invoke(Varargs args) {
|
||||||
|
try {
|
||||||
|
switch (opcode) {
|
||||||
|
case IO_FLUSH:
|
||||||
|
return iolib._io_flush();
|
||||||
|
case IO_TMPFILE:
|
||||||
|
return iolib._io_tmpfile();
|
||||||
|
case IO_CLOSE:
|
||||||
|
return iolib._io_close(args.arg1());
|
||||||
|
case IO_INPUT:
|
||||||
|
return iolib._io_input(args.arg1());
|
||||||
|
case IO_OUTPUT:
|
||||||
|
return iolib._io_output(args.arg1());
|
||||||
|
case IO_TYPE:
|
||||||
|
return iolib._io_type(args.arg1());
|
||||||
|
case IO_POPEN:
|
||||||
|
return iolib._io_popen(args.checkjstring(1), args.optjstring(2, "r"));
|
||||||
|
case IO_OPEN:
|
||||||
|
return iolib._io_open(args.checkjstring(1), args.optjstring(2, "r"));
|
||||||
|
case IO_LINES:
|
||||||
|
return iolib._io_lines(args);
|
||||||
|
case IO_READ:
|
||||||
|
return iolib._io_read(args);
|
||||||
|
case IO_WRITE:
|
||||||
|
return iolib._io_write(args);
|
||||||
|
|
||||||
|
case FILE_CLOSE:
|
||||||
|
return iolib._file_close(args.arg1());
|
||||||
|
case FILE_FLUSH:
|
||||||
|
return iolib._file_flush(args.arg1());
|
||||||
|
case FILE_SETVBUF:
|
||||||
|
return iolib._file_setvbuf(args.arg1(), args.checkjstring(2), args.optint(3, 8192));
|
||||||
|
case FILE_LINES:
|
||||||
|
return iolib._file_lines(args);
|
||||||
|
case FILE_READ:
|
||||||
|
return iolib._file_read(args.arg1(), args.subargs(2));
|
||||||
|
case FILE_SEEK:
|
||||||
|
return iolib._file_seek(args.arg1(), args.optjstring(2, "cur"), args.optint(3, 0));
|
||||||
|
case FILE_WRITE:
|
||||||
|
return iolib._file_write(args.arg1(), args.subargs(2));
|
||||||
|
|
||||||
|
case IO_INDEX:
|
||||||
|
return iolib._io_index(args.arg(2));
|
||||||
|
case LINES_ITER:
|
||||||
|
return iolib._lines_iter(f, toclose, this.args);
|
||||||
|
}
|
||||||
|
} catch (IOException ioe) {
|
||||||
|
if (opcode == LINES_ITER) {
|
||||||
|
String s = ioe.getMessage();
|
||||||
|
error(s != null? s: ioe.toString());
|
||||||
|
}
|
||||||
|
return errorresult(ioe);
|
||||||
|
}
|
||||||
|
return NONE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private File input() {
|
||||||
|
return infile != null? infile: (infile = ioopenfile(FTYPE_STDIN, "-", "r"));
|
||||||
|
}
|
||||||
|
|
||||||
|
// io.flush() -> bool
|
||||||
|
public Varargs _io_flush() throws IOException {
|
||||||
|
checkopen(output());
|
||||||
|
outfile.flush();
|
||||||
|
return LuaValue.TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// io.tmpfile() -> file
|
||||||
|
public Varargs _io_tmpfile() throws IOException {
|
||||||
|
return tmpFile();
|
||||||
|
}
|
||||||
|
|
||||||
|
// io.close([file]) -> void
|
||||||
|
public Varargs _io_close(LuaValue file) throws IOException {
|
||||||
|
File f = file.isnil()? output(): checkfile(file);
|
||||||
|
checkopen(f);
|
||||||
|
return ioclose(f);
|
||||||
|
}
|
||||||
|
|
||||||
|
// io.input([file]) -> file
|
||||||
|
public Varargs _io_input(LuaValue file) {
|
||||||
|
infile = file.isnil()? input()
|
||||||
|
: file.isstring()? ioopenfile(FTYPE_NAMED, file.checkjstring(), "r"): checkfile(file);
|
||||||
|
return infile;
|
||||||
|
}
|
||||||
|
|
||||||
|
// io.output(filename) -> file
|
||||||
|
public Varargs _io_output(LuaValue filename) {
|
||||||
|
outfile = filename.isnil()? output()
|
||||||
|
: filename.isstring()? ioopenfile(FTYPE_NAMED, filename.checkjstring(), "w"): checkfile(filename);
|
||||||
|
return outfile;
|
||||||
|
}
|
||||||
|
|
||||||
|
// io.type(obj) -> "file" | "closed file" | nil
|
||||||
|
public Varargs _io_type(LuaValue obj) {
|
||||||
|
File f = optfile(obj);
|
||||||
|
return f != null? f.isclosed()? CLOSED_FILE: FILE: NIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// io.popen(prog, [mode]) -> file
|
||||||
|
public Varargs _io_popen(String prog, String mode) throws IOException {
|
||||||
|
if (!"r".equals(mode) && !"w".equals(mode))
|
||||||
|
argerror(2, "invalid value: '" + mode + "'; must be one of 'r' or 'w'");
|
||||||
|
return openProgram(prog, mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
// io.open(filename, [mode]) -> file | nil,err
|
||||||
|
public Varargs _io_open(String filename, String mode) throws IOException {
|
||||||
|
return rawopenfile(FTYPE_NAMED, filename, mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
// io.lines(filename, ...) -> iterator
|
||||||
|
public Varargs _io_lines(Varargs args) {
|
||||||
|
String filename = args.optjstring(1, null);
|
||||||
|
File infile = filename == null? input(): ioopenfile(FTYPE_NAMED, filename, "r");
|
||||||
|
checkopen(infile);
|
||||||
|
return lines(infile, filename != null, args.subargs(2));
|
||||||
|
}
|
||||||
|
|
||||||
|
// io.read(...) -> (...)
|
||||||
|
public Varargs _io_read(Varargs args) throws IOException {
|
||||||
|
checkopen(input());
|
||||||
|
return ioread(infile, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
// io.write(...) -> void
|
||||||
|
public Varargs _io_write(Varargs args) throws IOException {
|
||||||
|
checkopen(output());
|
||||||
|
return iowrite(outfile, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
// file:close() -> void
|
||||||
|
public Varargs _file_close(LuaValue file) throws IOException {
|
||||||
|
return ioclose(checkfile(file));
|
||||||
|
}
|
||||||
|
|
||||||
|
// file:flush() -> void
|
||||||
|
public Varargs _file_flush(LuaValue file) throws IOException {
|
||||||
|
checkfile(file).flush();
|
||||||
|
return LuaValue.TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// file:setvbuf(mode,[size]) -> void
|
||||||
|
public Varargs _file_setvbuf(LuaValue file, String mode, int size) {
|
||||||
|
if ("no".equals(mode)) {
|
||||||
|
} else if ("full".equals(mode)) {
|
||||||
|
} else if ("line".equals(mode)) {
|
||||||
|
} else {
|
||||||
|
argerror(1, "invalid value: '" + mode + "'; must be one of 'no', 'full' or 'line'");
|
||||||
|
}
|
||||||
|
checkfile(file).setvbuf(mode, size);
|
||||||
|
return LuaValue.TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// file:lines(...) -> iterator
|
||||||
|
public Varargs _file_lines(Varargs args) {
|
||||||
|
return lines(checkfile(args.arg1()), false, args.subargs(2));
|
||||||
|
}
|
||||||
|
|
||||||
|
// file:read(...) -> (...)
|
||||||
|
public Varargs _file_read(LuaValue file, Varargs subargs) throws IOException {
|
||||||
|
return ioread(checkfile(file), subargs);
|
||||||
|
}
|
||||||
|
|
||||||
|
// file:seek([whence][,offset]) -> pos | nil,error
|
||||||
|
public Varargs _file_seek(LuaValue file, String whence, int offset) throws IOException {
|
||||||
|
if ("set".equals(whence)) {
|
||||||
|
} else if ("end".equals(whence)) {
|
||||||
|
} else if ("cur".equals(whence)) {
|
||||||
|
} else {
|
||||||
|
argerror(1, "invalid value: '" + whence + "'; must be one of 'set', 'cur' or 'end'");
|
||||||
|
}
|
||||||
|
return valueOf(checkfile(file).seek(whence, offset));
|
||||||
|
}
|
||||||
|
|
||||||
|
// file:write(...) -> void
|
||||||
|
public Varargs _file_write(LuaValue file, Varargs subargs) throws IOException {
|
||||||
|
return iowrite(checkfile(file), subargs);
|
||||||
|
}
|
||||||
|
|
||||||
|
// __index, returns a field
|
||||||
|
public Varargs _io_index(LuaValue v) {
|
||||||
|
return v.equals(STDOUT)? output(): v.equals(STDIN)? input(): v.equals(STDERR)? errput(): NIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// lines iterator(s,var) -> var'
|
||||||
|
public Varargs _lines_iter(LuaValue file, boolean toclose, Varargs args) throws IOException {
|
||||||
|
File f = optfile(file);
|
||||||
|
if (f == null)
|
||||||
|
argerror(1, "not a file: " + file);
|
||||||
|
if (f.isclosed())
|
||||||
|
error("file is already closed");
|
||||||
|
Varargs ret = ioread(f, args);
|
||||||
|
if (toclose && ret.isnil(1) && f.eof())
|
||||||
|
f.close();
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
private File output() {
|
||||||
|
return outfile != null? outfile: (outfile = ioopenfile(FTYPE_STDOUT, "-", "w"));
|
||||||
|
}
|
||||||
|
|
||||||
|
private File errput() {
|
||||||
|
return errfile != null? errfile: (errfile = ioopenfile(FTYPE_STDERR, "-", "w"));
|
||||||
|
}
|
||||||
|
|
||||||
|
private File ioopenfile(int filetype, String filename, String mode) {
|
||||||
|
try {
|
||||||
|
return rawopenfile(filetype, filename, mode);
|
||||||
|
} catch (Exception e) {
|
||||||
|
error("io error: " + e.getMessage());
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Varargs ioclose(File f) throws IOException {
|
||||||
|
if (f.isstdfile())
|
||||||
|
return errorresult("cannot close standard file");
|
||||||
|
else {
|
||||||
|
f.close();
|
||||||
|
return successresult();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Varargs successresult() {
|
||||||
|
return LuaValue.TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Varargs errorresult(Exception ioe) {
|
||||||
|
String s = ioe.getMessage();
|
||||||
|
return errorresult("io error: " + (s != null? s: ioe.toString()));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Varargs errorresult(String errortext) {
|
||||||
|
return varargsOf(NIL, valueOf(errortext));
|
||||||
|
}
|
||||||
|
|
||||||
|
private Varargs lines(final File f, boolean toclose, Varargs args) {
|
||||||
|
try {
|
||||||
|
return new IoLibV(f, "lnext", LINES_ITER, this, toclose, args);
|
||||||
|
} catch (Exception e) {
|
||||||
|
return error("lines: " + e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Varargs iowrite(File f, Varargs args) throws IOException {
|
||||||
|
for (int i = 1, n = args.narg(); i <= n; i++)
|
||||||
|
f.write(args.checkstring(i));
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Varargs ioread(File f, Varargs args) throws IOException {
|
||||||
|
int i, n = args.narg();
|
||||||
|
if (n == 0)
|
||||||
|
return freadline(f, false);
|
||||||
|
LuaValue[] v = new LuaValue[n];
|
||||||
|
LuaValue ai, vi;
|
||||||
|
LuaString fmt;
|
||||||
|
for (i = 0; i < n;) {
|
||||||
|
item: switch ((ai = args.arg(i+1)).type()) {
|
||||||
|
case LuaValue.TNUMBER:
|
||||||
|
vi = freadbytes(f, ai.toint());
|
||||||
|
break item;
|
||||||
|
case LuaValue.TSTRING:
|
||||||
|
fmt = ai.checkstring();
|
||||||
|
if (fmt.m_length >= 2 && fmt.m_bytes[fmt.m_offset] == '*') {
|
||||||
|
switch (fmt.m_bytes[fmt.m_offset+1]) {
|
||||||
|
case 'n':
|
||||||
|
vi = freadnumber(f);
|
||||||
|
break item;
|
||||||
|
case 'l':
|
||||||
|
vi = freadline(f, false);
|
||||||
|
break item;
|
||||||
|
case 'L':
|
||||||
|
vi = freadline(f, true);
|
||||||
|
break item;
|
||||||
|
case 'a':
|
||||||
|
vi = freadall(f);
|
||||||
|
break item;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return argerror(i+1, "(invalid format)");
|
||||||
|
}
|
||||||
|
if ((v[i++] = vi).isnil())
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return i == 0? NIL: varargsOf(v, 0, i);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static File checkfile(LuaValue val) {
|
||||||
|
File f = optfile(val);
|
||||||
|
if (f == null)
|
||||||
|
argerror(1, "file");
|
||||||
|
checkopen(f);
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static File optfile(LuaValue val) {
|
||||||
|
return (val instanceof File)? (File) val: null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static File checkopen(File file) {
|
||||||
|
if (file.isclosed())
|
||||||
|
error("attempt to use a closed file");
|
||||||
|
return file;
|
||||||
|
}
|
||||||
|
|
||||||
|
private File rawopenfile(int filetype, String filename, String mode) throws IOException {
|
||||||
|
int len = mode.length();
|
||||||
|
for (int i = 0; i < len; i++) { // [rwa][+]?b*
|
||||||
|
char ch = mode.charAt(i);
|
||||||
|
if ((i == 0 && "rwa".indexOf(ch) >= 0) || (i == 1 && ch == '+'))
|
||||||
|
continue;
|
||||||
|
if (i >= 1 && ch == 'b')
|
||||||
|
continue;
|
||||||
|
len = -1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (len <= 0)
|
||||||
|
argerror(2, "invalid mode: '" + mode + "'");
|
||||||
|
|
||||||
|
switch (filetype) {
|
||||||
|
case FTYPE_STDIN:
|
||||||
|
return wrapStdin();
|
||||||
|
case FTYPE_STDOUT:
|
||||||
|
return wrapStdout();
|
||||||
|
case FTYPE_STDERR:
|
||||||
|
return wrapStderr();
|
||||||
|
}
|
||||||
|
boolean isreadmode = mode.startsWith("r");
|
||||||
|
boolean isappend = mode.startsWith("a");
|
||||||
|
boolean isupdate = mode.indexOf('+') > 0;
|
||||||
|
boolean isbinary = mode.endsWith("b");
|
||||||
|
return openFile(filename, isreadmode, isappend, isupdate, isbinary);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------------- file reading utilitied ------------------
|
||||||
|
|
||||||
|
public static LuaValue freadbytes(File f, int count) throws IOException {
|
||||||
|
if (count == 0)
|
||||||
|
return f.eof()? NIL: EMPTYSTRING;
|
||||||
|
byte[] b = new byte[count];
|
||||||
|
int r;
|
||||||
|
if ((r = f.read(b, 0, b.length)) < 0)
|
||||||
|
return NIL;
|
||||||
|
return LuaString.valueUsing(b, 0, r);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static LuaValue freaduntil(File f, boolean lineonly, boolean withend) throws IOException {
|
||||||
|
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||||
|
int c;
|
||||||
|
try {
|
||||||
|
if (lineonly) {
|
||||||
|
loop: while ( (c = f.read()) >= 0 ) {
|
||||||
|
switch (c) {
|
||||||
|
case '\r':
|
||||||
|
if (withend)
|
||||||
|
baos.write(c);
|
||||||
|
break;
|
||||||
|
case '\n':
|
||||||
|
if (withend)
|
||||||
|
baos.write(c);
|
||||||
|
break loop;
|
||||||
|
default:
|
||||||
|
baos.write(c);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
while ( (c = f.read()) >= 0 )
|
||||||
|
baos.write(c);
|
||||||
|
}
|
||||||
|
} catch (EOFException e) {
|
||||||
|
c = -1;
|
||||||
|
}
|
||||||
|
return (c < 0 && baos.size() == 0)? (LuaValue) NIL: (LuaValue) LuaString.valueUsing(baos.toByteArray());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static LuaValue freadline(File f, boolean withend) throws IOException {
|
||||||
|
return freaduntil(f, true, withend);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static LuaValue freadall(File f) throws IOException {
|
||||||
|
int n = f.remaining();
|
||||||
|
if (n >= 0) {
|
||||||
|
return n == 0? EMPTYSTRING: freadbytes(f, n);
|
||||||
|
} else {
|
||||||
|
return freaduntil(f, false, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static LuaValue freadnumber(File f) throws IOException {
|
||||||
|
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||||
|
freadchars(f, " \t\r\n", null);
|
||||||
|
freadchars(f, "-+", baos);
|
||||||
|
//freadchars(f,"0",baos);
|
||||||
|
//freadchars(f,"xX",baos);
|
||||||
|
freadchars(f, "0123456789", baos);
|
||||||
|
freadchars(f, ".", baos);
|
||||||
|
freadchars(f, "0123456789", baos);
|
||||||
|
//freadchars(f,"eEfFgG",baos);
|
||||||
|
// freadchars(f,"+-",baos);
|
||||||
|
//freadchars(f,"0123456789",baos);
|
||||||
|
String s = baos.toString();
|
||||||
|
return s.length() > 0? valueOf(Double.parseDouble(s)): NIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void freadchars(File f, String chars, ByteArrayOutputStream baos) throws IOException {
|
||||||
|
int c;
|
||||||
|
while ( true ) {
|
||||||
|
c = f.peek();
|
||||||
|
if (chars.indexOf(c) < 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
f.read();
|
||||||
|
if (baos != null)
|
||||||
|
baos.write(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -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"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"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,85 +152,112 @@ abstract public class LibFunction extends LuaFunction {
|
|||||||
protected LibFunction() {
|
protected LibFunction() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public String tojstring() {
|
public String tojstring() {
|
||||||
return name != null? name: super.tojstring();
|
return name != null? "function: " + name: super.tojstring();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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.
|
||||||
* @see #bind(LuaValue, Class, String[], int)
|
* @see #bind(LuaValue, Class, String[], int)
|
||||||
*/
|
*/
|
||||||
protected void bind(LuaValue env, Class factory, String[] names ) {
|
protected void bind(LuaValue env, Class factory, String[] names) {
|
||||||
bind( env, factory, names, 0 );
|
bind(env, factory, names, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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.
|
||||||
* @param firstopcode the first opcode to use
|
* @param firstopcode the first opcode to use
|
||||||
* @see #bind(LuaValue, Class, String[])
|
* @see #bind(LuaValue, Class, String[])
|
||||||
*/
|
*/
|
||||||
protected void bind(LuaValue env, Class factory, String[] names, int firstopcode ) {
|
protected void bind(LuaValue env, Class factory, String[] names, int firstopcode) {
|
||||||
try {
|
try {
|
||||||
for ( int i=0, n=names.length; i<n; i++ ) {
|
for (int i = 0, n = names.length; i < n; i++) {
|
||||||
LibFunction f = (LibFunction) factory.newInstance();
|
LibFunction f = (LibFunction) factory.newInstance();
|
||||||
f.opcode = firstopcode + i;
|
f.opcode = firstopcode+i;
|
||||||
f.name = names[i];
|
f.name = names[i];
|
||||||
env.set(f.name, f);
|
env.set(f.name, f);
|
||||||
}
|
}
|
||||||
} catch ( Exception e ) {
|
} catch (Exception e) {
|
||||||
throw new LuaError( "bind failed: "+e );
|
throw new LuaError("bind failed: " + e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Java code generation utility to allocate storage for upvalue, leave it empty */
|
/**
|
||||||
|
* Java code generation utility to allocate storage for upvalue, leave it
|
||||||
|
* empty
|
||||||
|
*/
|
||||||
protected static LuaValue[] newupe() {
|
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");
|
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));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -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,60 +48,82 @@ 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>
|
||||||
|
* {
|
||||||
|
* @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>
|
||||||
|
* {
|
||||||
|
* @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());
|
||||||
math.set("ceil", new ceil());
|
math.set("ceil", new ceil());
|
||||||
math.set("cos", new cos());
|
math.set("cos", new cos());
|
||||||
@@ -110,12 +132,12 @@ public class MathLib extends TwoArgFunction {
|
|||||||
math.set("floor", new floor());
|
math.set("floor", new floor());
|
||||||
math.set("fmod", new fmod());
|
math.set("fmod", new fmod());
|
||||||
math.set("frexp", new frexp());
|
math.set("frexp", new frexp());
|
||||||
math.set("huge", LuaDouble.POSINF );
|
math.set("huge", LuaDouble.POSINF);
|
||||||
math.set("ldexp", new ldexp());
|
math.set("ldexp", new ldexp());
|
||||||
math.set("max", new max());
|
math.set("max", new max());
|
||||||
math.set("min", new min());
|
math.set("min", new min());
|
||||||
math.set("modf", new modf());
|
math.set("modf", new modf());
|
||||||
math.set("pi", Math.PI );
|
math.set("pi", Math.PI);
|
||||||
math.set("pow", new pow());
|
math.set("pow", new pow());
|
||||||
random r;
|
random r;
|
||||||
math.set("random", r = new random());
|
math.set("random", r = new random());
|
||||||
@@ -125,124 +147,204 @@ 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);
|
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 BinaryOp {
|
static final class fmod extends TwoArgFunction {
|
||||||
protected double call(double x, double y) {
|
@Override
|
||||||
double q = x/y;
|
public LuaValue call(LuaValue xv, LuaValue yv) {
|
||||||
return x - y * (q>=0? Math.floor(q): Math.ceil(q));
|
if (yv.checkdouble() == 0.0d)
|
||||||
|
return LuaDouble.NAN;
|
||||||
|
if (xv.islong() && yv.islong()) {
|
||||||
|
return valueOf(xv.tolong()%yv.tolong());
|
||||||
|
}
|
||||||
|
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)
|
||||||
long bits = Double.doubleToLongBits( x );
|
return varargsOf(ZERO, ZERO);
|
||||||
double m = ((bits & (~(-1L<<52))) + (1L<<52)) * ((bits >= 0)? (.5 / (1L<<52)): (-.5 / (1L<<52)));
|
long bits = Double.doubleToLongBits(x);
|
||||||
double e = (((int) (bits >> 52)) & 0x7ff) - 1022;
|
double m = ((bits & ~(-1L<<52))+(1L<<52))*(bits >= 0? .5/(1L<<52): -.5/(1L<<52));
|
||||||
return varargsOf( valueOf(m), valueOf(e) );
|
double e = ((int) (bits>>52) & 0x7ff)-1022;
|
||||||
|
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) {
|
||||||
double m = args.checkdouble(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) {
|
||||||
m = Math.max(m,args.checkdouble(i));
|
LuaValue v = args.checknumber(i);
|
||||||
return valueOf(m);
|
if (m.lt_b(v))
|
||||||
|
m = v;
|
||||||
|
}
|
||||||
|
return m;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static class min extends VarArgFunction {
|
static class min extends VarArgFunction {
|
||||||
|
@Override
|
||||||
public Varargs invoke(Varargs args) {
|
public Varargs invoke(Varargs args) {
|
||||||
double m = args.checkdouble(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) {
|
||||||
m = Math.min(m,args.checkdouble(i));
|
LuaValue v = args.checknumber(i);
|
||||||
return valueOf(m);
|
if (v.lt_b(m))
|
||||||
|
m = v;
|
||||||
|
}
|
||||||
|
return m;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static class modf extends VarArgFunction {
|
static class modf extends VarArgFunction {
|
||||||
|
@Override
|
||||||
public Varargs invoke(Varargs args) {
|
public Varargs invoke(Varargs args) {
|
||||||
double x = args.checkdouble(1);
|
LuaValue n = args.arg1();
|
||||||
double intPart = ( x > 0 ) ? Math.floor( x ) : Math.ceil( x );
|
/* number is its own integer part, no fractional part */
|
||||||
double fracPart = x - intPart;
|
if (n.islong())
|
||||||
return varargsOf( valueOf(intPart), valueOf(fracPart) );
|
return varargsOf(n.tonumber(), valueOf(0.0));
|
||||||
|
double x = n.checkdouble();
|
||||||
|
/* integer part (rounds toward zero) */
|
||||||
|
double intPart = x > 0? Math.floor(x): Math.ceil(x);
|
||||||
|
/* fractional part (test needed for inf/-inf) */
|
||||||
|
double fracPart = x == intPart? 0.0: x-intPart;
|
||||||
|
return varargsOf(valueOf(intPart), valueOf(fracPart));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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)
|
||||||
return valueOf( 1 + random.nextInt(m) );
|
argerror(1, "interval is empty");
|
||||||
|
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)
|
||||||
return valueOf( m + random.nextInt(n+1-m) );
|
argerror(2, "interval is empty");
|
||||||
|
return valueOf(m+random.nextInt(n+1-m));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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);
|
||||||
@@ -250,42 +352,41 @@ public class MathLib extends TwoArgFunction {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** compute power using installed math library, or default if there is no math library installed */
|
/**
|
||||||
|
* compute power using installed math library, or default if there is no
|
||||||
|
* math library installed
|
||||||
|
*/
|
||||||
public static LuaValue dpow(double a, double b) {
|
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Hook to override default dpow behavior with faster implementation.
|
* Hook to override default dpow behavior with faster implementation.
|
||||||
*/
|
*/
|
||||||
public double dpow_lib(double a, double b) {
|
public double dpow_lib(double a, double b) {
|
||||||
return dpow_default(a,b);
|
return dpow_default(a, b);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Default JME version computes using longhand heuristics.
|
* Default JME version computes using longhand heuristics.
|
||||||
*/
|
*/
|
||||||
protected static double dpow_default(double a, double b) {
|
protected static double dpow_default(double a, double b) {
|
||||||
if ( b < 0 )
|
if (b < 0)
|
||||||
return 1 / dpow_default( a, -b );
|
return 1/dpow_default(a, -b);
|
||||||
double p = 1;
|
double p = 1;
|
||||||
int whole = (int) b;
|
int whole = (int) b;
|
||||||
for ( double v=a; whole > 0; whole>>=1, v*=v )
|
for (double v = a; whole > 0; whole >>= 1, v *= v)
|
||||||
if ( (whole & 1) != 0 )
|
if ((whole & 1) != 0)
|
||||||
p *= v;
|
p *= v;
|
||||||
if ( (b -= whole) > 0 ) {
|
if ((b -= whole) > 0) {
|
||||||
int frac = (int) (0x10000 * b);
|
int frac = (int) (0x10000*b);
|
||||||
for ( ; (frac&0xffff)!=0; frac<<=1 ) {
|
for (; (frac & 0xffff) != 0; frac <<= 1) {
|
||||||
a = Math.sqrt(a);
|
a = Math.sqrt(a);
|
||||||
if ( (frac & 0x8000) != 0 )
|
if ((frac & 0x8000) != 0)
|
||||||
p *= a;
|
p *= a;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -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());
|
||||||
}
|
}
|
||||||
522
luaj-core/src/main/java/org/luaj/vm2/lib/OsLib.java
Normal file
522
luaj-core/src/main/java/org/luaj/vm2/lib/OsLib.java
Normal 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>
|
||||||
|
* {
|
||||||
|
* @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>
|
||||||
|
* {
|
||||||
|
* @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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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,73 +32,94 @@ 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>
|
||||||
|
* {
|
||||||
|
* @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
|
||||||
public static String DEFAULT_LUA_PATH;
|
* system property <code>"luaj.package.path"</code>, and is
|
||||||
|
* <code>"?.lua"</code> by default.
|
||||||
|
*/
|
||||||
|
public static final String DEFAULT_LUA_PATH;
|
||||||
static {
|
static {
|
||||||
|
String path = null;
|
||||||
try {
|
try {
|
||||||
DEFAULT_LUA_PATH = System.getProperty("luaj.package.path");
|
path = System.getProperty("luaj.package.path");
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
System.out.println(e.toString());
|
System.out.println(e.toString());
|
||||||
}
|
}
|
||||||
if (DEFAULT_LUA_PATH == null)
|
if (path == null) {
|
||||||
DEFAULT_LUA_PATH = "?.lua";
|
path = "?.lua";
|
||||||
|
}
|
||||||
|
DEFAULT_LUA_PATH = path;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final LuaString _LOADED = valueOf("loaded");
|
static final LuaString _LOADED = valueOf("loaded");
|
||||||
private static final LuaString _LOADLIB = valueOf("loadlib");
|
private static final LuaString _LOADLIB = valueOf("loadlib");
|
||||||
private static final LuaString _PRELOAD = valueOf("preload");
|
static final LuaString _PRELOAD = valueOf("preload");
|
||||||
private static final LuaString _PATH = valueOf("path");
|
static final LuaString _PATH = valueOf("path");
|
||||||
private static final LuaString _SEARCHPATH = valueOf("searchpath");
|
static final LuaString _SEARCHPATH = valueOf("searchpath");
|
||||||
private 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;
|
||||||
@@ -108,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());
|
||||||
@@ -136,11 +168,13 @@ 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());
|
||||||
searchers.set(3, java_searcher = new java_searcher());
|
searchers.set(3, java_searcher = new java_searcher());
|
||||||
package_.set(_SEARCHERS, searchers);
|
package_.set(_SEARCHERS, searchers);
|
||||||
|
package_.set("config", FILE_SEP + "\n;\n?\n!\n-\n");
|
||||||
package_.get(_LOADED).set("package", package_);
|
package_.get(_LOADED).set("package", package_);
|
||||||
env.set("package", package_);
|
env.set("package", package_);
|
||||||
globals.package_ = this;
|
globals.package_ = this;
|
||||||
@@ -152,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";
|
||||||
}
|
}
|
||||||
@@ -168,38 +204,44 @@ 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 {
|
||||||
public LuaValue call( LuaValue arg ) {
|
@Override
|
||||||
|
public LuaValue call(LuaValue arg) {
|
||||||
LuaString name = arg.checkstring();
|
LuaString name = arg.checkstring();
|
||||||
LuaValue loaded = package_.get(_LOADED);
|
LuaValue loaded = package_.get(_LOADED);
|
||||||
LuaValue result = loaded.get(name);
|
LuaValue result = loaded.get(name);
|
||||||
if ( result.toboolean() ) {
|
if (result.toboolean()) {
|
||||||
if ( result == _SENTINEL )
|
if (result == _SENTINEL)
|
||||||
error("loop or previous error loading module '"+name+"'");
|
error("loop or previous error loading module '" + name + "'");
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -207,56 +249,56 @@ public class PackageLib extends TwoArgFunction {
|
|||||||
LuaTable tbl = package_.get(_SEARCHERS).checktable();
|
LuaTable tbl = package_.get(_SEARCHERS).checktable();
|
||||||
StringBuffer sb = new StringBuffer();
|
StringBuffer sb = new StringBuffer();
|
||||||
Varargs loader = null;
|
Varargs loader = null;
|
||||||
for ( int i=1; true; i++ ) {
|
for (int i = 1; true; i++) {
|
||||||
LuaValue searcher = tbl.get(i);
|
LuaValue searcher = tbl.get(i);
|
||||||
if ( searcher.isnil() ) {
|
if (searcher.isnil()) {
|
||||||
error( "module '"+name+"' not found: "+name+sb );
|
error("module '" + name + "' not found: " + name + sb);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* call loader with module name as argument */
|
/* call loader with module name as argument */
|
||||||
loader = searcher.invoke(name);
|
loader = searcher.invoke(name);
|
||||||
if ( loader.isfunction(1) )
|
if (loader.isfunction(1))
|
||||||
break;
|
break;
|
||||||
if ( loader.isstring(1) )
|
if (loader.isstring(1))
|
||||||
sb.append( loader.tojstring(1) );
|
sb.append(loader.tojstring(1));
|
||||||
}
|
}
|
||||||
|
|
||||||
// load the module using the loader
|
// load the module using the loader
|
||||||
loaded.set(name, _SENTINEL);
|
loaded.set(name, _SENTINEL);
|
||||||
result = loader.arg1().call(name, loader.arg(2));
|
result = loader.arg1().call(name, loader.arg(2));
|
||||||
if ( ! result.isnil() )
|
if (!result.isnil())
|
||||||
loaded.set( name, result );
|
loaded.set(name, result);
|
||||||
else if ( (result = loaded.get(name)) == _SENTINEL )
|
else if ((result = loaded.get(name)) == _SENTINEL)
|
||||||
loaded.set( name, result = LuaValue.TRUE );
|
loaded.set(name, result = LuaValue.TRUE);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class loadlib extends VarArgFunction {
|
public static class loadlib extends VarArgFunction {
|
||||||
public Varargs loadlib( Varargs args ) {
|
@Override
|
||||||
|
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"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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);
|
||||||
InputStream is = null;
|
|
||||||
|
|
||||||
// get package path
|
// get package path
|
||||||
LuaValue path = package_.get(_PATH);
|
LuaValue path = package_.get(_PATH);
|
||||||
if ( ! path.isstring() )
|
if (!path.isstring())
|
||||||
return valueOf("package.path is not a string");
|
return valueOf("package.path is not a string");
|
||||||
|
|
||||||
// get the searchpath function.
|
// get the searchpath function.
|
||||||
@@ -269,15 +311,16 @@ public class PackageLib extends TwoArgFunction {
|
|||||||
|
|
||||||
// Try to load the file.
|
// Try to load the file.
|
||||||
v = globals.loadfile(filename.tojstring());
|
v = globals.loadfile(filename.tojstring());
|
||||||
if ( v.arg1().isfunction() )
|
if (v.arg1().isfunction())
|
||||||
return LuaValue.varargsOf(v.arg1(), filename);
|
return LuaValue.varargsOf(v.arg1(), filename);
|
||||||
|
|
||||||
// report error
|
// report error
|
||||||
return varargsOf(NIL, valueOf("'"+filename+"': "+v.arg(2).tojstring()));
|
return varargsOf(NIL, valueOf("'" + filename + "': " + v.arg(2).tojstring()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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);
|
||||||
@@ -293,80 +336,92 @@ public class PackageLib extends TwoArgFunction {
|
|||||||
|
|
||||||
// find next template
|
// find next template
|
||||||
int b = e+1;
|
int b = e+1;
|
||||||
e = path.indexOf(';',b);
|
e = path.indexOf(';', b);
|
||||||
if ( e < 0 )
|
if (e < 0)
|
||||||
e = path.length();
|
e = path.length();
|
||||||
String template = path.substring(b,e);
|
String template = path.substring(b, e);
|
||||||
|
|
||||||
// create filename
|
// create filename
|
||||||
int q = template.indexOf('?');
|
int q = template.indexOf('?');
|
||||||
String filename = template;
|
String filename = template;
|
||||||
if ( q >= 0 ) {
|
if (q >= 0) {
|
||||||
filename = template.substring(0,q) + name + template.substring(q+1);
|
filename = template.substring(0, q)+name+template.substring(q+1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
// report error
|
// report error
|
||||||
if ( sb == null )
|
if (sb == null)
|
||||||
sb = new StringBuffer();
|
sb = new StringBuffer();
|
||||||
sb.append( "\n\t"+filename );
|
sb.append("\n\t" + filename);
|
||||||
}
|
}
|
||||||
return varargsOf(NIL, valueOf(sb.toString()));
|
return varargsOf(NIL, valueOf(sb.toString()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
Class c = null;
|
Class c = null;
|
||||||
LuaValue v = null;
|
LuaValue v = null;
|
||||||
try {
|
try {
|
||||||
c = Class.forName(classname);
|
c = Class.forName(classname);
|
||||||
v = (LuaValue) c.newInstance();
|
v = (LuaValue) c.newInstance();
|
||||||
if (v.isfunction())
|
if (v.isfunction())
|
||||||
((LuaFunction)v).initupvalue1(globals);
|
((LuaFunction) v).initupvalue1(globals);
|
||||||
return varargsOf(v, globals);
|
return varargsOf(v, globals);
|
||||||
} catch ( ClassNotFoundException cnfe ) {
|
} catch (ClassNotFoundException cnfe) {
|
||||||
return valueOf("\n\tno class '"+classname+"'" );
|
return valueOf("\n\tno class '" + classname + "'");
|
||||||
} catch ( Exception e ) {
|
} catch (Exception e) {
|
||||||
return valueOf("\n\tjava load failed on '"+classname+"', "+e );
|
return valueOf("\n\tjava load failed on '" + classname + "', " + e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Convert lua filename to valid class name */
|
/** Convert lua filename to valid class name */
|
||||||
public static final String toClassname( String filename ) {
|
public static final String toClassname(String filename) {
|
||||||
int n=filename.length();
|
int n = filename.length();
|
||||||
int j=n;
|
int j = n;
|
||||||
if ( filename.endsWith(".lua") )
|
if (filename.endsWith(".lua"))
|
||||||
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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return n==j? filename: filename.substring(0,j);
|
return n == j? filename: filename.substring(0, j);
|
||||||
}
|
}
|
||||||
|
|
||||||
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 '.':
|
||||||
case '$':
|
case '$':
|
||||||
case '_':
|
case '_':
|
||||||
@@ -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);
|
||||||
}
|
}
|
||||||
@@ -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.LuaClosure;
|
import org.luaj.vm2.*;
|
||||||
import org.luaj.vm2.Buffer;
|
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;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -49,7 +45,7 @@ import org.luaj.vm2.compiler.DumpState;
|
|||||||
* 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 StringLib());
|
* globals.load(new JseStringLib());
|
||||||
* System.out.println( globals.get("string").get("upper").call( LuaValue.valueOf("abcde") ) );
|
* System.out.println( globals.get("string").get("upper").call( LuaValue.valueOf("abcde") ) );
|
||||||
* } </pre>
|
* } </pre>
|
||||||
* <p>
|
* <p>
|
||||||
@@ -83,8 +79,8 @@ public class StringLib extends TwoArgFunction {
|
|||||||
*/
|
*/
|
||||||
public LuaValue call(LuaValue modname, LuaValue env) {
|
public LuaValue call(LuaValue modname, LuaValue env) {
|
||||||
LuaTable string = new LuaTable();
|
LuaTable string = new LuaTable();
|
||||||
string.set("byte", new byte_());
|
string.set("byte", new _byte());
|
||||||
string.set("char", new char_());
|
string.set("char", new _char());
|
||||||
string.set("dump", new dump());
|
string.set("dump", new dump());
|
||||||
string.set("find", new find());
|
string.set("find", new find());
|
||||||
string.set("format", new format());
|
string.set("format", new format());
|
||||||
@@ -97,12 +93,12 @@ public class StringLib extends TwoArgFunction {
|
|||||||
string.set("reverse", new reverse());
|
string.set("reverse", new reverse());
|
||||||
string.set("sub", new sub());
|
string.set("sub", new sub());
|
||||||
string.set("upper", new upper());
|
string.set("upper", new upper());
|
||||||
LuaTable mt = LuaValue.tableOf(
|
|
||||||
new LuaValue[] { INDEX, string });
|
|
||||||
env.set("string", string);
|
env.set("string", string);
|
||||||
env.get("package").get("loaded").set("string", string);
|
if (!env.get("package").isnil()) env.get("package").get("loaded").set("string", string);
|
||||||
if (LuaString.s_metatable == null)
|
if (LuaString.s_metatable == null) {
|
||||||
LuaString.s_metatable = mt;
|
LuaString.s_metatable = LuaValue.tableOf(new LuaValue[] { INDEX, string });
|
||||||
|
}
|
||||||
return string;
|
return string;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -117,7 +113,7 @@ public class StringLib extends TwoArgFunction {
|
|||||||
*
|
*
|
||||||
* @param args the calling args
|
* @param args the calling args
|
||||||
*/
|
*/
|
||||||
static final class byte_ extends VarArgFunction {
|
static final class _byte extends VarArgFunction {
|
||||||
public Varargs invoke(Varargs args) {
|
public Varargs invoke(Varargs args) {
|
||||||
LuaString s = args.checkstring(1);
|
LuaString s = args.checkstring(1);
|
||||||
int l = s.m_length;
|
int l = s.m_length;
|
||||||
@@ -148,13 +144,13 @@ public class StringLib extends TwoArgFunction {
|
|||||||
*
|
*
|
||||||
* @param args the calling VM
|
* @param args the calling VM
|
||||||
*/
|
*/
|
||||||
static final class char_ extends VarArgFunction {
|
static final class _char extends VarArgFunction {
|
||||||
public Varargs invoke(Varargs args) {
|
public Varargs invoke(Varargs args) {
|
||||||
int n = args.narg();
|
int n = args.narg();
|
||||||
byte[] bytes = new byte[n];
|
byte[] bytes = new byte[n];
|
||||||
for ( int i=0, a=1; i<n; i++, a++ ) {
|
for ( int i=0, a=1; i<n; i++, a++ ) {
|
||||||
int c = args.checkint(a);
|
int c = args.checkint(a);
|
||||||
if (c<0 || c>=256) argerror(a, "invalid value");
|
if (c<0 || c>=256) argerror(a, "invalid value for string.char [0; 255]: " + c);
|
||||||
bytes[i] = (byte) c;
|
bytes[i] = (byte) c;
|
||||||
}
|
}
|
||||||
return LuaString.valueUsing( bytes );
|
return LuaString.valueUsing( bytes );
|
||||||
@@ -162,20 +158,22 @@ public class StringLib extends TwoArgFunction {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* string.dump (function)
|
* string.dump (function[, stripDebug])
|
||||||
*
|
*
|
||||||
* Returns a string containing a binary representation of the given function,
|
* Returns a string containing a binary representation of the given function,
|
||||||
* so that a later loadstring on this string returns a copy of the function.
|
* so that a later loadstring on this string returns a copy of the function.
|
||||||
* function must be a Lua function without upvalues.
|
* function must be a Lua function without upvalues.
|
||||||
|
* Boolean param stripDebug - true to strip debugging info, false otherwise.
|
||||||
|
* The default value for stripDebug is true.
|
||||||
*
|
*
|
||||||
* TODO: port dumping code as optional add-on
|
* TODO: port dumping code as optional add-on
|
||||||
*/
|
*/
|
||||||
static final class dump extends OneArgFunction {
|
static final class dump extends VarArgFunction {
|
||||||
public LuaValue call(LuaValue arg) {
|
public Varargs invoke(Varargs args) {
|
||||||
LuaValue f = arg.checkfunction();
|
LuaValue f = args.checkfunction(1);
|
||||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||||
try {
|
try {
|
||||||
DumpState.dump( ((LuaClosure)f).p, baos, true );
|
DumpState.dump( ((LuaClosure)f).p, baos, args.optboolean(2, true) );
|
||||||
return LuaString.valueUsing(baos.toByteArray());
|
return LuaString.valueUsing(baos.toByteArray());
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
return error( e.getMessage() );
|
return error( e.getMessage() );
|
||||||
@@ -228,7 +226,7 @@ public class StringLib extends TwoArgFunction {
|
|||||||
* This function does not accept string values containing embedded zeros,
|
* This function does not accept string values containing embedded zeros,
|
||||||
* except as arguments to the q option.
|
* except as arguments to the q option.
|
||||||
*/
|
*/
|
||||||
static final class format extends VarArgFunction {
|
final class format extends VarArgFunction {
|
||||||
public Varargs invoke(Varargs args) {
|
public Varargs invoke(Varargs args) {
|
||||||
LuaString fmt = args.checkstring( 1 );
|
LuaString fmt = args.checkstring( 1 );
|
||||||
final int n = fmt.length();
|
final int n = fmt.length();
|
||||||
@@ -259,7 +257,7 @@ public class StringLib extends TwoArgFunction {
|
|||||||
break;
|
break;
|
||||||
case 'i':
|
case 'i':
|
||||||
case 'd':
|
case 'd':
|
||||||
fdsc.format( result, args.checkint( arg ) );
|
fdsc.format( result, args.checklong( arg ) );
|
||||||
break;
|
break;
|
||||||
case 'o':
|
case 'o':
|
||||||
case 'u':
|
case 'u':
|
||||||
@@ -272,16 +270,63 @@ public class StringLib extends TwoArgFunction {
|
|||||||
case 'f':
|
case 'f':
|
||||||
case 'g':
|
case 'g':
|
||||||
case 'G':
|
case 'G':
|
||||||
fdsc.format( result, args.checkdouble( arg ) );
|
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));
|
||||||
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;
|
||||||
@@ -298,7 +343,7 @@ public class StringLib extends TwoArgFunction {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void addquoted(Buffer buf, LuaString s) {
|
static void addquoted(Buffer buf, LuaString s) {
|
||||||
int c;
|
int c;
|
||||||
buf.append( (byte) '"' );
|
buf.append( (byte) '"' );
|
||||||
for ( int i = 0, n = s.length(); i < n; i++ ) {
|
for ( int i = 0, n = s.length(); i < n; i++ ) {
|
||||||
@@ -328,7 +373,7 @@ public class StringLib extends TwoArgFunction {
|
|||||||
|
|
||||||
private static final String FLAGS = "-+ #0";
|
private static final String FLAGS = "-+ #0";
|
||||||
|
|
||||||
static class FormatDesc {
|
class FormatDesc {
|
||||||
|
|
||||||
private boolean leftAdjust;
|
private boolean leftAdjust;
|
||||||
private boolean zeroPad;
|
private boolean zeroPad;
|
||||||
@@ -338,11 +383,13 @@ public class StringLib extends TwoArgFunction {
|
|||||||
private static final int MAX_FLAGS = 5;
|
private static final int MAX_FLAGS = 5;
|
||||||
|
|
||||||
private int width;
|
private int width;
|
||||||
private int precision;
|
int precision;
|
||||||
|
|
||||||
public final int conversion;
|
public final int conversion;
|
||||||
public final int length;
|
public final int length;
|
||||||
|
|
||||||
|
public final String src;
|
||||||
|
|
||||||
public FormatDesc(Varargs args, LuaString strfrmt, final int start) {
|
public FormatDesc(Varargs args, LuaString strfrmt, final int start) {
|
||||||
int p = start, n = strfrmt.length();
|
int p = start, n = strfrmt.length();
|
||||||
int c = 0;
|
int c = 0;
|
||||||
@@ -371,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';
|
||||||
@@ -382,19 +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();
|
||||||
}
|
}
|
||||||
|
|
||||||
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) {
|
||||||
@@ -425,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++;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -449,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 );
|
||||||
|
|
||||||
@@ -465,24 +541,53 @@ public class StringLib extends TwoArgFunction {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void format(Buffer buf, double x) {
|
public void format(Buffer buf, double x) {
|
||||||
// TODO
|
// TODO: Java does not support alternateForm with 'g'
|
||||||
buf.append( String.valueOf( x ) );
|
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 static final void pad(Buffer buf, char c, int n) {
|
public final void pad(Buffer buf, char c, int n) {
|
||||||
byte b = (byte)c;
|
byte b = (byte)c;
|
||||||
while ( n-- > 0 )
|
while ( n-- > 0 )
|
||||||
buf.append(b);
|
buf.append(b);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected String format(String src, double x) {
|
||||||
|
return String.valueOf(x);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* string.gmatch (s, pattern)
|
* string.gmatch (s, pattern)
|
||||||
*
|
*
|
||||||
@@ -519,18 +624,20 @@ public class StringLib extends TwoArgFunction {
|
|||||||
private final int srclen;
|
private final int srclen;
|
||||||
private final MatchState ms;
|
private final MatchState ms;
|
||||||
private int soffset;
|
private int soffset;
|
||||||
|
private int lastmatch;
|
||||||
public GMatchAux(Varargs args, LuaString src, LuaString pat) {
|
public GMatchAux(Varargs args, LuaString src, LuaString pat) {
|
||||||
this.srclen = src.length();
|
this.srclen = src.length();
|
||||||
this.ms = new MatchState(args, src, pat);
|
this.ms = new MatchState(args, src, pat);
|
||||||
this.soffset = 0;
|
this.soffset = 0;
|
||||||
|
this.lastmatch = -1;
|
||||||
}
|
}
|
||||||
public Varargs invoke(Varargs args) {
|
public Varargs invoke(Varargs args) {
|
||||||
for ( ; soffset<srclen; soffset++ ) {
|
for ( ; soffset<=srclen; soffset++ ) {
|
||||||
ms.reset();
|
ms.reset();
|
||||||
int res = ms.match(soffset, 0);
|
int res = ms.match(soffset, 0);
|
||||||
if ( res >=0 ) {
|
if ( res >=0 && res != lastmatch ) {
|
||||||
int soff = soffset;
|
int soff = soffset;
|
||||||
soffset = res;
|
lastmatch = soffset = res;
|
||||||
return ms.push_captures( true, soff, res );
|
return ms.push_captures( true, soff, res );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -589,8 +696,11 @@ public class StringLib extends TwoArgFunction {
|
|||||||
LuaString src = args.checkstring( 1 );
|
LuaString src = args.checkstring( 1 );
|
||||||
final int srclen = src.length();
|
final int srclen = src.length();
|
||||||
LuaString p = args.checkstring( 2 );
|
LuaString p = args.checkstring( 2 );
|
||||||
|
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 );
|
||||||
@@ -601,18 +711,15 @@ public class StringLib extends TwoArgFunction {
|
|||||||
while ( n < max_s ) {
|
while ( n < max_s ) {
|
||||||
ms.reset();
|
ms.reset();
|
||||||
int res = ms.match( soffset, anchor ? 1 : 0 );
|
int res = ms.match( soffset, anchor ? 1 : 0 );
|
||||||
if ( res != -1 ) {
|
if ( res != -1 && res != lastmatch ) { /* match? */
|
||||||
n++;
|
n++;
|
||||||
ms.add_value( lbuf, soffset, res, repl );
|
ms.add_value( lbuf, soffset, res, repl ); /* add replacement to buffer */
|
||||||
|
soffset = lastmatch = res;
|
||||||
}
|
}
|
||||||
if ( res != -1 && res > soffset )
|
else if ( soffset < srclen ) /* otherwise, skip one character */
|
||||||
soffset = res;
|
|
||||||
else if ( soffset < srclen )
|
|
||||||
lbuf.append( (byte) src.luaByte( soffset++ ) );
|
lbuf.append( (byte) src.luaByte( soffset++ ) );
|
||||||
else
|
else break; /* end of subject */
|
||||||
break;
|
if ( anchor ) break;
|
||||||
if ( anchor )
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
lbuf.append( src.substring( soffset, srclen ) );
|
lbuf.append( src.substring( soffset, srclen ) );
|
||||||
return varargsOf(lbuf.tostring(), valueOf(n));
|
return varargsOf(lbuf.tostring(), valueOf(n));
|
||||||
@@ -660,20 +767,33 @@ 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();
|
||||||
s.copyInto( 0, bytes, offset, len );
|
final byte[] bytes = new byte[len * n + lsep * (n - 1)];
|
||||||
|
int offset = 0;
|
||||||
|
while (n-- > 1) {
|
||||||
|
s.copyInto(0, bytes, offset, len);
|
||||||
|
offset += len;
|
||||||
|
if (lsep > 0) {
|
||||||
|
sep.copyInto(0, bytes, offset, lsep);
|
||||||
|
offset += lsep;
|
||||||
}
|
}
|
||||||
return LuaString.valueUsing( bytes );
|
}
|
||||||
|
s.copyInto(0, bytes, offset, len);
|
||||||
|
return LuaString.valueUsing(bytes);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -764,7 +884,7 @@ public class StringLib extends TwoArgFunction {
|
|||||||
|
|
||||||
boolean anchor = false;
|
boolean anchor = false;
|
||||||
int poff = 0;
|
int poff = 0;
|
||||||
if ( pat.luaByte( 0 ) == '^' ) {
|
if ( pat.length() > 0 && pat.luaByte( 0 ) == '^' ) {
|
||||||
anchor = true;
|
anchor = true;
|
||||||
poff = 1;
|
poff = 1;
|
||||||
}
|
}
|
||||||
@@ -785,7 +905,7 @@ public class StringLib extends TwoArgFunction {
|
|||||||
return NIL;
|
return NIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int posrelat( int pos, int len ) {
|
static int posrelat( int pos, int len ) {
|
||||||
return ( pos >= 0 ) ? pos : len + pos + 1;
|
return ( pos >= 0 ) ? pos : len + pos + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -795,6 +915,8 @@ public class StringLib extends TwoArgFunction {
|
|||||||
private static final LuaString SPECIALS = valueOf("^$*+?.([%-");
|
private static final LuaString SPECIALS = valueOf("^$*+?.([%-");
|
||||||
private static final int MAX_CAPTURES = 32;
|
private static final int MAX_CAPTURES = 32;
|
||||||
|
|
||||||
|
private static final int MAXCCALLS = 200;
|
||||||
|
|
||||||
private static final int CAP_UNFINISHED = -1;
|
private static final int CAP_UNFINISHED = -1;
|
||||||
private static final int CAP_POSITION = -2;
|
private static final int CAP_POSITION = -2;
|
||||||
|
|
||||||
@@ -807,12 +929,12 @@ public class StringLib extends TwoArgFunction {
|
|||||||
private static final byte MASK_CONTROL = 0x40;
|
private static final byte MASK_CONTROL = 0x40;
|
||||||
private static final byte MASK_HEXDIGIT = (byte)0x80;
|
private static final byte MASK_HEXDIGIT = (byte)0x80;
|
||||||
|
|
||||||
private static final byte[] CHAR_TABLE;
|
static final byte[] CHAR_TABLE;
|
||||||
|
|
||||||
static {
|
static {
|
||||||
CHAR_TABLE = new byte[256];
|
CHAR_TABLE = new byte[256];
|
||||||
|
|
||||||
for ( int i = 0; i < 256; ++i ) {
|
for ( int i = 0; i < 128; ++i ) {
|
||||||
final char c = (char) i;
|
final char c = (char) i;
|
||||||
CHAR_TABLE[i] = (byte)( ( Character.isDigit( c ) ? MASK_DIGIT : 0 ) |
|
CHAR_TABLE[i] = (byte)( ( Character.isDigit( c ) ? MASK_DIGIT : 0 ) |
|
||||||
( Character.isLowerCase( c ) ? MASK_LOWERCASE : 0 ) |
|
( Character.isLowerCase( c ) ? MASK_LOWERCASE : 0 ) |
|
||||||
@@ -821,7 +943,7 @@ public class StringLib extends TwoArgFunction {
|
|||||||
if ( ( c >= 'a' && c <= 'f' ) || ( c >= 'A' && c <= 'F' ) || ( c >= '0' && c <= '9' ) ) {
|
if ( ( c >= 'a' && c <= 'f' ) || ( c >= 'A' && c <= 'F' ) || ( c >= '0' && c <= '9' ) ) {
|
||||||
CHAR_TABLE[i] |= MASK_HEXDIGIT;
|
CHAR_TABLE[i] |= MASK_HEXDIGIT;
|
||||||
}
|
}
|
||||||
if ( ( c >= '!' && c <= '/' ) || ( c >= ':' && c <= '@' ) ) {
|
if ( ( c >= '!' && c <= '/' ) || ( c >= ':' && c <= '@' ) || ( c >= '[' && c <= '`' ) || ( c >= '{' && c <= '~' ) ) {
|
||||||
CHAR_TABLE[i] |= MASK_PUNCT;
|
CHAR_TABLE[i] |= MASK_PUNCT;
|
||||||
}
|
}
|
||||||
if ( ( CHAR_TABLE[i] & ( MASK_LOWERCASE | MASK_UPPERCASE ) ) != 0 ) {
|
if ( ( CHAR_TABLE[i] & ( MASK_LOWERCASE | MASK_UPPERCASE ) ) != 0 ) {
|
||||||
@@ -833,11 +955,12 @@ public class StringLib extends TwoArgFunction {
|
|||||||
CHAR_TABLE['\r'] |= MASK_SPACE;
|
CHAR_TABLE['\r'] |= MASK_SPACE;
|
||||||
CHAR_TABLE['\n'] |= MASK_SPACE;
|
CHAR_TABLE['\n'] |= MASK_SPACE;
|
||||||
CHAR_TABLE['\t'] |= MASK_SPACE;
|
CHAR_TABLE['\t'] |= MASK_SPACE;
|
||||||
CHAR_TABLE[0x0C /* '\v' */ ] |= MASK_SPACE;
|
CHAR_TABLE[0x0B /* '\v' */ ] |= MASK_SPACE;
|
||||||
CHAR_TABLE['\f'] |= MASK_SPACE;
|
CHAR_TABLE['\f'] |= MASK_SPACE;
|
||||||
};
|
};
|
||||||
|
|
||||||
static class MatchState {
|
static class MatchState {
|
||||||
|
int matchdepth; /* control for recursive depth (to avoid C stack overflow) */
|
||||||
final LuaString s;
|
final LuaString s;
|
||||||
final LuaString p;
|
final LuaString p;
|
||||||
final Varargs args;
|
final Varargs args;
|
||||||
@@ -852,10 +975,12 @@ public class StringLib extends TwoArgFunction {
|
|||||||
this.level = 0;
|
this.level = 0;
|
||||||
this.cinit = new int[ MAX_CAPTURES ];
|
this.cinit = new int[ MAX_CAPTURES ];
|
||||||
this.clen = new int[ MAX_CAPTURES ];
|
this.clen = new int[ MAX_CAPTURES ];
|
||||||
|
this.matchdepth = MAXCCALLS;
|
||||||
}
|
}
|
||||||
|
|
||||||
void reset() {
|
void reset() {
|
||||||
level = 0;
|
level = 0;
|
||||||
|
this.matchdepth = MAXCCALLS;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void add_s( Buffer lbuf, LuaString news, int soff, int e ) {
|
private void add_s( Buffer lbuf, LuaString news, int soff, int e ) {
|
||||||
@@ -866,8 +991,14 @@ public class StringLib extends TwoArgFunction {
|
|||||||
lbuf.append( (byte) b );
|
lbuf.append( (byte) b );
|
||||||
} else {
|
} else {
|
||||||
++i; // skip ESC
|
++i; // skip ESC
|
||||||
b = (byte) news.luaByte( i );
|
b = (byte)(i < l ? news.luaByte( i ) : 0);
|
||||||
if ( !Character.isDigit( (char) b ) ) {
|
if ( !Character.isDigit( (char) b ) ) {
|
||||||
|
if (b != L_ESC) error( "invalid use of '" + (char)L_ESC +
|
||||||
|
"' in replacement string: after '" + (char)L_ESC +
|
||||||
|
"' must be '0'-'9' or '" + (char)L_ESC +
|
||||||
|
"', but found " + (i < l ? "symbol '" + (char)b + "' with code " + b +
|
||||||
|
" at pos " + (i + 1) :
|
||||||
|
"end of string"));
|
||||||
lbuf.append( b );
|
lbuf.append( b );
|
||||||
} else if ( b == '0' ) {
|
} else if ( b == '0' ) {
|
||||||
lbuf.append( s.substring( soff, e ) );
|
lbuf.append( s.substring( soff, e ) );
|
||||||
@@ -924,7 +1055,7 @@ public class StringLib extends TwoArgFunction {
|
|||||||
if ( i == 0 ) {
|
if ( i == 0 ) {
|
||||||
return s.substring( soff, end );
|
return s.substring( soff, end );
|
||||||
} else {
|
} else {
|
||||||
return error( "invalid capture index" );
|
return error( "invalid capture index %" + (i + 1) );
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
int l = clen[i];
|
int l = clen[i];
|
||||||
@@ -943,7 +1074,7 @@ public class StringLib extends TwoArgFunction {
|
|||||||
private int check_capture( int l ) {
|
private int check_capture( int l ) {
|
||||||
l -= '1';
|
l -= '1';
|
||||||
if ( l < 0 || l >= level || this.clen[l] == CAP_UNFINISHED ) {
|
if ( l < 0 || l >= level || this.clen[l] == CAP_UNFINISHED ) {
|
||||||
error("invalid capture index");
|
error("invalid capture index %" + (l + 1));
|
||||||
}
|
}
|
||||||
return l;
|
return l;
|
||||||
}
|
}
|
||||||
@@ -961,19 +1092,19 @@ public class StringLib extends TwoArgFunction {
|
|||||||
switch ( p.luaByte( poffset++ ) ) {
|
switch ( p.luaByte( poffset++ ) ) {
|
||||||
case L_ESC:
|
case L_ESC:
|
||||||
if ( poffset == p.length() ) {
|
if ( poffset == p.length() ) {
|
||||||
error( "malformed pattern (ends with %)" );
|
error( "malformed pattern (ends with '%')" );
|
||||||
}
|
}
|
||||||
return poffset + 1;
|
return poffset + 1;
|
||||||
|
|
||||||
case '[':
|
case '[':
|
||||||
if ( p.luaByte( poffset ) == '^' ) poffset++;
|
if ( poffset != p.length() && p.luaByte( poffset ) == '^' ) poffset++;
|
||||||
do {
|
do {
|
||||||
if ( poffset == p.length() ) {
|
if ( poffset == p.length() ) {
|
||||||
error( "malformed pattern (missing ])" );
|
error( "malformed pattern (missing ']')" );
|
||||||
}
|
}
|
||||||
if ( p.luaByte( poffset++ ) == L_ESC && poffset != p.length() )
|
if ( p.luaByte( poffset++ ) == L_ESC && poffset < p.length() )
|
||||||
poffset++;
|
poffset++; /* skip escapes (e.g. '%]') */
|
||||||
} while ( p.luaByte( poffset ) != ']' );
|
} while ( poffset == p.length() || p.luaByte( poffset ) != ']' );
|
||||||
return poffset + 1;
|
return poffset + 1;
|
||||||
default:
|
default:
|
||||||
return poffset;
|
return poffset;
|
||||||
@@ -993,9 +1124,10 @@ public class StringLib extends TwoArgFunction {
|
|||||||
case 'c': res = ( cdata & MASK_CONTROL ) != 0; break;
|
case 'c': res = ( cdata & MASK_CONTROL ) != 0; break;
|
||||||
case 'p': res = ( cdata & MASK_PUNCT ) != 0; break;
|
case 'p': res = ( cdata & MASK_PUNCT ) != 0; break;
|
||||||
case 's': res = ( cdata & MASK_SPACE ) != 0; break;
|
case 's': res = ( cdata & MASK_SPACE ) != 0; break;
|
||||||
|
case 'g': res = ( cdata & ( MASK_ALPHA | MASK_DIGIT | MASK_PUNCT ) ) != 0; break;
|
||||||
case 'w': res = ( cdata & ( MASK_ALPHA | MASK_DIGIT ) ) != 0; break;
|
case 'w': res = ( cdata & ( MASK_ALPHA | MASK_DIGIT ) ) != 0; break;
|
||||||
case 'x': res = ( cdata & MASK_HEXDIGIT ) != 0; break;
|
case 'x': res = ( cdata & MASK_HEXDIGIT ) != 0; break;
|
||||||
case 'z': res = ( c == 0 ); break;
|
case 'z': res = ( c == 0 ); break; /* deprecated option */
|
||||||
default: return cl == c;
|
default: return cl == c;
|
||||||
}
|
}
|
||||||
return ( lcl == cl ) ? res : !res;
|
return ( lcl == cl ) ? res : !res;
|
||||||
@@ -1037,6 +1169,8 @@ public class StringLib extends TwoArgFunction {
|
|||||||
* where match ends, otherwise returns -1.
|
* where match ends, otherwise returns -1.
|
||||||
*/
|
*/
|
||||||
int match( int soffset, int poffset ) {
|
int match( int soffset, int poffset ) {
|
||||||
|
if (matchdepth-- == 0) error("pattern too complex");
|
||||||
|
try {
|
||||||
while ( true ) {
|
while ( true ) {
|
||||||
// Check if we are at the end of the pattern -
|
// Check if we are at the end of the pattern -
|
||||||
// equivalent to the '\0' case in the C version, but our pattern
|
// equivalent to the '\0' case in the C version, but our pattern
|
||||||
@@ -1062,13 +1196,14 @@ public class StringLib extends TwoArgFunction {
|
|||||||
continue;
|
continue;
|
||||||
case 'f': {
|
case 'f': {
|
||||||
poffset += 2;
|
poffset += 2;
|
||||||
if ( p.luaByte( poffset ) != '[' ) {
|
if ( poffset == p.length() || p.luaByte( poffset ) != '[' ) {
|
||||||
error("Missing [ after %f in pattern");
|
error("missing '[' after '%f' in pattern");
|
||||||
}
|
}
|
||||||
int ep = classend( poffset );
|
int ep = classend( poffset );
|
||||||
int previous = ( soffset == 0 ) ? -1 : s.luaByte( soffset - 1 );
|
int previous = ( soffset == 0 ) ? '\0' : s.luaByte( soffset - 1 );
|
||||||
|
int next = ( soffset == s.length() ) ? '\0' : s.luaByte( soffset );
|
||||||
if ( matchbracketclass( previous, poffset, ep - 1 ) ||
|
if ( matchbracketclass( previous, poffset, ep - 1 ) ||
|
||||||
matchbracketclass( s.luaByte( soffset ), poffset, ep - 1 ) )
|
!matchbracketclass( next, poffset, ep - 1 ) )
|
||||||
return -1;
|
return -1;
|
||||||
poffset = ep;
|
poffset = ep;
|
||||||
continue;
|
continue;
|
||||||
@@ -1112,6 +1247,9 @@ public class StringLib extends TwoArgFunction {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} finally {
|
||||||
|
matchdepth++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int max_expand( int soff, int poff, int ep ) {
|
int max_expand( int soff, int poff, int ep ) {
|
||||||
@@ -1175,7 +1313,7 @@ public class StringLib extends TwoArgFunction {
|
|||||||
int matchbalance( int soff, int poff ) {
|
int matchbalance( int soff, int poff ) {
|
||||||
final int plen = p.length();
|
final int plen = p.length();
|
||||||
if ( poff == plen || poff + 1 == plen ) {
|
if ( poff == plen || poff + 1 == plen ) {
|
||||||
error( "unbalanced pattern" );
|
error( "malformed pattern (missing arguments to '%b')" );
|
||||||
}
|
}
|
||||||
final int slen = s.length();
|
final int slen = s.length();
|
||||||
if ( soff >= slen )
|
if ( soff >= slen )
|
||||||
@@ -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>
|
||||||
|
* {
|
||||||
|
* @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>
|
||||||
|
* {
|
||||||
|
* @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,47 +87,55 @@ 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);
|
env.get("package").get("loaded").set("table", table);
|
||||||
return NIL;
|
return NIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static class TableLibFunction extends LibFunction {
|
|
||||||
public LuaValue call() {
|
|
||||||
return argerror(1, "table expected, got no value");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// "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());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// "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 0: case 1: {
|
|
||||||
return argerror(2, "value expected");
|
|
||||||
}
|
|
||||||
case 2: {
|
case 2: {
|
||||||
LuaTable table = args.arg1().checktable();
|
LuaTable table = args.checktable(1);
|
||||||
table.insert(table.length()+1,args.arg(2));
|
table.insert(table.length()+1, args.arg(2));
|
||||||
|
return NONE;
|
||||||
|
}
|
||||||
|
case 3: {
|
||||||
|
LuaTable table = args.checktable(1);
|
||||||
|
int pos = args.checkint(2);
|
||||||
|
int max = table.length()+1;
|
||||||
|
if (pos < 1 || pos > max)
|
||||||
|
argerror(2, "position out of bounds: " + pos + " not between 1 and " + max);
|
||||||
|
table.insert(pos, args.arg(3));
|
||||||
return NONE;
|
return NONE;
|
||||||
}
|
}
|
||||||
default: {
|
default: {
|
||||||
args.arg1().checktable().insert(args.checkint(2),args.arg(3));
|
return error("wrong number of arguments to 'table.insert': " + args.narg() + " (must be 2 or 3)");
|
||||||
return NONE;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -118,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());
|
||||||
@@ -127,30 +153,35 @@ 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) {
|
||||||
return args.arg1().checktable().remove(args.optint(2, 0));
|
LuaTable table = args.checktable(1);
|
||||||
|
int size = table.length();
|
||||||
|
int pos = args.optint(2, size);
|
||||||
|
if (pos != size && (pos < 1 || pos > size+1)) {
|
||||||
|
argerror(2, "position out of bounds: " + pos + " not between 1 and " + (size+1));
|
||||||
|
}
|
||||||
|
return table.remove(pos);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// "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.arg1().checktable().sort(
|
args.checktable(1).sort(args.isnil(2)? NIL: args.checkfunction(2));
|
||||||
args.arg(2).isnil()? NIL: args.arg(2).checkfunction());
|
|
||||||
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);
|
||||||
switch (args.narg()) {
|
// do not waste resource for calc rawlen if arg3 is not nil
|
||||||
case 1: return t.unpack();
|
int len = args.arg(3).isnil()? t.length(): 0;
|
||||||
case 2: return t.unpack(args.checkint(2));
|
return t.unpack(args.optint(2, 1), args.optint(3, len));
|
||||||
default: return t.unpack(args.checkint(2), args.checkint(3));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
package org.luaj.vm2.lib;
|
||||||
|
|
||||||
|
import org.luaj.vm2.LuaValue;
|
||||||
|
|
||||||
|
class TableLibFunction extends LibFunction {
|
||||||
|
@Override
|
||||||
|
public LuaValue call() {
|
||||||
|
return argerror(1, "table expected, got no value");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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,26 +51,31 @@ 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));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -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,26 +51,31 @@ 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));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -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);
|
||||||
}
|
}
|
||||||
@@ -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();
|
||||||
}
|
}
|
||||||
@@ -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());
|
||||||
135
luaj-core/src/test/java/org/luaj/vm2/LuaOperationsTest.java
Normal file
135
luaj-core/src/test/java/org/luaj/vm2/LuaOperationsTest.java
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
372
luaj-core/src/test/java/org/luaj/vm2/MetatableTest.java
Normal file
372
luaj-core/src/test/java/org/luaj/vm2/MetatableTest.java
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,98 +1,103 @@
|
|||||||
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();
|
||||||
|
|
||||||
assertEquals( 'H', is.read() );
|
assertEquals('H', is.read());
|
||||||
assertEquals( 'e', is.read() );
|
assertEquals('e', is.read());
|
||||||
assertEquals( 2, is.skip( 2 ) );
|
assertEquals(2, is.skip(2));
|
||||||
assertEquals( 'o', is.read() );
|
assertEquals('o', is.read());
|
||||||
assertEquals( -1, is.read() );
|
assertEquals(-1, is.read());
|
||||||
|
|
||||||
assertTrue( is.markSupported() );
|
assertTrue(is.markSupported());
|
||||||
|
|
||||||
is.reset();
|
is.reset();
|
||||||
|
|
||||||
assertEquals( 'H', is.read() );
|
assertEquals('H', is.read());
|
||||||
is.mark( 4 );
|
is.mark(4);
|
||||||
|
|
||||||
assertEquals( 'e', is.read() );
|
assertEquals('e', is.read());
|
||||||
is.reset();
|
is.reset();
|
||||||
assertEquals( 'e', is.read() );
|
assertEquals('e', is.read());
|
||||||
|
|
||||||
LuaString substr = str.substring( 1, 4 );
|
LuaString substr = str.substring(1, 4);
|
||||||
assertEquals( 3, substr.length() );
|
assertEquals(3, substr.length());
|
||||||
|
|
||||||
is.close();
|
is.close();
|
||||||
is = substr.toInputStream();
|
is = substr.toInputStream();
|
||||||
|
|
||||||
assertEquals( 'e', is.read() );
|
assertEquals('e', is.read());
|
||||||
assertEquals( 'l', is.read() );
|
assertEquals('l', is.read());
|
||||||
assertEquals( 'l', is.read() );
|
assertEquals('l', is.read());
|
||||||
assertEquals( -1, is.read() );
|
assertEquals(-1, is.read());
|
||||||
|
|
||||||
is = substr.toInputStream();
|
is = substr.toInputStream();
|
||||||
is.reset();
|
is.reset();
|
||||||
|
|
||||||
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++) {
|
||||||
int c = s.charAt(i);
|
int c = s.charAt(i);
|
||||||
if ( c < ' ' || c >= 0x80 ) {
|
if (c < ' ' || c >= 0x80) {
|
||||||
sb.append( "\\u"+Integer.toHexString(0x10000+c).substring(1) );
|
sb.append("\\u" + Integer.toHexString(0x10000+c).substring(1));
|
||||||
} else {
|
} else {
|
||||||
sb.append( (char) c );
|
sb.append((char) c);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
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);
|
||||||
LuaString ls = LuaString.valueOf(before);
|
LuaString ls = LuaString.valueOf(before);
|
||||||
String after = ls.tojstring();
|
String after = ls.tojstring();
|
||||||
assertEquals( userFriendly( before ), userFriendly( after ) );
|
assertEquals(userFriendly(before), userFriendly(after));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testUtf8() {
|
@Test
|
||||||
for ( int i=4; i<0xffff; i+=4 ) {
|
void testUtf8() {
|
||||||
|
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);
|
||||||
String after = ls.tojstring();
|
String after = ls.tojstring();
|
||||||
assertEquals( userFriendly( before ), userFriendly( after ) );
|
assertEquals(userFriendly(before), userFriendly(after));
|
||||||
}
|
}
|
||||||
char[] c = { (char) (1), (char) (2), (char) (3) };
|
char[] c = { (char) (1), (char) (2), (char) (3) };
|
||||||
String before = new String(c)+" 1-3";
|
String before = new String(c) + " 1-3";
|
||||||
LuaString ls = LuaString.valueOf(before);
|
LuaString ls = LuaString.valueOf(before);
|
||||||
String after = ls.tojstring();
|
String after = ls.tojstring();
|
||||||
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,58 +109,63 @@ 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);
|
||||||
String after = ls.tojstring();
|
String after = ls.tojstring();
|
||||||
assertEquals( userFriendly( "abc\0def" ), userFriendly( after ) );
|
assertEquals(userFriendly("abc\0def"), userFriendly(after));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testRecentStringsCacheDifferentHashcodes() {
|
@Test
|
||||||
final byte[] abc = {'a', 'b', 'c' };
|
void testRecentStringsCacheDifferentHashcodes() {
|
||||||
final byte[] xyz = {'x', 'y', 'z' };
|
final byte[] abc = { 'a', 'b', 'c' };
|
||||||
|
final byte[] xyz = { 'x', 'y', 'z' };
|
||||||
final LuaString abc1 = LuaString.valueOf(abc);
|
final LuaString abc1 = LuaString.valueOf(abc);
|
||||||
final LuaString xyz1 = LuaString.valueOf(xyz);
|
final LuaString xyz1 = LuaString.valueOf(xyz);
|
||||||
final LuaString abc2 = LuaString.valueOf(abc);
|
final LuaString abc2 = LuaString.valueOf(abc);
|
||||||
final LuaString xyz2 = LuaString.valueOf(xyz);
|
final LuaString xyz2 = LuaString.valueOf(xyz);
|
||||||
final int mod = LuaString.RECENT_STRINGS_CACHE_SIZE;
|
final int mod = LuaString.RECENT_STRINGS_CACHE_SIZE;
|
||||||
assertTrue(abc1.hashCode() % mod != xyz1.hashCode() % mod);
|
assertTrue(abc1.hashCode()%mod != xyz1.hashCode()%mod);
|
||||||
assertSame(abc1, abc2);
|
assertSame(abc1, abc2);
|
||||||
assertSame(xyz1, xyz2);
|
assertSame(xyz1, xyz2);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testRecentStringsCacheHashCollisionCacheHit() {
|
@Test
|
||||||
final byte[] abc = {'a', 'b', 'c' };
|
void testRecentStringsCacheHashCollisionCacheHit() {
|
||||||
final byte[] lyz = {'l', 'y', 'z' }; // chosen to have hash collision with 'abc'
|
final byte[] abc = { 'a', 'b', 'c' };
|
||||||
|
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);
|
||||||
final LuaString abc2 = LuaString.valueOf(abc); // in cache: 'abc'
|
final LuaString abc2 = LuaString.valueOf(abc); // in cache: 'abc'
|
||||||
final LuaString lyz1 = LuaString.valueOf(lyz);
|
final LuaString lyz1 = LuaString.valueOf(lyz);
|
||||||
final LuaString lyz2 = LuaString.valueOf(lyz); // in cache: 'lyz'
|
final LuaString lyz2 = LuaString.valueOf(lyz); // in cache: 'lyz'
|
||||||
final int mod = LuaString.RECENT_STRINGS_CACHE_SIZE;
|
final int mod = LuaString.RECENT_STRINGS_CACHE_SIZE;
|
||||||
assertEquals(abc1.hashCode() % mod, lyz1.hashCode() % mod);
|
assertEquals(abc1.hashCode()%mod, lyz1.hashCode()%mod);
|
||||||
assertNotSame(abc1, lyz1);
|
assertNotSame(abc1, lyz1);
|
||||||
assertFalse(abc1.equals(lyz1));
|
assertFalse(abc1.equals(lyz1));
|
||||||
assertSame(abc1, abc2);
|
assertSame(abc1, abc2);
|
||||||
assertSame(lyz1, lyz2);
|
assertSame(lyz1, lyz2);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testRecentStringsCacheHashCollisionCacheMiss() {
|
@Test
|
||||||
final byte[] abc = {'a', 'b', 'c' };
|
void testRecentStringsCacheHashCollisionCacheMiss() {
|
||||||
final byte[] lyz = {'l', 'y', 'z' }; // chosen to have hash collision with 'abc'
|
final byte[] abc = { 'a', 'b', 'c' };
|
||||||
|
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);
|
||||||
final LuaString lyz1 = LuaString.valueOf(lyz); // in cache: 'abc'
|
final LuaString lyz1 = LuaString.valueOf(lyz); // in cache: 'abc'
|
||||||
final LuaString abc2 = LuaString.valueOf(abc); // in cache: 'lyz'
|
final LuaString abc2 = LuaString.valueOf(abc); // in cache: 'lyz'
|
||||||
final LuaString lyz2 = LuaString.valueOf(lyz); // in cache: 'abc'
|
final LuaString lyz2 = LuaString.valueOf(lyz); // in cache: 'abc'
|
||||||
final int mod = LuaString.RECENT_STRINGS_CACHE_SIZE;
|
final int mod = LuaString.RECENT_STRINGS_CACHE_SIZE;
|
||||||
assertEquals(abc1.hashCode() % mod, lyz1.hashCode() % mod);
|
assertEquals(abc1.hashCode()%mod, lyz1.hashCode()%mod);
|
||||||
assertNotSame(abc1, lyz1);
|
assertNotSame(abc1, lyz1);
|
||||||
assertFalse(abc1.equals(lyz1));
|
assertFalse(abc1.equals(lyz1));
|
||||||
assertNotSame(abc1, abc2);
|
assertNotSame(abc1, abc2);
|
||||||
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";
|
||||||
@@ -175,8 +186,8 @@ public class StringTest extends TestCase {
|
|||||||
final LuaString xyz1 = LuaString.valueOf(xyz);
|
final LuaString xyz1 = LuaString.valueOf(xyz);
|
||||||
final LuaString xyz2 = LuaString.valueOf(xyz);
|
final LuaString xyz2 = LuaString.valueOf(xyz);
|
||||||
final int mod = LuaString.RECENT_STRINGS_CACHE_SIZE;
|
final int mod = LuaString.RECENT_STRINGS_CACHE_SIZE;
|
||||||
assertEquals(abc1.hashCode() % mod, lyz1.hashCode() % mod);
|
assertEquals(abc1.hashCode()%mod, lyz1.hashCode()%mod);
|
||||||
assertFalse(abc1.hashCode() % mod == xyz1.hashCode() % mod);
|
assertFalse(abc1.hashCode()%mod == xyz1.hashCode()%mod);
|
||||||
assertSame(abc1, abc2);
|
assertSame(abc1, abc2);
|
||||||
assertSame(lyz1, lyz2);
|
assertSame(lyz1, lyz2);
|
||||||
assertSame(xyz1, xyz2);
|
assertSame(xyz1, xyz2);
|
||||||
@@ -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);
|
||||||
@@ -325,7 +342,7 @@ public class StringTest extends TestCase {
|
|||||||
LuaString ghi = LuaString.valueOf("ghi");
|
LuaString ghi = LuaString.valueOf("ghi");
|
||||||
LuaString ihg = LuaString.valueOf("ihg");
|
LuaString ihg = LuaString.valueOf("ihg");
|
||||||
LuaString ijk = LuaString.valueOf("ijk");
|
LuaString ijk = LuaString.valueOf("ijk");
|
||||||
LuaString kji= LuaString.valueOf("kji");
|
LuaString kji = LuaString.valueOf("kji");
|
||||||
LuaString xyz = LuaString.valueOf("xyz");
|
LuaString xyz = LuaString.valueOf("xyz");
|
||||||
LuaString ABCdEFGHIJKL = LuaString.valueOf("ABCdEFGHIJKL");
|
LuaString ABCdEFGHIJKL = LuaString.valueOf("ABCdEFGHIJKL");
|
||||||
LuaString EFGHIJKL = ABCdEFGHIJKL.substring(4, 12);
|
LuaString EFGHIJKL = ABCdEFGHIJKL.substring(4, 12);
|
||||||
@@ -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));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
325
luaj-core/src/test/java/org/luaj/vm2/TableHashTest.java
Normal file
325
luaj-core/src/test/java/org/luaj/vm2/TableHashTest.java
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
437
luaj-core/src/test/java/org/luaj/vm2/TableTest.java
Normal file
437
luaj-core/src/test/java/org/luaj/vm2/TableTest.java
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
1293
luaj-core/src/test/java/org/luaj/vm2/TypeTest.java
Normal file
1293
luaj-core/src/test/java/org/luaj/vm2/TypeTest.java
Normal file
File diff suppressed because it is too large
Load Diff
1468
luaj-core/src/test/java/org/luaj/vm2/UnaryBinaryOperatorsTest.java
Normal file
1468
luaj-core/src/test/java/org/luaj/vm2/UnaryBinaryOperatorsTest.java
Normal file
File diff suppressed because it is too large
Load Diff
@@ -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");
|
||||||
@@ -45,30 +48,31 @@ public class VarargsTest extends TestCase {
|
|||||||
static Varargs DE = LuaValue.varargsOf(new LuaValue[] { D, E });
|
static Varargs DE = LuaValue.varargsOf(new LuaValue[] { D, E });
|
||||||
static Varargs E_G = LuaValue.varargsOf(new LuaValue[] { E, F, G });
|
static Varargs E_G = LuaValue.varargsOf(new LuaValue[] { E, F, G });
|
||||||
static Varargs FG = LuaValue.varargsOf(new LuaValue[] { F, G });
|
static Varargs FG = LuaValue.varargsOf(new LuaValue[] { F, G });
|
||||||
static LuaValue[] Z_H_array = {Z, A, B, C, D, E, F, G, H };
|
static LuaValue[] Z_H_array = { Z, A, B, C, D, E, F, G, H };
|
||||||
static Varargs A_G_alt = new Varargs.ArrayPartVarargs(Z_H_array, 1, 7);
|
static Varargs A_G_alt = new Varargs.ArrayPartVarargs(Z_H_array, 1, 7);
|
||||||
static Varargs B_E_alt = new Varargs.ArrayPartVarargs(Z_H_array, 2, 4);
|
static Varargs B_E_alt = new Varargs.ArrayPartVarargs(Z_H_array, 2, 4);
|
||||||
static Varargs C_G_alt = new Varargs.ArrayPartVarargs(Z_H_array, 3, 5);
|
static Varargs C_G_alt = new Varargs.ArrayPartVarargs(Z_H_array, 3, 5);
|
||||||
static Varargs C_E_alt = new Varargs.ArrayPartVarargs(Z_H_array, 3, 3);
|
static Varargs C_E_alt = new Varargs.ArrayPartVarargs(Z_H_array, 3, 3);
|
||||||
static Varargs C_E_alt2 = LuaValue.varargsOf(C, D, E);
|
static Varargs C_E_alt2 = LuaValue.varargsOf(C, D, E);
|
||||||
static Varargs DE_alt = new Varargs.PairVarargs(D,E);
|
static Varargs DE_alt = new Varargs.PairVarargs(D, E);
|
||||||
static Varargs DE_alt2 = LuaValue.varargsOf(D,E);
|
static Varargs DE_alt2 = LuaValue.varargsOf(D, E);
|
||||||
static Varargs E_G_alt = new Varargs.ArrayPartVarargs(Z_H_array, 5, 3);
|
static Varargs E_G_alt = new Varargs.ArrayPartVarargs(Z_H_array, 5, 3);
|
||||||
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));
|
||||||
assertEquals(x.arg(-1), y.arg(-1));
|
assertEquals(x.arg(-1), y.arg(-1));
|
||||||
assertEquals(x.arg(2), y.arg(2));
|
assertEquals(x.arg(2), y.arg(2));
|
||||||
assertEquals(x.arg(3), y.arg(3));
|
assertEquals(x.arg(3), y.arg(3));
|
||||||
for (int i = 4; i < x.narg() + 2; ++i)
|
for (int i = 4; i < x.narg()+2; ++i)
|
||||||
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,33 +176,32 @@ 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);
|
||||||
a_g = LuaValue.varargsOf(new LuaValue[] { A, B, }, LuaValue.varargsOf( new LuaValue[] { C, D, E, F, G }));
|
a_g = LuaValue.varargsOf(new LuaValue[] { A, B, }, LuaValue.varargsOf(new LuaValue[] { C, D, E, F, G }));
|
||||||
standardTestsA_G(a_g);
|
standardTestsA_G(a_g);
|
||||||
a_g = LuaValue.varargsOf(new LuaValue[] { A, B, C, }, LuaValue.varargsOf( new LuaValue[] { D, E, F, G }));
|
a_g = LuaValue.varargsOf(new LuaValue[] { A, B, C, }, LuaValue.varargsOf(new LuaValue[] { D, E, F, G }));
|
||||||
standardTestsA_G(a_g);
|
standardTestsA_G(a_g);
|
||||||
a_g = LuaValue.varargsOf(new LuaValue[] { A, B, C, D, }, LuaValue.varargsOf(E, F, G));
|
a_g = LuaValue.varargsOf(new LuaValue[] { A, B, C, D, }, LuaValue.varargsOf(E, F, G));
|
||||||
standardTestsA_G(a_g);
|
standardTestsA_G(a_g);
|
||||||
a_g = LuaValue.varargsOf(new LuaValue[] { A, B, C, D, E }, LuaValue.varargsOf( F, G ));
|
a_g = LuaValue.varargsOf(new LuaValue[] { A, B, C, D, E }, LuaValue.varargsOf(F, G));
|
||||||
standardTestsA_G(a_g);
|
standardTestsA_G(a_g);
|
||||||
a_g = LuaValue.varargsOf(new LuaValue[] { A, B, C, D, E, F, }, G );
|
a_g = LuaValue.varargsOf(new LuaValue[] { A, B, C, D, E, F, }, G);
|
||||||
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,18 +217,18 @@ 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);
|
||||||
fail("Failed to throw exception for index 0");
|
fail("Failed to throw exception for index 0");
|
||||||
} catch ( LuaError e ) {
|
} catch (LuaError e) {
|
||||||
assertEquals(expected_msg, e.getMessage());
|
assertEquals(expected_msg, e.getMessage());
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
v.subargs(-1);
|
v.subargs(-1);
|
||||||
fail("Failed to throw exception for index -1");
|
fail("Failed to throw exception for index -1");
|
||||||
} catch ( LuaError e ) {
|
} catch (LuaError e) {
|
||||||
assertEquals(expected_msg, e.getMessage());
|
assertEquals(expected_msg, e.getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
262
luaj-core/src/test/java/org/luaj/vm2/WeakTableTest.java
Normal file
262
luaj-core/src/test/java/org/luaj/vm2/WeakTableTest.java
Normal 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
BIN
luaj-jme-3.0.2.jar
Normal file
Binary file not shown.
39
luaj-jme/pom.xml
Normal file
39
luaj-jme/pom.xml
Normal 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>
|
||||||
@@ -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>
|
||||||
|
* {
|
||||||
|
* @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>
|
||||||
|
* {
|
||||||
|
* @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,44 +140,61 @@ 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 ) {
|
|
||||||
this( null, i, null );
|
private FileImpl(InputStream i) {
|
||||||
|
this(null, i, null);
|
||||||
}
|
}
|
||||||
private FileImpl( OutputStream o ) {
|
|
||||||
this( null, null, o );
|
private FileImpl(OutputStream o) {
|
||||||
|
this(null, null, o);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@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);
|
||||||
else
|
else
|
||||||
notimplemented();
|
notimplemented();
|
||||||
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,48 +213,54 @@ 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();
|
||||||
return lookahead;
|
return lookahead;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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;
|
||||||
lookahead = -1;
|
lookahead = -1;
|
||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
if ( is != null )
|
if (is != null)
|
||||||
return is.read();
|
return is.read();
|
||||||
notimplemented();
|
notimplemented();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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) {
|
||||||
if ( length > 0 && lookahead >= 0 ) {
|
if (length > 0 && lookahead >= 0) {
|
||||||
bytes[offset] = (byte) lookahead;
|
bytes[offset] = (byte) lookahead;
|
||||||
lookahead = -1;
|
lookahead = -1;
|
||||||
i += 1;
|
i += 1;
|
||||||
}
|
}
|
||||||
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 {
|
||||||
@@ -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>
|
||||||
|
* {
|
||||||
|
* @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
|
||||||
0
luaj-jme/src/main/resources/.keep
Normal file
0
luaj-jme/src/main/resources/.keep
Normal file
136
luaj-jme/src/test/java/org/luaj/vm2/lib/jme/OsLibTest.java
Normal file
136
luaj-jme/src/test/java/org/luaj/vm2/lib/jme/OsLibTest.java
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
0
luaj-jme/src/test/resources/.keep
Normal file
0
luaj-jme/src/test/resources/.keep
Normal file
BIN
luaj-jse-3.0.2.jar
Normal file
BIN
luaj-jse-3.0.2.jar
Normal file
Binary file not shown.
77
luaj-jse/pom.xml
Normal file
77
luaj-jse/pom.xml
Normal 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>
|
||||||
@@ -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);
|
||||||
@@ -68,10 +62,10 @@ public class lua {
|
|||||||
private static boolean print = false;
|
private static boolean print = false;
|
||||||
private static String encoding = null;
|
private static String encoding = null;
|
||||||
|
|
||||||
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;
|
||||||
@@ -79,17 +73,17 @@ public class lua {
|
|||||||
Vector libs = null;
|
Vector libs = null;
|
||||||
try {
|
try {
|
||||||
// stateful argument processing
|
// stateful argument processing
|
||||||
for ( int i=0; i<args.length; i++ ) {
|
for (int i = 0; i < args.length; i++) {
|
||||||
if ( ! processing || ! args[i].startsWith("-") ) {
|
if (!processing || !args[i].startsWith("-")) {
|
||||||
// input file - defer to last stage
|
// input file - defer to last stage
|
||||||
break;
|
break;
|
||||||
} else if ( args[i].length() <= 1 ) {
|
} else if (args[i].length() <= 1) {
|
||||||
// input file - defer to last stage
|
// input file - defer to last stage
|
||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
switch ( args[i].charAt(1) ) {
|
switch (args[i].charAt(1)) {
|
||||||
case 'e':
|
case 'e':
|
||||||
if ( ++i >= args.length )
|
if (++i >= args.length)
|
||||||
usageExit();
|
usageExit();
|
||||||
// input script - defer to last stage
|
// input script - defer to last stage
|
||||||
break;
|
break;
|
||||||
@@ -97,10 +91,10 @@ public class lua {
|
|||||||
luajc = true;
|
luajc = true;
|
||||||
break;
|
break;
|
||||||
case 'l':
|
case 'l':
|
||||||
if ( ++i >= args.length )
|
if (++i >= args.length)
|
||||||
usageExit();
|
usageExit();
|
||||||
libs = libs!=null? libs: new Vector();
|
libs = libs != null? libs: new Vector();
|
||||||
libs.addElement( args[i] );
|
libs.addElement(args[i]);
|
||||||
break;
|
break;
|
||||||
case 'i':
|
case 'i':
|
||||||
interactive = true;
|
interactive = true;
|
||||||
@@ -115,12 +109,12 @@ public class lua {
|
|||||||
print = true;
|
print = true;
|
||||||
break;
|
break;
|
||||||
case 'c':
|
case 'c':
|
||||||
if ( ++i >= args.length )
|
if (++i >= args.length)
|
||||||
usageExit();
|
usageExit();
|
||||||
encoding = args[i];
|
encoding = args[i];
|
||||||
break;
|
break;
|
||||||
case '-':
|
case '-':
|
||||||
if ( args[i].length() > 2 )
|
if (args[i].length() > 2)
|
||||||
usageExit();
|
usageExit();
|
||||||
processing = false;
|
processing = false;
|
||||||
break;
|
break;
|
||||||
@@ -132,33 +126,34 @@ public class lua {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// echo version
|
// echo version
|
||||||
if ( versioninfo )
|
if (versioninfo)
|
||||||
System.out.println(version);
|
System.out.println(version);
|
||||||
|
|
||||||
// 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)
|
||||||
for ( int i=0, n=libs!=null? libs.size(): 0; i<n; i++ )
|
LuaJC.install(globals);
|
||||||
loadLibrary( (String) libs.elementAt(i) );
|
for (int i = 0, n = libs != null? libs.size(): 0; i < n; i++)
|
||||||
|
loadLibrary((String) libs.elementAt(i));
|
||||||
|
|
||||||
// input script processing
|
// input script processing
|
||||||
processing = true;
|
processing = true;
|
||||||
for ( int i=0; i<args.length; i++ ) {
|
for (int i = 0; i < args.length; i++) {
|
||||||
if ( ! processing || ! args[i].startsWith("-") ) {
|
if (!processing || !args[i].startsWith("-")) {
|
||||||
processScript( new FileInputStream(args[i]), args[i], args, i );
|
processScript(new FileInputStream(args[i]), args[i], args, i);
|
||||||
break;
|
break;
|
||||||
} else if ( "-".equals( args[i] ) ) {
|
} else if ("-".equals(args[i])) {
|
||||||
processScript( System.in, "=stdin", args, i );
|
processScript(System.in, "=stdin", args, i);
|
||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
switch ( args[i].charAt(1) ) {
|
switch (args[i].charAt(1)) {
|
||||||
case 'l':
|
case 'l':
|
||||||
case 'c':
|
case 'c':
|
||||||
++i;
|
++i;
|
||||||
break;
|
break;
|
||||||
case 'e':
|
case 'e':
|
||||||
++i;
|
++i;
|
||||||
processScript( new ByteArrayInputStream(args[i].getBytes()), "string", args, i );
|
processScript(new ByteArrayInputStream(args[i].getBytes()), "string", args, i);
|
||||||
break;
|
break;
|
||||||
case '-':
|
case '-':
|
||||||
processing = false;
|
processing = false;
|
||||||
@@ -167,48 +162,48 @@ public class lua {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( interactive )
|
if (interactive)
|
||||||
interactiveMode();
|
interactiveMode();
|
||||||
|
|
||||||
} catch ( IOException ioe ) {
|
} catch (IOException ioe) {
|
||||||
System.err.println( ioe.toString() );
|
System.err.println(ioe.toString());
|
||||||
System.exit(-2);
|
System.exit(-2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void loadLibrary( String libname ) throws IOException {
|
private static void loadLibrary(String libname) throws IOException {
|
||||||
LuaValue slibname =LuaValue.valueOf(libname);
|
LuaValue slibname = LuaValue.valueOf(libname);
|
||||||
try {
|
try {
|
||||||
// load via plain require
|
// load via plain require
|
||||||
globals.get("require").call(slibname);
|
globals.get("require").call(slibname);
|
||||||
} catch ( Exception e ) {
|
} catch (Exception e) {
|
||||||
try {
|
try {
|
||||||
// load as java class
|
// load as java class
|
||||||
LuaValue v = (LuaValue) Class.forName(libname).newInstance();
|
LuaValue v = (LuaValue) Class.forName(libname).newInstance();
|
||||||
v.call(slibname, globals);
|
v.call(slibname, globals);
|
||||||
} catch ( Exception f ) {
|
} catch (Exception f) {
|
||||||
throw new IOException("loadLibrary("+libname+") failed: "+e+","+f );
|
throw new IOException("loadLibrary(" + libname + ") failed: " + e + "," + f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void processScript( InputStream script, String chunkname, String[] args, int firstarg ) throws IOException {
|
private static void processScript(InputStream script, String chunkname, String[] args, int firstarg)
|
||||||
|
throws IOException {
|
||||||
try {
|
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();
|
||||||
}
|
}
|
||||||
if (print && c.isclosure())
|
if (print && c.isclosure())
|
||||||
Print.print(c.checkclosure().p);
|
Print.print(c.checkclosure().p);
|
||||||
Varargs scriptargs = setGlobalArg(chunkname, args, firstarg, globals);
|
Varargs scriptargs = setGlobalArg(chunkname, args, firstarg, globals);
|
||||||
c.invoke( scriptargs );
|
c.invoke(scriptargs);
|
||||||
} catch ( Exception e ) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace( System.err );
|
e.printStackTrace(System.err);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -216,23 +211,23 @@ public class lua {
|
|||||||
if (args == null)
|
if (args == null)
|
||||||
return LuaValue.NONE;
|
return LuaValue.NONE;
|
||||||
LuaTable arg = LuaValue.tableOf();
|
LuaTable arg = LuaValue.tableOf();
|
||||||
for ( int j=0; j<args.length; j++ )
|
for (int j = 0; j < args.length; j++)
|
||||||
arg.set( j-i, LuaValue.valueOf(args[j]) );
|
arg.set(j-i, LuaValue.valueOf(args[j]));
|
||||||
arg.set(0, LuaValue.valueOf(chunkname));
|
arg.set(0, LuaValue.valueOf(chunkname));
|
||||||
arg.set(-1, LuaValue.valueOf("luaj"));
|
arg.set(-1, LuaValue.valueOf("luaj"));
|
||||||
globals.set("arg", arg);
|
globals.set("arg", arg);
|
||||||
return arg.unpack();
|
return arg.unpack();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void interactiveMode( ) throws IOException {
|
private static void interactiveMode() throws IOException {
|
||||||
BufferedReader reader = new BufferedReader( new InputStreamReader( System.in ) );
|
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
|
||||||
while ( true ) {
|
while ( true ) {
|
||||||
System.out.print("> ");
|
System.out.print("> ");
|
||||||
System.out.flush();
|
System.out.flush();
|
||||||
String line = reader.readLine();
|
String line = reader.readLine();
|
||||||
if ( line == null )
|
if (line == null)
|
||||||
return;
|
return;
|
||||||
processScript( new ByteArrayInputStream(line.getBytes()), "=stdin", null, 0 );
|
processScript(new ByteArrayInputStream(line.getBytes()), "=stdin", null, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -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);
|
||||||
@@ -71,27 +65,27 @@ public class luac {
|
|||||||
private boolean processing = true;
|
private boolean processing = true;
|
||||||
private String encoding = null;
|
private String encoding = null;
|
||||||
|
|
||||||
public static void main( String[] args ) throws IOException {
|
public static void main(String[] args) throws IOException {
|
||||||
new luac( args );
|
new luac(args);
|
||||||
}
|
}
|
||||||
|
|
||||||
private luac( String[] args ) throws IOException {
|
private luac(String[] args) throws IOException {
|
||||||
|
|
||||||
// process args
|
// process args
|
||||||
try {
|
try {
|
||||||
// get stateful args
|
// get stateful args
|
||||||
for ( int i=0; i<args.length; i++ ) {
|
for (int i = 0; i < args.length; i++) {
|
||||||
if ( ! processing || ! args[i].startsWith("-") ) {
|
if (!processing || !args[i].startsWith("-")) {
|
||||||
// input file - defer to next stage
|
// input file - defer to next stage
|
||||||
} else if ( args[i].length() <= 1 ) {
|
} else if (args[i].length() <= 1) {
|
||||||
// input file - defer to next stage
|
// input file - defer to next stage
|
||||||
} else {
|
} else {
|
||||||
switch ( args[i].charAt(1) ) {
|
switch (args[i].charAt(1)) {
|
||||||
case 'l':
|
case 'l':
|
||||||
list = true;
|
list = true;
|
||||||
break;
|
break;
|
||||||
case 'o':
|
case 'o':
|
||||||
if ( ++i >= args.length )
|
if (++i >= args.length)
|
||||||
usageExit();
|
usageExit();
|
||||||
output = args[i];
|
output = args[i];
|
||||||
break;
|
break;
|
||||||
@@ -105,7 +99,7 @@ public class luac {
|
|||||||
littleendian = true;
|
littleendian = true;
|
||||||
break;
|
break;
|
||||||
case 'i':
|
case 'i':
|
||||||
if ( args[i].length() <= 2 )
|
if (args[i].length() <= 2)
|
||||||
usageExit();
|
usageExit();
|
||||||
numberformat = Integer.parseInt(args[i].substring(2));
|
numberformat = Integer.parseInt(args[i].substring(2));
|
||||||
break;
|
break;
|
||||||
@@ -113,12 +107,12 @@ public class luac {
|
|||||||
versioninfo = true;
|
versioninfo = true;
|
||||||
break;
|
break;
|
||||||
case 'c':
|
case 'c':
|
||||||
if ( ++i >= args.length )
|
if (++i >= args.length)
|
||||||
usageExit();
|
usageExit();
|
||||||
encoding = args[i];
|
encoding = args[i];
|
||||||
break;
|
break;
|
||||||
case '-':
|
case '-':
|
||||||
if ( args[i].length() > 2 )
|
if (args[i].length() > 2)
|
||||||
usageExit();
|
usageExit();
|
||||||
processing = false;
|
processing = false;
|
||||||
break;
|
break;
|
||||||
@@ -130,24 +124,22 @@ public class luac {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// echo version
|
// echo version
|
||||||
if ( versioninfo )
|
if (versioninfo)
|
||||||
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++) {
|
||||||
if ( ! processing || ! args[i].startsWith("-") ) {
|
if (!processing || !args[i].startsWith("-")) {
|
||||||
String chunkname = args[i].substring(0,args[i].length()-4);
|
String chunkname = args[i].substring(0, args[i].length()-4);
|
||||||
processScript( globals, new FileInputStream(args[i]), chunkname, fos );
|
processScript(globals, new FileInputStream(args[i]), chunkname, fos);
|
||||||
} else if ( args[i].length() <= 1 ) {
|
} else if (args[i].length() <= 1) {
|
||||||
processScript( globals, System.in, "=stdin", fos );
|
processScript(globals, System.in, "=stdin", fos);
|
||||||
} else {
|
} else {
|
||||||
switch ( args[i].charAt(1) ) {
|
switch (args[i].charAt(1)) {
|
||||||
case 'o':
|
case 'o':
|
||||||
case 'c':
|
case 'c':
|
||||||
++i;
|
++i;
|
||||||
@@ -158,23 +150,22 @@ public class luac {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} finally {
|
|
||||||
fos.close();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch ( IOException ioe ) {
|
} catch (IOException ioe) {
|
||||||
System.err.println( ioe.toString() );
|
System.err.println(ioe.toString());
|
||||||
System.exit(-2);
|
System.exit(-2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void processScript( Globals globals, InputStream script, String chunkname, OutputStream out ) throws IOException {
|
private void processScript(Globals globals, InputStream script, String chunkname, OutputStream out)
|
||||||
|
throws IOException {
|
||||||
try {
|
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)
|
||||||
@@ -185,8 +176,8 @@ public class luac {
|
|||||||
DumpState.dump(chunk, out, stripdebug, numberformat, littleendian);
|
DumpState.dump(chunk, out, stripdebug, numberformat, littleendian);
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch ( Exception e ) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace( System.err );
|
e.printStackTrace(System.err);
|
||||||
} finally {
|
} finally {
|
||||||
script.close();
|
script.close();
|
||||||
}
|
}
|
||||||
270
luaj-jse/src/main/java/luajc.java
Normal file
270
luaj-jse/src/main/java/luajc.java
Normal 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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -26,15 +26,16 @@ 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) {
|
||||||
if ( s == null )
|
if (s == null)
|
||||||
return;
|
return;
|
||||||
stats.add(s);
|
stats.add(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void accept(Visitor visitor) {
|
public void accept(Visitor visitor) {
|
||||||
visitor.visit(this);
|
visitor.visit(this);
|
||||||
}
|
}
|
||||||
@@ -28,7 +28,7 @@ public class Chunk extends SyntaxElement {
|
|||||||
this.block = b;
|
this.block = b;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void accept( Visitor visitor ) {
|
public void accept(Visitor visitor) {
|
||||||
visitor.visit( this );
|
visitor.visit(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -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) {
|
||||||
@@ -33,7 +32,7 @@ public class Exp extends SyntaxElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static Exp numberconstant(String token) {
|
public static Exp numberconstant(String token) {
|
||||||
return new Constant( LuaValue.valueOf(token).tonumber() );
|
return new Constant(LuaValue.valueOf(token).tonumber());
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Exp varargs() {
|
public static Exp varargs() {
|
||||||
@@ -45,56 +44,75 @@ public class Exp extends SyntaxElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static Exp unaryexp(int op, Exp rhs) {
|
public static Exp unaryexp(int op, Exp 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))
|
||||||
return binaryexp( unaryexp(op, b.lhs), b.op, b.rhs );
|
return binaryexp(unaryexp(op, b.lhs), b.op, b.rhs);
|
||||||
}
|
}
|
||||||
return new UnopExp(op, rhs);
|
return new UnopExp(op, rhs);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Exp binaryexp(Exp lhs, int op, Exp rhs) {
|
public static Exp binaryexp(Exp lhs, int op, Exp rhs) {
|
||||||
if ( lhs instanceof UnopExp ) {
|
if (lhs instanceof UnopExp) {
|
||||||
UnopExp u = (UnopExp) lhs;
|
UnopExp u = (UnopExp) lhs;
|
||||||
if ( precedence(op) > precedence(u.op) )
|
if (precedence(op) > precedence(u.op))
|
||||||
return unaryexp( u.op, binaryexp( u.rhs, op, rhs ) );
|
return unaryexp(u.op, binaryexp(u.rhs, op, rhs));
|
||||||
}
|
}
|
||||||
// TODO: cumulate string concatenations together
|
// TODO: cumulate string concatenations together
|
||||||
// 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
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,25 +318,29 @@ 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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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);
|
||||||
}
|
}
|
||||||
@@ -50,13 +50,13 @@ 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void accept(Visitor visitor) {
|
public void accept(Visitor visitor) {
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user