Repository: egranata/aria Branch: master Commit: d3e204e68cb0 Files: 900 Total size: 1.9 MB Directory structure: gitextract_91w9n8tq/ ├── .github/ │ ├── dependabot.yml │ └── workflows/ │ ├── clippy.yml │ ├── fmt.yml │ ├── linux_build_test.yml │ ├── macos_build_test.yml │ ├── release.yml │ ├── slash_clippy.yml │ └── slash_fmt.yml ├── .gitignore ├── .pre-commit-config.yaml ├── CHANGELOG.md ├── CODEOWNERS ├── Cargo.toml ├── Dockerfile ├── LICENSE ├── README.md ├── add_license_marker.sh ├── aria ├── aria-bin/ │ ├── Cargo.toml │ ├── src/ │ │ ├── error_reporting.rs │ │ ├── error_reporting_test/ │ │ │ ├── expected.txt │ │ │ ├── main.aria │ │ │ └── util.aria │ │ ├── file_eval.rs │ │ ├── main.rs │ │ ├── repl_eval.rs │ │ ├── repl_preamble.aria │ │ └── test.rs │ ├── test_assert.aria │ └── test_uncaught_exception.aria ├── b ├── ci_tests.sh ├── compiler-lib/ │ ├── Cargo.toml │ └── src/ │ ├── bc_reader.rs │ ├── bc_writer.rs │ ├── builder/ │ │ ├── block.rs │ │ ├── compiler_opcodes.rs │ │ ├── func.rs │ │ └── mod.rs │ ├── constant_value.rs │ ├── do_compile/ │ │ ├── mod.rs │ │ ├── nodes/ │ │ │ ├── add_operation.rs │ │ │ ├── assert_statement.rs │ │ │ ├── assign_statement.rs │ │ │ ├── break_statement.rs │ │ │ ├── code_block.rs │ │ │ ├── comp_operation.rs │ │ │ ├── continue_statement.rs │ │ │ ├── enum_case_decl.rs │ │ │ ├── enum_decl.rs │ │ │ ├── expression.rs │ │ │ ├── expression_list.rs │ │ │ ├── expression_statement.rs │ │ │ ├── extension_decl.rs │ │ │ ├── float_literal.rs │ │ │ ├── for_statement.rs │ │ │ ├── function_body.rs │ │ │ ├── function_decl.rs │ │ │ ├── identifier.rs │ │ │ ├── if_statement.rs │ │ │ ├── import_from_statement.rs │ │ │ ├── import_statement.rs │ │ │ ├── int_literal.rs │ │ │ ├── lambda.rs │ │ │ ├── list_literal.rs │ │ │ ├── logical_operation.rs │ │ │ ├── match_pattern.rs │ │ │ ├── match_pattern_comp.rs │ │ │ ├── match_pattern_enum_case.rs │ │ │ ├── match_pattern_rel.rs │ │ │ ├── match_statement.rs │ │ │ ├── method_decl.rs │ │ │ ├── mixin_decl.rs │ │ │ ├── mod.rs │ │ │ ├── mul_operation.rs │ │ │ ├── paren_expression.rs │ │ │ ├── parsed_module.rs │ │ │ ├── postfix_rvalue.rs │ │ │ ├── primary.rs │ │ │ ├── rel_operation.rs │ │ │ ├── return_statement.rs │ │ │ ├── shift_operation.rs │ │ │ ├── statement.rs │ │ │ ├── string_literal.rs │ │ │ ├── struct_decl.rs │ │ │ ├── ternary_expression.rs │ │ │ ├── throw_statement.rs │ │ │ ├── try_block.rs │ │ │ ├── try_unwrap_expression.rs │ │ │ ├── unary_operation.rs │ │ │ ├── val_decl_entry.rs │ │ │ ├── val_decl_statement.rs │ │ │ ├── while_statement.rs │ │ │ └── write_opeq_statement.rs │ │ └── postfix.rs │ ├── dump/ │ │ ├── mod.rs │ │ └── opcodes.rs │ ├── lib.rs │ ├── line_table.rs │ ├── module.rs │ └── scope.rs ├── docker/ │ └── release/ │ └── Dockerfile ├── docs/ │ └── index.html ├── examples/ │ ├── 99bottles.aria │ ├── add_license_marker.aria │ ├── advent_of_code_2024_day1.aria │ ├── advent_of_code_2024_day2.aria │ ├── advent_of_code_2024_day3.aria │ ├── command_line_args.aria │ ├── currency.aria │ ├── dir.aria │ ├── fibonacci.aria │ ├── fibonacci_memoized.aria │ ├── fizzbuzz.aria │ ├── github_user.aria │ ├── hello.aria │ ├── parser.aria │ ├── peano.aria │ ├── pi.aria │ ├── sieve.aria │ └── string_escapes.aria ├── lib/ │ └── aria/ │ ├── core/ │ │ ├── arity.aria │ │ ├── bool.aria │ │ ├── box.aria │ │ ├── builtin.aria │ │ ├── float.aria │ │ ├── int.aria │ │ ├── list.aria │ │ ├── maybe.aria │ │ ├── nothing.aria │ │ ├── result.aria │ │ ├── runtime_error.aria │ │ ├── string.aria │ │ ├── unimplemented.aria │ │ └── unit.aria │ ├── date/ │ │ ├── instant.aria │ │ └── timezone.aria │ ├── io/ │ │ ├── file.aria │ │ └── path.aria │ ├── iterator/ │ │ ├── enumerate.aria │ │ ├── mixin.aria │ │ └── zip.aria │ ├── json/ │ │ ├── parser.aria │ │ ├── value.aria │ │ └── writer.aria │ ├── network/ │ │ ├── request.aria │ │ └── retry.aria │ ├── numerics/ │ │ ├── complex.aria │ │ ├── decimal.aria │ │ ├── float/ │ │ │ ├── exp.aria │ │ │ └── trig.aria │ │ ├── int/ │ │ │ └── pow.aria │ │ └── matrix.aria │ ├── ordering/ │ │ ├── compare.aria │ │ └── utils.aria │ ├── range/ │ │ ├── int_extension.aria │ │ └── range.aria │ ├── rng/ │ │ ├── mixin.aria │ │ ├── msws.aria │ │ └── xorshift.aria │ ├── string/ │ │ ├── classes.aria │ │ └── regex.aria │ ├── structures/ │ │ ├── hash/ │ │ │ ├── algo/ │ │ │ │ └── sip.aria │ │ │ └── list.aria │ │ ├── map.aria │ │ ├── queue.aria │ │ ├── set.aria │ │ └── stack.aria │ ├── system/ │ │ ├── coloring.aria │ │ └── platform.aria │ ├── test/ │ │ └── test.aria │ └── utils/ │ └── guard.aria ├── lib-test/ │ ├── README.md │ ├── all/ │ │ └── source.aria │ ├── attributes/ │ │ └── things.aria │ ├── base_module/ │ │ └── nested_module/ │ │ └── content.aria │ ├── circular/ │ │ ├── one.aria │ │ ├── two.aria │ │ └── zero.aria │ ├── cool_widget/ │ │ ├── buzz.aria │ │ ├── lib.aria │ │ └── widget.json │ ├── example/ │ │ ├── pair/ │ │ │ └── Pair.aria │ │ └── two/ │ │ └── things.aria │ ├── exported_var/ │ │ └── source.aria │ ├── ext/ │ │ └── string.aria │ ├── extensible/ │ │ ├── base.aria │ │ └── ext.aria │ ├── multiple/ │ │ └── module.aria │ ├── other_widget/ │ │ ├── a.aria │ │ ├── mod/ │ │ │ └── b.aria │ │ └── widget.json │ ├── same_root/ │ │ └── part1/ │ │ ├── file1.aria │ │ ├── file2.aria │ │ └── file3.aria │ ├── test_things.aria │ └── with_err/ │ └── error.aria ├── lsp/ │ ├── Cargo.toml │ └── src/ │ ├── document.rs │ ├── lexer.rs │ ├── lib.rs │ ├── main.rs │ └── parser.rs ├── microbenchmarks/ │ ├── attribute_read.aria │ ├── attribute_write.aria │ ├── enum_case.aria │ ├── infra.aria │ ├── int_arith.aria │ ├── list_filled.aria │ ├── list_from_closure.aria │ ├── list_read.aria │ ├── list_write.aria │ ├── map_loop.aria │ ├── method_call.aria │ └── sieve.aria ├── native-libs/ │ ├── file/ │ │ ├── Cargo.toml │ │ └── src/ │ │ └── lib.rs │ ├── network/ │ │ ├── Cargo.toml │ │ └── src/ │ │ └── lib.rs │ ├── path/ │ │ ├── Cargo.toml │ │ └── src/ │ │ └── lib.rs │ ├── platform/ │ │ ├── Cargo.toml │ │ └── src/ │ │ └── lib.rs │ ├── regex/ │ │ ├── Cargo.toml │ │ └── src/ │ │ └── lib.rs │ ├── timezone/ │ │ ├── Cargo.toml │ │ └── src/ │ │ └── lib.rs │ └── unicode/ │ ├── Cargo.toml │ └── src/ │ └── lib.rs ├── opcodes-lib/ │ ├── Cargo.toml │ └── src/ │ └── lib.rs ├── package.sh ├── parser-lib/ │ ├── Cargo.toml │ └── src/ │ ├── ast/ │ │ ├── derive/ │ │ │ └── mod.rs │ │ ├── mod.rs │ │ ├── nodes/ │ │ │ ├── add_eq_symbol.rs │ │ │ ├── add_operation.rs │ │ │ ├── add_symbol.rs │ │ │ ├── argument_decl.rs │ │ │ ├── argument_list.rs │ │ │ ├── assert_statement.rs │ │ │ ├── assign_statement.rs │ │ │ ├── break_statement.rs │ │ │ ├── code_block.rs │ │ │ ├── comp_operation.rs │ │ │ ├── comp_symbol.rs │ │ │ ├── continue_statement.rs │ │ │ ├── declaration_id.rs │ │ │ ├── else_piece.rs │ │ │ ├── elsif_piece.rs │ │ │ ├── enum_case_decl.rs │ │ │ ├── enum_decl.rs │ │ │ ├── enum_decl_entry.rs │ │ │ ├── expression.rs │ │ │ ├── expression_list.rs │ │ │ ├── expression_statement.rs │ │ │ ├── extension_decl.rs │ │ │ ├── float_literal.rs │ │ │ ├── for_statement.rs │ │ │ ├── function_body.rs │ │ │ ├── function_decl.rs │ │ │ ├── identifier.rs │ │ │ ├── identifier_list.rs │ │ │ ├── if_cond_piece.rs │ │ │ ├── if_piece.rs │ │ │ ├── if_statement.rs │ │ │ ├── import_from_statement.rs │ │ │ ├── import_path.rs │ │ │ ├── import_statement.rs │ │ │ ├── import_target.rs │ │ │ ├── int_literal.rs │ │ │ ├── lambda_body.rs │ │ │ ├── lambda_function.rs │ │ │ ├── list_literal.rs │ │ │ ├── log_operation.rs │ │ │ ├── log_symbol.rs │ │ │ ├── match_pattern.rs │ │ │ ├── match_pattern_comp.rs │ │ │ ├── match_pattern_enum_case.rs │ │ │ ├── match_pattern_rel.rs │ │ │ ├── match_rule.rs │ │ │ ├── match_statement.rs │ │ │ ├── method_access.rs │ │ │ ├── method_decl.rs │ │ │ ├── mixin_decl.rs │ │ │ ├── mixin_include_decl.rs │ │ │ ├── mod.rs │ │ │ ├── module_flag.rs │ │ │ ├── module_flags.rs │ │ │ ├── mul_operation.rs │ │ │ ├── mul_symbol.rs │ │ │ ├── operator_decl.rs │ │ │ ├── operator_symbol.rs │ │ │ ├── paren_expression.rs │ │ │ ├── parsed_module.rs │ │ │ ├── postfix_expression.rs │ │ │ ├── postfix_rvalue.rs │ │ │ ├── postfix_term.rs │ │ │ ├── postfix_term_attribute.rs │ │ │ ├── postfix_term_call.rs │ │ │ ├── postfix_term_enum_case.rs │ │ │ ├── postfix_term_field_write.rs │ │ │ ├── postfix_term_index.rs │ │ │ ├── postfix_term_index_write.rs │ │ │ ├── postfix_term_object_write.rs │ │ │ ├── postfix_term_try_protocol.rs │ │ │ ├── postfix_term_write.rs │ │ │ ├── postfix_term_write_list.rs │ │ │ ├── primary.rs │ │ │ ├── rel_operation.rs │ │ │ ├── rel_symbol.rs │ │ │ ├── return_statement.rs │ │ │ ├── shift_operation.rs │ │ │ ├── shift_symbol.rs │ │ │ ├── statement.rs │ │ │ ├── string_literal.rs │ │ │ ├── struct_decl.rs │ │ │ ├── struct_entry.rs │ │ │ ├── ternary_expression.rs │ │ │ ├── throw_statement.rs │ │ │ ├── top_level_entry.rs │ │ │ ├── try_block.rs │ │ │ ├── try_unwrap_expression.rs │ │ │ ├── unary_operation.rs │ │ │ ├── unary_symbol.rs │ │ │ ├── val_decl_entry.rs │ │ │ ├── val_decl_statement.rs │ │ │ ├── while_statement.rs │ │ │ └── write_op_eq_statement.rs │ │ └── prettyprint/ │ │ ├── mod.rs │ │ └── printout_accumulator.rs │ ├── grammar/ │ │ ├── grammar.pest │ │ └── mod.rs │ └── lib.rs ├── pgo ├── run_doc_script_tests.sh ├── t ├── test-bin/ │ ├── Cargo.toml │ └── src/ │ └── main.rs ├── tests/ │ ├── alloc_builtin_type.aria │ ├── and.aria │ ├── and_shortcircuit.aria │ ├── arg_isa_mixin.aria │ ├── arg_typehint.aria │ ├── argc_mismatch_error.aria │ ├── aria_version.aria │ ├── arity_of_callable.aria │ ├── as_user_printable.aria │ ├── assert_id_func.aria │ ├── bind_call_enum_instance_method.aria │ ├── bind_call_enum_type_method.aria │ ├── bind_of_free_func.aria │ ├── bind_of_func_on_builtin.aria │ ├── box_type.aria │ ├── break_in_forloop.aria │ ├── build_mixin.aria │ ├── builtin_isa_mixin.aria │ ├── builtin_maybe_enum.aria │ ├── builtin_type_func_takes_This.aria │ ├── builtin_type_type.aria │ ├── builtins_list_attributes.aria │ ├── bw_ops.aria │ ├── call_op_call.aria │ ├── call_struct_func.aria │ ├── chained_try_unwrap.aria │ ├── closure_range_list.aria │ ├── closure_with_body.aria │ ├── cmp_utils.aria │ ├── complex_hash.aria │ ├── complex_numbers.aria │ ├── complex_of_self.aria │ ├── complex_reverse_minus.aria │ ├── continue_in_forloop.aria │ ├── cross_func_exception.aria │ ├── cross_module_mixin_import.aria │ ├── cross_module_var.aria │ ├── cross_module_var_write.aria │ ├── custom_is_unwrap.aria │ ├── custom_to_json_value.aria │ ├── custom_try_unwrap_protocol.aria │ ├── decimal.aria │ ├── decimal_hash.aria │ ├── decimal_prettyprint.aria │ ├── deep_nested_struct.aria │ ├── default_arg_is_immutable.aria │ ├── dir_entries.aria │ ├── div_by_zero_error.aria │ ├── dot_write_of_local.aria │ ├── double_import_from.aria │ ├── double_module_import.aria │ ├── empty_expr_stmt.aria │ ├── empty_func.aria │ ├── enum_case_as_mixin.aria │ ├── enum_case_check_no_payload.aria │ ├── enum_equals.aria │ ├── enum_extend_mixin.aria │ ├── enum_in_struct.aria │ ├── enum_isa_mixn.aria │ ├── enum_list_attributes.aria │ ├── enum_match_case_first_wins.aria │ ├── enum_match_case_typehint.aria │ ├── enum_op_equals.aria │ ├── enum_prettyprint.aria │ ├── enum_with_struct_case.aria │ ├── enum_without_payload.aria │ ├── except_in_op_is_caught.aria │ ├── exception_backtrace.aria │ ├── extend_imported.aria │ ├── extend_included_mixin.aria │ ├── extend_struct.aria │ ├── extension_nested_struct.aria │ ├── extension_on_list.aria │ ├── extension_type_func.aria │ ├── file_io.aria │ ├── file_io.txt │ ├── file_lines_iter.aria │ ├── file_lines_iter.txt │ ├── flatten_results.aria │ ├── float_atan.aria │ ├── float_exp.aria │ ├── float_ln.aria │ ├── float_log_exp.aria │ ├── float_parse_scientific.aria │ ├── float_pow.aria │ ├── float_pretyprint.aria │ ├── float_sqrt.aria │ ├── flt_attrib.aria │ ├── for_else.aria │ ├── for_loop_test.aria │ ├── format_of_nested_brace.aria │ ├── format_with_opt_arg.aria │ ├── fp_arith.aria │ ├── fp_cmp_greater.aria │ ├── fp_cmp_gt_eq.aria │ ├── fp_cmp_lt_eq.aria │ ├── fp_cmp_smaller.aria │ ├── fp_consts.aria │ ├── fp_eq.aria │ ├── fp_ext_notation.aria │ ├── fp_int_arith.aria │ ├── fp_no_suffix.aria │ ├── from_import_two_things.aria │ ├── func_arg_type_mismatch.aria │ ├── func_as_arg.aria │ ├── func_has_multiple_optionals.aria │ ├── func_has_only_vararg.aria │ ├── func_has_vararg.aria │ ├── func_multiple_fixed_vararg.aria │ ├── func_only_takes_opt.aria │ ├── func_order_of_vararg.aria │ ├── func_returns_int.aria │ ├── func_returns_unit.aria │ ├── func_takes_args.aria │ ├── func_type_equals.aria │ ├── func_union_type_mismatch.aria │ ├── func_with_opt_vararg.aria │ ├── func_with_struct.aria │ ├── function_arity.aria │ ├── function_list_attributes.aria │ ├── getenv.aria │ ├── guard_on_return.aria │ ├── guards_exit_on_throw.aria │ ├── has_attr.aria │ ├── hash_builtins.aria │ ├── hash_instant.aria │ ├── hash_maybe.aria │ ├── hex_escapes.aria │ ├── http_get_headers.aria │ ├── http_post.aria │ ├── http_post_json.aria │ ├── http_request_custom_status.aria │ ├── http_simple_get.aria │ ├── identifier_casing.aria │ ├── identifier_syntax.aria │ ├── if_assign_val.aria │ ├── if_false.aria │ ├── if_postfix_obj.aria │ ├── if_takes_else.aria │ ├── if_takes_elsif.aria │ ├── if_takes_if.aria │ ├── if_true.aria │ ├── implicit_is_X.aria │ ├── import_all.aria │ ├── import_from.aria │ ├── import_pair_struct.aria │ ├── import_string_extension.aria │ ├── import_test_things.aria │ ├── import_two_things.aria │ ├── include_trivial_mixin.aria │ ├── index_get.aria │ ├── index_operators_empty.aria │ ├── index_out_of_bounds_error.aria │ ├── index_set.aria │ ├── index_vararg.aria │ ├── inner_function.aria │ ├── inner_function_redef.aria │ ├── inner_is_closure.aria │ ├── inner_outer_loop.aria │ ├── inner_val.aria │ ├── instant_from_unix_2024_12_29.aria │ ├── instant_from_unix_ts.aria │ ├── instant_now.aria │ ├── instant_offset_breaks_eq.aria │ ├── instant_with_tz_offset.aria │ ├── int_abs.aria │ ├── int_arith.aria │ ├── int_fp_int.aria │ ├── int_index_operator.aria │ ├── int_notations.aria │ ├── int_prettyprint_style.aria │ ├── int_range.aria │ ├── int_range_ops.aria │ ├── int_range_step.aria │ ├── int_range_where_iter.aria │ ├── int_shift_test.aria │ ├── int_wraps.aria │ ├── invalid_fileopen_throws.aria │ ├── invalid_utf8_bytes.aria │ ├── isa_intersection.aria │ ├── isa_match.aria │ ├── isa_mixin_union.aria │ ├── isa_operator.aria │ ├── iter_enum.aria │ ├── iter_zip.aria │ ├── iterable_skip.aria │ ├── iterable_truncate.aria │ ├── iterator_mixin.aria │ ├── iterator_type_mismatch.aria │ ├── json_flatten.aria │ ├── json_parse_array.aria │ ├── json_parse_nested.aria │ ├── json_parse_wellknown.aria │ ├── lambda_f_block.aria │ ├── lambda_f_define.aria │ ├── lambda_f_global.aria │ ├── lambda_refers_to_uplevel.aria │ ├── large_hex_int.aria │ ├── large_negative_literal.aria │ ├── list_append.aria │ ├── list_as_map_key.aria │ ├── list_contains.aria │ ├── list_custom_write.aria │ ├── list_drop.aria │ ├── list_equals.aria │ ├── list_filled.aria │ ├── list_for_loop.aria │ ├── list_functional.aria │ ├── list_hash.aria │ ├── list_iter_map.aria │ ├── list_join.aria │ ├── list_length.aria │ ├── list_mul_op.aria │ ├── list_negative_index.aria │ ├── list_op_add.aria │ ├── list_prettyprint.aria │ ├── list_product_negative.aria │ ├── list_search.aria │ ├── list_sorting.aria │ ├── list_sorting_with_cmp.aria │ ├── list_where_iterator.aria │ ├── list_write_out_of_bounds.aria │ ├── local_define_type_mismatch.aria │ ├── local_typehint_any.aria │ ├── local_write_type_mismatch.aria │ ├── lr_shift_custom_op.aria │ ├── lt_gt_comp.aria │ ├── lte_gte_comp.aria │ ├── map_0_capacity.aria │ ├── map_frequency_map.aria │ ├── map_hash_negative.aria │ ├── map_index_init.aria │ ├── map_insert.aria │ ├── map_iter.aria │ ├── map_iterator_where.aria │ ├── map_key_ops.aria │ ├── map_keys.aria │ ├── map_load_factor.aria │ ├── map_remove.aria │ ├── map_set_get.aria │ ├── match_equals.aria │ ├── match_extract_enum_payload.aria │ ├── match_isa_case.aria │ ├── match_not_eq.aria │ ├── match_payload_fails_with_no_payload.aria │ ├── match_rel.aria │ ├── match_uses_custom_op_equals.aria │ ├── match_without_commas.aria │ ├── matrix.aria │ ├── matrix_add.aria │ ├── matrix_det.aria │ ├── matrix_mul.aria │ ├── matrix_transpose.aria │ ├── max_min_empty.aria │ ├── maybe_unwrap.aria │ ├── method_arg_type_mismatch.aria │ ├── method_as_arg.aria │ ├── method_has_vararg.aria │ ├── method_on_type.aria │ ├── method_order_of_vararg.aria │ ├── mismatch_payload.aria │ ├── mix_int_fp_mod.aria │ ├── mix_object_init.aria │ ├── mixin_extension.aria │ ├── mixin_func_This.aria │ ├── mixin_has_enum.aria │ ├── mixin_has_struct.aria │ ├── mixin_in_extension.aria │ ├── mixin_include_mixin.aria │ ├── mixin_include_type_func.aria │ ├── mixin_multiple_commas.aria │ ├── mixin_of_builtin_type.aria │ ├── mixin_of_enum.aria │ ├── mixin_order.aria │ ├── mixin_refers_to_self_method.aria │ ├── mixin_shared_between_types.aria │ ├── mixin_val_decl.aria │ ├── mod_by_zero.aria │ ├── module_level_val.aria │ ├── module_level_var_fdeps.aria │ ├── module_list_attributes.aria │ ├── module_var_isa_mixin.aria │ ├── msrng.aria │ ├── mul_eq_ops.aria │ ├── multidecl_order.aria │ ├── multiple_imports_from.aria │ ├── multiwrite_multiple.aria │ ├── multiwrite_nesting.aria │ ├── multiwrite_of_attribute.aria │ ├── multiwrite_repeat.aria │ ├── multiwrite_side_effecting.aria │ ├── multiwrite_swap.aria │ ├── naked_return.aria │ ├── neg.aria │ ├── nested_closure.aria │ ├── nested_enum_in_func.aria │ ├── nested_enum_with_entries.aria │ ├── nested_extension.aria │ ├── nested_forloop.aria │ ├── nested_guard.aria │ ├── nested_guards_order.aria │ ├── nested_if.aria │ ├── nested_lambda_f.aria │ ├── nested_list.aria │ ├── nested_obj_write.aria │ ├── nested_struct_new.aria │ ├── new_path.aria │ ├── new_range_api.aria │ ├── no_such_case.aria │ ├── no_such_identifier.aria │ ├── not.aria │ ├── nothing_type.aria │ ├── now.aria │ ├── obj_box_read_write.aria │ ├── obj_prettyprint.aria │ ├── obj_write_comprehensive.aria │ ├── obj_write_in_expr.aria │ ├── obj_write_order.aria │ ├── one_guard.aria │ ├── one_line_function.aria │ ├── op_add.aria │ ├── op_call.aria │ ├── op_div.aria │ ├── op_equals.aria │ ├── op_gt.aria │ ├── op_gteq.aria │ ├── op_index_throws.aria │ ├── op_lt.aria │ ├── op_lteq.aria │ ├── op_mul.aria │ ├── op_rem.aria │ ├── op_sub.aria │ ├── operator_overload.aria │ ├── opt_args_this_usage.aria │ ├── or.aria │ ├── or_shortcircuit.aria │ ├── ordering_mixin.aria │ ├── paren_expression.aria │ ├── parse_enum_cases.aria │ ├── parse_fp.aria │ ├── parse_int.aria │ ├── pass_lambda.aria │ ├── path_canonical.aria │ ├── path_checks.aria │ ├── path_common_ancestor.aria │ ├── path_glob.aria │ ├── path_hash.aria │ ├── path_io.aria │ ├── path_io.txt │ ├── path_manipulation.aria │ ├── path_manipulation.txt │ ├── phi.aria │ ├── platform.aria │ ├── plus_minus_eq.aria │ ├── postfix_obj_write.aria │ ├── prettyprint_two_arg.aria │ ├── queue.aria │ ├── queue_with_cmp.aria │ ├── range_hash.aria │ ├── range_to_list.aria │ ├── read_index_multiple.aria │ ├── read_list_index.aria │ ├── read_write_val_of_function.aria │ ├── readattr.aria │ ├── redundant_local_loads.aria │ ├── redundant_named_loads.aria │ ├── regex_api.aria │ ├── result.aria │ ├── result_helpers.aria │ ├── result_to_exception.aria │ ├── result_unwrap.aria │ ├── retry_test.aria │ ├── return_paren_expr.aria │ ├── return_stops_eval.aria │ ├── rng_oneof.aria │ ├── rw_int_attrib.aria │ ├── rw_str_attrib.aria │ ├── set.aria │ ├── set_ops.aria │ ├── setenv.aria │ ├── shape_failed_read_works.aria │ ├── shift_eq_ops.aria │ ├── simple_closure.aria │ ├── simple_default_args.aria │ ├── simple_json_parse.aria │ ├── simple_json_parse_err.aria │ ├── simple_try_unwrap.aria │ ├── sip_hash_test.aria │ ├── sleep.aria │ ├── stack.aria │ ├── str_chr_bytes.aria │ ├── str_encoding.aria │ ├── str_equality.aria │ ├── str_int_mul.aria │ ├── str_len_vs_index.aria │ ├── string_classes.aria │ ├── string_concat.aria │ ├── string_contains.aria │ ├── string_format.aria │ ├── string_format_errors.aria │ ├── string_from_bytes.aria │ ├── string_index.aria │ ├── string_join.aria │ ├── string_negative_index.aria │ ├── string_prefix_suffix.aria │ ├── string_product_negative.aria │ ├── string_remove.aria │ ├── string_replace.aria │ ├── string_split.aria │ ├── string_trim.aria │ ├── strings_anagram_hash.aria │ ├── strlen.aria │ ├── struct_field.aria │ ├── struct_func_redecl.aria │ ├── struct_in_enum.aria │ ├── struct_in_struct.aria │ ├── struct_isa_mixin.aria │ ├── struct_list_attributes.aria │ ├── struct_methods_refer_each_other.aria │ ├── struct_methods_refer_outoforder.aria │ ├── struct_mixin_multiple.aria │ ├── struct_takes_self_arg.aria │ ├── struct_with_opt_args.aria │ ├── substring.aria │ ├── successive_ifs.aria │ ├── system_of_no_such_cmd_err.aria │ ├── ternary_operator.aria │ ├── ternary_operator_nested.aria │ ├── ternary_operator_precedence.aria │ ├── test_module.aria │ ├── test_shell_command.aria │ ├── test_with_no_main.aria │ ├── throw_in_catch.aria │ ├── throws_func.aria │ ├── to_json_string.aria │ ├── to_json_value.aria │ ├── top_level_assign.aria │ ├── top_level_code_block.aria │ ├── top_level_expr_stmt.aria │ ├── top_level_guard.aria │ ├── top_level_plus_eq.aria │ ├── top_level_shift_eq.aria │ ├── top_level_try.aria │ ├── trig.aria │ ├── trivial_if.aria │ ├── trivial_try_block.aria │ ├── try_nothrow.aria │ ├── try_unwinds_guard.aria │ ├── try_unwrap_coalesce.aria │ ├── try_unwrap_maybe.aria │ ├── try_unwrap_non_result.aria │ ├── type_func_takes_This.aria │ ├── type_root.aria │ ├── type_val_in_enum.aria │ ├── typecheck_as_struct.aria │ ├── unexpected_type_error.aria │ ├── union_type_passes.aria │ ├── unit_type.aria │ ├── unused_local_typechecks.aria │ ├── unused_local_value.aria │ ├── unused_typed_local.aria │ ├── unwrap_single_eval.aria │ ├── uplevel_can_write_attrib.aria │ ├── uplevel_write_before_read.aria │ ├── upper_lower.aria │ ├── while_break.aria │ ├── while_continue.aria │ ├── while_else.aria │ ├── while_missed.aria │ ├── while_taken.aria │ ├── widget_test.aria │ ├── write_attrib_struct.aria │ ├── write_index.aria │ ├── write_index_multiple.aria │ ├── write_list_index.aria │ ├── writeattr.aria │ ├── xor.aria │ └── xorshift.aria ├── tree_check.sh ├── vm-lib/ │ ├── Cargo.toml │ ├── benches/ │ │ └── control_flow.rs │ └── src/ │ ├── arity.rs │ ├── builtins/ │ │ ├── alloc.rs │ │ ├── arity.rs │ │ ├── boolean.rs │ │ ├── cmdline_args.rs │ │ ├── exit.rs │ │ ├── float.rs │ │ ├── getenv.rs │ │ ├── hasattr.rs │ │ ├── integer.rs │ │ ├── list.rs │ │ ├── listattrs.rs │ │ ├── maybe.rs │ │ ├── mod.rs │ │ ├── native_iterator.rs │ │ ├── now.rs │ │ ├── prettyprint.rs │ │ ├── print.rs │ │ ├── println.rs │ │ ├── readattr.rs │ │ ├── readln.rs │ │ ├── result.rs │ │ ├── runtime_error.rs │ │ ├── setenv.rs │ │ ├── sleep.rs │ │ ├── string.rs │ │ ├── system.rs │ │ ├── test_exit.aria │ │ ├── typ.rs │ │ ├── typeof_builtin.rs │ │ ├── unimplemented.rs │ │ ├── unit.rs │ │ └── writeattr.rs │ ├── console.rs │ ├── error/ │ │ ├── backtrace.rs │ │ ├── dylib_load.rs │ │ ├── exception.rs │ │ ├── mod.rs │ │ └── vm_error.rs │ ├── frame.rs │ ├── lib.rs │ ├── mixin_includer.rs │ ├── opcodes/ │ │ ├── mod.rs │ │ ├── prettyprint.rs │ │ └── sidecar.rs │ ├── runtime_module.rs │ ├── runtime_value/ │ │ ├── boolean.rs │ │ ├── bound_function.rs │ │ ├── builtin_value.rs │ │ ├── enum_case.rs │ │ ├── enumeration.rs │ │ ├── float.rs │ │ ├── function.rs │ │ ├── integer.rs │ │ ├── isa.rs │ │ ├── kind.rs │ │ ├── list.rs │ │ ├── mixin.rs │ │ ├── mod.rs │ │ ├── object.rs │ │ ├── opaque.rs │ │ ├── runtime_code_object.rs │ │ ├── rust_native_type.rs │ │ ├── string.rs │ │ └── structure.rs │ ├── shape.rs │ ├── stack.rs │ ├── symbol.rs │ ├── test.rs │ └── vm.rs └── vscode/ └── aria/ ├── .vscodeignore ├── LICENSE ├── README.md ├── build.sh ├── language-configuration.json ├── package.json ├── src/ │ └── extension.ts ├── syntaxes/ │ └── aria.tmLanguage.json ├── tsconfig.json └── tsconfig.tsbuildinfo ================================================ FILE CONTENTS ================================================ ================================================ FILE: .github/dependabot.yml ================================================ # To get started with Dependabot version updates, you'll need to specify which # package ecosystems to update and where the package manifests are located. # Please see the documentation for all configuration options: # https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file version: 2 updates: - package-ecosystem: "cargo" # See documentation for possible values directory: "/" # Location of package manifests schedule: interval: "weekly" ================================================ FILE: .github/workflows/clippy.yml ================================================ name: Run Clippy on PR on: repository_dispatch: types: [clippy-command] permissions: contents: write pull-requests: write jobs: clippy: runs-on: ubuntu-latest steps: - name: Resolve PR head id: pr run: | echo "repo=${{ github.event.client_payload.pull_request.head.repo.full_name }}" >> "$GITHUB_OUTPUT" echo "ref=${{ github.event.client_payload.pull_request.head.ref }}" >> "$GITHUB_OUTPUT" echo "number=${{ github.event.client_payload.pull_request.number }}" >> "$GITHUB_OUTPUT" - name: Set token id: token run: | if [ -n "${{ secrets.REPO_SCOPED_TOKEN }}" ]; then echo "token=${{ secrets.REPO_SCOPED_TOKEN }}" >> "$GITHUB_OUTPUT" else echo "token=${{ secrets.GITHUB_TOKEN }}" >> "$GITHUB_OUTPUT" fi - name: Checkout PR head uses: actions/checkout@v4 with: repository: ${{ steps.pr.outputs.repo }} ref: ${{ steps.pr.outputs.ref }} token: ${{ steps.token.outputs.token }} fetch-depth: 0 - name: Install Rust (stable + clippy) uses: dtolnay/rust-toolchain@stable with: components: clippy - name: Run cargo clippy id: clippy run: | set +e cargo clippy --all-targets --no-deps -- -D warnings > clippy_output.txt 2>&1 status=$? echo "status=$status" >> $GITHUB_OUTPUT exit 0 - name: Upload Clippy output uses: actions/upload-artifact@v4 with: name: clippy-log path: clippy_output.txt - name: Comment results on PR uses: peter-evans/create-or-update-comment@v4 with: token: ${{ steps.token.outputs.token }} issue-number: ${{ steps.pr.outputs.number }} body: | 🧹 `cargo clippy` has completed on `${{ steps.pr.outputs.ref }}`. ${{ steps.clippy.outputs.status == '0' && '✅ No issues found!' || '⚠️ Warnings or errors detected – see Clippy log artifact.' }} ================================================ FILE: .github/workflows/fmt.yml ================================================ name: Check PR Formatting with cargo fmt on: repository_dispatch: types: [fmt-command] permissions: contents: read pull-requests: write jobs: fmt: runs-on: ubuntu-latest steps: - name: Resolve PR head id: pr run: | echo "repo=${{ github.event.client_payload.pull_request.head.repo.full_name }}" >> "$GITHUB_OUTPUT" echo "ref=${{ github.event.client_payload.pull_request.head.ref }}" >> "$GITHUB_OUTPUT" echo "number=${{ github.event.client_payload.pull_request.number }}" >> "$GITHUB_OUTPUT" - name: Checkout PR head uses: actions/checkout@v4 with: repository: ${{ steps.pr.outputs.repo }} ref: ${{ steps.pr.outputs.ref }} fetch-depth: 0 - name: Install Rust (stable + rustfmt) uses: dtolnay/rust-toolchain@stable with: components: rustfmt - name: Run cargo fmt id: fmt run: | cargo fmt --all -- --check || echo "changes_needed=true" >> "$GITHUB_OUTPUT" - name: Comment on PR uses: peter-evans/create-or-update-comment@v4 with: token: ${{ secrets.GITHUB_TOKEN }} issue-number: ${{ steps.pr.outputs.number }} body: | ✅ `cargo fmt` completed on `${{ steps.pr.outputs.ref }}`. ${{ steps.fmt.outputs.changes_needed == 'true' && '❌ Formatting issues detected. Please run `cargo fmt --all` locally and push the fixes.' || '🎉 Code is properly formatted. No action needed.' }} ================================================ FILE: .github/workflows/linux_build_test.yml ================================================ name: LinuxBuildAndTest permissions: contents: read on: push: branches: [ "master" ] pull_request: branches: [ "master" ] env: CARGO_TERM_COLOR: always jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Check tree run: ./tree_check.sh - name: Build run: cargo build --verbose - name: Run tests run: ./ci_tests.sh ================================================ FILE: .github/workflows/macos_build_test.yml ================================================ name: MacOSBuildAndTest permissions: contents: read on: push: branches: [ "master" ] pull_request: branches: [ "master" ] env: CARGO_TERM_COLOR: always jobs: build: runs-on: macos-latest steps: - uses: actions/checkout@v4 - name: Check tree run: ./tree_check.sh - name: Build run: cargo build --verbose - name: Run tests run: ./ci_tests.sh ================================================ FILE: .github/workflows/release.yml ================================================ permissions: contents: write name: release on: push: tags: ["v*.*.*"] jobs: build: strategy: matrix: os: [ubuntu-latest, macos-latest] runs-on: ${{ matrix.os }} env: BIN_TARGETS: "aria" DYLIB_CRATES: "aria_file aria_http aria_path aria_platform aria_regex aria_timezone aria_unicode" EXTRA_FILES: "CHANGELOG.md" CARGO_TERM_COLOR: always steps: - uses: actions/checkout@v4 - uses: dtolnay/rust-toolchain@stable - name: Get version id: version run: echo "VERSION=${GITHUB_REF##refs/tags/}" >> "$GITHUB_ENV" - name: Build + package shell: bash run: ./package.sh - name: Upload release assets uses: softprops/action-gh-release@v2 with: files: | *.tgz *.tgz.sha256 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} ================================================ FILE: .github/workflows/slash_clippy.yml ================================================ name: SlashClippy on: issue_comment: types: [created] permissions: contents: write issues: write pull-requests: read jobs: dispatch: if: ${{ github.event.issue.pull_request && startsWith(github.event.comment.body, '/clippy') }} runs-on: ubuntu-latest permissions: issues: write pull-requests: write steps: - uses: peter-evans/slash-command-dispatch@v4 with: token: ${{ secrets.SLASH_COMMAND_PAT }} reaction-token: ${{ secrets.SLASH_COMMAND_PAT }} commands: clippy dispatch-type: repository issue-type: pull-request repository: ${{ github.repository }} ================================================ FILE: .github/workflows/slash_fmt.yml ================================================ name: SlashFmt on: issue_comment: types: [created] # Needed: # - issues: write → add 👍 reaction # - contents: write → fire repository_dispatch permissions: contents: write issues: write pull-requests: read jobs: dispatch: if: ${{ github.event.issue.pull_request && startsWith(github.event.comment.body, '/fmt') }} runs-on: ubuntu-latest permissions: issues: write pull-requests: write steps: - uses: peter-evans/slash-command-dispatch@v4 with: # Use GITHUB_TOKEN now that it has write perms token: ${{ secrets.SLASH_COMMAND_PAT }} reaction-token: ${{ secrets.SLASH_COMMAND_PAT }} commands: fmt dispatch-type: repository issue-type: pull-request repository: ${{ github.repository }} ================================================ FILE: .gitignore ================================================ # Rust & Cargo /target # Profilers callgrind.out.* perf.* # IDEs and Editors .vscode/ .idea/ *.swp *.swo # NPM node_modules/ out/ # Aria-specific history.aria /vscode/aria/*.vsix # OS-specific .DS_Store Thumbs.db .env ================================================ FILE: .pre-commit-config.yaml ================================================ repos: - repo: https://github.com/doublify/pre-commit-rust rev: v1.0 hooks: - id: fmt - id: cargo-check - id: clippy - repo: http://github.com/Quard/license-header-checker rev: v0.1 hooks: - id: license-header-checker files: \.rs$ args: - --comment-style - "//" - --license - "SPDX-License-Identifier: Apache-2.0\n" - repo: http://github.com/Quard/license-header-checker rev: v0.1 hooks: - id: license-header-checker files: \.aria$ args: - --license - "SPDX-License-Identifier: Apache-2.0\n" ================================================ FILE: CHANGELOG.md ================================================ # Changelog All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). For information on Aria's versioning scheme and release policy refer to [our Release Policy](https://arialang.github.io/release_policy.html). ## [0.9.20251222] ### Added - Values of builtin types can now be checked for `mixin` - Lists and strings allow wraparound indexing (e.g. `foo[-1]`) - shift-equal operators (`<<=` and `=>>`) - `\r` is now recognized as a valid escape sequence - `JSONValue` prettyprints ### Fixed - Multiplying a list or string by a negative integer returns an empty value - `File.writeln` now actually writes a newline - REPL input can now contain comments - `MixinRng.one_of` will fail if passed an empty list as input - String classes API now supports Unicode - Negative timestamps are now resolved correctly by `Instant` ### Changed - in `match` statements, `case Foo(blah)` will fail if `Foo` does not have a payload instead of throwing a VM error - `String.hash` will return different values for anagrams ### Deprecated None ### Removed None ## [0.9.20251118] ### Added - Add support for `??` and `!!` operators to `Maybe` objects - Support for skipping and truncating iterators - `SipHash` support has been added to the standard library - Benchmarking utilities have been introduced to measure performance of code snippets - `List` can now be hashed if all its values are hashable - `Path.glob` - Initial support for widgets as a code organizing structure - Draft language server protocol (LSP) support for better IDE integration - It is now possible to write `x,y = y,x` for swapping values (multiple assignment) and to declare multiple variables in one statement (`val x = 1, y = 2;`) - `Map.frequency_map` has been added to create frequency maps from iterables - Intersection types (`TypeA & TypeB`) have been introduced ### Fixed - `Map` would error if an object's `hash` returned a negative value; it now handles this correctly - It is now possible to write to a captured value without reading it - `isa` now works with mixins ### Changed - `Path.entries()` returns an iterator instead of a list for better performance - `Path` operations consistently return `Maybe` / `Result` types for improved error handling - `Iterator` uses `Maybe` instead of `.done` for its iteration protocol - Hexadecimal literals are treated as unsigned integers - Aria now lives under the `arialang` GitHub organization (https://github.com/arialang/aria) ### Deprecated None ### Removed None ================================================ FILE: CODEOWNERS ================================================ # Failsafe, if nobody else can pick up a review, I can * @egranata # List more specific code owners here .github/workflows/macos* @enricobolzonello native-libs/path @ZocoLini lib/aria/io/path.aria @ZocoLini .github/workflows/slash* @dlkritter .github/workflows/clippy.yml @dlkritter .github/workflows/fmt.yml @dlkritter lsp @feznyng vscode/aria @feznyng ================================================ FILE: Cargo.toml ================================================ [workspace] members = [ "aria-bin", "compiler-lib", "lsp", "native-libs/*", "opcodes-lib", "parser-lib", "test-bin", "vm-lib", ] resolver = "2" [profile.dist] inherits = "release" codegen-units = 1 lto = "fat" debug = true [profile.pgo] inherits = "release" lto = "thin" debug = true ================================================ FILE: Dockerfile ================================================ # syntax=docker/dockerfile:1 # This Docker container installs Aria from prebuilt binaries on Ubuntu 24.04. # It can be used as a base image for Aria development or to run Aria in CI. FROM ubuntu:24.04 # To build with a specific version, use: # docker build --build-arg ARIA_VERSION= --build-arg ARIA_BUILD_TIMESTAMP= --build-arg ARIA_EXPECTED_SHA256= -t aria: . # Example: # docker build --build-arg ARIA_VERSION=0.9.20251220 --build-arg ARIA_BUILD_TIMESTAMP=20251220123456 --build-arg ARIA_EXPECTED_SHA256=47cb8d9de3a2229f1a403e1c616679811f085e819c1743e263c16c2c2d001d50 -t aria:0.9.20251220 . ARG ARIA_VERSION=0.9.20251222 ARG ARIA_BUILD_TIMESTAMP=20251222174650 ARG ARIA_EXPECTED_SHA256=47cb8d9de3a2229f1a403e1c616679811f085e819c1743e263c16c2c2d001d50 ENV DEBIAN_FRONTEND=noninteractive RUN apt-get update \ && apt-get install -y --no-install-recommends ca-certificates curl tar findutils \ && rm -rf /var/lib/apt/lists/* RUN set -eux; \ url="https://github.com/arialang/aria/releases/download/v${ARIA_VERSION}/aria-${ARIA_VERSION}-x86_64-unknown-linux-gnu-${ARIA_BUILD_TIMESTAMP}.tgz"; \ mkdir -p /usr/aria; \ curl -fsSL "$url" -o /tmp/aria.tgz; \ echo "$ARIA_EXPECTED_SHA256 /tmp/aria.tgz" | sha256sum -c -; \ tar -xzf /tmp/aria.tgz -C /usr/aria; \ rm -f /tmp/aria.tgz; \ if [ ! -x /usr/aria/aria ]; then \ aria_path="$(find /usr/aria -maxdepth 4 -type f -name aria -perm -111 | head -n1 || true)"; \ if [ -n "$aria_path" ] && [ "$aria_path" != "/usr/aria/aria" ]; then \ ln -sf "$aria_path" /usr/aria/aria; \ fi; \ fi; \ if [ ! -x /usr/aria/aria ]; then \ echo "Error: 'aria' executable not found under /usr/aria after extraction from $url" >&2; \ exit 1; \ fi; \ ln -sf /usr/aria/aria /usr/local/bin/aria CMD ["bash", "-lc", "printf 'Aria is available in your environment. Start it by running \"aria\"\\n'; exec bash -i"] ================================================ FILE: LICENSE ================================================ Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright 2025 Enrico Granata Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ================================================ FILE: README.md ================================================ # Aria: A Fresh, Safe, and Flexible Language for High-Level Development [![Linux Build](https://github.com/arialang/aria/actions/workflows/linux_build_test.yml/badge.svg?branch=master)](https://github.com/arialang/aria/actions/workflows/linux_build_test.yml) [![Mac Build](https://github.com/arialang/aria/actions/workflows/macos_build_test.yml/badge.svg?branch=master)](https://github.com/arialang/aria/actions/workflows/macos_build_test.yml) [![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0) [![Docs](https://img.shields.io/badge/Docs-Available-blue.svg)](https://arialang.github.io/) [![Contributors](https://img.shields.io/github/contributors/arialang/aria)](https://github.com/arialang/aria/graphs/contributors) Please read [this post](https://arialang.github.io/blog/2026_02/post.html) for the latest update on Aria. Welcome to Aria. Aria is a modern, dynamic scripting language. It is meant to be a "sweet spot" language, easy to pick-up and with a good balance between ease of use, safety, and flexibility. Aria's design choices help you build great programs quickly. Aria has modern, safer error handling: Aria replaces unreliable `None` pointer checks with a modern, multi-tiered approach to error handling. By emphasizing algebraic data types (e.g. `Maybe`), Aria makes errors explicit, safer, and easier to manage, with fewer runtime surprises. `null`, the [billion dollar mistake](https://softwareengineering.stackexchange.com/questions/413149/if-null-is-a-billion-dollar-mistake-what-is-the-solution-to-represent-a-non-ini) just does not exist in Aria, making code safer, easier to maintain and error handling more robust. ```aria func main() { val x = Int.parse("abc123"); match x { case Ok(val) => { println("Parsed value: {0}".format(val)); }, case Err(err) => { println("Failed to parse integer: {0}".format(err)); } } } ``` Aria is memory safe from the start: Aria’s virtual machine, built on the Rust ecosystem, ensures memory safety out of the box, protecting you from common pitfalls like data corruption and security vulnerabilities. This lets you focus on building without worrying about risks you cannot manage. Memory safety protects your code from issues such as memory corruption and dangling pointers. These issues can be hard to track down in large, complex systems. Aria brings these guarantees right from the start, so you can focus on building, not debugging. Aria is designed for flexibility: Whether you need (some) type checks, an intuitive module system, or want to avoid the complexity of inheritance while still working with a modern object-based design, Aria adapts to your needs. It provides just enough structure to keep your code clean, without the overhead. Aria’s object-based design uses composition instead of inheritance, which removes a lot of complexity from the language. This makes Aria easier to learn, your code easier to understand and maintain, and libraries more composable. Many parts of the Aria library adopt `mixin`s to bring code reuse, and you can too. ```aria mixin Double { func double() { return this + this; } } extension Int { include Double } extension Float { include Double } func main() { println(3.double()); println(3.14.double()); } ``` Aria has a simple yet usable standard library, with date/time handling, networking, file system access, JSON support and more. ```aria import Instant from aria.date.instant; func main() { val now = Instant.now(); println("The current date and time is: {0}".format(now)); } ``` ```aria import JsonValue from aria.json.parser; func main() { val json_data = JsonValue.parse('{"name": "Aria", "version": "0.9"}')!.flatten(); println("Language: {0}, Version: {1}".format(json_data["name"], json_data["version"])); } ``` Aria is currently supported on Linux and macOS. Contributions for other operating systems are welcome and encouraged! ## A Taste of Aria Aria is easy to learn. Here's a [quick example](https://github.com/arialang/aria/blob/master/examples/github_user.aria) that fetches data from a web API and prints the result. In this example, Aria fetches user data from GitHub’s API and prints the number of public repositories for a given user. This shows how simple it is to interact with external APIs and handle dynamic data in Aria. ```aria # github_user.aria import Request from aria.network.request; import JsonValue from aria.json.parser; val whoami = "egranata"; func main() { val request = Request.new("https://api.github.com/users/{0}".format(whoami)); request.headers["User-Agent"] = "AriaLang/1.0"; val response = request.get(); if response.status_code == 200 { val user_data = JsonValue.parse(response.content)!.flatten(); println("User {1} has {0} public repositories.".format(user_data["public_repos"], whoami)); } else { println("Failed to fetch user data. Status: {0}".format(response.status_code)); } } ``` Running this is as simple as: ```shell $ aria github_user.aria User egranata has 5 public repositories. ``` ## Getting Started Ready to try Aria? Want to contribute to the language? Great! Whether you’re fixing bugs, adding features, or improving the documentation, we’d love your help! If it's your first time contributing, check out [good starter bugs](https://github.com/arialang/aria/issues?q=is%3Aissue%20state%3Aopen%20label%3A%22good%20first%20issue%22) or [help wanted](https://github.com/arialang/aria/issues?q=is%3Aissue%20state%3Aopen%20label%3A%22help%20wanted%22) on GitHub. For all this and more, visit [our website](https://arialang.github.io/)! ================================================ FILE: add_license_marker.sh ================================================ #!/bin/bash set -euo pipefail rust_license_comment="// SPDX-License-Identifier: Apache-2.0" aria_license_comment="# SPDX-License-Identifier: Apache-2.0" check_mode=false [[ "${1:-}" == "--check" ]] && check_mode=true missing=0 handle_file() { local file="$1" license="$2" if ! grep -qF "$license" "$file"; then if $check_mode; then echo "Missing license in $file" missing=1 else echo "Adding license to $file" tmp="$(mktemp "${file}.XXXX")" { printf '%s\n' "$license"; cat -- "$file"; } >"$tmp" chmod --reference="$file" "$tmp" 2>/dev/null || true mv -f -- "$tmp" "$file" fi fi } while IFS= read -r -d '' file; do case "$file" in *.rs) handle_file "$file" "$rust_license_comment" ;; *.aria) handle_file "$file" "$aria_license_comment" ;; esac done < <( find . -type d -name target -prune -o \ -type f \( -name '*.rs' -o -name '*.aria' \) -print0 ) if $check_mode; then if (( missing == 1 )); then exit 1; fi echo "All files have license info" fi ================================================ FILE: aria ================================================ #!/bin/sh cargo build --workspace --profile ${ARIA_BUILD_CONFIG:-"release"} SELF_DIR="$(dirname "$(readlink -f "${BASH_SOURCE[0]}")")" ARIA_LIB_DIR=${ARIA_LIB_DIR:-"${SELF_DIR}/lib:${SELF_DIR}/lib-test"} cargo run --profile ${ARIA_BUILD_CONFIG:-"release"} --package aria-bin -- $@ ================================================ FILE: aria-bin/Cargo.toml ================================================ [package] name = "aria-bin" version = "0.9.20251222" edition = "2024" [dependencies] opcodes-lib = { path = "../opcodes-lib" } parser-lib = { path = "../parser-lib" } compiler-lib = { path = "../compiler-lib" } vm-lib = { path = "../vm-lib" } clap = { version = "4.5.57", features = ["derive"] } ariadne = { git = "https://github.com/zesterer/ariadne.git", rev="b60b500" } reedline = "0.45.0" pprof = { version = "0.15.0", features = ["cpp", "default", "flamegraph", "framehop", "framehop-unwinder", "perfmaps", "_protobuf", "prost-codec"] } [[bin]] name = "aria" path = "src/main.rs" ================================================ FILE: aria-bin/src/error_reporting.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use std::{collections::HashMap, vec}; use aria_compiler::do_compile::CompilationError; use aria_parser::ast::{ParserError, SourcePointer}; use ariadne::{Color, Label, Report, ReportKind, Source}; use haxby_vm::{ error::{exception::VmException, vm_error::VmError}, vm::VirtualMachine, }; #[derive(Default, Debug, Clone)] pub struct StringCache { buffers: HashMap, } impl ariadne::Cache for StringCache { type Storage = String; fn fetch( &mut self, path: &String, ) -> Result<&Source<>::Storage>, impl std::fmt::Debug> { Ok::<&Source, Source>(&self.buffers[path]) } #[allow(refining_impl_trait)] fn display<'a>(&self, path: &'a String) -> Option { Some(Box::new((*path).clone())) } } pub(crate) type PrintableReport<'a> = ( ariadne::Report<'a, (std::string::String, std::ops::Range)>, StringCache, ); fn build_report_from_msg_and_location<'a>( msg: &str, locations: Vec, ) -> PrintableReport<'a> { let config = ariadne::Config::default().with_index_type(ariadne::IndexType::Byte); let magenta = Color::Magenta; let mut report = Report::build(ReportKind::Error, ("unknown".to_owned(), 0..0)) .with_message(msg) .with_config(config); let mut cache = StringCache::default(); for (idx, loc) in locations.iter().enumerate() { let loc = loc.clone(); report = report.with_label( Label::new(( loc.buffer.name.clone(), loc.location.start..loc.location.stop, )) .with_message("here") .with_order(idx as i32) .with_color(magenta), ); if !cache.buffers.contains_key(&loc.buffer.name) { cache.buffers.insert( loc.buffer.name.clone(), Source::from((*loc.buffer.content).clone()), ); } } (report.finish(), cache) } pub(crate) fn print_report_from_vm_exception(vm: &mut VirtualMachine, exc: &VmException) { let (report, cache) = build_report_from_vm_exception(vm, exc); report.eprint(cache).unwrap(); } pub(crate) fn print_report_from_compiler_error(err: &CompilationError) { let (report, cache) = build_report_from_compiler_error(err); report.eprint(cache).unwrap(); } pub(crate) fn print_report_from_parser_error(err: &ParserError) { let (report, cache) = build_report_from_parser_error(err); report.eprint(cache).unwrap(); } pub(crate) fn print_report_from_vm_error(err: &VmError) { let (report, cache) = build_report_from_vm_error(err); report.eprint(cache).unwrap(); } pub(crate) fn build_report_from_vm_error<'a>(err: &VmError) -> PrintableReport<'a> { let msg = err.reason.to_string(); if err.backtrace.is_empty() { if let Some(loc) = &err.loc { build_report_from_msg_and_location(&msg, vec![loc.clone()]) } else { build_report_from_msg_and_location(&msg, vec![]) } } else { let backtraces: Vec<_> = err.backtrace.entries_iter().cloned().collect(); build_report_from_msg_and_location(&msg, backtraces) } } pub(crate) fn build_report_from_vm_exception<'a>( vm: &mut VirtualMachine, exc: &'a VmException, ) -> PrintableReport<'a> { let mut cur_frame = Default::default(); let msg = exc.value.prettyprint(&mut cur_frame, vm); let backtraces: Vec<_> = exc.backtrace.entries_iter().cloned().collect(); build_report_from_msg_and_location(&msg, backtraces) } pub(crate) fn build_report_from_compiler_error<'a>( err: &'a CompilationError, ) -> PrintableReport<'a> { let msg = err.reason.to_string(); let loc = &err.loc; build_report_from_msg_and_location(&msg, vec![loc.clone()]) } pub(crate) fn build_report_from_parser_error<'a>(err: &'a ParserError) -> PrintableReport<'a> { let msg = &err.msg; let loc = &err.loc; build_report_from_msg_and_location(msg, vec![loc.clone()]) } ================================================ FILE: aria-bin/src/error_reporting_test/expected.txt ================================================ main.aria:6:9 util.aria:3:13 main.aria:14:8 ================================================ FILE: aria-bin/src/error_reporting_test/main.aria ================================================ # SPDX-License-Identifier: Apache-2.0 import foo from util; func op(x,y) { if x > 0 { throw "x is positive :("; } return y + x; } func main() { # this is reported as 6:9 (the location of the throw, not the location of the call) # which is a bug, but I need to fix that orthogonally to this test foo(op,3); } ================================================ FILE: aria-bin/src/error_reporting_test/util.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func foo(f, n) { return f(3,n); } ================================================ FILE: aria-bin/src/file_eval.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use aria_compiler::{CompilationOptions, compile_from_ast}; use aria_parser::ast::{ SourceBuffer, prettyprint::{PrettyPrintable, printout_accumulator::PrintoutAccumulator}, source_to_ast, }; use haxby_vm::{ runtime_module::RuntimeModule, vm::{VirtualMachine, VmOptions}, }; use crate::{ Args, error_reporting::{ print_report_from_compiler_error, print_report_from_parser_error, print_report_from_vm_error, print_report_from_vm_exception, }, }; impl From<&Args> for CompilationOptions { fn from(value: &Args) -> Self { CompilationOptions { optimize: !value.disable_optimizer, dump_builder: value.dump_ir, } } } // To permit return Err(report_blah(x)) where report_blah(x) -> () #[allow(clippy::unit_arg)] fn eval_buffer( sb: SourceBuffer, vm: &mut VirtualMachine, args: &Args, ) -> Result { let ast = match source_to_ast(&sb) { Ok(ast) => ast, Err(err) => { return Err(print_report_from_parser_error(&err)); } }; if args.dump_ast { let ast_buffer = PrintoutAccumulator::default(); let output = ast.prettyprint(ast_buffer).value(); println!("AST dump:\n{output}\n"); } let comp_opts = CompilationOptions::from(args); let c_module = match compile_from_ast(&ast, &comp_opts) { Ok(module) => module, Err(err) => { err.iter().for_each(print_report_from_compiler_error); return Err(()); } }; if args.dump_mod { let mod_buffer = PrintoutAccumulator::default(); let output = c_module.prettyprint(mod_buffer).value(); println!("Module dump:\n{output}\n"); } let r_module = match RuntimeModule::new(vm, c_module) { Ok(m) => m, Err(err) => { return Err(print_report_from_vm_error(&err.into())); } }; let r_module = match vm.load_into_module("", r_module) { Ok(rle) => match rle { haxby_vm::vm::RunloopExit::Ok(m) => m.module, haxby_vm::vm::RunloopExit::Exception(exc) => { return Err(print_report_from_vm_exception(vm, &exc)); } }, Err(err) => { return Err(print_report_from_vm_error(&err)); } }; let exec_result = vm.execute_module(&r_module); match exec_result { Ok(rle) => match rle { haxby_vm::vm::RunloopExit::Ok(_) => Ok(r_module), haxby_vm::vm::RunloopExit::Exception(exc) => { Err(print_report_from_vm_exception(vm, &exc)) } }, Err(err) => Err(print_report_from_vm_error(&err)), } } pub(crate) fn file_eval(path: &str, args: &Args) -> i32 { use pprof::protos::Message; use std::io::Write; let mut vm = VirtualMachine::with_options(VmOptions::from(args)); let guard = if args.perf_trace_dest.is_some() { match pprof::ProfilerGuardBuilder::default() .frequency(1000) .blocklist(&["libc", "libgcc", "pthread", "vdso"]) .build() { Ok(guard) => Some(guard), Err(err) => { eprintln!("could not start profiler: {}", err); return 1; } } } else { None }; let buffer = SourceBuffer::file(path); let exit = match buffer { Ok(src) => match eval_buffer(src, &mut vm, args) { Ok(_) => 0, Err(_) => 1, }, Err(err) => { println!("error reading source file: {err}"); 1 } }; if let Some(guard) = guard && let Ok(report) = guard.report().build() { let mut content = Vec::new(); if let Ok(mut dest_file) = std::fs::File::create(args.perf_trace_dest.as_ref().unwrap()) && let Ok(profile) = report.pprof() && let Ok(_) = profile.encode(&mut content) { dest_file .write_all(&content) .expect("could not write pprof report"); dest_file.flush().expect("could not flush pprof report"); } else { eprintln!("could not generate pprof report"); return exit; } } exit } ================================================ FILE: aria-bin/src/main.rs ================================================ // SPDX-License-Identifier: Apache-2.0 mod error_reporting; mod file_eval; mod repl_eval; #[cfg(test)] mod test; use clap::Parser; use haxby_vm::vm::{VirtualMachine, VmOptions}; #[derive(Default, Parser, Debug)] #[command(author, name = "aria", version = env!("CARGO_PKG_VERSION"), about, trailing_var_arg = true)] struct Args { /// The name of the program file to run path: Option, /// The destination for the VM performance trace #[arg(long("perf-trace-dest"))] perf_trace_dest: Option, /// Should the VM trace instruction execution #[arg(long("trace-exec"))] #[cfg(debug_assertions)] trace_exec: bool, /// Should the VM dump the stack at each instruction #[arg(long("trace-stack"))] #[cfg(debug_assertions)] trace_stack: bool, /// Should the AST be dumped after parsing #[arg(long("dump-ast"))] dump_ast: bool, /// Dump the compiler's intermediate representation #[arg(long("dump-ir"))] dump_ir: bool, /// Should the module be dumped after compilation #[arg(long("dump-module"))] dump_mod: bool, /// Turn off compile-time optimizations #[arg(long("disable-optimizer"))] disable_optimizer: bool, #[arg(trailing_var_arg = true)] extra_args: Vec, #[arg(long("print-lib-path"))] print_lib_path: bool, /// Turn off REPL preamble #[arg(long("no-repl-preamble"))] no_repl_preamble: bool, } impl From<&Args> for VmOptions { fn from(value: &Args) -> Self { let mut options = VmOptions::default(); #[cfg(debug_assertions)] if value.trace_exec { options.tracing = true; if value.trace_stack { options.dump_stack = true; } } options.vm_args = value.extra_args.clone(); options } } impl Args { fn check(&self) -> Vec { let mut ret = vec![]; if self.path.is_some() && self.no_repl_preamble { ret.push("--no-repl-preamble has no effect when a file path is provided".to_string()); } if self.path.is_none() && self.perf_trace_dest.is_some() { ret.push( "--perf-trace-dest has no effect when a file path is not provided".to_string(), ); } ret } } fn print_lib_paths() { let lib_paths = VirtualMachine::get_aria_library_paths(); for path in lib_paths { println!("{}", path.display()); } } fn main_loop() -> i32 { let args = Args::parse(); if args.print_lib_path { print_lib_paths(); return 0; } let checks = args.check(); if !checks.is_empty() { for check in checks { eprintln!("Error: {}", check); } return 1; } if let Some(path) = &args.path { file_eval::file_eval(path, &args) } else { repl_eval::repl_eval(&args) } } fn main() { let exit_code = main_loop(); std::process::exit(exit_code); } ================================================ FILE: aria-bin/src/repl_eval.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use std::ops::DerefMut; use aria_compiler::{CompilationOptions, compile_from_ast}; use aria_parser::ast::{ ExpressionStatement, SourceBuffer, TopLevelEntry, prettyprint::{PrettyPrintable, printout_accumulator::PrintoutAccumulator}, source_to_ast, }; use haxby_vm::{ runtime_module::RuntimeModule, vm::{VirtualMachine, VmOptions}, }; use reedline::{DefaultPrompt, Reedline, Validator}; use crate::{ Args, error_reporting::{ build_report_from_compiler_error, build_report_from_parser_error, build_report_from_vm_error, build_report_from_vm_exception, print_report_from_compiler_error, print_report_from_parser_error, print_report_from_vm_error, print_report_from_vm_exception, }, }; struct ReplValidator; impl Validator for ReplValidator { fn validate(&self, line: &str) -> reedline::ValidationResult { use reedline::ValidationResult::{Complete, Incomplete}; let mut quote: Option = None; // '" or '\'' let mut escaped = false; let mut balance: Vec = Vec::new(); let mut comment = false; for c in line.chars() { // inside string if let Some(q) = quote { if escaped { escaped = false; continue; } if c == '\\' { escaped = true; continue; } if c == q { quote = None; } continue; } else if c == '#' || comment { comment = c != '\n'; continue; } else { match c { '"' | '\'' => quote = Some(c), '(' => balance.push(')'), '[' => balance.push(']'), '{' => balance.push('}'), ')' | ']' | '}' => { if !matches!(balance.last(), Some(&need) if need == c) { return Complete; } else { balance.pop(); } } _ => {} } } } if quote.is_none() && balance.is_empty() { Complete } else { Incomplete } } } struct LineEditor { line_editor: Reedline, prompt: DefaultPrompt, } impl LineEditor { pub fn new() -> Self { let validator = Box::new(ReplValidator); let prompt = DefaultPrompt { left_prompt: reedline::DefaultPromptSegment::Empty, right_prompt: reedline::DefaultPromptSegment::Empty, }; #[cfg(test)] let line_editor = Reedline::create().with_validator(validator); #[cfg(not(test))] let line_editor = Reedline::create() .with_validator(validator) .with_history(Box::new( reedline::FileBackedHistory::with_file(1024, "history.aria".into()) .expect("history"), )); Self { line_editor, prompt, } } } impl LineEditor { fn read_input(&mut self) -> (String, bool) { let sig = self.line_editor.read_line(&self.prompt); match sig { Ok(reedline::Signal::Success(buffer)) => (buffer, false), Ok(reedline::Signal::CtrlC) | Ok(reedline::Signal::CtrlD) | Err(_) => { (String::new(), true) } } } } fn is_call_to_print_or_println(expr: &ExpressionStatement) -> bool { if let Some(v) = &expr.val { let (is_call, name) = v.is_function_call(); return is_call && matches!(name, Some("print") | Some("println")); } false } fn massage_ast_for_repl(ast: &mut aria_parser::ast::ParsedModule) -> bool { if ast.entries.is_empty() { return false; } let idx = ast.entries.len() - 1; let TopLevelEntry::ExpressionStatement(expr) = &ast.entries[idx] else { return false; }; if is_call_to_print_or_println(expr) { return false; } let Some(val) = &expr.val else { return false }; let new_node = val.call_function_passing_me("println"); ast.entries[idx] = TopLevelEntry::ExpressionStatement(ExpressionStatement { loc: val.loc().clone(), val: Some(new_node), }); true } #[cfg(test)] pub struct ReplStepResult { pub stdout: String, #[allow(dead_code)] pub stderr: String, pub ok: bool, } pub struct Repl<'a> { vm: VirtualMachine, module: RuntimeModule, args: &'a Args, counter: u64, } impl<'a> Repl<'a> { #[allow(clippy::unit_arg)] pub fn new(vm_options: VmOptions, args: &'a Args) -> Result { let mut vm = VirtualMachine::with_options(vm_options); let repl_module_preamble = if args.no_repl_preamble { "" } else { include_str!("repl_preamble.aria") }; let sb = SourceBuffer::stdin_with_name(repl_module_preamble, "repl"); let ast = match source_to_ast(&sb) { Ok(ast) => ast, Err(err) => { return Err(print_report_from_parser_error(&err)); } }; let comp_opts = CompilationOptions::default(); let c_module = match compile_from_ast(&ast, &comp_opts) { Ok(module) => module, Err(err) => { err.iter().for_each(print_report_from_compiler_error); return Err(()); } }; let r_module = match RuntimeModule::new(&mut vm, c_module) { Ok(m) => m, Err(err) => { return Err(print_report_from_vm_error(&err.into())); } }; let r_module = match vm.load_into_module("repl", r_module) { Ok(rle) => match rle { haxby_vm::vm::RunloopExit::Ok(m) => m.module, haxby_vm::vm::RunloopExit::Exception(exc) => { return Err(print_report_from_vm_exception(&mut vm, &exc)); } }, Err(err) => { return Err(print_report_from_vm_error(&err)); } }; vm.inject_imported_module("repl", r_module.clone()); Ok(Repl { vm, module: r_module, args, counter: 0, }) } fn try_parse_source( &mut self, buffer: &SourceBuffer, ) -> Result { source_to_ast(buffer) } #[allow(clippy::unit_arg)] pub fn process_buffer(&mut self, buffer: &str) -> Result { let module_name: String = format!("__repl_chunk_{}", self.counter); self.counter += 1; let module_source_code = format!("import * from repl;\n{}\n", buffer); let sb = SourceBuffer::stdin_with_name(&module_source_code, &module_name); let mut parsed_source = self.try_parse_source(&sb); if parsed_source.is_err() && !(buffer.ends_with('}') || buffer.ends_with(';')) { let buffer_with_semicolon = format!("{};", module_source_code); let sb2 = SourceBuffer::stdin_with_name(&buffer_with_semicolon, &module_name); let parsed_source2 = self.try_parse_source(&sb2); if parsed_source2.is_ok() { parsed_source = parsed_source2; } } let mut ast = match parsed_source { Ok(ast) => ast, Err(err) => { return Err(self.print_error_report(build_report_from_parser_error(&err))); } }; let mutated = massage_ast_for_repl(&mut ast); if self.args.dump_ast { let ast_buffer = PrintoutAccumulator::default(); let output = ast.prettyprint(ast_buffer).value(); println!("AST dump:\n{output}\n"); if mutated { println!("note: AST mutated for REPL purposes"); } } let comp_opts = CompilationOptions::default(); let c_module = match compile_from_ast(&ast, &comp_opts) { Ok(module) => module, Err(err) => { err.iter() .for_each(|e| self.print_error_report(build_report_from_compiler_error(e))); return Err(()); } }; if self.args.dump_mod { let mod_buffer = PrintoutAccumulator::default(); let output = c_module.prettyprint(mod_buffer).value(); println!("Module dump:\n{output}\n"); } let r_module = match RuntimeModule::new(&mut self.vm, c_module) { Ok(m) => m, Err(err) => { return Err(self.print_error_report(build_report_from_vm_error(&err.into()))); } }; if r_module .lift_all_symbols_from_other(&self.module, &self.vm) .is_err() { return Err(()); } let load_result = self.vm.load_into_module("repl", r_module); match load_result { Ok(rle) => match rle { haxby_vm::vm::RunloopExit::Ok(m) => { let new_module = m.module; let _ = self .module .lift_all_symbols_from_other(&new_module, &self.vm); Ok(new_module) } haxby_vm::vm::RunloopExit::Exception(exc) => { let report = build_report_from_vm_exception(&mut self.vm, &exc); Err(self.print_error_report(report)) } }, Err(err) => Err(self.print_error_report(build_report_from_vm_error(&err))), } } fn print_error_report(&mut self, report: crate::error_reporting::PrintableReport<'_>) { let console_rc = self.vm.console(); let mut console_borrow = console_rc.borrow_mut(); let console = console_borrow.deref_mut(); let _ = report.0.write(report.1, console); } #[cfg(test)] pub fn eval_line(&mut self, src: &str) -> ReplStepResult { fn diff(before: &str, after: &str) -> String { if after.len() >= before.len() { after[before.len()..].to_string() } else { String::new() } } let before_console = self .vm .console() .borrow() .as_any() .downcast_ref::() .unwrap() .clone(); let before_stdout = before_console.stdout.clone(); let before_stderr = before_console.stderr.clone(); let ok = self.process_buffer(src).is_ok(); let after_console = self .vm .console() .borrow() .as_any() .downcast_ref::() .unwrap() .clone(); let after_stdout = after_console.stdout.clone(); let after_stderr = after_console.stderr.clone(); ReplStepResult { stdout: diff(&before_stdout, &after_stdout), stderr: diff(&before_stderr, &after_stderr), ok, } } } pub(crate) fn repl_eval(args: &Args) -> i32 { let vm_opts = VmOptions::from(args); let mut repl = Repl::new(vm_opts, args).unwrap(); let mut ed = LineEditor::new(); loop { let (input, eof) = ed.read_input(); if eof { break; } let input = input.trim(); if input.is_empty() { continue; } else if input == ":quit" { break; } else { let _ = repl.process_buffer(input); } } 0 // REPL will always exit 0 } ================================================ FILE: aria-bin/src/repl_preamble.aria ================================================ # SPDX-License-Identifier: Apache-2.0 import File from aria.io.file; import Path from aria.io.path; import Request from aria.network.request; import Map from aria.structures.map; import Regex from aria.string.regex; import aria.iterator.mixin; import aria.numerics.float.exp; import aria.numerics.float.trig; import aria.numerics.int.pow; import aria.range.int_extension; ================================================ FILE: aria-bin/src/test.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use std::{cell::RefCell, rc::Rc}; use haxby_vm::console::TestConsole; use crate::{Args, repl_eval::Repl}; fn build_test_repl<'a>(cmdline_options: &'a Args) -> Repl<'a> { let console = Rc::new(RefCell::new(TestConsole::default())); let vm_options = haxby_vm::vm::VmOptions { console: console.clone(), ..Default::default() }; Repl::new(vm_options, cmdline_options).unwrap() } fn run_check_repl_line( repl: &mut Repl, line: &str, ok: bool, must_include_stdout: &[&str], must_include_stderr: &[&str], ) { let diff = repl.eval_line(line); assert!(diff.ok == ok); for expected in must_include_stdout { assert!( diff.stdout.contains(expected), "stdout ( {} ) did not contain expected ( {} )", diff.stdout, expected ); } for expected in must_include_stderr { assert!( diff.stderr.contains(expected), "stderr ( {} ) did not contain expected ( {} )", diff.stderr, expected ); } } fn run_passing_repl_line(repl: &mut Repl, line: &str, must_include_stdout: &[&str]) { run_check_repl_line(repl, line, true, must_include_stdout, &[]) } #[test] fn repl_can_print_integers() { let cmdline_options = Args::default(); let mut repl = build_test_repl(&cmdline_options); run_passing_repl_line(&mut repl, "42;", &["42"]); run_passing_repl_line(&mut repl, "3 + 4;", &["7"]); } #[test] fn repl_can_call_functions() { let cmdline_options = Args::default(); let mut repl = build_test_repl(&cmdline_options); run_passing_repl_line(&mut repl, "func foo(x) { return x + 1; }", &[]); run_passing_repl_line(&mut repl, "foo(12);", &["13"]); } #[test] fn repl_can_define_structs() { let cmdline_options = Args::default(); let mut repl = build_test_repl(&cmdline_options); run_passing_repl_line( &mut repl, r#" struct Pair { type func new(x,y) { return alloc(This) { .x = x, .y = y, }; } } "#, &[], ); run_passing_repl_line(&mut repl, "val p = Pair.new(4,5);", &[]); run_passing_repl_line( &mut repl, r#" extension Pair { func prettyprint() { return "Pair({0},{1})".format(this.x,this.y); } } "#, &[], ); run_passing_repl_line(&mut repl, "p;", &["Pair(4,5)"]); } #[test] fn repl_can_use_if_statement() { let cmdline_options = Args::default(); let mut repl = build_test_repl(&cmdline_options); run_passing_repl_line(&mut repl, "val x = 4;", &[]); run_passing_repl_line(&mut repl, "if (x > 2) { println(x + 1); }", &["5"]); run_passing_repl_line(&mut repl, "if (x > 4) { println(x + 1); }", &[""]); } #[test] fn repl_can_use_for_statement() { let cmdline_options = Args::default(); let mut repl = build_test_repl(&cmdline_options); run_passing_repl_line(&mut repl, "val l = [1,2,3,4,5,6];", &[]); run_passing_repl_line( &mut repl, "for i in l { println(i); }", &["1", "2", "3", "4", "5", "6"], ); } #[test] fn repl_can_use_while_statement() { let cmdline_options = Args::default(); let mut repl = build_test_repl(&cmdline_options); run_passing_repl_line(&mut repl, "val n = 10;", &[]); run_passing_repl_line( &mut repl, "while n > 0 { n -= 2; println(n); }", &["8", "6", "4", "2", "0"], ); } #[test] fn repl_can_use_match_statement() { let cmdline_options = Args::default(); let mut repl = build_test_repl(&cmdline_options); run_passing_repl_line(&mut repl, "val n = 10;", &[]); run_passing_repl_line( &mut repl, r#" match n { > 10 => { println("Greater than 10"); } } else { println("10 or less"); } "#, &["10 or less"], ); } #[test] fn repl_printout_maybe() { let cmdline_options = Args::default(); let mut repl = build_test_repl(&cmdline_options); run_passing_repl_line( &mut repl, r#" struct Pair { type func new(x,y) { return alloc(This) { .x = x, .y = y, }; } func prettyprint() { return "Pair({0},{1})".format(this.x,this.y); } } "#, &[""], ); run_passing_repl_line( &mut repl, "Maybe::Some(Pair.new(4,5));", &["Some(Pair(4,5))"], ); run_passing_repl_line(&mut repl, "Maybe::None;", &["None"]); } #[test] fn repl_adds_semicolon() { let cmdline_options = Args::default(); let mut repl = build_test_repl(&cmdline_options); run_passing_repl_line(&mut repl, "val x = 1", &[]); run_passing_repl_line(&mut repl, "val y = 2", &[]); run_passing_repl_line(&mut repl, "2 * y + x", &["5"]); } #[test] fn repl_preamble_works() { let cmdline_options = Args::default(); let mut repl = build_test_repl(&cmdline_options); run_passing_repl_line(&mut repl, "3.pow(2)", &["9"]); run_passing_repl_line(&mut repl, "val m = Map.new(); m[1] = 'one'; m[1]", &["one"]); run_passing_repl_line(&mut repl, "m.get(4)", &["None"]); } #[test] fn repl_skips_preamble() { let cmdline_options = Args { no_repl_preamble: true, ..Default::default() }; let mut repl = build_test_repl(&cmdline_options); run_check_repl_line( &mut repl, "3.pow(2)", false, &["identifier 'pow' not found"], &[], ); } #[test] fn repl_op_count_error() { let cmdline_options = Args { no_repl_preamble: true, ..Default::default() }; let mut repl = build_test_repl(&cmdline_options); run_check_repl_line( &mut repl, "struct Foo { operator[]=() { return 1; } }", false, &["operator []= accepts at least 1 arguments, but 0 were declared"], &[], ); run_check_repl_line( &mut repl, "struct Foo { operator + (a,b,c) { return 1; } }", false, &["operator + accepts exactly 1 arguments, but 3 were declared"], &[], ); } #[test] fn repl_test_printf() { let cmdline_options = Args::default(); let mut repl = build_test_repl(&cmdline_options); run_passing_repl_line(&mut repl, "'hello = {0}'.printf(42);", &["hello = 42"]); run_passing_repl_line( &mut repl, "'hello = {0} hi = {1}\n'.printf(42, 43);", &["hello = 42 hi = 43\n"], ); } #[test] fn repl_test_invalid_literal() { let cmdline_options = Args::default(); let mut repl = build_test_repl(&cmdline_options); run_check_repl_line( &mut repl, "0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", false, &["0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF is not a valid literal"], &[], ); } #[test] fn repl_allows_comments() { let cmdline_options = Args::default(); let mut repl = build_test_repl(&cmdline_options); run_passing_repl_line( &mut repl, r#" func foo() { # this is a comment return # this is another comment ( 12345 # comment after expression ); } "#, &[], ); run_passing_repl_line(&mut repl, "foo();", &["12345"]); } #[test] fn repl_handles_hashtag_in_string() { let cmdline_options = Args::default(); let mut repl = build_test_repl(&cmdline_options); run_passing_repl_line( &mut repl, r#" func foo() { # this is a comment return '#arialang'; } "#, &[], ); run_passing_repl_line(&mut repl, "foo();", &["#arialang"]); } #[test] fn repl_test_oneof_from_empty_list() { let cmdline_options = Args::default(); let mut repl = build_test_repl(&cmdline_options); run_check_repl_line( &mut repl, r#" import XorshiftRng from aria.rng.xorshift; val x = XorshiftRng.new(); x.one_of([]) "#, false, &["operation failed: cannot choose from empty list"], &[], ); } #[test] fn repl_includes_ranges() { let cmdline_options = Args::default(); let mut repl = build_test_repl(&cmdline_options); run_passing_repl_line( &mut repl, r#" val x = 0; for i in 0.to(5) { x += i; } "i = {0}\n".printf(x); "#, &["i = 10"], ); } ================================================ FILE: aria-bin/test_assert.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func foo() { assert false; } func main() { return foo(); } ================================================ FILE: aria-bin/test_uncaught_exception.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func foo() { return 3 / 0; } func main() { return foo(); } ================================================ FILE: b ================================================ #!/usr/bin/env bash set -e print_usage() { echo "Usage: $0 " echo "command: bench, micro, perf, time, valgrind" echo "bench: Name or partial name of the benchmark to run" } COMMAND=$1 BENCH=$2 if [ -z "$COMMAND" ]; then print_usage exit 1 fi SELF_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" ARIA_BUILD_CONFIG="${ARIA_BUILD_CONFIG:-release}" CPU_AFFINITY_MASK="${CPU_AFFINITY_MASK:-0x1}" if [ -z "${ARIA_EXECUTABLE:-}" ]; then cargo build --profile "$ARIA_BUILD_CONFIG" --bin aria TARGET_DIR=$(cd "$SELF_DIR" && cargo metadata --format-version 1 --no-deps 2>/dev/null | jq -r '.target_directory // empty' 2>/dev/null || true) if [ -z "$TARGET_DIR" ]; then TARGET_DIR="${SELF_DIR}/../target" fi ARIA_EXECUTABLE="${TARGET_DIR}/${ARIA_BUILD_CONFIG}/aria" fi export ARIA_EXECUTABLE ARIA_LIB_DIR="${ARIA_LIB_DIR:-${SELF_DIR}/lib:${SELF_DIR}/lib-test}" export ARIA_LIB_DIR="$ARIA_LIB_DIR" if [ "$COMMAND" = "bench" ]; then cargo bench --profile "$ARIA_BUILD_CONFIG" --package vm-lib "$BENCH" elif [ "$COMMAND" = "micro" ]; then if [ ! -f "$BENCH" ]; then BENCH="${SELF_DIR}/microbenchmarks/${BENCH}.aria" fi ARIA_LIB_DIR="${ARIA_LIB_DIR}:${SELF_DIR}/microbenchmarks" export ARIA_LIB_DIR if command -v taskset >/dev/null 2>&1; then exec taskset "$CPU_AFFINITY_MASK" "${ARIA_EXECUTABLE}" "$BENCH" "${@:3}" else exec "${ARIA_EXECUTABLE}" "$BENCH" "${@:3}" fi else OUTPUT=$(cargo bench --no-run --profile "$ARIA_BUILD_CONFIG" --package vm-lib "$BENCH" 2>&1) echo "$OUTPUT" EXECUTABLE_PATH=$(echo "$OUTPUT" | grep "^ Executable" | tail -n1 | awk '{gsub(/[()]/,"",$NF); print $NF}') case "$COMMAND" in perf) echo "Running with perf..." perf record -g "$EXECUTABLE_PATH" "$BENCH" ;; valgrind) echo "Running with Valgrind Callgrind..." ulimit -n 4096 valgrind --tool=callgrind "$EXECUTABLE_PATH" "$BENCH" ;; time) echo "Running with time..." time "$EXECUTABLE_PATH" "$BENCH" ;; *) echo "Invalid command" print_usage exit 1 ;; esac fi ================================================ FILE: ci_tests.sh ================================================ #!/usr/bin/env bash set -e SELF_DIR="$(dirname "$(readlink -f "${BASH_SOURCE[0]}")")" ${SELF_DIR}/t --sequential ================================================ FILE: compiler-lib/Cargo.toml ================================================ [package] name = "compiler-lib" version = "0.9.20251222" edition = "2024" [lib] name = "aria_compiler" path = "src/lib.rs" [dependencies] pest = "2.8.5" pest_derive = "2.8.5" opcodes-lib = { path = "../opcodes-lib" } parser-lib = { path = "../parser-lib" } enum-as-inner = "0.7.0" thiserror = "2.0.18" lazy_static = "1.5.0" ================================================ FILE: compiler-lib/src/bc_reader.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use haxby_opcodes::{BuiltinTypeId, BuiltinValueId, Opcode}; pub struct BytecodeReader { data: Vec, idx: usize, } impl TryFrom<&[u8]> for BytecodeReader { type Error = DecodeError; fn try_from(value: &[u8]) -> Result { if value.len() > u16::MAX as usize { Err(DecodeError::DataTooLarge) } else { Ok(Self { data: value.to_vec(), idx: 0, }) } } } #[derive(Clone, thiserror::Error, PartialEq, Eq, Debug)] pub enum DecodeError { #[error("bytecode exceeds maximum allowed size")] DataTooLarge, #[error("reached end of stream")] EndOfStream, #[error("insufficient data for decoding")] InsufficientData, #[error("{0} is not a known opcode")] UnknownOpcode(u8), #[error("{1} is not a valid operand for opcode {0}")] UnknownOperand(u8, u8), } pub type DecodeResult = Result; impl BytecodeReader { #[inline] fn read_u8(&mut self) -> DecodeResult { if self.idx < self.data.len() { let val = self.data[self.idx]; self.idx += 1; Ok(val) } else { Err(DecodeError::EndOfStream) } } #[inline] fn read_u16(&mut self) -> DecodeResult { if self.idx + 1 < self.data.len() { let val = u16::from_le_bytes([self.data[self.idx], self.data[self.idx + 1]]); self.idx += 2; Ok(val) } else { Err(DecodeError::EndOfStream) } } #[inline] fn read_u32(&mut self) -> DecodeResult { if self.idx + 3 < self.data.len() { let val = u32::from_le_bytes([ self.data[self.idx], self.data[self.idx + 1], self.data[self.idx + 2], self.data[self.idx + 3], ]); self.idx += 4; Ok(val) } else { Err(DecodeError::EndOfStream) } } pub fn jump_to_index(&mut self, idx: usize) { self.idx = idx; } pub fn get_index(&self) -> usize { self.idx } pub fn read_opcode(&mut self) -> DecodeResult { let next = self.read_u8()?; match next { haxby_opcodes::OPCODE_NOP => Ok(Opcode::Nop), haxby_opcodes::OPCODE_PUSH => self .read_u16() .map_or(Err(DecodeError::InsufficientData), |b| Ok(Opcode::Push(b))), haxby_opcodes::OPCODE_PUSH_0 => Ok(Opcode::Push0), haxby_opcodes::OPCODE_PUSH_1 => Ok(Opcode::Push1), haxby_opcodes::OPCODE_PUSH_TRUE => Ok(Opcode::PushTrue), haxby_opcodes::OPCODE_PUSH_FALSE => Ok(Opcode::PushFalse), haxby_opcodes::OPCODE_PUSH_BUILTIN_TYPE => { let arg0 = match self.read_u8() { Ok(b) => b, Err(_) => { return Err(DecodeError::InsufficientData); } }; let bt_id = match BuiltinTypeId::try_from(arg0) { Ok(id) => id, Err(_) => { return Err(DecodeError::UnknownOperand(next, arg0)); } }; Ok(Opcode::PushBuiltinTy(bt_id)) } haxby_opcodes::OPCODE_PUSH_RUNTIME_VALUE => { let arg0 = match self.read_u8() { Ok(b) => b, Err(_) => { return Err(DecodeError::InsufficientData); } }; let bt_id = match BuiltinValueId::try_from(arg0) { Ok(id) => id, Err(_) => { return Err(DecodeError::UnknownOperand(next, arg0)); } }; Ok(Opcode::PushRuntimeValue(bt_id)) } haxby_opcodes::OPCODE_POP => Ok(Opcode::Pop), haxby_opcodes::OPCODE_DUP => Ok(Opcode::Dup), haxby_opcodes::OPCODE_SWAP => Ok(Opcode::Swap), haxby_opcodes::OPCODE_COPY => self .read_u8() .map_or(Err(DecodeError::InsufficientData), |b| Ok(Opcode::Copy(b))), haxby_opcodes::OPCODE_ADD => Ok(Opcode::Add), haxby_opcodes::OPCODE_SUB => Ok(Opcode::Sub), haxby_opcodes::OPCODE_MUL => Ok(Opcode::Mul), haxby_opcodes::OPCODE_DIV => Ok(Opcode::Div), haxby_opcodes::OPCODE_REM => Ok(Opcode::Rem), haxby_opcodes::OPCODE_EQ => Ok(Opcode::Equal), haxby_opcodes::OPCODE_GT => Ok(Opcode::GreaterThan), haxby_opcodes::OPCODE_LT => Ok(Opcode::LessThan), haxby_opcodes::OPCODE_GTE => Ok(Opcode::GreaterThanEqual), haxby_opcodes::OPCODE_LTE => Ok(Opcode::LessThanEqual), haxby_opcodes::OPCODE_NEG => Ok(Opcode::Neg), haxby_opcodes::OPCODE_SHL => Ok(Opcode::ShiftLeft), haxby_opcodes::OPCODE_SHR => Ok(Opcode::ShiftRight), haxby_opcodes::OPCODE_NOT => Ok(Opcode::Not), haxby_opcodes::OPCODE_READ_LOCAL => self .read_u8() .map_or(Err(DecodeError::InsufficientData), |b| { Ok(Opcode::ReadLocal(b)) }), haxby_opcodes::OPCODE_WRITE_LOCAL => self .read_u8() .map_or(Err(DecodeError::InsufficientData), |b| { Ok(Opcode::WriteLocal(b)) }), haxby_opcodes::OPCODE_TYPEDEF_LOCAL => self .read_u8() .map_or(Err(DecodeError::InsufficientData), |b| { Ok(Opcode::TypedefLocal(b)) }), haxby_opcodes::OPCODE_READ_NAMED => self .read_u16() .map_or(Err(DecodeError::InsufficientData), |b| { Ok(Opcode::ReadNamed(b)) }), haxby_opcodes::OPCODE_WRITE_NAMED => self .read_u16() .map_or(Err(DecodeError::InsufficientData), |b| { Ok(Opcode::WriteNamed(b)) }), haxby_opcodes::OPCODE_TYPEDEF_NAMED => self .read_u16() .map_or(Err(DecodeError::InsufficientData), |b| { Ok(Opcode::TypedefNamed(b)) }), haxby_opcodes::OPCODE_READ_INDEX => self .read_u8() .map_or(Err(DecodeError::InsufficientData), |b| { Ok(Opcode::ReadIndex(b)) }), haxby_opcodes::OPCODE_WRITE_INDEX => self .read_u8() .map_or(Err(DecodeError::InsufficientData), |b| { Ok(Opcode::WriteIndex(b)) }), haxby_opcodes::OPCODE_READ_ATTRIBUTE => self .read_u16() .map_or(Err(DecodeError::InsufficientData), |b| { Ok(Opcode::ReadAttribute(b)) }), haxby_opcodes::OPCODE_WRITE_ATTRIBUTE => self .read_u16() .map_or(Err(DecodeError::InsufficientData), |b| { Ok(Opcode::WriteAttribute(b)) }), haxby_opcodes::OPCODE_READ_ATTRIBUTE_SYMBOL => self .read_u32() .map_or(Err(DecodeError::InsufficientData), |b| { Ok(Opcode::ReadAttributeSymbol(b)) }), haxby_opcodes::OPCODE_WRITE_ATTRIBUTE_SYMBOL => self .read_u32() .map_or(Err(DecodeError::InsufficientData), |b| { Ok(Opcode::WriteAttributeSymbol(b)) }), haxby_opcodes::OPCODE_READ_UPLEVEL => self .read_u8() .map_or(Err(DecodeError::InsufficientData), |b| { Ok(Opcode::ReadUplevel(b)) }), haxby_opcodes::OPCODE_LOGICAL_AND => Ok(Opcode::LogicalAnd), haxby_opcodes::OPCODE_LOGICAL_OR => Ok(Opcode::LogicalOr), haxby_opcodes::OPCODE_XOR => Ok(Opcode::Xor), haxby_opcodes::OPCODE_BITWISE_AND => Ok(Opcode::BitwiseAnd), haxby_opcodes::OPCODE_BITWISE_OR => Ok(Opcode::BitwiseOr), haxby_opcodes::OPCODE_JUMP_TRUE => self .read_u16() .map_or(Err(DecodeError::InsufficientData), |b| { Ok(Opcode::JumpTrue(b)) }), haxby_opcodes::OPCODE_JUMP_FALSE => self .read_u16() .map_or(Err(DecodeError::InsufficientData), |b| { Ok(Opcode::JumpFalse(b)) }), haxby_opcodes::OPCODE_JUMP => self .read_u16() .map_or(Err(DecodeError::InsufficientData), |b| Ok(Opcode::Jump(b))), haxby_opcodes::OPCODE_JUMP_CONDITIONALLY => { let arg0 = match self.read_u16() { Ok(b) => b, Err(_) => { return Err(DecodeError::InsufficientData); } }; let arg1 = match self.read_u16() { Ok(w) => w, Err(_) => { return Err(DecodeError::InsufficientData); } }; Ok(Opcode::JumpConditionally(arg0, arg1)) } haxby_opcodes::OPCODE_JUMP_IF_ARG_SUPPLIED => { let arg0 = match self.read_u8() { Ok(b) => b, Err(_) => { return Err(DecodeError::InsufficientData); } }; let arg1 = match self.read_u16() { Ok(w) => w, Err(_) => { return Err(DecodeError::InsufficientData); } }; Ok(Opcode::JumpIfArgSupplied(arg0, arg1)) } haxby_opcodes::OPCODE_CALL => self .read_u8() .map_or(Err(DecodeError::InsufficientData), |b| Ok(Opcode::Call(b))), haxby_opcodes::OPCODE_RETURN => Ok(Opcode::Return), haxby_opcodes::OPCODE_RETURN_UNIT => Ok(Opcode::ReturnUnit), haxby_opcodes::OPCODE_TRY_ENTER => self .read_u16() .map_or(Err(DecodeError::InsufficientData), |b| { Ok(Opcode::TryEnter(b)) }), haxby_opcodes::OPCODE_TRY_EXIT => Ok(Opcode::TryExit), haxby_opcodes::OPCODE_THROW => Ok(Opcode::Throw), haxby_opcodes::OPCODE_BUILD_LIST => self .read_u32() .map_or(Err(DecodeError::InsufficientData), |b| { Ok(Opcode::BuildList(b)) }), haxby_opcodes::OPCODE_BUILD_FUNCTION => Ok(Opcode::BuildFunction), haxby_opcodes::OPCODE_STORE_UPLEVEL => self .read_u8() .map_or(Err(DecodeError::InsufficientData), |b| { Ok(Opcode::StoreUplevel(b)) }), haxby_opcodes::OPCODE_BUILD_STRUCT => Ok(Opcode::BuildStruct), haxby_opcodes::OPCODE_BUILD_ENUM => Ok(Opcode::BuildEnum), haxby_opcodes::OPCODE_BUILD_MIXIN => Ok(Opcode::BuildMixin), haxby_opcodes::OPCODE_BIND_CASE => { let b0 = match self.read_u8() { Ok(b) => b, Err(_) => { return Err(DecodeError::InsufficientData); } }; let w1 = match self.read_u16() { Ok(w) => w, Err(_) => { return Err(DecodeError::InsufficientData); } }; Ok(Opcode::BindCase(b0, w1)) } haxby_opcodes::OPCODE_BIND_CASE_SYMBOL => { let b0 = match self.read_u8() { Ok(b) => b, Err(_) => { return Err(DecodeError::InsufficientData); } }; let w1 = match self.read_u32() { Ok(w) => w, Err(_) => { return Err(DecodeError::InsufficientData); } }; Ok(Opcode::BindCaseSymbol(b0, w1)) } haxby_opcodes::OPCODE_INCLUDE_MIXIN => Ok(Opcode::IncludeMixin), haxby_opcodes::OPCODE_NEW_ENUM_VAL => { let b0 = match self.read_u8() { Ok(b) => b, Err(_) => { return Err(DecodeError::InsufficientData); } }; let w1 = match self.read_u16() { Ok(w) => w, Err(_) => { return Err(DecodeError::InsufficientData); } }; Ok(Opcode::NewEnumVal(b0, w1)) } haxby_opcodes::OPCODE_ENUM_CHECK_IS_CASE => self .read_u16() .map_or(Err(DecodeError::InsufficientData), |b| { Ok(Opcode::EnumCheckIsCase(b)) }), haxby_opcodes::OPCODE_NEW_ENUM_VAL_SYMBOL => { let b0 = match self.read_u8() { Ok(b) => b, Err(_) => { return Err(DecodeError::InsufficientData); } }; let w1 = match self.read_u32() { Ok(w) => w, Err(_) => { return Err(DecodeError::InsufficientData); } }; Ok(Opcode::NewEnumValSymbol(b0, w1)) } haxby_opcodes::OPCODE_ENUM_CHECK_IS_CASE_SYMBOL => self .read_u32() .map_or(Err(DecodeError::InsufficientData), |b| { Ok(Opcode::EnumCheckIsCaseSymbol(b)) }), haxby_opcodes::OPCODE_ENUM_TRY_EXTRACT_PAYLOAD => Ok(Opcode::EnumTryExtractPayload), haxby_opcodes::OPCODE_TRY_UNWRAP_PROTOCOL => self .read_u8() .map_or(Err(DecodeError::InsufficientData), |b| { Ok(Opcode::TryUnwrapProtocol(b)) }), haxby_opcodes::OPCODE_ISA => Ok(Opcode::Isa), haxby_opcodes::OPCODE_IMPORT => self .read_u16() .map_or(Err(DecodeError::InsufficientData), |b| { Ok(Opcode::Import(b)) }), haxby_opcodes::OPCODE_LIFT_MODULE => Ok(Opcode::LiftModule), haxby_opcodes::OPCODE_LOAD_DYLIB => self .read_u16() .map_or(Err(DecodeError::InsufficientData), |b| { Ok(Opcode::LoadDylib(b)) }), haxby_opcodes::OPCODE_ASSERT => self .read_u16() .map_or(Err(DecodeError::InsufficientData), |b| { Ok(Opcode::Assert(b)) }), haxby_opcodes::OPCODE_HALT => Ok(Opcode::Halt), _ => Err(DecodeError::UnknownOpcode(next)), } } pub fn len(&self) -> usize { self.data.len() } pub fn is_empty(&self) -> bool { self.data.is_empty() } } ================================================ FILE: compiler-lib/src/bc_writer.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use haxby_opcodes::Opcode; #[derive(Default)] pub(crate) struct BytecodeWriter { data: Vec, } impl BytecodeWriter { fn write_u8(&mut self, val: u8) -> &mut Self { self.data.push(val); self } fn write_u16(&mut self, val: u16) -> &mut Self { let bytes = val.to_le_bytes(); self.write_u8(bytes[0]).write_u8(bytes[1]) } fn write_u32(&mut self, val: u32) -> &mut Self { let bytes = val.to_le_bytes(); self.write_u8(bytes[0]) .write_u8(bytes[1]) .write_u8(bytes[2]) .write_u8(bytes[3]) } pub(crate) fn write_opcode(&mut self, op: &Opcode) -> &mut Self { match op { Opcode::Nop => self.write_u8(haxby_opcodes::OPCODE_NOP), Opcode::Push(n) => self.write_u8(haxby_opcodes::OPCODE_PUSH).write_u16(*n), Opcode::Push0 => self.write_u8(haxby_opcodes::OPCODE_PUSH_0), Opcode::Push1 => self.write_u8(haxby_opcodes::OPCODE_PUSH_1), Opcode::PushTrue => self.write_u8(haxby_opcodes::OPCODE_PUSH_TRUE), Opcode::PushFalse => self.write_u8(haxby_opcodes::OPCODE_PUSH_FALSE), Opcode::PushBuiltinTy(n) => self .write_u8(haxby_opcodes::OPCODE_PUSH_BUILTIN_TYPE) .write_u8(n.to_u8()), Opcode::PushRuntimeValue(n) => self .write_u8(haxby_opcodes::OPCODE_PUSH_RUNTIME_VALUE) .write_u8(n.to_u8()), Opcode::Pop => self.write_u8(haxby_opcodes::OPCODE_POP), Opcode::Dup => self.write_u8(haxby_opcodes::OPCODE_DUP), Opcode::Swap => self.write_u8(haxby_opcodes::OPCODE_SWAP), Opcode::Copy(n) => self.write_u8(haxby_opcodes::OPCODE_COPY).write_u8(*n), Opcode::Add => self.write_u8(haxby_opcodes::OPCODE_ADD), Opcode::Sub => self.write_u8(haxby_opcodes::OPCODE_SUB), Opcode::Mul => self.write_u8(haxby_opcodes::OPCODE_MUL), Opcode::Div => self.write_u8(haxby_opcodes::OPCODE_DIV), Opcode::Rem => self.write_u8(haxby_opcodes::OPCODE_REM), Opcode::Neg => self.write_u8(haxby_opcodes::OPCODE_NEG), Opcode::ShiftLeft => self.write_u8(haxby_opcodes::OPCODE_SHL), Opcode::ShiftRight => self.write_u8(haxby_opcodes::OPCODE_SHR), Opcode::Not => self.write_u8(haxby_opcodes::OPCODE_NOT), Opcode::Equal => self.write_u8(haxby_opcodes::OPCODE_EQ), Opcode::ReadLocal(n) => self.write_u8(haxby_opcodes::OPCODE_READ_LOCAL).write_u8(*n), Opcode::WriteLocal(n) => self .write_u8(haxby_opcodes::OPCODE_WRITE_LOCAL) .write_u8(*n), Opcode::TypedefLocal(n) => self .write_u8(haxby_opcodes::OPCODE_TYPEDEF_LOCAL) .write_u8(*n), Opcode::ReadNamed(n) => self .write_u8(haxby_opcodes::OPCODE_READ_NAMED) .write_u16(*n), Opcode::WriteNamed(n) => self .write_u8(haxby_opcodes::OPCODE_WRITE_NAMED) .write_u16(*n), Opcode::TypedefNamed(n) => self .write_u8(haxby_opcodes::OPCODE_TYPEDEF_NAMED) .write_u16(*n), Opcode::ReadIndex(n) => self.write_u8(haxby_opcodes::OPCODE_READ_INDEX).write_u8(*n), Opcode::WriteIndex(n) => self .write_u8(haxby_opcodes::OPCODE_WRITE_INDEX) .write_u8(*n), Opcode::ReadAttribute(n) => self .write_u8(haxby_opcodes::OPCODE_READ_ATTRIBUTE) .write_u16(*n), Opcode::WriteAttribute(n) => self .write_u8(haxby_opcodes::OPCODE_WRITE_ATTRIBUTE) .write_u16(*n), Opcode::ReadAttributeSymbol(n) => self .write_u8(haxby_opcodes::OPCODE_READ_ATTRIBUTE_SYMBOL) .write_u32(*n), Opcode::WriteAttributeSymbol(n) => self .write_u8(haxby_opcodes::OPCODE_WRITE_ATTRIBUTE_SYMBOL) .write_u32(*n), Opcode::ReadUplevel(n) => self .write_u8(haxby_opcodes::OPCODE_READ_UPLEVEL) .write_u8(*n), Opcode::LogicalAnd => self.write_u8(haxby_opcodes::OPCODE_LOGICAL_AND), Opcode::LogicalOr => self.write_u8(haxby_opcodes::OPCODE_LOGICAL_OR), Opcode::Xor => self.write_u8(haxby_opcodes::OPCODE_XOR), Opcode::BitwiseAnd => self.write_u8(haxby_opcodes::OPCODE_BITWISE_AND), Opcode::BitwiseOr => self.write_u8(haxby_opcodes::OPCODE_BITWISE_OR), Opcode::GreaterThan => self.write_u8(haxby_opcodes::OPCODE_GT), Opcode::LessThan => self.write_u8(haxby_opcodes::OPCODE_LT), Opcode::GreaterThanEqual => self.write_u8(haxby_opcodes::OPCODE_GTE), Opcode::LessThanEqual => self.write_u8(haxby_opcodes::OPCODE_LTE), Opcode::JumpTrue(n) => self.write_u8(haxby_opcodes::OPCODE_JUMP_TRUE).write_u16(*n), Opcode::JumpFalse(n) => self .write_u8(haxby_opcodes::OPCODE_JUMP_FALSE) .write_u16(*n), Opcode::Jump(n) => self.write_u8(haxby_opcodes::OPCODE_JUMP).write_u16(*n), Opcode::JumpConditionally(t, f) => self .write_u8(haxby_opcodes::OPCODE_JUMP_CONDITIONALLY) .write_u16(*t) .write_u16(*f), Opcode::JumpIfArgSupplied(n, d) => self .write_u8(haxby_opcodes::OPCODE_JUMP_IF_ARG_SUPPLIED) .write_u8(*n) .write_u16(*d), Opcode::Call(n) => self.write_u8(haxby_opcodes::OPCODE_CALL).write_u8(*n), Opcode::Return => self.write_u8(haxby_opcodes::OPCODE_RETURN), Opcode::ReturnUnit => self.write_u8(haxby_opcodes::OPCODE_RETURN_UNIT), Opcode::TryEnter(n) => self.write_u8(haxby_opcodes::OPCODE_TRY_ENTER).write_u16(*n), Opcode::TryExit => self.write_u8(haxby_opcodes::OPCODE_TRY_EXIT), Opcode::Throw => self.write_u8(haxby_opcodes::OPCODE_THROW), Opcode::BuildList(n) => self .write_u8(haxby_opcodes::OPCODE_BUILD_LIST) .write_u32(*n), Opcode::BuildFunction => self.write_u8(haxby_opcodes::OPCODE_BUILD_FUNCTION), Opcode::StoreUplevel(n) => self .write_u8(haxby_opcodes::OPCODE_STORE_UPLEVEL) .write_u8(*n), Opcode::BuildStruct => self.write_u8(haxby_opcodes::OPCODE_BUILD_STRUCT), Opcode::BuildMixin => self.write_u8(haxby_opcodes::OPCODE_BUILD_MIXIN), Opcode::BuildEnum => self.write_u8(haxby_opcodes::OPCODE_BUILD_ENUM), Opcode::BindCase(a, n) => self .write_u8(haxby_opcodes::OPCODE_BIND_CASE) .write_u8(*a) .write_u16(*n), Opcode::BindCaseSymbol(a, n) => self .write_u8(haxby_opcodes::OPCODE_BIND_CASE_SYMBOL) .write_u8(*a) .write_u32(*n), Opcode::IncludeMixin => self.write_u8(haxby_opcodes::OPCODE_INCLUDE_MIXIN), Opcode::NewEnumVal(a, n) => self .write_u8(haxby_opcodes::OPCODE_NEW_ENUM_VAL) .write_u8(*a) .write_u16(*n), Opcode::NewEnumValSymbol(a, n) => self .write_u8(haxby_opcodes::OPCODE_NEW_ENUM_VAL_SYMBOL) .write_u8(*a) .write_u32(*n), Opcode::EnumCheckIsCase(n) => self .write_u8(haxby_opcodes::OPCODE_ENUM_CHECK_IS_CASE) .write_u16(*n), Opcode::EnumCheckIsCaseSymbol(n) => self .write_u8(haxby_opcodes::OPCODE_ENUM_CHECK_IS_CASE_SYMBOL) .write_u32(*n), Opcode::EnumTryExtractPayload => { self.write_u8(haxby_opcodes::OPCODE_ENUM_TRY_EXTRACT_PAYLOAD) } Opcode::TryUnwrapProtocol(n) => self .write_u8(haxby_opcodes::OPCODE_TRY_UNWRAP_PROTOCOL) .write_u8(*n), Opcode::Isa => self.write_u8(haxby_opcodes::OPCODE_ISA), Opcode::Import(n) => self.write_u8(haxby_opcodes::OPCODE_IMPORT).write_u16(*n), Opcode::LiftModule => self.write_u8(haxby_opcodes::OPCODE_LIFT_MODULE), Opcode::LoadDylib(n) => self .write_u8(haxby_opcodes::OPCODE_LOAD_DYLIB) .write_u16(*n), Opcode::Assert(n) => self.write_u8(haxby_opcodes::OPCODE_ASSERT).write_u16(*n), Opcode::Halt => self.write_u8(haxby_opcodes::OPCODE_HALT), } } pub(crate) fn get_data(&self) -> Vec { self.data.clone() } } ================================================ FILE: compiler-lib/src/builder/block.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use std::{cell::RefCell, collections::HashSet, rc::Rc}; use aria_parser::ast::SourcePointer; use crate::{ bc_writer::BytecodeWriter, builder::{compiler_opcodes::CompilerOpcode, func::FunctionBuilder}, constant_value::ConstantValues, line_table::LineTable, }; pub(crate) struct BasicBlockEntry { pub op: CompilerOpcode, pub src: Option, } impl BasicBlockEntry { fn to_vm_opcode(&self, parent: &FunctionBuilder) -> haxby_opcodes::Opcode { self.op.to_vm_opcode(parent) } } // TODO: this should really not be visible outside of block.rs pub(crate) struct BasicBlockImpl { name: String, id: usize, pub(crate) writer: RefCell>, } impl BasicBlockImpl { pub(crate) fn new(name: &str, id: usize) -> Self { Self { name: name.to_owned(), id, writer: RefCell::new(Default::default()), } } } #[derive(Clone)] pub struct BasicBlock { pub(crate) imp: Rc, } impl PartialEq for BasicBlock { fn eq(&self, other: &Self) -> bool { Rc::ptr_eq(&self.imp, &other.imp) } } impl Eq for BasicBlock {} #[derive(Default)] pub(crate) struct LocalValuesAccess { pub(crate) reads: HashSet, pub(crate) writes: HashSet, } impl LocalValuesAccess { pub(crate) fn calculate_unused_locals(&self) -> HashSet { self.writes.difference(&self.reads).cloned().collect() } } impl BasicBlock { pub(crate) fn new(name: &str, id: usize) -> Self { Self { imp: Rc::new(BasicBlockImpl::new(name, id)), } } pub fn name(&self) -> &str { &self.imp.name } pub fn id(&self) -> usize { self.imp.id } #[deprecated(note = "use write_opcode_and_source_info")] pub fn write_opcode(&self, op: CompilerOpcode) -> &Self { let bbe = BasicBlockEntry { op, src: None }; self.imp.writer.borrow_mut().push(bbe); self } pub fn write_opcode_and_source_info(&self, op: CompilerOpcode, src: SourcePointer) -> &Self { let bbe = BasicBlockEntry { op, src: Some(src) }; self.imp.writer.borrow_mut().push(bbe); self } pub fn len(&self) -> usize { self.imp.writer.borrow().len() } pub fn is_empty(&self) -> bool { self.imp.writer.borrow().is_empty() } pub fn is_terminal(&self) -> bool { let br = self.imp.writer.borrow(); for src_op in br.as_slice() { if src_op.op.is_terminal() { return true; } } false } #[allow(dead_code)] pub(crate) fn remove_op_at_idx(&self, idx: usize) { self.imp.writer.borrow_mut().remove(idx); } fn replace_double_jump(&self) -> bool { let mut any = false; let mut br = self.imp.writer.borrow_mut(); for i in 0..br.len() { if let CompilerOpcode::Jump(dest) = &br[i].op { let dest = dest.clone(); if dest.imp.id == self.imp.id { continue; } if dest.is_empty() { continue; } let dest_br = dest.imp.writer.borrow(); if let CompilerOpcode::Jump(final_dest) = &dest_br[0].op { br[i].op = CompilerOpcode::Jump(final_dest.clone()); any = true; } } } any } fn optimize_true_false(&self, cv: &ConstantValues) { let mut br = self.imp.writer.borrow_mut(); for i in 0..br.len() { if let CompilerOpcode::ReadNamed(idx) = &br[i].op && let Some(crate::constant_value::ConstantValue::String(x)) = cv.get(*idx as usize) { if x == "true" { br[i].op = CompilerOpcode::PushTrue; } else if x == "false" { br[i].op = CompilerOpcode::PushFalse; } } } } fn optimize_redundant_conditional_jumps(&self) { let mut br = self.imp.writer.borrow_mut(); let mut i = 0; while i + 1 < br.len() { match (&br[i].op, &br[i + 1].op) { (CompilerOpcode::PushTrue, CompilerOpcode::JumpTrue(target)) | (CompilerOpcode::PushFalse, CompilerOpcode::JumpFalse(target)) => { br[i].op = CompilerOpcode::Jump(target.clone()); br.remove(i + 1); continue; } (CompilerOpcode::PushTrue, CompilerOpcode::JumpFalse(_)) | (CompilerOpcode::PushFalse, CompilerOpcode::JumpTrue(_)) => { br[i].op = CompilerOpcode::Nop; br.remove(i + 1); continue; } _ => {} } i += 1; } } fn remove_instructions_after_terminal(&self) { let mut br = self.imp.writer.borrow_mut(); for i in 0..br.len() { if br[i].op.is_terminal() { while br.len() != i + 1 { br.remove(i + 1); } return; } } } fn remove_redundant_local_reads(&self) { let mut br = self.imp.writer.borrow_mut(); if br.len() < 2 { return; } for i in 0..br.len() - 1 { if let CompilerOpcode::ReadLocal(x) = br[i].op { let mut j = i + 1; while j < br.len() { match br[j].op { CompilerOpcode::ReadLocal(y) => { if x != y { break; } else { br[j].op = CompilerOpcode::Dup; } } _ => { break; } } j += 1; } } } } fn remove_redundant_named_reads(&self) { let mut br = self.imp.writer.borrow_mut(); if br.len() < 2 { return; } for i in 0..br.len() - 1 { if let CompilerOpcode::ReadNamed(x) = br[i].op { let mut j = i + 1; while j < br.len() { match br[j].op { CompilerOpcode::ReadNamed(y) => { if x != y { break; } else { br[j].op = CompilerOpcode::Dup; } } _ => { break; } } j += 1; } } } } fn remove_store_load_sequence(&self) { if self.len() < 2 { return; } let mut br = self.imp.writer.borrow_mut(); for i in 0..br.len() - 1 { if let CompilerOpcode::WriteLocal(x) = br[i].op && let CompilerOpcode::ReadLocal(y) = br[i + 1].op && x == y { br[i].op = CompilerOpcode::Dup; br[i + 1].op = CompilerOpcode::WriteLocal(x); } } } fn remove_nop_instructions(&self) { let mut br = self.imp.writer.borrow_mut(); br.retain(|x| !matches!(x.op, CompilerOpcode::Nop)); } fn remove_push_pop_pairs(&self) { if self.len() < 2 { return; } let mut br = self.imp.writer.borrow_mut(); for i in 0..br.len() - 1 { if let ( CompilerOpcode::Push0 | CompilerOpcode::Push1 | CompilerOpcode::PushFalse | CompilerOpcode::PushTrue | CompilerOpcode::Push(_) | CompilerOpcode::PushBuiltinTy(_) | CompilerOpcode::Dup, CompilerOpcode::Pop, ) = (&br[i].op, &br[i + 1].op) { br[i].op = CompilerOpcode::Nop; br[i + 1].op = CompilerOpcode::Nop; } } } pub(crate) fn run_optimize_passes(&self, cv: &ConstantValues) { self.optimize_true_false(cv); self.optimize_redundant_conditional_jumps(); self.remove_redundant_local_reads(); self.remove_redundant_named_reads(); self.remove_store_load_sequence(); self.remove_instructions_after_terminal(); self.remove_nop_instructions(); self.remove_push_pop_pairs(); self.remove_nop_instructions(); while self.replace_double_jump() {} } pub(crate) fn drop_unused_locals(&self, values: &HashSet) { let mut br = self.imp.writer.borrow_mut(); for i in 0..br.len() { match br[i].op { CompilerOpcode::ReadLocal(x) => { assert!(!values.contains(&x)); } CompilerOpcode::TypedefLocal(x) => { if values.contains(&x) { br[i].op = CompilerOpcode::Pop; } } CompilerOpcode::WriteLocal(x) => { if values.contains(&x) { br[i].op = CompilerOpcode::Pop; } } _ => {} } } } pub(crate) fn calculate_locals_access(&self, dest: &mut LocalValuesAccess) { let br = self.imp.writer.borrow(); for i in 0..br.len() { match br[i].op { CompilerOpcode::ReadLocal(x) | CompilerOpcode::StoreUplevel(x) => { dest.reads.insert(x); } CompilerOpcode::WriteLocal(x) => { dest.writes.insert(x); } CompilerOpcode::TypedefLocal(x) => { if i > 0 { if let CompilerOpcode::PushBuiltinTy(t) = br[i - 1].op && t.is_any() { dest.writes.insert(x); } else { dest.reads.insert(x); dest.writes.insert(x); } } else { // this is quite odd, as there would have to be something else defining // the type of the local on the stack, but just keep going for sake of completeness dest.writes.insert(x); } } _ => {} } } } pub(crate) fn write(&self, parent: &FunctionBuilder, dest: &mut BytecodeWriter) { let br = self.imp.writer.borrow(); for src_op in br.as_slice() { dest.write_opcode(&src_op.to_vm_opcode(parent)); } } pub(crate) fn write_line_table(&self, offset: u16, line_table: &LineTable) { let mut cur_offset = offset; let br = self.imp.writer.borrow(); for src_op in br.as_slice() { if let Some(src) = &src_op.src { line_table.insert(cur_offset, src.clone()); } cur_offset += 1; } } } impl std::fmt::Display for BasicBlock { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let br = self.imp.writer.borrow(); writeln!(f, "BasicBlock {}:", self.imp.name)?; for src_op in br.as_slice() { writeln!(f, " {}", src_op.op)?; } Ok(()) } } ================================================ FILE: compiler-lib/src/builder/compiler_opcodes.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use enum_as_inner::EnumAsInner; use haxby_opcodes::{ BuiltinTypeId, BuiltinValueId, Opcode as VmOpcode, enum_case_attribs::CASE_HAS_PAYLOAD, }; use crate::builder::{block::BasicBlock, func::FunctionBuilder}; #[derive(Clone, EnumAsInner)] pub enum CompilerOpcode { Nop, Push(u16), Push0, Push1, PushTrue, PushFalse, PushBuiltinTy(BuiltinTypeId), PushRuntimeValue(BuiltinValueId), Pop, Dup, Swap, Copy(u8), Add, Sub, Mul, Div, Rem, Neg, ShiftLeft, ShiftRight, Not, Equal, ReadLocal(u8), WriteLocal(u8), TypedefLocal(u8), ReadNamed(u16), WriteNamed(u16), TypedefNamed(u16), ReadIndex(u8), WriteIndex(u8), ReadAttribute(u16), WriteAttribute(u16), ReadUplevel(u8), LogicalAnd, BitwiseAnd, LogicalOr, BitwiseOr, Xor, GreaterThan, GreaterThanEqual, LessThan, LessThanEqual, JumpTrue(BasicBlock), JumpFalse(BasicBlock), Jump(BasicBlock), JumpConditionally(BasicBlock, BasicBlock), JumpIfArgSupplied(u8, BasicBlock), Call(u8), Return, ReturnUnit, TryEnter(BasicBlock), TryExit, Throw, BuildList(u32), BuildFunction, StoreUplevel(u8), BuildStruct, BuildEnum, BuildMixin, BindCase(u8, u16), IncludeMixin, NewEnumVal(bool, u16), EnumCheckIsCase(u16), EnumTryExtractPayload, TryUnwrapProtocol(u8), Isa, Import(u16), LiftModule, LoadDylib(u16), Assert(u16), Halt, } impl CompilerOpcode { pub fn is_terminal(&self) -> bool { match self { Self::Nop => false, Self::Push(_) => false, Self::Push0 => false, Self::Push1 => false, Self::PushTrue => false, Self::PushFalse => false, Self::PushBuiltinTy(_) => false, Self::PushRuntimeValue(_) => false, Self::Pop => false, Self::Dup => false, Self::Swap => false, Self::Copy(_) => false, Self::Add => false, Self::Sub => false, Self::Mul => false, Self::Div => false, Self::Rem => false, Self::Neg => false, Self::ShiftLeft => false, Self::ShiftRight => false, Self::Not => false, Self::Equal => false, Self::ReadLocal(_) => false, Self::WriteLocal(_) => false, Self::TypedefLocal(_) => false, Self::ReadNamed(_) => false, Self::WriteNamed(_) => false, Self::TypedefNamed(_) => false, Self::ReadIndex(_) => false, Self::WriteIndex(_) => false, Self::ReadAttribute(_) => false, Self::WriteAttribute(_) => false, Self::ReadUplevel(_) => false, Self::LogicalAnd => false, Self::LogicalOr => false, Self::Xor => false, Self::BitwiseAnd => false, Self::BitwiseOr => false, Self::LessThan => false, Self::GreaterThan => false, Self::LessThanEqual => false, Self::GreaterThanEqual => false, Self::JumpTrue(_) => false, Self::JumpFalse(_) => false, Self::Jump(_) => true, Self::JumpConditionally(..) => true, Self::JumpIfArgSupplied(..) => false, Self::Call(_) => false, Self::Return => true, Self::ReturnUnit => true, Self::TryEnter(_) => false, Self::TryExit => false, Self::Throw => true, Self::BuildList(_) => false, Self::BuildFunction => false, Self::StoreUplevel(_) => false, Self::BuildStruct => false, Self::BuildEnum => false, Self::BuildMixin => false, Self::BindCase(..) => false, Self::IncludeMixin => false, Self::NewEnumVal(..) => false, Self::EnumCheckIsCase(_) => false, Self::EnumTryExtractPayload => false, Self::TryUnwrapProtocol(_) => false, Self::Isa => false, Self::Import(_) => false, Self::LiftModule => false, Self::LoadDylib(_) => false, Self::Assert(_) => false, Self::Halt => true, } } pub fn is_jump_instruction(&self) -> Vec { match self { Self::TryEnter(dst) | Self::JumpIfArgSupplied(_, dst) | Self::Jump(dst) | Self::JumpTrue(dst) | Self::JumpFalse(dst) => vec![dst.clone()], Self::JumpConditionally(t, f) => vec![t.clone(), f.clone()], _ => vec![], } } pub fn to_vm_opcode(&self, parent: &FunctionBuilder) -> VmOpcode { match self { Self::Nop => VmOpcode::Nop, Self::Push(v) => VmOpcode::Push(*v), Self::Push0 => VmOpcode::Push0, Self::Push1 => VmOpcode::Push1, Self::PushTrue => VmOpcode::PushTrue, Self::PushFalse => VmOpcode::PushFalse, Self::PushBuiltinTy(n) => VmOpcode::PushBuiltinTy(*n), Self::PushRuntimeValue(n) => VmOpcode::PushRuntimeValue(*n), Self::Pop => VmOpcode::Pop, Self::Dup => VmOpcode::Dup, Self::Swap => VmOpcode::Swap, Self::Copy(n) => VmOpcode::Copy(*n), Self::Add => VmOpcode::Add, Self::Sub => VmOpcode::Sub, Self::Mul => VmOpcode::Mul, Self::Div => VmOpcode::Div, Self::Rem => VmOpcode::Rem, Self::Neg => VmOpcode::Neg, Self::ShiftLeft => VmOpcode::ShiftLeft, Self::ShiftRight => VmOpcode::ShiftRight, Self::Not => VmOpcode::Not, Self::Equal => VmOpcode::Equal, Self::ReadLocal(n) => VmOpcode::ReadLocal(*n), Self::WriteLocal(n) => VmOpcode::WriteLocal(*n), Self::TypedefLocal(n) => VmOpcode::TypedefLocal(*n), Self::ReadNamed(n) => VmOpcode::ReadNamed(*n), Self::WriteNamed(n) => VmOpcode::WriteNamed(*n), Self::TypedefNamed(n) => VmOpcode::TypedefNamed(*n), Self::ReadIndex(n) => VmOpcode::ReadIndex(*n), Self::WriteIndex(n) => VmOpcode::WriteIndex(*n), Self::ReadAttribute(n) => VmOpcode::ReadAttribute(*n), Self::WriteAttribute(n) => VmOpcode::WriteAttribute(*n), Self::ReadUplevel(n) => VmOpcode::ReadUplevel(*n), Self::LogicalAnd => VmOpcode::LogicalAnd, Self::LogicalOr => VmOpcode::LogicalOr, Self::Xor => VmOpcode::Xor, Self::BitwiseAnd => VmOpcode::BitwiseAnd, Self::BitwiseOr => VmOpcode::BitwiseOr, Self::GreaterThan => VmOpcode::GreaterThan, Self::LessThan => VmOpcode::LessThan, Self::GreaterThanEqual => VmOpcode::GreaterThanEqual, Self::LessThanEqual => VmOpcode::LessThanEqual, Self::JumpTrue(dst) => { let offset = parent .position_of_block_instructions(dst) .unwrap_or_else(|| panic!("invalid block {}", dst.name())); VmOpcode::JumpTrue(offset) } Self::JumpFalse(dst) => { let offset = parent .position_of_block_instructions(dst) .unwrap_or_else(|| panic!("invalid block {}", dst.name())); VmOpcode::JumpFalse(offset) } Self::Jump(dst) => { let offset = parent .position_of_block_instructions(dst) .unwrap_or_else(|| panic!("invalid block {}", dst.name())); VmOpcode::Jump(offset) } Self::JumpConditionally(t, f) => { let t_offset = parent .position_of_block_instructions(t) .unwrap_or_else(|| panic!("invalid block {}", t.name())); let f_offset = parent .position_of_block_instructions(f) .unwrap_or_else(|| panic!("invalid block {}", f.name())); VmOpcode::JumpConditionally(t_offset, f_offset) } Self::JumpIfArgSupplied(arg, dst) => { let offset = parent .position_of_block_instructions(dst) .unwrap_or_else(|| panic!("invalid block {}", dst.name())); VmOpcode::JumpIfArgSupplied(*arg, offset) } Self::Call(n) => VmOpcode::Call(*n), Self::Return => VmOpcode::Return, Self::ReturnUnit => VmOpcode::ReturnUnit, Self::TryEnter(dst) => { let offset = parent .position_of_block_instructions(dst) .unwrap_or_else(|| panic!("invalid block {}", dst.name())); VmOpcode::TryEnter(offset) } Self::TryExit => VmOpcode::TryExit, Self::Throw => VmOpcode::Throw, Self::BuildList(v) => VmOpcode::BuildList(*v), Self::BuildFunction => VmOpcode::BuildFunction, Self::StoreUplevel(a) => VmOpcode::StoreUplevel(*a), Self::BuildStruct => VmOpcode::BuildStruct, Self::BuildEnum => VmOpcode::BuildEnum, Self::BuildMixin => VmOpcode::BuildMixin, Self::BindCase(x, y) => VmOpcode::BindCase(*x, *y), Self::IncludeMixin => VmOpcode::IncludeMixin, Self::NewEnumVal(v, n) => { VmOpcode::NewEnumVal(if *v { CASE_HAS_PAYLOAD } else { 0 }, *n) } Self::EnumCheckIsCase(v) => VmOpcode::EnumCheckIsCase(*v), Self::EnumTryExtractPayload => VmOpcode::EnumTryExtractPayload, Self::TryUnwrapProtocol(v) => VmOpcode::TryUnwrapProtocol(*v), Self::Isa => VmOpcode::Isa, Self::Import(v) => VmOpcode::Import(*v), Self::LiftModule => VmOpcode::LiftModule, Self::LoadDylib(n) => VmOpcode::LoadDylib(*n), Self::Assert(v) => VmOpcode::Assert(*v), Self::Halt => VmOpcode::Halt, } } } impl std::fmt::Display for CompilerOpcode { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { use CompilerOpcode::*; match self { Nop => write!(f, "Nop"), Push(v) => write!(f, "Push({})", v), Push0 => write!(f, "Push0"), Push1 => write!(f, "Push1"), PushTrue => write!(f, "PushTrue"), PushFalse => write!(f, "PushFalse"), PushBuiltinTy(n) => write!(f, "PushBuiltinTy({})", n.name()), PushRuntimeValue(n) => write!(f, "PushRuntimeValue({})", n.name()), Pop => write!(f, "Pop"), Dup => write!(f, "Dup"), Swap => write!(f, "Swap"), Copy(n) => write!(f, "Copy({})", n), Add => write!(f, "Add"), Sub => write!(f, "Sub"), Mul => write!(f, "Mul"), Div => write!(f, "Div"), Rem => write!(f, "Rem"), Neg => write!(f, "Neg"), ShiftLeft => write!(f, "ShiftLeft"), ShiftRight => write!(f, "ShiftRight"), Not => write!(f, "Not"), Equal => write!(f, "Equal"), ReadLocal(n) => write!(f, "ReadLocal({})", n), WriteLocal(n) => write!(f, "WriteLocal({})", n), TypedefLocal(n) => write!(f, "TypedefLocal({})", n), ReadNamed(n) => write!(f, "ReadNamed({})", n), WriteNamed(n) => write!(f, "WriteNamed({})", n), TypedefNamed(n) => write!(f, "TypedefNamed({})", n), ReadIndex(n) => write!(f, "ReadIndex({})", n), WriteIndex(n) => write!(f, "WriteIndex({})", n), ReadAttribute(n) => write!(f, "ReadAttribute({})", n), WriteAttribute(n) => write!(f, "WriteAttribute({})", n), ReadUplevel(n) => write!(f, "ReadUplevel({})", n), LogicalAnd => write!(f, "LogicalAnd"), BitwiseAnd => write!(f, "BitwiseAnd"), LogicalOr => write!(f, "LogicalOr"), BitwiseOr => write!(f, "BitwiseOr"), Xor => write!(f, "Xor"), GreaterThan => write!(f, "GreaterThan"), GreaterThanEqual => write!(f, "GreaterThanEqual"), LessThan => write!(f, "LessThan"), LessThanEqual => write!(f, "LessThanEqual"), JumpTrue(dst) => write!(f, "JumpTrue({})", dst.name()), JumpFalse(dst) => write!(f, "JumpFalse({})", dst.name()), Jump(dst) => write!(f, "Jump({})", dst.name()), JumpIfArgSupplied(arg, dst) => { write!(f, "JumpIfArgSupplied({}, {})", arg, dst.name()) } JumpConditionally(tr, fa) => { write!(f, "JumpConditionally({}, {})", tr.name(), fa.name()) } Call(n) => write!(f, "Call({})", n), Return => write!(f, "Return"), ReturnUnit => write!(f, "ReturnUnit"), TryEnter(dst) => write!(f, "TryEnter({})", dst.name()), TryExit => write!(f, "TryExit"), Throw => write!(f, "Throw"), BuildList(v) => write!(f, "BuildList({})", v), BuildFunction => write!(f, "BuildFunction"), StoreUplevel(a) => write!(f, "StoreUplevel({})", a), BuildStruct => write!(f, "BuildStruct"), BuildEnum => write!(f, "BuildEnum"), BuildMixin => write!(f, "BuildMixin"), BindCase(x, y) => write!(f, "BindCase({}, {})", x, y), IncludeMixin => write!(f, "IncludeMixin"), NewEnumVal(has_payload, n) => write!(f, "NewEnumVal({}, {})", has_payload, n), EnumCheckIsCase(v) => write!(f, "EnumCheckIsCase({})", v), EnumTryExtractPayload => write!(f, "EnumTryExtractPayload"), TryUnwrapProtocol(v) => write!(f, "TryUnwrapProtocol({})", v), Isa => write!(f, "Isa"), Import(v) => write!(f, "Import({})", v), LiftModule => write!(f, "LiftModule"), LoadDylib(n) => write!(f, "LoadDylib({})", n), Assert(v) => write!(f, "Assert({})", v), Halt => write!(f, "Halt"), } } } ================================================ FILE: compiler-lib/src/builder/func.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use std::collections::HashSet; use crate::{ CompilationOptions, bc_writer::BytecodeWriter, builder::block::{BasicBlock, LocalValuesAccess}, constant_value::ConstantValues, line_table::LineTable, }; pub struct FunctionBuilder { blocks: Vec, names: HashSet, current: BasicBlock, bb_id: usize, line_table: LineTable, } impl Default for FunctionBuilder { fn default() -> Self { let mut this = Self { blocks: Vec::new(), names: HashSet::new(), current: BasicBlock::new("entry", 0), bb_id: 1, line_table: Default::default(), }; this.blocks.push(this.current.clone()); this.names.insert(this.current.name().to_owned()); this } } impl FunctionBuilder { pub fn try_get_block(&self, name: &str) -> Option { for blk in &self.blocks { if blk.name() == name { return Some(blk.clone()); } } None } pub fn get_block(&self, name: &str) -> BasicBlock { self.try_get_block(name).expect("block is missing") } fn uniq_name(&self, name: &str) -> String { let mut name = String::from(name); while self.names.contains(&name) { name += "_"; } name } fn make_new_block(&mut self, name: &str) -> BasicBlock { assert!(!self.names.contains(name)); let blk = BasicBlock::new(name, self.bb_id); self.bb_id += 1; blk } pub fn insert_block_after(&mut self, name: &str, target: &BasicBlock) -> BasicBlock { let name = self.uniq_name(name); let blk = self.make_new_block(&name); let mut inserted = false; for i in 0..self.blocks.len() { let blk_i = &self.blocks[i]; if blk_i.id() == target.id() { if i + 1 >= self.blocks.len() { self.blocks.push(blk.clone()); } else { self.blocks.insert(i + 1, blk.clone()); } inserted = true; break; } } if !inserted { self.blocks.push(blk.clone()); } self.names.insert(name); blk } pub fn append_block_at_end(&mut self, name: &str) -> BasicBlock { let name = self.uniq_name(name); let blk = self.make_new_block(&name); self.blocks.push(blk.clone()); self.names.insert(name); blk } pub fn set_current_block(&mut self, blk: BasicBlock) { self.current = blk; } pub fn get_current_block(&self) -> BasicBlock { self.current.clone() } pub fn position_of_block_instructions(&self, blk: &BasicBlock) -> Option { let mut count = 0; for next in &self.blocks { if next == blk { return Some(count as u16); } else { count += next.len() } } None } fn has_entrypoints(&self, blk: &BasicBlock) -> bool { for src_blk in &self.blocks { let br = src_blk.imp.writer.borrow(); for src_op in br.as_slice() { for dst in src_op.op.is_jump_instruction() { if dst.id() == blk.id() { return true; } } } } false } fn find_orphaned_blocks(&self) -> HashSet { let mut orphans = HashSet::::default(); for blk in &self.blocks { if blk.id() != 0 { let has_entrypoints = self.has_entrypoints(blk); if !has_entrypoints { orphans.insert(blk.id()); } } } orphans } fn remove_block_with_id(&mut self, id: usize) -> bool { for i in 0..self.blocks.len() { if self.blocks[i].id() == id { self.blocks.remove(i); return true; } } false } fn run_optimize_passes(&mut self, cv: &ConstantValues) { let orphans = self.find_orphaned_blocks(); for orphan_id in &orphans { assert!(self.remove_block_with_id(*orphan_id)); } let locals_access = self.calculate_locals_access(); let unused_locals = locals_access.calculate_unused_locals(); for blk in &self.blocks { if !unused_locals.is_empty() { blk.drop_unused_locals(&unused_locals); } blk.run_optimize_passes(cv); } } fn calculate_locals_access(&self) -> LocalValuesAccess { let mut dest = LocalValuesAccess::default(); for blk in &self.blocks { blk.calculate_locals_access(&mut dest); } dest } pub fn write( &mut self, cv: &ConstantValues, options: &CompilationOptions, ) -> Result, crate::do_compile::CompilationErrorReason> { if options.dump_builder { println!("(unopt) Intermediate Representation Dump:\n{}", self); } if options.optimize { self.run_optimize_passes(cv); if options.dump_builder { println!("(opt) Intermediate Representation Dump:\n{}", self); } } let mut dest = BytecodeWriter::default(); for blk in &self.blocks { assert!(blk.is_empty() || blk.is_terminal()); blk.write(self, &mut dest); } let ret = dest.get_data(); if ret.len() >= u16::MAX.into() { Err(crate::do_compile::CompilationErrorReason::FunctionBodyTooLarge) } else { Ok(ret) } } pub fn write_line_table(&self) -> &LineTable { for blk in &self.blocks { blk.write_line_table( self.position_of_block_instructions(blk).unwrap(), &self.line_table, ); } &self.line_table } } impl std::fmt::Display for FunctionBuilder { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { for blk in &self.blocks { writeln!(f, "{}", blk)?; } Ok(()) } } ================================================ FILE: compiler-lib/src/builder/mod.rs ================================================ // SPDX-License-Identifier: Apache-2.0 pub mod block; pub mod compiler_opcodes; pub mod func; ================================================ FILE: compiler-lib/src/constant_value.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use std::collections::HashMap; use aria_parser::ast::SourcePointer; use enum_as_inner::EnumAsInner; use crate::line_table::LineTable; #[derive(Clone, PartialEq, Eq)] pub struct CompiledCodeObject { pub name: String, pub attribute: u8, pub body: Vec, pub required_argc: u8, // arguments that are required to call this function pub default_argc: u8, // additional arguments that this function can accept pub loc: SourcePointer, pub line_table: LineTable, pub frame_size: u8, } #[derive(Clone, Copy)] pub struct FpConst(f64); impl FpConst { fn to_int(self) -> i64 { unsafe { std::mem::transmute(self) } } pub fn raw_value(&self) -> f64 { self.0 } } impl PartialEq for FpConst { fn eq(&self, other: &Self) -> bool { self.to_int() == other.to_int() } } impl Eq for FpConst {} impl std::hash::Hash for FpConst { fn hash(&self, state: &mut H) { self.to_int().hash(state) } } impl From for FpConst { fn from(value: f64) -> Self { Self(value) } } // ignore the line table and only hash on function code impl std::hash::Hash for CompiledCodeObject { fn hash(&self, state: &mut H) { self.body.hash(state); } } #[derive(EnumAsInner, Clone, PartialEq, Eq, Hash)] pub enum ConstantValue { Integer(i64), String(String), Float(FpConst), CompiledCodeObject(CompiledCodeObject), } impl std::fmt::Display for ConstantValue { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { Self::Integer(arg0) => write!(f, "int:{}", *arg0), Self::Float(arg0) => write!(f, "fp:{}", arg0.0), Self::String(arg0) => write!(f, "str:\"{}\"", *arg0), Self::CompiledCodeObject(_) => write!(f, "compiled-code-object"), } } } #[derive(Default)] pub struct ConstantValues { pub(crate) values: Vec, uniq: HashMap, } pub enum ConstantValuesError { OutOfSpace, } impl ConstantValues { pub fn insert(&mut self, v: ConstantValue) -> Result { if let Some(idx) = self.uniq.get(&v) { Ok(*idx as u16) } else { if self.values.len() == (u16::MAX as usize) { return Err(ConstantValuesError::OutOfSpace); } let idx = self.values.len(); self.uniq.insert(v.clone(), idx); self.values.push(v); Ok(idx as u16) } } pub fn get(&self, i: usize) -> Option { self.values.get(i).cloned() } pub fn len(&self) -> usize { self.values.len() } pub fn is_empty(&self) -> bool { self.values.is_empty() } pub fn values(&self) -> std::slice::Iter<'_, ConstantValue> { self.values.iter() } } ================================================ FILE: compiler-lib/src/do_compile/mod.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use std::{collections::HashSet, fmt::Display, path::PathBuf}; use aria_parser::ast::{ ArgumentDecl, ArgumentList, AssertStatement, CodeBlock, DeclarationId, ElsePiece, EnumCaseDecl, EnumDecl, EnumDeclEntry, Expression, FunctionBody, Identifier, MatchPattern, MatchPatternEnumCase, MatchRule, MatchStatement, MethodAccess, MethodDecl, MixinIncludeDecl, OperatorDecl, ParsedModule, ReturnStatement, SourceBuffer, SourcePointer, Statement, StringLiteral, StructDecl, StructEntry, ValDeclStatement, prettyprint::PrettyPrintable, source_to_ast, }; use haxby_opcodes::BuiltinTypeId; use thiserror::Error; use crate::{ CompilationOptions, builder::{block::BasicBlock, compiler_opcodes::CompilerOpcode, func::FunctionBuilder}, constant_value::{ConstantValue, ConstantValuesError}, module::CompiledModule, scope::{CompilationScope, ScopeError, ScopeErrorReason}, }; #[derive(Debug, Error)] pub enum CompilationErrorReason { #[error("identifier is reserved: '{0}'")] ReservedIdentifier(String), #[error("no such identifier: '{0}'")] NoSuchIdentifier(String), #[error("function body is larger than allowed")] FunctionBodyTooLarge, #[error("list length is out of bounds")] ListTooLarge, #[error("attempt to modify a read-only value")] ReadOnlyValue, #[error("{0} is not a valid literal")] InvalidLiteral(String), #[error("{0} is not a valid operator")] InvalidOperator(String), #[error("{0} cannot be reversed")] IrreversibleOperator(String), #[error("operator {0} accepts {1} arguments, but {2} were declared")] OperatorArityMismatch(String, OperatorArity, usize), #[error("attempt to read a write-only value")] WriteOnlyValue, #[error("parser error: {0}")] ParserError(String), #[error("module contains too many constant values")] TooManyConstants, #[error("function accepts too many arguments")] TooManyArguments, #[error("argument without a default value follows argument with default value")] DefaultArgsMustTrail, #[error("flow control statement not permitted in current context")] FlowControlNotAllowed, #[error("argument name '{0}' is already defined for this function")] DuplicateArgumentName(String), #[error("struct members do not support type hints")] NoTypeHintOnStructMember, #[error("nested closures are not supported")] NestedClosureDisallowed, #[error("attempted to write to {0} values, but {1} were provided")] AssignmentArityMismatch(usize, usize), } impl From<&ScopeErrorReason> for CompilationErrorReason { fn from(value: &ScopeErrorReason) -> Self { match value { ScopeErrorReason::TooManyConstants => CompilationErrorReason::TooManyConstants, ScopeErrorReason::NoSuchIdentifier(s) => { CompilationErrorReason::NoSuchIdentifier(s.clone()) } ScopeErrorReason::OverlyDeepClosure => CompilationErrorReason::NestedClosureDisallowed, } } } impl From for CompilationError { fn from(value: ScopeError) -> Self { CompilationError { loc: value.loc, reason: CompilationErrorReason::from(&value.reason), } } } impl From<&ConstantValuesError> for CompilationErrorReason { fn from(value: &ConstantValuesError) -> Self { match value { ConstantValuesError::OutOfSpace => CompilationErrorReason::TooManyConstants, } } } pub struct CompilationError { pub loc: SourcePointer, pub reason: CompilationErrorReason, } impl std::fmt::Display for CompilationError { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "at {}, error occurred: {}", self.loc, self.reason) } } impl std::fmt::Debug for CompilationError { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "at {}, error occurred: {}", self.loc, self.reason) } } pub type CompilationResult = Result; #[derive(Default)] struct ControlFlowTargets { break_dest: Option, continue_dest: Option, } struct CompileParams<'a> { module: &'a mut CompiledModule, scope: &'a CompilationScope, writer: &'a mut FunctionBuilder, cflow: &'a ControlFlowTargets, options: &'a CompilationOptions, } trait CompileNode<'a, T = (), E = CompilationError> { fn do_compile(&self, params: &'a mut CompileParams) -> CompilationResult; fn insert_const_or_fail( &self, params: &mut CompileParams, ct: ConstantValue, loc: &SourcePointer, ) -> CompilationResult { match params.module.constants.insert(ct) { Ok(idx) => Ok(idx), Err(_) => Err(CompilationError { loc: loc.clone(), reason: CompilationErrorReason::TooManyConstants, }), } } fn return_unit_value( &self, params: &mut CompileParams, loc: &SourcePointer, ) -> CompilationResult { params .writer .get_current_block() .write_opcode_and_source_info(CompilerOpcode::ReturnUnit, loc.clone()); Ok(()) } } mod nodes; mod postfix; fn ensure_arg_list_is_correct(args: &ArgumentList) -> CompilationResult { ensure_unique_arg_names(args)?; ensure_default_args_trailing(args)?; Ok(()) } fn ensure_unique_arg_names(args: &ArgumentList) -> CompilationResult { let mut arg_set = HashSet::new(); for arg in &args.names { if arg_set.contains(arg.name()) { return Err(CompilationError { loc: arg.loc.clone(), reason: CompilationErrorReason::DuplicateArgumentName(arg.name().to_owned()), }); } else { arg_set.insert(arg.name().to_owned()); } } Ok(()) } fn ensure_default_args_trailing(args: &ArgumentList) -> CompilationResult { let mut found_default = false; for arg in &args.names { if arg.deft.is_some() { found_default = true; } else if found_default { return Err(CompilationError { loc: arg.loc.clone(), reason: CompilationErrorReason::DefaultArgsMustTrail, }); } } Ok(()) } fn emit_arg_at_target( arg: &ArgumentDecl, idx: u8, params: &mut CompileParams, ) -> CompilationResult { if let Some(deft_expr) = arg.deft.as_ref() { let block = params .writer .append_block_at_end(&format!("supplied_arg_{idx}")); params .writer .get_current_block() .write_opcode_and_source_info( CompilerOpcode::JumpIfArgSupplied(idx, block.clone()), arg.loc.clone(), ); deft_expr.do_compile(params)?; params .writer .get_current_block() .write_opcode_and_source_info(CompilerOpcode::Jump(block.clone()), arg.loc.clone()); params.writer.set_current_block(block); } if let Some(ty) = arg.type_info() { ty.do_compile(params)?; } else { params .writer .get_current_block() .write_opcode_and_source_info( CompilerOpcode::PushBuiltinTy(BuiltinTypeId::Any), arg.loc.clone(), ); } params.scope.emit_typed_define( arg.name(), &mut params.module.constants, params.writer.get_current_block(), arg.loc.clone(), )?; params.scope.emit_write( arg.name(), &mut params.module.constants, params.writer.get_current_block(), arg.loc.clone(), )?; Ok(()) } #[allow(dead_code)] struct ArgumentCountInfo { user_args: u8, required_args: u8, default_args: u8, varargs: bool, } fn emit_args_at_target( prefix_args: &[ArgumentDecl], args: &ArgumentList, suffix_args: &[ArgumentDecl], params: &mut CompileParams, ) -> CompilationResult { ensure_arg_list_is_correct(args)?; let total_args = prefix_args.len() + args.names.len() + suffix_args.len(); if total_args > u8::MAX.into() { return Err(CompilationError { loc: args.loc.clone(), reason: CompilationErrorReason::TooManyArguments, }); } let mut argc_info = ArgumentCountInfo { user_args: args.len() as u8, required_args: 0, default_args: 0, varargs: args.vararg, }; let mut arg_idx: u8 = 0; for arg in prefix_args { emit_arg_at_target(arg, arg_idx, params)?; argc_info.required_args += 1; arg_idx += 1; } for arg in &args.names { emit_arg_at_target(arg, arg_idx, params)?; if arg.deft.is_some() { argc_info.default_args += 1; } else { argc_info.required_args += 1; } arg_idx += 1; } for arg in suffix_args { emit_arg_at_target(arg, arg_idx, params)?; argc_info.required_args += 1; arg_idx += 1; } if args.vararg { params.scope.emit_untyped_define( "varargs", &mut params.module.constants, params.writer.get_current_block(), args.loc.clone(), )?; } Ok(argc_info) } // assume your parent struct is on the stack fn emit_type_mixin_include_decl_compile( mi: &MixinIncludeDecl, params: &mut CompileParams, ) -> CompilationResult { mi.what.do_compile(params)?; params .writer .get_current_block() .write_opcode_and_source_info(CompilerOpcode::IncludeMixin, mi.loc.clone()); Ok(()) } // assume your parent struct is on the stack fn emit_method_decl_compile(md: &MethodDecl, params: &mut CompileParams) -> CompilationResult { md.do_compile(params)?; let name_idx = md.insert_const_or_fail( params, ConstantValue::String(md.name.value.clone()), &md.loc, )?; params .writer .get_current_block() .write_opcode_and_source_info(CompilerOpcode::BuildFunction, md.loc.clone()) .write_opcode_and_source_info(CompilerOpcode::WriteAttribute(name_idx), md.loc.clone()); Ok(()) } #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum OperatorArity { Exactly(usize), AtLeast(usize), } impl OperatorArity { fn unary() -> Self { OperatorArity::Exactly(1) } fn any() -> Self { OperatorArity::AtLeast(0) } fn is_acceptable(&self, arg_count: usize) -> bool { match self { OperatorArity::Exactly(n) => *n == arg_count, OperatorArity::AtLeast(n) => arg_count >= *n, } } } impl Display for OperatorArity { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { OperatorArity::Exactly(n) => write!(f, "exactly {n}"), OperatorArity::AtLeast(n) => write!(f, "at least {n}"), } } } struct OperatorInfo { arity: OperatorArity, // number of arguments (minus the receiver this) direct_name: &'static str, reverse_name: &'static str, } lazy_static::lazy_static! { static ref OPERATOR_INFO: std::collections::HashMap<&'static str, OperatorInfo> = { let mut map = std::collections::HashMap::new(); map.insert( "+", OperatorInfo { arity: OperatorArity::unary(), direct_name: "add", reverse_name: "radd", }, ); map.insert( "-", OperatorInfo { arity: OperatorArity::unary(), direct_name: "sub", reverse_name: "rsub", }, ); map.insert( "*", OperatorInfo { arity: OperatorArity::unary(), direct_name: "mul", reverse_name: "rmul", }, ); map.insert( "/", OperatorInfo { arity: OperatorArity::unary(), direct_name: "div", reverse_name: "rdiv", }, ); map.insert( "%", OperatorInfo { arity: OperatorArity::unary(), direct_name: "rem", reverse_name: "rrem", }, ); map.insert( "<<", OperatorInfo { arity: OperatorArity::unary(), direct_name: "lshift", reverse_name: "rlshift", }, ); map.insert( ">>", OperatorInfo { arity: OperatorArity::unary(), direct_name: "rshift", reverse_name: "rrshift", }, ); map.insert("==", OperatorInfo { arity: OperatorArity::unary(), direct_name: "equals", reverse_name: "", }, ); map.insert("<", OperatorInfo { arity: OperatorArity::unary(), direct_name: "lt", reverse_name: "gt", }, ); map.insert(">", OperatorInfo { arity: OperatorArity::unary(), direct_name: "gt", reverse_name: "lt", }, ); map.insert("<=", OperatorInfo { arity: OperatorArity::unary(), direct_name: "lteq", reverse_name: "gteq", }, ); map.insert(">=", OperatorInfo { arity: OperatorArity::unary(), direct_name: "gteq", reverse_name: "lteq", }, ); map.insert("&", OperatorInfo { arity: OperatorArity::unary(), direct_name: "bwand", reverse_name: "rbwand", }, ); map.insert("|", OperatorInfo { arity: OperatorArity::unary(), direct_name: "bwor", reverse_name: "rbwor", }, ); map.insert("^", OperatorInfo { arity: OperatorArity::unary(), direct_name: "xor", reverse_name: "rxor", }, ); map.insert("u-", OperatorInfo { arity: OperatorArity::Exactly(0), direct_name: "neg", reverse_name: "", }, ); map.insert("()", OperatorInfo { arity: OperatorArity::any(), direct_name: "call", reverse_name: "", }, ); map.insert("[]", OperatorInfo { arity: OperatorArity::any(), direct_name: "read_index", reverse_name: "", }, ); map.insert("[]=", OperatorInfo { arity: OperatorArity::AtLeast(1), direct_name: "write_index", reverse_name: "", }, ); map }; } // assume your parent struct is on the stack fn emit_operator_decl_compile(op: &OperatorDecl, params: &mut CompileParams) -> CompilationResult { let op_symbol = op .symbol .prettyprint( aria_parser::ast::prettyprint::printout_accumulator::PrintoutAccumulator::default(), ) .value(); let op_info = match OPERATOR_INFO.get(op_symbol.as_str()) { Some(info) => info, None => { return Err(CompilationError { loc: op.loc.clone(), reason: CompilationErrorReason::InvalidOperator(op_symbol), }); } }; if !op_info.arity.is_acceptable(op.args.len()) { return Err(CompilationError { loc: op.loc.clone(), reason: CompilationErrorReason::OperatorArityMismatch( op_symbol, op_info.arity, op.args.len(), ), }); } if op.reverse && op_info.reverse_name.is_empty() { return Err(CompilationError { loc: op.loc.clone(), reason: CompilationErrorReason::IrreversibleOperator(op_symbol), }); } let op_fn_name = format!( "_op_impl_{}", if op.reverse { op_info.reverse_name } else { op_info.direct_name } ); let md = MethodDecl { loc: op.loc.clone(), access: MethodAccess::Instance, name: Identifier { loc: op.loc.clone(), value: op_fn_name, }, args: op.args.clone(), body: op.body.clone(), }; emit_method_decl_compile(&md, params) } // assume your parent struct is on the stack fn emit_type_val_decl_compile( vd: &ValDeclStatement, params: &mut CompileParams, ) -> CompilationResult { for decl in &vd.decls { if decl.id.ty.is_some() { return Err(CompilationError { loc: vd.loc.clone(), reason: CompilationErrorReason::NoTypeHintOnStructMember, }); } decl.val.do_compile(params)?; let name_idx = vd.insert_const_or_fail( params, ConstantValue::String(decl.id.name.value.clone()), &vd.loc, )?; params .writer .get_current_block() .write_opcode_and_source_info(CompilerOpcode::WriteAttribute(name_idx), vd.loc.clone()); } Ok(()) } // assume your parent struct is on the stack fn emit_type_members_compile( entries: &[StructEntry], params: &mut CompileParams, drop_at_end: bool, ) -> CompilationResult { for se in entries { params .writer .get_current_block() .write_opcode_and_source_info(CompilerOpcode::Dup, se.loc().clone()); match se { aria_parser::ast::StructEntry::Method(md) => emit_method_decl_compile(md, params)?, aria_parser::ast::StructEntry::Operator(od) => emit_operator_decl_compile(od, params)?, aria_parser::ast::StructEntry::Variable(vd) => emit_type_val_decl_compile(vd, params)?, aria_parser::ast::StructEntry::Struct(sd) => { do_struct_compile(sd, params)?; let name_idx = sd.insert_const_or_fail( params, ConstantValue::String(sd.name.value.clone()), &sd.loc, )?; params .writer .get_current_block() .write_opcode_and_source_info( CompilerOpcode::WriteAttribute(name_idx), sd.loc.clone(), ); } aria_parser::ast::StructEntry::Enum(ed) => { do_enum_compile(ed, params, |name, params| { params .writer .get_current_block() .write_opcode_and_source_info(CompilerOpcode::Swap, ed.loc.clone()); params .writer .get_current_block() .write_opcode_and_source_info(CompilerOpcode::Copy(1), ed.loc.clone()); let name_idx = ed.insert_const_or_fail( params, ConstantValue::String(name.to_owned()), &ed.loc, )?; params .writer .get_current_block() .write_opcode_and_source_info( CompilerOpcode::WriteAttribute(name_idx), ed.loc.clone(), ); Ok(()) })?; } aria_parser::ast::StructEntry::MixinInclude(mi) => { emit_type_mixin_include_decl_compile(mi, params)? } } } if drop_at_end { // remove the last leftover struct #[allow(deprecated)] // no entry to ascribe this write to params .writer .get_current_block() .write_opcode(CompilerOpcode::Pop); } Ok(()) } fn do_struct_compile(sd: &StructDecl, params: &mut CompileParams) -> CompilationResult { let self_name = StringLiteral { loc: sd.loc.clone(), value: sd.name.value.clone(), }; self_name.do_compile(params)?; params .writer .get_current_block() .write_opcode_and_source_info(CompilerOpcode::BuildStruct, sd.loc.clone()); // Inject mixin includes for each item in the inherits list let body = if !sd.inherits.is_empty() { let mut new_body = vec![]; for mixin_expr in &sd.inherits { new_body.push(StructEntry::MixinInclude(Box::new(MixinIncludeDecl { loc: sd.loc.clone(), what: mixin_expr.clone(), }))); } new_body.extend_from_slice(&sd.body); new_body } else { sd.body.clone() }; emit_type_members_compile(&body, params, false) } fn do_enum_compile( ed: &EnumDecl, params: &mut CompileParams, name_writer: T, ) -> CompilationResult where T: FnOnce(&str, &mut CompileParams) -> CompilationResult, { let self_name = StringLiteral { loc: ed.loc.clone(), value: ed.name.value.clone(), }; self_name.do_compile(params)?; params .writer .get_current_block() .write_opcode_and_source_info(CompilerOpcode::BuildEnum, ed.loc.clone()); name_writer(&ed.name.value, params)?; let mut cases: Vec = vec![]; let mut entries: Vec = vec![]; for ede in &ed.body { match ede { EnumDeclEntry::EnumCaseDecl(case) => cases.push(case.clone()), EnumDeclEntry::StructEntry(entry) => entries.push(entry.clone()), } } let enum_helper_methods = generate_case_helpers_extension_for_enum(&cases); emit_type_members_compile(&enum_helper_methods, params, false)?; emit_type_members_compile(&entries, params, false)?; emit_enum_cases(&cases, params)?; params .writer .get_current_block() .write_opcode_and_source_info(CompilerOpcode::Pop, ed.loc.clone()); Ok(()) } fn generate_is_case_helper_for_enum(case: &EnumCaseDecl) -> MethodDecl { let return_true_stmt = ReturnStatement::from(&Expression::from(&Identifier { loc: case.loc.clone(), value: "true".to_owned(), })); let return_false_stmt = ReturnStatement::from(&Expression::from(&Identifier { loc: case.loc.clone(), value: "false".to_owned(), })); let match_case_pattern = MatchPatternEnumCase { loc: case.loc.clone(), case: case.name.clone(), payload: None, }; let match_rule = MatchRule { loc: case.loc.clone(), patterns: vec![MatchPattern::MatchPatternEnumCase(match_case_pattern)], then: CodeBlock::from(&Statement::ReturnStatement(return_true_stmt)), }; let match_statement = MatchStatement { loc: case.loc.clone(), expr: Expression::from(&Identifier { loc: case.loc.clone(), value: "this".to_owned(), }), rules: vec![match_rule], els: Some(ElsePiece { loc: case.loc.clone(), then: CodeBlock::from(&Statement::ReturnStatement(return_false_stmt)), }), }; let method_body = FunctionBody { code: CodeBlock::from(&Statement::MatchStatement(match_statement)), }; MethodDecl { loc: case.loc.clone(), access: MethodAccess::Instance, name: Identifier { loc: case.loc.clone(), value: format!("is_{}", case.name.value), }, args: ArgumentList::empty(case.loc.clone()), body: method_body, } } fn generate_unwap_case_helper_for_enum(case: &EnumCaseDecl) -> MethodDecl { assert!(case.payload.is_some()); let return_true_stmt = ReturnStatement::from(&Expression::from(&Identifier { loc: case.loc.clone(), value: "__case_payload".to_owned(), })); let assert_false_stmt = AssertStatement { loc: case.loc.clone(), val: Expression::from(&Identifier { loc: case.loc.clone(), value: "false".to_owned(), }), }; let match_case_pattern = MatchPatternEnumCase { loc: case.loc.clone(), case: case.name.clone(), payload: Some(DeclarationId { loc: case.loc.clone(), name: Identifier { loc: case.loc.clone(), value: "__case_payload".to_owned(), }, ty: None, }), }; let match_rule = MatchRule { loc: case.loc.clone(), patterns: vec![MatchPattern::MatchPatternEnumCase(match_case_pattern)], then: CodeBlock::from(&Statement::ReturnStatement(return_true_stmt)), }; let match_statement = MatchStatement { loc: case.loc.clone(), expr: Expression::from(&Identifier { loc: case.loc.clone(), value: "this".to_owned(), }), rules: vec![match_rule], els: Some(ElsePiece { loc: case.loc.clone(), then: CodeBlock::from(&Statement::AssertStatement(assert_false_stmt)), }), }; let method_body = FunctionBody { code: CodeBlock::from(&Statement::MatchStatement(match_statement)), }; MethodDecl { loc: case.loc.clone(), access: MethodAccess::Instance, name: Identifier { loc: case.loc.clone(), value: format!("unwrap_{}", case.name.value), }, args: ArgumentList::empty(case.loc.clone()), body: method_body, } } fn generate_case_helpers_extension_for_enum(cases: &[EnumCaseDecl]) -> Vec { let mut entries: Vec = vec![]; for case in cases { entries.push(StructEntry::Method(Box::new( generate_is_case_helper_for_enum(case), ))); if case.payload.is_some() { entries.push(StructEntry::Method(Box::new( generate_unwap_case_helper_for_enum(case), ))); } } entries } // assume your parent enum is on the stack fn emit_enum_cases(cases: &[EnumCaseDecl], params: &mut CompileParams) -> CompilationResult { for case in cases { case.do_compile(params)?; } Ok(()) } pub(crate) fn compile_from_ast( ast: &ParsedModule, options: &CompilationOptions, ) -> CompilationResult> { let mut dest = CompiledModule::default(); let scope = CompilationScope::module(); let mut mod_init_bytecode = FunctionBuilder::default(); let cflow = ControlFlowTargets::default(); let mut c_params = CompileParams { module: &mut dest, scope: &scope, writer: &mut mod_init_bytecode, cflow: &cflow, options, }; ast.do_compile(&mut c_params)?; Ok(dest) } pub(crate) fn compile_from_source( src: &SourceBuffer, options: &CompilationOptions, ) -> CompilationResult> { let ast = match source_to_ast(src) { Ok(ast) => ast, Err(err) => { return Err(vec![CompilationError { loc: err.loc, reason: CompilationErrorReason::ParserError(err.msg), }]); } }; compile_from_ast(&ast, options).map(|mut module| { // The source buffer name is the cannonalized path to the source file if it was created from a file. // Once we check it is an existing file, we can use it to find the widget path. let src_path = PathBuf::from(&src.name); module.widget_root_path = if src_path.exists() { // Ensure the source buffer name is a file path debug_assert!(src_path.is_file()); let mut ancestors = src_path.ancestors(); loop { if let Some(widget_path) = ancestors.next() { let widget_json = widget_path.join("widget.json"); if !widget_json.exists() { continue; } break Some(widget_path.to_path_buf()); } break None; } } else { None }; module }) } ================================================ FILE: compiler-lib/src/do_compile/nodes/add_operation.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use crate::{ builder::compiler_opcodes::CompilerOpcode, do_compile::{CompilationResult, CompileNode, CompileParams}, }; impl<'a> CompileNode<'a> for aria_parser::ast::AddOperation { fn do_compile(&self, params: &'a mut CompileParams) -> CompilationResult { self.left.do_compile(params)?; for right in &self.right { right.1.do_compile(params)?; params .writer .get_current_block() .write_opcode_and_source_info( match right.0 { aria_parser::ast::AddSymbol::Plus => CompilerOpcode::Add, aria_parser::ast::AddSymbol::Minus => CompilerOpcode::Sub, }, self.loc.clone(), ); } Ok(()) } } ================================================ FILE: compiler-lib/src/do_compile/nodes/assert_statement.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use aria_parser::ast::prettyprint::{PrettyPrintable, printout_accumulator::PrintoutAccumulator}; use crate::{ builder::compiler_opcodes::CompilerOpcode, constant_value::ConstantValue, do_compile::{CompilationResult, CompileNode, CompileParams}, }; impl<'a> CompileNode<'a> for aria_parser::ast::AssertStatement { fn do_compile(&self, params: &'a mut CompileParams) -> CompilationResult { self.val.do_compile(params)?; let poa = PrintoutAccumulator::default(); let poa = self.val.prettyprint(poa).value(); let msg_idx = self.insert_const_or_fail(params, ConstantValue::String(poa), &self.loc)?; params .writer .get_current_block() .write_opcode_and_source_info(CompilerOpcode::Assert(msg_idx), self.loc.clone()); Ok(()) } } ================================================ FILE: compiler-lib/src/do_compile/nodes/assign_statement.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use aria_parser::ast::{ DeclarationId, Expression, Identifier, IntLiteral, Primary, Statement, ValDeclEntry, ValDeclStatement, }; use crate::do_compile::{CompilationResult, CompileNode, CompileParams, postfix::PostfixValue}; impl<'a> CompileNode<'a> for aria_parser::ast::AssignStatement { fn do_compile(&self, params: &'a mut CompileParams) -> CompilationResult { if self.id.len() != self.val.len() { return Err(crate::do_compile::CompilationError { loc: self.loc.clone(), reason: crate::do_compile::CompilationErrorReason::AssignmentArityMismatch( self.id.len(), self.val.len(), ), }); } if self.id.len() == 1 { let pv = PostfixValue::from(&self.id[0]); pv.emit_write(&self.val[0], params) } else { let temp_buffer_store = Identifier { loc: self.loc.clone(), value: format!("__multiwrite_temp_store{:?}", self.loc.location), }; let zero_val = Expression::from(&Primary::IntLiteral(IntLiteral { loc: self.loc.clone(), base: aria_parser::ast::IntLiteralBase::Decimal, val: "0".to_string(), })); let temp_buffer_expression = Expression::from(&temp_buffer_store.clone()); Statement::ValDeclStatement(ValDeclStatement { loc: self.loc.clone(), decls: vec![ValDeclEntry { loc: self.loc.clone(), id: DeclarationId::from(&temp_buffer_store), val: zero_val, }], }) .do_compile(params)?; for rhs in self.val.iter().rev() { rhs.do_compile(params)?; } for lhs in self.id.iter() { params.scope.emit_write( &temp_buffer_store.value, &mut params.module.constants, params.writer.get_current_block(), lhs.loc.clone(), )?; let pv = PostfixValue::from(lhs); pv.emit_write(&temp_buffer_expression, params)?; } Ok(()) } } } ================================================ FILE: compiler-lib/src/do_compile/nodes/break_statement.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use crate::{ builder::compiler_opcodes::CompilerOpcode, do_compile::{ CompilationError, CompilationErrorReason, CompilationResult, CompileNode, CompileParams, }, }; impl<'a> CompileNode<'a> for aria_parser::ast::BreakStatement { fn do_compile(&self, params: &'a mut CompileParams) -> CompilationResult { if let Some(break_target) = ¶ms.cflow.break_dest { params .writer .get_current_block() .write_opcode_and_source_info( CompilerOpcode::Jump(break_target.clone()), self.loc.clone(), ); Ok(()) } else { Err(CompilationError { loc: self.loc.clone(), reason: CompilationErrorReason::FlowControlNotAllowed, }) } } } ================================================ FILE: compiler-lib/src/do_compile/nodes/code_block.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use crate::do_compile::{CompilationResult, CompileNode, CompileParams}; impl<'a> CompileNode<'a> for aria_parser::ast::CodeBlock { fn do_compile(&self, params: &'a mut CompileParams) -> CompilationResult { let c_scope = params.scope.child(); let mut c_params = CompileParams { module: params.module, scope: &c_scope, writer: params.writer, cflow: params.cflow, options: params.options, }; for entry in &self.entries { entry.do_compile(&mut c_params)?; } Ok(()) } } ================================================ FILE: compiler-lib/src/do_compile/nodes/comp_operation.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use crate::{ builder::compiler_opcodes::CompilerOpcode, do_compile::{CompilationResult, CompileNode, CompileParams}, }; impl<'a> CompileNode<'a> for aria_parser::ast::CompOperation { fn do_compile(&self, params: &'a mut CompileParams) -> CompilationResult { self.left.do_compile(params)?; if let Some(right) = &self.right { right.1.do_compile(params)?; match right.0 { aria_parser::ast::CompSymbol::Equal => params .writer .get_current_block() .write_opcode_and_source_info(CompilerOpcode::Equal, self.loc.clone()), aria_parser::ast::CompSymbol::NotEqual => params .writer .get_current_block() .write_opcode_and_source_info(CompilerOpcode::Equal, self.loc.clone()) .write_opcode_and_source_info(CompilerOpcode::Not, self.loc.clone()), aria_parser::ast::CompSymbol::Isa => params .writer .get_current_block() .write_opcode_and_source_info(CompilerOpcode::Isa, self.loc.clone()), }; } Ok(()) } } ================================================ FILE: compiler-lib/src/do_compile/nodes/continue_statement.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use crate::{ builder::compiler_opcodes::CompilerOpcode, do_compile::{ CompilationError, CompilationErrorReason, CompilationResult, CompileNode, CompileParams, }, }; impl<'a> CompileNode<'a> for aria_parser::ast::ContinueStatement { fn do_compile(&self, params: &'a mut CompileParams) -> CompilationResult { if let Some(continue_target) = ¶ms.cflow.continue_dest { params .writer .get_current_block() .write_opcode_and_source_info( CompilerOpcode::Jump(continue_target.clone()), self.loc.clone(), ); Ok(()) } else { Err(CompilationError { loc: self.loc.clone(), reason: CompilationErrorReason::FlowControlNotAllowed, }) } } } ================================================ FILE: compiler-lib/src/do_compile/nodes/enum_case_decl.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use haxby_opcodes::enum_case_attribs::CASE_HAS_PAYLOAD; use crate::{ builder::compiler_opcodes::CompilerOpcode, constant_value::ConstantValue, do_compile::{CompilationResult, CompileNode, CompileParams}, }; impl<'a> CompileNode<'a> for aria_parser::ast::EnumCaseDecl { fn do_compile(&self, params: &'a mut CompileParams) -> CompilationResult<()> { params .writer .get_current_block() .write_opcode_and_source_info(CompilerOpcode::Dup, self.loc.clone()); let attrib_byte = match &self.payload { Some(expr) => { expr.do_compile(params)?; CASE_HAS_PAYLOAD } None => 0, }; let name_idx = self.insert_const_or_fail( params, ConstantValue::String(self.name.value.clone()), &self.loc, )?; params .writer .get_current_block() .write_opcode_and_source_info( CompilerOpcode::BindCase(attrib_byte, name_idx), self.loc.clone(), ); Ok(()) } } ================================================ FILE: compiler-lib/src/do_compile/nodes/enum_decl.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use crate::{ builder::compiler_opcodes::CompilerOpcode, do_compile::{CompilationResult, CompileNode, CompileParams, do_enum_compile}, }; impl<'a> CompileNode<'a> for aria_parser::ast::EnumDecl { fn do_compile(&self, params: &'a mut CompileParams) -> CompilationResult { do_enum_compile(self, params, |name, params| { params .writer .get_current_block() .write_opcode_and_source_info(CompilerOpcode::Dup, self.loc.clone()); params .scope .emit_untyped_define( name, &mut params.module.constants, params.writer.get_current_block(), self.loc.clone(), ) .map_err(Into::into) }) } } ================================================ FILE: compiler-lib/src/do_compile/nodes/expression.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use crate::do_compile::{CompilationResult, CompileNode, CompileParams}; impl<'a> CompileNode<'a> for aria_parser::ast::Expression { fn do_compile(&self, params: &'a mut CompileParams) -> CompilationResult { match self { Self::LogOperation(lo) => lo.do_compile(params), Self::LambdaFunction(lf) => lf.do_compile(params), Self::TernaryExpression(te) => te.do_compile(params), Self::TryUnwrapExpression(te) => te.do_compile(params), } } } ================================================ FILE: compiler-lib/src/do_compile/nodes/expression_list.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use crate::do_compile::{CompilationResult, CompileNode, CompileParams}; impl<'a> CompileNode<'a, usize> for aria_parser::ast::ExpressionList { fn do_compile(&self, params: &'a mut CompileParams) -> CompilationResult { for expr in &self.expressions { expr.do_compile(params)?; } Ok(self.expressions.len()) } } ================================================ FILE: compiler-lib/src/do_compile/nodes/expression_statement.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use crate::do_compile::{CompilationResult, CompileNode, CompileParams}; impl<'a> CompileNode<'a> for aria_parser::ast::ExpressionStatement { fn do_compile(&self, params: &'a mut CompileParams) -> CompilationResult { if let Some(val) = &self.val { val.do_compile(params)?; params .writer .get_current_block() .write_opcode_and_source_info( crate::builder::compiler_opcodes::CompilerOpcode::Pop, self.loc.clone(), ); } Ok(()) } } ================================================ FILE: compiler-lib/src/do_compile/nodes/extension_decl.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use crate::do_compile::{ CompilationResult, CompileNode, CompileParams, MixinIncludeDecl, StructEntry, emit_type_members_compile, }; impl<'a> CompileNode<'a> for aria_parser::ast::ExtensionDecl { fn do_compile(&self, params: &'a mut CompileParams) -> CompilationResult { self.target.do_compile(params)?; // Inject mixin includes for each item in the inherits list if !self.inherits.is_empty() { let mut new_body = vec![]; for mixin_expr in &self.inherits { new_body.push(StructEntry::MixinInclude(Box::new(MixinIncludeDecl { loc: self.loc.clone(), what: mixin_expr.clone(), }))); } new_body.extend_from_slice(&self.body); emit_type_members_compile(&new_body, params, true) } else { emit_type_members_compile(&self.body, params, true) } } } ================================================ FILE: compiler-lib/src/do_compile/nodes/float_literal.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use crate::{ builder::compiler_opcodes::CompilerOpcode, constant_value::ConstantValue, do_compile::{ CompilationError, CompilationErrorReason, CompilationResult, CompileNode, CompileParams, }, }; impl<'a> CompileNode<'a> for aria_parser::ast::FloatLiteral { fn do_compile(&self, params: &'a mut CompileParams) -> CompilationResult { let fp_val = self .val .strip_suffix("f") .unwrap_or(&self.val) .parse::() .map_err(|_| CompilationError { loc: self.loc.clone(), reason: CompilationErrorReason::InvalidLiteral(self.val.clone()), })?; let const_idx = self.insert_const_or_fail(params, ConstantValue::Float(fp_val.into()), &self.loc)?; params .writer .get_current_block() .write_opcode_and_source_info(CompilerOpcode::Push(const_idx), self.loc.clone()); Ok(()) } } ================================================ FILE: compiler-lib/src/do_compile/nodes/for_statement.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use aria_parser::ast::{ AssignStatement, BreakStatement, CodeBlock, DeclarationId, ElsePiece, Expression, Identifier, IfCondPiece, IfPiece, IfStatement, MatchRule, MatchStatement, ParenExpression, PostfixExpression, PostfixRvalue, PostfixTerm, PostfixTermEnumCase, Primary, Statement, ThrowStatement, UnaryOperation, ValDeclEntry, ValDeclStatement, WhileStatement, }; use crate::do_compile::{CompilationResult, CompileNode, CompileParams}; macro_rules! val_decl_statement { ($loc:expr, $id:expr, $val:expr) => { Statement::ValDeclStatement(ValDeclStatement { loc: $loc, decls: vec![ValDeclEntry { loc: $loc, id: DeclarationId::from(&Identifier { loc: $loc, value: $id.clone(), }), val: $val, }], }) }; } impl<'a> CompileNode<'a> for aria_parser::ast::ForStatement { fn do_compile(&self, params: &'a mut CompileParams) -> CompilationResult { // the else block makes the logic here quite tricky and worth commenting // essentially it boils down to the following logic: // { // val iter = ; // val any_hit = false; // while true { // val next = iter.next(); // match next { // case Some(x) => { // any_hit = true; // val x = next.value; // // } // case None => { // if !any_hit { // // } // break; # out of the while loop // } // } // } // } // this is the iterator let iter_name_ident = Identifier { loc: self.loc.clone(), value: format!("__for__iter__{}", self.id.value), }; // this is the next value from the iterator (the Maybe, not the actual object) let val_next_ident = Identifier { loc: self.loc.clone(), value: format!("__for__next__{}", self.id.value), }; // this becomes true when the for {} body is executed at least once let any_hit_ident = Identifier { loc: self.loc.clone(), value: format!("__for__any_hit__{}", self.id.value), }; let fetch_iter_val = val_decl_statement!( self.loc.clone(), iter_name_ident.value, Expression::from(&PostfixExpression::method_call( &Primary::ParenExpression(ParenExpression::from(&self.expr)), "iterator", &[] )) ); let any_hit_val = val_decl_statement!( self.loc.clone(), any_hit_ident.value, Expression::from(&Identifier { loc: self.loc.clone(), value: "false".to_owned(), }) ); let true_cond = Expression::from(&Identifier { loc: self.loc.clone(), value: "true".to_owned(), }); // val __for__next__ = __for__iter__.next(); let fetch_next_val = val_decl_statement!( self.loc.clone(), val_next_ident.value, Expression::from(&PostfixExpression::method_call( &Primary::Identifier(iter_name_ident.clone()), "next", &[] )) ); // !__for__any_hit let check_any_hit_expr = Expression::from(&UnaryOperation { loc: self.loc.clone(), operand: Some(aria_parser::ast::UnarySymbol::Exclamation), postfix: PostfixRvalue { loc: self.loc.clone(), expr: PostfixExpression::from(&Primary::Identifier(any_hit_ident.clone())), }, }); // if !__for__any_hit { } let if_not_any_hit = IfCondPiece { loc: self.loc.clone(), expression: Box::new(check_any_hit_expr), then: CodeBlock { loc: self.loc.clone(), entries: if let Some(els) = &self.els { els.then.entries.clone() } else { vec![] }, }, }; let if_not_any_hit = Statement::IfStatement(IfStatement { loc: self.loc.clone(), iff: IfPiece { content: if_not_any_hit, }, elsif: vec![], els: None, }); // __for__any_hit = true; let assign_to_any_hit = Statement::AssignStatement(AssignStatement { loc: self.loc.clone(), id: vec![PostfixExpression::from(&Primary::Identifier( any_hit_ident.clone(), ))], val: vec![true_cond.clone()], }); // case Some(x) let case_some_blk = MatchRule::enum_and_case( self.loc.clone(), "Maybe", "Some", Some(self.id.clone()), CodeBlock { loc: self.loc.clone(), entries: vec![assign_to_any_hit, Statement::CodeBlock(self.then.clone())], }, ); // case None let case_none_block = MatchRule::enum_and_case( self.loc.clone(), "Maybe", "None", None, CodeBlock { loc: self.loc.clone(), entries: vec![ if_not_any_hit, Statement::BreakStatement(BreakStatement { loc: self.loc.clone(), }), ], }, ); // RuntimeError::UnexpectedType let unexpected_type = Expression::from(&PostfixExpression { loc: self.loc.clone(), base: Primary::Identifier(Identifier { loc: self.loc.clone(), value: "RuntimeError".to_owned(), }), terms: vec![PostfixTerm::PostfixTermEnumCase(PostfixTermEnumCase { loc: self.loc.clone(), id: Identifier { loc: self.loc.clone(), value: "UnexpectedType".to_owned(), }, payload: None, })], }); // throw UT let throw_ut = Statement::ThrowStatement(ThrowStatement { loc: self.loc.clone(), val: unexpected_type, }); // read __for__next let read_for_next = Expression::from(&PostfixExpression::from(&Primary::Identifier( val_next_ident.clone(), ))); // match __for__next { some(x), none, els => throw UT } let match_for_next = Statement::MatchStatement(MatchStatement { loc: self.loc.clone(), expr: read_for_next, rules: vec![case_some_blk, case_none_block], els: Some(ElsePiece { loc: self.loc.clone(), then: CodeBlock { loc: self.loc.clone(), entries: vec![throw_ut], }, }), }); // while (true) { fetch_next; match_next; } let while_body = CodeBlock { loc: self.loc.clone(), entries: vec![fetch_next_val, match_for_next], }; // this is while true { do the body } let w = Statement::WhileStatement(WhileStatement { loc: self.loc.clone(), cond: true_cond, then: while_body, els: None, }); // create the iterator and the any_hit marker, then loop over the iterator let blk = CodeBlock { loc: self.loc.clone(), entries: vec![fetch_iter_val, any_hit_val, w], }; blk.do_compile(params) } } ================================================ FILE: compiler-lib/src/do_compile/nodes/function_body.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use crate::do_compile::{CompilationResult, CompileNode, CompileParams}; impl<'a> CompileNode<'a> for aria_parser::ast::FunctionBody { fn do_compile(&self, params: &'a mut CompileParams) -> CompilationResult { self.code.do_compile(params) } } ================================================ FILE: compiler-lib/src/do_compile/nodes/function_decl.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use haxby_opcodes::function_attribs::FUNC_ACCEPTS_VARARG; use crate::{ builder::{compiler_opcodes::CompilerOpcode, func::FunctionBuilder}, constant_value::{CompiledCodeObject, ConstantValue}, do_compile::{ CompilationError, CompilationResult, CompileNode, CompileParams, ControlFlowTargets, emit_args_at_target, }, }; impl<'a> CompileNode<'a> for aria_parser::ast::FunctionDecl { fn do_compile(&self, params: &'a mut CompileParams) -> CompilationResult { let cflow = ControlFlowTargets::default(); let mut writer = FunctionBuilder::default(); let mut c_params = CompileParams { module: params.module, scope: params.scope, writer: &mut writer, cflow: &cflow, options: params.options, }; let argc = emit_args_at_target(&[], &self.args, &[], &mut c_params)?; self.body.do_compile(&mut c_params)?; self.return_unit_value(&mut c_params, &self.loc)?; let co = match writer.write(¶ms.module.constants, params.options) { Ok(c) => c, Err(er) => { return Err(CompilationError { loc: self.loc.clone(), reason: er, }); } }; let frame_size = params.scope.as_function_root().unwrap().num_locals(); let line_table = writer.write_line_table().clone(); let a = if self.args.vararg { FUNC_ACCEPTS_VARARG } else { 0_u8 }; let cco = CompiledCodeObject { name: self.name.value.clone(), attribute: a, body: co, required_argc: argc.required_args, default_argc: argc.default_args, loc: self.loc.clone(), line_table, frame_size, }; let cco_idx = self.insert_const_or_fail(params, ConstantValue::CompiledCodeObject(cco), &self.loc)?; params .writer .get_current_block() .write_opcode_and_source_info(CompilerOpcode::Push(cco_idx), self.loc.clone()) .write_opcode_and_source_info(CompilerOpcode::BuildFunction, self.loc.clone()); for uplv in params .scope .as_function_root() .unwrap() .uplevels .borrow() .iter() { params .writer .get_current_block() .write_opcode_and_source_info( CompilerOpcode::StoreUplevel(uplv.idx_in_uplevel), self.loc.clone(), ); } params .scope .get_module_scope() .unwrap() .emit_untyped_define( &self.name.value, &mut params.module.constants, params.writer.get_current_block(), self.loc.clone(), )?; Ok(()) } } ================================================ FILE: compiler-lib/src/do_compile/nodes/identifier.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use crate::do_compile::{CompilationResult, CompileNode, CompileParams}; impl<'a> CompileNode<'a> for aria_parser::ast::Identifier { fn do_compile(&self, params: &'a mut CompileParams) -> CompilationResult { params.scope.emit_read( &self.value, &mut params.module.constants, params.writer.get_current_block(), self.loc.clone(), )?; Ok(()) } } ================================================ FILE: compiler-lib/src/do_compile/nodes/if_statement.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use crate::{ builder::compiler_opcodes::CompilerOpcode, do_compile::{CompilationResult, CompileNode, CompileParams}, }; impl<'a> CompileNode<'a> for aria_parser::ast::IfStatement { fn do_compile(&self, params: &'a mut CompileParams) -> CompilationResult { let after_all = params .writer .append_block_at_end(&format!("after_all_{}", self.loc)); // a trivial if is of the form // if foo { // bar //} // in which case, we can simply emit a jump to "after all", i.e. compile as // // JUMP_FALSE // ... // JUMP since the block needs to be terminated // ... let is_trivial_if = self.elsif.is_empty() && self.els.is_none(); // compile the first if { self.iff.content.expression.do_compile(params)?; let if_true = params.writer.insert_block_after( &format!("if_true_{}", self.loc), ¶ms.writer.get_current_block(), ); let if_false = params .writer .insert_block_after(&format!("if_false_{}", self.loc), &if_true); if is_trivial_if { params .writer .get_current_block() .write_opcode_and_source_info( CompilerOpcode::JumpFalse(after_all.clone()), self.iff.content.loc.clone(), ); } else { params .writer .get_current_block() .write_opcode_and_source_info( CompilerOpcode::JumpConditionally(if_true.clone(), if_false.clone()), self.iff.content.loc.clone(), ); params.writer.set_current_block(if_true); } self.iff.content.then.do_compile(params)?; params .writer .get_current_block() .write_opcode_and_source_info( CompilerOpcode::Jump(after_all.clone()), self.iff.content.loc.clone(), ); params.writer.set_current_block(if_false); } // compile every elsif { for elsif in &self.elsif { elsif.content.expression.do_compile(params)?; let if_true = params.writer.insert_block_after( &format!("if_true_{}", self.loc), ¶ms.writer.get_current_block(), ); let if_false = params .writer .insert_block_after(&format!("if_false_{}", self.loc), &if_true); params .writer .get_current_block() .write_opcode_and_source_info( CompilerOpcode::JumpConditionally(if_true.clone(), if_false.clone()), elsif.content.then.loc.clone(), ); params.writer.set_current_block(if_true); elsif.content.then.do_compile(params)?; params .writer .get_current_block() .write_opcode_and_source_info( CompilerOpcode::Jump(after_all.clone()), elsif.content.loc.clone(), ); params.writer.set_current_block(if_false); } } // compile the else { if let Some(els) = &self.els { els.then.do_compile(params)?; } } if !is_trivial_if { // jump to after all params .writer .get_current_block() .write_opcode_and_source_info( CompilerOpcode::Jump(after_all.clone()), self.loc.clone(), ); } params.writer.set_current_block(after_all); Ok(()) } } ================================================ FILE: compiler-lib/src/do_compile/nodes/import_from_statement.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use haxby_opcodes::BuiltinValueId; use crate::{ builder::compiler_opcodes::CompilerOpcode, constant_value::ConstantValue, do_compile::{CompilationResult, CompileNode, CompileParams}, }; impl<'a> CompileNode<'a> for aria_parser::ast::ImportFromStatement { fn do_compile(&self, params: &'a mut CompileParams) -> CompilationResult { let path_idx = self.insert_const_or_fail( params, ConstantValue::String(self.from.to_dotted_string()), &self.loc, )?; match &self.what { aria_parser::ast::ImportTarget::IdentifierList(identifiers) => { for identifier in &identifiers.identifiers { let ident_idx = self.insert_const_or_fail( params, ConstantValue::String(identifier.value.clone()), &self.loc, )?; params .writer .get_current_block() .write_opcode_and_source_info( CompilerOpcode::Import(path_idx), self.loc.clone(), ) .write_opcode_and_source_info( CompilerOpcode::ReadAttribute(ident_idx), self.loc.clone(), ); params.scope.emit_untyped_define( &identifier.value, &mut params.module.constants, params.writer.get_current_block(), self.loc.clone(), )?; } } aria_parser::ast::ImportTarget::All => { let path_idx = self.insert_const_or_fail( params, ConstantValue::String(self.from.to_dotted_string()), &self.loc, )?; params .writer .get_current_block() .write_opcode_and_source_info( CompilerOpcode::Import(path_idx), self.loc.clone(), ) .write_opcode_and_source_info( CompilerOpcode::PushRuntimeValue(BuiltinValueId::ThisModule), self.loc.clone(), ) .write_opcode_and_source_info(CompilerOpcode::LiftModule, self.loc.clone()); } } Ok(()) } } ================================================ FILE: compiler-lib/src/do_compile/nodes/import_statement.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use crate::{ builder::compiler_opcodes::CompilerOpcode, constant_value::ConstantValue, do_compile::{CompilationResult, CompileNode, CompileParams}, }; impl<'a> CompileNode<'a> for aria_parser::ast::ImportStatement { fn do_compile(&self, params: &'a mut CompileParams) -> CompilationResult { let path_idx = self.insert_const_or_fail( params, ConstantValue::String(self.what.to_dotted_string()), &self.loc, )?; params .writer .get_current_block() .write_opcode_and_source_info(CompilerOpcode::Import(path_idx), self.loc.clone()); Ok(()) } } ================================================ FILE: compiler-lib/src/do_compile/nodes/int_literal.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use crate::{ builder::compiler_opcodes::CompilerOpcode, constant_value::ConstantValue, do_compile::{ CompilationError, CompilationErrorReason, CompilationResult, CompileNode, CompileParams, }, }; impl<'a> CompileNode<'a> for aria_parser::ast::IntLiteral { fn do_compile(&self, params: &'a mut CompileParams) -> CompilationResult { let inp_str = &self.val.replace('_', ""); // I don't particularly like this code, but I don't know an easy way to write // if X { Result } else if XX { Result } ... . map_err(...)? as B; // basically, some paths want to generate a u64 and some want to generate an i64, // but all need to converge on i64 in the end. let val = if let Some(hex_str) = inp_str.strip_prefix("0x") { u64::from_str_radix(hex_str, 16).map_err(|_| CompilationError { loc: self.loc.clone(), reason: CompilationErrorReason::InvalidLiteral(inp_str.to_owned()), })? as i64 } else if let Some(bin_str) = inp_str.strip_prefix("0b") { u64::from_str_radix(bin_str, 2).map_err(|_| CompilationError { loc: self.loc.clone(), reason: CompilationErrorReason::InvalidLiteral(inp_str.to_owned()), })? as i64 } else if let Some(oct_str) = inp_str.strip_prefix("0o") { i64::from_str_radix(oct_str, 8).map_err(|_| CompilationError { loc: self.loc.clone(), reason: CompilationErrorReason::InvalidLiteral(inp_str.to_owned()), })? } else { inp_str.parse::().map_err(|_| CompilationError { loc: self.loc.clone(), reason: CompilationErrorReason::InvalidLiteral(inp_str.to_owned()), })? }; if val == 0 { params .writer .get_current_block() .write_opcode_and_source_info(CompilerOpcode::Push0, self.loc.clone()); } else if val == 1 { params .writer .get_current_block() .write_opcode_and_source_info(CompilerOpcode::Push1, self.loc.clone()); } else { let const_idx = self.insert_const_or_fail(params, ConstantValue::Integer(val), &self.loc)?; params .writer .get_current_block() .write_opcode_and_source_info(CompilerOpcode::Push(const_idx), self.loc.clone()); } Ok(()) } } ================================================ FILE: compiler-lib/src/do_compile/nodes/lambda.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use aria_parser::ast::{FunctionBody, FunctionDecl, Identifier}; use crate::do_compile::{CompilationResult, CompileNode, CompileParams}; impl<'a> CompileNode<'a> for aria_parser::ast::LambdaFunction { fn do_compile(&self, params: &'a mut CompileParams) -> CompilationResult { let body: FunctionBody = From::from(self.body.as_ref()); let f_name = format!("", self.loc); let f_obj = FunctionDecl { loc: body.loc().clone(), name: Identifier { loc: self.loc.clone(), value: f_name.clone(), }, args: self.args.clone(), body, }; let f_body_scope = params.scope.closure(params.writer.get_current_block()); let mut f_body_params = CompileParams { module: params.module, scope: &f_body_scope, writer: params.writer, cflow: params.cflow, options: params.options, }; f_obj.do_compile(&mut f_body_params)?; params.scope.emit_read( &f_name, &mut params.module.constants, params.writer.get_current_block(), self.loc.clone(), )?; Ok(()) } } ================================================ FILE: compiler-lib/src/do_compile/nodes/list_literal.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use crate::{ builder::compiler_opcodes::CompilerOpcode, do_compile::{ CompilationError, CompilationErrorReason, CompilationResult, CompileNode, CompileParams, }, }; impl<'a> CompileNode<'a> for aria_parser::ast::ListLiteral { fn do_compile(&self, params: &'a mut CompileParams) -> CompilationResult { let count = self .items .expressions .iter() .map(|arg| arg.do_compile(params)) .count(); if count > u32::MAX as usize { Err(CompilationError { loc: self.loc.clone(), reason: CompilationErrorReason::ListTooLarge, }) } else { params .writer .get_current_block() .write_opcode_and_source_info( CompilerOpcode::BuildList(count as u32), self.loc.clone(), ); Ok(()) } } } ================================================ FILE: compiler-lib/src/do_compile/nodes/logical_operation.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use crate::{ builder::compiler_opcodes::CompilerOpcode, do_compile::{CompilationResult, CompileNode, CompileParams}, }; impl<'a> CompileNode<'a> for aria_parser::ast::LogOperation { fn do_compile(&self, params: &'a mut CompileParams) -> CompilationResult { self.left.do_compile(params)?; for right in &self.right { match right.0 { // xor and bitwise operators do not shortcircut aria_parser::ast::LogSymbol::Ampersand => { right.1.do_compile(params)?; params .writer .get_current_block() .write_opcode_and_source_info(CompilerOpcode::BitwiseAnd, self.loc.clone()); } aria_parser::ast::LogSymbol::Pipe => { right.1.do_compile(params)?; params .writer .get_current_block() .write_opcode_and_source_info(CompilerOpcode::BitwiseOr, self.loc.clone()); } aria_parser::ast::LogSymbol::Caret => { right.1.do_compile(params)?; params .writer .get_current_block() .write_opcode_and_source_info(CompilerOpcode::Xor, self.loc.clone()); } aria_parser::ast::LogSymbol::DoubleAmpersand => { let bb_and_true = params .writer .append_block_at_end(&format!("bb_and_true{}", self.loc)); let bb_and_done = params .writer .append_block_at_end(&format!("bb_and_done{}", self.loc)); params .writer .get_current_block() .write_opcode_and_source_info( CompilerOpcode::JumpTrue(bb_and_true.clone()), self.loc.clone(), ); params .writer .get_current_block() .write_opcode_and_source_info(CompilerOpcode::PushFalse, self.loc.clone()); params .writer .get_current_block() .write_opcode_and_source_info( CompilerOpcode::Jump(bb_and_done.clone()), self.loc.clone(), ); params.writer.set_current_block(bb_and_true); right.1.do_compile(params)?; // true and X == X params .writer .get_current_block() .write_opcode_and_source_info( CompilerOpcode::Jump(bb_and_done.clone()), self.loc.clone(), ); params.writer.set_current_block(bb_and_done); } aria_parser::ast::LogSymbol::DoublePipe => { let bb_or_true = params .writer .append_block_at_end(&format!("bb_or_true{}", self.loc)); let bb_or_done = params .writer .append_block_at_end(&format!("bb_or_done{}", self.loc)); params .writer .get_current_block() .write_opcode_and_source_info( CompilerOpcode::JumpTrue(bb_or_true.clone()), self.loc.clone(), ); right.1.do_compile(params)?; // false or X == X params .writer .get_current_block() .write_opcode_and_source_info( CompilerOpcode::Jump(bb_or_done.clone()), self.loc.clone(), ); params.writer.set_current_block(bb_or_true); params .writer .get_current_block() .write_opcode_and_source_info(CompilerOpcode::PushTrue, self.loc.clone()); params .writer .get_current_block() .write_opcode_and_source_info( CompilerOpcode::Jump(bb_or_done.clone()), self.loc.clone(), ); params.writer.set_current_block(bb_or_done); } } } Ok(()) } } ================================================ FILE: compiler-lib/src/do_compile/nodes/match_pattern.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use crate::do_compile::{CompilationResult, CompileNode, CompileParams}; impl<'a> CompileNode<'a> for aria_parser::ast::MatchPattern { fn do_compile(&self, params: &'a mut CompileParams) -> CompilationResult { match self { Self::MatchPatternComp(e) => e.do_compile(params), Self::MatchPatternRel(e) => e.do_compile(params), Self::MatchPatternEnumCase(e) => e.do_compile(params), } } } ================================================ FILE: compiler-lib/src/do_compile/nodes/match_pattern_comp.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use crate::{ builder::compiler_opcodes::CompilerOpcode, do_compile::{CompilationResult, CompileNode, CompileParams}, }; impl<'a> CompileNode<'a> for aria_parser::ast::MatchPatternComp { fn do_compile(&self, params: &'a mut CompileParams) -> CompilationResult { self.expr.do_compile(params)?; match self.op { aria_parser::ast::CompSymbol::Equal => { params .writer .get_current_block() .write_opcode_and_source_info(CompilerOpcode::Equal, self.loc.clone()); } aria_parser::ast::CompSymbol::NotEqual => { params .writer .get_current_block() .write_opcode_and_source_info(CompilerOpcode::Equal, self.loc.clone()) .write_opcode_and_source_info(CompilerOpcode::Not, self.loc.clone()); } aria_parser::ast::CompSymbol::Isa => { params .writer .get_current_block() .write_opcode_and_source_info(CompilerOpcode::Isa, self.loc.clone()); } } Ok(()) } } ================================================ FILE: compiler-lib/src/do_compile/nodes/match_pattern_enum_case.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use aria_parser::ast::SourcePointer; use crate::{ builder::compiler_opcodes::CompilerOpcode, constant_value::ConstantValue, do_compile::{CompilationResult, CompileNode, CompileParams}, }; fn emit_case_without_payload( _: &SourcePointer, case: &aria_parser::ast::Identifier, params: &mut CompileParams, ) -> CompilationResult { let case_name_idx = case.insert_const_or_fail(params, ConstantValue::String(case.value.clone()), &case.loc)?; params .writer .get_current_block() .write_opcode_and_source_info( CompilerOpcode::EnumCheckIsCase(case_name_idx), case.loc.clone(), ); Ok(()) } fn emit_case_with_payload( loc: &SourcePointer, case: &aria_parser::ast::Identifier, payload: &aria_parser::ast::DeclarationId, params: &mut CompileParams, ) -> CompilationResult { emit_case_without_payload(loc, case, params)?; // jump here when any intermediate check fails, this will push false on the stack let payload_check_failed = params .writer .append_block_at_end(&format!("payload_chck_failed{}", case.loc)); // this is where match expects to continue, with either true or false on the stack // and possibly a local symbol bound on success let payload_check_aftermath = params .writer .append_block_at_end(&format!("payload_chck_aftermath{}", case.loc)); params .writer .get_current_block() .write_opcode_and_source_info( CompilerOpcode::JumpFalse(payload_check_failed.clone()), loc.clone(), ); // we know we have a case match - now extract the payload params.scope.emit_read( "__match_control_expr", &mut params.module.constants, params.writer.get_current_block(), payload.loc.clone(), )?; params .writer .get_current_block() .write_opcode_and_source_info(CompilerOpcode::EnumTryExtractPayload, payload.loc.clone()); params .writer .get_current_block() .write_opcode_and_source_info( CompilerOpcode::JumpFalse(payload_check_failed.clone()), loc.clone(), ); // if we're here, we know we have a payload - bind it to a local variable now if let Some(ty) = &payload.ty { params .writer .get_current_block() .write_opcode_and_source_info(CompilerOpcode::Dup, loc.clone()); ty.do_compile(params)?; params .writer .get_current_block() .write_opcode_and_source_info(CompilerOpcode::Isa, loc.clone()) .write_opcode_and_source_info( CompilerOpcode::JumpFalse(payload_check_failed.clone()), loc.clone(), ); } params.scope.emit_untyped_define( &payload.name.value, &mut params.module.constants, params.writer.get_current_block(), loc.clone(), )?; // if we're still here, we passed all checks - push true and jump to aftermath params .writer .get_current_block() .write_opcode_and_source_info(CompilerOpcode::PushTrue, loc.clone()) .write_opcode_and_source_info( CompilerOpcode::Jump(payload_check_aftermath.clone()), loc.clone(), ); params.writer.set_current_block(payload_check_failed); params .writer .get_current_block() .write_opcode_and_source_info(CompilerOpcode::PushFalse, loc.clone()) .write_opcode_and_source_info( CompilerOpcode::Jump(payload_check_aftermath.clone()), loc.clone(), ); params.writer.set_current_block(payload_check_aftermath); Ok(()) } impl<'a> CompileNode<'a> for aria_parser::ast::MatchPatternEnumCase { fn do_compile(&self, params: &'a mut CompileParams) -> CompilationResult { match &self.payload { None => emit_case_without_payload(&self.loc, &self.case, params), Some(decl_id) => emit_case_with_payload(&self.loc, &self.case, decl_id, params), } } } ================================================ FILE: compiler-lib/src/do_compile/nodes/match_pattern_rel.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use crate::{ builder::compiler_opcodes::CompilerOpcode, do_compile::{CompilationResult, CompileNode, CompileParams}, }; impl<'a> CompileNode<'a> for aria_parser::ast::MatchPatternRel { fn do_compile(&self, params: &'a mut CompileParams) -> CompilationResult { self.expr.do_compile(params)?; match self.op { aria_parser::ast::RelSymbol::Less => { params .writer .get_current_block() .write_opcode_and_source_info(CompilerOpcode::LessThan, self.loc.clone()); } aria_parser::ast::RelSymbol::LessEqual => { params .writer .get_current_block() .write_opcode_and_source_info(CompilerOpcode::LessThanEqual, self.loc.clone()); } aria_parser::ast::RelSymbol::Greater => { params .writer .get_current_block() .write_opcode_and_source_info(CompilerOpcode::GreaterThan, self.loc.clone()); } aria_parser::ast::RelSymbol::GreaterEqual => { params .writer .get_current_block() .write_opcode_and_source_info( CompilerOpcode::GreaterThanEqual, self.loc.clone(), ); } } Ok(()) } } ================================================ FILE: compiler-lib/src/do_compile/nodes/match_statement.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use crate::{ builder::compiler_opcodes::CompilerOpcode, do_compile::{CompilationResult, CompileNode, CompileParams}, }; impl<'a> CompileNode<'a> for aria_parser::ast::MatchStatement { fn do_compile(&self, params: &'a mut CompileParams) -> CompilationResult { let c_scope = params.scope.child(); let mut match_param = CompileParams { module: params.module, scope: &c_scope, writer: params.writer, cflow: params.cflow, options: params.options, }; self.expr.do_compile(&mut match_param)?; // store the control expression here so it can be used match_param.scope.emit_untyped_define( "__match_control_expr", &mut match_param.module.constants, match_param.writer.get_current_block(), self.loc.clone(), )?; let match_after = match_param .writer .append_block_at_end(&format!("match_after_{}", self.loc)); for rule in &self.rules { let r_scope = match_param.scope.child(); let mut rule_param = CompileParams { module: match_param.module, scope: &r_scope, writer: match_param.writer, cflow: match_param.cflow, options: match_param.options, }; let match_hit = rule_param.writer.insert_block_after( &format!("match_hit_{}", rule.loc), &rule_param.writer.get_current_block(), ); let match_miss = rule_param .writer .insert_block_after(&format!("match_miss_{}", rule.loc), &match_hit); for pattern in &rule.patterns { rule_param.scope.emit_read( "__match_control_expr", &mut rule_param.module.constants, rule_param.writer.get_current_block(), pattern.loc().clone(), )?; // pattern is going to leave true (hit) or false (miss) // and may add local variables to the scope pattern.do_compile(&mut rule_param)?; rule_param .writer .get_current_block() .write_opcode_and_source_info( CompilerOpcode::JumpFalse(match_miss.clone()), pattern.loc().clone(), ); } rule_param .writer .get_current_block() .write_opcode_and_source_info( CompilerOpcode::Jump(match_hit.clone()), rule.loc.clone(), ); rule_param.writer.set_current_block(match_hit); rule.then.do_compile(&mut rule_param)?; rule_param .writer .get_current_block() .write_opcode_and_source_info( CompilerOpcode::Jump(match_after.clone()), rule.loc.clone(), ); rule_param.writer.set_current_block(match_miss); } if let Some(els) = &self.els { els.then.do_compile(&mut match_param)?; } match_param .writer .get_current_block() .write_opcode_and_source_info( CompilerOpcode::Jump(match_after.clone()), self.loc.clone(), ); match_param.writer.set_current_block(match_after); Ok(()) } } ================================================ FILE: compiler-lib/src/do_compile/nodes/method_decl.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use aria_parser::ast::{DeclarationId, Identifier}; use haxby_opcodes::function_attribs::{FUNC_ACCEPTS_VARARG, FUNC_IS_METHOD, METHOD_ATTRIBUTE_TYPE}; use crate::{ builder::{compiler_opcodes::CompilerOpcode, func::FunctionBuilder}, constant_value::{CompiledCodeObject, ConstantValue}, do_compile::{ CompilationError, CompilationResult, CompileNode, CompileParams, ControlFlowTargets, emit_args_at_target, }, scope::CompilationScope, }; impl<'a> CompileNode<'a> for aria_parser::ast::MethodDecl { fn do_compile(&self, params: &'a mut CompileParams) -> CompilationResult { let attribute = if self.args.vararg { FUNC_ACCEPTS_VARARG } else { 0 } | FUNC_IS_METHOD | if self.access == aria_parser::ast::MethodAccess::Type { METHOD_ATTRIBUTE_TYPE } else { 0 }; let f_scope = CompilationScope::function(params.scope); let cflow = ControlFlowTargets::default(); let mut writer = FunctionBuilder::default(); let mut c_params = CompileParams { module: params.module, scope: &f_scope, writer: &mut writer, cflow: &cflow, options: params.options, }; let this_arg = From::from(&DeclarationId { loc: self.loc.clone(), name: Identifier { loc: self.loc.clone(), value: match self.access { aria_parser::ast::MethodAccess::Instance => "this", aria_parser::ast::MethodAccess::Type => "This", } .to_owned(), }, ty: None, }); let argc = emit_args_at_target(&[this_arg], &self.args, &[], &mut c_params)?; self.body.do_compile(&mut c_params)?; self.return_unit_value(&mut c_params, &self.loc)?; let frame_size = c_params.scope.as_function_root().unwrap().num_locals(); let co = match writer.write(¶ms.module.constants, params.options) { Ok(c) => c, Err(er) => { return Err(CompilationError { loc: self.loc.clone(), reason: er, }); } }; let line_table = writer.write_line_table().clone(); let cco = CompiledCodeObject { name: self.name.value.clone(), attribute, body: co, required_argc: argc.required_args, default_argc: argc.default_args, loc: self.loc.clone(), line_table, frame_size, }; let cco_idx = self.insert_const_or_fail(params, ConstantValue::CompiledCodeObject(cco), &self.loc)?; params .writer .get_current_block() .write_opcode_and_source_info(CompilerOpcode::Push(cco_idx), self.loc.clone()); Ok(()) } } ================================================ FILE: compiler-lib/src/do_compile/nodes/mixin_decl.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use aria_parser::ast::StringLiteral; use crate::{ builder::compiler_opcodes::CompilerOpcode, do_compile::{CompilationResult, CompileNode, CompileParams, emit_type_members_compile}, }; impl<'a> CompileNode<'a> for aria_parser::ast::MixinDecl { fn do_compile(&self, params: &'a mut CompileParams) -> CompilationResult { let self_name = StringLiteral { loc: self.loc.clone(), value: self.name.value.clone(), }; self_name.do_compile(params)?; params .writer .get_current_block() .write_opcode_and_source_info(CompilerOpcode::BuildMixin, self.loc.clone()) .write_opcode_and_source_info(CompilerOpcode::Dup, self.loc.clone()); params.scope.emit_untyped_define( &self.name.value, &mut params.module.constants, params.writer.get_current_block(), self.loc.clone(), )?; emit_type_members_compile(&self.body, params, true) } } ================================================ FILE: compiler-lib/src/do_compile/nodes/mod.rs ================================================ // SPDX-License-Identifier: Apache-2.0 mod add_operation; mod assert_statement; mod assign_statement; mod break_statement; mod code_block; mod comp_operation; mod continue_statement; mod enum_case_decl; mod enum_decl; mod expression; mod expression_list; mod expression_statement; mod extension_decl; mod float_literal; mod for_statement; mod function_body; mod function_decl; mod identifier; mod if_statement; mod import_from_statement; mod import_statement; mod int_literal; mod lambda; mod list_literal; mod logical_operation; mod match_pattern; mod match_pattern_comp; mod match_pattern_enum_case; mod match_pattern_rel; mod match_statement; mod method_decl; mod mixin_decl; mod mul_operation; mod paren_expression; mod parsed_module; mod postfix_rvalue; mod primary; mod rel_operation; mod return_statement; mod shift_operation; mod statement; mod string_literal; mod struct_decl; mod ternary_expression; mod throw_statement; mod try_block; mod try_unwrap_expression; mod unary_operation; mod val_decl_entry; mod val_decl_statement; mod while_statement; mod write_opeq_statement; ================================================ FILE: compiler-lib/src/do_compile/nodes/mul_operation.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use crate::{ builder::compiler_opcodes::CompilerOpcode, do_compile::{CompilationResult, CompileNode, CompileParams}, }; impl<'a> CompileNode<'a> for aria_parser::ast::MulOperation { fn do_compile(&self, params: &'a mut CompileParams) -> CompilationResult { self.left.do_compile(params)?; for right in &self.right { right.1.do_compile(params)?; params .writer .get_current_block() .write_opcode_and_source_info( match right.0 { aria_parser::ast::MulSymbol::Star => CompilerOpcode::Mul, aria_parser::ast::MulSymbol::Slash => CompilerOpcode::Div, aria_parser::ast::MulSymbol::Percent => CompilerOpcode::Rem, }, self.loc.clone(), ); } Ok(()) } } ================================================ FILE: compiler-lib/src/do_compile/nodes/paren_expression.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use crate::do_compile::{CompilationResult, CompileNode, CompileParams}; impl<'a> CompileNode<'a> for aria_parser::ast::ParenExpression { fn do_compile(&self, params: &'a mut CompileParams) -> CompilationResult { self.value.do_compile(params) } } ================================================ FILE: compiler-lib/src/do_compile/nodes/parsed_module.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use aria_parser::ast::{ImportFromStatement, ImportPath, ParsedModule}; use haxby_opcodes::BuiltinValueId; use crate::{ builder::compiler_opcodes::CompilerOpcode, constant_value::{CompiledCodeObject, ConstantValue}, do_compile::{CompilationError, CompilationResult, CompileNode, CompileParams}, }; macro_rules! collate_error_if_any { {$expression: expr, $errors: expr} => { if let Err(e) = $expression { $errors.push(e); } } } impl<'a> CompileNode<'a, (), Vec> for ParsedModule { fn do_compile( &self, params: &'a mut CompileParams, ) -> CompilationResult<(), Vec> { let mut errors = vec![]; if !self .flags .flags .contains(&aria_parser::ast::ModuleFlag::NoStandardLibrary) { let import_core_statement = ImportFromStatement { loc: self.loc.clone(), what: aria_parser::ast::ImportTarget::All, from: ImportPath::from_dotted_string(self.loc.clone(), "aria.core.builtin"), }; collate_error_if_any!(import_core_statement.do_compile(params), errors); } for pf in &self.entries { match pf { aria_parser::ast::TopLevelEntry::ValDeclStatement(v) => { collate_error_if_any!(v.do_compile(params), errors) } aria_parser::ast::TopLevelEntry::WriteOpEqStatement(w) => { collate_error_if_any!(w.do_compile(params), errors) } aria_parser::ast::TopLevelEntry::AssignStatement(a) => { collate_error_if_any!(a.do_compile(params), errors) } aria_parser::ast::TopLevelEntry::FunctionDecl(f) => { let f_scope = params.scope.function(); let mut f_params = CompileParams { module: params.module, scope: &f_scope, writer: params.writer, cflow: params.cflow, options: params.options, }; collate_error_if_any!(f.do_compile(&mut f_params), errors) } aria_parser::ast::TopLevelEntry::StructDecl(s) => { collate_error_if_any!(s.do_compile(params), errors) } aria_parser::ast::TopLevelEntry::MixinDecl(m) => { collate_error_if_any!(m.do_compile(params), errors) } aria_parser::ast::TopLevelEntry::ExtensionDecl(e) => { collate_error_if_any!(e.do_compile(params), errors) } aria_parser::ast::TopLevelEntry::ExpressionStatement(e) => { collate_error_if_any!(e.do_compile(params), errors) } aria_parser::ast::TopLevelEntry::AssertStatement(a) => { collate_error_if_any!(a.do_compile(params), errors) } aria_parser::ast::TopLevelEntry::EnumDecl(e) => { collate_error_if_any!(e.do_compile(params), errors) } aria_parser::ast::TopLevelEntry::ImportStatement(i) => { collate_error_if_any!(i.do_compile(params), errors) } aria_parser::ast::TopLevelEntry::ImportFromStatement(i) => { collate_error_if_any!(i.do_compile(params), errors) } aria_parser::ast::TopLevelEntry::IfStatement(i) => { collate_error_if_any!(i.do_compile(params), errors) } aria_parser::ast::TopLevelEntry::MatchStatement(m) => { collate_error_if_any!(m.do_compile(params), errors) } aria_parser::ast::TopLevelEntry::WhileStatement(w) => { collate_error_if_any!(w.do_compile(params), errors) } aria_parser::ast::TopLevelEntry::ForStatement(f) => { collate_error_if_any!(f.do_compile(params), errors) } aria_parser::ast::TopLevelEntry::CodeBlock(c) => { collate_error_if_any!(c.do_compile(params), errors) } aria_parser::ast::TopLevelEntry::TryBlock(t) => { collate_error_if_any!(t.do_compile(params), errors) } } } for flag in &self.flags.flags { if let aria_parser::ast::ModuleFlag::UsesDylib(lib) = flag { let cidx = match self.insert_const_or_fail( params, ConstantValue::String(lib.clone()), &self.loc, ) { Ok(i) => i, Err(e) => { errors.push(e); return Err(errors); } }; #[allow(deprecated)] // flags have no location info params .writer .get_current_block() .write_opcode(CompilerOpcode::PushRuntimeValue(BuiltinValueId::ThisModule)) .write_opcode(CompilerOpcode::LoadDylib(cidx)); } } #[allow(deprecated)] // no entry to ascribe this write to params .writer .get_current_block() .write_opcode(CompilerOpcode::ReturnUnit); let co = match params .writer .write(¶ms.module.constants, params.options) { Ok(c) => c, Err(e) => { errors.push(CompilationError { loc: self.loc.clone(), reason: e, }); return Err(errors); } }; let frame_size = 0; let line_table = params.writer.write_line_table().clone(); let __entry_cco = CompiledCodeObject { name: "__entry".to_owned(), attribute: 0, body: co, required_argc: 0, default_argc: 0, loc: self.loc.clone(), line_table, frame_size, }; if let Err(e) = self.insert_const_or_fail( params, ConstantValue::CompiledCodeObject(__entry_cco), &self.loc, ) { errors.push(e); } if errors.is_empty() { Ok(()) } else { Err(errors) } } } ================================================ FILE: compiler-lib/src/do_compile/nodes/postfix_rvalue.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use crate::do_compile::{CompilationResult, CompileNode, CompileParams, postfix::PostfixValue}; impl<'a> CompileNode<'a> for aria_parser::ast::PostfixRvalue { fn do_compile(&self, params: &'a mut CompileParams) -> CompilationResult { let pv = PostfixValue::from(&self.expr); pv.emit_read(params) } } ================================================ FILE: compiler-lib/src/do_compile/nodes/primary.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use crate::do_compile::{CompilationResult, CompileNode, CompileParams}; impl<'a> CompileNode<'a> for aria_parser::ast::Primary { fn do_compile(&self, params: &'a mut CompileParams) -> CompilationResult { match self { Self::IntLiteral(il) => il.do_compile(params), Self::FloatLiteral(fp) => fp.do_compile(params), Self::Identifier(id) => id.do_compile(params), Self::ListLiteral(ll) => ll.do_compile(params), Self::StringLiteral(sl) => sl.do_compile(params), Self::ParenExpression(pe) => pe.do_compile(params), } } } ================================================ FILE: compiler-lib/src/do_compile/nodes/rel_operation.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use crate::{ builder::compiler_opcodes::CompilerOpcode, do_compile::{CompilationResult, CompileNode, CompileParams}, }; impl<'a> CompileNode<'a> for aria_parser::ast::RelOperation { fn do_compile(&self, params: &'a mut CompileParams) -> CompilationResult { self.left.do_compile(params)?; if let Some(rhs) = &self.right { rhs.1.do_compile(params)?; params .writer .get_current_block() .write_opcode_and_source_info( match rhs.0 { aria_parser::ast::RelSymbol::Greater => CompilerOpcode::GreaterThan, aria_parser::ast::RelSymbol::Less => CompilerOpcode::LessThan, aria_parser::ast::RelSymbol::GreaterEqual => { CompilerOpcode::GreaterThanEqual } aria_parser::ast::RelSymbol::LessEqual => CompilerOpcode::LessThanEqual, }, self.loc.clone(), ); } Ok(()) } } ================================================ FILE: compiler-lib/src/do_compile/nodes/return_statement.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use crate::{ builder::compiler_opcodes::CompilerOpcode, do_compile::{CompilationResult, CompileNode, CompileParams}, }; impl<'a> CompileNode<'a> for aria_parser::ast::ReturnStatement { fn do_compile(&self, params: &'a mut CompileParams) -> CompilationResult { if let Some(val) = &self.val { val.do_compile(params)?; params .writer .get_current_block() .write_opcode_and_source_info(CompilerOpcode::Return, self.loc.clone()); } else { self.return_unit_value(params, &self.loc)?; } Ok(()) } } ================================================ FILE: compiler-lib/src/do_compile/nodes/shift_operation.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use crate::{ builder::compiler_opcodes::CompilerOpcode, do_compile::{CompilationResult, CompileNode, CompileParams}, }; impl<'a> CompileNode<'a> for aria_parser::ast::ShiftOperation { fn do_compile(&self, params: &'a mut CompileParams) -> CompilationResult { self.left.do_compile(params)?; if let Some(rhs) = &self.right { rhs.1.do_compile(params)?; params .writer .get_current_block() .write_opcode_and_source_info( match rhs.0 { aria_parser::ast::ShiftSymbol::Leftward => CompilerOpcode::ShiftLeft, aria_parser::ast::ShiftSymbol::Rightward => CompilerOpcode::ShiftRight, }, self.loc.clone(), ); }; Ok(()) } } ================================================ FILE: compiler-lib/src/do_compile/nodes/statement.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use crate::do_compile::{CompilationResult, CompileNode, CompileParams}; impl<'a> CompileNode<'a> for aria_parser::ast::Statement { fn do_compile(&self, params: &'a mut CompileParams) -> CompilationResult { match self { Self::ValDeclStatement(l) => l.do_compile(params), Self::AssignStatement(a) => a.do_compile(params), Self::WriteOpEqStatement(w) => w.do_compile(params), Self::IfStatement(i) => i.do_compile(params), Self::MatchStatement(m) => m.do_compile(params), Self::WhileStatement(w) => w.do_compile(params), Self::ForStatement(f) => f.do_compile(params), Self::ReturnStatement(r) => r.do_compile(params), Self::ThrowStatement(t) => t.do_compile(params), Self::TryBlock(t) => t.do_compile(params), Self::AssertStatement(a) => a.do_compile(params), Self::CodeBlock(c) => c.do_compile(params), Self::ExpressionStatement(e) => e.do_compile(params), Self::BreakStatement(b) => b.do_compile(params), Self::ContinueStatement(c) => c.do_compile(params), Self::StructDecl(s) => s.do_compile(params), Self::EnumDecl(e) => e.do_compile(params), Self::FunctionDecl(f) => { let f_scope = params.scope.closure(params.writer.get_current_block()); let mut f_params = CompileParams { module: params.module, scope: &f_scope, writer: params.writer, cflow: params.cflow, options: params.options, }; f.do_compile(&mut f_params) } } } } ================================================ FILE: compiler-lib/src/do_compile/nodes/string_literal.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use crate::{ builder::compiler_opcodes::CompilerOpcode, constant_value::ConstantValue, do_compile::{CompilationResult, CompileNode, CompileParams}, }; impl<'a> CompileNode<'a> for aria_parser::ast::StringLiteral { fn do_compile(&self, params: &'a mut CompileParams) -> CompilationResult { let const_idx = self.insert_const_or_fail( params, ConstantValue::String(self.value.clone()), &self.loc, )?; params .writer .get_current_block() .write_opcode_and_source_info(CompilerOpcode::Push(const_idx), self.loc.clone()); Ok(()) } } ================================================ FILE: compiler-lib/src/do_compile/nodes/struct_decl.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use crate::do_compile::{CompilationResult, CompileNode, CompileParams, do_struct_compile}; impl<'a> CompileNode<'a> for aria_parser::ast::StructDecl { fn do_compile(&self, params: &'a mut CompileParams) -> CompilationResult { do_struct_compile(self, params)?; params.scope.emit_untyped_define( &self.name.value, &mut params.module.constants, params.writer.get_current_block(), self.loc.clone(), )?; Ok(()) } } ================================================ FILE: compiler-lib/src/do_compile/nodes/ternary_expression.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use crate::{ builder::compiler_opcodes::CompilerOpcode, do_compile::{CompilationResult, CompileNode, CompileParams}, }; use aria_parser::ast::TernaryExpression; impl<'a> CompileNode<'a> for TernaryExpression { fn do_compile(&self, params: &'a mut CompileParams) -> CompilationResult { self.condition.do_compile(params)?; let false_branch = params .writer .append_block_at_end(&format!("ternary_false_{}", self.loc)); let end_branch = params .writer .append_block_at_end(&format!("ternary_end_{}", self.loc)); params .writer .get_current_block() .write_opcode_and_source_info( CompilerOpcode::JumpFalse(false_branch.clone()), self.loc.clone(), ); self.true_expression.do_compile(params)?; params .writer .get_current_block() .write_opcode_and_source_info( CompilerOpcode::Jump(end_branch.clone()), self.loc.clone(), ); params.writer.set_current_block(false_branch); self.false_expression.do_compile(params)?; params .writer .get_current_block() .write_opcode_and_source_info( CompilerOpcode::Jump(end_branch.clone()), self.loc.clone(), ); params.writer.set_current_block(end_branch); Ok(()) } } ================================================ FILE: compiler-lib/src/do_compile/nodes/throw_statement.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use crate::{ builder::compiler_opcodes::CompilerOpcode, do_compile::{CompilationResult, CompileNode, CompileParams}, }; impl<'a> CompileNode<'a> for aria_parser::ast::ThrowStatement { fn do_compile(&self, params: &'a mut CompileParams) -> CompilationResult { self.val.do_compile(params)?; params .writer .get_current_block() .write_opcode_and_source_info(CompilerOpcode::Throw, self.loc.clone()); Ok(()) } } ================================================ FILE: compiler-lib/src/do_compile/nodes/try_block.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use crate::{ builder::compiler_opcodes::CompilerOpcode, do_compile::{CompilationResult, CompileNode, CompileParams}, }; impl<'a> CompileNode<'a> for aria_parser::ast::TryBlock { fn do_compile(&self, params: &'a mut CompileParams) -> CompilationResult { let try_block = params.writer.insert_block_after( &format!("try_{}", &self.body.loc), ¶ms.writer.get_current_block(), ); let catch_block = params .writer .insert_block_after(&format!("catch_{}", &self.catch.loc), &try_block); let after_block = params .writer .insert_block_after(&format!("try_after_catch_{}", &self.body.loc), &catch_block); params .writer .get_current_block() .write_opcode_and_source_info( CompilerOpcode::Jump(try_block.clone()), self.loc.clone(), ); params.writer.set_current_block(try_block); params .writer .get_current_block() .write_opcode_and_source_info( CompilerOpcode::TryEnter(catch_block.clone()), self.loc.clone(), ); self.body.do_compile(params)?; params .writer .get_current_block() .write_opcode_and_source_info(CompilerOpcode::TryExit, self.loc.clone()); params .writer .get_current_block() .write_opcode_and_source_info( CompilerOpcode::Jump(after_block.clone()), self.loc.clone(), ); params.writer.set_current_block(catch_block); let catch_scope = params.scope.child(); let mut catch_params = CompileParams { module: params.module, scope: &catch_scope, writer: params.writer, cflow: params.cflow, options: params.options, }; catch_params.scope.emit_untyped_define( &self.id.value, &mut catch_params.module.constants, catch_params.writer.get_current_block(), self.id.loc.clone(), )?; self.catch.do_compile(&mut catch_params)?; catch_params .writer .get_current_block() .write_opcode_and_source_info( CompilerOpcode::Jump(after_block.clone()), self.loc.clone(), ); catch_params.writer.set_current_block(after_block); Ok(()) } } ================================================ FILE: compiler-lib/src/do_compile/nodes/try_unwrap_expression.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use aria_parser::ast::TryUnwrapExpression; use haxby_opcodes::BuiltinTypeId; use crate::{ builder::compiler_opcodes::CompilerOpcode, constant_value::ConstantValue, do_compile::{ CompilationError, CompilationErrorReason, CompilationResult, CompileNode, CompileParams, }, }; impl<'a> CompileNode<'a> for TryUnwrapExpression { fn do_compile(&self, params: &'a mut CompileParams) -> CompilationResult { self.left.do_compile(params)?; let try_unwrap_protocol_idx = params .module .constants .insert(ConstantValue::String("try_unwrap_protocol".to_string())) .map_err(|_| CompilationError { loc: self.loc.clone(), reason: CompilationErrorReason::TooManyConstants, })?; params .writer .get_current_block() .write_opcode_and_source_info( CompilerOpcode::PushBuiltinTy(BuiltinTypeId::Result), self.loc.clone(), ) .write_opcode_and_source_info( CompilerOpcode::ReadAttribute(try_unwrap_protocol_idx), self.loc.clone(), ) .write_opcode_and_source_info(CompilerOpcode::Call(1), self.loc.clone()) .write_opcode_and_source_info( CompilerOpcode::TryUnwrapProtocol( haxby_opcodes::try_unwrap_protocol_mode::FLAG_TO_CALLER, ), self.loc.clone(), ); let fallback_block = params .writer .append_block_at_end(&format!("try_unwrap_fallback_{}", self.loc)); let end_block = params .writer .append_block_at_end(&format!("try_unwrap_end_{}", self.loc)); params .writer .get_current_block() .write_opcode_and_source_info( CompilerOpcode::JumpConditionally(end_block.clone(), fallback_block.clone()), self.loc.clone(), ); params.writer.set_current_block(fallback_block); params .writer .get_current_block() .write_opcode_and_source_info(CompilerOpcode::Pop, self.loc.clone()); self.right.do_compile(params)?; params .writer .get_current_block() .write_opcode_and_source_info( CompilerOpcode::Jump(end_block.clone()), self.loc.clone(), ); params.writer.set_current_block(end_block); Ok(()) } } ================================================ FILE: compiler-lib/src/do_compile/nodes/unary_operation.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use crate::{ builder::compiler_opcodes::CompilerOpcode, do_compile::{CompilationResult, CompileNode, CompileParams}, }; impl<'a> CompileNode<'a> for aria_parser::ast::UnaryOperation { fn do_compile(&self, params: &'a mut CompileParams) -> CompilationResult { self.postfix.do_compile(params)?; if let Some(op) = self.operand { params .writer .get_current_block() .write_opcode_and_source_info( match op { aria_parser::ast::UnarySymbol::Exclamation => CompilerOpcode::Not, aria_parser::ast::UnarySymbol::Minus => CompilerOpcode::Neg, }, self.loc.clone(), ); } Ok(()) } } ================================================ FILE: compiler-lib/src/do_compile/nodes/val_decl_entry.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use haxby_opcodes::BuiltinTypeId; use crate::{ builder::compiler_opcodes::CompilerOpcode, do_compile::{ CompilationError, CompilationErrorReason, CompilationResult, CompileNode, CompileParams, }, }; impl<'a> CompileNode<'a> for aria_parser::ast::ValDeclEntry { fn do_compile(&self, params: &'a mut CompileParams) -> CompilationResult { match self.id.name.value.as_str() { "true" | "false" => { return Err(CompilationError { loc: self.loc.clone(), reason: CompilationErrorReason::ReservedIdentifier(self.id.name.value.clone()), }); } _ => {} }; self.val.do_compile(params)?; if let Some(ty) = &self.id.ty { ty.do_compile(params)?; } else { params .writer .get_current_block() .write_opcode_and_source_info( CompilerOpcode::PushBuiltinTy(BuiltinTypeId::Any), self.loc.clone(), ); } params.scope.emit_typed_define( &self.id.name.value, &mut params.module.constants, params.writer.get_current_block(), self.loc.clone(), )?; params.scope.emit_write( &self.id.name.value, &mut params.module.constants, params.writer.get_current_block(), self.loc.clone(), )?; Ok(()) } } ================================================ FILE: compiler-lib/src/do_compile/nodes/val_decl_statement.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use crate::do_compile::{CompilationResult, CompileNode, CompileParams}; impl<'a> CompileNode<'a> for aria_parser::ast::ValDeclStatement { fn do_compile(&self, params: &'a mut CompileParams) -> CompilationResult { for decl in &self.decls { decl.do_compile(params)?; } Ok(()) } } ================================================ FILE: compiler-lib/src/do_compile/nodes/while_statement.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use crate::{ builder::compiler_opcodes::CompilerOpcode, do_compile::{CompilationResult, CompileNode, CompileParams, ControlFlowTargets}, }; impl<'a> CompileNode<'a> for aria_parser::ast::WhileStatement { fn do_compile(&self, params: &'a mut CompileParams) -> CompilationResult { let first_check = params .writer .append_block_at_end(&format!("first_check_{}", self.loc)); let check = params .writer .append_block_at_end(&format!("check_{}", self.loc)); let then = params .writer .append_block_at_end(&format!("then_{}", self.loc)); let els = params .writer .append_block_at_end(&format!("else_{}", self.loc)); let after = params .writer .append_block_at_end(&format!("after_{}", self.loc)); let w_cflow = ControlFlowTargets { break_dest: Some(after.clone()), continue_dest: Some(check.clone()), }; let mut c_params = CompileParams { module: params.module, scope: params.scope, writer: params.writer, cflow: &w_cflow, options: params.options, }; // the logic here is a bit tricky because of the else: // jump to first_check, which will check the condition // if true, jump to then, which will execute the body // if false, jump to else, which will then jump to after // then will jump back to check, which will check the condition again // if the condition is still true, it will jump to then again // if the condition is false, it will jump to after (not to else) c_params .writer .get_current_block() .write_opcode_and_source_info( CompilerOpcode::Jump(first_check.clone()), self.loc.clone(), ); c_params.writer.set_current_block(first_check.clone()); self.cond.do_compile(&mut c_params)?; c_params .writer .get_current_block() .write_opcode_and_source_info( CompilerOpcode::JumpTrue(then.clone()), self.then.loc.clone(), ); c_params .writer .get_current_block() .write_opcode_and_source_info(CompilerOpcode::Jump(els.clone()), self.loc.clone()); c_params.writer.set_current_block(check.clone()); self.cond.do_compile(&mut c_params)?; c_params .writer .get_current_block() .write_opcode_and_source_info( CompilerOpcode::JumpTrue(then.clone()), self.then.loc.clone(), ); c_params .writer .get_current_block() .write_opcode_and_source_info(CompilerOpcode::Jump(after.clone()), self.loc.clone()); c_params.writer.set_current_block(then); self.then.do_compile(&mut c_params)?; c_params .writer .get_current_block() .write_opcode_and_source_info(CompilerOpcode::Jump(check.clone()), self.loc.clone()); c_params.writer.set_current_block(els); if let Some(els) = &self.els { els.then.do_compile(&mut c_params)?; } c_params .writer .get_current_block() .write_opcode_and_source_info(CompilerOpcode::Jump(after.clone()), self.loc.clone()); c_params.writer.set_current_block(after); Ok(()) } } ================================================ FILE: compiler-lib/src/do_compile/nodes/write_opeq_statement.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use aria_parser::ast::{ AddOperation, AddSymbol, AssignStatement, CompOperation, Expression, LogOperation, MulOperation, MulSymbol, ParenExpression, PostfixExpression, PostfixRvalue, Primary, RelOperation, ShiftOperation, ShiftSymbol, UnaryOperation, }; use crate::do_compile::{CompilationResult, CompileNode, CompileParams}; impl<'a> CompileNode<'a> for aria_parser::ast::WriteOpEqStatement { fn do_compile(&self, params: &'a mut CompileParams) -> CompilationResult { let rhs_as_unary = UnaryOperation::from(&PostfixRvalue::from(&PostfixExpression::from( &Primary::ParenExpression(ParenExpression { loc: self.val.loc().clone(), value: Box::new(self.val.clone()), }), ))); let rhs_as_mul = MulOperation::from(&rhs_as_unary); let final_expr = match self.op { aria_parser::ast::AddEqSymbol::PlusEq => { let add_op = AddOperation { loc: self.loc.clone(), left: MulOperation::from(&UnaryOperation::from(&PostfixRvalue::from(&self.id))), right: vec![(AddSymbol::Plus, rhs_as_mul)], }; Expression::from(&LogOperation::from(&CompOperation::from( &RelOperation::from(&ShiftOperation::from(&add_op)), ))) } aria_parser::ast::AddEqSymbol::MinusEq => { let add_op = AddOperation { loc: self.loc.clone(), left: MulOperation::from(&UnaryOperation::from(&PostfixRvalue::from(&self.id))), right: vec![(AddSymbol::Minus, rhs_as_mul)], }; Expression::from(&LogOperation::from(&CompOperation::from( &RelOperation::from(&ShiftOperation::from(&add_op)), ))) } aria_parser::ast::AddEqSymbol::StarEq => { let mo = MulOperation { loc: self.loc.clone(), left: UnaryOperation::from(&PostfixRvalue::from(&self.id)), right: vec![(MulSymbol::Star, rhs_as_unary)], }; let add_op = AddOperation { loc: self.loc.clone(), left: mo, right: vec![], }; Expression::from(&LogOperation::from(&CompOperation::from( &RelOperation::from(&ShiftOperation::from(&add_op)), ))) } aria_parser::ast::AddEqSymbol::SlashEq => { let mo = MulOperation { loc: self.loc.clone(), left: UnaryOperation::from(&PostfixRvalue::from(&self.id)), right: vec![(MulSymbol::Slash, rhs_as_unary)], }; let add_op = AddOperation { loc: self.loc.clone(), left: mo, right: vec![], }; Expression::from(&LogOperation::from(&CompOperation::from( &RelOperation::from(&ShiftOperation::from(&add_op)), ))) } aria_parser::ast::AddEqSymbol::PercentEq => { let mo = MulOperation { loc: self.loc.clone(), left: UnaryOperation::from(&PostfixRvalue::from(&self.id)), right: vec![(MulSymbol::Percent, rhs_as_unary)], }; let add_op = AddOperation { loc: self.loc.clone(), left: mo, right: vec![], }; Expression::from(&LogOperation::from(&CompOperation::from( &RelOperation::from(&ShiftOperation::from(&add_op)), ))) } aria_parser::ast::AddEqSymbol::ShiftLeftEq => { let shift_op = ShiftOperation { loc: self.loc.clone(), left: AddOperation::from(&MulOperation::from(&UnaryOperation::from( &PostfixRvalue::from(&self.id), ))), right: Some(( ShiftSymbol::Leftward, AddOperation::from(&MulOperation::from(&rhs_as_unary)), )), }; Expression::from(&LogOperation::from(&CompOperation::from( &RelOperation::from(&shift_op), ))) } aria_parser::ast::AddEqSymbol::ShiftRightEq => { let shift_op = ShiftOperation { loc: self.loc.clone(), left: AddOperation::from(&MulOperation::from(&UnaryOperation::from( &PostfixRvalue::from(&self.id), ))), right: Some(( ShiftSymbol::Rightward, AddOperation::from(&MulOperation::from(&rhs_as_unary)), )), }; Expression::from(&LogOperation::from(&CompOperation::from( &RelOperation::from(&shift_op), ))) } }; let assign_stmt = AssignStatement { loc: self.loc.clone(), id: vec![self.id.clone()], val: vec![final_expr], }; assign_stmt.do_compile(params) } } ================================================ FILE: compiler-lib/src/do_compile/postfix.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use aria_parser::ast::{Expression, ExpressionList, Identifier, SourcePointer}; use haxby_opcodes::BuiltinTypeId; use crate::{builder::compiler_opcodes::CompilerOpcode, constant_value::ConstantValue}; use super::{ CompilationError, CompilationErrorReason, CompilationResult, CompileNode, CompileParams, }; #[derive(Debug)] pub(super) struct FieldWrite { pub(super) field: Identifier, pub(super) value: Expression, } #[derive(Debug)] pub(super) struct IndexWrite { pub(super) index: ExpressionList, pub(super) value: Expression, } #[allow(clippy::large_enum_variant)] #[derive(Debug)] pub(super) enum ObjWrite { Field(FieldWrite), Index(IndexWrite), } impl ObjWrite { fn loc(&self) -> &SourcePointer { match self { ObjWrite::Field(f) => &f.field.loc, ObjWrite::Index(i) => &i.index.loc, } } } #[allow(clippy::large_enum_variant)] pub(super) enum PostfixValue { Primary(Box), Attribute(Box, Box), Call(Box, Box, SourcePointer), Case(Box, Box, Option), Index(Box, Box), ObjWrite(Box, Vec), TryProtocol( Box, Box, ), } impl<'a> PostfixValue { pub(super) fn emit_read(&self, params: &'a mut CompileParams) -> CompilationResult { match self { PostfixValue::Primary(primary) => primary.do_compile(params), PostfixValue::Call(base, args, loc) => { for expr in args.expressions.iter().rev() { expr.do_compile(params)?; } let argc = args.expressions.len(); base.emit_read(params)?; params .writer .get_current_block() .write_opcode_and_source_info(CompilerOpcode::Call(argc as u8), loc.clone()); Ok(()) } PostfixValue::Case(base, case, payload) => { if let Some(p) = payload { p.do_compile(params)?; } base.emit_read(params)?; let identifier_idx = match params .module .constants .insert(ConstantValue::String(case.value.clone())) { Ok(c) => c, Err(_) => { return Err(CompilationError { loc: case.loc.clone(), reason: CompilationErrorReason::TooManyConstants, }); } }; params .writer .get_current_block() .write_opcode_and_source_info( CompilerOpcode::NewEnumVal(payload.is_some(), identifier_idx), case.loc.clone(), ); Ok(()) } PostfixValue::Index(base, index) => { base.emit_read(params)?; index.do_compile(params)?; params .writer .get_current_block() .write_opcode_and_source_info( CompilerOpcode::ReadIndex(index.expressions.len() as u8), index.loc.clone(), ); Ok(()) } PostfixValue::Attribute(base, identifier) => { let identifier_idx = match params .module .constants .insert(ConstantValue::String(identifier.value.clone())) { Ok(c) => c, Err(_) => { return Err(CompilationError { loc: identifier.loc.clone(), reason: CompilationErrorReason::TooManyConstants, }); } }; base.emit_read(params)?; params .writer .get_current_block() .write_opcode_and_source_info( CompilerOpcode::ReadAttribute(identifier_idx), identifier.loc.clone(), ); Ok(()) } PostfixValue::ObjWrite(base, terms) => { base.emit_read(params)?; for term in terms { params .writer .get_current_block() .write_opcode_and_source_info(CompilerOpcode::Dup, term.loc().clone()); match term { ObjWrite::Field(field_write) => { let identifier_idx = params .module .constants .insert(ConstantValue::String(field_write.field.value.clone())) .map_err(|_| CompilationError { loc: field_write.field.loc.clone(), reason: CompilationErrorReason::TooManyConstants, })?; field_write.value.do_compile(params)?; params .writer .get_current_block() .write_opcode_and_source_info( CompilerOpcode::WriteAttribute(identifier_idx), term.loc().clone(), ); } ObjWrite::Index(index_write) => { index_write.index.do_compile(params)?; index_write.value.do_compile(params)?; params .writer .get_current_block() .write_opcode_and_source_info( CompilerOpcode::WriteIndex(1_u8), term.loc().clone(), ); } } } Ok(()) } PostfixValue::TryProtocol(base, tp) => { let mode = match tp.mode { aria_parser::ast::TryProtocolMode::Return => { haxby_opcodes::try_unwrap_protocol_mode::PROPAGATE_ERROR } aria_parser::ast::TryProtocolMode::Assert => { haxby_opcodes::try_unwrap_protocol_mode::ASSERT_ERROR } }; base.emit_read(params)?; let try_unwrap_protocol_idx = params .module .constants .insert(ConstantValue::String("try_unwrap_protocol".to_string())) .map_err(|_| CompilationError { loc: tp.loc.clone(), reason: CompilationErrorReason::TooManyConstants, })?; params .writer .get_current_block() .write_opcode_and_source_info( CompilerOpcode::PushBuiltinTy(BuiltinTypeId::Result), tp.loc.clone(), ) .write_opcode_and_source_info( CompilerOpcode::ReadAttribute(try_unwrap_protocol_idx), tp.loc.clone(), ) .write_opcode_and_source_info(CompilerOpcode::Call(1), tp.loc.clone()) .write_opcode_and_source_info( CompilerOpcode::TryUnwrapProtocol(mode), tp.loc.clone(), ); Ok(()) } } } pub(super) fn emit_write( &self, val: &aria_parser::ast::Expression, params: &'a mut CompileParams, ) -> CompilationResult { match self { PostfixValue::Primary(primary) => match primary.as_ref() { aria_parser::ast::Primary::Identifier(id) => { val.do_compile(params)?; params.scope.emit_write( &id.value, &mut params.module.constants, params.writer.get_current_block(), primary.loc().clone(), )?; Ok(()) } _ => Err(CompilationError { loc: primary.loc().clone(), reason: CompilationErrorReason::ReadOnlyValue, }), }, PostfixValue::Call(.., loc) => Err(CompilationError { loc: loc.clone(), reason: CompilationErrorReason::ReadOnlyValue, }), PostfixValue::Case(_, case, _) => Err(CompilationError { loc: case.loc.clone(), reason: CompilationErrorReason::ReadOnlyValue, }), PostfixValue::Index(base, index) => { base.emit_read(params)?; index.do_compile(params)?; val.do_compile(params)?; params .writer .get_current_block() .write_opcode_and_source_info( CompilerOpcode::WriteIndex(index.expressions.len() as u8), index.loc.clone(), ); Ok(()) } PostfixValue::Attribute(base, identifier) => { let identifier_idx = match params .module .constants .insert(ConstantValue::String(identifier.value.clone())) { Ok(c) => c, Err(_) => { return Err(CompilationError { loc: identifier.loc.clone(), reason: CompilationErrorReason::TooManyConstants, }); } }; base.emit_read(params)?; val.do_compile(params)?; params .writer .get_current_block() .write_opcode_and_source_info( CompilerOpcode::WriteAttribute(identifier_idx), identifier.loc.clone(), ); Ok(()) } PostfixValue::ObjWrite(_, terms) => { let loc = terms.first().map(|x| x.loc()).unwrap_or(val.loc()).clone(); Err(CompilationError { loc, reason: CompilationErrorReason::WriteOnlyValue, }) } PostfixValue::TryProtocol(_, tp) => Err(CompilationError { loc: tp.loc.clone(), reason: CompilationErrorReason::ReadOnlyValue, }), } } } impl From<&aria_parser::ast::PostfixExpression> for PostfixValue { fn from(value: &aria_parser::ast::PostfixExpression) -> Self { let mut current = PostfixValue::Primary(Box::new(value.base.clone())); for term in &value.terms { match term { aria_parser::ast::PostfixTerm::PostfixTermAttribute(attr) => { current = PostfixValue::Attribute(Box::new(current), Box::new(attr.id.clone())) } aria_parser::ast::PostfixTerm::PostfixTermIndex(index) => { current = PostfixValue::Index(Box::new(current), Box::new(index.index.clone())) } aria_parser::ast::PostfixTerm::PostfixTermCall(call) => { current = PostfixValue::Call( Box::new(current), Box::new(call.args.clone()), call.loc.clone(), ) } aria_parser::ast::PostfixTerm::PostfixTermEnumCase(case) => { current = PostfixValue::Case( Box::new(current), Box::new(case.id.clone()), case.payload.clone(), ) } aria_parser::ast::PostfixTerm::PostfixTermObjectWrite(wrt) => { use aria_parser::ast::PostfixTermWrite::{ PostfixTermFieldWrite, PostfixTermIndexWrite, }; let mut terms = vec![]; for term in &wrt.terms.terms { match term { PostfixTermFieldWrite(term) => { let expr = if let Some(expr) = &term.val { expr.clone() } else { Expression::from(&term.id) }; terms.push(ObjWrite::Field(FieldWrite { field: term.id.clone(), value: expr, })); } PostfixTermIndexWrite(term) => { terms.push(ObjWrite::Index(IndexWrite { index: term.idx.clone(), value: term.val.clone(), })); } } } current = PostfixValue::ObjWrite(Box::new(current), terms) } aria_parser::ast::PostfixTerm::PostfixTermTryProtocol(tp) => { current = PostfixValue::TryProtocol(Box::new(current), Box::new(tp.clone())) } } } current } } ================================================ FILE: compiler-lib/src/dump/mod.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use aria_parser::ast::prettyprint::{PrettyPrintable, printout_accumulator::PrintoutAccumulator}; use opcodes::opcode_prettyprint; use crate::{ bc_reader::BytecodeReader, constant_value::{CompiledCodeObject, ConstantValue, ConstantValues}, module::CompiledModule, }; pub mod opcodes; pub trait StringResolver { fn resolve_compile_time_constant(&self, _: u16) -> Option { None } fn resolve_run_time_symbol(&self, _: u32) -> Option { None } } impl StringResolver for CompiledModule { fn resolve_compile_time_constant(&self, idx: u16) -> Option { match self.constants.values.get(idx as usize) { Some(cv) => { let poa = PrintoutAccumulator::default(); let poa = cv.dump(self, poa); Some(poa.value()) } _ => None, } } } trait ModuleDump { fn dump( &self, resolver: &dyn StringResolver, buffer: PrintoutAccumulator, ) -> PrintoutAccumulator; } impl ModuleDump for ConstantValue { fn dump( &self, resolver: &dyn StringResolver, buffer: PrintoutAccumulator, ) -> PrintoutAccumulator { match self { ConstantValue::Integer(n) => buffer << "int(" << n << ")", ConstantValue::String(s) => buffer << "str(\"" << s.as_str() << "\")", ConstantValue::Float(f) => buffer << "fp(" << f.raw_value() << ")", ConstantValue::CompiledCodeObject(cco) => cco.dump(resolver, buffer), } } } impl ModuleDump for ConstantValues { fn dump( &self, resolver: &dyn StringResolver, buffer: PrintoutAccumulator, ) -> PrintoutAccumulator { let mut dest = buffer; for cv in self.values.iter().enumerate() { dest = dest << "cv @" << cv.0 << " -> "; dest = cv.1.dump(resolver, dest) << "\n" } dest } } impl ModuleDump for CompiledCodeObject { fn dump( &self, resolver: &dyn StringResolver, buffer: PrintoutAccumulator, ) -> PrintoutAccumulator { let mut dest = buffer << "cco(name:\"" << self.name.as_str() << " required arguments:" << self.required_argc << " default arguments:" << self.default_argc << " frame size:" << self.frame_size << ") bc=\n"; let mut bcr = match BytecodeReader::try_from(self.body.as_slice()) { Ok(bcr) => bcr, Err(e) => { return dest << " \n"; } }; let mut op_idx = 0; loop { let idx_str = format!(" {op_idx:05}: "); match bcr.read_opcode() { Ok(op) => { dest = opcode_prettyprint(op, resolver, dest << idx_str); if let Some(lte) = self.line_table.get(op_idx as u16) { dest = dest << format!(" --> {lte}") << "\n"; } else { dest = dest << "\n"; } op_idx += 1; } Err(_) => { break; } } } dest } } impl PrettyPrintable for CompiledModule { fn prettyprint(&self, buffer: PrintoutAccumulator) -> PrintoutAccumulator { self.constants.dump(self, buffer) } } ================================================ FILE: compiler-lib/src/dump/opcodes.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use aria_parser::ast::prettyprint::printout_accumulator::PrintoutAccumulator; use haxby_opcodes::Opcode; fn const_best_repr(resolver: &dyn super::StringResolver, idx: u16) -> String { match resolver.resolve_compile_time_constant(idx) { Some(s) => s.to_string(), None => format!("invalid const @{idx}"), } } fn symbol_best_repr(resolver: &dyn super::StringResolver, idx: u32) -> String { match resolver.resolve_run_time_symbol(idx) { Some(s) => s.to_string(), None => format!("invalid const @{idx}"), } } fn try_protocol_mode_to_str(id: u8) -> &'static str { match id { haxby_opcodes::try_unwrap_protocol_mode::PROPAGATE_ERROR => "RETURN", haxby_opcodes::try_unwrap_protocol_mode::ASSERT_ERROR => "ASSERT", _ => "Unknown", } } pub fn opcode_prettyprint( opcode: Opcode, resolver: &dyn super::StringResolver, buffer: PrintoutAccumulator, ) -> PrintoutAccumulator { match opcode { Opcode::Push(idx) => { buffer << "PUSH(@" << idx << ") [" << const_best_repr(resolver, idx) << "]" } Opcode::PushBuiltinTy(n) => { buffer << "PUSH_BUILTIN_TY(" << n.to_u8() << ") [" << n.name() << "]" } Opcode::PushRuntimeValue(n) => { buffer << "PUSH_RUNTIME_VAL(" << n.to_u8() << ") [" << n.name() << "]" } Opcode::ReadNamed(idx) => { buffer << "READ_NAMED(@" << idx << ") [" << const_best_repr(resolver, idx) << "]" } Opcode::WriteNamed(idx) => { buffer << "WRITE_NAMED(@" << idx << ") [" << const_best_repr(resolver, idx) << "]" } Opcode::TypedefNamed(idx) => { buffer << "TYPEDEF_NAMED(@" << idx << ") [" << const_best_repr(resolver, idx) << "]" } Opcode::ReadAttribute(idx) => { buffer << "READ_ATTRIB(@" << idx << ") [" << const_best_repr(resolver, idx) << "]" } Opcode::WriteAttribute(idx) => { buffer << "WRITE_ATTRIB(@" << idx << ") [" << const_best_repr(resolver, idx) << "]" } Opcode::ReadAttributeSymbol(idx) => { buffer << "READ_ATTRIB_SYMBOL(#" << idx << ") [" << symbol_best_repr(resolver, idx) << "]" } Opcode::WriteAttributeSymbol(idx) => { buffer << "WRITE_ATTRIB_SYMBOL(#" << idx << ") [" << symbol_best_repr(resolver, idx) << "]" } Opcode::BindCase(arg, idx) => { buffer << "BIND_CASE(" << arg << ",@" << idx << ") [" << const_best_repr(resolver, idx) << "]" } Opcode::BindCaseSymbol(arg, idx) => { buffer << "BIND_CASE_SYMBOL(" << arg << ",#" << idx << ") [" << symbol_best_repr(resolver, idx) << "]" } Opcode::NewEnumVal(flag, idx) => { buffer << "NEW_ENUM_VAL(" << flag << ",@" << idx << ") [" << const_best_repr(resolver, idx) << "]" } Opcode::NewEnumValSymbol(flag, idx) => { buffer << "NEW_ENUM_VAL_SYMBOL(" << flag << ",#" << idx << ") [" << symbol_best_repr(resolver, idx) << "]" } Opcode::EnumCheckIsCase(idx) => { buffer << "ENUM_CHECK_IS_CASE(@" << idx << ") [" << const_best_repr(resolver, idx) << "]" } Opcode::EnumCheckIsCaseSymbol(idx) => { buffer << "ENUM_CHECK_IS_CASE_SYMBOL(#" << idx << ") [" << symbol_best_repr(resolver, idx) << "]" } Opcode::Import(idx) => { buffer << "IMPORT(@" << idx << ") [" << const_best_repr(resolver, idx) << "]" } Opcode::LoadDylib(idx) => { buffer << "LOAD_DYLIB(@" << idx << ") [" << const_best_repr(resolver, idx) << "]" } Opcode::Assert(idx) => { buffer << "ASSERT(@" << idx << ") [" << const_best_repr(resolver, idx) << "]" } Opcode::TryUnwrapProtocol(mode) => { buffer << "TRY_UNWRAP_PROTOCOL " << try_protocol_mode_to_str(mode) } Opcode::Nop | Opcode::Push0 | Opcode::Push1 | Opcode::PushTrue | Opcode::PushFalse | Opcode::Pop | Opcode::Dup | Opcode::Swap | Opcode::Copy(_) | Opcode::Add | Opcode::Sub | Opcode::Mul | Opcode::Div | Opcode::Rem | Opcode::Neg | Opcode::ShiftLeft | Opcode::ShiftRight | Opcode::Not | Opcode::Equal | Opcode::ReadLocal(_) | Opcode::WriteLocal(_) | Opcode::TypedefLocal(_) | Opcode::ReadIndex(_) | Opcode::WriteIndex(_) | Opcode::ReadUplevel(_) | Opcode::LogicalAnd | Opcode::LogicalOr | Opcode::Xor | Opcode::BitwiseAnd | Opcode::BitwiseOr | Opcode::GreaterThan | Opcode::LessThan | Opcode::GreaterThanEqual | Opcode::LessThanEqual | Opcode::JumpTrue(_) | Opcode::JumpFalse(_) | Opcode::Jump(_) | Opcode::JumpConditionally(..) | Opcode::JumpIfArgSupplied(..) | Opcode::Call(_) | Opcode::Return | Opcode::ReturnUnit | Opcode::TryEnter(_) | Opcode::TryExit | Opcode::Throw | Opcode::BuildList(_) | Opcode::BuildFunction | Opcode::StoreUplevel(_) | Opcode::BuildStruct | Opcode::BuildEnum | Opcode::BuildMixin | Opcode::IncludeMixin | Opcode::EnumTryExtractPayload | Opcode::Isa | Opcode::LiftModule | Opcode::Halt => buffer << opcode.to_string(), } } ================================================ FILE: compiler-lib/src/lib.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use aria_parser::ast::{ParsedModule, SourceBuffer}; use do_compile::{CompilationError, CompilationResult}; use module::CompiledModule; pub mod bc_reader; pub mod bc_writer; pub mod builder; pub mod constant_value; pub mod do_compile; pub mod dump; pub mod line_table; pub mod module; pub mod scope; pub struct CompilationOptions { pub optimize: bool, pub dump_builder: bool, } impl Default for CompilationOptions { fn default() -> Self { Self { optimize: true, dump_builder: false, } } } pub fn compile_from_source( src: &SourceBuffer, options: &CompilationOptions, ) -> CompilationResult> { do_compile::compile_from_source(src, options) } pub fn compile_from_ast( ast: &ParsedModule, options: &CompilationOptions, ) -> CompilationResult> { do_compile::compile_from_ast(ast, options) } ================================================ FILE: compiler-lib/src/line_table.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use std::{cell::RefCell, collections::HashMap, rc::Rc}; use aria_parser::ast::SourcePointer; #[derive(Default)] struct LineTableImpl { map: RefCell>, } #[derive(Clone, Default)] pub struct LineTable { imp: Rc, } impl LineTable { pub fn insert(&self, idx: u16, ptr: SourcePointer) { self.imp.map.borrow_mut().insert(idx, ptr); } pub fn get(&self, idx: u16) -> Option { self.imp.map.borrow().get(&idx).cloned() } } impl PartialEq for LineTable { fn eq(&self, other: &Self) -> bool { Rc::ptr_eq(&self.imp, &other.imp) } } impl Eq for LineTable {} ================================================ FILE: compiler-lib/src/module.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use std::path::PathBuf; use crate::constant_value::{CompiledCodeObject, ConstantValue, ConstantValues}; #[derive(Default)] pub struct CompiledModule { pub constants: ConstantValues, pub widget_root_path: Option, } impl CompiledModule { pub fn load_indexed_const(&self, idx: u16) -> Option { self.constants.get(idx as usize) } // relies on __entry being the last code object stored in the module // after everything else is compiled pub fn load_entry_code_object(&self) -> CompiledCodeObject { let cco = self .constants .get(self.constants.len() - 1) .expect("missing __entry constant"); cco.as_compiled_code_object() .expect("__entry constant is not a code object") .clone() } } ================================================ FILE: compiler-lib/src/scope.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use std::{cell::RefCell, collections::HashMap, rc::Rc}; use aria_parser::ast::SourcePointer; use haxby_opcodes::BuiltinTypeId; use crate::{ builder::{block::BasicBlock, compiler_opcodes::CompilerOpcode}, constant_value::ConstantValues, }; trait Numeric { fn zero() -> Output; fn one() -> Output; } impl Numeric for u8 { fn zero() -> u8 { 0_u8 } fn one() -> u8 { 1_u8 } } impl Numeric for u16 { fn zero() -> u16 { 0_u16 } fn one() -> u16 { 1_u16 } } struct IndexProviderImpl where T: std::ops::AddAssign + Numeric + Copy, { next_idx: T, } impl Default for IndexProviderImpl where T: std::ops::AddAssign + Numeric + Copy, { fn default() -> Self { Self { next_idx: T::zero(), } } } impl IndexProviderImpl where T: std::ops::AddAssign + Numeric + Copy, { fn next(&mut self) -> T { let current = self.next_idx; self.next_idx += T::one(); current } fn get_max_index(&self) -> T { self.next_idx } } pub enum ScopeErrorReason { TooManyConstants, OverlyDeepClosure, NoSuchIdentifier(String), } pub struct ScopeError { pub loc: SourcePointer, pub reason: ScopeErrorReason, } pub type ScopeResult = Result; #[derive(Default)] pub struct ModuleRootScope { symbols: RefCell>, } impl ModuleRootScope { pub fn emit_typed_define( &self, name: &str, consts: &mut ConstantValues, dest: BasicBlock, loc: SourcePointer, ) -> ScopeResult { let symbol_idx = match consts.insert(crate::constant_value::ConstantValue::String( name.to_owned(), )) { Ok(c) => c, Err(_) => { return Err(ScopeError { loc, reason: ScopeErrorReason::TooManyConstants, }); } }; self.symbols .borrow_mut() .insert(name.to_owned(), symbol_idx); dest.write_opcode_and_source_info(CompilerOpcode::TypedefNamed(symbol_idx), loc); Ok(()) } pub fn emit_write( &self, name: &str, consts: &mut ConstantValues, dest: BasicBlock, loc: SourcePointer, ) -> ScopeResult { if let Some(existing_idx) = self.symbols.borrow().get(name) { dest.write_opcode_and_source_info(CompilerOpcode::WriteNamed(*existing_idx), loc); Ok(()) } else { let symbol_idx = match consts.insert(crate::constant_value::ConstantValue::String( name.to_owned(), )) { Ok(c) => c, Err(_) => { return Err(ScopeError { loc, reason: ScopeErrorReason::TooManyConstants, }); } }; dest.write_opcode_and_source_info(CompilerOpcode::WriteNamed(symbol_idx), loc); Ok(()) } } pub fn emit_read( &self, name: &str, consts: &mut ConstantValues, dest: BasicBlock, loc: SourcePointer, ) -> ScopeResult { if let Some(existing_idx) = self.symbols.borrow().get(name) { dest.write_opcode_and_source_info(CompilerOpcode::ReadNamed(*existing_idx), loc); } else { let symbol_idx = match consts.insert(crate::constant_value::ConstantValue::String( name.to_owned(), )) { Ok(c) => c, Err(_) => { return Err(ScopeError { loc, reason: ScopeErrorReason::TooManyConstants, }); } }; dest.write_opcode_and_source_info(CompilerOpcode::ReadNamed(symbol_idx), loc); } Ok(()) } fn resolve_uplevel_symbol( &self, _: &str, _: BasicBlock, _: SourcePointer, _: bool, ) -> ScopeResult> { Ok(None) } } pub struct ModuleChildScope { symbols: RefCell>, parent: CompilationScope, } impl ModuleChildScope { fn new(parent: CompilationScope) -> Self { Self { symbols: Default::default(), parent, } } pub fn emit_typed_define( &self, name: &str, consts: &mut ConstantValues, dest: BasicBlock, loc: SourcePointer, ) -> ScopeResult { let symbol_idx = match consts.insert(crate::constant_value::ConstantValue::String( name.to_owned(), )) { Ok(c) => c, Err(_) => { return Err(ScopeError { loc, reason: ScopeErrorReason::TooManyConstants, }); } }; self.symbols .borrow_mut() .insert(name.to_owned(), symbol_idx); dest.write_opcode_and_source_info(CompilerOpcode::TypedefNamed(symbol_idx), loc); Ok(()) } pub fn emit_write( &self, name: &str, consts: &mut ConstantValues, dest: BasicBlock, loc: SourcePointer, ) -> ScopeResult { if let Some(existing_idx) = self.symbols.borrow().get(name) { dest.write_opcode_and_source_info(CompilerOpcode::WriteNamed(*existing_idx), loc); Ok(()) } else { self.parent.emit_write(name, consts, dest, loc) } } pub fn emit_read( &self, name: &str, consts: &mut ConstantValues, dest: BasicBlock, loc: SourcePointer, ) -> ScopeResult { if let Some(existing_idx) = self.symbols.borrow().get(name) { dest.write_opcode_and_source_info(CompilerOpcode::ReadNamed(*existing_idx), loc); Ok(()) } else { self.parent.emit_read(name, consts, dest, loc) } } fn resolve_uplevel_symbol( &self, _: &str, _: BasicBlock, _: SourcePointer, _: bool, ) -> ScopeResult> { Ok(None) } } #[derive(Copy, Clone)] pub(crate) struct UplevelInfo { pub idx_in_uplevel: u8, } #[derive(Copy, Clone)] struct UplevelSymbolResolution { depth: u8, index_at_depth: u8, } pub struct FunctionRootScope { symbols: RefCell>, index_provider: RefCell>, parent: CompilationScope, lexical_parent: Option<(CompilationScope, BasicBlock)>, pub(crate) uplevels: RefCell>, } impl FunctionRootScope { fn root_function(parent: CompilationScope) -> Self { Self { symbols: Default::default(), index_provider: Default::default(), parent: parent.get_module_scope().unwrap(), lexical_parent: None, uplevels: Default::default(), } } fn closure(lexical_parent: (CompilationScope, BasicBlock)) -> Self { Self { symbols: Default::default(), index_provider: Default::default(), parent: lexical_parent.0.get_module_scope().unwrap(), lexical_parent: Some(lexical_parent), uplevels: Default::default(), } } pub fn num_locals(&self) -> u8 { self.index_provider.borrow().get_max_index() } pub fn emit_typed_define( &self, name: &str, _: &mut ConstantValues, dest: BasicBlock, loc: SourcePointer, ) -> ScopeResult { let next_idx = self.index_provider.borrow_mut().next(); self.symbols.borrow_mut().insert(name.to_owned(), next_idx); dest.write_opcode_and_source_info(CompilerOpcode::TypedefLocal(next_idx), loc); Ok(()) } pub fn emit_write( &self, name: &str, consts: &mut ConstantValues, dest: BasicBlock, loc: SourcePointer, ) -> ScopeResult { if let Some(existing_idx) = self.symbols.borrow().get(name) { dest.write_opcode_and_source_info(CompilerOpcode::WriteLocal(*existing_idx), loc); Ok(()) } else if let Some(uplevel_info) = self.resolve_uplevel_symbol(name, dest.clone(), loc.clone(), false)? { dest.write_opcode_and_source_info( CompilerOpcode::WriteLocal(uplevel_info.index_at_depth), loc.clone(), ); Ok(()) } else { self.parent.emit_write(name, consts, dest, loc) } } fn store_uplevel_as_local( &self, name: &str, dest: BasicBlock, loc: SourcePointer, uplevel: UplevelSymbolResolution, want_dup_on_stack: bool, ) -> ScopeResult { if uplevel.depth > 1 { return Err(ScopeError { loc, reason: ScopeErrorReason::OverlyDeepClosure, }); } let index_in_local = self.index_provider.borrow_mut().next(); self.symbols .borrow_mut() .insert(name.to_owned(), index_in_local); self.uplevels.borrow_mut().push(UplevelInfo { idx_in_uplevel: uplevel.index_at_depth, }); dest.write_opcode_and_source_info( CompilerOpcode::ReadUplevel(uplevel.index_at_depth), loc.clone(), ); if want_dup_on_stack { dest.write_opcode_and_source_info(CompilerOpcode::Dup, loc.clone()); } dest.write_opcode_and_source_info(CompilerOpcode::WriteLocal(index_in_local), loc); Ok(UplevelSymbolResolution { depth: 0, index_at_depth: index_in_local, }) } pub fn emit_read( &self, name: &str, consts: &mut ConstantValues, dest: BasicBlock, loc: SourcePointer, ) -> ScopeResult { let maybe_idx = self.symbols.borrow().get(name).cloned(); if let Some(existing_idx) = maybe_idx { dest.write_opcode_and_source_info(CompilerOpcode::ReadLocal(existing_idx), loc); return Ok(()); } if self .resolve_uplevel_symbol(name, dest.clone(), loc.clone(), true)? .is_some() { return Ok(()); } self.parent.emit_read(name, consts, dest, loc) } fn resolve_uplevel_symbol( &self, name: &str, dest: BasicBlock, loc: SourcePointer, want_dup_on_stack: bool, ) -> ScopeResult> { let maybe_idx = self.symbols.borrow().get(name).cloned(); if let Some(existing_idx) = maybe_idx { Ok(Some(UplevelSymbolResolution { depth: 0, index_at_depth: existing_idx, })) } else if let Some(cp) = &self.lexical_parent { let sr = cp.0.resolve_uplevel_symbol(name, cp.1.clone(), loc.clone(), want_dup_on_stack)?; if let Some(sr) = sr { let sr = self.store_uplevel_as_local(name, dest, loc, sr, want_dup_on_stack)?; Ok(Some(sr)) } else { Ok(None) } } else { Ok(None) } } } pub struct FunctionChildScope { symbols: RefCell>, parent: CompilationScope, } impl FunctionChildScope { fn new(parent: CompilationScope) -> Self { Self { symbols: Default::default(), parent, } } fn get_function_root(&self) -> Rc { match &self.parent { CompilationScope::FunctionRoot(r) => r.clone(), CompilationScope::FunctionChild(c) => c.get_function_root(), _ => panic!("function scope should end in a function, not a module"), } } pub fn emit_typed_define( &self, name: &str, _: &mut ConstantValues, dest: BasicBlock, loc: SourcePointer, ) -> ScopeResult { let next_idx = self.get_function_root().index_provider.borrow_mut().next(); self.symbols.borrow_mut().insert(name.to_owned(), next_idx); dest.write_opcode_and_source_info(CompilerOpcode::TypedefLocal(next_idx), loc); Ok(()) } pub fn emit_write( &self, name: &str, consts: &mut ConstantValues, dest: BasicBlock, loc: SourcePointer, ) -> ScopeResult { if let Some(existing_idx) = self.symbols.borrow().get(name) { dest.write_opcode_and_source_info(CompilerOpcode::WriteLocal(*existing_idx), loc); Ok(()) } else { self.parent.emit_write(name, consts, dest, loc) } } pub fn emit_read( &self, name: &str, consts: &mut ConstantValues, dest: BasicBlock, loc: SourcePointer, ) -> ScopeResult { if let Some(existing_idx) = self.symbols.borrow().get(name) { dest.write_opcode_and_source_info(CompilerOpcode::ReadLocal(*existing_idx), loc); Ok(()) } else { self.parent.emit_read(name, consts, dest, loc) } } fn resolve_uplevel_symbol( &self, name: &str, dest: BasicBlock, loc: SourcePointer, want_dup_on_stack: bool, ) -> ScopeResult> { if let Some(existing_idx) = self.symbols.borrow().get(name) { Ok(Some(UplevelSymbolResolution { depth: 0, index_at_depth: *existing_idx, })) } else { self.parent .resolve_uplevel_symbol(name, dest, loc, want_dup_on_stack) } } } #[derive(enum_as_inner::EnumAsInner, Clone)] pub enum CompilationScope { ModuleRoot(Rc), ModuleChild(Rc), FunctionRoot(Rc), FunctionChild(Rc), } impl CompilationScope { pub fn module() -> Self { Self::ModuleRoot(Rc::new(ModuleRootScope::default())) } pub fn function(&self) -> Self { Self::FunctionRoot(Rc::new(FunctionRootScope::root_function(self.clone()))) } pub fn closure(&self, dest: BasicBlock) -> Self { Self::FunctionRoot(Rc::new(FunctionRootScope::closure((self.clone(), dest)))) } pub(crate) fn get_module_scope(&self) -> Option { match self { Self::ModuleRoot(_) => Some(self.clone()), Self::ModuleChild(_) => Some(self.clone()), Self::FunctionRoot(fr) => fr.parent.get_module_scope(), Self::FunctionChild(fc) => fc.parent.get_module_scope(), } } pub fn child(&self) -> Self { match self { CompilationScope::ModuleRoot(_) | CompilationScope::ModuleChild(_) => { Self::ModuleChild(Rc::new(ModuleChildScope::new(self.clone()))) } CompilationScope::FunctionRoot(_) | CompilationScope::FunctionChild(_) => { Self::FunctionChild(Rc::new(FunctionChildScope::new(self.clone()))) } } } pub fn emit_typed_define( &self, name: &str, consts: &mut ConstantValues, dest: BasicBlock, loc: SourcePointer, ) -> ScopeResult { match self { Self::ModuleRoot(r) => r.emit_typed_define(name, consts, dest, loc), Self::FunctionRoot(r) => r.emit_typed_define(name, consts, dest, loc), Self::ModuleChild(c) => c.emit_typed_define(name, consts, dest, loc), Self::FunctionChild(c) => c.emit_typed_define(name, consts, dest, loc), } } pub fn emit_untyped_define( &self, name: &str, consts: &mut ConstantValues, dest: BasicBlock, loc: SourcePointer, ) -> ScopeResult { dest.write_opcode_and_source_info( CompilerOpcode::PushBuiltinTy(BuiltinTypeId::Any), loc.clone(), ); self.emit_typed_define(name, consts, dest.clone(), loc.clone())?; self.emit_write(name, consts, dest, loc) } pub fn emit_write( &self, name: &str, consts: &mut ConstantValues, dest: BasicBlock, loc: SourcePointer, ) -> ScopeResult { match self { Self::ModuleRoot(r) => r.emit_write(name, consts, dest, loc), Self::FunctionRoot(r) => r.emit_write(name, consts, dest, loc), Self::ModuleChild(c) => c.emit_write(name, consts, dest, loc), Self::FunctionChild(c) => c.emit_write(name, consts, dest, loc), } } pub fn emit_read( &self, name: &str, consts: &mut ConstantValues, dest: BasicBlock, loc: SourcePointer, ) -> ScopeResult { match self { Self::ModuleRoot(r) => r.emit_read(name, consts, dest, loc), Self::FunctionRoot(r) => r.emit_read(name, consts, dest, loc), Self::ModuleChild(c) => c.emit_read(name, consts, dest, loc), Self::FunctionChild(c) => c.emit_read(name, consts, dest, loc), } } fn resolve_uplevel_symbol( &self, name: &str, dest: BasicBlock, loc: SourcePointer, want_dup_on_stack: bool, ) -> ScopeResult> { match self { Self::ModuleRoot(r) => r.resolve_uplevel_symbol(name, dest, loc, want_dup_on_stack), Self::ModuleChild(c) => c.resolve_uplevel_symbol(name, dest, loc, want_dup_on_stack), Self::FunctionRoot(r) => r.resolve_uplevel_symbol(name, dest, loc, want_dup_on_stack), Self::FunctionChild(c) => c.resolve_uplevel_symbol(name, dest, loc, want_dup_on_stack), } } } ================================================ FILE: docker/release/Dockerfile ================================================ # syntax=docker/dockerfile:1 FROM ubuntu:24.04 # Build arguments for Aria version and build timestamp # To build with a specific version, use: # docker build --build-arg ARIA_VERSION= --build-arg ARIA_BUILD_TIMESTAMP= -t aria: . # Example: # docker build --build-arg ARIA_VERSION=0.9.20251220 --build-arg ARIA_BUILD_TIMESTAMP=20251220123456 -t aria:0.9.20251220 . ARG ARIA_VERSION=0.9.20251222 ARG ARIA_BUILD_TIMESTAMP=20251222174650 ARG ARIA_EXPECTED_SHA256=47cb8d9de3a2229f1a403e1c616679811f085e819c1743e263c16c2c2d001d50 ENV DEBIAN_FRONTEND=noninteractive RUN apt-get update \ && apt-get install -y --no-install-recommends ca-certificates curl tar findutils \ && rm -rf /var/lib/apt/lists/* RUN set -eux; \ url="https://github.com/arialang/aria/releases/download/v${ARIA_VERSION}/aria-${ARIA_VERSION}-x86_64-unknown-linux-gnu-${ARIA_BUILD_TIMESTAMP}.tgz"; \ mkdir -p /usr/aria; \ curl -fsSL "$url" -o /tmp/aria.tgz; \ echo "$ARIA_EXPECTED_SHA256 /tmp/aria.tgz" | sha256sum -c -; \ tar -xzf /tmp/aria.tgz -C /usr/aria; \ rm -f /tmp/aria.tgz; \ if [ ! -x /usr/aria/aria ]; then \ aria_path="$(find /usr/aria -maxdepth 4 -type f -name aria -perm -111 | head -n1 || true)"; \ if [ -n "$aria_path" ] && [ "$aria_path" != "/usr/aria/aria" ]; then \ ln -sf "$aria_path" /usr/aria/aria; \ fi; \ fi; \ test -x /usr/aria/aria; \ ln -sf /usr/aria/aria /usr/local/bin/aria CMD ["bash", "-lc", "echo 'Aria is available in your environment. Start it by running \"aria\"\n'; exec bash -i"] ================================================ FILE: docs/index.html ================================================ If you are not redirected automatically, follow this link to the new documentation site. ================================================ FILE: examples/99bottles.aria ================================================ # SPDX-License-Identifier: Apache-2.0 struct Lyrics { type func new(n: Int) { assert n > 0; return alloc(This) { .n = n, }; } func prettyprint() { val suffix_n = this.n == 1 ? "" : "s"; val suffix_n_minus_1 = this.n == 2 ? "" : "s"; return "{0} bottle{2} of beer on the wall, {0} bottle{2} of beer.\nTake one down and pass it around, {1} bottle{3} of beer on the wall.\n".format(this.n, this.n-1, suffix_n, suffix_n_minus_1); } } struct Song { type func new(n: Int) { assert n > 0; return alloc(This) { .n = n, }; } func iterator() { return this; } func next() { if this.n == 0 { return Maybe::None; } val n = this.n; this.n -= 1; return Maybe::Some(Lyrics.new(n)); } } val song = Song.new(99); for verse in song { println(verse); } ================================================ FILE: examples/add_license_marker.aria ================================================ # SPDX-License-Identifier: Apache-2.0 import File from aria.io.file; import Path from aria.io.path; import aria.iterator.mixin; val rust_license_comment="// SPDX-License-Identifier: Apache-2.0"; val aria_license_comment="# SPDX-License-Identifier: Apache-2.0"; struct Checker { type func new(ext: String, marker: String, check: Bool, exclusions: List) = alloc(This) { .ext, .marker, .check, .exclusions }; func should_exclude(path) { val path = path.prettyprint(); return this.exclusions.any(|e| => path.contains(e)); } operator()() { val glob_pattern = "**/*.{0}".format(this.ext); val glob_iterator = Path.glob(glob_pattern)!; for file in glob_iterator { if this.should_exclude(file) { continue; } val line0 = File.open(file, File.OpenMode.new().read())!.readln(); if line0 != this.marker { if this.check { println("[ERROR] file '{0}' missing license marker!".format(file)); return false; } else { println("adding license marker to {0}".format(file)); val rest_of_file = File.open(file, File.OpenMode.new().read())!.read_all(); File.open(file, File.OpenMode.new().write().truncate())!.write("{0}\n{1}".format(this.marker, rest_of_file)); } } } return true; } } func main(args) { val check = false; if args.len() == 1 && args[0] == "--check" { check = true; } val aria_checker = Checker.new("aria", aria_license_comment, check, ["target/"]); val rust_checker = Checker.new("rs", rust_license_comment, check, ["target/"]); if !aria_checker() || !rust_checker() { exit(1); } if check { println("all files have license markers"); } exit(0); } ================================================ FILE: examples/advent_of_code_2024_day1.aria ================================================ # SPDX-License-Identifier: Apache-2.0 import Zip from aria.iterator.zip; val list1 = [3,4,2,1,3,3]; val list2 = [4,3,5,3,9,3]; assert list1.len() == list2.len(); list1.quicksort(); list2.quicksort(); val z = Zip.new(list1, list2); val sum = 0; for pair in z { val distance = (pair[0] - pair[1]).abs(); sum += distance; } println("The total distance is {0}".format(sum)); ================================================ FILE: examples/advent_of_code_2024_day2.aria ================================================ # SPDX-License-Identifier: Apache-2.0 import Set from aria.structures.set; import Range from aria.range.range; enum Direction { case Increasing, case Equal, case Decreasing, } extension Direction { func hash() { match this { case Increasing => { return 6037; }, case Equal => { return 4154; }, case Decreasing => { return 7889; } } } } func get_direction(a, b) { if a > b { return Direction::Increasing; } elsif a == b { return Direction::Equal; } else { return Direction::Decreasing; } } func get_directions(nums) { val directions = Set.new(); val idx = 0; val bound = nums.len() - 2; for idx in Range.from(0).through(bound) { val a = nums[idx]; val b = nums[idx+1]; directions.set(get_direction(a,b)); } return directions; } func get_max_delta(nums) { val max_delta = -1; val idx = 0; val bound = nums.len() - 2; for idx in Range.from(0).through(bound) { val a = nums[idx]; val b = nums[idx+1]; val delta = (a-b).abs(); if delta > max_delta { max_delta = delta; } } return max_delta; } val inputs = [ [7,6,4,2,1], [1,2,7,8,9], [9,7,6,2,1], [8,6,4,4,1], [1,3,6,7,9], ]; for input in inputs { val directions = get_directions(input); if directions.len() != 1 || directions.contains(Direction::Equal) { println("Input {0} is unsafe (not always increasing/decreasing)".format(input.join())); continue; } val max_delta = get_max_delta(input); if max_delta > 3 { println("Input {0} is unsafe (levels change by more than 3)".format(input.join())); continue; } println("Input {0} is safe".format(input.join())); } ================================================ FILE: examples/advent_of_code_2024_day3.aria ================================================ # SPDX-License-Identifier: Apache-2.0 import Regex from aria.string.regex; func find_all_mul_matches(str) { val r = Regex.new("mul\\(\\d{1,3},\\d{1,3}\\)"); val ret = []; for m in r.matches(str) { ret.append(m.value); } return ret; } func main() { val input = "xmul(2,4)%&mul[3,7]!@^do_not_mul(5,5)+mul(32,64]then(mul(11,8)mul(8,5))"; val multiplications = find_all_mul_matches(input); val total = 0; for multiplication in multiplications { val operands = multiplication.replace("mul(", "").replace(")","").split(","); assert operands.len() == 2; val op1 = Int.parse(operands[0])!; val op2 = Int.parse(operands[1])!; total += op1 * op2; } println("The total value is {0}".format(total)); } ================================================ FILE: examples/command_line_args.aria ================================================ # SPDX-License-Identifier: Apache-2.0 for arg in cmdline_arguments() { println("argument = '{0}'".format(arg)); } ================================================ FILE: examples/currency.aria ================================================ # SPDX-License-Identifier: Apache-2.0 import Request from aria.network.request; import JsonValue from aria.json.parser; import Map from aria.structures.map; enum FetchResult { case Success(Map), case Error(String) } func get_rates(currency: String) { val url = "https://open.er-api.com/v6/latest/{0}".format(currency.uppercase()); val response = Request.new(url).get()?; if response.status_code == 200 { val data = JsonValue.parse(response.content)?.flatten(); match data.get("rates") { case Some(rates) => { return FetchResult::Success(rates); }, case None => { return FetchResult::Error("No rates found for {0}".format(currency)); } } } else { return FetchResult::Error("HTTP request failed with status code {0}".format(response.status_code)); } } func convert(value, target, rates) { return rates.get(target).apply(|x| => x * value); } func main() { val args = cmdline_arguments(); if args.len() != 3 { println("Usage: currency "); println("Example: currency 100 USD EUR"); return Unit::unit; } val value = Float.parse(args[0]); if value.is_Err() { println("Please provide a valid numeric value to convert."); return Unit::unit; } value = value!; val source_currency = args[1].uppercase(); val target_currency = args[2].uppercase(); val fetched_rates = get_rates(source_currency); val rates = Map.new(); match fetched_rates { case Error(e) => { println("Failed to fetch exchange rates: {0}".format(e)); return Unit::unit; } case Success(r) => { rates = r; } } val converted_value = convert(value, target_currency, rates); if converted_value.is_None() { println("Conversion rate for {0} not found.".format(target_currency)); } else { println("{0} {1} is equivalent to {2} {3}.".format(value, source_currency, converted_value.unwrap_Some(), target_currency)); } } ================================================ FILE: examples/dir.aria ================================================ # SPDX-License-Identifier: Apache-2.0 import Instant from aria.date.instant; import Path from aria.io.path; func pad(n) { if n < 10 { return "0{0}".format(n); } else { return "{0}".format(n); } } func run_over_dir(path: Path) { val files_count = 0; val dirs_count = 0; val total_size = 0; for entry in path.entries() { val mod_time = entry .modified() .unwrap_or(Instant.new_with_local_timestamp(0)); val month = pad(mod_time.month); val day = pad(mod_time.day); val year = mod_time.year; val hour = mod_time.hour; val minute = pad(mod_time.minute); val am_pm = "AM"; if hour >= 12 { am_pm = "PM"; if hour > 12 { hour = hour - 12; } } if hour == 0 { hour = 12; } val date_str = "{0}/{1}/{2}".format(month, day, year); val time_str = "{0}:{1} {2}".format(pad(hour), minute, am_pm); if entry.is_directory() { dirs_count += 1; println("{0} {1} {2}".format( date_str, time_str, entry.get_filename() ?? "" )); } else { val size = entry.size(); match size { case Err(_) => { size = 0; } case Ok(bytes) => { size = bytes; } } total_size += size; files_count += 1; val size_str = "{0}".format(size); val padding = " " * (14 - size_str.len()); println("{0} {1} {2} {3}".format( date_str, time_str, size_str, entry.get_filename() ?? "" )); } } println(""); println(" {0} File(s) {1} bytes".format(files_count, total_size)); println(" {0} Dir(s)".format(dirs_count)); } func main() { val args = cmdline_arguments(); for arg in args { val arg_path = Path.new(arg); if !arg_path.exists() || !arg_path.is_directory() { println("{0} is not a valid directory; ignoring".format(arg)); continue; } run_over_dir(arg_path); } } ================================================ FILE: examples/fibonacci.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func fibonacci(n) { if n == 0 { return 0; } elsif n == 1 { return 1; } else { return fibonacci(n-1) + fibonacci(n-2); } } println(fibonacci(28)); ================================================ FILE: examples/fibonacci_memoized.aria ================================================ # SPDX-License-Identifier: Apache-2.0 import Map from aria.structures.map; struct Fibonacci { type func new() { return alloc(This) { .cache = Map.new(){[0] = 0, [1] = 1}, }; } func eval(n) { match this.cache.get(n) { case Some(result) => { return result; } } else { val result = this.eval(n-1) + this.eval(n-2); this.cache[n] = result; return result; } } func fibonacci(n) { return this.eval(n); } } val f = Fibonacci.new(); println(f.fibonacci(28)); ================================================ FILE: examples/fizzbuzz.aria ================================================ # SPDX-License-Identifier: Apache-2.0 import Range from aria.range.range; extension Int { func is_divisible_by(n: Int) { return (this % n) == 0; } func to_fizzbuzz_string() { val div_by_3 = this.is_divisible_by(3); val div_by_5 = this.is_divisible_by(5); if div_by_3 && div_by_5 { return "FizzBuzz"; } elsif div_by_3 { return "Fizz"; } elsif div_by_5 { return "Buzz"; } else { return this; } } } for n in Range.from(1).through(20) { println("{0} -> {1}".format(n, n.to_fizzbuzz_string())); } ================================================ FILE: examples/github_user.aria ================================================ # SPDX-License-Identifier: Apache-2.0 import Request from aria.network.request; import JsonValue from aria.json.parser; val whoami = "egranata"; func main() { val request = Request.new("https://api.github.com/users/{0}".format(whoami)); request.headers["User-Agent"] = "AriaLang/1.0"; val response = request.get()!; if response.status_code == 200 { val user_data = JsonValue.parse(response.content)!.flatten(); println("User {1} has {0} public repositories.".format(user_data["public_repos"], whoami)); } else { println("Failed to fetch user data. Status: {0}".format(response.status_code)); } } ================================================ FILE: examples/hello.aria ================================================ # SPDX-License-Identifier: Apache-2.0 println('Hello World!'); ================================================ FILE: examples/parser.aria ================================================ # SPDX-License-Identifier: Apache-2.0 import Map from aria.structures.map; import aria.string.classes; enum Token { case Number(Int), case Identifier(String), case Plus, case Minus, case Star, case Slash, case LeftParen, case RightParen, case EOF, } extension Token { func prettyprint() { match this { case Number(n) => { return prettyprint(n); }, case Identifier(s) => { return s; }, case Plus => { return "+"; }, case Minus => { return "-"; }, case Star => { return "*"; }, case Slash => { return "/"; }, case LeftParen => { return "("; }, case RightParen => { return ")"; }, case EOF => { return ""; }, } } } struct Lexer { struct InvalidCharacter { type func new(c) { return alloc(This) { .c = c, }; } func prettyprint() { return "Invalid character: '{0}'".format(this.c); } } type func new(text) { return alloc(This) { .text = text, .pos = 0, }; } func current() { return this.text[this.pos]; } func eof() { return this.pos >= this.text.len(); } func advance() { this.pos += 1; } func whitespace() { while !this.eof() { val c = this.current(); if c.is_whitespace() { this.advance(); } else { break; } } } func identifier() { val id_str = ""; while !this.eof() { val c = this.current(); if !c.is_alphanumeric() { break; } else { id_str += c; this.advance(); } } return Token::Identifier(id_str); } func number() { val num_str = ""; while !this.eof() { val c = this.current(); if !c.is_digit() { break; } else { num_str += c; this.advance(); } } return Token::Number(Int.parse(num_str)!); } func next() { while !this.eof() { if this.current().is_whitespace() { this.whitespace(); } if this.current().is_digit() { return this.number(); } if this.current().is_letter() { return this.identifier(); } if this.current() == "+" { this.advance(); return Token::Plus; } if this.current() == "-" { this.advance(); return Token::Minus; } if this.current() == "*" { this.advance(); return Token::Star; } if this.current() == "/" { this.advance(); return Token::Slash; } if this.current() == "(" { this.advance(); return Token::LeftParen; } if this.current() == ")" { this.advance(); return Token::RightParen; } throw Lexer.InvalidCharacter.new(this.current()); } return Token::EOF; } } struct Ast { struct Identifier { type func new(name: String) { return alloc(This) { .name = name, }; } func prettyprint() { return "Identifier({0})".format(this.name); } func eval(identifiers) { return identifiers[this.name]; } } struct Number { type func new(v: Int) { return alloc(This) { .value = v, }; } func prettyprint() { return "Number({0})".format(this.value); } func eval(_) { return this.value; } } struct BinaryOperation { enum Operator { case Add, case Sub, case Mul, case Div, } } } extension Ast.BinaryOperation { type func new(left, right, op: Ast.BinaryOperation.Operator) { return alloc(This) { .left = left, .op = op, .right = right, }; } func prettyprint() { return "BinOp(({0}) {1} ({2}))".format(this.left, this.op, this.right); } func eval(identifiers) { val left = this.left.eval(identifiers); val right = this.right.eval(identifiers); match this.op { case Add => { return left + right; }, case Sub => { return left - right; }, case Mul => { return left * right; }, case Div => { return left / right; }, } else { assert(false); } } } extension Ast.BinaryOperation.Operator { type func from(src: Token) { match src { case Plus => { return This::Add; }, case Minus => { return This::Sub; }, case Star => { return This::Mul; }, case Slash => { return This::Div; }, } else { assert(false); } } func prettyprint() { match this { case Add => { return "+"; }, case Sub => { return "-"; }, case Mul => { return "*"; }, case Div => { return "/"; }, } } } struct Parser { struct UnexpectedToken { func prettyprint() { return "Unexpected token encountered"; } } type func new(lexer: Lexer) { return alloc(This) { .lexer = lexer, .current_token = lexer.next(), }; } func eat(f) { if f(this.current_token) { this.current_token = this.lexer.next(); return true; } else { return false; } } func factor() { val token = this.current_token; if this.eat(|t| => t.is_Number()) { return Ast.Number.new(token.unwrap_Number()); } elsif this.eat(|t| => t.is_LeftParen()) { val node = this.expr(); assert (this.eat(|t| => t.is_RightParen())); return node; } elsif this.eat(|t| => t.is_Identifier()) { return Ast.Identifier.new(token.unwrap_Identifier()); } else { throw alloc(Parser.UnexpectedToken); } } func term() { val node = this.factor(); while true { val op = this.current_token; if this.eat(|t| => t.is_Star() || t.is_Slash()) { op = Ast.BinaryOperation.Operator.from(op); node = Ast.BinaryOperation.new(node, this.factor(), op); } else { return node; } } } func expr() { val node = this.term(); while true { val op = this.current_token; if this.eat(|t| => t.is_Plus() || t.is_Minus()) { op = Ast.BinaryOperation.Operator.from(op); node = Ast.BinaryOperation.new(node, this.term(), op); } else { return node; } } } func parse() { return this.expr(); } } func main() { val identifiers = Map.new() { ["answer"] = 42, }; val input = "answer + 4 * (5 - 7 / 2)"; val lxr = Lexer.new(input); val parser = Parser.new(Lexer.new(input)); val ast = parser.parse(); println("{0} -> {1}".format(ast, ast.eval(identifiers))); } ================================================ FILE: examples/peano.aria ================================================ # SPDX-License-Identifier: Apache-2.0 enum Peano { case Zero, case Succ(Peano), } extension Peano { func prettyprint() { match this { case Zero => { return ""; }, case Succ(x) => { return "+" + x.prettyprint(); }, } } func double() { match this { case Zero => { return Peano::Zero; }, case Succ(x) => { return Peano::Succ(Peano::Succ(x.double())); }, } } func quadruple() { return this.double().double(); } func succ() { return Peano::Succ(this); } } val three = Peano::Zero.succ().succ().succ(); val twelve = three.quadruple(); println("{0}".format(twelve)); ================================================ FILE: examples/pi.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func calc_pi() { val lasts = 0; val t = 3.0f; val s = 3; val n = 1; val na = 0; val d = 0; val da = 24; while s != lasts { lasts = s; n = n + na; na = na + 8; d = d + da; da = da + 32; t = (t * n) / d; s = s + t; } return s; } println("pi = {0}".format(calc_pi())); ================================================ FILE: examples/sieve.aria ================================================ # SPDX-License-Identifier: Apache-2.0 # Based on https://github.com/PlummersSoftwareLLC/Primes/blob/drag-race/PrimeWren/solution_1/primes.wren import Map from aria.structures.map; val DICT = Map.new() { [10] = 4, [100] = 25, [1000] = 168, [10000] = 1229, [100000] = 9592, [1000000] = 78498, [10000000] = 664579, [100000000] = 5761455, [1000000000] = 50847534, [10000000000] = 455052511, }; extension Int { func sqrt() { val x = this; val y = (x + 1) / 2; while y < x { x = y; y = (x + this / x) / 2; } return x; } } struct Sieve { type func new(size: Int) = alloc(This) { .size, .bits = List.filled(false, size), }; func run() { val bits = this.bits; val size = this.size; val factor = 3; val q = size.sqrt(); while factor <= q { val num = factor; while num < size { if !bits[num] { factor = num; break; } num += 2; } val num2 = factor * factor; while num2 < size { bits[num2] = true; num2 += factor * 2; } factor += 2; } } func count_primes() { val count = 1; val num = 3; while num < this.size { if !this.bits[num] { count += 1; } num += 2; } return count; } func validate() = DICT.contains(this.size) && DICT[this.size] == this.count_primes(); func print_results(show, duration, passes) { if show { print("2, "); val count = 1; val num = 3; while num < this.size { if !this.bits[num] { "{0}, ".printf(num); count += 1; } num += 2; } println(""); } assert this.validate(); "egranata;{0};{1:.2};1;algorithm=base,faithful=yes\n".printf(passes, duration/1000.0); } } val passes = 0; val start_time = now(); while true { val sieve = Sieve.new(1000000); sieve.run(); passes += 1; val duration = now() - start_time; if duration >= 5000 { sieve.print_results(false, duration, passes); break; } } ================================================ FILE: examples/string_escapes.aria ================================================ # SPDX-License-Identifier: Apache-2.0 import Color, ColorScheme from aria.system.coloring; println("Hello {0}, this is an {1} {2}".format( "world".red(), "example".blue().white_bg(), "program".with_bold() )); val color_scheme = ColorScheme.new().with_foreground_color(Color::BrightMagenta).with_background_color(Color::BrightWhite).with_bold(true); println("This is yet another example string".with_style(color_scheme)); println("And this one is {0} unformatted.".format("mostly".with_foreground_color(Color::RGB(Color.RGB.new(255,165,0))))); println("And this one uses {0} background color".format("hexadecimal".with_background_color(Color::RGB(Color.RGB.new_with_hex_string("#c3e91c")!)))); ================================================ FILE: lib/aria/core/arity.aria ================================================ # SPDX-License-Identifier: Apache-2.0 flag: no_std; struct Arity { enum UpperBound { case Bounded(Int), case Varargs, func prettyprint() { match this { case Bounded(n) => { return "up to {0}".format(n); }, case Varargs => { return "varargs"; }, } } } # this type is generally allocated by the Aria VM directly, not by user code # new() is not going to be called type func new() { return alloc(This) { .min = 0, .max = This.UpperBound::Varargs, .has_receiver = false, }; } func prettyprint() { return "min: {0} (implicit receiver: {2}), max: {1}".format(this.min, this.max, this.has_receiver); } func is_Varargs() { return this.max.is_Varargs(); } func can_call_with_argc(argc: Int) { if argc < this.min { return false; } match this.max { case Bounded(n) => { return argc <= n; }, case Varargs => { return true; }, } } } ================================================ FILE: lib/aria/core/bool.aria ================================================ # SPDX-License-Identifier: Apache-2.0 flag: no_std; extension Bool { func hash() { return this ? 4093 : 7877; } } ================================================ FILE: lib/aria/core/box.aria ================================================ # SPDX-License-Identifier: Apache-2.0 flag: no_std; func Box() { struct Box {} return alloc(Box); } ================================================ FILE: lib/aria/core/builtin.aria ================================================ # SPDX-License-Identifier: Apache-2.0 flag: no_std; import aria.core.runtime_error; import aria.core.arity; import aria.core.bool; import Box from aria.core.box; import aria.core.float; import aria.core.int; import aria.core.list; import aria.core.maybe; import aria.core.result; import aria.core.string; import Nothing from aria.core.nothing; import aria.core.unimplemented; import aria.core.unit; ================================================ FILE: lib/aria/core/float.aria ================================================ # SPDX-License-Identifier: Apache-2.0 flag: no_std; func char_to_int(c: String) { match c { == "0" => { return 0; }, == "1" => { return 1; }, == "2" => { return 2; }, == "3" => { return 3; }, == "4" => { return 4; }, == "5" => { return 5; }, == "6" => { return 6; }, == "7" => { return 7; }, == "8" => { return 8; }, == "9" => { return 9; }, } else { return Maybe::None; } } extension Float { type val pi = 3.14159265358979323846f; type val e = 2.71828182845904523536f; type val π = Float.pi; type val phi = 1.618033988749895f; type val φ = Float.phi; func abs() { return this >= 0 ? this : -this; } struct DomainError { type func new(msg: String) { return alloc(This) { .msg = msg }; } instance func prettyprint() { return "floating-point domain error: {0}".format(this.msg); } } func sqrt() { match this { == 0 => { return 0.0f; }, == 1 => { return 1.0f; }, < 0 => { throw Float.DomainError.new("square root undefined for negative values"); }, } val ε = 0.000000000001f; val guess = this / 2; val i = 0; val n = 1000; while i < n { i = i + 1; val next_guess = (guess + this / guess) / 2; if (next_guess - guess).abs() < ε { return next_guess; } else { guess = next_guess; } } return guess; } type func parse(s: String) { if s.len() == 0 || s == "-" || s == "." { return Result::Err("invalid float format"); } val ret = 0.0f; val i = 0; val sign = 1; val decimal_found = false; val decimal_factor = 0.1f; val s: List = s.chars(); if s[0] == "-" { i = 1; sign = -1; } while i < s.len() { val chr = s[i]; if chr == "e" || chr == "E" { break; } if chr == "." { if decimal_found { return Result::Err("duplicate decimal point"); } decimal_found = true; } else { val digit = char_to_int(chr); if digit == Maybe::None { return Result::Err("invalid float digit: " + chr); } if decimal_found { ret = ret + digit * decimal_factor; decimal_factor = decimal_factor / 10; } else { ret = ret * 10 + digit; } } i += 1; } ret = sign * ret; if i < s.len() { i += 1; if i >= s.len() { return Result::Err("missing exponent"); } val exp_sign = 1; if s[i] == "-" { exp_sign = -1; i += 1; } elsif s[i] == "+" { i += 1; } if i >= s.len() { return Result::Err("missing exponent digits"); } val exp_value = 0; while i < s.len() { val digit = char_to_int(s[i]); if digit == Maybe::None { return Result::Err("invalid float exponent digit: " + s[i]); } exp_value = exp_value * 10 + digit; i += 1; } val exp = exp_sign * exp_value; val factor = 1.0f; val j = 0; val limit = exp < 0 ? -exp : exp; while j < limit { factor = factor * 10; j += 1; } ret = exp < 0 ? ret / factor : ret * factor; } return Result::Ok(ret); } } ================================================ FILE: lib/aria/core/int.aria ================================================ # SPDX-License-Identifier: Apache-2.0 flag: no_std; extension Int { func hash() { return this; } func abs() { return this >= 0 ? this : -this; } func float() { return this + 0.0f; } type func parse(s: String) { val index: Int = 0; val sign: Int = 1; if s.has_prefix("-") { sign = -1; index = 1; } elsif s.has_prefix("+") { index = 1; } if index > 0 { s = s.substring(index, s.len()); index = 0; } val base: Int = 10; if s.has_prefix("0x") || s.has_prefix("0X") { index = 2; base = 16; } elsif s.has_prefix("0b") || s.has_prefix("0B") { index = 2; base = 2; } elsif s.has_prefix("0o") || s.has_prefix("0O") { index = 2; base = 8; } if index > 0 { s = s.substring(index, s.len()); index = 0; } if s == "" { return Result::Err("empty integer string"); } match Int.parse_radix(s, base) { case Ok(value) => { return Result::Ok(sign * value); }, case Err(e) => { return Result::Err(e); }, } } type func parse_radix(s: String, base: Int) { if base < 2 || base > 36 { return Result::Err("invalid radix"); } if s.len() == 0 { return Result::Err("empty integer string"); } val s: List = s.chars(); val ret: Int = 0; val i: Int = 0; while i < s.len() { val chr = s[i]; val digit = chr.encoding(); match digit { >= 48 and <= 57 => { # decimal digits if (digit - 48) >= base { return Result::Err("invalid integer digit: " + chr); } digit = digit - 48; }, >= 65 and <= 90 => { # uppercase letters if (digit - 65 + 10) >= base { return Result::Err("invalid integer digit: " + chr); } digit = digit - 65 + 10; }, >= 97 and <= 122 => { # lowercase letters if (digit - 97 + 10) >= base { return Result::Err("invalid integer digit: " + chr); } digit = digit - 97 + 10; }, } else { return Result::Err("invalid integer digit: " + chr); } ret = ret * base + digit; i += 1; } return Result::Ok(ret); } } extension Int { struct DomainError { type func new(msg: String) { return alloc(This) { .msg = msg }; } instance func prettyprint() { return "integer domain error: {0}".format(this.msg); } } } ================================================ FILE: lib/aria/core/list.aria ================================================ # SPDX-License-Identifier: Apache-2.0 flag: no_std; import Box from aria.core.box; extension List { func repeat(n: Int) { if n <= 0 { return []; } if n == 1 { return this; } val ret = this; while n > 1 { ret = ret + this; n -= 1; } return ret; } operator *(rhs: Int) { return this.repeat(rhs); } reverse operator *(lhs: Int) { return this.repeat(lhs); } func prettyprint() { return "[" + this.join() + "]"; } func join(sep=", ") = sep.join(this); func contains(x) { for item in this { if item == x { return true; } } return false; } type func from_function(f, n: Int) { if n <= 0 { return []; } val ret = List.new_with_capacity(n); val i = 0; while i < n { ret.append(f(i)); i = i + 1; } return ret; } type func filled(x, n: Int) { if n <= 0 { return []; } val ret = List.new_with_capacity(n); val i = 0; while i < n { ret.append(x); i = i + 1; } return ret; } operator ==(rhs: List) { if rhs.len() != this.len() { return false; } val idx = 0; while idx < this.len() { val this_idx = this[idx]; val rhs_idx = rhs[idx]; if this_idx != rhs_idx { return false; } idx += 1; } return true; } operator +(rhs: List) { val ret = []; for item in this { ret.append(item); } for item in rhs { ret.append(item); } return ret; } struct ListIterator { type func new(l: List) { return alloc(This){ .list = l, .len = l.len(), .index = 0, }; } func next() { if this.index == this.len { return Maybe::None; } else { val v = this.list[this.index]; this.index = this.index + 1; return Maybe::Some(v); } } } func iterator() { return List.ListIterator.new(this); } func quicksort_with_comparator(f) { this.qks_helper(0, this.len() - 1, f); } func quicksort() { this.quicksort_with_comparator(|x,y| => x < y); } func qks_helper(left, right, f) { if left >= right { return 0; } val pivotIndex = this.partition(left, right, f); this.qks_helper(left, pivotIndex - 1, f); this.qks_helper(pivotIndex + 1, right, f); } func partition(left, right, f) { val pivot = this[right]; val i = left; val j = left; while j < right { if f(this[j], pivot) { val temp = this[i]; this[i] = this[j]; this[j] = temp; i += 1; } j += 1; } val temp = this[i]; this[i] = this[right]; this[right] = temp; return i; } func binary_search(target) { return this.bs_helper(target, 0, this.len() - 1); } func bs_helper(target, left, right) { if left > right { return Maybe::None; } val mid = (left + right) / 2; if this[mid] == target { return Maybe::Some(mid); } elsif this[mid] < target { return this.bs_helper(target, mid + 1, right); } else { return this.bs_helper(target, left, mid - 1); } } } ================================================ FILE: lib/aria/core/maybe.aria ================================================ # SPDX-License-Identifier: Apache-2.0 flag: no_std; extension Maybe { func apply(f) { match this { case Some(x) => { return Maybe::Some(f(x)); }, case None => { return Maybe::None; } } } func hash() { match this { case Some(x) => { return x.hash(); }, } else { return 0; } } func unwrap_or(els) = this ?? els; func prettyprint() { match this { case None => { return "None"; }, case Some(value) => { return "Some({0})".format(value); } } } # these helpers are built by the Aria compiler, but since Maybe is a builtin type we need to provide them here func is_Some() { match this { case Some(_) => { return true; }, } else { return false; } } func is_None() { match this { case None => { return true; }, } else { return false; } } func unwrap_Some() { match this { case Some(value) => { return value; }, } else { assert false; } } } ================================================ FILE: lib/aria/core/nothing.aria ================================================ # SPDX-License-Identifier: Apache-2.0 flag: no_std; enum Nothing {} ================================================ FILE: lib/aria/core/result.aria ================================================ # SPDX-License-Identifier: Apache-2.0 flag: no_std; func ok(v) { return Result::Ok(v); } func err(e) { return Result::Err(e); } extension Result { # these helpers are built by the Aria compiler, but since Result is a builtin type we need to provide them here func is_Ok() { match this { case Ok(_) => { return true; }, } else { return false; } } func is_Err() { match this { case Err(_) => { return true; }, } else { return false; } } func unwrap_Ok() { match this { case Ok(value) => { return value; }, } else { assert false; } } func unwrap_Err() { match this { case Err(value) => { return value; }, } else { assert false; } } } extension Result { func apply(f) { match this { case Ok(x) => { return Result::Ok(f(x)); }, case Err(e) => { return Result::Err(e); } } } type func new_with_maybe(m: Maybe) { match m { case Some(v) => { return ok(v); } case None => { return err(Unit.new()); } } } type func new_with_try(f) { try { return ok(f()); } catch e { return err(e); } } func or_throw() { match this { case Ok(v) => { return v; } case Err(e) => { throw e; } } } func prettyprint() { match this { case Ok(v) => { return "Ok({0})".format(v); }, case Err(e) => { return "Err({0})".format(e); } } } func apply(f) { match this { case Ok(v) => { return Result::Ok(f(v)); }, case Err(e) => { return Result::Err(e); } } } func unwrap_or(els) = this ?? els; func hash() { match this { case Ok(v) => { return v.hash(); }, case Err(e) => { return e.hash(); } } } } extension Maybe { type func new_with_result(r: Result) { match r { case Ok(v) => { return Maybe::Some(v); } case Err(_) => { return Maybe::None; } } } } extension Result { # what this does: # if the object is a participant in the "try protocol", it will call _op_try_view() # if the result is a Maybe or a Result, it will return that object up to the VM; # if the result is something else, or the object does not implement the protocol, it will return Result::Ok(x) # the TRY_UNWRAP_PROTOCOL bytecode will then inspect this value and: # if it's a Result::Ok(x), it will push "x" onto the stack; # if it's a Result::Err(e), it will RETURN Err(e) from the current function # for anything else, it will raise a type error type func try_unwrap_protocol(x) { func process_value(x) { match x { isa Maybe => { return x; }, isa Result => { return x; }, } else { return Result::Ok(x); } } if hasattr(x, "_op_try_view") { return process_value(x._op_try_view()); } else { return process_value(x); } } } extension Result { func _op_try_view() = this; } extension Maybe { func _op_try_view() = this; } ================================================ FILE: lib/aria/core/runtime_error.aria ================================================ # SPDX-License-Identifier: Apache-2.0 flag: no_std; extension RuntimeError.ArgcMismatch { func prettyprint() = "argument count mismatch, {0} expected, {1} actual".format(this.expected, this.actual); } extension RuntimeError { # helpers that are normally provided by the Aria compiler but we must define them here for a builtin type func is_DivisionByZero() { match this { case DivisionByZero => { return true; }, } else { return false; } } func is_EnumWithoutPayload() { match this { case EnumWithoutPayload => { return true; }, } else { return false; } } func is_IndexOutOfBounds() { match this { case IndexOutOfBounds(_) => { return true; }, } else { return false; } } func unwrap_IndexOutOfBounds() { match this { case IndexOutOfBounds(x) => { return x; }, } else { assert false; } } func is_MismatchedArgumentCount() { match this { case MismatchedArgumentCount(_) => { return true; }, } else { return false; } } func unwrap_MismatchedArgumentCount() { match this { case MismatchedArgumentCount(x) => { return x; }, } else { assert false; } } func is_NoSuchCase() { match this { case NoSuchCase(_) => { return true; }, } else { return false; } } func unwrap_NoSuchCase() { match this { case NoSuchCase(x) => { return x; }, } else { assert false; } } func is_NoSuchIdentifier() { match this { case NoSuchIdentifier(_) => { return true; }, } else { return false; } } func unwrap_NoSuchIdentifier() { match this { case NoSuchIdentifier(x) => { return x; }, } else { assert false; } } func is_OperationFailed() { match this { case OperationFailed(_) => { return true; }, } else { return false; } } func unwrap_OperationFailed() { match this { case OperationFailed(x) => { return x; }, } else { assert false; } } func is_UnexpectedType() { match this { case UnexpectedType => { return true; }, } else { return false; } } } extension RuntimeError { func prettyprint() { match this { case DivisionByZero => { return "division by zero"; }, case EnumWithoutPayload => { return "enum case has no payload"; }, case IndexOutOfBounds(n) => { return "index {0} is out of bounds".format(n); }, case MismatchedArgumentCount(m) => { return m.prettyprint(); }, case NoSuchCase(s) => { return "case '{0}' not found".format(s); }, case NoSuchIdentifier(s) => { return "identifier '{0}' not found".format(s); }, case OperationFailed(s) => { return "operation failed: {0}".format(s); } case UnexpectedType => { return "unexpected type"; } } return "unprintable error"; } } ================================================ FILE: lib/aria/core/string.aria ================================================ # SPDX-License-Identifier: Apache-2.0 flag: no_std; # this is conceptually the same as what's in aria.string.classes # but we don't want to import from the core builtin library, so # the duplication of this rather trivial code is acceptable func is_digit(s: String) { match s { == "0" => { return true; }, == "1" => { return true; }, == "2" => { return true; }, == "3" => { return true; }, == "4" => { return true; }, == "5" => { return true; }, == "6" => { return true; }, == "7" => { return true; }, == "8" => { return true; }, == "9" => { return true; }, } else { return false; } } extension String { operator[](index: Int) { if index < 0 { index += this.len(); } return this._get_at(index); } } extension String { struct EncodingError { type func new(msg: String) { return alloc(This) { .msg = msg }; } instance func prettyprint() { return "encoding error: {0}".format(this.msg); } } func repeat(n: Int) { if n <= 0 { return ""; } if n == 1 { return this; } val ret = this; while n > 1 { ret = ret + this; n -= 1; } return ret; } operator *(rhs: Int) { return this.repeat(rhs); } reverse operator *(lhs: Int) { return this.repeat(lhs); } func trim() { return this.trim_head().trim_tail(); } func prettyprint() { return this; } func format(...) { return this._format_impl(varargs); } func _format_impl(varargs) { val ret = ""; val chars = this.chars(); val len = this.len(); val idx = 0; while idx < len { val c = chars[idx]; if c == "{" && idx + 1 < len && chars[idx + 1] == "{" { ret += "{"; idx += 2; continue; } if c == "}" && idx + 1 < len && chars[idx + 1] == "}" { ret += "}"; idx += 2; continue; } if c == "{" { idx += 1; val num_str = ""; val style_str = ""; val has_style = false; val found_closing_brace = false; while idx < len { val c = chars[idx]; if c == "}" { idx += 1; found_closing_brace = true; break; } elsif c == ":" && !has_style { has_style = true; idx += 1; } elsif !has_style { num_str += c; idx += 1; } else { style_str += c; idx += 1; } } if !found_closing_brace { if has_style { ret += "{" + num_str + ":" + style_str; } else { ret += "{" + num_str; } continue; } match Int.parse(num_str) { case Ok(i) => { if i >= varargs.len() { if has_style { ret += "{" + num_str + ":" + style_str + "}"; } else { ret += "{" + num_str + "}"; } } else { val arg = varargs[i]; if hasattr(arg, "prettyprint") { val pp_arity = arity(arg.prettyprint); val accepts_1 = pp_arity.can_call_with_argc(1); val accepts_0 = pp_arity.can_call_with_argc(0); # Decision logic for calling prettyprint: # - If prettyprint(x) is a valid signature and no style string is provided, # we would prefer to call prettyprint() with no arguments. # - However, if calling with no arguments would fail, use the 1-argument version # with an empty style string if that's the only allowed call. if (has_style && accepts_1) || (!has_style && accepts_1 && !accepts_0) { ret += arg.prettyprint(style_str); } elsif accepts_0 { ret += arg.prettyprint(); } else { ret += prettyprint(arg); } } else { ret += prettyprint(arg); } } } } else { if has_style { ret += "{" + num_str + ":" + style_str + "}"; } else { ret += "{" + num_str + "}"; } } continue; } ret += c; idx += 1; } return ret; } func substring(from: Int, to: Int) { val ret = ""; while from < this.len() { if from > to { break; } ret = ret + this[from]; from += 1; } return ret; } func hash() { val ret = 0; for b in this.bytes() { ret = 31 * ret + b; } return ret; } func join(iter) { val ret = ""; val first = true; for item in iter { val item = prettyprint(item); if !first { ret += this; } ret += item; first = false; } return ret; } func remove(pattern) = this.replace(pattern, ""); } extension String { func printf(...) { val s = this._format_impl(varargs); print(s); } } ================================================ FILE: lib/aria/core/unimplemented.aria ================================================ # SPDX-License-Identifier: Apache-2.0 flag: no_std; extension Unimplemented { func prettyprint() = "unimplemented"; operator ==(rhs) = rhs isa Unimplemented; } ================================================ FILE: lib/aria/core/unit.aria ================================================ # SPDX-License-Identifier: Apache-2.0 flag: no_std; extension Unit { type func new() = Unit::unit; func prettyprint() = "unit"; operator ==(rhs) = rhs isa Unit; # this is normally provided by the compiler, but since Unit is a builtin type we need to provide it here func is_unit() = true; } ================================================ FILE: lib/aria/date/instant.aria ================================================ # SPDX-License-Identifier: Apache-2.0 import Range from aria.range.range; import tz_info from aria.date.timezone; import SipHasher from aria.structures.hash.algo.sip; func is_leap_year(year: Int) { return (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0); } func leap_years_since_1970(year: Int) { return ((year - 1969) / 4) - ((year - 1901) / 100) + ((year - 1601) / 400); } func leap_years_through_end_of(year: Int) { return (year / 4) - (year / 100) + (year / 400); } val SECONDS_PER_MINUTE = 60; val SECONDS_PER_HOUR = 3600; val SECONDS_PER_DAY = 86400; val DAYS_PER_YEAR = 365; val EPOCH_YEAR = 1970; val CUMULATIVE_DAYS = [0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365]; val LEAP_CUMULATIVE_DAYS = [0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366]; val MONTH_NAMES = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]; func offset_to_string(offset_minutes) { match offset_minutes { == 0 => { return ""; } < 0 => { offset_minutes = -offset_minutes; } } val hours = offset_minutes / 60; val minutes = offset_minutes % 60; val sign = offset_minutes >= 0 ? "+" : "-"; return "{0}{1:2}:{2:2}".format(sign, hours, minutes); } func split_ms_floor(timestamp_ms: Int) { val sec = timestamp_ms / 1000; val ms = timestamp_ms % 1000; if ms < 0 { return [sec - 1, ms + 1000]; } else { return [sec, ms]; } } struct Instant { type func _before_epoch(timestamp_ms) { val parts = split_ms_floor(timestamp_ms); val timestamp_s = parts[0]; val millisecond = parts[1]; val days = timestamp_s / SECONDS_PER_DAY; val rem = timestamp_s % SECONDS_PER_DAY; while rem < 0 { rem += SECONDS_PER_DAY; days -= 1; } while rem >= SECONDS_PER_DAY { rem -= SECONDS_PER_DAY; days += 1; } val hour = rem / SECONDS_PER_HOUR; rem %= SECONDS_PER_HOUR; val minute = rem / 60; val second = rem % 60; val year = 1970; while true { if days >= 0 { if is_leap_year(year) { if days < 366 { break; } } else { if days < 365 { break; } } } val yg = year + days / 365; if days % 365 < 0 { yg -= 1; } days -= ((yg - year) * 365 + leap_years_through_end_of(yg - 1) - leap_years_through_end_of(year - 1)); year = yg; } val months = is_leap_year(year) ? LEAP_CUMULATIVE_DAYS : CUMULATIVE_DAYS; val month = 1; for i in Range.from(1).through(12) { if days < months[i] { month = i; break; } } val day = (days - months[month - 1]) + 1; return alloc(This) { .year, .month, .day, .hour, .minute, .second, .millisecond, }; } type func _after_epoch(timestamp_ms) { val total_seconds = timestamp_ms / 1000; val year = EPOCH_YEAR + (total_seconds / (DAYS_PER_YEAR * SECONDS_PER_DAY)); while true { val days_since_epoch = (year - EPOCH_YEAR) * 365 + leap_years_since_1970(year); val seconds_since_epoch = days_since_epoch * SECONDS_PER_DAY; if total_seconds >= seconds_since_epoch { break; } year -= 1; } val day_of_year = (total_seconds / SECONDS_PER_DAY) - ((year - EPOCH_YEAR) * 365 + leap_years_since_1970(year)); val months = CUMULATIVE_DAYS; if is_leap_year(year) { months = LEAP_CUMULATIVE_DAYS; } val month = 12; for i in Range.from(1).through(11) { if day_of_year < months[i] { month = i; break; } } val day = (day_of_year - months[month - 1]) + 1; val remaining_seconds = total_seconds % SECONDS_PER_DAY; val hour = remaining_seconds / SECONDS_PER_HOUR; remaining_seconds %= SECONDS_PER_HOUR; val minute = remaining_seconds / SECONDS_PER_MINUTE; val second = remaining_seconds % SECONDS_PER_MINUTE; return alloc(This) { .year = year, .month = month, .day = day, .hour = hour, .minute = minute, .second = second, .millisecond = timestamp_ms % 1000, }; } type func new_with_utc_timestamp(timestamp_ms) { return This.new_with_timestamp_and_offset(timestamp_ms, 0); } type func new_with_timestamp_and_offset(timestamp_ms, offset_minutes) { val offset_ms = offset_minutes * SECONDS_PER_MINUTE * 1000; val actual_timestamp_ms = timestamp_ms + offset_ms; val i = (actual_timestamp_ms >= 0 ? Instant._after_epoch(actual_timestamp_ms) : Instant._before_epoch(actual_timestamp_ms)){ .utc_timestamp_ms = timestamp_ms, .offset_minutes, }; return i; } type func new_with_local_timestamp(timestamp_ms) { val tz_offset = tz_info()[0]; val offset_ms = tz_offset * SECONDS_PER_MINUTE * 1000; return Instant.new_with_timestamp_and_offset(timestamp_ms, tz_offset); } type func now() { val tz_offset = tz_info()[0]; return Instant.new_with_timestamp_and_offset(now(), tz_offset); } instance func with_timezone_offset(offset_minutes) { return Instant.new_with_timestamp_and_offset(this.utc_timestamp_ms, offset_minutes); } instance func prettyprint() { return "{0} {1} {2} {3:2}:{4:2}:{5:2}.{6:3}{7}".format( MONTH_NAMES[this.month - 1], this.day, this.year, this.hour, this.minute, this.second, this.millisecond, offset_to_string(this.offset_minutes) ); } func hash() { val hasher = SipHasher.new(0x0706050403020100, 0x0f0e0d0c0b0a0908); hasher.write(this.utc_timestamp_ms); hasher.write(this.offset_minutes); return hasher.finish(); } operator == (other: Instant) { return this.utc_timestamp_ms == other.utc_timestamp_ms && this.offset_minutes == other.offset_minutes; } } ================================================ FILE: lib/aria/date/timezone.aria ================================================ # SPDX-License-Identifier: Apache-2.0 flag: uses_dylib("aria_timezone"); ================================================ FILE: lib/aria/io/file.aria ================================================ # SPDX-License-Identifier: Apache-2.0 flag: uses_dylib("aria_file"); import guard from aria.utils.guard; import aria.io.path; struct File { struct IOError { type func new(message: String) { return alloc(This) { .message = message }; } instance func prettyprint() { return "IO error: {0}".format(this.message); } } func guard_exit() { this.close(); } func close() { this._close(); } # the values here must be kept in sync with native-libs/file struct OpenMode { type func new() { return alloc(This) { .mode = 0, }; } func read() { this.mode = this.mode | 1; return this; } func write() { this.mode = this.mode | 2; return this; } func append() { this.mode = this.mode | 4; return this; } func truncate() { this.mode = this.mode | 8; return this; } func create() { this.mode = this.mode | 16; return this; } } type func open(path, mode: File.OpenMode) { if path isa aria.io.path.Path { path = path.prettyprint(); } return File._new(path, mode.mode); } func read_all() { return this._read_all(); } func read(n: Int) { val buffer = this._read_count(n); return String.new_with_bytes(buffer); } func write(s) { this._write_str(s); } func try_readln() { val buffer = []; val c = 0; try { c = this._read_count(1); } catch e { return Maybe::None; } if c[0] == 10 { return Maybe::Some(""); } while true { buffer.append(c[0]); try { c = this._read_count(1); } catch e { break; } if c[0] == 10 { break; } } return Maybe::Some(String.new_with_bytes(buffer)); } # this is slow! func readln() { val maybe_line = this.try_readln(); return maybe_line ?? ""; } func writeln(s) { this.write(s); this.write("\n"); } func get_position() { return this._getpos(); } func set_position(offset: Int) { this._setpos(offset); } func len() { return this._getsize(); } enum SeekMode { case Start(Int), case Current(Int), case End(Int), } func seek(mode: File.SeekMode) { match mode { case Start(offset) => { return this.set_position(offset); }, case Current(offset) => { return this.set_position(this.get_position() + offset); }, case End(offset) => { return this.set_position(this.len() + offset); }, } } func flush() { this._flush(); } func lines() { return FileLineIterator.new(this); } } struct FileLineIterator { type func new(file) { return alloc(This) { .file = file, }; } func iterator() { return this; } func next() { return this.file.try_readln(); } } extension aria.io.path.Path { func read() { return guard(File.open(this.prettyprint(), File.OpenMode.new().read())).do(|file| => { return file.read_all(); }); } func write(text) { guard(File.open(this.prettyprint(), File.OpenMode.new().write().truncate())).do(|file| => { file.write(text); }); } } ================================================ FILE: lib/aria/io/path.aria ================================================ # SPDX-License-Identifier: Apache-2.0 flag: uses_dylib("aria_path"); import aria.date.instant; import Iterator from aria.iterator.mixin; struct Path { struct Error { type func new(msg) = alloc(This) {.msg}; func prettyprint() { return "path error: {0}".format(this.msg); } } struct Iterator { func iterator() { return this; } include Iterator } type func new_with_current_directory() { return This._cwd(); } type func new_with_environment_variable(var) { return getenv(var).apply(|p| => { return This.new(p); }); } type func new(s: String) { return This._new(s); } type func glob(pattern: String) { return This._glob(pattern); } func append(rhs: String|Path) { if rhs isa String { this._append(rhs); } elsif rhs isa Path { this._append(rhs.prettyprint()); } return this; } operator /(rhs: String|Path) { return Path.new(this.prettyprint()).append(rhs); } func parent() { return Path.new(this.prettyprint()).pop(); } func created() { match this._when_created() { case Ok(val) => { return Result::Ok(aria.date.instant.Instant.new_with_local_timestamp(val)); } case Err(err) => { return Result::Err(err); } }; } func accessed() { match this._when_accessed() { case Ok(val) => { return Result::Ok(aria.date.instant.Instant.new_with_local_timestamp(val)); } case Err(err) => { return Result::Err(err); } }; } func modified() { match this._when_modified() { case Ok(val) => { return Result::Ok(aria.date.instant.Instant.new_with_local_timestamp(val)); } case Err(err) => { return Result::Err(err); } }; } # we could use the builtin _copy, except for type validation func copy_to(other: Path) { this._copy(other); } func hash() { return this.prettyprint().hash(); } } ================================================ FILE: lib/aria/iterator/enumerate.aria ================================================ # SPDX-License-Identifier: Apache-2.0 struct Enumerate { type func new(iter) { if hasattr(iter, "iterator") { iter = iter.iterator(); } return alloc(This) { .iter = iter, .index = 0, }; } func iterator() { return this; } func next() { val iter_next = this.iter.next(); match iter_next { case None => { return Maybe::None; }, case Some(v) => { val next = Maybe::Some(Box(){ .index = this.index, .value = v, }); this.index += 1; return next; }, } } } ================================================ FILE: lib/aria/iterator/mixin.aria ================================================ # SPDX-License-Identifier: Apache-2.0 import ok, err from aria.core.result; struct FilteringIterator { type func new(i, f) { return alloc(This){ .it = i, .clause = f, }; } func next() { while true { val nv = this.it.next(); match nv { case Some(x) => { if this.clause(x) { return Maybe::Some(x); } else { continue; } }, case None => { return Maybe::None; } } } } } struct MappingIterator { type func new(i, f) { return alloc(This){ .it = i, .clause = f, }; } func next() { while true { val nv = this.it.next(); match nv { case None => { return Maybe::None; }, case Some(x) => { return Maybe::Some(this.clause(x)); } } } } } struct CountReducer { type func new() = alloc(This) {.count = 0}; operator () (_x,_y) { this.count += 1; return this; } } struct TruncatedIterator { type func new(i, n: Int) { return alloc(This){ .it = i, .remaining = n, }; } func next() { if this.remaining <= 0 { return Maybe::None; } this.remaining -= 1; return this.it.next(); } } func append_to_list(x,y) { x.append(y); return x; } mixin Iterator { # allow running a for loop directly on an iterator func iterator() = this; func where(f) { return FilteringIterator.new(this,f); } func map(f) { return MappingIterator.new(this,f); } func to_list() { return this.reduce(append_to_list, []); } func flatten_results() { val out = []; for v in this { match v { isa Result and case Ok(x) => { out.append(x); }, isa Result and case Err(e) => { return err(e); }, } else { out.append(v); } } return ok(out); } func all(f) { for v in this { if !f(v) { return false; } } return true; } func any(f) = this.find(f).is_Some(); func find(f) { for v in this { if f(v) { return Maybe::Some(v); } } return Maybe::None; } func position(f) { val index = 0; for v in this { if f(v) { return Maybe::Some(index); } index += 1; } return Maybe::None; } func reduce(f, v0) { val acc = v0; for v in this { acc = f(acc, v); } return acc; } func sum(v0=0) = this.reduce(|x,y| => x+y, v0); func product(v0=1) = this.reduce(|x,y| => x*y, v0); func max() { val current_max = this.next()?; for v in this { if v > current_max { current_max = v; } } return Maybe::Some(current_max); } func min() { val current_min = this.next()?; for v in this { if v < current_min { current_min = v; } } return Maybe::Some(current_min); } func count() = this.reduce(|acc,_| => acc + 1, 0); func first() = this.next(); func last() { val last_value = Maybe::None; for v in this { last_value = Maybe::Some(v); } return last_value; } func nth(n: Int) { if n < 0 { return Maybe::None; } val current_index = 0; for v in this { if current_index == n { return Maybe::Some(v); } current_index += 1; } return Maybe::None; } func skip(n: Int) { while n > 0 { if this.next().is_None() { break; }; n -= 1; } return this; } func truncate(n: Int) = TruncatedIterator.new(this, n); } extension FilteringIterator { include Iterator } extension MappingIterator { include Iterator } extension TruncatedIterator { include Iterator } extension List.ListIterator { include Iterator } mixin Iterable { func where(f) = this.iterator().where(f); func map(f) = this.iterator().map(f); func reduce(f,v0) = this.iterator().reduce(f,v0); func to_list() = this.iterator().to_list(); func all(f) = this.iterator().all(f); func any(f) = this.iterator().any(f); func find(f) = this.iterator().find(f); func position(f) = this.iterator().position(f); func sum(v0=0) = this.iterator().sum(v0); func product(v0=1) = this.iterator().product(v0); func max() = this.iterator().max(); func min() = this.iterator().min(); func count() = this.iterator().count(); func first() = this.iterator().first(); func last() = this.iterator().last(); func nth(n) = this.iterator().nth(n); func skip(n: Int) = this.iterator().skip(n); func truncate(n: Int) = this.iterator().truncate(n); } extension List { include Iterable } ================================================ FILE: lib/aria/iterator/zip.aria ================================================ # SPDX-License-Identifier: Apache-2.0 import aria.iterator.mixin; func iter_or_self(i) { return hasattr(i, "iterator") ? i.iterator() : i; } struct Zip { type func new(...) { val iterators = varargs.iterator().map(iter_or_self).to_list(); return alloc(This){ .iterators = iterators, }; } func iterator() { return this; } func next() { val next_values = []; for iter in this.iterators { next_values.append(iter.next()?); } return Maybe::Some(next_values); } } ================================================ FILE: lib/aria/json/parser.aria ================================================ # SPDX-License-Identifier: Apache-2.0 import Map from aria.structures.map; import aria.string.classes; import JsonValue from aria.json.value; import JsonNull from aria.json.value; import ok, err from aria.core.result; struct JsonStream { type func new(s) { return alloc(This) { .input = s.chars(), .pos = 0 }; } func peek() { return this.pos < this.input.len() ? this.input[this.pos] : Maybe::None; } func next() { val c = this.peek(); this.pos += 1; return c; } func eat(expected) { if this.peek() == expected { this.next(); return true; } else { return false; } } func skip_whitespace() { while true { val c = this.peek(); if c == ' ' || c == '\t' || c == '\n' || c == '\r' { this.next(); } else { break; } } } } extension JsonValue { type func parse(s) { return ok(parse_value(JsonStream.new(s))?); } } struct JsonParseError { type func new(why: String) { return alloc(This) { .message = why, }; } func prettyprint() { return "JsonParseError: " + this.message; } } func json_err(msg) { return err(JsonParseError.new(msg)); } func parse_value(stream) { stream.skip_whitespace(); val c = stream.peek(); if c == '"' { return JsonValue::String(parse_string(stream)?); } elsif c == '{' { return JsonValue::Object(parse_object(stream)?); } elsif c == '[' { return JsonValue::Array(parse_array(stream)?); } elsif c == 't' { return parse_true(stream)?; } elsif c == 'f' { return parse_false(stream)?; } elsif c == 'n' { return parse_null(stream)?; } elsif c.is_digit() || c == '-' { return JsonValue::Number(parse_number(stream))?; } else { return json_err("Not a valid JSON value: " + c); } } func parse_string(stream) { if !stream.eat('"') { return json_err("missing quotes in JSON string"); } val result = ""; while true { val c = stream.next(); if c == '"' { break; } elsif c == '\\' { val esc = stream.next(); if esc == 'n' { result += '\n'; } elsif esc == 't' { result += '\t'; } elsif esc == '"' { result += '"'; } elsif esc == '\\' { result += '\\'; } else { return json_err("invalid escape sequence in JSON string"); } } else { result += c; } } return ok(result); } func parse_number(stream) { val text = ""; if stream.peek() == '-' { text += stream.next(); } while true { val c = stream.peek(); if c.is_digit() { text += stream.next(); } else { break; } } if stream.peek() == '.' { text += stream.next(); while true { val c = stream.peek(); if c.is_digit() { text += stream.next(); } else { break; } } } return Float.parse(text)?; } func parse_true(stream) { if stream.next() != 't' || stream.next() != 'r' || stream.next() != 'u' || stream.next() != 'e' { return json_err("invalid boolean true value in JSON"); } else { return ok(JsonValue::Boolean(true)); } } func parse_false(stream) { if stream.next() != 'f' || stream.next() != 'a' || stream.next() != 'l' || stream.next() != 's' || stream.next() != 'e' { return json_err("invalid boolean false value in JSON"); } else { return ok(JsonValue::Boolean(false)); } } func parse_null(stream) { if stream.next() != 'n' || stream.next() != 'u' || stream.next() != 'l' || stream.next() != 'l' { return json_err("invalid null value in JSON"); } else { return ok(JsonValue::Null(alloc(JsonNull))); } } func parse_object(stream) { val map = Map.new(); stream.eat('{'); stream.skip_whitespace(); if stream.peek() == '}' { stream.next(); return map; } while true { stream.skip_whitespace(); val key = parse_string(stream)?; stream.skip_whitespace(); if !stream.eat(':') { return json_err("Invalid JSON object key-value pair"); } val value = parse_value(stream)?; map.set(key, value); stream.skip_whitespace(); if stream.eat('}') { break; } elsif stream.eat(',') { continue; } else { return json_err("Unexpected character in JSON object"); } } return ok(map); } func parse_array(stream) { val list = []; stream.eat('['); stream.skip_whitespace(); if stream.peek() == ']' { stream.next(); return list; } while true { val value = parse_value(stream)?; list.append(value); stream.skip_whitespace(); if stream.eat(']') { break; } elsif stream.eat(',') { continue; } else { return json_err("Unexpected character in JSON array"); } } return ok(list); } ================================================ FILE: lib/aria/json/value.aria ================================================ # SPDX-License-Identifier: Apache-2.0 import aria.structures.map; struct JsonNull {} enum JsonValue { case Object(aria.structures.map.Map), case Array(List), case String(String), case Number(Float), case Boolean(Bool), case Null(JsonNull), } extension JsonValue { func flatten() { match this { case Boolean(x) => { return x; }, case Number(x) => { return x; }, case String(x) => { return x; }, case Array(x) => { val ret = []; for v in x { ret.append(v.flatten()); } return ret; }, case Object(x) => { val ret = aria.structures.map.Map.new(); for v in x { ret.set(v.key, v.value.flatten()); } return ret; }, case Null(x) => { return x; }, } } func prettyprint() { match this { case Boolean(x) => { return "{0}".format(x); }, case Number(x) => { return "{0}".format(x); }, case String(x) => { return '"{0}"'.format(x); }, case Array(x) => { val items = []; for v in x { items.append(v.prettyprint()); } return "[{0}]".format(items.join(", ")); }, case Object(x) => { val items = []; for v in x { items.append('"{0}": {1}'.format(v.key, v.value)); } return "{" + "{0}".format(items.join(", ")) + "}" + "}"; }, case Null(x) => { return "null"; }, } } } ================================================ FILE: lib/aria/json/writer.aria ================================================ # SPDX-License-Identifier: Apache-2.0 import Map from aria.structures.map; import JsonValue from aria.json.value; import JsonNull from aria.json.value; import ok, err from aria.core.result; # this is a type-check only prototype func _to_json_thing(this) {} struct JsonConvertError { type func new(why: String) { return alloc(This) { .message = why, }; } func prettyprint() { return "JsonConvertError: " + this.message; } } func json_err(msg) { return err(JsonConvertError.new(msg)); } extension JsonValue { type func new_with_value(x) { match x { isa String => { return ok(JsonValue::String(x)); }, isa Int => { return ok(JsonValue::Number(x + 0.0f)); }, isa Float => { return ok(JsonValue::Number(x)); }, isa Bool => { return ok(JsonValue::Boolean(x)); }, isa List => { val ret = []; for item in x { ret.append(JsonValue.new_with_value(item)?); } return ok(JsonValue::Array(ret)); } isa Map => { val ret = Map.new(); for item in x { val key = item.key; if !(key isa String) { key = format("{0}", key); } val value = JsonValue.new_with_value(item.value)?; ret.set(key, value); } return ok(JsonValue::Object(ret)); } isa JsonNull => { return ok(JsonValue::Null(alloc(JsonNull))); } } else { if hasattr(x, "to_json_value") { val to_json_value = x.to_json_value; if arity(to_json_value).can_call_with_argc(0) { return to_json_value()?; } } } return json_err("type of value {0} cannot be converted as JSON".format(x)); } } func escape_json_string(s: String) { val result = ""; for c in s.chars() { if c == '"' { result += '\\"'; } elsif c == '\\' { result += "\\\\"; } elsif c == '\n' { result += "\\n"; } elsif c == '\r' { result += "\\r"; } elsif c == '\t' { result += "\\t"; } elsif c == '\b' { result += "\\b"; } elsif c == '\f' { result += "\\f"; } else { result += c; } } return result; } extension JsonValue { func to_json_string() { match this { case Object(map) => { val parts = []; for entry in map { val key = escape_json_string(entry.key); val value_str = entry.value.to_json_string(); parts.append('"' + key + '":' + value_str); } return "{" + parts.join() + "}"; }, case Array(items) => { val parts = []; for item in items { parts.append(item.to_json_string()); } return "[" + parts.join() + "]"; }, case String(s) => { return '"' + escape_json_string(s) + '"'; }, case Number(n) => { return "{0}".format(n); }, case Boolean(b) => { return b ? "true" : "false"; }, case Null(x) => { return "null"; }, } } } ================================================ FILE: lib/aria/network/request.aria ================================================ # SPDX-License-Identifier: Apache-2.0 flag: uses_dylib("aria_http"); import Map from aria.structures.map; import JsonValue, JsonNull from aria.json.value; import aria.json.writer; struct Request { struct Response { func prettyprint() { return "aria.network.Request.Response(code={0})".format(this.status_code); } } struct Error { type func new(msg) { return alloc(This) { .msg = msg, }; } func prettyprint() { return "network error: {0}".format(this.msg); } } type func new(url: String) { return alloc(This) { .url = url, .headers = Map.new(), .timeout = 30.0f, }; } func get() { # the native impl takes and returns headers as a key/value pair list # but we use Map in Aria - this code handles that conversion logic val headers = []; for h in this.headers { headers.append([h.key, h.value]); } val response = this._get(headers)?; val headers = Map.new(); for header in response.headers { headers.set(header[0], header[1]); } response.headers = headers; return Result::Ok(response); } func post(data: String) { # the native impl takes and returns headers as a key/value pair list # but we use Map in Aria - this code handles that conversion logic val headers = []; for h in this.headers { headers.append([h.key, h.value]); } val response = this._post(headers, data)?; val headers = Map.new(); for header in response.headers { headers.set(header[0], header[1]); } response.headers = headers; return Result::Ok(response); } func post_as_json(data) { val the_val = JsonValue.new_with_value(data)?.to_json_string(); this.headers["Content-Type"] = "application/json"; return this.post(the_val); } } ================================================ FILE: lib/aria/network/retry.aria ================================================ # SPDX-License-Identifier: Apache-2.0 enum RetryResult { case Pass(Any), case Fail(Maybe), # last value if any case Exception(Any), # last exception from f/check } extension RetryResult { func _op_try_view() { match this { case Pass(v) => { return Result::Ok(v); }, case Fail(v) => { return Result::Err(v); }, case Exception(e) => { # swallow the difference between a failure and an exception return Result::Err(e); } } } } func retry(f, check, attempts_count = 3, delay_ms = 500) { if attempts_count <= 0 { return RetryResult::Fail(Maybe::None); } if delay_ms < 0 { return RetryResult::Fail(Maybe::None); } val last_result = Maybe::None; val last_exception = Maybe::None; while attempts_count > 0 { last_exception = Maybe::None; # same as a do { } while(false) in C, since there is no path but out while true { val result = Maybe::None; try { result = f(); } catch e { last_exception = Maybe::Some(e); break; } val checked = false; try { checked = check(result); } catch e { last_exception = Maybe::Some(e); break; } if checked { return RetryResult::Pass(result); } else { last_result = Maybe::Some(result); } break; } attempts_count -= 1; if attempts_count > 0 { sleep_ms(delay_ms); } } if last_exception.is_Some() { return RetryResult::Exception(last_exception.unwrap_Some()); } else { return RetryResult::Fail(last_result); } } ================================================ FILE: lib/aria/numerics/complex.aria ================================================ # SPDX-License-Identifier: Apache-2.0 struct Complex { type func new(r: Int|Float, i: Int|Float = 0) { return alloc(This) { .real = r + 0.0f, # ensure floating point .imag = i + 0.0f, # ensure floating point }; } type func zero() { return This.new(0,0); } func conj() { return Complex.new(this.real, -this.imag); } func reciprocal() { val den = (this.real * this.real + this.imag * this.imag) + 0.0f; return Complex.new(this.real/den, -this.imag/den); } func prettyprint() { if this.imag == 0 { return "{0}".format(this.real); } elsif this.real == 0 { return "{0}i".format(this.imag); } elsif this.imag >= 0 { return "{0}+{1}i".format(this.real, this.imag); } else { return "{0}{1}i".format(this.real, this.imag); } } operator +(rhs) { if (rhs isa Int) || (rhs isa Float) { return Complex.new(this.real + rhs, this.imag); } elsif rhs isa Complex { return Complex.new(this.real + rhs.real, this.imag + rhs.imag); } else { throw alloc(Unimplemented); } } reverse operator +(lhs) { return this._op_impl_add(lhs); } operator *(rhs) { if (rhs isa Int) || (rhs isa Float) { return Complex.new(this.real * rhs, this.imag * rhs); } elsif rhs isa Complex { val real_part = this.real * rhs.real - this.imag * rhs.imag; val imag_part = this.real * rhs.imag + this.imag * rhs.real; return Complex.new(real_part, imag_part); } else { throw alloc(Unimplemented); } } reverse operator *(lhs) { return this._op_impl_mul(lhs); } reverse operator /(lhs) { if (lhs isa Int) || (lhs isa Float) { lhs = Complex.new(lhs,0); } if lhs isa Complex { return lhs / this; } else { throw alloc(Unimplemented); } } operator /(rhs) { if (rhs isa Int) || (rhs isa Float) { return Complex.new(this.real / rhs, this.imag / rhs); } elsif rhs isa Complex { return this * rhs.reciprocal(); } else { throw alloc(Unimplemented); } } reverse operator -(lhs) { if (lhs isa Int) || (lhs isa Float) { return Complex.new(lhs - this.real, -this.imag); } elsif lhs isa Complex { return Complex.new(lhs.real - this.real, lhs.imag - this.imag); } else { throw alloc(Unimplemented); } } operator -(rhs) { if (rhs isa Int) || (rhs isa Float) { return Complex.new(this.real - rhs, this.imag); } elsif rhs isa Complex { return Complex.new(this.real - rhs.real, this.imag - rhs.imag); } else { throw alloc(Unimplemented); } } operator ==(rhs) { if rhs isa Complex { return this.real == rhs.real && this.imag == rhs.imag; } elsif (rhs isa Int) || (rhs isa Float) { return this.real == rhs && this.imag == 0; } else { throw alloc(Unimplemented); } } func hash() { val h = this.real.hash() ^ (this.imag.hash() + 0x9e3779b97f4a7c15); h = h ^ (h >> 30); h = h * 0xbf58476d1ce4e5b9; h = h ^ (h >> 27); h = h * 0x94d049bb133111eb; h = h ^ (h >> 31); return h; } } extension Complex { type val i = Complex.new(0,1); type val j = Complex.i; } ================================================ FILE: lib/aria/numerics/decimal.aria ================================================ # SPDX-License-Identifier: Apache-2.0 import CompareResult, TotalOrdering from aria.ordering.compare; import aria.numerics.int.pow; func pow(x: Int, y: Int) { if y == 0 { return 1; } if y == 1 { return x; } val ret = x; while y > 1 { ret *= x; y -= 1; } return ret; } func max(x,y) { return x > y ? x : y; } struct Decimal { type func parse(v: String) { val parts = v.split("."); match parts.len() { == 1 => { val v = Int.parse(parts[0]); return v.apply(|value| => This.new_with_parts(value, 0)); }, == 2 => { val integer_part = Int.parse(parts[0])?; val decimal_part = parts[1]; val scale = decimal_part.len(); val combined_str = parts[0] + decimal_part; val value = Int.parse(combined_str); return value.apply(|v| => This.new_with_parts(v, scale)); } } else { return Result::Err("invalid decimal string"); } } type func new(v: Int|Float) { match v { isa Int => { return This.new_with_parts(v, 0); }, isa Float => { # relies on Float.prettyprint doing the right thing # really, there should be a way on Float to extract the # integer and fractional parts directly val s = prettyprint(v); val parts = s.split("."); match parts.len() { == 1 => { return This.new_with_parts(v.int(), 0); }, == 2 => { val decimal_part = parts[1]; val scale = decimal_part.len(); val value = (v * pow(10, scale)).int(); return This.new_with_parts(value, scale); } } } } } type func new_with_parts(v: Int, s: Int) { while s > 0 && v % 10 == 0 { v /= 10; s -= 1; } return alloc(This){ .value = v, .scale = s, }; } operator u-() { return alloc(Decimal){ .value = -this.value, .scale = this.scale, }; } reverse operator -(lhs) { return -this + lhs; } reverse operator /(lhs) { if lhs isa Int { lhs = Decimal.new(lhs); } elsif lhs isa Float { lhs = Decimal.new(lhs); } elsif !(lhs isa Decimal) { throw alloc(Unimplemented); } return lhs / this; } operator +(other: Int|Float|Decimal) { if other isa Int { other = Decimal.new(other); } elsif other isa Float { other = Decimal.new(other); } if this.scale == other.scale { return Decimal.new_with_parts(this.value + other.value, this.scale); } else { val max_scale = max(this.scale, other.scale); val this_value = this.value * pow(10, (max_scale - this.scale)); val other_value = other.value * pow(10, (max_scale - other.scale)); return Decimal.new_with_parts(this_value + other_value, max_scale); } } reverse operator +(lhs) { return this._op_impl_add(lhs); } operator -(other: Int|Float|Decimal) { if other isa Int { other = Decimal.new(other); } elsif other isa Float { other = Decimal.new(other); } if this.scale == other.scale { return Decimal.new_with_parts(this.value - other.value, this.scale); } else { val max_scale = max(this.scale, other.scale); val this_value = this.value * pow(10, (max_scale - this.scale)); val other_value = other.value * pow(10, (max_scale - other.scale)); return Decimal.new_with_parts(this_value - other_value, max_scale); } } operator *(other: Int|Float|Decimal) { if other isa Int { other = Decimal.new(other); } elsif other isa Float { other = Decimal.new(other); } return Decimal.new_with_parts(this.value * other.value, this.scale + other.scale); } reverse operator *(lhs) { return this._op_impl_mul(lhs); } operator /(other: Int|Float|Decimal) { if other isa Int { other = Decimal.new(other); } elsif other isa Float { other = Decimal.new(other); } return Decimal.new_with_parts(this.value * pow(10, other.scale) / other.value, this.scale); } func align(other) { if this.scale == other.scale { return [this, other]; } val max_scale = max(this.scale, other.scale); val this_value = this.value * pow(10, max_scale - this.scale); val other_value = other.value * pow(10, max_scale - other.scale); val a0 = alloc(Decimal){ .value=this_value, .scale=max_scale }; val a1 = alloc(Decimal){ .value=other_value, .scale=max_scale }; return [a0,a1]; } func comp(other) { if other isa Int { other = Decimal.new(other); } elsif other isa Float { other = Decimal.new(other); } elsif !(other isa Decimal) { throw alloc(Unimplemented); } val a = this.align(other); if a[0].value == a[1].value { return CompareResult::eq; } elsif a[0].value > a[1].value { return CompareResult::gt; } else { return CompareResult::lt; } } func prettyprint(fmt: String = "") { if fmt == "" { return this.default_prettyprint(); } val parts = fmt.split("."); if parts.len() != 2 || parts[0] != "" { return this.default_prettyprint(); } val n_maybe = Int.parse(parts[1]); match n_maybe { case Err => { return this.default_prettyprint(); }, case Ok(N) => { if N <= 0 { return this.default_prettyprint(); } if this.scale <= N { return this.default_prettyprint(); } val drop = this.scale - N; val factor = 10.pow(drop); val v = this.value; val rounded = v >= 0 ? (v + factor / 2) / factor : (v - factor / 2) / factor; return Decimal.new_with_parts(rounded, N).default_prettyprint(); } } } func default_prettyprint() { val abs_value_str = prettyprint(this.value.abs()); val sign = ""; if this.value < 0 { sign = "-"; } if this.scale == 0 { return sign + abs_value_str; } val value_str = abs_value_str; val len = value_str.len(); if len <= this.scale { return sign + "0." + "0" * (this.scale - len) + value_str; } val integer_part = value_str.substring(0, len - this.scale - 1); val fractional_part = value_str.substring(len - this.scale, len - 1); return sign + integer_part + "." + fractional_part; } func hash() { val h = this.value ^ (this.scale + 0x9e3779b97f4a7c15); h = h ^ (h >> 30); h = h * 0xbf58476d1ce4e5b9; h = h ^ (h >> 27); h = h * 0x94d049bb133111eb; h = h ^ (h >> 31); return h; } include TotalOrdering } ================================================ FILE: lib/aria/numerics/float/exp.aria ================================================ # SPDX-License-Identifier: Apache-2.0 extension Float { func ln() { if this <= 0 { throw Float.DomainError.new("logarithm undefined for non-positive values"); } val LN2 = 0.6931471805599453; val ε = 1.0e-15; val max_iterations = 10000; val x = this; val k = 0; val mant = x; while mant >= 2.0f { mant = mant / 2.0f; k = k + 1; } while mant < 1.0f { mant = mant * 2.0f; k = k - 1; } if mant == 1.0f { return k * LN2; } val y = (mant - 1.0f) / (mant + 1.0f); val y2 = y * y; val term = y; val sum = 0.0f; val n = 1; val iterations = 0; while iterations < max_iterations { sum = sum + term / n; term = term * y2; n = n + 2; iterations = iterations + 1; if (term.abs() / n) < ε { break; } } val ln_val = 2.0f * sum; return ln_val + k * LN2; } func exp() { val ε = 0.000000000001f; val max_iterations = 1000; if this == 0.0f { return 1.0f; } val reduced = this; val scale = 0; while reduced.abs() > 0.5f { reduced = reduced / 2.0f; scale = scale + 1; } val result = 1.0f; val term = 1.0f; val iterations = 0; while iterations < max_iterations { iterations = iterations + 1; term = term * reduced / iterations; if term.abs() < ε { break; } result = result + term; } val i = 0; while i < scale { result = result * result; i = i + 1; } return result; } func pow(exponent: Int|Float) { match exponent { == 0 => { return 1.0f; }, == 1 => { return this; } isa Int => { exponent += 0.0f; } } if this < 0 && exponent % 1 != 0 { throw Float.DomainError.new("cannot calculate fractional power of negative integer"); } val is_exponent_negative = exponent < 0; val abs_exponent = exponent.abs(); val integer_part = abs_exponent.floor(); val fractional_part = abs_exponent - integer_part; val result = 1.0f; val temp = this; val i = 0; while i < integer_part { result = result * temp; i = i + 1; } if fractional_part > 0 { result = result * this.sqrt().pow(fractional_part * 2); } if is_exponent_negative { result = 1.0f / result; } return result; } } ================================================ FILE: lib/aria/numerics/float/trig.aria ================================================ # SPDX-License-Identifier: Apache-2.0 extension Float { func sin() { val τ = Float.π*2; val ε = 0.000000000001f; val x = this % τ; if x > Float.π { x -= τ; } val term = x; val result = term; val n = 1; while term.abs() > ε { n += 2; term = term * (-x * x / (n * (n - 1))); result = result + term; } return result; } func cos() { val τ = Float.π*2; val ε = 0.000000000001f; val x = this % τ; if x > Float.π { x -= τ; } val term = 1.0f; val result = term; val n = 0; while term.abs() > ε { n += 2; term = term * (-x * x / (n * (n - 1))); result = result + term; } return result; } func tan() { return this.sin() / this.cos(); } func arcsin() { if this < -1.0f || this > 1.0f { throw Float.DomainError.new("not a valid sine value"); } val ε = 0.000000000001f; val x = this; val term = x; val result = term; val n = 1; while term.abs() > ε { term = term * (x * x * (2 * n - 1) * (2 * n - 1)) / ((2 * n) * (2 * n + 1)); result = result + term; n += 1; } return result; } func arccos() { if this < -1.0f || this > 1.0f { throw Float.DomainError.new("not a valid cosine value"); } return Float.π / 2 - this.arcsin(); } func arctan() { val ε = 0.000000000001f; val x = this; if x == -1.0f { return -Float.π / 4; } if x == 1.0f { return Float.π / 4; } if x.abs() > 1.0f { if x > 0.0f { return Float.π / 2 - (1.0f / x).arctan(); } else { return -Float.π / 2 - (1.0f / x).arctan(); } } if x.abs() > 0.5f { val y = (x - 1) / (x + 1); return Float.π / 4 + y.arctan(); } val term = x; val result = term; val n = 1; while term.abs() > ε { n += 2; term = term * (-x * x * (n - 2) / n); result = result + term; } return result; } } ================================================ FILE: lib/aria/numerics/int/pow.aria ================================================ # SPDX-License-Identifier: Apache-2.0 extension Int { func pow(y: Int) { if y < 0 { throw Int.DomainError.new("Negative exponent not supported"); } if y == 0 { return 1; } if this == 0 { return 0; } val base = this; val exp = y; val res = 1; while exp > 0 { if exp % 2 != 0 { res *= base; } if exp == 1 { break; } base *= base; exp /= 2; } return res; } } ================================================ FILE: lib/aria/numerics/matrix.aria ================================================ # SPDX-License-Identifier: Apache-2.0 import CompareResult, TotalOrdering from aria.ordering.compare; import Map from aria.structures.map; import Range from aria.range.range; struct MatrixIndex { type func new(row: Int, col: Int) { return alloc(This) { .row = row, .col = col, }; } func hash() { return this.row * 31 + this.col; } operator ==(other) { return this.row == other.row && this.col == other.col; } } struct Matrix { struct DimensionMismatch { type func new(msg: String) { return alloc(This) { .msg = msg, }; } func prettyprint() { return "DimensionMismatch: " + this.msg; } } type func new(rows: Int, cols: Int) { return alloc(This) { .rows = rows, .cols = cols, .data = Map.new(), }; } func get(row: Int, col: Int) { if row >= this.rows || col >= this.cols { throw Matrix.DimensionMismatch.new("Index out of bounds: ({0},{1})".format(row, col)); } match this.data.get(MatrixIndex.new(row, col)) { case Some(value) => { return value; } } else { # ideally, we would find the type of (0,0) and default to it # and only return float if 0,0 is missing (or a float) return 0.0f; } } operator[](row: Int, col: Int) { return this.get(row, col); } func set(row: Int, col: Int, value) { if row >= this.rows || col >= this.cols { throw Matrix.DimensionMismatch.new("Index out of bounds: ({0},{1})".format(row, col)); } this.data.set(MatrixIndex.new(row, col), value); } operator[]=(row: Int, col: Int, value) { this.set(row, col, value); } operator +(other: Matrix) { if (this.rows != other.rows || this.cols != other.cols) { throw Matrix.DimensionMismatch.new("Matrix dimensions do not match for addition"); } val result = Matrix.new(this.rows, this.cols); for row in Range.from(0).to(this.rows) { for col in Range.from(0).to(this.cols) { result.set(row, col, this.get(row, col) + other.get(row, col)); } } return result; } operator ==(other: Matrix) { if (this.rows != other.rows || this.cols != other.cols) { return false; } for row in Range.from(0).to(this.rows) { for col in Range.from(0).to(this.cols) { if this.get(row, col) != other.get(row, col) { return false; } } } return true; } operator -(other: Matrix) { if (this.rows != other.rows || this.cols != other.cols) { throw Matrix.DimensionMismatch.new("Matrix dimensions do not match for subtraction"); } val result = Matrix.new(this.rows, this.cols); for row in Range.from(0).to(this.rows) { for col in Range.from(0).to(this.cols) { result.set(row, col, this.get(row, col) - other.get(row, col)); } } return result; } func transpose() { val result = Matrix.new(this.cols, this.rows); for row in Range.from(0).to(this.rows) { for col in Range.from(0).to(this.cols) { result.set(col, row, this.get(row, col)); } } return result; } func prettyprint() { val ret = []; for row in Range.from(0).to(this.rows) { val row_str = []; for col in Range.from(0).to(this.cols) { row_str.append(this.get(row, col)); } ret.append("[" + row_str.join() + "]"); } return "Matrix(" + ret.join() + ")"; } operator *(other: Matrix) { if (this.cols != other.rows) { throw Matrix.DimensionMismatch.new("Matrix dimensions do not match for multiplication"); } val result = Matrix.new(this.rows, other.cols); for row in Range.from(0).to(this.rows) { for col in Range.from(0).to(other.cols) { val sum = alloc(typeof(this.get(0,0))); for k in Range.from(0).to(this.cols) { sum += this.get(row, k) * other.get(k, col); } result.set(row, col, sum); } } return result; } func determinant() { if (this.rows != this.cols) { throw Matrix.DimensionMismatch.new("Determinant can only be calculated for square matrices"); } val n = this.rows; if n == 1 { return this.get(0, 0); } elsif n == 2 { return this.get(0, 0) * this.get(1, 1) - this.get(0, 1) * this.get(1, 0); } val work = Matrix.new(n, n); for row in Range.from(0).to(n) { for col in Range.from(0).to(n) { work.set(row, col, this.get(row, col) * 1.0f); } } val det = 1.0f; val sign = 1.0f; for col in Range.from(0).to(n) { val pivot_row = col; val pivot_val = work.get(col, col); if pivot_val < 0.0f { pivot_val = -pivot_val; } for row in Range.from(col + 1).to(n) { val abs_val = work.get(row, col); if abs_val < 0.0f { abs_val = -abs_val; } if abs_val > pivot_val { pivot_val = abs_val; pivot_row = row; } } if pivot_val == 0.0f { return 0.0f; } if pivot_row != col { for k in Range.from(0).to(n) { val temp = work.get(col, k); work.set(col, k, work.get(pivot_row, k)); work.set(pivot_row, k, temp); } sign = -sign; } val pivot = work.get(col, col); for row in Range.from(col + 1).to(n) { val factor = work.get(row, col) / pivot; for k in Range.from(col).to(n) { work.set(row, k, work.get(row, k) - factor * work.get(col, k)); } } } for i in Range.from(0).to(n) { det *= work.get(i, i); } return det * sign; } } ================================================ FILE: lib/aria/ordering/compare.aria ================================================ # SPDX-License-Identifier: Apache-2.0 enum CompareResult { case lt, case eq, case gt, } mixin TotalOrdering { # requires func comp(this,x) that returns a CompareResult operator ==(rhs) { match this.comp(rhs) { isa CompareResult and case eq => { return true; } } else { return false; } } operator < (rhs) { match this.comp(rhs) { isa CompareResult and case lt => { return true; } } else { return false; } } operator > (rhs) { match this.comp(rhs) { isa CompareResult and case gt => { return true; } } else { return false; } } operator <= (rhs) { match this.comp(rhs) { isa CompareResult and case lt => { return true; }, isa CompareResult and case eq => { return true; } } else { return false; } } operator >= (rhs) { match this.comp(rhs) { isa CompareResult and case gt => { return true; }, isa CompareResult and case eq => { return true; } } else { return false; } } } ================================================ FILE: lib/aria/ordering/utils.aria ================================================ # SPDX-License-Identifier: Apache-2.0 import CompareResult from aria.ordering.compare; func min(l: List) { val min = l[0]; for i in l { if i < min { min = i; } } return min; } func min_with_comparator(l: List, cmp) { val min = l[0]; for i in l { if cmp(i, min).is_lt() { min = i; } } return min; } func max(l: List) { val max = l[0]; for i in l { if i > max { max = i; } } return max; } func max_with_comparator(l: List, cmp) { val max = l[0]; for i in l { if cmp(i, max).is_gt() { max = i; } } return max; } func min_max(l: List) { val min = l[0]; val max = l[0]; for i in l { if i < min { min = i; } if i > max { max = i; } } return Box(){ .min = min, .max = max }; } func min_max_with_comparator(l: List, cmp) { val min = l[0]; val max = l[0]; for i in l { if cmp(i, min).is_lt() { min = i; } if cmp(i, max).is_gt() { max = i; } } return Box(){ .min = min, .max = max }; } ================================================ FILE: lib/aria/range/int_extension.aria ================================================ # SPDX-License-Identifier: Apache-2.0 import Range from aria.range.range; extension Int { func to(n: Int) { return Range.from(this).to(n); } func through(n: Int) { return Range.from(this).through(n); } } ================================================ FILE: lib/aria/range/range.aria ================================================ # SPDX-License-Identifier: Apache-2.0 import Iterator,Iterable from aria.iterator.mixin; struct InvalidRangeError { type func new(msg: String) = alloc(This) {.msg}; func prettyprint() { return "range error: {0}".format(this.msg); } } struct RangeIterator { type func new(from, to, step) { if step == 0 { throw InvalidRangeError.new("iteration step cannot be zero"); } val cur = from; val lim = to; if step < 0 { cur = to - 1; lim = from - 1; } return alloc(This) { .current = cur, .limit = lim, .step = step, }; } func next() { if this.step > 0 { if this.current >= this.limit { return Maybe::None; } } else { if this.current <= this.limit { return Maybe::None; } } val result = this.current; this.current += this.step; return Maybe::Some(result); } include Iterator } struct RangeImpl { type func new(from, to) = alloc(This) {.from, .to}; func step(n) { return RangeIterator.new(this.from, this.to, n); } func iterator() { return this.step(1); } func descending() { return this.step(-1); } func contains(x) { return x >= this.from && x < this.to; } func length() { return this.to - this.from; } func union(other) { val lo = other.from < this.from ? other.from : this.from; val hi = other.to > this.to ? other.to : this.to; return RangeImpl.new(lo, hi); } func intersection(other) { val lo = other.from > this.from ? other.from : this.from; val hi = other.to < this.to ? other.to : this.to; return lo >= hi ? RangeImpl.new(0, 0) : RangeImpl.new(lo, hi); } include Iterable func prettyprint() { return "Range from={0} to={1}".format(this.from, this.to); } func hash() { val h = this.from ^ (this.to + 0x9e3779b97f4a7c15); h = h ^ (h >> 30); h = h * 0xbf58476d1ce4e5b9; h = h ^ (h >> 27); h = h * 0x94d049bb133111eb; h = h ^ (h >> 31); return h; } operator == (other: RangeImpl) { return this.from == other.from && this.to == other.to; } } struct RangeFrom { type func new(n) { return alloc(This) { .from = n, }; } func to(n) { if this.from > n { throw InvalidRangeError.new("lower bound {0} is greater than upper bound {1}".format(this.from, n)); } return RangeImpl.new(this.from, n); } func through(n) { if this.from > n { throw InvalidRangeError.new("lower bound {0} is greater than upper bound {1}".format(this.from, n)); } return RangeImpl.new(this.from, n+1); # inclusive range - end at n + 1 } } struct Range { type func from(n) { return RangeFrom.new(n); } } ================================================ FILE: lib/aria/rng/mixin.aria ================================================ # SPDX-License-Identifier: Apache-2.0 mixin RngRange { # assume the Rng has instance func next() func in_range(low, high) { val range = high - low + 1; val n = this.next(); return low + ((n % range + range) % range); } func one_of(x: List) { if x.len() == 0 { throw RuntimeError::OperationFailed("cannot choose from empty list"); } val low = 0; val high = x.len() - 1; val index = this.in_range(low, high); return x[index]; } } ================================================ FILE: lib/aria/rng/msws.aria ================================================ # SPDX-License-Identifier: Apache-2.0 import aria.rng.mixin; struct MiddleSquareRng { type func new() { return MiddleSquareRng.new_with_params(now(),0x5ad4eceda1ce2a9); } type func new_with_params(x,s) = alloc(This){ .x, .w = 0, .s, }; func next() { this.x = this.x * this.x; this.w += this.s; this.x += this.w; this.x = (this.x >> 32) | (this.x << 32); return this.x; } include aria.rng.mixin.RngRange } ================================================ FILE: lib/aria/rng/xorshift.aria ================================================ # SPDX-License-Identifier: Apache-2.0 import aria.rng.mixin; struct XorshiftRng { type func new() { return XorshiftRng.new_with_seed(now()); } type func new_with_seed(seed) { return alloc(This) { .x = seed | 1 }; } func next() { this.x = this.x ^ (this.x << 7); this.x = this.x ^ (this.x >> 9); return this.x; } include aria.rng.mixin.RngRange } ================================================ FILE: lib/aria/string/classes.aria ================================================ # SPDX-License-Identifier: Apache-2.0 flag: uses_dylib("aria_unicode"); extension String { func is_letter() = this.is_lowercase_letter() || this.is_uppercase_letter(); func is_alphanumeric() = this.is_letter() || this.is_digit(); } ================================================ FILE: lib/aria/string/regex.aria ================================================ # SPDX-License-Identifier: Apache-2.0 flag: uses_dylib("aria_regex"); struct Regex { struct Match { func prettyprint() { return 'match(start={0} len={1} val="{2}")'.format(this.start, this.len, this.value); } } struct Error { type func new(msg: String) { return alloc(This) {.msg = msg}; } func prettyprint() { return "regex error: {0}".format(this.msg); } } func prettyprint() { return 'Regex("{0}")'.format(this.pattern); } } ================================================ FILE: lib/aria/structures/hash/algo/sip.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func rotl64(x,r) = ((x << r) | (x >> (64 - r))); func load_le_u64(p) = p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24) | (p[4] << 32) | (p[5] << 40) | (p[6] << 48) | (p[7] << 56); struct SipHasher { type func new(k0: Int, k1: Int) = alloc(This) { .k0, .k1, .v0 = k0 ^ 0x736f6d6570736575, .v1 = k1 ^ 0x646f72616e646f6d, .v2 = k0 ^ 0x6c7967656e657261, .v3 = k1 ^ 0x7465646279746573, .len = 0, .buf = [0,0,0,0,0,0,0,0], .buflen = 0, }; func sip_round() { this.v0 = this.v0 + this.v1; this.v1 = rotl64(this.v1, 13); this.v1 = this.v1 ^ this.v0; this.v0 = rotl64(this.v0, 32); this.v2 = this.v2 + this.v3; this.v3 = rotl64(this.v3, 16); this.v3 = this.v3 ^ this.v2; this.v0 = this.v0 + this.v3; this.v3 = rotl64(this.v3, 21); this.v3 = this.v3 ^ this.v0; this.v2 = this.v2 + this.v1; this.v1 = rotl64(this.v1, 17); this.v1 = this.v1 ^ this.v2; this.v2 = rotl64(this.v2, 32); return this; } func compress(m) { this.v3 = this.v3 ^ m; this.sip_round(); this.v0 = this.v0 ^ m; } func write(data) { if !(data isa List) { data = [data]; } val i = 0; if this.buflen > 0 { while i < data.len() && this.buflen < 8 { this.buf[this.buflen] = data[i]; this.buflen += 1; i += 1; } if this.buflen == 8 { this.compress(load_le_u64(this.buf)); this.buflen = 0; } } while i + 8 <= data.len() { val m8 = [0,0,0,0,0,0,0,0]; m8[0] = data[i+0]; m8[1] = data[i+1]; m8[2] = data[i+2]; m8[3] = data[i+3]; m8[4] = data[i+4]; m8[5] = data[i+5]; m8[6] = data[i+6]; m8[7] = data[i+7]; val m = load_le_u64(m8); this.compress(m); i += 8; } while i < data.len() { this.buf[this.buflen] = data[i]; this.buflen += 1; i += 1; } this.len += data.len(); return this; } func finish() { val b = this.len << 56; val i = 0; while i < this.buflen { b = b | this.buf[i] << (8 * i); i += 1; } this.v3 = this.v3 ^ b; this.sip_round(); this.v0 = this.v0 ^ b; this.v2 = this.v2 ^ 0xff; this.sip_round().sip_round().sip_round(); return (this.v0 ^ this.v1) ^ (this.v2 ^ this.v3); } } ================================================ FILE: lib/aria/structures/hash/list.aria ================================================ # SPDX-License-Identifier: Apache-2.0 import SipHasher from aria.structures.hash.algo.sip; extension List { func hash() { val hasher = SipHasher.new(0x0706050403020100, 0x0f0e0d0c0b0a0908); for item in this { # TODO: runtime error, skip non-hashable items? hasher.write(item.hash()); } return hasher.finish(); } } ================================================ FILE: lib/aria/structures/map.aria ================================================ # SPDX-License-Identifier: Apache-2.0 import Iterator,Iterable from aria.iterator.mixin; struct Map { type val DEFAULT_CAPACITY = 128; struct Entry { type func new(key, value) = alloc(This) {.key, .value}; } func calc_hash(k) { val h = k.hash(); val n = this.capacity; return ((h % n) + n) % n; } type func new() { return Map.new_with_capacity(Map.DEFAULT_CAPACITY); } type func new_with_capacity(capacity: Int) { if capacity <= 0 { capacity = Map.DEFAULT_CAPACITY; } return alloc(This) { .buckets = List.from_function(|_| => [], capacity), .count = 0, .capacity, }; } type func frequency_map(iter) { val this = This.new(); for item in iter { val count = this.get(item) ?? 0; this.set(item, count + 1); } return this; } func load_factor() { return (this.count * 1.0f) / (this.capacity * 1.0f); } func resize(new_capacity: Int) { val old_buckets = this.buckets; this.buckets = List.from_function(|_| => [], new_capacity); this.capacity = new_capacity; this.count = 0; for bucket in old_buckets { for entry in bucket { if entry isa Map.Entry { this.set(entry.key, entry.value); } } } } func keys() { val remaining = this.len(); val ret = []; val buckets_len = this.buckets.len(); for bucket in this.buckets { for entry in bucket { if entry isa Map.Entry { ret.append(entry.key); remaining -= 1; if remaining == 0 { return ret; } } } } assert remaining == 0; return ret; } func prettyprint() { val first = true; val ret = ""; val count = this.len(); for bucket in this.buckets { for entry in bucket { if entry isa Map.Entry { if first { ret = "[{0}]->{1}".format(entry.key, entry.value); first = false; } else { ret = ret + ", [{0}]->{1}".format(entry.key, entry.value); } count -= 1; if count == 0 { return "Map(" + ret + ")"; } } } } return "Map(" + ret + ")"; } func set(k,v) { if this.load_factor() > 0.7f { this.resize(this.capacity * 2); } val h = this.calc_hash(k); val bucket = this.buckets[h]; val bucket_len = bucket.len(); val idx = 0; val need_append = true; val len_increase = true; while idx < bucket_len { match bucket[idx] { isa Map.Entry => { if bucket[idx].key == k { len_increase = false; # key overwrite does not increase len bucket[idx].value = v; need_append = false; break; } }, isa Maybe => { bucket[idx] = Map.Entry.new(k,v); need_append = false; break; } } idx = idx + 1; } if need_append { bucket.append(Map.Entry.new(k,v)); } if len_increase { this.count += 1; } return len_increase; } func remove(k) { val h = this.calc_hash(k); val bucket = this.buckets[h]; val bucket_len = bucket.len(); val idx = 0; while idx < bucket_len { match bucket[idx] { isa Map.Entry => { if bucket[idx].key == k { assert this.count > 0; this.count -= 1; bucket[idx] = Maybe::None; return true; } } } idx = idx + 1; } return false; } func get(k) { val h = this.calc_hash(k); val bucket = this.buckets[h]; val bucket_len = bucket.len(); for entry in bucket { if (entry isa Map.Entry) && entry.key == k { return Maybe::Some(entry.value); } } return Maybe::None; } func contains(k) { return this.get(k).is_Some(); } func len() { return this.count; } operator [](k) { return this.get(k).unwrap_Some(); } operator []=(k,v) { return this.set(k,v); } struct MapIterator { type func new(m: Map) { return alloc(This){ .buckets = m.buckets, .bucket_idx = 0, .entry_idx = 0, }; } func next() { val buckets = this.buckets; val num_buckets = buckets.len(); while this.bucket_idx < num_buckets { val bucket = buckets[this.bucket_idx]; while this.entry_idx < bucket.len() { val entry = bucket[this.entry_idx]; this.entry_idx += 1; if entry isa Map.Entry { return Maybe::Some(Box(){ .key = entry.key, .value = entry.value }); } } this.bucket_idx += 1; this.entry_idx = 0; } return Maybe::None; } include Iterator } func iterator() { return Map.MapIterator.new(this); } include Iterable } ================================================ FILE: lib/aria/structures/queue.aria ================================================ # SPDX-License-Identifier: Apache-2.0 struct PriorityQueue { type func new() = This.new_with_comparator(|x,y| => x < y); type func new_with_comparator(cmp) = alloc(This) { .data = [], .cmp, }; func push(item) { this.data.append(item); this._sift_up(this.data.len() - 1); } func pop() { val top = this.data[0]; val last = this.data.drop(); if this.data.len() > 0 { this.data[0] = last; this._sift_down(0); } return top; } func peek() { return this.data.len() == 0 ? Maybe::None : Maybe::Some(this.data[0]); } func len() { return this.data.len(); } func _sift_up(index) { val i = index; while i > 0 { val parent = (i - 1) / 2; if this.cmp(this.data[i], this.data[parent]) { val tmp = this.data[i]; this.data[i] = this.data[parent]; this.data[parent] = tmp; i = parent; } else { break; } } } func _sift_down(index) { val i = index; val n = this.data.len(); while true { val left = 2 * i + 1; val right = 2 * i + 2; val smallest = i; if left < n && this.cmp(this.data[left], this.data[smallest]) { smallest = left; } if right < n && this.cmp(this.data[right], this.data[smallest]) { smallest = right; } if smallest == i { break; } val tmp = this.data[i]; this.data[i] = this.data[smallest]; this.data[smallest] = tmp; i = smallest; } } } ================================================ FILE: lib/aria/structures/set.aria ================================================ # SPDX-License-Identifier: Apache-2.0 import Map from aria.structures.map; struct Set { type func new() = alloc(This) { .impl = Map.new(), }; type func new_with_items(...) { val ret = Set.new(); for item in varargs { ret.set(item); } return ret; } func set(x) { this.impl.set(x, true); } func contains(x) { return this.impl.contains(x); } func remove(x) { this.impl.remove(x); } func len() { return this.impl.len(); } func union(other) { val ret = Set.new(); for x in this { ret.set(x); } for x in other { ret.set(x); } return ret; } func intersection(other) { val ret = Set.new(); for x in this { if other.contains(x) { ret.set(x); } } return ret; } func difference(other) { val ret = Set.new(); for x in this { if !other.contains(x) { ret.set(x); } } return ret; } struct SetIterator { type func new(set) { return alloc(This) { .impl = set.impl.iterator(), }; } func next() { val nv = this.impl.next(); return Maybe::Some(nv?.key); } } func iterator() { return Set.SetIterator.new(this); } } ================================================ FILE: lib/aria/structures/stack.aria ================================================ # SPDX-License-Identifier: Apache-2.0 struct Stack { type func new() = alloc(This) { .store = [], .count = 0, }; func len() { return this.count; } func is_empty() { return this.count == 0; } func push(x) { if this.count == this.store.len() { this.store.append(x); } else { this.store[this.count] = x; } this.count += 1; } func peek_at(offset) { if offset >= this.count { return Maybe::None; } else { return Maybe::Some(this.store[this.count - 1 - offset]); } } func peek() { return this.peek_at(0); } func try_pop() { val p = this.peek(); match p { case Some => { assert this.count > 0; this.count -= 1; } } return p; } func pop() { return this.try_pop().unwrap_Some(); } } ================================================ FILE: lib/aria/system/coloring.aria ================================================ # SPDX-License-Identifier: Apache-2.0 enum Color { case Black, case Red, case Green, case Yellow, case Blue, case Magenta, case Cyan, case White, case BrightBlack, case BrightRed, case BrightGreen, case BrightYellow, case BrightBlue, case BrightMagenta, case BrightCyan, case BrightWhite, struct RGB { type func new(red: Int, green: Int, blue: Int) { if red < 0 { red *= -1; } if green < 0 { green *= -1; } if blue < 0 { blue *= -1; } red = red % 256; green = green % 256; blue = blue % 256; return alloc(This) { .red, .green, .blue }; } type func new_with_hex_string(s: String) { if s.len() == 7 && s[0] == '#' { s = s.substring(1, s.len()); } if s.len() != 6 { return Result::Err("Invalid RGB hex string length"); } val red = s.substring(0,1); val green = s.substring(2,3); val blue = s.substring(4,5); val red = Int.parse_radix(red, 16)?; val green = Int.parse_radix(green, 16)?; val blue = Int.parse_radix(blue, 16)?; return Result::Ok(This.new(red, green, blue)); } func prettyprint() { return "RGB({0}, {1}, {2})".format(this.red, this.green, this.blue); } func to_ansi_sequence() { return "2;{0};{1};{2}".format(this.red, this.green, this.blue); } } case RGB(Color.RGB), } extension Color { func prettyprint() { match this { case Black => { return "Black"; }, case Red => { return "Red"; }, case Green => { return "Green"; }, case Yellow => { return "Yellow"; }, case Blue => { return "Blue"; }, case Magenta => { return "Magenta"; }, case Cyan => { return "Cyan"; }, case White => { return "White"; }, case BrightBlack => { return "Bright Black"; }, case BrightRed => { return "Bright Red"; }, case BrightGreen => { return "Bright Green"; }, case BrightYellow => { return "Bright Yellow"; }, case BrightBlue => { return "Bright Blue"; }, case BrightMagenta => { return "Bright Magenta"; }, case BrightCyan => { return "Bright Cyan"; }, case BrightWhite => { return "Bright White"; }, case RGB(r) => { return r.prettyprint(); }, } } } extension Color { func to_ansi_sequence(fg: Bool) { match this { case Black => { return fg ? "30" : "40"; }, case Red => { return fg ? "31" : "41"; }, case Green => { return fg ? "32" : "42"; }, case Yellow => { return fg ? "33" : "43"; }, case Blue => { return fg ? "34" : "44"; }, case Magenta => { return fg ? "35" : "45"; }, case Cyan => { return fg ? "36" : "46"; }, case White => { return fg ? "37" : "47"; }, case BrightBlack => { return fg ? "90" : "100"; }, case BrightRed => { return fg ? "91" : "101"; }, case BrightGreen => { return fg ? "92" : "102"; }, case BrightYellow => { return fg ? "93" : "103"; }, case BrightBlue => { return fg ? "94" : "104"; }, case BrightMagenta => { return fg ? "95" : "105"; }, case BrightCyan => { return fg ? "96" : "106"; }, case BrightWhite => { return fg ? "97" : "107"; }, case RGB(r) => { val color_seq = r.to_ansi_sequence(); return "{0};{1}".format(fg ? 38 : 48, color_seq); } } } } struct ColorScheme { type func new() = alloc(This).reset(); func reset() { this.bold = false; this.fg = Maybe::None; this.bg = Maybe::None; return this; } func with_background_color(c: Color) { this.bg = Maybe::Some(c); return this; } func with_foreground_color(c: Color) { this.fg = Maybe::Some(c); return this; } func with_bold(b: Bool) { this.bold = b; return this; } func apply(s: String) { val result = s; val flags_on = []; val flags_off = []; if this.bold { flags_on.append("1"); flags_off.append("22"); } match this.fg { case Some(c) => { flags_on.append(c.to_ansi_sequence(true)); flags_off.append("39"); }, } match this.bg { case Some(c) => { flags_on.append(c.to_ansi_sequence(false)); flags_off.append("49"); }, } assert flags_on.len() == flags_off.len(); if flags_on.len() == 0 { return result; } else { return "\x1b[{0}m{1}\x1b[{2}m".format(";".join(flags_on), result, ";".join(flags_off)); } } func prettyprint() { val fg_string = "foreground: default"; match this.fg { case Some(c) => { fg_string = "foreground: " + c.prettyprint(); }, } val bg_string = "background: default"; match this.bg { case Some(c) => { bg_string = "background: " + c.prettyprint(); }, } val bold_string = this.bold ? "bold: on" : "bold: off"; return "color scheme: " + fg_string + " " + bg_string + " " + bold_string; } } extension String { func with_background_color(c: Color) { return "\x1b[{0}m{1}\x1b[49m".format(c.to_ansi_sequence(false), this); } func with_foreground_color(c: Color) { return "\x1b[{0}m{1}\x1b[39m".format(c.to_ansi_sequence(true), this); } func with_bold() { return "\x1b[1m{0}\x1b[22m".format(this); } func with_style(s: ColorScheme) { return s.apply(this); } func black() = this.with_foreground_color(Color::Black); func red() = this.with_foreground_color(Color::Red); func green() = this.with_foreground_color(Color::Green); func yellow() = this.with_foreground_color(Color::Yellow); func blue() = this.with_foreground_color(Color::Blue); func magenta() = this.with_foreground_color(Color::Magenta); func cyan() = this.with_foreground_color(Color::Cyan); func white() = this.with_foreground_color(Color::White); func black_bg() = this.with_background_color(Color::Black); func red_bg() = this.with_background_color(Color::Red); func green_bg() = this.with_background_color(Color::Green); func yellow_bg() = this.with_background_color(Color::Yellow); func blue_bg() = this.with_background_color(Color::Blue); func magenta_bg() = this.with_background_color(Color::Magenta); func cyan_bg() = this.with_background_color(Color::Cyan); func white_bg() = this.with_background_color(Color::White); func bright_black() = this.with_foreground_color(Color::BrightBlack); func bright_red() = this.with_foreground_color(Color::BrightRed); func bright_green() = this.with_foreground_color(Color::BrightGreen); func bright_yellow() = this.with_foreground_color(Color::BrightYellow); func bright_blue() = this.with_foreground_color(Color::BrightBlue); func bright_magenta() = this.with_foreground_color(Color::BrightMagenta); func bright_cyan() = this.with_foreground_color(Color::BrightCyan); func bright_white() = this.with_foreground_color(Color::BrightWhite); func bright_black_bg() = this.with_background_color(Color::BrightBlack); func bright_red_bg() = this.with_background_color(Color::BrightRed); func bright_green_bg() = this.with_background_color(Color::BrightGreen); func bright_yellow_bg() = this.with_background_color(Color::BrightYellow); func bright_blue_bg() = this.with_background_color(Color::BrightBlue); func bright_magenta_bg() = this.with_background_color(Color::BrightMagenta); func bright_cyan_bg() = this.with_background_color(Color::BrightCyan); func bright_white_bg() = this.with_background_color(Color::BrightWhite); } ================================================ FILE: lib/aria/system/platform.aria ================================================ # SPDX-License-Identifier: Apache-2.0 flag: uses_dylib("aria_platform"); enum Platform { struct LinuxPlatform { type func new(kernel_version: String) { return alloc(This) { .kernel_version = kernel_version }; } func prettyprint() { return "Linux kernel version: {0}".format(this.kernel_version); } func name() { return "Linux"; } } struct macOSPlatform { type func new(os_build: String) { return alloc(This) { .os_build = os_build }; } func prettyprint() { return "macOS build: {0}".format(this.os_build); } func name() { return "macOS"; } } # code in the native layer relies on the order of these cases # if we ever add or change cases, go update the code in # native-libs/platform/src/lib.rs to match the case numbering case Linux(Platform.LinuxPlatform), case macOS(Platform.macOSPlatform), case Unknown, func prettyprint() { match this { case Linux(platform) => { return platform.prettyprint(); } case macOS(platform) => { return platform.prettyprint(); } case Unknown => { return "Unknown platform"; } } } func name() { match this { case Linux(platform) => { return platform.name(); } case macOS(platform) => { return platform.name(); } case Unknown => { return "Unknown platform"; } } } } ================================================ FILE: lib/aria/test/test.aria ================================================ # SPDX-License-Identifier: Apache-2.0 enum TestResult { case Pass, case Fail(String) } extension TestResult { func prettyprint() { match this { case Pass => { return "passed"; }, case Fail(e) => { return prettyprint(e); }, } } } struct ComparisonMismatch { type func new(expected, actual, description) { return alloc(This) { .expected = expected, .actual = actual, .description = description }; } instance func prettyprint() { return "expected: {0} {1} {2}, but it was not".format(this.actual, this.description, this.expected); } } struct OperationFailure { type func new(operation, message) { return alloc(This) { .operation = operation, .message = message }; } instance func prettyprint() { return "operation {0} expected to {1}".format(this.operation, this.message); } } mixin TestCase { # this.test() is required, and expected to not throw any errors # if test.setup() and test.teardown() are defined they will be called # encourage tests to use setup/teardown for any non trivial construction type func new() { return alloc(This); } func run() { if hasattr(this, "setup") { try { this.setup(); # setup cannot return error, but can throw } catch e { return TestResult::Fail("setup error: {0}".format(e)); } } val ret = TestResult::Pass; try { this.test(); # test cannot return error, but can throw } catch e { ret = TestResult::Fail("test failure: {0}".format(e)); } if hasattr(this, "teardown") { try { this.teardown(); } catch e { # ignore teardown errors for now # should a teardown error cause a test to fail? probably not } } return ret; } func assert_equal(expected, actual) { if expected != actual { throw ComparisonMismatch.new(expected, actual, "equal to"); } } func assert_not_equal(expected, actual) { if expected == actual { throw ComparisonMismatch.new(expected, actual, "different from"); } } func assert_throws(f) { try { f(); throw OperationFailure.new(prettyprint(f), "throw but didn't"); } catch e { # this is expected } } } struct TestSuite { type func new(name) { return alloc(This) { .name = name, .tests = [] }; } instance func add_test(test) { this.tests.append(test); return this; } instance func run(silent=false) { val num_fail = 0; val num_pass = 0; for test in this.tests { val result = test.run(); if !silent { println("{0}: {1}".format(prettyprint(test), result.prettyprint())); } if result.is_Fail() { num_fail += 1; } else { num_pass += 1; } } if !silent { println("{0} tests, {1} passed, {2} failed".format(this.tests.len(), num_pass, num_fail)); } return num_fail; } } ================================================ FILE: lib/aria/utils/guard.aria ================================================ # SPDX-License-Identifier: Apache-2.0 import ok,err from aria.core.result; func guard(x) = GuardImpl.new(x); struct GuardImpl { struct GuardError { type func new(msg) = alloc(This) { .msg }; func prettyprint() = "GuardError: {0}".format(this.msg); } type func new(obj) = alloc(This) { .obj }; func _call_guard_exit() { if hasattr(this.obj, "guard_exit") { val arity_exit = arity(this.obj.guard_exit); if arity_exit.can_call_with_argc(0) { try { this.obj.guard_exit(); } catch _ { # ignore errors during guard_exit in this context } } } } func do(f) { val arity_f = arity(f); if !arity_f.can_call_with_argc(1) { return Result::Err(GuardError::new("guard function must take exactly one argument")); } try { val ret = f(this.obj); this._call_guard_exit(); return ret?; } catch e { this._call_guard_exit(); throw e; } } } ================================================ FILE: lib-test/README.md ================================================ # lib/test lib/test contains modules to test Aria's import subsystem These modules should not be used in production Aria programs as they are unstable and subject to change without notice ================================================ FILE: lib-test/all/source.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func something(x,y) { return x + y - 1; } func something_else(x,y,z) { return something(x,y) + z; } struct SomeType { type func new() { return alloc(This) { .x = 1, }; } instance func do_something() { this.x = something(this.x, 3); return this; } } ================================================ FILE: lib-test/attributes/things.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func foo(x,y) { return x + y; } struct Bar { type func new() { return alloc(This); } } enum A { case X } mixin Something { func answer() { return 42; } } ================================================ FILE: lib-test/base_module/nested_module/content.aria ================================================ # SPDX-License-Identifier: Apache-2.0 struct Foo { func answer() { return 42; } } ================================================ FILE: lib-test/circular/one.aria ================================================ # SPDX-License-Identifier: Apache-2.0 import circular.two; ================================================ FILE: lib-test/circular/two.aria ================================================ # SPDX-License-Identifier: Apache-2.0 import circular.zero; ================================================ FILE: lib-test/circular/zero.aria ================================================ # SPDX-License-Identifier: Apache-2.0 import circular.one; ================================================ FILE: lib-test/cool_widget/buzz.aria ================================================ # SPDX-License-Identifier: Apache-2.0 struct Buzz { func prettyprint() { return "Buzz is 25 years old"; } } ================================================ FILE: lib-test/cool_widget/lib.aria ================================================ # SPDX-License-Identifier: Apache-2.0 import Buzz from widget.buzz; import A from other_widget.a; import B from other_widget.a; struct Paco { type func build_buzz() { return alloc(Buzz); } } struct AWrapper { type func new() { return alloc(AWrapper) { .a = alloc(A) }; } func prettyprint() { return this.a.prettyprint(); } } struct BWrapper { type func new() { return alloc(BWrapper) { .b = B.new() }; } func prettyprint() { return this.b.prettyprint(); } } ================================================ FILE: lib-test/cool_widget/widget.json ================================================ {} ================================================ FILE: lib-test/example/pair/Pair.aria ================================================ # SPDX-License-Identifier: Apache-2.0 struct Pair { type func new(x,y) { return alloc(This){ .x = x, .y = y, }; } func swap() { return Pair.new(this.y, this.x); } } extension Pair { func max() { if this.x > this.y { return this.x; } else { return this.y; } } } ================================================ FILE: lib-test/example/two/things.aria ================================================ # SPDX-License-Identifier: Apache-2.0 struct One { type func new(x) { return alloc(This) { .x = x + 1, }; } func double() { return this.x + this.x; } } struct Two { type func new(x) { return alloc(This) { .x = x - 1, }; } func half() { return this.x / 2; } } ================================================ FILE: lib-test/exported_var/source.aria ================================================ # SPDX-License-Identifier: Apache-2.0 val foo = 123; func change_foo(x) { foo = x; } func fetch_foo() { return foo; } ================================================ FILE: lib-test/ext/string.aria ================================================ # SPDX-License-Identifier: Apache-2.0 extension String { func test_method() { return this.len() + 1; } } ================================================ FILE: lib-test/extensible/base.aria ================================================ # SPDX-License-Identifier: Apache-2.0 struct Base { type func new(x,y) { return alloc(This){ .x = x, .y = y, }; } func swap() { return Base.new(this.y, this.x); } } ================================================ FILE: lib-test/extensible/ext.aria ================================================ # SPDX-License-Identifier: Apache-2.0 import extensible.base; import Base from extensible.base; extension extensible.base.Base { func move(x,y) { this.x = this.x + x; this.y = this.y + y; return this; } func one_right() { return this.move(0,1); } func one_up() { return this.move(1,0); } func prettyprint() { return "({0},{1})".format(this.x, this.y); } } ================================================ FILE: lib-test/multiple/module.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func one(x,y) { return x + y; } func two(x,y) { return x * y; } ================================================ FILE: lib-test/other_widget/a.aria ================================================ # SPDX-License-Identifier: Apache-2.0 import InnerB from widget.mod.b; struct A { type func new() { return alloc(A); } func prettyprint() { return "A"; } } struct B { type func new() { return alloc(B) { .b = alloc(InnerB) }; } func prettyprint() { return this.b.prettyprint(); } } ================================================ FILE: lib-test/other_widget/mod/b.aria ================================================ # SPDX-License-Identifier: Apache-2.0 struct InnerB { func prettyprint() { return "InnerB"; } } ================================================ FILE: lib-test/other_widget/widget.json ================================================ {} ================================================ FILE: lib-test/same_root/part1/file1.aria ================================================ # SPDX-License-Identifier: Apache-2.0 import same_root.part1.file2; struct Foo { include same_root.part1.file2.Something type func new() { return alloc(This) { .value = 123, }; } } ================================================ FILE: lib-test/same_root/part1/file2.aria ================================================ # SPDX-License-Identifier: Apache-2.0 mixin Something { func answer() { return 42 + this.value; } } ================================================ FILE: lib-test/same_root/part1/file3.aria ================================================ # SPDX-License-Identifier: Apache-2.0 import same_root.part1.file2; struct MeFirst { include same_root.part1.file2.Something type func new() { return alloc(This) { .value = 321, }; } } ================================================ FILE: lib-test/test_things.aria ================================================ # SPDX-License-Identifier: Apache-2.0 val x = 1; func foo(x,y) { return x + y; } func bar(y) { return x + y; } ================================================ FILE: lib-test/with_err/error.aria ================================================ # SPDX-License-Identifier: Apache-2.0 struct 123 {}; ================================================ FILE: lsp/Cargo.toml ================================================ [package] name = "lsp" version = "0.1.0" edition = "2024" [dependencies] logos = "0.16.1" rowan = "0.16.1" line-index = "0.1.2" tower-lsp = "0.20.0" tokio = { version = "1.49.0", features = ["full"] } parking_lot = "0.12" [dev-dependencies] pretty_assertions = "1.4.1" ================================================ FILE: lsp/src/document.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use std::collections::HashMap; use std::sync::Arc; use crate::parser::{self, Parse, SyntaxNode, SyntaxToken}; use line_index::{LineCol, LineIndex}; use rowan::{TextRange, TextSize}; #[derive(Clone)] pub struct DocumentState { text: Arc, text_size: TextSize, line_index: Arc, parse: Arc, defs: HashMap>, } impl DocumentState { pub fn new(text: String) -> Self { let line_index = LineIndex::new(&text); let parse = parser::parse(&text); let syntax = parse.syntax(); let defs = build_index(&syntax); Self { text_size: TextSize::of(&text), text: Arc::new(text), parse: Arc::new(parse), line_index: Arc::new(line_index), defs, } } pub fn update_text(&mut self, text: String) { self.text_size = TextSize::of(&text); self.text = Arc::new(text); self.line_index = Arc::new(LineIndex::new(&self.text)); let parse = parser::parse(&self.text); let syntax = parse.syntax(); self.parse = Arc::new(parse); self.defs = build_index(&syntax); } pub fn token_at_line_col(&self, line: u32, col: u32) -> Option { let line_col = line_index::LineCol { line, col }; let offset = self.line_index.offset(line_col)?; use crate::lexer::SyntaxKind as K; if offset > self.text_size { return None; } match self.parse.syntax().token_at_offset(offset) { rowan::TokenAtOffset::Single(tok) => Some(tok), rowan::TokenAtOffset::Between(left, right) => { // Prefer non-trivia if possible let is_trivia = |t: &SyntaxToken| matches!(t.kind(), K::Whitespace | K::LineComment); match (is_trivia(&left), is_trivia(&right)) { (false, false) => Some(left), (false, true) => Some(left), (true, false) => Some(right), (true, true) => Some(left), } } rowan::TokenAtOffset::None => None, } } pub fn line_col(&self, offset: rowan::TextSize) -> LineCol { self.line_index.line_col(offset) } pub fn text(&self) -> String { self.text.to_string() } pub fn offset_at_line_col(&self, line: u32, col: u32) -> Option { let lc = line_index::LineCol { line, col }; self.line_index.offset(lc) } pub fn def(&self, line: u32, col: u32) -> Option { let tok = self.token_at_line_col(line, col)?; if tok.kind() == crate::lexer::SyntaxKind::Identifier { let name = tok.text(); let at = tok.text_range().start(); let entries = self.defs.get(name)?; let mut candidates: Vec<&DefEntry> = entries .iter() .filter(|e| e.scope_range.contains(at) && (e.hoisted || e.decl_start <= at)) .collect(); if candidates.is_empty() { candidates = entries.iter().filter(|e| e.hoisted).collect(); } candidates .into_iter() .min_by(|a, b| { use std::cmp::Ordering; let len_ord = a.scope_range.len().cmp(&b.scope_range.len()); if len_ord != Ordering::Equal { return len_ord; } // Prefer later declaration start (descending) b.decl_start.cmp(&a.decl_start) }) .map(|e| e.def_range) } else { None } } pub fn parse_error_ranges(&self) -> Vec<(TextRange, String)> { let mut out: Vec<(TextRange, String)> = Vec::new(); for err in self.parse.errors() { let msg = format!("expected {:?}", err.expected()); if let Some(pos) = err.pos() { let start = TextSize::from(pos.start as u32); let end = TextSize::from(pos.end as u32); out.push((TextRange::new(start, end), msg)); } else { let eof = self.text_size; out.push((TextRange::new(eof, eof), msg)); } } out } } #[derive(Clone, Copy, Debug)] struct DefEntry { def_range: TextRange, scope_range: TextRange, decl_start: TextSize, hoisted: bool, } fn build_index(root: &SyntaxNode) -> HashMap> { use crate::lexer::SyntaxKind as K; let mut defs: HashMap> = HashMap::new(); for node in root.descendants() { match node.kind() { K::StmtVal | K::Param | K::Func => { if let Some(tok) = node .children_with_tokens() .filter_map(|e| e.into_token()) .find(|t| t.kind() == K::Identifier) { let name = tok.text().to_string(); let mut scope_owner = node.parent(); while let Some(parent) = scope_owner.clone() { match parent.kind() { K::Func | K::Block => break, _ => scope_owner = parent.parent(), } } let (scope_range, hoisted) = match scope_owner.as_ref() { Some(owner) => (owner.text_range(), false), None => (root.text_range(), true), }; let entry = DefEntry { def_range: tok.text_range(), scope_range, decl_start: tok.text_range().start(), hoisted, }; defs.entry(name).or_default().push(entry); } } _ => {} } } defs } #[cfg(test)] mod tests { use crate::lexer::SyntaxKind; use super::*; fn sample_text() -> String { // 0: "val x = 1;" // 1: "func foo(a, b) {}" // 2: "func bar() { val y = 2; }" "val x = 1;\nfunc foo(a, b) {}\nfunc bar() { val y = 2; }\n".to_string() } #[test] fn token_at_line_col_out_of_bounds_is_none() { let doc = DocumentState::new(sample_text()); assert!(doc.token_at_line_col(0, 10_000).is_none()); } #[test] fn line_col_matches_token_start() { let mut doc = DocumentState::new(sample_text()); let x_tok = doc.token_at_line_col(0, 4).expect("token x"); assert_eq!(x_tok.text(), "x"); assert_eq!(x_tok.kind(), SyntaxKind::Identifier); doc.update_text(sample_text() + "\nval x = 5;"); let func_tok = doc.token_at_line_col(1, 0).expect("token func"); assert_eq!(func_tok.text(), "func"); assert_eq!(func_tok.kind(), SyntaxKind::FuncKwd); } #[test] fn parse_errors_include_expected_tokens() { let text = "val x".to_string(); let doc = DocumentState::new(text); let errs = doc.parse_error_ranges(); assert!(!errs.is_empty(), "should report at least one parse error"); assert!( errs.iter() .any(|(_, m)| m.contains("Assign") || m.contains("Semicolon")), "message should mention expected token like Assign or Semicolon: {:?}", errs ); } } ================================================ FILE: lsp/src/lexer.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use logos::Logos; #[derive(Logos, Debug, Clone, PartialEq, Hash, Eq, PartialOrd, Ord, Copy)] #[repr(u16)] pub enum SyntaxKind { #[token("assert")] AssertKwd, #[token("break")] BreakKwd, #[token("case")] CaseKwd, #[token("catch")] CatchKwd, #[token("continue")] ContinueKwd, #[token("else")] ElseKwd, #[token("elsif")] ElsifKwd, #[token("enum")] EnumKwd, #[token("extension")] ExtensionKwd, #[token("flag")] FlagKwd, #[token("for")] ForKwd, #[token("from")] FromKwd, #[token("func")] FuncKwd, #[token("if")] IfKwd, #[token("import")] ImportKwd, #[token("in")] InKwd, #[token("include")] IncludeKwd, #[token("instance")] InstanceKwd, #[token("isa")] IsaKwd, #[token("match")] MatchKwd, #[token("mixin")] MixinKwd, #[token("operator")] OperatorKwd, #[token("return")] ReturnKwd, #[token("reverse")] ReverseKwd, #[token("struct")] StructKwd, #[token("throw")] ThrowKwd, #[token("try")] TryKwd, #[token("type")] TypeKwd, #[token("val")] ValKwd, #[token("while")] WhileKwd, #[token("and")] AndKwd, #[token("+")] Plus, #[token("-")] Minus, #[token("u-")] UnaryMinus, #[token("*")] Star, #[token("/")] Slash, #[token("%")] Percent, #[token("<<=")] LeftShiftAssign, #[token(">>=")] RightShiftAssign, #[token("<<")] LeftShift, #[token(">>")] RightShift, #[token("==")] Equal, #[token("!=")] NotEqual, #[token("<=")] LessEqual, #[token(">=")] GreaterEqual, #[token("<")] Less, #[token(">")] Greater, #[token("&&")] LogicalAnd, #[token("||")] LogicalOr, #[token("&")] BitwiseAnd, #[token("|")] Pipe, #[token("^")] BitwiseXor, #[token("!")] Not, #[token("=")] Assign, #[token("+=")] PlusAssign, #[token("-=")] MinusAssign, #[token("*=")] StarAssign, #[token("/=")] SlashAssign, #[token("%=")] PercentAssign, #[token("?")] Question, #[token(":")] Colon, #[token("::")] DoubleColon, #[token("=>")] Arrow, #[token("...")] Ellipsis, #[token("(")] LeftParen, #[token(")")] RightParen, #[token("[")] LeftBracket, #[token("]")] RightBracket, #[token("{")] LeftBrace, #[token("}")] RightBrace, #[token(",")] Comma, #[token(";")] Semicolon, #[token(".")] Dot, #[token("true")] TrueKwd, #[token("false")] FalseKwd, #[regex(r"0x[0-9a-fA-F]+(_[0-9a-fA-F]+)*")] HexIntLiteral, #[regex(r"0o[0-7]+(_[0-7]+)*")] OctIntLiteral, #[regex(r"0b[01]+(_[01]+)*")] BinIntLiteral, #[regex(r"[0-9]+(_[0-9]+)*")] DecIntLiteral, #[regex(r"[0-9]+\.[0-9]+([eE][+-]?[0-9]+)?f?")] FloatLiteral, #[regex(r#""([^"\\]|\\.)*""#)] #[regex(r#"'([^'\\]|\\.)*'"#)] StringLiteral, #[regex( r#"[\p{XID_Start}\p{Emoji_Presentation}_$][\p{XID_Continue}\p{Emoji_Presentation}_$]*"#, priority = 1 )] Identifier, // trivia #[regex(r"[ \t\n\f]+")] Whitespace, #[regex(r"#[^\n]*", allow_greedy = true)] LineComment, // Error token for unrecognized input Error, // compound types File, ErrorTree, Func, Lambda, Block, ParamList, Param, StmtVal, StmtReturn, StmtExpr, StmtIf, StmtFor, StmtMatch, StmtWhile, StmtImport, StmtAssert, ExprName, ExprCall, ExprBinary, ExprUnary, ExprParen, ExprLiteral, ExprMember, ExprIndex, ExprTernary, ExprAssign, ExprType, ExprNonNull, ExprNullish, Mixin, MixinInclude, MixinEntry, Struct, StructEntry, Enum, EnumCase, EnumEntry, Extension, Operator, Guard, TryBlock, MatchRule, MatchPattern, IdentList, QualifiedIdent, ImportPath, ArgList, ListLiteral, ModuleFlag, Eof, } pub fn lex(s: &str) -> Vec> { let mut lexer = SyntaxKind::lexer(s); let mut tokens = Vec::new(); while let Some(token_result) = lexer.next() { let slice = lexer.slice(); match token_result { Ok(token) => tokens.push(Ok((token, slice, lexer.span()))), Err(_) => { let span = lexer.span(); tokens.push(Err(LexError { message: format!("Unexpected character(s): '{slice}'"), span, text: slice.to_string(), })); } } } tokens } #[derive(Debug, Clone, PartialEq)] pub struct LexError { pub message: String, pub span: std::ops::Range, pub text: String, } #[cfg(test)] mod tests { use super::*; fn non_trivia_tokens(input: &str) -> Vec { use SyntaxKind::*; lex(input) .into_iter() .filter_map(|r| r.ok()) .map(|(k, _, _)| k) .filter(|k| !matches!(k, Whitespace | LineComment)) .collect() } #[test] fn test_keywords() { let tokens = non_trivia_tokens("func if else while"); assert_eq!(tokens.len(), 4); assert_eq!(tokens[0], SyntaxKind::FuncKwd); assert_eq!(tokens[1], SyntaxKind::IfKwd); assert_eq!(tokens[2], SyntaxKind::ElseKwd); assert_eq!(tokens[3], SyntaxKind::WhileKwd); } #[test] fn test_identifiers() { let tokens = non_trivia_tokens("myVar _private $special"); assert_eq!(tokens.len(), 3); assert_eq!(tokens[0], SyntaxKind::Identifier); assert_eq!(tokens[1], SyntaxKind::Identifier); assert_eq!(tokens[2], SyntaxKind::Identifier); } #[test] fn test_literals() { let tokens = non_trivia_tokens(r#"42 0x1A 0o77 0b101 3.14 "hello" 'world'"#); assert_eq!(tokens.len(), 7); assert_eq!(tokens[0], SyntaxKind::DecIntLiteral); assert_eq!(tokens[1], SyntaxKind::HexIntLiteral); assert_eq!(tokens[2], SyntaxKind::OctIntLiteral); assert_eq!(tokens[3], SyntaxKind::BinIntLiteral); assert_eq!(tokens[4], SyntaxKind::FloatLiteral); assert_eq!(tokens[5], SyntaxKind::StringLiteral); assert_eq!(tokens[6], SyntaxKind::StringLiteral); } #[test] fn test_operators() { let tokens = non_trivia_tokens("+ - * / % == != <= >= << >> && ||"); assert_eq!(tokens.len(), 13); assert_eq!(tokens[0], SyntaxKind::Plus); assert_eq!(tokens[1], SyntaxKind::Minus); assert_eq!(tokens[2], SyntaxKind::Star); assert_eq!(tokens[3], SyntaxKind::Slash); assert_eq!(tokens[4], SyntaxKind::Percent); assert_eq!(tokens[5], SyntaxKind::Equal); assert_eq!(tokens[6], SyntaxKind::NotEqual); assert_eq!(tokens[7], SyntaxKind::LessEqual); assert_eq!(tokens[8], SyntaxKind::GreaterEqual); assert_eq!(tokens[9], SyntaxKind::LeftShift); assert_eq!(tokens[10], SyntaxKind::RightShift); assert_eq!(tokens[11], SyntaxKind::LogicalAnd); assert_eq!(tokens[12], SyntaxKind::LogicalOr); } #[test] fn test_comments_and_whitespace() { let tokens = non_trivia_tokens("func # this is a comment\n main"); assert_eq!(tokens.len(), 2); assert_eq!(tokens[0], SyntaxKind::FuncKwd); assert_eq!(tokens[1], SyntaxKind::Identifier); } #[test] fn test_complex_expression() { let lexer = SyntaxKind::lexer("val x = func(a, b) { return a + b; }"); let tokens: Vec<_> = lexer.collect(); assert!(!tokens.is_empty()); assert_eq!(tokens[0], Ok(SyntaxKind::ValKwd)); } fn test_files_in_directory(dir: &str) { use std::fs; use std::path::Path; println!("reading inside {dir}"); let dir = Path::new(dir); if !dir.exists() { println!("Examples directory not found, skipping test"); return; } let entries = fs::read_dir(dir).expect("Failed to read examples directory"); for entry in entries { let entry = entry.expect("Failed to read directory entry"); let path = entry.path(); if path.extension().and_then(|s| s.to_str()) == Some("aria") { let filename = path.file_name().unwrap().to_str().unwrap(); let content = fs::read_to_string(&path).expect(&format!("Failed to read file: {}", filename)); let tokens = lex(&content); let errors: Vec<_> = tokens .iter() .filter_map(|token| token.as_ref().err()) .collect(); if !errors.is_empty() { println!("\n{} has lexer errors:", filename); for error in &errors { println!( " {} at position {}..{}", error.message, error.span.start, error.span.end ); } } assert!(errors.is_empty()); } if path.is_dir() { test_files_in_directory(path.to_path_buf().to_str().unwrap()); } } } #[test] fn test_example_files_lex_without_errors() { test_files_in_directory("../examples"); } #[test] fn test_files_lex_without_errors() { test_files_in_directory("../tests"); } #[test] fn test_std_lib_lex_without_errors() { test_files_in_directory("../lib"); } #[test] fn test_std_lib_test_lex_without_errors() { test_files_in_directory("../lib-test"); } #[test] fn test_error_reporting() { let tokens = lex("func @ invalid # comment"); let errors: Vec<_> = tokens.iter().filter_map(|t| t.as_ref().err()).collect(); if !errors.is_empty() { println!("Lexer errors found:"); for error in &errors { println!( " {} at position {}..{}", error.message, error.span.start, error.span.end ); } } let successful_tokens: Vec<_> = tokens.iter().filter_map(|t| t.as_ref().ok()).collect(); assert!(!successful_tokens.is_empty()); assert_eq!(successful_tokens[0].0, SyntaxKind::FuncKwd); } #[test] fn test_star_number_separation() { let tokens = lex("*2"); let successful_tokens: Vec<_> = tokens.iter().filter_map(|t| t.as_ref().ok()).collect(); println!("Tokens for '*2': {:?}", successful_tokens); // Should be two tokens: Star and DecIntLiteral assert_eq!(successful_tokens.len(), 2); assert_eq!(successful_tokens[0].0, SyntaxKind::Star); assert_eq!(successful_tokens[1].0, SyntaxKind::DecIntLiteral); assert_eq!(successful_tokens[0].1, "*"); assert_eq!(successful_tokens[1].1, "2"); } #[test] fn test_operator_number_separation() { // Test various operator-number combinations let test_cases = vec![ ( "*2", vec![(SyntaxKind::Star, "*"), (SyntaxKind::DecIntLiteral, "2")], ), ( "+3", vec![(SyntaxKind::Plus, "+"), (SyntaxKind::DecIntLiteral, "3")], ), ( "-4", vec![(SyntaxKind::Minus, "-"), (SyntaxKind::DecIntLiteral, "4")], ), ( "/5", vec![(SyntaxKind::Slash, "/"), (SyntaxKind::DecIntLiteral, "5")], ), ( "%6", vec![(SyntaxKind::Percent, "%"), (SyntaxKind::DecIntLiteral, "6")], ), ]; for (input, expected) in test_cases { let tokens = lex(input); let successful_tokens: Vec<_> = tokens.iter().filter_map(|t| t.as_ref().ok()).collect(); assert_eq!( successful_tokens.len(), expected.len(), "Failed for input: {}", input ); for (i, (expected_kind, expected_text)) in expected.iter().enumerate() { assert_eq!( successful_tokens[i].0, *expected_kind, "Failed kind for input: {} at position {}", input, i ); assert_eq!( successful_tokens[i].1, *expected_text, "Failed text for input: {} at position {}", input, i ); } } } #[test] fn test_emoji_identifiers() { // Test emoji identifiers still work let tokens = lex("😎 💯"); let successful_tokens: Vec<_> = tokens .into_iter() .filter_map(|t| t.ok()) .filter(|(k, _, _)| !matches!(k, SyntaxKind::Whitespace | SyntaxKind::LineComment)) .collect(); assert_eq!(successful_tokens.len(), 2); assert_eq!(successful_tokens[0].0, SyntaxKind::Identifier); assert_eq!(successful_tokens[1].0, SyntaxKind::Identifier); assert_eq!(successful_tokens[0].1, "😎"); assert_eq!(successful_tokens[1].1, "💯"); } } ================================================ FILE: lsp/src/lib.rs ================================================ // SPDX-License-Identifier: Apache-2.0 pub mod document; pub mod lexer; pub mod parser; ================================================ FILE: lsp/src/main.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use line_index::{LineCol, LineIndex}; use lsp::document::DocumentState; use rowan::TextRange; use std::collections::HashMap; use tokio::sync::mpsc::{UnboundedSender, unbounded_channel}; use tower_lsp::jsonrpc::Result; use tower_lsp::lsp_types::*; use tower_lsp::{Client, LanguageServer, LspService, Server}; #[derive(Clone)] struct Logger { tx: UnboundedSender, } impl Logger { fn new(client: Client) -> Self { let (tx, mut rx) = unbounded_channel::(); tokio::spawn(async move { while let Some(msg) = rx.recv().await { let _ = client.log_message(MessageType::INFO, msg).await; } }); Self { tx } } fn info(&self, msg: impl Into) { let _ = self.tx.send(msg.into()); } } struct Backend { logger: Logger, client: Client, documents: parking_lot::Mutex>, } impl Backend { fn info(&self, msg: String) { self.logger.info(msg); } } fn to_lsp_position(doc: &DocumentState, offset: rowan::TextSize) -> Position { let lc = doc.line_col(offset); Position::new(lc.line, lc.col) } fn to_lsp_range(doc: &DocumentState, range: TextRange) -> Range { Range::new( to_lsp_position(doc, range.start()), to_lsp_position(doc, range.end()), ) } #[tower_lsp::async_trait] impl LanguageServer for Backend { async fn initialize(&self, _: InitializeParams) -> Result { self.info("Initializing Aria LSP".to_string()); Ok(InitializeResult { server_info: None, capabilities: ServerCapabilities { text_document_sync: Some(TextDocumentSyncCapability::Kind( TextDocumentSyncKind::INCREMENTAL, )), definition_provider: Some(OneOf::Left(true)), ..ServerCapabilities::default() }, }) } async fn initialized(&self, _: InitializedParams) { self.info("Aria LSP initialized".to_string()); } async fn shutdown(&self) -> Result<()> { Ok(()) } async fn did_open(&self, params: DidOpenTextDocumentParams) { let uri = params.text_document.uri; let text = params.text_document.text; self.info(format!("opened file {uri}")); let (diags, uri_clone) = { let mut docs = self.documents.lock(); let doc = DocumentState::new(text); let diags = { let mut v = Vec::new(); for (range, msg) in doc.parse_error_ranges() { v.push(Diagnostic { range: to_lsp_range(&doc, range), severity: Some(DiagnosticSeverity::ERROR), code: None, code_description: None, source: Some("aria-parser".into()), message: msg, related_information: None, tags: None, data: None, }); } v }; docs.insert(uri.clone(), doc); (diags, uri.clone()) }; let _ = self .client .publish_diagnostics(uri_clone, diags, None) .await; } async fn did_change(&self, params: DidChangeTextDocumentParams) { let uri = params.text_document.uri; let (diags_opt, uri_clone) = { let mut docs = self.documents.lock(); if let Some(doc) = docs.get_mut(&uri) { let mut text = doc.text(); let mut index = LineIndex::new(&text); for change in params.content_changes { if let Some(range) = change.range { let Some(start_ts) = index.offset(LineCol { line: range.start.line, col: range.start.character, }) else { continue; }; let Some(end_ts) = index.offset(LineCol { line: range.end.line, col: range.end.character, }) else { continue; }; let start: usize = u32::from(start_ts) as usize; let end: usize = u32::from(end_ts) as usize; if start <= end && end <= text.len() { let mut new_text = String::with_capacity( text.len() - (end - start) + change.text.len(), ); new_text.push_str(&text[..start]); new_text.push_str(&change.text); new_text.push_str(&text[end..]); text = new_text; index = LineIndex::new(&text); } else { self.info(format!( "skipping invalid change range for {uri}: {range:?}" )); } } else { // Full text replacement text = change.text; index = LineIndex::new(&text); } } doc.update_text(text); let diags = { let mut v = Vec::new(); for (range, msg) in doc.parse_error_ranges() { v.push(Diagnostic { range: to_lsp_range(doc, range), severity: Some(DiagnosticSeverity::ERROR), code: None, code_description: None, source: Some("aria-parser".into()), message: msg, related_information: None, tags: None, data: None, }); } v }; (Some(diags), Some(uri.clone())) } else { (None, None) } }; if let (Some(diags), Some(uri2)) = (diags_opt, uri_clone) { let _ = self.client.publish_diagnostics(uri2, diags, None).await; } } async fn did_close(&self, params: DidCloseTextDocumentParams) { let uri = params.text_document.uri; let mut docs = self.documents.lock(); docs.remove(&uri); } async fn goto_definition( &self, params: GotoDefinitionParams, ) -> Result> { let uri = params.text_document_position_params.text_document.uri; let position = params.text_document_position_params.position; self.info(format!( "goto_definition {} {:?}", uri.clone(), position.clone() )); let docs = self.documents.lock(); let Some(doc) = docs.get(&uri) else { return Ok(None); }; if let Some(def_range) = doc.def(position.line, position.character) { let lsp_range = to_lsp_range(doc, def_range); let loc = Location::new(uri.clone(), lsp_range); self.info(format!("found a definition at {loc:?}")); return Ok(Some(GotoDefinitionResponse::Scalar(loc))); } self.info("no definitions found".to_string()); Ok(None) } } #[tokio::main] async fn main() { let stdin = tokio::io::stdin(); let stdout = tokio::io::stdout(); let (service, socket) = LspService::build(|client| { let logger = Logger::new(client.clone()); Backend { logger, client: client.clone(), documents: parking_lot::Mutex::new(HashMap::new()), } }) .finish(); Server::new(stdin, stdout, socket).serve(service).await; } ================================================ FILE: lsp/src/parser.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use crate::lexer::{self, SyntaxKind}; use SyntaxKind::*; use core::ops::Range; use line_index::LineIndex; use rowan::{GreenNode, GreenNodeBuilder, TextSize}; use std::cell::Cell; impl From for rowan::SyntaxKind { fn from(kind: SyntaxKind) -> Self { Self(kind as u16) } } #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] pub enum Lang {} impl rowan::Language for Lang { type Kind = SyntaxKind; fn kind_from_raw(raw: rowan::SyntaxKind) -> Self::Kind { assert!(raw.0 <= Eof as u16); unsafe { std::mem::transmute::(raw.0) } } fn kind_to_raw(kind: Self::Kind) -> rowan::SyntaxKind { kind.into() } } #[derive(Debug, Clone)] pub struct ParseError { expected: SyntaxKind, pos: Option>, } pub struct Parse { green_node: GreenNode, errors: Vec, } impl Parse { pub fn syntax(&self) -> SyntaxNode { SyntaxNode::new_root(self.green_node.clone()) } pub fn errors(&self) -> &Vec { &self.errors } } impl ParseError { pub fn expected(&self) -> SyntaxKind { self.expected } pub fn pos(&self) -> Option> { self.pos.clone() } } pub fn parse(text: &str) -> Parse { #[derive(Debug)] enum Event { Open { kind: SyntaxKind }, Close, Advance, } struct MarkOpened { index: usize, } struct MarkClosed { index: usize, } struct Parser<'a> { tokens: Vec<(SyntaxKind, &'a str, logos::Span)>, pos: usize, fuel: Cell, events: Vec, errors: Vec, line_index: LineIndex, } fn is_trivia(kind: SyntaxKind) -> bool { matches!(kind, SyntaxKind::Whitespace | SyntaxKind::LineComment) } fn prefix_binding_power(op: SyntaxKind) -> Option<((), u8)> { use SyntaxKind::*; match op { Not | Minus => Some(((), 23)), _ => None, } } fn is_expr_start(kind: SyntaxKind) -> bool { use SyntaxKind::*; matches!( kind, Identifier | HexIntLiteral | OctIntLiteral | BinIntLiteral | DecIntLiteral | FloatLiteral | StringLiteral | TrueKwd | FalseKwd | LeftParen | LeftBracket | Pipe | LogicalOr | Not | Minus ) } fn postfix_binding_power(op: SyntaxKind) -> Option<(u8, ())> { use SyntaxKind::*; match op { LeftParen | LeftBracket | Dot | DoubleColon => Some((25, ())), _ => None, } } fn infix_binding_power(op: SyntaxKind) -> Option<(u8, u8)> { use SyntaxKind::*; match op { // Assignment operators (right-associative, lowest precedence) Assign | PlusAssign | MinusAssign | StarAssign | SlashAssign | PercentAssign | LeftShiftAssign | RightShiftAssign => Some((2, 1)), LogicalOr => Some((3, 4)), LogicalAnd => Some((5, 6)), BitwiseXor => Some((7, 8)), BitwiseAnd => Some((9, 10)), Pipe => Some((11, 12)), Equal | NotEqual | IsaKwd => Some((13, 14)), Less | LessEqual | Greater | GreaterEqual => Some((15, 16)), LeftShift | RightShift => Some((17, 18)), Plus | Minus => Some((19, 20)), Star | Slash | Percent => Some((21, 22)), _ => None, } } impl Parser<'_> { fn file(&mut self) { let m: MarkOpened = self.open(); self.trivia(); while !self.eof() { match self.nth(0) { ImportKwd => self.stmt_import(), FlagKwd => self.module_flag(), StructKwd => self.decl_struct_or_ext(Struct, StructKwd), MixinKwd => self.decl_mixin(), EnumKwd => self.decl_enum(), ExtensionKwd => self.decl_struct_or_ext(Extension, ExtensionKwd), FuncKwd => self.decl_func(), _ => self.stmt(), } } self.trivia(); self.close(m, File); } fn mixin_include(&mut self) { assert!(self.at(IncludeKwd)); let m = self.open(); self.expect(IncludeKwd); let _ = self.expr(); self.close(m, MixinInclude); } fn decl_struct_or_ext(&mut self, kind: SyntaxKind, kwd: SyntaxKind) { assert!(self.at(kwd)); let m = self.open(); self.expect(kwd); if kwd == StructKwd { self.qualified_ident(); } else { let _ = self.expr(); } self.expect(LeftBrace); while !self.at(RightBrace) && !self.eof() { self.entry(StructEntry); } self.expect(RightBrace); self.close(m, kind); } fn entry(&mut self, kind: SyntaxKind) { let m = self.open(); match self.nth(0) { FuncKwd => self.decl_func(), OperatorKwd | ReverseKwd => self.decl_operator(), StructKwd => self.decl_struct_or_ext(Struct, StructKwd), EnumKwd => self.decl_enum(), IncludeKwd => self.mixin_include(), TypeKwd | InstanceKwd => { if self.nth(1) == FuncKwd { self.decl_func(); } else { self.decl_val(); } } _ => self.advance_with_error(kind), } self.close(m, StructEntry); } fn decl_enum(&mut self) { assert!(self.at(EnumKwd)); let m = self.open(); self.expect(EnumKwd); self.qualified_ident(); self.expect(LeftBrace); while !self.at(RightBrace) && !self.eof() { match self.nth(0) { CaseKwd => self.enum_case(), _ => self.enum_entry(), } if self.at(Comma) { self.expect(Comma); } } self.expect(RightBrace); self.close(m, Enum); } fn module_flag(&mut self) { assert!(self.at(FlagKwd)); let m = self.open(); self.expect(FlagKwd); self.expect(Colon); self.expect(Identifier); if self.at(LeftParen) { self.expect(LeftParen); // Value must be a string literal per grammar if self.at(StringLiteral) { self.expect(StringLiteral); } else { // fall back to generic expr to recover if not a string let _ = self.expr(); } self.expect(RightParen); } self.expect(Semicolon); self.close(m, ModuleFlag); } fn enum_case(&mut self) { assert!(self.at(CaseKwd)); let m = self.open(); self.expect(CaseKwd); self.expect(Identifier); if self.at(LeftParen) { self.expect(LeftParen); let _ = self.expr(); self.expect(RightParen); } self.close(m, EnumCase); } fn enum_entry(&mut self) { let m = self.open(); self.entry(EnumEntry); self.close(m, EnumEntry); } fn decl_mixin(&mut self) { assert!(self.at(MixinKwd)); let m = self.open(); self.expect(MixinKwd); self.qualified_ident(); self.expect(LeftBrace); while !self.at(RightBrace) && !self.eof() { self.entry(MixinEntry); } self.expect(RightBrace); self.close(m, Mixin); } fn decl_operator(&mut self) { let m = self.open(); if self.at(ReverseKwd) { self.expect(ReverseKwd); } self.expect(OperatorKwd); // Operator symbol - need to handle various operator tokens match self.nth(0) { Plus | Minus | UnaryMinus | Star | Slash | Percent | LeftShift | RightShift | Equal | LessEqual | GreaterEqual | Less | Greater | BitwiseAnd | Pipe | BitwiseXor => { self.advance(); } LeftParen => { self.advance(); self.expect(RightParen); } LeftBracket => { self.advance(); self.expect(RightBracket); if self.at(Assign) { self.expect(Assign) } } _ => self.advance_with_error(Operator), } if self.at(LeftParen) { self.param_list(LeftParen, RightParen); } self.func_body(); self.close(m, Operator); } fn decl_func(&mut self) { let m = self.open(); self.parse_access_modifier(); self.expect(FuncKwd); self.expect(Identifier); if self.at(LeftParen) { self.param_list(LeftParen, RightParen); } self.func_body(); self.close(m, Func); } fn func_body(&mut self) { if self.at(LeftBrace) { self.block(); } else if self.at(Assign) { self.expect(Assign); let _ = self.expr(); self.expect(Semicolon); } } fn parse_access_modifier(&mut self) { if self.at(TypeKwd) { self.expect(TypeKwd); } if self.at(InstanceKwd) { self.expect(InstanceKwd); } } fn param_list(&mut self, left_delim: SyntaxKind, right_delim: SyntaxKind) { self.assert_tok(left_delim); let m = self.open(); self.expect(left_delim); while !self.at(right_delim) && !self.eof() { if self.at(Identifier) || self.at(Ellipsis) { self.param(self.nth(0), right_delim); } else { break; } } self.expect(right_delim); self.close(m, ParamList); } fn param(&mut self, kind: SyntaxKind, right_delim: SyntaxKind) { assert!(self.at(kind)); let m = self.open(); self.expect(kind); if self.at(Colon) { self.type_annotation(); } // Support default value for optional parameters: name [: type] = expr if self.at(Assign) { self.expect(Assign); let _ = self.expr(); } if !self.at(right_delim) { self.expect(Comma); } self.close(m, Param); } fn type_annotation(&mut self) { self.assert_tok(Colon); self.expect(Colon); let m = self.open(); while self.at(Identifier) { self.expect(Identifier); if self.at(Dot) { self.expect(Dot); } if self.at(Pipe) { self.expect(Pipe); } if self.at(BitwiseAnd) { self.expect(BitwiseAnd); } } self.close(m, ExprType); } fn block(&mut self) { self.assert_tok(LeftBrace); let m = self.open(); self.expect(LeftBrace); while !self.at(RightBrace) && !self.eof() { self.stmt(); } self.expect(RightBrace); self.close(m, Block); } fn stmt(&mut self) { match self.nth(0) { AssertKwd => self.stmt_kwd_with_expr(AssertKwd), BreakKwd => self.stmt_single_token(BreakKwd), ContinueKwd => self.stmt_single_token(ContinueKwd), ValKwd => self.decl_val(), IfKwd => self.stmt_if(), MatchKwd => self.stmt_match(), WhileKwd => self.stmt_while(), ForKwd => self.stmt_for(), ThrowKwd => self.stmt_kwd_with_expr(ThrowKwd), ReturnKwd => self.stmt_return(), LeftBrace => self.block(), TryKwd => self.try_catch(), StructKwd => self.decl_struct_or_ext(Struct, StructKwd), EnumKwd => self.decl_enum(), FuncKwd => self.decl_func(), _ => self.stmt_expr(), } } fn stmt_if(&mut self) { assert!(self.at(IfKwd)); let m = self.open(); // if piece self.expect(IfKwd); let _ = self.expr(); self.block(); // elsif pieces while self.at(ElsifKwd) { self.expect(ElsifKwd); let _ = self.expr(); self.block(); } // optional else piece if self.at(ElseKwd) { self.expect(ElseKwd); self.block(); } self.close(m, StmtIf); } fn stmt_for(&mut self) { assert!(self.at(ForKwd)); let m = self.open(); self.expect(ForKwd); self.expect(Identifier); self.expect(InKwd); let _ = self.expr(); self.block(); // optional else piece if self.at(ElseKwd) { self.expect(ElseKwd); self.block(); } self.close(m, StmtFor); } fn stmt_match(&mut self) { assert!(self.at(MatchKwd)); let m = self.open(); self.expect(MatchKwd); let _ = self.expr(); self.expect(LeftBrace); // Parse match rules if !self.at(RightBrace) { self.match_rule(); while (self.at(Comma) || !self.at(RightBrace)) && !self.eof() { if self.at(Comma) { self.expect(Comma); } if !self.at(RightBrace) { self.match_rule(); } } if self.at(Comma) { self.expect(Comma); } } self.expect(RightBrace); // optional else piece if self.at(ElseKwd) { self.expect(ElseKwd); self.block(); } self.close(m, StmtMatch); } fn match_rule(&mut self) { let m = self.open(); self.match_pattern(); // Handle "and" patterns while self.at(AndKwd) { self.expect(AndKwd); self.match_pattern(); } self.expect(Arrow); // "=>" self.block(); self.close(m, MatchRule); } fn match_pattern(&mut self) { let m = self.open(); match self.nth(0) { CaseKwd => { self.expect(CaseKwd); self.expect(Identifier); if self.at(LeftParen) { self.expect(LeftParen); self.expect(Identifier); if self.at(Colon) { self.expect(Colon); let _ = self.expr(); } self.expect(RightParen); } } Equal | NotEqual | IsaKwd => { self.advance(); // comparison operator let _ = self.expr(); } Less | LessEqual | Greater | GreaterEqual => { self.advance(); // relational operator let _ = self.expr(); } _ => self.advance_with_error(MatchPattern), } self.close(m, MatchPattern); } fn stmt_while(&mut self) { assert!(self.at(WhileKwd)); let m = self.open(); self.expect(WhileKwd); let _ = self.expr(); self.block(); // optional else piece if self.at(ElseKwd) { self.expect(ElseKwd); self.block(); } self.close(m, StmtWhile); } fn try_catch(&mut self) { assert!(self.at(TryKwd)); let m = self.open(); self.expect(TryKwd); self.block(); self.expect(CatchKwd); self.expect(Identifier); self.block(); self.close(m, TryBlock); } fn stmt_import(&mut self) { assert!(self.at(ImportKwd)); let m = self.open(); self.expect(ImportKwd); let mut is_from_import = false; let mut temp_pos = self.pos; while temp_pos < self.tokens.len() && self.tokens[temp_pos].0 != FromKwd && self.tokens[temp_pos].0 != Semicolon { temp_pos += 1; } if temp_pos < self.tokens.len() && self.tokens[temp_pos].0 == FromKwd { is_from_import = true; } if is_from_import { if self.at(Star) { self.expect(Star); } else { self.ident_list(); } self.expect(FromKwd); } self.import_path(); self.expect(Semicolon); self.close(m, StmtImport); } fn decl_val(&mut self) { let m = self.open(); self.parse_access_modifier(); self.expect(ValKwd); loop { self.expect(Identifier); if self.at(Colon) { self.type_annotation(); } self.expect(Assign); let _ = self.expr(); if self.at(Comma) { self.expect(Comma); } else { break; } } self.expect(Semicolon); self.close(m, StmtVal); } fn stmt_single_token(&mut self, kind: SyntaxKind) { assert!(self.at(kind)); let m = self.open(); self.expect(kind); self.expect(Semicolon); self.close(m, StmtReturn); } fn stmt_return(&mut self) { assert!(self.at(ReturnKwd)); let m = self.open(); self.expect(ReturnKwd); if !self.at(Semicolon) { let _ = self.expr(); } self.expect(Semicolon); self.close(m, StmtReturn); } fn stmt_kwd_with_expr(&mut self, kind: SyntaxKind) { assert!(self.at(kind)); let m = self.open(); self.expect(kind); let _ = self.expr(); self.expect(Semicolon); self.close(m, StmtAssert); } fn init_list(&mut self) { // Recognize an initializer block only when the brace starts with a field or index init if self.at(LeftBrace) { let ahead = self.nth(1); if ahead != Dot && ahead != LeftBracket { return; } } else { return; } self.assert_tok(LeftBrace); self.expect(LeftBrace); // Parse a comma-separated list of mixed field/index writes, optional trailing comma while !self.at(RightBrace) && !self.eof() { if self.at(Dot) { // Field write: .identifier [= expr]? self.expect(Dot); self.expect(Identifier); if self.at(Assign) { self.expect(Assign); let _ = self.expr(); } } else if self.at(LeftBracket) { // Index write: [expr_list?] = expr self.expr_list(LeftBracket, RightBracket); self.expect(Assign); let _ = self.expr(); } else { // Recovery: unexpected token inside init block self.report_error(RightBrace); break; } if self.at(Comma) { self.expect(Comma); // allow trailing comma; loop condition will exit on RightBrace } else { // no more entries break; } } self.expect(RightBrace); } fn ident_list(&mut self) { let m = self.open(); self.expect(Identifier); while self.at(Comma) { self.expect(Comma); if self.at(Identifier) { self.expect(Identifier); } } self.close(m, IdentList); } fn qualified_ident(&mut self) { let m = self.open(); self.expect(Identifier); while self.at(Dot) { self.expect(Dot); self.expect(Identifier); } self.close(m, QualifiedIdent); } fn import_path(&mut self) { let m = self.open(); self.qualified_ident(); self.close(m, ImportPath); } fn stmt_expr(&mut self) { let m = self.open(); if !self.at(Semicolon) { let _ = self.expr(); // Allow multiple comma-separated expressions in a single // expression statement (e.g. multi-write patterns). while self.at(Comma) { self.expect(Comma); // Allow a trailing comma before semicolon, but don't // try to parse another expression in that case. if self.at(Semicolon) { break; } let _ = self.expr(); } } self.expect(Semicolon); self.close(m, StmtExpr); } fn expr(&mut self) -> MarkClosed { if self.at(Pipe) || self.at(LogicalOr) { self.decl_lambda() } else { self.expr_bp(0) } } fn decl_lambda(&mut self) -> MarkClosed { let m = self.open(); if self.at(LogicalOr) { // Empty parameter list in the form of '||' self.expect(LogicalOr); } else { // Standard parameter list in the form of '|x, y|' self.param_list(Pipe, Pipe); } self.expect(Arrow); if self.at(LeftBrace) { self.block(); } else { let _ = self.expr(); } self.close(m, Lambda) } fn expr_bp(&mut self, min_bp: u8) -> MarkClosed { let mut lhs = self.expr_primary(); loop { let op = self.nth(0); // Support initializer blocks as a postfix after any expression // e.g. "expr{ .field = value, [key] = value }" // Only consume if the brace actually starts an init block (next is '.' or '[') if op == LeftBrace { let ahead = self.nth(1); if ahead == Dot || ahead == LeftBracket { self.init_list(); continue; } } if let Some((l_bp, ())) = postfix_binding_power(op) { if l_bp < min_bp { break; } lhs = match op { LeftParen => { let m = self.open_before(lhs); self.arg_list(); self.init_list(); self.close(m, ExprCall) } LeftBracket => { let m = self.open_before(lhs); self.expr_list(LeftBracket, RightBracket); self.close(m, ExprIndex) } Dot => { let m = self.open_before(lhs); self.expect(Dot); self.expect(Identifier); self.close(m, ExprMember) } DoubleColon => { let m = self.open_before(lhs); self.expect(DoubleColon); self.expect(Identifier); if self.at(LeftParen) { self.expect(LeftParen); let _ = self.expr_bp(0); self.expect(RightParen); } self.close(m, ExprMember) } _ => break, }; continue; } if op == Not { let l_bp = 25u8; if l_bp < min_bp { break; } let m = self.open_before(lhs); self.expect(Not); lhs = self.close(m, ExprNonNull); continue; } if op == Question && !self.is_ternary_question() { let l_bp = 25u8; if l_bp < min_bp { break; } let m = self.open_before(lhs); self.expect(Question); lhs = self.close(m, ExprNullish); continue; } if op == Question { let (l_bp, r_bp) = (1, 2); if l_bp < min_bp { break; } let m = self.open_before(lhs); self.expect(Question); let _ = self.expr_bp(r_bp); self.expect(Colon); let _ = self.expr_bp(r_bp); lhs = self.close(m, ExprTernary); continue; } if let Some((l_bp, r_bp)) = infix_binding_power(op) { if l_bp < min_bp { break; } let m = self.open_before(lhs); self.advance(); // consume operator let _ = self.expr_bp(r_bp); // Use ExprAssign for assignment operators, ExprBinary for others let node_kind = match op { Assign | PlusAssign | MinusAssign | StarAssign | SlashAssign | PercentAssign | LeftShiftAssign | RightShiftAssign => ExprAssign, _ => ExprBinary, }; lhs = self.close(m, node_kind); continue; } break; } lhs } fn is_ternary_question(&self) -> bool { let mut idx = self.pos + 1; let mut first_kind = None; while let Some(tok) = self.tokens.get(idx) { if is_trivia(tok.0) { idx += 1; continue; } first_kind = Some(tok.0); break; } let Some(first_kind) = first_kind else { return false; }; if !is_expr_start(first_kind) { return false; } let mut paren_depth = 0i32; let mut bracket_depth = 0i32; let mut brace_depth = 0i32; let mut scan_idx = idx; while let Some(tok) = self.tokens.get(scan_idx) { if is_trivia(tok.0) { scan_idx += 1; continue; } match tok.0 { LeftParen => paren_depth += 1, RightParen => { if paren_depth == 0 { return false; } paren_depth -= 1; } LeftBracket => bracket_depth += 1, RightBracket => { if bracket_depth == 0 { return false; } bracket_depth -= 1; } LeftBrace => brace_depth += 1, RightBrace => { if brace_depth == 0 { return false; } brace_depth -= 1; } Colon if paren_depth == 0 && bracket_depth == 0 && brace_depth == 0 => { return true; } Comma | Semicolon if paren_depth == 0 && bracket_depth == 0 && brace_depth == 0 => { return false; } _ => {} } scan_idx += 1; } false } fn expr_primary(&mut self) -> MarkClosed { let m = self.open(); match self.nth(0) { HexIntLiteral | OctIntLiteral | BinIntLiteral | DecIntLiteral | FloatLiteral | StringLiteral | TrueKwd | FalseKwd => { self.advance(); self.close(m, ExprLiteral) } Identifier => { self.advance(); self.init_list(); self.close(m, ExprName) } LeftParen => { self.expect(LeftParen); let _ = self.expr_bp(0); self.expect(RightParen); self.close(m, ExprParen) } LeftBracket => { self.expr_list(LeftBracket, RightBracket); self.close(m, ListLiteral) } op if prefix_binding_power(op).is_some() => { let ((), r_bp) = prefix_binding_power(op).unwrap(); self.advance(); let _ = self.expr_bp(r_bp); self.close(m, ExprUnary) } _ => { if !self.eof() { self.advance(); } self.close(m, ErrorTree) } } } fn expr_list(&mut self, left_delim: SyntaxKind, right_delim: SyntaxKind) { self.expect(left_delim); if self.at(right_delim) { self.expect(right_delim); return; } self.expr(); while self.at(Comma) && !self.eof() { self.expect(Comma); if !self.at(right_delim) { self.expr(); } } self.expect(right_delim); } fn arg_list(&mut self) { assert!(self.at(LeftParen)); let m = self.open(); self.expr_list(LeftParen, RightParen); self.close(m, ArgList); } fn open(&mut self) -> MarkOpened { let mark = MarkOpened { index: self.events.len(), }; self.events.push(Event::Open { kind: ErrorTree }); mark } fn close(&mut self, m: MarkOpened, kind: SyntaxKind) -> MarkClosed { self.events[m.index] = Event::Open { kind }; self.events.push(Event::Close); MarkClosed { index: m.index } } fn open_before(&mut self, m: MarkClosed) -> MarkOpened { let mark = MarkOpened { index: m.index }; // TODO: do something to avoid element shifting self.events.insert(m.index, Event::Open { kind: ErrorTree }); mark } fn advance(&mut self) { // Before consuming a significant token, emit any leading trivia while let Some(tok) = self.tokens.get(self.pos) { if is_trivia(tok.0) { self.events.push(Event::Advance); self.pos += 1; } else { break; } } assert!(!self.eof()); self.fuel.set(256); self.events.push(Event::Advance); self.pos += 1; } fn eof(&self) -> bool { // true if there are no more non-trivia tokens let mut idx = self.pos; while let Some(tok) = self.tokens.get(idx) { if is_trivia(tok.0) { idx += 1; continue; } return false; } true } fn nth(&self, lookahead: usize) -> SyntaxKind { if self.fuel.get() == 0 { panic!("parser is stuck") } self.fuel.set(self.fuel.get() - 1); let mut idx = self.pos; let mut remaining = lookahead; while let Some(tok) = self.tokens.get(idx) { if is_trivia(tok.0) { idx += 1; continue; } if remaining == 0 { return tok.0; } remaining -= 1; idx += 1; } Eof } fn nth_token(&self, lookahead: usize) -> Option<&(SyntaxKind, &str, logos::Span)> { self.tokens.get(self.pos + lookahead) } fn at(&self, kind: SyntaxKind) -> bool { self.nth(0) == kind || (kind == Identifier && self.is_keyword(self.nth(0))) } fn eat(&mut self, kind: SyntaxKind) -> bool { if self.at(kind) { self.advance(); true } else { false } } fn is_keyword(&self, kind: SyntaxKind) -> bool { matches!( kind, AssertKwd | BreakKwd | CaseKwd | CatchKwd | ContinueKwd | ElseKwd | ElsifKwd | EnumKwd | ExtensionKwd | FlagKwd | ForKwd | FromKwd | FuncKwd | IfKwd | ImportKwd | InKwd | IncludeKwd | InstanceKwd | IsaKwd | MatchKwd | MixinKwd | OperatorKwd | ReturnKwd | ReverseKwd | StructKwd | ThrowKwd | TryKwd | TypeKwd | ValKwd | WhileKwd | AndKwd | TrueKwd | FalseKwd ) } fn expect(&mut self, kind: SyntaxKind) { if self.eat(kind) { return; } self.report_error(kind); } fn advance_with_error(&mut self, token: SyntaxKind) { let m = self.open(); self.report_error(token); self.advance(); self.close(m, ErrorTree); } fn report_error(&mut self, expected: SyntaxKind) { let pos = self.nth_token(0).map(|tok| tok.2.clone()); self.errors.push(ParseError { expected, pos }); } fn trivia(&mut self) { while let Some(tok) = self.tokens.get(self.pos) { if is_trivia(tok.0) { self.events.push(Event::Advance); self.pos += 1; } else { break; } } } fn assert_tok(&mut self, kind: SyntaxKind) { assert!( self.at(kind), "expected {:?} but found {:?} at {:?}", kind, self.nth(0), self.line_index.line_col(TextSize::from(self.pos as u32)) ); } fn build_tree(self) -> Parse { { let mut opens = 0usize; let mut closes = 0usize; let mut advances = 0usize; let mut depth = 0isize; for (i, ev) in self.events.iter().enumerate() { match ev { Event::Open { .. } => { opens += 1; depth += 1; } Event::Close => { closes += 1; depth -= 1; assert!( depth >= 0, "Unbalanced Close at event {i} (more closes than opens)" ); } Event::Advance => { advances += 1; } } } assert_eq!( opens, closes, "Mismatched Open/Close count: opens={opens} closes={closes}" ); let total_tokens = self.tokens.len(); assert_eq!( advances, total_tokens, "Advance count {advances} does not match tokens len {total_tokens}" ); } // TODO: add a shared node cache let mut builder = GreenNodeBuilder::new(); let mut tokens = self.tokens.into_iter(); for (idx, event) in self.events.into_iter().enumerate() { let res = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| match event { Event::Open { kind } => { builder.start_node(kind.into()); } Event::Close => { builder.finish_node(); } Event::Advance => { let (token, slice, _) = tokens.next().unwrap(); builder.token(token.into(), slice); } })); if res.is_err() { eprintln!("Rowan builder panic at event index {idx}"); std::panic::resume_unwind(res.err().unwrap()); } } assert!(tokens.next().is_none()); let res_finish = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| builder.finish())); match res_finish { Ok(gn) => Parse { green_node: gn, errors: self.errors, }, Err(p) => { eprintln!("Rowan builder.finish() panic"); std::panic::resume_unwind(p) } } } } let lex = lexer::lex(text); let tokens = lex.into_iter().map(|res| res.unwrap()).collect(); let mut parser = Parser { tokens, pos: 0, fuel: Cell::new(256), events: Vec::new(), errors: Vec::new(), line_index: LineIndex::new(text), }; parser.file(); parser.build_tree() } pub type SyntaxNode = rowan::SyntaxNode; #[allow(unused)] pub type SyntaxToken = rowan::SyntaxToken; #[allow(unused)] pub type SyntaxElement = rowan::NodeOrToken; #[cfg(test)] mod tests { use super::*; use line_index::LineIndex; use pretty_assertions::assert_eq; fn tree_to_string(node: SyntaxNode) -> String { let mut result = Vec::new(); let index = CompressedIndex::new(&node); tree_to_string_impl(&node, 0, &index, &mut result); result.join("\n") } // Build a mapping from original token ranges to compressed coordinates // that exclude trivia. struct CompressedIndex { // (original_text_range, compressed_start, compressed_end) entries: Vec<(rowan::TextRange, usize, usize)>, } impl CompressedIndex { fn new(root: &SyntaxNode) -> Self { use crate::lexer::SyntaxKind as K; let mut entries = Vec::new(); let mut comp = 0usize; for el in root.descendants_with_tokens() { if let rowan::NodeOrToken::Token(tok) = el { if matches!(tok.kind(), K::Whitespace | K::LineComment) { continue; } let len = tok.text().len(); let start = comp; let end = comp + len; entries.push((tok.text_range(), start, end)); comp = end; } } Self { entries } } fn token_range(&self, tok: &SyntaxToken) -> Option<(usize, usize)> { let r = tok.text_range(); self.entries .iter() .find_map(|(rr, s, e)| if *rr == r { Some((*s, *e)) } else { None }) } fn node_range(&self, node: &SyntaxNode) -> Option<(usize, usize)> { use crate::lexer::SyntaxKind as K; let mut first: Option = None; let mut last: Option = None; for el in node.descendants_with_tokens() { if let rowan::NodeOrToken::Token(tok) = el { if matches!(tok.kind(), K::Whitespace | K::LineComment) { continue; } if let Some((s, e)) = self.token_range(&tok) { if first.is_none() { first = Some(s); } last = Some(e); } } } match (first, last) { (Some(s), Some(e)) => Some((s, e)), _ => None, } } } fn tree_to_string_impl( node: &SyntaxNode, depth: usize, index: &CompressedIndex, result: &mut Vec, ) { let indent = " ".repeat(depth); if let Some((s, e)) = index.node_range(node) { result.push(format!("{}{:?}@{}..{}", indent, node.kind(), s, e)); } else { // empty node result.push(format!("{}{:?}@0..0", indent, node.kind())); } for child in node.children_with_tokens() { match child { rowan::NodeOrToken::Node(child_node) => { tree_to_string_impl(&child_node, depth + 1, index, result); } rowan::NodeOrToken::Token(token) => { use crate::lexer::SyntaxKind as K; if matches!(token.kind(), K::Whitespace | K::LineComment) { continue; } let token_indent = " ".repeat(depth + 1); if let Some((s, e)) = index.token_range(&token) { result.push(format!( "{}{:?}@{}..{} {:?}", token_indent, token.kind(), s, e, token.text() )); } } } } } fn expect_tree(input: &str, lines: &[&str]) { let node = parse(input).syntax(); let tree_str = tree_to_string(node); let expected = lines.join("\n"); assert_eq!( expected, tree_str, "tree should be\n{}\nbut is\n{}", expected, tree_str ); } #[test] fn test_empty() { expect_tree("", &["File@0..0"]) } #[test] fn test_empty_function() { expect_tree( "func empty_func() {}", &[ "File@0..18", " Func@0..18", " FuncKwd@0..4 \"func\"", " Identifier@4..14 \"empty_func\"", " ParamList@14..16", " LeftParen@14..15 \"(\"", " RightParen@15..16 \")\"", " Block@16..18", " LeftBrace@16..17 \"{\"", " RightBrace@17..18 \"}\"", ], ) } #[test] fn test_param_list() { expect_tree( "func empty_func(x, y) {}", &[ "File@0..21", " Func@0..21", " FuncKwd@0..4 \"func\"", " Identifier@4..14 \"empty_func\"", " ParamList@14..19", " LeftParen@14..15 \"(\"", " Param@15..17", " Identifier@15..16 \"x\"", " Comma@16..17 \",\"", " Param@17..18", " Identifier@17..18 \"y\"", " RightParen@18..19 \")\"", " Block@19..21", " LeftBrace@19..20 \"{\"", " RightBrace@20..21 \"}\"", ], ) } #[test] fn test_val() { expect_tree( "func test() { val x = 5; }", &[ "File@0..19", " Func@0..19", " FuncKwd@0..4 \"func\"", " Identifier@4..8 \"test\"", " ParamList@8..10", " LeftParen@8..9 \"(\"", " RightParen@9..10 \")\"", " Block@10..19", " LeftBrace@10..11 \"{\"", " StmtVal@11..18", " ValKwd@11..14 \"val\"", " Identifier@14..15 \"x\"", " Assign@15..16 \"=\"", " ExprLiteral@16..17", " DecIntLiteral@16..17 \"5\"", " Semicolon@17..18 \";\"", " RightBrace@18..19 \"}\"", ], ) } #[test] fn test_binary_expr() { expect_tree( "func test() { val x = 1 + 2 * 3; }", &[ "File@0..23", " Func@0..23", " FuncKwd@0..4 \"func\"", " Identifier@4..8 \"test\"", " ParamList@8..10", " LeftParen@8..9 \"(\"", " RightParen@9..10 \")\"", " Block@10..23", " LeftBrace@10..11 \"{\"", " StmtVal@11..22", " ValKwd@11..14 \"val\"", " Identifier@14..15 \"x\"", " Assign@15..16 \"=\"", " ExprBinary@16..21", " ExprLiteral@16..17", " DecIntLiteral@16..17 \"1\"", " Plus@17..18 \"+\"", " ExprBinary@18..21", " ExprLiteral@18..19", " DecIntLiteral@18..19 \"2\"", " Star@19..20 \"*\"", " ExprLiteral@20..21", " DecIntLiteral@20..21 \"3\"", " Semicolon@21..22 \";\"", " RightBrace@22..23 \"}\"", ], ) } #[test] fn test_list_literal_empty() { expect_tree( "func test() { val x = []; }", &[ "File@0..20", " Func@0..20", " FuncKwd@0..4 \"func\"", " Identifier@4..8 \"test\"", " ParamList@8..10", " LeftParen@8..9 \"(\"", " RightParen@9..10 \")\"", " Block@10..20", " LeftBrace@10..11 \"{\"", " StmtVal@11..19", " ValKwd@11..14 \"val\"", " Identifier@14..15 \"x\"", " Assign@15..16 \"=\"", " ListLiteral@16..18", " LeftBracket@16..17 \"[\"", " RightBracket@17..18 \"]\"", " Semicolon@18..19 \";\"", " RightBrace@19..20 \"}\"", ], ) } #[test] fn test_list_literal_with_elements() { expect_tree( "func test() { val x = [1, 2, 3]; }", &[ "File@0..25", " Func@0..25", " FuncKwd@0..4 \"func\"", " Identifier@4..8 \"test\"", " ParamList@8..10", " LeftParen@8..9 \"(\"", " RightParen@9..10 \")\"", " Block@10..25", " LeftBrace@10..11 \"{\"", " StmtVal@11..24", " ValKwd@11..14 \"val\"", " Identifier@14..15 \"x\"", " Assign@15..16 \"=\"", " ListLiteral@16..23", " LeftBracket@16..17 \"[\"", " ExprLiteral@17..18", " DecIntLiteral@17..18 \"1\"", " Comma@18..19 \",\"", " ExprLiteral@19..20", " DecIntLiteral@19..20 \"2\"", " Comma@20..21 \",\"", " ExprLiteral@21..22", " DecIntLiteral@21..22 \"3\"", " RightBracket@22..23 \"]\"", " Semicolon@23..24 \";\"", " RightBrace@24..25 \"}\"", ], ) } #[test] fn test_list_literal_nested() { expect_tree( "func test() { val x = [[1, 2], [3]]; }", &[ "File@0..29", " Func@0..29", " FuncKwd@0..4 \"func\"", " Identifier@4..8 \"test\"", " ParamList@8..10", " LeftParen@8..9 \"(\"", " RightParen@9..10 \")\"", " Block@10..29", " LeftBrace@10..11 \"{\"", " StmtVal@11..28", " ValKwd@11..14 \"val\"", " Identifier@14..15 \"x\"", " Assign@15..16 \"=\"", " ListLiteral@16..27", " LeftBracket@16..17 \"[\"", " ListLiteral@17..22", " LeftBracket@17..18 \"[\"", " ExprLiteral@18..19", " DecIntLiteral@18..19 \"1\"", " Comma@19..20 \",\"", " ExprLiteral@20..21", " DecIntLiteral@20..21 \"2\"", " RightBracket@21..22 \"]\"", " Comma@22..23 \",\"", " ListLiteral@23..26", " LeftBracket@23..24 \"[\"", " ExprLiteral@24..25", " DecIntLiteral@24..25 \"3\"", " RightBracket@25..26 \"]\"", " RightBracket@26..27 \"]\"", " Semicolon@27..28 \";\"", " RightBrace@28..29 \"}\"", ], ) } #[test] fn test_unary_expr() { expect_tree( "func test() { val x = -5; }", &[ "File@0..20", " Func@0..20", " FuncKwd@0..4 \"func\"", " Identifier@4..8 \"test\"", " ParamList@8..10", " LeftParen@8..9 \"(\"", " RightParen@9..10 \")\"", " Block@10..20", " LeftBrace@10..11 \"{\"", " StmtVal@11..19", " ValKwd@11..14 \"val\"", " Identifier@14..15 \"x\"", " Assign@15..16 \"=\"", " ExprUnary@16..18", " Minus@16..17 \"-\"", " ExprLiteral@17..18", " DecIntLiteral@17..18 \"5\"", " Semicolon@18..19 \";\"", " RightBrace@19..20 \"}\"", ], ) } #[test] fn test_member_access() { expect_tree( "func test() { val x = obj.field; }", &[ "File@0..27", " Func@0..27", " FuncKwd@0..4 \"func\"", " Identifier@4..8 \"test\"", " ParamList@8..10", " LeftParen@8..9 \"(\"", " RightParen@9..10 \")\"", " Block@10..27", " LeftBrace@10..11 \"{\"", " StmtVal@11..26", " ValKwd@11..14 \"val\"", " Identifier@14..15 \"x\"", " Assign@15..16 \"=\"", " ExprMember@16..25", " ExprName@16..19", " Identifier@16..19 \"obj\"", " Dot@19..20 \".\"", " Identifier@20..25 \"field\"", " Semicolon@25..26 \";\"", " RightBrace@26..27 \"}\"", ], ) } #[test] fn test_array_access() { expect_tree( "func test() { val x = arr[0]; }", &[ "File@0..24", " Func@0..24", " FuncKwd@0..4 \"func\"", " Identifier@4..8 \"test\"", " ParamList@8..10", " LeftParen@8..9 \"(\"", " RightParen@9..10 \")\"", " Block@10..24", " LeftBrace@10..11 \"{\"", " StmtVal@11..23", " ValKwd@11..14 \"val\"", " Identifier@14..15 \"x\"", " Assign@15..16 \"=\"", " ExprIndex@16..22", " ExprName@16..19", " Identifier@16..19 \"arr\"", " LeftBracket@19..20 \"[\"", " ExprLiteral@20..21", " DecIntLiteral@20..21 \"0\"", " RightBracket@21..22 \"]\"", " Semicolon@22..23 \";\"", " RightBrace@23..24 \"}\"", ], ) } #[test] fn test_function_call() { expect_tree( "func test() { val x = foo(1, 2); }", &[ "File@0..26", " Func@0..26", " FuncKwd@0..4 \"func\"", " Identifier@4..8 \"test\"", " ParamList@8..10", " LeftParen@8..9 \"(\"", " RightParen@9..10 \")\"", " Block@10..26", " LeftBrace@10..11 \"{\"", " StmtVal@11..25", " ValKwd@11..14 \"val\"", " Identifier@14..15 \"x\"", " Assign@15..16 \"=\"", " ExprCall@16..24", " ExprName@16..19", " Identifier@16..19 \"foo\"", " ArgList@19..24", " LeftParen@19..20 \"(\"", " ExprLiteral@20..21", " DecIntLiteral@20..21 \"1\"", " Comma@21..22 \",\"", " ExprLiteral@22..23", " DecIntLiteral@22..23 \"2\"", " RightParen@23..24 \")\"", " Semicolon@24..25 \";\"", " RightBrace@25..26 \"}\"", ], ) } #[test] fn test_chained_postfix() { expect_tree( "func test() { val x = obj.method().field[0]; }", &[ "File@0..39", " Func@0..39", " FuncKwd@0..4 \"func\"", " Identifier@4..8 \"test\"", " ParamList@8..10", " LeftParen@8..9 \"(\"", " RightParen@9..10 \")\"", " Block@10..39", " LeftBrace@10..11 \"{\"", " StmtVal@11..38", " ValKwd@11..14 \"val\"", " Identifier@14..15 \"x\"", " Assign@15..16 \"=\"", " ExprIndex@16..37", " ExprMember@16..34", " ExprCall@16..28", " ExprMember@16..26", " ExprName@16..19", " Identifier@16..19 \"obj\"", " Dot@19..20 \".\"", " Identifier@20..26 \"method\"", " ArgList@26..28", " LeftParen@26..27 \"(\"", " RightParen@27..28 \")\"", " Dot@28..29 \".\"", " Identifier@29..34 \"field\"", " LeftBracket@34..35 \"[\"", " ExprLiteral@35..36", " DecIntLiteral@35..36 \"0\"", " RightBracket@36..37 \"]\"", " Semicolon@37..38 \";\"", " RightBrace@38..39 \"}\"", ], ) } fn test_files_in_directory_parse(dir: &str, dir_should_error: Vec) { use std::fs; use std::path::Path; let test_dir = Path::new(dir); if !test_dir.exists() { println!("Directory not found, skipping test: {}", dir); return; } let expect_err = dir_should_error.contains(&test_dir.file_name().unwrap().to_str().unwrap().to_owned()); let entries = fs::read_dir(test_dir).expect(&format!("Failed to read directory: {}", dir)); for entry in entries { let entry = entry.expect("Failed to read directory entry"); let path = entry.path(); if path.extension().and_then(|s| s.to_str()) == Some("aria") { let filename = path.file_name().unwrap().to_str().unwrap(); println!("Parsing {}", filename); let content = fs::read_to_string(&path).expect(&format!("Failed to read file: {}", filename)); let parse_result = parse(&content); if expect_err && parse_result.errors.is_empty() { println!("\n{} should have parse errors but did not:", filename); let line_index = LineIndex::new(&content); for error in &parse_result.errors { let line = line_index .line_col(error.pos.as_ref().unwrap().start.try_into().unwrap()); println!(" {:?} at {:?}", error, line); } println!("\n\n{}", tree_to_string(parse_result.syntax())); panic!("Parse errors found in {}", filename); } else if !expect_err && !parse_result.errors.is_empty() { println!("\n{} has parse errors:", filename); let line_index = LineIndex::new(&content); for error in &parse_result.errors { let line = line_index .line_col(error.pos.as_ref().unwrap().start.try_into().unwrap()); println!(" {:?} at {:?}", error, line); } println!("\n\n{}", tree_to_string(parse_result.syntax())); panic!("Parse errors found in {}", filename); } } if path.is_dir() { test_files_in_directory_parse( path.to_path_buf().to_str().unwrap(), dir_should_error.clone(), ); } } } #[test] fn test_assignment_basic() { expect_tree( "func test() { x = 5; }", &[ "File@0..16", " Func@0..16", " FuncKwd@0..4 \"func\"", " Identifier@4..8 \"test\"", " ParamList@8..10", " LeftParen@8..9 \"(\"", " RightParen@9..10 \")\"", " Block@10..16", " LeftBrace@10..11 \"{\"", " StmtExpr@11..15", " ExprAssign@11..14", " ExprName@11..12", " Identifier@11..12 \"x\"", " Assign@12..13 \"=\"", " ExprLiteral@13..14", " DecIntLiteral@13..14 \"5\"", " Semicolon@14..15 \";\"", " RightBrace@15..16 \"}\"", ], ) } #[test] fn test_assignment_compound() { expect_tree( "func test() { x += 5; }", &[ "File@0..17", " Func@0..17", " FuncKwd@0..4 \"func\"", " Identifier@4..8 \"test\"", " ParamList@8..10", " LeftParen@8..9 \"(\"", " RightParen@9..10 \")\"", " Block@10..17", " LeftBrace@10..11 \"{\"", " StmtExpr@11..16", " ExprAssign@11..15", " ExprName@11..12", " Identifier@11..12 \"x\"", " PlusAssign@12..14 \"+=\"", " ExprLiteral@14..15", " DecIntLiteral@14..15 \"5\"", " Semicolon@15..16 \";\"", " RightBrace@16..17 \"}\"", ], ) } #[test] fn test_assignment_all_compound_operators() { expect_tree( "func test() { x -= 1; y *= 2; z /= 3; w %= 4; }", &[ "File@0..32", " Func@0..32", " FuncKwd@0..4 \"func\"", " Identifier@4..8 \"test\"", " ParamList@8..10", " LeftParen@8..9 \"(\"", " RightParen@9..10 \")\"", " Block@10..32", " LeftBrace@10..11 \"{\"", " StmtExpr@11..16", " ExprAssign@11..15", " ExprName@11..12", " Identifier@11..12 \"x\"", " MinusAssign@12..14 \"-=\"", " ExprLiteral@14..15", " DecIntLiteral@14..15 \"1\"", " Semicolon@15..16 \";\"", " StmtExpr@16..21", " ExprAssign@16..20", " ExprName@16..17", " Identifier@16..17 \"y\"", " StarAssign@17..19 \"*=\"", " ExprLiteral@19..20", " DecIntLiteral@19..20 \"2\"", " Semicolon@20..21 \";\"", " StmtExpr@21..26", " ExprAssign@21..25", " ExprName@21..22", " Identifier@21..22 \"z\"", " SlashAssign@22..24 \"/=\"", " ExprLiteral@24..25", " DecIntLiteral@24..25 \"3\"", " Semicolon@25..26 \";\"", " StmtExpr@26..31", " ExprAssign@26..30", " ExprName@26..27", " Identifier@26..27 \"w\"", " PercentAssign@27..29 \"%=\"", " ExprLiteral@29..30", " DecIntLiteral@29..30 \"4\"", " Semicolon@30..31 \";\"", " RightBrace@31..32 \"}\"", ], ) } #[test] fn test_assignment_precedence() { expect_tree( "func test() { x = y + z; }", &[ "File@0..18", " Func@0..18", " FuncKwd@0..4 \"func\"", " Identifier@4..8 \"test\"", " ParamList@8..10", " LeftParen@8..9 \"(\"", " RightParen@9..10 \")\"", " Block@10..18", " LeftBrace@10..11 \"{\"", " StmtExpr@11..17", " ExprAssign@11..16", " ExprName@11..12", " Identifier@11..12 \"x\"", " Assign@12..13 \"=\"", " ExprBinary@13..16", " ExprName@13..14", " Identifier@13..14 \"y\"", " Plus@14..15 \"+\"", " ExprName@15..16", " Identifier@15..16 \"z\"", " Semicolon@16..17 \";\"", " RightBrace@17..18 \"}\"", ], ) } #[test] fn test_assignment_right_associative() { expect_tree( "func test() { x = y = z; }", &[ "File@0..18", " Func@0..18", " FuncKwd@0..4 \"func\"", " Identifier@4..8 \"test\"", " ParamList@8..10", " LeftParen@8..9 \"(\"", " RightParen@9..10 \")\"", " Block@10..18", " LeftBrace@10..11 \"{\"", " StmtExpr@11..17", " ExprAssign@11..16", " ExprName@11..12", " Identifier@11..12 \"x\"", " Assign@12..13 \"=\"", " ExprAssign@13..16", " ExprName@13..14", " Identifier@13..14 \"y\"", " Assign@14..15 \"=\"", " ExprName@15..16", " Identifier@15..16 \"z\"", " Semicolon@16..17 \";\"", " RightBrace@17..18 \"}\"", ], ) } #[test] fn test_simple_binary_expr() { expect_tree( "func test() { val x = y-1; }", &[ "File@0..21", " Func@0..21", " FuncKwd@0..4 \"func\"", " Identifier@4..8 \"test\"", " ParamList@8..10", " LeftParen@8..9 \"(\"", " RightParen@9..10 \")\"", " Block@10..21", " LeftBrace@10..11 \"{\"", " StmtVal@11..20", " ValKwd@11..14 \"val\"", " Identifier@14..15 \"x\"", " Assign@15..16 \"=\"", " ExprBinary@16..19", " ExprName@16..17", " Identifier@16..17 \"y\"", " Minus@17..18 \"-\"", " ExprLiteral@18..19", " DecIntLiteral@18..19 \"1\"", " Semicolon@19..20 \";\"", " RightBrace@20..21 \"}\"", ], ) } #[test] fn test_assert_statement() { expect_tree( "func test() { assert x > 0; }", &[ "File@0..22", " Func@0..22", " FuncKwd@0..4 \"func\"", " Identifier@4..8 \"test\"", " ParamList@8..10", " LeftParen@8..9 \"(\"", " RightParen@9..10 \")\"", " Block@10..22", " LeftBrace@10..11 \"{\"", " StmtAssert@11..21", " AssertKwd@11..17 \"assert\"", " ExprBinary@17..20", " ExprName@17..18", " Identifier@17..18 \"x\"", " Greater@18..19 \">\"", " ExprLiteral@19..20", " DecIntLiteral@19..20 \"0\"", " Semicolon@20..21 \";\"", " RightBrace@21..22 \"}\"", ], ) } #[test] fn test_example_files_parse_without_errors() { test_files_in_directory_parse("../examples", vec![]); } #[test] fn test_files_parse_without_errors() { test_files_in_directory_parse("../tests", vec![]); } #[test] fn test_std_lib_files_parse_without_errors() { test_files_in_directory_parse("../lib", vec![]); } #[test] fn test_std_lib_test_files_parse_without_errors() { test_files_in_directory_parse("../lib-test", vec!["with_err".to_string()]); } } ================================================ FILE: microbenchmarks/attribute_read.aria ================================================ # SPDX-License-Identifier: Apache-2.0 import aria.range.int_extension; import Microbenchmark from infra; func foo(_) {} struct ListWrite : Microbenchmark { func prepare() { val b = Box(); b.value0 = 0; b.value1 = 1; b.value2 = 2; b.value3 = 3; b.value4 = 4; b.value5 = 5; b.value6 = 6; b.value7 = 7; b.value8 = 8; b.value9 = 9; b.value10 = 10; b.value11 = 11; b.value12 = 12; b.value13 = 13; b.value14 = 14; b.value15 = 15; b.value16 = 16; b.value17 = 17; b.value18 = 18; b.value19 = 19; b.value20 = 20; b.value21 = 21; b.value22 = 22; b.value23 = 23; b.value24 = 24; b.value25 = 25; b.value26 = 26; b.value27 = 27; b.value28 = 28; b.value29 = 29; b.value30 = 30; b.value31 = 31; b.value32 = 32; b.value33 = 33; b.value34 = 34; b.value35 = 35; b.value36 = 36; b.value37 = 37; b.value38 = 38; b.value39 = 39; b.value40 = 40; b.value41 = 41; b.value42 = 42; b.value43 = 43; b.value44 = 44; b.value45 = 45; b.value46 = 46; b.value47 = 47; b.value48 = 48; b.value49 = 49; b.value50 = 50; b.value51 = 51; b.value52 = 52; b.value53 = 53; b.value54 = 54; b.value55 = 55; b.value56 = 56; b.value57 = 57; b.value58 = 58; b.value59 = 59; b.value60 = 60; b.value61 = 61; b.value62 = 62; b.value63 = 63; b.value64 = 64; b.value65 = 65; b.value66 = 66; b.value67 = 67; b.value68 = 68; b.value69 = 69; b.value70 = 70; b.value71 = 71; b.value72 = 72; b.value73 = 73; b.value74 = 74; b.value75 = 75; b.value76 = 76; b.value77 = 77; b.value78 = 78; b.value79 = 79; b.value80 = 80; b.value81 = 81; b.value82 = 82; b.value83 = 83; b.value84 = 84; b.value85 = 85; b.value86 = 86; b.value87 = 87; b.value88 = 88; b.value89 = 89; b.value90 = 90; b.value91 = 91; b.value92 = 92; b.value93 = 93; b.value94 = 94; b.value95 = 95; b.value96 = 96; b.value97 = 97; b.value98 = 98; b.value99 = 99; b.value100 = 100; b.value101 = 101; b.value102 = 102; b.value103 = 103; b.value104 = 104; b.value105 = 105; b.value106 = 106; b.value107 = 107; b.value108 = 108; b.value109 = 109; b.value110 = 110; b.value111 = 111; b.value112 = 112; b.value113 = 113; b.value114 = 114; b.value115 = 115; b.value116 = 116; b.value117 = 117; b.value118 = 118; b.value119 = 119; b.value120 = 120; b.value121 = 121; b.value122 = 122; b.value123 = 123; b.value124 = 124; b.value125 = 125; b.value126 = 126; b.value127 = 127; b.value128 = 128; b.value129 = 129; b.value130 = 130; b.value131 = 131; b.value132 = 132; b.value133 = 133; b.value134 = 134; b.value135 = 135; b.value136 = 136; b.value137 = 137; b.value138 = 138; b.value139 = 139; b.value140 = 140; b.value141 = 141; b.value142 = 142; b.value143 = 143; b.value144 = 144; b.value145 = 145; b.value146 = 146; b.value147 = 147; b.value148 = 148; b.value149 = 149; b.value150 = 150; b.value151 = 151; b.value152 = 152; b.value153 = 153; b.value154 = 154; b.value155 = 155; b.value156 = 156; b.value157 = 157; b.value158 = 158; b.value159 = 159; b.value160 = 160; b.value161 = 161; b.value162 = 162; b.value163 = 163; b.value164 = 164; b.value165 = 165; b.value166 = 166; b.value167 = 167; b.value168 = 168; b.value169 = 169; b.value170 = 170; b.value171 = 171; b.value172 = 172; b.value173 = 173; b.value174 = 174; b.value175 = 175; b.value176 = 176; b.value177 = 177; b.value178 = 178; b.value179 = 179; b.value180 = 180; b.value181 = 181; b.value182 = 182; b.value183 = 183; b.value184 = 184; b.value185 = 185; b.value186 = 186; b.value187 = 187; b.value188 = 188; b.value189 = 189; b.value190 = 190; b.value191 = 191; b.value192 = 192; b.value193 = 193; b.value194 = 194; b.value195 = 195; b.value196 = 196; b.value197 = 197; b.value198 = 198; b.value199 = 199; b.value200 = 200; b.value201 = 201; b.value202 = 202; b.value203 = 203; b.value204 = 204; b.value205 = 205; b.value206 = 206; b.value207 = 207; b.value208 = 208; b.value209 = 209; b.value210 = 210; b.value211 = 211; b.value212 = 212; b.value213 = 213; b.value214 = 214; b.value215 = 215; b.value216 = 216; b.value217 = 217; b.value218 = 218; b.value219 = 219; b.value220 = 220; b.value221 = 221; b.value222 = 222; b.value223 = 223; b.value224 = 224; b.value225 = 225; b.value226 = 226; b.value227 = 227; b.value228 = 228; b.value229 = 229; b.value230 = 230; b.value231 = 231; b.value232 = 232; b.value233 = 233; b.value234 = 234; b.value235 = 235; b.value236 = 236; b.value237 = 237; b.value238 = 238; b.value239 = 239; b.value240 = 240; b.value241 = 241; b.value242 = 242; b.value243 = 243; b.value244 = 244; b.value245 = 245; b.value246 = 246; b.value247 = 247; b.value248 = 248; b.value249 = 249; b.value250 = 250; b.value251 = 251; b.value252 = 252; b.value253 = 253; b.value254 = 254; b.value255 = 255; b.value256 = 256; b.value257 = 257; b.value258 = 258; b.value259 = 259; b.value260 = 260; b.value261 = 261; b.value262 = 262; b.value263 = 263; b.value264 = 264; b.value265 = 265; b.value266 = 266; b.value267 = 267; b.value268 = 268; b.value269 = 269; b.value270 = 270; b.value271 = 271; b.value272 = 272; b.value273 = 273; b.value274 = 274; b.value275 = 275; b.value276 = 276; b.value277 = 277; b.value278 = 278; b.value279 = 279; b.value280 = 280; b.value281 = 281; b.value282 = 282; b.value283 = 283; b.value284 = 284; b.value285 = 285; b.value286 = 286; b.value287 = 287; b.value288 = 288; b.value289 = 289; b.value290 = 290; b.value291 = 291; b.value292 = 292; b.value293 = 293; b.value294 = 294; b.value295 = 295; b.value296 = 296; b.value297 = 297; b.value298 = 298; b.value299 = 299; b.value300 = 300; b.value301 = 301; b.value302 = 302; b.value303 = 303; b.value304 = 304; b.value305 = 305; b.value306 = 306; b.value307 = 307; b.value308 = 308; b.value309 = 309; b.value310 = 310; b.value311 = 311; b.value312 = 312; b.value313 = 313; b.value314 = 314; b.value315 = 315; b.value316 = 316; b.value317 = 317; b.value318 = 318; b.value319 = 319; b.value320 = 320; b.value321 = 321; b.value322 = 322; b.value323 = 323; b.value324 = 324; b.value325 = 325; b.value326 = 326; b.value327 = 327; b.value328 = 328; b.value329 = 329; b.value330 = 330; b.value331 = 331; b.value332 = 332; b.value333 = 333; b.value334 = 334; b.value335 = 335; b.value336 = 336; b.value337 = 337; b.value338 = 338; b.value339 = 339; b.value340 = 340; b.value341 = 341; b.value342 = 342; b.value343 = 343; b.value344 = 344; b.value345 = 345; b.value346 = 346; b.value347 = 347; b.value348 = 348; b.value349 = 349; b.value350 = 350; b.value351 = 351; b.value352 = 352; b.value353 = 353; b.value354 = 354; b.value355 = 355; b.value356 = 356; b.value357 = 357; b.value358 = 358; b.value359 = 359; b.value360 = 360; b.value361 = 361; b.value362 = 362; b.value363 = 363; b.value364 = 364; b.value365 = 365; b.value366 = 366; b.value367 = 367; b.value368 = 368; b.value369 = 369; b.value370 = 370; b.value371 = 371; b.value372 = 372; b.value373 = 373; b.value374 = 374; b.value375 = 375; b.value376 = 376; b.value377 = 377; b.value378 = 378; b.value379 = 379; b.value380 = 380; b.value381 = 381; b.value382 = 382; b.value383 = 383; b.value384 = 384; b.value385 = 385; b.value386 = 386; b.value387 = 387; b.value388 = 388; b.value389 = 389; b.value390 = 390; b.value391 = 391; b.value392 = 392; b.value393 = 393; b.value394 = 394; b.value395 = 395; b.value396 = 396; b.value397 = 397; b.value398 = 398; b.value399 = 399; b.value400 = 400; b.value401 = 401; b.value402 = 402; b.value403 = 403; b.value404 = 404; b.value405 = 405; b.value406 = 406; b.value407 = 407; b.value408 = 408; b.value409 = 409; b.value410 = 410; b.value411 = 411; b.value412 = 412; b.value413 = 413; b.value414 = 414; b.value415 = 415; b.value416 = 416; b.value417 = 417; b.value418 = 418; b.value419 = 419; b.value420 = 420; b.value421 = 421; b.value422 = 422; b.value423 = 423; b.value424 = 424; b.value425 = 425; b.value426 = 426; b.value427 = 427; b.value428 = 428; b.value429 = 429; b.value430 = 430; b.value431 = 431; b.value432 = 432; b.value433 = 433; b.value434 = 434; b.value435 = 435; b.value436 = 436; b.value437 = 437; b.value438 = 438; b.value439 = 439; b.value440 = 440; b.value441 = 441; b.value442 = 442; b.value443 = 443; b.value444 = 444; b.value445 = 445; b.value446 = 446; b.value447 = 447; b.value448 = 448; b.value449 = 449; b.value450 = 450; b.value451 = 451; b.value452 = 452; b.value453 = 453; b.value454 = 454; b.value455 = 455; b.value456 = 456; b.value457 = 457; b.value458 = 458; b.value459 = 459; b.value460 = 460; b.value461 = 461; b.value462 = 462; b.value463 = 463; b.value464 = 464; b.value465 = 465; b.value466 = 466; b.value467 = 467; b.value468 = 468; b.value469 = 469; b.value470 = 470; b.value471 = 471; b.value472 = 472; b.value473 = 473; b.value474 = 474; b.value475 = 475; b.value476 = 476; b.value477 = 477; b.value478 = 478; b.value479 = 479; b.value480 = 480; b.value481 = 481; b.value482 = 482; b.value483 = 483; b.value484 = 484; b.value485 = 485; b.value486 = 486; b.value487 = 487; b.value488 = 488; b.value489 = 489; b.value490 = 490; b.value491 = 491; b.value492 = 492; b.value493 = 493; b.value494 = 494; b.value495 = 495; b.value496 = 496; b.value497 = 497; b.value498 = 498; b.value499 = 499; b.value500 = 500; b.value501 = 501; b.value502 = 502; b.value503 = 503; b.value504 = 504; b.value505 = 505; b.value506 = 506; b.value507 = 507; b.value508 = 508; b.value509 = 509; b.value510 = 510; b.value511 = 511; b.value512 = 512; b.value513 = 513; b.value514 = 514; b.value515 = 515; b.value516 = 516; b.value517 = 517; b.value518 = 518; b.value519 = 519; b.value520 = 520; b.value521 = 521; b.value522 = 522; b.value523 = 523; b.value524 = 524; b.value525 = 525; b.value526 = 526; b.value527 = 527; b.value528 = 528; b.value529 = 529; b.value530 = 530; b.value531 = 531; b.value532 = 532; b.value533 = 533; b.value534 = 534; b.value535 = 535; b.value536 = 536; b.value537 = 537; b.value538 = 538; b.value539 = 539; b.value540 = 540; b.value541 = 541; b.value542 = 542; b.value543 = 543; b.value544 = 544; b.value545 = 545; b.value546 = 546; b.value547 = 547; b.value548 = 548; b.value549 = 549; b.value550 = 550; b.value551 = 551; b.value552 = 552; b.value553 = 553; b.value554 = 554; b.value555 = 555; b.value556 = 556; b.value557 = 557; b.value558 = 558; b.value559 = 559; b.value560 = 560; b.value561 = 561; b.value562 = 562; b.value563 = 563; b.value564 = 564; b.value565 = 565; b.value566 = 566; b.value567 = 567; b.value568 = 568; b.value569 = 569; b.value570 = 570; b.value571 = 571; b.value572 = 572; b.value573 = 573; b.value574 = 574; b.value575 = 575; b.value576 = 576; b.value577 = 577; b.value578 = 578; b.value579 = 579; b.value580 = 580; b.value581 = 581; b.value582 = 582; b.value583 = 583; b.value584 = 584; b.value585 = 585; b.value586 = 586; b.value587 = 587; b.value588 = 588; b.value589 = 589; b.value590 = 590; b.value591 = 591; b.value592 = 592; b.value593 = 593; b.value594 = 594; b.value595 = 595; b.value596 = 596; b.value597 = 597; b.value598 = 598; b.value599 = 599; b.value600 = 600; b.value601 = 601; b.value602 = 602; b.value603 = 603; b.value604 = 604; b.value605 = 605; b.value606 = 606; b.value607 = 607; b.value608 = 608; b.value609 = 609; b.value610 = 610; b.value611 = 611; b.value612 = 612; b.value613 = 613; b.value614 = 614; b.value615 = 615; b.value616 = 616; b.value617 = 617; b.value618 = 618; b.value619 = 619; b.value620 = 620; b.value621 = 621; b.value622 = 622; b.value623 = 623; b.value624 = 624; b.value625 = 625; b.value626 = 626; b.value627 = 627; b.value628 = 628; b.value629 = 629; b.value630 = 630; b.value631 = 631; b.value632 = 632; b.value633 = 633; b.value634 = 634; b.value635 = 635; b.value636 = 636; b.value637 = 637; b.value638 = 638; b.value639 = 639; b.value640 = 640; b.value641 = 641; b.value642 = 642; b.value643 = 643; b.value644 = 644; b.value645 = 645; b.value646 = 646; b.value647 = 647; b.value648 = 648; b.value649 = 649; b.value650 = 650; b.value651 = 651; b.value652 = 652; b.value653 = 653; b.value654 = 654; b.value655 = 655; b.value656 = 656; b.value657 = 657; b.value658 = 658; b.value659 = 659; b.value660 = 660; b.value661 = 661; b.value662 = 662; b.value663 = 663; b.value664 = 664; b.value665 = 665; b.value666 = 666; b.value667 = 667; b.value668 = 668; b.value669 = 669; b.value670 = 670; b.value671 = 671; b.value672 = 672; b.value673 = 673; b.value674 = 674; b.value675 = 675; b.value676 = 676; b.value677 = 677; b.value678 = 678; b.value679 = 679; b.value680 = 680; b.value681 = 681; b.value682 = 682; b.value683 = 683; b.value684 = 684; b.value685 = 685; b.value686 = 686; b.value687 = 687; b.value688 = 688; b.value689 = 689; b.value690 = 690; b.value691 = 691; b.value692 = 692; b.value693 = 693; b.value694 = 694; b.value695 = 695; b.value696 = 696; b.value697 = 697; b.value698 = 698; b.value699 = 699; b.value700 = 700; b.value701 = 701; b.value702 = 702; b.value703 = 703; b.value704 = 704; b.value705 = 705; b.value706 = 706; b.value707 = 707; b.value708 = 708; b.value709 = 709; b.value710 = 710; b.value711 = 711; b.value712 = 712; b.value713 = 713; b.value714 = 714; b.value715 = 715; b.value716 = 716; b.value717 = 717; b.value718 = 718; b.value719 = 719; b.value720 = 720; b.value721 = 721; b.value722 = 722; b.value723 = 723; b.value724 = 724; b.value725 = 725; b.value726 = 726; b.value727 = 727; b.value728 = 728; b.value729 = 729; b.value730 = 730; b.value731 = 731; b.value732 = 732; b.value733 = 733; b.value734 = 734; b.value735 = 735; b.value736 = 736; b.value737 = 737; b.value738 = 738; b.value739 = 739; b.value740 = 740; b.value741 = 741; b.value742 = 742; b.value743 = 743; b.value744 = 744; b.value745 = 745; b.value746 = 746; b.value747 = 747; b.value748 = 748; b.value749 = 749; b.value750 = 750; b.value751 = 751; b.value752 = 752; b.value753 = 753; b.value754 = 754; b.value755 = 755; b.value756 = 756; b.value757 = 757; b.value758 = 758; b.value759 = 759; b.value760 = 760; b.value761 = 761; b.value762 = 762; b.value763 = 763; b.value764 = 764; b.value765 = 765; b.value766 = 766; b.value767 = 767; b.value768 = 768; b.value769 = 769; b.value770 = 770; b.value771 = 771; b.value772 = 772; b.value773 = 773; b.value774 = 774; b.value775 = 775; b.value776 = 776; b.value777 = 777; b.value778 = 778; b.value779 = 779; b.value780 = 780; b.value781 = 781; b.value782 = 782; b.value783 = 783; b.value784 = 784; b.value785 = 785; b.value786 = 786; b.value787 = 787; b.value788 = 788; b.value789 = 789; b.value790 = 790; b.value791 = 791; b.value792 = 792; b.value793 = 793; b.value794 = 794; b.value795 = 795; b.value796 = 796; b.value797 = 797; b.value798 = 798; b.value799 = 799; b.value800 = 800; b.value801 = 801; b.value802 = 802; b.value803 = 803; b.value804 = 804; b.value805 = 805; b.value806 = 806; b.value807 = 807; b.value808 = 808; b.value809 = 809; b.value810 = 810; b.value811 = 811; b.value812 = 812; b.value813 = 813; b.value814 = 814; b.value815 = 815; b.value816 = 816; b.value817 = 817; b.value818 = 818; b.value819 = 819; b.value820 = 820; b.value821 = 821; b.value822 = 822; b.value823 = 823; b.value824 = 824; b.value825 = 825; b.value826 = 826; b.value827 = 827; b.value828 = 828; b.value829 = 829; b.value830 = 830; b.value831 = 831; b.value832 = 832; b.value833 = 833; b.value834 = 834; b.value835 = 835; b.value836 = 836; b.value837 = 837; b.value838 = 838; b.value839 = 839; b.value840 = 840; b.value841 = 841; b.value842 = 842; b.value843 = 843; b.value844 = 844; b.value845 = 845; b.value846 = 846; b.value847 = 847; b.value848 = 848; b.value849 = 849; b.value850 = 850; b.value851 = 851; b.value852 = 852; b.value853 = 853; b.value854 = 854; b.value855 = 855; b.value856 = 856; b.value857 = 857; b.value858 = 858; b.value859 = 859; b.value860 = 860; b.value861 = 861; b.value862 = 862; b.value863 = 863; b.value864 = 864; b.value865 = 865; b.value866 = 866; b.value867 = 867; b.value868 = 868; b.value869 = 869; b.value870 = 870; b.value871 = 871; b.value872 = 872; b.value873 = 873; b.value874 = 874; b.value875 = 875; b.value876 = 876; b.value877 = 877; b.value878 = 878; b.value879 = 879; b.value880 = 880; b.value881 = 881; b.value882 = 882; b.value883 = 883; b.value884 = 884; b.value885 = 885; b.value886 = 886; b.value887 = 887; b.value888 = 888; b.value889 = 889; b.value890 = 890; b.value891 = 891; b.value892 = 892; b.value893 = 893; b.value894 = 894; b.value895 = 895; b.value896 = 896; b.value897 = 897; b.value898 = 898; b.value899 = 899; b.value900 = 900; b.value901 = 901; b.value902 = 902; b.value903 = 903; b.value904 = 904; b.value905 = 905; b.value906 = 906; b.value907 = 907; b.value908 = 908; b.value909 = 909; b.value910 = 910; b.value911 = 911; b.value912 = 912; b.value913 = 913; b.value914 = 914; b.value915 = 915; b.value916 = 916; b.value917 = 917; b.value918 = 918; b.value919 = 919; b.value920 = 920; b.value921 = 921; b.value922 = 922; b.value923 = 923; b.value924 = 924; b.value925 = 925; b.value926 = 926; b.value927 = 927; b.value928 = 928; b.value929 = 929; b.value930 = 930; b.value931 = 931; b.value932 = 932; b.value933 = 933; b.value934 = 934; b.value935 = 935; b.value936 = 936; b.value937 = 937; b.value938 = 938; b.value939 = 939; b.value940 = 940; b.value941 = 941; b.value942 = 942; b.value943 = 943; b.value944 = 944; b.value945 = 945; b.value946 = 946; b.value947 = 947; b.value948 = 948; b.value949 = 949; b.value950 = 950; b.value951 = 951; b.value952 = 952; b.value953 = 953; b.value954 = 954; b.value955 = 955; b.value956 = 956; b.value957 = 957; b.value958 = 958; b.value959 = 959; b.value960 = 960; b.value961 = 961; b.value962 = 962; b.value963 = 963; b.value964 = 964; b.value965 = 965; b.value966 = 966; b.value967 = 967; b.value968 = 968; b.value969 = 969; b.value970 = 970; b.value971 = 971; b.value972 = 972; b.value973 = 973; b.value974 = 974; b.value975 = 975; b.value976 = 976; b.value977 = 977; b.value978 = 978; b.value979 = 979; b.value980 = 980; b.value981 = 981; b.value982 = 982; b.value983 = 983; b.value984 = 984; b.value985 = 985; b.value986 = 986; b.value987 = 987; b.value988 = 988; b.value989 = 989; b.value990 = 990; b.value991 = 991; b.value992 = 992; b.value993 = 993; b.value994 = 994; b.value995 = 995; b.value996 = 996; b.value997 = 997; b.value998 = 998; b.value999 = 999; b.value1000 = 1000; b.value1001 = 1001; b.value1002 = 1002; b.value1003 = 1003; b.value1004 = 1004; b.value1005 = 1005; b.value1006 = 1006; b.value1007 = 1007; b.value1008 = 1008; b.value1009 = 1009; b.value1010 = 1010; b.value1011 = 1011; b.value1012 = 1012; b.value1013 = 1013; b.value1014 = 1014; b.value1015 = 1015; b.value1016 = 1016; b.value1017 = 1017; b.value1018 = 1018; b.value1019 = 1019; b.value1020 = 1020; b.value1021 = 1021; b.value1022 = 1022; b.value1023 = 1023; b.value1024 = 1024; b.value1025 = 1025; b.value1026 = 1026; b.value1027 = 1027; b.value1028 = 1028; b.value1029 = 1029; b.value1030 = 1030; b.value1031 = 1031; b.value1032 = 1032; b.value1033 = 1033; b.value1034 = 1034; b.value1035 = 1035; b.value1036 = 1036; b.value1037 = 1037; b.value1038 = 1038; b.value1039 = 1039; b.value1040 = 1040; b.value1041 = 1041; b.value1042 = 1042; b.value1043 = 1043; b.value1044 = 1044; b.value1045 = 1045; b.value1046 = 1046; b.value1047 = 1047; b.value1048 = 1048; b.value1049 = 1049; b.value1050 = 1050; b.value1051 = 1051; b.value1052 = 1052; b.value1053 = 1053; b.value1054 = 1054; b.value1055 = 1055; b.value1056 = 1056; b.value1057 = 1057; b.value1058 = 1058; b.value1059 = 1059; b.value1060 = 1060; b.value1061 = 1061; b.value1062 = 1062; b.value1063 = 1063; b.value1064 = 1064; b.value1065 = 1065; b.value1066 = 1066; b.value1067 = 1067; b.value1068 = 1068; b.value1069 = 1069; b.value1070 = 1070; b.value1071 = 1071; b.value1072 = 1072; b.value1073 = 1073; b.value1074 = 1074; b.value1075 = 1075; b.value1076 = 1076; b.value1077 = 1077; b.value1078 = 1078; b.value1079 = 1079; b.value1080 = 1080; b.value1081 = 1081; b.value1082 = 1082; b.value1083 = 1083; b.value1084 = 1084; b.value1085 = 1085; b.value1086 = 1086; b.value1087 = 1087; b.value1088 = 1088; b.value1089 = 1089; b.value1090 = 1090; b.value1091 = 1091; b.value1092 = 1092; b.value1093 = 1093; b.value1094 = 1094; b.value1095 = 1095; b.value1096 = 1096; b.value1097 = 1097; b.value1098 = 1098; b.value1099 = 1099; b.value1100 = 1100; b.value1101 = 1101; b.value1102 = 1102; b.value1103 = 1103; b.value1104 = 1104; b.value1105 = 1105; b.value1106 = 1106; b.value1107 = 1107; b.value1108 = 1108; b.value1109 = 1109; b.value1110 = 1110; b.value1111 = 1111; b.value1112 = 1112; b.value1113 = 1113; b.value1114 = 1114; b.value1115 = 1115; b.value1116 = 1116; b.value1117 = 1117; b.value1118 = 1118; b.value1119 = 1119; b.value1120 = 1120; b.value1121 = 1121; b.value1122 = 1122; b.value1123 = 1123; b.value1124 = 1124; b.value1125 = 1125; b.value1126 = 1126; b.value1127 = 1127; b.value1128 = 1128; b.value1129 = 1129; b.value1130 = 1130; b.value1131 = 1131; b.value1132 = 1132; b.value1133 = 1133; b.value1134 = 1134; b.value1135 = 1135; b.value1136 = 1136; b.value1137 = 1137; b.value1138 = 1138; b.value1139 = 1139; b.value1140 = 1140; b.value1141 = 1141; b.value1142 = 1142; b.value1143 = 1143; b.value1144 = 1144; b.value1145 = 1145; b.value1146 = 1146; b.value1147 = 1147; b.value1148 = 1148; b.value1149 = 1149; b.value1150 = 1150; b.value1151 = 1151; b.value1152 = 1152; b.value1153 = 1153; b.value1154 = 1154; b.value1155 = 1155; b.value1156 = 1156; b.value1157 = 1157; b.value1158 = 1158; b.value1159 = 1159; b.value1160 = 1160; b.value1161 = 1161; b.value1162 = 1162; b.value1163 = 1163; b.value1164 = 1164; b.value1165 = 1165; b.value1166 = 1166; b.value1167 = 1167; b.value1168 = 1168; b.value1169 = 1169; b.value1170 = 1170; b.value1171 = 1171; b.value1172 = 1172; b.value1173 = 1173; b.value1174 = 1174; b.value1175 = 1175; b.value1176 = 1176; b.value1177 = 1177; b.value1178 = 1178; b.value1179 = 1179; b.value1180 = 1180; b.value1181 = 1181; b.value1182 = 1182; b.value1183 = 1183; b.value1184 = 1184; b.value1185 = 1185; b.value1186 = 1186; b.value1187 = 1187; b.value1188 = 1188; b.value1189 = 1189; b.value1190 = 1190; b.value1191 = 1191; b.value1192 = 1192; b.value1193 = 1193; b.value1194 = 1194; b.value1195 = 1195; b.value1196 = 1196; b.value1197 = 1197; b.value1198 = 1198; b.value1199 = 1199; b.value1200 = 1200; b.value1201 = 1201; b.value1202 = 1202; b.value1203 = 1203; b.value1204 = 1204; b.value1205 = 1205; b.value1206 = 1206; b.value1207 = 1207; b.value1208 = 1208; b.value1209 = 1209; b.value1210 = 1210; b.value1211 = 1211; b.value1212 = 1212; b.value1213 = 1213; b.value1214 = 1214; b.value1215 = 1215; b.value1216 = 1216; b.value1217 = 1217; b.value1218 = 1218; b.value1219 = 1219; b.value1220 = 1220; b.value1221 = 1221; b.value1222 = 1222; b.value1223 = 1223; b.value1224 = 1224; b.value1225 = 1225; b.value1226 = 1226; b.value1227 = 1227; b.value1228 = 1228; b.value1229 = 1229; b.value1230 = 1230; b.value1231 = 1231; b.value1232 = 1232; b.value1233 = 1233; b.value1234 = 1234; b.value1235 = 1235; b.value1236 = 1236; b.value1237 = 1237; b.value1238 = 1238; b.value1239 = 1239; b.value1240 = 1240; b.value1241 = 1241; b.value1242 = 1242; b.value1243 = 1243; b.value1244 = 1244; b.value1245 = 1245; b.value1246 = 1246; b.value1247 = 1247; b.value1248 = 1248; b.value1249 = 1249; b.value1250 = 1250; b.value1251 = 1251; b.value1252 = 1252; b.value1253 = 1253; b.value1254 = 1254; b.value1255 = 1255; b.value1256 = 1256; b.value1257 = 1257; b.value1258 = 1258; b.value1259 = 1259; b.value1260 = 1260; b.value1261 = 1261; b.value1262 = 1262; b.value1263 = 1263; b.value1264 = 1264; b.value1265 = 1265; b.value1266 = 1266; b.value1267 = 1267; b.value1268 = 1268; b.value1269 = 1269; b.value1270 = 1270; b.value1271 = 1271; b.value1272 = 1272; b.value1273 = 1273; b.value1274 = 1274; b.value1275 = 1275; b.value1276 = 1276; b.value1277 = 1277; b.value1278 = 1278; b.value1279 = 1279; b.value1280 = 1280; b.value1281 = 1281; b.value1282 = 1282; b.value1283 = 1283; b.value1284 = 1284; b.value1285 = 1285; b.value1286 = 1286; b.value1287 = 1287; b.value1288 = 1288; b.value1289 = 1289; b.value1290 = 1290; b.value1291 = 1291; b.value1292 = 1292; b.value1293 = 1293; b.value1294 = 1294; b.value1295 = 1295; b.value1296 = 1296; b.value1297 = 1297; b.value1298 = 1298; b.value1299 = 1299; b.value1300 = 1300; b.value1301 = 1301; b.value1302 = 1302; b.value1303 = 1303; b.value1304 = 1304; b.value1305 = 1305; b.value1306 = 1306; b.value1307 = 1307; b.value1308 = 1308; b.value1309 = 1309; b.value1310 = 1310; b.value1311 = 1311; b.value1312 = 1312; b.value1313 = 1313; b.value1314 = 1314; b.value1315 = 1315; b.value1316 = 1316; b.value1317 = 1317; b.value1318 = 1318; b.value1319 = 1319; b.value1320 = 1320; b.value1321 = 1321; b.value1322 = 1322; b.value1323 = 1323; b.value1324 = 1324; b.value1325 = 1325; b.value1326 = 1326; b.value1327 = 1327; b.value1328 = 1328; b.value1329 = 1329; b.value1330 = 1330; b.value1331 = 1331; b.value1332 = 1332; b.value1333 = 1333; b.value1334 = 1334; b.value1335 = 1335; b.value1336 = 1336; b.value1337 = 1337; b.value1338 = 1338; b.value1339 = 1339; b.value1340 = 1340; b.value1341 = 1341; b.value1342 = 1342; b.value1343 = 1343; b.value1344 = 1344; b.value1345 = 1345; b.value1346 = 1346; b.value1347 = 1347; b.value1348 = 1348; b.value1349 = 1349; b.value1350 = 1350; b.value1351 = 1351; b.value1352 = 1352; b.value1353 = 1353; b.value1354 = 1354; b.value1355 = 1355; b.value1356 = 1356; b.value1357 = 1357; b.value1358 = 1358; b.value1359 = 1359; b.value1360 = 1360; b.value1361 = 1361; b.value1362 = 1362; b.value1363 = 1363; b.value1364 = 1364; b.value1365 = 1365; b.value1366 = 1366; b.value1367 = 1367; b.value1368 = 1368; b.value1369 = 1369; b.value1370 = 1370; b.value1371 = 1371; b.value1372 = 1372; b.value1373 = 1373; b.value1374 = 1374; b.value1375 = 1375; b.value1376 = 1376; b.value1377 = 1377; b.value1378 = 1378; b.value1379 = 1379; b.value1380 = 1380; b.value1381 = 1381; b.value1382 = 1382; b.value1383 = 1383; b.value1384 = 1384; b.value1385 = 1385; b.value1386 = 1386; b.value1387 = 1387; b.value1388 = 1388; b.value1389 = 1389; b.value1390 = 1390; b.value1391 = 1391; b.value1392 = 1392; b.value1393 = 1393; b.value1394 = 1394; b.value1395 = 1395; b.value1396 = 1396; b.value1397 = 1397; b.value1398 = 1398; b.value1399 = 1399; b.value1400 = 1400; b.value1401 = 1401; b.value1402 = 1402; b.value1403 = 1403; b.value1404 = 1404; b.value1405 = 1405; b.value1406 = 1406; b.value1407 = 1407; b.value1408 = 1408; b.value1409 = 1409; b.value1410 = 1410; b.value1411 = 1411; b.value1412 = 1412; b.value1413 = 1413; b.value1414 = 1414; b.value1415 = 1415; b.value1416 = 1416; b.value1417 = 1417; b.value1418 = 1418; b.value1419 = 1419; b.value1420 = 1420; b.value1421 = 1421; b.value1422 = 1422; b.value1423 = 1423; b.value1424 = 1424; b.value1425 = 1425; b.value1426 = 1426; b.value1427 = 1427; b.value1428 = 1428; b.value1429 = 1429; b.value1430 = 1430; b.value1431 = 1431; b.value1432 = 1432; b.value1433 = 1433; b.value1434 = 1434; b.value1435 = 1435; b.value1436 = 1436; b.value1437 = 1437; b.value1438 = 1438; b.value1439 = 1439; b.value1440 = 1440; b.value1441 = 1441; b.value1442 = 1442; b.value1443 = 1443; b.value1444 = 1444; b.value1445 = 1445; b.value1446 = 1446; b.value1447 = 1447; b.value1448 = 1448; b.value1449 = 1449; b.value1450 = 1450; b.value1451 = 1451; b.value1452 = 1452; b.value1453 = 1453; b.value1454 = 1454; b.value1455 = 1455; b.value1456 = 1456; b.value1457 = 1457; b.value1458 = 1458; b.value1459 = 1459; b.value1460 = 1460; b.value1461 = 1461; b.value1462 = 1462; b.value1463 = 1463; b.value1464 = 1464; b.value1465 = 1465; b.value1466 = 1466; b.value1467 = 1467; b.value1468 = 1468; b.value1469 = 1469; b.value1470 = 1470; b.value1471 = 1471; b.value1472 = 1472; b.value1473 = 1473; b.value1474 = 1474; b.value1475 = 1475; b.value1476 = 1476; b.value1477 = 1477; b.value1478 = 1478; b.value1479 = 1479; b.value1480 = 1480; b.value1481 = 1481; b.value1482 = 1482; b.value1483 = 1483; b.value1484 = 1484; b.value1485 = 1485; b.value1486 = 1486; b.value1487 = 1487; b.value1488 = 1488; b.value1489 = 1489; b.value1490 = 1490; b.value1491 = 1491; b.value1492 = 1492; b.value1493 = 1493; b.value1494 = 1494; b.value1495 = 1495; b.value1496 = 1496; b.value1497 = 1497; b.value1498 = 1498; b.value1499 = 1499; b.value1500 = 1500; b.value1501 = 1501; b.value1502 = 1502; b.value1503 = 1503; b.value1504 = 1504; b.value1505 = 1505; b.value1506 = 1506; b.value1507 = 1507; b.value1508 = 1508; b.value1509 = 1509; b.value1510 = 1510; b.value1511 = 1511; b.value1512 = 1512; b.value1513 = 1513; b.value1514 = 1514; b.value1515 = 1515; b.value1516 = 1516; b.value1517 = 1517; b.value1518 = 1518; b.value1519 = 1519; b.value1520 = 1520; b.value1521 = 1521; b.value1522 = 1522; b.value1523 = 1523; b.value1524 = 1524; b.value1525 = 1525; b.value1526 = 1526; b.value1527 = 1527; b.value1528 = 1528; b.value1529 = 1529; b.value1530 = 1530; b.value1531 = 1531; b.value1532 = 1532; b.value1533 = 1533; b.value1534 = 1534; b.value1535 = 1535; b.value1536 = 1536; b.value1537 = 1537; b.value1538 = 1538; b.value1539 = 1539; b.value1540 = 1540; b.value1541 = 1541; b.value1542 = 1542; b.value1543 = 1543; b.value1544 = 1544; b.value1545 = 1545; b.value1546 = 1546; b.value1547 = 1547; b.value1548 = 1548; b.value1549 = 1549; b.value1550 = 1550; b.value1551 = 1551; b.value1552 = 1552; b.value1553 = 1553; b.value1554 = 1554; b.value1555 = 1555; b.value1556 = 1556; b.value1557 = 1557; b.value1558 = 1558; b.value1559 = 1559; b.value1560 = 1560; b.value1561 = 1561; b.value1562 = 1562; b.value1563 = 1563; b.value1564 = 1564; b.value1565 = 1565; b.value1566 = 1566; b.value1567 = 1567; b.value1568 = 1568; b.value1569 = 1569; b.value1570 = 1570; b.value1571 = 1571; b.value1572 = 1572; b.value1573 = 1573; b.value1574 = 1574; b.value1575 = 1575; b.value1576 = 1576; b.value1577 = 1577; b.value1578 = 1578; b.value1579 = 1579; b.value1580 = 1580; b.value1581 = 1581; b.value1582 = 1582; b.value1583 = 1583; b.value1584 = 1584; b.value1585 = 1585; b.value1586 = 1586; b.value1587 = 1587; b.value1588 = 1588; b.value1589 = 1589; b.value1590 = 1590; b.value1591 = 1591; b.value1592 = 1592; b.value1593 = 1593; b.value1594 = 1594; b.value1595 = 1595; b.value1596 = 1596; b.value1597 = 1597; b.value1598 = 1598; b.value1599 = 1599; b.value1600 = 1600; b.value1601 = 1601; b.value1602 = 1602; b.value1603 = 1603; b.value1604 = 1604; b.value1605 = 1605; b.value1606 = 1606; b.value1607 = 1607; b.value1608 = 1608; b.value1609 = 1609; b.value1610 = 1610; b.value1611 = 1611; b.value1612 = 1612; b.value1613 = 1613; b.value1614 = 1614; b.value1615 = 1615; b.value1616 = 1616; b.value1617 = 1617; b.value1618 = 1618; b.value1619 = 1619; b.value1620 = 1620; b.value1621 = 1621; b.value1622 = 1622; b.value1623 = 1623; b.value1624 = 1624; b.value1625 = 1625; b.value1626 = 1626; b.value1627 = 1627; b.value1628 = 1628; b.value1629 = 1629; b.value1630 = 1630; b.value1631 = 1631; b.value1632 = 1632; b.value1633 = 1633; b.value1634 = 1634; b.value1635 = 1635; b.value1636 = 1636; b.value1637 = 1637; b.value1638 = 1638; b.value1639 = 1639; b.value1640 = 1640; b.value1641 = 1641; b.value1642 = 1642; b.value1643 = 1643; b.value1644 = 1644; b.value1645 = 1645; b.value1646 = 1646; b.value1647 = 1647; b.value1648 = 1648; b.value1649 = 1649; b.value1650 = 1650; b.value1651 = 1651; b.value1652 = 1652; b.value1653 = 1653; b.value1654 = 1654; b.value1655 = 1655; b.value1656 = 1656; b.value1657 = 1657; b.value1658 = 1658; b.value1659 = 1659; b.value1660 = 1660; b.value1661 = 1661; b.value1662 = 1662; b.value1663 = 1663; b.value1664 = 1664; b.value1665 = 1665; b.value1666 = 1666; b.value1667 = 1667; b.value1668 = 1668; b.value1669 = 1669; b.value1670 = 1670; b.value1671 = 1671; b.value1672 = 1672; b.value1673 = 1673; b.value1674 = 1674; b.value1675 = 1675; b.value1676 = 1676; b.value1677 = 1677; b.value1678 = 1678; b.value1679 = 1679; b.value1680 = 1680; b.value1681 = 1681; b.value1682 = 1682; b.value1683 = 1683; b.value1684 = 1684; b.value1685 = 1685; b.value1686 = 1686; b.value1687 = 1687; b.value1688 = 1688; b.value1689 = 1689; b.value1690 = 1690; b.value1691 = 1691; b.value1692 = 1692; b.value1693 = 1693; b.value1694 = 1694; b.value1695 = 1695; b.value1696 = 1696; b.value1697 = 1697; b.value1698 = 1698; b.value1699 = 1699; b.value1700 = 1700; b.value1701 = 1701; b.value1702 = 1702; b.value1703 = 1703; b.value1704 = 1704; b.value1705 = 1705; b.value1706 = 1706; b.value1707 = 1707; b.value1708 = 1708; b.value1709 = 1709; b.value1710 = 1710; b.value1711 = 1711; b.value1712 = 1712; b.value1713 = 1713; b.value1714 = 1714; b.value1715 = 1715; b.value1716 = 1716; b.value1717 = 1717; b.value1718 = 1718; b.value1719 = 1719; b.value1720 = 1720; b.value1721 = 1721; b.value1722 = 1722; b.value1723 = 1723; b.value1724 = 1724; b.value1725 = 1725; b.value1726 = 1726; b.value1727 = 1727; b.value1728 = 1728; b.value1729 = 1729; b.value1730 = 1730; b.value1731 = 1731; b.value1732 = 1732; b.value1733 = 1733; b.value1734 = 1734; b.value1735 = 1735; b.value1736 = 1736; b.value1737 = 1737; b.value1738 = 1738; b.value1739 = 1739; b.value1740 = 1740; b.value1741 = 1741; b.value1742 = 1742; b.value1743 = 1743; b.value1744 = 1744; b.value1745 = 1745; b.value1746 = 1746; b.value1747 = 1747; b.value1748 = 1748; b.value1749 = 1749; b.value1750 = 1750; b.value1751 = 1751; b.value1752 = 1752; b.value1753 = 1753; b.value1754 = 1754; b.value1755 = 1755; b.value1756 = 1756; b.value1757 = 1757; b.value1758 = 1758; b.value1759 = 1759; b.value1760 = 1760; b.value1761 = 1761; b.value1762 = 1762; b.value1763 = 1763; b.value1764 = 1764; b.value1765 = 1765; b.value1766 = 1766; b.value1767 = 1767; b.value1768 = 1768; b.value1769 = 1769; b.value1770 = 1770; b.value1771 = 1771; b.value1772 = 1772; b.value1773 = 1773; b.value1774 = 1774; b.value1775 = 1775; b.value1776 = 1776; b.value1777 = 1777; b.value1778 = 1778; b.value1779 = 1779; b.value1780 = 1780; b.value1781 = 1781; b.value1782 = 1782; b.value1783 = 1783; b.value1784 = 1784; b.value1785 = 1785; b.value1786 = 1786; b.value1787 = 1787; b.value1788 = 1788; b.value1789 = 1789; b.value1790 = 1790; b.value1791 = 1791; b.value1792 = 1792; b.value1793 = 1793; b.value1794 = 1794; b.value1795 = 1795; b.value1796 = 1796; b.value1797 = 1797; b.value1798 = 1798; b.value1799 = 1799; b.value1800 = 1800; b.value1801 = 1801; b.value1802 = 1802; b.value1803 = 1803; b.value1804 = 1804; b.value1805 = 1805; b.value1806 = 1806; b.value1807 = 1807; b.value1808 = 1808; b.value1809 = 1809; b.value1810 = 1810; b.value1811 = 1811; b.value1812 = 1812; b.value1813 = 1813; b.value1814 = 1814; b.value1815 = 1815; b.value1816 = 1816; b.value1817 = 1817; b.value1818 = 1818; b.value1819 = 1819; b.value1820 = 1820; b.value1821 = 1821; b.value1822 = 1822; b.value1823 = 1823; b.value1824 = 1824; b.value1825 = 1825; b.value1826 = 1826; b.value1827 = 1827; b.value1828 = 1828; b.value1829 = 1829; b.value1830 = 1830; b.value1831 = 1831; b.value1832 = 1832; b.value1833 = 1833; b.value1834 = 1834; b.value1835 = 1835; b.value1836 = 1836; b.value1837 = 1837; b.value1838 = 1838; b.value1839 = 1839; b.value1840 = 1840; b.value1841 = 1841; b.value1842 = 1842; b.value1843 = 1843; b.value1844 = 1844; b.value1845 = 1845; b.value1846 = 1846; b.value1847 = 1847; b.value1848 = 1848; b.value1849 = 1849; b.value1850 = 1850; b.value1851 = 1851; b.value1852 = 1852; b.value1853 = 1853; b.value1854 = 1854; b.value1855 = 1855; b.value1856 = 1856; b.value1857 = 1857; b.value1858 = 1858; b.value1859 = 1859; b.value1860 = 1860; b.value1861 = 1861; b.value1862 = 1862; b.value1863 = 1863; b.value1864 = 1864; b.value1865 = 1865; b.value1866 = 1866; b.value1867 = 1867; b.value1868 = 1868; b.value1869 = 1869; b.value1870 = 1870; b.value1871 = 1871; b.value1872 = 1872; b.value1873 = 1873; b.value1874 = 1874; b.value1875 = 1875; b.value1876 = 1876; b.value1877 = 1877; b.value1878 = 1878; b.value1879 = 1879; b.value1880 = 1880; b.value1881 = 1881; b.value1882 = 1882; b.value1883 = 1883; b.value1884 = 1884; b.value1885 = 1885; b.value1886 = 1886; b.value1887 = 1887; b.value1888 = 1888; b.value1889 = 1889; b.value1890 = 1890; b.value1891 = 1891; b.value1892 = 1892; b.value1893 = 1893; b.value1894 = 1894; b.value1895 = 1895; b.value1896 = 1896; b.value1897 = 1897; b.value1898 = 1898; b.value1899 = 1899; b.value1900 = 1900; b.value1901 = 1901; b.value1902 = 1902; b.value1903 = 1903; b.value1904 = 1904; b.value1905 = 1905; b.value1906 = 1906; b.value1907 = 1907; b.value1908 = 1908; b.value1909 = 1909; b.value1910 = 1910; b.value1911 = 1911; b.value1912 = 1912; b.value1913 = 1913; b.value1914 = 1914; b.value1915 = 1915; b.value1916 = 1916; b.value1917 = 1917; b.value1918 = 1918; b.value1919 = 1919; b.value1920 = 1920; b.value1921 = 1921; b.value1922 = 1922; b.value1923 = 1923; b.value1924 = 1924; b.value1925 = 1925; b.value1926 = 1926; b.value1927 = 1927; b.value1928 = 1928; b.value1929 = 1929; b.value1930 = 1930; b.value1931 = 1931; b.value1932 = 1932; b.value1933 = 1933; b.value1934 = 1934; b.value1935 = 1935; b.value1936 = 1936; b.value1937 = 1937; b.value1938 = 1938; b.value1939 = 1939; b.value1940 = 1940; b.value1941 = 1941; b.value1942 = 1942; b.value1943 = 1943; b.value1944 = 1944; b.value1945 = 1945; b.value1946 = 1946; b.value1947 = 1947; b.value1948 = 1948; b.value1949 = 1949; b.value1950 = 1950; b.value1951 = 1951; b.value1952 = 1952; b.value1953 = 1953; b.value1954 = 1954; b.value1955 = 1955; b.value1956 = 1956; b.value1957 = 1957; b.value1958 = 1958; b.value1959 = 1959; b.value1960 = 1960; b.value1961 = 1961; b.value1962 = 1962; b.value1963 = 1963; b.value1964 = 1964; b.value1965 = 1965; b.value1966 = 1966; b.value1967 = 1967; b.value1968 = 1968; b.value1969 = 1969; b.value1970 = 1970; b.value1971 = 1971; b.value1972 = 1972; b.value1973 = 1973; b.value1974 = 1974; b.value1975 = 1975; b.value1976 = 1976; b.value1977 = 1977; b.value1978 = 1978; b.value1979 = 1979; b.value1980 = 1980; b.value1981 = 1981; b.value1982 = 1982; b.value1983 = 1983; b.value1984 = 1984; b.value1985 = 1985; b.value1986 = 1986; b.value1987 = 1987; b.value1988 = 1988; b.value1989 = 1989; b.value1990 = 1990; b.value1991 = 1991; b.value1992 = 1992; b.value1993 = 1993; b.value1994 = 1994; b.value1995 = 1995; b.value1996 = 1996; b.value1997 = 1997; b.value1998 = 1998; b.value1999 = 1999; b.value2000 = 2000; b.value2001 = 2001; b.value2002 = 2002; b.value2003 = 2003; b.value2004 = 2004; b.value2005 = 2005; b.value2006 = 2006; b.value2007 = 2007; b.value2008 = 2008; b.value2009 = 2009; b.value2010 = 2010; b.value2011 = 2011; b.value2012 = 2012; b.value2013 = 2013; b.value2014 = 2014; b.value2015 = 2015; b.value2016 = 2016; b.value2017 = 2017; b.value2018 = 2018; b.value2019 = 2019; b.value2020 = 2020; b.value2021 = 2021; b.value2022 = 2022; b.value2023 = 2023; b.value2024 = 2024; b.value2025 = 2025; b.value2026 = 2026; b.value2027 = 2027; b.value2028 = 2028; b.value2029 = 2029; b.value2030 = 2030; b.value2031 = 2031; b.value2032 = 2032; b.value2033 = 2033; b.value2034 = 2034; b.value2035 = 2035; b.value2036 = 2036; b.value2037 = 2037; b.value2038 = 2038; b.value2039 = 2039; b.value2040 = 2040; b.value2041 = 2041; b.value2042 = 2042; b.value2043 = 2043; b.value2044 = 2044; b.value2045 = 2045; b.value2046 = 2046; b.value2047 = 2047; b.value2048 = 2048; b.value2049 = 2049; b.value2050 = 2050; b.value2051 = 2051; b.value2052 = 2052; b.value2053 = 2053; b.value2054 = 2054; b.value2055 = 2055; b.value2056 = 2056; b.value2057 = 2057; b.value2058 = 2058; b.value2059 = 2059; b.value2060 = 2060; b.value2061 = 2061; b.value2062 = 2062; b.value2063 = 2063; b.value2064 = 2064; b.value2065 = 2065; b.value2066 = 2066; b.value2067 = 2067; b.value2068 = 2068; b.value2069 = 2069; b.value2070 = 2070; b.value2071 = 2071; b.value2072 = 2072; b.value2073 = 2073; b.value2074 = 2074; b.value2075 = 2075; b.value2076 = 2076; b.value2077 = 2077; b.value2078 = 2078; b.value2079 = 2079; b.value2080 = 2080; b.value2081 = 2081; b.value2082 = 2082; b.value2083 = 2083; b.value2084 = 2084; b.value2085 = 2085; b.value2086 = 2086; b.value2087 = 2087; b.value2088 = 2088; b.value2089 = 2089; b.value2090 = 2090; b.value2091 = 2091; b.value2092 = 2092; b.value2093 = 2093; b.value2094 = 2094; b.value2095 = 2095; b.value2096 = 2096; b.value2097 = 2097; b.value2098 = 2098; b.value2099 = 2099; b.value2100 = 2100; b.value2101 = 2101; b.value2102 = 2102; b.value2103 = 2103; b.value2104 = 2104; b.value2105 = 2105; b.value2106 = 2106; b.value2107 = 2107; b.value2108 = 2108; b.value2109 = 2109; b.value2110 = 2110; b.value2111 = 2111; b.value2112 = 2112; b.value2113 = 2113; b.value2114 = 2114; b.value2115 = 2115; b.value2116 = 2116; b.value2117 = 2117; b.value2118 = 2118; b.value2119 = 2119; b.value2120 = 2120; b.value2121 = 2121; b.value2122 = 2122; b.value2123 = 2123; b.value2124 = 2124; b.value2125 = 2125; b.value2126 = 2126; b.value2127 = 2127; b.value2128 = 2128; b.value2129 = 2129; b.value2130 = 2130; b.value2131 = 2131; b.value2132 = 2132; b.value2133 = 2133; b.value2134 = 2134; b.value2135 = 2135; b.value2136 = 2136; b.value2137 = 2137; b.value2138 = 2138; b.value2139 = 2139; b.value2140 = 2140; b.value2141 = 2141; b.value2142 = 2142; b.value2143 = 2143; b.value2144 = 2144; b.value2145 = 2145; b.value2146 = 2146; b.value2147 = 2147; b.value2148 = 2148; b.value2149 = 2149; b.value2150 = 2150; b.value2151 = 2151; b.value2152 = 2152; b.value2153 = 2153; b.value2154 = 2154; b.value2155 = 2155; b.value2156 = 2156; b.value2157 = 2157; b.value2158 = 2158; b.value2159 = 2159; b.value2160 = 2160; b.value2161 = 2161; b.value2162 = 2162; b.value2163 = 2163; b.value2164 = 2164; b.value2165 = 2165; b.value2166 = 2166; b.value2167 = 2167; b.value2168 = 2168; b.value2169 = 2169; b.value2170 = 2170; b.value2171 = 2171; b.value2172 = 2172; b.value2173 = 2173; b.value2174 = 2174; b.value2175 = 2175; b.value2176 = 2176; b.value2177 = 2177; b.value2178 = 2178; b.value2179 = 2179; b.value2180 = 2180; b.value2181 = 2181; b.value2182 = 2182; b.value2183 = 2183; b.value2184 = 2184; b.value2185 = 2185; b.value2186 = 2186; b.value2187 = 2187; b.value2188 = 2188; b.value2189 = 2189; b.value2190 = 2190; b.value2191 = 2191; b.value2192 = 2192; b.value2193 = 2193; b.value2194 = 2194; b.value2195 = 2195; b.value2196 = 2196; b.value2197 = 2197; b.value2198 = 2198; b.value2199 = 2199; b.value2200 = 2200; b.value2201 = 2201; b.value2202 = 2202; b.value2203 = 2203; b.value2204 = 2204; b.value2205 = 2205; b.value2206 = 2206; b.value2207 = 2207; b.value2208 = 2208; b.value2209 = 2209; b.value2210 = 2210; b.value2211 = 2211; b.value2212 = 2212; b.value2213 = 2213; b.value2214 = 2214; b.value2215 = 2215; b.value2216 = 2216; b.value2217 = 2217; b.value2218 = 2218; b.value2219 = 2219; b.value2220 = 2220; b.value2221 = 2221; b.value2222 = 2222; b.value2223 = 2223; b.value2224 = 2224; b.value2225 = 2225; b.value2226 = 2226; b.value2227 = 2227; b.value2228 = 2228; b.value2229 = 2229; b.value2230 = 2230; b.value2231 = 2231; b.value2232 = 2232; b.value2233 = 2233; b.value2234 = 2234; b.value2235 = 2235; b.value2236 = 2236; b.value2237 = 2237; b.value2238 = 2238; b.value2239 = 2239; b.value2240 = 2240; b.value2241 = 2241; b.value2242 = 2242; b.value2243 = 2243; b.value2244 = 2244; b.value2245 = 2245; b.value2246 = 2246; b.value2247 = 2247; b.value2248 = 2248; b.value2249 = 2249; b.value2250 = 2250; b.value2251 = 2251; b.value2252 = 2252; b.value2253 = 2253; b.value2254 = 2254; b.value2255 = 2255; b.value2256 = 2256; b.value2257 = 2257; b.value2258 = 2258; b.value2259 = 2259; b.value2260 = 2260; b.value2261 = 2261; b.value2262 = 2262; b.value2263 = 2263; b.value2264 = 2264; b.value2265 = 2265; b.value2266 = 2266; b.value2267 = 2267; b.value2268 = 2268; b.value2269 = 2269; b.value2270 = 2270; b.value2271 = 2271; b.value2272 = 2272; b.value2273 = 2273; b.value2274 = 2274; b.value2275 = 2275; b.value2276 = 2276; b.value2277 = 2277; b.value2278 = 2278; b.value2279 = 2279; b.value2280 = 2280; b.value2281 = 2281; b.value2282 = 2282; b.value2283 = 2283; b.value2284 = 2284; b.value2285 = 2285; b.value2286 = 2286; b.value2287 = 2287; b.value2288 = 2288; b.value2289 = 2289; b.value2290 = 2290; b.value2291 = 2291; b.value2292 = 2292; b.value2293 = 2293; b.value2294 = 2294; b.value2295 = 2295; b.value2296 = 2296; b.value2297 = 2297; b.value2298 = 2298; b.value2299 = 2299; b.value2300 = 2300; b.value2301 = 2301; b.value2302 = 2302; b.value2303 = 2303; b.value2304 = 2304; b.value2305 = 2305; b.value2306 = 2306; b.value2307 = 2307; b.value2308 = 2308; b.value2309 = 2309; b.value2310 = 2310; b.value2311 = 2311; b.value2312 = 2312; b.value2313 = 2313; b.value2314 = 2314; b.value2315 = 2315; b.value2316 = 2316; b.value2317 = 2317; b.value2318 = 2318; b.value2319 = 2319; b.value2320 = 2320; b.value2321 = 2321; b.value2322 = 2322; b.value2323 = 2323; b.value2324 = 2324; b.value2325 = 2325; b.value2326 = 2326; b.value2327 = 2327; b.value2328 = 2328; b.value2329 = 2329; b.value2330 = 2330; b.value2331 = 2331; b.value2332 = 2332; b.value2333 = 2333; b.value2334 = 2334; b.value2335 = 2335; b.value2336 = 2336; b.value2337 = 2337; b.value2338 = 2338; b.value2339 = 2339; b.value2340 = 2340; b.value2341 = 2341; b.value2342 = 2342; b.value2343 = 2343; b.value2344 = 2344; b.value2345 = 2345; b.value2346 = 2346; b.value2347 = 2347; b.value2348 = 2348; b.value2349 = 2349; b.value2350 = 2350; b.value2351 = 2351; b.value2352 = 2352; b.value2353 = 2353; b.value2354 = 2354; b.value2355 = 2355; b.value2356 = 2356; b.value2357 = 2357; b.value2358 = 2358; b.value2359 = 2359; b.value2360 = 2360; b.value2361 = 2361; b.value2362 = 2362; b.value2363 = 2363; b.value2364 = 2364; b.value2365 = 2365; b.value2366 = 2366; b.value2367 = 2367; b.value2368 = 2368; b.value2369 = 2369; b.value2370 = 2370; b.value2371 = 2371; b.value2372 = 2372; b.value2373 = 2373; b.value2374 = 2374; b.value2375 = 2375; b.value2376 = 2376; b.value2377 = 2377; b.value2378 = 2378; b.value2379 = 2379; b.value2380 = 2380; b.value2381 = 2381; b.value2382 = 2382; b.value2383 = 2383; b.value2384 = 2384; b.value2385 = 2385; b.value2386 = 2386; b.value2387 = 2387; b.value2388 = 2388; b.value2389 = 2389; b.value2390 = 2390; b.value2391 = 2391; b.value2392 = 2392; b.value2393 = 2393; b.value2394 = 2394; b.value2395 = 2395; b.value2396 = 2396; b.value2397 = 2397; b.value2398 = 2398; b.value2399 = 2399; b.value2400 = 2400; b.value2401 = 2401; b.value2402 = 2402; b.value2403 = 2403; b.value2404 = 2404; b.value2405 = 2405; b.value2406 = 2406; b.value2407 = 2407; b.value2408 = 2408; b.value2409 = 2409; b.value2410 = 2410; b.value2411 = 2411; b.value2412 = 2412; b.value2413 = 2413; b.value2414 = 2414; b.value2415 = 2415; b.value2416 = 2416; b.value2417 = 2417; b.value2418 = 2418; b.value2419 = 2419; b.value2420 = 2420; b.value2421 = 2421; b.value2422 = 2422; b.value2423 = 2423; b.value2424 = 2424; b.value2425 = 2425; b.value2426 = 2426; b.value2427 = 2427; b.value2428 = 2428; b.value2429 = 2429; b.value2430 = 2430; b.value2431 = 2431; b.value2432 = 2432; b.value2433 = 2433; b.value2434 = 2434; b.value2435 = 2435; b.value2436 = 2436; b.value2437 = 2437; b.value2438 = 2438; b.value2439 = 2439; b.value2440 = 2440; b.value2441 = 2441; b.value2442 = 2442; b.value2443 = 2443; b.value2444 = 2444; b.value2445 = 2445; b.value2446 = 2446; b.value2447 = 2447; b.value2448 = 2448; b.value2449 = 2449; b.value2450 = 2450; b.value2451 = 2451; b.value2452 = 2452; b.value2453 = 2453; b.value2454 = 2454; b.value2455 = 2455; b.value2456 = 2456; b.value2457 = 2457; b.value2458 = 2458; b.value2459 = 2459; b.value2460 = 2460; b.value2461 = 2461; b.value2462 = 2462; b.value2463 = 2463; b.value2464 = 2464; b.value2465 = 2465; b.value2466 = 2466; b.value2467 = 2467; b.value2468 = 2468; b.value2469 = 2469; b.value2470 = 2470; b.value2471 = 2471; b.value2472 = 2472; b.value2473 = 2473; b.value2474 = 2474; b.value2475 = 2475; b.value2476 = 2476; b.value2477 = 2477; b.value2478 = 2478; b.value2479 = 2479; b.value2480 = 2480; b.value2481 = 2481; b.value2482 = 2482; b.value2483 = 2483; b.value2484 = 2484; b.value2485 = 2485; b.value2486 = 2486; b.value2487 = 2487; b.value2488 = 2488; b.value2489 = 2489; b.value2490 = 2490; b.value2491 = 2491; b.value2492 = 2492; b.value2493 = 2493; b.value2494 = 2494; b.value2495 = 2495; b.value2496 = 2496; b.value2497 = 2497; b.value2498 = 2498; b.value2499 = 2499; b.value2500 = 2500; b.value2501 = 2501; b.value2502 = 2502; b.value2503 = 2503; b.value2504 = 2504; b.value2505 = 2505; b.value2506 = 2506; b.value2507 = 2507; b.value2508 = 2508; b.value2509 = 2509; b.value2510 = 2510; b.value2511 = 2511; b.value2512 = 2512; b.value2513 = 2513; b.value2514 = 2514; b.value2515 = 2515; b.value2516 = 2516; b.value2517 = 2517; b.value2518 = 2518; b.value2519 = 2519; b.value2520 = 2520; b.value2521 = 2521; b.value2522 = 2522; b.value2523 = 2523; b.value2524 = 2524; b.value2525 = 2525; b.value2526 = 2526; b.value2527 = 2527; b.value2528 = 2528; b.value2529 = 2529; b.value2530 = 2530; b.value2531 = 2531; b.value2532 = 2532; b.value2533 = 2533; b.value2534 = 2534; b.value2535 = 2535; b.value2536 = 2536; b.value2537 = 2537; b.value2538 = 2538; b.value2539 = 2539; b.value2540 = 2540; b.value2541 = 2541; b.value2542 = 2542; b.value2543 = 2543; b.value2544 = 2544; b.value2545 = 2545; b.value2546 = 2546; b.value2547 = 2547; b.value2548 = 2548; b.value2549 = 2549; b.value2550 = 2550; b.value2551 = 2551; b.value2552 = 2552; b.value2553 = 2553; b.value2554 = 2554; b.value2555 = 2555; b.value2556 = 2556; b.value2557 = 2557; b.value2558 = 2558; b.value2559 = 2559; b.value2560 = 2560; b.value2561 = 2561; b.value2562 = 2562; b.value2563 = 2563; b.value2564 = 2564; b.value2565 = 2565; b.value2566 = 2566; b.value2567 = 2567; b.value2568 = 2568; b.value2569 = 2569; b.value2570 = 2570; b.value2571 = 2571; b.value2572 = 2572; b.value2573 = 2573; b.value2574 = 2574; b.value2575 = 2575; b.value2576 = 2576; b.value2577 = 2577; b.value2578 = 2578; b.value2579 = 2579; b.value2580 = 2580; b.value2581 = 2581; b.value2582 = 2582; b.value2583 = 2583; b.value2584 = 2584; b.value2585 = 2585; b.value2586 = 2586; b.value2587 = 2587; b.value2588 = 2588; b.value2589 = 2589; b.value2590 = 2590; b.value2591 = 2591; b.value2592 = 2592; b.value2593 = 2593; b.value2594 = 2594; b.value2595 = 2595; b.value2596 = 2596; b.value2597 = 2597; b.value2598 = 2598; b.value2599 = 2599; b.value2600 = 2600; b.value2601 = 2601; b.value2602 = 2602; b.value2603 = 2603; b.value2604 = 2604; b.value2605 = 2605; b.value2606 = 2606; b.value2607 = 2607; b.value2608 = 2608; b.value2609 = 2609; b.value2610 = 2610; b.value2611 = 2611; b.value2612 = 2612; b.value2613 = 2613; b.value2614 = 2614; b.value2615 = 2615; b.value2616 = 2616; b.value2617 = 2617; b.value2618 = 2618; b.value2619 = 2619; b.value2620 = 2620; b.value2621 = 2621; b.value2622 = 2622; b.value2623 = 2623; b.value2624 = 2624; b.value2625 = 2625; b.value2626 = 2626; b.value2627 = 2627; b.value2628 = 2628; b.value2629 = 2629; b.value2630 = 2630; b.value2631 = 2631; b.value2632 = 2632; b.value2633 = 2633; b.value2634 = 2634; b.value2635 = 2635; b.value2636 = 2636; b.value2637 = 2637; b.value2638 = 2638; b.value2639 = 2639; b.value2640 = 2640; b.value2641 = 2641; b.value2642 = 2642; b.value2643 = 2643; b.value2644 = 2644; b.value2645 = 2645; b.value2646 = 2646; b.value2647 = 2647; b.value2648 = 2648; b.value2649 = 2649; b.value2650 = 2650; b.value2651 = 2651; b.value2652 = 2652; b.value2653 = 2653; b.value2654 = 2654; b.value2655 = 2655; b.value2656 = 2656; b.value2657 = 2657; b.value2658 = 2658; b.value2659 = 2659; b.value2660 = 2660; b.value2661 = 2661; b.value2662 = 2662; b.value2663 = 2663; b.value2664 = 2664; b.value2665 = 2665; b.value2666 = 2666; b.value2667 = 2667; b.value2668 = 2668; b.value2669 = 2669; b.value2670 = 2670; b.value2671 = 2671; b.value2672 = 2672; b.value2673 = 2673; b.value2674 = 2674; b.value2675 = 2675; b.value2676 = 2676; b.value2677 = 2677; b.value2678 = 2678; b.value2679 = 2679; b.value2680 = 2680; b.value2681 = 2681; b.value2682 = 2682; b.value2683 = 2683; b.value2684 = 2684; b.value2685 = 2685; b.value2686 = 2686; b.value2687 = 2687; b.value2688 = 2688; b.value2689 = 2689; b.value2690 = 2690; b.value2691 = 2691; b.value2692 = 2692; b.value2693 = 2693; b.value2694 = 2694; b.value2695 = 2695; b.value2696 = 2696; b.value2697 = 2697; b.value2698 = 2698; b.value2699 = 2699; b.value2700 = 2700; b.value2701 = 2701; b.value2702 = 2702; b.value2703 = 2703; b.value2704 = 2704; b.value2705 = 2705; b.value2706 = 2706; b.value2707 = 2707; b.value2708 = 2708; b.value2709 = 2709; b.value2710 = 2710; b.value2711 = 2711; b.value2712 = 2712; b.value2713 = 2713; b.value2714 = 2714; b.value2715 = 2715; b.value2716 = 2716; b.value2717 = 2717; b.value2718 = 2718; b.value2719 = 2719; b.value2720 = 2720; b.value2721 = 2721; b.value2722 = 2722; b.value2723 = 2723; b.value2724 = 2724; b.value2725 = 2725; b.value2726 = 2726; b.value2727 = 2727; b.value2728 = 2728; b.value2729 = 2729; b.value2730 = 2730; b.value2731 = 2731; b.value2732 = 2732; b.value2733 = 2733; b.value2734 = 2734; b.value2735 = 2735; b.value2736 = 2736; b.value2737 = 2737; b.value2738 = 2738; b.value2739 = 2739; b.value2740 = 2740; b.value2741 = 2741; b.value2742 = 2742; b.value2743 = 2743; b.value2744 = 2744; b.value2745 = 2745; b.value2746 = 2746; b.value2747 = 2747; b.value2748 = 2748; b.value2749 = 2749; b.value2750 = 2750; b.value2751 = 2751; b.value2752 = 2752; b.value2753 = 2753; b.value2754 = 2754; b.value2755 = 2755; b.value2756 = 2756; b.value2757 = 2757; b.value2758 = 2758; b.value2759 = 2759; b.value2760 = 2760; b.value2761 = 2761; b.value2762 = 2762; b.value2763 = 2763; b.value2764 = 2764; b.value2765 = 2765; b.value2766 = 2766; b.value2767 = 2767; b.value2768 = 2768; b.value2769 = 2769; b.value2770 = 2770; b.value2771 = 2771; b.value2772 = 2772; b.value2773 = 2773; b.value2774 = 2774; b.value2775 = 2775; b.value2776 = 2776; b.value2777 = 2777; b.value2778 = 2778; b.value2779 = 2779; b.value2780 = 2780; b.value2781 = 2781; b.value2782 = 2782; b.value2783 = 2783; b.value2784 = 2784; b.value2785 = 2785; b.value2786 = 2786; b.value2787 = 2787; b.value2788 = 2788; b.value2789 = 2789; b.value2790 = 2790; b.value2791 = 2791; b.value2792 = 2792; b.value2793 = 2793; b.value2794 = 2794; b.value2795 = 2795; b.value2796 = 2796; b.value2797 = 2797; b.value2798 = 2798; b.value2799 = 2799; b.value2800 = 2800; b.value2801 = 2801; b.value2802 = 2802; b.value2803 = 2803; b.value2804 = 2804; b.value2805 = 2805; b.value2806 = 2806; b.value2807 = 2807; b.value2808 = 2808; b.value2809 = 2809; b.value2810 = 2810; b.value2811 = 2811; b.value2812 = 2812; b.value2813 = 2813; b.value2814 = 2814; b.value2815 = 2815; b.value2816 = 2816; b.value2817 = 2817; b.value2818 = 2818; b.value2819 = 2819; b.value2820 = 2820; b.value2821 = 2821; b.value2822 = 2822; b.value2823 = 2823; b.value2824 = 2824; b.value2825 = 2825; b.value2826 = 2826; b.value2827 = 2827; b.value2828 = 2828; b.value2829 = 2829; b.value2830 = 2830; b.value2831 = 2831; b.value2832 = 2832; b.value2833 = 2833; b.value2834 = 2834; b.value2835 = 2835; b.value2836 = 2836; b.value2837 = 2837; b.value2838 = 2838; b.value2839 = 2839; b.value2840 = 2840; b.value2841 = 2841; b.value2842 = 2842; b.value2843 = 2843; b.value2844 = 2844; b.value2845 = 2845; b.value2846 = 2846; b.value2847 = 2847; b.value2848 = 2848; b.value2849 = 2849; b.value2850 = 2850; b.value2851 = 2851; b.value2852 = 2852; b.value2853 = 2853; b.value2854 = 2854; b.value2855 = 2855; b.value2856 = 2856; b.value2857 = 2857; b.value2858 = 2858; b.value2859 = 2859; b.value2860 = 2860; b.value2861 = 2861; b.value2862 = 2862; b.value2863 = 2863; b.value2864 = 2864; b.value2865 = 2865; b.value2866 = 2866; b.value2867 = 2867; b.value2868 = 2868; b.value2869 = 2869; b.value2870 = 2870; b.value2871 = 2871; b.value2872 = 2872; b.value2873 = 2873; b.value2874 = 2874; b.value2875 = 2875; b.value2876 = 2876; b.value2877 = 2877; b.value2878 = 2878; b.value2879 = 2879; b.value2880 = 2880; b.value2881 = 2881; b.value2882 = 2882; b.value2883 = 2883; b.value2884 = 2884; b.value2885 = 2885; b.value2886 = 2886; b.value2887 = 2887; b.value2888 = 2888; b.value2889 = 2889; b.value2890 = 2890; b.value2891 = 2891; b.value2892 = 2892; b.value2893 = 2893; b.value2894 = 2894; b.value2895 = 2895; b.value2896 = 2896; b.value2897 = 2897; b.value2898 = 2898; b.value2899 = 2899; b.value2900 = 2900; b.value2901 = 2901; b.value2902 = 2902; b.value2903 = 2903; b.value2904 = 2904; b.value2905 = 2905; b.value2906 = 2906; b.value2907 = 2907; b.value2908 = 2908; b.value2909 = 2909; b.value2910 = 2910; b.value2911 = 2911; b.value2912 = 2912; b.value2913 = 2913; b.value2914 = 2914; b.value2915 = 2915; b.value2916 = 2916; b.value2917 = 2917; b.value2918 = 2918; b.value2919 = 2919; b.value2920 = 2920; b.value2921 = 2921; b.value2922 = 2922; b.value2923 = 2923; b.value2924 = 2924; b.value2925 = 2925; b.value2926 = 2926; b.value2927 = 2927; b.value2928 = 2928; b.value2929 = 2929; b.value2930 = 2930; b.value2931 = 2931; b.value2932 = 2932; b.value2933 = 2933; b.value2934 = 2934; b.value2935 = 2935; b.value2936 = 2936; b.value2937 = 2937; b.value2938 = 2938; b.value2939 = 2939; b.value2940 = 2940; b.value2941 = 2941; b.value2942 = 2942; b.value2943 = 2943; b.value2944 = 2944; b.value2945 = 2945; b.value2946 = 2946; b.value2947 = 2947; b.value2948 = 2948; b.value2949 = 2949; b.value2950 = 2950; b.value2951 = 2951; b.value2952 = 2952; b.value2953 = 2953; b.value2954 = 2954; b.value2955 = 2955; b.value2956 = 2956; b.value2957 = 2957; b.value2958 = 2958; b.value2959 = 2959; b.value2960 = 2960; b.value2961 = 2961; b.value2962 = 2962; b.value2963 = 2963; b.value2964 = 2964; b.value2965 = 2965; b.value2966 = 2966; b.value2967 = 2967; b.value2968 = 2968; b.value2969 = 2969; b.value2970 = 2970; b.value2971 = 2971; b.value2972 = 2972; b.value2973 = 2973; b.value2974 = 2974; b.value2975 = 2975; b.value2976 = 2976; b.value2977 = 2977; b.value2978 = 2978; b.value2979 = 2979; b.value2980 = 2980; b.value2981 = 2981; b.value2982 = 2982; b.value2983 = 2983; b.value2984 = 2984; b.value2985 = 2985; b.value2986 = 2986; b.value2987 = 2987; b.value2988 = 2988; b.value2989 = 2989; b.value2990 = 2990; b.value2991 = 2991; b.value2992 = 2992; b.value2993 = 2993; b.value2994 = 2994; b.value2995 = 2995; b.value2996 = 2996; b.value2997 = 2997; b.value2998 = 2998; b.value2999 = 2999; b.value3000 = 3000; b.value3001 = 3001; b.value3002 = 3002; b.value3003 = 3003; b.value3004 = 3004; b.value3005 = 3005; b.value3006 = 3006; b.value3007 = 3007; b.value3008 = 3008; b.value3009 = 3009; b.value3010 = 3010; b.value3011 = 3011; b.value3012 = 3012; b.value3013 = 3013; b.value3014 = 3014; b.value3015 = 3015; b.value3016 = 3016; b.value3017 = 3017; b.value3018 = 3018; b.value3019 = 3019; b.value3020 = 3020; b.value3021 = 3021; b.value3022 = 3022; b.value3023 = 3023; b.value3024 = 3024; b.value3025 = 3025; b.value3026 = 3026; b.value3027 = 3027; b.value3028 = 3028; b.value3029 = 3029; b.value3030 = 3030; b.value3031 = 3031; b.value3032 = 3032; b.value3033 = 3033; b.value3034 = 3034; b.value3035 = 3035; b.value3036 = 3036; b.value3037 = 3037; b.value3038 = 3038; b.value3039 = 3039; b.value3040 = 3040; b.value3041 = 3041; b.value3042 = 3042; b.value3043 = 3043; b.value3044 = 3044; b.value3045 = 3045; b.value3046 = 3046; b.value3047 = 3047; b.value3048 = 3048; b.value3049 = 3049; b.value3050 = 3050; b.value3051 = 3051; b.value3052 = 3052; b.value3053 = 3053; b.value3054 = 3054; b.value3055 = 3055; b.value3056 = 3056; b.value3057 = 3057; b.value3058 = 3058; b.value3059 = 3059; b.value3060 = 3060; b.value3061 = 3061; b.value3062 = 3062; b.value3063 = 3063; b.value3064 = 3064; b.value3065 = 3065; b.value3066 = 3066; b.value3067 = 3067; b.value3068 = 3068; b.value3069 = 3069; b.value3070 = 3070; b.value3071 = 3071; b.value3072 = 3072; b.value3073 = 3073; b.value3074 = 3074; b.value3075 = 3075; b.value3076 = 3076; b.value3077 = 3077; b.value3078 = 3078; b.value3079 = 3079; b.value3080 = 3080; b.value3081 = 3081; b.value3082 = 3082; b.value3083 = 3083; b.value3084 = 3084; b.value3085 = 3085; b.value3086 = 3086; b.value3087 = 3087; b.value3088 = 3088; b.value3089 = 3089; b.value3090 = 3090; b.value3091 = 3091; b.value3092 = 3092; b.value3093 = 3093; b.value3094 = 3094; b.value3095 = 3095; b.value3096 = 3096; b.value3097 = 3097; b.value3098 = 3098; b.value3099 = 3099; b.value3100 = 3100; b.value3101 = 3101; b.value3102 = 3102; b.value3103 = 3103; b.value3104 = 3104; b.value3105 = 3105; b.value3106 = 3106; b.value3107 = 3107; b.value3108 = 3108; b.value3109 = 3109; b.value3110 = 3110; b.value3111 = 3111; b.value3112 = 3112; b.value3113 = 3113; b.value3114 = 3114; b.value3115 = 3115; b.value3116 = 3116; b.value3117 = 3117; b.value3118 = 3118; b.value3119 = 3119; b.value3120 = 3120; b.value3121 = 3121; b.value3122 = 3122; b.value3123 = 3123; b.value3124 = 3124; b.value3125 = 3125; b.value3126 = 3126; b.value3127 = 3127; b.value3128 = 3128; b.value3129 = 3129; b.value3130 = 3130; b.value3131 = 3131; b.value3132 = 3132; b.value3133 = 3133; b.value3134 = 3134; b.value3135 = 3135; b.value3136 = 3136; b.value3137 = 3137; b.value3138 = 3138; b.value3139 = 3139; b.value3140 = 3140; b.value3141 = 3141; b.value3142 = 3142; b.value3143 = 3143; b.value3144 = 3144; b.value3145 = 3145; b.value3146 = 3146; b.value3147 = 3147; b.value3148 = 3148; b.value3149 = 3149; b.value3150 = 3150; b.value3151 = 3151; b.value3152 = 3152; b.value3153 = 3153; b.value3154 = 3154; b.value3155 = 3155; b.value3156 = 3156; b.value3157 = 3157; b.value3158 = 3158; b.value3159 = 3159; b.value3160 = 3160; b.value3161 = 3161; b.value3162 = 3162; b.value3163 = 3163; b.value3164 = 3164; b.value3165 = 3165; b.value3166 = 3166; b.value3167 = 3167; b.value3168 = 3168; b.value3169 = 3169; b.value3170 = 3170; b.value3171 = 3171; b.value3172 = 3172; b.value3173 = 3173; b.value3174 = 3174; b.value3175 = 3175; b.value3176 = 3176; b.value3177 = 3177; b.value3178 = 3178; b.value3179 = 3179; b.value3180 = 3180; b.value3181 = 3181; b.value3182 = 3182; b.value3183 = 3183; b.value3184 = 3184; b.value3185 = 3185; b.value3186 = 3186; b.value3187 = 3187; b.value3188 = 3188; b.value3189 = 3189; b.value3190 = 3190; b.value3191 = 3191; b.value3192 = 3192; b.value3193 = 3193; b.value3194 = 3194; b.value3195 = 3195; b.value3196 = 3196; b.value3197 = 3197; b.value3198 = 3198; b.value3199 = 3199; b.value3200 = 3200; b.value3201 = 3201; b.value3202 = 3202; b.value3203 = 3203; b.value3204 = 3204; b.value3205 = 3205; b.value3206 = 3206; b.value3207 = 3207; b.value3208 = 3208; b.value3209 = 3209; b.value3210 = 3210; b.value3211 = 3211; b.value3212 = 3212; b.value3213 = 3213; b.value3214 = 3214; b.value3215 = 3215; b.value3216 = 3216; b.value3217 = 3217; b.value3218 = 3218; b.value3219 = 3219; b.value3220 = 3220; b.value3221 = 3221; b.value3222 = 3222; b.value3223 = 3223; b.value3224 = 3224; b.value3225 = 3225; b.value3226 = 3226; b.value3227 = 3227; b.value3228 = 3228; b.value3229 = 3229; b.value3230 = 3230; b.value3231 = 3231; b.value3232 = 3232; b.value3233 = 3233; b.value3234 = 3234; b.value3235 = 3235; b.value3236 = 3236; b.value3237 = 3237; b.value3238 = 3238; b.value3239 = 3239; b.value3240 = 3240; b.value3241 = 3241; b.value3242 = 3242; b.value3243 = 3243; b.value3244 = 3244; b.value3245 = 3245; b.value3246 = 3246; b.value3247 = 3247; b.value3248 = 3248; b.value3249 = 3249; b.value3250 = 3250; b.value3251 = 3251; b.value3252 = 3252; b.value3253 = 3253; b.value3254 = 3254; b.value3255 = 3255; b.value3256 = 3256; b.value3257 = 3257; b.value3258 = 3258; b.value3259 = 3259; b.value3260 = 3260; b.value3261 = 3261; b.value3262 = 3262; b.value3263 = 3263; b.value3264 = 3264; b.value3265 = 3265; b.value3266 = 3266; b.value3267 = 3267; b.value3268 = 3268; b.value3269 = 3269; b.value3270 = 3270; b.value3271 = 3271; b.value3272 = 3272; b.value3273 = 3273; b.value3274 = 3274; b.value3275 = 3275; b.value3276 = 3276; b.value3277 = 3277; b.value3278 = 3278; b.value3279 = 3279; b.value3280 = 3280; b.value3281 = 3281; b.value3282 = 3282; b.value3283 = 3283; b.value3284 = 3284; b.value3285 = 3285; b.value3286 = 3286; b.value3287 = 3287; b.value3288 = 3288; b.value3289 = 3289; b.value3290 = 3290; b.value3291 = 3291; b.value3292 = 3292; b.value3293 = 3293; b.value3294 = 3294; b.value3295 = 3295; b.value3296 = 3296; b.value3297 = 3297; b.value3298 = 3298; b.value3299 = 3299; b.value3300 = 3300; b.value3301 = 3301; b.value3302 = 3302; b.value3303 = 3303; b.value3304 = 3304; b.value3305 = 3305; b.value3306 = 3306; b.value3307 = 3307; b.value3308 = 3308; b.value3309 = 3309; b.value3310 = 3310; b.value3311 = 3311; b.value3312 = 3312; b.value3313 = 3313; b.value3314 = 3314; b.value3315 = 3315; b.value3316 = 3316; b.value3317 = 3317; b.value3318 = 3318; b.value3319 = 3319; b.value3320 = 3320; b.value3321 = 3321; b.value3322 = 3322; b.value3323 = 3323; b.value3324 = 3324; b.value3325 = 3325; b.value3326 = 3326; b.value3327 = 3327; b.value3328 = 3328; b.value3329 = 3329; b.value3330 = 3330; b.value3331 = 3331; b.value3332 = 3332; b.value3333 = 3333; b.value3334 = 3334; b.value3335 = 3335; b.value3336 = 3336; b.value3337 = 3337; b.value3338 = 3338; b.value3339 = 3339; b.value3340 = 3340; b.value3341 = 3341; b.value3342 = 3342; b.value3343 = 3343; b.value3344 = 3344; b.value3345 = 3345; b.value3346 = 3346; b.value3347 = 3347; b.value3348 = 3348; b.value3349 = 3349; b.value3350 = 3350; b.value3351 = 3351; b.value3352 = 3352; b.value3353 = 3353; b.value3354 = 3354; b.value3355 = 3355; b.value3356 = 3356; b.value3357 = 3357; b.value3358 = 3358; b.value3359 = 3359; b.value3360 = 3360; b.value3361 = 3361; b.value3362 = 3362; b.value3363 = 3363; b.value3364 = 3364; b.value3365 = 3365; b.value3366 = 3366; b.value3367 = 3367; b.value3368 = 3368; b.value3369 = 3369; b.value3370 = 3370; b.value3371 = 3371; b.value3372 = 3372; b.value3373 = 3373; b.value3374 = 3374; b.value3375 = 3375; b.value3376 = 3376; b.value3377 = 3377; b.value3378 = 3378; b.value3379 = 3379; b.value3380 = 3380; b.value3381 = 3381; b.value3382 = 3382; b.value3383 = 3383; b.value3384 = 3384; b.value3385 = 3385; b.value3386 = 3386; b.value3387 = 3387; b.value3388 = 3388; b.value3389 = 3389; b.value3390 = 3390; b.value3391 = 3391; b.value3392 = 3392; b.value3393 = 3393; b.value3394 = 3394; b.value3395 = 3395; b.value3396 = 3396; b.value3397 = 3397; b.value3398 = 3398; b.value3399 = 3399; b.value3400 = 3400; b.value3401 = 3401; b.value3402 = 3402; b.value3403 = 3403; b.value3404 = 3404; b.value3405 = 3405; b.value3406 = 3406; b.value3407 = 3407; b.value3408 = 3408; b.value3409 = 3409; b.value3410 = 3410; b.value3411 = 3411; b.value3412 = 3412; b.value3413 = 3413; b.value3414 = 3414; b.value3415 = 3415; b.value3416 = 3416; b.value3417 = 3417; b.value3418 = 3418; b.value3419 = 3419; b.value3420 = 3420; b.value3421 = 3421; b.value3422 = 3422; b.value3423 = 3423; b.value3424 = 3424; b.value3425 = 3425; b.value3426 = 3426; b.value3427 = 3427; b.value3428 = 3428; b.value3429 = 3429; b.value3430 = 3430; b.value3431 = 3431; b.value3432 = 3432; b.value3433 = 3433; b.value3434 = 3434; b.value3435 = 3435; b.value3436 = 3436; b.value3437 = 3437; b.value3438 = 3438; b.value3439 = 3439; b.value3440 = 3440; b.value3441 = 3441; b.value3442 = 3442; b.value3443 = 3443; b.value3444 = 3444; b.value3445 = 3445; b.value3446 = 3446; b.value3447 = 3447; b.value3448 = 3448; b.value3449 = 3449; b.value3450 = 3450; b.value3451 = 3451; b.value3452 = 3452; b.value3453 = 3453; b.value3454 = 3454; b.value3455 = 3455; b.value3456 = 3456; b.value3457 = 3457; b.value3458 = 3458; b.value3459 = 3459; b.value3460 = 3460; b.value3461 = 3461; b.value3462 = 3462; b.value3463 = 3463; b.value3464 = 3464; b.value3465 = 3465; b.value3466 = 3466; b.value3467 = 3467; b.value3468 = 3468; b.value3469 = 3469; b.value3470 = 3470; b.value3471 = 3471; b.value3472 = 3472; b.value3473 = 3473; b.value3474 = 3474; b.value3475 = 3475; b.value3476 = 3476; b.value3477 = 3477; b.value3478 = 3478; b.value3479 = 3479; b.value3480 = 3480; b.value3481 = 3481; b.value3482 = 3482; b.value3483 = 3483; b.value3484 = 3484; b.value3485 = 3485; b.value3486 = 3486; b.value3487 = 3487; b.value3488 = 3488; b.value3489 = 3489; b.value3490 = 3490; b.value3491 = 3491; b.value3492 = 3492; b.value3493 = 3493; b.value3494 = 3494; b.value3495 = 3495; b.value3496 = 3496; b.value3497 = 3497; b.value3498 = 3498; b.value3499 = 3499; b.value3500 = 3500; b.value3501 = 3501; b.value3502 = 3502; b.value3503 = 3503; b.value3504 = 3504; b.value3505 = 3505; b.value3506 = 3506; b.value3507 = 3507; b.value3508 = 3508; b.value3509 = 3509; b.value3510 = 3510; b.value3511 = 3511; b.value3512 = 3512; b.value3513 = 3513; b.value3514 = 3514; b.value3515 = 3515; b.value3516 = 3516; b.value3517 = 3517; b.value3518 = 3518; b.value3519 = 3519; b.value3520 = 3520; b.value3521 = 3521; b.value3522 = 3522; b.value3523 = 3523; b.value3524 = 3524; b.value3525 = 3525; b.value3526 = 3526; b.value3527 = 3527; b.value3528 = 3528; b.value3529 = 3529; b.value3530 = 3530; b.value3531 = 3531; b.value3532 = 3532; b.value3533 = 3533; b.value3534 = 3534; b.value3535 = 3535; b.value3536 = 3536; b.value3537 = 3537; b.value3538 = 3538; b.value3539 = 3539; b.value3540 = 3540; b.value3541 = 3541; b.value3542 = 3542; b.value3543 = 3543; b.value3544 = 3544; b.value3545 = 3545; b.value3546 = 3546; b.value3547 = 3547; b.value3548 = 3548; b.value3549 = 3549; b.value3550 = 3550; b.value3551 = 3551; b.value3552 = 3552; b.value3553 = 3553; b.value3554 = 3554; b.value3555 = 3555; b.value3556 = 3556; b.value3557 = 3557; b.value3558 = 3558; b.value3559 = 3559; b.value3560 = 3560; b.value3561 = 3561; b.value3562 = 3562; b.value3563 = 3563; b.value3564 = 3564; b.value3565 = 3565; b.value3566 = 3566; b.value3567 = 3567; b.value3568 = 3568; b.value3569 = 3569; b.value3570 = 3570; b.value3571 = 3571; b.value3572 = 3572; b.value3573 = 3573; b.value3574 = 3574; b.value3575 = 3575; b.value3576 = 3576; b.value3577 = 3577; b.value3578 = 3578; b.value3579 = 3579; b.value3580 = 3580; b.value3581 = 3581; b.value3582 = 3582; b.value3583 = 3583; b.value3584 = 3584; b.value3585 = 3585; b.value3586 = 3586; b.value3587 = 3587; b.value3588 = 3588; b.value3589 = 3589; b.value3590 = 3590; b.value3591 = 3591; b.value3592 = 3592; b.value3593 = 3593; b.value3594 = 3594; b.value3595 = 3595; b.value3596 = 3596; b.value3597 = 3597; b.value3598 = 3598; b.value3599 = 3599; b.value3600 = 3600; b.value3601 = 3601; b.value3602 = 3602; b.value3603 = 3603; b.value3604 = 3604; b.value3605 = 3605; b.value3606 = 3606; b.value3607 = 3607; b.value3608 = 3608; b.value3609 = 3609; b.value3610 = 3610; b.value3611 = 3611; b.value3612 = 3612; b.value3613 = 3613; b.value3614 = 3614; b.value3615 = 3615; b.value3616 = 3616; b.value3617 = 3617; b.value3618 = 3618; b.value3619 = 3619; b.value3620 = 3620; b.value3621 = 3621; b.value3622 = 3622; b.value3623 = 3623; b.value3624 = 3624; b.value3625 = 3625; b.value3626 = 3626; b.value3627 = 3627; b.value3628 = 3628; b.value3629 = 3629; b.value3630 = 3630; b.value3631 = 3631; b.value3632 = 3632; b.value3633 = 3633; b.value3634 = 3634; b.value3635 = 3635; b.value3636 = 3636; b.value3637 = 3637; b.value3638 = 3638; b.value3639 = 3639; b.value3640 = 3640; b.value3641 = 3641; b.value3642 = 3642; b.value3643 = 3643; b.value3644 = 3644; b.value3645 = 3645; b.value3646 = 3646; b.value3647 = 3647; b.value3648 = 3648; b.value3649 = 3649; b.value3650 = 3650; b.value3651 = 3651; b.value3652 = 3652; b.value3653 = 3653; b.value3654 = 3654; b.value3655 = 3655; b.value3656 = 3656; b.value3657 = 3657; b.value3658 = 3658; b.value3659 = 3659; b.value3660 = 3660; b.value3661 = 3661; b.value3662 = 3662; b.value3663 = 3663; b.value3664 = 3664; b.value3665 = 3665; b.value3666 = 3666; b.value3667 = 3667; b.value3668 = 3668; b.value3669 = 3669; b.value3670 = 3670; b.value3671 = 3671; b.value3672 = 3672; b.value3673 = 3673; b.value3674 = 3674; b.value3675 = 3675; b.value3676 = 3676; b.value3677 = 3677; b.value3678 = 3678; b.value3679 = 3679; b.value3680 = 3680; b.value3681 = 3681; b.value3682 = 3682; b.value3683 = 3683; b.value3684 = 3684; b.value3685 = 3685; b.value3686 = 3686; b.value3687 = 3687; b.value3688 = 3688; b.value3689 = 3689; b.value3690 = 3690; b.value3691 = 3691; b.value3692 = 3692; b.value3693 = 3693; b.value3694 = 3694; b.value3695 = 3695; b.value3696 = 3696; b.value3697 = 3697; b.value3698 = 3698; b.value3699 = 3699; b.value3700 = 3700; b.value3701 = 3701; b.value3702 = 3702; b.value3703 = 3703; b.value3704 = 3704; b.value3705 = 3705; b.value3706 = 3706; b.value3707 = 3707; b.value3708 = 3708; b.value3709 = 3709; b.value3710 = 3710; b.value3711 = 3711; b.value3712 = 3712; b.value3713 = 3713; b.value3714 = 3714; b.value3715 = 3715; b.value3716 = 3716; b.value3717 = 3717; b.value3718 = 3718; b.value3719 = 3719; b.value3720 = 3720; b.value3721 = 3721; b.value3722 = 3722; b.value3723 = 3723; b.value3724 = 3724; b.value3725 = 3725; b.value3726 = 3726; b.value3727 = 3727; b.value3728 = 3728; b.value3729 = 3729; b.value3730 = 3730; b.value3731 = 3731; b.value3732 = 3732; b.value3733 = 3733; b.value3734 = 3734; b.value3735 = 3735; b.value3736 = 3736; b.value3737 = 3737; b.value3738 = 3738; b.value3739 = 3739; b.value3740 = 3740; b.value3741 = 3741; b.value3742 = 3742; b.value3743 = 3743; b.value3744 = 3744; b.value3745 = 3745; b.value3746 = 3746; b.value3747 = 3747; b.value3748 = 3748; b.value3749 = 3749; b.value3750 = 3750; b.value3751 = 3751; b.value3752 = 3752; b.value3753 = 3753; b.value3754 = 3754; b.value3755 = 3755; b.value3756 = 3756; b.value3757 = 3757; b.value3758 = 3758; b.value3759 = 3759; b.value3760 = 3760; b.value3761 = 3761; b.value3762 = 3762; b.value3763 = 3763; b.value3764 = 3764; b.value3765 = 3765; b.value3766 = 3766; b.value3767 = 3767; b.value3768 = 3768; b.value3769 = 3769; b.value3770 = 3770; b.value3771 = 3771; b.value3772 = 3772; b.value3773 = 3773; b.value3774 = 3774; b.value3775 = 3775; b.value3776 = 3776; b.value3777 = 3777; b.value3778 = 3778; b.value3779 = 3779; b.value3780 = 3780; b.value3781 = 3781; b.value3782 = 3782; b.value3783 = 3783; b.value3784 = 3784; b.value3785 = 3785; b.value3786 = 3786; b.value3787 = 3787; b.value3788 = 3788; b.value3789 = 3789; b.value3790 = 3790; b.value3791 = 3791; b.value3792 = 3792; b.value3793 = 3793; b.value3794 = 3794; b.value3795 = 3795; b.value3796 = 3796; b.value3797 = 3797; b.value3798 = 3798; b.value3799 = 3799; b.value3800 = 3800; b.value3801 = 3801; b.value3802 = 3802; b.value3803 = 3803; b.value3804 = 3804; b.value3805 = 3805; b.value3806 = 3806; b.value3807 = 3807; b.value3808 = 3808; b.value3809 = 3809; b.value3810 = 3810; b.value3811 = 3811; b.value3812 = 3812; b.value3813 = 3813; b.value3814 = 3814; b.value3815 = 3815; b.value3816 = 3816; b.value3817 = 3817; b.value3818 = 3818; b.value3819 = 3819; b.value3820 = 3820; b.value3821 = 3821; b.value3822 = 3822; b.value3823 = 3823; b.value3824 = 3824; b.value3825 = 3825; b.value3826 = 3826; b.value3827 = 3827; b.value3828 = 3828; b.value3829 = 3829; b.value3830 = 3830; b.value3831 = 3831; b.value3832 = 3832; b.value3833 = 3833; b.value3834 = 3834; b.value3835 = 3835; b.value3836 = 3836; b.value3837 = 3837; b.value3838 = 3838; b.value3839 = 3839; b.value3840 = 3840; b.value3841 = 3841; b.value3842 = 3842; b.value3843 = 3843; b.value3844 = 3844; b.value3845 = 3845; b.value3846 = 3846; b.value3847 = 3847; b.value3848 = 3848; b.value3849 = 3849; b.value3850 = 3850; b.value3851 = 3851; b.value3852 = 3852; b.value3853 = 3853; b.value3854 = 3854; b.value3855 = 3855; b.value3856 = 3856; b.value3857 = 3857; b.value3858 = 3858; b.value3859 = 3859; b.value3860 = 3860; b.value3861 = 3861; b.value3862 = 3862; b.value3863 = 3863; b.value3864 = 3864; b.value3865 = 3865; b.value3866 = 3866; b.value3867 = 3867; b.value3868 = 3868; b.value3869 = 3869; b.value3870 = 3870; b.value3871 = 3871; b.value3872 = 3872; b.value3873 = 3873; b.value3874 = 3874; b.value3875 = 3875; b.value3876 = 3876; b.value3877 = 3877; b.value3878 = 3878; b.value3879 = 3879; b.value3880 = 3880; b.value3881 = 3881; b.value3882 = 3882; b.value3883 = 3883; b.value3884 = 3884; b.value3885 = 3885; b.value3886 = 3886; b.value3887 = 3887; b.value3888 = 3888; b.value3889 = 3889; b.value3890 = 3890; b.value3891 = 3891; b.value3892 = 3892; b.value3893 = 3893; b.value3894 = 3894; b.value3895 = 3895; b.value3896 = 3896; b.value3897 = 3897; b.value3898 = 3898; b.value3899 = 3899; b.value3900 = 3900; b.value3901 = 3901; b.value3902 = 3902; b.value3903 = 3903; b.value3904 = 3904; b.value3905 = 3905; b.value3906 = 3906; b.value3907 = 3907; b.value3908 = 3908; b.value3909 = 3909; b.value3910 = 3910; b.value3911 = 3911; b.value3912 = 3912; b.value3913 = 3913; b.value3914 = 3914; b.value3915 = 3915; b.value3916 = 3916; b.value3917 = 3917; b.value3918 = 3918; b.value3919 = 3919; b.value3920 = 3920; b.value3921 = 3921; b.value3922 = 3922; b.value3923 = 3923; b.value3924 = 3924; b.value3925 = 3925; b.value3926 = 3926; b.value3927 = 3927; b.value3928 = 3928; b.value3929 = 3929; b.value3930 = 3930; b.value3931 = 3931; b.value3932 = 3932; b.value3933 = 3933; b.value3934 = 3934; b.value3935 = 3935; b.value3936 = 3936; b.value3937 = 3937; b.value3938 = 3938; b.value3939 = 3939; b.value3940 = 3940; b.value3941 = 3941; b.value3942 = 3942; b.value3943 = 3943; b.value3944 = 3944; b.value3945 = 3945; b.value3946 = 3946; b.value3947 = 3947; b.value3948 = 3948; b.value3949 = 3949; b.value3950 = 3950; b.value3951 = 3951; b.value3952 = 3952; b.value3953 = 3953; b.value3954 = 3954; b.value3955 = 3955; b.value3956 = 3956; b.value3957 = 3957; b.value3958 = 3958; b.value3959 = 3959; b.value3960 = 3960; b.value3961 = 3961; b.value3962 = 3962; b.value3963 = 3963; b.value3964 = 3964; b.value3965 = 3965; b.value3966 = 3966; b.value3967 = 3967; b.value3968 = 3968; b.value3969 = 3969; b.value3970 = 3970; b.value3971 = 3971; b.value3972 = 3972; b.value3973 = 3973; b.value3974 = 3974; b.value3975 = 3975; b.value3976 = 3976; b.value3977 = 3977; b.value3978 = 3978; b.value3979 = 3979; b.value3980 = 3980; b.value3981 = 3981; b.value3982 = 3982; b.value3983 = 3983; b.value3984 = 3984; b.value3985 = 3985; b.value3986 = 3986; b.value3987 = 3987; b.value3988 = 3988; b.value3989 = 3989; b.value3990 = 3990; b.value3991 = 3991; b.value3992 = 3992; b.value3993 = 3993; b.value3994 = 3994; b.value3995 = 3995; b.value3996 = 3996; b.value3997 = 3997; b.value3998 = 3998; b.value3999 = 3999; b.value4000 = 4000; b.value4001 = 4001; b.value4002 = 4002; b.value4003 = 4003; b.value4004 = 4004; b.value4005 = 4005; b.value4006 = 4006; b.value4007 = 4007; b.value4008 = 4008; b.value4009 = 4009; b.value4010 = 4010; b.value4011 = 4011; b.value4012 = 4012; b.value4013 = 4013; b.value4014 = 4014; b.value4015 = 4015; b.value4016 = 4016; b.value4017 = 4017; b.value4018 = 4018; b.value4019 = 4019; b.value4020 = 4020; b.value4021 = 4021; b.value4022 = 4022; b.value4023 = 4023; b.value4024 = 4024; b.value4025 = 4025; b.value4026 = 4026; b.value4027 = 4027; b.value4028 = 4028; b.value4029 = 4029; b.value4030 = 4030; b.value4031 = 4031; b.value4032 = 4032; b.value4033 = 4033; b.value4034 = 4034; b.value4035 = 4035; b.value4036 = 4036; b.value4037 = 4037; b.value4038 = 4038; b.value4039 = 4039; b.value4040 = 4040; b.value4041 = 4041; b.value4042 = 4042; b.value4043 = 4043; b.value4044 = 4044; b.value4045 = 4045; b.value4046 = 4046; b.value4047 = 4047; b.value4048 = 4048; b.value4049 = 4049; b.value4050 = 4050; b.value4051 = 4051; b.value4052 = 4052; b.value4053 = 4053; b.value4054 = 4054; b.value4055 = 4055; b.value4056 = 4056; b.value4057 = 4057; b.value4058 = 4058; b.value4059 = 4059; b.value4060 = 4060; b.value4061 = 4061; b.value4062 = 4062; b.value4063 = 4063; b.value4064 = 4064; b.value4065 = 4065; b.value4066 = 4066; b.value4067 = 4067; b.value4068 = 4068; b.value4069 = 4069; b.value4070 = 4070; b.value4071 = 4071; b.value4072 = 4072; b.value4073 = 4073; b.value4074 = 4074; b.value4075 = 4075; b.value4076 = 4076; b.value4077 = 4077; b.value4078 = 4078; b.value4079 = 4079; b.value4080 = 4080; b.value4081 = 4081; b.value4082 = 4082; b.value4083 = 4083; b.value4084 = 4084; b.value4085 = 4085; b.value4086 = 4086; b.value4087 = 4087; b.value4088 = 4088; b.value4089 = 4089; b.value4090 = 4090; b.value4091 = 4091; b.value4092 = 4092; b.value4093 = 4093; b.value4094 = 4094; b.value4095 = 4095; b.value4096 = 4096; b.value4097 = 4097; b.value4098 = 4098; b.value4099 = 4099; b.value4100 = 4100; b.value4101 = 4101; b.value4102 = 4102; b.value4103 = 4103; b.value4104 = 4104; b.value4105 = 4105; b.value4106 = 4106; b.value4107 = 4107; b.value4108 = 4108; b.value4109 = 4109; b.value4110 = 4110; b.value4111 = 4111; b.value4112 = 4112; b.value4113 = 4113; b.value4114 = 4114; b.value4115 = 4115; b.value4116 = 4116; b.value4117 = 4117; b.value4118 = 4118; b.value4119 = 4119; b.value4120 = 4120; b.value4121 = 4121; b.value4122 = 4122; b.value4123 = 4123; b.value4124 = 4124; b.value4125 = 4125; b.value4126 = 4126; b.value4127 = 4127; b.value4128 = 4128; b.value4129 = 4129; b.value4130 = 4130; b.value4131 = 4131; b.value4132 = 4132; b.value4133 = 4133; b.value4134 = 4134; b.value4135 = 4135; b.value4136 = 4136; b.value4137 = 4137; b.value4138 = 4138; b.value4139 = 4139; b.value4140 = 4140; b.value4141 = 4141; b.value4142 = 4142; b.value4143 = 4143; b.value4144 = 4144; b.value4145 = 4145; b.value4146 = 4146; b.value4147 = 4147; b.value4148 = 4148; b.value4149 = 4149; b.value4150 = 4150; b.value4151 = 4151; b.value4152 = 4152; b.value4153 = 4153; b.value4154 = 4154; b.value4155 = 4155; b.value4156 = 4156; b.value4157 = 4157; b.value4158 = 4158; b.value4159 = 4159; b.value4160 = 4160; b.value4161 = 4161; b.value4162 = 4162; b.value4163 = 4163; b.value4164 = 4164; b.value4165 = 4165; b.value4166 = 4166; b.value4167 = 4167; b.value4168 = 4168; b.value4169 = 4169; b.value4170 = 4170; b.value4171 = 4171; b.value4172 = 4172; b.value4173 = 4173; b.value4174 = 4174; b.value4175 = 4175; b.value4176 = 4176; b.value4177 = 4177; b.value4178 = 4178; b.value4179 = 4179; b.value4180 = 4180; b.value4181 = 4181; b.value4182 = 4182; b.value4183 = 4183; b.value4184 = 4184; b.value4185 = 4185; b.value4186 = 4186; b.value4187 = 4187; b.value4188 = 4188; b.value4189 = 4189; b.value4190 = 4190; b.value4191 = 4191; b.value4192 = 4192; b.value4193 = 4193; b.value4194 = 4194; b.value4195 = 4195; b.value4196 = 4196; b.value4197 = 4197; b.value4198 = 4198; b.value4199 = 4199; b.value4200 = 4200; b.value4201 = 4201; b.value4202 = 4202; b.value4203 = 4203; b.value4204 = 4204; b.value4205 = 4205; b.value4206 = 4206; b.value4207 = 4207; b.value4208 = 4208; b.value4209 = 4209; b.value4210 = 4210; b.value4211 = 4211; b.value4212 = 4212; b.value4213 = 4213; b.value4214 = 4214; b.value4215 = 4215; b.value4216 = 4216; b.value4217 = 4217; b.value4218 = 4218; b.value4219 = 4219; b.value4220 = 4220; b.value4221 = 4221; b.value4222 = 4222; b.value4223 = 4223; b.value4224 = 4224; b.value4225 = 4225; b.value4226 = 4226; b.value4227 = 4227; b.value4228 = 4228; b.value4229 = 4229; b.value4230 = 4230; b.value4231 = 4231; b.value4232 = 4232; b.value4233 = 4233; b.value4234 = 4234; b.value4235 = 4235; b.value4236 = 4236; b.value4237 = 4237; b.value4238 = 4238; b.value4239 = 4239; b.value4240 = 4240; b.value4241 = 4241; b.value4242 = 4242; b.value4243 = 4243; b.value4244 = 4244; b.value4245 = 4245; b.value4246 = 4246; b.value4247 = 4247; b.value4248 = 4248; b.value4249 = 4249; b.value4250 = 4250; b.value4251 = 4251; b.value4252 = 4252; b.value4253 = 4253; b.value4254 = 4254; b.value4255 = 4255; b.value4256 = 4256; b.value4257 = 4257; b.value4258 = 4258; b.value4259 = 4259; b.value4260 = 4260; b.value4261 = 4261; b.value4262 = 4262; b.value4263 = 4263; b.value4264 = 4264; b.value4265 = 4265; b.value4266 = 4266; b.value4267 = 4267; b.value4268 = 4268; b.value4269 = 4269; b.value4270 = 4270; b.value4271 = 4271; b.value4272 = 4272; b.value4273 = 4273; b.value4274 = 4274; b.value4275 = 4275; b.value4276 = 4276; b.value4277 = 4277; b.value4278 = 4278; b.value4279 = 4279; b.value4280 = 4280; b.value4281 = 4281; b.value4282 = 4282; b.value4283 = 4283; b.value4284 = 4284; b.value4285 = 4285; b.value4286 = 4286; b.value4287 = 4287; b.value4288 = 4288; b.value4289 = 4289; b.value4290 = 4290; b.value4291 = 4291; b.value4292 = 4292; b.value4293 = 4293; b.value4294 = 4294; b.value4295 = 4295; b.value4296 = 4296; b.value4297 = 4297; b.value4298 = 4298; b.value4299 = 4299; b.value4300 = 4300; b.value4301 = 4301; b.value4302 = 4302; b.value4303 = 4303; b.value4304 = 4304; b.value4305 = 4305; b.value4306 = 4306; b.value4307 = 4307; b.value4308 = 4308; b.value4309 = 4309; b.value4310 = 4310; b.value4311 = 4311; b.value4312 = 4312; b.value4313 = 4313; b.value4314 = 4314; b.value4315 = 4315; b.value4316 = 4316; b.value4317 = 4317; b.value4318 = 4318; b.value4319 = 4319; b.value4320 = 4320; b.value4321 = 4321; b.value4322 = 4322; b.value4323 = 4323; b.value4324 = 4324; b.value4325 = 4325; b.value4326 = 4326; b.value4327 = 4327; b.value4328 = 4328; b.value4329 = 4329; b.value4330 = 4330; b.value4331 = 4331; b.value4332 = 4332; b.value4333 = 4333; b.value4334 = 4334; b.value4335 = 4335; b.value4336 = 4336; b.value4337 = 4337; b.value4338 = 4338; b.value4339 = 4339; b.value4340 = 4340; b.value4341 = 4341; b.value4342 = 4342; b.value4343 = 4343; b.value4344 = 4344; b.value4345 = 4345; b.value4346 = 4346; b.value4347 = 4347; b.value4348 = 4348; b.value4349 = 4349; b.value4350 = 4350; b.value4351 = 4351; b.value4352 = 4352; b.value4353 = 4353; b.value4354 = 4354; b.value4355 = 4355; b.value4356 = 4356; b.value4357 = 4357; b.value4358 = 4358; b.value4359 = 4359; b.value4360 = 4360; b.value4361 = 4361; b.value4362 = 4362; b.value4363 = 4363; b.value4364 = 4364; b.value4365 = 4365; b.value4366 = 4366; b.value4367 = 4367; b.value4368 = 4368; b.value4369 = 4369; b.value4370 = 4370; b.value4371 = 4371; b.value4372 = 4372; b.value4373 = 4373; b.value4374 = 4374; b.value4375 = 4375; b.value4376 = 4376; b.value4377 = 4377; b.value4378 = 4378; b.value4379 = 4379; b.value4380 = 4380; b.value4381 = 4381; b.value4382 = 4382; b.value4383 = 4383; b.value4384 = 4384; b.value4385 = 4385; b.value4386 = 4386; b.value4387 = 4387; b.value4388 = 4388; b.value4389 = 4389; b.value4390 = 4390; b.value4391 = 4391; b.value4392 = 4392; b.value4393 = 4393; b.value4394 = 4394; b.value4395 = 4395; b.value4396 = 4396; b.value4397 = 4397; b.value4398 = 4398; b.value4399 = 4399; b.value4400 = 4400; b.value4401 = 4401; b.value4402 = 4402; b.value4403 = 4403; b.value4404 = 4404; b.value4405 = 4405; b.value4406 = 4406; b.value4407 = 4407; b.value4408 = 4408; b.value4409 = 4409; b.value4410 = 4410; b.value4411 = 4411; b.value4412 = 4412; b.value4413 = 4413; b.value4414 = 4414; b.value4415 = 4415; b.value4416 = 4416; b.value4417 = 4417; b.value4418 = 4418; b.value4419 = 4419; b.value4420 = 4420; b.value4421 = 4421; b.value4422 = 4422; b.value4423 = 4423; b.value4424 = 4424; b.value4425 = 4425; b.value4426 = 4426; b.value4427 = 4427; b.value4428 = 4428; b.value4429 = 4429; b.value4430 = 4430; b.value4431 = 4431; b.value4432 = 4432; b.value4433 = 4433; b.value4434 = 4434; b.value4435 = 4435; b.value4436 = 4436; b.value4437 = 4437; b.value4438 = 4438; b.value4439 = 4439; b.value4440 = 4440; b.value4441 = 4441; b.value4442 = 4442; b.value4443 = 4443; b.value4444 = 4444; b.value4445 = 4445; b.value4446 = 4446; b.value4447 = 4447; b.value4448 = 4448; b.value4449 = 4449; b.value4450 = 4450; b.value4451 = 4451; b.value4452 = 4452; b.value4453 = 4453; b.value4454 = 4454; b.value4455 = 4455; b.value4456 = 4456; b.value4457 = 4457; b.value4458 = 4458; b.value4459 = 4459; b.value4460 = 4460; b.value4461 = 4461; b.value4462 = 4462; b.value4463 = 4463; b.value4464 = 4464; b.value4465 = 4465; b.value4466 = 4466; b.value4467 = 4467; b.value4468 = 4468; b.value4469 = 4469; b.value4470 = 4470; b.value4471 = 4471; b.value4472 = 4472; b.value4473 = 4473; b.value4474 = 4474; b.value4475 = 4475; b.value4476 = 4476; b.value4477 = 4477; b.value4478 = 4478; b.value4479 = 4479; b.value4480 = 4480; b.value4481 = 4481; b.value4482 = 4482; b.value4483 = 4483; b.value4484 = 4484; b.value4485 = 4485; b.value4486 = 4486; b.value4487 = 4487; b.value4488 = 4488; b.value4489 = 4489; b.value4490 = 4490; b.value4491 = 4491; b.value4492 = 4492; b.value4493 = 4493; b.value4494 = 4494; b.value4495 = 4495; b.value4496 = 4496; b.value4497 = 4497; b.value4498 = 4498; b.value4499 = 4499; b.value4500 = 4500; b.value4501 = 4501; b.value4502 = 4502; b.value4503 = 4503; b.value4504 = 4504; b.value4505 = 4505; b.value4506 = 4506; b.value4507 = 4507; b.value4508 = 4508; b.value4509 = 4509; b.value4510 = 4510; b.value4511 = 4511; b.value4512 = 4512; b.value4513 = 4513; b.value4514 = 4514; b.value4515 = 4515; b.value4516 = 4516; b.value4517 = 4517; b.value4518 = 4518; b.value4519 = 4519; b.value4520 = 4520; b.value4521 = 4521; b.value4522 = 4522; b.value4523 = 4523; b.value4524 = 4524; b.value4525 = 4525; b.value4526 = 4526; b.value4527 = 4527; b.value4528 = 4528; b.value4529 = 4529; b.value4530 = 4530; b.value4531 = 4531; b.value4532 = 4532; b.value4533 = 4533; b.value4534 = 4534; b.value4535 = 4535; b.value4536 = 4536; b.value4537 = 4537; b.value4538 = 4538; b.value4539 = 4539; b.value4540 = 4540; b.value4541 = 4541; b.value4542 = 4542; b.value4543 = 4543; b.value4544 = 4544; b.value4545 = 4545; b.value4546 = 4546; b.value4547 = 4547; b.value4548 = 4548; b.value4549 = 4549; b.value4550 = 4550; b.value4551 = 4551; b.value4552 = 4552; b.value4553 = 4553; b.value4554 = 4554; b.value4555 = 4555; b.value4556 = 4556; b.value4557 = 4557; b.value4558 = 4558; b.value4559 = 4559; b.value4560 = 4560; b.value4561 = 4561; b.value4562 = 4562; b.value4563 = 4563; b.value4564 = 4564; b.value4565 = 4565; b.value4566 = 4566; b.value4567 = 4567; b.value4568 = 4568; b.value4569 = 4569; b.value4570 = 4570; b.value4571 = 4571; b.value4572 = 4572; b.value4573 = 4573; b.value4574 = 4574; b.value4575 = 4575; b.value4576 = 4576; b.value4577 = 4577; b.value4578 = 4578; b.value4579 = 4579; b.value4580 = 4580; b.value4581 = 4581; b.value4582 = 4582; b.value4583 = 4583; b.value4584 = 4584; b.value4585 = 4585; b.value4586 = 4586; b.value4587 = 4587; b.value4588 = 4588; b.value4589 = 4589; b.value4590 = 4590; b.value4591 = 4591; b.value4592 = 4592; b.value4593 = 4593; b.value4594 = 4594; b.value4595 = 4595; b.value4596 = 4596; b.value4597 = 4597; b.value4598 = 4598; b.value4599 = 4599; b.value4600 = 4600; b.value4601 = 4601; b.value4602 = 4602; b.value4603 = 4603; b.value4604 = 4604; b.value4605 = 4605; b.value4606 = 4606; b.value4607 = 4607; b.value4608 = 4608; b.value4609 = 4609; b.value4610 = 4610; b.value4611 = 4611; b.value4612 = 4612; b.value4613 = 4613; b.value4614 = 4614; b.value4615 = 4615; b.value4616 = 4616; b.value4617 = 4617; b.value4618 = 4618; b.value4619 = 4619; b.value4620 = 4620; b.value4621 = 4621; b.value4622 = 4622; b.value4623 = 4623; b.value4624 = 4624; b.value4625 = 4625; b.value4626 = 4626; b.value4627 = 4627; b.value4628 = 4628; b.value4629 = 4629; b.value4630 = 4630; b.value4631 = 4631; b.value4632 = 4632; b.value4633 = 4633; b.value4634 = 4634; b.value4635 = 4635; b.value4636 = 4636; b.value4637 = 4637; b.value4638 = 4638; b.value4639 = 4639; b.value4640 = 4640; b.value4641 = 4641; b.value4642 = 4642; b.value4643 = 4643; b.value4644 = 4644; b.value4645 = 4645; b.value4646 = 4646; b.value4647 = 4647; b.value4648 = 4648; b.value4649 = 4649; b.value4650 = 4650; b.value4651 = 4651; b.value4652 = 4652; b.value4653 = 4653; b.value4654 = 4654; b.value4655 = 4655; b.value4656 = 4656; b.value4657 = 4657; b.value4658 = 4658; b.value4659 = 4659; b.value4660 = 4660; b.value4661 = 4661; b.value4662 = 4662; b.value4663 = 4663; b.value4664 = 4664; b.value4665 = 4665; b.value4666 = 4666; b.value4667 = 4667; b.value4668 = 4668; b.value4669 = 4669; b.value4670 = 4670; b.value4671 = 4671; b.value4672 = 4672; b.value4673 = 4673; b.value4674 = 4674; b.value4675 = 4675; b.value4676 = 4676; b.value4677 = 4677; b.value4678 = 4678; b.value4679 = 4679; b.value4680 = 4680; b.value4681 = 4681; b.value4682 = 4682; b.value4683 = 4683; b.value4684 = 4684; b.value4685 = 4685; b.value4686 = 4686; b.value4687 = 4687; b.value4688 = 4688; b.value4689 = 4689; b.value4690 = 4690; b.value4691 = 4691; b.value4692 = 4692; b.value4693 = 4693; b.value4694 = 4694; b.value4695 = 4695; b.value4696 = 4696; b.value4697 = 4697; b.value4698 = 4698; b.value4699 = 4699; b.value4700 = 4700; b.value4701 = 4701; b.value4702 = 4702; b.value4703 = 4703; b.value4704 = 4704; b.value4705 = 4705; b.value4706 = 4706; b.value4707 = 4707; b.value4708 = 4708; b.value4709 = 4709; b.value4710 = 4710; b.value4711 = 4711; b.value4712 = 4712; b.value4713 = 4713; b.value4714 = 4714; b.value4715 = 4715; b.value4716 = 4716; b.value4717 = 4717; b.value4718 = 4718; b.value4719 = 4719; b.value4720 = 4720; b.value4721 = 4721; b.value4722 = 4722; b.value4723 = 4723; b.value4724 = 4724; b.value4725 = 4725; b.value4726 = 4726; b.value4727 = 4727; b.value4728 = 4728; b.value4729 = 4729; b.value4730 = 4730; b.value4731 = 4731; b.value4732 = 4732; b.value4733 = 4733; b.value4734 = 4734; b.value4735 = 4735; b.value4736 = 4736; b.value4737 = 4737; b.value4738 = 4738; b.value4739 = 4739; b.value4740 = 4740; b.value4741 = 4741; b.value4742 = 4742; b.value4743 = 4743; b.value4744 = 4744; b.value4745 = 4745; b.value4746 = 4746; b.value4747 = 4747; b.value4748 = 4748; b.value4749 = 4749; b.value4750 = 4750; b.value4751 = 4751; b.value4752 = 4752; b.value4753 = 4753; b.value4754 = 4754; b.value4755 = 4755; b.value4756 = 4756; b.value4757 = 4757; b.value4758 = 4758; b.value4759 = 4759; b.value4760 = 4760; b.value4761 = 4761; b.value4762 = 4762; b.value4763 = 4763; b.value4764 = 4764; b.value4765 = 4765; b.value4766 = 4766; b.value4767 = 4767; b.value4768 = 4768; b.value4769 = 4769; b.value4770 = 4770; b.value4771 = 4771; b.value4772 = 4772; b.value4773 = 4773; b.value4774 = 4774; b.value4775 = 4775; b.value4776 = 4776; b.value4777 = 4777; b.value4778 = 4778; b.value4779 = 4779; b.value4780 = 4780; b.value4781 = 4781; b.value4782 = 4782; b.value4783 = 4783; b.value4784 = 4784; b.value4785 = 4785; b.value4786 = 4786; b.value4787 = 4787; b.value4788 = 4788; b.value4789 = 4789; b.value4790 = 4790; b.value4791 = 4791; b.value4792 = 4792; b.value4793 = 4793; b.value4794 = 4794; b.value4795 = 4795; b.value4796 = 4796; b.value4797 = 4797; b.value4798 = 4798; b.value4799 = 4799; b.value4800 = 4800; b.value4801 = 4801; b.value4802 = 4802; b.value4803 = 4803; b.value4804 = 4804; b.value4805 = 4805; b.value4806 = 4806; b.value4807 = 4807; b.value4808 = 4808; b.value4809 = 4809; b.value4810 = 4810; b.value4811 = 4811; b.value4812 = 4812; b.value4813 = 4813; b.value4814 = 4814; b.value4815 = 4815; b.value4816 = 4816; b.value4817 = 4817; b.value4818 = 4818; b.value4819 = 4819; b.value4820 = 4820; b.value4821 = 4821; b.value4822 = 4822; b.value4823 = 4823; b.value4824 = 4824; b.value4825 = 4825; b.value4826 = 4826; b.value4827 = 4827; b.value4828 = 4828; b.value4829 = 4829; b.value4830 = 4830; b.value4831 = 4831; b.value4832 = 4832; b.value4833 = 4833; b.value4834 = 4834; b.value4835 = 4835; b.value4836 = 4836; b.value4837 = 4837; b.value4838 = 4838; b.value4839 = 4839; b.value4840 = 4840; b.value4841 = 4841; b.value4842 = 4842; b.value4843 = 4843; b.value4844 = 4844; b.value4845 = 4845; b.value4846 = 4846; b.value4847 = 4847; b.value4848 = 4848; b.value4849 = 4849; b.value4850 = 4850; b.value4851 = 4851; b.value4852 = 4852; b.value4853 = 4853; b.value4854 = 4854; b.value4855 = 4855; b.value4856 = 4856; b.value4857 = 4857; b.value4858 = 4858; b.value4859 = 4859; b.value4860 = 4860; b.value4861 = 4861; b.value4862 = 4862; b.value4863 = 4863; b.value4864 = 4864; b.value4865 = 4865; b.value4866 = 4866; b.value4867 = 4867; b.value4868 = 4868; b.value4869 = 4869; b.value4870 = 4870; b.value4871 = 4871; b.value4872 = 4872; b.value4873 = 4873; b.value4874 = 4874; b.value4875 = 4875; b.value4876 = 4876; b.value4877 = 4877; b.value4878 = 4878; b.value4879 = 4879; b.value4880 = 4880; b.value4881 = 4881; b.value4882 = 4882; b.value4883 = 4883; b.value4884 = 4884; b.value4885 = 4885; b.value4886 = 4886; b.value4887 = 4887; b.value4888 = 4888; b.value4889 = 4889; b.value4890 = 4890; b.value4891 = 4891; b.value4892 = 4892; b.value4893 = 4893; b.value4894 = 4894; b.value4895 = 4895; b.value4896 = 4896; b.value4897 = 4897; b.value4898 = 4898; b.value4899 = 4899; b.value4900 = 4900; b.value4901 = 4901; b.value4902 = 4902; b.value4903 = 4903; b.value4904 = 4904; b.value4905 = 4905; b.value4906 = 4906; b.value4907 = 4907; b.value4908 = 4908; b.value4909 = 4909; b.value4910 = 4910; b.value4911 = 4911; b.value4912 = 4912; b.value4913 = 4913; b.value4914 = 4914; b.value4915 = 4915; b.value4916 = 4916; b.value4917 = 4917; b.value4918 = 4918; b.value4919 = 4919; b.value4920 = 4920; b.value4921 = 4921; b.value4922 = 4922; b.value4923 = 4923; b.value4924 = 4924; b.value4925 = 4925; b.value4926 = 4926; b.value4927 = 4927; b.value4928 = 4928; b.value4929 = 4929; b.value4930 = 4930; b.value4931 = 4931; b.value4932 = 4932; b.value4933 = 4933; b.value4934 = 4934; b.value4935 = 4935; b.value4936 = 4936; b.value4937 = 4937; b.value4938 = 4938; b.value4939 = 4939; b.value4940 = 4940; b.value4941 = 4941; b.value4942 = 4942; b.value4943 = 4943; b.value4944 = 4944; b.value4945 = 4945; b.value4946 = 4946; b.value4947 = 4947; b.value4948 = 4948; b.value4949 = 4949; b.value4950 = 4950; b.value4951 = 4951; b.value4952 = 4952; b.value4953 = 4953; b.value4954 = 4954; b.value4955 = 4955; b.value4956 = 4956; b.value4957 = 4957; b.value4958 = 4958; b.value4959 = 4959; b.value4960 = 4960; b.value4961 = 4961; b.value4962 = 4962; b.value4963 = 4963; b.value4964 = 4964; b.value4965 = 4965; b.value4966 = 4966; b.value4967 = 4967; b.value4968 = 4968; b.value4969 = 4969; b.value4970 = 4970; b.value4971 = 4971; b.value4972 = 4972; b.value4973 = 4973; b.value4974 = 4974; b.value4975 = 4975; b.value4976 = 4976; b.value4977 = 4977; b.value4978 = 4978; b.value4979 = 4979; b.value4980 = 4980; b.value4981 = 4981; b.value4982 = 4982; b.value4983 = 4983; b.value4984 = 4984; b.value4985 = 4985; b.value4986 = 4986; b.value4987 = 4987; b.value4988 = 4988; b.value4989 = 4989; b.value4990 = 4990; b.value4991 = 4991; b.value4992 = 4992; b.value4993 = 4993; b.value4994 = 4994; b.value4995 = 4995; b.value4996 = 4996; b.value4997 = 4997; b.value4998 = 4998; b.value4999 = 4999; b.value5000 = 5000; b.value5001 = 5001; b.value5002 = 5002; b.value5003 = 5003; b.value5004 = 5004; b.value5005 = 5005; b.value5006 = 5006; b.value5007 = 5007; b.value5008 = 5008; b.value5009 = 5009; b.value5010 = 5010; b.value5011 = 5011; b.value5012 = 5012; b.value5013 = 5013; b.value5014 = 5014; b.value5015 = 5015; b.value5016 = 5016; b.value5017 = 5017; b.value5018 = 5018; b.value5019 = 5019; b.value5020 = 5020; b.value5021 = 5021; b.value5022 = 5022; b.value5023 = 5023; b.value5024 = 5024; b.value5025 = 5025; b.value5026 = 5026; b.value5027 = 5027; b.value5028 = 5028; b.value5029 = 5029; b.value5030 = 5030; b.value5031 = 5031; b.value5032 = 5032; b.value5033 = 5033; b.value5034 = 5034; b.value5035 = 5035; b.value5036 = 5036; b.value5037 = 5037; b.value5038 = 5038; b.value5039 = 5039; b.value5040 = 5040; b.value5041 = 5041; b.value5042 = 5042; b.value5043 = 5043; b.value5044 = 5044; b.value5045 = 5045; b.value5046 = 5046; b.value5047 = 5047; b.value5048 = 5048; b.value5049 = 5049; b.value5050 = 5050; b.value5051 = 5051; b.value5052 = 5052; b.value5053 = 5053; b.value5054 = 5054; b.value5055 = 5055; b.value5056 = 5056; b.value5057 = 5057; b.value5058 = 5058; b.value5059 = 5059; b.value5060 = 5060; b.value5061 = 5061; b.value5062 = 5062; b.value5063 = 5063; b.value5064 = 5064; b.value5065 = 5065; b.value5066 = 5066; b.value5067 = 5067; b.value5068 = 5068; b.value5069 = 5069; b.value5070 = 5070; b.value5071 = 5071; b.value5072 = 5072; b.value5073 = 5073; b.value5074 = 5074; b.value5075 = 5075; b.value5076 = 5076; b.value5077 = 5077; b.value5078 = 5078; b.value5079 = 5079; b.value5080 = 5080; b.value5081 = 5081; b.value5082 = 5082; b.value5083 = 5083; b.value5084 = 5084; b.value5085 = 5085; b.value5086 = 5086; b.value5087 = 5087; b.value5088 = 5088; b.value5089 = 5089; b.value5090 = 5090; b.value5091 = 5091; b.value5092 = 5092; b.value5093 = 5093; b.value5094 = 5094; b.value5095 = 5095; b.value5096 = 5096; b.value5097 = 5097; b.value5098 = 5098; b.value5099 = 5099; b.value5100 = 5100; b.value5101 = 5101; b.value5102 = 5102; b.value5103 = 5103; b.value5104 = 5104; b.value5105 = 5105; b.value5106 = 5106; b.value5107 = 5107; b.value5108 = 5108; b.value5109 = 5109; b.value5110 = 5110; b.value5111 = 5111; b.value5112 = 5112; b.value5113 = 5113; b.value5114 = 5114; b.value5115 = 5115; b.value5116 = 5116; b.value5117 = 5117; b.value5118 = 5118; b.value5119 = 5119; b.value5120 = 5120; b.value5121 = 5121; b.value5122 = 5122; b.value5123 = 5123; b.value5124 = 5124; b.value5125 = 5125; b.value5126 = 5126; b.value5127 = 5127; b.value5128 = 5128; b.value5129 = 5129; b.value5130 = 5130; b.value5131 = 5131; b.value5132 = 5132; b.value5133 = 5133; b.value5134 = 5134; b.value5135 = 5135; b.value5136 = 5136; b.value5137 = 5137; b.value5138 = 5138; b.value5139 = 5139; b.value5140 = 5140; b.value5141 = 5141; b.value5142 = 5142; b.value5143 = 5143; b.value5144 = 5144; b.value5145 = 5145; b.value5146 = 5146; b.value5147 = 5147; b.value5148 = 5148; b.value5149 = 5149; b.value5150 = 5150; b.value5151 = 5151; b.value5152 = 5152; b.value5153 = 5153; b.value5154 = 5154; b.value5155 = 5155; b.value5156 = 5156; b.value5157 = 5157; b.value5158 = 5158; b.value5159 = 5159; b.value5160 = 5160; b.value5161 = 5161; b.value5162 = 5162; b.value5163 = 5163; b.value5164 = 5164; b.value5165 = 5165; b.value5166 = 5166; b.value5167 = 5167; b.value5168 = 5168; b.value5169 = 5169; b.value5170 = 5170; b.value5171 = 5171; b.value5172 = 5172; b.value5173 = 5173; b.value5174 = 5174; b.value5175 = 5175; b.value5176 = 5176; b.value5177 = 5177; b.value5178 = 5178; b.value5179 = 5179; b.value5180 = 5180; b.value5181 = 5181; b.value5182 = 5182; b.value5183 = 5183; b.value5184 = 5184; b.value5185 = 5185; b.value5186 = 5186; b.value5187 = 5187; b.value5188 = 5188; b.value5189 = 5189; b.value5190 = 5190; b.value5191 = 5191; b.value5192 = 5192; b.value5193 = 5193; b.value5194 = 5194; b.value5195 = 5195; b.value5196 = 5196; b.value5197 = 5197; b.value5198 = 5198; b.value5199 = 5199; b.value5200 = 5200; b.value5201 = 5201; b.value5202 = 5202; b.value5203 = 5203; b.value5204 = 5204; b.value5205 = 5205; b.value5206 = 5206; b.value5207 = 5207; b.value5208 = 5208; b.value5209 = 5209; b.value5210 = 5210; b.value5211 = 5211; b.value5212 = 5212; b.value5213 = 5213; b.value5214 = 5214; b.value5215 = 5215; b.value5216 = 5216; b.value5217 = 5217; b.value5218 = 5218; b.value5219 = 5219; b.value5220 = 5220; b.value5221 = 5221; b.value5222 = 5222; b.value5223 = 5223; b.value5224 = 5224; b.value5225 = 5225; b.value5226 = 5226; b.value5227 = 5227; b.value5228 = 5228; b.value5229 = 5229; b.value5230 = 5230; b.value5231 = 5231; b.value5232 = 5232; b.value5233 = 5233; b.value5234 = 5234; b.value5235 = 5235; b.value5236 = 5236; b.value5237 = 5237; b.value5238 = 5238; b.value5239 = 5239; b.value5240 = 5240; b.value5241 = 5241; b.value5242 = 5242; b.value5243 = 5243; b.value5244 = 5244; b.value5245 = 5245; b.value5246 = 5246; b.value5247 = 5247; b.value5248 = 5248; b.value5249 = 5249; b.value5250 = 5250; b.value5251 = 5251; b.value5252 = 5252; b.value5253 = 5253; b.value5254 = 5254; b.value5255 = 5255; b.value5256 = 5256; b.value5257 = 5257; b.value5258 = 5258; b.value5259 = 5259; b.value5260 = 5260; b.value5261 = 5261; b.value5262 = 5262; b.value5263 = 5263; b.value5264 = 5264; b.value5265 = 5265; b.value5266 = 5266; b.value5267 = 5267; b.value5268 = 5268; b.value5269 = 5269; b.value5270 = 5270; b.value5271 = 5271; b.value5272 = 5272; b.value5273 = 5273; b.value5274 = 5274; b.value5275 = 5275; b.value5276 = 5276; b.value5277 = 5277; b.value5278 = 5278; b.value5279 = 5279; b.value5280 = 5280; b.value5281 = 5281; b.value5282 = 5282; b.value5283 = 5283; b.value5284 = 5284; b.value5285 = 5285; b.value5286 = 5286; b.value5287 = 5287; b.value5288 = 5288; b.value5289 = 5289; b.value5290 = 5290; b.value5291 = 5291; b.value5292 = 5292; b.value5293 = 5293; b.value5294 = 5294; b.value5295 = 5295; b.value5296 = 5296; b.value5297 = 5297; b.value5298 = 5298; b.value5299 = 5299; b.value5300 = 5300; b.value5301 = 5301; b.value5302 = 5302; b.value5303 = 5303; b.value5304 = 5304; b.value5305 = 5305; b.value5306 = 5306; b.value5307 = 5307; b.value5308 = 5308; b.value5309 = 5309; b.value5310 = 5310; b.value5311 = 5311; b.value5312 = 5312; b.value5313 = 5313; b.value5314 = 5314; b.value5315 = 5315; b.value5316 = 5316; b.value5317 = 5317; b.value5318 = 5318; b.value5319 = 5319; b.value5320 = 5320; b.value5321 = 5321; b.value5322 = 5322; b.value5323 = 5323; b.value5324 = 5324; b.value5325 = 5325; b.value5326 = 5326; b.value5327 = 5327; b.value5328 = 5328; b.value5329 = 5329; b.value5330 = 5330; b.value5331 = 5331; b.value5332 = 5332; b.value5333 = 5333; b.value5334 = 5334; b.value5335 = 5335; b.value5336 = 5336; b.value5337 = 5337; b.value5338 = 5338; b.value5339 = 5339; b.value5340 = 5340; b.value5341 = 5341; b.value5342 = 5342; b.value5343 = 5343; b.value5344 = 5344; b.value5345 = 5345; b.value5346 = 5346; b.value5347 = 5347; b.value5348 = 5348; b.value5349 = 5349; b.value5350 = 5350; b.value5351 = 5351; b.value5352 = 5352; b.value5353 = 5353; b.value5354 = 5354; b.value5355 = 5355; b.value5356 = 5356; b.value5357 = 5357; b.value5358 = 5358; b.value5359 = 5359; b.value5360 = 5360; b.value5361 = 5361; b.value5362 = 5362; b.value5363 = 5363; b.value5364 = 5364; b.value5365 = 5365; b.value5366 = 5366; b.value5367 = 5367; b.value5368 = 5368; b.value5369 = 5369; b.value5370 = 5370; b.value5371 = 5371; b.value5372 = 5372; b.value5373 = 5373; b.value5374 = 5374; b.value5375 = 5375; b.value5376 = 5376; b.value5377 = 5377; b.value5378 = 5378; b.value5379 = 5379; b.value5380 = 5380; b.value5381 = 5381; b.value5382 = 5382; b.value5383 = 5383; b.value5384 = 5384; b.value5385 = 5385; b.value5386 = 5386; b.value5387 = 5387; b.value5388 = 5388; b.value5389 = 5389; b.value5390 = 5390; b.value5391 = 5391; b.value5392 = 5392; b.value5393 = 5393; b.value5394 = 5394; b.value5395 = 5395; b.value5396 = 5396; b.value5397 = 5397; b.value5398 = 5398; b.value5399 = 5399; b.value5400 = 5400; b.value5401 = 5401; b.value5402 = 5402; b.value5403 = 5403; b.value5404 = 5404; b.value5405 = 5405; b.value5406 = 5406; b.value5407 = 5407; b.value5408 = 5408; b.value5409 = 5409; b.value5410 = 5410; b.value5411 = 5411; b.value5412 = 5412; b.value5413 = 5413; b.value5414 = 5414; b.value5415 = 5415; b.value5416 = 5416; b.value5417 = 5417; b.value5418 = 5418; b.value5419 = 5419; b.value5420 = 5420; b.value5421 = 5421; b.value5422 = 5422; b.value5423 = 5423; b.value5424 = 5424; b.value5425 = 5425; b.value5426 = 5426; b.value5427 = 5427; b.value5428 = 5428; b.value5429 = 5429; b.value5430 = 5430; b.value5431 = 5431; b.value5432 = 5432; b.value5433 = 5433; b.value5434 = 5434; b.value5435 = 5435; b.value5436 = 5436; b.value5437 = 5437; b.value5438 = 5438; b.value5439 = 5439; b.value5440 = 5440; b.value5441 = 5441; b.value5442 = 5442; b.value5443 = 5443; b.value5444 = 5444; b.value5445 = 5445; b.value5446 = 5446; b.value5447 = 5447; b.value5448 = 5448; b.value5449 = 5449; b.value5450 = 5450; b.value5451 = 5451; b.value5452 = 5452; b.value5453 = 5453; b.value5454 = 5454; b.value5455 = 5455; b.value5456 = 5456; b.value5457 = 5457; b.value5458 = 5458; b.value5459 = 5459; b.value5460 = 5460; b.value5461 = 5461; b.value5462 = 5462; b.value5463 = 5463; b.value5464 = 5464; b.value5465 = 5465; b.value5466 = 5466; b.value5467 = 5467; b.value5468 = 5468; b.value5469 = 5469; b.value5470 = 5470; b.value5471 = 5471; b.value5472 = 5472; b.value5473 = 5473; b.value5474 = 5474; b.value5475 = 5475; b.value5476 = 5476; b.value5477 = 5477; b.value5478 = 5478; b.value5479 = 5479; b.value5480 = 5480; b.value5481 = 5481; b.value5482 = 5482; b.value5483 = 5483; b.value5484 = 5484; b.value5485 = 5485; b.value5486 = 5486; b.value5487 = 5487; b.value5488 = 5488; b.value5489 = 5489; b.value5490 = 5490; b.value5491 = 5491; b.value5492 = 5492; b.value5493 = 5493; b.value5494 = 5494; b.value5495 = 5495; b.value5496 = 5496; b.value5497 = 5497; b.value5498 = 5498; b.value5499 = 5499; b.value5500 = 5500; b.value5501 = 5501; b.value5502 = 5502; b.value5503 = 5503; b.value5504 = 5504; b.value5505 = 5505; b.value5506 = 5506; b.value5507 = 5507; b.value5508 = 5508; b.value5509 = 5509; b.value5510 = 5510; b.value5511 = 5511; b.value5512 = 5512; b.value5513 = 5513; b.value5514 = 5514; b.value5515 = 5515; b.value5516 = 5516; b.value5517 = 5517; b.value5518 = 5518; b.value5519 = 5519; b.value5520 = 5520; b.value5521 = 5521; b.value5522 = 5522; b.value5523 = 5523; b.value5524 = 5524; b.value5525 = 5525; b.value5526 = 5526; b.value5527 = 5527; b.value5528 = 5528; b.value5529 = 5529; b.value5530 = 5530; b.value5531 = 5531; b.value5532 = 5532; b.value5533 = 5533; b.value5534 = 5534; b.value5535 = 5535; b.value5536 = 5536; b.value5537 = 5537; b.value5538 = 5538; b.value5539 = 5539; b.value5540 = 5540; b.value5541 = 5541; b.value5542 = 5542; b.value5543 = 5543; b.value5544 = 5544; b.value5545 = 5545; b.value5546 = 5546; b.value5547 = 5547; b.value5548 = 5548; b.value5549 = 5549; b.value5550 = 5550; b.value5551 = 5551; b.value5552 = 5552; b.value5553 = 5553; b.value5554 = 5554; b.value5555 = 5555; b.value5556 = 5556; b.value5557 = 5557; b.value5558 = 5558; b.value5559 = 5559; b.value5560 = 5560; b.value5561 = 5561; b.value5562 = 5562; b.value5563 = 5563; b.value5564 = 5564; b.value5565 = 5565; b.value5566 = 5566; b.value5567 = 5567; b.value5568 = 5568; b.value5569 = 5569; b.value5570 = 5570; b.value5571 = 5571; b.value5572 = 5572; b.value5573 = 5573; b.value5574 = 5574; b.value5575 = 5575; b.value5576 = 5576; b.value5577 = 5577; b.value5578 = 5578; b.value5579 = 5579; b.value5580 = 5580; b.value5581 = 5581; b.value5582 = 5582; b.value5583 = 5583; b.value5584 = 5584; b.value5585 = 5585; b.value5586 = 5586; b.value5587 = 5587; b.value5588 = 5588; b.value5589 = 5589; b.value5590 = 5590; b.value5591 = 5591; b.value5592 = 5592; b.value5593 = 5593; b.value5594 = 5594; b.value5595 = 5595; b.value5596 = 5596; b.value5597 = 5597; b.value5598 = 5598; b.value5599 = 5599; b.value5600 = 5600; b.value5601 = 5601; b.value5602 = 5602; b.value5603 = 5603; b.value5604 = 5604; b.value5605 = 5605; b.value5606 = 5606; b.value5607 = 5607; b.value5608 = 5608; b.value5609 = 5609; b.value5610 = 5610; b.value5611 = 5611; b.value5612 = 5612; b.value5613 = 5613; b.value5614 = 5614; b.value5615 = 5615; b.value5616 = 5616; b.value5617 = 5617; b.value5618 = 5618; b.value5619 = 5619; b.value5620 = 5620; b.value5621 = 5621; b.value5622 = 5622; b.value5623 = 5623; b.value5624 = 5624; b.value5625 = 5625; b.value5626 = 5626; b.value5627 = 5627; b.value5628 = 5628; b.value5629 = 5629; b.value5630 = 5630; b.value5631 = 5631; b.value5632 = 5632; b.value5633 = 5633; b.value5634 = 5634; b.value5635 = 5635; b.value5636 = 5636; b.value5637 = 5637; b.value5638 = 5638; b.value5639 = 5639; b.value5640 = 5640; b.value5641 = 5641; b.value5642 = 5642; b.value5643 = 5643; b.value5644 = 5644; b.value5645 = 5645; b.value5646 = 5646; b.value5647 = 5647; b.value5648 = 5648; b.value5649 = 5649; b.value5650 = 5650; b.value5651 = 5651; b.value5652 = 5652; b.value5653 = 5653; b.value5654 = 5654; b.value5655 = 5655; b.value5656 = 5656; b.value5657 = 5657; b.value5658 = 5658; b.value5659 = 5659; b.value5660 = 5660; b.value5661 = 5661; b.value5662 = 5662; b.value5663 = 5663; b.value5664 = 5664; b.value5665 = 5665; b.value5666 = 5666; b.value5667 = 5667; b.value5668 = 5668; b.value5669 = 5669; b.value5670 = 5670; b.value5671 = 5671; b.value5672 = 5672; b.value5673 = 5673; b.value5674 = 5674; b.value5675 = 5675; b.value5676 = 5676; b.value5677 = 5677; b.value5678 = 5678; b.value5679 = 5679; b.value5680 = 5680; b.value5681 = 5681; b.value5682 = 5682; b.value5683 = 5683; b.value5684 = 5684; b.value5685 = 5685; b.value5686 = 5686; b.value5687 = 5687; b.value5688 = 5688; b.value5689 = 5689; b.value5690 = 5690; b.value5691 = 5691; b.value5692 = 5692; b.value5693 = 5693; b.value5694 = 5694; b.value5695 = 5695; b.value5696 = 5696; b.value5697 = 5697; b.value5698 = 5698; b.value5699 = 5699; b.value5700 = 5700; b.value5701 = 5701; b.value5702 = 5702; b.value5703 = 5703; b.value5704 = 5704; b.value5705 = 5705; b.value5706 = 5706; b.value5707 = 5707; b.value5708 = 5708; b.value5709 = 5709; b.value5710 = 5710; b.value5711 = 5711; b.value5712 = 5712; b.value5713 = 5713; b.value5714 = 5714; b.value5715 = 5715; b.value5716 = 5716; b.value5717 = 5717; b.value5718 = 5718; b.value5719 = 5719; b.value5720 = 5720; b.value5721 = 5721; b.value5722 = 5722; b.value5723 = 5723; b.value5724 = 5724; b.value5725 = 5725; b.value5726 = 5726; b.value5727 = 5727; b.value5728 = 5728; b.value5729 = 5729; b.value5730 = 5730; b.value5731 = 5731; b.value5732 = 5732; b.value5733 = 5733; b.value5734 = 5734; b.value5735 = 5735; b.value5736 = 5736; b.value5737 = 5737; b.value5738 = 5738; b.value5739 = 5739; b.value5740 = 5740; b.value5741 = 5741; b.value5742 = 5742; b.value5743 = 5743; b.value5744 = 5744; b.value5745 = 5745; b.value5746 = 5746; b.value5747 = 5747; b.value5748 = 5748; b.value5749 = 5749; b.value5750 = 5750; b.value5751 = 5751; b.value5752 = 5752; b.value5753 = 5753; b.value5754 = 5754; b.value5755 = 5755; b.value5756 = 5756; b.value5757 = 5757; b.value5758 = 5758; b.value5759 = 5759; b.value5760 = 5760; b.value5761 = 5761; b.value5762 = 5762; b.value5763 = 5763; b.value5764 = 5764; b.value5765 = 5765; b.value5766 = 5766; b.value5767 = 5767; b.value5768 = 5768; b.value5769 = 5769; b.value5770 = 5770; b.value5771 = 5771; b.value5772 = 5772; b.value5773 = 5773; b.value5774 = 5774; b.value5775 = 5775; b.value5776 = 5776; b.value5777 = 5777; b.value5778 = 5778; b.value5779 = 5779; b.value5780 = 5780; b.value5781 = 5781; b.value5782 = 5782; b.value5783 = 5783; b.value5784 = 5784; b.value5785 = 5785; b.value5786 = 5786; b.value5787 = 5787; b.value5788 = 5788; b.value5789 = 5789; b.value5790 = 5790; b.value5791 = 5791; b.value5792 = 5792; b.value5793 = 5793; b.value5794 = 5794; b.value5795 = 5795; b.value5796 = 5796; b.value5797 = 5797; b.value5798 = 5798; b.value5799 = 5799; b.value5800 = 5800; b.value5801 = 5801; b.value5802 = 5802; b.value5803 = 5803; b.value5804 = 5804; b.value5805 = 5805; b.value5806 = 5806; b.value5807 = 5807; b.value5808 = 5808; b.value5809 = 5809; b.value5810 = 5810; b.value5811 = 5811; b.value5812 = 5812; b.value5813 = 5813; b.value5814 = 5814; b.value5815 = 5815; b.value5816 = 5816; b.value5817 = 5817; b.value5818 = 5818; b.value5819 = 5819; b.value5820 = 5820; b.value5821 = 5821; b.value5822 = 5822; b.value5823 = 5823; b.value5824 = 5824; b.value5825 = 5825; b.value5826 = 5826; b.value5827 = 5827; b.value5828 = 5828; b.value5829 = 5829; b.value5830 = 5830; b.value5831 = 5831; b.value5832 = 5832; b.value5833 = 5833; b.value5834 = 5834; b.value5835 = 5835; b.value5836 = 5836; b.value5837 = 5837; b.value5838 = 5838; b.value5839 = 5839; b.value5840 = 5840; b.value5841 = 5841; b.value5842 = 5842; b.value5843 = 5843; b.value5844 = 5844; b.value5845 = 5845; b.value5846 = 5846; b.value5847 = 5847; b.value5848 = 5848; b.value5849 = 5849; b.value5850 = 5850; b.value5851 = 5851; b.value5852 = 5852; b.value5853 = 5853; b.value5854 = 5854; b.value5855 = 5855; b.value5856 = 5856; b.value5857 = 5857; b.value5858 = 5858; b.value5859 = 5859; b.value5860 = 5860; b.value5861 = 5861; b.value5862 = 5862; b.value5863 = 5863; b.value5864 = 5864; b.value5865 = 5865; b.value5866 = 5866; b.value5867 = 5867; b.value5868 = 5868; b.value5869 = 5869; b.value5870 = 5870; b.value5871 = 5871; b.value5872 = 5872; b.value5873 = 5873; b.value5874 = 5874; b.value5875 = 5875; b.value5876 = 5876; b.value5877 = 5877; b.value5878 = 5878; b.value5879 = 5879; b.value5880 = 5880; b.value5881 = 5881; b.value5882 = 5882; b.value5883 = 5883; b.value5884 = 5884; b.value5885 = 5885; b.value5886 = 5886; b.value5887 = 5887; b.value5888 = 5888; b.value5889 = 5889; b.value5890 = 5890; b.value5891 = 5891; b.value5892 = 5892; b.value5893 = 5893; b.value5894 = 5894; b.value5895 = 5895; b.value5896 = 5896; b.value5897 = 5897; b.value5898 = 5898; b.value5899 = 5899; b.value5900 = 5900; b.value5901 = 5901; b.value5902 = 5902; b.value5903 = 5903; b.value5904 = 5904; b.value5905 = 5905; b.value5906 = 5906; b.value5907 = 5907; b.value5908 = 5908; b.value5909 = 5909; b.value5910 = 5910; b.value5911 = 5911; b.value5912 = 5912; b.value5913 = 5913; b.value5914 = 5914; b.value5915 = 5915; b.value5916 = 5916; b.value5917 = 5917; b.value5918 = 5918; b.value5919 = 5919; b.value5920 = 5920; b.value5921 = 5921; b.value5922 = 5922; b.value5923 = 5923; b.value5924 = 5924; b.value5925 = 5925; b.value5926 = 5926; b.value5927 = 5927; b.value5928 = 5928; b.value5929 = 5929; b.value5930 = 5930; b.value5931 = 5931; b.value5932 = 5932; b.value5933 = 5933; b.value5934 = 5934; b.value5935 = 5935; b.value5936 = 5936; b.value5937 = 5937; b.value5938 = 5938; b.value5939 = 5939; b.value5940 = 5940; b.value5941 = 5941; b.value5942 = 5942; b.value5943 = 5943; b.value5944 = 5944; b.value5945 = 5945; b.value5946 = 5946; b.value5947 = 5947; b.value5948 = 5948; b.value5949 = 5949; b.value5950 = 5950; b.value5951 = 5951; b.value5952 = 5952; b.value5953 = 5953; b.value5954 = 5954; b.value5955 = 5955; b.value5956 = 5956; b.value5957 = 5957; b.value5958 = 5958; b.value5959 = 5959; b.value5960 = 5960; b.value5961 = 5961; b.value5962 = 5962; b.value5963 = 5963; b.value5964 = 5964; b.value5965 = 5965; b.value5966 = 5966; b.value5967 = 5967; b.value5968 = 5968; b.value5969 = 5969; b.value5970 = 5970; b.value5971 = 5971; b.value5972 = 5972; b.value5973 = 5973; b.value5974 = 5974; b.value5975 = 5975; b.value5976 = 5976; b.value5977 = 5977; b.value5978 = 5978; b.value5979 = 5979; b.value5980 = 5980; b.value5981 = 5981; b.value5982 = 5982; b.value5983 = 5983; b.value5984 = 5984; b.value5985 = 5985; b.value5986 = 5986; b.value5987 = 5987; b.value5988 = 5988; b.value5989 = 5989; b.value5990 = 5990; b.value5991 = 5991; b.value5992 = 5992; b.value5993 = 5993; b.value5994 = 5994; b.value5995 = 5995; b.value5996 = 5996; b.value5997 = 5997; b.value5998 = 5998; b.value5999 = 5999; b.value6000 = 6000; b.value6001 = 6001; b.value6002 = 6002; b.value6003 = 6003; b.value6004 = 6004; b.value6005 = 6005; b.value6006 = 6006; b.value6007 = 6007; b.value6008 = 6008; b.value6009 = 6009; b.value6010 = 6010; b.value6011 = 6011; b.value6012 = 6012; b.value6013 = 6013; b.value6014 = 6014; b.value6015 = 6015; b.value6016 = 6016; b.value6017 = 6017; b.value6018 = 6018; b.value6019 = 6019; b.value6020 = 6020; b.value6021 = 6021; b.value6022 = 6022; b.value6023 = 6023; b.value6024 = 6024; b.value6025 = 6025; b.value6026 = 6026; b.value6027 = 6027; b.value6028 = 6028; b.value6029 = 6029; b.value6030 = 6030; b.value6031 = 6031; b.value6032 = 6032; b.value6033 = 6033; b.value6034 = 6034; b.value6035 = 6035; b.value6036 = 6036; b.value6037 = 6037; b.value6038 = 6038; b.value6039 = 6039; b.value6040 = 6040; b.value6041 = 6041; b.value6042 = 6042; b.value6043 = 6043; b.value6044 = 6044; b.value6045 = 6045; b.value6046 = 6046; b.value6047 = 6047; b.value6048 = 6048; b.value6049 = 6049; b.value6050 = 6050; b.value6051 = 6051; b.value6052 = 6052; b.value6053 = 6053; b.value6054 = 6054; b.value6055 = 6055; b.value6056 = 6056; b.value6057 = 6057; b.value6058 = 6058; b.value6059 = 6059; b.value6060 = 6060; b.value6061 = 6061; b.value6062 = 6062; b.value6063 = 6063; b.value6064 = 6064; b.value6065 = 6065; b.value6066 = 6066; b.value6067 = 6067; b.value6068 = 6068; b.value6069 = 6069; b.value6070 = 6070; b.value6071 = 6071; b.value6072 = 6072; b.value6073 = 6073; b.value6074 = 6074; b.value6075 = 6075; b.value6076 = 6076; b.value6077 = 6077; b.value6078 = 6078; b.value6079 = 6079; b.value6080 = 6080; b.value6081 = 6081; b.value6082 = 6082; b.value6083 = 6083; b.value6084 = 6084; b.value6085 = 6085; b.value6086 = 6086; b.value6087 = 6087; b.value6088 = 6088; b.value6089 = 6089; b.value6090 = 6090; b.value6091 = 6091; b.value6092 = 6092; b.value6093 = 6093; b.value6094 = 6094; b.value6095 = 6095; b.value6096 = 6096; b.value6097 = 6097; b.value6098 = 6098; b.value6099 = 6099; b.value6100 = 6100; b.value6101 = 6101; b.value6102 = 6102; b.value6103 = 6103; b.value6104 = 6104; b.value6105 = 6105; b.value6106 = 6106; b.value6107 = 6107; b.value6108 = 6108; b.value6109 = 6109; b.value6110 = 6110; b.value6111 = 6111; b.value6112 = 6112; b.value6113 = 6113; b.value6114 = 6114; b.value6115 = 6115; b.value6116 = 6116; b.value6117 = 6117; b.value6118 = 6118; b.value6119 = 6119; b.value6120 = 6120; b.value6121 = 6121; b.value6122 = 6122; b.value6123 = 6123; b.value6124 = 6124; b.value6125 = 6125; b.value6126 = 6126; b.value6127 = 6127; b.value6128 = 6128; b.value6129 = 6129; b.value6130 = 6130; b.value6131 = 6131; b.value6132 = 6132; b.value6133 = 6133; b.value6134 = 6134; b.value6135 = 6135; b.value6136 = 6136; b.value6137 = 6137; b.value6138 = 6138; b.value6139 = 6139; b.value6140 = 6140; b.value6141 = 6141; b.value6142 = 6142; b.value6143 = 6143; b.value6144 = 6144; b.value6145 = 6145; b.value6146 = 6146; b.value6147 = 6147; b.value6148 = 6148; b.value6149 = 6149; b.value6150 = 6150; b.value6151 = 6151; b.value6152 = 6152; b.value6153 = 6153; b.value6154 = 6154; b.value6155 = 6155; b.value6156 = 6156; b.value6157 = 6157; b.value6158 = 6158; b.value6159 = 6159; b.value6160 = 6160; b.value6161 = 6161; b.value6162 = 6162; b.value6163 = 6163; b.value6164 = 6164; b.value6165 = 6165; b.value6166 = 6166; b.value6167 = 6167; b.value6168 = 6168; b.value6169 = 6169; b.value6170 = 6170; b.value6171 = 6171; b.value6172 = 6172; b.value6173 = 6173; b.value6174 = 6174; b.value6175 = 6175; b.value6176 = 6176; b.value6177 = 6177; b.value6178 = 6178; b.value6179 = 6179; b.value6180 = 6180; b.value6181 = 6181; b.value6182 = 6182; b.value6183 = 6183; b.value6184 = 6184; b.value6185 = 6185; b.value6186 = 6186; b.value6187 = 6187; b.value6188 = 6188; b.value6189 = 6189; b.value6190 = 6190; b.value6191 = 6191; b.value6192 = 6192; b.value6193 = 6193; b.value6194 = 6194; b.value6195 = 6195; b.value6196 = 6196; b.value6197 = 6197; b.value6198 = 6198; b.value6199 = 6199; b.value6200 = 6200; b.value6201 = 6201; b.value6202 = 6202; b.value6203 = 6203; b.value6204 = 6204; b.value6205 = 6205; b.value6206 = 6206; b.value6207 = 6207; b.value6208 = 6208; b.value6209 = 6209; b.value6210 = 6210; b.value6211 = 6211; b.value6212 = 6212; b.value6213 = 6213; b.value6214 = 6214; b.value6215 = 6215; b.value6216 = 6216; b.value6217 = 6217; b.value6218 = 6218; b.value6219 = 6219; b.value6220 = 6220; b.value6221 = 6221; b.value6222 = 6222; b.value6223 = 6223; b.value6224 = 6224; b.value6225 = 6225; b.value6226 = 6226; b.value6227 = 6227; b.value6228 = 6228; b.value6229 = 6229; b.value6230 = 6230; b.value6231 = 6231; b.value6232 = 6232; b.value6233 = 6233; b.value6234 = 6234; b.value6235 = 6235; b.value6236 = 6236; b.value6237 = 6237; b.value6238 = 6238; b.value6239 = 6239; b.value6240 = 6240; b.value6241 = 6241; b.value6242 = 6242; b.value6243 = 6243; b.value6244 = 6244; b.value6245 = 6245; b.value6246 = 6246; b.value6247 = 6247; b.value6248 = 6248; b.value6249 = 6249; b.value6250 = 6250; b.value6251 = 6251; b.value6252 = 6252; b.value6253 = 6253; b.value6254 = 6254; b.value6255 = 6255; b.value6256 = 6256; b.value6257 = 6257; b.value6258 = 6258; b.value6259 = 6259; b.value6260 = 6260; b.value6261 = 6261; b.value6262 = 6262; b.value6263 = 6263; b.value6264 = 6264; b.value6265 = 6265; b.value6266 = 6266; b.value6267 = 6267; b.value6268 = 6268; b.value6269 = 6269; b.value6270 = 6270; b.value6271 = 6271; b.value6272 = 6272; b.value6273 = 6273; b.value6274 = 6274; b.value6275 = 6275; b.value6276 = 6276; b.value6277 = 6277; b.value6278 = 6278; b.value6279 = 6279; b.value6280 = 6280; b.value6281 = 6281; b.value6282 = 6282; b.value6283 = 6283; b.value6284 = 6284; b.value6285 = 6285; b.value6286 = 6286; b.value6287 = 6287; b.value6288 = 6288; b.value6289 = 6289; b.value6290 = 6290; b.value6291 = 6291; b.value6292 = 6292; b.value6293 = 6293; b.value6294 = 6294; b.value6295 = 6295; b.value6296 = 6296; b.value6297 = 6297; b.value6298 = 6298; b.value6299 = 6299; b.value6300 = 6300; b.value6301 = 6301; b.value6302 = 6302; b.value6303 = 6303; b.value6304 = 6304; b.value6305 = 6305; b.value6306 = 6306; b.value6307 = 6307; b.value6308 = 6308; b.value6309 = 6309; b.value6310 = 6310; b.value6311 = 6311; b.value6312 = 6312; b.value6313 = 6313; b.value6314 = 6314; b.value6315 = 6315; b.value6316 = 6316; b.value6317 = 6317; b.value6318 = 6318; b.value6319 = 6319; b.value6320 = 6320; b.value6321 = 6321; b.value6322 = 6322; b.value6323 = 6323; b.value6324 = 6324; b.value6325 = 6325; b.value6326 = 6326; b.value6327 = 6327; b.value6328 = 6328; b.value6329 = 6329; b.value6330 = 6330; b.value6331 = 6331; b.value6332 = 6332; b.value6333 = 6333; b.value6334 = 6334; b.value6335 = 6335; b.value6336 = 6336; b.value6337 = 6337; b.value6338 = 6338; b.value6339 = 6339; b.value6340 = 6340; b.value6341 = 6341; b.value6342 = 6342; b.value6343 = 6343; b.value6344 = 6344; b.value6345 = 6345; b.value6346 = 6346; b.value6347 = 6347; b.value6348 = 6348; b.value6349 = 6349; b.value6350 = 6350; b.value6351 = 6351; b.value6352 = 6352; b.value6353 = 6353; b.value6354 = 6354; b.value6355 = 6355; b.value6356 = 6356; b.value6357 = 6357; b.value6358 = 6358; b.value6359 = 6359; b.value6360 = 6360; b.value6361 = 6361; b.value6362 = 6362; b.value6363 = 6363; b.value6364 = 6364; b.value6365 = 6365; b.value6366 = 6366; b.value6367 = 6367; b.value6368 = 6368; b.value6369 = 6369; b.value6370 = 6370; b.value6371 = 6371; b.value6372 = 6372; b.value6373 = 6373; b.value6374 = 6374; b.value6375 = 6375; b.value6376 = 6376; b.value6377 = 6377; b.value6378 = 6378; b.value6379 = 6379; b.value6380 = 6380; b.value6381 = 6381; b.value6382 = 6382; b.value6383 = 6383; b.value6384 = 6384; b.value6385 = 6385; b.value6386 = 6386; b.value6387 = 6387; b.value6388 = 6388; b.value6389 = 6389; b.value6390 = 6390; b.value6391 = 6391; b.value6392 = 6392; b.value6393 = 6393; b.value6394 = 6394; b.value6395 = 6395; b.value6396 = 6396; b.value6397 = 6397; b.value6398 = 6398; b.value6399 = 6399; b.value6400 = 6400; b.value6401 = 6401; b.value6402 = 6402; b.value6403 = 6403; b.value6404 = 6404; b.value6405 = 6405; b.value6406 = 6406; b.value6407 = 6407; b.value6408 = 6408; b.value6409 = 6409; b.value6410 = 6410; b.value6411 = 6411; b.value6412 = 6412; b.value6413 = 6413; b.value6414 = 6414; b.value6415 = 6415; b.value6416 = 6416; b.value6417 = 6417; b.value6418 = 6418; b.value6419 = 6419; b.value6420 = 6420; b.value6421 = 6421; b.value6422 = 6422; b.value6423 = 6423; b.value6424 = 6424; b.value6425 = 6425; b.value6426 = 6426; b.value6427 = 6427; b.value6428 = 6428; b.value6429 = 6429; b.value6430 = 6430; b.value6431 = 6431; b.value6432 = 6432; b.value6433 = 6433; b.value6434 = 6434; b.value6435 = 6435; b.value6436 = 6436; b.value6437 = 6437; b.value6438 = 6438; b.value6439 = 6439; b.value6440 = 6440; b.value6441 = 6441; b.value6442 = 6442; b.value6443 = 6443; b.value6444 = 6444; b.value6445 = 6445; b.value6446 = 6446; b.value6447 = 6447; b.value6448 = 6448; b.value6449 = 6449; b.value6450 = 6450; b.value6451 = 6451; b.value6452 = 6452; b.value6453 = 6453; b.value6454 = 6454; b.value6455 = 6455; b.value6456 = 6456; b.value6457 = 6457; b.value6458 = 6458; b.value6459 = 6459; b.value6460 = 6460; b.value6461 = 6461; b.value6462 = 6462; b.value6463 = 6463; b.value6464 = 6464; b.value6465 = 6465; b.value6466 = 6466; b.value6467 = 6467; b.value6468 = 6468; b.value6469 = 6469; b.value6470 = 6470; b.value6471 = 6471; b.value6472 = 6472; b.value6473 = 6473; b.value6474 = 6474; b.value6475 = 6475; b.value6476 = 6476; b.value6477 = 6477; b.value6478 = 6478; b.value6479 = 6479; b.value6480 = 6480; b.value6481 = 6481; b.value6482 = 6482; b.value6483 = 6483; b.value6484 = 6484; b.value6485 = 6485; b.value6486 = 6486; b.value6487 = 6487; b.value6488 = 6488; b.value6489 = 6489; b.value6490 = 6490; b.value6491 = 6491; b.value6492 = 6492; b.value6493 = 6493; b.value6494 = 6494; b.value6495 = 6495; b.value6496 = 6496; b.value6497 = 6497; b.value6498 = 6498; b.value6499 = 6499; b.value6500 = 6500; b.value6501 = 6501; b.value6502 = 6502; b.value6503 = 6503; b.value6504 = 6504; b.value6505 = 6505; b.value6506 = 6506; b.value6507 = 6507; b.value6508 = 6508; b.value6509 = 6509; b.value6510 = 6510; b.value6511 = 6511; b.value6512 = 6512; b.value6513 = 6513; b.value6514 = 6514; b.value6515 = 6515; b.value6516 = 6516; b.value6517 = 6517; b.value6518 = 6518; b.value6519 = 6519; b.value6520 = 6520; b.value6521 = 6521; b.value6522 = 6522; b.value6523 = 6523; b.value6524 = 6524; b.value6525 = 6525; b.value6526 = 6526; b.value6527 = 6527; b.value6528 = 6528; b.value6529 = 6529; b.value6530 = 6530; b.value6531 = 6531; b.value6532 = 6532; b.value6533 = 6533; b.value6534 = 6534; b.value6535 = 6535; b.value6536 = 6536; b.value6537 = 6537; b.value6538 = 6538; b.value6539 = 6539; b.value6540 = 6540; b.value6541 = 6541; b.value6542 = 6542; b.value6543 = 6543; b.value6544 = 6544; b.value6545 = 6545; b.value6546 = 6546; b.value6547 = 6547; b.value6548 = 6548; b.value6549 = 6549; b.value6550 = 6550; b.value6551 = 6551; b.value6552 = 6552; b.value6553 = 6553; b.value6554 = 6554; b.value6555 = 6555; b.value6556 = 6556; b.value6557 = 6557; b.value6558 = 6558; b.value6559 = 6559; b.value6560 = 6560; b.value6561 = 6561; b.value6562 = 6562; b.value6563 = 6563; b.value6564 = 6564; b.value6565 = 6565; b.value6566 = 6566; b.value6567 = 6567; b.value6568 = 6568; b.value6569 = 6569; b.value6570 = 6570; b.value6571 = 6571; b.value6572 = 6572; b.value6573 = 6573; b.value6574 = 6574; b.value6575 = 6575; b.value6576 = 6576; b.value6577 = 6577; b.value6578 = 6578; b.value6579 = 6579; b.value6580 = 6580; b.value6581 = 6581; b.value6582 = 6582; b.value6583 = 6583; b.value6584 = 6584; b.value6585 = 6585; b.value6586 = 6586; b.value6587 = 6587; b.value6588 = 6588; b.value6589 = 6589; b.value6590 = 6590; b.value6591 = 6591; b.value6592 = 6592; b.value6593 = 6593; b.value6594 = 6594; b.value6595 = 6595; b.value6596 = 6596; b.value6597 = 6597; b.value6598 = 6598; b.value6599 = 6599; b.value6600 = 6600; b.value6601 = 6601; b.value6602 = 6602; b.value6603 = 6603; b.value6604 = 6604; b.value6605 = 6605; b.value6606 = 6606; b.value6607 = 6607; b.value6608 = 6608; b.value6609 = 6609; b.value6610 = 6610; b.value6611 = 6611; b.value6612 = 6612; b.value6613 = 6613; b.value6614 = 6614; b.value6615 = 6615; b.value6616 = 6616; b.value6617 = 6617; b.value6618 = 6618; b.value6619 = 6619; b.value6620 = 6620; b.value6621 = 6621; b.value6622 = 6622; b.value6623 = 6623; b.value6624 = 6624; b.value6625 = 6625; b.value6626 = 6626; b.value6627 = 6627; b.value6628 = 6628; b.value6629 = 6629; b.value6630 = 6630; b.value6631 = 6631; b.value6632 = 6632; b.value6633 = 6633; b.value6634 = 6634; b.value6635 = 6635; b.value6636 = 6636; b.value6637 = 6637; b.value6638 = 6638; b.value6639 = 6639; b.value6640 = 6640; b.value6641 = 6641; b.value6642 = 6642; b.value6643 = 6643; b.value6644 = 6644; b.value6645 = 6645; b.value6646 = 6646; b.value6647 = 6647; b.value6648 = 6648; b.value6649 = 6649; b.value6650 = 6650; b.value6651 = 6651; b.value6652 = 6652; b.value6653 = 6653; b.value6654 = 6654; b.value6655 = 6655; b.value6656 = 6656; b.value6657 = 6657; b.value6658 = 6658; b.value6659 = 6659; b.value6660 = 6660; b.value6661 = 6661; b.value6662 = 6662; b.value6663 = 6663; b.value6664 = 6664; b.value6665 = 6665; b.value6666 = 6666; b.value6667 = 6667; b.value6668 = 6668; b.value6669 = 6669; b.value6670 = 6670; b.value6671 = 6671; b.value6672 = 6672; b.value6673 = 6673; b.value6674 = 6674; b.value6675 = 6675; b.value6676 = 6676; b.value6677 = 6677; b.value6678 = 6678; b.value6679 = 6679; b.value6680 = 6680; b.value6681 = 6681; b.value6682 = 6682; b.value6683 = 6683; b.value6684 = 6684; b.value6685 = 6685; b.value6686 = 6686; b.value6687 = 6687; b.value6688 = 6688; b.value6689 = 6689; b.value6690 = 6690; b.value6691 = 6691; b.value6692 = 6692; b.value6693 = 6693; b.value6694 = 6694; b.value6695 = 6695; b.value6696 = 6696; b.value6697 = 6697; b.value6698 = 6698; b.value6699 = 6699; b.value6700 = 6700; b.value6701 = 6701; b.value6702 = 6702; b.value6703 = 6703; b.value6704 = 6704; b.value6705 = 6705; b.value6706 = 6706; b.value6707 = 6707; b.value6708 = 6708; b.value6709 = 6709; b.value6710 = 6710; b.value6711 = 6711; b.value6712 = 6712; b.value6713 = 6713; b.value6714 = 6714; b.value6715 = 6715; b.value6716 = 6716; b.value6717 = 6717; b.value6718 = 6718; b.value6719 = 6719; b.value6720 = 6720; b.value6721 = 6721; b.value6722 = 6722; b.value6723 = 6723; b.value6724 = 6724; b.value6725 = 6725; b.value6726 = 6726; b.value6727 = 6727; b.value6728 = 6728; b.value6729 = 6729; b.value6730 = 6730; b.value6731 = 6731; b.value6732 = 6732; b.value6733 = 6733; b.value6734 = 6734; b.value6735 = 6735; b.value6736 = 6736; b.value6737 = 6737; b.value6738 = 6738; b.value6739 = 6739; b.value6740 = 6740; b.value6741 = 6741; b.value6742 = 6742; b.value6743 = 6743; b.value6744 = 6744; b.value6745 = 6745; b.value6746 = 6746; b.value6747 = 6747; b.value6748 = 6748; b.value6749 = 6749; b.value6750 = 6750; b.value6751 = 6751; b.value6752 = 6752; b.value6753 = 6753; b.value6754 = 6754; b.value6755 = 6755; b.value6756 = 6756; b.value6757 = 6757; b.value6758 = 6758; b.value6759 = 6759; b.value6760 = 6760; b.value6761 = 6761; b.value6762 = 6762; b.value6763 = 6763; b.value6764 = 6764; b.value6765 = 6765; b.value6766 = 6766; b.value6767 = 6767; b.value6768 = 6768; b.value6769 = 6769; b.value6770 = 6770; b.value6771 = 6771; b.value6772 = 6772; b.value6773 = 6773; b.value6774 = 6774; b.value6775 = 6775; b.value6776 = 6776; b.value6777 = 6777; b.value6778 = 6778; b.value6779 = 6779; b.value6780 = 6780; b.value6781 = 6781; b.value6782 = 6782; b.value6783 = 6783; b.value6784 = 6784; b.value6785 = 6785; b.value6786 = 6786; b.value6787 = 6787; b.value6788 = 6788; b.value6789 = 6789; b.value6790 = 6790; b.value6791 = 6791; b.value6792 = 6792; b.value6793 = 6793; b.value6794 = 6794; b.value6795 = 6795; b.value6796 = 6796; b.value6797 = 6797; b.value6798 = 6798; b.value6799 = 6799; b.value6800 = 6800; b.value6801 = 6801; b.value6802 = 6802; b.value6803 = 6803; b.value6804 = 6804; b.value6805 = 6805; b.value6806 = 6806; b.value6807 = 6807; b.value6808 = 6808; b.value6809 = 6809; b.value6810 = 6810; b.value6811 = 6811; b.value6812 = 6812; b.value6813 = 6813; b.value6814 = 6814; b.value6815 = 6815; b.value6816 = 6816; b.value6817 = 6817; b.value6818 = 6818; b.value6819 = 6819; b.value6820 = 6820; b.value6821 = 6821; b.value6822 = 6822; b.value6823 = 6823; b.value6824 = 6824; b.value6825 = 6825; b.value6826 = 6826; b.value6827 = 6827; b.value6828 = 6828; b.value6829 = 6829; b.value6830 = 6830; b.value6831 = 6831; b.value6832 = 6832; b.value6833 = 6833; b.value6834 = 6834; b.value6835 = 6835; b.value6836 = 6836; b.value6837 = 6837; b.value6838 = 6838; b.value6839 = 6839; b.value6840 = 6840; b.value6841 = 6841; b.value6842 = 6842; b.value6843 = 6843; b.value6844 = 6844; b.value6845 = 6845; b.value6846 = 6846; b.value6847 = 6847; b.value6848 = 6848; b.value6849 = 6849; b.value6850 = 6850; b.value6851 = 6851; b.value6852 = 6852; b.value6853 = 6853; b.value6854 = 6854; b.value6855 = 6855; b.value6856 = 6856; b.value6857 = 6857; b.value6858 = 6858; b.value6859 = 6859; b.value6860 = 6860; b.value6861 = 6861; b.value6862 = 6862; b.value6863 = 6863; b.value6864 = 6864; b.value6865 = 6865; b.value6866 = 6866; b.value6867 = 6867; b.value6868 = 6868; b.value6869 = 6869; b.value6870 = 6870; b.value6871 = 6871; b.value6872 = 6872; b.value6873 = 6873; b.value6874 = 6874; b.value6875 = 6875; b.value6876 = 6876; b.value6877 = 6877; b.value6878 = 6878; b.value6879 = 6879; b.value6880 = 6880; b.value6881 = 6881; b.value6882 = 6882; b.value6883 = 6883; b.value6884 = 6884; b.value6885 = 6885; b.value6886 = 6886; b.value6887 = 6887; b.value6888 = 6888; b.value6889 = 6889; b.value6890 = 6890; b.value6891 = 6891; b.value6892 = 6892; b.value6893 = 6893; b.value6894 = 6894; b.value6895 = 6895; b.value6896 = 6896; b.value6897 = 6897; b.value6898 = 6898; b.value6899 = 6899; b.value6900 = 6900; b.value6901 = 6901; b.value6902 = 6902; b.value6903 = 6903; b.value6904 = 6904; b.value6905 = 6905; b.value6906 = 6906; b.value6907 = 6907; b.value6908 = 6908; b.value6909 = 6909; b.value6910 = 6910; b.value6911 = 6911; b.value6912 = 6912; b.value6913 = 6913; b.value6914 = 6914; b.value6915 = 6915; b.value6916 = 6916; b.value6917 = 6917; b.value6918 = 6918; b.value6919 = 6919; b.value6920 = 6920; b.value6921 = 6921; b.value6922 = 6922; b.value6923 = 6923; b.value6924 = 6924; b.value6925 = 6925; b.value6926 = 6926; b.value6927 = 6927; b.value6928 = 6928; b.value6929 = 6929; b.value6930 = 6930; b.value6931 = 6931; b.value6932 = 6932; b.value6933 = 6933; b.value6934 = 6934; b.value6935 = 6935; b.value6936 = 6936; b.value6937 = 6937; b.value6938 = 6938; b.value6939 = 6939; b.value6940 = 6940; b.value6941 = 6941; b.value6942 = 6942; b.value6943 = 6943; b.value6944 = 6944; b.value6945 = 6945; b.value6946 = 6946; b.value6947 = 6947; b.value6948 = 6948; b.value6949 = 6949; b.value6950 = 6950; b.value6951 = 6951; b.value6952 = 6952; b.value6953 = 6953; b.value6954 = 6954; b.value6955 = 6955; b.value6956 = 6956; b.value6957 = 6957; b.value6958 = 6958; b.value6959 = 6959; b.value6960 = 6960; b.value6961 = 6961; b.value6962 = 6962; b.value6963 = 6963; b.value6964 = 6964; b.value6965 = 6965; b.value6966 = 6966; b.value6967 = 6967; b.value6968 = 6968; b.value6969 = 6969; b.value6970 = 6970; b.value6971 = 6971; b.value6972 = 6972; b.value6973 = 6973; b.value6974 = 6974; b.value6975 = 6975; b.value6976 = 6976; b.value6977 = 6977; b.value6978 = 6978; b.value6979 = 6979; b.value6980 = 6980; b.value6981 = 6981; b.value6982 = 6982; b.value6983 = 6983; b.value6984 = 6984; b.value6985 = 6985; b.value6986 = 6986; b.value6987 = 6987; b.value6988 = 6988; b.value6989 = 6989; b.value6990 = 6990; b.value6991 = 6991; b.value6992 = 6992; b.value6993 = 6993; b.value6994 = 6994; b.value6995 = 6995; b.value6996 = 6996; b.value6997 = 6997; b.value6998 = 6998; b.value6999 = 6999; b.value7000 = 7000; b.value7001 = 7001; b.value7002 = 7002; b.value7003 = 7003; b.value7004 = 7004; b.value7005 = 7005; b.value7006 = 7006; b.value7007 = 7007; b.value7008 = 7008; b.value7009 = 7009; b.value7010 = 7010; b.value7011 = 7011; b.value7012 = 7012; b.value7013 = 7013; b.value7014 = 7014; b.value7015 = 7015; b.value7016 = 7016; b.value7017 = 7017; b.value7018 = 7018; b.value7019 = 7019; b.value7020 = 7020; b.value7021 = 7021; b.value7022 = 7022; b.value7023 = 7023; b.value7024 = 7024; b.value7025 = 7025; b.value7026 = 7026; b.value7027 = 7027; b.value7028 = 7028; b.value7029 = 7029; b.value7030 = 7030; b.value7031 = 7031; b.value7032 = 7032; b.value7033 = 7033; b.value7034 = 7034; b.value7035 = 7035; b.value7036 = 7036; b.value7037 = 7037; b.value7038 = 7038; b.value7039 = 7039; b.value7040 = 7040; b.value7041 = 7041; b.value7042 = 7042; b.value7043 = 7043; b.value7044 = 7044; b.value7045 = 7045; b.value7046 = 7046; b.value7047 = 7047; b.value7048 = 7048; b.value7049 = 7049; b.value7050 = 7050; b.value7051 = 7051; b.value7052 = 7052; b.value7053 = 7053; b.value7054 = 7054; b.value7055 = 7055; b.value7056 = 7056; b.value7057 = 7057; b.value7058 = 7058; b.value7059 = 7059; b.value7060 = 7060; b.value7061 = 7061; b.value7062 = 7062; b.value7063 = 7063; b.value7064 = 7064; b.value7065 = 7065; b.value7066 = 7066; b.value7067 = 7067; b.value7068 = 7068; b.value7069 = 7069; b.value7070 = 7070; b.value7071 = 7071; b.value7072 = 7072; b.value7073 = 7073; b.value7074 = 7074; b.value7075 = 7075; b.value7076 = 7076; b.value7077 = 7077; b.value7078 = 7078; b.value7079 = 7079; b.value7080 = 7080; b.value7081 = 7081; b.value7082 = 7082; b.value7083 = 7083; b.value7084 = 7084; b.value7085 = 7085; b.value7086 = 7086; b.value7087 = 7087; b.value7088 = 7088; b.value7089 = 7089; b.value7090 = 7090; b.value7091 = 7091; b.value7092 = 7092; b.value7093 = 7093; b.value7094 = 7094; b.value7095 = 7095; b.value7096 = 7096; b.value7097 = 7097; b.value7098 = 7098; b.value7099 = 7099; b.value7100 = 7100; b.value7101 = 7101; b.value7102 = 7102; b.value7103 = 7103; b.value7104 = 7104; b.value7105 = 7105; b.value7106 = 7106; b.value7107 = 7107; b.value7108 = 7108; b.value7109 = 7109; b.value7110 = 7110; b.value7111 = 7111; b.value7112 = 7112; b.value7113 = 7113; b.value7114 = 7114; b.value7115 = 7115; b.value7116 = 7116; b.value7117 = 7117; b.value7118 = 7118; b.value7119 = 7119; b.value7120 = 7120; b.value7121 = 7121; b.value7122 = 7122; b.value7123 = 7123; b.value7124 = 7124; b.value7125 = 7125; b.value7126 = 7126; b.value7127 = 7127; b.value7128 = 7128; b.value7129 = 7129; b.value7130 = 7130; b.value7131 = 7131; b.value7132 = 7132; b.value7133 = 7133; b.value7134 = 7134; b.value7135 = 7135; b.value7136 = 7136; b.value7137 = 7137; b.value7138 = 7138; b.value7139 = 7139; b.value7140 = 7140; b.value7141 = 7141; b.value7142 = 7142; b.value7143 = 7143; b.value7144 = 7144; b.value7145 = 7145; b.value7146 = 7146; b.value7147 = 7147; b.value7148 = 7148; b.value7149 = 7149; b.value7150 = 7150; b.value7151 = 7151; b.value7152 = 7152; b.value7153 = 7153; b.value7154 = 7154; b.value7155 = 7155; b.value7156 = 7156; b.value7157 = 7157; b.value7158 = 7158; b.value7159 = 7159; b.value7160 = 7160; b.value7161 = 7161; b.value7162 = 7162; b.value7163 = 7163; b.value7164 = 7164; b.value7165 = 7165; b.value7166 = 7166; b.value7167 = 7167; b.value7168 = 7168; b.value7169 = 7169; b.value7170 = 7170; b.value7171 = 7171; b.value7172 = 7172; b.value7173 = 7173; b.value7174 = 7174; b.value7175 = 7175; b.value7176 = 7176; b.value7177 = 7177; b.value7178 = 7178; b.value7179 = 7179; b.value7180 = 7180; b.value7181 = 7181; b.value7182 = 7182; b.value7183 = 7183; b.value7184 = 7184; b.value7185 = 7185; b.value7186 = 7186; b.value7187 = 7187; b.value7188 = 7188; b.value7189 = 7189; b.value7190 = 7190; b.value7191 = 7191; b.value7192 = 7192; b.value7193 = 7193; b.value7194 = 7194; b.value7195 = 7195; b.value7196 = 7196; b.value7197 = 7197; b.value7198 = 7198; b.value7199 = 7199; b.value7200 = 7200; b.value7201 = 7201; b.value7202 = 7202; b.value7203 = 7203; b.value7204 = 7204; b.value7205 = 7205; b.value7206 = 7206; b.value7207 = 7207; b.value7208 = 7208; b.value7209 = 7209; b.value7210 = 7210; b.value7211 = 7211; b.value7212 = 7212; b.value7213 = 7213; b.value7214 = 7214; b.value7215 = 7215; b.value7216 = 7216; b.value7217 = 7217; b.value7218 = 7218; b.value7219 = 7219; b.value7220 = 7220; b.value7221 = 7221; b.value7222 = 7222; b.value7223 = 7223; b.value7224 = 7224; b.value7225 = 7225; b.value7226 = 7226; b.value7227 = 7227; b.value7228 = 7228; b.value7229 = 7229; b.value7230 = 7230; b.value7231 = 7231; b.value7232 = 7232; b.value7233 = 7233; b.value7234 = 7234; b.value7235 = 7235; b.value7236 = 7236; b.value7237 = 7237; b.value7238 = 7238; b.value7239 = 7239; b.value7240 = 7240; b.value7241 = 7241; b.value7242 = 7242; b.value7243 = 7243; b.value7244 = 7244; b.value7245 = 7245; b.value7246 = 7246; b.value7247 = 7247; b.value7248 = 7248; b.value7249 = 7249; b.value7250 = 7250; b.value7251 = 7251; b.value7252 = 7252; b.value7253 = 7253; b.value7254 = 7254; b.value7255 = 7255; b.value7256 = 7256; b.value7257 = 7257; b.value7258 = 7258; b.value7259 = 7259; b.value7260 = 7260; b.value7261 = 7261; b.value7262 = 7262; b.value7263 = 7263; b.value7264 = 7264; b.value7265 = 7265; b.value7266 = 7266; b.value7267 = 7267; b.value7268 = 7268; b.value7269 = 7269; b.value7270 = 7270; b.value7271 = 7271; b.value7272 = 7272; b.value7273 = 7273; b.value7274 = 7274; b.value7275 = 7275; b.value7276 = 7276; b.value7277 = 7277; b.value7278 = 7278; b.value7279 = 7279; b.value7280 = 7280; b.value7281 = 7281; b.value7282 = 7282; b.value7283 = 7283; b.value7284 = 7284; b.value7285 = 7285; b.value7286 = 7286; b.value7287 = 7287; b.value7288 = 7288; b.value7289 = 7289; b.value7290 = 7290; b.value7291 = 7291; b.value7292 = 7292; b.value7293 = 7293; b.value7294 = 7294; b.value7295 = 7295; b.value7296 = 7296; b.value7297 = 7297; b.value7298 = 7298; b.value7299 = 7299; b.value7300 = 7300; b.value7301 = 7301; b.value7302 = 7302; b.value7303 = 7303; b.value7304 = 7304; b.value7305 = 7305; b.value7306 = 7306; b.value7307 = 7307; b.value7308 = 7308; b.value7309 = 7309; b.value7310 = 7310; b.value7311 = 7311; b.value7312 = 7312; b.value7313 = 7313; b.value7314 = 7314; b.value7315 = 7315; b.value7316 = 7316; b.value7317 = 7317; b.value7318 = 7318; b.value7319 = 7319; b.value7320 = 7320; b.value7321 = 7321; b.value7322 = 7322; b.value7323 = 7323; b.value7324 = 7324; b.value7325 = 7325; b.value7326 = 7326; b.value7327 = 7327; b.value7328 = 7328; b.value7329 = 7329; b.value7330 = 7330; b.value7331 = 7331; b.value7332 = 7332; b.value7333 = 7333; b.value7334 = 7334; b.value7335 = 7335; b.value7336 = 7336; b.value7337 = 7337; b.value7338 = 7338; b.value7339 = 7339; b.value7340 = 7340; b.value7341 = 7341; b.value7342 = 7342; b.value7343 = 7343; b.value7344 = 7344; b.value7345 = 7345; b.value7346 = 7346; b.value7347 = 7347; b.value7348 = 7348; b.value7349 = 7349; b.value7350 = 7350; b.value7351 = 7351; b.value7352 = 7352; b.value7353 = 7353; b.value7354 = 7354; b.value7355 = 7355; b.value7356 = 7356; b.value7357 = 7357; b.value7358 = 7358; b.value7359 = 7359; b.value7360 = 7360; b.value7361 = 7361; b.value7362 = 7362; b.value7363 = 7363; b.value7364 = 7364; b.value7365 = 7365; b.value7366 = 7366; b.value7367 = 7367; b.value7368 = 7368; b.value7369 = 7369; b.value7370 = 7370; b.value7371 = 7371; b.value7372 = 7372; b.value7373 = 7373; b.value7374 = 7374; b.value7375 = 7375; b.value7376 = 7376; b.value7377 = 7377; b.value7378 = 7378; b.value7379 = 7379; b.value7380 = 7380; b.value7381 = 7381; b.value7382 = 7382; b.value7383 = 7383; b.value7384 = 7384; b.value7385 = 7385; b.value7386 = 7386; b.value7387 = 7387; b.value7388 = 7388; b.value7389 = 7389; b.value7390 = 7390; b.value7391 = 7391; b.value7392 = 7392; b.value7393 = 7393; b.value7394 = 7394; b.value7395 = 7395; b.value7396 = 7396; b.value7397 = 7397; b.value7398 = 7398; b.value7399 = 7399; b.value7400 = 7400; b.value7401 = 7401; b.value7402 = 7402; b.value7403 = 7403; b.value7404 = 7404; b.value7405 = 7405; b.value7406 = 7406; b.value7407 = 7407; b.value7408 = 7408; b.value7409 = 7409; b.value7410 = 7410; b.value7411 = 7411; b.value7412 = 7412; b.value7413 = 7413; b.value7414 = 7414; b.value7415 = 7415; b.value7416 = 7416; b.value7417 = 7417; b.value7418 = 7418; b.value7419 = 7419; b.value7420 = 7420; b.value7421 = 7421; b.value7422 = 7422; b.value7423 = 7423; b.value7424 = 7424; b.value7425 = 7425; b.value7426 = 7426; b.value7427 = 7427; b.value7428 = 7428; b.value7429 = 7429; b.value7430 = 7430; b.value7431 = 7431; b.value7432 = 7432; b.value7433 = 7433; b.value7434 = 7434; b.value7435 = 7435; b.value7436 = 7436; b.value7437 = 7437; b.value7438 = 7438; b.value7439 = 7439; b.value7440 = 7440; b.value7441 = 7441; b.value7442 = 7442; b.value7443 = 7443; b.value7444 = 7444; b.value7445 = 7445; b.value7446 = 7446; b.value7447 = 7447; b.value7448 = 7448; b.value7449 = 7449; b.value7450 = 7450; b.value7451 = 7451; b.value7452 = 7452; b.value7453 = 7453; b.value7454 = 7454; b.value7455 = 7455; b.value7456 = 7456; b.value7457 = 7457; b.value7458 = 7458; b.value7459 = 7459; b.value7460 = 7460; b.value7461 = 7461; b.value7462 = 7462; b.value7463 = 7463; b.value7464 = 7464; b.value7465 = 7465; b.value7466 = 7466; b.value7467 = 7467; b.value7468 = 7468; b.value7469 = 7469; b.value7470 = 7470; b.value7471 = 7471; b.value7472 = 7472; b.value7473 = 7473; b.value7474 = 7474; b.value7475 = 7475; b.value7476 = 7476; b.value7477 = 7477; b.value7478 = 7478; b.value7479 = 7479; b.value7480 = 7480; b.value7481 = 7481; b.value7482 = 7482; b.value7483 = 7483; b.value7484 = 7484; b.value7485 = 7485; b.value7486 = 7486; b.value7487 = 7487; b.value7488 = 7488; b.value7489 = 7489; b.value7490 = 7490; b.value7491 = 7491; b.value7492 = 7492; b.value7493 = 7493; b.value7494 = 7494; b.value7495 = 7495; b.value7496 = 7496; b.value7497 = 7497; b.value7498 = 7498; b.value7499 = 7499; b.value7500 = 7500; b.value7501 = 7501; b.value7502 = 7502; b.value7503 = 7503; b.value7504 = 7504; b.value7505 = 7505; b.value7506 = 7506; b.value7507 = 7507; b.value7508 = 7508; b.value7509 = 7509; b.value7510 = 7510; b.value7511 = 7511; b.value7512 = 7512; b.value7513 = 7513; b.value7514 = 7514; b.value7515 = 7515; b.value7516 = 7516; b.value7517 = 7517; b.value7518 = 7518; b.value7519 = 7519; b.value7520 = 7520; b.value7521 = 7521; b.value7522 = 7522; b.value7523 = 7523; b.value7524 = 7524; b.value7525 = 7525; b.value7526 = 7526; b.value7527 = 7527; b.value7528 = 7528; b.value7529 = 7529; b.value7530 = 7530; b.value7531 = 7531; b.value7532 = 7532; b.value7533 = 7533; b.value7534 = 7534; b.value7535 = 7535; b.value7536 = 7536; b.value7537 = 7537; b.value7538 = 7538; b.value7539 = 7539; b.value7540 = 7540; b.value7541 = 7541; b.value7542 = 7542; b.value7543 = 7543; b.value7544 = 7544; b.value7545 = 7545; b.value7546 = 7546; b.value7547 = 7547; b.value7548 = 7548; b.value7549 = 7549; b.value7550 = 7550; b.value7551 = 7551; b.value7552 = 7552; b.value7553 = 7553; b.value7554 = 7554; b.value7555 = 7555; b.value7556 = 7556; b.value7557 = 7557; b.value7558 = 7558; b.value7559 = 7559; b.value7560 = 7560; b.value7561 = 7561; b.value7562 = 7562; b.value7563 = 7563; b.value7564 = 7564; b.value7565 = 7565; b.value7566 = 7566; b.value7567 = 7567; b.value7568 = 7568; b.value7569 = 7569; b.value7570 = 7570; b.value7571 = 7571; b.value7572 = 7572; b.value7573 = 7573; b.value7574 = 7574; b.value7575 = 7575; b.value7576 = 7576; b.value7577 = 7577; b.value7578 = 7578; b.value7579 = 7579; b.value7580 = 7580; b.value7581 = 7581; b.value7582 = 7582; b.value7583 = 7583; b.value7584 = 7584; b.value7585 = 7585; b.value7586 = 7586; b.value7587 = 7587; b.value7588 = 7588; b.value7589 = 7589; b.value7590 = 7590; b.value7591 = 7591; b.value7592 = 7592; b.value7593 = 7593; b.value7594 = 7594; b.value7595 = 7595; b.value7596 = 7596; b.value7597 = 7597; b.value7598 = 7598; b.value7599 = 7599; b.value7600 = 7600; b.value7601 = 7601; b.value7602 = 7602; b.value7603 = 7603; b.value7604 = 7604; b.value7605 = 7605; b.value7606 = 7606; b.value7607 = 7607; b.value7608 = 7608; b.value7609 = 7609; b.value7610 = 7610; b.value7611 = 7611; b.value7612 = 7612; b.value7613 = 7613; b.value7614 = 7614; b.value7615 = 7615; b.value7616 = 7616; b.value7617 = 7617; b.value7618 = 7618; b.value7619 = 7619; b.value7620 = 7620; b.value7621 = 7621; b.value7622 = 7622; b.value7623 = 7623; b.value7624 = 7624; b.value7625 = 7625; b.value7626 = 7626; b.value7627 = 7627; b.value7628 = 7628; b.value7629 = 7629; b.value7630 = 7630; b.value7631 = 7631; b.value7632 = 7632; b.value7633 = 7633; b.value7634 = 7634; b.value7635 = 7635; b.value7636 = 7636; b.value7637 = 7637; b.value7638 = 7638; b.value7639 = 7639; b.value7640 = 7640; b.value7641 = 7641; b.value7642 = 7642; b.value7643 = 7643; b.value7644 = 7644; b.value7645 = 7645; b.value7646 = 7646; b.value7647 = 7647; b.value7648 = 7648; b.value7649 = 7649; b.value7650 = 7650; b.value7651 = 7651; b.value7652 = 7652; b.value7653 = 7653; b.value7654 = 7654; b.value7655 = 7655; b.value7656 = 7656; b.value7657 = 7657; b.value7658 = 7658; b.value7659 = 7659; b.value7660 = 7660; b.value7661 = 7661; b.value7662 = 7662; b.value7663 = 7663; b.value7664 = 7664; b.value7665 = 7665; b.value7666 = 7666; b.value7667 = 7667; b.value7668 = 7668; b.value7669 = 7669; b.value7670 = 7670; b.value7671 = 7671; b.value7672 = 7672; b.value7673 = 7673; b.value7674 = 7674; b.value7675 = 7675; b.value7676 = 7676; b.value7677 = 7677; b.value7678 = 7678; b.value7679 = 7679; b.value7680 = 7680; b.value7681 = 7681; b.value7682 = 7682; b.value7683 = 7683; b.value7684 = 7684; b.value7685 = 7685; b.value7686 = 7686; b.value7687 = 7687; b.value7688 = 7688; b.value7689 = 7689; b.value7690 = 7690; b.value7691 = 7691; b.value7692 = 7692; b.value7693 = 7693; b.value7694 = 7694; b.value7695 = 7695; b.value7696 = 7696; b.value7697 = 7697; b.value7698 = 7698; b.value7699 = 7699; b.value7700 = 7700; b.value7701 = 7701; b.value7702 = 7702; b.value7703 = 7703; b.value7704 = 7704; b.value7705 = 7705; b.value7706 = 7706; b.value7707 = 7707; b.value7708 = 7708; b.value7709 = 7709; b.value7710 = 7710; b.value7711 = 7711; b.value7712 = 7712; b.value7713 = 7713; b.value7714 = 7714; b.value7715 = 7715; b.value7716 = 7716; b.value7717 = 7717; b.value7718 = 7718; b.value7719 = 7719; b.value7720 = 7720; b.value7721 = 7721; b.value7722 = 7722; b.value7723 = 7723; b.value7724 = 7724; b.value7725 = 7725; b.value7726 = 7726; b.value7727 = 7727; b.value7728 = 7728; b.value7729 = 7729; b.value7730 = 7730; b.value7731 = 7731; b.value7732 = 7732; b.value7733 = 7733; b.value7734 = 7734; b.value7735 = 7735; b.value7736 = 7736; b.value7737 = 7737; b.value7738 = 7738; b.value7739 = 7739; b.value7740 = 7740; b.value7741 = 7741; b.value7742 = 7742; b.value7743 = 7743; b.value7744 = 7744; b.value7745 = 7745; b.value7746 = 7746; b.value7747 = 7747; b.value7748 = 7748; b.value7749 = 7749; b.value7750 = 7750; b.value7751 = 7751; b.value7752 = 7752; b.value7753 = 7753; b.value7754 = 7754; b.value7755 = 7755; b.value7756 = 7756; b.value7757 = 7757; b.value7758 = 7758; b.value7759 = 7759; b.value7760 = 7760; b.value7761 = 7761; b.value7762 = 7762; b.value7763 = 7763; b.value7764 = 7764; b.value7765 = 7765; b.value7766 = 7766; b.value7767 = 7767; b.value7768 = 7768; b.value7769 = 7769; b.value7770 = 7770; b.value7771 = 7771; b.value7772 = 7772; b.value7773 = 7773; b.value7774 = 7774; b.value7775 = 7775; b.value7776 = 7776; b.value7777 = 7777; this.b = b; } # no need for teardown since we recreate the list each time func test() { for i in 0.to(50) { val b = this.b; foo(b.value0); foo(b.value1); foo(b.value2); foo(b.value3); foo(b.value4); foo(b.value5); foo(b.value6); foo(b.value7); foo(b.value8); foo(b.value9); foo(b.value10); foo(b.value11); foo(b.value12); foo(b.value13); foo(b.value14); foo(b.value15); foo(b.value16); foo(b.value17); foo(b.value18); foo(b.value19); foo(b.value20); foo(b.value21); foo(b.value22); foo(b.value23); foo(b.value24); foo(b.value25); foo(b.value26); foo(b.value27); foo(b.value28); foo(b.value29); foo(b.value30); foo(b.value31); foo(b.value32); foo(b.value33); foo(b.value34); foo(b.value35); foo(b.value36); foo(b.value37); foo(b.value38); foo(b.value39); foo(b.value40); foo(b.value41); foo(b.value42); foo(b.value43); foo(b.value44); foo(b.value45); foo(b.value46); foo(b.value47); foo(b.value48); foo(b.value49); foo(b.value50); foo(b.value51); foo(b.value52); foo(b.value53); foo(b.value54); foo(b.value55); foo(b.value56); foo(b.value57); foo(b.value58); foo(b.value59); foo(b.value60); foo(b.value61); foo(b.value62); foo(b.value63); foo(b.value64); foo(b.value65); foo(b.value66); foo(b.value67); foo(b.value68); foo(b.value69); foo(b.value70); foo(b.value71); foo(b.value72); foo(b.value73); foo(b.value74); foo(b.value75); foo(b.value76); foo(b.value77); foo(b.value78); foo(b.value79); foo(b.value80); foo(b.value81); foo(b.value82); foo(b.value83); foo(b.value84); foo(b.value85); foo(b.value86); foo(b.value87); foo(b.value88); foo(b.value89); foo(b.value90); foo(b.value91); foo(b.value92); foo(b.value93); foo(b.value94); foo(b.value95); foo(b.value96); foo(b.value97); foo(b.value98); foo(b.value99); foo(b.value100); foo(b.value101); foo(b.value102); foo(b.value103); foo(b.value104); foo(b.value105); foo(b.value106); foo(b.value107); foo(b.value108); foo(b.value109); foo(b.value110); foo(b.value111); foo(b.value112); foo(b.value113); foo(b.value114); foo(b.value115); foo(b.value116); foo(b.value117); foo(b.value118); foo(b.value119); foo(b.value120); foo(b.value121); foo(b.value122); foo(b.value123); foo(b.value124); foo(b.value125); foo(b.value126); foo(b.value127); foo(b.value128); foo(b.value129); foo(b.value130); foo(b.value131); foo(b.value132); foo(b.value133); foo(b.value134); foo(b.value135); foo(b.value136); foo(b.value137); foo(b.value138); foo(b.value139); foo(b.value140); foo(b.value141); foo(b.value142); foo(b.value143); foo(b.value144); foo(b.value145); foo(b.value146); foo(b.value147); foo(b.value148); foo(b.value149); foo(b.value150); foo(b.value151); foo(b.value152); foo(b.value153); foo(b.value154); foo(b.value155); foo(b.value156); foo(b.value157); foo(b.value158); foo(b.value159); foo(b.value160); foo(b.value161); foo(b.value162); foo(b.value163); foo(b.value164); foo(b.value165); foo(b.value166); foo(b.value167); foo(b.value168); foo(b.value169); foo(b.value170); foo(b.value171); foo(b.value172); foo(b.value173); foo(b.value174); foo(b.value175); foo(b.value176); foo(b.value177); foo(b.value178); foo(b.value179); foo(b.value180); foo(b.value181); foo(b.value182); foo(b.value183); foo(b.value184); foo(b.value185); foo(b.value186); foo(b.value187); foo(b.value188); foo(b.value189); foo(b.value190); foo(b.value191); foo(b.value192); foo(b.value193); foo(b.value194); foo(b.value195); foo(b.value196); foo(b.value197); foo(b.value198); foo(b.value199); foo(b.value200); foo(b.value201); foo(b.value202); foo(b.value203); foo(b.value204); foo(b.value205); foo(b.value206); foo(b.value207); foo(b.value208); foo(b.value209); foo(b.value210); foo(b.value211); foo(b.value212); foo(b.value213); foo(b.value214); foo(b.value215); foo(b.value216); foo(b.value217); foo(b.value218); foo(b.value219); foo(b.value220); foo(b.value221); foo(b.value222); foo(b.value223); foo(b.value224); foo(b.value225); foo(b.value226); foo(b.value227); foo(b.value228); foo(b.value229); foo(b.value230); foo(b.value231); foo(b.value232); foo(b.value233); foo(b.value234); foo(b.value235); foo(b.value236); foo(b.value237); foo(b.value238); foo(b.value239); foo(b.value240); foo(b.value241); foo(b.value242); foo(b.value243); foo(b.value244); foo(b.value245); foo(b.value246); foo(b.value247); foo(b.value248); foo(b.value249); foo(b.value250); foo(b.value251); foo(b.value252); foo(b.value253); foo(b.value254); foo(b.value255); foo(b.value256); foo(b.value257); foo(b.value258); foo(b.value259); foo(b.value260); foo(b.value261); foo(b.value262); foo(b.value263); foo(b.value264); foo(b.value265); foo(b.value266); foo(b.value267); foo(b.value268); foo(b.value269); foo(b.value270); foo(b.value271); foo(b.value272); foo(b.value273); foo(b.value274); foo(b.value275); foo(b.value276); foo(b.value277); foo(b.value278); foo(b.value279); foo(b.value280); foo(b.value281); foo(b.value282); foo(b.value283); foo(b.value284); foo(b.value285); foo(b.value286); foo(b.value287); foo(b.value288); foo(b.value289); foo(b.value290); foo(b.value291); foo(b.value292); foo(b.value293); foo(b.value294); foo(b.value295); foo(b.value296); foo(b.value297); foo(b.value298); foo(b.value299); foo(b.value300); foo(b.value301); foo(b.value302); foo(b.value303); foo(b.value304); foo(b.value305); foo(b.value306); foo(b.value307); foo(b.value308); foo(b.value309); foo(b.value310); foo(b.value311); foo(b.value312); foo(b.value313); foo(b.value314); foo(b.value315); foo(b.value316); foo(b.value317); foo(b.value318); foo(b.value319); foo(b.value320); foo(b.value321); foo(b.value322); foo(b.value323); foo(b.value324); foo(b.value325); foo(b.value326); foo(b.value327); foo(b.value328); foo(b.value329); foo(b.value330); foo(b.value331); foo(b.value332); foo(b.value333); foo(b.value334); foo(b.value335); foo(b.value336); foo(b.value337); foo(b.value338); foo(b.value339); foo(b.value340); foo(b.value341); foo(b.value342); foo(b.value343); foo(b.value344); foo(b.value345); foo(b.value346); foo(b.value347); foo(b.value348); foo(b.value349); foo(b.value350); foo(b.value351); foo(b.value352); foo(b.value353); foo(b.value354); foo(b.value355); foo(b.value356); foo(b.value357); foo(b.value358); foo(b.value359); foo(b.value360); foo(b.value361); foo(b.value362); foo(b.value363); foo(b.value364); foo(b.value365); foo(b.value366); foo(b.value367); foo(b.value368); foo(b.value369); foo(b.value370); foo(b.value371); foo(b.value372); foo(b.value373); foo(b.value374); foo(b.value375); foo(b.value376); foo(b.value377); foo(b.value378); foo(b.value379); foo(b.value380); foo(b.value381); foo(b.value382); foo(b.value383); foo(b.value384); foo(b.value385); foo(b.value386); foo(b.value387); foo(b.value388); foo(b.value389); foo(b.value390); foo(b.value391); foo(b.value392); foo(b.value393); foo(b.value394); foo(b.value395); foo(b.value396); foo(b.value397); foo(b.value398); foo(b.value399); foo(b.value400); foo(b.value401); foo(b.value402); foo(b.value403); foo(b.value404); foo(b.value405); foo(b.value406); foo(b.value407); foo(b.value408); foo(b.value409); foo(b.value410); foo(b.value411); foo(b.value412); foo(b.value413); foo(b.value414); foo(b.value415); foo(b.value416); foo(b.value417); foo(b.value418); foo(b.value419); foo(b.value420); foo(b.value421); foo(b.value422); foo(b.value423); foo(b.value424); foo(b.value425); foo(b.value426); foo(b.value427); foo(b.value428); foo(b.value429); foo(b.value430); foo(b.value431); foo(b.value432); foo(b.value433); foo(b.value434); foo(b.value435); foo(b.value436); foo(b.value437); foo(b.value438); foo(b.value439); foo(b.value440); foo(b.value441); foo(b.value442); foo(b.value443); foo(b.value444); foo(b.value445); foo(b.value446); foo(b.value447); foo(b.value448); foo(b.value449); foo(b.value450); foo(b.value451); foo(b.value452); foo(b.value453); foo(b.value454); foo(b.value455); foo(b.value456); foo(b.value457); foo(b.value458); foo(b.value459); foo(b.value460); foo(b.value461); foo(b.value462); foo(b.value463); foo(b.value464); foo(b.value465); foo(b.value466); foo(b.value467); foo(b.value468); foo(b.value469); foo(b.value470); foo(b.value471); foo(b.value472); foo(b.value473); foo(b.value474); foo(b.value475); foo(b.value476); foo(b.value477); foo(b.value478); foo(b.value479); foo(b.value480); foo(b.value481); foo(b.value482); foo(b.value483); foo(b.value484); foo(b.value485); foo(b.value486); foo(b.value487); foo(b.value488); foo(b.value489); foo(b.value490); foo(b.value491); foo(b.value492); foo(b.value493); foo(b.value494); foo(b.value495); foo(b.value496); foo(b.value497); foo(b.value498); foo(b.value499); foo(b.value500); foo(b.value501); foo(b.value502); foo(b.value503); foo(b.value504); foo(b.value505); foo(b.value506); foo(b.value507); foo(b.value508); foo(b.value509); foo(b.value510); foo(b.value511); foo(b.value512); foo(b.value513); foo(b.value514); foo(b.value515); foo(b.value516); foo(b.value517); foo(b.value518); foo(b.value519); foo(b.value520); foo(b.value521); foo(b.value522); foo(b.value523); foo(b.value524); foo(b.value525); foo(b.value526); foo(b.value527); foo(b.value528); foo(b.value529); foo(b.value530); foo(b.value531); foo(b.value532); foo(b.value533); foo(b.value534); foo(b.value535); foo(b.value536); foo(b.value537); foo(b.value538); foo(b.value539); foo(b.value540); foo(b.value541); foo(b.value542); foo(b.value543); foo(b.value544); foo(b.value545); foo(b.value546); foo(b.value547); foo(b.value548); foo(b.value549); foo(b.value550); foo(b.value551); foo(b.value552); foo(b.value553); foo(b.value554); foo(b.value555); foo(b.value556); foo(b.value557); foo(b.value558); foo(b.value559); foo(b.value560); foo(b.value561); foo(b.value562); foo(b.value563); foo(b.value564); foo(b.value565); foo(b.value566); foo(b.value567); foo(b.value568); foo(b.value569); foo(b.value570); foo(b.value571); foo(b.value572); foo(b.value573); foo(b.value574); foo(b.value575); foo(b.value576); foo(b.value577); foo(b.value578); foo(b.value579); foo(b.value580); foo(b.value581); foo(b.value582); foo(b.value583); foo(b.value584); foo(b.value585); foo(b.value586); foo(b.value587); foo(b.value588); foo(b.value589); foo(b.value590); foo(b.value591); foo(b.value592); foo(b.value593); foo(b.value594); foo(b.value595); foo(b.value596); foo(b.value597); foo(b.value598); foo(b.value599); foo(b.value600); foo(b.value601); foo(b.value602); foo(b.value603); foo(b.value604); foo(b.value605); foo(b.value606); foo(b.value607); foo(b.value608); foo(b.value609); foo(b.value610); foo(b.value611); foo(b.value612); foo(b.value613); foo(b.value614); foo(b.value615); foo(b.value616); foo(b.value617); foo(b.value618); foo(b.value619); foo(b.value620); foo(b.value621); foo(b.value622); foo(b.value623); foo(b.value624); foo(b.value625); foo(b.value626); foo(b.value627); foo(b.value628); foo(b.value629); foo(b.value630); foo(b.value631); foo(b.value632); foo(b.value633); foo(b.value634); foo(b.value635); foo(b.value636); foo(b.value637); foo(b.value638); foo(b.value639); foo(b.value640); foo(b.value641); foo(b.value642); foo(b.value643); foo(b.value644); foo(b.value645); foo(b.value646); foo(b.value647); foo(b.value648); foo(b.value649); foo(b.value650); foo(b.value651); foo(b.value652); foo(b.value653); foo(b.value654); foo(b.value655); foo(b.value656); foo(b.value657); foo(b.value658); foo(b.value659); foo(b.value660); foo(b.value661); foo(b.value662); foo(b.value663); foo(b.value664); foo(b.value665); foo(b.value666); foo(b.value667); foo(b.value668); foo(b.value669); foo(b.value670); foo(b.value671); foo(b.value672); foo(b.value673); foo(b.value674); foo(b.value675); foo(b.value676); foo(b.value677); foo(b.value678); foo(b.value679); foo(b.value680); foo(b.value681); foo(b.value682); foo(b.value683); foo(b.value684); foo(b.value685); foo(b.value686); foo(b.value687); foo(b.value688); foo(b.value689); foo(b.value690); foo(b.value691); foo(b.value692); foo(b.value693); foo(b.value694); foo(b.value695); foo(b.value696); foo(b.value697); foo(b.value698); foo(b.value699); foo(b.value700); foo(b.value701); foo(b.value702); foo(b.value703); foo(b.value704); foo(b.value705); foo(b.value706); foo(b.value707); foo(b.value708); foo(b.value709); foo(b.value710); foo(b.value711); foo(b.value712); foo(b.value713); foo(b.value714); foo(b.value715); foo(b.value716); foo(b.value717); foo(b.value718); foo(b.value719); foo(b.value720); foo(b.value721); foo(b.value722); foo(b.value723); foo(b.value724); foo(b.value725); foo(b.value726); foo(b.value727); foo(b.value728); foo(b.value729); foo(b.value730); foo(b.value731); foo(b.value732); foo(b.value733); foo(b.value734); foo(b.value735); foo(b.value736); foo(b.value737); foo(b.value738); foo(b.value739); foo(b.value740); foo(b.value741); foo(b.value742); foo(b.value743); foo(b.value744); foo(b.value745); foo(b.value746); foo(b.value747); foo(b.value748); foo(b.value749); foo(b.value750); foo(b.value751); foo(b.value752); foo(b.value753); foo(b.value754); foo(b.value755); foo(b.value756); foo(b.value757); foo(b.value758); foo(b.value759); foo(b.value760); foo(b.value761); foo(b.value762); foo(b.value763); foo(b.value764); foo(b.value765); foo(b.value766); foo(b.value767); foo(b.value768); foo(b.value769); foo(b.value770); foo(b.value771); foo(b.value772); foo(b.value773); foo(b.value774); foo(b.value775); foo(b.value776); foo(b.value777); foo(b.value778); foo(b.value779); foo(b.value780); foo(b.value781); foo(b.value782); foo(b.value783); foo(b.value784); foo(b.value785); foo(b.value786); foo(b.value787); foo(b.value788); foo(b.value789); foo(b.value790); foo(b.value791); foo(b.value792); foo(b.value793); foo(b.value794); foo(b.value795); foo(b.value796); foo(b.value797); foo(b.value798); foo(b.value799); foo(b.value800); foo(b.value801); foo(b.value802); foo(b.value803); foo(b.value804); foo(b.value805); foo(b.value806); foo(b.value807); foo(b.value808); foo(b.value809); foo(b.value810); foo(b.value811); foo(b.value812); foo(b.value813); foo(b.value814); foo(b.value815); foo(b.value816); foo(b.value817); foo(b.value818); foo(b.value819); foo(b.value820); foo(b.value821); foo(b.value822); foo(b.value823); foo(b.value824); foo(b.value825); foo(b.value826); foo(b.value827); foo(b.value828); foo(b.value829); foo(b.value830); foo(b.value831); foo(b.value832); foo(b.value833); foo(b.value834); foo(b.value835); foo(b.value836); foo(b.value837); foo(b.value838); foo(b.value839); foo(b.value840); foo(b.value841); foo(b.value842); foo(b.value843); foo(b.value844); foo(b.value845); foo(b.value846); foo(b.value847); foo(b.value848); foo(b.value849); foo(b.value850); foo(b.value851); foo(b.value852); foo(b.value853); foo(b.value854); foo(b.value855); foo(b.value856); foo(b.value857); foo(b.value858); foo(b.value859); foo(b.value860); foo(b.value861); foo(b.value862); foo(b.value863); foo(b.value864); foo(b.value865); foo(b.value866); foo(b.value867); foo(b.value868); foo(b.value869); foo(b.value870); foo(b.value871); foo(b.value872); foo(b.value873); foo(b.value874); foo(b.value875); foo(b.value876); foo(b.value877); foo(b.value878); foo(b.value879); foo(b.value880); foo(b.value881); foo(b.value882); foo(b.value883); foo(b.value884); foo(b.value885); foo(b.value886); foo(b.value887); foo(b.value888); foo(b.value889); foo(b.value890); foo(b.value891); foo(b.value892); foo(b.value893); foo(b.value894); foo(b.value895); foo(b.value896); foo(b.value897); foo(b.value898); foo(b.value899); foo(b.value900); foo(b.value901); foo(b.value902); foo(b.value903); foo(b.value904); foo(b.value905); foo(b.value906); foo(b.value907); foo(b.value908); foo(b.value909); foo(b.value910); foo(b.value911); foo(b.value912); foo(b.value913); foo(b.value914); foo(b.value915); foo(b.value916); foo(b.value917); foo(b.value918); foo(b.value919); foo(b.value920); foo(b.value921); foo(b.value922); foo(b.value923); foo(b.value924); foo(b.value925); foo(b.value926); foo(b.value927); foo(b.value928); foo(b.value929); foo(b.value930); foo(b.value931); foo(b.value932); foo(b.value933); foo(b.value934); foo(b.value935); foo(b.value936); foo(b.value937); foo(b.value938); foo(b.value939); foo(b.value940); foo(b.value941); foo(b.value942); foo(b.value943); foo(b.value944); foo(b.value945); foo(b.value946); foo(b.value947); foo(b.value948); foo(b.value949); foo(b.value950); foo(b.value951); foo(b.value952); foo(b.value953); foo(b.value954); foo(b.value955); foo(b.value956); foo(b.value957); foo(b.value958); foo(b.value959); foo(b.value960); foo(b.value961); foo(b.value962); foo(b.value963); foo(b.value964); foo(b.value965); foo(b.value966); foo(b.value967); foo(b.value968); foo(b.value969); foo(b.value970); foo(b.value971); foo(b.value972); foo(b.value973); foo(b.value974); foo(b.value975); foo(b.value976); foo(b.value977); foo(b.value978); foo(b.value979); foo(b.value980); foo(b.value981); foo(b.value982); foo(b.value983); foo(b.value984); foo(b.value985); foo(b.value986); foo(b.value987); foo(b.value988); foo(b.value989); foo(b.value990); foo(b.value991); foo(b.value992); foo(b.value993); foo(b.value994); foo(b.value995); foo(b.value996); foo(b.value997); foo(b.value998); foo(b.value999); foo(b.value1000); foo(b.value1001); foo(b.value1002); foo(b.value1003); foo(b.value1004); foo(b.value1005); foo(b.value1006); foo(b.value1007); foo(b.value1008); foo(b.value1009); foo(b.value1010); foo(b.value1011); foo(b.value1012); foo(b.value1013); foo(b.value1014); foo(b.value1015); foo(b.value1016); foo(b.value1017); foo(b.value1018); foo(b.value1019); foo(b.value1020); foo(b.value1021); foo(b.value1022); foo(b.value1023); foo(b.value1024); foo(b.value1025); foo(b.value1026); foo(b.value1027); foo(b.value1028); foo(b.value1029); foo(b.value1030); foo(b.value1031); foo(b.value1032); foo(b.value1033); foo(b.value1034); foo(b.value1035); foo(b.value1036); foo(b.value1037); foo(b.value1038); foo(b.value1039); foo(b.value1040); foo(b.value1041); foo(b.value1042); foo(b.value1043); foo(b.value1044); foo(b.value1045); foo(b.value1046); foo(b.value1047); foo(b.value1048); foo(b.value1049); foo(b.value1050); foo(b.value1051); foo(b.value1052); foo(b.value1053); foo(b.value1054); foo(b.value1055); foo(b.value1056); foo(b.value1057); foo(b.value1058); foo(b.value1059); foo(b.value1060); foo(b.value1061); foo(b.value1062); foo(b.value1063); foo(b.value1064); foo(b.value1065); foo(b.value1066); foo(b.value1067); foo(b.value1068); foo(b.value1069); foo(b.value1070); foo(b.value1071); foo(b.value1072); foo(b.value1073); foo(b.value1074); foo(b.value1075); foo(b.value1076); foo(b.value1077); foo(b.value1078); foo(b.value1079); foo(b.value1080); foo(b.value1081); foo(b.value1082); foo(b.value1083); foo(b.value1084); foo(b.value1085); foo(b.value1086); foo(b.value1087); foo(b.value1088); foo(b.value1089); foo(b.value1090); foo(b.value1091); foo(b.value1092); foo(b.value1093); foo(b.value1094); foo(b.value1095); foo(b.value1096); foo(b.value1097); foo(b.value1098); foo(b.value1099); foo(b.value1100); foo(b.value1101); foo(b.value1102); foo(b.value1103); foo(b.value1104); foo(b.value1105); foo(b.value1106); foo(b.value1107); foo(b.value1108); foo(b.value1109); foo(b.value1110); foo(b.value1111); foo(b.value1112); foo(b.value1113); foo(b.value1114); foo(b.value1115); foo(b.value1116); foo(b.value1117); foo(b.value1118); foo(b.value1119); foo(b.value1120); foo(b.value1121); foo(b.value1122); foo(b.value1123); foo(b.value1124); foo(b.value1125); foo(b.value1126); foo(b.value1127); foo(b.value1128); foo(b.value1129); foo(b.value1130); foo(b.value1131); foo(b.value1132); foo(b.value1133); foo(b.value1134); foo(b.value1135); foo(b.value1136); foo(b.value1137); foo(b.value1138); foo(b.value1139); foo(b.value1140); foo(b.value1141); foo(b.value1142); foo(b.value1143); foo(b.value1144); foo(b.value1145); foo(b.value1146); foo(b.value1147); foo(b.value1148); foo(b.value1149); foo(b.value1150); foo(b.value1151); foo(b.value1152); foo(b.value1153); foo(b.value1154); foo(b.value1155); foo(b.value1156); foo(b.value1157); foo(b.value1158); foo(b.value1159); foo(b.value1160); foo(b.value1161); foo(b.value1162); foo(b.value1163); foo(b.value1164); foo(b.value1165); foo(b.value1166); foo(b.value1167); foo(b.value1168); foo(b.value1169); foo(b.value1170); foo(b.value1171); foo(b.value1172); foo(b.value1173); foo(b.value1174); foo(b.value1175); foo(b.value1176); foo(b.value1177); foo(b.value1178); foo(b.value1179); foo(b.value1180); foo(b.value1181); foo(b.value1182); foo(b.value1183); foo(b.value1184); foo(b.value1185); foo(b.value1186); foo(b.value1187); foo(b.value1188); foo(b.value1189); foo(b.value1190); foo(b.value1191); foo(b.value1192); foo(b.value1193); foo(b.value1194); foo(b.value1195); foo(b.value1196); foo(b.value1197); foo(b.value1198); foo(b.value1199); foo(b.value1200); foo(b.value1201); foo(b.value1202); foo(b.value1203); foo(b.value1204); foo(b.value1205); foo(b.value1206); foo(b.value1207); foo(b.value1208); foo(b.value1209); foo(b.value1210); foo(b.value1211); foo(b.value1212); foo(b.value1213); foo(b.value1214); foo(b.value1215); foo(b.value1216); foo(b.value1217); foo(b.value1218); foo(b.value1219); foo(b.value1220); foo(b.value1221); foo(b.value1222); foo(b.value1223); foo(b.value1224); foo(b.value1225); foo(b.value1226); foo(b.value1227); foo(b.value1228); foo(b.value1229); foo(b.value1230); foo(b.value1231); foo(b.value1232); foo(b.value1233); foo(b.value1234); foo(b.value1235); foo(b.value1236); foo(b.value1237); foo(b.value1238); foo(b.value1239); foo(b.value1240); foo(b.value1241); foo(b.value1242); foo(b.value1243); foo(b.value1244); foo(b.value1245); foo(b.value1246); foo(b.value1247); foo(b.value1248); foo(b.value1249); foo(b.value1250); foo(b.value1251); foo(b.value1252); foo(b.value1253); foo(b.value1254); foo(b.value1255); foo(b.value1256); foo(b.value1257); foo(b.value1258); foo(b.value1259); foo(b.value1260); foo(b.value1261); foo(b.value1262); foo(b.value1263); foo(b.value1264); foo(b.value1265); foo(b.value1266); foo(b.value1267); foo(b.value1268); foo(b.value1269); foo(b.value1270); foo(b.value1271); foo(b.value1272); foo(b.value1273); foo(b.value1274); foo(b.value1275); foo(b.value1276); foo(b.value1277); foo(b.value1278); foo(b.value1279); foo(b.value1280); foo(b.value1281); foo(b.value1282); foo(b.value1283); foo(b.value1284); foo(b.value1285); foo(b.value1286); foo(b.value1287); foo(b.value1288); foo(b.value1289); foo(b.value1290); foo(b.value1291); foo(b.value1292); foo(b.value1293); foo(b.value1294); foo(b.value1295); foo(b.value1296); foo(b.value1297); foo(b.value1298); foo(b.value1299); foo(b.value1300); foo(b.value1301); foo(b.value1302); foo(b.value1303); foo(b.value1304); foo(b.value1305); foo(b.value1306); foo(b.value1307); foo(b.value1308); foo(b.value1309); foo(b.value1310); foo(b.value1311); foo(b.value1312); foo(b.value1313); foo(b.value1314); foo(b.value1315); foo(b.value1316); foo(b.value1317); foo(b.value1318); foo(b.value1319); foo(b.value1320); foo(b.value1321); foo(b.value1322); foo(b.value1323); foo(b.value1324); foo(b.value1325); foo(b.value1326); foo(b.value1327); foo(b.value1328); foo(b.value1329); foo(b.value1330); foo(b.value1331); foo(b.value1332); foo(b.value1333); foo(b.value1334); foo(b.value1335); foo(b.value1336); foo(b.value1337); foo(b.value1338); foo(b.value1339); foo(b.value1340); foo(b.value1341); foo(b.value1342); foo(b.value1343); foo(b.value1344); foo(b.value1345); foo(b.value1346); foo(b.value1347); foo(b.value1348); foo(b.value1349); foo(b.value1350); foo(b.value1351); foo(b.value1352); foo(b.value1353); foo(b.value1354); foo(b.value1355); foo(b.value1356); foo(b.value1357); foo(b.value1358); foo(b.value1359); foo(b.value1360); foo(b.value1361); foo(b.value1362); foo(b.value1363); foo(b.value1364); foo(b.value1365); foo(b.value1366); foo(b.value1367); foo(b.value1368); foo(b.value1369); foo(b.value1370); foo(b.value1371); foo(b.value1372); foo(b.value1373); foo(b.value1374); foo(b.value1375); foo(b.value1376); foo(b.value1377); foo(b.value1378); foo(b.value1379); foo(b.value1380); foo(b.value1381); foo(b.value1382); foo(b.value1383); foo(b.value1384); foo(b.value1385); foo(b.value1386); foo(b.value1387); foo(b.value1388); foo(b.value1389); foo(b.value1390); foo(b.value1391); foo(b.value1392); foo(b.value1393); foo(b.value1394); foo(b.value1395); foo(b.value1396); foo(b.value1397); foo(b.value1398); foo(b.value1399); foo(b.value1400); foo(b.value1401); foo(b.value1402); foo(b.value1403); foo(b.value1404); foo(b.value1405); foo(b.value1406); foo(b.value1407); foo(b.value1408); foo(b.value1409); foo(b.value1410); foo(b.value1411); foo(b.value1412); foo(b.value1413); foo(b.value1414); foo(b.value1415); foo(b.value1416); foo(b.value1417); foo(b.value1418); foo(b.value1419); foo(b.value1420); foo(b.value1421); foo(b.value1422); foo(b.value1423); foo(b.value1424); foo(b.value1425); foo(b.value1426); foo(b.value1427); foo(b.value1428); foo(b.value1429); foo(b.value1430); foo(b.value1431); foo(b.value1432); foo(b.value1433); foo(b.value1434); foo(b.value1435); foo(b.value1436); foo(b.value1437); foo(b.value1438); foo(b.value1439); foo(b.value1440); foo(b.value1441); foo(b.value1442); foo(b.value1443); foo(b.value1444); foo(b.value1445); foo(b.value1446); foo(b.value1447); foo(b.value1448); foo(b.value1449); foo(b.value1450); foo(b.value1451); foo(b.value1452); foo(b.value1453); foo(b.value1454); foo(b.value1455); foo(b.value1456); foo(b.value1457); foo(b.value1458); foo(b.value1459); foo(b.value1460); foo(b.value1461); foo(b.value1462); foo(b.value1463); foo(b.value1464); foo(b.value1465); foo(b.value1466); foo(b.value1467); foo(b.value1468); foo(b.value1469); foo(b.value1470); foo(b.value1471); foo(b.value1472); foo(b.value1473); foo(b.value1474); foo(b.value1475); foo(b.value1476); foo(b.value1477); foo(b.value1478); foo(b.value1479); foo(b.value1480); foo(b.value1481); foo(b.value1482); foo(b.value1483); foo(b.value1484); foo(b.value1485); foo(b.value1486); foo(b.value1487); foo(b.value1488); foo(b.value1489); foo(b.value1490); foo(b.value1491); foo(b.value1492); foo(b.value1493); foo(b.value1494); foo(b.value1495); foo(b.value1496); foo(b.value1497); foo(b.value1498); foo(b.value1499); foo(b.value1500); foo(b.value1501); foo(b.value1502); foo(b.value1503); foo(b.value1504); foo(b.value1505); foo(b.value1506); foo(b.value1507); foo(b.value1508); foo(b.value1509); foo(b.value1510); foo(b.value1511); foo(b.value1512); foo(b.value1513); foo(b.value1514); foo(b.value1515); foo(b.value1516); foo(b.value1517); foo(b.value1518); foo(b.value1519); foo(b.value1520); foo(b.value1521); foo(b.value1522); foo(b.value1523); foo(b.value1524); foo(b.value1525); foo(b.value1526); foo(b.value1527); foo(b.value1528); foo(b.value1529); foo(b.value1530); foo(b.value1531); foo(b.value1532); foo(b.value1533); foo(b.value1534); foo(b.value1535); foo(b.value1536); foo(b.value1537); foo(b.value1538); foo(b.value1539); foo(b.value1540); foo(b.value1541); foo(b.value1542); foo(b.value1543); foo(b.value1544); foo(b.value1545); foo(b.value1546); foo(b.value1547); foo(b.value1548); foo(b.value1549); foo(b.value1550); foo(b.value1551); foo(b.value1552); foo(b.value1553); foo(b.value1554); foo(b.value1555); foo(b.value1556); foo(b.value1557); foo(b.value1558); foo(b.value1559); foo(b.value1560); foo(b.value1561); foo(b.value1562); foo(b.value1563); foo(b.value1564); foo(b.value1565); foo(b.value1566); foo(b.value1567); foo(b.value1568); foo(b.value1569); foo(b.value1570); foo(b.value1571); foo(b.value1572); foo(b.value1573); foo(b.value1574); foo(b.value1575); foo(b.value1576); foo(b.value1577); foo(b.value1578); foo(b.value1579); foo(b.value1580); foo(b.value1581); foo(b.value1582); foo(b.value1583); foo(b.value1584); foo(b.value1585); foo(b.value1586); foo(b.value1587); foo(b.value1588); foo(b.value1589); foo(b.value1590); foo(b.value1591); foo(b.value1592); foo(b.value1593); foo(b.value1594); foo(b.value1595); foo(b.value1596); foo(b.value1597); foo(b.value1598); foo(b.value1599); foo(b.value1600); foo(b.value1601); foo(b.value1602); foo(b.value1603); foo(b.value1604); foo(b.value1605); foo(b.value1606); foo(b.value1607); foo(b.value1608); foo(b.value1609); foo(b.value1610); foo(b.value1611); foo(b.value1612); foo(b.value1613); foo(b.value1614); foo(b.value1615); foo(b.value1616); foo(b.value1617); foo(b.value1618); foo(b.value1619); foo(b.value1620); foo(b.value1621); foo(b.value1622); foo(b.value1623); foo(b.value1624); foo(b.value1625); foo(b.value1626); foo(b.value1627); foo(b.value1628); foo(b.value1629); foo(b.value1630); foo(b.value1631); foo(b.value1632); foo(b.value1633); foo(b.value1634); foo(b.value1635); foo(b.value1636); foo(b.value1637); foo(b.value1638); foo(b.value1639); foo(b.value1640); foo(b.value1641); foo(b.value1642); foo(b.value1643); foo(b.value1644); foo(b.value1645); foo(b.value1646); foo(b.value1647); foo(b.value1648); foo(b.value1649); foo(b.value1650); foo(b.value1651); foo(b.value1652); foo(b.value1653); foo(b.value1654); foo(b.value1655); foo(b.value1656); foo(b.value1657); foo(b.value1658); foo(b.value1659); foo(b.value1660); foo(b.value1661); foo(b.value1662); foo(b.value1663); foo(b.value1664); foo(b.value1665); foo(b.value1666); foo(b.value1667); foo(b.value1668); foo(b.value1669); foo(b.value1670); foo(b.value1671); foo(b.value1672); foo(b.value1673); foo(b.value1674); foo(b.value1675); foo(b.value1676); foo(b.value1677); foo(b.value1678); foo(b.value1679); foo(b.value1680); foo(b.value1681); foo(b.value1682); foo(b.value1683); foo(b.value1684); foo(b.value1685); foo(b.value1686); foo(b.value1687); foo(b.value1688); foo(b.value1689); foo(b.value1690); foo(b.value1691); foo(b.value1692); foo(b.value1693); foo(b.value1694); foo(b.value1695); foo(b.value1696); foo(b.value1697); foo(b.value1698); foo(b.value1699); foo(b.value1700); foo(b.value1701); foo(b.value1702); foo(b.value1703); foo(b.value1704); foo(b.value1705); foo(b.value1706); foo(b.value1707); foo(b.value1708); foo(b.value1709); foo(b.value1710); foo(b.value1711); foo(b.value1712); foo(b.value1713); foo(b.value1714); foo(b.value1715); foo(b.value1716); foo(b.value1717); foo(b.value1718); foo(b.value1719); foo(b.value1720); foo(b.value1721); foo(b.value1722); foo(b.value1723); foo(b.value1724); foo(b.value1725); foo(b.value1726); foo(b.value1727); foo(b.value1728); foo(b.value1729); foo(b.value1730); foo(b.value1731); foo(b.value1732); foo(b.value1733); foo(b.value1734); foo(b.value1735); foo(b.value1736); foo(b.value1737); foo(b.value1738); foo(b.value1739); foo(b.value1740); foo(b.value1741); foo(b.value1742); foo(b.value1743); foo(b.value1744); foo(b.value1745); foo(b.value1746); foo(b.value1747); foo(b.value1748); foo(b.value1749); foo(b.value1750); foo(b.value1751); foo(b.value1752); foo(b.value1753); foo(b.value1754); foo(b.value1755); foo(b.value1756); foo(b.value1757); foo(b.value1758); foo(b.value1759); foo(b.value1760); foo(b.value1761); foo(b.value1762); foo(b.value1763); foo(b.value1764); foo(b.value1765); foo(b.value1766); foo(b.value1767); foo(b.value1768); foo(b.value1769); foo(b.value1770); foo(b.value1771); foo(b.value1772); foo(b.value1773); foo(b.value1774); foo(b.value1775); foo(b.value1776); foo(b.value1777); foo(b.value1778); foo(b.value1779); foo(b.value1780); foo(b.value1781); foo(b.value1782); foo(b.value1783); foo(b.value1784); foo(b.value1785); foo(b.value1786); foo(b.value1787); foo(b.value1788); foo(b.value1789); foo(b.value1790); foo(b.value1791); foo(b.value1792); foo(b.value1793); foo(b.value1794); foo(b.value1795); foo(b.value1796); foo(b.value1797); foo(b.value1798); foo(b.value1799); foo(b.value1800); foo(b.value1801); foo(b.value1802); foo(b.value1803); foo(b.value1804); foo(b.value1805); foo(b.value1806); foo(b.value1807); foo(b.value1808); foo(b.value1809); foo(b.value1810); foo(b.value1811); foo(b.value1812); foo(b.value1813); foo(b.value1814); foo(b.value1815); foo(b.value1816); foo(b.value1817); foo(b.value1818); foo(b.value1819); foo(b.value1820); foo(b.value1821); foo(b.value1822); foo(b.value1823); foo(b.value1824); foo(b.value1825); foo(b.value1826); foo(b.value1827); foo(b.value1828); foo(b.value1829); foo(b.value1830); foo(b.value1831); foo(b.value1832); foo(b.value1833); foo(b.value1834); foo(b.value1835); foo(b.value1836); foo(b.value1837); foo(b.value1838); foo(b.value1839); foo(b.value1840); foo(b.value1841); foo(b.value1842); foo(b.value1843); foo(b.value1844); foo(b.value1845); foo(b.value1846); foo(b.value1847); foo(b.value1848); foo(b.value1849); foo(b.value1850); foo(b.value1851); foo(b.value1852); foo(b.value1853); foo(b.value1854); foo(b.value1855); foo(b.value1856); foo(b.value1857); foo(b.value1858); foo(b.value1859); foo(b.value1860); foo(b.value1861); foo(b.value1862); foo(b.value1863); foo(b.value1864); foo(b.value1865); foo(b.value1866); foo(b.value1867); foo(b.value1868); foo(b.value1869); foo(b.value1870); foo(b.value1871); foo(b.value1872); foo(b.value1873); foo(b.value1874); foo(b.value1875); foo(b.value1876); foo(b.value1877); foo(b.value1878); foo(b.value1879); foo(b.value1880); foo(b.value1881); foo(b.value1882); foo(b.value1883); foo(b.value1884); foo(b.value1885); foo(b.value1886); foo(b.value1887); foo(b.value1888); foo(b.value1889); foo(b.value1890); foo(b.value1891); foo(b.value1892); foo(b.value1893); foo(b.value1894); foo(b.value1895); foo(b.value1896); foo(b.value1897); foo(b.value1898); foo(b.value1899); foo(b.value1900); foo(b.value1901); foo(b.value1902); foo(b.value1903); foo(b.value1904); foo(b.value1905); foo(b.value1906); foo(b.value1907); foo(b.value1908); foo(b.value1909); foo(b.value1910); foo(b.value1911); foo(b.value1912); foo(b.value1913); foo(b.value1914); foo(b.value1915); foo(b.value1916); foo(b.value1917); foo(b.value1918); foo(b.value1919); foo(b.value1920); foo(b.value1921); foo(b.value1922); foo(b.value1923); foo(b.value1924); foo(b.value1925); foo(b.value1926); foo(b.value1927); foo(b.value1928); foo(b.value1929); foo(b.value1930); foo(b.value1931); foo(b.value1932); foo(b.value1933); foo(b.value1934); foo(b.value1935); foo(b.value1936); foo(b.value1937); foo(b.value1938); foo(b.value1939); foo(b.value1940); foo(b.value1941); foo(b.value1942); foo(b.value1943); foo(b.value1944); foo(b.value1945); foo(b.value1946); foo(b.value1947); foo(b.value1948); foo(b.value1949); foo(b.value1950); foo(b.value1951); foo(b.value1952); foo(b.value1953); foo(b.value1954); foo(b.value1955); foo(b.value1956); foo(b.value1957); foo(b.value1958); foo(b.value1959); foo(b.value1960); foo(b.value1961); foo(b.value1962); foo(b.value1963); foo(b.value1964); foo(b.value1965); foo(b.value1966); foo(b.value1967); foo(b.value1968); foo(b.value1969); foo(b.value1970); foo(b.value1971); foo(b.value1972); foo(b.value1973); foo(b.value1974); foo(b.value1975); foo(b.value1976); foo(b.value1977); foo(b.value1978); foo(b.value1979); foo(b.value1980); foo(b.value1981); foo(b.value1982); foo(b.value1983); foo(b.value1984); foo(b.value1985); foo(b.value1986); foo(b.value1987); foo(b.value1988); foo(b.value1989); foo(b.value1990); foo(b.value1991); foo(b.value1992); foo(b.value1993); foo(b.value1994); foo(b.value1995); foo(b.value1996); foo(b.value1997); foo(b.value1998); foo(b.value1999); foo(b.value2000); foo(b.value2001); foo(b.value2002); foo(b.value2003); foo(b.value2004); foo(b.value2005); foo(b.value2006); foo(b.value2007); foo(b.value2008); foo(b.value2009); foo(b.value2010); foo(b.value2011); foo(b.value2012); foo(b.value2013); foo(b.value2014); foo(b.value2015); foo(b.value2016); foo(b.value2017); foo(b.value2018); foo(b.value2019); foo(b.value2020); foo(b.value2021); foo(b.value2022); foo(b.value2023); foo(b.value2024); foo(b.value2025); foo(b.value2026); foo(b.value2027); foo(b.value2028); foo(b.value2029); foo(b.value2030); foo(b.value2031); foo(b.value2032); foo(b.value2033); foo(b.value2034); foo(b.value2035); foo(b.value2036); foo(b.value2037); foo(b.value2038); foo(b.value2039); foo(b.value2040); foo(b.value2041); foo(b.value2042); foo(b.value2043); foo(b.value2044); foo(b.value2045); foo(b.value2046); foo(b.value2047); foo(b.value2048); foo(b.value2049); foo(b.value2050); foo(b.value2051); foo(b.value2052); foo(b.value2053); foo(b.value2054); foo(b.value2055); foo(b.value2056); foo(b.value2057); foo(b.value2058); foo(b.value2059); foo(b.value2060); foo(b.value2061); foo(b.value2062); foo(b.value2063); foo(b.value2064); foo(b.value2065); foo(b.value2066); foo(b.value2067); foo(b.value2068); foo(b.value2069); foo(b.value2070); foo(b.value2071); foo(b.value2072); foo(b.value2073); foo(b.value2074); foo(b.value2075); foo(b.value2076); foo(b.value2077); foo(b.value2078); foo(b.value2079); foo(b.value2080); foo(b.value2081); foo(b.value2082); foo(b.value2083); foo(b.value2084); foo(b.value2085); foo(b.value2086); foo(b.value2087); foo(b.value2088); foo(b.value2089); foo(b.value2090); foo(b.value2091); foo(b.value2092); foo(b.value2093); foo(b.value2094); foo(b.value2095); foo(b.value2096); foo(b.value2097); foo(b.value2098); foo(b.value2099); foo(b.value2100); foo(b.value2101); foo(b.value2102); foo(b.value2103); foo(b.value2104); foo(b.value2105); foo(b.value2106); foo(b.value2107); foo(b.value2108); foo(b.value2109); foo(b.value2110); foo(b.value2111); foo(b.value2112); foo(b.value2113); foo(b.value2114); foo(b.value2115); foo(b.value2116); foo(b.value2117); foo(b.value2118); foo(b.value2119); foo(b.value2120); foo(b.value2121); foo(b.value2122); foo(b.value2123); foo(b.value2124); foo(b.value2125); foo(b.value2126); foo(b.value2127); foo(b.value2128); foo(b.value2129); foo(b.value2130); foo(b.value2131); foo(b.value2132); foo(b.value2133); foo(b.value2134); foo(b.value2135); foo(b.value2136); foo(b.value2137); foo(b.value2138); foo(b.value2139); foo(b.value2140); foo(b.value2141); foo(b.value2142); foo(b.value2143); foo(b.value2144); foo(b.value2145); foo(b.value2146); foo(b.value2147); foo(b.value2148); foo(b.value2149); foo(b.value2150); foo(b.value2151); foo(b.value2152); foo(b.value2153); foo(b.value2154); foo(b.value2155); foo(b.value2156); foo(b.value2157); foo(b.value2158); foo(b.value2159); foo(b.value2160); foo(b.value2161); foo(b.value2162); foo(b.value2163); foo(b.value2164); foo(b.value2165); foo(b.value2166); foo(b.value2167); foo(b.value2168); foo(b.value2169); foo(b.value2170); foo(b.value2171); foo(b.value2172); foo(b.value2173); foo(b.value2174); foo(b.value2175); foo(b.value2176); foo(b.value2177); foo(b.value2178); foo(b.value2179); foo(b.value2180); foo(b.value2181); foo(b.value2182); foo(b.value2183); foo(b.value2184); foo(b.value2185); foo(b.value2186); foo(b.value2187); foo(b.value2188); foo(b.value2189); foo(b.value2190); foo(b.value2191); foo(b.value2192); foo(b.value2193); foo(b.value2194); foo(b.value2195); foo(b.value2196); foo(b.value2197); foo(b.value2198); foo(b.value2199); foo(b.value2200); foo(b.value2201); foo(b.value2202); foo(b.value2203); foo(b.value2204); foo(b.value2205); foo(b.value2206); foo(b.value2207); foo(b.value2208); foo(b.value2209); foo(b.value2210); foo(b.value2211); foo(b.value2212); foo(b.value2213); foo(b.value2214); foo(b.value2215); foo(b.value2216); foo(b.value2217); foo(b.value2218); foo(b.value2219); foo(b.value2220); foo(b.value2221); foo(b.value2222); foo(b.value2223); foo(b.value2224); foo(b.value2225); foo(b.value2226); foo(b.value2227); foo(b.value2228); foo(b.value2229); foo(b.value2230); foo(b.value2231); foo(b.value2232); foo(b.value2233); foo(b.value2234); foo(b.value2235); foo(b.value2236); foo(b.value2237); foo(b.value2238); foo(b.value2239); foo(b.value2240); foo(b.value2241); foo(b.value2242); foo(b.value2243); foo(b.value2244); foo(b.value2245); foo(b.value2246); foo(b.value2247); foo(b.value2248); foo(b.value2249); foo(b.value2250); foo(b.value2251); foo(b.value2252); foo(b.value2253); foo(b.value2254); foo(b.value2255); foo(b.value2256); foo(b.value2257); foo(b.value2258); foo(b.value2259); foo(b.value2260); foo(b.value2261); foo(b.value2262); foo(b.value2263); foo(b.value2264); foo(b.value2265); foo(b.value2266); foo(b.value2267); foo(b.value2268); foo(b.value2269); foo(b.value2270); foo(b.value2271); foo(b.value2272); foo(b.value2273); foo(b.value2274); foo(b.value2275); foo(b.value2276); foo(b.value2277); foo(b.value2278); foo(b.value2279); foo(b.value2280); foo(b.value2281); foo(b.value2282); foo(b.value2283); foo(b.value2284); foo(b.value2285); foo(b.value2286); foo(b.value2287); foo(b.value2288); foo(b.value2289); foo(b.value2290); foo(b.value2291); foo(b.value2292); foo(b.value2293); foo(b.value2294); foo(b.value2295); foo(b.value2296); foo(b.value2297); foo(b.value2298); foo(b.value2299); foo(b.value2300); foo(b.value2301); foo(b.value2302); foo(b.value2303); foo(b.value2304); foo(b.value2305); foo(b.value2306); foo(b.value2307); foo(b.value2308); foo(b.value2309); foo(b.value2310); foo(b.value2311); foo(b.value2312); foo(b.value2313); foo(b.value2314); foo(b.value2315); foo(b.value2316); foo(b.value2317); foo(b.value2318); foo(b.value2319); foo(b.value2320); foo(b.value2321); foo(b.value2322); foo(b.value2323); foo(b.value2324); foo(b.value2325); foo(b.value2326); foo(b.value2327); foo(b.value2328); foo(b.value2329); foo(b.value2330); foo(b.value2331); foo(b.value2332); foo(b.value2333); foo(b.value2334); foo(b.value2335); foo(b.value2336); foo(b.value2337); foo(b.value2338); foo(b.value2339); foo(b.value2340); foo(b.value2341); foo(b.value2342); foo(b.value2343); foo(b.value2344); foo(b.value2345); foo(b.value2346); foo(b.value2347); foo(b.value2348); foo(b.value2349); foo(b.value2350); foo(b.value2351); foo(b.value2352); foo(b.value2353); foo(b.value2354); foo(b.value2355); foo(b.value2356); foo(b.value2357); foo(b.value2358); foo(b.value2359); foo(b.value2360); foo(b.value2361); foo(b.value2362); foo(b.value2363); foo(b.value2364); foo(b.value2365); foo(b.value2366); foo(b.value2367); foo(b.value2368); foo(b.value2369); foo(b.value2370); foo(b.value2371); foo(b.value2372); foo(b.value2373); foo(b.value2374); foo(b.value2375); foo(b.value2376); foo(b.value2377); foo(b.value2378); foo(b.value2379); foo(b.value2380); foo(b.value2381); foo(b.value2382); foo(b.value2383); foo(b.value2384); foo(b.value2385); foo(b.value2386); foo(b.value2387); foo(b.value2388); foo(b.value2389); foo(b.value2390); foo(b.value2391); foo(b.value2392); foo(b.value2393); foo(b.value2394); foo(b.value2395); foo(b.value2396); foo(b.value2397); foo(b.value2398); foo(b.value2399); foo(b.value2400); foo(b.value2401); foo(b.value2402); foo(b.value2403); foo(b.value2404); foo(b.value2405); foo(b.value2406); foo(b.value2407); foo(b.value2408); foo(b.value2409); foo(b.value2410); foo(b.value2411); foo(b.value2412); foo(b.value2413); foo(b.value2414); foo(b.value2415); foo(b.value2416); foo(b.value2417); foo(b.value2418); foo(b.value2419); foo(b.value2420); foo(b.value2421); foo(b.value2422); foo(b.value2423); foo(b.value2424); foo(b.value2425); foo(b.value2426); foo(b.value2427); foo(b.value2428); foo(b.value2429); foo(b.value2430); foo(b.value2431); foo(b.value2432); foo(b.value2433); foo(b.value2434); foo(b.value2435); foo(b.value2436); foo(b.value2437); foo(b.value2438); foo(b.value2439); foo(b.value2440); foo(b.value2441); foo(b.value2442); foo(b.value2443); foo(b.value2444); foo(b.value2445); foo(b.value2446); foo(b.value2447); foo(b.value2448); foo(b.value2449); foo(b.value2450); foo(b.value2451); foo(b.value2452); foo(b.value2453); foo(b.value2454); foo(b.value2455); foo(b.value2456); foo(b.value2457); foo(b.value2458); foo(b.value2459); foo(b.value2460); foo(b.value2461); foo(b.value2462); foo(b.value2463); foo(b.value2464); foo(b.value2465); foo(b.value2466); foo(b.value2467); foo(b.value2468); foo(b.value2469); foo(b.value2470); foo(b.value2471); foo(b.value2472); foo(b.value2473); foo(b.value2474); foo(b.value2475); foo(b.value2476); foo(b.value2477); foo(b.value2478); foo(b.value2479); foo(b.value2480); foo(b.value2481); foo(b.value2482); foo(b.value2483); foo(b.value2484); foo(b.value2485); foo(b.value2486); foo(b.value2487); foo(b.value2488); foo(b.value2489); foo(b.value2490); foo(b.value2491); foo(b.value2492); foo(b.value2493); foo(b.value2494); foo(b.value2495); foo(b.value2496); foo(b.value2497); foo(b.value2498); foo(b.value2499); foo(b.value2500); foo(b.value2501); foo(b.value2502); foo(b.value2503); foo(b.value2504); foo(b.value2505); foo(b.value2506); foo(b.value2507); foo(b.value2508); foo(b.value2509); foo(b.value2510); foo(b.value2511); foo(b.value2512); foo(b.value2513); foo(b.value2514); foo(b.value2515); foo(b.value2516); foo(b.value2517); foo(b.value2518); foo(b.value2519); foo(b.value2520); foo(b.value2521); foo(b.value2522); foo(b.value2523); foo(b.value2524); foo(b.value2525); foo(b.value2526); foo(b.value2527); foo(b.value2528); foo(b.value2529); foo(b.value2530); foo(b.value2531); foo(b.value2532); foo(b.value2533); foo(b.value2534); foo(b.value2535); foo(b.value2536); foo(b.value2537); foo(b.value2538); foo(b.value2539); foo(b.value2540); foo(b.value2541); foo(b.value2542); foo(b.value2543); foo(b.value2544); foo(b.value2545); foo(b.value2546); foo(b.value2547); foo(b.value2548); foo(b.value2549); foo(b.value2550); foo(b.value2551); foo(b.value2552); foo(b.value2553); foo(b.value2554); foo(b.value2555); foo(b.value2556); foo(b.value2557); foo(b.value2558); foo(b.value2559); foo(b.value2560); foo(b.value2561); foo(b.value2562); foo(b.value2563); foo(b.value2564); foo(b.value2565); foo(b.value2566); foo(b.value2567); foo(b.value2568); foo(b.value2569); foo(b.value2570); foo(b.value2571); foo(b.value2572); foo(b.value2573); foo(b.value2574); foo(b.value2575); foo(b.value2576); foo(b.value2577); foo(b.value2578); foo(b.value2579); foo(b.value2580); foo(b.value2581); foo(b.value2582); foo(b.value2583); foo(b.value2584); foo(b.value2585); foo(b.value2586); foo(b.value2587); foo(b.value2588); foo(b.value2589); foo(b.value2590); foo(b.value2591); foo(b.value2592); foo(b.value2593); foo(b.value2594); foo(b.value2595); foo(b.value2596); foo(b.value2597); foo(b.value2598); foo(b.value2599); foo(b.value2600); foo(b.value2601); foo(b.value2602); foo(b.value2603); foo(b.value2604); foo(b.value2605); foo(b.value2606); foo(b.value2607); foo(b.value2608); foo(b.value2609); foo(b.value2610); foo(b.value2611); foo(b.value2612); foo(b.value2613); foo(b.value2614); foo(b.value2615); foo(b.value2616); foo(b.value2617); foo(b.value2618); foo(b.value2619); foo(b.value2620); foo(b.value2621); foo(b.value2622); foo(b.value2623); foo(b.value2624); foo(b.value2625); foo(b.value2626); foo(b.value2627); foo(b.value2628); foo(b.value2629); foo(b.value2630); foo(b.value2631); foo(b.value2632); foo(b.value2633); foo(b.value2634); foo(b.value2635); foo(b.value2636); foo(b.value2637); foo(b.value2638); foo(b.value2639); foo(b.value2640); foo(b.value2641); foo(b.value2642); foo(b.value2643); foo(b.value2644); foo(b.value2645); foo(b.value2646); foo(b.value2647); foo(b.value2648); foo(b.value2649); foo(b.value2650); foo(b.value2651); foo(b.value2652); foo(b.value2653); foo(b.value2654); foo(b.value2655); foo(b.value2656); foo(b.value2657); foo(b.value2658); foo(b.value2659); foo(b.value2660); foo(b.value2661); foo(b.value2662); foo(b.value2663); foo(b.value2664); foo(b.value2665); foo(b.value2666); foo(b.value2667); foo(b.value2668); foo(b.value2669); foo(b.value2670); foo(b.value2671); foo(b.value2672); foo(b.value2673); foo(b.value2674); foo(b.value2675); foo(b.value2676); foo(b.value2677); foo(b.value2678); foo(b.value2679); foo(b.value2680); foo(b.value2681); foo(b.value2682); foo(b.value2683); foo(b.value2684); foo(b.value2685); foo(b.value2686); foo(b.value2687); foo(b.value2688); foo(b.value2689); foo(b.value2690); foo(b.value2691); foo(b.value2692); foo(b.value2693); foo(b.value2694); foo(b.value2695); foo(b.value2696); foo(b.value2697); foo(b.value2698); foo(b.value2699); foo(b.value2700); foo(b.value2701); foo(b.value2702); foo(b.value2703); foo(b.value2704); foo(b.value2705); foo(b.value2706); foo(b.value2707); foo(b.value2708); foo(b.value2709); foo(b.value2710); foo(b.value2711); foo(b.value2712); foo(b.value2713); foo(b.value2714); foo(b.value2715); foo(b.value2716); foo(b.value2717); foo(b.value2718); foo(b.value2719); foo(b.value2720); foo(b.value2721); foo(b.value2722); foo(b.value2723); foo(b.value2724); foo(b.value2725); foo(b.value2726); foo(b.value2727); foo(b.value2728); foo(b.value2729); foo(b.value2730); foo(b.value2731); foo(b.value2732); foo(b.value2733); foo(b.value2734); foo(b.value2735); foo(b.value2736); foo(b.value2737); foo(b.value2738); foo(b.value2739); foo(b.value2740); foo(b.value2741); foo(b.value2742); foo(b.value2743); foo(b.value2744); foo(b.value2745); foo(b.value2746); foo(b.value2747); foo(b.value2748); foo(b.value2749); foo(b.value2750); foo(b.value2751); foo(b.value2752); foo(b.value2753); foo(b.value2754); foo(b.value2755); foo(b.value2756); foo(b.value2757); foo(b.value2758); foo(b.value2759); foo(b.value2760); foo(b.value2761); foo(b.value2762); foo(b.value2763); foo(b.value2764); foo(b.value2765); foo(b.value2766); foo(b.value2767); foo(b.value2768); foo(b.value2769); foo(b.value2770); foo(b.value2771); foo(b.value2772); foo(b.value2773); foo(b.value2774); foo(b.value2775); foo(b.value2776); foo(b.value2777); foo(b.value2778); foo(b.value2779); foo(b.value2780); foo(b.value2781); foo(b.value2782); foo(b.value2783); foo(b.value2784); foo(b.value2785); foo(b.value2786); foo(b.value2787); foo(b.value2788); foo(b.value2789); foo(b.value2790); foo(b.value2791); foo(b.value2792); foo(b.value2793); foo(b.value2794); foo(b.value2795); foo(b.value2796); foo(b.value2797); foo(b.value2798); foo(b.value2799); foo(b.value2800); foo(b.value2801); foo(b.value2802); foo(b.value2803); foo(b.value2804); foo(b.value2805); foo(b.value2806); foo(b.value2807); foo(b.value2808); foo(b.value2809); foo(b.value2810); foo(b.value2811); foo(b.value2812); foo(b.value2813); foo(b.value2814); foo(b.value2815); foo(b.value2816); foo(b.value2817); foo(b.value2818); foo(b.value2819); foo(b.value2820); foo(b.value2821); foo(b.value2822); foo(b.value2823); foo(b.value2824); foo(b.value2825); foo(b.value2826); foo(b.value2827); foo(b.value2828); foo(b.value2829); foo(b.value2830); foo(b.value2831); foo(b.value2832); foo(b.value2833); foo(b.value2834); foo(b.value2835); foo(b.value2836); foo(b.value2837); foo(b.value2838); foo(b.value2839); foo(b.value2840); foo(b.value2841); foo(b.value2842); foo(b.value2843); foo(b.value2844); foo(b.value2845); foo(b.value2846); foo(b.value2847); foo(b.value2848); foo(b.value2849); foo(b.value2850); foo(b.value2851); foo(b.value2852); foo(b.value2853); foo(b.value2854); foo(b.value2855); foo(b.value2856); foo(b.value2857); foo(b.value2858); foo(b.value2859); foo(b.value2860); foo(b.value2861); foo(b.value2862); foo(b.value2863); foo(b.value2864); foo(b.value2865); foo(b.value2866); foo(b.value2867); foo(b.value2868); foo(b.value2869); foo(b.value2870); foo(b.value2871); foo(b.value2872); foo(b.value2873); foo(b.value2874); foo(b.value2875); foo(b.value2876); foo(b.value2877); foo(b.value2878); foo(b.value2879); foo(b.value2880); foo(b.value2881); foo(b.value2882); foo(b.value2883); foo(b.value2884); foo(b.value2885); foo(b.value2886); foo(b.value2887); foo(b.value2888); foo(b.value2889); foo(b.value2890); foo(b.value2891); foo(b.value2892); foo(b.value2893); foo(b.value2894); foo(b.value2895); foo(b.value2896); foo(b.value2897); foo(b.value2898); foo(b.value2899); foo(b.value2900); foo(b.value2901); foo(b.value2902); foo(b.value2903); foo(b.value2904); foo(b.value2905); foo(b.value2906); foo(b.value2907); foo(b.value2908); foo(b.value2909); foo(b.value2910); foo(b.value2911); foo(b.value2912); foo(b.value2913); foo(b.value2914); foo(b.value2915); foo(b.value2916); foo(b.value2917); foo(b.value2918); foo(b.value2919); foo(b.value2920); foo(b.value2921); foo(b.value2922); foo(b.value2923); foo(b.value2924); foo(b.value2925); foo(b.value2926); foo(b.value2927); foo(b.value2928); foo(b.value2929); foo(b.value2930); foo(b.value2931); foo(b.value2932); foo(b.value2933); foo(b.value2934); foo(b.value2935); foo(b.value2936); foo(b.value2937); foo(b.value2938); foo(b.value2939); foo(b.value2940); foo(b.value2941); foo(b.value2942); foo(b.value2943); foo(b.value2944); foo(b.value2945); foo(b.value2946); foo(b.value2947); foo(b.value2948); foo(b.value2949); foo(b.value2950); foo(b.value2951); foo(b.value2952); foo(b.value2953); foo(b.value2954); foo(b.value2955); foo(b.value2956); foo(b.value2957); foo(b.value2958); foo(b.value2959); foo(b.value2960); foo(b.value2961); foo(b.value2962); foo(b.value2963); foo(b.value2964); foo(b.value2965); foo(b.value2966); foo(b.value2967); foo(b.value2968); foo(b.value2969); foo(b.value2970); foo(b.value2971); foo(b.value2972); foo(b.value2973); foo(b.value2974); foo(b.value2975); foo(b.value2976); foo(b.value2977); foo(b.value2978); foo(b.value2979); foo(b.value2980); foo(b.value2981); foo(b.value2982); foo(b.value2983); foo(b.value2984); foo(b.value2985); foo(b.value2986); foo(b.value2987); foo(b.value2988); foo(b.value2989); foo(b.value2990); foo(b.value2991); foo(b.value2992); foo(b.value2993); foo(b.value2994); foo(b.value2995); foo(b.value2996); foo(b.value2997); foo(b.value2998); foo(b.value2999); foo(b.value3000); foo(b.value3001); foo(b.value3002); foo(b.value3003); foo(b.value3004); foo(b.value3005); foo(b.value3006); foo(b.value3007); foo(b.value3008); foo(b.value3009); foo(b.value3010); foo(b.value3011); foo(b.value3012); foo(b.value3013); foo(b.value3014); foo(b.value3015); foo(b.value3016); foo(b.value3017); foo(b.value3018); foo(b.value3019); foo(b.value3020); foo(b.value3021); foo(b.value3022); foo(b.value3023); foo(b.value3024); foo(b.value3025); foo(b.value3026); foo(b.value3027); foo(b.value3028); foo(b.value3029); foo(b.value3030); foo(b.value3031); foo(b.value3032); foo(b.value3033); foo(b.value3034); foo(b.value3035); foo(b.value3036); foo(b.value3037); foo(b.value3038); foo(b.value3039); foo(b.value3040); foo(b.value3041); foo(b.value3042); foo(b.value3043); foo(b.value3044); foo(b.value3045); foo(b.value3046); foo(b.value3047); foo(b.value3048); foo(b.value3049); foo(b.value3050); foo(b.value3051); foo(b.value3052); foo(b.value3053); foo(b.value3054); foo(b.value3055); foo(b.value3056); foo(b.value3057); foo(b.value3058); foo(b.value3059); foo(b.value3060); foo(b.value3061); foo(b.value3062); foo(b.value3063); foo(b.value3064); foo(b.value3065); foo(b.value3066); foo(b.value3067); foo(b.value3068); foo(b.value3069); foo(b.value3070); foo(b.value3071); foo(b.value3072); foo(b.value3073); foo(b.value3074); foo(b.value3075); foo(b.value3076); foo(b.value3077); foo(b.value3078); foo(b.value3079); foo(b.value3080); foo(b.value3081); foo(b.value3082); foo(b.value3083); foo(b.value3084); foo(b.value3085); foo(b.value3086); foo(b.value3087); foo(b.value3088); foo(b.value3089); foo(b.value3090); foo(b.value3091); foo(b.value3092); foo(b.value3093); foo(b.value3094); foo(b.value3095); foo(b.value3096); foo(b.value3097); foo(b.value3098); foo(b.value3099); foo(b.value3100); foo(b.value3101); foo(b.value3102); foo(b.value3103); foo(b.value3104); foo(b.value3105); foo(b.value3106); foo(b.value3107); foo(b.value3108); foo(b.value3109); foo(b.value3110); foo(b.value3111); foo(b.value3112); foo(b.value3113); foo(b.value3114); foo(b.value3115); foo(b.value3116); foo(b.value3117); foo(b.value3118); foo(b.value3119); foo(b.value3120); foo(b.value3121); foo(b.value3122); foo(b.value3123); foo(b.value3124); foo(b.value3125); foo(b.value3126); foo(b.value3127); foo(b.value3128); foo(b.value3129); foo(b.value3130); foo(b.value3131); foo(b.value3132); foo(b.value3133); foo(b.value3134); foo(b.value3135); foo(b.value3136); foo(b.value3137); foo(b.value3138); foo(b.value3139); foo(b.value3140); foo(b.value3141); foo(b.value3142); foo(b.value3143); foo(b.value3144); foo(b.value3145); foo(b.value3146); foo(b.value3147); foo(b.value3148); foo(b.value3149); foo(b.value3150); foo(b.value3151); foo(b.value3152); foo(b.value3153); foo(b.value3154); foo(b.value3155); foo(b.value3156); foo(b.value3157); foo(b.value3158); foo(b.value3159); foo(b.value3160); foo(b.value3161); foo(b.value3162); foo(b.value3163); foo(b.value3164); foo(b.value3165); foo(b.value3166); foo(b.value3167); foo(b.value3168); foo(b.value3169); foo(b.value3170); foo(b.value3171); foo(b.value3172); foo(b.value3173); foo(b.value3174); foo(b.value3175); foo(b.value3176); foo(b.value3177); foo(b.value3178); foo(b.value3179); foo(b.value3180); foo(b.value3181); foo(b.value3182); foo(b.value3183); foo(b.value3184); foo(b.value3185); foo(b.value3186); foo(b.value3187); foo(b.value3188); foo(b.value3189); foo(b.value3190); foo(b.value3191); foo(b.value3192); foo(b.value3193); foo(b.value3194); foo(b.value3195); foo(b.value3196); foo(b.value3197); foo(b.value3198); foo(b.value3199); foo(b.value3200); foo(b.value3201); foo(b.value3202); foo(b.value3203); foo(b.value3204); foo(b.value3205); foo(b.value3206); foo(b.value3207); foo(b.value3208); foo(b.value3209); foo(b.value3210); foo(b.value3211); foo(b.value3212); foo(b.value3213); foo(b.value3214); foo(b.value3215); foo(b.value3216); foo(b.value3217); foo(b.value3218); foo(b.value3219); foo(b.value3220); foo(b.value3221); foo(b.value3222); foo(b.value3223); foo(b.value3224); foo(b.value3225); foo(b.value3226); foo(b.value3227); foo(b.value3228); foo(b.value3229); foo(b.value3230); foo(b.value3231); foo(b.value3232); foo(b.value3233); foo(b.value3234); foo(b.value3235); foo(b.value3236); foo(b.value3237); foo(b.value3238); foo(b.value3239); foo(b.value3240); foo(b.value3241); foo(b.value3242); foo(b.value3243); foo(b.value3244); foo(b.value3245); foo(b.value3246); foo(b.value3247); foo(b.value3248); foo(b.value3249); foo(b.value3250); foo(b.value3251); foo(b.value3252); foo(b.value3253); foo(b.value3254); foo(b.value3255); foo(b.value3256); foo(b.value3257); foo(b.value3258); foo(b.value3259); foo(b.value3260); foo(b.value3261); foo(b.value3262); foo(b.value3263); foo(b.value3264); foo(b.value3265); foo(b.value3266); foo(b.value3267); foo(b.value3268); foo(b.value3269); foo(b.value3270); foo(b.value3271); foo(b.value3272); foo(b.value3273); foo(b.value3274); foo(b.value3275); foo(b.value3276); foo(b.value3277); foo(b.value3278); foo(b.value3279); foo(b.value3280); foo(b.value3281); foo(b.value3282); foo(b.value3283); foo(b.value3284); foo(b.value3285); foo(b.value3286); foo(b.value3287); foo(b.value3288); foo(b.value3289); foo(b.value3290); foo(b.value3291); foo(b.value3292); foo(b.value3293); foo(b.value3294); foo(b.value3295); foo(b.value3296); foo(b.value3297); foo(b.value3298); foo(b.value3299); foo(b.value3300); foo(b.value3301); foo(b.value3302); foo(b.value3303); foo(b.value3304); foo(b.value3305); foo(b.value3306); foo(b.value3307); foo(b.value3308); foo(b.value3309); foo(b.value3310); foo(b.value3311); foo(b.value3312); foo(b.value3313); foo(b.value3314); foo(b.value3315); foo(b.value3316); foo(b.value3317); foo(b.value3318); foo(b.value3319); foo(b.value3320); foo(b.value3321); foo(b.value3322); foo(b.value3323); foo(b.value3324); foo(b.value3325); foo(b.value3326); foo(b.value3327); foo(b.value3328); foo(b.value3329); foo(b.value3330); foo(b.value3331); foo(b.value3332); foo(b.value3333); foo(b.value3334); foo(b.value3335); foo(b.value3336); foo(b.value3337); foo(b.value3338); foo(b.value3339); foo(b.value3340); foo(b.value3341); foo(b.value3342); foo(b.value3343); foo(b.value3344); foo(b.value3345); foo(b.value3346); foo(b.value3347); foo(b.value3348); foo(b.value3349); foo(b.value3350); foo(b.value3351); foo(b.value3352); foo(b.value3353); foo(b.value3354); foo(b.value3355); foo(b.value3356); foo(b.value3357); foo(b.value3358); foo(b.value3359); foo(b.value3360); foo(b.value3361); foo(b.value3362); foo(b.value3363); foo(b.value3364); foo(b.value3365); foo(b.value3366); foo(b.value3367); foo(b.value3368); foo(b.value3369); foo(b.value3370); foo(b.value3371); foo(b.value3372); foo(b.value3373); foo(b.value3374); foo(b.value3375); foo(b.value3376); foo(b.value3377); foo(b.value3378); foo(b.value3379); foo(b.value3380); foo(b.value3381); foo(b.value3382); foo(b.value3383); foo(b.value3384); foo(b.value3385); foo(b.value3386); foo(b.value3387); foo(b.value3388); foo(b.value3389); foo(b.value3390); foo(b.value3391); foo(b.value3392); foo(b.value3393); foo(b.value3394); foo(b.value3395); foo(b.value3396); foo(b.value3397); foo(b.value3398); foo(b.value3399); foo(b.value3400); foo(b.value3401); foo(b.value3402); foo(b.value3403); foo(b.value3404); foo(b.value3405); foo(b.value3406); foo(b.value3407); foo(b.value3408); foo(b.value3409); foo(b.value3410); foo(b.value3411); foo(b.value3412); foo(b.value3413); foo(b.value3414); foo(b.value3415); foo(b.value3416); foo(b.value3417); foo(b.value3418); foo(b.value3419); foo(b.value3420); foo(b.value3421); foo(b.value3422); foo(b.value3423); foo(b.value3424); foo(b.value3425); foo(b.value3426); foo(b.value3427); foo(b.value3428); foo(b.value3429); foo(b.value3430); foo(b.value3431); foo(b.value3432); foo(b.value3433); foo(b.value3434); foo(b.value3435); foo(b.value3436); foo(b.value3437); foo(b.value3438); foo(b.value3439); foo(b.value3440); foo(b.value3441); foo(b.value3442); foo(b.value3443); foo(b.value3444); foo(b.value3445); foo(b.value3446); foo(b.value3447); foo(b.value3448); foo(b.value3449); foo(b.value3450); foo(b.value3451); foo(b.value3452); foo(b.value3453); foo(b.value3454); foo(b.value3455); foo(b.value3456); foo(b.value3457); foo(b.value3458); foo(b.value3459); foo(b.value3460); foo(b.value3461); foo(b.value3462); foo(b.value3463); foo(b.value3464); foo(b.value3465); foo(b.value3466); foo(b.value3467); foo(b.value3468); foo(b.value3469); foo(b.value3470); foo(b.value3471); foo(b.value3472); foo(b.value3473); foo(b.value3474); foo(b.value3475); foo(b.value3476); foo(b.value3477); foo(b.value3478); foo(b.value3479); foo(b.value3480); foo(b.value3481); foo(b.value3482); foo(b.value3483); foo(b.value3484); foo(b.value3485); foo(b.value3486); foo(b.value3487); foo(b.value3488); foo(b.value3489); foo(b.value3490); foo(b.value3491); foo(b.value3492); foo(b.value3493); foo(b.value3494); foo(b.value3495); foo(b.value3496); foo(b.value3497); foo(b.value3498); foo(b.value3499); foo(b.value3500); foo(b.value3501); foo(b.value3502); foo(b.value3503); foo(b.value3504); foo(b.value3505); foo(b.value3506); foo(b.value3507); foo(b.value3508); foo(b.value3509); foo(b.value3510); foo(b.value3511); foo(b.value3512); foo(b.value3513); foo(b.value3514); foo(b.value3515); foo(b.value3516); foo(b.value3517); foo(b.value3518); foo(b.value3519); foo(b.value3520); foo(b.value3521); foo(b.value3522); foo(b.value3523); foo(b.value3524); foo(b.value3525); foo(b.value3526); foo(b.value3527); foo(b.value3528); foo(b.value3529); foo(b.value3530); foo(b.value3531); foo(b.value3532); foo(b.value3533); foo(b.value3534); foo(b.value3535); foo(b.value3536); foo(b.value3537); foo(b.value3538); foo(b.value3539); foo(b.value3540); foo(b.value3541); foo(b.value3542); foo(b.value3543); foo(b.value3544); foo(b.value3545); foo(b.value3546); foo(b.value3547); foo(b.value3548); foo(b.value3549); foo(b.value3550); foo(b.value3551); foo(b.value3552); foo(b.value3553); foo(b.value3554); foo(b.value3555); foo(b.value3556); foo(b.value3557); foo(b.value3558); foo(b.value3559); foo(b.value3560); foo(b.value3561); foo(b.value3562); foo(b.value3563); foo(b.value3564); foo(b.value3565); foo(b.value3566); foo(b.value3567); foo(b.value3568); foo(b.value3569); foo(b.value3570); foo(b.value3571); foo(b.value3572); foo(b.value3573); foo(b.value3574); foo(b.value3575); foo(b.value3576); foo(b.value3577); foo(b.value3578); foo(b.value3579); foo(b.value3580); foo(b.value3581); foo(b.value3582); foo(b.value3583); foo(b.value3584); foo(b.value3585); foo(b.value3586); foo(b.value3587); foo(b.value3588); foo(b.value3589); foo(b.value3590); foo(b.value3591); foo(b.value3592); foo(b.value3593); foo(b.value3594); foo(b.value3595); foo(b.value3596); foo(b.value3597); foo(b.value3598); foo(b.value3599); foo(b.value3600); foo(b.value3601); foo(b.value3602); foo(b.value3603); foo(b.value3604); foo(b.value3605); foo(b.value3606); foo(b.value3607); foo(b.value3608); foo(b.value3609); foo(b.value3610); foo(b.value3611); foo(b.value3612); foo(b.value3613); foo(b.value3614); foo(b.value3615); foo(b.value3616); foo(b.value3617); foo(b.value3618); foo(b.value3619); foo(b.value3620); foo(b.value3621); foo(b.value3622); foo(b.value3623); foo(b.value3624); foo(b.value3625); foo(b.value3626); foo(b.value3627); foo(b.value3628); foo(b.value3629); foo(b.value3630); foo(b.value3631); foo(b.value3632); foo(b.value3633); foo(b.value3634); foo(b.value3635); foo(b.value3636); foo(b.value3637); foo(b.value3638); foo(b.value3639); foo(b.value3640); foo(b.value3641); foo(b.value3642); foo(b.value3643); foo(b.value3644); foo(b.value3645); foo(b.value3646); foo(b.value3647); foo(b.value3648); foo(b.value3649); foo(b.value3650); foo(b.value3651); foo(b.value3652); foo(b.value3653); foo(b.value3654); foo(b.value3655); foo(b.value3656); foo(b.value3657); foo(b.value3658); foo(b.value3659); foo(b.value3660); foo(b.value3661); foo(b.value3662); foo(b.value3663); foo(b.value3664); foo(b.value3665); foo(b.value3666); foo(b.value3667); foo(b.value3668); foo(b.value3669); foo(b.value3670); foo(b.value3671); foo(b.value3672); foo(b.value3673); foo(b.value3674); foo(b.value3675); foo(b.value3676); foo(b.value3677); foo(b.value3678); foo(b.value3679); foo(b.value3680); foo(b.value3681); foo(b.value3682); foo(b.value3683); foo(b.value3684); foo(b.value3685); foo(b.value3686); foo(b.value3687); foo(b.value3688); foo(b.value3689); foo(b.value3690); foo(b.value3691); foo(b.value3692); foo(b.value3693); foo(b.value3694); foo(b.value3695); foo(b.value3696); foo(b.value3697); foo(b.value3698); foo(b.value3699); foo(b.value3700); foo(b.value3701); foo(b.value3702); foo(b.value3703); foo(b.value3704); foo(b.value3705); foo(b.value3706); foo(b.value3707); foo(b.value3708); foo(b.value3709); foo(b.value3710); foo(b.value3711); foo(b.value3712); foo(b.value3713); foo(b.value3714); foo(b.value3715); foo(b.value3716); foo(b.value3717); foo(b.value3718); foo(b.value3719); foo(b.value3720); foo(b.value3721); foo(b.value3722); foo(b.value3723); foo(b.value3724); foo(b.value3725); foo(b.value3726); foo(b.value3727); foo(b.value3728); foo(b.value3729); foo(b.value3730); foo(b.value3731); foo(b.value3732); foo(b.value3733); foo(b.value3734); foo(b.value3735); foo(b.value3736); foo(b.value3737); foo(b.value3738); foo(b.value3739); foo(b.value3740); foo(b.value3741); foo(b.value3742); foo(b.value3743); foo(b.value3744); foo(b.value3745); foo(b.value3746); foo(b.value3747); foo(b.value3748); foo(b.value3749); foo(b.value3750); foo(b.value3751); foo(b.value3752); foo(b.value3753); foo(b.value3754); foo(b.value3755); foo(b.value3756); foo(b.value3757); foo(b.value3758); foo(b.value3759); foo(b.value3760); foo(b.value3761); foo(b.value3762); foo(b.value3763); foo(b.value3764); foo(b.value3765); foo(b.value3766); foo(b.value3767); foo(b.value3768); foo(b.value3769); foo(b.value3770); foo(b.value3771); foo(b.value3772); foo(b.value3773); foo(b.value3774); foo(b.value3775); foo(b.value3776); foo(b.value3777); foo(b.value3778); foo(b.value3779); foo(b.value3780); foo(b.value3781); foo(b.value3782); foo(b.value3783); foo(b.value3784); foo(b.value3785); foo(b.value3786); foo(b.value3787); foo(b.value3788); foo(b.value3789); foo(b.value3790); foo(b.value3791); foo(b.value3792); foo(b.value3793); foo(b.value3794); foo(b.value3795); foo(b.value3796); foo(b.value3797); foo(b.value3798); foo(b.value3799); foo(b.value3800); foo(b.value3801); foo(b.value3802); foo(b.value3803); foo(b.value3804); foo(b.value3805); foo(b.value3806); foo(b.value3807); foo(b.value3808); foo(b.value3809); foo(b.value3810); foo(b.value3811); foo(b.value3812); foo(b.value3813); foo(b.value3814); foo(b.value3815); foo(b.value3816); foo(b.value3817); foo(b.value3818); foo(b.value3819); foo(b.value3820); foo(b.value3821); foo(b.value3822); foo(b.value3823); foo(b.value3824); foo(b.value3825); foo(b.value3826); foo(b.value3827); foo(b.value3828); foo(b.value3829); foo(b.value3830); foo(b.value3831); foo(b.value3832); foo(b.value3833); foo(b.value3834); foo(b.value3835); foo(b.value3836); foo(b.value3837); foo(b.value3838); foo(b.value3839); foo(b.value3840); foo(b.value3841); foo(b.value3842); foo(b.value3843); foo(b.value3844); foo(b.value3845); foo(b.value3846); foo(b.value3847); foo(b.value3848); foo(b.value3849); foo(b.value3850); foo(b.value3851); foo(b.value3852); foo(b.value3853); foo(b.value3854); foo(b.value3855); foo(b.value3856); foo(b.value3857); foo(b.value3858); foo(b.value3859); foo(b.value3860); foo(b.value3861); foo(b.value3862); foo(b.value3863); foo(b.value3864); foo(b.value3865); foo(b.value3866); foo(b.value3867); foo(b.value3868); foo(b.value3869); foo(b.value3870); foo(b.value3871); foo(b.value3872); foo(b.value3873); foo(b.value3874); foo(b.value3875); foo(b.value3876); foo(b.value3877); foo(b.value3878); foo(b.value3879); foo(b.value3880); foo(b.value3881); foo(b.value3882); foo(b.value3883); foo(b.value3884); foo(b.value3885); foo(b.value3886); foo(b.value3887); foo(b.value3888); foo(b.value3889); foo(b.value3890); foo(b.value3891); foo(b.value3892); foo(b.value3893); foo(b.value3894); foo(b.value3895); foo(b.value3896); foo(b.value3897); foo(b.value3898); foo(b.value3899); foo(b.value3900); foo(b.value3901); foo(b.value3902); foo(b.value3903); foo(b.value3904); foo(b.value3905); foo(b.value3906); foo(b.value3907); foo(b.value3908); foo(b.value3909); foo(b.value3910); foo(b.value3911); foo(b.value3912); foo(b.value3913); foo(b.value3914); foo(b.value3915); foo(b.value3916); foo(b.value3917); foo(b.value3918); foo(b.value3919); foo(b.value3920); foo(b.value3921); foo(b.value3922); foo(b.value3923); foo(b.value3924); foo(b.value3925); foo(b.value3926); foo(b.value3927); foo(b.value3928); foo(b.value3929); foo(b.value3930); foo(b.value3931); foo(b.value3932); foo(b.value3933); foo(b.value3934); foo(b.value3935); foo(b.value3936); foo(b.value3937); foo(b.value3938); foo(b.value3939); foo(b.value3940); foo(b.value3941); foo(b.value3942); foo(b.value3943); foo(b.value3944); foo(b.value3945); foo(b.value3946); foo(b.value3947); foo(b.value3948); foo(b.value3949); foo(b.value3950); foo(b.value3951); foo(b.value3952); foo(b.value3953); foo(b.value3954); foo(b.value3955); foo(b.value3956); foo(b.value3957); foo(b.value3958); foo(b.value3959); foo(b.value3960); foo(b.value3961); foo(b.value3962); foo(b.value3963); foo(b.value3964); foo(b.value3965); foo(b.value3966); foo(b.value3967); foo(b.value3968); foo(b.value3969); foo(b.value3970); foo(b.value3971); foo(b.value3972); foo(b.value3973); foo(b.value3974); foo(b.value3975); foo(b.value3976); foo(b.value3977); foo(b.value3978); foo(b.value3979); foo(b.value3980); foo(b.value3981); foo(b.value3982); foo(b.value3983); foo(b.value3984); foo(b.value3985); foo(b.value3986); foo(b.value3987); foo(b.value3988); foo(b.value3989); foo(b.value3990); foo(b.value3991); foo(b.value3992); foo(b.value3993); foo(b.value3994); foo(b.value3995); foo(b.value3996); foo(b.value3997); foo(b.value3998); foo(b.value3999); foo(b.value4000); foo(b.value4001); foo(b.value4002); foo(b.value4003); foo(b.value4004); foo(b.value4005); foo(b.value4006); foo(b.value4007); foo(b.value4008); foo(b.value4009); foo(b.value4010); foo(b.value4011); foo(b.value4012); foo(b.value4013); foo(b.value4014); foo(b.value4015); foo(b.value4016); foo(b.value4017); foo(b.value4018); foo(b.value4019); foo(b.value4020); foo(b.value4021); foo(b.value4022); foo(b.value4023); foo(b.value4024); foo(b.value4025); foo(b.value4026); foo(b.value4027); foo(b.value4028); foo(b.value4029); foo(b.value4030); foo(b.value4031); foo(b.value4032); foo(b.value4033); foo(b.value4034); foo(b.value4035); foo(b.value4036); foo(b.value4037); foo(b.value4038); foo(b.value4039); foo(b.value4040); foo(b.value4041); foo(b.value4042); foo(b.value4043); foo(b.value4044); foo(b.value4045); foo(b.value4046); foo(b.value4047); foo(b.value4048); foo(b.value4049); foo(b.value4050); foo(b.value4051); foo(b.value4052); foo(b.value4053); foo(b.value4054); foo(b.value4055); foo(b.value4056); foo(b.value4057); foo(b.value4058); foo(b.value4059); foo(b.value4060); foo(b.value4061); foo(b.value4062); foo(b.value4063); foo(b.value4064); foo(b.value4065); foo(b.value4066); foo(b.value4067); foo(b.value4068); foo(b.value4069); foo(b.value4070); foo(b.value4071); foo(b.value4072); foo(b.value4073); foo(b.value4074); foo(b.value4075); foo(b.value4076); foo(b.value4077); foo(b.value4078); foo(b.value4079); foo(b.value4080); foo(b.value4081); foo(b.value4082); foo(b.value4083); foo(b.value4084); foo(b.value4085); foo(b.value4086); foo(b.value4087); foo(b.value4088); foo(b.value4089); foo(b.value4090); foo(b.value4091); foo(b.value4092); foo(b.value4093); foo(b.value4094); foo(b.value4095); foo(b.value4096); foo(b.value4097); foo(b.value4098); foo(b.value4099); foo(b.value4100); foo(b.value4101); foo(b.value4102); foo(b.value4103); foo(b.value4104); foo(b.value4105); foo(b.value4106); foo(b.value4107); foo(b.value4108); foo(b.value4109); foo(b.value4110); foo(b.value4111); foo(b.value4112); foo(b.value4113); foo(b.value4114); foo(b.value4115); foo(b.value4116); foo(b.value4117); foo(b.value4118); foo(b.value4119); foo(b.value4120); foo(b.value4121); foo(b.value4122); foo(b.value4123); foo(b.value4124); foo(b.value4125); foo(b.value4126); foo(b.value4127); foo(b.value4128); foo(b.value4129); foo(b.value4130); foo(b.value4131); foo(b.value4132); foo(b.value4133); foo(b.value4134); foo(b.value4135); foo(b.value4136); foo(b.value4137); foo(b.value4138); foo(b.value4139); foo(b.value4140); foo(b.value4141); foo(b.value4142); foo(b.value4143); foo(b.value4144); foo(b.value4145); foo(b.value4146); foo(b.value4147); foo(b.value4148); foo(b.value4149); foo(b.value4150); foo(b.value4151); foo(b.value4152); foo(b.value4153); foo(b.value4154); foo(b.value4155); foo(b.value4156); foo(b.value4157); foo(b.value4158); foo(b.value4159); foo(b.value4160); foo(b.value4161); foo(b.value4162); foo(b.value4163); foo(b.value4164); foo(b.value4165); foo(b.value4166); foo(b.value4167); foo(b.value4168); foo(b.value4169); foo(b.value4170); foo(b.value4171); foo(b.value4172); foo(b.value4173); foo(b.value4174); foo(b.value4175); foo(b.value4176); foo(b.value4177); foo(b.value4178); foo(b.value4179); foo(b.value4180); foo(b.value4181); foo(b.value4182); foo(b.value4183); foo(b.value4184); foo(b.value4185); foo(b.value4186); foo(b.value4187); foo(b.value4188); foo(b.value4189); foo(b.value4190); foo(b.value4191); foo(b.value4192); foo(b.value4193); foo(b.value4194); foo(b.value4195); foo(b.value4196); foo(b.value4197); foo(b.value4198); foo(b.value4199); foo(b.value4200); foo(b.value4201); foo(b.value4202); foo(b.value4203); foo(b.value4204); foo(b.value4205); foo(b.value4206); foo(b.value4207); foo(b.value4208); foo(b.value4209); foo(b.value4210); foo(b.value4211); foo(b.value4212); foo(b.value4213); foo(b.value4214); foo(b.value4215); foo(b.value4216); foo(b.value4217); foo(b.value4218); foo(b.value4219); foo(b.value4220); foo(b.value4221); foo(b.value4222); foo(b.value4223); foo(b.value4224); foo(b.value4225); foo(b.value4226); foo(b.value4227); foo(b.value4228); foo(b.value4229); foo(b.value4230); foo(b.value4231); foo(b.value4232); foo(b.value4233); foo(b.value4234); foo(b.value4235); foo(b.value4236); foo(b.value4237); foo(b.value4238); foo(b.value4239); foo(b.value4240); foo(b.value4241); foo(b.value4242); foo(b.value4243); foo(b.value4244); foo(b.value4245); foo(b.value4246); foo(b.value4247); foo(b.value4248); foo(b.value4249); foo(b.value4250); foo(b.value4251); foo(b.value4252); foo(b.value4253); foo(b.value4254); foo(b.value4255); foo(b.value4256); foo(b.value4257); foo(b.value4258); foo(b.value4259); foo(b.value4260); foo(b.value4261); foo(b.value4262); foo(b.value4263); foo(b.value4264); foo(b.value4265); foo(b.value4266); foo(b.value4267); foo(b.value4268); foo(b.value4269); foo(b.value4270); foo(b.value4271); foo(b.value4272); foo(b.value4273); foo(b.value4274); foo(b.value4275); foo(b.value4276); foo(b.value4277); foo(b.value4278); foo(b.value4279); foo(b.value4280); foo(b.value4281); foo(b.value4282); foo(b.value4283); foo(b.value4284); foo(b.value4285); foo(b.value4286); foo(b.value4287); foo(b.value4288); foo(b.value4289); foo(b.value4290); foo(b.value4291); foo(b.value4292); foo(b.value4293); foo(b.value4294); foo(b.value4295); foo(b.value4296); foo(b.value4297); foo(b.value4298); foo(b.value4299); foo(b.value4300); foo(b.value4301); foo(b.value4302); foo(b.value4303); foo(b.value4304); foo(b.value4305); foo(b.value4306); foo(b.value4307); foo(b.value4308); foo(b.value4309); foo(b.value4310); foo(b.value4311); foo(b.value4312); foo(b.value4313); foo(b.value4314); foo(b.value4315); foo(b.value4316); foo(b.value4317); foo(b.value4318); foo(b.value4319); foo(b.value4320); foo(b.value4321); foo(b.value4322); foo(b.value4323); foo(b.value4324); foo(b.value4325); foo(b.value4326); foo(b.value4327); foo(b.value4328); foo(b.value4329); foo(b.value4330); foo(b.value4331); foo(b.value4332); foo(b.value4333); foo(b.value4334); foo(b.value4335); foo(b.value4336); foo(b.value4337); foo(b.value4338); foo(b.value4339); foo(b.value4340); foo(b.value4341); foo(b.value4342); foo(b.value4343); foo(b.value4344); foo(b.value4345); foo(b.value4346); foo(b.value4347); foo(b.value4348); foo(b.value4349); foo(b.value4350); foo(b.value4351); foo(b.value4352); foo(b.value4353); foo(b.value4354); foo(b.value4355); foo(b.value4356); foo(b.value4357); foo(b.value4358); foo(b.value4359); foo(b.value4360); foo(b.value4361); foo(b.value4362); foo(b.value4363); foo(b.value4364); foo(b.value4365); foo(b.value4366); foo(b.value4367); foo(b.value4368); foo(b.value4369); foo(b.value4370); foo(b.value4371); foo(b.value4372); foo(b.value4373); foo(b.value4374); foo(b.value4375); foo(b.value4376); foo(b.value4377); foo(b.value4378); foo(b.value4379); foo(b.value4380); foo(b.value4381); foo(b.value4382); foo(b.value4383); foo(b.value4384); foo(b.value4385); foo(b.value4386); foo(b.value4387); foo(b.value4388); foo(b.value4389); foo(b.value4390); foo(b.value4391); foo(b.value4392); foo(b.value4393); foo(b.value4394); foo(b.value4395); foo(b.value4396); foo(b.value4397); foo(b.value4398); foo(b.value4399); foo(b.value4400); foo(b.value4401); foo(b.value4402); foo(b.value4403); foo(b.value4404); foo(b.value4405); foo(b.value4406); foo(b.value4407); foo(b.value4408); foo(b.value4409); foo(b.value4410); foo(b.value4411); foo(b.value4412); foo(b.value4413); foo(b.value4414); foo(b.value4415); foo(b.value4416); foo(b.value4417); foo(b.value4418); foo(b.value4419); foo(b.value4420); foo(b.value4421); foo(b.value4422); foo(b.value4423); foo(b.value4424); foo(b.value4425); foo(b.value4426); foo(b.value4427); foo(b.value4428); foo(b.value4429); foo(b.value4430); foo(b.value4431); foo(b.value4432); foo(b.value4433); foo(b.value4434); foo(b.value4435); foo(b.value4436); foo(b.value4437); foo(b.value4438); foo(b.value4439); foo(b.value4440); foo(b.value4441); foo(b.value4442); foo(b.value4443); foo(b.value4444); foo(b.value4445); foo(b.value4446); foo(b.value4447); foo(b.value4448); foo(b.value4449); foo(b.value4450); foo(b.value4451); foo(b.value4452); foo(b.value4453); foo(b.value4454); foo(b.value4455); foo(b.value4456); foo(b.value4457); foo(b.value4458); foo(b.value4459); foo(b.value4460); foo(b.value4461); foo(b.value4462); foo(b.value4463); foo(b.value4464); foo(b.value4465); foo(b.value4466); foo(b.value4467); foo(b.value4468); foo(b.value4469); foo(b.value4470); foo(b.value4471); foo(b.value4472); foo(b.value4473); foo(b.value4474); foo(b.value4475); foo(b.value4476); foo(b.value4477); foo(b.value4478); foo(b.value4479); foo(b.value4480); foo(b.value4481); foo(b.value4482); foo(b.value4483); foo(b.value4484); foo(b.value4485); foo(b.value4486); foo(b.value4487); foo(b.value4488); foo(b.value4489); foo(b.value4490); foo(b.value4491); foo(b.value4492); foo(b.value4493); foo(b.value4494); foo(b.value4495); foo(b.value4496); foo(b.value4497); foo(b.value4498); foo(b.value4499); foo(b.value4500); foo(b.value4501); foo(b.value4502); foo(b.value4503); foo(b.value4504); foo(b.value4505); foo(b.value4506); foo(b.value4507); foo(b.value4508); foo(b.value4509); foo(b.value4510); foo(b.value4511); foo(b.value4512); foo(b.value4513); foo(b.value4514); foo(b.value4515); foo(b.value4516); foo(b.value4517); foo(b.value4518); foo(b.value4519); foo(b.value4520); foo(b.value4521); foo(b.value4522); foo(b.value4523); foo(b.value4524); foo(b.value4525); foo(b.value4526); foo(b.value4527); foo(b.value4528); foo(b.value4529); foo(b.value4530); foo(b.value4531); foo(b.value4532); foo(b.value4533); foo(b.value4534); foo(b.value4535); foo(b.value4536); foo(b.value4537); foo(b.value4538); foo(b.value4539); foo(b.value4540); foo(b.value4541); foo(b.value4542); foo(b.value4543); foo(b.value4544); foo(b.value4545); foo(b.value4546); foo(b.value4547); foo(b.value4548); foo(b.value4549); foo(b.value4550); foo(b.value4551); foo(b.value4552); foo(b.value4553); foo(b.value4554); foo(b.value4555); foo(b.value4556); foo(b.value4557); foo(b.value4558); foo(b.value4559); foo(b.value4560); foo(b.value4561); foo(b.value4562); foo(b.value4563); foo(b.value4564); foo(b.value4565); foo(b.value4566); foo(b.value4567); foo(b.value4568); foo(b.value4569); foo(b.value4570); foo(b.value4571); foo(b.value4572); foo(b.value4573); foo(b.value4574); foo(b.value4575); foo(b.value4576); foo(b.value4577); foo(b.value4578); foo(b.value4579); foo(b.value4580); foo(b.value4581); foo(b.value4582); foo(b.value4583); foo(b.value4584); foo(b.value4585); foo(b.value4586); foo(b.value4587); foo(b.value4588); foo(b.value4589); foo(b.value4590); foo(b.value4591); foo(b.value4592); foo(b.value4593); foo(b.value4594); foo(b.value4595); foo(b.value4596); foo(b.value4597); foo(b.value4598); foo(b.value4599); foo(b.value4600); foo(b.value4601); foo(b.value4602); foo(b.value4603); foo(b.value4604); foo(b.value4605); foo(b.value4606); foo(b.value4607); foo(b.value4608); foo(b.value4609); foo(b.value4610); foo(b.value4611); foo(b.value4612); foo(b.value4613); foo(b.value4614); foo(b.value4615); foo(b.value4616); foo(b.value4617); foo(b.value4618); foo(b.value4619); foo(b.value4620); foo(b.value4621); foo(b.value4622); foo(b.value4623); foo(b.value4624); foo(b.value4625); foo(b.value4626); foo(b.value4627); foo(b.value4628); foo(b.value4629); foo(b.value4630); foo(b.value4631); foo(b.value4632); foo(b.value4633); foo(b.value4634); foo(b.value4635); foo(b.value4636); foo(b.value4637); foo(b.value4638); foo(b.value4639); foo(b.value4640); foo(b.value4641); foo(b.value4642); foo(b.value4643); foo(b.value4644); foo(b.value4645); foo(b.value4646); foo(b.value4647); foo(b.value4648); foo(b.value4649); foo(b.value4650); foo(b.value4651); foo(b.value4652); foo(b.value4653); foo(b.value4654); foo(b.value4655); foo(b.value4656); foo(b.value4657); foo(b.value4658); foo(b.value4659); foo(b.value4660); foo(b.value4661); foo(b.value4662); foo(b.value4663); foo(b.value4664); foo(b.value4665); foo(b.value4666); foo(b.value4667); foo(b.value4668); foo(b.value4669); foo(b.value4670); foo(b.value4671); foo(b.value4672); foo(b.value4673); foo(b.value4674); foo(b.value4675); foo(b.value4676); foo(b.value4677); foo(b.value4678); foo(b.value4679); foo(b.value4680); foo(b.value4681); foo(b.value4682); foo(b.value4683); foo(b.value4684); foo(b.value4685); foo(b.value4686); foo(b.value4687); foo(b.value4688); foo(b.value4689); foo(b.value4690); foo(b.value4691); foo(b.value4692); foo(b.value4693); foo(b.value4694); foo(b.value4695); foo(b.value4696); foo(b.value4697); foo(b.value4698); foo(b.value4699); foo(b.value4700); foo(b.value4701); foo(b.value4702); foo(b.value4703); foo(b.value4704); foo(b.value4705); foo(b.value4706); foo(b.value4707); foo(b.value4708); foo(b.value4709); foo(b.value4710); foo(b.value4711); foo(b.value4712); foo(b.value4713); foo(b.value4714); foo(b.value4715); foo(b.value4716); foo(b.value4717); foo(b.value4718); foo(b.value4719); foo(b.value4720); foo(b.value4721); foo(b.value4722); foo(b.value4723); foo(b.value4724); foo(b.value4725); foo(b.value4726); foo(b.value4727); foo(b.value4728); foo(b.value4729); foo(b.value4730); foo(b.value4731); foo(b.value4732); foo(b.value4733); foo(b.value4734); foo(b.value4735); foo(b.value4736); foo(b.value4737); foo(b.value4738); foo(b.value4739); foo(b.value4740); foo(b.value4741); foo(b.value4742); foo(b.value4743); foo(b.value4744); foo(b.value4745); foo(b.value4746); foo(b.value4747); foo(b.value4748); foo(b.value4749); foo(b.value4750); foo(b.value4751); foo(b.value4752); foo(b.value4753); foo(b.value4754); foo(b.value4755); foo(b.value4756); foo(b.value4757); foo(b.value4758); foo(b.value4759); foo(b.value4760); foo(b.value4761); foo(b.value4762); foo(b.value4763); foo(b.value4764); foo(b.value4765); foo(b.value4766); foo(b.value4767); foo(b.value4768); foo(b.value4769); foo(b.value4770); foo(b.value4771); foo(b.value4772); foo(b.value4773); foo(b.value4774); foo(b.value4775); foo(b.value4776); foo(b.value4777); foo(b.value4778); foo(b.value4779); foo(b.value4780); foo(b.value4781); foo(b.value4782); foo(b.value4783); foo(b.value4784); foo(b.value4785); foo(b.value4786); foo(b.value4787); foo(b.value4788); foo(b.value4789); foo(b.value4790); foo(b.value4791); foo(b.value4792); foo(b.value4793); foo(b.value4794); foo(b.value4795); foo(b.value4796); foo(b.value4797); foo(b.value4798); foo(b.value4799); foo(b.value4800); foo(b.value4801); foo(b.value4802); foo(b.value4803); foo(b.value4804); foo(b.value4805); foo(b.value4806); foo(b.value4807); foo(b.value4808); foo(b.value4809); foo(b.value4810); foo(b.value4811); foo(b.value4812); foo(b.value4813); foo(b.value4814); foo(b.value4815); foo(b.value4816); foo(b.value4817); foo(b.value4818); foo(b.value4819); foo(b.value4820); foo(b.value4821); foo(b.value4822); foo(b.value4823); foo(b.value4824); foo(b.value4825); foo(b.value4826); foo(b.value4827); foo(b.value4828); foo(b.value4829); foo(b.value4830); foo(b.value4831); foo(b.value4832); foo(b.value4833); foo(b.value4834); foo(b.value4835); foo(b.value4836); foo(b.value4837); foo(b.value4838); foo(b.value4839); foo(b.value4840); foo(b.value4841); foo(b.value4842); foo(b.value4843); foo(b.value4844); foo(b.value4845); foo(b.value4846); foo(b.value4847); foo(b.value4848); foo(b.value4849); foo(b.value4850); foo(b.value4851); foo(b.value4852); foo(b.value4853); foo(b.value4854); foo(b.value4855); foo(b.value4856); foo(b.value4857); foo(b.value4858); foo(b.value4859); foo(b.value4860); foo(b.value4861); foo(b.value4862); foo(b.value4863); foo(b.value4864); foo(b.value4865); foo(b.value4866); foo(b.value4867); foo(b.value4868); foo(b.value4869); foo(b.value4870); foo(b.value4871); foo(b.value4872); foo(b.value4873); foo(b.value4874); foo(b.value4875); foo(b.value4876); foo(b.value4877); foo(b.value4878); foo(b.value4879); foo(b.value4880); foo(b.value4881); foo(b.value4882); foo(b.value4883); foo(b.value4884); foo(b.value4885); foo(b.value4886); foo(b.value4887); foo(b.value4888); foo(b.value4889); foo(b.value4890); foo(b.value4891); foo(b.value4892); foo(b.value4893); foo(b.value4894); foo(b.value4895); foo(b.value4896); foo(b.value4897); foo(b.value4898); foo(b.value4899); foo(b.value4900); foo(b.value4901); foo(b.value4902); foo(b.value4903); foo(b.value4904); foo(b.value4905); foo(b.value4906); foo(b.value4907); foo(b.value4908); foo(b.value4909); foo(b.value4910); foo(b.value4911); foo(b.value4912); foo(b.value4913); foo(b.value4914); foo(b.value4915); foo(b.value4916); foo(b.value4917); foo(b.value4918); foo(b.value4919); foo(b.value4920); foo(b.value4921); foo(b.value4922); foo(b.value4923); foo(b.value4924); foo(b.value4925); foo(b.value4926); foo(b.value4927); foo(b.value4928); foo(b.value4929); foo(b.value4930); foo(b.value4931); foo(b.value4932); foo(b.value4933); foo(b.value4934); foo(b.value4935); foo(b.value4936); foo(b.value4937); foo(b.value4938); foo(b.value4939); foo(b.value4940); foo(b.value4941); foo(b.value4942); foo(b.value4943); foo(b.value4944); foo(b.value4945); foo(b.value4946); foo(b.value4947); foo(b.value4948); foo(b.value4949); foo(b.value4950); foo(b.value4951); foo(b.value4952); foo(b.value4953); foo(b.value4954); foo(b.value4955); foo(b.value4956); foo(b.value4957); foo(b.value4958); foo(b.value4959); foo(b.value4960); foo(b.value4961); foo(b.value4962); foo(b.value4963); foo(b.value4964); foo(b.value4965); foo(b.value4966); foo(b.value4967); foo(b.value4968); foo(b.value4969); foo(b.value4970); foo(b.value4971); foo(b.value4972); foo(b.value4973); foo(b.value4974); foo(b.value4975); foo(b.value4976); foo(b.value4977); foo(b.value4978); foo(b.value4979); foo(b.value4980); foo(b.value4981); foo(b.value4982); foo(b.value4983); foo(b.value4984); foo(b.value4985); foo(b.value4986); foo(b.value4987); foo(b.value4988); foo(b.value4989); foo(b.value4990); foo(b.value4991); foo(b.value4992); foo(b.value4993); foo(b.value4994); foo(b.value4995); foo(b.value4996); foo(b.value4997); foo(b.value4998); foo(b.value4999); foo(b.value5000); foo(b.value5001); foo(b.value5002); foo(b.value5003); foo(b.value5004); foo(b.value5005); foo(b.value5006); foo(b.value5007); foo(b.value5008); foo(b.value5009); foo(b.value5010); foo(b.value5011); foo(b.value5012); foo(b.value5013); foo(b.value5014); foo(b.value5015); foo(b.value5016); foo(b.value5017); foo(b.value5018); foo(b.value5019); foo(b.value5020); foo(b.value5021); foo(b.value5022); foo(b.value5023); foo(b.value5024); foo(b.value5025); foo(b.value5026); foo(b.value5027); foo(b.value5028); foo(b.value5029); foo(b.value5030); foo(b.value5031); foo(b.value5032); foo(b.value5033); foo(b.value5034); foo(b.value5035); foo(b.value5036); foo(b.value5037); foo(b.value5038); foo(b.value5039); foo(b.value5040); foo(b.value5041); foo(b.value5042); foo(b.value5043); foo(b.value5044); foo(b.value5045); foo(b.value5046); foo(b.value5047); foo(b.value5048); foo(b.value5049); foo(b.value5050); foo(b.value5051); foo(b.value5052); foo(b.value5053); foo(b.value5054); foo(b.value5055); foo(b.value5056); foo(b.value5057); foo(b.value5058); foo(b.value5059); foo(b.value5060); foo(b.value5061); foo(b.value5062); foo(b.value5063); foo(b.value5064); foo(b.value5065); foo(b.value5066); foo(b.value5067); foo(b.value5068); foo(b.value5069); foo(b.value5070); foo(b.value5071); foo(b.value5072); foo(b.value5073); foo(b.value5074); foo(b.value5075); foo(b.value5076); foo(b.value5077); foo(b.value5078); foo(b.value5079); foo(b.value5080); foo(b.value5081); foo(b.value5082); foo(b.value5083); foo(b.value5084); foo(b.value5085); foo(b.value5086); foo(b.value5087); foo(b.value5088); foo(b.value5089); foo(b.value5090); foo(b.value5091); foo(b.value5092); foo(b.value5093); foo(b.value5094); foo(b.value5095); foo(b.value5096); foo(b.value5097); foo(b.value5098); foo(b.value5099); foo(b.value5100); foo(b.value5101); foo(b.value5102); foo(b.value5103); foo(b.value5104); foo(b.value5105); foo(b.value5106); foo(b.value5107); foo(b.value5108); foo(b.value5109); foo(b.value5110); foo(b.value5111); foo(b.value5112); foo(b.value5113); foo(b.value5114); foo(b.value5115); foo(b.value5116); foo(b.value5117); foo(b.value5118); foo(b.value5119); foo(b.value5120); foo(b.value5121); foo(b.value5122); foo(b.value5123); foo(b.value5124); foo(b.value5125); foo(b.value5126); foo(b.value5127); foo(b.value5128); foo(b.value5129); foo(b.value5130); foo(b.value5131); foo(b.value5132); foo(b.value5133); foo(b.value5134); foo(b.value5135); foo(b.value5136); foo(b.value5137); foo(b.value5138); foo(b.value5139); foo(b.value5140); foo(b.value5141); foo(b.value5142); foo(b.value5143); foo(b.value5144); foo(b.value5145); foo(b.value5146); foo(b.value5147); foo(b.value5148); foo(b.value5149); foo(b.value5150); foo(b.value5151); foo(b.value5152); foo(b.value5153); foo(b.value5154); foo(b.value5155); foo(b.value5156); foo(b.value5157); foo(b.value5158); foo(b.value5159); foo(b.value5160); foo(b.value5161); foo(b.value5162); foo(b.value5163); foo(b.value5164); foo(b.value5165); foo(b.value5166); foo(b.value5167); foo(b.value5168); foo(b.value5169); foo(b.value5170); foo(b.value5171); foo(b.value5172); foo(b.value5173); foo(b.value5174); foo(b.value5175); foo(b.value5176); foo(b.value5177); foo(b.value5178); foo(b.value5179); foo(b.value5180); foo(b.value5181); foo(b.value5182); foo(b.value5183); foo(b.value5184); foo(b.value5185); foo(b.value5186); foo(b.value5187); foo(b.value5188); foo(b.value5189); foo(b.value5190); foo(b.value5191); foo(b.value5192); foo(b.value5193); foo(b.value5194); foo(b.value5195); foo(b.value5196); foo(b.value5197); foo(b.value5198); foo(b.value5199); foo(b.value5200); foo(b.value5201); foo(b.value5202); foo(b.value5203); foo(b.value5204); foo(b.value5205); foo(b.value5206); foo(b.value5207); foo(b.value5208); foo(b.value5209); foo(b.value5210); foo(b.value5211); foo(b.value5212); foo(b.value5213); foo(b.value5214); foo(b.value5215); foo(b.value5216); foo(b.value5217); foo(b.value5218); foo(b.value5219); foo(b.value5220); foo(b.value5221); foo(b.value5222); foo(b.value5223); foo(b.value5224); foo(b.value5225); foo(b.value5226); foo(b.value5227); foo(b.value5228); foo(b.value5229); foo(b.value5230); foo(b.value5231); foo(b.value5232); foo(b.value5233); foo(b.value5234); foo(b.value5235); foo(b.value5236); foo(b.value5237); foo(b.value5238); foo(b.value5239); foo(b.value5240); foo(b.value5241); foo(b.value5242); foo(b.value5243); foo(b.value5244); foo(b.value5245); foo(b.value5246); foo(b.value5247); foo(b.value5248); } } } ListWrite.new("List Read").run(); ================================================ FILE: microbenchmarks/attribute_write.aria ================================================ # SPDX-License-Identifier: Apache-2.0 import aria.range.int_extension; import Microbenchmark from infra; struct ListWrite : Microbenchmark { func test() { for i in 0.to(50) { val b = Box(); b.value0 = 0; b.value1 = 1; b.value2 = 2; b.value3 = 3; b.value4 = 4; b.value5 = 5; b.value6 = 6; b.value7 = 7; b.value8 = 8; b.value9 = 9; b.value10 = 10; b.value11 = 11; b.value12 = 12; b.value13 = 13; b.value14 = 14; b.value15 = 15; b.value16 = 16; b.value17 = 17; b.value18 = 18; b.value19 = 19; b.value20 = 20; b.value21 = 21; b.value22 = 22; b.value23 = 23; b.value24 = 24; b.value25 = 25; b.value26 = 26; b.value27 = 27; b.value28 = 28; b.value29 = 29; b.value30 = 30; b.value31 = 31; b.value32 = 32; b.value33 = 33; b.value34 = 34; b.value35 = 35; b.value36 = 36; b.value37 = 37; b.value38 = 38; b.value39 = 39; b.value40 = 40; b.value41 = 41; b.value42 = 42; b.value43 = 43; b.value44 = 44; b.value45 = 45; b.value46 = 46; b.value47 = 47; b.value48 = 48; b.value49 = 49; b.value50 = 50; b.value51 = 51; b.value52 = 52; b.value53 = 53; b.value54 = 54; b.value55 = 55; b.value56 = 56; b.value57 = 57; b.value58 = 58; b.value59 = 59; b.value60 = 60; b.value61 = 61; b.value62 = 62; b.value63 = 63; b.value64 = 64; b.value65 = 65; b.value66 = 66; b.value67 = 67; b.value68 = 68; b.value69 = 69; b.value70 = 70; b.value71 = 71; b.value72 = 72; b.value73 = 73; b.value74 = 74; b.value75 = 75; b.value76 = 76; b.value77 = 77; b.value78 = 78; b.value79 = 79; b.value80 = 80; b.value81 = 81; b.value82 = 82; b.value83 = 83; b.value84 = 84; b.value85 = 85; b.value86 = 86; b.value87 = 87; b.value88 = 88; b.value89 = 89; b.value90 = 90; b.value91 = 91; b.value92 = 92; b.value93 = 93; b.value94 = 94; b.value95 = 95; b.value96 = 96; b.value97 = 97; b.value98 = 98; b.value99 = 99; b.value100 = 100; b.value101 = 101; b.value102 = 102; b.value103 = 103; b.value104 = 104; b.value105 = 105; b.value106 = 106; b.value107 = 107; b.value108 = 108; b.value109 = 109; b.value110 = 110; b.value111 = 111; b.value112 = 112; b.value113 = 113; b.value114 = 114; b.value115 = 115; b.value116 = 116; b.value117 = 117; b.value118 = 118; b.value119 = 119; b.value120 = 120; b.value121 = 121; b.value122 = 122; b.value123 = 123; b.value124 = 124; b.value125 = 125; b.value126 = 126; b.value127 = 127; b.value128 = 128; b.value129 = 129; b.value130 = 130; b.value131 = 131; b.value132 = 132; b.value133 = 133; b.value134 = 134; b.value135 = 135; b.value136 = 136; b.value137 = 137; b.value138 = 138; b.value139 = 139; b.value140 = 140; b.value141 = 141; b.value142 = 142; b.value143 = 143; b.value144 = 144; b.value145 = 145; b.value146 = 146; b.value147 = 147; b.value148 = 148; b.value149 = 149; b.value150 = 150; b.value151 = 151; b.value152 = 152; b.value153 = 153; b.value154 = 154; b.value155 = 155; b.value156 = 156; b.value157 = 157; b.value158 = 158; b.value159 = 159; b.value160 = 160; b.value161 = 161; b.value162 = 162; b.value163 = 163; b.value164 = 164; b.value165 = 165; b.value166 = 166; b.value167 = 167; b.value168 = 168; b.value169 = 169; b.value170 = 170; b.value171 = 171; b.value172 = 172; b.value173 = 173; b.value174 = 174; b.value175 = 175; b.value176 = 176; b.value177 = 177; b.value178 = 178; b.value179 = 179; b.value180 = 180; b.value181 = 181; b.value182 = 182; b.value183 = 183; b.value184 = 184; b.value185 = 185; b.value186 = 186; b.value187 = 187; b.value188 = 188; b.value189 = 189; b.value190 = 190; b.value191 = 191; b.value192 = 192; b.value193 = 193; b.value194 = 194; b.value195 = 195; b.value196 = 196; b.value197 = 197; b.value198 = 198; b.value199 = 199; b.value200 = 200; b.value201 = 201; b.value202 = 202; b.value203 = 203; b.value204 = 204; b.value205 = 205; b.value206 = 206; b.value207 = 207; b.value208 = 208; b.value209 = 209; b.value210 = 210; b.value211 = 211; b.value212 = 212; b.value213 = 213; b.value214 = 214; b.value215 = 215; b.value216 = 216; b.value217 = 217; b.value218 = 218; b.value219 = 219; b.value220 = 220; b.value221 = 221; b.value222 = 222; b.value223 = 223; b.value224 = 224; b.value225 = 225; b.value226 = 226; b.value227 = 227; b.value228 = 228; b.value229 = 229; b.value230 = 230; b.value231 = 231; b.value232 = 232; b.value233 = 233; b.value234 = 234; b.value235 = 235; b.value236 = 236; b.value237 = 237; b.value238 = 238; b.value239 = 239; b.value240 = 240; b.value241 = 241; b.value242 = 242; b.value243 = 243; b.value244 = 244; b.value245 = 245; b.value246 = 246; b.value247 = 247; b.value248 = 248; b.value249 = 249; b.value250 = 250; b.value251 = 251; b.value252 = 252; b.value253 = 253; b.value254 = 254; b.value255 = 255; b.value256 = 256; b.value257 = 257; b.value258 = 258; b.value259 = 259; b.value260 = 260; b.value261 = 261; b.value262 = 262; b.value263 = 263; b.value264 = 264; b.value265 = 265; b.value266 = 266; b.value267 = 267; b.value268 = 268; b.value269 = 269; b.value270 = 270; b.value271 = 271; b.value272 = 272; b.value273 = 273; b.value274 = 274; b.value275 = 275; b.value276 = 276; b.value277 = 277; b.value278 = 278; b.value279 = 279; b.value280 = 280; b.value281 = 281; b.value282 = 282; b.value283 = 283; b.value284 = 284; b.value285 = 285; b.value286 = 286; b.value287 = 287; b.value288 = 288; b.value289 = 289; b.value290 = 290; b.value291 = 291; b.value292 = 292; b.value293 = 293; b.value294 = 294; b.value295 = 295; b.value296 = 296; b.value297 = 297; b.value298 = 298; b.value299 = 299; b.value300 = 300; b.value301 = 301; b.value302 = 302; b.value303 = 303; b.value304 = 304; b.value305 = 305; b.value306 = 306; b.value307 = 307; b.value308 = 308; b.value309 = 309; b.value310 = 310; b.value311 = 311; b.value312 = 312; b.value313 = 313; b.value314 = 314; b.value315 = 315; b.value316 = 316; b.value317 = 317; b.value318 = 318; b.value319 = 319; b.value320 = 320; b.value321 = 321; b.value322 = 322; b.value323 = 323; b.value324 = 324; b.value325 = 325; b.value326 = 326; b.value327 = 327; b.value328 = 328; b.value329 = 329; b.value330 = 330; b.value331 = 331; b.value332 = 332; b.value333 = 333; b.value334 = 334; b.value335 = 335; b.value336 = 336; b.value337 = 337; b.value338 = 338; b.value339 = 339; b.value340 = 340; b.value341 = 341; b.value342 = 342; b.value343 = 343; b.value344 = 344; b.value345 = 345; b.value346 = 346; b.value347 = 347; b.value348 = 348; b.value349 = 349; b.value350 = 350; b.value351 = 351; b.value352 = 352; b.value353 = 353; b.value354 = 354; b.value355 = 355; b.value356 = 356; b.value357 = 357; b.value358 = 358; b.value359 = 359; b.value360 = 360; b.value361 = 361; b.value362 = 362; b.value363 = 363; b.value364 = 364; b.value365 = 365; b.value366 = 366; b.value367 = 367; b.value368 = 368; b.value369 = 369; b.value370 = 370; b.value371 = 371; b.value372 = 372; b.value373 = 373; b.value374 = 374; b.value375 = 375; b.value376 = 376; b.value377 = 377; b.value378 = 378; b.value379 = 379; b.value380 = 380; b.value381 = 381; b.value382 = 382; b.value383 = 383; b.value384 = 384; b.value385 = 385; b.value386 = 386; b.value387 = 387; b.value388 = 388; b.value389 = 389; b.value390 = 390; b.value391 = 391; b.value392 = 392; b.value393 = 393; b.value394 = 394; b.value395 = 395; b.value396 = 396; b.value397 = 397; b.value398 = 398; b.value399 = 399; b.value400 = 400; b.value401 = 401; b.value402 = 402; b.value403 = 403; b.value404 = 404; b.value405 = 405; b.value406 = 406; b.value407 = 407; b.value408 = 408; b.value409 = 409; b.value410 = 410; b.value411 = 411; b.value412 = 412; b.value413 = 413; b.value414 = 414; b.value415 = 415; b.value416 = 416; b.value417 = 417; b.value418 = 418; b.value419 = 419; b.value420 = 420; b.value421 = 421; b.value422 = 422; b.value423 = 423; b.value424 = 424; b.value425 = 425; b.value426 = 426; b.value427 = 427; b.value428 = 428; b.value429 = 429; b.value430 = 430; b.value431 = 431; b.value432 = 432; b.value433 = 433; b.value434 = 434; b.value435 = 435; b.value436 = 436; b.value437 = 437; b.value438 = 438; b.value439 = 439; b.value440 = 440; b.value441 = 441; b.value442 = 442; b.value443 = 443; b.value444 = 444; b.value445 = 445; b.value446 = 446; b.value447 = 447; b.value448 = 448; b.value449 = 449; b.value450 = 450; b.value451 = 451; b.value452 = 452; b.value453 = 453; b.value454 = 454; b.value455 = 455; b.value456 = 456; b.value457 = 457; b.value458 = 458; b.value459 = 459; b.value460 = 460; b.value461 = 461; b.value462 = 462; b.value463 = 463; b.value464 = 464; b.value465 = 465; b.value466 = 466; b.value467 = 467; b.value468 = 468; b.value469 = 469; b.value470 = 470; b.value471 = 471; b.value472 = 472; b.value473 = 473; b.value474 = 474; b.value475 = 475; b.value476 = 476; b.value477 = 477; b.value478 = 478; b.value479 = 479; b.value480 = 480; b.value481 = 481; b.value482 = 482; b.value483 = 483; b.value484 = 484; b.value485 = 485; b.value486 = 486; b.value487 = 487; b.value488 = 488; b.value489 = 489; b.value490 = 490; b.value491 = 491; b.value492 = 492; b.value493 = 493; b.value494 = 494; b.value495 = 495; b.value496 = 496; b.value497 = 497; b.value498 = 498; b.value499 = 499; b.value500 = 500; b.value501 = 501; b.value502 = 502; b.value503 = 503; b.value504 = 504; b.value505 = 505; b.value506 = 506; b.value507 = 507; b.value508 = 508; b.value509 = 509; b.value510 = 510; b.value511 = 511; b.value512 = 512; b.value513 = 513; b.value514 = 514; b.value515 = 515; b.value516 = 516; b.value517 = 517; b.value518 = 518; b.value519 = 519; b.value520 = 520; b.value521 = 521; b.value522 = 522; b.value523 = 523; b.value524 = 524; b.value525 = 525; b.value526 = 526; b.value527 = 527; b.value528 = 528; b.value529 = 529; b.value530 = 530; b.value531 = 531; b.value532 = 532; b.value533 = 533; b.value534 = 534; b.value535 = 535; b.value536 = 536; b.value537 = 537; b.value538 = 538; b.value539 = 539; b.value540 = 540; b.value541 = 541; b.value542 = 542; b.value543 = 543; b.value544 = 544; b.value545 = 545; b.value546 = 546; b.value547 = 547; b.value548 = 548; b.value549 = 549; b.value550 = 550; b.value551 = 551; b.value552 = 552; b.value553 = 553; b.value554 = 554; b.value555 = 555; b.value556 = 556; b.value557 = 557; b.value558 = 558; b.value559 = 559; b.value560 = 560; b.value561 = 561; b.value562 = 562; b.value563 = 563; b.value564 = 564; b.value565 = 565; b.value566 = 566; b.value567 = 567; b.value568 = 568; b.value569 = 569; b.value570 = 570; b.value571 = 571; b.value572 = 572; b.value573 = 573; b.value574 = 574; b.value575 = 575; b.value576 = 576; b.value577 = 577; b.value578 = 578; b.value579 = 579; b.value580 = 580; b.value581 = 581; b.value582 = 582; b.value583 = 583; b.value584 = 584; b.value585 = 585; b.value586 = 586; b.value587 = 587; b.value588 = 588; b.value589 = 589; b.value590 = 590; b.value591 = 591; b.value592 = 592; b.value593 = 593; b.value594 = 594; b.value595 = 595; b.value596 = 596; b.value597 = 597; b.value598 = 598; b.value599 = 599; b.value600 = 600; b.value601 = 601; b.value602 = 602; b.value603 = 603; b.value604 = 604; b.value605 = 605; b.value606 = 606; b.value607 = 607; b.value608 = 608; b.value609 = 609; b.value610 = 610; b.value611 = 611; b.value612 = 612; b.value613 = 613; b.value614 = 614; b.value615 = 615; b.value616 = 616; b.value617 = 617; b.value618 = 618; b.value619 = 619; b.value620 = 620; b.value621 = 621; b.value622 = 622; b.value623 = 623; b.value624 = 624; b.value625 = 625; b.value626 = 626; b.value627 = 627; b.value628 = 628; b.value629 = 629; b.value630 = 630; b.value631 = 631; b.value632 = 632; b.value633 = 633; b.value634 = 634; b.value635 = 635; b.value636 = 636; b.value637 = 637; b.value638 = 638; b.value639 = 639; b.value640 = 640; b.value641 = 641; b.value642 = 642; b.value643 = 643; b.value644 = 644; b.value645 = 645; b.value646 = 646; b.value647 = 647; b.value648 = 648; b.value649 = 649; b.value650 = 650; b.value651 = 651; b.value652 = 652; b.value653 = 653; b.value654 = 654; b.value655 = 655; b.value656 = 656; b.value657 = 657; b.value658 = 658; b.value659 = 659; b.value660 = 660; b.value661 = 661; b.value662 = 662; b.value663 = 663; b.value664 = 664; b.value665 = 665; b.value666 = 666; b.value667 = 667; b.value668 = 668; b.value669 = 669; b.value670 = 670; b.value671 = 671; b.value672 = 672; b.value673 = 673; b.value674 = 674; b.value675 = 675; b.value676 = 676; b.value677 = 677; b.value678 = 678; b.value679 = 679; b.value680 = 680; b.value681 = 681; b.value682 = 682; b.value683 = 683; b.value684 = 684; b.value685 = 685; b.value686 = 686; b.value687 = 687; b.value688 = 688; b.value689 = 689; b.value690 = 690; b.value691 = 691; b.value692 = 692; b.value693 = 693; b.value694 = 694; b.value695 = 695; b.value696 = 696; b.value697 = 697; b.value698 = 698; b.value699 = 699; b.value700 = 700; b.value701 = 701; b.value702 = 702; b.value703 = 703; b.value704 = 704; b.value705 = 705; b.value706 = 706; b.value707 = 707; b.value708 = 708; b.value709 = 709; b.value710 = 710; b.value711 = 711; b.value712 = 712; b.value713 = 713; b.value714 = 714; b.value715 = 715; b.value716 = 716; b.value717 = 717; b.value718 = 718; b.value719 = 719; b.value720 = 720; b.value721 = 721; b.value722 = 722; b.value723 = 723; b.value724 = 724; b.value725 = 725; b.value726 = 726; b.value727 = 727; b.value728 = 728; b.value729 = 729; b.value730 = 730; b.value731 = 731; b.value732 = 732; b.value733 = 733; b.value734 = 734; b.value735 = 735; b.value736 = 736; b.value737 = 737; b.value738 = 738; b.value739 = 739; b.value740 = 740; b.value741 = 741; b.value742 = 742; b.value743 = 743; b.value744 = 744; b.value745 = 745; b.value746 = 746; b.value747 = 747; b.value748 = 748; b.value749 = 749; b.value750 = 750; b.value751 = 751; b.value752 = 752; b.value753 = 753; b.value754 = 754; b.value755 = 755; b.value756 = 756; b.value757 = 757; b.value758 = 758; b.value759 = 759; b.value760 = 760; b.value761 = 761; b.value762 = 762; b.value763 = 763; b.value764 = 764; b.value765 = 765; b.value766 = 766; b.value767 = 767; b.value768 = 768; b.value769 = 769; b.value770 = 770; b.value771 = 771; b.value772 = 772; b.value773 = 773; b.value774 = 774; b.value775 = 775; b.value776 = 776; b.value777 = 777; b.value778 = 778; b.value779 = 779; b.value780 = 780; b.value781 = 781; b.value782 = 782; b.value783 = 783; b.value784 = 784; b.value785 = 785; b.value786 = 786; b.value787 = 787; b.value788 = 788; b.value789 = 789; b.value790 = 790; b.value791 = 791; b.value792 = 792; b.value793 = 793; b.value794 = 794; b.value795 = 795; b.value796 = 796; b.value797 = 797; b.value798 = 798; b.value799 = 799; b.value800 = 800; b.value801 = 801; b.value802 = 802; b.value803 = 803; b.value804 = 804; b.value805 = 805; b.value806 = 806; b.value807 = 807; b.value808 = 808; b.value809 = 809; b.value810 = 810; b.value811 = 811; b.value812 = 812; b.value813 = 813; b.value814 = 814; b.value815 = 815; b.value816 = 816; b.value817 = 817; b.value818 = 818; b.value819 = 819; b.value820 = 820; b.value821 = 821; b.value822 = 822; b.value823 = 823; b.value824 = 824; b.value825 = 825; b.value826 = 826; b.value827 = 827; b.value828 = 828; b.value829 = 829; b.value830 = 830; b.value831 = 831; b.value832 = 832; b.value833 = 833; b.value834 = 834; b.value835 = 835; b.value836 = 836; b.value837 = 837; b.value838 = 838; b.value839 = 839; b.value840 = 840; b.value841 = 841; b.value842 = 842; b.value843 = 843; b.value844 = 844; b.value845 = 845; b.value846 = 846; b.value847 = 847; b.value848 = 848; b.value849 = 849; b.value850 = 850; b.value851 = 851; b.value852 = 852; b.value853 = 853; b.value854 = 854; b.value855 = 855; b.value856 = 856; b.value857 = 857; b.value858 = 858; b.value859 = 859; b.value860 = 860; b.value861 = 861; b.value862 = 862; b.value863 = 863; b.value864 = 864; b.value865 = 865; b.value866 = 866; b.value867 = 867; b.value868 = 868; b.value869 = 869; b.value870 = 870; b.value871 = 871; b.value872 = 872; b.value873 = 873; b.value874 = 874; b.value875 = 875; b.value876 = 876; b.value877 = 877; b.value878 = 878; b.value879 = 879; b.value880 = 880; b.value881 = 881; b.value882 = 882; b.value883 = 883; b.value884 = 884; b.value885 = 885; b.value886 = 886; b.value887 = 887; b.value888 = 888; b.value889 = 889; b.value890 = 890; b.value891 = 891; b.value892 = 892; b.value893 = 893; b.value894 = 894; b.value895 = 895; b.value896 = 896; b.value897 = 897; b.value898 = 898; b.value899 = 899; b.value900 = 900; b.value901 = 901; b.value902 = 902; b.value903 = 903; b.value904 = 904; b.value905 = 905; b.value906 = 906; b.value907 = 907; b.value908 = 908; b.value909 = 909; b.value910 = 910; b.value911 = 911; b.value912 = 912; b.value913 = 913; b.value914 = 914; b.value915 = 915; b.value916 = 916; b.value917 = 917; b.value918 = 918; b.value919 = 919; b.value920 = 920; b.value921 = 921; b.value922 = 922; b.value923 = 923; b.value924 = 924; b.value925 = 925; b.value926 = 926; b.value927 = 927; b.value928 = 928; b.value929 = 929; b.value930 = 930; b.value931 = 931; b.value932 = 932; b.value933 = 933; b.value934 = 934; b.value935 = 935; b.value936 = 936; b.value937 = 937; b.value938 = 938; b.value939 = 939; b.value940 = 940; b.value941 = 941; b.value942 = 942; b.value943 = 943; b.value944 = 944; b.value945 = 945; b.value946 = 946; b.value947 = 947; b.value948 = 948; b.value949 = 949; b.value950 = 950; b.value951 = 951; b.value952 = 952; b.value953 = 953; b.value954 = 954; b.value955 = 955; b.value956 = 956; b.value957 = 957; b.value958 = 958; b.value959 = 959; b.value960 = 960; b.value961 = 961; b.value962 = 962; b.value963 = 963; b.value964 = 964; b.value965 = 965; b.value966 = 966; b.value967 = 967; b.value968 = 968; b.value969 = 969; b.value970 = 970; b.value971 = 971; b.value972 = 972; b.value973 = 973; b.value974 = 974; b.value975 = 975; b.value976 = 976; b.value977 = 977; b.value978 = 978; b.value979 = 979; b.value980 = 980; b.value981 = 981; b.value982 = 982; b.value983 = 983; b.value984 = 984; b.value985 = 985; b.value986 = 986; b.value987 = 987; b.value988 = 988; b.value989 = 989; b.value990 = 990; b.value991 = 991; b.value992 = 992; b.value993 = 993; b.value994 = 994; b.value995 = 995; b.value996 = 996; b.value997 = 997; b.value998 = 998; b.value999 = 999; b.value1000 = 1000; b.value1001 = 1001; b.value1002 = 1002; b.value1003 = 1003; b.value1004 = 1004; b.value1005 = 1005; b.value1006 = 1006; b.value1007 = 1007; b.value1008 = 1008; b.value1009 = 1009; b.value1010 = 1010; b.value1011 = 1011; b.value1012 = 1012; b.value1013 = 1013; b.value1014 = 1014; b.value1015 = 1015; b.value1016 = 1016; b.value1017 = 1017; b.value1018 = 1018; b.value1019 = 1019; b.value1020 = 1020; b.value1021 = 1021; b.value1022 = 1022; b.value1023 = 1023; b.value1024 = 1024; b.value1025 = 1025; b.value1026 = 1026; b.value1027 = 1027; b.value1028 = 1028; b.value1029 = 1029; b.value1030 = 1030; b.value1031 = 1031; b.value1032 = 1032; b.value1033 = 1033; b.value1034 = 1034; b.value1035 = 1035; b.value1036 = 1036; b.value1037 = 1037; b.value1038 = 1038; b.value1039 = 1039; b.value1040 = 1040; b.value1041 = 1041; b.value1042 = 1042; b.value1043 = 1043; b.value1044 = 1044; b.value1045 = 1045; b.value1046 = 1046; b.value1047 = 1047; b.value1048 = 1048; b.value1049 = 1049; b.value1050 = 1050; b.value1051 = 1051; b.value1052 = 1052; b.value1053 = 1053; b.value1054 = 1054; b.value1055 = 1055; b.value1056 = 1056; b.value1057 = 1057; b.value1058 = 1058; b.value1059 = 1059; b.value1060 = 1060; b.value1061 = 1061; b.value1062 = 1062; b.value1063 = 1063; b.value1064 = 1064; b.value1065 = 1065; b.value1066 = 1066; b.value1067 = 1067; b.value1068 = 1068; b.value1069 = 1069; b.value1070 = 1070; b.value1071 = 1071; b.value1072 = 1072; b.value1073 = 1073; b.value1074 = 1074; b.value1075 = 1075; b.value1076 = 1076; b.value1077 = 1077; b.value1078 = 1078; b.value1079 = 1079; b.value1080 = 1080; b.value1081 = 1081; b.value1082 = 1082; b.value1083 = 1083; b.value1084 = 1084; b.value1085 = 1085; b.value1086 = 1086; b.value1087 = 1087; b.value1088 = 1088; b.value1089 = 1089; b.value1090 = 1090; b.value1091 = 1091; b.value1092 = 1092; b.value1093 = 1093; b.value1094 = 1094; b.value1095 = 1095; b.value1096 = 1096; b.value1097 = 1097; b.value1098 = 1098; b.value1099 = 1099; b.value1100 = 1100; b.value1101 = 1101; b.value1102 = 1102; b.value1103 = 1103; b.value1104 = 1104; b.value1105 = 1105; b.value1106 = 1106; b.value1107 = 1107; b.value1108 = 1108; b.value1109 = 1109; b.value1110 = 1110; b.value1111 = 1111; b.value1112 = 1112; b.value1113 = 1113; b.value1114 = 1114; b.value1115 = 1115; b.value1116 = 1116; b.value1117 = 1117; b.value1118 = 1118; b.value1119 = 1119; b.value1120 = 1120; b.value1121 = 1121; b.value1122 = 1122; b.value1123 = 1123; b.value1124 = 1124; b.value1125 = 1125; b.value1126 = 1126; b.value1127 = 1127; b.value1128 = 1128; b.value1129 = 1129; b.value1130 = 1130; b.value1131 = 1131; b.value1132 = 1132; b.value1133 = 1133; b.value1134 = 1134; b.value1135 = 1135; b.value1136 = 1136; b.value1137 = 1137; b.value1138 = 1138; b.value1139 = 1139; b.value1140 = 1140; b.value1141 = 1141; b.value1142 = 1142; b.value1143 = 1143; b.value1144 = 1144; b.value1145 = 1145; b.value1146 = 1146; b.value1147 = 1147; b.value1148 = 1148; b.value1149 = 1149; b.value1150 = 1150; b.value1151 = 1151; b.value1152 = 1152; b.value1153 = 1153; b.value1154 = 1154; b.value1155 = 1155; b.value1156 = 1156; b.value1157 = 1157; b.value1158 = 1158; b.value1159 = 1159; b.value1160 = 1160; b.value1161 = 1161; b.value1162 = 1162; b.value1163 = 1163; b.value1164 = 1164; b.value1165 = 1165; b.value1166 = 1166; b.value1167 = 1167; b.value1168 = 1168; b.value1169 = 1169; b.value1170 = 1170; b.value1171 = 1171; b.value1172 = 1172; b.value1173 = 1173; b.value1174 = 1174; b.value1175 = 1175; b.value1176 = 1176; b.value1177 = 1177; b.value1178 = 1178; b.value1179 = 1179; b.value1180 = 1180; b.value1181 = 1181; b.value1182 = 1182; b.value1183 = 1183; b.value1184 = 1184; b.value1185 = 1185; b.value1186 = 1186; b.value1187 = 1187; b.value1188 = 1188; b.value1189 = 1189; b.value1190 = 1190; b.value1191 = 1191; b.value1192 = 1192; b.value1193 = 1193; b.value1194 = 1194; b.value1195 = 1195; b.value1196 = 1196; b.value1197 = 1197; b.value1198 = 1198; b.value1199 = 1199; b.value1200 = 1200; b.value1201 = 1201; b.value1202 = 1202; b.value1203 = 1203; b.value1204 = 1204; b.value1205 = 1205; b.value1206 = 1206; b.value1207 = 1207; b.value1208 = 1208; b.value1209 = 1209; b.value1210 = 1210; b.value1211 = 1211; b.value1212 = 1212; b.value1213 = 1213; b.value1214 = 1214; b.value1215 = 1215; b.value1216 = 1216; b.value1217 = 1217; b.value1218 = 1218; b.value1219 = 1219; b.value1220 = 1220; b.value1221 = 1221; b.value1222 = 1222; b.value1223 = 1223; b.value1224 = 1224; b.value1225 = 1225; b.value1226 = 1226; b.value1227 = 1227; b.value1228 = 1228; b.value1229 = 1229; b.value1230 = 1230; b.value1231 = 1231; b.value1232 = 1232; b.value1233 = 1233; b.value1234 = 1234; b.value1235 = 1235; b.value1236 = 1236; b.value1237 = 1237; b.value1238 = 1238; b.value1239 = 1239; b.value1240 = 1240; b.value1241 = 1241; b.value1242 = 1242; b.value1243 = 1243; b.value1244 = 1244; b.value1245 = 1245; b.value1246 = 1246; b.value1247 = 1247; b.value1248 = 1248; b.value1249 = 1249; b.value1250 = 1250; b.value1251 = 1251; b.value1252 = 1252; b.value1253 = 1253; b.value1254 = 1254; b.value1255 = 1255; b.value1256 = 1256; b.value1257 = 1257; b.value1258 = 1258; b.value1259 = 1259; b.value1260 = 1260; b.value1261 = 1261; b.value1262 = 1262; b.value1263 = 1263; b.value1264 = 1264; b.value1265 = 1265; b.value1266 = 1266; b.value1267 = 1267; b.value1268 = 1268; b.value1269 = 1269; b.value1270 = 1270; b.value1271 = 1271; b.value1272 = 1272; b.value1273 = 1273; b.value1274 = 1274; b.value1275 = 1275; b.value1276 = 1276; b.value1277 = 1277; b.value1278 = 1278; b.value1279 = 1279; b.value1280 = 1280; b.value1281 = 1281; b.value1282 = 1282; b.value1283 = 1283; b.value1284 = 1284; b.value1285 = 1285; b.value1286 = 1286; b.value1287 = 1287; b.value1288 = 1288; b.value1289 = 1289; b.value1290 = 1290; b.value1291 = 1291; b.value1292 = 1292; b.value1293 = 1293; b.value1294 = 1294; b.value1295 = 1295; b.value1296 = 1296; b.value1297 = 1297; b.value1298 = 1298; b.value1299 = 1299; b.value1300 = 1300; b.value1301 = 1301; b.value1302 = 1302; b.value1303 = 1303; b.value1304 = 1304; b.value1305 = 1305; b.value1306 = 1306; b.value1307 = 1307; b.value1308 = 1308; b.value1309 = 1309; b.value1310 = 1310; b.value1311 = 1311; b.value1312 = 1312; b.value1313 = 1313; b.value1314 = 1314; b.value1315 = 1315; b.value1316 = 1316; b.value1317 = 1317; b.value1318 = 1318; b.value1319 = 1319; b.value1320 = 1320; b.value1321 = 1321; b.value1322 = 1322; b.value1323 = 1323; b.value1324 = 1324; b.value1325 = 1325; b.value1326 = 1326; b.value1327 = 1327; b.value1328 = 1328; b.value1329 = 1329; b.value1330 = 1330; b.value1331 = 1331; b.value1332 = 1332; b.value1333 = 1333; b.value1334 = 1334; b.value1335 = 1335; b.value1336 = 1336; b.value1337 = 1337; b.value1338 = 1338; b.value1339 = 1339; b.value1340 = 1340; b.value1341 = 1341; b.value1342 = 1342; b.value1343 = 1343; b.value1344 = 1344; b.value1345 = 1345; b.value1346 = 1346; b.value1347 = 1347; b.value1348 = 1348; b.value1349 = 1349; b.value1350 = 1350; b.value1351 = 1351; b.value1352 = 1352; b.value1353 = 1353; b.value1354 = 1354; b.value1355 = 1355; b.value1356 = 1356; b.value1357 = 1357; b.value1358 = 1358; b.value1359 = 1359; b.value1360 = 1360; b.value1361 = 1361; b.value1362 = 1362; b.value1363 = 1363; b.value1364 = 1364; b.value1365 = 1365; b.value1366 = 1366; b.value1367 = 1367; b.value1368 = 1368; b.value1369 = 1369; b.value1370 = 1370; b.value1371 = 1371; b.value1372 = 1372; b.value1373 = 1373; b.value1374 = 1374; b.value1375 = 1375; b.value1376 = 1376; b.value1377 = 1377; b.value1378 = 1378; b.value1379 = 1379; b.value1380 = 1380; b.value1381 = 1381; b.value1382 = 1382; b.value1383 = 1383; b.value1384 = 1384; b.value1385 = 1385; b.value1386 = 1386; b.value1387 = 1387; b.value1388 = 1388; b.value1389 = 1389; b.value1390 = 1390; b.value1391 = 1391; b.value1392 = 1392; b.value1393 = 1393; b.value1394 = 1394; b.value1395 = 1395; b.value1396 = 1396; b.value1397 = 1397; b.value1398 = 1398; b.value1399 = 1399; b.value1400 = 1400; b.value1401 = 1401; b.value1402 = 1402; b.value1403 = 1403; b.value1404 = 1404; b.value1405 = 1405; b.value1406 = 1406; b.value1407 = 1407; b.value1408 = 1408; b.value1409 = 1409; b.value1410 = 1410; b.value1411 = 1411; b.value1412 = 1412; b.value1413 = 1413; b.value1414 = 1414; b.value1415 = 1415; b.value1416 = 1416; b.value1417 = 1417; b.value1418 = 1418; b.value1419 = 1419; b.value1420 = 1420; b.value1421 = 1421; b.value1422 = 1422; b.value1423 = 1423; b.value1424 = 1424; b.value1425 = 1425; b.value1426 = 1426; b.value1427 = 1427; b.value1428 = 1428; b.value1429 = 1429; b.value1430 = 1430; b.value1431 = 1431; b.value1432 = 1432; b.value1433 = 1433; b.value1434 = 1434; b.value1435 = 1435; b.value1436 = 1436; b.value1437 = 1437; b.value1438 = 1438; b.value1439 = 1439; b.value1440 = 1440; b.value1441 = 1441; b.value1442 = 1442; b.value1443 = 1443; b.value1444 = 1444; b.value1445 = 1445; b.value1446 = 1446; b.value1447 = 1447; b.value1448 = 1448; b.value1449 = 1449; b.value1450 = 1450; b.value1451 = 1451; b.value1452 = 1452; b.value1453 = 1453; b.value1454 = 1454; b.value1455 = 1455; b.value1456 = 1456; b.value1457 = 1457; b.value1458 = 1458; b.value1459 = 1459; b.value1460 = 1460; b.value1461 = 1461; b.value1462 = 1462; b.value1463 = 1463; b.value1464 = 1464; b.value1465 = 1465; b.value1466 = 1466; b.value1467 = 1467; b.value1468 = 1468; b.value1469 = 1469; b.value1470 = 1470; b.value1471 = 1471; b.value1472 = 1472; b.value1473 = 1473; b.value1474 = 1474; b.value1475 = 1475; b.value1476 = 1476; b.value1477 = 1477; b.value1478 = 1478; b.value1479 = 1479; b.value1480 = 1480; b.value1481 = 1481; b.value1482 = 1482; b.value1483 = 1483; b.value1484 = 1484; b.value1485 = 1485; b.value1486 = 1486; b.value1487 = 1487; b.value1488 = 1488; b.value1489 = 1489; b.value1490 = 1490; b.value1491 = 1491; b.value1492 = 1492; b.value1493 = 1493; b.value1494 = 1494; b.value1495 = 1495; b.value1496 = 1496; b.value1497 = 1497; b.value1498 = 1498; b.value1499 = 1499; b.value1500 = 1500; b.value1501 = 1501; b.value1502 = 1502; b.value1503 = 1503; b.value1504 = 1504; b.value1505 = 1505; b.value1506 = 1506; b.value1507 = 1507; b.value1508 = 1508; b.value1509 = 1509; b.value1510 = 1510; b.value1511 = 1511; b.value1512 = 1512; b.value1513 = 1513; b.value1514 = 1514; b.value1515 = 1515; b.value1516 = 1516; b.value1517 = 1517; b.value1518 = 1518; b.value1519 = 1519; b.value1520 = 1520; b.value1521 = 1521; b.value1522 = 1522; b.value1523 = 1523; b.value1524 = 1524; b.value1525 = 1525; b.value1526 = 1526; b.value1527 = 1527; b.value1528 = 1528; b.value1529 = 1529; b.value1530 = 1530; b.value1531 = 1531; b.value1532 = 1532; b.value1533 = 1533; b.value1534 = 1534; b.value1535 = 1535; b.value1536 = 1536; b.value1537 = 1537; b.value1538 = 1538; b.value1539 = 1539; b.value1540 = 1540; b.value1541 = 1541; b.value1542 = 1542; b.value1543 = 1543; b.value1544 = 1544; b.value1545 = 1545; b.value1546 = 1546; b.value1547 = 1547; b.value1548 = 1548; b.value1549 = 1549; b.value1550 = 1550; b.value1551 = 1551; b.value1552 = 1552; b.value1553 = 1553; b.value1554 = 1554; b.value1555 = 1555; b.value1556 = 1556; b.value1557 = 1557; b.value1558 = 1558; b.value1559 = 1559; b.value1560 = 1560; b.value1561 = 1561; b.value1562 = 1562; b.value1563 = 1563; b.value1564 = 1564; b.value1565 = 1565; b.value1566 = 1566; b.value1567 = 1567; b.value1568 = 1568; b.value1569 = 1569; b.value1570 = 1570; b.value1571 = 1571; b.value1572 = 1572; b.value1573 = 1573; b.value1574 = 1574; b.value1575 = 1575; b.value1576 = 1576; b.value1577 = 1577; b.value1578 = 1578; b.value1579 = 1579; b.value1580 = 1580; b.value1581 = 1581; b.value1582 = 1582; b.value1583 = 1583; b.value1584 = 1584; b.value1585 = 1585; b.value1586 = 1586; b.value1587 = 1587; b.value1588 = 1588; b.value1589 = 1589; b.value1590 = 1590; b.value1591 = 1591; b.value1592 = 1592; b.value1593 = 1593; b.value1594 = 1594; b.value1595 = 1595; b.value1596 = 1596; b.value1597 = 1597; b.value1598 = 1598; b.value1599 = 1599; b.value1600 = 1600; b.value1601 = 1601; b.value1602 = 1602; b.value1603 = 1603; b.value1604 = 1604; b.value1605 = 1605; b.value1606 = 1606; b.value1607 = 1607; b.value1608 = 1608; b.value1609 = 1609; b.value1610 = 1610; b.value1611 = 1611; b.value1612 = 1612; b.value1613 = 1613; b.value1614 = 1614; b.value1615 = 1615; b.value1616 = 1616; b.value1617 = 1617; b.value1618 = 1618; b.value1619 = 1619; b.value1620 = 1620; b.value1621 = 1621; b.value1622 = 1622; b.value1623 = 1623; b.value1624 = 1624; b.value1625 = 1625; b.value1626 = 1626; b.value1627 = 1627; b.value1628 = 1628; b.value1629 = 1629; b.value1630 = 1630; b.value1631 = 1631; b.value1632 = 1632; b.value1633 = 1633; b.value1634 = 1634; b.value1635 = 1635; b.value1636 = 1636; b.value1637 = 1637; b.value1638 = 1638; b.value1639 = 1639; b.value1640 = 1640; b.value1641 = 1641; b.value1642 = 1642; b.value1643 = 1643; b.value1644 = 1644; b.value1645 = 1645; b.value1646 = 1646; b.value1647 = 1647; b.value1648 = 1648; b.value1649 = 1649; b.value1650 = 1650; b.value1651 = 1651; b.value1652 = 1652; b.value1653 = 1653; b.value1654 = 1654; b.value1655 = 1655; b.value1656 = 1656; b.value1657 = 1657; b.value1658 = 1658; b.value1659 = 1659; b.value1660 = 1660; b.value1661 = 1661; b.value1662 = 1662; b.value1663 = 1663; b.value1664 = 1664; b.value1665 = 1665; b.value1666 = 1666; b.value1667 = 1667; b.value1668 = 1668; b.value1669 = 1669; b.value1670 = 1670; b.value1671 = 1671; b.value1672 = 1672; b.value1673 = 1673; b.value1674 = 1674; b.value1675 = 1675; b.value1676 = 1676; b.value1677 = 1677; b.value1678 = 1678; b.value1679 = 1679; b.value1680 = 1680; b.value1681 = 1681; b.value1682 = 1682; b.value1683 = 1683; b.value1684 = 1684; b.value1685 = 1685; b.value1686 = 1686; b.value1687 = 1687; b.value1688 = 1688; b.value1689 = 1689; b.value1690 = 1690; b.value1691 = 1691; b.value1692 = 1692; b.value1693 = 1693; b.value1694 = 1694; b.value1695 = 1695; b.value1696 = 1696; b.value1697 = 1697; b.value1698 = 1698; b.value1699 = 1699; b.value1700 = 1700; b.value1701 = 1701; b.value1702 = 1702; b.value1703 = 1703; b.value1704 = 1704; b.value1705 = 1705; b.value1706 = 1706; b.value1707 = 1707; b.value1708 = 1708; b.value1709 = 1709; b.value1710 = 1710; b.value1711 = 1711; b.value1712 = 1712; b.value1713 = 1713; b.value1714 = 1714; b.value1715 = 1715; b.value1716 = 1716; b.value1717 = 1717; b.value1718 = 1718; b.value1719 = 1719; b.value1720 = 1720; b.value1721 = 1721; b.value1722 = 1722; b.value1723 = 1723; b.value1724 = 1724; b.value1725 = 1725; b.value1726 = 1726; b.value1727 = 1727; b.value1728 = 1728; b.value1729 = 1729; b.value1730 = 1730; b.value1731 = 1731; b.value1732 = 1732; b.value1733 = 1733; b.value1734 = 1734; b.value1735 = 1735; b.value1736 = 1736; b.value1737 = 1737; b.value1738 = 1738; b.value1739 = 1739; b.value1740 = 1740; b.value1741 = 1741; b.value1742 = 1742; b.value1743 = 1743; b.value1744 = 1744; b.value1745 = 1745; b.value1746 = 1746; b.value1747 = 1747; b.value1748 = 1748; b.value1749 = 1749; b.value1750 = 1750; b.value1751 = 1751; b.value1752 = 1752; b.value1753 = 1753; b.value1754 = 1754; b.value1755 = 1755; b.value1756 = 1756; b.value1757 = 1757; b.value1758 = 1758; b.value1759 = 1759; b.value1760 = 1760; b.value1761 = 1761; b.value1762 = 1762; b.value1763 = 1763; b.value1764 = 1764; b.value1765 = 1765; b.value1766 = 1766; b.value1767 = 1767; b.value1768 = 1768; b.value1769 = 1769; b.value1770 = 1770; b.value1771 = 1771; b.value1772 = 1772; b.value1773 = 1773; b.value1774 = 1774; b.value1775 = 1775; b.value1776 = 1776; b.value1777 = 1777; b.value1778 = 1778; b.value1779 = 1779; b.value1780 = 1780; b.value1781 = 1781; b.value1782 = 1782; b.value1783 = 1783; b.value1784 = 1784; b.value1785 = 1785; b.value1786 = 1786; b.value1787 = 1787; b.value1788 = 1788; b.value1789 = 1789; b.value1790 = 1790; b.value1791 = 1791; b.value1792 = 1792; b.value1793 = 1793; b.value1794 = 1794; b.value1795 = 1795; b.value1796 = 1796; b.value1797 = 1797; b.value1798 = 1798; b.value1799 = 1799; b.value1800 = 1800; b.value1801 = 1801; b.value1802 = 1802; b.value1803 = 1803; b.value1804 = 1804; b.value1805 = 1805; b.value1806 = 1806; b.value1807 = 1807; b.value1808 = 1808; b.value1809 = 1809; b.value1810 = 1810; b.value1811 = 1811; b.value1812 = 1812; b.value1813 = 1813; b.value1814 = 1814; b.value1815 = 1815; b.value1816 = 1816; b.value1817 = 1817; b.value1818 = 1818; b.value1819 = 1819; b.value1820 = 1820; b.value1821 = 1821; b.value1822 = 1822; b.value1823 = 1823; b.value1824 = 1824; b.value1825 = 1825; b.value1826 = 1826; b.value1827 = 1827; b.value1828 = 1828; b.value1829 = 1829; b.value1830 = 1830; b.value1831 = 1831; b.value1832 = 1832; b.value1833 = 1833; b.value1834 = 1834; b.value1835 = 1835; b.value1836 = 1836; b.value1837 = 1837; b.value1838 = 1838; b.value1839 = 1839; b.value1840 = 1840; b.value1841 = 1841; b.value1842 = 1842; b.value1843 = 1843; b.value1844 = 1844; b.value1845 = 1845; b.value1846 = 1846; b.value1847 = 1847; b.value1848 = 1848; b.value1849 = 1849; b.value1850 = 1850; b.value1851 = 1851; b.value1852 = 1852; b.value1853 = 1853; b.value1854 = 1854; b.value1855 = 1855; b.value1856 = 1856; b.value1857 = 1857; b.value1858 = 1858; b.value1859 = 1859; b.value1860 = 1860; b.value1861 = 1861; b.value1862 = 1862; b.value1863 = 1863; b.value1864 = 1864; b.value1865 = 1865; b.value1866 = 1866; b.value1867 = 1867; b.value1868 = 1868; b.value1869 = 1869; b.value1870 = 1870; b.value1871 = 1871; b.value1872 = 1872; b.value1873 = 1873; b.value1874 = 1874; b.value1875 = 1875; b.value1876 = 1876; b.value1877 = 1877; b.value1878 = 1878; b.value1879 = 1879; b.value1880 = 1880; b.value1881 = 1881; b.value1882 = 1882; b.value1883 = 1883; b.value1884 = 1884; b.value1885 = 1885; b.value1886 = 1886; b.value1887 = 1887; b.value1888 = 1888; b.value1889 = 1889; b.value1890 = 1890; b.value1891 = 1891; b.value1892 = 1892; b.value1893 = 1893; b.value1894 = 1894; b.value1895 = 1895; b.value1896 = 1896; b.value1897 = 1897; b.value1898 = 1898; b.value1899 = 1899; b.value1900 = 1900; b.value1901 = 1901; b.value1902 = 1902; b.value1903 = 1903; b.value1904 = 1904; b.value1905 = 1905; b.value1906 = 1906; b.value1907 = 1907; b.value1908 = 1908; b.value1909 = 1909; b.value1910 = 1910; b.value1911 = 1911; b.value1912 = 1912; b.value1913 = 1913; b.value1914 = 1914; b.value1915 = 1915; b.value1916 = 1916; b.value1917 = 1917; b.value1918 = 1918; b.value1919 = 1919; b.value1920 = 1920; b.value1921 = 1921; b.value1922 = 1922; b.value1923 = 1923; b.value1924 = 1924; b.value1925 = 1925; b.value1926 = 1926; b.value1927 = 1927; b.value1928 = 1928; b.value1929 = 1929; b.value1930 = 1930; b.value1931 = 1931; b.value1932 = 1932; b.value1933 = 1933; b.value1934 = 1934; b.value1935 = 1935; b.value1936 = 1936; b.value1937 = 1937; b.value1938 = 1938; b.value1939 = 1939; b.value1940 = 1940; b.value1941 = 1941; b.value1942 = 1942; b.value1943 = 1943; b.value1944 = 1944; b.value1945 = 1945; b.value1946 = 1946; b.value1947 = 1947; b.value1948 = 1948; b.value1949 = 1949; b.value1950 = 1950; b.value1951 = 1951; b.value1952 = 1952; b.value1953 = 1953; b.value1954 = 1954; b.value1955 = 1955; b.value1956 = 1956; b.value1957 = 1957; b.value1958 = 1958; b.value1959 = 1959; b.value1960 = 1960; b.value1961 = 1961; b.value1962 = 1962; b.value1963 = 1963; b.value1964 = 1964; b.value1965 = 1965; b.value1966 = 1966; b.value1967 = 1967; b.value1968 = 1968; b.value1969 = 1969; b.value1970 = 1970; b.value1971 = 1971; b.value1972 = 1972; b.value1973 = 1973; b.value1974 = 1974; b.value1975 = 1975; b.value1976 = 1976; b.value1977 = 1977; b.value1978 = 1978; b.value1979 = 1979; b.value1980 = 1980; b.value1981 = 1981; b.value1982 = 1982; b.value1983 = 1983; b.value1984 = 1984; b.value1985 = 1985; b.value1986 = 1986; b.value1987 = 1987; b.value1988 = 1988; b.value1989 = 1989; b.value1990 = 1990; b.value1991 = 1991; b.value1992 = 1992; b.value1993 = 1993; b.value1994 = 1994; b.value1995 = 1995; b.value1996 = 1996; b.value1997 = 1997; b.value1998 = 1998; b.value1999 = 1999; b.value2000 = 2000; b.value2001 = 2001; b.value2002 = 2002; b.value2003 = 2003; b.value2004 = 2004; b.value2005 = 2005; b.value2006 = 2006; b.value2007 = 2007; b.value2008 = 2008; b.value2009 = 2009; b.value2010 = 2010; b.value2011 = 2011; b.value2012 = 2012; b.value2013 = 2013; b.value2014 = 2014; b.value2015 = 2015; b.value2016 = 2016; b.value2017 = 2017; b.value2018 = 2018; b.value2019 = 2019; b.value2020 = 2020; b.value2021 = 2021; b.value2022 = 2022; b.value2023 = 2023; b.value2024 = 2024; b.value2025 = 2025; b.value2026 = 2026; b.value2027 = 2027; b.value2028 = 2028; b.value2029 = 2029; b.value2030 = 2030; b.value2031 = 2031; b.value2032 = 2032; b.value2033 = 2033; b.value2034 = 2034; b.value2035 = 2035; b.value2036 = 2036; b.value2037 = 2037; b.value2038 = 2038; b.value2039 = 2039; b.value2040 = 2040; b.value2041 = 2041; b.value2042 = 2042; b.value2043 = 2043; b.value2044 = 2044; b.value2045 = 2045; b.value2046 = 2046; b.value2047 = 2047; b.value2048 = 2048; b.value2049 = 2049; b.value2050 = 2050; b.value2051 = 2051; b.value2052 = 2052; b.value2053 = 2053; b.value2054 = 2054; b.value2055 = 2055; b.value2056 = 2056; b.value2057 = 2057; b.value2058 = 2058; b.value2059 = 2059; b.value2060 = 2060; b.value2061 = 2061; b.value2062 = 2062; b.value2063 = 2063; b.value2064 = 2064; b.value2065 = 2065; b.value2066 = 2066; b.value2067 = 2067; b.value2068 = 2068; b.value2069 = 2069; b.value2070 = 2070; b.value2071 = 2071; b.value2072 = 2072; b.value2073 = 2073; b.value2074 = 2074; b.value2075 = 2075; b.value2076 = 2076; b.value2077 = 2077; b.value2078 = 2078; b.value2079 = 2079; b.value2080 = 2080; b.value2081 = 2081; b.value2082 = 2082; b.value2083 = 2083; b.value2084 = 2084; b.value2085 = 2085; b.value2086 = 2086; b.value2087 = 2087; b.value2088 = 2088; b.value2089 = 2089; b.value2090 = 2090; b.value2091 = 2091; b.value2092 = 2092; b.value2093 = 2093; b.value2094 = 2094; b.value2095 = 2095; b.value2096 = 2096; b.value2097 = 2097; b.value2098 = 2098; b.value2099 = 2099; b.value2100 = 2100; b.value2101 = 2101; b.value2102 = 2102; b.value2103 = 2103; b.value2104 = 2104; b.value2105 = 2105; b.value2106 = 2106; b.value2107 = 2107; b.value2108 = 2108; b.value2109 = 2109; b.value2110 = 2110; b.value2111 = 2111; b.value2112 = 2112; b.value2113 = 2113; b.value2114 = 2114; b.value2115 = 2115; b.value2116 = 2116; b.value2117 = 2117; b.value2118 = 2118; b.value2119 = 2119; b.value2120 = 2120; b.value2121 = 2121; b.value2122 = 2122; b.value2123 = 2123; b.value2124 = 2124; b.value2125 = 2125; b.value2126 = 2126; b.value2127 = 2127; b.value2128 = 2128; b.value2129 = 2129; b.value2130 = 2130; b.value2131 = 2131; b.value2132 = 2132; b.value2133 = 2133; b.value2134 = 2134; b.value2135 = 2135; b.value2136 = 2136; b.value2137 = 2137; b.value2138 = 2138; b.value2139 = 2139; b.value2140 = 2140; b.value2141 = 2141; b.value2142 = 2142; b.value2143 = 2143; b.value2144 = 2144; b.value2145 = 2145; b.value2146 = 2146; b.value2147 = 2147; b.value2148 = 2148; b.value2149 = 2149; b.value2150 = 2150; b.value2151 = 2151; b.value2152 = 2152; b.value2153 = 2153; b.value2154 = 2154; b.value2155 = 2155; b.value2156 = 2156; b.value2157 = 2157; b.value2158 = 2158; b.value2159 = 2159; b.value2160 = 2160; b.value2161 = 2161; b.value2162 = 2162; b.value2163 = 2163; b.value2164 = 2164; b.value2165 = 2165; b.value2166 = 2166; b.value2167 = 2167; b.value2168 = 2168; b.value2169 = 2169; b.value2170 = 2170; b.value2171 = 2171; b.value2172 = 2172; b.value2173 = 2173; b.value2174 = 2174; b.value2175 = 2175; b.value2176 = 2176; b.value2177 = 2177; b.value2178 = 2178; b.value2179 = 2179; b.value2180 = 2180; b.value2181 = 2181; b.value2182 = 2182; b.value2183 = 2183; b.value2184 = 2184; b.value2185 = 2185; b.value2186 = 2186; b.value2187 = 2187; b.value2188 = 2188; b.value2189 = 2189; b.value2190 = 2190; b.value2191 = 2191; b.value2192 = 2192; b.value2193 = 2193; b.value2194 = 2194; b.value2195 = 2195; b.value2196 = 2196; b.value2197 = 2197; b.value2198 = 2198; b.value2199 = 2199; b.value2200 = 2200; b.value2201 = 2201; b.value2202 = 2202; b.value2203 = 2203; b.value2204 = 2204; b.value2205 = 2205; b.value2206 = 2206; b.value2207 = 2207; b.value2208 = 2208; b.value2209 = 2209; b.value2210 = 2210; b.value2211 = 2211; b.value2212 = 2212; b.value2213 = 2213; b.value2214 = 2214; b.value2215 = 2215; b.value2216 = 2216; b.value2217 = 2217; b.value2218 = 2218; b.value2219 = 2219; b.value2220 = 2220; b.value2221 = 2221; b.value2222 = 2222; b.value2223 = 2223; b.value2224 = 2224; b.value2225 = 2225; b.value2226 = 2226; b.value2227 = 2227; b.value2228 = 2228; b.value2229 = 2229; b.value2230 = 2230; b.value2231 = 2231; b.value2232 = 2232; b.value2233 = 2233; b.value2234 = 2234; b.value2235 = 2235; b.value2236 = 2236; b.value2237 = 2237; b.value2238 = 2238; b.value2239 = 2239; b.value2240 = 2240; b.value2241 = 2241; b.value2242 = 2242; b.value2243 = 2243; b.value2244 = 2244; b.value2245 = 2245; b.value2246 = 2246; b.value2247 = 2247; b.value2248 = 2248; b.value2249 = 2249; b.value2250 = 2250; b.value2251 = 2251; b.value2252 = 2252; b.value2253 = 2253; b.value2254 = 2254; b.value2255 = 2255; b.value2256 = 2256; b.value2257 = 2257; b.value2258 = 2258; b.value2259 = 2259; b.value2260 = 2260; b.value2261 = 2261; b.value2262 = 2262; b.value2263 = 2263; b.value2264 = 2264; b.value2265 = 2265; b.value2266 = 2266; b.value2267 = 2267; b.value2268 = 2268; b.value2269 = 2269; b.value2270 = 2270; b.value2271 = 2271; b.value2272 = 2272; b.value2273 = 2273; b.value2274 = 2274; b.value2275 = 2275; b.value2276 = 2276; b.value2277 = 2277; b.value2278 = 2278; b.value2279 = 2279; b.value2280 = 2280; b.value2281 = 2281; b.value2282 = 2282; b.value2283 = 2283; b.value2284 = 2284; b.value2285 = 2285; b.value2286 = 2286; b.value2287 = 2287; b.value2288 = 2288; b.value2289 = 2289; b.value2290 = 2290; b.value2291 = 2291; b.value2292 = 2292; b.value2293 = 2293; b.value2294 = 2294; b.value2295 = 2295; b.value2296 = 2296; b.value2297 = 2297; b.value2298 = 2298; b.value2299 = 2299; b.value2300 = 2300; b.value2301 = 2301; b.value2302 = 2302; b.value2303 = 2303; b.value2304 = 2304; b.value2305 = 2305; b.value2306 = 2306; b.value2307 = 2307; b.value2308 = 2308; b.value2309 = 2309; b.value2310 = 2310; b.value2311 = 2311; b.value2312 = 2312; b.value2313 = 2313; b.value2314 = 2314; b.value2315 = 2315; b.value2316 = 2316; b.value2317 = 2317; b.value2318 = 2318; b.value2319 = 2319; b.value2320 = 2320; b.value2321 = 2321; b.value2322 = 2322; b.value2323 = 2323; b.value2324 = 2324; b.value2325 = 2325; b.value2326 = 2326; b.value2327 = 2327; b.value2328 = 2328; b.value2329 = 2329; b.value2330 = 2330; b.value2331 = 2331; b.value2332 = 2332; b.value2333 = 2333; b.value2334 = 2334; b.value2335 = 2335; b.value2336 = 2336; b.value2337 = 2337; b.value2338 = 2338; b.value2339 = 2339; b.value2340 = 2340; b.value2341 = 2341; b.value2342 = 2342; b.value2343 = 2343; b.value2344 = 2344; b.value2345 = 2345; b.value2346 = 2346; b.value2347 = 2347; b.value2348 = 2348; b.value2349 = 2349; b.value2350 = 2350; b.value2351 = 2351; b.value2352 = 2352; b.value2353 = 2353; b.value2354 = 2354; b.value2355 = 2355; b.value2356 = 2356; b.value2357 = 2357; b.value2358 = 2358; b.value2359 = 2359; b.value2360 = 2360; b.value2361 = 2361; b.value2362 = 2362; b.value2363 = 2363; b.value2364 = 2364; b.value2365 = 2365; b.value2366 = 2366; b.value2367 = 2367; b.value2368 = 2368; b.value2369 = 2369; b.value2370 = 2370; b.value2371 = 2371; b.value2372 = 2372; b.value2373 = 2373; b.value2374 = 2374; b.value2375 = 2375; b.value2376 = 2376; b.value2377 = 2377; b.value2378 = 2378; b.value2379 = 2379; b.value2380 = 2380; b.value2381 = 2381; b.value2382 = 2382; b.value2383 = 2383; b.value2384 = 2384; b.value2385 = 2385; b.value2386 = 2386; b.value2387 = 2387; b.value2388 = 2388; b.value2389 = 2389; b.value2390 = 2390; b.value2391 = 2391; b.value2392 = 2392; b.value2393 = 2393; b.value2394 = 2394; b.value2395 = 2395; b.value2396 = 2396; b.value2397 = 2397; b.value2398 = 2398; b.value2399 = 2399; b.value2400 = 2400; b.value2401 = 2401; b.value2402 = 2402; b.value2403 = 2403; b.value2404 = 2404; b.value2405 = 2405; b.value2406 = 2406; b.value2407 = 2407; b.value2408 = 2408; b.value2409 = 2409; b.value2410 = 2410; b.value2411 = 2411; b.value2412 = 2412; b.value2413 = 2413; b.value2414 = 2414; b.value2415 = 2415; b.value2416 = 2416; b.value2417 = 2417; b.value2418 = 2418; b.value2419 = 2419; b.value2420 = 2420; b.value2421 = 2421; b.value2422 = 2422; b.value2423 = 2423; b.value2424 = 2424; b.value2425 = 2425; b.value2426 = 2426; b.value2427 = 2427; b.value2428 = 2428; b.value2429 = 2429; b.value2430 = 2430; b.value2431 = 2431; b.value2432 = 2432; b.value2433 = 2433; b.value2434 = 2434; b.value2435 = 2435; b.value2436 = 2436; b.value2437 = 2437; b.value2438 = 2438; b.value2439 = 2439; b.value2440 = 2440; b.value2441 = 2441; b.value2442 = 2442; b.value2443 = 2443; b.value2444 = 2444; b.value2445 = 2445; b.value2446 = 2446; b.value2447 = 2447; b.value2448 = 2448; b.value2449 = 2449; b.value2450 = 2450; b.value2451 = 2451; b.value2452 = 2452; b.value2453 = 2453; b.value2454 = 2454; b.value2455 = 2455; b.value2456 = 2456; b.value2457 = 2457; b.value2458 = 2458; b.value2459 = 2459; b.value2460 = 2460; b.value2461 = 2461; b.value2462 = 2462; b.value2463 = 2463; b.value2464 = 2464; b.value2465 = 2465; b.value2466 = 2466; b.value2467 = 2467; b.value2468 = 2468; b.value2469 = 2469; b.value2470 = 2470; b.value2471 = 2471; b.value2472 = 2472; b.value2473 = 2473; b.value2474 = 2474; b.value2475 = 2475; b.value2476 = 2476; b.value2477 = 2477; b.value2478 = 2478; b.value2479 = 2479; b.value2480 = 2480; b.value2481 = 2481; b.value2482 = 2482; b.value2483 = 2483; b.value2484 = 2484; b.value2485 = 2485; b.value2486 = 2486; b.value2487 = 2487; b.value2488 = 2488; b.value2489 = 2489; b.value2490 = 2490; b.value2491 = 2491; b.value2492 = 2492; b.value2493 = 2493; b.value2494 = 2494; b.value2495 = 2495; b.value2496 = 2496; b.value2497 = 2497; b.value2498 = 2498; b.value2499 = 2499; b.value2500 = 2500; b.value2501 = 2501; b.value2502 = 2502; b.value2503 = 2503; b.value2504 = 2504; b.value2505 = 2505; b.value2506 = 2506; b.value2507 = 2507; b.value2508 = 2508; b.value2509 = 2509; b.value2510 = 2510; b.value2511 = 2511; b.value2512 = 2512; b.value2513 = 2513; b.value2514 = 2514; b.value2515 = 2515; b.value2516 = 2516; b.value2517 = 2517; b.value2518 = 2518; b.value2519 = 2519; b.value2520 = 2520; b.value2521 = 2521; b.value2522 = 2522; b.value2523 = 2523; b.value2524 = 2524; b.value2525 = 2525; b.value2526 = 2526; b.value2527 = 2527; b.value2528 = 2528; b.value2529 = 2529; b.value2530 = 2530; b.value2531 = 2531; b.value2532 = 2532; b.value2533 = 2533; b.value2534 = 2534; b.value2535 = 2535; b.value2536 = 2536; b.value2537 = 2537; b.value2538 = 2538; b.value2539 = 2539; b.value2540 = 2540; b.value2541 = 2541; b.value2542 = 2542; b.value2543 = 2543; b.value2544 = 2544; b.value2545 = 2545; b.value2546 = 2546; b.value2547 = 2547; b.value2548 = 2548; b.value2549 = 2549; b.value2550 = 2550; b.value2551 = 2551; b.value2552 = 2552; b.value2553 = 2553; b.value2554 = 2554; b.value2555 = 2555; b.value2556 = 2556; b.value2557 = 2557; b.value2558 = 2558; b.value2559 = 2559; b.value2560 = 2560; b.value2561 = 2561; b.value2562 = 2562; b.value2563 = 2563; b.value2564 = 2564; b.value2565 = 2565; b.value2566 = 2566; b.value2567 = 2567; b.value2568 = 2568; b.value2569 = 2569; b.value2570 = 2570; b.value2571 = 2571; b.value2572 = 2572; b.value2573 = 2573; b.value2574 = 2574; b.value2575 = 2575; b.value2576 = 2576; b.value2577 = 2577; b.value2578 = 2578; b.value2579 = 2579; b.value2580 = 2580; b.value2581 = 2581; b.value2582 = 2582; b.value2583 = 2583; b.value2584 = 2584; b.value2585 = 2585; b.value2586 = 2586; b.value2587 = 2587; b.value2588 = 2588; b.value2589 = 2589; b.value2590 = 2590; b.value2591 = 2591; b.value2592 = 2592; b.value2593 = 2593; b.value2594 = 2594; b.value2595 = 2595; b.value2596 = 2596; b.value2597 = 2597; b.value2598 = 2598; b.value2599 = 2599; b.value2600 = 2600; b.value2601 = 2601; b.value2602 = 2602; b.value2603 = 2603; b.value2604 = 2604; b.value2605 = 2605; b.value2606 = 2606; b.value2607 = 2607; b.value2608 = 2608; b.value2609 = 2609; b.value2610 = 2610; b.value2611 = 2611; b.value2612 = 2612; b.value2613 = 2613; b.value2614 = 2614; b.value2615 = 2615; b.value2616 = 2616; b.value2617 = 2617; b.value2618 = 2618; b.value2619 = 2619; b.value2620 = 2620; b.value2621 = 2621; b.value2622 = 2622; b.value2623 = 2623; b.value2624 = 2624; b.value2625 = 2625; b.value2626 = 2626; b.value2627 = 2627; b.value2628 = 2628; b.value2629 = 2629; b.value2630 = 2630; b.value2631 = 2631; b.value2632 = 2632; b.value2633 = 2633; b.value2634 = 2634; b.value2635 = 2635; b.value2636 = 2636; b.value2637 = 2637; b.value2638 = 2638; b.value2639 = 2639; b.value2640 = 2640; b.value2641 = 2641; b.value2642 = 2642; b.value2643 = 2643; b.value2644 = 2644; b.value2645 = 2645; b.value2646 = 2646; b.value2647 = 2647; b.value2648 = 2648; b.value2649 = 2649; b.value2650 = 2650; b.value2651 = 2651; b.value2652 = 2652; b.value2653 = 2653; b.value2654 = 2654; b.value2655 = 2655; b.value2656 = 2656; b.value2657 = 2657; b.value2658 = 2658; b.value2659 = 2659; b.value2660 = 2660; b.value2661 = 2661; b.value2662 = 2662; b.value2663 = 2663; b.value2664 = 2664; b.value2665 = 2665; b.value2666 = 2666; b.value2667 = 2667; b.value2668 = 2668; b.value2669 = 2669; b.value2670 = 2670; b.value2671 = 2671; b.value2672 = 2672; b.value2673 = 2673; b.value2674 = 2674; b.value2675 = 2675; b.value2676 = 2676; b.value2677 = 2677; b.value2678 = 2678; b.value2679 = 2679; b.value2680 = 2680; b.value2681 = 2681; b.value2682 = 2682; b.value2683 = 2683; b.value2684 = 2684; b.value2685 = 2685; b.value2686 = 2686; b.value2687 = 2687; b.value2688 = 2688; b.value2689 = 2689; b.value2690 = 2690; b.value2691 = 2691; b.value2692 = 2692; b.value2693 = 2693; b.value2694 = 2694; b.value2695 = 2695; b.value2696 = 2696; b.value2697 = 2697; b.value2698 = 2698; b.value2699 = 2699; b.value2700 = 2700; b.value2701 = 2701; b.value2702 = 2702; b.value2703 = 2703; b.value2704 = 2704; b.value2705 = 2705; b.value2706 = 2706; b.value2707 = 2707; b.value2708 = 2708; b.value2709 = 2709; b.value2710 = 2710; b.value2711 = 2711; b.value2712 = 2712; b.value2713 = 2713; b.value2714 = 2714; b.value2715 = 2715; b.value2716 = 2716; b.value2717 = 2717; b.value2718 = 2718; b.value2719 = 2719; b.value2720 = 2720; b.value2721 = 2721; b.value2722 = 2722; b.value2723 = 2723; b.value2724 = 2724; b.value2725 = 2725; b.value2726 = 2726; b.value2727 = 2727; b.value2728 = 2728; b.value2729 = 2729; b.value2730 = 2730; b.value2731 = 2731; b.value2732 = 2732; b.value2733 = 2733; b.value2734 = 2734; b.value2735 = 2735; b.value2736 = 2736; b.value2737 = 2737; b.value2738 = 2738; b.value2739 = 2739; b.value2740 = 2740; b.value2741 = 2741; b.value2742 = 2742; b.value2743 = 2743; b.value2744 = 2744; b.value2745 = 2745; b.value2746 = 2746; b.value2747 = 2747; b.value2748 = 2748; b.value2749 = 2749; b.value2750 = 2750; b.value2751 = 2751; b.value2752 = 2752; b.value2753 = 2753; b.value2754 = 2754; b.value2755 = 2755; b.value2756 = 2756; b.value2757 = 2757; b.value2758 = 2758; b.value2759 = 2759; b.value2760 = 2760; b.value2761 = 2761; b.value2762 = 2762; b.value2763 = 2763; b.value2764 = 2764; b.value2765 = 2765; b.value2766 = 2766; b.value2767 = 2767; b.value2768 = 2768; b.value2769 = 2769; b.value2770 = 2770; b.value2771 = 2771; b.value2772 = 2772; b.value2773 = 2773; b.value2774 = 2774; b.value2775 = 2775; b.value2776 = 2776; b.value2777 = 2777; b.value2778 = 2778; b.value2779 = 2779; b.value2780 = 2780; b.value2781 = 2781; b.value2782 = 2782; b.value2783 = 2783; b.value2784 = 2784; b.value2785 = 2785; b.value2786 = 2786; b.value2787 = 2787; b.value2788 = 2788; b.value2789 = 2789; b.value2790 = 2790; b.value2791 = 2791; b.value2792 = 2792; b.value2793 = 2793; b.value2794 = 2794; b.value2795 = 2795; b.value2796 = 2796; b.value2797 = 2797; b.value2798 = 2798; b.value2799 = 2799; b.value2800 = 2800; b.value2801 = 2801; b.value2802 = 2802; b.value2803 = 2803; b.value2804 = 2804; b.value2805 = 2805; b.value2806 = 2806; b.value2807 = 2807; b.value2808 = 2808; b.value2809 = 2809; b.value2810 = 2810; b.value2811 = 2811; b.value2812 = 2812; b.value2813 = 2813; b.value2814 = 2814; b.value2815 = 2815; b.value2816 = 2816; b.value2817 = 2817; b.value2818 = 2818; b.value2819 = 2819; b.value2820 = 2820; b.value2821 = 2821; b.value2822 = 2822; b.value2823 = 2823; b.value2824 = 2824; b.value2825 = 2825; b.value2826 = 2826; b.value2827 = 2827; b.value2828 = 2828; b.value2829 = 2829; b.value2830 = 2830; b.value2831 = 2831; b.value2832 = 2832; b.value2833 = 2833; b.value2834 = 2834; b.value2835 = 2835; b.value2836 = 2836; b.value2837 = 2837; b.value2838 = 2838; b.value2839 = 2839; b.value2840 = 2840; b.value2841 = 2841; b.value2842 = 2842; b.value2843 = 2843; b.value2844 = 2844; b.value2845 = 2845; b.value2846 = 2846; b.value2847 = 2847; b.value2848 = 2848; b.value2849 = 2849; b.value2850 = 2850; b.value2851 = 2851; b.value2852 = 2852; b.value2853 = 2853; b.value2854 = 2854; b.value2855 = 2855; b.value2856 = 2856; b.value2857 = 2857; b.value2858 = 2858; b.value2859 = 2859; b.value2860 = 2860; b.value2861 = 2861; b.value2862 = 2862; b.value2863 = 2863; b.value2864 = 2864; b.value2865 = 2865; b.value2866 = 2866; b.value2867 = 2867; b.value2868 = 2868; b.value2869 = 2869; b.value2870 = 2870; b.value2871 = 2871; b.value2872 = 2872; b.value2873 = 2873; b.value2874 = 2874; b.value2875 = 2875; b.value2876 = 2876; b.value2877 = 2877; b.value2878 = 2878; b.value2879 = 2879; b.value2880 = 2880; b.value2881 = 2881; b.value2882 = 2882; b.value2883 = 2883; b.value2884 = 2884; b.value2885 = 2885; b.value2886 = 2886; b.value2887 = 2887; b.value2888 = 2888; b.value2889 = 2889; b.value2890 = 2890; b.value2891 = 2891; b.value2892 = 2892; b.value2893 = 2893; b.value2894 = 2894; b.value2895 = 2895; b.value2896 = 2896; b.value2897 = 2897; b.value2898 = 2898; b.value2899 = 2899; b.value2900 = 2900; b.value2901 = 2901; b.value2902 = 2902; b.value2903 = 2903; b.value2904 = 2904; b.value2905 = 2905; b.value2906 = 2906; b.value2907 = 2907; b.value2908 = 2908; b.value2909 = 2909; b.value2910 = 2910; b.value2911 = 2911; b.value2912 = 2912; b.value2913 = 2913; b.value2914 = 2914; b.value2915 = 2915; b.value2916 = 2916; b.value2917 = 2917; b.value2918 = 2918; b.value2919 = 2919; b.value2920 = 2920; b.value2921 = 2921; b.value2922 = 2922; b.value2923 = 2923; b.value2924 = 2924; b.value2925 = 2925; b.value2926 = 2926; b.value2927 = 2927; b.value2928 = 2928; b.value2929 = 2929; b.value2930 = 2930; b.value2931 = 2931; b.value2932 = 2932; b.value2933 = 2933; b.value2934 = 2934; b.value2935 = 2935; b.value2936 = 2936; b.value2937 = 2937; b.value2938 = 2938; b.value2939 = 2939; b.value2940 = 2940; b.value2941 = 2941; b.value2942 = 2942; b.value2943 = 2943; b.value2944 = 2944; b.value2945 = 2945; b.value2946 = 2946; b.value2947 = 2947; b.value2948 = 2948; b.value2949 = 2949; b.value2950 = 2950; b.value2951 = 2951; b.value2952 = 2952; b.value2953 = 2953; b.value2954 = 2954; b.value2955 = 2955; b.value2956 = 2956; b.value2957 = 2957; b.value2958 = 2958; b.value2959 = 2959; b.value2960 = 2960; b.value2961 = 2961; b.value2962 = 2962; b.value2963 = 2963; b.value2964 = 2964; b.value2965 = 2965; b.value2966 = 2966; b.value2967 = 2967; b.value2968 = 2968; b.value2969 = 2969; b.value2970 = 2970; b.value2971 = 2971; b.value2972 = 2972; b.value2973 = 2973; b.value2974 = 2974; b.value2975 = 2975; b.value2976 = 2976; b.value2977 = 2977; b.value2978 = 2978; b.value2979 = 2979; b.value2980 = 2980; b.value2981 = 2981; b.value2982 = 2982; b.value2983 = 2983; b.value2984 = 2984; b.value2985 = 2985; b.value2986 = 2986; b.value2987 = 2987; b.value2988 = 2988; b.value2989 = 2989; b.value2990 = 2990; b.value2991 = 2991; b.value2992 = 2992; b.value2993 = 2993; b.value2994 = 2994; b.value2995 = 2995; b.value2996 = 2996; b.value2997 = 2997; b.value2998 = 2998; b.value2999 = 2999; b.value3000 = 3000; b.value3001 = 3001; b.value3002 = 3002; b.value3003 = 3003; b.value3004 = 3004; b.value3005 = 3005; b.value3006 = 3006; b.value3007 = 3007; b.value3008 = 3008; b.value3009 = 3009; b.value3010 = 3010; b.value3011 = 3011; b.value3012 = 3012; b.value3013 = 3013; b.value3014 = 3014; b.value3015 = 3015; b.value3016 = 3016; b.value3017 = 3017; b.value3018 = 3018; b.value3019 = 3019; b.value3020 = 3020; b.value3021 = 3021; b.value3022 = 3022; b.value3023 = 3023; b.value3024 = 3024; b.value3025 = 3025; b.value3026 = 3026; b.value3027 = 3027; b.value3028 = 3028; b.value3029 = 3029; b.value3030 = 3030; b.value3031 = 3031; b.value3032 = 3032; b.value3033 = 3033; b.value3034 = 3034; b.value3035 = 3035; b.value3036 = 3036; b.value3037 = 3037; b.value3038 = 3038; b.value3039 = 3039; b.value3040 = 3040; b.value3041 = 3041; b.value3042 = 3042; b.value3043 = 3043; b.value3044 = 3044; b.value3045 = 3045; b.value3046 = 3046; b.value3047 = 3047; b.value3048 = 3048; b.value3049 = 3049; b.value3050 = 3050; b.value3051 = 3051; b.value3052 = 3052; b.value3053 = 3053; b.value3054 = 3054; b.value3055 = 3055; b.value3056 = 3056; b.value3057 = 3057; b.value3058 = 3058; b.value3059 = 3059; b.value3060 = 3060; b.value3061 = 3061; b.value3062 = 3062; b.value3063 = 3063; b.value3064 = 3064; b.value3065 = 3065; b.value3066 = 3066; b.value3067 = 3067; b.value3068 = 3068; b.value3069 = 3069; b.value3070 = 3070; b.value3071 = 3071; b.value3072 = 3072; b.value3073 = 3073; b.value3074 = 3074; b.value3075 = 3075; b.value3076 = 3076; b.value3077 = 3077; b.value3078 = 3078; b.value3079 = 3079; b.value3080 = 3080; b.value3081 = 3081; b.value3082 = 3082; b.value3083 = 3083; b.value3084 = 3084; b.value3085 = 3085; b.value3086 = 3086; b.value3087 = 3087; b.value3088 = 3088; b.value3089 = 3089; b.value3090 = 3090; b.value3091 = 3091; b.value3092 = 3092; b.value3093 = 3093; b.value3094 = 3094; b.value3095 = 3095; b.value3096 = 3096; b.value3097 = 3097; b.value3098 = 3098; b.value3099 = 3099; b.value3100 = 3100; b.value3101 = 3101; b.value3102 = 3102; b.value3103 = 3103; b.value3104 = 3104; b.value3105 = 3105; b.value3106 = 3106; b.value3107 = 3107; b.value3108 = 3108; b.value3109 = 3109; b.value3110 = 3110; b.value3111 = 3111; b.value3112 = 3112; b.value3113 = 3113; b.value3114 = 3114; b.value3115 = 3115; b.value3116 = 3116; b.value3117 = 3117; b.value3118 = 3118; b.value3119 = 3119; b.value3120 = 3120; b.value3121 = 3121; b.value3122 = 3122; b.value3123 = 3123; b.value3124 = 3124; b.value3125 = 3125; b.value3126 = 3126; b.value3127 = 3127; b.value3128 = 3128; b.value3129 = 3129; b.value3130 = 3130; b.value3131 = 3131; b.value3132 = 3132; b.value3133 = 3133; b.value3134 = 3134; b.value3135 = 3135; b.value3136 = 3136; b.value3137 = 3137; b.value3138 = 3138; b.value3139 = 3139; b.value3140 = 3140; b.value3141 = 3141; b.value3142 = 3142; b.value3143 = 3143; b.value3144 = 3144; b.value3145 = 3145; b.value3146 = 3146; b.value3147 = 3147; b.value3148 = 3148; b.value3149 = 3149; b.value3150 = 3150; b.value3151 = 3151; b.value3152 = 3152; b.value3153 = 3153; b.value3154 = 3154; b.value3155 = 3155; b.value3156 = 3156; b.value3157 = 3157; b.value3158 = 3158; b.value3159 = 3159; b.value3160 = 3160; b.value3161 = 3161; b.value3162 = 3162; b.value3163 = 3163; b.value3164 = 3164; b.value3165 = 3165; b.value3166 = 3166; b.value3167 = 3167; b.value3168 = 3168; b.value3169 = 3169; b.value3170 = 3170; b.value3171 = 3171; b.value3172 = 3172; b.value3173 = 3173; b.value3174 = 3174; b.value3175 = 3175; b.value3176 = 3176; b.value3177 = 3177; b.value3178 = 3178; b.value3179 = 3179; b.value3180 = 3180; b.value3181 = 3181; b.value3182 = 3182; b.value3183 = 3183; b.value3184 = 3184; b.value3185 = 3185; b.value3186 = 3186; b.value3187 = 3187; b.value3188 = 3188; b.value3189 = 3189; b.value3190 = 3190; b.value3191 = 3191; b.value3192 = 3192; b.value3193 = 3193; b.value3194 = 3194; b.value3195 = 3195; b.value3196 = 3196; b.value3197 = 3197; b.value3198 = 3198; b.value3199 = 3199; b.value3200 = 3200; b.value3201 = 3201; b.value3202 = 3202; b.value3203 = 3203; b.value3204 = 3204; b.value3205 = 3205; b.value3206 = 3206; b.value3207 = 3207; b.value3208 = 3208; b.value3209 = 3209; b.value3210 = 3210; b.value3211 = 3211; b.value3212 = 3212; b.value3213 = 3213; b.value3214 = 3214; b.value3215 = 3215; b.value3216 = 3216; b.value3217 = 3217; b.value3218 = 3218; b.value3219 = 3219; b.value3220 = 3220; b.value3221 = 3221; b.value3222 = 3222; b.value3223 = 3223; b.value3224 = 3224; b.value3225 = 3225; b.value3226 = 3226; b.value3227 = 3227; b.value3228 = 3228; b.value3229 = 3229; b.value3230 = 3230; b.value3231 = 3231; b.value3232 = 3232; b.value3233 = 3233; b.value3234 = 3234; b.value3235 = 3235; b.value3236 = 3236; b.value3237 = 3237; b.value3238 = 3238; b.value3239 = 3239; b.value3240 = 3240; b.value3241 = 3241; b.value3242 = 3242; b.value3243 = 3243; b.value3244 = 3244; b.value3245 = 3245; b.value3246 = 3246; b.value3247 = 3247; b.value3248 = 3248; b.value3249 = 3249; b.value3250 = 3250; b.value3251 = 3251; b.value3252 = 3252; b.value3253 = 3253; b.value3254 = 3254; b.value3255 = 3255; b.value3256 = 3256; b.value3257 = 3257; b.value3258 = 3258; b.value3259 = 3259; b.value3260 = 3260; b.value3261 = 3261; b.value3262 = 3262; b.value3263 = 3263; b.value3264 = 3264; b.value3265 = 3265; b.value3266 = 3266; b.value3267 = 3267; b.value3268 = 3268; b.value3269 = 3269; b.value3270 = 3270; b.value3271 = 3271; b.value3272 = 3272; b.value3273 = 3273; b.value3274 = 3274; b.value3275 = 3275; b.value3276 = 3276; b.value3277 = 3277; b.value3278 = 3278; b.value3279 = 3279; b.value3280 = 3280; b.value3281 = 3281; b.value3282 = 3282; b.value3283 = 3283; b.value3284 = 3284; b.value3285 = 3285; b.value3286 = 3286; b.value3287 = 3287; b.value3288 = 3288; b.value3289 = 3289; b.value3290 = 3290; b.value3291 = 3291; b.value3292 = 3292; b.value3293 = 3293; b.value3294 = 3294; b.value3295 = 3295; b.value3296 = 3296; b.value3297 = 3297; b.value3298 = 3298; b.value3299 = 3299; b.value3300 = 3300; b.value3301 = 3301; b.value3302 = 3302; b.value3303 = 3303; b.value3304 = 3304; b.value3305 = 3305; b.value3306 = 3306; b.value3307 = 3307; b.value3308 = 3308; b.value3309 = 3309; b.value3310 = 3310; b.value3311 = 3311; b.value3312 = 3312; b.value3313 = 3313; b.value3314 = 3314; b.value3315 = 3315; b.value3316 = 3316; b.value3317 = 3317; b.value3318 = 3318; b.value3319 = 3319; b.value3320 = 3320; b.value3321 = 3321; b.value3322 = 3322; b.value3323 = 3323; b.value3324 = 3324; b.value3325 = 3325; b.value3326 = 3326; b.value3327 = 3327; b.value3328 = 3328; b.value3329 = 3329; b.value3330 = 3330; b.value3331 = 3331; b.value3332 = 3332; b.value3333 = 3333; b.value3334 = 3334; b.value3335 = 3335; b.value3336 = 3336; b.value3337 = 3337; b.value3338 = 3338; b.value3339 = 3339; b.value3340 = 3340; b.value3341 = 3341; b.value3342 = 3342; b.value3343 = 3343; b.value3344 = 3344; b.value3345 = 3345; b.value3346 = 3346; b.value3347 = 3347; b.value3348 = 3348; b.value3349 = 3349; b.value3350 = 3350; b.value3351 = 3351; b.value3352 = 3352; b.value3353 = 3353; b.value3354 = 3354; b.value3355 = 3355; b.value3356 = 3356; b.value3357 = 3357; b.value3358 = 3358; b.value3359 = 3359; b.value3360 = 3360; b.value3361 = 3361; b.value3362 = 3362; b.value3363 = 3363; b.value3364 = 3364; b.value3365 = 3365; b.value3366 = 3366; b.value3367 = 3367; b.value3368 = 3368; b.value3369 = 3369; b.value3370 = 3370; b.value3371 = 3371; b.value3372 = 3372; b.value3373 = 3373; b.value3374 = 3374; b.value3375 = 3375; b.value3376 = 3376; b.value3377 = 3377; b.value3378 = 3378; b.value3379 = 3379; b.value3380 = 3380; b.value3381 = 3381; b.value3382 = 3382; b.value3383 = 3383; b.value3384 = 3384; b.value3385 = 3385; b.value3386 = 3386; b.value3387 = 3387; b.value3388 = 3388; b.value3389 = 3389; b.value3390 = 3390; b.value3391 = 3391; b.value3392 = 3392; b.value3393 = 3393; b.value3394 = 3394; b.value3395 = 3395; b.value3396 = 3396; b.value3397 = 3397; b.value3398 = 3398; b.value3399 = 3399; b.value3400 = 3400; b.value3401 = 3401; b.value3402 = 3402; b.value3403 = 3403; b.value3404 = 3404; b.value3405 = 3405; b.value3406 = 3406; b.value3407 = 3407; b.value3408 = 3408; b.value3409 = 3409; b.value3410 = 3410; b.value3411 = 3411; b.value3412 = 3412; b.value3413 = 3413; b.value3414 = 3414; b.value3415 = 3415; b.value3416 = 3416; b.value3417 = 3417; b.value3418 = 3418; b.value3419 = 3419; b.value3420 = 3420; b.value3421 = 3421; b.value3422 = 3422; b.value3423 = 3423; b.value3424 = 3424; b.value3425 = 3425; b.value3426 = 3426; b.value3427 = 3427; b.value3428 = 3428; b.value3429 = 3429; b.value3430 = 3430; b.value3431 = 3431; b.value3432 = 3432; b.value3433 = 3433; b.value3434 = 3434; b.value3435 = 3435; b.value3436 = 3436; b.value3437 = 3437; b.value3438 = 3438; b.value3439 = 3439; b.value3440 = 3440; b.value3441 = 3441; b.value3442 = 3442; b.value3443 = 3443; b.value3444 = 3444; b.value3445 = 3445; b.value3446 = 3446; b.value3447 = 3447; b.value3448 = 3448; b.value3449 = 3449; b.value3450 = 3450; b.value3451 = 3451; b.value3452 = 3452; b.value3453 = 3453; b.value3454 = 3454; b.value3455 = 3455; b.value3456 = 3456; b.value3457 = 3457; b.value3458 = 3458; b.value3459 = 3459; b.value3460 = 3460; b.value3461 = 3461; b.value3462 = 3462; b.value3463 = 3463; b.value3464 = 3464; b.value3465 = 3465; b.value3466 = 3466; b.value3467 = 3467; b.value3468 = 3468; b.value3469 = 3469; b.value3470 = 3470; b.value3471 = 3471; b.value3472 = 3472; b.value3473 = 3473; b.value3474 = 3474; b.value3475 = 3475; b.value3476 = 3476; b.value3477 = 3477; b.value3478 = 3478; b.value3479 = 3479; b.value3480 = 3480; b.value3481 = 3481; b.value3482 = 3482; b.value3483 = 3483; b.value3484 = 3484; b.value3485 = 3485; b.value3486 = 3486; b.value3487 = 3487; b.value3488 = 3488; b.value3489 = 3489; b.value3490 = 3490; b.value3491 = 3491; b.value3492 = 3492; b.value3493 = 3493; b.value3494 = 3494; b.value3495 = 3495; b.value3496 = 3496; b.value3497 = 3497; b.value3498 = 3498; b.value3499 = 3499; b.value3500 = 3500; b.value3501 = 3501; b.value3502 = 3502; b.value3503 = 3503; b.value3504 = 3504; b.value3505 = 3505; b.value3506 = 3506; b.value3507 = 3507; b.value3508 = 3508; b.value3509 = 3509; b.value3510 = 3510; b.value3511 = 3511; b.value3512 = 3512; b.value3513 = 3513; b.value3514 = 3514; b.value3515 = 3515; b.value3516 = 3516; b.value3517 = 3517; b.value3518 = 3518; b.value3519 = 3519; b.value3520 = 3520; b.value3521 = 3521; b.value3522 = 3522; b.value3523 = 3523; b.value3524 = 3524; b.value3525 = 3525; b.value3526 = 3526; b.value3527 = 3527; b.value3528 = 3528; b.value3529 = 3529; b.value3530 = 3530; b.value3531 = 3531; b.value3532 = 3532; b.value3533 = 3533; b.value3534 = 3534; b.value3535 = 3535; b.value3536 = 3536; b.value3537 = 3537; b.value3538 = 3538; b.value3539 = 3539; b.value3540 = 3540; b.value3541 = 3541; b.value3542 = 3542; b.value3543 = 3543; b.value3544 = 3544; b.value3545 = 3545; b.value3546 = 3546; b.value3547 = 3547; b.value3548 = 3548; b.value3549 = 3549; b.value3550 = 3550; b.value3551 = 3551; b.value3552 = 3552; b.value3553 = 3553; b.value3554 = 3554; b.value3555 = 3555; b.value3556 = 3556; b.value3557 = 3557; b.value3558 = 3558; b.value3559 = 3559; b.value3560 = 3560; b.value3561 = 3561; b.value3562 = 3562; b.value3563 = 3563; b.value3564 = 3564; b.value3565 = 3565; b.value3566 = 3566; b.value3567 = 3567; b.value3568 = 3568; b.value3569 = 3569; b.value3570 = 3570; b.value3571 = 3571; b.value3572 = 3572; b.value3573 = 3573; b.value3574 = 3574; b.value3575 = 3575; b.value3576 = 3576; b.value3577 = 3577; b.value3578 = 3578; b.value3579 = 3579; b.value3580 = 3580; b.value3581 = 3581; b.value3582 = 3582; b.value3583 = 3583; b.value3584 = 3584; b.value3585 = 3585; b.value3586 = 3586; b.value3587 = 3587; b.value3588 = 3588; b.value3589 = 3589; b.value3590 = 3590; b.value3591 = 3591; b.value3592 = 3592; b.value3593 = 3593; b.value3594 = 3594; b.value3595 = 3595; b.value3596 = 3596; b.value3597 = 3597; b.value3598 = 3598; b.value3599 = 3599; b.value3600 = 3600; b.value3601 = 3601; b.value3602 = 3602; b.value3603 = 3603; b.value3604 = 3604; b.value3605 = 3605; b.value3606 = 3606; b.value3607 = 3607; b.value3608 = 3608; b.value3609 = 3609; b.value3610 = 3610; b.value3611 = 3611; b.value3612 = 3612; b.value3613 = 3613; b.value3614 = 3614; b.value3615 = 3615; b.value3616 = 3616; b.value3617 = 3617; b.value3618 = 3618; b.value3619 = 3619; b.value3620 = 3620; b.value3621 = 3621; b.value3622 = 3622; b.value3623 = 3623; b.value3624 = 3624; b.value3625 = 3625; b.value3626 = 3626; b.value3627 = 3627; b.value3628 = 3628; b.value3629 = 3629; b.value3630 = 3630; b.value3631 = 3631; b.value3632 = 3632; b.value3633 = 3633; b.value3634 = 3634; b.value3635 = 3635; b.value3636 = 3636; b.value3637 = 3637; b.value3638 = 3638; b.value3639 = 3639; b.value3640 = 3640; b.value3641 = 3641; b.value3642 = 3642; b.value3643 = 3643; b.value3644 = 3644; b.value3645 = 3645; b.value3646 = 3646; b.value3647 = 3647; b.value3648 = 3648; b.value3649 = 3649; b.value3650 = 3650; b.value3651 = 3651; b.value3652 = 3652; b.value3653 = 3653; b.value3654 = 3654; b.value3655 = 3655; b.value3656 = 3656; b.value3657 = 3657; b.value3658 = 3658; b.value3659 = 3659; b.value3660 = 3660; b.value3661 = 3661; b.value3662 = 3662; b.value3663 = 3663; b.value3664 = 3664; b.value3665 = 3665; b.value3666 = 3666; b.value3667 = 3667; b.value3668 = 3668; b.value3669 = 3669; b.value3670 = 3670; b.value3671 = 3671; b.value3672 = 3672; b.value3673 = 3673; b.value3674 = 3674; b.value3675 = 3675; b.value3676 = 3676; b.value3677 = 3677; b.value3678 = 3678; b.value3679 = 3679; b.value3680 = 3680; b.value3681 = 3681; b.value3682 = 3682; b.value3683 = 3683; b.value3684 = 3684; b.value3685 = 3685; b.value3686 = 3686; b.value3687 = 3687; b.value3688 = 3688; b.value3689 = 3689; b.value3690 = 3690; b.value3691 = 3691; b.value3692 = 3692; b.value3693 = 3693; b.value3694 = 3694; b.value3695 = 3695; b.value3696 = 3696; b.value3697 = 3697; b.value3698 = 3698; b.value3699 = 3699; b.value3700 = 3700; b.value3701 = 3701; b.value3702 = 3702; b.value3703 = 3703; b.value3704 = 3704; b.value3705 = 3705; b.value3706 = 3706; b.value3707 = 3707; b.value3708 = 3708; b.value3709 = 3709; b.value3710 = 3710; b.value3711 = 3711; b.value3712 = 3712; b.value3713 = 3713; b.value3714 = 3714; b.value3715 = 3715; b.value3716 = 3716; b.value3717 = 3717; b.value3718 = 3718; b.value3719 = 3719; b.value3720 = 3720; b.value3721 = 3721; b.value3722 = 3722; b.value3723 = 3723; b.value3724 = 3724; b.value3725 = 3725; b.value3726 = 3726; b.value3727 = 3727; b.value3728 = 3728; b.value3729 = 3729; b.value3730 = 3730; b.value3731 = 3731; b.value3732 = 3732; b.value3733 = 3733; b.value3734 = 3734; b.value3735 = 3735; b.value3736 = 3736; b.value3737 = 3737; b.value3738 = 3738; b.value3739 = 3739; b.value3740 = 3740; b.value3741 = 3741; b.value3742 = 3742; b.value3743 = 3743; b.value3744 = 3744; b.value3745 = 3745; b.value3746 = 3746; b.value3747 = 3747; b.value3748 = 3748; b.value3749 = 3749; b.value3750 = 3750; b.value3751 = 3751; b.value3752 = 3752; b.value3753 = 3753; b.value3754 = 3754; b.value3755 = 3755; b.value3756 = 3756; b.value3757 = 3757; b.value3758 = 3758; b.value3759 = 3759; b.value3760 = 3760; b.value3761 = 3761; b.value3762 = 3762; b.value3763 = 3763; b.value3764 = 3764; b.value3765 = 3765; b.value3766 = 3766; b.value3767 = 3767; b.value3768 = 3768; b.value3769 = 3769; b.value3770 = 3770; b.value3771 = 3771; b.value3772 = 3772; b.value3773 = 3773; b.value3774 = 3774; b.value3775 = 3775; b.value3776 = 3776; b.value3777 = 3777; b.value3778 = 3778; b.value3779 = 3779; b.value3780 = 3780; b.value3781 = 3781; b.value3782 = 3782; b.value3783 = 3783; b.value3784 = 3784; b.value3785 = 3785; b.value3786 = 3786; b.value3787 = 3787; b.value3788 = 3788; b.value3789 = 3789; b.value3790 = 3790; b.value3791 = 3791; b.value3792 = 3792; b.value3793 = 3793; b.value3794 = 3794; b.value3795 = 3795; b.value3796 = 3796; b.value3797 = 3797; b.value3798 = 3798; b.value3799 = 3799; b.value3800 = 3800; b.value3801 = 3801; b.value3802 = 3802; b.value3803 = 3803; b.value3804 = 3804; b.value3805 = 3805; b.value3806 = 3806; b.value3807 = 3807; b.value3808 = 3808; b.value3809 = 3809; b.value3810 = 3810; b.value3811 = 3811; b.value3812 = 3812; b.value3813 = 3813; b.value3814 = 3814; b.value3815 = 3815; b.value3816 = 3816; b.value3817 = 3817; b.value3818 = 3818; b.value3819 = 3819; b.value3820 = 3820; b.value3821 = 3821; b.value3822 = 3822; b.value3823 = 3823; b.value3824 = 3824; b.value3825 = 3825; b.value3826 = 3826; b.value3827 = 3827; b.value3828 = 3828; b.value3829 = 3829; b.value3830 = 3830; b.value3831 = 3831; b.value3832 = 3832; b.value3833 = 3833; b.value3834 = 3834; b.value3835 = 3835; b.value3836 = 3836; b.value3837 = 3837; b.value3838 = 3838; b.value3839 = 3839; b.value3840 = 3840; b.value3841 = 3841; b.value3842 = 3842; b.value3843 = 3843; b.value3844 = 3844; b.value3845 = 3845; b.value3846 = 3846; b.value3847 = 3847; b.value3848 = 3848; b.value3849 = 3849; b.value3850 = 3850; b.value3851 = 3851; b.value3852 = 3852; b.value3853 = 3853; b.value3854 = 3854; b.value3855 = 3855; b.value3856 = 3856; b.value3857 = 3857; b.value3858 = 3858; b.value3859 = 3859; b.value3860 = 3860; b.value3861 = 3861; b.value3862 = 3862; b.value3863 = 3863; b.value3864 = 3864; b.value3865 = 3865; b.value3866 = 3866; b.value3867 = 3867; b.value3868 = 3868; b.value3869 = 3869; b.value3870 = 3870; b.value3871 = 3871; b.value3872 = 3872; b.value3873 = 3873; b.value3874 = 3874; b.value3875 = 3875; b.value3876 = 3876; b.value3877 = 3877; b.value3878 = 3878; b.value3879 = 3879; b.value3880 = 3880; b.value3881 = 3881; b.value3882 = 3882; b.value3883 = 3883; b.value3884 = 3884; b.value3885 = 3885; b.value3886 = 3886; b.value3887 = 3887; b.value3888 = 3888; b.value3889 = 3889; b.value3890 = 3890; b.value3891 = 3891; b.value3892 = 3892; b.value3893 = 3893; b.value3894 = 3894; b.value3895 = 3895; b.value3896 = 3896; b.value3897 = 3897; b.value3898 = 3898; b.value3899 = 3899; b.value3900 = 3900; b.value3901 = 3901; b.value3902 = 3902; b.value3903 = 3903; b.value3904 = 3904; b.value3905 = 3905; b.value3906 = 3906; b.value3907 = 3907; b.value3908 = 3908; b.value3909 = 3909; b.value3910 = 3910; b.value3911 = 3911; b.value3912 = 3912; b.value3913 = 3913; b.value3914 = 3914; b.value3915 = 3915; b.value3916 = 3916; b.value3917 = 3917; b.value3918 = 3918; b.value3919 = 3919; b.value3920 = 3920; b.value3921 = 3921; b.value3922 = 3922; b.value3923 = 3923; b.value3924 = 3924; b.value3925 = 3925; b.value3926 = 3926; b.value3927 = 3927; b.value3928 = 3928; b.value3929 = 3929; b.value3930 = 3930; b.value3931 = 3931; b.value3932 = 3932; b.value3933 = 3933; b.value3934 = 3934; b.value3935 = 3935; b.value3936 = 3936; b.value3937 = 3937; b.value3938 = 3938; b.value3939 = 3939; b.value3940 = 3940; b.value3941 = 3941; b.value3942 = 3942; b.value3943 = 3943; b.value3944 = 3944; b.value3945 = 3945; b.value3946 = 3946; b.value3947 = 3947; b.value3948 = 3948; b.value3949 = 3949; b.value3950 = 3950; b.value3951 = 3951; b.value3952 = 3952; b.value3953 = 3953; b.value3954 = 3954; b.value3955 = 3955; b.value3956 = 3956; b.value3957 = 3957; b.value3958 = 3958; b.value3959 = 3959; b.value3960 = 3960; b.value3961 = 3961; b.value3962 = 3962; b.value3963 = 3963; b.value3964 = 3964; b.value3965 = 3965; b.value3966 = 3966; b.value3967 = 3967; b.value3968 = 3968; b.value3969 = 3969; b.value3970 = 3970; b.value3971 = 3971; b.value3972 = 3972; b.value3973 = 3973; b.value3974 = 3974; b.value3975 = 3975; b.value3976 = 3976; b.value3977 = 3977; b.value3978 = 3978; b.value3979 = 3979; b.value3980 = 3980; b.value3981 = 3981; b.value3982 = 3982; b.value3983 = 3983; b.value3984 = 3984; b.value3985 = 3985; b.value3986 = 3986; b.value3987 = 3987; b.value3988 = 3988; b.value3989 = 3989; b.value3990 = 3990; b.value3991 = 3991; b.value3992 = 3992; b.value3993 = 3993; b.value3994 = 3994; b.value3995 = 3995; b.value3996 = 3996; b.value3997 = 3997; b.value3998 = 3998; b.value3999 = 3999; b.value4000 = 4000; b.value4001 = 4001; b.value4002 = 4002; b.value4003 = 4003; b.value4004 = 4004; b.value4005 = 4005; b.value4006 = 4006; b.value4007 = 4007; b.value4008 = 4008; b.value4009 = 4009; b.value4010 = 4010; b.value4011 = 4011; b.value4012 = 4012; b.value4013 = 4013; b.value4014 = 4014; b.value4015 = 4015; b.value4016 = 4016; b.value4017 = 4017; b.value4018 = 4018; b.value4019 = 4019; b.value4020 = 4020; b.value4021 = 4021; b.value4022 = 4022; b.value4023 = 4023; b.value4024 = 4024; b.value4025 = 4025; b.value4026 = 4026; b.value4027 = 4027; b.value4028 = 4028; b.value4029 = 4029; b.value4030 = 4030; b.value4031 = 4031; b.value4032 = 4032; b.value4033 = 4033; b.value4034 = 4034; b.value4035 = 4035; b.value4036 = 4036; b.value4037 = 4037; b.value4038 = 4038; b.value4039 = 4039; b.value4040 = 4040; b.value4041 = 4041; b.value4042 = 4042; b.value4043 = 4043; b.value4044 = 4044; b.value4045 = 4045; b.value4046 = 4046; b.value4047 = 4047; b.value4048 = 4048; b.value4049 = 4049; b.value4050 = 4050; b.value4051 = 4051; b.value4052 = 4052; b.value4053 = 4053; b.value4054 = 4054; b.value4055 = 4055; b.value4056 = 4056; b.value4057 = 4057; b.value4058 = 4058; b.value4059 = 4059; b.value4060 = 4060; b.value4061 = 4061; b.value4062 = 4062; b.value4063 = 4063; b.value4064 = 4064; b.value4065 = 4065; b.value4066 = 4066; b.value4067 = 4067; b.value4068 = 4068; b.value4069 = 4069; b.value4070 = 4070; b.value4071 = 4071; b.value4072 = 4072; b.value4073 = 4073; b.value4074 = 4074; b.value4075 = 4075; b.value4076 = 4076; b.value4077 = 4077; b.value4078 = 4078; b.value4079 = 4079; b.value4080 = 4080; b.value4081 = 4081; b.value4082 = 4082; b.value4083 = 4083; b.value4084 = 4084; b.value4085 = 4085; b.value4086 = 4086; b.value4087 = 4087; b.value4088 = 4088; b.value4089 = 4089; b.value4090 = 4090; b.value4091 = 4091; b.value4092 = 4092; b.value4093 = 4093; b.value4094 = 4094; b.value4095 = 4095; b.value4096 = 4096; b.value4097 = 4097; b.value4098 = 4098; b.value4099 = 4099; b.value4100 = 4100; b.value4101 = 4101; b.value4102 = 4102; b.value4103 = 4103; b.value4104 = 4104; b.value4105 = 4105; b.value4106 = 4106; b.value4107 = 4107; b.value4108 = 4108; b.value4109 = 4109; b.value4110 = 4110; b.value4111 = 4111; b.value4112 = 4112; b.value4113 = 4113; b.value4114 = 4114; b.value4115 = 4115; b.value4116 = 4116; b.value4117 = 4117; b.value4118 = 4118; b.value4119 = 4119; b.value4120 = 4120; b.value4121 = 4121; b.value4122 = 4122; b.value4123 = 4123; b.value4124 = 4124; b.value4125 = 4125; b.value4126 = 4126; b.value4127 = 4127; b.value4128 = 4128; b.value4129 = 4129; b.value4130 = 4130; b.value4131 = 4131; b.value4132 = 4132; b.value4133 = 4133; b.value4134 = 4134; b.value4135 = 4135; b.value4136 = 4136; b.value4137 = 4137; b.value4138 = 4138; b.value4139 = 4139; b.value4140 = 4140; b.value4141 = 4141; b.value4142 = 4142; b.value4143 = 4143; b.value4144 = 4144; b.value4145 = 4145; b.value4146 = 4146; b.value4147 = 4147; b.value4148 = 4148; b.value4149 = 4149; b.value4150 = 4150; b.value4151 = 4151; b.value4152 = 4152; b.value4153 = 4153; b.value4154 = 4154; b.value4155 = 4155; b.value4156 = 4156; b.value4157 = 4157; b.value4158 = 4158; b.value4159 = 4159; b.value4160 = 4160; b.value4161 = 4161; b.value4162 = 4162; b.value4163 = 4163; b.value4164 = 4164; b.value4165 = 4165; b.value4166 = 4166; b.value4167 = 4167; b.value4168 = 4168; b.value4169 = 4169; b.value4170 = 4170; b.value4171 = 4171; b.value4172 = 4172; b.value4173 = 4173; b.value4174 = 4174; b.value4175 = 4175; b.value4176 = 4176; b.value4177 = 4177; b.value4178 = 4178; b.value4179 = 4179; b.value4180 = 4180; b.value4181 = 4181; b.value4182 = 4182; b.value4183 = 4183; b.value4184 = 4184; b.value4185 = 4185; b.value4186 = 4186; b.value4187 = 4187; b.value4188 = 4188; b.value4189 = 4189; b.value4190 = 4190; b.value4191 = 4191; b.value4192 = 4192; b.value4193 = 4193; b.value4194 = 4194; b.value4195 = 4195; b.value4196 = 4196; b.value4197 = 4197; b.value4198 = 4198; b.value4199 = 4199; b.value4200 = 4200; b.value4201 = 4201; b.value4202 = 4202; b.value4203 = 4203; b.value4204 = 4204; b.value4205 = 4205; b.value4206 = 4206; b.value4207 = 4207; b.value4208 = 4208; b.value4209 = 4209; b.value4210 = 4210; b.value4211 = 4211; b.value4212 = 4212; b.value4213 = 4213; b.value4214 = 4214; b.value4215 = 4215; b.value4216 = 4216; b.value4217 = 4217; b.value4218 = 4218; b.value4219 = 4219; b.value4220 = 4220; b.value4221 = 4221; b.value4222 = 4222; b.value4223 = 4223; b.value4224 = 4224; b.value4225 = 4225; b.value4226 = 4226; b.value4227 = 4227; b.value4228 = 4228; b.value4229 = 4229; b.value4230 = 4230; b.value4231 = 4231; b.value4232 = 4232; b.value4233 = 4233; b.value4234 = 4234; b.value4235 = 4235; b.value4236 = 4236; b.value4237 = 4237; b.value4238 = 4238; b.value4239 = 4239; b.value4240 = 4240; b.value4241 = 4241; b.value4242 = 4242; b.value4243 = 4243; b.value4244 = 4244; b.value4245 = 4245; b.value4246 = 4246; b.value4247 = 4247; b.value4248 = 4248; b.value4249 = 4249; b.value4250 = 4250; b.value4251 = 4251; b.value4252 = 4252; b.value4253 = 4253; b.value4254 = 4254; b.value4255 = 4255; b.value4256 = 4256; b.value4257 = 4257; b.value4258 = 4258; b.value4259 = 4259; b.value4260 = 4260; b.value4261 = 4261; b.value4262 = 4262; b.value4263 = 4263; b.value4264 = 4264; b.value4265 = 4265; b.value4266 = 4266; b.value4267 = 4267; b.value4268 = 4268; b.value4269 = 4269; b.value4270 = 4270; b.value4271 = 4271; b.value4272 = 4272; b.value4273 = 4273; b.value4274 = 4274; b.value4275 = 4275; b.value4276 = 4276; b.value4277 = 4277; b.value4278 = 4278; b.value4279 = 4279; b.value4280 = 4280; b.value4281 = 4281; b.value4282 = 4282; b.value4283 = 4283; b.value4284 = 4284; b.value4285 = 4285; b.value4286 = 4286; b.value4287 = 4287; b.value4288 = 4288; b.value4289 = 4289; b.value4290 = 4290; b.value4291 = 4291; b.value4292 = 4292; b.value4293 = 4293; b.value4294 = 4294; b.value4295 = 4295; b.value4296 = 4296; b.value4297 = 4297; b.value4298 = 4298; b.value4299 = 4299; b.value4300 = 4300; b.value4301 = 4301; b.value4302 = 4302; b.value4303 = 4303; b.value4304 = 4304; b.value4305 = 4305; b.value4306 = 4306; b.value4307 = 4307; b.value4308 = 4308; b.value4309 = 4309; b.value4310 = 4310; b.value4311 = 4311; b.value4312 = 4312; b.value4313 = 4313; b.value4314 = 4314; b.value4315 = 4315; b.value4316 = 4316; b.value4317 = 4317; b.value4318 = 4318; b.value4319 = 4319; b.value4320 = 4320; b.value4321 = 4321; b.value4322 = 4322; b.value4323 = 4323; b.value4324 = 4324; b.value4325 = 4325; b.value4326 = 4326; b.value4327 = 4327; b.value4328 = 4328; b.value4329 = 4329; b.value4330 = 4330; b.value4331 = 4331; b.value4332 = 4332; b.value4333 = 4333; b.value4334 = 4334; b.value4335 = 4335; b.value4336 = 4336; b.value4337 = 4337; b.value4338 = 4338; b.value4339 = 4339; b.value4340 = 4340; b.value4341 = 4341; b.value4342 = 4342; b.value4343 = 4343; b.value4344 = 4344; b.value4345 = 4345; b.value4346 = 4346; b.value4347 = 4347; b.value4348 = 4348; b.value4349 = 4349; b.value4350 = 4350; b.value4351 = 4351; b.value4352 = 4352; b.value4353 = 4353; b.value4354 = 4354; b.value4355 = 4355; b.value4356 = 4356; b.value4357 = 4357; b.value4358 = 4358; b.value4359 = 4359; b.value4360 = 4360; b.value4361 = 4361; b.value4362 = 4362; b.value4363 = 4363; b.value4364 = 4364; b.value4365 = 4365; b.value4366 = 4366; b.value4367 = 4367; b.value4368 = 4368; b.value4369 = 4369; b.value4370 = 4370; b.value4371 = 4371; b.value4372 = 4372; b.value4373 = 4373; b.value4374 = 4374; b.value4375 = 4375; b.value4376 = 4376; b.value4377 = 4377; b.value4378 = 4378; b.value4379 = 4379; b.value4380 = 4380; b.value4381 = 4381; b.value4382 = 4382; b.value4383 = 4383; b.value4384 = 4384; b.value4385 = 4385; b.value4386 = 4386; b.value4387 = 4387; b.value4388 = 4388; b.value4389 = 4389; b.value4390 = 4390; b.value4391 = 4391; b.value4392 = 4392; b.value4393 = 4393; b.value4394 = 4394; b.value4395 = 4395; b.value4396 = 4396; b.value4397 = 4397; b.value4398 = 4398; b.value4399 = 4399; b.value4400 = 4400; b.value4401 = 4401; b.value4402 = 4402; b.value4403 = 4403; b.value4404 = 4404; b.value4405 = 4405; b.value4406 = 4406; b.value4407 = 4407; b.value4408 = 4408; b.value4409 = 4409; b.value4410 = 4410; b.value4411 = 4411; b.value4412 = 4412; b.value4413 = 4413; b.value4414 = 4414; b.value4415 = 4415; b.value4416 = 4416; b.value4417 = 4417; b.value4418 = 4418; b.value4419 = 4419; b.value4420 = 4420; b.value4421 = 4421; b.value4422 = 4422; b.value4423 = 4423; b.value4424 = 4424; b.value4425 = 4425; b.value4426 = 4426; b.value4427 = 4427; b.value4428 = 4428; b.value4429 = 4429; b.value4430 = 4430; b.value4431 = 4431; b.value4432 = 4432; b.value4433 = 4433; b.value4434 = 4434; b.value4435 = 4435; b.value4436 = 4436; b.value4437 = 4437; b.value4438 = 4438; b.value4439 = 4439; b.value4440 = 4440; b.value4441 = 4441; b.value4442 = 4442; b.value4443 = 4443; b.value4444 = 4444; b.value4445 = 4445; b.value4446 = 4446; b.value4447 = 4447; b.value4448 = 4448; b.value4449 = 4449; b.value4450 = 4450; b.value4451 = 4451; b.value4452 = 4452; b.value4453 = 4453; b.value4454 = 4454; b.value4455 = 4455; b.value4456 = 4456; b.value4457 = 4457; b.value4458 = 4458; b.value4459 = 4459; b.value4460 = 4460; b.value4461 = 4461; b.value4462 = 4462; b.value4463 = 4463; b.value4464 = 4464; b.value4465 = 4465; b.value4466 = 4466; b.value4467 = 4467; b.value4468 = 4468; b.value4469 = 4469; b.value4470 = 4470; b.value4471 = 4471; b.value4472 = 4472; b.value4473 = 4473; b.value4474 = 4474; b.value4475 = 4475; b.value4476 = 4476; b.value4477 = 4477; b.value4478 = 4478; b.value4479 = 4479; b.value4480 = 4480; b.value4481 = 4481; b.value4482 = 4482; b.value4483 = 4483; b.value4484 = 4484; b.value4485 = 4485; b.value4486 = 4486; b.value4487 = 4487; b.value4488 = 4488; b.value4489 = 4489; b.value4490 = 4490; b.value4491 = 4491; b.value4492 = 4492; b.value4493 = 4493; b.value4494 = 4494; b.value4495 = 4495; b.value4496 = 4496; b.value4497 = 4497; b.value4498 = 4498; b.value4499 = 4499; b.value4500 = 4500; b.value4501 = 4501; b.value4502 = 4502; b.value4503 = 4503; b.value4504 = 4504; b.value4505 = 4505; b.value4506 = 4506; b.value4507 = 4507; b.value4508 = 4508; b.value4509 = 4509; b.value4510 = 4510; b.value4511 = 4511; b.value4512 = 4512; b.value4513 = 4513; b.value4514 = 4514; b.value4515 = 4515; b.value4516 = 4516; b.value4517 = 4517; b.value4518 = 4518; b.value4519 = 4519; b.value4520 = 4520; b.value4521 = 4521; b.value4522 = 4522; b.value4523 = 4523; b.value4524 = 4524; b.value4525 = 4525; b.value4526 = 4526; b.value4527 = 4527; b.value4528 = 4528; b.value4529 = 4529; b.value4530 = 4530; b.value4531 = 4531; b.value4532 = 4532; b.value4533 = 4533; b.value4534 = 4534; b.value4535 = 4535; b.value4536 = 4536; b.value4537 = 4537; b.value4538 = 4538; b.value4539 = 4539; b.value4540 = 4540; b.value4541 = 4541; b.value4542 = 4542; b.value4543 = 4543; b.value4544 = 4544; b.value4545 = 4545; b.value4546 = 4546; b.value4547 = 4547; b.value4548 = 4548; b.value4549 = 4549; b.value4550 = 4550; b.value4551 = 4551; b.value4552 = 4552; b.value4553 = 4553; b.value4554 = 4554; b.value4555 = 4555; b.value4556 = 4556; b.value4557 = 4557; b.value4558 = 4558; b.value4559 = 4559; b.value4560 = 4560; b.value4561 = 4561; b.value4562 = 4562; b.value4563 = 4563; b.value4564 = 4564; b.value4565 = 4565; b.value4566 = 4566; b.value4567 = 4567; b.value4568 = 4568; b.value4569 = 4569; b.value4570 = 4570; b.value4571 = 4571; b.value4572 = 4572; b.value4573 = 4573; b.value4574 = 4574; b.value4575 = 4575; b.value4576 = 4576; b.value4577 = 4577; b.value4578 = 4578; b.value4579 = 4579; b.value4580 = 4580; b.value4581 = 4581; b.value4582 = 4582; b.value4583 = 4583; b.value4584 = 4584; b.value4585 = 4585; b.value4586 = 4586; b.value4587 = 4587; b.value4588 = 4588; b.value4589 = 4589; b.value4590 = 4590; b.value4591 = 4591; b.value4592 = 4592; b.value4593 = 4593; b.value4594 = 4594; b.value4595 = 4595; b.value4596 = 4596; b.value4597 = 4597; b.value4598 = 4598; b.value4599 = 4599; b.value4600 = 4600; b.value4601 = 4601; b.value4602 = 4602; b.value4603 = 4603; b.value4604 = 4604; b.value4605 = 4605; b.value4606 = 4606; b.value4607 = 4607; b.value4608 = 4608; b.value4609 = 4609; b.value4610 = 4610; b.value4611 = 4611; b.value4612 = 4612; b.value4613 = 4613; b.value4614 = 4614; b.value4615 = 4615; b.value4616 = 4616; b.value4617 = 4617; b.value4618 = 4618; b.value4619 = 4619; b.value4620 = 4620; b.value4621 = 4621; b.value4622 = 4622; b.value4623 = 4623; b.value4624 = 4624; b.value4625 = 4625; b.value4626 = 4626; b.value4627 = 4627; b.value4628 = 4628; b.value4629 = 4629; b.value4630 = 4630; b.value4631 = 4631; b.value4632 = 4632; b.value4633 = 4633; b.value4634 = 4634; b.value4635 = 4635; b.value4636 = 4636; b.value4637 = 4637; b.value4638 = 4638; b.value4639 = 4639; b.value4640 = 4640; b.value4641 = 4641; b.value4642 = 4642; b.value4643 = 4643; b.value4644 = 4644; b.value4645 = 4645; b.value4646 = 4646; b.value4647 = 4647; b.value4648 = 4648; b.value4649 = 4649; b.value4650 = 4650; b.value4651 = 4651; b.value4652 = 4652; b.value4653 = 4653; b.value4654 = 4654; b.value4655 = 4655; b.value4656 = 4656; b.value4657 = 4657; b.value4658 = 4658; b.value4659 = 4659; b.value4660 = 4660; b.value4661 = 4661; b.value4662 = 4662; b.value4663 = 4663; b.value4664 = 4664; b.value4665 = 4665; b.value4666 = 4666; b.value4667 = 4667; b.value4668 = 4668; b.value4669 = 4669; b.value4670 = 4670; b.value4671 = 4671; b.value4672 = 4672; b.value4673 = 4673; b.value4674 = 4674; b.value4675 = 4675; b.value4676 = 4676; b.value4677 = 4677; b.value4678 = 4678; b.value4679 = 4679; b.value4680 = 4680; b.value4681 = 4681; b.value4682 = 4682; b.value4683 = 4683; b.value4684 = 4684; b.value4685 = 4685; b.value4686 = 4686; b.value4687 = 4687; b.value4688 = 4688; b.value4689 = 4689; b.value4690 = 4690; b.value4691 = 4691; b.value4692 = 4692; b.value4693 = 4693; b.value4694 = 4694; b.value4695 = 4695; b.value4696 = 4696; b.value4697 = 4697; b.value4698 = 4698; b.value4699 = 4699; b.value4700 = 4700; b.value4701 = 4701; b.value4702 = 4702; b.value4703 = 4703; b.value4704 = 4704; b.value4705 = 4705; b.value4706 = 4706; b.value4707 = 4707; b.value4708 = 4708; b.value4709 = 4709; b.value4710 = 4710; b.value4711 = 4711; b.value4712 = 4712; b.value4713 = 4713; b.value4714 = 4714; b.value4715 = 4715; b.value4716 = 4716; b.value4717 = 4717; b.value4718 = 4718; b.value4719 = 4719; b.value4720 = 4720; b.value4721 = 4721; b.value4722 = 4722; b.value4723 = 4723; b.value4724 = 4724; b.value4725 = 4725; b.value4726 = 4726; b.value4727 = 4727; b.value4728 = 4728; b.value4729 = 4729; b.value4730 = 4730; b.value4731 = 4731; b.value4732 = 4732; b.value4733 = 4733; b.value4734 = 4734; b.value4735 = 4735; b.value4736 = 4736; b.value4737 = 4737; b.value4738 = 4738; b.value4739 = 4739; b.value4740 = 4740; b.value4741 = 4741; b.value4742 = 4742; b.value4743 = 4743; b.value4744 = 4744; b.value4745 = 4745; b.value4746 = 4746; b.value4747 = 4747; b.value4748 = 4748; b.value4749 = 4749; b.value4750 = 4750; b.value4751 = 4751; b.value4752 = 4752; b.value4753 = 4753; b.value4754 = 4754; b.value4755 = 4755; b.value4756 = 4756; b.value4757 = 4757; b.value4758 = 4758; b.value4759 = 4759; b.value4760 = 4760; b.value4761 = 4761; b.value4762 = 4762; b.value4763 = 4763; b.value4764 = 4764; b.value4765 = 4765; b.value4766 = 4766; b.value4767 = 4767; b.value4768 = 4768; b.value4769 = 4769; b.value4770 = 4770; b.value4771 = 4771; b.value4772 = 4772; b.value4773 = 4773; b.value4774 = 4774; b.value4775 = 4775; b.value4776 = 4776; b.value4777 = 4777; b.value4778 = 4778; b.value4779 = 4779; b.value4780 = 4780; b.value4781 = 4781; b.value4782 = 4782; b.value4783 = 4783; b.value4784 = 4784; b.value4785 = 4785; b.value4786 = 4786; b.value4787 = 4787; b.value4788 = 4788; b.value4789 = 4789; b.value4790 = 4790; b.value4791 = 4791; b.value4792 = 4792; b.value4793 = 4793; b.value4794 = 4794; b.value4795 = 4795; b.value4796 = 4796; b.value4797 = 4797; b.value4798 = 4798; b.value4799 = 4799; b.value4800 = 4800; b.value4801 = 4801; b.value4802 = 4802; b.value4803 = 4803; b.value4804 = 4804; b.value4805 = 4805; b.value4806 = 4806; b.value4807 = 4807; b.value4808 = 4808; b.value4809 = 4809; b.value4810 = 4810; b.value4811 = 4811; b.value4812 = 4812; b.value4813 = 4813; b.value4814 = 4814; b.value4815 = 4815; b.value4816 = 4816; b.value4817 = 4817; b.value4818 = 4818; b.value4819 = 4819; b.value4820 = 4820; b.value4821 = 4821; b.value4822 = 4822; b.value4823 = 4823; b.value4824 = 4824; b.value4825 = 4825; b.value4826 = 4826; b.value4827 = 4827; b.value4828 = 4828; b.value4829 = 4829; b.value4830 = 4830; b.value4831 = 4831; b.value4832 = 4832; b.value4833 = 4833; b.value4834 = 4834; b.value4835 = 4835; b.value4836 = 4836; b.value4837 = 4837; b.value4838 = 4838; b.value4839 = 4839; b.value4840 = 4840; b.value4841 = 4841; b.value4842 = 4842; b.value4843 = 4843; b.value4844 = 4844; b.value4845 = 4845; b.value4846 = 4846; b.value4847 = 4847; b.value4848 = 4848; b.value4849 = 4849; b.value4850 = 4850; b.value4851 = 4851; b.value4852 = 4852; b.value4853 = 4853; b.value4854 = 4854; b.value4855 = 4855; b.value4856 = 4856; b.value4857 = 4857; b.value4858 = 4858; b.value4859 = 4859; b.value4860 = 4860; b.value4861 = 4861; b.value4862 = 4862; b.value4863 = 4863; b.value4864 = 4864; b.value4865 = 4865; b.value4866 = 4866; b.value4867 = 4867; b.value4868 = 4868; b.value4869 = 4869; b.value4870 = 4870; b.value4871 = 4871; b.value4872 = 4872; b.value4873 = 4873; b.value4874 = 4874; b.value4875 = 4875; b.value4876 = 4876; b.value4877 = 4877; b.value4878 = 4878; b.value4879 = 4879; b.value4880 = 4880; b.value4881 = 4881; b.value4882 = 4882; b.value4883 = 4883; b.value4884 = 4884; b.value4885 = 4885; b.value4886 = 4886; b.value4887 = 4887; b.value4888 = 4888; b.value4889 = 4889; b.value4890 = 4890; b.value4891 = 4891; b.value4892 = 4892; b.value4893 = 4893; b.value4894 = 4894; b.value4895 = 4895; b.value4896 = 4896; b.value4897 = 4897; b.value4898 = 4898; b.value4899 = 4899; b.value4900 = 4900; b.value4901 = 4901; b.value4902 = 4902; b.value4903 = 4903; b.value4904 = 4904; b.value4905 = 4905; b.value4906 = 4906; b.value4907 = 4907; b.value4908 = 4908; b.value4909 = 4909; b.value4910 = 4910; b.value4911 = 4911; b.value4912 = 4912; b.value4913 = 4913; b.value4914 = 4914; b.value4915 = 4915; b.value4916 = 4916; b.value4917 = 4917; b.value4918 = 4918; b.value4919 = 4919; b.value4920 = 4920; b.value4921 = 4921; b.value4922 = 4922; b.value4923 = 4923; b.value4924 = 4924; b.value4925 = 4925; b.value4926 = 4926; b.value4927 = 4927; b.value4928 = 4928; b.value4929 = 4929; b.value4930 = 4930; b.value4931 = 4931; b.value4932 = 4932; b.value4933 = 4933; b.value4934 = 4934; b.value4935 = 4935; b.value4936 = 4936; b.value4937 = 4937; b.value4938 = 4938; b.value4939 = 4939; b.value4940 = 4940; b.value4941 = 4941; b.value4942 = 4942; b.value4943 = 4943; b.value4944 = 4944; b.value4945 = 4945; b.value4946 = 4946; b.value4947 = 4947; b.value4948 = 4948; b.value4949 = 4949; b.value4950 = 4950; b.value4951 = 4951; b.value4952 = 4952; b.value4953 = 4953; b.value4954 = 4954; b.value4955 = 4955; b.value4956 = 4956; b.value4957 = 4957; b.value4958 = 4958; b.value4959 = 4959; b.value4960 = 4960; b.value4961 = 4961; b.value4962 = 4962; b.value4963 = 4963; b.value4964 = 4964; b.value4965 = 4965; b.value4966 = 4966; b.value4967 = 4967; b.value4968 = 4968; b.value4969 = 4969; b.value4970 = 4970; b.value4971 = 4971; b.value4972 = 4972; b.value4973 = 4973; b.value4974 = 4974; b.value4975 = 4975; b.value4976 = 4976; b.value4977 = 4977; b.value4978 = 4978; b.value4979 = 4979; b.value4980 = 4980; b.value4981 = 4981; b.value4982 = 4982; b.value4983 = 4983; b.value4984 = 4984; b.value4985 = 4985; b.value4986 = 4986; b.value4987 = 4987; b.value4988 = 4988; b.value4989 = 4989; b.value4990 = 4990; b.value4991 = 4991; b.value4992 = 4992; b.value4993 = 4993; b.value4994 = 4994; b.value4995 = 4995; b.value4996 = 4996; b.value4997 = 4997; b.value4998 = 4998; b.value4999 = 4999; b.value5000 = 5000; b.value5001 = 5001; b.value5002 = 5002; b.value5003 = 5003; b.value5004 = 5004; b.value5005 = 5005; b.value5006 = 5006; b.value5007 = 5007; b.value5008 = 5008; b.value5009 = 5009; b.value5010 = 5010; b.value5011 = 5011; b.value5012 = 5012; b.value5013 = 5013; b.value5014 = 5014; b.value5015 = 5015; b.value5016 = 5016; b.value5017 = 5017; b.value5018 = 5018; b.value5019 = 5019; b.value5020 = 5020; b.value5021 = 5021; b.value5022 = 5022; b.value5023 = 5023; b.value5024 = 5024; b.value5025 = 5025; b.value5026 = 5026; b.value5027 = 5027; b.value5028 = 5028; b.value5029 = 5029; b.value5030 = 5030; b.value5031 = 5031; b.value5032 = 5032; b.value5033 = 5033; b.value5034 = 5034; b.value5035 = 5035; b.value5036 = 5036; b.value5037 = 5037; b.value5038 = 5038; b.value5039 = 5039; b.value5040 = 5040; b.value5041 = 5041; b.value5042 = 5042; b.value5043 = 5043; b.value5044 = 5044; b.value5045 = 5045; b.value5046 = 5046; b.value5047 = 5047; b.value5048 = 5048; b.value5049 = 5049; b.value5050 = 5050; b.value5051 = 5051; b.value5052 = 5052; b.value5053 = 5053; b.value5054 = 5054; b.value5055 = 5055; b.value5056 = 5056; b.value5057 = 5057; b.value5058 = 5058; b.value5059 = 5059; b.value5060 = 5060; b.value5061 = 5061; b.value5062 = 5062; b.value5063 = 5063; b.value5064 = 5064; b.value5065 = 5065; b.value5066 = 5066; b.value5067 = 5067; b.value5068 = 5068; b.value5069 = 5069; b.value5070 = 5070; b.value5071 = 5071; b.value5072 = 5072; b.value5073 = 5073; b.value5074 = 5074; b.value5075 = 5075; b.value5076 = 5076; b.value5077 = 5077; b.value5078 = 5078; b.value5079 = 5079; b.value5080 = 5080; b.value5081 = 5081; b.value5082 = 5082; b.value5083 = 5083; b.value5084 = 5084; b.value5085 = 5085; b.value5086 = 5086; b.value5087 = 5087; b.value5088 = 5088; b.value5089 = 5089; b.value5090 = 5090; b.value5091 = 5091; b.value5092 = 5092; b.value5093 = 5093; b.value5094 = 5094; b.value5095 = 5095; b.value5096 = 5096; b.value5097 = 5097; b.value5098 = 5098; b.value5099 = 5099; b.value5100 = 5100; b.value5101 = 5101; b.value5102 = 5102; b.value5103 = 5103; b.value5104 = 5104; b.value5105 = 5105; b.value5106 = 5106; b.value5107 = 5107; b.value5108 = 5108; b.value5109 = 5109; b.value5110 = 5110; b.value5111 = 5111; b.value5112 = 5112; b.value5113 = 5113; b.value5114 = 5114; b.value5115 = 5115; b.value5116 = 5116; b.value5117 = 5117; b.value5118 = 5118; b.value5119 = 5119; b.value5120 = 5120; b.value5121 = 5121; b.value5122 = 5122; b.value5123 = 5123; b.value5124 = 5124; b.value5125 = 5125; b.value5126 = 5126; b.value5127 = 5127; b.value5128 = 5128; b.value5129 = 5129; b.value5130 = 5130; b.value5131 = 5131; b.value5132 = 5132; b.value5133 = 5133; b.value5134 = 5134; b.value5135 = 5135; b.value5136 = 5136; b.value5137 = 5137; b.value5138 = 5138; b.value5139 = 5139; b.value5140 = 5140; b.value5141 = 5141; b.value5142 = 5142; b.value5143 = 5143; b.value5144 = 5144; b.value5145 = 5145; b.value5146 = 5146; b.value5147 = 5147; b.value5148 = 5148; b.value5149 = 5149; b.value5150 = 5150; b.value5151 = 5151; b.value5152 = 5152; b.value5153 = 5153; b.value5154 = 5154; b.value5155 = 5155; b.value5156 = 5156; b.value5157 = 5157; b.value5158 = 5158; b.value5159 = 5159; b.value5160 = 5160; b.value5161 = 5161; b.value5162 = 5162; b.value5163 = 5163; b.value5164 = 5164; b.value5165 = 5165; b.value5166 = 5166; b.value5167 = 5167; b.value5168 = 5168; b.value5169 = 5169; b.value5170 = 5170; b.value5171 = 5171; b.value5172 = 5172; b.value5173 = 5173; b.value5174 = 5174; b.value5175 = 5175; b.value5176 = 5176; b.value5177 = 5177; b.value5178 = 5178; b.value5179 = 5179; b.value5180 = 5180; b.value5181 = 5181; b.value5182 = 5182; b.value5183 = 5183; b.value5184 = 5184; b.value5185 = 5185; b.value5186 = 5186; b.value5187 = 5187; b.value5188 = 5188; b.value5189 = 5189; b.value5190 = 5190; b.value5191 = 5191; b.value5192 = 5192; b.value5193 = 5193; b.value5194 = 5194; b.value5195 = 5195; b.value5196 = 5196; b.value5197 = 5197; b.value5198 = 5198; b.value5199 = 5199; b.value5200 = 5200; b.value5201 = 5201; b.value5202 = 5202; b.value5203 = 5203; b.value5204 = 5204; b.value5205 = 5205; b.value5206 = 5206; b.value5207 = 5207; b.value5208 = 5208; b.value5209 = 5209; b.value5210 = 5210; b.value5211 = 5211; b.value5212 = 5212; b.value5213 = 5213; b.value5214 = 5214; b.value5215 = 5215; b.value5216 = 5216; b.value5217 = 5217; b.value5218 = 5218; b.value5219 = 5219; b.value5220 = 5220; b.value5221 = 5221; b.value5222 = 5222; b.value5223 = 5223; b.value5224 = 5224; b.value5225 = 5225; b.value5226 = 5226; b.value5227 = 5227; b.value5228 = 5228; b.value5229 = 5229; b.value5230 = 5230; b.value5231 = 5231; b.value5232 = 5232; b.value5233 = 5233; b.value5234 = 5234; b.value5235 = 5235; b.value5236 = 5236; b.value5237 = 5237; b.value5238 = 5238; b.value5239 = 5239; b.value5240 = 5240; b.value5241 = 5241; b.value5242 = 5242; b.value5243 = 5243; b.value5244 = 5244; b.value5245 = 5245; b.value5246 = 5246; b.value5247 = 5247; b.value5248 = 5248; b.value5249 = 5249; b.value5250 = 5250; b.value5251 = 5251; b.value5252 = 5252; b.value5253 = 5253; b.value5254 = 5254; b.value5255 = 5255; b.value5256 = 5256; b.value5257 = 5257; b.value5258 = 5258; b.value5259 = 5259; b.value5260 = 5260; b.value5261 = 5261; b.value5262 = 5262; b.value5263 = 5263; b.value5264 = 5264; b.value5265 = 5265; b.value5266 = 5266; b.value5267 = 5267; b.value5268 = 5268; b.value5269 = 5269; b.value5270 = 5270; b.value5271 = 5271; b.value5272 = 5272; b.value5273 = 5273; b.value5274 = 5274; b.value5275 = 5275; b.value5276 = 5276; b.value5277 = 5277; b.value5278 = 5278; b.value5279 = 5279; b.value5280 = 5280; b.value5281 = 5281; b.value5282 = 5282; b.value5283 = 5283; b.value5284 = 5284; b.value5285 = 5285; b.value5286 = 5286; b.value5287 = 5287; b.value5288 = 5288; b.value5289 = 5289; b.value5290 = 5290; b.value5291 = 5291; b.value5292 = 5292; b.value5293 = 5293; b.value5294 = 5294; b.value5295 = 5295; b.value5296 = 5296; b.value5297 = 5297; b.value5298 = 5298; b.value5299 = 5299; b.value5300 = 5300; b.value5301 = 5301; b.value5302 = 5302; b.value5303 = 5303; b.value5304 = 5304; b.value5305 = 5305; b.value5306 = 5306; b.value5307 = 5307; b.value5308 = 5308; b.value5309 = 5309; b.value5310 = 5310; b.value5311 = 5311; b.value5312 = 5312; b.value5313 = 5313; b.value5314 = 5314; b.value5315 = 5315; b.value5316 = 5316; b.value5317 = 5317; b.value5318 = 5318; b.value5319 = 5319; b.value5320 = 5320; b.value5321 = 5321; b.value5322 = 5322; b.value5323 = 5323; b.value5324 = 5324; b.value5325 = 5325; b.value5326 = 5326; b.value5327 = 5327; b.value5328 = 5328; b.value5329 = 5329; b.value5330 = 5330; b.value5331 = 5331; b.value5332 = 5332; b.value5333 = 5333; b.value5334 = 5334; b.value5335 = 5335; b.value5336 = 5336; b.value5337 = 5337; b.value5338 = 5338; b.value5339 = 5339; b.value5340 = 5340; b.value5341 = 5341; b.value5342 = 5342; b.value5343 = 5343; b.value5344 = 5344; b.value5345 = 5345; b.value5346 = 5346; b.value5347 = 5347; b.value5348 = 5348; b.value5349 = 5349; b.value5350 = 5350; b.value5351 = 5351; b.value5352 = 5352; b.value5353 = 5353; b.value5354 = 5354; b.value5355 = 5355; b.value5356 = 5356; b.value5357 = 5357; b.value5358 = 5358; b.value5359 = 5359; b.value5360 = 5360; b.value5361 = 5361; b.value5362 = 5362; b.value5363 = 5363; b.value5364 = 5364; b.value5365 = 5365; b.value5366 = 5366; b.value5367 = 5367; b.value5368 = 5368; b.value5369 = 5369; b.value5370 = 5370; b.value5371 = 5371; b.value5372 = 5372; b.value5373 = 5373; b.value5374 = 5374; b.value5375 = 5375; b.value5376 = 5376; b.value5377 = 5377; b.value5378 = 5378; b.value5379 = 5379; b.value5380 = 5380; b.value5381 = 5381; b.value5382 = 5382; b.value5383 = 5383; b.value5384 = 5384; b.value5385 = 5385; b.value5386 = 5386; b.value5387 = 5387; b.value5388 = 5388; b.value5389 = 5389; b.value5390 = 5390; b.value5391 = 5391; b.value5392 = 5392; b.value5393 = 5393; b.value5394 = 5394; b.value5395 = 5395; b.value5396 = 5396; b.value5397 = 5397; b.value5398 = 5398; b.value5399 = 5399; b.value5400 = 5400; b.value5401 = 5401; b.value5402 = 5402; b.value5403 = 5403; b.value5404 = 5404; b.value5405 = 5405; b.value5406 = 5406; b.value5407 = 5407; b.value5408 = 5408; b.value5409 = 5409; b.value5410 = 5410; b.value5411 = 5411; b.value5412 = 5412; b.value5413 = 5413; b.value5414 = 5414; b.value5415 = 5415; b.value5416 = 5416; b.value5417 = 5417; b.value5418 = 5418; b.value5419 = 5419; b.value5420 = 5420; b.value5421 = 5421; b.value5422 = 5422; b.value5423 = 5423; b.value5424 = 5424; b.value5425 = 5425; b.value5426 = 5426; b.value5427 = 5427; b.value5428 = 5428; b.value5429 = 5429; b.value5430 = 5430; b.value5431 = 5431; b.value5432 = 5432; b.value5433 = 5433; b.value5434 = 5434; b.value5435 = 5435; b.value5436 = 5436; b.value5437 = 5437; b.value5438 = 5438; b.value5439 = 5439; b.value5440 = 5440; b.value5441 = 5441; b.value5442 = 5442; b.value5443 = 5443; b.value5444 = 5444; b.value5445 = 5445; b.value5446 = 5446; b.value5447 = 5447; b.value5448 = 5448; b.value5449 = 5449; b.value5450 = 5450; b.value5451 = 5451; b.value5452 = 5452; b.value5453 = 5453; b.value5454 = 5454; b.value5455 = 5455; b.value5456 = 5456; b.value5457 = 5457; b.value5458 = 5458; b.value5459 = 5459; b.value5460 = 5460; b.value5461 = 5461; b.value5462 = 5462; b.value5463 = 5463; b.value5464 = 5464; b.value5465 = 5465; b.value5466 = 5466; b.value5467 = 5467; b.value5468 = 5468; b.value5469 = 5469; b.value5470 = 5470; b.value5471 = 5471; b.value5472 = 5472; b.value5473 = 5473; b.value5474 = 5474; b.value5475 = 5475; b.value5476 = 5476; b.value5477 = 5477; b.value5478 = 5478; b.value5479 = 5479; b.value5480 = 5480; b.value5481 = 5481; b.value5482 = 5482; b.value5483 = 5483; b.value5484 = 5484; b.value5485 = 5485; b.value5486 = 5486; b.value5487 = 5487; b.value5488 = 5488; b.value5489 = 5489; b.value5490 = 5490; b.value5491 = 5491; b.value5492 = 5492; b.value5493 = 5493; b.value5494 = 5494; b.value5495 = 5495; b.value5496 = 5496; b.value5497 = 5497; b.value5498 = 5498; b.value5499 = 5499; b.value5500 = 5500; b.value5501 = 5501; b.value5502 = 5502; b.value5503 = 5503; b.value5504 = 5504; b.value5505 = 5505; b.value5506 = 5506; b.value5507 = 5507; b.value5508 = 5508; b.value5509 = 5509; b.value5510 = 5510; b.value5511 = 5511; b.value5512 = 5512; b.value5513 = 5513; b.value5514 = 5514; b.value5515 = 5515; b.value5516 = 5516; b.value5517 = 5517; b.value5518 = 5518; b.value5519 = 5519; b.value5520 = 5520; b.value5521 = 5521; b.value5522 = 5522; b.value5523 = 5523; b.value5524 = 5524; b.value5525 = 5525; b.value5526 = 5526; b.value5527 = 5527; b.value5528 = 5528; b.value5529 = 5529; b.value5530 = 5530; b.value5531 = 5531; b.value5532 = 5532; b.value5533 = 5533; b.value5534 = 5534; b.value5535 = 5535; b.value5536 = 5536; b.value5537 = 5537; b.value5538 = 5538; b.value5539 = 5539; b.value5540 = 5540; b.value5541 = 5541; b.value5542 = 5542; b.value5543 = 5543; b.value5544 = 5544; b.value5545 = 5545; b.value5546 = 5546; b.value5547 = 5547; b.value5548 = 5548; b.value5549 = 5549; b.value5550 = 5550; b.value5551 = 5551; b.value5552 = 5552; b.value5553 = 5553; b.value5554 = 5554; b.value5555 = 5555; b.value5556 = 5556; b.value5557 = 5557; b.value5558 = 5558; b.value5559 = 5559; b.value5560 = 5560; b.value5561 = 5561; b.value5562 = 5562; b.value5563 = 5563; b.value5564 = 5564; b.value5565 = 5565; b.value5566 = 5566; b.value5567 = 5567; b.value5568 = 5568; b.value5569 = 5569; b.value5570 = 5570; b.value5571 = 5571; b.value5572 = 5572; b.value5573 = 5573; b.value5574 = 5574; b.value5575 = 5575; b.value5576 = 5576; b.value5577 = 5577; b.value5578 = 5578; b.value5579 = 5579; b.value5580 = 5580; b.value5581 = 5581; b.value5582 = 5582; b.value5583 = 5583; b.value5584 = 5584; b.value5585 = 5585; b.value5586 = 5586; b.value5587 = 5587; b.value5588 = 5588; b.value5589 = 5589; b.value5590 = 5590; b.value5591 = 5591; b.value5592 = 5592; b.value5593 = 5593; b.value5594 = 5594; b.value5595 = 5595; b.value5596 = 5596; b.value5597 = 5597; b.value5598 = 5598; b.value5599 = 5599; b.value5600 = 5600; b.value5601 = 5601; b.value5602 = 5602; b.value5603 = 5603; b.value5604 = 5604; b.value5605 = 5605; b.value5606 = 5606; b.value5607 = 5607; b.value5608 = 5608; b.value5609 = 5609; b.value5610 = 5610; b.value5611 = 5611; b.value5612 = 5612; b.value5613 = 5613; b.value5614 = 5614; b.value5615 = 5615; b.value5616 = 5616; b.value5617 = 5617; b.value5618 = 5618; b.value5619 = 5619; b.value5620 = 5620; b.value5621 = 5621; b.value5622 = 5622; b.value5623 = 5623; b.value5624 = 5624; b.value5625 = 5625; b.value5626 = 5626; b.value5627 = 5627; b.value5628 = 5628; b.value5629 = 5629; b.value5630 = 5630; b.value5631 = 5631; b.value5632 = 5632; b.value5633 = 5633; b.value5634 = 5634; b.value5635 = 5635; b.value5636 = 5636; b.value5637 = 5637; b.value5638 = 5638; b.value5639 = 5639; b.value5640 = 5640; b.value5641 = 5641; b.value5642 = 5642; b.value5643 = 5643; b.value5644 = 5644; b.value5645 = 5645; b.value5646 = 5646; b.value5647 = 5647; b.value5648 = 5648; b.value5649 = 5649; b.value5650 = 5650; b.value5651 = 5651; b.value5652 = 5652; b.value5653 = 5653; b.value5654 = 5654; b.value5655 = 5655; b.value5656 = 5656; b.value5657 = 5657; b.value5658 = 5658; b.value5659 = 5659; b.value5660 = 5660; b.value5661 = 5661; b.value5662 = 5662; b.value5663 = 5663; b.value5664 = 5664; b.value5665 = 5665; b.value5666 = 5666; b.value5667 = 5667; b.value5668 = 5668; b.value5669 = 5669; b.value5670 = 5670; b.value5671 = 5671; b.value5672 = 5672; b.value5673 = 5673; b.value5674 = 5674; b.value5675 = 5675; b.value5676 = 5676; b.value5677 = 5677; b.value5678 = 5678; b.value5679 = 5679; b.value5680 = 5680; b.value5681 = 5681; b.value5682 = 5682; b.value5683 = 5683; b.value5684 = 5684; b.value5685 = 5685; b.value5686 = 5686; b.value5687 = 5687; b.value5688 = 5688; b.value5689 = 5689; b.value5690 = 5690; b.value5691 = 5691; b.value5692 = 5692; b.value5693 = 5693; b.value5694 = 5694; b.value5695 = 5695; b.value5696 = 5696; b.value5697 = 5697; b.value5698 = 5698; b.value5699 = 5699; b.value5700 = 5700; b.value5701 = 5701; b.value5702 = 5702; b.value5703 = 5703; b.value5704 = 5704; b.value5705 = 5705; b.value5706 = 5706; b.value5707 = 5707; b.value5708 = 5708; b.value5709 = 5709; b.value5710 = 5710; b.value5711 = 5711; b.value5712 = 5712; b.value5713 = 5713; b.value5714 = 5714; b.value5715 = 5715; b.value5716 = 5716; b.value5717 = 5717; b.value5718 = 5718; b.value5719 = 5719; b.value5720 = 5720; b.value5721 = 5721; b.value5722 = 5722; b.value5723 = 5723; b.value5724 = 5724; b.value5725 = 5725; b.value5726 = 5726; b.value5727 = 5727; b.value5728 = 5728; b.value5729 = 5729; b.value5730 = 5730; b.value5731 = 5731; b.value5732 = 5732; b.value5733 = 5733; b.value5734 = 5734; b.value5735 = 5735; b.value5736 = 5736; b.value5737 = 5737; b.value5738 = 5738; b.value5739 = 5739; b.value5740 = 5740; b.value5741 = 5741; b.value5742 = 5742; b.value5743 = 5743; b.value5744 = 5744; b.value5745 = 5745; b.value5746 = 5746; b.value5747 = 5747; b.value5748 = 5748; b.value5749 = 5749; b.value5750 = 5750; b.value5751 = 5751; b.value5752 = 5752; b.value5753 = 5753; b.value5754 = 5754; b.value5755 = 5755; b.value5756 = 5756; b.value5757 = 5757; b.value5758 = 5758; b.value5759 = 5759; b.value5760 = 5760; b.value5761 = 5761; b.value5762 = 5762; b.value5763 = 5763; b.value5764 = 5764; b.value5765 = 5765; b.value5766 = 5766; b.value5767 = 5767; b.value5768 = 5768; b.value5769 = 5769; b.value5770 = 5770; b.value5771 = 5771; b.value5772 = 5772; b.value5773 = 5773; b.value5774 = 5774; b.value5775 = 5775; b.value5776 = 5776; b.value5777 = 5777; b.value5778 = 5778; b.value5779 = 5779; b.value5780 = 5780; b.value5781 = 5781; b.value5782 = 5782; b.value5783 = 5783; b.value5784 = 5784; b.value5785 = 5785; b.value5786 = 5786; b.value5787 = 5787; b.value5788 = 5788; b.value5789 = 5789; b.value5790 = 5790; b.value5791 = 5791; b.value5792 = 5792; b.value5793 = 5793; b.value5794 = 5794; b.value5795 = 5795; b.value5796 = 5796; b.value5797 = 5797; b.value5798 = 5798; b.value5799 = 5799; b.value5800 = 5800; b.value5801 = 5801; b.value5802 = 5802; b.value5803 = 5803; b.value5804 = 5804; b.value5805 = 5805; b.value5806 = 5806; b.value5807 = 5807; b.value5808 = 5808; b.value5809 = 5809; b.value5810 = 5810; b.value5811 = 5811; b.value5812 = 5812; b.value5813 = 5813; b.value5814 = 5814; b.value5815 = 5815; b.value5816 = 5816; b.value5817 = 5817; b.value5818 = 5818; b.value5819 = 5819; b.value5820 = 5820; b.value5821 = 5821; b.value5822 = 5822; b.value5823 = 5823; b.value5824 = 5824; b.value5825 = 5825; b.value5826 = 5826; b.value5827 = 5827; b.value5828 = 5828; b.value5829 = 5829; b.value5830 = 5830; b.value5831 = 5831; b.value5832 = 5832; b.value5833 = 5833; b.value5834 = 5834; b.value5835 = 5835; b.value5836 = 5836; b.value5837 = 5837; b.value5838 = 5838; b.value5839 = 5839; b.value5840 = 5840; b.value5841 = 5841; b.value5842 = 5842; b.value5843 = 5843; b.value5844 = 5844; b.value5845 = 5845; b.value5846 = 5846; b.value5847 = 5847; b.value5848 = 5848; b.value5849 = 5849; b.value5850 = 5850; b.value5851 = 5851; b.value5852 = 5852; b.value5853 = 5853; b.value5854 = 5854; b.value5855 = 5855; b.value5856 = 5856; b.value5857 = 5857; b.value5858 = 5858; b.value5859 = 5859; b.value5860 = 5860; b.value5861 = 5861; b.value5862 = 5862; b.value5863 = 5863; b.value5864 = 5864; b.value5865 = 5865; b.value5866 = 5866; b.value5867 = 5867; b.value5868 = 5868; b.value5869 = 5869; b.value5870 = 5870; b.value5871 = 5871; b.value5872 = 5872; b.value5873 = 5873; b.value5874 = 5874; b.value5875 = 5875; b.value5876 = 5876; b.value5877 = 5877; b.value5878 = 5878; b.value5879 = 5879; b.value5880 = 5880; b.value5881 = 5881; b.value5882 = 5882; b.value5883 = 5883; b.value5884 = 5884; b.value5885 = 5885; b.value5886 = 5886; b.value5887 = 5887; b.value5888 = 5888; b.value5889 = 5889; b.value5890 = 5890; b.value5891 = 5891; b.value5892 = 5892; b.value5893 = 5893; b.value5894 = 5894; b.value5895 = 5895; b.value5896 = 5896; b.value5897 = 5897; b.value5898 = 5898; b.value5899 = 5899; b.value5900 = 5900; b.value5901 = 5901; b.value5902 = 5902; b.value5903 = 5903; b.value5904 = 5904; b.value5905 = 5905; b.value5906 = 5906; b.value5907 = 5907; b.value5908 = 5908; b.value5909 = 5909; b.value5910 = 5910; b.value5911 = 5911; b.value5912 = 5912; b.value5913 = 5913; b.value5914 = 5914; b.value5915 = 5915; b.value5916 = 5916; b.value5917 = 5917; b.value5918 = 5918; b.value5919 = 5919; b.value5920 = 5920; b.value5921 = 5921; b.value5922 = 5922; b.value5923 = 5923; b.value5924 = 5924; b.value5925 = 5925; b.value5926 = 5926; b.value5927 = 5927; b.value5928 = 5928; b.value5929 = 5929; b.value5930 = 5930; b.value5931 = 5931; b.value5932 = 5932; b.value5933 = 5933; b.value5934 = 5934; b.value5935 = 5935; b.value5936 = 5936; b.value5937 = 5937; b.value5938 = 5938; b.value5939 = 5939; b.value5940 = 5940; b.value5941 = 5941; b.value5942 = 5942; b.value5943 = 5943; b.value5944 = 5944; b.value5945 = 5945; b.value5946 = 5946; b.value5947 = 5947; b.value5948 = 5948; b.value5949 = 5949; b.value5950 = 5950; b.value5951 = 5951; b.value5952 = 5952; b.value5953 = 5953; b.value5954 = 5954; b.value5955 = 5955; b.value5956 = 5956; b.value5957 = 5957; b.value5958 = 5958; b.value5959 = 5959; b.value5960 = 5960; b.value5961 = 5961; b.value5962 = 5962; b.value5963 = 5963; b.value5964 = 5964; b.value5965 = 5965; b.value5966 = 5966; b.value5967 = 5967; b.value5968 = 5968; b.value5969 = 5969; b.value5970 = 5970; b.value5971 = 5971; b.value5972 = 5972; b.value5973 = 5973; b.value5974 = 5974; b.value5975 = 5975; b.value5976 = 5976; b.value5977 = 5977; b.value5978 = 5978; b.value5979 = 5979; b.value5980 = 5980; b.value5981 = 5981; b.value5982 = 5982; b.value5983 = 5983; b.value5984 = 5984; b.value5985 = 5985; b.value5986 = 5986; b.value5987 = 5987; b.value5988 = 5988; b.value5989 = 5989; b.value5990 = 5990; b.value5991 = 5991; b.value5992 = 5992; b.value5993 = 5993; b.value5994 = 5994; b.value5995 = 5995; b.value5996 = 5996; b.value5997 = 5997; b.value5998 = 5998; b.value5999 = 5999; b.value6000 = 6000; b.value6001 = 6001; b.value6002 = 6002; b.value6003 = 6003; b.value6004 = 6004; b.value6005 = 6005; b.value6006 = 6006; b.value6007 = 6007; b.value6008 = 6008; b.value6009 = 6009; b.value6010 = 6010; b.value6011 = 6011; b.value6012 = 6012; b.value6013 = 6013; b.value6014 = 6014; b.value6015 = 6015; b.value6016 = 6016; b.value6017 = 6017; b.value6018 = 6018; b.value6019 = 6019; b.value6020 = 6020; b.value6021 = 6021; b.value6022 = 6022; b.value6023 = 6023; b.value6024 = 6024; b.value6025 = 6025; b.value6026 = 6026; b.value6027 = 6027; b.value6028 = 6028; b.value6029 = 6029; b.value6030 = 6030; b.value6031 = 6031; b.value6032 = 6032; b.value6033 = 6033; b.value6034 = 6034; b.value6035 = 6035; b.value6036 = 6036; b.value6037 = 6037; b.value6038 = 6038; b.value6039 = 6039; b.value6040 = 6040; b.value6041 = 6041; b.value6042 = 6042; b.value6043 = 6043; b.value6044 = 6044; b.value6045 = 6045; b.value6046 = 6046; b.value6047 = 6047; b.value6048 = 6048; b.value6049 = 6049; b.value6050 = 6050; b.value6051 = 6051; b.value6052 = 6052; b.value6053 = 6053; b.value6054 = 6054; b.value6055 = 6055; b.value6056 = 6056; b.value6057 = 6057; b.value6058 = 6058; b.value6059 = 6059; b.value6060 = 6060; b.value6061 = 6061; b.value6062 = 6062; b.value6063 = 6063; b.value6064 = 6064; b.value6065 = 6065; b.value6066 = 6066; b.value6067 = 6067; b.value6068 = 6068; b.value6069 = 6069; b.value6070 = 6070; b.value6071 = 6071; b.value6072 = 6072; b.value6073 = 6073; b.value6074 = 6074; b.value6075 = 6075; b.value6076 = 6076; b.value6077 = 6077; b.value6078 = 6078; b.value6079 = 6079; b.value6080 = 6080; b.value6081 = 6081; b.value6082 = 6082; b.value6083 = 6083; b.value6084 = 6084; b.value6085 = 6085; b.value6086 = 6086; b.value6087 = 6087; b.value6088 = 6088; b.value6089 = 6089; b.value6090 = 6090; b.value6091 = 6091; b.value6092 = 6092; b.value6093 = 6093; b.value6094 = 6094; b.value6095 = 6095; b.value6096 = 6096; b.value6097 = 6097; b.value6098 = 6098; b.value6099 = 6099; b.value6100 = 6100; b.value6101 = 6101; b.value6102 = 6102; b.value6103 = 6103; b.value6104 = 6104; b.value6105 = 6105; b.value6106 = 6106; b.value6107 = 6107; b.value6108 = 6108; b.value6109 = 6109; b.value6110 = 6110; b.value6111 = 6111; b.value6112 = 6112; b.value6113 = 6113; b.value6114 = 6114; b.value6115 = 6115; b.value6116 = 6116; b.value6117 = 6117; b.value6118 = 6118; b.value6119 = 6119; b.value6120 = 6120; b.value6121 = 6121; b.value6122 = 6122; b.value6123 = 6123; b.value6124 = 6124; b.value6125 = 6125; b.value6126 = 6126; b.value6127 = 6127; b.value6128 = 6128; b.value6129 = 6129; b.value6130 = 6130; b.value6131 = 6131; b.value6132 = 6132; b.value6133 = 6133; b.value6134 = 6134; b.value6135 = 6135; b.value6136 = 6136; b.value6137 = 6137; b.value6138 = 6138; b.value6139 = 6139; b.value6140 = 6140; b.value6141 = 6141; b.value6142 = 6142; b.value6143 = 6143; b.value6144 = 6144; b.value6145 = 6145; b.value6146 = 6146; b.value6147 = 6147; b.value6148 = 6148; b.value6149 = 6149; b.value6150 = 6150; b.value6151 = 6151; b.value6152 = 6152; b.value6153 = 6153; b.value6154 = 6154; b.value6155 = 6155; b.value6156 = 6156; b.value6157 = 6157; b.value6158 = 6158; b.value6159 = 6159; b.value6160 = 6160; b.value6161 = 6161; b.value6162 = 6162; b.value6163 = 6163; b.value6164 = 6164; b.value6165 = 6165; b.value6166 = 6166; b.value6167 = 6167; b.value6168 = 6168; b.value6169 = 6169; b.value6170 = 6170; b.value6171 = 6171; b.value6172 = 6172; b.value6173 = 6173; b.value6174 = 6174; b.value6175 = 6175; b.value6176 = 6176; b.value6177 = 6177; b.value6178 = 6178; b.value6179 = 6179; b.value6180 = 6180; b.value6181 = 6181; b.value6182 = 6182; b.value6183 = 6183; b.value6184 = 6184; b.value6185 = 6185; b.value6186 = 6186; b.value6187 = 6187; b.value6188 = 6188; b.value6189 = 6189; b.value6190 = 6190; b.value6191 = 6191; b.value6192 = 6192; b.value6193 = 6193; b.value6194 = 6194; b.value6195 = 6195; b.value6196 = 6196; b.value6197 = 6197; b.value6198 = 6198; b.value6199 = 6199; b.value6200 = 6200; b.value6201 = 6201; b.value6202 = 6202; b.value6203 = 6203; b.value6204 = 6204; b.value6205 = 6205; b.value6206 = 6206; b.value6207 = 6207; b.value6208 = 6208; b.value6209 = 6209; b.value6210 = 6210; b.value6211 = 6211; b.value6212 = 6212; b.value6213 = 6213; b.value6214 = 6214; b.value6215 = 6215; b.value6216 = 6216; b.value6217 = 6217; b.value6218 = 6218; b.value6219 = 6219; b.value6220 = 6220; b.value6221 = 6221; b.value6222 = 6222; b.value6223 = 6223; b.value6224 = 6224; b.value6225 = 6225; b.value6226 = 6226; b.value6227 = 6227; b.value6228 = 6228; b.value6229 = 6229; b.value6230 = 6230; b.value6231 = 6231; b.value6232 = 6232; b.value6233 = 6233; b.value6234 = 6234; b.value6235 = 6235; b.value6236 = 6236; b.value6237 = 6237; b.value6238 = 6238; b.value6239 = 6239; b.value6240 = 6240; b.value6241 = 6241; b.value6242 = 6242; b.value6243 = 6243; b.value6244 = 6244; b.value6245 = 6245; b.value6246 = 6246; b.value6247 = 6247; b.value6248 = 6248; b.value6249 = 6249; b.value6250 = 6250; b.value6251 = 6251; b.value6252 = 6252; b.value6253 = 6253; b.value6254 = 6254; b.value6255 = 6255; b.value6256 = 6256; b.value6257 = 6257; b.value6258 = 6258; b.value6259 = 6259; b.value6260 = 6260; b.value6261 = 6261; b.value6262 = 6262; b.value6263 = 6263; b.value6264 = 6264; b.value6265 = 6265; b.value6266 = 6266; b.value6267 = 6267; b.value6268 = 6268; b.value6269 = 6269; b.value6270 = 6270; b.value6271 = 6271; b.value6272 = 6272; b.value6273 = 6273; b.value6274 = 6274; b.value6275 = 6275; b.value6276 = 6276; b.value6277 = 6277; b.value6278 = 6278; b.value6279 = 6279; b.value6280 = 6280; b.value6281 = 6281; b.value6282 = 6282; b.value6283 = 6283; b.value6284 = 6284; b.value6285 = 6285; b.value6286 = 6286; b.value6287 = 6287; b.value6288 = 6288; b.value6289 = 6289; b.value6290 = 6290; b.value6291 = 6291; b.value6292 = 6292; b.value6293 = 6293; b.value6294 = 6294; b.value6295 = 6295; b.value6296 = 6296; b.value6297 = 6297; b.value6298 = 6298; b.value6299 = 6299; b.value6300 = 6300; b.value6301 = 6301; b.value6302 = 6302; b.value6303 = 6303; b.value6304 = 6304; b.value6305 = 6305; b.value6306 = 6306; b.value6307 = 6307; b.value6308 = 6308; b.value6309 = 6309; b.value6310 = 6310; b.value6311 = 6311; b.value6312 = 6312; b.value6313 = 6313; b.value6314 = 6314; b.value6315 = 6315; b.value6316 = 6316; b.value6317 = 6317; b.value6318 = 6318; b.value6319 = 6319; b.value6320 = 6320; b.value6321 = 6321; b.value6322 = 6322; b.value6323 = 6323; b.value6324 = 6324; b.value6325 = 6325; b.value6326 = 6326; b.value6327 = 6327; b.value6328 = 6328; b.value6329 = 6329; b.value6330 = 6330; b.value6331 = 6331; b.value6332 = 6332; b.value6333 = 6333; b.value6334 = 6334; b.value6335 = 6335; b.value6336 = 6336; b.value6337 = 6337; b.value6338 = 6338; b.value6339 = 6339; b.value6340 = 6340; b.value6341 = 6341; b.value6342 = 6342; b.value6343 = 6343; b.value6344 = 6344; b.value6345 = 6345; b.value6346 = 6346; b.value6347 = 6347; b.value6348 = 6348; b.value6349 = 6349; b.value6350 = 6350; b.value6351 = 6351; b.value6352 = 6352; b.value6353 = 6353; b.value6354 = 6354; b.value6355 = 6355; b.value6356 = 6356; b.value6357 = 6357; b.value6358 = 6358; b.value6359 = 6359; b.value6360 = 6360; b.value6361 = 6361; b.value6362 = 6362; b.value6363 = 6363; b.value6364 = 6364; b.value6365 = 6365; b.value6366 = 6366; b.value6367 = 6367; b.value6368 = 6368; b.value6369 = 6369; b.value6370 = 6370; b.value6371 = 6371; b.value6372 = 6372; b.value6373 = 6373; b.value6374 = 6374; b.value6375 = 6375; b.value6376 = 6376; b.value6377 = 6377; b.value6378 = 6378; b.value6379 = 6379; b.value6380 = 6380; b.value6381 = 6381; b.value6382 = 6382; b.value6383 = 6383; b.value6384 = 6384; b.value6385 = 6385; b.value6386 = 6386; b.value6387 = 6387; b.value6388 = 6388; b.value6389 = 6389; b.value6390 = 6390; b.value6391 = 6391; b.value6392 = 6392; b.value6393 = 6393; b.value6394 = 6394; b.value6395 = 6395; b.value6396 = 6396; b.value6397 = 6397; b.value6398 = 6398; b.value6399 = 6399; b.value6400 = 6400; b.value6401 = 6401; b.value6402 = 6402; b.value6403 = 6403; b.value6404 = 6404; b.value6405 = 6405; b.value6406 = 6406; b.value6407 = 6407; b.value6408 = 6408; b.value6409 = 6409; b.value6410 = 6410; b.value6411 = 6411; b.value6412 = 6412; b.value6413 = 6413; b.value6414 = 6414; b.value6415 = 6415; b.value6416 = 6416; b.value6417 = 6417; b.value6418 = 6418; b.value6419 = 6419; b.value6420 = 6420; b.value6421 = 6421; b.value6422 = 6422; b.value6423 = 6423; b.value6424 = 6424; b.value6425 = 6425; b.value6426 = 6426; b.value6427 = 6427; b.value6428 = 6428; b.value6429 = 6429; b.value6430 = 6430; b.value6431 = 6431; b.value6432 = 6432; b.value6433 = 6433; b.value6434 = 6434; b.value6435 = 6435; b.value6436 = 6436; b.value6437 = 6437; b.value6438 = 6438; b.value6439 = 6439; b.value6440 = 6440; b.value6441 = 6441; b.value6442 = 6442; b.value6443 = 6443; b.value6444 = 6444; b.value6445 = 6445; b.value6446 = 6446; b.value6447 = 6447; b.value6448 = 6448; b.value6449 = 6449; b.value6450 = 6450; b.value6451 = 6451; b.value6452 = 6452; b.value6453 = 6453; b.value6454 = 6454; b.value6455 = 6455; b.value6456 = 6456; b.value6457 = 6457; b.value6458 = 6458; b.value6459 = 6459; b.value6460 = 6460; b.value6461 = 6461; b.value6462 = 6462; b.value6463 = 6463; b.value6464 = 6464; b.value6465 = 6465; b.value6466 = 6466; b.value6467 = 6467; b.value6468 = 6468; b.value6469 = 6469; b.value6470 = 6470; b.value6471 = 6471; b.value6472 = 6472; b.value6473 = 6473; b.value6474 = 6474; b.value6475 = 6475; b.value6476 = 6476; b.value6477 = 6477; b.value6478 = 6478; b.value6479 = 6479; b.value6480 = 6480; b.value6481 = 6481; b.value6482 = 6482; b.value6483 = 6483; b.value6484 = 6484; b.value6485 = 6485; b.value6486 = 6486; b.value6487 = 6487; b.value6488 = 6488; b.value6489 = 6489; b.value6490 = 6490; b.value6491 = 6491; b.value6492 = 6492; b.value6493 = 6493; b.value6494 = 6494; b.value6495 = 6495; b.value6496 = 6496; b.value6497 = 6497; b.value6498 = 6498; b.value6499 = 6499; b.value6500 = 6500; b.value6501 = 6501; b.value6502 = 6502; b.value6503 = 6503; b.value6504 = 6504; b.value6505 = 6505; b.value6506 = 6506; b.value6507 = 6507; b.value6508 = 6508; b.value6509 = 6509; b.value6510 = 6510; b.value6511 = 6511; b.value6512 = 6512; b.value6513 = 6513; b.value6514 = 6514; b.value6515 = 6515; b.value6516 = 6516; b.value6517 = 6517; b.value6518 = 6518; b.value6519 = 6519; b.value6520 = 6520; b.value6521 = 6521; b.value6522 = 6522; b.value6523 = 6523; b.value6524 = 6524; b.value6525 = 6525; b.value6526 = 6526; b.value6527 = 6527; b.value6528 = 6528; b.value6529 = 6529; b.value6530 = 6530; b.value6531 = 6531; b.value6532 = 6532; b.value6533 = 6533; b.value6534 = 6534; b.value6535 = 6535; b.value6536 = 6536; b.value6537 = 6537; b.value6538 = 6538; b.value6539 = 6539; b.value6540 = 6540; b.value6541 = 6541; b.value6542 = 6542; b.value6543 = 6543; b.value6544 = 6544; b.value6545 = 6545; b.value6546 = 6546; b.value6547 = 6547; b.value6548 = 6548; b.value6549 = 6549; b.value6550 = 6550; b.value6551 = 6551; b.value6552 = 6552; b.value6553 = 6553; b.value6554 = 6554; b.value6555 = 6555; b.value6556 = 6556; b.value6557 = 6557; b.value6558 = 6558; b.value6559 = 6559; b.value6560 = 6560; b.value6561 = 6561; b.value6562 = 6562; b.value6563 = 6563; b.value6564 = 6564; b.value6565 = 6565; b.value6566 = 6566; b.value6567 = 6567; b.value6568 = 6568; b.value6569 = 6569; b.value6570 = 6570; b.value6571 = 6571; b.value6572 = 6572; b.value6573 = 6573; b.value6574 = 6574; b.value6575 = 6575; b.value6576 = 6576; b.value6577 = 6577; b.value6578 = 6578; b.value6579 = 6579; b.value6580 = 6580; b.value6581 = 6581; b.value6582 = 6582; b.value6583 = 6583; b.value6584 = 6584; b.value6585 = 6585; b.value6586 = 6586; b.value6587 = 6587; b.value6588 = 6588; b.value6589 = 6589; b.value6590 = 6590; b.value6591 = 6591; b.value6592 = 6592; b.value6593 = 6593; b.value6594 = 6594; b.value6595 = 6595; b.value6596 = 6596; b.value6597 = 6597; b.value6598 = 6598; b.value6599 = 6599; b.value6600 = 6600; b.value6601 = 6601; b.value6602 = 6602; b.value6603 = 6603; b.value6604 = 6604; b.value6605 = 6605; b.value6606 = 6606; b.value6607 = 6607; b.value6608 = 6608; b.value6609 = 6609; b.value6610 = 6610; b.value6611 = 6611; b.value6612 = 6612; b.value6613 = 6613; b.value6614 = 6614; b.value6615 = 6615; b.value6616 = 6616; b.value6617 = 6617; b.value6618 = 6618; b.value6619 = 6619; b.value6620 = 6620; b.value6621 = 6621; b.value6622 = 6622; b.value6623 = 6623; b.value6624 = 6624; b.value6625 = 6625; b.value6626 = 6626; b.value6627 = 6627; b.value6628 = 6628; b.value6629 = 6629; b.value6630 = 6630; b.value6631 = 6631; b.value6632 = 6632; b.value6633 = 6633; b.value6634 = 6634; b.value6635 = 6635; b.value6636 = 6636; b.value6637 = 6637; b.value6638 = 6638; b.value6639 = 6639; b.value6640 = 6640; b.value6641 = 6641; b.value6642 = 6642; b.value6643 = 6643; b.value6644 = 6644; b.value6645 = 6645; b.value6646 = 6646; b.value6647 = 6647; b.value6648 = 6648; b.value6649 = 6649; b.value6650 = 6650; b.value6651 = 6651; b.value6652 = 6652; b.value6653 = 6653; b.value6654 = 6654; b.value6655 = 6655; b.value6656 = 6656; b.value6657 = 6657; b.value6658 = 6658; b.value6659 = 6659; b.value6660 = 6660; b.value6661 = 6661; b.value6662 = 6662; b.value6663 = 6663; b.value6664 = 6664; b.value6665 = 6665; b.value6666 = 6666; b.value6667 = 6667; b.value6668 = 6668; b.value6669 = 6669; b.value6670 = 6670; b.value6671 = 6671; b.value6672 = 6672; b.value6673 = 6673; b.value6674 = 6674; b.value6675 = 6675; b.value6676 = 6676; b.value6677 = 6677; b.value6678 = 6678; b.value6679 = 6679; b.value6680 = 6680; b.value6681 = 6681; b.value6682 = 6682; b.value6683 = 6683; b.value6684 = 6684; b.value6685 = 6685; b.value6686 = 6686; b.value6687 = 6687; b.value6688 = 6688; b.value6689 = 6689; b.value6690 = 6690; b.value6691 = 6691; b.value6692 = 6692; b.value6693 = 6693; b.value6694 = 6694; b.value6695 = 6695; b.value6696 = 6696; b.value6697 = 6697; b.value6698 = 6698; b.value6699 = 6699; b.value6700 = 6700; b.value6701 = 6701; b.value6702 = 6702; b.value6703 = 6703; b.value6704 = 6704; b.value6705 = 6705; b.value6706 = 6706; b.value6707 = 6707; b.value6708 = 6708; b.value6709 = 6709; b.value6710 = 6710; b.value6711 = 6711; b.value6712 = 6712; b.value6713 = 6713; b.value6714 = 6714; b.value6715 = 6715; b.value6716 = 6716; b.value6717 = 6717; b.value6718 = 6718; b.value6719 = 6719; b.value6720 = 6720; b.value6721 = 6721; b.value6722 = 6722; b.value6723 = 6723; b.value6724 = 6724; b.value6725 = 6725; b.value6726 = 6726; b.value6727 = 6727; b.value6728 = 6728; b.value6729 = 6729; b.value6730 = 6730; b.value6731 = 6731; b.value6732 = 6732; b.value6733 = 6733; b.value6734 = 6734; b.value6735 = 6735; b.value6736 = 6736; b.value6737 = 6737; b.value6738 = 6738; b.value6739 = 6739; b.value6740 = 6740; b.value6741 = 6741; b.value6742 = 6742; b.value6743 = 6743; b.value6744 = 6744; b.value6745 = 6745; b.value6746 = 6746; b.value6747 = 6747; b.value6748 = 6748; b.value6749 = 6749; b.value6750 = 6750; b.value6751 = 6751; b.value6752 = 6752; b.value6753 = 6753; b.value6754 = 6754; b.value6755 = 6755; b.value6756 = 6756; b.value6757 = 6757; b.value6758 = 6758; b.value6759 = 6759; b.value6760 = 6760; b.value6761 = 6761; b.value6762 = 6762; b.value6763 = 6763; b.value6764 = 6764; b.value6765 = 6765; b.value6766 = 6766; b.value6767 = 6767; b.value6768 = 6768; b.value6769 = 6769; b.value6770 = 6770; b.value6771 = 6771; b.value6772 = 6772; b.value6773 = 6773; b.value6774 = 6774; b.value6775 = 6775; b.value6776 = 6776; b.value6777 = 6777; b.value6778 = 6778; b.value6779 = 6779; b.value6780 = 6780; b.value6781 = 6781; b.value6782 = 6782; b.value6783 = 6783; b.value6784 = 6784; b.value6785 = 6785; b.value6786 = 6786; b.value6787 = 6787; b.value6788 = 6788; b.value6789 = 6789; b.value6790 = 6790; b.value6791 = 6791; b.value6792 = 6792; b.value6793 = 6793; b.value6794 = 6794; b.value6795 = 6795; b.value6796 = 6796; b.value6797 = 6797; b.value6798 = 6798; b.value6799 = 6799; b.value6800 = 6800; b.value6801 = 6801; b.value6802 = 6802; b.value6803 = 6803; b.value6804 = 6804; b.value6805 = 6805; b.value6806 = 6806; b.value6807 = 6807; b.value6808 = 6808; b.value6809 = 6809; b.value6810 = 6810; b.value6811 = 6811; b.value6812 = 6812; b.value6813 = 6813; b.value6814 = 6814; b.value6815 = 6815; b.value6816 = 6816; b.value6817 = 6817; b.value6818 = 6818; b.value6819 = 6819; b.value6820 = 6820; b.value6821 = 6821; b.value6822 = 6822; b.value6823 = 6823; b.value6824 = 6824; b.value6825 = 6825; b.value6826 = 6826; b.value6827 = 6827; b.value6828 = 6828; b.value6829 = 6829; b.value6830 = 6830; b.value6831 = 6831; b.value6832 = 6832; b.value6833 = 6833; b.value6834 = 6834; b.value6835 = 6835; b.value6836 = 6836; b.value6837 = 6837; b.value6838 = 6838; b.value6839 = 6839; b.value6840 = 6840; b.value6841 = 6841; b.value6842 = 6842; b.value6843 = 6843; b.value6844 = 6844; b.value6845 = 6845; b.value6846 = 6846; b.value6847 = 6847; b.value6848 = 6848; b.value6849 = 6849; b.value6850 = 6850; b.value6851 = 6851; b.value6852 = 6852; b.value6853 = 6853; b.value6854 = 6854; b.value6855 = 6855; b.value6856 = 6856; b.value6857 = 6857; b.value6858 = 6858; b.value6859 = 6859; b.value6860 = 6860; b.value6861 = 6861; b.value6862 = 6862; b.value6863 = 6863; b.value6864 = 6864; b.value6865 = 6865; b.value6866 = 6866; b.value6867 = 6867; b.value6868 = 6868; b.value6869 = 6869; b.value6870 = 6870; b.value6871 = 6871; b.value6872 = 6872; b.value6873 = 6873; b.value6874 = 6874; b.value6875 = 6875; b.value6876 = 6876; b.value6877 = 6877; b.value6878 = 6878; b.value6879 = 6879; b.value6880 = 6880; b.value6881 = 6881; b.value6882 = 6882; b.value6883 = 6883; b.value6884 = 6884; b.value6885 = 6885; b.value6886 = 6886; b.value6887 = 6887; b.value6888 = 6888; b.value6889 = 6889; b.value6890 = 6890; b.value6891 = 6891; b.value6892 = 6892; b.value6893 = 6893; b.value6894 = 6894; b.value6895 = 6895; b.value6896 = 6896; b.value6897 = 6897; b.value6898 = 6898; b.value6899 = 6899; b.value6900 = 6900; b.value6901 = 6901; b.value6902 = 6902; b.value6903 = 6903; b.value6904 = 6904; b.value6905 = 6905; b.value6906 = 6906; b.value6907 = 6907; b.value6908 = 6908; b.value6909 = 6909; b.value6910 = 6910; b.value6911 = 6911; b.value6912 = 6912; b.value6913 = 6913; b.value6914 = 6914; b.value6915 = 6915; b.value6916 = 6916; b.value6917 = 6917; b.value6918 = 6918; b.value6919 = 6919; b.value6920 = 6920; b.value6921 = 6921; b.value6922 = 6922; b.value6923 = 6923; b.value6924 = 6924; b.value6925 = 6925; b.value6926 = 6926; b.value6927 = 6927; b.value6928 = 6928; b.value6929 = 6929; b.value6930 = 6930; b.value6931 = 6931; b.value6932 = 6932; b.value6933 = 6933; b.value6934 = 6934; b.value6935 = 6935; b.value6936 = 6936; b.value6937 = 6937; b.value6938 = 6938; b.value6939 = 6939; b.value6940 = 6940; b.value6941 = 6941; b.value6942 = 6942; b.value6943 = 6943; b.value6944 = 6944; b.value6945 = 6945; b.value6946 = 6946; b.value6947 = 6947; b.value6948 = 6948; b.value6949 = 6949; b.value6950 = 6950; b.value6951 = 6951; b.value6952 = 6952; b.value6953 = 6953; b.value6954 = 6954; b.value6955 = 6955; b.value6956 = 6956; b.value6957 = 6957; b.value6958 = 6958; b.value6959 = 6959; b.value6960 = 6960; b.value6961 = 6961; b.value6962 = 6962; b.value6963 = 6963; b.value6964 = 6964; b.value6965 = 6965; b.value6966 = 6966; b.value6967 = 6967; b.value6968 = 6968; b.value6969 = 6969; b.value6970 = 6970; b.value6971 = 6971; b.value6972 = 6972; b.value6973 = 6973; b.value6974 = 6974; b.value6975 = 6975; b.value6976 = 6976; b.value6977 = 6977; b.value6978 = 6978; b.value6979 = 6979; b.value6980 = 6980; b.value6981 = 6981; b.value6982 = 6982; b.value6983 = 6983; b.value6984 = 6984; b.value6985 = 6985; b.value6986 = 6986; b.value6987 = 6987; b.value6988 = 6988; b.value6989 = 6989; b.value6990 = 6990; b.value6991 = 6991; b.value6992 = 6992; b.value6993 = 6993; b.value6994 = 6994; b.value6995 = 6995; b.value6996 = 6996; b.value6997 = 6997; b.value6998 = 6998; b.value6999 = 6999; b.value7000 = 7000; b.value7001 = 7001; b.value7002 = 7002; b.value7003 = 7003; b.value7004 = 7004; b.value7005 = 7005; b.value7006 = 7006; b.value7007 = 7007; b.value7008 = 7008; b.value7009 = 7009; b.value7010 = 7010; b.value7011 = 7011; b.value7012 = 7012; b.value7013 = 7013; b.value7014 = 7014; b.value7015 = 7015; b.value7016 = 7016; b.value7017 = 7017; b.value7018 = 7018; b.value7019 = 7019; b.value7020 = 7020; b.value7021 = 7021; b.value7022 = 7022; b.value7023 = 7023; b.value7024 = 7024; b.value7025 = 7025; b.value7026 = 7026; b.value7027 = 7027; b.value7028 = 7028; b.value7029 = 7029; b.value7030 = 7030; b.value7031 = 7031; b.value7032 = 7032; b.value7033 = 7033; b.value7034 = 7034; b.value7035 = 7035; b.value7036 = 7036; b.value7037 = 7037; b.value7038 = 7038; b.value7039 = 7039; b.value7040 = 7040; b.value7041 = 7041; b.value7042 = 7042; b.value7043 = 7043; b.value7044 = 7044; b.value7045 = 7045; b.value7046 = 7046; b.value7047 = 7047; b.value7048 = 7048; b.value7049 = 7049; b.value7050 = 7050; b.value7051 = 7051; b.value7052 = 7052; b.value7053 = 7053; b.value7054 = 7054; b.value7055 = 7055; b.value7056 = 7056; b.value7057 = 7057; b.value7058 = 7058; b.value7059 = 7059; b.value7060 = 7060; b.value7061 = 7061; b.value7062 = 7062; b.value7063 = 7063; b.value7064 = 7064; b.value7065 = 7065; b.value7066 = 7066; b.value7067 = 7067; b.value7068 = 7068; b.value7069 = 7069; b.value7070 = 7070; b.value7071 = 7071; b.value7072 = 7072; b.value7073 = 7073; b.value7074 = 7074; b.value7075 = 7075; b.value7076 = 7076; b.value7077 = 7077; b.value7078 = 7078; b.value7079 = 7079; b.value7080 = 7080; b.value7081 = 7081; b.value7082 = 7082; b.value7083 = 7083; b.value7084 = 7084; b.value7085 = 7085; b.value7086 = 7086; b.value7087 = 7087; b.value7088 = 7088; b.value7089 = 7089; b.value7090 = 7090; b.value7091 = 7091; b.value7092 = 7092; b.value7093 = 7093; b.value7094 = 7094; b.value7095 = 7095; b.value7096 = 7096; b.value7097 = 7097; b.value7098 = 7098; b.value7099 = 7099; b.value7100 = 7100; b.value7101 = 7101; b.value7102 = 7102; b.value7103 = 7103; b.value7104 = 7104; b.value7105 = 7105; b.value7106 = 7106; b.value7107 = 7107; b.value7108 = 7108; b.value7109 = 7109; b.value7110 = 7110; b.value7111 = 7111; b.value7112 = 7112; b.value7113 = 7113; b.value7114 = 7114; b.value7115 = 7115; b.value7116 = 7116; b.value7117 = 7117; b.value7118 = 7118; b.value7119 = 7119; b.value7120 = 7120; b.value7121 = 7121; b.value7122 = 7122; b.value7123 = 7123; b.value7124 = 7124; b.value7125 = 7125; b.value7126 = 7126; b.value7127 = 7127; b.value7128 = 7128; b.value7129 = 7129; b.value7130 = 7130; b.value7131 = 7131; b.value7132 = 7132; b.value7133 = 7133; b.value7134 = 7134; b.value7135 = 7135; b.value7136 = 7136; b.value7137 = 7137; b.value7138 = 7138; b.value7139 = 7139; b.value7140 = 7140; b.value7141 = 7141; b.value7142 = 7142; b.value7143 = 7143; b.value7144 = 7144; b.value7145 = 7145; b.value7146 = 7146; b.value7147 = 7147; b.value7148 = 7148; b.value7149 = 7149; b.value7150 = 7150; b.value7151 = 7151; b.value7152 = 7152; b.value7153 = 7153; b.value7154 = 7154; b.value7155 = 7155; b.value7156 = 7156; b.value7157 = 7157; b.value7158 = 7158; b.value7159 = 7159; b.value7160 = 7160; b.value7161 = 7161; b.value7162 = 7162; b.value7163 = 7163; b.value7164 = 7164; b.value7165 = 7165; b.value7166 = 7166; b.value7167 = 7167; b.value7168 = 7168; b.value7169 = 7169; b.value7170 = 7170; b.value7171 = 7171; b.value7172 = 7172; b.value7173 = 7173; b.value7174 = 7174; b.value7175 = 7175; b.value7176 = 7176; b.value7177 = 7177; b.value7178 = 7178; b.value7179 = 7179; b.value7180 = 7180; b.value7181 = 7181; b.value7182 = 7182; b.value7183 = 7183; b.value7184 = 7184; b.value7185 = 7185; b.value7186 = 7186; b.value7187 = 7187; b.value7188 = 7188; b.value7189 = 7189; b.value7190 = 7190; b.value7191 = 7191; b.value7192 = 7192; b.value7193 = 7193; b.value7194 = 7194; b.value7195 = 7195; b.value7196 = 7196; b.value7197 = 7197; b.value7198 = 7198; b.value7199 = 7199; b.value7200 = 7200; b.value7201 = 7201; b.value7202 = 7202; b.value7203 = 7203; b.value7204 = 7204; b.value7205 = 7205; b.value7206 = 7206; b.value7207 = 7207; b.value7208 = 7208; b.value7209 = 7209; b.value7210 = 7210; b.value7211 = 7211; b.value7212 = 7212; b.value7213 = 7213; b.value7214 = 7214; b.value7215 = 7215; b.value7216 = 7216; b.value7217 = 7217; b.value7218 = 7218; b.value7219 = 7219; b.value7220 = 7220; b.value7221 = 7221; b.value7222 = 7222; b.value7223 = 7223; b.value7224 = 7224; b.value7225 = 7225; b.value7226 = 7226; b.value7227 = 7227; b.value7228 = 7228; b.value7229 = 7229; b.value7230 = 7230; b.value7231 = 7231; b.value7232 = 7232; b.value7233 = 7233; b.value7234 = 7234; b.value7235 = 7235; b.value7236 = 7236; b.value7237 = 7237; b.value7238 = 7238; b.value7239 = 7239; b.value7240 = 7240; b.value7241 = 7241; b.value7242 = 7242; b.value7243 = 7243; b.value7244 = 7244; b.value7245 = 7245; b.value7246 = 7246; b.value7247 = 7247; b.value7248 = 7248; b.value7249 = 7249; b.value7250 = 7250; b.value7251 = 7251; b.value7252 = 7252; b.value7253 = 7253; b.value7254 = 7254; b.value7255 = 7255; b.value7256 = 7256; b.value7257 = 7257; b.value7258 = 7258; b.value7259 = 7259; b.value7260 = 7260; b.value7261 = 7261; b.value7262 = 7262; b.value7263 = 7263; b.value7264 = 7264; b.value7265 = 7265; b.value7266 = 7266; b.value7267 = 7267; b.value7268 = 7268; b.value7269 = 7269; b.value7270 = 7270; b.value7271 = 7271; b.value7272 = 7272; b.value7273 = 7273; b.value7274 = 7274; b.value7275 = 7275; b.value7276 = 7276; b.value7277 = 7277; b.value7278 = 7278; b.value7279 = 7279; b.value7280 = 7280; b.value7281 = 7281; b.value7282 = 7282; b.value7283 = 7283; b.value7284 = 7284; b.value7285 = 7285; b.value7286 = 7286; b.value7287 = 7287; b.value7288 = 7288; b.value7289 = 7289; b.value7290 = 7290; b.value7291 = 7291; b.value7292 = 7292; b.value7293 = 7293; b.value7294 = 7294; b.value7295 = 7295; b.value7296 = 7296; b.value7297 = 7297; b.value7298 = 7298; b.value7299 = 7299; b.value7300 = 7300; b.value7301 = 7301; b.value7302 = 7302; b.value7303 = 7303; b.value7304 = 7304; b.value7305 = 7305; b.value7306 = 7306; b.value7307 = 7307; b.value7308 = 7308; b.value7309 = 7309; b.value7310 = 7310; b.value7311 = 7311; b.value7312 = 7312; b.value7313 = 7313; b.value7314 = 7314; b.value7315 = 7315; b.value7316 = 7316; b.value7317 = 7317; b.value7318 = 7318; b.value7319 = 7319; b.value7320 = 7320; b.value7321 = 7321; b.value7322 = 7322; b.value7323 = 7323; b.value7324 = 7324; b.value7325 = 7325; b.value7326 = 7326; b.value7327 = 7327; b.value7328 = 7328; b.value7329 = 7329; b.value7330 = 7330; b.value7331 = 7331; b.value7332 = 7332; b.value7333 = 7333; b.value7334 = 7334; b.value7335 = 7335; b.value7336 = 7336; b.value7337 = 7337; b.value7338 = 7338; b.value7339 = 7339; b.value7340 = 7340; b.value7341 = 7341; b.value7342 = 7342; b.value7343 = 7343; b.value7344 = 7344; b.value7345 = 7345; b.value7346 = 7346; b.value7347 = 7347; b.value7348 = 7348; b.value7349 = 7349; b.value7350 = 7350; b.value7351 = 7351; b.value7352 = 7352; b.value7353 = 7353; b.value7354 = 7354; b.value7355 = 7355; b.value7356 = 7356; b.value7357 = 7357; b.value7358 = 7358; b.value7359 = 7359; b.value7360 = 7360; b.value7361 = 7361; b.value7362 = 7362; b.value7363 = 7363; b.value7364 = 7364; b.value7365 = 7365; b.value7366 = 7366; b.value7367 = 7367; b.value7368 = 7368; b.value7369 = 7369; b.value7370 = 7370; b.value7371 = 7371; b.value7372 = 7372; b.value7373 = 7373; b.value7374 = 7374; b.value7375 = 7375; b.value7376 = 7376; b.value7377 = 7377; b.value7378 = 7378; b.value7379 = 7379; b.value7380 = 7380; b.value7381 = 7381; b.value7382 = 7382; b.value7383 = 7383; b.value7384 = 7384; b.value7385 = 7385; b.value7386 = 7386; b.value7387 = 7387; b.value7388 = 7388; b.value7389 = 7389; b.value7390 = 7390; b.value7391 = 7391; b.value7392 = 7392; b.value7393 = 7393; b.value7394 = 7394; b.value7395 = 7395; b.value7396 = 7396; b.value7397 = 7397; b.value7398 = 7398; b.value7399 = 7399; b.value7400 = 7400; b.value7401 = 7401; b.value7402 = 7402; b.value7403 = 7403; b.value7404 = 7404; b.value7405 = 7405; b.value7406 = 7406; b.value7407 = 7407; b.value7408 = 7408; b.value7409 = 7409; b.value7410 = 7410; b.value7411 = 7411; b.value7412 = 7412; b.value7413 = 7413; b.value7414 = 7414; b.value7415 = 7415; b.value7416 = 7416; b.value7417 = 7417; b.value7418 = 7418; b.value7419 = 7419; b.value7420 = 7420; b.value7421 = 7421; b.value7422 = 7422; b.value7423 = 7423; b.value7424 = 7424; b.value7425 = 7425; b.value7426 = 7426; b.value7427 = 7427; b.value7428 = 7428; b.value7429 = 7429; b.value7430 = 7430; b.value7431 = 7431; b.value7432 = 7432; b.value7433 = 7433; b.value7434 = 7434; b.value7435 = 7435; b.value7436 = 7436; b.value7437 = 7437; b.value7438 = 7438; b.value7439 = 7439; b.value7440 = 7440; b.value7441 = 7441; b.value7442 = 7442; b.value7443 = 7443; b.value7444 = 7444; b.value7445 = 7445; b.value7446 = 7446; b.value7447 = 7447; b.value7448 = 7448; b.value7449 = 7449; b.value7450 = 7450; b.value7451 = 7451; b.value7452 = 7452; b.value7453 = 7453; b.value7454 = 7454; b.value7455 = 7455; b.value7456 = 7456; b.value7457 = 7457; b.value7458 = 7458; b.value7459 = 7459; b.value7460 = 7460; b.value7461 = 7461; b.value7462 = 7462; b.value7463 = 7463; b.value7464 = 7464; b.value7465 = 7465; b.value7466 = 7466; b.value7467 = 7467; b.value7468 = 7468; b.value7469 = 7469; b.value7470 = 7470; b.value7471 = 7471; b.value7472 = 7472; b.value7473 = 7473; b.value7474 = 7474; b.value7475 = 7475; b.value7476 = 7476; b.value7477 = 7477; b.value7478 = 7478; b.value7479 = 7479; b.value7480 = 7480; b.value7481 = 7481; b.value7482 = 7482; b.value7483 = 7483; b.value7484 = 7484; b.value7485 = 7485; b.value7486 = 7486; b.value7487 = 7487; b.value7488 = 7488; b.value7489 = 7489; b.value7490 = 7490; b.value7491 = 7491; b.value7492 = 7492; b.value7493 = 7493; b.value7494 = 7494; b.value7495 = 7495; b.value7496 = 7496; b.value7497 = 7497; b.value7498 = 7498; b.value7499 = 7499; b.value7500 = 7500; b.value7501 = 7501; b.value7502 = 7502; b.value7503 = 7503; b.value7504 = 7504; b.value7505 = 7505; b.value7506 = 7506; b.value7507 = 7507; b.value7508 = 7508; b.value7509 = 7509; b.value7510 = 7510; b.value7511 = 7511; b.value7512 = 7512; b.value7513 = 7513; b.value7514 = 7514; b.value7515 = 7515; b.value7516 = 7516; b.value7517 = 7517; b.value7518 = 7518; b.value7519 = 7519; b.value7520 = 7520; b.value7521 = 7521; b.value7522 = 7522; b.value7523 = 7523; b.value7524 = 7524; b.value7525 = 7525; b.value7526 = 7526; b.value7527 = 7527; b.value7528 = 7528; b.value7529 = 7529; b.value7530 = 7530; b.value7531 = 7531; b.value7532 = 7532; b.value7533 = 7533; b.value7534 = 7534; b.value7535 = 7535; b.value7536 = 7536; b.value7537 = 7537; b.value7538 = 7538; b.value7539 = 7539; b.value7540 = 7540; b.value7541 = 7541; b.value7542 = 7542; b.value7543 = 7543; b.value7544 = 7544; b.value7545 = 7545; b.value7546 = 7546; b.value7547 = 7547; b.value7548 = 7548; b.value7549 = 7549; b.value7550 = 7550; b.value7551 = 7551; b.value7552 = 7552; b.value7553 = 7553; b.value7554 = 7554; b.value7555 = 7555; b.value7556 = 7556; b.value7557 = 7557; b.value7558 = 7558; b.value7559 = 7559; b.value7560 = 7560; b.value7561 = 7561; b.value7562 = 7562; b.value7563 = 7563; b.value7564 = 7564; b.value7565 = 7565; b.value7566 = 7566; b.value7567 = 7567; b.value7568 = 7568; b.value7569 = 7569; b.value7570 = 7570; b.value7571 = 7571; b.value7572 = 7572; b.value7573 = 7573; b.value7574 = 7574; b.value7575 = 7575; b.value7576 = 7576; b.value7577 = 7577; b.value7578 = 7578; b.value7579 = 7579; b.value7580 = 7580; b.value7581 = 7581; b.value7582 = 7582; b.value7583 = 7583; b.value7584 = 7584; b.value7585 = 7585; b.value7586 = 7586; b.value7587 = 7587; b.value7588 = 7588; b.value7589 = 7589; b.value7590 = 7590; b.value7591 = 7591; b.value7592 = 7592; b.value7593 = 7593; b.value7594 = 7594; b.value7595 = 7595; b.value7596 = 7596; b.value7597 = 7597; b.value7598 = 7598; b.value7599 = 7599; b.value7600 = 7600; b.value7601 = 7601; b.value7602 = 7602; b.value7603 = 7603; b.value7604 = 7604; b.value7605 = 7605; b.value7606 = 7606; b.value7607 = 7607; b.value7608 = 7608; b.value7609 = 7609; b.value7610 = 7610; b.value7611 = 7611; b.value7612 = 7612; b.value7613 = 7613; b.value7614 = 7614; b.value7615 = 7615; b.value7616 = 7616; b.value7617 = 7617; b.value7618 = 7618; b.value7619 = 7619; b.value7620 = 7620; b.value7621 = 7621; b.value7622 = 7622; b.value7623 = 7623; b.value7624 = 7624; b.value7625 = 7625; b.value7626 = 7626; b.value7627 = 7627; b.value7628 = 7628; b.value7629 = 7629; b.value7630 = 7630; b.value7631 = 7631; b.value7632 = 7632; b.value7633 = 7633; b.value7634 = 7634; b.value7635 = 7635; b.value7636 = 7636; b.value7637 = 7637; b.value7638 = 7638; b.value7639 = 7639; b.value7640 = 7640; b.value7641 = 7641; b.value7642 = 7642; b.value7643 = 7643; b.value7644 = 7644; b.value7645 = 7645; b.value7646 = 7646; b.value7647 = 7647; b.value7648 = 7648; b.value7649 = 7649; b.value7650 = 7650; b.value7651 = 7651; b.value7652 = 7652; b.value7653 = 7653; b.value7654 = 7654; b.value7655 = 7655; b.value7656 = 7656; b.value7657 = 7657; b.value7658 = 7658; b.value7659 = 7659; b.value7660 = 7660; b.value7661 = 7661; b.value7662 = 7662; b.value7663 = 7663; b.value7664 = 7664; b.value7665 = 7665; b.value7666 = 7666; b.value7667 = 7667; b.value7668 = 7668; b.value7669 = 7669; b.value7670 = 7670; b.value7671 = 7671; b.value7672 = 7672; b.value7673 = 7673; b.value7674 = 7674; b.value7675 = 7675; b.value7676 = 7676; b.value7677 = 7677; b.value7678 = 7678; b.value7679 = 7679; b.value7680 = 7680; b.value7681 = 7681; b.value7682 = 7682; b.value7683 = 7683; b.value7684 = 7684; b.value7685 = 7685; b.value7686 = 7686; b.value7687 = 7687; b.value7688 = 7688; b.value7689 = 7689; b.value7690 = 7690; b.value7691 = 7691; b.value7692 = 7692; b.value7693 = 7693; b.value7694 = 7694; b.value7695 = 7695; b.value7696 = 7696; b.value7697 = 7697; b.value7698 = 7698; b.value7699 = 7699; b.value7700 = 7700; b.value7701 = 7701; b.value7702 = 7702; b.value7703 = 7703; b.value7704 = 7704; b.value7705 = 7705; b.value7706 = 7706; b.value7707 = 7707; b.value7708 = 7708; b.value7709 = 7709; b.value7710 = 7710; b.value7711 = 7711; b.value7712 = 7712; b.value7713 = 7713; b.value7714 = 7714; b.value7715 = 7715; b.value7716 = 7716; b.value7717 = 7717; b.value7718 = 7718; b.value7719 = 7719; b.value7720 = 7720; b.value7721 = 7721; b.value7722 = 7722; b.value7723 = 7723; b.value7724 = 7724; b.value7725 = 7725; b.value7726 = 7726; b.value7727 = 7727; b.value7728 = 7728; b.value7729 = 7729; b.value7730 = 7730; b.value7731 = 7731; b.value7732 = 7732; b.value7733 = 7733; b.value7734 = 7734; b.value7735 = 7735; b.value7736 = 7736; b.value7737 = 7737; b.value7738 = 7738; b.value7739 = 7739; b.value7740 = 7740; b.value7741 = 7741; b.value7742 = 7742; b.value7743 = 7743; b.value7744 = 7744; b.value7745 = 7745; b.value7746 = 7746; b.value7747 = 7747; b.value7748 = 7748; b.value7749 = 7749; b.value7750 = 7750; b.value7751 = 7751; b.value7752 = 7752; b.value7753 = 7753; b.value7754 = 7754; b.value7755 = 7755; b.value7756 = 7756; b.value7757 = 7757; b.value7758 = 7758; b.value7759 = 7759; b.value7760 = 7760; b.value7761 = 7761; b.value7762 = 7762; b.value7763 = 7763; b.value7764 = 7764; b.value7765 = 7765; b.value7766 = 7766; b.value7767 = 7767; b.value7768 = 7768; b.value7769 = 7769; b.value7770 = 7770; b.value7771 = 7771; b.value7772 = 7772; b.value7773 = 7773; b.value7774 = 7774; b.value7775 = 7775; b.value7776 = 7776; b.value7777 = 7777; } } } ListWrite.new("Attribute Write").run(); ================================================ FILE: microbenchmarks/enum_case.aria ================================================ # SPDX-License-Identifier: Apache-2.0 import aria.range.int_extension; import Microbenchmark from infra; enum Foo { case A, case B } extension Foo { type func get_case(x) { if x { return Foo::A; } else { return Foo::B; } } } func foo(_) {} struct EnumCaseCreation : Microbenchmark { func test() { val which = true; for _ in 0.to(100_000) { foo(Foo.get_case(which)); which = !which; } } } EnumCaseCreation.new("Enum Case Creation").run(); ================================================ FILE: microbenchmarks/infra.aria ================================================ # SPDX-License-Identifier: Apache-2.0 import aria.range.int_extension; struct Timer { type func new(f) { return alloc(This) { .fn = f, .samples = [] }; } func run(n=1) { val start = now(); for _ in 0.to(n) { this.fn(); } val end = now(); val duration = (end - start)/1000.0; this.samples.append(duration); return duration; } func average() { if this.samples.len() == 0 { return 0.0; } return this.samples.sum() / this.samples.len(); } func percentile(p) { val n = this.samples.len(); if n == 0 { return 0.0; } val s = this.samples; s.quicksort(); val idxf = (p / 100.0) * (n - 1); val idx = idxf.int(); return s[idx]; } func p50() { return this.percentile(50.0); } func p99() { return this.percentile(99.0); } func p999() { return this.percentile(99.9); } func max() { return this.samples.max(); } func min() { return this.samples.min(); } } struct BenchmarkArguments { type func new() { val verbose = false; val count = 100; val args = cmdline_arguments(); val i = 0; while i < args.len() { if args[i] == "--verbose" { verbose = true; } elsif args[i] == "--count" && i + 1 < args.len() { match Int.parse(args[i+1]) { case Ok(x) => { count = x; }, case Err(e) => { println("Invalid count argument: {0}".format(e)); } } i += 1; } i += 1; } return Box(){.count, .verbose}; } } # include this mixin and provide a func test() to create a microbenchmark mixin Microbenchmark { type func new(name) = alloc(This) { .name }; # override this if you need to prepare data before running the benchmark func prepare() {} # override this if you need to clean up after running the benchmark func teardown() {} func _iter(collect, verbose) { this.prepare(); if collect { val duration = this.timer.run(); if verbose { println("{1} duration: {0:.3}s".format(duration, this.name)); } } else { this.test(); } this.teardown(); } func run(n=Maybe::None) { val args = BenchmarkArguments.new(); val count = n ?? args.count; assert hasattr(this, "test"); if !hasattr(this, "timer") { this.timer = Timer.new(this.test); } count += 10; val ten = 10; # and now do the real testing for _ in 0.to(count) { this._iter(ten == 0, ten == 0 && args.verbose); if ten > 0 { ten -= 1; } } println("{0} min: {1:.3}s p50: {2:.3}s p99: {3:.3}s p999: {4:.3}s max: {5:.3}s".format( this.name, this.timer.min()??, this.timer.p50(), this.timer.p99(), this.timer.p999(), this.timer.max()?? )); } } ================================================ FILE: microbenchmarks/int_arith.aria ================================================ # SPDX-License-Identifier: Apache-2.0 import aria.range.int_extension; import Microbenchmark from infra; struct IntegerArithmetic : Microbenchmark { func test() { val n = 2; val m = 1; while n < 500_000_000_000 { n = n + 2 * m + n / m; m = m + 1; } } } IntegerArithmetic.new("Integer Arithmetic").run(); ================================================ FILE: microbenchmarks/list_filled.aria ================================================ # SPDX-License-Identifier: Apache-2.0 import aria.range.int_extension; import Microbenchmark from infra; func foo(_) {} struct ListFilled : Microbenchmark { func test() { foo(List.filled(false, 1_000_000)); } } ListFilled.new("List Filled").run(); ================================================ FILE: microbenchmarks/list_from_closure.aria ================================================ # SPDX-License-Identifier: Apache-2.0 import aria.range.int_extension; import Microbenchmark from infra; func foo(_) {} struct ListFromClosure : Microbenchmark { func test() { foo(List.from_function(|_| => false, 1_000_000)); } } ListFromClosure.new("List From Closure").run(); ================================================ FILE: microbenchmarks/list_read.aria ================================================ # SPDX-License-Identifier: Apache-2.0 import aria.range.int_extension; import Microbenchmark from infra; func foo(_) {} struct ListWrite : Microbenchmark { func prepare() { this.list = List.filled(false, 100000); } # no need for teardown since we recreate the list each time func test() { for n in this.list { foo(n); } } } ListWrite.new("List Read").run(); ================================================ FILE: microbenchmarks/list_write.aria ================================================ # SPDX-License-Identifier: Apache-2.0 import aria.range.int_extension; import Microbenchmark from infra; struct ListWrite : Microbenchmark { func test() { val l = []; for i in 0.to(100000) { l.append(i); } } } ListWrite.new("List Write").run(); ================================================ FILE: microbenchmarks/map_loop.aria ================================================ # SPDX-License-Identifier: Apache-2.0 import Map from aria.structures.map; import Microbenchmark from infra; struct MapLoop : Microbenchmark { func prepare() { val m = Map.new(); for i in 0.to(12_000) { m.set(i, i); } this.m = m; } func test() { for item in this.m { assert item.value == item.key; } } } MapLoop.new("Map Iterator").run(); ================================================ FILE: microbenchmarks/method_call.aria ================================================ # SPDX-License-Identifier: Apache-2.0 import aria.range.int_extension; import Microbenchmark from infra; struct Foo { func answer() = 42; } struct MethodCall : Microbenchmark { func prepare() { this.foo = alloc(Foo); } func test() { for i in 0.to(100_000) { assert this.foo.answer() == 42; } } } MethodCall.new("Method Call").run(); ================================================ FILE: microbenchmarks/sieve.aria ================================================ # SPDX-License-Identifier: Apache-2.0 import aria.range.int_extension; import Microbenchmark from infra; # Based on https://github.com/PlummersSoftwareLLC/Primes/blob/drag-race/PrimeWren/solution_1/primes.wren import Map from aria.structures.map; val DICT = Map.new() { [10] = 4, [100] = 25, [1000] = 168, [10000] = 1229, [100000] = 9592, [1000000] = 78498, [10000000] = 664579, [100000000] = 5761455, [1000000000] = 50847534, [10000000000] = 455052511, }; extension Int { func sqrt() { val x = this; val y = (x + 1) / 2; while y < x { x = y; y = (x + this / x) / 2; } return x; } } struct SieveImpl { type func new(size: Int) = alloc(This) { .size, .bits = List.filled(false, size), }; func run() { val bits = this.bits; val size = this.size; val factor = 3; val q = size.sqrt(); while factor <= q { val num = factor; while num < size { if !bits[num] { factor = num; break; } num += 2; } val num2 = factor * factor; while num2 < size { bits[num2] = true; num2 += factor * 2; } factor += 2; } } func count_primes() { val count = 1; val num = 3; while num < this.size { if !this.bits[num] { count += 1; } num += 2; } return count; } func validate() = DICT.contains(this.size) && DICT[this.size] == this.count_primes(); } struct Sieve : Microbenchmark { func teardown() { assert this.impl.validate(); } func test() { this.impl = SieveImpl.new(1000000); this.impl.run(); } } Sieve.new("Sieve of Eratosthenes").run(); ================================================ FILE: native-libs/file/Cargo.toml ================================================ [package] name = "file-lib" version = "0.9.20251222" edition = "2024" [lib] name = "aria_file" path = "src/lib.rs" crate-type = ["cdylib"] [dependencies] vm-lib = { path = "../../vm-lib" } opcodes-lib = { path = "../../opcodes-lib" } ================================================ FILE: native-libs/file/src/lib.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use haxby_opcodes::function_attribs::{FUNC_IS_METHOD, METHOD_ATTRIBUTE_TYPE}; use haxby_vm::{ builtins::VmGlobals, error::{dylib_load::LoadResult, exception::VmException, vm_error::VmErrorReason}, frame::Frame, runtime_module::RuntimeModule, runtime_value::{ RuntimeValue, function::BuiltinFunctionImpl, list::List, object::Object, opaque::OpaqueValue, structure::Struct, }, symbol::Symbol, vm::{self, RunloopExit}, }; use std::{ cell::RefCell, fs::{File, OpenOptions}, io::{Read, Seek, Write}, rc::Rc, }; const FILE_MODE_READ: i64 = 1; const FILE_MODE_WRITE: i64 = 2; const FILE_MODE_APPEND: i64 = 4; const FILE_MODE_TRUNCATE: i64 = 8; const FILE_MODE_NEED_NEW: i64 = 16; fn open_options_from_int(n: i64) -> OpenOptions { let mut opts = OpenOptions::new(); if (n & FILE_MODE_READ) != 0 { opts.read(true); } if (n & FILE_MODE_WRITE) != 0 { opts.write(true); if (n & FILE_MODE_NEED_NEW) != 0 { opts.create_new(true); } else { opts.create(true); } if (n & FILE_MODE_TRUNCATE) != 0 { opts.truncate(true); } } if (n & FILE_MODE_APPEND) != 0 { opts.append(true); if (n & FILE_MODE_NEED_NEW) != 0 { opts.create_new(true); } else { opts.create(true); } if (n & FILE_MODE_TRUNCATE) != 0 { opts.truncate(true); } } opts } struct MutableFile { file: RefCell, } fn file_symbol(builtins: &VmGlobals) -> Result { builtins .lookup_symbol("__file") .ok_or(VmErrorReason::UnexpectedVmState) } fn mut_file_from_aria( aria_file: &Object, builtins: &VmGlobals, ) -> Result, VmErrorReason> { let file_sym = file_symbol(builtins)?; let rust_file_obj = aria_file .read(builtins, file_sym) .ok_or(VmErrorReason::UnexpectedVmState)?; rust_file_obj .as_opaque_concrete::() .ok_or(VmErrorReason::UnexpectedVmState) } fn throw_io_error( the_struct: &Struct, message: String, builtins: &mut VmGlobals, ) -> crate::vm::ExecutionResult { let err_sym = builtins .intern_symbol("IOError") .expect("too many symbols interned"); let io_error = the_struct.extract_field(builtins, err_sym, |f: RuntimeValue| f.as_struct().cloned())?; let io_error = RuntimeValue::Object(Object::new(&io_error)); let message_sym = builtins .intern_symbol("message") .expect("too many symbols interned"); let _ = io_error.write_attribute(message_sym, RuntimeValue::String(message.into()), builtins); Ok(RunloopExit::Exception(VmException::from_value(io_error))) } #[derive(Default)] struct New {} impl BuiltinFunctionImpl for New { fn eval( &self, frame: &mut Frame, vm: &mut crate::vm::VirtualMachine, ) -> crate::vm::ExecutionResult { let the_struct = VmGlobals::extract_arg(frame, |x: RuntimeValue| x.as_struct().cloned())?; let the_path = VmGlobals::extract_arg(frame, |x: RuntimeValue| x.as_string().cloned())?; let the_mode = VmGlobals::extract_arg(frame, |x: RuntimeValue| x.as_integer().cloned())?; let opts = open_options_from_int(*the_mode.raw_value()); match opts.open(the_path.raw_value()) { Ok(file) => { let file = MutableFile { file: RefCell::new(file), }; let file_obj = OpaqueValue::new(file); let aria_file_obj = RuntimeValue::Object(Object::new(&the_struct)); let file_sym = vm .globals .intern_symbol("__file") .expect("too many symbols interned"); let _ = aria_file_obj.write_attribute( file_sym, RuntimeValue::Opaque(file_obj), &mut vm.globals, ); frame.stack.push(aria_file_obj); Ok(RunloopExit::Ok(())) } Err(e) => throw_io_error( &the_struct, format!("Failed to open file: {e}"), &mut vm.globals, ), } } fn attrib_byte(&self) -> u8 { FUNC_IS_METHOD | METHOD_ATTRIBUTE_TYPE } fn arity(&self) -> haxby_vm::arity::Arity { haxby_vm::arity::Arity::required(3) } fn name(&self) -> &str { "_new" } } #[derive(Default)] struct Close {} impl BuiltinFunctionImpl for Close { fn eval( &self, frame: &mut Frame, vm: &mut crate::vm::VirtualMachine, ) -> crate::vm::ExecutionResult { let aria_file = VmGlobals::extract_arg(frame, |x: RuntimeValue| x.as_object().cloned())?; let file_sym = file_symbol(&vm.globals)?; let unit = vm.globals.create_unit_object()?; let rust_file_obj = mut_file_from_aria(&aria_file, &vm.globals)?; let _ = rust_file_obj.file.borrow_mut().flush(); aria_file.write(&mut vm.globals, file_sym, unit); Ok(RunloopExit::Ok(())) } fn attrib_byte(&self) -> u8 { FUNC_IS_METHOD } fn arity(&self) -> haxby_vm::arity::Arity { haxby_vm::arity::Arity::zero() } fn name(&self) -> &str { "_close" } } #[derive(Default)] struct ReadAll {} impl BuiltinFunctionImpl for ReadAll { fn eval( &self, frame: &mut Frame, vm: &mut crate::vm::VirtualMachine, ) -> crate::vm::ExecutionResult { let aria_file = VmGlobals::extract_arg(frame, |x: RuntimeValue| x.as_object().cloned())?; let rust_file_obj = mut_file_from_aria(&aria_file, &vm.globals)?; let mut dest = String::new(); { let mut file_ref = rust_file_obj.file.borrow_mut(); match file_ref.read_to_string(&mut dest) { Ok(_) => { frame.stack.push(RuntimeValue::String(dest.into())); Ok(RunloopExit::Ok(())) } Err(e) => throw_io_error( aria_file.get_struct(), format!("Failed to read file: {e}"), &mut vm.globals, ), } } } fn attrib_byte(&self) -> u8 { FUNC_IS_METHOD } fn arity(&self) -> haxby_vm::arity::Arity { haxby_vm::arity::Arity::required(1) } fn name(&self) -> &str { "_read_all" } } #[derive(Default)] struct ReadCount {} impl BuiltinFunctionImpl for ReadCount { fn eval( &self, frame: &mut Frame, vm: &mut crate::vm::VirtualMachine, ) -> crate::vm::ExecutionResult { let aria_file = VmGlobals::extract_arg(frame, |x: RuntimeValue| x.as_object().cloned())?; let count = VmGlobals::extract_arg(frame, |x: RuntimeValue| x.as_integer().cloned())?; let rust_file_obj = mut_file_from_aria(&aria_file, &vm.globals)?; let mut bytes = vec![0u8; *count.raw_value() as usize]; { let mut file_ref = rust_file_obj.file.borrow_mut(); match file_ref.read_exact(&mut bytes) { Ok(_) => { let result = bytes .iter() .map(|&b| b as i64) .map(|n| RuntimeValue::Integer(n.into())) .collect::>(); let result = List::from(&result); frame.stack.push(RuntimeValue::List(result)); Ok(RunloopExit::Ok(())) } Err(e) => throw_io_error( aria_file.get_struct(), format!("Failed to read file: {e}"), &mut vm.globals, ), } } } fn attrib_byte(&self) -> u8 { FUNC_IS_METHOD } fn arity(&self) -> haxby_vm::arity::Arity { haxby_vm::arity::Arity::required(2) } fn name(&self) -> &str { "_read_count" } } #[derive(Default)] struct WriteStr {} impl BuiltinFunctionImpl for WriteStr { fn eval( &self, frame: &mut Frame, vm: &mut crate::vm::VirtualMachine, ) -> crate::vm::ExecutionResult { let aria_file = VmGlobals::extract_arg(frame, |x: RuntimeValue| x.as_object().cloned())?; let text = VmGlobals::extract_arg(frame, |x: RuntimeValue| x.as_string().cloned())?; let rust_file_obj = mut_file_from_aria(&aria_file, &vm.globals)?; let mut rfo = rust_file_obj.file.borrow_mut(); match rfo.write(text.raw_value().as_bytes()) { Ok(n) => { frame.stack.push(RuntimeValue::Integer((n as i64).into())); Ok(RunloopExit::Ok(())) } Err(e) => throw_io_error( aria_file.get_struct(), format!("Failed to write file: {e}"), &mut vm.globals, ), } } fn attrib_byte(&self) -> u8 { FUNC_IS_METHOD } fn arity(&self) -> haxby_vm::arity::Arity { haxby_vm::arity::Arity::required(2) } fn name(&self) -> &str { "_write_str" } } #[derive(Default)] struct GetPos {} impl BuiltinFunctionImpl for GetPos { fn eval( &self, frame: &mut Frame, vm: &mut crate::vm::VirtualMachine, ) -> crate::vm::ExecutionResult { let aria_file = VmGlobals::extract_arg(frame, |x: RuntimeValue| x.as_object().cloned())?; let rust_file_obj = mut_file_from_aria(&aria_file, &vm.globals)?; let mut rfo = rust_file_obj.file.borrow_mut(); match rfo.stream_position() { Ok(n) => { frame.stack.push(RuntimeValue::Integer((n as i64).into())); Ok(RunloopExit::Ok(())) } Err(e) => throw_io_error( aria_file.get_struct(), format!("Failed to get file position: {e}"), &mut vm.globals, ), } } fn attrib_byte(&self) -> u8 { FUNC_IS_METHOD } fn arity(&self) -> haxby_vm::arity::Arity { haxby_vm::arity::Arity::required(1) } fn name(&self) -> &str { "_getpos" } } #[derive(Default)] struct SetPos {} impl BuiltinFunctionImpl for SetPos { fn eval( &self, frame: &mut Frame, vm: &mut crate::vm::VirtualMachine, ) -> crate::vm::ExecutionResult { let aria_file = VmGlobals::extract_arg(frame, |x: RuntimeValue| x.as_object().cloned())?; let offset = VmGlobals::extract_arg(frame, |x: RuntimeValue| x.as_integer().cloned())?; let rust_file_obj = mut_file_from_aria(&aria_file, &vm.globals)?; let mut rfo = rust_file_obj.file.borrow_mut(); match rfo.seek(std::io::SeekFrom::Start(*offset.raw_value() as u64)) { Ok(n) => { frame.stack.push(RuntimeValue::Integer((n as i64).into())); Ok(RunloopExit::Ok(())) } Err(e) => throw_io_error( aria_file.get_struct(), format!("Failed to set file position: {e}"), &mut vm.globals, ), } } fn attrib_byte(&self) -> u8 { FUNC_IS_METHOD } fn arity(&self) -> haxby_vm::arity::Arity { haxby_vm::arity::Arity::required(2) } fn name(&self) -> &str { "_setpos" } } #[derive(Default)] struct GetSize {} impl BuiltinFunctionImpl for GetSize { fn eval( &self, frame: &mut Frame, vm: &mut crate::vm::VirtualMachine, ) -> crate::vm::ExecutionResult { let aria_file = VmGlobals::extract_arg(frame, |x: RuntimeValue| x.as_object().cloned())?; let rust_file_obj = mut_file_from_aria(&aria_file, &vm.globals)?; let rfo = rust_file_obj.file.borrow_mut(); match rfo.metadata() { Ok(m) => { frame .stack .push(RuntimeValue::Integer((m.len() as i64).into())); Ok(RunloopExit::Ok(())) } Err(e) => throw_io_error( aria_file.get_struct(), format!("Failed to flush file: {e}"), &mut vm.globals, ), } } fn attrib_byte(&self) -> u8 { FUNC_IS_METHOD } fn arity(&self) -> haxby_vm::arity::Arity { haxby_vm::arity::Arity::required(1) } fn name(&self) -> &str { "_getsize" } } #[derive(Default)] struct Flush {} impl BuiltinFunctionImpl for Flush { fn eval( &self, frame: &mut Frame, vm: &mut crate::vm::VirtualMachine, ) -> crate::vm::ExecutionResult { let aria_file = VmGlobals::extract_arg(frame, |x: RuntimeValue| x.as_object().cloned())?; let rust_file_obj = mut_file_from_aria(&aria_file, &vm.globals)?; let mut rfo = rust_file_obj.file.borrow_mut(); match rfo.flush() { Ok(_) => Ok(RunloopExit::Ok(())), Err(e) => throw_io_error( aria_file.get_struct(), format!("Failed to flush file: {e}"), &mut vm.globals, ), } } fn attrib_byte(&self) -> u8 { FUNC_IS_METHOD } fn arity(&self) -> haxby_vm::arity::Arity { haxby_vm::arity::Arity::required(1) } fn name(&self) -> &str { "_getsize" } } #[unsafe(no_mangle)] #[allow(clippy::not_unsafe_ptr_arg_deref)] pub extern "C" fn dylib_haxby_inject( vm: *mut haxby_vm::vm::VirtualMachine, module: *const RuntimeModule, ) -> LoadResult { match unsafe { (vm.as_mut(), module.as_ref()) } { (Some(vm), Some(module)) => { let file = match module.load_named_value("File") { Some(file) => file, None => { return LoadResult::error("cannot find File"); } }; let file_struct = match file.as_struct() { Some(file) => file, None => { return LoadResult::error("File is not a struct"); } }; file_struct.insert_builtin::(&mut vm.globals); file_struct.insert_builtin::(&mut vm.globals); file_struct.insert_builtin::(&mut vm.globals); file_struct.insert_builtin::(&mut vm.globals); file_struct.insert_builtin::(&mut vm.globals); file_struct.insert_builtin::(&mut vm.globals); file_struct.insert_builtin::(&mut vm.globals); file_struct.insert_builtin::(&mut vm.globals); file_struct.insert_builtin::(&mut vm.globals); LoadResult::success() } _ => LoadResult::error("invalid file module"), } } ================================================ FILE: native-libs/network/Cargo.toml ================================================ [package] name = "network-lib" version = "0.9.20251222" edition = "2024" [lib] name = "aria_http" path = "src/lib.rs" crate-type = ["cdylib"] [dependencies] vm-lib = { path = "../../vm-lib" } opcodes-lib = { path = "../../opcodes-lib" } reqwest = { version = "0.13.1", features = ["blocking"] } ================================================ FILE: native-libs/network/src/lib.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use haxby_opcodes::function_attribs::FUNC_IS_METHOD; use haxby_vm::{ error::dylib_load::LoadResult, runtime_module::RuntimeModule, runtime_value::{RuntimeValue, list::List, object::Object}, vm::ExecutionResult, }; #[derive(Default)] struct RequestGet {} impl haxby_vm::runtime_value::function::BuiltinFunctionImpl for RequestGet { fn eval( &self, frame: &mut haxby_vm::frame::Frame, vm: &mut haxby_vm::vm::VirtualMachine, ) -> haxby_vm::vm::ExecutionResult { let this = haxby_vm::builtins::VmGlobals::extract_arg(frame, |x| x.as_object().cloned())?; let headers = haxby_vm::builtins::VmGlobals::extract_arg(frame, |x| x.as_list().cloned())?; let url_sym = vm .globals .intern_symbol("url") .expect("too many symbols interned"); let timeout_sym = vm .globals .intern_symbol("timeout") .expect("too many symbols interned"); let response_sym = vm .globals .intern_symbol("Response") .expect("too many symbols interned"); let error_sym = vm .globals .intern_symbol("Error") .expect("too many symbols interned"); let status_code_sym = vm .globals .intern_symbol("status_code") .expect("too many symbols interned"); let headers_sym = vm .globals .intern_symbol("headers") .expect("too many symbols interned"); let content_sym = vm .globals .intern_symbol("content") .expect("too many symbols interned"); let msg_sym = vm .globals .intern_symbol("msg") .expect("too many symbols interned"); let this_url = this.extract_field(&vm.globals, url_sym, |field: RuntimeValue| { field.as_string().cloned() })?; let this_timeout = this.extract_field(&vm.globals, timeout_sym, |field: RuntimeValue| { field.as_float().cloned() })?; let as_struct = this.get_struct(); let this_response = as_struct.extract_field(&vm.globals, response_sym, |field: RuntimeValue| { field.as_struct().cloned() })?; let this_error = as_struct.extract_field(&vm.globals, error_sym, |field: RuntimeValue| { field.as_struct().cloned() })?; let mut client = reqwest::blocking::Client::new() .get(this_url.raw_value()) .timeout(std::time::Duration::from_secs_f64( *this_timeout.raw_value(), )); for i in 0..headers.len() { let header = headers.get_at(i).unwrap(); if let Some(list) = header.as_list() && list.len() == 2 { let key = list.get_at(0).unwrap(); let value = list.get_at(1).unwrap(); if let (Some(key), Some(value)) = (key.as_string(), value.as_string()) { client = client.header(key.raw_value(), value.raw_value()); } } } match client.send() { Ok(r) => { let response_obj = RuntimeValue::Object(Object::new(&this_response)); let _ = response_obj.write_attribute( status_code_sym, haxby_vm::runtime_value::RuntimeValue::Integer( (r.status().as_u16() as i64).into(), ), &mut vm.globals, ); let header_list = List::from(&[]); for header in r.headers() { let header_kvp = List::from(&[ RuntimeValue::String(header.0.as_str().into()), RuntimeValue::String(header.1.to_str().unwrap_or("").into()), ]); header_list.append(RuntimeValue::List(header_kvp)); } let _ = response_obj.write_attribute( headers_sym, RuntimeValue::List(header_list), &mut vm.globals, ); match r.text() { Ok(content) => { let _ = response_obj.write_attribute( content_sym, RuntimeValue::String(content.into()), &mut vm.globals, ); } _ => { let error_obj = RuntimeValue::Object(Object::new(&this_error)); let _ = error_obj.write_attribute( msg_sym, RuntimeValue::String("content is not a valid String".into()), &mut vm.globals, ); let result_err = vm.globals.create_result_err(error_obj)?; frame.stack.push(result_err); return ExecutionResult::Ok(haxby_vm::vm::RunloopExit::Ok(())); } } let result_ok = vm.globals.create_result_ok(response_obj.clone())?; frame.stack.push(result_ok); Ok(haxby_vm::vm::RunloopExit::Ok(())) } Err(e) => { let error_obj = RuntimeValue::Object(Object::new(&this_error)); let _ = error_obj.write_attribute( msg_sym, RuntimeValue::String(e.to_string().into()), &mut vm.globals, ); let result_err = vm.globals.create_result_err(error_obj)?; frame.stack.push(result_err); ExecutionResult::Ok(haxby_vm::vm::RunloopExit::Ok(())) } } } fn attrib_byte(&self) -> u8 { FUNC_IS_METHOD } fn arity(&self) -> haxby_vm::arity::Arity { haxby_vm::arity::Arity::required(2) } fn name(&self) -> &str { "_get" } } #[derive(Default)] struct RequestPost {} impl haxby_vm::runtime_value::function::BuiltinFunctionImpl for RequestPost { fn eval( &self, frame: &mut haxby_vm::frame::Frame, vm: &mut haxby_vm::vm::VirtualMachine, ) -> haxby_vm::vm::ExecutionResult { let this = haxby_vm::builtins::VmGlobals::extract_arg(frame, |x| x.as_object().cloned())?; let headers = haxby_vm::builtins::VmGlobals::extract_arg(frame, |x| x.as_list().cloned())?; let payload = haxby_vm::builtins::VmGlobals::extract_arg(frame, |x| x.as_string().cloned())?; let url_sym = vm .globals .intern_symbol("url") .expect("too many symbols interned"); let timeout_sym = vm .globals .intern_symbol("timeout") .expect("too many symbols interned"); let response_sym = vm .globals .intern_symbol("Response") .expect("too many symbols interned"); let error_sym = vm .globals .intern_symbol("Error") .expect("too many symbols interned"); let status_code_sym = vm .globals .intern_symbol("status_code") .expect("too many symbols interned"); let headers_sym = vm .globals .intern_symbol("headers") .expect("too many symbols interned"); let content_sym = vm .globals .intern_symbol("content") .expect("too many symbols interned"); let msg_sym = vm .globals .intern_symbol("msg") .expect("too many symbols interned"); let this_url = this.extract_field(&vm.globals, url_sym, |field: RuntimeValue| { field.as_string().cloned() })?; let this_timeout = this.extract_field(&vm.globals, timeout_sym, |field: RuntimeValue| { field.as_float().cloned() })?; let as_struct = this.get_struct(); let this_response = as_struct.extract_field(&vm.globals, response_sym, |field: RuntimeValue| { field.as_struct().cloned() })?; let this_error = as_struct.extract_field(&vm.globals, error_sym, |field: RuntimeValue| { field.as_struct().cloned() })?; let mut client = reqwest::blocking::Client::new() .post(this_url.raw_value()) .body(payload.raw_value().to_owned()) .timeout(std::time::Duration::from_secs_f64( *this_timeout.raw_value(), )); for i in 0..headers.len() { let header = headers.get_at(i).unwrap(); if let Some(list) = header.as_list() && list.len() == 2 { let key = list.get_at(0).unwrap(); let value = list.get_at(1).unwrap(); if let (Some(key), Some(value)) = (key.as_string(), value.as_string()) { client = client.header(key.raw_value(), value.raw_value()); } } } match client.send() { Ok(r) => { let response_obj = RuntimeValue::Object(Object::new(&this_response)); let _ = response_obj.write_attribute( status_code_sym, haxby_vm::runtime_value::RuntimeValue::Integer( (r.status().as_u16() as i64).into(), ), &mut vm.globals, ); let header_list = List::from(&[]); for header in r.headers() { let header_kvp = List::from(&[ RuntimeValue::String(header.0.as_str().into()), RuntimeValue::String(header.1.to_str().unwrap_or("").into()), ]); header_list.append(RuntimeValue::List(header_kvp)); } let _ = response_obj.write_attribute( headers_sym, RuntimeValue::List(header_list), &mut vm.globals, ); match r.text() { Ok(content) => { let _ = response_obj.write_attribute( content_sym, RuntimeValue::String(content.into()), &mut vm.globals, ); } _ => { let error_obj = RuntimeValue::Object(Object::new(&this_error)); let _ = error_obj.write_attribute( msg_sym, RuntimeValue::String("content is not a valid String".into()), &mut vm.globals, ); let result_err = vm.globals.create_result_err(error_obj)?; frame.stack.push(result_err); return ExecutionResult::Ok(haxby_vm::vm::RunloopExit::Ok(())); } } let result_ok = vm.globals.create_result_ok(response_obj.clone())?; frame.stack.push(result_ok); Ok(haxby_vm::vm::RunloopExit::Ok(())) } Err(e) => { let error_obj = RuntimeValue::Object(Object::new(&this_error)); let _ = error_obj.write_attribute( msg_sym, RuntimeValue::String(e.to_string().into()), &mut vm.globals, ); let result_err = vm.globals.create_result_err(error_obj)?; frame.stack.push(result_err); ExecutionResult::Ok(haxby_vm::vm::RunloopExit::Ok(())) } } } fn attrib_byte(&self) -> u8 { FUNC_IS_METHOD } fn arity(&self) -> haxby_vm::arity::Arity { haxby_vm::arity::Arity::required(3) } fn name(&self) -> &str { "_post" } } #[unsafe(no_mangle)] #[allow(clippy::not_unsafe_ptr_arg_deref)] pub extern "C" fn dylib_haxby_inject( vm: *mut haxby_vm::vm::VirtualMachine, module: *const RuntimeModule, ) -> LoadResult { match unsafe { (vm.as_mut(), module.as_ref()) } { (Some(vm), Some(module)) => { let request = match module.load_named_value("Request") { Some(request) => request, None => { return LoadResult::error("cannot find Request"); } }; let request = match request.as_struct() { Some(request) => request, None => { return LoadResult::error("Request is not a struct"); } }; request.insert_builtin::(&mut vm.globals); request.insert_builtin::(&mut vm.globals); LoadResult::success() } _ => LoadResult::error("invalid network module"), } } ================================================ FILE: native-libs/path/Cargo.toml ================================================ [package] name = "path-lib" version = "0.9.20251222" edition = "2024" [lib] name = "aria_path" path = "src/lib.rs" crate-type = ["cdylib"] [dependencies] glob = { version = "0.3.3" } vm-lib = { path = "../../vm-lib" } opcodes-lib = { path = "../../opcodes-lib" } ================================================ FILE: native-libs/path/src/lib.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use haxby_opcodes::function_attribs::{FUNC_IS_METHOD, METHOD_ATTRIBUTE_TYPE}; use haxby_vm::{ builtins::{ VmGlobals, native_iterator::{AriaNativeIterator, NativeIteratorImpl, create_iterator_struct}, }, error::{dylib_load::LoadResult, vm_error::VmErrorReason}, frame::Frame, runtime_module::RuntimeModule, runtime_value::{ RuntimeValue, function::BuiltinFunctionImpl, object::Object, opaque::OpaqueValue, }, symbol::Symbol, vm::{self, RunloopExit}, }; use std::{cell::RefCell, path::PathBuf, rc::Rc, time::SystemTime}; struct MutablePath { content: RefCell, } fn new_from_path>( the_struct: &haxby_vm::runtime_value::structure::Struct, the_path: P, path_sym: Symbol, builtins: &mut VmGlobals, ) -> RuntimeValue { let pb = PathBuf::from(the_path.as_ref()); let pb = MutablePath { content: RefCell::new(pb), }; let path_obj = OpaqueValue::new(pb); RuntimeValue::Object(Object::new(the_struct).with_value( builtins, path_sym, RuntimeValue::Opaque(path_obj), )) } fn create_path_result_err( path_struct: &haxby_vm::runtime_value::structure::Struct, message: String, vm: &mut vm::VirtualMachine, ) -> Result { let error_sym = vm .globals .intern_symbol("Error") .expect("too many symbols interned"); let path_error = path_struct.extract_field(&vm.globals, error_sym, |field: RuntimeValue| { field.as_struct().cloned() })?; let path_error = RuntimeValue::Object(Object::new(&path_error)); let msg_sym = vm .globals .intern_symbol("msg") .expect("too many symbols interned"); let _ = path_error.write_attribute( msg_sym, RuntimeValue::String(message.into()), &mut vm.globals, ); vm.globals.create_result_err(path_error) } fn mut_path_from_aria( aria_object: &Object, builtins: &VmGlobals, ) -> Result, VmErrorReason> { let path_sym = builtins .lookup_symbol("__path") .ok_or(VmErrorReason::UnexpectedVmState)?; let rust_obj = aria_object .read(builtins, path_sym) .ok_or(VmErrorReason::UnexpectedVmState)?; rust_obj .as_opaque_concrete::() .ok_or(VmErrorReason::UnexpectedVmState) } fn path_symbol(vm: &mut vm::VirtualMachine) -> Symbol { vm.globals .intern_symbol("__path") .expect("too many symbols interned") } #[derive(Default)] struct New {} impl BuiltinFunctionImpl for New { fn eval( &self, frame: &mut Frame, vm: &mut vm::VirtualMachine, ) -> vm::ExecutionResult { let the_struct = VmGlobals::extract_arg(frame, |x: RuntimeValue| x.as_struct().cloned())?; let the_path = VmGlobals::extract_arg(frame, |x: RuntimeValue| x.as_string().cloned())?; let path_sym = path_symbol(vm); frame.stack.push(new_from_path( &the_struct, the_path.raw_value(), path_sym, &mut vm.globals, )); Ok(RunloopExit::Ok(())) } fn attrib_byte(&self) -> u8 { FUNC_IS_METHOD | METHOD_ATTRIBUTE_TYPE } fn arity(&self) -> haxby_vm::arity::Arity { haxby_vm::arity::Arity::required(2) } fn name(&self) -> &str { "_new" } } struct PathBufAriaIterator { iter: Box>, the_struct: haxby_vm::runtime_value::structure::Struct, path_sym: Symbol, } impl AriaNativeIterator for PathBufAriaIterator { type Item = RuntimeValue; fn next(&mut self, vm: &mut crate::vm::VirtualMachine) -> Option { let next_pathbuf = self.iter.next()?; let next_runtime_val = new_from_path( &self.the_struct, next_pathbuf, self.path_sym, &mut vm.globals, ); Some(next_runtime_val) } } #[derive(Default)] struct Glob {} impl BuiltinFunctionImpl for Glob { fn eval( &self, frame: &mut Frame, vm: &mut vm::VirtualMachine, ) -> vm::ExecutionResult { let the_struct = VmGlobals::extract_arg(frame, |x: RuntimeValue| x.as_struct().cloned())?; let glob_expr = VmGlobals::extract_arg(frame, |x: RuntimeValue| x.as_string().cloned())?; let path_sym = path_symbol(vm); let val = match glob::glob(glob_expr.raw_value()) { Ok(path) => { let iterator_sym = vm .globals .intern_symbol("Iterator") .expect("too many symbols interned"); let iterator_rv = the_struct .load_named_value(&vm.globals, iterator_sym) .ok_or(VmErrorReason::UnexpectedVmState)?; let iterator_struct = iterator_rv .as_struct() .ok_or(VmErrorReason::UnexpectedVmState)?; let values = path.flatten(); let iterator = create_iterator_struct( iterator_struct, NativeIteratorImpl::new(PathBufAriaIterator { iter: Box::new(values), the_struct: the_struct.clone(), path_sym, }), &mut vm.globals, ); vm.globals.create_result_ok(iterator)? } Err(e) => create_path_result_err(&the_struct, e.to_string(), vm)?, }; frame.stack.push(val); Ok(RunloopExit::Ok(())) } fn attrib_byte(&self) -> u8 { FUNC_IS_METHOD | METHOD_ATTRIBUTE_TYPE } fn arity(&self) -> haxby_vm::arity::Arity { haxby_vm::arity::Arity::required(2) } fn name(&self) -> &str { "_glob" } } #[derive(Default)] struct Cwd {} impl BuiltinFunctionImpl for Cwd { fn eval( &self, frame: &mut Frame, vm: &mut vm::VirtualMachine, ) -> vm::ExecutionResult { let the_struct = VmGlobals::extract_arg(frame, |x: RuntimeValue| x.as_struct().cloned())?; let cwd = std::env::current_dir().map_err(|_| VmErrorReason::UnexpectedVmState)?; let path_sym = path_symbol(vm); frame .stack .push(new_from_path(&the_struct, &cwd, path_sym, &mut vm.globals)); Ok(RunloopExit::Ok(())) } fn attrib_byte(&self) -> u8 { FUNC_IS_METHOD | METHOD_ATTRIBUTE_TYPE } fn arity(&self) -> haxby_vm::arity::Arity { haxby_vm::arity::Arity::required(1) } fn name(&self) -> &str { "_cwd" } } #[derive(Default)] struct Prettyprint {} impl BuiltinFunctionImpl for Prettyprint { fn eval( &self, frame: &mut Frame, vm: &mut vm::VirtualMachine, ) -> vm::ExecutionResult { let aria_object = VmGlobals::extract_arg(frame, |x: RuntimeValue| x.as_object().cloned())?; let rust_obj = mut_path_from_aria(&aria_object, &vm.globals)?; let rfo = rust_obj.content.borrow_mut(); match rfo.as_os_str().to_str() { Some(s) => { frame.stack.push(RuntimeValue::String(s.into())); Ok(RunloopExit::Ok(())) } None => Err(VmErrorReason::UnexpectedVmState.into()), } } fn attrib_byte(&self) -> u8 { FUNC_IS_METHOD } fn arity(&self) -> haxby_vm::arity::Arity { haxby_vm::arity::Arity::required(1) } fn name(&self) -> &str { "prettyprint" } } #[derive(Default)] struct Append {} impl BuiltinFunctionImpl for Append { fn eval( &self, frame: &mut Frame, vm: &mut vm::VirtualMachine, ) -> vm::ExecutionResult { let aria_object = VmGlobals::extract_arg(frame, |x: RuntimeValue| x.as_object().cloned())?; let the_path = VmGlobals::extract_arg(frame, |x: RuntimeValue| x.as_string().cloned())?; let rust_obj = mut_path_from_aria(&aria_object, &vm.globals)?; let mut rfo = rust_obj.content.borrow_mut(); rfo.push(the_path.raw_value()); frame.stack.push(vm.globals.create_unit_object()?); Ok(RunloopExit::Ok(())) } fn attrib_byte(&self) -> u8 { FUNC_IS_METHOD } fn arity(&self) -> haxby_vm::arity::Arity { haxby_vm::arity::Arity::required(2) } fn name(&self) -> &str { "_append" } } #[derive(Default)] struct Pop {} impl BuiltinFunctionImpl for Pop { fn eval( &self, frame: &mut Frame, vm: &mut vm::VirtualMachine, ) -> vm::ExecutionResult { let aria_object = VmGlobals::extract_arg(frame, |x: RuntimeValue| x.as_object().cloned())?; let rust_obj = mut_path_from_aria(&aria_object, &vm.globals)?; let mut rfo = rust_obj.content.borrow_mut(); rfo.pop(); frame.stack.push(RuntimeValue::Object(aria_object)); Ok(RunloopExit::Ok(())) } fn attrib_byte(&self) -> u8 { FUNC_IS_METHOD } fn arity(&self) -> haxby_vm::arity::Arity { haxby_vm::arity::Arity::required(1) } fn name(&self) -> &str { "pop" } } #[derive(Default)] struct IsAbsolutePath {} impl BuiltinFunctionImpl for IsAbsolutePath { fn eval( &self, frame: &mut Frame, vm: &mut vm::VirtualMachine, ) -> vm::ExecutionResult { let aria_object = VmGlobals::extract_arg(frame, |x: RuntimeValue| x.as_object().cloned())?; let rust_obj = mut_path_from_aria(&aria_object, &vm.globals)?; let rfo = rust_obj.content.borrow_mut(); frame .stack .push(RuntimeValue::Boolean((rfo.is_absolute()).into())); Ok(RunloopExit::Ok(())) } fn attrib_byte(&self) -> u8 { FUNC_IS_METHOD } fn arity(&self) -> haxby_vm::arity::Arity { haxby_vm::arity::Arity::required(1) } fn name(&self) -> &str { "is_absolute" } } #[derive(Default)] struct Exists {} impl BuiltinFunctionImpl for Exists { fn eval( &self, frame: &mut Frame, vm: &mut vm::VirtualMachine, ) -> vm::ExecutionResult { let aria_object = VmGlobals::extract_arg(frame, |x: RuntimeValue| x.as_object().cloned())?; let rust_obj = mut_path_from_aria(&aria_object, &vm.globals)?; let rfo = rust_obj.content.borrow_mut(); frame .stack .push(RuntimeValue::Boolean((rfo.exists()).into())); Ok(RunloopExit::Ok(())) } fn attrib_byte(&self) -> u8 { FUNC_IS_METHOD } fn arity(&self) -> haxby_vm::arity::Arity { haxby_vm::arity::Arity::required(1) } fn name(&self) -> &str { "exists" } } #[derive(Default)] struct IsDirectory {} impl BuiltinFunctionImpl for IsDirectory { fn eval( &self, frame: &mut Frame, vm: &mut vm::VirtualMachine, ) -> vm::ExecutionResult { let aria_object = VmGlobals::extract_arg(frame, |x: RuntimeValue| x.as_object().cloned())?; let rust_obj = mut_path_from_aria(&aria_object, &vm.globals)?; let rfo = rust_obj.content.borrow_mut(); frame .stack .push(RuntimeValue::Boolean((rfo.is_dir()).into())); Ok(RunloopExit::Ok(())) } fn attrib_byte(&self) -> u8 { FUNC_IS_METHOD } fn arity(&self) -> haxby_vm::arity::Arity { haxby_vm::arity::Arity::required(1) } fn name(&self) -> &str { "is_directory" } } #[derive(Default)] struct IsFile {} impl BuiltinFunctionImpl for IsFile { fn eval( &self, frame: &mut Frame, vm: &mut vm::VirtualMachine, ) -> vm::ExecutionResult { let aria_object = VmGlobals::extract_arg(frame, |x: RuntimeValue| x.as_object().cloned())?; let rust_obj = mut_path_from_aria(&aria_object, &vm.globals)?; let rfo = rust_obj.content.borrow_mut(); frame .stack .push(RuntimeValue::Boolean((rfo.is_file()).into())); Ok(RunloopExit::Ok(())) } fn attrib_byte(&self) -> u8 { FUNC_IS_METHOD } fn arity(&self) -> haxby_vm::arity::Arity { haxby_vm::arity::Arity::required(1) } fn name(&self) -> &str { "is_file" } } #[derive(Default)] struct IsSymlink {} impl BuiltinFunctionImpl for IsSymlink { fn eval( &self, frame: &mut Frame, vm: &mut vm::VirtualMachine, ) -> vm::ExecutionResult { let aria_object = VmGlobals::extract_arg(frame, |x: RuntimeValue| x.as_object().cloned())?; let rust_obj = mut_path_from_aria(&aria_object, &vm.globals)?; let rfo = rust_obj.content.borrow_mut(); frame .stack .push(RuntimeValue::Boolean((rfo.is_symlink()).into())); Ok(RunloopExit::Ok(())) } fn attrib_byte(&self) -> u8 { FUNC_IS_METHOD } fn arity(&self) -> haxby_vm::arity::Arity { haxby_vm::arity::Arity::required(1) } fn name(&self) -> &str { "is_symlink" } } #[derive(Default)] struct Canonical {} impl BuiltinFunctionImpl for Canonical { fn eval( &self, frame: &mut Frame, vm: &mut vm::VirtualMachine, ) -> vm::ExecutionResult { let aria_object = VmGlobals::extract_arg(frame, |x: RuntimeValue| x.as_object().cloned())?; let path_sym = path_symbol(vm); let rust_obj = mut_path_from_aria(&aria_object, &vm.globals)?; let rfo = rust_obj.content.borrow_mut(); let val = match rfo.canonicalize() { Ok(path) => { let canonical_object = new_from_path(aria_object.get_struct(), &path, path_sym, &mut vm.globals); vm.globals.create_result_ok(canonical_object)? } Err(e) => create_path_result_err(aria_object.get_struct(), e.to_string(), vm)?, }; frame.stack.push(val); Ok(RunloopExit::Ok(())) } fn attrib_byte(&self) -> u8 { FUNC_IS_METHOD } fn arity(&self) -> haxby_vm::arity::Arity { haxby_vm::arity::Arity::required(1) } fn name(&self) -> &str { "new_canonical" } } #[derive(Default)] struct Size {} impl BuiltinFunctionImpl for Size { fn eval( &self, frame: &mut Frame, vm: &mut vm::VirtualMachine, ) -> vm::ExecutionResult { let aria_object = VmGlobals::extract_arg(frame, |x: RuntimeValue| x.as_object().cloned())?; let rust_obj = mut_path_from_aria(&aria_object, &vm.globals)?; let rfo = rust_obj.content.borrow_mut(); let val = match rfo.metadata() { Ok(md) => vm .globals .create_result_ok(RuntimeValue::Integer((md.len() as i64).into()))?, Err(e) => create_path_result_err(aria_object.get_struct(), e.to_string(), vm)?, }; frame.stack.push(val); Ok(RunloopExit::Ok(())) } fn attrib_byte(&self) -> u8 { FUNC_IS_METHOD } fn arity(&self) -> haxby_vm::arity::Arity { haxby_vm::arity::Arity::required(1) } fn name(&self) -> &str { "size" } } #[derive(Default)] struct CreatedTime {} impl BuiltinFunctionImpl for CreatedTime { fn eval( &self, frame: &mut Frame, vm: &mut vm::VirtualMachine, ) -> vm::ExecutionResult { let aria_object = VmGlobals::extract_arg(frame, |x: RuntimeValue| x.as_object().cloned())?; let rust_obj = mut_path_from_aria(&aria_object, &vm.globals)?; let rfo = rust_obj.content.borrow_mut(); let val = match rfo.metadata() { Ok(md) => match md.created() { Err(e) => create_path_result_err(aria_object.get_struct(), e.to_string(), vm)?, Ok(val) => { let val = val .duration_since(SystemTime::UNIX_EPOCH) .unwrap() .as_millis(); vm.globals .create_result_ok(RuntimeValue::Integer((val as i64).into()))? } }, Err(e) => create_path_result_err(aria_object.get_struct(), e.to_string(), vm)?, }; frame.stack.push(val); Ok(RunloopExit::Ok(())) } fn attrib_byte(&self) -> u8 { FUNC_IS_METHOD } fn arity(&self) -> haxby_vm::arity::Arity { haxby_vm::arity::Arity::required(1) } fn name(&self) -> &str { "_when_created" } } #[derive(Default)] struct AccessedTime {} impl BuiltinFunctionImpl for AccessedTime { fn eval( &self, frame: &mut Frame, vm: &mut vm::VirtualMachine, ) -> vm::ExecutionResult { let aria_object = VmGlobals::extract_arg(frame, |x: RuntimeValue| x.as_object().cloned())?; let rust_obj = mut_path_from_aria(&aria_object, &vm.globals)?; let rfo = rust_obj.content.borrow_mut(); let val = match rfo.metadata() { Ok(md) => match md.accessed() { Err(e) => create_path_result_err(aria_object.get_struct(), e.to_string(), vm)?, Ok(val) => { let val = val .duration_since(SystemTime::UNIX_EPOCH) .unwrap() .as_millis(); vm.globals .create_result_ok(RuntimeValue::Integer((val as i64).into()))? } }, Err(e) => create_path_result_err(aria_object.get_struct(), e.to_string(), vm)?, }; frame.stack.push(val); Ok(RunloopExit::Ok(())) } fn attrib_byte(&self) -> u8 { FUNC_IS_METHOD } fn arity(&self) -> haxby_vm::arity::Arity { haxby_vm::arity::Arity::required(1) } fn name(&self) -> &str { "_when_accessed" } } #[derive(Default)] struct ModifiedTime {} impl BuiltinFunctionImpl for ModifiedTime { fn eval( &self, frame: &mut Frame, vm: &mut vm::VirtualMachine, ) -> vm::ExecutionResult { let aria_object = VmGlobals::extract_arg(frame, |x: RuntimeValue| x.as_object().cloned())?; let rust_obj = mut_path_from_aria(&aria_object, &vm.globals)?; let rfo = rust_obj.content.borrow_mut(); let val = match rfo.metadata() { Ok(md) => match md.modified() { Err(e) => create_path_result_err(aria_object.get_struct(), e.to_string(), vm)?, Ok(val) => { let val = val .duration_since(SystemTime::UNIX_EPOCH) .unwrap() .as_millis(); vm.globals .create_result_ok(RuntimeValue::Integer((val as i64).into()))? } }, Err(e) => create_path_result_err(aria_object.get_struct(), e.to_string(), vm)?, }; frame.stack.push(val); Ok(RunloopExit::Ok(())) } fn attrib_byte(&self) -> u8 { FUNC_IS_METHOD } fn arity(&self) -> haxby_vm::arity::Arity { haxby_vm::arity::Arity::required(1) } fn name(&self) -> &str { "_when_modified" } } #[derive(Default)] struct Filename {} impl BuiltinFunctionImpl for Filename { fn eval( &self, frame: &mut Frame, vm: &mut vm::VirtualMachine, ) -> vm::ExecutionResult { let aria_object = VmGlobals::extract_arg(frame, |x: RuntimeValue| x.as_object().cloned())?; let rust_obj = mut_path_from_aria(&aria_object, &vm.globals)?; let rfo = rust_obj.content.borrow_mut(); match rfo.file_name() { Some(name) => { let name = name.to_str().ok_or(VmErrorReason::UnexpectedVmState)?; let val = vm .globals .create_maybe_some(RuntimeValue::String(name.into()))?; frame.stack.push(val); } None => { let val = vm.globals.create_maybe_none()?; frame.stack.push(val); } } Ok(RunloopExit::Ok(())) } fn attrib_byte(&self) -> u8 { FUNC_IS_METHOD } fn arity(&self) -> haxby_vm::arity::Arity { haxby_vm::arity::Arity::required(1) } fn name(&self) -> &str { "get_filename" } } #[derive(Default)] struct Extension {} impl BuiltinFunctionImpl for Extension { fn eval( &self, frame: &mut Frame, vm: &mut vm::VirtualMachine, ) -> vm::ExecutionResult { let aria_object = VmGlobals::extract_arg(frame, |x: RuntimeValue| x.as_object().cloned())?; let rust_obj = mut_path_from_aria(&aria_object, &vm.globals)?; let rfo = rust_obj.content.borrow_mut(); match rfo.extension() { Some(name) => { let name = name.to_str().ok_or(VmErrorReason::UnexpectedVmState)?; let val = vm .globals .create_maybe_some(RuntimeValue::String(name.into()))?; frame.stack.push(val); } None => { let val = vm.globals.create_maybe_none()?; frame.stack.push(val); } } Ok(RunloopExit::Ok(())) } fn attrib_byte(&self) -> u8 { FUNC_IS_METHOD } fn arity(&self) -> haxby_vm::arity::Arity { haxby_vm::arity::Arity::required(1) } fn name(&self) -> &str { "get_extension" } } #[derive(Default)] struct Entries {} impl BuiltinFunctionImpl for Entries { fn eval( &self, frame: &mut Frame, vm: &mut vm::VirtualMachine, ) -> vm::ExecutionResult { let aria_object = VmGlobals::extract_arg(frame, |x: RuntimeValue| x.as_object().cloned())?; let path_sym = path_symbol(vm); let aria_struct = aria_object.get_struct().clone(); let iterator_sym = vm .globals .intern_symbol("Iterator") .expect("too many symbols interned"); let iterator_struct = aria_struct.extract_field(&vm.globals, iterator_sym, |f: RuntimeValue| { f.as_struct().cloned() })?; let rust_obj = mut_path_from_aria(&aria_object, &vm.globals)?; let rfo = rust_obj.content.borrow_mut(); if let Ok(rd) = rfo.read_dir() { let values = rd.flatten().map(|e| e.path()); let iterator = create_iterator_struct( &iterator_struct, NativeIteratorImpl::new(PathBufAriaIterator { iter: Box::new(values), the_struct: aria_struct.clone(), path_sym, }), &mut vm.globals, ); frame.stack.push(iterator); } else { let iterator = create_iterator_struct( &iterator_struct, NativeIteratorImpl::empty(), &mut vm.globals, ); frame.stack.push(iterator); } Ok(RunloopExit::Ok(())) } fn attrib_byte(&self) -> u8 { FUNC_IS_METHOD } fn arity(&self) -> haxby_vm::arity::Arity { haxby_vm::arity::Arity::required(1) } fn name(&self) -> &str { "entries" } } #[derive(Default)] struct MakeDirectory {} impl BuiltinFunctionImpl for MakeDirectory { fn eval( &self, frame: &mut Frame, vm: &mut vm::VirtualMachine, ) -> vm::ExecutionResult { let aria_object = VmGlobals::extract_arg(frame, |x: RuntimeValue| x.as_object().cloned())?; let rust_obj = mut_path_from_aria(&aria_object, &vm.globals)?; let rfo = rust_obj.content.borrow_mut(); frame.stack.push(RuntimeValue::Boolean( std::fs::create_dir(rfo.as_path()).is_ok().into(), )); Ok(RunloopExit::Ok(())) } fn attrib_byte(&self) -> u8 { FUNC_IS_METHOD } fn arity(&self) -> haxby_vm::arity::Arity { haxby_vm::arity::Arity::required(1) } fn name(&self) -> &str { "mkdir" } } #[derive(Default)] struct MakeDirectories {} impl BuiltinFunctionImpl for MakeDirectories { fn eval( &self, frame: &mut Frame, vm: &mut vm::VirtualMachine, ) -> vm::ExecutionResult { let aria_object = VmGlobals::extract_arg(frame, |x: RuntimeValue| x.as_object().cloned())?; let rust_obj = mut_path_from_aria(&aria_object, &vm.globals)?; let rfo = rust_obj.content.borrow_mut(); frame.stack.push(RuntimeValue::Boolean( std::fs::create_dir_all(rfo.as_path()).is_ok().into(), )); Ok(RunloopExit::Ok(())) } fn attrib_byte(&self) -> u8 { FUNC_IS_METHOD } fn arity(&self) -> haxby_vm::arity::Arity { haxby_vm::arity::Arity::required(1) } fn name(&self) -> &str { "mkdirs" } } #[derive(Default)] struct RemoveDirectory {} impl BuiltinFunctionImpl for RemoveDirectory { fn eval( &self, frame: &mut Frame, vm: &mut vm::VirtualMachine, ) -> vm::ExecutionResult { let aria_object = VmGlobals::extract_arg(frame, |x: RuntimeValue| x.as_object().cloned())?; let rust_obj = mut_path_from_aria(&aria_object, &vm.globals)?; let rfo = rust_obj.content.borrow_mut(); frame.stack.push(RuntimeValue::Boolean( std::fs::remove_dir(rfo.as_path()).is_ok().into(), )); Ok(RunloopExit::Ok(())) } fn attrib_byte(&self) -> u8 { FUNC_IS_METHOD } fn arity(&self) -> haxby_vm::arity::Arity { haxby_vm::arity::Arity::required(1) } fn name(&self) -> &str { "rmdir" } } #[derive(Default)] struct RemoveFile {} impl BuiltinFunctionImpl for RemoveFile { fn eval( &self, frame: &mut Frame, vm: &mut vm::VirtualMachine, ) -> vm::ExecutionResult { let aria_object = VmGlobals::extract_arg(frame, |x: RuntimeValue| x.as_object().cloned())?; let rust_obj = mut_path_from_aria(&aria_object, &vm.globals)?; let rfo = rust_obj.content.borrow_mut(); frame.stack.push(RuntimeValue::Boolean( std::fs::remove_file(rfo.as_path()).is_ok().into(), )); Ok(RunloopExit::Ok(())) } fn attrib_byte(&self) -> u8 { FUNC_IS_METHOD } fn arity(&self) -> haxby_vm::arity::Arity { haxby_vm::arity::Arity::required(1) } fn name(&self) -> &str { "erase" } } #[derive(Default)] struct Copy {} impl BuiltinFunctionImpl for Copy { fn eval( &self, frame: &mut Frame, vm: &mut vm::VirtualMachine, ) -> vm::ExecutionResult { let this_path = VmGlobals::extract_arg(frame, |x: RuntimeValue| x.as_object().cloned())?; let other_path = VmGlobals::extract_arg(frame, |x: RuntimeValue| x.as_object().cloned())?; let this_path = mut_path_from_aria(&this_path, &vm.globals)?; let other_path = mut_path_from_aria(&other_path, &vm.globals)?; let this_path = this_path.content.borrow_mut(); let other_path = other_path.content.borrow_mut(); frame.stack.push(RuntimeValue::Boolean( std::fs::copy(this_path.as_path(), other_path.as_path()) .is_ok() .into(), )); Ok(RunloopExit::Ok(())) } fn attrib_byte(&self) -> u8 { FUNC_IS_METHOD } fn arity(&self) -> haxby_vm::arity::Arity { haxby_vm::arity::Arity::required(2) } fn name(&self) -> &str { "_copy" } } #[derive(Default)] struct CommonAncestor {} impl BuiltinFunctionImpl for CommonAncestor { fn eval( &self, frame: &mut Frame, vm: &mut vm::VirtualMachine, ) -> vm::ExecutionResult { let this_path = VmGlobals::extract_arg(frame, |x: RuntimeValue| x.as_object().cloned())?; let this_struct = this_path.get_struct(); let other_path = VmGlobals::extract_arg(frame, |x: RuntimeValue| x.as_object().cloned())?; let path_sym = path_symbol(vm); let this_path = mut_path_from_aria(&this_path, &vm.globals)?; let other_path = mut_path_from_aria(&other_path, &vm.globals)?; let this_path = this_path.content.borrow_mut(); let other_path = other_path.content.borrow_mut(); let val = match this_path.ancestors().find(|p| other_path.starts_with(p)) { Some(p) => { let candidate = new_from_path(this_struct, p, path_sym, &mut vm.globals); vm.globals.create_maybe_some(candidate)? } None => vm.globals.create_maybe_none()?, }; frame.stack.push(val); Ok(RunloopExit::Ok(())) } fn attrib_byte(&self) -> u8 { FUNC_IS_METHOD } fn arity(&self) -> haxby_vm::arity::Arity { haxby_vm::arity::Arity::required(2) } fn name(&self) -> &str { "common_ancestor" } } #[derive(Default)] struct Equals {} impl BuiltinFunctionImpl for Equals { fn eval( &self, frame: &mut Frame, vm: &mut vm::VirtualMachine, ) -> vm::ExecutionResult { let this_path = VmGlobals::extract_arg(frame, |x: RuntimeValue| x.as_object().cloned())?; let other_path = VmGlobals::extract_arg(frame, |x: RuntimeValue| x.as_object().cloned())?; let this_path = mut_path_from_aria(&this_path, &vm.globals)?; let other_path = mut_path_from_aria(&other_path, &vm.globals)?; let this_path = this_path.content.borrow_mut(); let other_path = other_path.content.borrow_mut(); frame .stack .push(RuntimeValue::Boolean((*this_path == *other_path).into())); Ok(RunloopExit::Ok(())) } fn attrib_byte(&self) -> u8 { FUNC_IS_METHOD } fn arity(&self) -> haxby_vm::arity::Arity { haxby_vm::arity::Arity::required(2) } fn name(&self) -> &str { "_op_impl_equals" } } #[unsafe(no_mangle)] #[allow(clippy::not_unsafe_ptr_arg_deref)] pub extern "C" fn dylib_haxby_inject( vm: *mut haxby_vm::vm::VirtualMachine, module: *const RuntimeModule, ) -> LoadResult { match unsafe { (vm.as_mut(), module.as_ref()) } { (Some(vm), Some(module)) => { let path = match module.load_named_value("Path") { Some(path) => path, None => { return LoadResult::error("cannot find Path"); } }; let path_struct = match path.as_struct() { Some(path) => path, None => { return LoadResult::error("Path is not a struct"); } }; path_struct.insert_builtin::(&mut vm.globals); path_struct.insert_builtin::(&mut vm.globals); path_struct.insert_builtin::(&mut vm.globals); path_struct.insert_builtin::(&mut vm.globals); path_struct.insert_builtin::(&mut vm.globals); path_struct.insert_builtin::(&mut vm.globals); path_struct.insert_builtin::(&mut vm.globals); path_struct.insert_builtin::(&mut vm.globals); path_struct.insert_builtin::(&mut vm.globals); path_struct.insert_builtin::(&mut vm.globals); path_struct.insert_builtin::(&mut vm.globals); path_struct.insert_builtin::(&mut vm.globals); path_struct.insert_builtin::(&mut vm.globals); path_struct.insert_builtin::(&mut vm.globals); path_struct.insert_builtin::(&mut vm.globals); path_struct.insert_builtin::(&mut vm.globals); path_struct.insert_builtin::(&mut vm.globals); path_struct.insert_builtin::(&mut vm.globals); path_struct.insert_builtin::(&mut vm.globals); path_struct.insert_builtin::(&mut vm.globals); path_struct.insert_builtin::(&mut vm.globals); path_struct.insert_builtin::(&mut vm.globals); path_struct.insert_builtin::(&mut vm.globals); path_struct.insert_builtin::(&mut vm.globals); path_struct.insert_builtin::(&mut vm.globals); path_struct.insert_builtin::(&mut vm.globals); LoadResult::success() } _ => LoadResult::error("invalid path module"), } } ================================================ FILE: native-libs/platform/Cargo.toml ================================================ [package] name = "platform-lib" version = "0.9.20251222" edition = "2024" [lib] name = "aria_platform" path = "src/lib.rs" crate-type = ["cdylib"] [dependencies] vm-lib = { path = "../../vm-lib" } opcodes-lib = { path = "../../opcodes-lib" } ================================================ FILE: native-libs/platform/src/lib.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use haxby_opcodes::function_attribs::{FUNC_IS_METHOD, METHOD_ATTRIBUTE_TYPE}; use haxby_vm::{ builtins::VmGlobals, error::dylib_load::LoadResult, frame::Frame, runtime_module::RuntimeModule, runtime_value::RuntimeValue, runtime_value::function::BuiltinFunctionImpl, vm::RunloopExit, }; #[allow(unused)] const LINUX_CASE: usize = 0; #[allow(unused)] const MACOS_CASE: usize = 1; #[allow(unused)] const UNKNOWN_CASE: usize = 2; #[derive(Default)] struct GetPlatformInfo {} impl BuiltinFunctionImpl for GetPlatformInfo { #[cfg(target_os = "linux")] fn eval( &self, frame: &mut Frame, vm: &mut haxby_vm::vm::VirtualMachine, ) -> haxby_vm::vm::ExecutionResult { use haxby_vm::{error::vm_error::VmErrorReason, runtime_value::object::Object}; let kernel_version = match std::fs::read_to_string("/proc/sys/kernel/osrelease") { Ok(ver) => ver.trim().to_string(), Err(_) => String::from("unknown"), }; let platform_enum = VmGlobals::extract_arg(frame, |x: RuntimeValue| x.as_enum().cloned())?; let linux_platform_sym = vm .globals .intern_symbol("LinuxPlatform") .expect("too many symbols interned"); let linux_info = platform_enum .load_named_value(&vm.globals, linux_platform_sym) .ok_or(VmErrorReason::UnexpectedVmState)?; let linux_info = linux_info .as_struct() .ok_or(VmErrorReason::UnexpectedVmState)?; let linux_info = RuntimeValue::Object(Object::new(linux_info)); let kernel_version_sym = vm .globals .intern_symbol("kernel_version") .expect("too many symbols interned"); let _ = linux_info.write_attribute( kernel_version_sym, RuntimeValue::String(kernel_version.into()), &mut vm.globals, ); let linux_enum_instance = platform_enum .make_value(LINUX_CASE, Some(linux_info)) .ok_or(VmErrorReason::UnexpectedVmState)?; frame .stack .push(RuntimeValue::EnumValue(linux_enum_instance)); Ok(RunloopExit::Ok(())) } #[cfg(target_os = "macos")] fn eval( &self, frame: &mut Frame, vm: &mut haxby_vm::vm::VirtualMachine, ) -> haxby_vm::vm::ExecutionResult { use haxby_vm::{error::vm_error::VmErrorReason, runtime_value::object::Object}; // Get macOS version using `sw_vers -productVersion` let mac_version = match std::process::Command::new("sw_vers") .arg("-productVersion") .output() { Ok(output) if output.status.success() => { String::from_utf8_lossy(&output.stdout).trim().to_string() } _ => String::from("unknown"), }; let platform_enum = VmGlobals::extract_arg(frame, |x: RuntimeValue| x.as_enum().cloned())?; let mac_platform_sym = vm .globals .intern_symbol("macOSPlatform") .expect("too many symbols interned"); let mac_info = platform_enum .load_named_value(&vm.globals, mac_platform_sym) .ok_or(VmErrorReason::UnexpectedVmState)?; let mac_info = mac_info .as_struct() .ok_or(VmErrorReason::UnexpectedVmState)?; let mac_info = RuntimeValue::Object(Object::new(mac_info)); let os_build_sym = vm .globals .intern_symbol("os_build") .expect("too many symbols interned"); let _ = mac_info.write_attribute( os_build_sym, RuntimeValue::String(mac_version.into()), &mut vm.globals, ); let mac_enum_instance = platform_enum .make_value(MACOS_CASE, Some(mac_info)) .ok_or(VmErrorReason::UnexpectedVmState)?; frame.stack.push(RuntimeValue::EnumValue(mac_enum_instance)); Ok(RunloopExit::Ok(())) } #[cfg(not(any(target_os = "linux", target_os = "macos")))] fn eval( &self, frame: &mut Frame, _: &mut haxby_vm::vm::VirtualMachine, ) -> haxby_vm::vm::ExecutionResult { use haxby_vm::{error::vm_error::VmErrorReason, runtime_value::object::Object}; let platform_enum = VmGlobals::extract_arg(frame, |x: RuntimeValue| x.as_enum().clone())?; let unknown_case = platform_enum .get_idx_of_case(&vm.globals, "Unknown") .ok_or(VmErrorReason::UnexpectedVmState)?; let unknown_enum_instance = platform_enum .make_value(unknown_case, None) .ok_or(VmErrorReason::UnexpectedVmState)?; frame .stack .push(RuntimeValue::EnumValue(unknown_enum_instance)); Ok(RunloopExit::Ok(())) } fn arity(&self) -> haxby_vm::arity::Arity { haxby_vm::arity::Arity::required(1) } fn attrib_byte(&self) -> u8 { FUNC_IS_METHOD | METHOD_ATTRIBUTE_TYPE } fn name(&self) -> &str { "local" } } #[unsafe(no_mangle)] #[allow(clippy::not_unsafe_ptr_arg_deref)] pub extern "C" fn dylib_haxby_inject( vm: *mut haxby_vm::vm::VirtualMachine, module: *const RuntimeModule, ) -> LoadResult { match unsafe { (vm.as_mut(), module.as_ref()) } { (Some(vm), Some(module)) => { let platform = match module.load_named_value("Platform") { Some(platform) => platform, None => { return LoadResult::error("cannot find Platform"); } }; let platform_enum = match platform.as_enum() { Some(platform) => platform, None => { return LoadResult::error("Platform is not an enum"); } }; platform_enum.insert_builtin::(&mut vm.globals); LoadResult::success() } _ => LoadResult::error("invalid platform module"), } } ================================================ FILE: native-libs/regex/Cargo.toml ================================================ [package] name = "regex-lib" version = "0.9.20251222" edition = "2024" [lib] name = "aria_regex" path = "src/lib.rs" crate-type = ["cdylib"] [dependencies] vm-lib = { path = "../../vm-lib" } opcodes-lib = { path = "../../opcodes-lib" } regex = "1.12.2" ================================================ FILE: native-libs/regex/src/lib.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use haxby_opcodes::function_attribs::{FUNC_IS_METHOD, METHOD_ATTRIBUTE_TYPE}; use haxby_vm::{ builtins::VmGlobals, error::{dylib_load::LoadResult, exception::VmException, vm_error::VmErrorReason}, frame::Frame, runtime_module::RuntimeModule, runtime_value::{ RuntimeValue, function::BuiltinFunctionImpl, list::List, object::Object, opaque::OpaqueValue, structure::Struct, }, vm::{ExecutionResult, RunloopExit, VirtualMachine}, }; fn create_regex_error( regex_struct: &Struct, message: String, builtins: &mut VmGlobals, ) -> Result { let error_sym = builtins .intern_symbol("Error") .expect("too many symbols interned"); let regex_error = regex_struct .load_named_value(builtins, error_sym) .ok_or(VmErrorReason::UnexpectedVmState)?; let regex_error = regex_error .as_struct() .ok_or(VmErrorReason::UnexpectedType)?; let regex_error = RuntimeValue::Object(Object::new(regex_error)); let msg_sym = builtins .intern_symbol("msg") .expect("too many symbols interned"); let _ = regex_error.write_attribute(msg_sym, RuntimeValue::String(message.into()), builtins); Ok(regex_error) } #[derive(Default)] struct New {} impl BuiltinFunctionImpl for New { fn eval(&self, frame: &mut Frame, vm: &mut VirtualMachine) -> ExecutionResult { let the_struct = VmGlobals::extract_arg(frame, |x: RuntimeValue| x.as_struct().cloned())?; let the_pattern = VmGlobals::extract_arg(frame, |x: RuntimeValue| x.as_string().cloned())?; let rust_regex_obj = match regex::Regex::new(the_pattern.raw_value()) { Ok(s) => s, Err(e) => { let err = create_regex_error(&the_struct, e.to_string(), &mut vm.globals); return match err { Ok(s) => Ok(RunloopExit::Exception(VmException::from_value(s))), Err(e) => Err(e.into()), }; } }; let rust_regex_obj = OpaqueValue::new(rust_regex_obj); let aria_regex_obj = RuntimeValue::Object(Object::new(&the_struct)); let pattern_impl_sym = vm .globals .intern_symbol("__pattern") .expect("too many symbols interned"); let pattern_sym = vm .globals .intern_symbol("pattern") .expect("too many symbols interned"); let _ = aria_regex_obj.write_attribute( pattern_impl_sym, RuntimeValue::Opaque(rust_regex_obj), &mut vm.globals, ); let _ = aria_regex_obj.write_attribute( pattern_sym, RuntimeValue::String(the_pattern), &mut vm.globals, ); frame.stack.push(aria_regex_obj); Ok(RunloopExit::Ok(())) } fn attrib_byte(&self) -> u8 { FUNC_IS_METHOD | METHOD_ATTRIBUTE_TYPE } fn arity(&self) -> haxby_vm::arity::Arity { haxby_vm::arity::Arity::required(2) } fn name(&self) -> &str { "new" } } #[derive(Default)] struct AnyMatch {} impl BuiltinFunctionImpl for AnyMatch { fn eval(&self, frame: &mut Frame, vm: &mut VirtualMachine) -> ExecutionResult { let aria_regex = VmGlobals::extract_arg(frame, |x: RuntimeValue| x.as_object().cloned())?; let the_haystack = VmGlobals::extract_arg(frame, |x: RuntimeValue| x.as_string().cloned())?; let pattern_sym = vm .globals .lookup_symbol("__pattern") .ok_or(VmErrorReason::UnexpectedVmState)?; let rust_regex_obj = match aria_regex.read(&vm.globals, pattern_sym) { Some(s) => s, None => return Err(VmErrorReason::UnexpectedVmState.into()), }; let rust_regex_obj = match rust_regex_obj.as_opaque_concrete::() { Some(s) => s, None => return Err(VmErrorReason::UnexpectedVmState.into()), }; let matches = rust_regex_obj.is_match(the_haystack.raw_value()); frame.stack.push(RuntimeValue::Boolean(matches.into())); Ok(RunloopExit::Ok(())) } fn attrib_byte(&self) -> u8 { FUNC_IS_METHOD } fn arity(&self) -> haxby_vm::arity::Arity { haxby_vm::arity::Arity::required(2) } fn name(&self) -> &str { "any_match" } } #[derive(Default)] struct Matches {} impl BuiltinFunctionImpl for Matches { fn eval(&self, frame: &mut Frame, vm: &mut VirtualMachine) -> ExecutionResult { let aria_regex = VmGlobals::extract_arg(frame, |x: RuntimeValue| x.as_object().cloned())?; let aria_struct = aria_regex.get_struct().clone(); let the_haystack = VmGlobals::extract_arg(frame, |x: RuntimeValue| x.as_string().cloned())?; let match_sym = vm .globals .intern_symbol("Match") .expect("too many symbols interned"); let match_struct_type = aria_struct.extract_field(&vm.globals, match_sym, |e: RuntimeValue| { e.as_struct().cloned() })?; let pattern_sym = vm .globals .lookup_symbol("__pattern") .ok_or(VmErrorReason::UnexpectedVmState)?; let rust_regex_obj = match aria_regex.read(&vm.globals, pattern_sym) { Some(s) => s, None => return Err(VmErrorReason::UnexpectedVmState.into()), }; let rust_regex_obj = match rust_regex_obj.as_opaque_concrete::() { Some(s) => s, None => return Err(VmErrorReason::UnexpectedVmState.into()), }; let matches: Vec<_> = rust_regex_obj .find_iter(the_haystack.raw_value()) .map(|mh| (mh.start() as i64, mh.len() as i64, mh.as_str())) .collect(); let matches_list = List::default(); let start_sym = vm .globals .intern_symbol("start") .expect("too many symbols interned"); let len_sym = vm .globals .intern_symbol("len") .expect("too many symbols interned"); let value_sym = vm .globals .intern_symbol("value") .expect("too many symbols interned"); for m in matches { let match_obj = RuntimeValue::Object(Object::new(&match_struct_type)); let _ = match_obj.write_attribute( start_sym, RuntimeValue::Integer(m.0.into()), &mut vm.globals, ); let _ = match_obj.write_attribute( len_sym, RuntimeValue::Integer(m.1.into()), &mut vm.globals, ); let _ = match_obj.write_attribute( value_sym, RuntimeValue::String(m.2.into()), &mut vm.globals, ); matches_list.append(match_obj); } frame.stack.push(RuntimeValue::List(matches_list)); Ok(RunloopExit::Ok(())) } fn attrib_byte(&self) -> u8 { FUNC_IS_METHOD } fn arity(&self) -> haxby_vm::arity::Arity { haxby_vm::arity::Arity::required(2) } fn name(&self) -> &str { "matches" } } #[derive(Default)] struct Replace {} impl BuiltinFunctionImpl for Replace { fn eval(&self, frame: &mut Frame, vm: &mut VirtualMachine) -> ExecutionResult { let aria_regex = VmGlobals::extract_arg(frame, |x: RuntimeValue| x.as_object().cloned())?; let the_haystack = VmGlobals::extract_arg(frame, |x: RuntimeValue| x.as_string().cloned())?; let new_value = VmGlobals::extract_arg(frame, |x: RuntimeValue| x.as_string().cloned())?; let pattern_sym = vm .globals .lookup_symbol("__pattern") .ok_or(VmErrorReason::UnexpectedVmState)?; let rust_regex_obj = match aria_regex.read(&vm.globals, pattern_sym) { Some(s) => s, None => return Err(VmErrorReason::UnexpectedVmState.into()), }; let rust_regex_obj = match rust_regex_obj.as_opaque_concrete::() { Some(s) => s, None => return Err(VmErrorReason::UnexpectedVmState.into()), }; let target = rust_regex_obj .replace_all(the_haystack.raw_value(), new_value.raw_value()) .to_string(); frame.stack.push(RuntimeValue::String(target.into())); Ok(RunloopExit::Ok(())) } fn attrib_byte(&self) -> u8 { FUNC_IS_METHOD } fn arity(&self) -> haxby_vm::arity::Arity { haxby_vm::arity::Arity::required(3) } fn name(&self) -> &str { "replace" } } #[unsafe(no_mangle)] #[allow(clippy::not_unsafe_ptr_arg_deref)] pub extern "C" fn dylib_haxby_inject( vm: *mut haxby_vm::vm::VirtualMachine, module: *const RuntimeModule, ) -> LoadResult { match unsafe { (vm.as_mut(), module.as_ref()) } { (Some(vm), Some(module)) => { let regex = match module.load_named_value("Regex") { Some(regex) => regex, None => { return LoadResult::error("cannot find Regex"); } }; let regex = match regex.as_struct() { Some(regex) => regex, None => { return LoadResult::error("Regex is not a struct"); } }; regex.insert_builtin::(&mut vm.globals); regex.insert_builtin::(&mut vm.globals); regex.insert_builtin::(&mut vm.globals); regex.insert_builtin::(&mut vm.globals); LoadResult::success() } _ => LoadResult::error("invalid regex module"), } } ================================================ FILE: native-libs/timezone/Cargo.toml ================================================ [package] name = "timezone-lib" version = "0.9.20251222" edition = "2024" [lib] name = "aria_timezone" path = "src/lib.rs" crate-type = ["cdylib"] [dependencies] vm-lib = { path = "../../vm-lib" } opcodes-lib = { path = "../../opcodes-lib" } libc = "0.2.180" ================================================ FILE: native-libs/timezone/src/lib.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use haxby_vm::{ error::dylib_load::LoadResult, runtime_module::RuntimeModule, runtime_value::{RuntimeValue, function::BuiltinFunctionImpl, list::List}, vm::RunloopExit, }; #[derive(Default)] struct TimezoneInfo {} impl BuiltinFunctionImpl for TimezoneInfo { fn eval( &self, cur_frame: &mut haxby_vm::frame::Frame, _: &mut haxby_vm::vm::VirtualMachine, ) -> haxby_vm::vm::ExecutionResult { let now = std::time::SystemTime::now() .duration_since(std::time::UNIX_EPOCH) .expect("before the epoch") .as_secs() as i64; let mut tm = libc::tm { tm_sec: 0, tm_min: 0, tm_hour: 0, tm_mday: 0, tm_mon: 0, tm_year: 0, tm_wday: 0, tm_yday: 0, tm_isdst: 0, tm_gmtoff: 0, tm_zone: std::ptr::null_mut(), }; unsafe { libc::localtime_r(&now, &mut tm); } let tm_zone_name = if tm.tm_zone.is_null() { "unknown" } else { unsafe { std::ffi::CStr::from_ptr(tm.tm_zone) .to_str() .unwrap_or("invalid") } }; let resulting_object = List::from(&[]); resulting_object.append(RuntimeValue::Integer((tm.tm_gmtoff / 60).into())); resulting_object.append(RuntimeValue::String(tm_zone_name.to_string().into())); cur_frame.stack.push(RuntimeValue::List(resulting_object)); Ok(RunloopExit::Ok(())) } fn arity(&self) -> haxby_vm::arity::Arity { haxby_vm::arity::Arity::zero() } fn name(&self) -> &str { "tz_info" } } #[unsafe(no_mangle)] #[allow(clippy::not_unsafe_ptr_arg_deref)] pub extern "C" fn dylib_haxby_inject( _: *mut haxby_vm::vm::VirtualMachine, module: *const RuntimeModule, ) -> LoadResult { match unsafe { module.as_ref() } { Some(module) => { module.insert_builtin::(); LoadResult::success() } None => LoadResult::error("invalid platform module"), } } ================================================ FILE: native-libs/unicode/Cargo.toml ================================================ [package] name = "unicode-lib" version = "0.9.20251222" edition = "2024" [lib] name = "aria_unicode" path = "src/lib.rs" crate-type = ["cdylib"] [dependencies] vm-lib = { path = "../../vm-lib" } opcodes-lib = { path = "../../opcodes-lib" } libc = "0.2.180" unicode_categories = "0.1.1" ================================================ FILE: native-libs/unicode/src/lib.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use haxby_opcodes::BuiltinTypeId; use haxby_vm::{ builtins::VmGlobals, error::{dylib_load::LoadResult, vm_error::VmErrorReason}, runtime_module::RuntimeModule, runtime_value::{RuntimeValue, function::BuiltinFunctionImpl}, vm::RunloopExit, }; use unicode_categories::UnicodeCategories; trait CharFunctionImpl { fn do_check(c: char) -> bool; fn name() -> &'static str; } macro_rules! make_char_fn { ($name:ident, $method:ident) => { #[allow(non_camel_case_types)] #[derive(Default)] struct $name {} impl CharFunctionImpl for $name { fn do_check(c: char) -> bool { c.$method() } fn name() -> &'static str { stringify!($name) } } }; } make_char_fn!(is_lowercase_letter, is_letter_lowercase); make_char_fn!(is_uppercase_letter, is_letter_uppercase); make_char_fn!(is_digit, is_number); make_char_fn!(is_whitespace, is_whitespace); struct CharBuiltinFunction { _marker: std::marker::PhantomData, } impl Default for CharBuiltinFunction { fn default() -> Self { Self { _marker: std::marker::PhantomData, } } } impl BuiltinFunctionImpl for CharBuiltinFunction { fn eval( &self, cur_frame: &mut haxby_vm::frame::Frame, _: &mut haxby_vm::vm::VirtualMachine, ) -> haxby_vm::vm::ExecutionResult { let this = VmGlobals::extract_arg(cur_frame, |x: RuntimeValue| x.as_string().cloned())?; let this_raw = this.raw_value(); if let Some(char0) = this_raw.chars().next() { let is = T::do_check(char0); cur_frame.stack.push(RuntimeValue::Boolean(is.into())); Ok(RunloopExit::Ok(())) } else { Err(VmErrorReason::IndexOutOfBounds(0).into()) } } fn arity(&self) -> haxby_vm::arity::Arity { haxby_vm::arity::Arity::required(1) } fn name(&self) -> &str { T::name() } } #[unsafe(no_mangle)] #[allow(clippy::not_unsafe_ptr_arg_deref)] pub extern "C" fn dylib_haxby_inject( vm: *mut haxby_vm::vm::VirtualMachine, module: *const RuntimeModule, ) -> LoadResult { // the aria module isn't really useful here since it's just a placeholder to inject methods // into the String builtin type, but I'd rather be safe here and check that it's also a valid // module, not just a valid VM instance if let (Some(vm), Some(_)) = unsafe { (vm.as_mut(), module.as_ref()) } && let Some(string) = vm .globals .get_builtin_type_by_id(BuiltinTypeId::String) .as_rust_native() { string.insert_builtin::>(&mut vm.globals); string.insert_builtin::>(&mut vm.globals); string.insert_builtin::>(&mut vm.globals); string.insert_builtin::>(&mut vm.globals); return LoadResult::success(); } LoadResult::error("cannot inject class methods into String builtin") } ================================================ FILE: opcodes-lib/Cargo.toml ================================================ [package] name = "opcodes-lib" version = "0.9.20251222" edition = "2024" [lib] name = "haxby_opcodes" path = "src/lib.rs" [dependencies] enum-as-inner = "0.7.0" ================================================ FILE: opcodes-lib/src/lib.rs ================================================ // SPDX-License-Identifier: Apache-2.0 pub const OPCODE_NOP: u8 = 0; pub const OPCODE_PUSH: u8 = 1; pub const OPCODE_PUSH_0: u8 = 2; pub const OPCODE_PUSH_1: u8 = 3; pub const OPCODE_PUSH_TRUE: u8 = 4; pub const OPCODE_PUSH_FALSE: u8 = 5; pub const OPCODE_PUSH_BUILTIN_TYPE: u8 = 6; pub const OPCODE_PUSH_RUNTIME_VALUE: u8 = 7; pub const OPCODE_POP: u8 = 8; pub const OPCODE_DUP: u8 = 9; pub const OPCODE_SWAP: u8 = 10; pub const OPCODE_COPY: u8 = 11; // .. pub const OPCODE_ADD: u8 = 20; pub const OPCODE_SUB: u8 = 21; pub const OPCODE_MUL: u8 = 22; pub const OPCODE_DIV: u8 = 23; pub const OPCODE_REM: u8 = 24; pub const OPCODE_NEG: u8 = 25; pub const OPCODE_SHL: u8 = 26; pub const OPCODE_SHR: u8 = 27; // ... pub const OPCODE_READ_LOCAL: u8 = 30; pub const OPCODE_WRITE_LOCAL: u8 = 31; pub const OPCODE_TYPEDEF_LOCAL: u8 = 32; pub const OPCODE_READ_NAMED: u8 = 33; pub const OPCODE_WRITE_NAMED: u8 = 34; pub const OPCODE_TYPEDEF_NAMED: u8 = 35; pub const OPCODE_READ_INDEX: u8 = 36; pub const OPCODE_WRITE_INDEX: u8 = 37; pub const OPCODE_READ_ATTRIBUTE: u8 = 38; pub const OPCODE_WRITE_ATTRIBUTE: u8 = 39; pub const OPCODE_READ_UPLEVEL: u8 = 40; // ... pub const OPCODE_EQ: u8 = 50; pub const OPCODE_LT: u8 = 51; pub const OPCODE_GT: u8 = 52; pub const OPCODE_LTE: u8 = 53; pub const OPCODE_GTE: u8 = 54; pub const OPCODE_ISA: u8 = 55; pub const OPCODE_LOGICAL_AND: u8 = 56; pub const OPCODE_LOGICAL_OR: u8 = 57; pub const OPCODE_XOR: u8 = 58; pub const OPCODE_NOT: u8 = 59; pub const OPCODE_BITWISE_AND: u8 = 60; pub const OPCODE_BITWISE_OR: u8 = 61; pub const OPCODE_JUMP: u8 = 62; pub const OPCODE_JUMP_TRUE: u8 = 63; pub const OPCODE_JUMP_FALSE: u8 = 64; pub const OPCODE_JUMP_CONDITIONALLY: u8 = 65; pub const OPCODE_JUMP_IF_ARG_SUPPLIED: u8 = 66; // ... pub const OPCODE_TRY_ENTER: u8 = 72; pub const OPCODE_TRY_EXIT: u8 = 73; pub const OPCODE_THROW: u8 = 74; pub const OPCODE_CALL: u8 = 75; pub const OPCODE_RETURN: u8 = 76; pub const OPCODE_RETURN_UNIT: u8 = 77; // ... pub const OPCODE_BUILD_LIST: u8 = 80; pub const OPCODE_BUILD_FUNCTION: u8 = 81; pub const OPCODE_STORE_UPLEVEL: u8 = 82; pub const OPCODE_BUILD_STRUCT: u8 = 83; pub const OPCODE_BUILD_ENUM: u8 = 84; pub const OPCODE_BUILD_MIXIN: u8 = 85; pub const OPCODE_BIND_CASE: u8 = 87; pub const OPCODE_INCLUDE_MIXIN: u8 = 88; pub const OPCODE_NEW_ENUM_VAL: u8 = 89; pub const OPCODE_ENUM_CHECK_IS_CASE: u8 = 90; pub const OPCODE_ENUM_TRY_EXTRACT_PAYLOAD: u8 = 91; pub const OPCODE_TRY_UNWRAP_PROTOCOL: u8 = 92; // .. pub const OPCODE_READ_ATTRIBUTE_SYMBOL: u8 = 100; pub const OPCODE_WRITE_ATTRIBUTE_SYMBOL: u8 = 101; pub const OPCODE_NEW_ENUM_VAL_SYMBOL: u8 = 102; pub const OPCODE_ENUM_CHECK_IS_CASE_SYMBOL: u8 = 103; pub const OPCODE_BIND_CASE_SYMBOL: u8 = 104; // ... pub const OPCODE_IMPORT: u8 = 250; pub const OPCODE_LIFT_MODULE: u8 = 251; pub const OPCODE_LOAD_DYLIB: u8 = 252; pub const OPCODE_ASSERT: u8 = 253; pub const OPCODE_HALT: u8 = 254; #[rustfmt::skip] pub mod function_attribs { pub const FUNC_IS_METHOD: u8 = 1_u8 << 0; pub const METHOD_ATTRIBUTE_TYPE: u8 = 1_u8 << 1; pub const FUNC_ACCEPTS_VARARG: u8 = 1_u8 << 2; } #[allow(unused_imports)] use function_attribs::*; #[repr(u8)] #[derive(Clone, Copy, PartialEq, Eq, enum_as_inner::EnumAsInner)] pub enum BuiltinValueId { ThisModule = 0, } impl BuiltinValueId { pub fn to_u8(&self) -> u8 { *self as u8 } pub fn name(&self) -> &'static str { match self { BuiltinValueId::ThisModule => "ThisModule", } } } impl TryFrom for BuiltinValueId { type Error = (); fn try_from(value: u8) -> Result { match value { 0 => Ok(BuiltinValueId::ThisModule), _ => Err(()), } } } #[repr(u8)] #[derive(Clone, Copy, PartialEq, Eq, enum_as_inner::EnumAsInner)] pub enum BuiltinTypeId { Any = 0, Module = 1, Unit = 2, Unimplemented = 3, Maybe = 4, Result = 5, Int = 6, String = 7, RuntimeError = 8, Bool = 9, Float = 10, List = 11, Type = 12, } impl BuiltinTypeId { pub fn to_u8(&self) -> u8 { *self as u8 } pub fn last() -> Self { BuiltinTypeId::Type } pub fn name(&self) -> &'static str { match self { BuiltinTypeId::Any => "Any", BuiltinTypeId::Module => "Module", BuiltinTypeId::Int => "Int", BuiltinTypeId::List => "List", BuiltinTypeId::String => "String", BuiltinTypeId::Bool => "Bool", BuiltinTypeId::Maybe => "Maybe", BuiltinTypeId::Float => "Float", BuiltinTypeId::Unimplemented => "Unimplemented", BuiltinTypeId::RuntimeError => "RuntimeError", BuiltinTypeId::Unit => "Unit", BuiltinTypeId::Result => "Result", BuiltinTypeId::Type => "Type", } } } impl TryFrom for BuiltinTypeId { type Error = (); fn try_from(value: u8) -> Result { match value { 0 => Ok(BuiltinTypeId::Any), 1 => Ok(BuiltinTypeId::Module), 2 => Ok(BuiltinTypeId::Unit), 3 => Ok(BuiltinTypeId::Unimplemented), 4 => Ok(BuiltinTypeId::Maybe), 5 => Ok(BuiltinTypeId::Result), 6 => Ok(BuiltinTypeId::Int), 7 => Ok(BuiltinTypeId::String), 8 => Ok(BuiltinTypeId::RuntimeError), 9 => Ok(BuiltinTypeId::Bool), 10 => Ok(BuiltinTypeId::Float), 11 => Ok(BuiltinTypeId::List), 12 => Ok(BuiltinTypeId::Type), _ => Err(()), } } } #[rustfmt::skip] pub mod enum_case_attribs { pub const CASE_HAS_PAYLOAD: u8 = 1_u8 << 0; } #[allow(unused_imports)] use enum_case_attribs::*; #[rustfmt::skip] pub mod try_unwrap_protocol_mode { pub const PROPAGATE_ERROR: u8 = 1; pub const ASSERT_ERROR: u8 = 2; pub const FLAG_TO_CALLER: u8 = 3; } #[allow(unused_imports)] use try_unwrap_protocol_mode::*; #[derive(Clone, Copy)] pub enum Opcode { Nop, Push(u16), Push0, Push1, PushTrue, PushFalse, PushBuiltinTy(BuiltinTypeId), PushRuntimeValue(BuiltinValueId), Pop, Dup, Swap, Copy(u8), Add, Sub, Mul, Div, Rem, Neg, ShiftLeft, ShiftRight, Not, Equal, LessThan, GreaterThan, LessThanEqual, GreaterThanEqual, ReadLocal(u8), WriteLocal(u8), TypedefLocal(u8), ReadNamed(u16), WriteNamed(u16), TypedefNamed(u16), ReadIndex(u8), WriteIndex(u8), ReadAttribute(u16), WriteAttribute(u16), ReadAttributeSymbol(u32), WriteAttributeSymbol(u32), ReadUplevel(u8), LogicalAnd, LogicalOr, Xor, BitwiseAnd, BitwiseOr, JumpTrue(u16), JumpFalse(u16), Jump(u16), JumpConditionally(u16, u16), JumpIfArgSupplied(u8, u16), Call(u8), Return, ReturnUnit, TryEnter(u16), TryExit, Throw, BuildList(u32), BuildFunction, StoreUplevel(u8), BuildStruct, BuildEnum, BuildMixin, BindCase(u8, u16), BindCaseSymbol(u8, u32), IncludeMixin, NewEnumVal(u8, u16), NewEnumValSymbol(u8, u32), EnumCheckIsCase(u16), EnumCheckIsCaseSymbol(u32), EnumTryExtractPayload, TryUnwrapProtocol(u8), Isa, Import(u16), LiftModule, LoadDylib(u16), Assert(u16), Halt, } impl std::fmt::Display for Opcode { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { Self::Nop => write!(f, "NOP"), Self::Push(arg0) => write!(f, "PUSH @{arg0}"), Self::Push0 => write!(f, "PUSH_0"), Self::Push1 => write!(f, "PUSH_1"), Self::PushTrue => write!(f, "PUSH_T"), Self::PushFalse => write!(f, "PUSH_F"), Self::PushBuiltinTy(arg0) => write!(f, "PUSH_BUILTIN_TY {}", arg0.name()), Self::PushRuntimeValue(arg0) => write!(f, "PUSH_RUNTIME_VAL {}", arg0.name()), Self::Pop => write!(f, "POP"), Self::Dup => write!(f, "DUP"), Self::Swap => write!(f, "SWAP"), Self::Copy(n) => write!(f, "COPY -{n}"), Self::Add => write!(f, "ADD"), Self::Sub => write!(f, "SUB"), Self::Mul => write!(f, "MUL"), Self::Div => write!(f, "DIV"), Self::Rem => write!(f, "REM"), Self::Equal => write!(f, "EQ"), Self::Neg => write!(f, "NEG"), Self::ShiftLeft => write!(f, "SHL"), Self::ShiftRight => write!(f, "SHR"), Self::Not => write!(f, "NOT"), Self::ReadLocal(arg0) => write!(f, "READ_LOCAL {arg0}"), Self::WriteLocal(arg0) => write!(f, "WRITE_LOCAL {arg0}"), Self::TypedefLocal(arg0) => write!(f, "TYPEDEF_LOCAL {arg0}"), Self::ReadNamed(arg0) => write!(f, "READ_NAMED @{arg0}"), Self::WriteNamed(arg0) => write!(f, "WRITE_NAMED @{arg0}"), Self::TypedefNamed(arg0) => write!(f, "TYPEDEF_NAMED @{arg0}"), Self::ReadIndex(arg0) => write!(f, "READ_INDEX {arg0}"), Self::WriteIndex(arg0) => write!(f, "WRITE_INDEX {arg0}"), Self::ReadAttribute(arg0) => write!(f, "READ_ATTRIB @{arg0}"), Self::WriteAttribute(arg0) => write!(f, "WRITE_ATTRIB @{arg0}"), Self::ReadAttributeSymbol(arg0) => write!(f, "READ_ATTRIB_SYM #{arg0}"), Self::WriteAttributeSymbol(arg0) => write!(f, "WRITE_ATTRIB_SYM #{arg0}"), Self::ReadUplevel(arg0) => write!(f, "READ_UPLEVEL {arg0}"), Self::LogicalAnd => write!(f, "ANDL"), Self::LogicalOr => write!(f, "ORL"), Self::Xor => write!(f, "XOR"), Self::BitwiseAnd => write!(f, "ANDB"), Self::BitwiseOr => write!(f, "ORB"), Self::LessThan => write!(f, "LT"), Self::GreaterThan => write!(f, "GT"), Self::LessThanEqual => write!(f, "LTE"), Self::GreaterThanEqual => write!(f, "GTE"), Self::JumpTrue(arg0) => write!(f, "JUMP_TRUE {arg0}"), Self::JumpFalse(arg0) => write!(f, "JUMP_FALSE {arg0}"), Self::Jump(arg0) => write!(f, "JUMP {arg0}"), Self::JumpConditionally(arg0, arg1) => write!(f, "JUMP_CONDITIONALLY {arg0} {arg1}"), Self::JumpIfArgSupplied(arg0, arg1) => write!(f, "JUMP_IF_ARG_SUPPLIED {arg0} {arg1}"), Self::Call(arg0) => write!(f, "CALL {arg0}"), Self::Return => write!(f, "RETURN"), Self::ReturnUnit => write!(f, "RETURN_UNIT"), Self::TryEnter(arg0) => write!(f, "ENTER_TRY {arg0}"), Self::TryExit => write!(f, "EXIT_TRY"), Self::Throw => write!(f, "THROW"), Self::BuildList(arg0) => write!(f, "BUILD_LIST {arg0}"), Self::BuildFunction => write!(f, "BUILD_FUNC"), Self::StoreUplevel(arg0) => write!(f, "STORE_UPLEVEL {arg0}"), Self::BuildStruct => write!(f, "BUILD_STRUCT"), Self::BuildEnum => write!(f, "BUILD_ENUM"), Self::BuildMixin => write!(f, "BUILD_MIXIN"), Self::BindCase(arg0, arg1) => write!(f, "BIND_CASE {arg0} @{arg1}"), Self::BindCaseSymbol(arg0, arg1) => write!(f, "BIND_CASE_SYM {arg0} #{arg1}"), Self::IncludeMixin => write!(f, "INCLUDE_MIXIN"), Self::NewEnumVal(arg0, arg1) => write!(f, "NEW_ENUM_VAL {arg0} @{arg1}"), Self::NewEnumValSymbol(arg0, arg1) => write!(f, "NEW_ENUM_VAL_SYM {arg0} #{arg1}"), Self::EnumCheckIsCase(arg0) => write!(f, "ENUM_CHECK_IS_CASE @{arg0}"), Self::EnumCheckIsCaseSymbol(arg0) => write!(f, "ENUM_CHECK_IS_CASE_SYM #{arg0}"), Self::EnumTryExtractPayload => write!(f, "ENUM_TRY_EXTRACT_PAYLOAD"), Self::TryUnwrapProtocol(mode) => write!(f, "TRY_UNWRAP_PROTOCOL {mode}"), Self::Isa => write!(f, "ISA"), Self::Import(arg0) => write!(f, "IMPORT @{arg0}"), Self::LiftModule => write!(f, "LIFT_MODULE"), Self::LoadDylib(arg0) => write!(f, "LOAD_DYLIB @{arg0}"), Self::Assert(arg0) => write!(f, "ASSERT @{arg0}"), Self::Halt => write!(f, "HALT"), } } } ================================================ FILE: package.sh ================================================ set -euo pipefail PROFILE=${PROFILE:-dist} # The authoritative copy of these variables is in .github/workflows/release.yml BIN_TARGETS="${BIN_TARGETS:-aria}" DYLIB_CRATES="${DYLIB_CRATES:-aria_file aria_http aria_path aria_platform aria_regex aria_timezone}" EXTRA_FILES="${EXTRA_FILES:-}" NAME="aria" VER=`awk '/^\[package\]/{p=1;next} /^\[/{p=0} p && $1=="version" { if (match($0, /"[^"]+"/)) { v=substr($0, RSTART+1, RLENGTH-2) # strip quotes print v exit } }' aria-bin/Cargo.toml` TS="$(date -u +%Y%m%d%H%M%S)" RUNOS="${RUNNER_OS:-$(uname -s)}" HOST_TRIPLE="$(rustc -vV | sed -n 's/^host: //p')" LIB_PREFIX="lib" LIB_EXT="so" case "$RUNOS" in macOS|Darwin) LIB_PREFIX="lib"; LIB_EXT="dylib" ;; Linux) LIB_PREFIX="lib"; LIB_EXT="so" ;; esac cargo build --workspace --profile "$PROFILE" ARIA_BUILD_CONFIG=${PROFILE} ./ci_tests.sh STAGING_ROOT="$(mktemp -d)" trap 'rm -rf "$STAGING_ROOT"' EXIT ARCHIVE_DIR="${NAME}-${VER}-${HOST_TRIPLE}" DEST="$STAGING_ROOT/$ARCHIVE_DIR" if [[ -n "$BIN_TARGETS" ]]; then for b in $BIN_TARGETS; do src="target/${PROFILE}/${b}" [[ -f "$src" ]] || { echo "Missing binary: $src" >&2; exit 2; } mkdir -p "$DEST/bin" cp -v "$src" "$DEST/bin/" done else echo "No binaries specified to be copied" >&2; exit 2; fi if [[ -n "$DYLIB_CRATES" ]]; then for c in $DYLIB_CRATES; do libname="${LIB_PREFIX}${c}.${LIB_EXT}" src="target/${PROFILE}/${libname}" [[ -f "$src" ]] || { echo "Missing cdylib: $src" >&2; exit 3; } mkdir -p "$DEST/bin" cp -v "$src" "$DEST/bin/" done fi [[ -d lib ]] && mkdir -p "$DEST/lib" && cp -a lib/. "$DEST/lib/" [[ -d examples ]] && mkdir -p "$DEST/share/examples" && cp -a examples/. "$DEST/share/examples" [[ -f docs/manual.md ]] && mkdir -p "$DEST/share/docs" && cp -a docs/manual.md "$DEST/share/docs" [[ -f docs/stdlib.md ]] && mkdir -p "$DEST/share/docs" && cp -a docs/stdlib.md "$DEST/share/docs" [[ -f docs/style_guide.md ]] && mkdir -p "$DEST/share/docs" && cp -a docs/style_guide.md "$DEST/share/docs" if [[ -n "$EXTRA_FILES" ]]; then shopt -s nullglob dotglob for f in $EXTRA_FILES; do mkdir -p "$DEST/bin" "$DEST/lib" "$DEST/share" [[ -e "$f" ]] || { echo "Skipping missing: $f" >&2; continue; } cp -av "$f" "$DEST/share/" done shopt -u nullglob dotglob fi ARCHIVE="${ARCHIVE_DIR}-${TS}.tgz" tar -C "$STAGING_ROOT" -czf "$ARCHIVE" "$ARCHIVE_DIR" if command -v sha256sum >/dev/null 2>&1; then sha256sum "$ARCHIVE" > "${ARCHIVE}.sha256" elif command -v shasum >/dev/null 2>&1; then shasum -a 256 "$ARCHIVE" > "${ARCHIVE}.sha256" elif command -v certutil >/dev/null 2>&1; then certutil -hashfile "$ARCHIVE" SHA256 | sed -n '1p' > "${ARCHIVE}.sha256" fi echo "Built: $ARCHIVE" ================================================ FILE: parser-lib/Cargo.toml ================================================ [package] name = "parser-lib" version = "0.9.20251222" edition = "2024" [lib] name = "aria_parser" path = "src/lib.rs" [dependencies] pest = "2.8.5" pest_derive = "2.8.5" ================================================ FILE: parser-lib/src/ast/derive/mod.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use crate::grammar::Rule; use super::SourceBuffer; pub(super) trait Derive { fn from_parse_tree(p: pest::iterators::Pair<'_, Rule>, source: &SourceBuffer) -> Self where Self: Sized; } #[macro_export] macro_rules! gen_from_components { ( $rule:ident; $( $field:ident : $ty:ty ),* $(,)? ) => { fn from_parse_tree(p: pest::iterators::Pair<'_, $crate::grammar::Rule>, source: &$crate::ast::SourceBuffer) -> Self { assert!(p.as_rule() == $crate::grammar::Rule::$rule); let loc = From::from(&p.as_span()); let mut inner = p.into_inner(); $( let $field = <$ty>::from_parse_tree( inner.next().expect(concat!("need ", stringify!($field))), source ); )* Self { loc: source.pointer(loc), $( $field, )* } } } } #[macro_export] macro_rules! gen_from_options { ($rule:ident; $(($variant_rule:ident, $variant_type:ident)),* $(,)?) => { fn from_parse_tree(p: pest::iterators::Pair<'_, $crate::grammar::Rule>, source: &$crate::ast::SourceBuffer) -> Self { assert!(p.as_rule() == $crate::grammar::Rule::$rule); let mut inner = p.into_inner(); let next = inner.next().expect("need content"); match next.as_rule() { $($crate::grammar::Rule::$variant_rule => { Self::$variant_type($variant_type::from_parse_tree(next, source)) }),* _ => panic!("invalid node"), } } } } ================================================ FILE: parser-lib/src/ast/mod.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use std::{fmt::Display, path::Path, rc::Rc}; use pest::{Parser, error::InputLocation}; use crate::grammar::{HaxbyParser, Rule}; mod derive; mod nodes; pub mod prettyprint; #[derive(Debug, Clone, PartialEq, Eq, Copy)] pub struct Location { pub start: usize, pub stop: usize, } #[derive(Debug, Clone, PartialEq, Eq)] pub struct SourceBuffer { pub content: Rc, pub name: String, } impl AsRef for SourceBuffer { fn as_ref(&self) -> &str { self.content.as_ref() } } impl SourceBuffer { pub fn stdin(input: &str) -> Self { Self { content: Rc::new(input.to_owned()), name: String::from(""), } } pub fn stdin_with_name(input: &str, name: &str) -> Self { Self { content: Rc::new(input.to_owned()), name: String::from(name), } } pub fn from_path(path: &Path) -> Result { let content = std::fs::read_to_string(path)?; let path = match std::fs::canonicalize(path) { Ok(cp) => cp.to_str().unwrap_or("").to_owned(), Err(_) => "".to_owned(), }; Ok(Self { content: Rc::new(content), name: path, }) } pub fn file(path: &str) -> Result { let content = std::fs::read_to_string(path)?; let path = match std::fs::canonicalize(path) { Ok(cp) => match cp.to_str() { Some(cps) => cps, None => path, } .to_owned(), Err(_) => path.to_owned(), }; Ok(Self { content: Rc::new(content), name: path, }) } pub fn as_str(&self) -> String { self.content.as_ref().to_owned() } pub fn pointer(&self, loc: Location) -> SourcePointer { SourcePointer { location: loc, buffer: self.clone(), } } } impl SourceBuffer { pub fn lines(&self) -> Vec { self.content.lines().map(|x| x.to_owned()).collect() } pub fn indices_for_position(&self, pos: usize) -> (usize, usize) { let start = self.content[..pos].rfind('\n').map_or(0, |idx| idx + 1); let end = self.content[pos..] .find('\n') .map_or(self.content.len(), |idx| pos + idx); (start, end) } pub fn line_for_position(&self, pos: usize) -> String { let (start, end) = self.indices_for_position(pos); self.content[start..end].to_owned() } pub fn line_index_for_position(&self, pos: usize) -> usize { self.content[..pos].chars().filter(|&c| c == '\n').count() } pub fn pointer_to_whole_buffer(&self) -> SourcePointer { let start = 0; let stop = self.content.len(); let loc = Location { start, stop }; self.pointer(loc) } pub fn pointer_to_last_line(&self) -> SourcePointer { let (start, stop) = self.indices_for_position(self.content.len() - 1); let loc = Location { start, stop }; self.pointer(loc) } } #[derive(Debug, Clone, PartialEq, Eq)] pub struct SourcePointer { pub location: Location, pub buffer: SourceBuffer, } impl Display for SourcePointer { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!( f, "{}:{}", self.buffer.name, 1 + self.buffer.line_index_for_position(self.location.start) ) } } impl<'i> From<&pest::Span<'i>> for Location { fn from(value: &pest::Span<'i>) -> Self { Self { start: value.start(), stop: value.end(), } } } impl From<&InputLocation> for Location { fn from(value: &InputLocation) -> Self { match value { InputLocation::Pos(pos) => Location { start: *pos, stop: *pos, }, InputLocation::Span(span) => Location { start: span.0, stop: span.1, }, } } } #[derive(Debug, Clone, PartialEq, Eq)] pub enum IntLiteralBase { Binary, Octal, Decimal, Hexadecimal, } #[derive(Debug, Clone, PartialEq, Eq)] pub struct IntLiteral { pub loc: SourcePointer, pub base: IntLiteralBase, pub val: String, } #[derive(Debug, Clone, PartialEq, Eq)] pub struct FloatLiteral { pub loc: SourcePointer, pub val: String, } #[derive(Debug, Clone, PartialEq, Eq)] pub struct StringLiteral { pub loc: SourcePointer, pub value: String, } #[derive(Debug, Clone, PartialEq, Eq)] pub struct Identifier { pub loc: SourcePointer, pub value: String, } #[derive(Debug, Clone, PartialEq, Eq)] pub struct IdentifierList { pub loc: SourcePointer, pub identifiers: Vec, } impl IdentifierList { pub fn empty(loc: SourcePointer) -> Self { Self { loc, identifiers: vec![], } } } #[derive(Debug, Clone, PartialEq, Eq)] pub struct ExpressionList { pub loc: SourcePointer, pub expressions: Vec, } impl ExpressionList { pub fn empty(loc: SourcePointer) -> Self { Self { loc, expressions: vec![], } } } #[derive(Debug, Clone, PartialEq, Eq)] pub struct ListLiteral { pub loc: SourcePointer, pub items: ExpressionList, } #[derive(Debug, Clone, PartialEq, Eq)] pub struct ParenExpression { pub loc: SourcePointer, pub value: Box, } impl From<&Expression> for ParenExpression { fn from(value: &Expression) -> Self { Self { loc: value.loc().clone(), value: Box::new(value.clone()), } } } #[derive(Debug, Clone, PartialEq, Eq)] pub enum Primary { IntLiteral(IntLiteral), FloatLiteral(FloatLiteral), Identifier(Identifier), ListLiteral(ListLiteral), StringLiteral(StringLiteral), ParenExpression(ParenExpression), } impl Primary { pub fn loc(&self) -> &SourcePointer { match self { Self::IntLiteral(il) => &il.loc, Self::FloatLiteral(fp) => &fp.loc, Self::Identifier(id) => &id.loc, Self::ListLiteral(ll) => &ll.loc, Self::StringLiteral(sl) => &sl.loc, Self::ParenExpression(pe) => &pe.loc, } } pub fn is_int_literal(&self) -> bool { matches!(self, Self::IntLiteral(_)) } pub fn is_float_literal(&self) -> bool { matches!(self, Self::FloatLiteral(_)) } pub fn as_int_literal(&self) -> Option<&IntLiteral> { if let Self::IntLiteral(il) = self { Some(il) } else { None } } pub fn as_float_literal(&self) -> Option<&FloatLiteral> { if let Self::FloatLiteral(fl) = self { Some(fl) } else { None } } } #[derive(Debug, Clone, PartialEq, Eq)] pub struct PostfixTermAttribute { pub loc: SourcePointer, pub id: Identifier, } #[derive(Debug, Clone, PartialEq, Eq)] pub struct PostfixTermIndex { pub loc: SourcePointer, pub index: ExpressionList, } #[derive(Debug, Clone, PartialEq, Eq)] pub struct PostfixTermCall { pub loc: SourcePointer, pub args: ExpressionList, } #[derive(Debug, Clone, PartialEq, Eq)] pub struct PostfixTermEnumCase { pub loc: SourcePointer, pub id: Identifier, pub payload: Option, } #[derive(Debug, Clone, PartialEq, Eq)] pub struct PostfixTermFieldWrite { pub loc: SourcePointer, pub id: Identifier, pub val: Option, } #[derive(Debug, Clone, PartialEq, Eq)] pub struct PostfixTermIndexWrite { pub loc: SourcePointer, pub idx: ExpressionList, pub val: Expression, } #[allow(clippy::large_enum_variant)] #[derive(Debug, Clone, PartialEq, Eq)] pub enum PostfixTermWrite { PostfixTermFieldWrite(PostfixTermFieldWrite), PostfixTermIndexWrite(PostfixTermIndexWrite), } impl PostfixTermWrite { pub fn loc(&self) -> &SourcePointer { match self { Self::PostfixTermFieldWrite(fw) => &fw.loc, Self::PostfixTermIndexWrite(iw) => &iw.loc, } } } #[derive(Debug, Clone, PartialEq, Eq)] pub struct PostfixTermWriteList { pub loc: SourcePointer, pub terms: Vec, } #[derive(Debug, Clone, PartialEq, Eq)] pub struct PostfixTermObjectWrite { pub loc: SourcePointer, pub terms: PostfixTermWriteList, } #[derive(Debug, Clone, PartialEq, Eq)] pub enum TryProtocolMode { Return, Assert, } #[derive(Debug, Clone, PartialEq, Eq)] pub struct PostfixTermTryProtocol { pub loc: SourcePointer, pub mode: TryProtocolMode, } #[allow(clippy::large_enum_variant)] #[derive(Debug, Clone, PartialEq, Eq)] pub enum PostfixTerm { PostfixTermAttribute(PostfixTermAttribute), PostfixTermIndex(PostfixTermIndex), PostfixTermCall(PostfixTermCall), PostfixTermObjectWrite(PostfixTermObjectWrite), PostfixTermEnumCase(PostfixTermEnumCase), PostfixTermTryProtocol(PostfixTermTryProtocol), } #[derive(Debug, Clone, PartialEq, Eq)] pub struct PostfixExpression { pub loc: SourcePointer, pub base: Primary, pub terms: Vec, } impl PostfixExpression { pub fn attrib_read(base: &Primary, name: &str) -> PostfixExpression { let read_attr = PostfixTerm::PostfixTermAttribute(PostfixTermAttribute { loc: base.loc().clone(), id: Identifier { loc: base.loc().clone(), value: name.to_owned(), }, }); Self { loc: base.loc().clone(), base: base.clone(), terms: vec![read_attr], } } pub fn method_call(base: &Primary, name: &str, args: &[Expression]) -> PostfixExpression { let read_attr = PostfixTerm::PostfixTermAttribute(PostfixTermAttribute { loc: base.loc().clone(), id: Identifier { loc: base.loc().clone(), value: name.to_owned(), }, }); let call_attr = PostfixTerm::PostfixTermCall(PostfixTermCall { loc: base.loc().clone(), args: ExpressionList { loc: base.loc().clone(), expressions: args.to_vec(), }, }); Self { loc: base.loc().clone(), base: base.clone(), terms: vec![read_attr, call_attr], } } } impl From<&Primary> for PostfixExpression { fn from(value: &Primary) -> Self { Self { loc: value.loc().clone(), base: value.clone(), terms: vec![], } } } #[derive(Debug, Clone, PartialEq, Eq)] pub struct PostfixRvalue { pub loc: SourcePointer, pub expr: PostfixExpression, } impl From<&PostfixExpression> for PostfixRvalue { fn from(value: &PostfixExpression) -> Self { Self { loc: value.loc.clone(), expr: value.clone(), } } } #[derive(Debug, Clone, PartialEq, Eq, Copy)] pub enum UnarySymbol { Exclamation, Minus, } #[derive(Debug, Clone, PartialEq, Eq)] pub struct UnaryOperation { pub loc: SourcePointer, pub operand: Option, pub postfix: PostfixRvalue, } impl From<&PostfixRvalue> for UnaryOperation { fn from(value: &PostfixRvalue) -> Self { Self { loc: value.loc.clone(), operand: None, postfix: value.clone(), } } } #[derive(Debug, Clone, PartialEq, Eq)] pub enum MulSymbol { Star, Slash, Percent, } #[derive(Debug, Clone, PartialEq, Eq)] pub enum AddSymbol { Plus, Minus, } #[derive(Debug, Clone, PartialEq, Eq)] pub enum AddEqSymbol { PlusEq, MinusEq, StarEq, SlashEq, PercentEq, ShiftLeftEq, ShiftRightEq, } #[derive(Debug, Clone, PartialEq, Eq)] pub struct MulOperation { pub loc: SourcePointer, pub left: UnaryOperation, pub right: Vec<(MulSymbol, UnaryOperation)>, } impl From<&UnaryOperation> for MulOperation { fn from(value: &UnaryOperation) -> Self { Self { loc: value.loc.clone(), left: value.clone(), right: vec![], } } } #[derive(Debug, Clone, PartialEq, Eq)] pub struct AddOperation { pub loc: SourcePointer, pub left: MulOperation, pub right: Vec<(AddSymbol, MulOperation)>, } impl From<&MulOperation> for AddOperation { fn from(value: &MulOperation) -> Self { Self { loc: value.loc.clone(), left: value.clone(), right: vec![], } } } #[derive(Debug, Clone, PartialEq, Eq, Copy)] pub enum ShiftSymbol { Leftward, Rightward, } #[derive(Debug, Clone, PartialEq, Eq)] pub struct ShiftOperation { pub loc: SourcePointer, pub left: AddOperation, pub right: Option<(ShiftSymbol, AddOperation)>, } impl From<&AddOperation> for ShiftOperation { fn from(value: &AddOperation) -> Self { Self { loc: value.loc.clone(), left: value.clone(), right: None, } } } #[derive(Debug, Clone, PartialEq, Eq, Copy)] pub enum RelSymbol { Less, LessEqual, Greater, GreaterEqual, } #[derive(Debug, Clone, PartialEq, Eq)] pub struct RelOperation { pub loc: SourcePointer, pub left: ShiftOperation, pub right: Option<(RelSymbol, ShiftOperation)>, } impl From<&ShiftOperation> for RelOperation { fn from(value: &ShiftOperation) -> Self { Self { loc: value.loc.clone(), left: value.clone(), right: None, } } } #[derive(Debug, Clone, PartialEq, Eq)] pub enum CompSymbol { Equal, NotEqual, Isa, } #[derive(Debug, Clone, PartialEq, Eq)] pub struct CompOperation { pub loc: SourcePointer, pub left: RelOperation, pub right: Option<(CompSymbol, RelOperation)>, } impl From<&RelOperation> for CompOperation { fn from(value: &RelOperation) -> Self { Self { loc: value.loc.clone(), left: value.clone(), right: None, } } } #[derive(Debug, Clone, PartialEq, Eq)] pub enum LogSymbol { Ampersand, DoubleAmpersand, DoublePipe, Pipe, Caret, } #[derive(Debug, Clone, PartialEq, Eq)] pub struct LogOperation { pub loc: SourcePointer, pub left: CompOperation, pub right: Vec<(LogSymbol, CompOperation)>, } impl From<&CompOperation> for LogOperation { fn from(value: &CompOperation) -> Self { Self { loc: value.loc.clone(), left: value.clone(), right: vec![], } } } #[derive(Debug, Clone, PartialEq, Eq)] #[allow(clippy::large_enum_variant)] pub enum LambdaBody { Expression(Expression), CodeBlock(CodeBlock), } impl From<&LambdaBody> for FunctionBody { fn from(value: &LambdaBody) -> Self { match value { LambdaBody::Expression(e) => { let ret_stmt = ReturnStatement { loc: e.loc().clone(), val: Some(e.clone()), }; Self { code: CodeBlock { loc: ret_stmt.loc.clone(), entries: vec![Statement::ReturnStatement(ret_stmt)], }, } } LambdaBody::CodeBlock(b) => Self { code: b.clone() }, } } } #[derive(Debug, Clone, PartialEq, Eq)] pub struct LambdaFunction { pub loc: SourcePointer, pub args: ArgumentList, pub body: Box, } #[derive(Debug, Clone, PartialEq, Eq)] pub struct FunctionBody { pub code: CodeBlock, } impl FunctionBody { pub fn loc(&self) -> &SourcePointer { &self.code.loc } } #[derive(Debug, Clone, PartialEq, Eq)] pub struct TernaryExpression { pub loc: SourcePointer, pub condition: Box, pub true_expression: Box, pub false_expression: Box, } #[derive(Debug, Clone, PartialEq, Eq)] pub struct TryUnwrapExpression { pub loc: SourcePointer, pub left: Box, pub right: Box, } #[derive(Debug, Clone, PartialEq, Eq)] #[allow(clippy::large_enum_variant)] pub enum Expression { LambdaFunction(LambdaFunction), LogOperation(LogOperation), TernaryExpression(TernaryExpression), TryUnwrapExpression(TryUnwrapExpression), } impl From<&LogOperation> for Expression { fn from(value: &LogOperation) -> Self { Self::LogOperation(value.clone()) } } impl From<&Identifier> for Expression { fn from(value: &Identifier) -> Self { let pfe = PostfixExpression::from(&Primary::Identifier(value.clone())); Self::from(&pfe) } } impl From<&Primary> for Expression { fn from(value: &Primary) -> Self { let pfe = PostfixExpression::from(value); Self::from(&pfe) } } impl From<&UnaryOperation> for Expression { fn from(value: &UnaryOperation) -> Self { Self::from(&LogOperation::from(&CompOperation::from( &RelOperation::from(&ShiftOperation::from(&AddOperation::from( &MulOperation::from(value), ))), ))) } } impl From<&PostfixExpression> for Expression { fn from(value: &PostfixExpression) -> Self { Self::from(&LogOperation::from(&CompOperation::from( &RelOperation::from(&ShiftOperation::from(&AddOperation::from( &MulOperation::from(&UnaryOperation::from(&PostfixRvalue::from(value))), ))), ))) } } impl Expression { pub fn loc(&self) -> &SourcePointer { match self { Expression::LogOperation(c) => &c.loc, Expression::LambdaFunction(f) => &f.loc, Expression::TernaryExpression(t) => &t.loc, Expression::TryUnwrapExpression(t) => &t.loc, } } } impl Expression { pub fn call_function_passing_me(&self, func_name: &str) -> Expression { let loc = self.loc().clone(); let func_ident = Identifier { loc: loc.clone(), value: func_name.to_owned(), }; let base = Primary::Identifier(func_ident); let args = ExpressionList { loc: loc.clone(), expressions: vec![self.clone()], }; let call = PostfixTerm::PostfixTermCall(PostfixTermCall { loc: loc.clone(), args, }); let pfe = PostfixExpression { loc, base, terms: vec![call], }; Expression::from(&pfe) } pub fn is_function_call(&self) -> (bool, Option<&str>) { fn peel(log: &LogOperation) -> Option<&PostfixExpression> { if !log.right.is_empty() { return None; } let comp: &CompOperation = &log.left; if comp.right.is_some() { return None; } let rel: &RelOperation = &comp.left; if rel.right.is_some() { return None; } let shift: &ShiftOperation = &rel.left; if shift.right.is_some() { return None; } let add: &AddOperation = &shift.left; if !add.right.is_empty() { return None; } let mul: &MulOperation = &add.left; if !mul.right.is_empty() { return None; } let UnaryOperation { postfix, .. } = &mul.left; Some(&postfix.expr) } fn resolve_name(pfe: &PostfixExpression) -> Option<&str> { let last = pfe.terms.last()?; if !matches!(last, PostfixTerm::PostfixTermCall(_)) { return None; } if pfe.terms.len() == 1 && let crate::ast::Primary::Identifier(id) = &pfe.base { return Some(&id.value); } if pfe.terms.len() >= 2 && let PostfixTerm::PostfixTermAttribute(attr) = &pfe.terms[pfe.terms.len() - 2] { return Some(&attr.id.value); } None } match self { Expression::LogOperation(log) => { if let Some(pfe) = peel(log) && matches!(pfe.terms.last(), Some(PostfixTerm::PostfixTermCall(_))) { return (true, resolve_name(pfe)); } (false, None) } _ => (false, None), } } } #[derive(Debug, Clone, PartialEq, Eq)] pub struct DeclarationId { pub loc: SourcePointer, pub name: Identifier, pub ty: Option, } impl From<&Identifier> for DeclarationId { fn from(value: &Identifier) -> Self { Self { loc: value.loc.clone(), name: value.clone(), ty: None, } } } #[derive(Debug, Clone, PartialEq, Eq)] pub struct ExpressionStatement { pub loc: SourcePointer, pub val: Option, } #[derive(Debug, Clone, PartialEq, Eq)] pub struct ValDeclEntry { pub loc: SourcePointer, pub id: DeclarationId, pub val: Expression, } #[derive(Debug, Clone, PartialEq, Eq)] pub struct ValDeclStatement { pub loc: SourcePointer, pub decls: Vec, } #[derive(Debug, Clone, PartialEq, Eq)] pub struct AssignStatement { pub loc: SourcePointer, pub id: Vec, pub val: Vec, } #[derive(Debug, Clone, PartialEq, Eq)] pub struct WriteOpEqStatement { pub loc: SourcePointer, pub id: PostfixExpression, pub op: AddEqSymbol, pub val: Expression, } #[derive(Debug, Clone, PartialEq, Eq)] pub struct IfCondPiece { pub loc: SourcePointer, pub expression: Box, pub then: CodeBlock, } #[derive(Debug, Clone, PartialEq, Eq)] pub struct ElsePiece { pub loc: SourcePointer, pub then: CodeBlock, } #[derive(Debug, Clone, PartialEq, Eq)] pub struct ElsifPiece { pub content: IfCondPiece, } #[derive(Debug, Clone, PartialEq, Eq)] pub struct IfPiece { pub content: IfCondPiece, } #[derive(Debug, Clone, PartialEq, Eq)] pub struct IfStatement { pub loc: SourcePointer, pub iff: IfPiece, pub elsif: Vec, pub els: Option, } #[derive(Debug, Clone, PartialEq, Eq)] pub struct MatchPatternComp { pub loc: SourcePointer, pub op: CompSymbol, pub expr: Expression, } #[derive(Debug, Clone, PartialEq, Eq)] pub struct MatchPatternRel { pub loc: SourcePointer, pub op: RelSymbol, pub expr: Expression, } impl MatchPatternComp { pub fn isa(loc: SourcePointer, expr: Expression) -> Self { Self { loc, op: CompSymbol::Isa, expr, } } } #[derive(Debug, Clone, PartialEq, Eq)] pub struct MatchPatternEnumCase { pub loc: SourcePointer, pub case: Identifier, pub payload: Option, } #[derive(Debug, Clone, PartialEq, Eq)] pub enum MatchPattern { MatchPatternComp(MatchPatternComp), MatchPatternRel(MatchPatternRel), MatchPatternEnumCase(MatchPatternEnumCase), } impl MatchPattern { pub fn loc(&self) -> &SourcePointer { match self { Self::MatchPatternComp(e) => &e.loc, Self::MatchPatternRel(e) => &e.loc, Self::MatchPatternEnumCase(c) => &c.loc, } } } #[derive(Debug, Clone, PartialEq, Eq)] pub struct MatchRule { pub loc: SourcePointer, pub patterns: Vec, pub then: CodeBlock, } impl MatchRule { pub fn enum_and_case( loc: SourcePointer, enumm: &str, case: &str, payload: Option, then: CodeBlock, ) -> Self { let enumm = Identifier { loc: loc.clone(), value: enumm.to_owned(), }; let case = Identifier { loc: loc.clone(), value: case.to_owned(), }; let payload = payload.map(|p| DeclarationId::from(&p)); let case_pattern = MatchPattern::MatchPatternEnumCase(MatchPatternEnumCase { loc: enumm.loc.clone(), case, payload, }); let isa_pattern = MatchPattern::MatchPatternComp(MatchPatternComp { loc: loc.clone(), op: CompSymbol::Isa, expr: From::from(&enumm), }); Self { loc, patterns: vec![isa_pattern, case_pattern], then, } } } #[derive(Debug, Clone, PartialEq, Eq)] pub struct MatchStatement { pub loc: SourcePointer, pub expr: Expression, pub rules: Vec, pub els: Option, } #[derive(Debug, Clone, PartialEq, Eq)] pub struct WhileStatement { pub loc: SourcePointer, pub cond: Expression, pub then: CodeBlock, pub els: Option, } #[derive(Debug, Clone, PartialEq, Eq)] pub struct ForStatement { pub loc: SourcePointer, pub id: Identifier, pub expr: Expression, pub then: CodeBlock, pub els: Option, } #[derive(Debug, Clone, PartialEq, Eq)] pub struct ReturnStatement { pub loc: SourcePointer, pub val: Option, } impl From<&Expression> for ReturnStatement { fn from(val: &Expression) -> Self { Self { loc: val.loc().clone(), val: Some(val.clone()), } } } #[derive(Debug, Clone, PartialEq, Eq)] pub struct ThrowStatement { pub loc: SourcePointer, pub val: Expression, } #[derive(Debug, Clone, PartialEq, Eq)] pub struct AssertStatement { pub loc: SourcePointer, pub val: Expression, } #[derive(Debug, Clone, PartialEq, Eq)] pub struct BreakStatement { pub loc: SourcePointer, } #[derive(Debug, Clone, PartialEq, Eq)] pub struct ContinueStatement { pub loc: SourcePointer, } #[derive(Debug, Clone, PartialEq, Eq)] pub struct TryBlock { pub loc: SourcePointer, pub body: CodeBlock, pub id: Identifier, pub catch: CodeBlock, } #[derive(Debug, Clone, PartialEq, Eq)] #[allow(clippy::large_enum_variant)] pub enum Statement { ValDeclStatement(ValDeclStatement), AssignStatement(AssignStatement), WriteOpEqStatement(WriteOpEqStatement), IfStatement(IfStatement), MatchStatement(MatchStatement), WhileStatement(WhileStatement), ForStatement(ForStatement), CodeBlock(CodeBlock), ReturnStatement(ReturnStatement), ThrowStatement(ThrowStatement), TryBlock(TryBlock), AssertStatement(AssertStatement), ExpressionStatement(ExpressionStatement), BreakStatement(BreakStatement), ContinueStatement(ContinueStatement), StructDecl(StructDecl), EnumDecl(EnumDecl), FunctionDecl(FunctionDecl), } impl Statement { pub fn loc(&self) -> &SourcePointer { match self { Self::ValDeclStatement(a) => &a.loc, Self::AssignStatement(a) => &a.loc, Self::WriteOpEqStatement(a) => &a.loc, Self::IfStatement(a) => &a.loc, Self::MatchStatement(a) => &a.loc, Self::WhileStatement(a) => &a.loc, Self::ForStatement(a) => &a.loc, Self::CodeBlock(a) => &a.loc, Self::ReturnStatement(a) => &a.loc, Self::ThrowStatement(a) => &a.loc, Self::TryBlock(a) => &a.loc, Self::AssertStatement(a) => &a.loc, Self::ExpressionStatement(a) => &a.loc, Self::BreakStatement(a) => &a.loc, Self::ContinueStatement(a) => &a.loc, Self::StructDecl(s) => &s.loc, Self::EnumDecl(e) => &e.loc, Self::FunctionDecl(f) => &f.loc, } } } #[derive(Debug, Clone, PartialEq, Eq)] pub struct CodeBlock { pub loc: SourcePointer, pub entries: Vec, } impl From<&Statement> for CodeBlock { fn from(value: &Statement) -> Self { Self { loc: value.loc().clone(), entries: vec![value.clone()], } } } #[derive(Debug, Clone, PartialEq, Eq)] pub struct ArgumentDecl { pub loc: SourcePointer, pub id: DeclarationId, pub deft: Option, } impl ArgumentDecl { pub fn name(&self) -> &String { &self.id.name.value } pub fn type_info(&self) -> Option<&Expression> { self.id.ty.as_ref() } } impl From<&DeclarationId> for ArgumentDecl { fn from(value: &DeclarationId) -> Self { Self { loc: value.loc.clone(), id: value.clone(), deft: None, } } } #[derive(Debug, Clone, PartialEq, Eq)] pub struct ArgumentList { pub loc: SourcePointer, pub names: Vec, pub vararg: bool, } impl ArgumentList { pub fn empty(loc: SourcePointer) -> Self { Self { loc, names: vec![], vararg: false, } } pub fn len(&self) -> usize { self.names.len() } pub fn is_empty(&self) -> bool { self.names.is_empty() } } #[derive(Debug, Clone, PartialEq, Eq)] pub struct FunctionDecl { pub loc: SourcePointer, pub name: Identifier, pub args: ArgumentList, pub body: FunctionBody, } #[derive(Debug, Clone, PartialEq, Eq)] pub enum MethodAccess { Instance, Type, } #[derive(Debug, Clone, PartialEq, Eq)] pub struct MethodDecl { pub loc: SourcePointer, pub access: MethodAccess, pub name: Identifier, pub args: ArgumentList, pub body: FunctionBody, } #[derive(Debug, Clone, PartialEq, Eq)] pub enum OperatorSymbol { Plus, Minus, UnaryMinus, Star, Slash, Percent, LeftShift, RightShift, Equals, LessThanEqual, GreaterThanEqual, LessThan, GreaterThan, BitwiseAnd, BitwiseOr, BitwiseXor, Call, GetSquareBrackets, SetSquareBrackets, } #[derive(Debug, Clone, PartialEq, Eq)] pub struct OperatorDecl { pub loc: SourcePointer, pub reverse: bool, pub symbol: OperatorSymbol, pub args: ArgumentList, pub body: FunctionBody, } #[derive(Debug, Clone, PartialEq, Eq)] pub struct MixinIncludeDecl { pub loc: SourcePointer, pub what: Expression, } #[derive(Debug, Clone, PartialEq, Eq)] pub enum StructEntry { Method(Box), Operator(Box), Variable(Box), Struct(Box), Enum(Box), MixinInclude(Box), } impl StructEntry { pub fn loc(&self) -> &SourcePointer { match self { Self::Method(m) => &m.loc, Self::Operator(o) => &o.loc, Self::Variable(v) => &v.loc, Self::Struct(s) => &s.loc, Self::Enum(e) => &e.loc, Self::MixinInclude(m) => &m.loc, } } } #[derive(Debug, Clone, PartialEq, Eq)] pub struct StructDecl { pub loc: SourcePointer, pub name: Identifier, pub inherits: Vec, pub body: Vec, } #[derive(Debug, Clone, PartialEq, Eq)] pub struct MixinDecl { pub loc: SourcePointer, pub name: Identifier, pub body: Vec, } #[derive(Debug, Clone, PartialEq, Eq)] pub struct EnumCaseDecl { pub loc: SourcePointer, pub name: Identifier, pub payload: Option, } #[derive(Debug, Clone, PartialEq, Eq)] #[allow(clippy::large_enum_variant)] pub enum EnumDeclEntry { EnumCaseDecl(EnumCaseDecl), StructEntry(StructEntry), } impl EnumDeclEntry { pub fn loc(&self) -> &SourcePointer { match self { Self::EnumCaseDecl(e) => &e.loc, Self::StructEntry(s) => s.loc(), } } } #[derive(Debug, Clone, PartialEq, Eq)] pub struct EnumDecl { pub loc: SourcePointer, pub name: Identifier, pub body: Vec, } #[derive(Debug, Clone, PartialEq, Eq)] pub struct ExtensionDecl { pub loc: SourcePointer, pub target: Expression, pub inherits: Vec, pub body: Vec, } #[derive(Debug, Clone, PartialEq, Eq)] pub struct ImportPath { pub loc: SourcePointer, pub entries: Vec, } impl ImportPath { pub fn from_dotted_string(loc: SourcePointer, dotted: &str) -> Self { Self { loc: loc.clone(), entries: dotted .split('.') .map(|x| Identifier { loc: loc.clone(), value: x.to_owned(), }) .collect(), } } pub fn to_dotted_string(&self) -> String { self.entries .iter() .map(|x| x.value.clone()) .collect::>() .join(".") } pub fn to_path_string(&self) -> String { self.entries .iter() .map(|x| x.value.clone()) .collect::>() .join("/") } } #[derive(Debug, Clone, PartialEq, Eq)] pub struct ImportStatement { pub loc: SourcePointer, pub what: ImportPath, } #[derive(Debug, Clone, PartialEq, Eq)] pub enum ImportTarget { IdentifierList(IdentifierList), All, } #[derive(Debug, Clone, PartialEq, Eq)] pub struct ImportFromStatement { pub loc: SourcePointer, pub what: ImportTarget, pub from: ImportPath, } #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub enum ModuleFlag { NoStandardLibrary, UsesDylib(String), } #[derive(Debug, Clone, PartialEq, Eq)] pub struct ModuleFlags { pub flags: Vec, } impl ModuleFlags { pub fn empty() -> Self { Self { flags: vec![] } } } #[derive(Debug, Clone, PartialEq, Eq)] #[allow(clippy::large_enum_variant)] pub enum TopLevelEntry { ExpressionStatement(ExpressionStatement), ValDeclStatement(ValDeclStatement), WriteOpEqStatement(WriteOpEqStatement), AssignStatement(AssignStatement), FunctionDecl(FunctionDecl), StructDecl(StructDecl), MixinDecl(MixinDecl), EnumDecl(EnumDecl), ExtensionDecl(ExtensionDecl), AssertStatement(AssertStatement), ImportStatement(ImportStatement), ImportFromStatement(ImportFromStatement), IfStatement(IfStatement), MatchStatement(MatchStatement), WhileStatement(WhileStatement), ForStatement(ForStatement), CodeBlock(CodeBlock), TryBlock(TryBlock), } #[derive(Debug, Clone, PartialEq, Eq)] pub struct ParsedModule { pub loc: SourcePointer, pub flags: ModuleFlags, pub entries: Vec, } #[derive(Debug, Clone, PartialEq, Eq)] pub struct ParserError { pub loc: SourcePointer, pub msg: String, } impl std::fmt::Display for ParserError { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "{}", self.msg) } } pub type ParserResult = Result; pub fn source_to_ast(source: &SourceBuffer) -> ParserResult { let input = &source.as_str(); let parse_tree = HaxbyParser::parse(Rule::module, input); match parse_tree { Ok(mut pt) => Ok(::from_parse_tree( pt.next_back().expect("invalid parse tree"), source, )), Err(err) => { let loc = From::from(&err.location); let ptr = source.pointer(loc); Err(ParserError { loc: ptr, msg: err.variant.message().to_string(), }) } } } ================================================ FILE: parser-lib/src/ast/nodes/add_eq_symbol.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use crate::{ ast::{ AddEqSymbol, SourceBuffer, derive::Derive, prettyprint::{PrettyPrintable, printout_accumulator::PrintoutAccumulator}, }, grammar::Rule, }; impl Derive for AddEqSymbol { fn from_parse_tree(p: pest::iterators::Pair<'_, Rule>, _: &SourceBuffer) -> Self { assert!(p.as_rule() == Rule::add_op_eq); match p.as_str() { "+=" => Self::PlusEq, "-=" => Self::MinusEq, "*=" => Self::StarEq, "/=" => Self::SlashEq, "%=" => Self::PercentEq, "<<=" => Self::ShiftLeftEq, ">>=" => Self::ShiftRightEq, _ => panic!("operator expected"), } } } impl PrettyPrintable for AddEqSymbol { fn prettyprint(&self, buffer: PrintoutAccumulator) -> PrintoutAccumulator { buffer.write(match self { Self::PlusEq => "+=", Self::MinusEq => "-=", Self::StarEq => "*=", Self::SlashEq => "/=", Self::PercentEq => "%=", Self::ShiftLeftEq => "<<=", Self::ShiftRightEq => ">>=", }) } } ================================================ FILE: parser-lib/src/ast/nodes/add_operation.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use crate::{ ast::{ AddOperation, AddSymbol, MulOperation, SourceBuffer, derive::Derive, prettyprint::{PrettyPrintable, printout_accumulator::PrintoutAccumulator}, }, grammar::Rule, }; impl Derive for AddOperation { #[allow(clippy::len_zero)] fn from_parse_tree(p: pest::iterators::Pair<'_, Rule>, source: &SourceBuffer) -> Self { assert!(p.as_rule() == Rule::add); let loc = From::from(&p.as_span()); let mut inner = p.into_inner(); if inner.len() == 1 { let left = MulOperation::from_parse_tree(inner.peek().expect("need a mul"), source); Self { loc: source.pointer(loc), left, right: vec![], } } else if inner.len() > 0 { let left = MulOperation::from_parse_tree(inner.next().expect("need a left mul"), source); let mut right = vec![]; loop { let op = inner.next(); if op.is_none() { break; }; let op = AddSymbol::from_parse_tree(op.unwrap(), source); let atom = MulOperation::from_parse_tree( inner.next().expect("add needs a right hand side"), source, ); right.push((op, atom)); } Self { loc: source.pointer(loc), left, right, } } else { panic!("add does not contain") } } } impl PrettyPrintable for AddOperation { fn prettyprint(&self, buffer: PrintoutAccumulator) -> PrintoutAccumulator { let mut this = self.left.prettyprint(buffer); for (op, atom) in &self.right { this = this << op << atom; } this } } ================================================ FILE: parser-lib/src/ast/nodes/add_symbol.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use crate::{ ast::{ AddSymbol, SourceBuffer, derive::Derive, prettyprint::{PrettyPrintable, printout_accumulator::PrintoutAccumulator}, }, grammar::Rule, }; impl Derive for AddSymbol { fn from_parse_tree(p: pest::iterators::Pair<'_, Rule>, _: &SourceBuffer) -> Self { assert!(p.as_rule() == Rule::add_op); match p.as_str() { "+" => Self::Plus, "-" => Self::Minus, _ => panic!("+ or - expected"), } } } impl PrettyPrintable for AddSymbol { fn prettyprint(&self, buffer: PrintoutAccumulator) -> PrintoutAccumulator { buffer.write(match self { Self::Plus => "+", Self::Minus => "-", }) } } ================================================ FILE: parser-lib/src/ast/nodes/argument_decl.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use crate::{ ast::{ ArgumentDecl, DeclarationId, Expression, SourceBuffer, derive::Derive, prettyprint::{PrettyPrintable, printout_accumulator::PrintoutAccumulator}, }, grammar::Rule, }; impl Derive for ArgumentDecl { fn from_parse_tree(p: pest::iterators::Pair<'_, Rule>, source: &SourceBuffer) -> Self { assert!(p.as_rule() == Rule::arg_decl); let loc = From::from(&p.as_span()); let mut inner = p.into_inner(); let id = DeclarationId::from_parse_tree(inner.next().expect("expected decl_id"), source); let deft = inner.next().map(|p| Expression::from_parse_tree(p, source)); Self { loc: source.pointer(loc), id, deft, } } } impl PrettyPrintable for ArgumentDecl { fn prettyprint(&self, buffer: PrintoutAccumulator) -> PrintoutAccumulator { let buffer = buffer << &self.id; if let Some(deft) = &self.deft { buffer << " = " << deft } else { buffer } } } ================================================ FILE: parser-lib/src/ast/nodes/argument_list.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use crate::{ ast::{ ArgumentDecl, ArgumentList, SourceBuffer, derive::Derive, prettyprint::{PrettyPrintable, printout_accumulator::PrintoutAccumulator}, }, grammar::Rule, }; impl Derive for ArgumentList { fn from_parse_tree(p: pest::iterators::Pair<'_, Rule>, source: &SourceBuffer) -> Self { assert!(p.as_rule() == Rule::arg_list); let loc = From::from(&p.as_span()); let inner = p.into_inner(); let mut names = vec![]; let mut vararg = false; for e in inner { if e.as_rule() == Rule::vararg_marker { vararg = true; } else if e.as_rule() == Rule::arg_decl { names.push(ArgumentDecl::from_parse_tree(e, source)); } else { panic!("Unexpected rule in argument list: {:?}", e.as_rule()); } } Self { loc: source.pointer(loc), names, vararg, } } } impl PrettyPrintable for ArgumentList { fn prettyprint(&self, buffer: PrintoutAccumulator) -> PrintoutAccumulator { let buffer = buffer.write_separated_list(&self.names, ","); if self.vararg { buffer << "..." } else { buffer } } } ================================================ FILE: parser-lib/src/ast/nodes/assert_statement.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use crate::{ ast::{ AssertStatement, Expression, derive::Derive, prettyprint::{PrettyPrintable, printout_accumulator::PrintoutAccumulator}, }, gen_from_components, }; impl Derive for AssertStatement { gen_from_components!(assert_stmt; val: Expression); } impl PrettyPrintable for AssertStatement { fn prettyprint(&self, buffer: PrintoutAccumulator) -> PrintoutAccumulator { buffer << "assert " << &self.val << ";" } } ================================================ FILE: parser-lib/src/ast/nodes/assign_statement.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use crate::ast::{ AssignStatement, Expression, PostfixExpression, derive::Derive, prettyprint::{PrettyPrintable, printout_accumulator::PrintoutAccumulator}, }; impl Derive for AssignStatement { fn from_parse_tree( p: pest::iterators::Pair<'_, crate::grammar::Rule>, source: &crate::ast::SourceBuffer, ) -> Self { assert!(p.as_rule() == crate::grammar::Rule::val_write_stmt); let loc = From::from(&p.as_span()); let inner = p.into_inner(); let mut id = vec![]; let mut val = vec![]; for next in inner { match next.as_rule() { crate::grammar::Rule::postfix_lv => { id.push(::from_parse_tree(next, source)); } crate::grammar::Rule::expression => { val.push(::from_parse_tree(next, source)); } _ => panic!("unexpected token, want postfix_lv or expression"), } } Self { loc: source.pointer(loc), id, val, } } } impl PrettyPrintable for AssignStatement { fn prettyprint(&self, buffer: PrintoutAccumulator) -> PrintoutAccumulator { buffer .write_separated_list(&self.id, ", ") .write(" = ") .write_separated_list(&self.val, ", ") << ";" } } ================================================ FILE: parser-lib/src/ast/nodes/break_statement.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use crate::{ ast::{ BreakStatement, SourceBuffer, derive::Derive, prettyprint::{PrettyPrintable, printout_accumulator::PrintoutAccumulator}, }, grammar::Rule, }; impl Derive for BreakStatement { fn from_parse_tree(p: pest::iterators::Pair<'_, Rule>, source: &SourceBuffer) -> Self { assert!(p.as_rule() == Rule::break_stmt); let loc = From::from(&p.as_span()); Self { loc: source.pointer(loc), } } } impl PrettyPrintable for BreakStatement { fn prettyprint(&self, buffer: PrintoutAccumulator) -> PrintoutAccumulator { buffer << "break;" } } ================================================ FILE: parser-lib/src/ast/nodes/code_block.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use crate::{ ast::{ CodeBlock, SourceBuffer, Statement, derive::Derive, prettyprint::{PrettyPrintable, printout_accumulator::PrintoutAccumulator}, }, grammar::Rule, }; impl Derive for CodeBlock { fn from_parse_tree(p: pest::iterators::Pair<'_, Rule>, source: &SourceBuffer) -> Self { assert!(p.as_rule() == Rule::code_block); let loc = From::from(&p.as_span()); let inner = p.into_inner(); let entries = inner .map(|e| Statement::from_parse_tree(e, source)) .collect::>(); Self { loc: source.pointer(loc), entries, } } } impl PrettyPrintable for CodeBlock { fn prettyprint(&self, buffer: PrintoutAccumulator) -> PrintoutAccumulator { buffer.write_indented_list(&self.entries, "{\n", "\n", "\n}") } } ================================================ FILE: parser-lib/src/ast/nodes/comp_operation.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use crate::{ ast::{ CompOperation, CompSymbol, RelOperation, SourceBuffer, derive::Derive, prettyprint::{PrettyPrintable, printout_accumulator::PrintoutAccumulator}, }, grammar::Rule, }; impl Derive for CompOperation { fn from_parse_tree(p: pest::iterators::Pair<'_, Rule>, source: &SourceBuffer) -> Self { assert!(p.as_rule() == Rule::comp); let loc = From::from(&p.as_span()); let mut inner = p.into_inner(); if inner.len() == 1 { let left = RelOperation::from_parse_tree(inner.peek().expect("need a add"), source); Self { loc: source.pointer(loc), left, right: None, } } else { let left = RelOperation::from_parse_tree(inner.next().expect("need first add"), source); let op = CompSymbol::from_parse_tree(inner.next().expect("need op"), source); let right = RelOperation::from_parse_tree(inner.next().expect("need second add"), source); Self { loc: source.pointer(loc), left, right: Some((op, right)), } } } } impl PrettyPrintable for CompOperation { fn prettyprint(&self, buffer: PrintoutAccumulator) -> PrintoutAccumulator { let this = self.left.prettyprint(buffer); if let Some(right) = &self.right { this << " " << &right.0 << " " << &right.1 } else { this } } } ================================================ FILE: parser-lib/src/ast/nodes/comp_symbol.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use crate::{ ast::{ CompSymbol, SourceBuffer, derive::Derive, prettyprint::{PrettyPrintable, printout_accumulator::PrintoutAccumulator}, }, grammar::Rule, }; impl Derive for CompSymbol { fn from_parse_tree(p: pest::iterators::Pair<'_, Rule>, _: &SourceBuffer) -> Self { assert!(p.as_rule() == Rule::comp_op); match p.as_str() { "==" => Self::Equal, "!=" => Self::NotEqual, "isa" => Self::Isa, _ => panic!("* or / expected"), } } } impl PrettyPrintable for CompSymbol { fn prettyprint(&self, buffer: PrintoutAccumulator) -> PrintoutAccumulator { buffer.write(match self { Self::Equal => "==", Self::NotEqual => "!=", Self::Isa => "isa", }) } } ================================================ FILE: parser-lib/src/ast/nodes/continue_statement.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use crate::{ ast::{ ContinueStatement, SourceBuffer, derive::Derive, prettyprint::{PrettyPrintable, printout_accumulator::PrintoutAccumulator}, }, grammar::Rule, }; impl Derive for ContinueStatement { fn from_parse_tree(p: pest::iterators::Pair<'_, Rule>, source: &SourceBuffer) -> Self { assert!(p.as_rule() == Rule::continue_stmt); let loc = From::from(&p.as_span()); Self { loc: source.pointer(loc), } } } impl PrettyPrintable for ContinueStatement { fn prettyprint(&self, buffer: PrintoutAccumulator) -> PrintoutAccumulator { buffer << "continue;" } } ================================================ FILE: parser-lib/src/ast/nodes/declaration_id.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use crate::{ ast::{ DeclarationId, Expression, Identifier, SourceBuffer, derive::Derive, prettyprint::{PrettyPrintable, printout_accumulator::PrintoutAccumulator}, }, grammar::Rule, }; impl Derive for DeclarationId { fn from_parse_tree(p: pest::iterators::Pair<'_, Rule>, source: &SourceBuffer) -> Self { assert!(p.as_rule() == Rule::decl_id); let loc = From::from(&p.as_span()); let mut inner = p.into_inner(); let name = Identifier::from_parse_tree(inner.next().expect("need identifier"), source); let ty = inner .next() .map(|next| Expression::from_parse_tree(next, source)); Self { loc: source.pointer(loc), name, ty, } } } impl PrettyPrintable for DeclarationId { fn prettyprint(&self, buffer: PrintoutAccumulator) -> PrintoutAccumulator { let buffer = buffer << &self.name; if let Some(ty) = &self.ty { buffer << " : " << ty } else { buffer } } } ================================================ FILE: parser-lib/src/ast/nodes/else_piece.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use crate::{ ast::{ CodeBlock, ElsePiece, SourceBuffer, derive::Derive, prettyprint::{PrettyPrintable, printout_accumulator::PrintoutAccumulator}, }, grammar::Rule, }; impl Derive for ElsePiece { fn from_parse_tree(p: pest::iterators::Pair<'_, Rule>, source: &SourceBuffer) -> Self { assert!(p.as_rule() == Rule::else_piece); let loc = From::from(&p.as_span()); let mut inner = p.into_inner(); let body = inner.next().expect("need body"); let then = CodeBlock::from_parse_tree(body, source); Self { loc: source.pointer(loc), then, } } } impl PrettyPrintable for ElsePiece { fn prettyprint(&self, buffer: PrintoutAccumulator) -> PrintoutAccumulator { buffer << "else " << &self.then } } ================================================ FILE: parser-lib/src/ast/nodes/elsif_piece.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use crate::{ ast::{ ElsifPiece, IfCondPiece, SourceBuffer, derive::Derive, prettyprint::{PrettyPrintable, printout_accumulator::PrintoutAccumulator}, }, grammar::Rule, }; impl Derive for ElsifPiece { fn from_parse_tree(p: pest::iterators::Pair<'_, Rule>, source: &SourceBuffer) -> Self { assert!(p.as_rule() == Rule::elsif_piece); let mut inner = p.into_inner(); let content = inner.next().expect("need content"); let content = IfCondPiece::from_parse_tree(content, source); Self { content } } } impl PrettyPrintable for ElsifPiece { fn prettyprint(&self, buffer: PrintoutAccumulator) -> PrintoutAccumulator { buffer << "elsif " << &self.content } } ================================================ FILE: parser-lib/src/ast/nodes/enum_case_decl.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use crate::{ ast::{ EnumCaseDecl, Expression, Identifier, SourceBuffer, derive::Derive, prettyprint::{PrettyPrintable, printout_accumulator::PrintoutAccumulator}, }, grammar::Rule, }; impl Derive for EnumCaseDecl { fn from_parse_tree(p: pest::iterators::Pair<'_, Rule>, source: &SourceBuffer) -> Self { assert!(p.as_rule() == Rule::enum_case_decl); let loc = From::from(&p.as_span()); let mut inner = p.into_inner(); let name = Identifier::from_parse_tree(inner.next().expect("need identifier"), source); let payload = inner .next() .map(|next| Expression::from_parse_tree(next, source)); Self { loc: source.pointer(loc), name, payload, } } } impl PrettyPrintable for EnumCaseDecl { fn prettyprint(&self, buffer: PrintoutAccumulator) -> PrintoutAccumulator { let buffer = buffer << &self.name; if let Some(payload) = &self.payload { buffer << "(" << payload << ")" } else { buffer } } } ================================================ FILE: parser-lib/src/ast/nodes/enum_decl.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use crate::{ ast::{ EnumCaseDecl, EnumDecl, EnumDeclEntry, Identifier, SourceBuffer, StructEntry, derive::Derive, prettyprint::{PrettyPrintable, printout_accumulator::PrintoutAccumulator}, }, grammar::Rule, }; impl Derive for EnumDecl { fn from_parse_tree(p: pest::iterators::Pair<'_, Rule>, source: &SourceBuffer) -> Self { assert!(p.as_rule() == Rule::enum_decl); let loc = From::from(&p.as_span()); let mut inner = p.into_inner(); let name = Identifier::from_parse_tree(inner.next().expect("need identifier"), source); let mut entries = vec![]; for next in inner { if next.as_rule() != Rule::enum_decl_entry { panic!("invalid enum entry :{next}"); } let inner_rule = next.into_inner().next().expect("need enum entry"); match inner_rule.as_rule() { Rule::struct_entry => { entries.push(EnumDeclEntry::StructEntry(StructEntry::from_parse_tree( inner_rule, source, ))); } Rule::enum_case_decl => { entries.push(EnumDeclEntry::EnumCaseDecl(EnumCaseDecl::from_parse_tree( inner_rule, source, ))); } _ => panic!("invalid enum entry :{inner_rule}"), } } Self { loc: source.pointer(loc), name, body: entries, } } } impl PrettyPrintable for EnumDecl { fn prettyprint(&self, buffer: PrintoutAccumulator) -> PrintoutAccumulator { (buffer << "enum " << &self.name).write_indented_list(&self.body, "{\n", "\n", "\n}") } } ================================================ FILE: parser-lib/src/ast/nodes/enum_decl_entry.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use crate::{ ast::{ EnumDeclEntry, derive::Derive, prettyprint::{PrettyPrintable, printout_accumulator::PrintoutAccumulator}, }, gen_from_options, }; use crate::ast::{EnumCaseDecl, StructEntry}; impl Derive for EnumDeclEntry { gen_from_options!(enum_decl_entry; (enum_case_decl, EnumCaseDecl), (struct_entry, StructEntry)); } impl PrettyPrintable for EnumDeclEntry { fn prettyprint(&self, buffer: PrintoutAccumulator) -> PrintoutAccumulator { match self { Self::EnumCaseDecl(e) => e.prettyprint(buffer), Self::StructEntry(s) => s.prettyprint(buffer), } } } ================================================ FILE: parser-lib/src/ast/nodes/expression.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use crate::{ ast::TernaryExpression, ast::{ Expression, LambdaFunction, LogOperation, SourceBuffer, TryUnwrapExpression, derive::Derive, prettyprint::{PrettyPrintable, printout_accumulator::PrintoutAccumulator}, }, grammar::Rule, }; impl Derive for Expression { fn from_parse_tree(p: pest::iterators::Pair<'_, Rule>, source: &SourceBuffer) -> Self { assert!(p.as_rule() == Rule::expression); let content = p.into_inner().next().expect("needs an atom inside"); match content.as_rule() { Rule::log => Self::LogOperation(LogOperation::from_parse_tree(content, source)), Rule::lambda_f => { Self::LambdaFunction(LambdaFunction::from_parse_tree(content, source)) } Rule::ternary_expr => { Self::TernaryExpression(TernaryExpression::from_parse_tree(content, source)) } Rule::try_unwrap_expr => { Self::TryUnwrapExpression(TryUnwrapExpression::from_parse_tree(content, source)) } _ => panic!("atom does not contain"), } } } impl PrettyPrintable for Expression { fn prettyprint(&self, buffer: PrintoutAccumulator) -> PrintoutAccumulator { match self { Expression::LogOperation(c) => c.prettyprint(buffer), Expression::LambdaFunction(f) => f.prettyprint(buffer), Expression::TernaryExpression(t) => t.prettyprint(buffer), Expression::TryUnwrapExpression(t) => t.prettyprint(buffer), } } } ================================================ FILE: parser-lib/src/ast/nodes/expression_list.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use crate::{ ast::{ Expression, ExpressionList, SourceBuffer, derive::Derive, prettyprint::{PrettyPrintable, printout_accumulator::PrintoutAccumulator}, }, grammar::Rule, }; impl Derive for ExpressionList { fn from_parse_tree(p: pest::iterators::Pair<'_, Rule>, source: &SourceBuffer) -> Self { assert!(p.as_rule() == Rule::expr_list); let loc = From::from(&p.as_span()); let inner = p.into_inner(); let expressions = inner .map(|e| Expression::from_parse_tree(e, source)) .collect::>(); Self { loc: source.pointer(loc), expressions, } } } impl PrettyPrintable for ExpressionList { fn prettyprint(&self, buffer: PrintoutAccumulator) -> PrintoutAccumulator { buffer.write_separated_list(&self.expressions, ",") } } ================================================ FILE: parser-lib/src/ast/nodes/expression_statement.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use crate::{ ast::{ Expression, ExpressionStatement, SourceBuffer, derive::Derive, prettyprint::{PrettyPrintable, printout_accumulator::PrintoutAccumulator}, }, grammar::Rule, }; impl Derive for ExpressionStatement { fn from_parse_tree(p: pest::iterators::Pair<'_, Rule>, source: &SourceBuffer) -> Self { assert!(p.as_rule() == Rule::expr_stmt); let loc = From::from(&p.as_span()); let mut inner = p.into_inner(); let val = inner.next().map(|p| Expression::from_parse_tree(p, source)); Self { loc: source.pointer(loc), val, } } } impl PrettyPrintable for ExpressionStatement { fn prettyprint(&self, buffer: PrintoutAccumulator) -> PrintoutAccumulator { if let Some(val) = &self.val { buffer << val << ";" } else { buffer << ";" } } } ================================================ FILE: parser-lib/src/ast/nodes/extension_decl.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use crate::{ ast::{ Expression, ExtensionDecl, SourceBuffer, StructEntry, derive::Derive, prettyprint::{PrettyPrintable, printout_accumulator::PrintoutAccumulator}, }, grammar::Rule, }; impl Derive for ExtensionDecl { fn from_parse_tree(p: pest::iterators::Pair<'_, Rule>, source: &SourceBuffer) -> Self { assert!(p.as_rule() == Rule::extension_decl); let loc = From::from(&p.as_span()); let mut inner = p.into_inner(); let target = Expression::from_parse_tree(inner.next().expect("need identifier"), source); let inherits = if let Some(next) = inner.peek() { if next.as_rule() == Rule::expr_list { let expr_list = inner.next().unwrap(); expr_list .into_inner() .map(|expr| Expression::from_parse_tree(expr, source)) .collect() } else { vec![] } } else { vec![] }; let mut body = vec![]; for next in inner { let next = StructEntry::from_parse_tree(next, source); body.push(next); } Self { loc: source.pointer(loc), target, inherits, body, } } } impl PrettyPrintable for ExtensionDecl { fn prettyprint(&self, buffer: PrintoutAccumulator) -> PrintoutAccumulator { (buffer << "extension " << &self.target).write_indented_list(&self.body, "{\n", "\n", "\n}") } } ================================================ FILE: parser-lib/src/ast/nodes/float_literal.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use crate::{ ast::{ FloatLiteral, SourceBuffer, derive::Derive, prettyprint::{PrettyPrintable, printout_accumulator::PrintoutAccumulator}, }, grammar::Rule, }; impl Derive for FloatLiteral { fn from_parse_tree(p: pest::iterators::Pair<'_, Rule>, source: &SourceBuffer) -> Self { assert!(p.as_rule() == Rule::fp_literal); let loc = From::from(&p.as_span()); Self { loc: source.pointer(loc), val: p.as_str().to_owned(), } } } impl PrettyPrintable for FloatLiteral { fn prettyprint(&self, buffer: PrintoutAccumulator) -> PrintoutAccumulator { buffer.write(&self.val) } } ================================================ FILE: parser-lib/src/ast/nodes/for_statement.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use crate::{ ast::{ CodeBlock, ElsePiece, Expression, ForStatement, Identifier, derive::Derive, prettyprint::{PrettyPrintable, printout_accumulator::PrintoutAccumulator}, }, grammar::Rule, }; impl Derive for ForStatement { fn from_parse_tree( p: pest::iterators::Pair<'_, crate::grammar::Rule>, source: &crate::ast::SourceBuffer, ) -> Self { assert!(p.as_rule() == Rule::for_stmt); let loc = From::from(&p.as_span()); let mut inner = p.into_inner(); let id = Identifier::from_parse_tree(inner.next().expect("need identifier"), source); let expr = Expression::from_parse_tree(inner.next().expect("need expression"), source); let then = CodeBlock::from_parse_tree(inner.next().expect("need then block"), source); let els = inner .next() .map(|else_p| ElsePiece::from_parse_tree(else_p, source)); Self { loc: source.pointer(loc), id, expr, then, els, } } } impl PrettyPrintable for ForStatement { fn prettyprint(&self, buffer: PrintoutAccumulator) -> PrintoutAccumulator { buffer << "for( " << &self.id << " in " << &self.expr << ") " << &self.then } } ================================================ FILE: parser-lib/src/ast/nodes/function_body.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use crate::{ ast::{ CodeBlock, Expression, FunctionBody, ReturnStatement, SourceBuffer, Statement, derive::Derive, prettyprint::{PrettyPrintable, printout_accumulator::PrintoutAccumulator}, }, grammar::Rule, }; impl Derive for FunctionBody { fn from_parse_tree(p: pest::iterators::Pair<'_, Rule>, source: &SourceBuffer) -> Self { assert!(p.as_rule() == Rule::function_body); let loc = From::from(&p.as_span()); let mut inner_body = p.into_inner(); let i = inner_body.next().expect("need inner body part"); match i.as_rule() { Rule::code_block => Self { code: CodeBlock::from_parse_tree(i, source), }, Rule::expression => { let expr = Expression::from_parse_tree(i, source); let return_stmt = ReturnStatement { loc: expr.loc().clone(), val: Some(expr), }; Self { code: CodeBlock { loc: source.pointer(loc), entries: vec![Statement::ReturnStatement(return_stmt)], }, } } _ => panic!("Unexpected rule for inner function body: {i:?}"), } } } impl PrettyPrintable for FunctionBody { fn prettyprint(&self, buffer: PrintoutAccumulator) -> PrintoutAccumulator { buffer << &self.code } } ================================================ FILE: parser-lib/src/ast/nodes/function_decl.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use crate::{ ast::{ ArgumentList, FunctionBody, FunctionDecl, Identifier, SourceBuffer, derive::Derive, prettyprint::{PrettyPrintable, printout_accumulator::PrintoutAccumulator}, }, grammar::Rule, }; impl Derive for FunctionDecl { fn from_parse_tree(p: pest::iterators::Pair<'_, Rule>, source: &SourceBuffer) -> Self { assert!(p.as_rule() == Rule::function_decl); let loc = From::from(&p.as_span()); let mut inner = p.into_inner(); let name = Identifier::from_parse_tree(inner.next().expect("need identifier"), source); let p = inner.peek().unwrap(); let args = if p.as_rule() == Rule::arg_list { let p = inner.next().unwrap(); ArgumentList::from_parse_tree(p, source) } else { ArgumentList::empty(source.pointer(loc)) }; let body = FunctionBody::from_parse_tree(inner.next().expect("need body"), source); Self { loc: source.pointer(loc), name, args, body, } } } impl PrettyPrintable for FunctionDecl { fn prettyprint(&self, buffer: PrintoutAccumulator) -> PrintoutAccumulator { buffer << "func " << &self.name << " (" << &self.args << ") " << &self.body } } ================================================ FILE: parser-lib/src/ast/nodes/identifier.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use crate::{ ast::{ Identifier, SourceBuffer, derive::Derive, prettyprint::{PrettyPrintable, printout_accumulator::PrintoutAccumulator}, }, grammar::Rule, }; impl Derive for Identifier { fn from_parse_tree(p: pest::iterators::Pair<'_, Rule>, source: &SourceBuffer) -> Self { assert!(p.as_rule() == Rule::identifier); let loc = From::from(&p.as_span()); Self { loc: source.pointer(loc), value: p.as_str().to_owned(), } } } impl PrettyPrintable for Identifier { fn prettyprint(&self, buffer: PrintoutAccumulator) -> PrintoutAccumulator { buffer.write(&self.value) } } ================================================ FILE: parser-lib/src/ast/nodes/identifier_list.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use crate::{ ast::{ Identifier, IdentifierList, SourceBuffer, derive::Derive, prettyprint::{PrettyPrintable, printout_accumulator::PrintoutAccumulator}, }, grammar::Rule, }; impl Derive for IdentifierList { fn from_parse_tree(p: pest::iterators::Pair<'_, Rule>, source: &SourceBuffer) -> Self { assert!(p.as_rule() == Rule::ident_list); let loc = From::from(&p.as_span()); let inner = p.into_inner(); let identifiers = inner .map(|e| Identifier::from_parse_tree(e, source)) .collect::>(); Self { loc: source.pointer(loc), identifiers, } } } impl PrettyPrintable for IdentifierList { fn prettyprint(&self, buffer: PrintoutAccumulator) -> PrintoutAccumulator { buffer.write_separated_list(&self.identifiers, ",") } } ================================================ FILE: parser-lib/src/ast/nodes/if_cond_piece.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use crate::{ ast::{ CodeBlock, Expression, IfCondPiece, SourceBuffer, derive::Derive, prettyprint::{PrettyPrintable, printout_accumulator::PrintoutAccumulator}, }, grammar::Rule, }; impl Derive for IfCondPiece { fn from_parse_tree(p: pest::iterators::Pair<'_, Rule>, source: &SourceBuffer) -> Self { assert!(p.as_rule() == Rule::if_cond_piece); let loc = From::from(&p.as_span()); let mut inner = p.into_inner(); let expr = inner.next().expect("need expression"); let body = inner.next().expect("need body"); let expression = Expression::from_parse_tree(expr, source); let then = CodeBlock::from_parse_tree(body, source); Self { loc: source.pointer(loc), expression: Box::new(expression), then, } } } impl PrettyPrintable for IfCondPiece { fn prettyprint(&self, buffer: PrintoutAccumulator) -> PrintoutAccumulator { buffer << "(" << &self.expression << ")" << &self.then } } ================================================ FILE: parser-lib/src/ast/nodes/if_piece.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use crate::{ ast::{ IfCondPiece, IfPiece, SourceBuffer, derive::Derive, prettyprint::{PrettyPrintable, printout_accumulator::PrintoutAccumulator}, }, grammar::Rule, }; impl Derive for IfPiece { fn from_parse_tree(p: pest::iterators::Pair<'_, Rule>, source: &SourceBuffer) -> Self { assert!(p.as_rule() == Rule::if_piece); let mut inner = p.into_inner(); let content = inner.next().expect("need content"); let content = IfCondPiece::from_parse_tree(content, source); Self { content } } } impl PrettyPrintable for IfPiece { fn prettyprint(&self, buffer: PrintoutAccumulator) -> PrintoutAccumulator { buffer << "if " << &self.content } } ================================================ FILE: parser-lib/src/ast/nodes/if_statement.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use crate::{ ast::{ ElsePiece, ElsifPiece, IfPiece, IfStatement, SourceBuffer, derive::Derive, prettyprint::{PrettyPrintable, printout_accumulator::PrintoutAccumulator}, }, grammar::Rule, }; impl Derive for IfStatement { fn from_parse_tree(p: pest::iterators::Pair<'_, Rule>, source: &SourceBuffer) -> Self { assert!(p.as_rule() == Rule::if_stmt); let loc = From::from(&p.as_span()); let mut inner = p.into_inner(); let ifpiece = inner.next().expect("need if piece"); let iff = IfPiece::from_parse_tree(ifpiece, source); let mut elsif_pieces = vec![]; loop { let p = inner.peek(); if p.is_none() { break; } if p.unwrap().as_rule() != Rule::elsif_piece { break; } let p = inner.next().unwrap(); let elsif_rule = ElsifPiece::from_parse_tree(p, source); elsif_pieces.push(elsif_rule); } let p = inner.peek(); let els = if p.is_none() { None } else { let els_piece = inner.next().unwrap(); let els = ElsePiece::from_parse_tree(els_piece, source); Some(els) }; Self { loc: source.pointer(loc), iff, elsif: elsif_pieces, els, } } } impl PrettyPrintable for IfStatement { fn prettyprint(&self, buffer: PrintoutAccumulator) -> PrintoutAccumulator { let mut this = self.iff.prettyprint(buffer); for elsif in &self.elsif { this = elsif.prettyprint(this); } this << &self.els } } ================================================ FILE: parser-lib/src/ast/nodes/import_from_statement.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use crate::{ ast::{ ImportFromStatement, ImportPath, ImportTarget, SourceBuffer, derive::Derive, prettyprint::{PrettyPrintable, printout_accumulator::PrintoutAccumulator}, }, grammar::Rule, }; impl Derive for ImportFromStatement { fn from_parse_tree(p: pest::iterators::Pair<'_, Rule>, source: &SourceBuffer) -> Self { assert!(p.as_rule() == Rule::import_id_stmt); let loc = From::from(&p.as_span()); let mut inner = p.into_inner(); let what = ImportTarget::from_parse_tree(inner.next().expect("need identifiers"), source); let from = ImportPath::from_parse_tree(inner.next().expect("need a path"), source); Self { loc: source.pointer(loc), what, from, } } } impl PrettyPrintable for ImportFromStatement { fn prettyprint(&self, buffer: PrintoutAccumulator) -> PrintoutAccumulator { buffer << "import " << &self.what << " from " << &self.from << ";" } } ================================================ FILE: parser-lib/src/ast/nodes/import_path.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use crate::{ ast::{ Identifier, ImportPath, SourceBuffer, derive::Derive, prettyprint::{PrettyPrintable, printout_accumulator::PrintoutAccumulator}, }, grammar::Rule, }; impl Derive for ImportPath { fn from_parse_tree(p: pest::iterators::Pair<'_, Rule>, source: &SourceBuffer) -> Self { assert!(p.as_rule() == Rule::import_path); let loc = From::from(&p.as_span()); let inner = p.into_inner(); let entries = inner .map(|x| Identifier::from_parse_tree(x, source)) .collect(); Self { loc: source.pointer(loc), entries, } } } impl PrettyPrintable for ImportPath { fn prettyprint(&self, buffer: PrintoutAccumulator) -> PrintoutAccumulator { buffer.write_separated_list(&self.entries, ".") } } ================================================ FILE: parser-lib/src/ast/nodes/import_statement.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use crate::{ ast::{ ImportPath, ImportStatement, SourceBuffer, derive::Derive, prettyprint::{PrettyPrintable, printout_accumulator::PrintoutAccumulator}, }, grammar::Rule, }; impl Derive for ImportStatement { fn from_parse_tree(p: pest::iterators::Pair<'_, Rule>, source: &SourceBuffer) -> Self { assert!(p.as_rule() == Rule::import_stmt); let loc = From::from(&p.as_span()); let mut inner = p.into_inner(); let what = ImportPath::from_parse_tree(inner.next().expect("need a path"), source); Self { loc: source.pointer(loc), what, } } } impl PrettyPrintable for ImportStatement { fn prettyprint(&self, buffer: PrintoutAccumulator) -> PrintoutAccumulator { buffer << "import " << &self.what << ";" } } ================================================ FILE: parser-lib/src/ast/nodes/import_target.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use crate::{ ast::{ IdentifierList, ImportTarget, SourceBuffer, derive::Derive, prettyprint::{PrettyPrintable, printout_accumulator::PrintoutAccumulator}, }, grammar::Rule, }; impl Derive for ImportTarget { fn from_parse_tree(p: pest::iterators::Pair<'_, Rule>, source: &SourceBuffer) -> Self { assert!(p.as_rule() == Rule::import_target); let mut inner = p.into_inner(); let tgt = inner.next().expect("need an import target"); match tgt.as_rule() { Rule::ident_list => Self::IdentifierList(IdentifierList::from_parse_tree(tgt, source)), Rule::import_all => Self::All, _ => panic!("invalid import target"), } } } impl PrettyPrintable for ImportTarget { fn prettyprint(&self, buffer: PrintoutAccumulator) -> PrintoutAccumulator { match self { ImportTarget::IdentifierList(il) => il.prettyprint(buffer), ImportTarget::All => buffer << "*", } } } ================================================ FILE: parser-lib/src/ast/nodes/int_literal.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use crate::ast::{ IntLiteral, IntLiteralBase, derive::Derive, prettyprint::{PrettyPrintable, printout_accumulator::PrintoutAccumulator}, }; impl Derive for IntLiteral { fn from_parse_tree( p: pest::iterators::Pair<'_, crate::grammar::Rule>, source: &crate::ast::SourceBuffer, ) -> Self { assert!(p.as_rule() == crate::grammar::Rule::int_literal); let loc = From::from(&p.as_span()); let val = p.as_str().to_owned(); let base = match p .into_inner() .next() .expect("need a literal content") .as_rule() { crate::grammar::Rule::bin_int_literal => IntLiteralBase::Binary, crate::grammar::Rule::oct_int_literal => IntLiteralBase::Octal, crate::grammar::Rule::dec_int_literal => IntLiteralBase::Decimal, crate::grammar::Rule::hex_int_literal => IntLiteralBase::Hexadecimal, _ => panic!("unexpected int literal base"), }; Self { loc: source.pointer(loc), base, val, } } } impl PrettyPrintable for IntLiteral { fn prettyprint(&self, buffer: PrintoutAccumulator) -> PrintoutAccumulator { buffer.write(&self.val) } } ================================================ FILE: parser-lib/src/ast/nodes/lambda_body.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use crate::{ ast::{ CodeBlock, Expression, LambdaBody, derive::Derive, prettyprint::{PrettyPrintable, printout_accumulator::PrintoutAccumulator}, }, gen_from_options, }; impl Derive for LambdaBody { gen_from_options!(lambda_f_body; (code_block, CodeBlock), (expression, Expression)); } impl PrettyPrintable for LambdaBody { fn prettyprint(&self, buffer: PrintoutAccumulator) -> PrintoutAccumulator { match self { LambdaBody::CodeBlock(c) => c.prettyprint(buffer), LambdaBody::Expression(e) => e.prettyprint(buffer), } } } ================================================ FILE: parser-lib/src/ast/nodes/lambda_function.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use crate::{ ast::{ ArgumentList, LambdaBody, LambdaFunction, SourceBuffer, derive::Derive, prettyprint::{PrettyPrintable, printout_accumulator::PrintoutAccumulator}, }, grammar::Rule, }; impl Derive for LambdaFunction { fn from_parse_tree(p: pest::iterators::Pair<'_, Rule>, source: &SourceBuffer) -> Self { assert!(p.as_rule() == Rule::lambda_f); let loc = From::from(&p.as_span()); let mut inner = p.into_inner(); let args = ArgumentList::from_parse_tree(inner.next().expect("need arguments"), source); let body = LambdaBody::from_parse_tree(inner.next().expect("need body"), source); Self { loc: source.pointer(loc), args, body: Box::new(body), } } } impl PrettyPrintable for LambdaFunction { fn prettyprint(&self, buffer: PrintoutAccumulator) -> PrintoutAccumulator { buffer << "|" << &self.args << "| => " << &self.body } } ================================================ FILE: parser-lib/src/ast/nodes/list_literal.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use crate::{ ast::{ ExpressionList, ListLiteral, SourceBuffer, derive::Derive, prettyprint::{PrettyPrintable, printout_accumulator::PrintoutAccumulator}, }, grammar::Rule, }; impl Derive for ListLiteral { fn from_parse_tree(p: pest::iterators::Pair<'_, Rule>, source: &SourceBuffer) -> Self { assert!(p.as_rule() == Rule::list_literal); let loc = From::from(&p.as_span()); let mut inner = p.into_inner(); let items = if let Some(next) = inner.next() { ExpressionList::from_parse_tree(next, source) } else { ExpressionList::empty(source.pointer(loc)) }; Self { loc: source.pointer(loc), items, } } } impl PrettyPrintable for ListLiteral { fn prettyprint(&self, buffer: PrintoutAccumulator) -> PrintoutAccumulator { buffer << "[" << &self.items << "]" } } ================================================ FILE: parser-lib/src/ast/nodes/log_operation.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use crate::{ ast::{ CompOperation, LogOperation, LogSymbol, SourceBuffer, derive::Derive, prettyprint::{PrettyPrintable, printout_accumulator::PrintoutAccumulator}, }, grammar::Rule, }; impl Derive for LogOperation { #[allow(clippy::len_zero)] fn from_parse_tree(p: pest::iterators::Pair<'_, Rule>, source: &SourceBuffer) -> Self { assert!(p.as_rule() == Rule::log); let loc = From::from(&p.as_span()); let mut inner = p.into_inner(); if inner.len() == 1 { let left = CompOperation::from_parse_tree(inner.peek().expect("need a mul"), source); Self { loc: source.pointer(loc), left, right: vec![], } } else if inner.len() > 0 { let left = CompOperation::from_parse_tree(inner.next().expect("need a left mul"), source); let mut right = vec![]; loop { let op = inner.next(); if op.is_none() { break; }; let op = LogSymbol::from_parse_tree(op.unwrap(), source); let atom = CompOperation::from_parse_tree( inner.next().expect("add needs a right hand side"), source, ); right.push((op, atom)); } Self { loc: source.pointer(loc), left, right, } } else { panic!("add does not contain") } } } impl PrettyPrintable for LogOperation { fn prettyprint(&self, buffer: PrintoutAccumulator) -> PrintoutAccumulator { let mut this = self.left.prettyprint(buffer); for (op, atom) in &self.right { this = this << op << atom; } this } } ================================================ FILE: parser-lib/src/ast/nodes/log_symbol.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use crate::{ ast::{ LogSymbol, SourceBuffer, derive::Derive, prettyprint::{PrettyPrintable, printout_accumulator::PrintoutAccumulator}, }, grammar::Rule, }; impl Derive for LogSymbol { fn from_parse_tree(p: pest::iterators::Pair<'_, Rule>, _: &SourceBuffer) -> Self { assert!(p.as_rule() == Rule::log_op); match p.as_str() { "&" => Self::Ampersand, "^" => Self::Caret, "|" => Self::Pipe, "&&" => Self::DoubleAmpersand, "||" => Self::DoublePipe, _ => panic!("&^| expected"), } } } impl PrettyPrintable for LogSymbol { fn prettyprint(&self, buffer: PrintoutAccumulator) -> PrintoutAccumulator { buffer.write(match self { Self::Ampersand => "&", Self::DoubleAmpersand => "&&", Self::Caret => "^", Self::Pipe => "|", Self::DoublePipe => "||", }) } } ================================================ FILE: parser-lib/src/ast/nodes/match_pattern.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use crate::{ ast::{ MatchPattern, MatchPatternComp, MatchPatternEnumCase, MatchPatternRel, derive::Derive, prettyprint::{PrettyPrintable, printout_accumulator::PrintoutAccumulator}, }, gen_from_options, }; impl Derive for MatchPattern { gen_from_options!( match_pattern; (match_pattern_comp, MatchPatternComp), (match_pattern_enum_case, MatchPatternEnumCase), (match_pattern_rel, MatchPatternRel), ); } impl PrettyPrintable for MatchPattern { fn prettyprint(&self, buffer: PrintoutAccumulator) -> PrintoutAccumulator { match self { Self::MatchPatternComp(e) => e.prettyprint(buffer), Self::MatchPatternRel(e) => e.prettyprint(buffer), Self::MatchPatternEnumCase(e) => e.prettyprint(buffer), } } } ================================================ FILE: parser-lib/src/ast/nodes/match_pattern_comp.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use crate::{ ast::{ CompSymbol, Expression, MatchPatternComp, derive::Derive, prettyprint::{PrettyPrintable, printout_accumulator::PrintoutAccumulator}, }, gen_from_components, }; impl Derive for MatchPatternComp { gen_from_components!(match_pattern_comp; op: CompSymbol, expr: Expression); } impl PrettyPrintable for MatchPatternComp { fn prettyprint(&self, buffer: PrintoutAccumulator) -> PrintoutAccumulator { buffer << &self.op << &self.expr } } ================================================ FILE: parser-lib/src/ast/nodes/match_pattern_enum_case.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use crate::{ ast::{ DeclarationId, Identifier, MatchPatternEnumCase, SourceBuffer, derive::Derive, prettyprint::{PrettyPrintable, printout_accumulator::PrintoutAccumulator}, }, grammar::Rule, }; impl Derive for MatchPatternEnumCase { fn from_parse_tree(p: pest::iterators::Pair<'_, Rule>, source: &SourceBuffer) -> Self { assert!(p.as_rule() == Rule::match_pattern_enum_case); let loc = From::from(&p.as_span()); let mut inner = p.into_inner(); let case = Identifier::from_parse_tree(inner.next().expect("need expression"), source); let payload = inner .next() .map(|next| DeclarationId::from_parse_tree(next, source)); Self { loc: source.pointer(loc), case, payload, } } } impl PrettyPrintable for MatchPatternEnumCase { fn prettyprint(&self, buffer: PrintoutAccumulator) -> PrintoutAccumulator { let buffer = buffer << " case " << &self.case; if let Some(p) = &self.payload { buffer << "(" << p << ")" } else { buffer } } } ================================================ FILE: parser-lib/src/ast/nodes/match_pattern_rel.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use crate::{ ast::{ Expression, MatchPatternRel, RelSymbol, derive::Derive, prettyprint::{PrettyPrintable, printout_accumulator::PrintoutAccumulator}, }, gen_from_components, }; impl Derive for MatchPatternRel { gen_from_components!(match_pattern_rel; op: RelSymbol, expr: Expression); } impl PrettyPrintable for MatchPatternRel { fn prettyprint(&self, buffer: PrintoutAccumulator) -> PrintoutAccumulator { buffer << &self.op << &self.expr } } ================================================ FILE: parser-lib/src/ast/nodes/match_rule.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use crate::{ ast::{ CodeBlock, MatchPattern, MatchRule, SourceBuffer, derive::Derive, prettyprint::{PrettyPrintable, printout_accumulator::PrintoutAccumulator}, }, grammar::Rule, }; impl Derive for MatchRule { fn from_parse_tree(p: pest::iterators::Pair<'_, Rule>, source: &SourceBuffer) -> Self { assert!(p.as_rule() == Rule::match_rule); let loc = From::from(&p.as_span()); let mut inner = p.into_inner(); let mut patterns = vec![]; let then = { loop { let next = inner.next().expect("need rules"); match next.as_rule() { Rule::match_pattern => { patterns.push(MatchPattern::from_parse_tree(next, source)); } Rule::code_block => { break CodeBlock::from_parse_tree(next, source); } _ => panic!("invalid rule entry"), } } }; Self { loc: source.pointer(loc), patterns, then, } } } impl PrettyPrintable for MatchRule { fn prettyprint(&self, buffer: PrintoutAccumulator) -> PrintoutAccumulator { buffer.write_separated_list(&self.patterns, " and ") << " => " << &self.then } } ================================================ FILE: parser-lib/src/ast/nodes/match_statement.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use crate::{ ast::{ ElsePiece, Expression, MatchRule, MatchStatement, SourceBuffer, derive::Derive, prettyprint::{PrettyPrintable, printout_accumulator::PrintoutAccumulator}, }, grammar::Rule, }; impl Derive for MatchStatement { fn from_parse_tree(p: pest::iterators::Pair<'_, Rule>, source: &SourceBuffer) -> Self { assert!(p.as_rule() == Rule::match_stmt); let loc = From::from(&p.as_span()); let mut inner = p.into_inner(); let expr = Expression::from_parse_tree(inner.next().expect("need expression"), source); let mut rules = vec![]; let els = { loop { let next = match inner.next() { Some(x) => x, None => { break None; } }; match next.as_rule() { Rule::match_rule => { rules.push(MatchRule::from_parse_tree(next, source)); } Rule::else_piece => { break Some(ElsePiece::from_parse_tree(next, source)); } _ => panic!("invalid rule entry"), } } }; Self { loc: source.pointer(loc), expr, rules, els, } } } impl PrettyPrintable for MatchStatement { fn prettyprint(&self, buffer: PrintoutAccumulator) -> PrintoutAccumulator { let buffer = (buffer << "match " << &self.expr).write_indented_list(&self.rules, "{\n", "\n", ""); if let Some(e) = &self.els { buffer << "\n else " << e << "\n}" } else { buffer << "\n}" } } } ================================================ FILE: parser-lib/src/ast/nodes/method_access.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use crate::{ ast::{ MethodAccess, SourceBuffer, derive::Derive, prettyprint::{PrettyPrintable, printout_accumulator::PrintoutAccumulator}, }, grammar::Rule, }; impl Derive for MethodAccess { fn from_parse_tree(p: pest::iterators::Pair<'_, Rule>, _: &SourceBuffer) -> Self { assert!(p.as_rule() == Rule::method_access); match p.as_str() { "instance" => Self::Instance, "type" => Self::Type, _ => panic!("instance or type expected"), } } } impl PrettyPrintable for MethodAccess { fn prettyprint(&self, buffer: PrintoutAccumulator) -> PrintoutAccumulator { buffer << match self { MethodAccess::Instance => "instance", MethodAccess::Type => "type", } } } ================================================ FILE: parser-lib/src/ast/nodes/method_decl.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use crate::{ ast::{ ArgumentList, FunctionBody, Identifier, MethodAccess, MethodDecl, SourceBuffer, derive::Derive, prettyprint::{PrettyPrintable, printout_accumulator::PrintoutAccumulator}, }, grammar::Rule, }; impl Derive for MethodDecl { fn from_parse_tree(p: pest::iterators::Pair<'_, Rule>, source: &SourceBuffer) -> Self { assert!(p.as_rule() == Rule::method_decl); let loc = From::from(&p.as_span()); let mut inner = p.into_inner(); let next = inner.peek().expect("expected next"); let access = if next.as_rule() == Rule::method_access { MethodAccess::from_parse_tree(inner.next().unwrap(), source) } else { MethodAccess::Instance }; let name = Identifier::from_parse_tree(inner.next().expect("need identifier"), source); let p = inner.peek().unwrap(); let args = if p.as_rule() == Rule::arg_list { let p = inner.next().unwrap(); ArgumentList::from_parse_tree(p, source) } else { ArgumentList::empty(source.pointer(loc)) }; let body = FunctionBody::from_parse_tree(inner.next().expect("need body"), source); Self { loc: source.pointer(loc), access, name, args, body, } } } impl PrettyPrintable for MethodDecl { fn prettyprint(&self, buffer: PrintoutAccumulator) -> PrintoutAccumulator { buffer << &self.access << " func " << &self.name << " (" << &self.args << ") " << &self.body } } ================================================ FILE: parser-lib/src/ast/nodes/mixin_decl.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use crate::{ ast::{ Identifier, MixinDecl, SourceBuffer, StructEntry, derive::Derive, prettyprint::{PrettyPrintable, printout_accumulator::PrintoutAccumulator}, }, grammar::Rule, }; impl Derive for MixinDecl { fn from_parse_tree(p: pest::iterators::Pair<'_, Rule>, source: &SourceBuffer) -> Self { assert!(p.as_rule() == Rule::mixin_decl); let loc = From::from(&p.as_span()); let mut inner = p.into_inner(); let name = Identifier::from_parse_tree(inner.next().expect("need identifier"), source); let mut body = vec![]; for next in inner { let next = StructEntry::from_parse_tree(next, source); body.push(next); } Self { loc: source.pointer(loc), name, body, } } } impl PrettyPrintable for MixinDecl { fn prettyprint(&self, buffer: PrintoutAccumulator) -> PrintoutAccumulator { (buffer << "mixin " << &self.name).write_indented_list(&self.body, "{\n", "\n", "\n}") } } ================================================ FILE: parser-lib/src/ast/nodes/mixin_include_decl.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use crate::{ ast::{ Expression, MixinIncludeDecl, derive::Derive, prettyprint::{PrettyPrintable, printout_accumulator::PrintoutAccumulator}, }, gen_from_components, }; impl Derive for MixinIncludeDecl { gen_from_components!(mixin_include_decl; what: Expression); } impl PrettyPrintable for MixinIncludeDecl { fn prettyprint(&self, buffer: PrintoutAccumulator) -> PrintoutAccumulator { buffer << "include " << &self.what } } ================================================ FILE: parser-lib/src/ast/nodes/mod.rs ================================================ // SPDX-License-Identifier: Apache-2.0 mod add_eq_symbol; mod add_operation; mod add_symbol; mod argument_decl; mod argument_list; mod assert_statement; mod assign_statement; mod break_statement; mod code_block; mod comp_operation; mod comp_symbol; mod continue_statement; mod declaration_id; mod else_piece; mod elsif_piece; mod enum_case_decl; mod enum_decl; mod enum_decl_entry; mod expression; mod expression_list; mod expression_statement; mod extension_decl; mod float_literal; mod for_statement; mod function_body; mod function_decl; mod identifier; mod identifier_list; mod if_cond_piece; mod if_piece; mod if_statement; mod import_from_statement; mod import_path; mod import_statement; mod import_target; mod int_literal; mod lambda_body; mod lambda_function; mod list_literal; mod log_operation; mod log_symbol; mod match_pattern; mod match_pattern_comp; mod match_pattern_enum_case; mod match_pattern_rel; mod match_rule; mod match_statement; mod method_access; mod method_decl; mod mixin_decl; mod mixin_include_decl; mod module_flag; mod module_flags; mod mul_operation; mod mul_symbol; mod operator_decl; mod operator_symbol; mod paren_expression; mod parsed_module; mod postfix_expression; mod postfix_rvalue; mod postfix_term; mod postfix_term_attribute; mod postfix_term_call; mod postfix_term_enum_case; mod postfix_term_field_write; mod postfix_term_index; mod postfix_term_index_write; mod postfix_term_object_write; mod postfix_term_try_protocol; mod postfix_term_write; mod postfix_term_write_list; mod primary; mod rel_operation; mod rel_symbol; mod return_statement; mod shift_operation; mod shift_symbol; mod statement; mod string_literal; mod struct_decl; mod struct_entry; mod ternary_expression; mod throw_statement; mod top_level_entry; mod try_block; mod try_unwrap_expression; mod unary_operation; mod unary_symbol; mod val_decl_entry; mod val_decl_statement; mod while_statement; mod write_op_eq_statement; ================================================ FILE: parser-lib/src/ast/nodes/module_flag.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use crate::{ ast::{ Identifier, ModuleFlag, SourceBuffer, StringLiteral, derive::Derive, prettyprint::{PrettyPrintable, printout_accumulator::PrintoutAccumulator}, }, grammar::Rule, }; impl Derive for ModuleFlag { fn from_parse_tree(p: pest::iterators::Pair<'_, Rule>, source: &SourceBuffer) -> Self { assert!(p.as_rule() == Rule::module_flag); let mut inner = p.into_inner(); let flag = Identifier::from_parse_tree(inner.next().expect("need flag"), source); match flag.value.as_str() { "no_std" => Self::NoStandardLibrary, "uses_dylib" => { let path = StringLiteral::from_parse_tree(inner.next().expect("need path"), source); Self::UsesDylib(path.value) } _ => panic!("unknown module flag"), } } } impl PrettyPrintable for ModuleFlag { fn prettyprint(&self, buffer: PrintoutAccumulator) -> PrintoutAccumulator { match self { ModuleFlag::NoStandardLibrary => buffer << "flag: no_std;", ModuleFlag::UsesDylib(dylib) => buffer << "flag: uses_dylib(" << dylib.as_str() << ");", } } } ================================================ FILE: parser-lib/src/ast/nodes/module_flags.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use crate::{ ast::{ ModuleFlag, ModuleFlags, SourceBuffer, derive::Derive, prettyprint::{PrettyPrintable, printout_accumulator::PrintoutAccumulator}, }, grammar::Rule, }; impl Derive for ModuleFlags { fn from_parse_tree(p: pest::iterators::Pair<'_, Rule>, source: &SourceBuffer) -> Self { assert!(p.as_rule() == Rule::module_flags); let inner = p.into_inner(); let mut flags = vec![]; for entry in inner { match entry.as_rule() { Rule::module_flag => { flags.push(ModuleFlag::from_parse_tree(entry, source)); } _ => panic!("invalid module flag"), } } Self { flags } } } impl PrettyPrintable for ModuleFlags { fn prettyprint(&self, buffer: PrintoutAccumulator) -> PrintoutAccumulator { buffer.write_separated_list(&self.flags, "\n") } } ================================================ FILE: parser-lib/src/ast/nodes/mul_operation.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use crate::{ ast::{ MulOperation, MulSymbol, SourceBuffer, UnaryOperation, derive::Derive, prettyprint::{PrettyPrintable, printout_accumulator::PrintoutAccumulator}, }, grammar::Rule, }; impl Derive for MulOperation { #[allow(clippy::len_zero)] fn from_parse_tree(p: pest::iterators::Pair<'_, Rule>, source: &SourceBuffer) -> Self { assert!(p.as_rule() == Rule::mul); let loc = From::from(&p.as_span()); let mut inner = p.into_inner(); let left = UnaryOperation::from_parse_tree(inner.peek().expect("need an atom"), source); if inner.len() == 1 { Self { loc: source.pointer(loc), left, right: vec![], } } else if inner.len() > 0 { let _ = inner.next(); let mut right = vec![]; loop { let op = inner.next(); if op.is_none() { break; }; let op = MulSymbol::from_parse_tree(op.unwrap(), source); let atom = UnaryOperation::from_parse_tree( inner.next().expect("mul needs a right hand side"), source, ); right.push((op, atom)); } Self { loc: source.pointer(loc), left, right, } } else { panic!("mul does not contain") } } } impl PrettyPrintable for MulOperation { fn prettyprint(&self, buffer: PrintoutAccumulator) -> PrintoutAccumulator { let mut this = self.left.prettyprint(buffer); for (op, atom) in &self.right { this = this << op << atom; } this } } ================================================ FILE: parser-lib/src/ast/nodes/mul_symbol.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use crate::{ ast::{ MulSymbol, SourceBuffer, derive::Derive, prettyprint::{PrettyPrintable, printout_accumulator::PrintoutAccumulator}, }, grammar::Rule, }; impl Derive for MulSymbol { fn from_parse_tree(p: pest::iterators::Pair<'_, Rule>, _: &SourceBuffer) -> Self { assert!(p.as_rule() == Rule::mul_op); match p.as_str() { "*" => MulSymbol::Star, "/" => MulSymbol::Slash, "%" => MulSymbol::Percent, _ => panic!("one of *, / or % expected"), } } } impl PrettyPrintable for MulSymbol { fn prettyprint(&self, buffer: PrintoutAccumulator) -> PrintoutAccumulator { buffer.write(match self { Self::Star => "*", Self::Slash => "/", Self::Percent => "%", }) } } ================================================ FILE: parser-lib/src/ast/nodes/operator_decl.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use crate::{ ast::{ ArgumentList, FunctionBody, OperatorDecl, OperatorSymbol, SourceBuffer, derive::Derive, prettyprint::{PrettyPrintable, printout_accumulator::PrintoutAccumulator}, }, grammar::Rule, }; impl Derive for OperatorDecl { fn from_parse_tree(p: pest::iterators::Pair<'_, Rule>, source: &SourceBuffer) -> Self { assert!(p.as_rule() == Rule::operator_decl); let loc = From::from(&p.as_span()); let mut inner = p.into_inner(); let next = inner.peek().expect("expected next"); let reverse = if next.as_rule() == Rule::operator_direction { let _ = inner.next(); true } else { false }; let symbol = OperatorSymbol::from_parse_tree(inner.next().expect("need operator symbol"), source); let next = inner.peek().unwrap(); let args = if next.as_rule() == Rule::arg_list { let p = inner.next().unwrap(); ArgumentList::from_parse_tree(p, source) } else { ArgumentList::empty(source.pointer(loc)) }; let body = FunctionBody::from_parse_tree(inner.next().expect("need body"), source); Self { loc: source.pointer(loc), reverse, symbol, args, body, } } } impl PrettyPrintable for OperatorDecl { fn prettyprint(&self, buffer: PrintoutAccumulator) -> PrintoutAccumulator { buffer << if self.reverse { "reverse operator " } else { "operator " } << &self.symbol << " (" << &self.args << ") " << &self.body } } ================================================ FILE: parser-lib/src/ast/nodes/operator_symbol.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use crate::{ ast::{ OperatorSymbol, SourceBuffer, derive::Derive, prettyprint::{PrettyPrintable, printout_accumulator::PrintoutAccumulator}, }, grammar::Rule, }; impl Derive for OperatorSymbol { fn from_parse_tree(p: pest::iterators::Pair<'_, Rule>, _: &SourceBuffer) -> Self { assert!(p.as_rule() == Rule::operator_symbol); match p.as_str() { "+" => Self::Plus, "-" => Self::Minus, "u-" => Self::UnaryMinus, "*" => Self::Star, "/" => Self::Slash, "%" => Self::Percent, "<<" => Self::LeftShift, ">>" => Self::RightShift, "==" => Self::Equals, "<=" => Self::LessThanEqual, ">=" => Self::GreaterThanEqual, "<" => Self::LessThan, ">" => Self::GreaterThan, "&" => Self::BitwiseAnd, "|" => Self::BitwiseOr, "^" => Self::BitwiseXor, "()" => Self::Call, "[]" => Self::GetSquareBrackets, "[]=" => Self::SetSquareBrackets, _ => panic!("valid operator symbol expected, found: {}", p.as_str()), } } } impl PrettyPrintable for OperatorSymbol { fn prettyprint(&self, buffer: PrintoutAccumulator) -> PrintoutAccumulator { buffer.write(match self { Self::Plus => "+", Self::Minus => "-", Self::UnaryMinus => "u-", Self::Star => "*", Self::Slash => "/", Self::Percent => "%", Self::LeftShift => "<<", Self::RightShift => ">>", Self::LessThanEqual => "<=", Self::GreaterThanEqual => ">=", Self::LessThan => "<", Self::GreaterThan => ">", Self::Equals => "==", Self::BitwiseAnd => "&", Self::BitwiseOr => "|", Self::BitwiseXor => "^", Self::Call => "()", Self::GetSquareBrackets => "[]", Self::SetSquareBrackets => "[]=", }) } } ================================================ FILE: parser-lib/src/ast/nodes/paren_expression.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use crate::{ ast::{ Expression, ParenExpression, SourceBuffer, derive::Derive, prettyprint::{PrettyPrintable, printout_accumulator::PrintoutAccumulator}, }, grammar::Rule, }; impl Derive for ParenExpression { fn from_parse_tree(p: pest::iterators::Pair<'_, Rule>, source: &SourceBuffer) -> Self { assert!(p.as_rule() == Rule::paren_expr); let loc = From::from(&p.as_span()); let mut inner = p.into_inner(); let value = Expression::from_parse_tree(inner.next().expect("need expression"), source); Self { loc: source.pointer(loc), value: Box::new(value), } } } impl PrettyPrintable for ParenExpression { fn prettyprint(&self, buffer: PrintoutAccumulator) -> PrintoutAccumulator { buffer << "(" << &self.value << ")" } } ================================================ FILE: parser-lib/src/ast/nodes/parsed_module.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use crate::{ ast::{ ModuleFlags, ParsedModule, SourceBuffer, TopLevelEntry, derive::Derive, prettyprint::{PrettyPrintable, printout_accumulator::PrintoutAccumulator}, }, grammar::Rule, }; impl Derive for ParsedModule { fn from_parse_tree(p: pest::iterators::Pair<'_, Rule>, source: &SourceBuffer) -> Self { assert!(p.as_rule() == Rule::module); let loc = From::from(&p.as_span()); let inner = p.into_inner(); let mut flags = ModuleFlags::empty(); let mut entries = vec![]; for entry in inner { match entry.as_rule() { Rule::module_flags => flags = ModuleFlags::from_parse_tree(entry, source), Rule::top_level_entry => { entries.push(TopLevelEntry::from_parse_tree(entry, source)) } _ => {} } } Self { loc: source.pointer(loc), flags, entries, } } } impl PrettyPrintable for ParsedModule { fn prettyprint(&self, buffer: PrintoutAccumulator) -> PrintoutAccumulator { self.flags .prettyprint(buffer) .write_separated_list(&self.entries, "\n") } } ================================================ FILE: parser-lib/src/ast/nodes/postfix_expression.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use crate::{ ast::{ PostfixExpression, PostfixTerm, Primary, SourceBuffer, derive::Derive, prettyprint::{PrettyPrintable, printout_accumulator::PrintoutAccumulator}, }, grammar::Rule, }; impl Derive for PostfixExpression { fn from_parse_tree(p: pest::iterators::Pair<'_, Rule>, source: &SourceBuffer) -> Self { assert!(p.as_rule() == Rule::postfix_lv); let loc = From::from(&p.as_span()); let mut inner = p.into_inner(); let base = Primary::from_parse_tree(inner.next().expect("postfix need base"), source); let mut terms = vec![]; loop { let next = inner.next(); if next.is_none() { break; }; let next = PostfixTerm::from_parse_tree(next.expect("need postfix term"), source); terms.push(next); } Self { loc: source.pointer(loc), base, terms, } } } impl PrettyPrintable for PostfixExpression { fn prettyprint(&self, buffer: PrintoutAccumulator) -> PrintoutAccumulator { let mut this = self.base.prettyprint(buffer); for term in &self.terms { this = term.prettyprint(this); } this } } ================================================ FILE: parser-lib/src/ast/nodes/postfix_rvalue.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use crate::{ ast::{ PostfixExpression, PostfixRvalue, derive::Derive, prettyprint::{PrettyPrintable, printout_accumulator::PrintoutAccumulator}, }, gen_from_components, }; impl Derive for PostfixRvalue { gen_from_components!(postfix_rv; expr: PostfixExpression); } impl PrettyPrintable for PostfixRvalue { fn prettyprint(&self, buffer: PrintoutAccumulator) -> PrintoutAccumulator { self.expr.prettyprint(buffer) } } ================================================ FILE: parser-lib/src/ast/nodes/postfix_term.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use crate::{ ast::{ PostfixTerm, derive::Derive, prettyprint::{PrettyPrintable, printout_accumulator::PrintoutAccumulator}, }, gen_from_options, }; use crate::ast::{ PostfixTermAttribute, PostfixTermCall, PostfixTermEnumCase, PostfixTermIndex, PostfixTermObjectWrite, PostfixTermTryProtocol, }; impl Derive for PostfixTerm { gen_from_options!( postfix_term; (postfix_term_attrib, PostfixTermAttribute), (postfix_term_index, PostfixTermIndex), (postfix_term_call, PostfixTermCall), (postfix_term_enum_case, PostfixTermEnumCase), (postfix_term_object_write, PostfixTermObjectWrite), (postfix_term_try_protocol, PostfixTermTryProtocol) ); } impl PrettyPrintable for PostfixTerm { fn prettyprint(&self, buffer: PrintoutAccumulator) -> PrintoutAccumulator { match self { Self::PostfixTermAttribute(a) => a.prettyprint(buffer), Self::PostfixTermIndex(i) => i.prettyprint(buffer), Self::PostfixTermCall(c) => c.prettyprint(buffer), Self::PostfixTermEnumCase(c) => c.prettyprint(buffer), Self::PostfixTermObjectWrite(w) => w.prettyprint(buffer), Self::PostfixTermTryProtocol(t) => t.prettyprint(buffer), } } } ================================================ FILE: parser-lib/src/ast/nodes/postfix_term_attribute.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use crate::{ ast::{ Identifier, PostfixTermAttribute, derive::Derive, prettyprint::{PrettyPrintable, printout_accumulator::PrintoutAccumulator}, }, gen_from_components, }; impl Derive for PostfixTermAttribute { gen_from_components!(postfix_term_attrib; id: Identifier); } impl PrettyPrintable for PostfixTermAttribute { fn prettyprint(&self, buffer: PrintoutAccumulator) -> PrintoutAccumulator { buffer << "." << &self.id } } ================================================ FILE: parser-lib/src/ast/nodes/postfix_term_call.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use crate::{ ast::{ ExpressionList, PostfixTermCall, SourceBuffer, derive::Derive, prettyprint::{PrettyPrintable, printout_accumulator::PrintoutAccumulator}, }, grammar::Rule, }; impl Derive for PostfixTermCall { fn from_parse_tree(p: pest::iterators::Pair<'_, Rule>, source: &SourceBuffer) -> Self { assert!(p.as_rule() == Rule::postfix_term_call); let loc = From::from(&p.as_span()); let mut inner = p.into_inner(); let args = inner.find(|val| val.as_rule() == Rule::expr_list); let args = if let Some(el) = args { ExpressionList::from_parse_tree(el, source) } else { ExpressionList::empty(source.pointer(loc)) }; Self { loc: source.pointer(loc), args, } } } impl PrettyPrintable for PostfixTermCall { fn prettyprint(&self, buffer: PrintoutAccumulator) -> PrintoutAccumulator { buffer << "(" << &self.args << ")" } } ================================================ FILE: parser-lib/src/ast/nodes/postfix_term_enum_case.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use crate::{ ast::{ Expression, Identifier, PostfixTermEnumCase, SourceBuffer, derive::Derive, prettyprint::{PrettyPrintable, printout_accumulator::PrintoutAccumulator}, }, grammar::Rule, }; impl Derive for PostfixTermEnumCase { fn from_parse_tree(p: pest::iterators::Pair<'_, Rule>, source: &SourceBuffer) -> Self { assert!(p.as_rule() == Rule::postfix_term_enum_case); let loc = From::from(&p.as_span()); let mut inner = p.into_inner(); let id = Identifier::from_parse_tree(inner.next().expect("need identifier"), source); let payload = inner .next() .map(|next| Expression::from_parse_tree(next, source)); Self { loc: source.pointer(loc), id, payload, } } } impl PrettyPrintable for PostfixTermEnumCase { fn prettyprint(&self, buffer: PrintoutAccumulator) -> PrintoutAccumulator { let buffer = buffer << "::" << &self.id; if let Some(payload) = &self.payload { buffer << "(" << payload << ")" } else { buffer } } } ================================================ FILE: parser-lib/src/ast/nodes/postfix_term_field_write.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use crate::{ ast::{ Expression, Identifier, PostfixTermFieldWrite, SourceBuffer, derive::Derive, prettyprint::{PrettyPrintable, printout_accumulator::PrintoutAccumulator}, }, grammar::Rule, }; impl Derive for PostfixTermFieldWrite { fn from_parse_tree(p: pest::iterators::Pair<'_, Rule>, source: &SourceBuffer) -> Self { assert!(p.as_rule() == Rule::postfix_term_field_write); let loc = From::from(&p.as_span()); let mut inner = p.into_inner(); let id = Identifier::from_parse_tree(inner.next().expect("postfix need id"), source); let val = inner.next().map(|p| Expression::from_parse_tree(p, source)); Self { loc: source.pointer(loc), id, val, } } } impl PrettyPrintable for PostfixTermFieldWrite { fn prettyprint(&self, buffer: PrintoutAccumulator) -> PrintoutAccumulator { let buffer = buffer << "." << &self.id; if let Some(val) = &self.val { buffer << " = " << val } else { buffer } } } ================================================ FILE: parser-lib/src/ast/nodes/postfix_term_index.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use crate::ast::{ ExpressionList, PostfixTermIndex, derive::Derive, prettyprint::{PrettyPrintable, printout_accumulator::PrintoutAccumulator}, }; impl Derive for PostfixTermIndex { fn from_parse_tree( p: pest::iterators::Pair<'_, crate::grammar::Rule>, source: &crate::ast::SourceBuffer, ) -> Self { assert!(p.as_rule() == crate::grammar::Rule::postfix_term_index); let loc = From::from(&p.as_span()); let mut inner = p.into_inner(); let index = inner .next() .map_or(ExpressionList::empty(source.pointer(loc)), |e| { ::from_parse_tree(e, source) }); Self { loc: source.pointer(loc), index, } } } impl PrettyPrintable for PostfixTermIndex { fn prettyprint(&self, buffer: PrintoutAccumulator) -> PrintoutAccumulator { buffer << "[" << &self.index << "]" } } ================================================ FILE: parser-lib/src/ast/nodes/postfix_term_index_write.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use crate::ast::{ Expression, ExpressionList, PostfixTermIndexWrite, derive::Derive, prettyprint::{PrettyPrintable, printout_accumulator::PrintoutAccumulator}, }; impl Derive for PostfixTermIndexWrite { fn from_parse_tree( p: pest::iterators::Pair<'_, crate::grammar::Rule>, source: &crate::ast::SourceBuffer, ) -> Self { assert!(p.as_rule() == crate::grammar::Rule::postfix_term_index_write); let loc = From::from(&p.as_span()); let mut inner = p.into_inner(); let idx = if inner.peek().expect("need index").as_rule() == crate::grammar::Rule::expr_list { ::from_parse_tree( inner.next().expect(concat!("need ", stringify!(idx))), source, ) } else { ExpressionList::empty(source.pointer(loc)) }; let val = ::from_parse_tree( inner.next().expect(concat!("need ", stringify!(val))), source, ); Self { loc: source.pointer(loc), idx, val, } } } impl PrettyPrintable for PostfixTermIndexWrite { fn prettyprint(&self, buffer: PrintoutAccumulator) -> PrintoutAccumulator { buffer << "[" << &self.idx << "] = " << &self.val } } ================================================ FILE: parser-lib/src/ast/nodes/postfix_term_object_write.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use crate::{ ast::{ PostfixTermObjectWrite, PostfixTermWriteList, derive::Derive, prettyprint::{PrettyPrintable, printout_accumulator::PrintoutAccumulator}, }, gen_from_components, }; impl Derive for PostfixTermObjectWrite { gen_from_components!(postfix_term_object_write; terms: PostfixTermWriteList); } impl PrettyPrintable for PostfixTermObjectWrite { fn prettyprint(&self, buffer: PrintoutAccumulator) -> PrintoutAccumulator { buffer << "{" << &self.terms << "}" } } ================================================ FILE: parser-lib/src/ast/nodes/postfix_term_try_protocol.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use crate::{ ast::{ PostfixTermTryProtocol, SourceBuffer, TryProtocolMode, derive::Derive, prettyprint::{PrettyPrintable, printout_accumulator::PrintoutAccumulator}, }, grammar::Rule, }; impl Derive for PostfixTermTryProtocol { fn from_parse_tree(p: pest::iterators::Pair<'_, Rule>, source: &SourceBuffer) -> Self { assert!(p.as_rule() == Rule::postfix_term_try_protocol); let loc = From::from(&p.as_span()); let token_rule = p .into_inner() .next() .and_then(|inner| inner.into_inner().next()) .map(|inner| inner.as_rule()) .unwrap_or_else(|| panic!("? or ! expected")); let mode = match token_rule { Rule::postfix_term_try_protocol_return_token => TryProtocolMode::Return, Rule::postfix_term_try_protocol_assert_token => TryProtocolMode::Assert, _ => panic!("? or ! expected"), }; Self { loc: source.pointer(loc), mode, } } } impl PrettyPrintable for PostfixTermTryProtocol { fn prettyprint(&self, buffer: PrintoutAccumulator) -> PrintoutAccumulator { buffer << match self.mode { TryProtocolMode::Assert => "!", TryProtocolMode::Return => "?", } } } ================================================ FILE: parser-lib/src/ast/nodes/postfix_term_write.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use crate::{ ast::{ PostfixTermFieldWrite, PostfixTermIndexWrite, PostfixTermWrite, derive::Derive, prettyprint::{PrettyPrintable, printout_accumulator::PrintoutAccumulator}, }, gen_from_options, }; impl Derive for PostfixTermWrite { gen_from_options!(postfix_term_write; (postfix_term_field_write, PostfixTermFieldWrite), (postfix_term_index_write, PostfixTermIndexWrite)); } impl PrettyPrintable for PostfixTermWrite { fn prettyprint(&self, buffer: PrintoutAccumulator) -> PrintoutAccumulator { match self { Self::PostfixTermFieldWrite(v) => v.prettyprint(buffer), Self::PostfixTermIndexWrite(v) => v.prettyprint(buffer), } } } ================================================ FILE: parser-lib/src/ast/nodes/postfix_term_write_list.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use crate::{ ast::{ PostfixTermWrite, PostfixTermWriteList, SourceBuffer, derive::Derive, prettyprint::{PrettyPrintable, printout_accumulator::PrintoutAccumulator}, }, grammar::Rule, }; impl Derive for PostfixTermWriteList { fn from_parse_tree(p: pest::iterators::Pair<'_, Rule>, source: &SourceBuffer) -> Self { assert!(p.as_rule() == Rule::postfix_term_write_list); let loc = From::from(&p.as_span()); let inner = p.into_inner(); let terms = inner .map(|i| PostfixTermWrite::from_parse_tree(i, source)) .collect(); Self { loc: source.pointer(loc), terms, } } } impl PrettyPrintable for PostfixTermWriteList { fn prettyprint(&self, buffer: PrintoutAccumulator) -> PrintoutAccumulator { buffer.write_separated_list(&self.terms, ", ") } } ================================================ FILE: parser-lib/src/ast/nodes/primary.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use crate::{ ast::{ Primary, derive::Derive, prettyprint::{PrettyPrintable, printout_accumulator::PrintoutAccumulator}, }, gen_from_options, }; use crate::ast::FloatLiteral; use crate::ast::Identifier; use crate::ast::IntLiteral; use crate::ast::ListLiteral; use crate::ast::ParenExpression; use crate::ast::StringLiteral; impl Derive for Primary { gen_from_options!( primary; (int_literal, IntLiteral), (fp_literal, FloatLiteral), (identifier, Identifier), (list_literal, ListLiteral), (str_literal, StringLiteral), (paren_expr, ParenExpression) ); } impl PrettyPrintable for Primary { fn prettyprint(&self, buffer: PrintoutAccumulator) -> PrintoutAccumulator { match self { Self::IntLiteral(il) => il.prettyprint(buffer), Self::FloatLiteral(fp) => fp.prettyprint(buffer), Self::Identifier(id) => id.prettyprint(buffer), Self::ListLiteral(ll) => ll.prettyprint(buffer), Self::StringLiteral(sl) => sl.prettyprint(buffer), Self::ParenExpression(pe) => pe.prettyprint(buffer), } } } ================================================ FILE: parser-lib/src/ast/nodes/rel_operation.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use crate::{ ast::{ RelOperation, RelSymbol, ShiftOperation, SourceBuffer, derive::Derive, prettyprint::{PrettyPrintable, printout_accumulator::PrintoutAccumulator}, }, grammar::Rule, }; impl Derive for RelOperation { fn from_parse_tree(p: pest::iterators::Pair<'_, Rule>, source: &SourceBuffer) -> Self { assert!(p.as_rule() == Rule::rel); let loc = From::from(&p.as_span()); let mut inner = p.into_inner(); if inner.len() == 1 { let left = ShiftOperation::from_parse_tree(inner.next().expect("left operand"), source); Self { loc: source.pointer(loc), left, right: None, } } else if inner.len() == 3 { let left = ShiftOperation::from_parse_tree(inner.next().expect("left operand"), source); let op = RelSymbol::from_parse_tree(inner.next().expect("rel operator"), source); let right = ShiftOperation::from_parse_tree(inner.next().expect("right operand"), source); Self { loc: source.pointer(loc), left, right: Some((op, right)), } } else { panic!("invalid rel length"); } } } impl PrettyPrintable for RelOperation { fn prettyprint(&self, buffer: PrintoutAccumulator) -> PrintoutAccumulator { let this = self.left.prettyprint(buffer); if let Some(rhs) = &self.right { this << &rhs.0 << &rhs.1 } else { this } } } ================================================ FILE: parser-lib/src/ast/nodes/rel_symbol.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use crate::{ ast::{ RelSymbol, SourceBuffer, derive::Derive, prettyprint::{PrettyPrintable, printout_accumulator::PrintoutAccumulator}, }, grammar::Rule, }; impl Derive for RelSymbol { fn from_parse_tree(p: pest::iterators::Pair<'_, Rule>, _: &SourceBuffer) -> Self { assert!(p.as_rule() == Rule::rel_op); match p.as_str() { "<" => RelSymbol::Less, "<=" => RelSymbol::LessEqual, ">" => RelSymbol::Greater, ">=" => RelSymbol::GreaterEqual, _ => panic!("<=> expected"), } } } impl PrettyPrintable for RelSymbol { fn prettyprint(&self, buffer: PrintoutAccumulator) -> PrintoutAccumulator { buffer.write(match self { Self::Less => "<", Self::LessEqual => "<=", Self::Greater => ">", Self::GreaterEqual => ">=", }) } } ================================================ FILE: parser-lib/src/ast/nodes/return_statement.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use crate::{ ast::{ Expression, ReturnStatement, SourceBuffer, derive::Derive, prettyprint::{PrettyPrintable, printout_accumulator::PrintoutAccumulator}, }, grammar::Rule, }; impl Derive for ReturnStatement { fn from_parse_tree(p: pest::iterators::Pair<'_, Rule>, source: &SourceBuffer) -> Self { assert!(p.as_rule() == Rule::return_stmt); let loc = From::from(&p.as_span()); let mut inner = p.into_inner(); let val = inner.next().map(|p| Expression::from_parse_tree(p, source)); Self { loc: source.pointer(loc), val, } } } impl PrettyPrintable for ReturnStatement { fn prettyprint(&self, buffer: PrintoutAccumulator) -> PrintoutAccumulator { let mut buffer = buffer << "return"; if let Some(val) = &self.val { buffer = buffer << " " << val; } buffer << ";" } } ================================================ FILE: parser-lib/src/ast/nodes/shift_operation.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use crate::{ ast::{ AddOperation, ShiftOperation, ShiftSymbol, SourceBuffer, derive::Derive, prettyprint::{PrettyPrintable, printout_accumulator::PrintoutAccumulator}, }, grammar::Rule, }; impl Derive for ShiftOperation { fn from_parse_tree(p: pest::iterators::Pair<'_, Rule>, source: &SourceBuffer) -> Self { assert!(p.as_rule() == Rule::shift); let loc = From::from(&p.as_span()); let mut inner = p.into_inner(); if inner.len() == 1 { let left = AddOperation::from_parse_tree(inner.next().expect("left operand"), source); Self { loc: source.pointer(loc), left, right: None, } } else if inner.len() == 3 { let left = AddOperation::from_parse_tree(inner.next().expect("left operand"), source); let op = ShiftSymbol::from_parse_tree(inner.next().expect("shift operator"), source); let right = AddOperation::from_parse_tree(inner.next().expect("right operand"), source); Self { loc: source.pointer(loc), left, right: Some((op, right)), } } else { panic!("invalid shift length"); } } } impl PrettyPrintable for ShiftOperation { fn prettyprint(&self, buffer: PrintoutAccumulator) -> PrintoutAccumulator { let this = self.left.prettyprint(buffer); if let Some(rhs) = &self.right { this << &rhs.0 << &rhs.1 } else { this } } } ================================================ FILE: parser-lib/src/ast/nodes/shift_symbol.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use crate::{ ast::{ ShiftSymbol, SourceBuffer, derive::Derive, prettyprint::{PrettyPrintable, printout_accumulator::PrintoutAccumulator}, }, grammar::Rule, }; impl Derive for ShiftSymbol { fn from_parse_tree(p: pest::iterators::Pair<'_, Rule>, _: &SourceBuffer) -> Self { assert!(p.as_rule() == Rule::shift_op); match p.as_str() { "<<" => Self::Leftward, ">>" => Self::Rightward, _ => panic!("<< or >> expected"), } } } impl PrettyPrintable for ShiftSymbol { fn prettyprint(&self, buffer: PrintoutAccumulator) -> PrintoutAccumulator { buffer.write(match self { Self::Leftward => "<<", Self::Rightward => ">>", }) } } ================================================ FILE: parser-lib/src/ast/nodes/statement.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use crate::{ ast::{ AssertStatement, AssignStatement, BreakStatement, CodeBlock, ContinueStatement, EnumDecl, ExpressionStatement, ForStatement, FunctionDecl, IfStatement, MatchStatement, ReturnStatement, Statement, StructDecl, ThrowStatement, TryBlock, ValDeclStatement, WhileStatement, WriteOpEqStatement, derive::Derive, prettyprint::{PrettyPrintable, printout_accumulator::PrintoutAccumulator}, }, gen_from_options, }; impl Derive for Statement { gen_from_options!( statement; (assert_stmt, AssertStatement), (break_stmt, BreakStatement), (code_block, CodeBlock), (continue_stmt, ContinueStatement), (expr_stmt, ExpressionStatement), (for_stmt, ForStatement), (if_stmt, IfStatement), (match_stmt, MatchStatement), (return_stmt, ReturnStatement), (throw_stmt, ThrowStatement), (try_block, TryBlock), (val_add_eq_write, WriteOpEqStatement), (val_decl_stmt, ValDeclStatement), (val_write_stmt, AssignStatement), (while_stmt, WhileStatement), (struct_decl, StructDecl), (enum_decl, EnumDecl), (function_decl, FunctionDecl), ); } impl PrettyPrintable for Statement { fn prettyprint(&self, buffer: PrintoutAccumulator) -> PrintoutAccumulator { match self { Self::ValDeclStatement(v) => v.prettyprint(buffer), Self::AssignStatement(a) => a.prettyprint(buffer), Self::WriteOpEqStatement(w) => w.prettyprint(buffer), Self::IfStatement(i) => i.prettyprint(buffer), Self::MatchStatement(m) => m.prettyprint(buffer), Self::WhileStatement(w) => w.prettyprint(buffer), Self::ForStatement(f) => f.prettyprint(buffer), Self::CodeBlock(c) => c.prettyprint(buffer), Self::ReturnStatement(r) => r.prettyprint(buffer), Self::ThrowStatement(t) => t.prettyprint(buffer), Self::TryBlock(t) => t.prettyprint(buffer), Self::AssertStatement(a) => a.prettyprint(buffer), Self::ExpressionStatement(e) => e.prettyprint(buffer), Self::BreakStatement(b) => b.prettyprint(buffer), Self::ContinueStatement(c) => c.prettyprint(buffer), Self::StructDecl(s) => s.prettyprint(buffer), Self::EnumDecl(e) => e.prettyprint(buffer), Self::FunctionDecl(f) => f.prettyprint(buffer), } } } ================================================ FILE: parser-lib/src/ast/nodes/string_literal.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use crate::{ ast::{ SourceBuffer, StringLiteral, derive::Derive, prettyprint::{PrettyPrintable, printout_accumulator::PrintoutAccumulator}, }, grammar::Rule, }; // TODO: process string literals in the compiler code, not the parser // the parser has no good way to report an error, so complete the processing // in the compiler where we can fail on an invalid escape sequence fn process_string_literal(s: &str) -> String { fn process_string_escapes(s: &str) -> String { let mut result = String::new(); let mut chars = s.chars().peekable(); while let Some(c) = chars.next() { if c == '\\' { if let Some(next) = chars.peek() { match next { 'n' => { result.push('\n'); chars.next(); } 'r' => { result.push('\r'); chars.next(); } 't' => { result.push('\t'); chars.next(); } '\\' => { result.push('\\'); chars.next(); } 'X' | 'x' => { let _ = chars.next(); if let (Some(high), Some(low)) = (chars.next(), chars.next()) && let (Some(high), Some(low)) = (high.to_digit(16), low.to_digit(16)) { result.push((high << 4 | low) as u8 as char); } } 'U' | 'u' => { let _ = chars.next(); if chars.peek() == Some(&'{') { let _ = chars.next(); let mut hex_digits = String::new(); while let Some(&next) = chars.peek() { if next == '}' { let _ = chars.next(); break; } else { hex_digits.push(chars.next().unwrap()); } } if let Ok(codepoint) = u32::from_str_radix(&hex_digits, 16) && let Some(chr) = char::from_u32(codepoint) { result.push(chr); } } } _ => { result.push(c); } } } else { result.push(c); } } else { result.push(c); } } result } let s = &s[1..s.len() - 1]; process_string_escapes(s) } impl Derive for StringLiteral { fn from_parse_tree(p: pest::iterators::Pair<'_, Rule>, source: &SourceBuffer) -> Self { assert!(p.as_rule() == Rule::str_literal); let loc = From::from(&p.as_span()); Self { loc: source.pointer(loc), value: process_string_literal(p.as_str()), } } } impl PrettyPrintable for StringLiteral { fn prettyprint(&self, buffer: PrintoutAccumulator) -> PrintoutAccumulator { buffer.write(&self.value) } } ================================================ FILE: parser-lib/src/ast/nodes/struct_decl.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use crate::{ ast::{ Expression, Identifier, SourceBuffer, StructDecl, StructEntry, derive::Derive, prettyprint::{PrettyPrintable, printout_accumulator::PrintoutAccumulator}, }, grammar::Rule, }; impl Derive for StructDecl { fn from_parse_tree(p: pest::iterators::Pair<'_, Rule>, source: &SourceBuffer) -> Self { assert!(p.as_rule() == Rule::struct_decl); let loc = From::from(&p.as_span()); let mut inner = p.into_inner(); let name = Identifier::from_parse_tree(inner.next().expect("need identifier"), source); let inherits = if let Some(next) = inner.peek() { if next.as_rule() == Rule::expr_list { let expr_list = inner.next().unwrap(); expr_list .into_inner() .map(|expr| Expression::from_parse_tree(expr, source)) .collect() } else { vec![] } } else { vec![] }; let mut body = vec![]; for next in inner { let next = StructEntry::from_parse_tree(next, source); body.push(next); } Self { loc: source.pointer(loc), name, inherits, body, } } } impl PrettyPrintable for StructDecl { fn prettyprint(&self, buffer: PrintoutAccumulator) -> PrintoutAccumulator { (buffer << "struct " << &self.name).write_indented_list(&self.body, "{\n", "\n", "\n}") } } ================================================ FILE: parser-lib/src/ast/nodes/struct_entry.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use crate::{ ast::{ EnumDecl, MethodDecl, MixinIncludeDecl, OperatorDecl, SourceBuffer, StructDecl, StructEntry, ValDeclStatement, derive::Derive, prettyprint::{PrettyPrintable, printout_accumulator::PrintoutAccumulator}, }, grammar::Rule, }; impl Derive for StructEntry { fn from_parse_tree(p: pest::iterators::Pair<'_, Rule>, source: &SourceBuffer) -> Self { assert!(p.as_rule() == Rule::struct_entry); let content = p.into_inner().next().expect("needs an atom inside"); match content.as_rule() { Rule::method_decl => { Self::Method(Box::new(MethodDecl::from_parse_tree(content, source))) } Rule::operator_decl => { Self::Operator(Box::new(OperatorDecl::from_parse_tree(content, source))) } Rule::val_decl_stmt => { Self::Variable(Box::new(ValDeclStatement::from_parse_tree(content, source))) } Rule::struct_decl => { Self::Struct(Box::new(StructDecl::from_parse_tree(content, source))) } Rule::enum_decl => Self::Enum(Box::new(EnumDecl::from_parse_tree(content, source))), Rule::mixin_include_decl => { Self::MixinInclude(Box::new(MixinIncludeDecl::from_parse_tree(content, source))) } _ => panic!("invalid struct entry kind"), } } } impl PrettyPrintable for StructEntry { fn prettyprint(&self, buffer: PrintoutAccumulator) -> PrintoutAccumulator { match self { Self::Method(m) => m.prettyprint(buffer), Self::Operator(o) => o.prettyprint(buffer), Self::Variable(v) => v.prettyprint(buffer << "type "), Self::Struct(s) => s.prettyprint(buffer), Self::Enum(e) => e.prettyprint(buffer), Self::MixinInclude(m) => m.prettyprint(buffer), } } } ================================================ FILE: parser-lib/src/ast/nodes/ternary_expression.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use crate::{ ast::{ Expression, LogOperation, SourceBuffer, TernaryExpression, derive::Derive, prettyprint::{PrettyPrintable, printout_accumulator::PrintoutAccumulator}, }, grammar::Rule, }; impl Derive for TernaryExpression { fn from_parse_tree(p: pest::iterators::Pair<'_, Rule>, source: &SourceBuffer) -> Self { assert!(p.as_rule() == Rule::ternary_expr); let loc = From::from(&p.as_span()); let mut inner = p.into_inner(); let condition = LogOperation::from_parse_tree(inner.next().unwrap(), source); let true_expression = Expression::from_parse_tree(inner.next().unwrap(), source); let false_expression = Expression::from_parse_tree(inner.next().unwrap(), source); TernaryExpression { loc: source.pointer(loc), condition: Box::new(condition), true_expression: Box::new(true_expression), false_expression: Box::new(false_expression), } } } impl PrettyPrintable for TernaryExpression { fn prettyprint(&self, buffer: PrintoutAccumulator) -> PrintoutAccumulator { self.condition.prettyprint(buffer) << " ? " << self.true_expression.as_ref() << " : " << self.false_expression.as_ref() } } ================================================ FILE: parser-lib/src/ast/nodes/throw_statement.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use crate::{ ast::{ Expression, ThrowStatement, derive::Derive, prettyprint::{PrettyPrintable, printout_accumulator::PrintoutAccumulator}, }, gen_from_components, }; impl Derive for ThrowStatement { gen_from_components!(throw_stmt; val: Expression); } impl PrettyPrintable for ThrowStatement { fn prettyprint(&self, buffer: PrintoutAccumulator) -> PrintoutAccumulator { buffer << "throw " << &self.val << ";" } } ================================================ FILE: parser-lib/src/ast/nodes/top_level_entry.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use crate::{ ast::{ AssertStatement, AssignStatement, CodeBlock, EnumDecl, ExpressionStatement, ExtensionDecl, ForStatement, FunctionDecl, IfStatement, ImportFromStatement, ImportStatement, MatchStatement, MixinDecl, StructDecl, TopLevelEntry, TryBlock, ValDeclStatement, WhileStatement, WriteOpEqStatement, derive::Derive, prettyprint::{PrettyPrintable, printout_accumulator::PrintoutAccumulator}, }, gen_from_options, }; impl Derive for TopLevelEntry { gen_from_options!( top_level_entry; (assert_stmt, AssertStatement), (enum_decl, EnumDecl), (expr_stmt, ExpressionStatement), (extension_decl, ExtensionDecl), (function_decl, FunctionDecl), (import_id_stmt, ImportFromStatement), (import_stmt, ImportStatement), (mixin_decl, MixinDecl), (struct_decl, StructDecl), (val_decl_stmt, ValDeclStatement), (val_write_stmt, AssignStatement), (if_stmt, IfStatement), (match_stmt, MatchStatement), (while_stmt, WhileStatement), (for_stmt, ForStatement), (val_add_eq_write, WriteOpEqStatement), (try_block, TryBlock), (code_block, CodeBlock), ); } impl PrettyPrintable for TopLevelEntry { fn prettyprint(&self, buffer: PrintoutAccumulator) -> PrintoutAccumulator { match self { Self::ValDeclStatement(v) => v.prettyprint(buffer), Self::WriteOpEqStatement(w) => w.prettyprint(buffer), Self::AssignStatement(a) => a.prettyprint(buffer), Self::FunctionDecl(f) => f.prettyprint(buffer), Self::StructDecl(s) => s.prettyprint(buffer), Self::MixinDecl(m) => m.prettyprint(buffer), Self::EnumDecl(e) => e.prettyprint(buffer), Self::ExtensionDecl(e) => e.prettyprint(buffer), Self::AssertStatement(a) => a.prettyprint(buffer), Self::ExpressionStatement(e) => e.prettyprint(buffer), Self::ImportStatement(i) => i.prettyprint(buffer), Self::ImportFromStatement(i) => i.prettyprint(buffer), Self::IfStatement(i) => i.prettyprint(buffer), Self::MatchStatement(m) => m.prettyprint(buffer), Self::WhileStatement(w) => w.prettyprint(buffer), Self::ForStatement(f) => f.prettyprint(buffer), Self::CodeBlock(c) => c.prettyprint(buffer), Self::TryBlock(t) => t.prettyprint(buffer), } } } ================================================ FILE: parser-lib/src/ast/nodes/try_block.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use crate::{ ast::{ CodeBlock, Identifier, TryBlock, derive::Derive, prettyprint::{PrettyPrintable, printout_accumulator::PrintoutAccumulator}, }, gen_from_components, }; impl Derive for TryBlock { gen_from_components!(try_block; body: CodeBlock, id: Identifier, catch: CodeBlock); } impl PrettyPrintable for TryBlock { fn prettyprint(&self, buffer: PrintoutAccumulator) -> PrintoutAccumulator { buffer << "try " << &self.body << " catch (" << &self.id << ") " << &self.catch } } ================================================ FILE: parser-lib/src/ast/nodes/try_unwrap_expression.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use crate::{ ast::{ Expression, LogOperation, SourceBuffer, TryUnwrapExpression, derive::Derive, prettyprint::{PrettyPrintable, printout_accumulator::PrintoutAccumulator}, }, grammar::Rule, }; impl Derive for TryUnwrapExpression { fn from_parse_tree(p: pest::iterators::Pair<'_, Rule>, source: &SourceBuffer) -> Self { assert!(p.as_rule() == Rule::try_unwrap_expr); let loc = From::from(&p.as_span()); let mut inner = p.into_inner(); let left = LogOperation::from_parse_tree(inner.next().unwrap(), source); let right = Expression::from_parse_tree(inner.next().unwrap(), source); TryUnwrapExpression { loc: source.pointer(loc), left: Box::new(left), right: Box::new(right), } } } impl PrettyPrintable for TryUnwrapExpression { fn prettyprint(&self, buffer: PrintoutAccumulator) -> PrintoutAccumulator { self.left.prettyprint(buffer) << " ?? " << self.right.as_ref() } } ================================================ FILE: parser-lib/src/ast/nodes/unary_operation.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use crate::{ ast::{ PostfixExpression, PostfixRvalue, SourceBuffer, UnaryOperation, UnarySymbol, derive::Derive, prettyprint::{PrettyPrintable, printout_accumulator::PrintoutAccumulator}, }, grammar::Rule, }; impl Derive for UnaryOperation { fn from_parse_tree(p: pest::iterators::Pair<'_, Rule>, source: &SourceBuffer) -> Self { assert!(p.as_rule() == Rule::unary); let loc = From::from(&p.as_span()); let mut inner = p.into_inner(); if inner.len() == 1 { let postfix = inner.next().expect("need postfix"); let postfix = PostfixRvalue::from_parse_tree(postfix, source); Self { loc: source.pointer(loc), operand: None, postfix, } } else if inner.len() == 2 { let operand = inner.next().expect("need operand"); let operand = UnarySymbol::from_parse_tree(operand, source); let postfix = inner.next().expect("need postfix"); let postfix = PostfixRvalue::from_parse_tree(postfix, source); if operand == UnarySymbol::Minus && postfix.expr.terms.is_empty() && let Some(il) = postfix.expr.base.as_int_literal() && il.base == crate::ast::IntLiteralBase::Decimal { let new_val = if il.val.starts_with('-') { il.val.strip_prefix('-').unwrap_or(&il.val).to_string() } else { format!("-{}", il.val) }; let new_il = crate::ast::IntLiteral { loc: il.loc.clone(), base: il.base.clone(), val: new_val, }; return Self { loc: source.pointer(loc), operand: None, postfix: PostfixRvalue { loc: postfix.loc.clone(), expr: PostfixExpression { loc: postfix.expr.loc.clone(), base: crate::ast::Primary::IntLiteral(new_il), terms: vec![], }, }, }; } Self { loc: source.pointer(loc), operand: Some(operand), postfix, } } else { panic!("unexpected unary operation structure"); } } } impl PrettyPrintable for UnaryOperation { fn prettyprint(&self, buffer: PrintoutAccumulator) -> PrintoutAccumulator { buffer << &self.operand << &self.postfix } } ================================================ FILE: parser-lib/src/ast/nodes/unary_symbol.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use crate::{ ast::{ SourceBuffer, UnarySymbol, derive::Derive, prettyprint::{PrettyPrintable, printout_accumulator::PrintoutAccumulator}, }, grammar::Rule, }; impl Derive for UnarySymbol { fn from_parse_tree(p: pest::iterators::Pair<'_, Rule>, _: &SourceBuffer) -> Self { assert!(p.as_rule() == Rule::unary_op); match p.as_str() { "!" => Self::Exclamation, "-" => Self::Minus, _ => panic!("! or - expected"), } } } impl PrettyPrintable for UnarySymbol { fn prettyprint(&self, buffer: PrintoutAccumulator) -> PrintoutAccumulator { buffer.write(match self { Self::Exclamation => "!", Self::Minus => "-", }) } } ================================================ FILE: parser-lib/src/ast/nodes/val_decl_entry.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use crate::{ ast::{ DeclarationId, Expression, ValDeclEntry, derive::Derive, prettyprint::{PrettyPrintable, printout_accumulator::PrintoutAccumulator}, }, gen_from_components, }; impl Derive for ValDeclEntry { gen_from_components!(val_decl_entry; id: DeclarationId, val: Expression); } impl PrettyPrintable for ValDeclEntry { fn prettyprint(&self, buffer: PrintoutAccumulator) -> PrintoutAccumulator { buffer << &self.id << " = " << &self.val } } ================================================ FILE: parser-lib/src/ast/nodes/val_decl_statement.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use crate::{ ast::{ SourceBuffer, ValDeclEntry, ValDeclStatement, derive::Derive, prettyprint::{PrettyPrintable, printout_accumulator::PrintoutAccumulator}, }, grammar::Rule, }; impl Derive for ValDeclStatement { fn from_parse_tree(p: pest::iterators::Pair<'_, Rule>, source: &SourceBuffer) -> Self { assert!(p.as_rule() == Rule::val_decl_stmt); let loc = From::from(&p.as_span()); let decls = p .into_inner() .map(|i| ValDeclEntry::from_parse_tree(i, source)) .collect::>(); Self { loc: source.pointer(loc), decls, } } } impl PrettyPrintable for ValDeclStatement { fn prettyprint(&self, buffer: PrintoutAccumulator) -> PrintoutAccumulator { (buffer << "val ").write_separated_list(&self.decls, ", ") << ";" } } ================================================ FILE: parser-lib/src/ast/nodes/while_statement.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use crate::{ ast::{ CodeBlock, ElsePiece, Expression, WhileStatement, derive::Derive, prettyprint::{PrettyPrintable, printout_accumulator::PrintoutAccumulator}, }, grammar::Rule, }; impl Derive for WhileStatement { fn from_parse_tree( p: pest::iterators::Pair<'_, crate::grammar::Rule>, source: &crate::ast::SourceBuffer, ) -> Self { assert!(p.as_rule() == Rule::while_stmt); let loc = From::from(&p.as_span()); let mut inner = p.into_inner(); let cond = Expression::from_parse_tree(inner.next().expect("need condition"), source); let then = CodeBlock::from_parse_tree(inner.next().expect("need then block"), source); let els = inner .next() .map(|else_p| ElsePiece::from_parse_tree(else_p, source)); Self { loc: source.pointer(loc), cond, then, els, } } } impl PrettyPrintable for WhileStatement { fn prettyprint(&self, buffer: PrintoutAccumulator) -> PrintoutAccumulator { buffer << "while " << &self.cond << &self.then } } ================================================ FILE: parser-lib/src/ast/nodes/write_op_eq_statement.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use crate::{ ast::{ AddEqSymbol, Expression, PostfixExpression, WriteOpEqStatement, derive::Derive, prettyprint::{PrettyPrintable, printout_accumulator::PrintoutAccumulator}, }, gen_from_components, }; impl Derive for WriteOpEqStatement { gen_from_components!(val_add_eq_write; id: PostfixExpression, op: AddEqSymbol, val: Expression); } impl PrettyPrintable for WriteOpEqStatement { fn prettyprint(&self, buffer: PrintoutAccumulator) -> PrintoutAccumulator { buffer << &self.id << &self.op << &self.val << ";" } } ================================================ FILE: parser-lib/src/ast/prettyprint/mod.rs ================================================ // SPDX-License-Identifier: Apache-2.0 pub mod printout_accumulator; use crate::ast::prettyprint::printout_accumulator::PrintoutAccumulator; pub trait PrettyPrintable { fn prettyprint( &self, buffer: printout_accumulator::PrintoutAccumulator, ) -> printout_accumulator::PrintoutAccumulator; } impl PrettyPrintable for Box where T: PrettyPrintable, { fn prettyprint(&self, buffer: PrintoutAccumulator) -> PrintoutAccumulator { buffer << self.as_ref() } } ================================================ FILE: parser-lib/src/ast/prettyprint/printout_accumulator.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use crate::ast::prettyprint::PrettyPrintable; #[derive(Default)] pub struct PrintoutAccumulator { buffer: String, depth: usize, } impl PrintoutAccumulator { pub(crate) fn indent_more(mut self) -> Self { self.depth += 1; self } pub(crate) fn indent_less(mut self) -> Self { if self.depth > 0 { self.depth -= 1; } self } pub(crate) fn write(mut self, text: &str) -> Self { if self.depth == 0 || text.find('\n').is_none() { self.buffer.push_str(text); } else { for ch in text.chars() { self.buffer.push(ch); if ch == '\n' { self.buffer.push_str(&" ".repeat(self.depth * 4)); } } } self } pub(crate) fn write_indented_list( self, values: &[T], prefix: &str, sep: &str, suffix: &str, ) -> Self { let mut this = self.indent_more().write(prefix); let mut first = true; for value in values { if first { first = false; } else { this = this.write(sep); } this = value.prettyprint(this); } this.indent_less().write(suffix) } pub(crate) fn write_separated_list( self, values: &[T], sep: &str, ) -> Self { let mut first = true; let mut this = self; for value in values { if first { first = false; } else { this = this.write(sep); } this = value.prettyprint(this); } this } pub fn value(&self) -> String { self.buffer.clone() } } impl<'a, T: PrettyPrintable> std::ops::Shl<&'a T> for PrintoutAccumulator { type Output = Self; fn shl(self, item: &'a T) -> Self::Output { item.prettyprint(self) } } impl<'a> std::ops::Shl<&'a str> for PrintoutAccumulator { type Output = Self; fn shl(self, text: &'a str) -> Self::Output { self.write(text) } } impl std::ops::Shl for PrintoutAccumulator { type Output = Self; fn shl(self, text: String) -> Self::Output { self.write(&text) } } impl std::ops::Shl<&i64> for PrintoutAccumulator { type Output = Self; fn shl(self, n: &i64) -> Self::Output { self.write(&n.to_string()) } } impl std::ops::Shl for PrintoutAccumulator { type Output = Self; fn shl(self, n: f64) -> Self::Output { self.write(&n.to_string()) } } impl std::ops::Shl for PrintoutAccumulator { type Output = Self; fn shl(self, n: usize) -> Self::Output { self.write(&n.to_string()) } } impl std::ops::Shl for PrintoutAccumulator { type Output = Self; fn shl(self, n: u32) -> Self::Output { self.write(&n.to_string()) } } impl std::ops::Shl for PrintoutAccumulator { type Output = Self; fn shl(self, n: u16) -> Self::Output { self.write(&n.to_string()) } } impl std::ops::Shl for PrintoutAccumulator { type Output = Self; fn shl(self, n: u8) -> Self::Output { self.write(&n.to_string()) } } impl std::ops::Shl<&usize> for PrintoutAccumulator { type Output = Self; fn shl(self, n: &usize) -> Self::Output { self.write(&format!("{n}")) } } impl<'a, T> std::ops::Shl<&'a Option> for PrintoutAccumulator where T: PrettyPrintable, { type Output = Self; fn shl(self, val: &'a Option) -> Self::Output { if let Some(val) = val { val.prettyprint(self) } else { self } } } ================================================ FILE: parser-lib/src/grammar/grammar.pest ================================================ WHITESPACE = _{ " " | "\n" | "\t" } COMMENT = _{ "#" ~ (!"\n" ~ ANY)* } // this should only matter for keywords that take an expression keywords = _{ "assert" | "else" | "elsif" | "extension" | "if" | "include" | "match" | "return" | "throw" | "while" } identifier_start = @{ (XID_START | EMOJI_PRESENTATION | "_" | "$") } identifier_next = @{ (XID_CONTINUE | EMOJI_PRESENTATION | "_" | "$") } identifier = @{ !(keywords ~ !identifier_next) ~ !("__" ~ identifier_next*) ~ identifier_start ~ identifier_next* } ident_list = { identifier ~ ("," ~ identifier)* ~ ","? } hex_int_literal = @{ "0x" ~ ASCII_HEX_DIGIT+ ~ ("_" ~ ASCII_HEX_DIGIT+)* } oct_int_literal = @{ "0o" ~ ASCII_OCT_DIGIT+ ~ ("_" ~ ASCII_OCT_DIGIT+)* } bin_int_literal = @{ "0b" ~ ASCII_BIN_DIGIT+ ~ ("_" ~ ASCII_BIN_DIGIT+)* } dec_int_literal = @{ "-"? ~ ASCII_DIGIT+ ~ ("_" ~ ASCII_DIGIT+)* } int_literal = { hex_int_literal | oct_int_literal | bin_int_literal | dec_int_literal } fp_literal = @{ "-"? ~ ASCII_DIGIT+ ~ "." ~ ASCII_DIGIT+ ~ exp_part? ~ "f"? } exp_part = { ("e" | "E") ~ ("+" | "-")? ~ ASCII_DIGIT+ } str_literal_dbl_qt = @{ "\"" ~ (!"\"" ~ ANY)* ~ "\"" } str_literal_sgl_qt = @{ "'" ~ (!"'" ~ ANY)* ~ "'" } str_literal = @{ str_literal_dbl_qt | str_literal_sgl_qt } list_literal = { "[" ~ expr_list? ~ "]" } expr_list = { expression ~ ("," ~ expression)* ~ ","? } paren_expr = { "(" ~ expression ~ ")" } primary = { identifier | fp_literal | str_literal | int_literal | list_literal | paren_expr } postfix_term_field_write = { "." ~ identifier ~ ("=" ~ expression)? } postfix_term_index_write = { "[" ~ expr_list? ~ "]" ~ "=" ~ expression } postfix_term_write = { postfix_term_field_write | postfix_term_index_write } postfix_term_write_list = { postfix_term_write ~ ("," ~ postfix_term_write)* ~ ","? } postfix_term_attrib = { "." ~ identifier } postfix_term_index = { "[" ~ expr_list? ~ "]" } postfix_term_call = { "(" ~ expr_list? ~ ")" } postfix_term_object_write = { "{" ~ postfix_term_write_list ~ "}" } postfix_term_enum_case = { "::" ~ identifier ~ ("(" ~ expression ~ ")")? } ternary_guard = { ternary_guard_start ~ ternary_guard_item* ~ ":" } ternary_guard_start = _{ identifier | fp_literal | str_literal | int_literal | "(" ~ ternary_guard_inner* ~ ")" | "[" ~ ternary_guard_inner* ~ "]" | "!" | "-" | "|" } ternary_guard_item = _{ str_literal | "(" ~ ternary_guard_inner* ~ ")" | "[" ~ ternary_guard_inner* ~ "]" | "{" ~ ternary_guard_inner* ~ "}" | !(":" | ";" | "," | ")" | "]" | "}") ~ ANY } ternary_guard_inner = _{ str_literal | "(" ~ ternary_guard_inner* ~ ")" | "[" ~ ternary_guard_inner* ~ "]" | "{" ~ ternary_guard_inner* ~ "}" | !(")" | "]" | "}") ~ ANY } try_unwrap_guard = { "?" ~ expression } postfix_term_try_protocol_assert_token = @{ "!" ~ !"=" } postfix_term_try_protocol_return_token = @{ "?" } postfix_term_try_protocol_assert = { postfix_term_try_protocol_assert_token } postfix_term_try_protocol_return = { postfix_term_try_protocol_return_token ~ !ternary_guard ~ !try_unwrap_guard } postfix_term_try_protocol = { postfix_term_try_protocol_assert | postfix_term_try_protocol_return } postfix_term = { postfix_term_object_write | postfix_term_enum_case | postfix_term_attrib | postfix_term_index | postfix_term_call | postfix_term_try_protocol } postfix_lv = { primary ~ postfix_term* } postfix_rv = { postfix_lv } unary_op = @{ "!" | "-" } unary = { unary_op? ~ postfix_rv } mul_op = @{ "*" | "/" | "%" } mul = { unary ~ (mul_op ~ unary)* } add_op = @{ "+" | "-" } add = { mul ~ (add_op ~ mul)* } shift_op = @{ "<<" | ">>" } shift = { add ~ (shift_op ~ add)? } rel_op = @{ "<=" | "<" | ">=" | ">" } rel = { shift ~ (rel_op ~ shift)? } comp_op = @{ "==" | "!=" | "isa" } comp = { rel ~ (comp_op ~ rel)? } log_op = @{ "&&" | "||" | "^" | "&" | "|" } log = { comp ~ (log_op ~ comp)* } try_unwrap_expr = { log ~ "??" ~ expression } ternary_expr = { log ~ "?" ~ expression ~ ":" ~ expression } lambda_f_body = { expression | code_block } lambda_f = { "|" ~ arg_list ~ "|" ~ "=>" ~ lambda_f_body } expression = { ternary_expr | lambda_f | try_unwrap_expr | log } decl_id = { identifier ~ (":" ~ expression)? } val_decl_entry = { decl_id ~ "=" ~ expression } val_decl_stmt = { "val" ~ val_decl_entry ~ ("," ~ val_decl_entry)* ~ ";" } val_write_stmt = { postfix_lv ~ ("," ~ postfix_lv)* ~ "=" ~ expression ~ ("," ~ expression)* ~ ";" } add_op_eq = @{ "+=" | "-=" | "*=" | "/=" | "%=" | "<<=" | ">>=" } val_add_eq_write = { postfix_lv ~ add_op_eq ~ expression ~ ";" } if_cond_piece = { expression ~ code_block } if_piece = { "if" ~ if_cond_piece } elsif_piece = { "elsif" ~ if_cond_piece } else_piece = { "else" ~ code_block } if_stmt = { if_piece ~ elsif_piece* ~ else_piece? } match_pattern_comp = { comp_op ~ expression } match_pattern_rel = { rel_op ~ expression } match_pattern_enum_case = { "case" ~ identifier ~ ("(" ~ decl_id ~ ")")? } match_pattern = { match_pattern_enum_case | match_pattern_comp | match_pattern_rel } match_rule = { match_pattern ~ ("and" ~ match_pattern)* ~ "=>" ~ code_block } match_stmt = { "match" ~ expression ~ "{" ~ match_rule ~ (","? ~ match_rule)* ~ ","? ~ "}" ~ else_piece? } while_stmt = { "while" ~ expression ~ code_block ~ else_piece? } for_stmt = { "for" ~ identifier ~ "in" ~ expression ~ code_block ~ else_piece? } return_stmt = { "return" ~ expression? ~ ";" } assert_stmt = { "assert" ~ expression ~ ";" } break_stmt = { "break" ~ ";" } continue_stmt = { "continue" ~ ";" } expr_stmt = { expression? ~ ";" } throw_stmt = { "throw" ~ expression ~ ";" } statement = { break_stmt | continue_stmt | expr_stmt | assert_stmt | val_write_stmt | val_decl_stmt | val_add_eq_write | if_stmt | match_stmt | while_stmt | for_stmt | throw_stmt | return_stmt | code_block | try_block | struct_decl | enum_decl | function_decl } code_block = { "{" ~ (statement)* ~ "}" } try_block = { "try" ~ code_block ~ "catch" ~ identifier ~ code_block } vararg_marker = { "..." ~ ","? } arg_decl = { decl_id ~ ("=" ~ expression)? } arg_list = { (arg_decl ~ ("," ~ arg_decl)* ~ ","?)? ~ vararg_marker? } function_body = { code_block | ("=" ~ expression ~ ";") } function_decl = { "func" ~ identifier ~ "(" ~ arg_list? ~ ")" ~ function_body } method_access = @{ "instance" | "type" } method_decl = { method_access? ~ "func" ~ identifier ~ "(" ~ arg_list? ~ ")" ~ function_body } operator_direction = @{ "reverse" } operator_symbol = @{ "+" | "u-" | "-" | "*" | "/" | "%" | "<<" | ">>" | "==" | "<=" | ">=" | "<" | ">" | "&" | "|" | "^" | "()" | "[]=" | "[]" } operator_decl = { operator_direction? ~ "operator" ~ operator_symbol ~ "(" ~ arg_list? ~ ")" ~ function_body } mixin_decl = { "mixin" ~ identifier ~ "{" ~ struct_entry* ~ "}" } mixin_include_decl = { "include" ~ expression } struct_entry = { method_decl | operator_decl | "type" ~ val_decl_stmt | mixin_include_decl | struct_decl | enum_decl } struct_decl = { "struct" ~ identifier ~ (":" ~ expr_list)? ~ "{" ~ struct_entry* ~ "}" } extension_decl = { "extension" ~ expression ~ (":" ~ expr_list)? ~ "{" ~ struct_entry* ~ "}" } enum_case_decl = { "case" ~ identifier ~ ("(" ~ expression ~ ")")? } enum_decl_entry = { (enum_case_decl | struct_entry) ~ ","? } enum_decl = { "enum" ~ identifier ~ "{" ~ enum_decl_entry* ~ "}" } import_all = { "*" } import_target = { ident_list | import_all } import_path = { identifier ~ ("." ~ identifier)* } import_stmt = { "import" ~ import_path ~ ";" } import_id_stmt = { "import" ~ import_target ~ "from" ~ import_path ~ ";" } top_level_entry = { import_id_stmt | import_stmt | expr_stmt | val_write_stmt | val_decl_stmt | val_add_eq_write | struct_decl | mixin_decl | enum_decl | extension_decl | function_decl | assert_stmt | if_stmt | match_stmt | while_stmt | for_stmt | code_block | try_block } module_flag = { "flag:" ~ identifier ~ ("(" ~ str_literal ~ ")")? ~ ";" } module_flags = { module_flag* } module = { SOI ~ module_flags? ~ top_level_entry* ~ EOI } ================================================ FILE: parser-lib/src/grammar/mod.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use pest_derive::Parser; #[derive(Parser)] #[grammar = "grammar/grammar.pest"] pub struct HaxbyParser; ================================================ FILE: parser-lib/src/lib.rs ================================================ // SPDX-License-Identifier: Apache-2.0 pub mod ast; pub mod grammar; ================================================ FILE: pgo ================================================ #!/bin/sh SELF_DIR="$(cd "$(dirname "$0")" && pwd)" ARIA_LIB_DIR="${ARIA_LIB_DIR:-${SELF_DIR}/lib}" RUST_MIN_STACK=16777216 cargo install cargo-pgo && rustup component add llvm-tools-preview output=$(cargo pgo build -- --profile pgo 2>&1) aria_bin=$(printf "%s\n" "$output" | sed -n 's/.* Now run \(.*\/aria\) on your workload.*/\1/p') # TODO: write a more interesting benchmark workload RUST_MIN_STACK=${RUST_MIN_STACK} ARIA_LIB_DIR=${ARIA_LIB_DIR} ${aria_bin} ${SELF_DIR}/examples/sieve.aria cargo pgo optimize build -- --profile pgo aria_parent=$(dirname "$aria_bin") json=false for arg in "$@"; do if [ "$arg" = "--json" ]; then json=true; break; fi done # emit JSON so that automated tools can process the path to the optimized binary # e.g. path=`jq -r '.output_path' /path/to/json.out` if [ "$json" = true ]; then printf '{"output_path":"%s"}\n' "$aria_parent" else printf 'Run PGO optimized Aria as ARIA_LIB_DIR="%s" %s\n' "${ARIA_LIB_DIR}" "${aria_bin}" fi ================================================ FILE: run_doc_script_tests.sh ================================================ #!/usr/bin/env bash set -euo pipefail SELF_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" ARIA_BUILD_CONFIG="${ARIA_BUILD_CONFIG:-dev}" ARIA_LIB_DIR="${ARIA_LIB_DIR:-${SELF_DIR}/lib:${SELF_DIR}/lib-test}" ARIA_TEST_DIR="${ARIA_TEST_DIR:-${SELF_DIR}/tests}" RUST_MIN_STACK=16777216 print_help() { cat <<'EOF' Usage: run_doc_script_tests.sh INPUT_FILE [OUTDIR] Extract all ```aria fenced code blocks from INPUT_FILE into numbered OUTDIR/*.aria files, run each of them with the local 'aria' binary, and clean up afterwards. If OUTDIR is not provided, a temporary directory under /tmp is created and removed automatically. EOF } if [ "$#" -eq 0 ]; then print_help exit 1 fi if [ "$#" -eq 1 ] && [ "${1-}" = "--help" ]; then print_help exit 0 fi infile="$1" if [ "${2-}" != "" ]; then outdir="$2" cleanup_outdir=0 else outdir="$(mktemp -d /tmp/aria_manual_tests.XXXXXX)" cleanup_outdir=1 fi mkdir -p "$outdir" awk -P -v outdir="$outdir" ' BEGIN { inn=0; idx=0; } # start fence: ```aria /^[[:space:]]*```aria[[:space:]]*$/ { inn=1 fname = outdir "/" idx ".aria" print "" > fname idx++ next } # end fence: ``` /^[[:space:]]*```[[:space:]]*$/ { if (inn==1) { inn=0 close(fname) next } } inn==1 { print >> fname } ' "$infile" [ -d "$outdir" ] || exit 0 for f in "$outdir"/*.aria; do [ -f "$f" ] || continue echo "Running test $f" "${SELF_DIR}/aria" "$f" done if [ "$cleanup_outdir" -eq 1 ]; then rm -rf "$outdir" fi ================================================ FILE: t ================================================ #!/usr/bin/env bash set -e SELF_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" ARIA_BUILD_CONFIG="${ARIA_BUILD_CONFIG:-dev}" ARIA_LIB_DIR="${ARIA_LIB_DIR:-${SELF_DIR}/lib:${SELF_DIR}/lib-test}" ARIA_TEST_DIR="${ARIA_TEST_DIR:-${SELF_DIR}/tests}" RUST_MIN_STACK=16777216 cargo build --workspace --profile "$ARIA_BUILD_CONFIG" ARIA_LIB_DIR="$ARIA_LIB_DIR" cargo test --profile "$ARIA_BUILD_CONFIG" --package vm-lib ARIA_LIB_DIR="$ARIA_LIB_DIR" cargo test --profile "$ARIA_BUILD_CONFIG" --package aria-bin set +e ARIA_LIB_DIR="$ARIA_LIB_DIR" cargo run --profile "$ARIA_BUILD_CONFIG" --package aria-bin -- vm-lib/src/builtins/test_exit.aria EXIT_CODE=$? set -e if [ $EXIT_CODE -ne 42 ]; then echo "❌ test_exit.aria exited with code $EXIT_CODE, expected 42" exit 1 else echo "✅ test_exit.aria exited with code $EXIT_CODE" fi set +e ARIA_LIB_DIR="$ARIA_LIB_DIR" cargo run --profile "$ARIA_BUILD_CONFIG" --package aria-bin -- aria-bin/test_assert.aria EXIT_CODE=$? set -e if [ $EXIT_CODE -ne 1 ]; then echo "❌ test_assert.aria exited with code $EXIT_CODE, expected 1" exit 1 else echo "✅ test_assert.aria exited with code $EXIT_CODE" fi set +e ARIA_LIB_DIR="$ARIA_LIB_DIR" cargo run --profile "$ARIA_BUILD_CONFIG" --package aria-bin -- aria-bin/test_uncaught_exception.aria EXIT_CODE=$? set -e if [ $EXIT_CODE -ne 1 ]; then echo "❌ test_uncaught_exception.aria exited with code $EXIT_CODE, expected 1" exit 1 else echo "✅ test_uncaught_exception.aria exited with code $EXIT_CODE" fi set +e ERROR_REPORTING_TEMPLATE="$SELF_DIR"/aria-bin/src/error_reporting_test/expected.txt ERROR_REPORTING_OUTPUT=$(ARIA_LIB_DIR_EXTRA="$SELF_DIR"/aria-bin/src/error_reporting_test \ ARIA_LIB_DIR="$ARIA_LIB_DIR" \ cargo run --profile "$ARIA_BUILD_CONFIG" \ --package aria-bin -- \ "$SELF_DIR"/aria-bin/src/error_reporting_test/main.aria 2>&1) set -e echo "$ERROR_REPORTING_OUTPUT" | awk ' match($0, /\/[^[:space:]]+:[0-9]+:[0-9]+/) { path = substr($0, RSTART, RLENGTH) n = split(path, parts, "/") print parts[n] } ' | diff -u "$ERROR_REPORTING_TEMPLATE" - && echo "OK" || { echo "Mismatch - actual output ${ERROR_REPORTING_OUTPUT}"; exit 1; } ARIA_TEST_DIR="$ARIA_TEST_DIR" \ ARIA_LIB_DIR="$ARIA_LIB_DIR" \ RUST_MIN_STACK="$RUST_MIN_STACK" \ cargo run --profile "$ARIA_BUILD_CONFIG" --package test-bin -- --path "tests/**/*.aria" --verbose "$@" ================================================ FILE: test-bin/Cargo.toml ================================================ [package] name = "test-bin" version = "0.9.20251222" edition = "2024" [dependencies] ariadne = { git = "https://github.com/zesterer/ariadne.git", rev="b60b500" } clap = { version = "4.5.57", features = ["derive"] } glob = "0.3.3" rayon = "1.11.0" parser-lib = { path = "../parser-lib" } compiler-lib = { path = "../compiler-lib" } vm-lib = { path = "../vm-lib" } regex = "1.12.2" once_cell = "1.21.3" enum-as-inner = "0.7.0" [[bin]] name = "test" path = "src/main.rs" ================================================ FILE: test-bin/src/main.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use std::{ collections::HashSet, fmt::Display, process::{ExitCode, Termination, exit}, time::{Duration, Instant}, }; use aria_compiler::compile_from_source; use aria_parser::ast::SourceBuffer; use clap::Parser; use enum_as_inner::EnumAsInner; use glob::Paths; use haxby_vm::vm::VirtualMachine; use rayon::prelude::*; use regex::Regex; #[derive(clap::ValueEnum, Clone, Debug, Default)] enum SortBy { #[default] Name, Duration, } #[derive(Parser, Debug)] #[command(author, version, about)] struct Args { /// A glob expression resulting in which test files to run #[arg(long)] path: String, #[arg(long)] /// Print additional output information verbose: bool, #[arg(long)] /// Run tests sequentially instead of in parallel sequential: bool, #[arg(long = "fail-fast")] /// Exit when any test fails, instead of running the entire suite fail_fast: bool, #[arg(long, value_enum, default_value_t)] /// Sort test results by name or duration sort_by: SortBy, /// Skip tests whose file name matches any of these regexes. May repeat. #[arg(long = "skip-pattern")] skip_pattern: Vec, } #[derive(Clone, EnumAsInner)] enum TestCaseOutcome { Pass, Fail(String), #[allow(dead_code)] XFail(String), } impl TestCaseOutcome { fn result_emoji(&self) -> &'static str { match self { TestCaseOutcome::Pass => "✅", TestCaseOutcome::Fail(_) => "❌", TestCaseOutcome::XFail(_) => "⚠️ ", } } fn display_error_reason(&self) -> String { if let Some(reason) = self.as_fail() { format!("[{}]", reason) } else { String::new() } } } #[derive(Clone)] struct TestCaseResult { test: String, duration: Duration, result: TestCaseOutcome, } impl TestCaseResult { fn pass(test: &str, duration: Duration) -> Self { Self { test: test.to_owned(), duration, result: TestCaseOutcome::Pass, } } fn fail(test: &str, duration: Duration, reason: String) -> Self { Self { test: test.to_owned(), duration, result: TestCaseOutcome::Fail(reason), } } fn xfail(test: &str, duration: Duration, reason: String) -> Self { Self { test: test.to_owned(), duration, result: TestCaseOutcome::XFail(reason), } } } impl Display for TestCaseResult { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!( f, "{} {} {} [in {}.{:03} seconds]", self.result.result_emoji(), self.test, self.result.display_error_reason(), self.duration.as_secs(), self.duration.subsec_millis() ) } } fn should_skip_file_name(path: &std::path::Path, skip_regex: &[Regex]) -> bool { let Some(fname) = path.file_name().and_then(|s| s.to_str()) else { return false; }; skip_regex.iter().any(|re| re.is_match(fname)) } fn parse_tags_from_file(path: &str) -> HashSet { let mut tags = HashSet::new(); let Ok(text) = std::fs::read_to_string(path) else { return tags; }; static TAGS_RE: once_cell::sync::Lazy = once_cell::sync::Lazy::new(|| Regex::new(r"(?i)^\s*###\s*TAGS:\s*(.+)\s*$").unwrap()); for line in text.lines() { if let Some(cap) = TAGS_RE.captures(line) && let Some(list) = cap.get(1) { for t in list.as_str().split(',') { let t = t.trim(); if !t.is_empty() { tags.insert(t.to_ascii_uppercase()); } } } } tags } fn run_test_from_pattern(path: &str) -> TestCaseResult { let tags = parse_tags_from_file(path); let start_wall = Instant::now(); let run_once = || -> TestCaseResult { let start = Instant::now(); let buffer = match SourceBuffer::file(path) { Ok(buffer) => buffer, Err(err) => { return TestCaseResult::fail(path, start.elapsed(), format!("I/O error: {err}")); } }; let entry_cm = match compile_from_source(&buffer, &Default::default()) { Ok(m) => m, Err(e) => { let err_msg = e .iter() .map(|e| e.to_string()) .collect::>() .join("\n"); return TestCaseResult::fail( path, start.elapsed(), format!("compilation error: {err_msg}"), ); } }; let mut vm = VirtualMachine::default(); let entry_rm = match vm.load_module("", entry_cm) { Ok(rle) => match rle { haxby_vm::vm::RunloopExit::Ok(m) => m.module, haxby_vm::vm::RunloopExit::Exception(e) => { let mut frame = Default::default(); let epp = e.value.prettyprint(&mut frame, &mut vm); return TestCaseResult::fail(path, start.elapsed(), epp); } }, Err(err) => return TestCaseResult::fail(path, start.elapsed(), err.prettyprint(None)), }; match vm.execute_module(&entry_rm) { Ok(rle) => match rle { haxby_vm::vm::RunloopExit::Ok(_) => TestCaseResult::pass(path, start.elapsed()), haxby_vm::vm::RunloopExit::Exception(e) => { let mut frame = Default::default(); let epp = e.value.prettyprint(&mut frame, &mut vm); TestCaseResult::fail(path, start.elapsed(), epp) } }, Err(err) => { TestCaseResult::fail(path, start.elapsed(), err.prettyprint(Some(entry_rm))) } } }; let mut outcome = run_once(); let is_flaky = tags.contains("FLAKEY") || tags.contains("FLAKY"); if is_flaky && outcome.result.is_fail() { outcome = run_once(); } let is_xfail = tags.contains("XFAIL"); if is_xfail { match &outcome.result { TestCaseOutcome::Pass => { return TestCaseResult::fail( path, start_wall.elapsed(), "unexpected pass (XFAIL)".into(), ); } TestCaseOutcome::Fail(reason) => { return TestCaseResult::xfail(path, start_wall.elapsed(), reason.clone()); } _ => { panic!("test runner should only produce pass/fail") } } } outcome } #[derive(Default)] struct SuiteReport { passes: Vec, fails: Vec, xfails: Vec, duration: Duration, } impl SuiteReport { fn num_fails(&self) -> usize { self.fails.len() } fn num_passes(&self) -> usize { self.passes.len() } fn num_xfails(&self) -> usize { self.xfails.len() } fn len(&self) -> usize { self.num_fails() + self.num_passes() + self.num_xfails() } fn pass(&mut self, result: TestCaseResult) { self.passes.push(result); } fn fail(&mut self, result: TestCaseResult) { self.fails.push(result); } fn xfail(&mut self, result: TestCaseResult) { self.xfails.push(result); } fn sort(&mut self, by: &SortBy) -> &mut Self { match by { SortBy::Name => { self.passes.sort_by(|a, b| a.test.cmp(&b.test)); self.fails.sort_by(|a, b| a.test.cmp(&b.test)); self.xfails.sort_by(|a, b| a.test.cmp(&b.test)); } SortBy::Duration => { self.passes.sort_by(|a, b| a.duration.cmp(&b.duration)); self.fails.sort_by(|a, b| a.duration.cmp(&b.duration)); self.xfails.sort_by(|a, b| a.duration.cmp(&b.duration)); } } self } } impl Display for SuiteReport { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { for pass in &self.passes { writeln!(f, "{}", pass)?; } for xfail in &self.xfails { writeln!(f, "{}", xfail)?; } for fail in &self.fails { writeln!(f, "{}", fail)?; } write!( f, "{} tests total - {} passed, {} failed, {} xfailed - in {}.{:03} seconds", self.len(), self.num_passes(), self.num_fails(), self.num_xfails(), self.duration.as_secs(), self.duration.subsec_millis(), ) } } impl Termination for SuiteReport { fn report(self) -> ExitCode { if self.num_fails() > 0 { ExitCode::FAILURE } else { ExitCode::SUCCESS } } } fn run_tests_from_pattern(patterns: Paths, args: &Args, skip_regex: &[Regex]) -> SuiteReport { let mut results = SuiteReport::default(); let start = Instant::now(); let outcomes = if args.sequential { let mut ret = vec![]; for pattern in patterns.flatten() { if should_skip_file_name(&pattern, skip_regex) { continue; } let test_name = pattern.file_stem().unwrap().to_str().unwrap(); let test_path = pattern.as_os_str().to_str().unwrap(); if args.verbose { println!("Running {test_name} (at {test_path})"); } let result = run_test_from_pattern(test_path); if args.fail_fast && result.result.is_fail() { ret.push(result); break; } else { ret.push(result); } } ret } else { patterns .flatten() .filter(|p| !should_skip_file_name(p, skip_regex)) .par_bridge() .map(|path| { let test_path = path.as_os_str().to_str().unwrap(); run_test_from_pattern(test_path) }) .collect::<_>() }; results.duration = start.elapsed(); for result in outcomes { match &result.result { TestCaseOutcome::Pass => results.pass(result), TestCaseOutcome::Fail(_) => { results.fail(result); } TestCaseOutcome::XFail(_) => { results.xfail(result); } } } results } fn main() -> SuiteReport { let args = Args::parse(); if args.fail_fast && !args.sequential { println!("--fail-fast is only supported in sequential mode; ignoring"); } let mut skip_regex = Vec::new(); for pattern in &args.skip_pattern { match Regex::new(pattern) { Ok(re) => skip_regex.push(re), Err(e) => { eprintln!("invalid --skip-pattern `{pattern}`: {e}"); exit(2); } } } let mut results = match glob::glob(&args.path) { Ok(pattern) => run_tests_from_pattern(pattern, &args, &skip_regex), Err(err) => { eprintln!("invalid pattern: {err}"); exit(1); } }; if results.num_fails() == 0 && !args.verbose { println!("All tests passed; --verbose to print full report"); exit(0); } results.sort(&args.sort_by); println!("{}", results); results } ================================================ FILE: tests/alloc_builtin_type.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func main() { assert alloc(Int) == 0; assert alloc(Float) == 0.0f; assert alloc(Bool) == false; assert alloc(String) == ""; assert alloc(List) == []; } ================================================ FILE: tests/and.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func boolean() { assert (true && true) == true; assert (true && false) == false; assert (false && true) == false; assert (false && false) == false; } func integer() { val a = 0b00101110101011110001; val b = 0b00010100001100011010; assert (a & b) == 0b00000100001000010000; } func main() { integer(); boolean(); } ================================================ FILE: tests/and_shortcircuit.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func main() { val x = [1,0]; assert !(false && (x[0] / x[1] == 4)); } ================================================ FILE: tests/arg_isa_mixin.aria ================================================ # SPDX-License-Identifier: Apache-2.0 mixin A {} struct S { include A } func foo(x: A) { return 42; } struct T {} func main() { assert foo(alloc(S)) == 42; try { foo(alloc(T)); assert false; } catch e { assert e.is_UnexpectedType(); } } ================================================ FILE: tests/arg_typehint.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func add(x: Int, y: Int) { return x + y; } func len_plus_one(x: List) { return add(x.len(), 1); } func main() { assert len_plus_one([]) == 1; } ================================================ FILE: tests/argc_mismatch_error.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func takes_three(x,y,z) { return x + y - z; } func main() { val caught = false; try { assert takes_three(1,2,3,4) == 5; } catch e { match e { isa RuntimeError and case MismatchedArgumentCount(n) => { caught = ((n.expected == 3) && (n.actual == 4)); } } } assert caught; } ================================================ FILE: tests/aria_version.aria ================================================ # SPDX-License-Identifier: Apache-2.0 assert ARIA_VERSION != ""; assert ARIA_VERSION.has_prefix("0."); # this will break for 1.0, let it, we'll fix the test then ================================================ FILE: tests/arity_of_callable.aria ================================================ # SPDX-License-Identifier: Apache-2.0 struct Callable { operator()(n,m=0) { return n + m + 1; } } func main() { val c = alloc(Callable); val a = arity(c); assert a.min == 1; assert a.max.is_Bounded(); assert a.max.unwrap_Bounded() == 2; assert a.has_receiver == true; assert c(1) == 2; assert c(0, 2) == 3; } ================================================ FILE: tests/as_user_printable.aria ================================================ # SPDX-License-Identifier: Apache-2.0 struct Foo { func prettyprint() { return "I'm a Foo"; } } func main() { val l = [1,2, alloc(Foo), false, 3.14f]; assert prettyprint(l) == "[1, 2, I'm a Foo, false, 3.14]"; } ================================================ FILE: tests/assert_id_func.aria ================================================ # SPDX-License-Identifier: Apache-2.0 val called = false; func assert_test(x,y) { called = true; assert x == y; } func main() { assert !called; assert_test(3,3); assert called; } ================================================ FILE: tests/bind_call_enum_instance_method.aria ================================================ # SPDX-License-Identifier: Apache-2.0 enum Foo { case A, case B, } extension Foo { instance func number() { return 42; } } func main() { val a = Foo::A; assert a.number() == 42; assert Foo::B.number() == 42; } ================================================ FILE: tests/bind_call_enum_type_method.aria ================================================ # SPDX-License-Identifier: Apache-2.0 enum Foo {} extension Foo { type func answer() { return 42; } } func main() { assert Foo.answer() == 42; } ================================================ FILE: tests/bind_of_free_func.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func x_and_then_some(this,x) { return this.x + x; } struct Foo { type func new(x) { return alloc(This){ .x = x, }; } } func main() { val f = Foo.new(3); # on the instance, do not bind to this f.add = x_and_then_some; assert f.add(f, 4) == 7; # on the type, bind to this Foo.and_add = x_and_then_some; assert f.and_add(4) == 7; } ================================================ FILE: tests/bind_of_func_on_builtin.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func x_and_then_some(this,x) { return this + x; } func for_int() { Int.bar = x_and_then_some; val n = 3; n.foo = x_and_then_some; assert n.foo(4) == 7; assert n.bar(4) == 7; } func for_float() { Float.bar = x_and_then_some; val n = 3.0f; n.foo = x_and_then_some; assert n.foo(4) == 7.0f; assert n.bar(4) == 7.0f; } func for_string() { String.bar = x_and_then_some; val n = "hello "; n.foo = x_and_then_some; assert n.foo("world") == "hello world"; assert n.bar("world") == "hello world"; } func negate_and(this,x) { return !this && x; } func for_bool() { Bool.bar = negate_and; val n = false; n.foo = negate_and; assert n.foo(true) == true; assert n.bar(true) == true; } func main() { for_int(); for_float(); for_string(); for_bool(); } ================================================ FILE: tests/box_type.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func main() { val b = Box(); b.x = 1; b.y = 2; assert b.y == 2; assert b.x == 1; } ================================================ FILE: tests/break_in_forloop.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func main() { val l = [1,2,3,4,5]; val sum = 0; for item in l { sum = sum + item; if item == 3 { break; } } assert sum == 6; } ================================================ FILE: tests/build_mixin.aria ================================================ # SPDX-License-Identifier: Apache-2.0 mixin Answer { func answer() { return 42; } } func main() { assert hasattr(Answer, "answer"); } ================================================ FILE: tests/builtin_isa_mixin.aria ================================================ # SPDX-License-Identifier: Apache-2.0 mixin Double { func double(x) { return x * 2; } } extension Int { include Double } func main() { assert 3 isa Double; } ================================================ FILE: tests/builtin_maybe_enum.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func double(x) { return x + x; } func main() { val s = Maybe::Some(123); val n = Maybe::None; assert(s.is_Some()); assert(n.is_None()); assert(s.unwrap_Some() == 123); val double_s = s.apply(double).apply(double); val double_n = n.apply(double).apply(double); assert(double_s.is_Some()); assert(double_n.is_None()); assert(double_s.unwrap_Some() == 492); } ================================================ FILE: tests/builtin_type_func_takes_This.aria ================================================ # SPDX-License-Identifier: Apache-2.0 extension Int { type func from_string(x: String) { return This.parse(x)!; } } func main() { val n = Int.from_string("123"); assert n == 123; } ================================================ FILE: tests/builtin_type_type.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func main() { val x = 3; val y = typeof(x); assert x isa Int; assert y == Int; val z = typeof(y); assert z == Type; assert z isa Type; # Type is the root of the hierarchy so no matter how deep you go... assert typeof(typeof(typeof(typeof(typeof(typeof(3)))))) == Type; } ================================================ FILE: tests/builtins_list_attributes.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func main() { val i = 3; i.foo = "three"; val i_attributes = listattrs(i); assert i_attributes.contains("foo"); assert i_attributes.contains("hash"); assert i_attributes.contains("parse"); # should type methods be included? assert i_attributes.len() >= 3; val f = 3.14f; f.text = "pi"; val f_attributes = listattrs(f); assert f_attributes.contains("text"); assert f_attributes.contains("hash"); assert f_attributes.len() >= 2; val b = false; b.truthy = false; val b_attributes = listattrs(b); assert b_attributes.contains("truthy"); assert b_attributes.contains("hash"); assert b_attributes.len() >= 2; val s = "hello"; s.french = "bonjour"; val s_attributes = listattrs(s); assert s_attributes.contains("french"); assert s_attributes.contains("hash"); assert s_attributes.len() >= 2; val l = [1,2,3]; l.max = 3; l.sum = 6; val l_attributes = listattrs(l); assert l_attributes.contains("max"); assert l_attributes.contains("sum"); assert l_attributes.contains("len"); assert l_attributes.len() >= 3; } ================================================ FILE: tests/bw_ops.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func min(x: Float, y: Float) { if x < y { return x; } else { return y; } } func max(x: Float, y: Float) { if x > y { return x; } else { return y; } } struct FuzzyNumber { type func new(x: Float) { return alloc(This){ .x = x%1, }; } operator &(other) { if other isa FuzzyNumber { return FuzzyNumber.new(min(this.x, other.x)); } else { throw alloc(Unimplemented); } } operator |(other) { if other isa FuzzyNumber { return FuzzyNumber.new(max(this.x, other.x)); } else { throw alloc(Unimplemented); } } operator u-() { return FuzzyNumber.new(1 - this.x); } operator ^(other) { if other isa FuzzyNumber { return (this | other) & -(this & other); } else { throw alloc(Unimplemented); } } operator ==(other) { if other isa FuzzyNumber { return this.x == other.x; } else { throw alloc(Unimplemented); } } } func main() { val a = FuzzyNumber.new(0.3f); val b = FuzzyNumber.new(0.4f); assert (a&b) == a; assert (a|b) == b; assert (a^b) == b; } ================================================ FILE: tests/call_op_call.aria ================================================ # SPDX-License-Identifier: Apache-2.0 struct HasOpCall { operator ()() { return 123; } } struct CanBeCalled { type func new() { return alloc(This); } operator ()() { return alloc(HasOpCall)(); } } func main() { # should this really be supported? assert (CanBeCalled.new())() == 123; } ================================================ FILE: tests/call_struct_func.aria ================================================ # SPDX-License-Identifier: Apache-2.0 struct Foo { func write(x) { this.x = x; } func read() { return this.x; } } func main() { val f = alloc(Foo); f.write(123); assert f.read() == 123; f.write(456); assert f.read() == 456; } ================================================ FILE: tests/chained_try_unwrap.aria ================================================ # SPDX-License-Identifier: Apache-2.0 import ok, err from aria.core.result; val n = ok(ok(ok(3))); assert n??? == 3; assert n??! == 3; assert n!?? == 3; assert n!!! == 3; val m = ok(3); val m = m ? == 3 ? 4 : 5; assert m == 4; ================================================ FILE: tests/closure_range_list.aria ================================================ # SPDX-License-Identifier: Apache-2.0 import aria.iterator.mixin; import Range from aria.range.range; func main() { val closures = []; val how_many = Range.from(0).through(100); for i in how_many { closures.append(|x| => x + i); } val x = 0; for closure in closures { assert closure(3) == 3 + x; x += 1; } } ================================================ FILE: tests/closure_with_body.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func greater_than_N(N) { return |x| => { if x > N { return true; } else { return false; } }; } func main() { assert greater_than_N(5)(3) == false; assert greater_than_N(6)(8) == true; assert greater_than_N(5)(6) == true; assert greater_than_N(3)(1) == false; } ================================================ FILE: tests/cmp_utils.aria ================================================ # SPDX-License-Identifier: Apache-2.0 import min,max,min_max from aria.ordering.utils; import min_with_comparator,max_with_comparator,min_max_with_comparator from aria.ordering.utils; import CompareResult from aria.ordering.compare; func main() { val list = [1,2,3,4,5,6,7,8,9,10]; assert min(list) == 1; assert max(list) == 10; val mM = min_max(list); assert mM.min == 1; assert mM.max == 10; list = ["a", "abc", "hello world", "this is a very long string"]; val cmp = |x,y| => { if x.len() == y.len() { return CompareResult::eq; } elsif x.len() < y.len() { return CompareResult::lt; } else { return CompareResult::gt; } }; assert min_with_comparator(list, cmp) == "a"; assert max_with_comparator(list, cmp) == "this is a very long string"; mM = min_max_with_comparator(list, cmp); assert mM.min == "a"; assert mM.max == "this is a very long string"; } ================================================ FILE: tests/complex_hash.aria ================================================ # SPDX-License-Identifier: Apache-2.0 import Complex from aria.numerics.complex; func main() { val c1 = Complex.new(3,5); val c2 = Complex.new(4,3); val c3 = Complex.new(1,1); assert c1.hash() != c2.hash(); assert c1.hash() != c3.hash(); assert c2.hash() != c3.hash(); assert c1.hash() == c1.hash(); assert c2.hash() == c2.hash(); assert c3.hash() == c3.hash(); val c4 = Complex.new(1,1); assert c4.hash() == c3.hash(); assert c3 == c4; } ================================================ FILE: tests/complex_numbers.aria ================================================ # SPDX-License-Identifier: Apache-2.0 import Complex from aria.numerics.complex; func complex(i,j) { return Complex.new(i) + j * Complex.i; } func main() { val one = complex(1,0); val some_num = complex(3,2); assert one == 1; assert one == 1.0f; assert some_num != 3; assert some_num != 2; assert some_num != 3.0f; assert some_num != 2.0f; assert (some_num + one) == complex(4,2); assert one + complex(0,1) == complex(1,1); assert 1 + complex(2,2) == some_num; assert (some_num - one) == complex(2,2); assert (some_num - complex(0,2)) == 3; assert 1 - complex(1,2) - complex(0,1) == complex(0,-3); assert complex(3,2) * complex(4,-1) == complex(14,5); assert 2 * complex(0,1) == complex(0,2); assert 2 * complex(1,0) == 2; assert some_num.conj() == complex(3,-2); assert one.conj() == one; assert complex(3,4).reciprocal() == complex(0.12f, -0.16f); val quot = complex(2,3) / complex(1,-2); assert (quot.real + 0.8f).abs() <= 0.0001f; assert (quot.imag - 1.4f).abs() <= 0.0001f; } ================================================ FILE: tests/complex_of_self.aria ================================================ # SPDX-License-Identifier: Apache-2.0 import Complex from aria.numerics.complex; func main() { val error = false; try { val c1 = Complex.new("hello", 5); } catch e { error = true; assert e isa RuntimeError; assert e.is_UnexpectedType(); } assert error; } ================================================ FILE: tests/complex_reverse_minus.aria ================================================ # SPDX-License-Identifier: Apache-2.0 import Complex from aria.numerics.complex; assert (3 - Complex.new(3,4)).imag == -4; ================================================ FILE: tests/continue_in_forloop.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func main() { val l = [1,2,3,4,5]; val sum = 0; for item in l { sum = sum + item; continue; assert false; } assert sum == 15; } ================================================ FILE: tests/cross_func_exception.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func throws(x: Int) { throw x + 1; } func call_throw() { println(throws(5)); } func handle_it() { val handled = false; try { call_throw(); } catch e { handled = true; assert e == 6; } return handled; } func main() { assert handle_it() == true; } ================================================ FILE: tests/cross_module_mixin_import.aria ================================================ # SPDX-License-Identifier: Apache-2.0 import MeFirst from same_root.part1.file3; import Foo from same_root.part1.file1; func main() { val f = Foo.new(); val m = MeFirst.new(); assert f.answer() == 165; assert m.answer() == 363; } ================================================ FILE: tests/cross_module_var.aria ================================================ # SPDX-License-Identifier: Apache-2.0 import * from exported_var.source; func main() { assert foo == 123; assert fetch_foo() == 123; assert exported_var.source.foo == 123; assert exported_var.source.fetch_foo() == 123; change_foo(111); assert foo == 123; # TODO: should it be 111? assert fetch_foo() == 111; assert exported_var.source.foo == 111; assert exported_var.source.fetch_foo() == 111; exported_var.source.change_foo(222); assert foo == 123; # TODO: should it be 222? assert fetch_foo() == 222; assert exported_var.source.foo == 222; assert exported_var.source.fetch_foo() == 222; } ================================================ FILE: tests/cross_module_var_write.aria ================================================ # SPDX-License-Identifier: Apache-2.0 ### TAGS: XFAIL import * from exported_var.source; func main() { foo = 456; assert foo == 456; assert fetch_foo() == 456; # expected to fail here assert exported_var.source.foo == 456; assert exported_var.source.fetch_foo() == 456; } ================================================ FILE: tests/custom_is_unwrap.aria ================================================ # SPDX-License-Identifier: Apache-2.0 enum E { case A(Int), case B, case C(String) func is_A() { return 12; } func unwrap_C() { return "hello"; } } func main() { val ea = E::A(5); val eb = E::B; val ec = E::C("world"); assert ea.is_A() == 12; assert eb.is_A() == 12; assert ec.is_A() == 12; assert ea.unwrap_C() == "hello"; assert ea.unwrap_A() == 5; assert eb.unwrap_C() == "hello"; assert ec.unwrap_C() == "hello"; } ================================================ FILE: tests/custom_to_json_value.aria ================================================ # SPDX-License-Identifier: Apache-2.0 import aria.json.writer; import JsonValue from aria.json.value; import Map from aria.structures.map; struct CustomJson { type func new(x,y) { return alloc(This) { .x = x, .y = y, }; } func to_json_value() { return Result::Ok(JsonValue::Object(Map.new() { ["x"] = JsonValue.new_with_value(this.x)?, ["y"] = JsonValue.new_with_value(this.y)?, })); } } func main() { val map = Map.new(); map["hello"] = CustomJson.new(3,4); map["hi"] = false; val json_map = JsonValue.new_with_value(map)!; assert json_map isa JsonValue; val unwrap_map = json_map.unwrap_Object(); assert unwrap_map isa Map; assert unwrap_map["hello"].is_Object(); val custom_object = unwrap_map["hello"].flatten(); assert custom_object isa Map; assert custom_object["x"] == 3.0f; assert custom_object["y"] == 4.0f; assert unwrap_map["hi"].is_Boolean(); assert unwrap_map["hi"].flatten() == false; } ================================================ FILE: tests/custom_try_unwrap_protocol.aria ================================================ # SPDX-License-Identifier: Apache-2.0 import ok,err from aria.core.result; struct Number { type func new(x) = alloc(This) {.x}; func _op_try_view() { if this.x == 5 { return ok(this.x); } else { return err("not five"); } } } func main() { val five = Number.new(5); val six = Number.new(6); assert five? == 5; assert five! == 5; assert six?.is_Err(); assert six?.unwrap_Err() == "not five"; } ================================================ FILE: tests/decimal.aria ================================================ # SPDX-License-Identifier: Apache-2.0 import Decimal from aria.numerics.decimal; func main() { assert Decimal.parse("3.14")! + Decimal.parse("3.14")! == Decimal.new(6.28f); assert 3 + Decimal.parse("5")! == Decimal.new(8); assert 3.1f + Decimal.parse("2.5")! == Decimal.new(5.6f); assert Decimal.parse("5")! - Decimal.parse("3.1")! == Decimal.parse("1.9")!; assert 4 - Decimal.parse("3.5")! == Decimal.new(0.5f); assert Decimal.parse("3.14")! * 2 == Decimal.new(6.28f); assert 2 * Decimal.parse("3.14")! == Decimal.new(6.28f); assert Decimal.parse("12")! / Decimal.new(3) == Decimal.new(4); assert 12 / Decimal.parse("3")! == Decimal.new(4); assert Decimal.parse("3.14")! > Decimal.parse("2.0")!; assert Decimal.parse("5.123")! < Decimal.parse("6.28")!; assert Decimal.parse("5")! != Decimal.parse("6")!; assert Decimal.new(5) >= Decimal.new(4); assert Decimal.new(5) >= Decimal.parse("5.00000")!; assert Decimal.parse("5.0")! <= Decimal.new(5); assert Decimal.parse("5.0")! <= Decimal.new(5.001); assert Decimal.parse("foo").is_Err(); assert Decimal.parse("3.14.15").is_Err(); assert Decimal.parse("3.14e2").is_Err(); # TODO: support scientific notation } ================================================ FILE: tests/decimal_hash.aria ================================================ # SPDX-License-Identifier: Apache-2.0 import Decimal from aria.numerics.decimal; func main() { val d1 = Decimal.parse("123.456")!; val d2 = Decimal.parse("123.457")!; val d3 = Decimal.parse("321.456")!; assert d1.hash() != d2.hash(); assert d1.hash() != d3.hash(); assert d2.hash() != d3.hash(); assert d1.hash() == d1.hash(); assert d2.hash() == d2.hash(); assert d3.hash() == d3.hash(); val d4 = Decimal.parse("321.456")!; assert d4.hash() == d3.hash(); assert d3 == d4; } ================================================ FILE: tests/decimal_prettyprint.aria ================================================ # SPDX-License-Identifier: Apache-2.0 import Decimal from aria.numerics.decimal; func main() { val f1 = Decimal.parse("3.14159265359")!; assert "{0}".format(f1) == "3.14159265359"; assert "{0:.2}".format(f1) == "3.14"; assert "{0:.3}".format(f1) == "3.142"; assert "{0:.4}".format(f1) == "3.1416"; } ================================================ FILE: tests/deep_nested_struct.aria ================================================ # SPDX-License-Identifier: Apache-2.0 struct A { struct B { struct C { struct D { func foo() { return 42; } } type func subtract(x,y) { return x - y; } } type func getD() { return alloc(A.B.C.D); } instance func bar() { return 123; } } type func whoami() { return "A"; } instance func multiply(x,y) { return x * y; } } func main() { assert hasattr(A, "B"); assert hasattr(A.B, "C"); assert hasattr(A.B.C, "D"); assert hasattr(A, "whoami"); assert hasattr(A.B, "getD"); assert A.whoami() == "A"; assert alloc(A).multiply(3,4) == 12; assert A.B.getD().foo() == 42; assert alloc(A.B).bar() == 123; assert A.B.C.subtract(7,4) == 3; assert alloc(A.B.C.D).foo() == 42; } ================================================ FILE: tests/default_arg_is_immutable.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func add_to_list(n,l=[]) { l.append(n); return l; } func main() { val l1 = add_to_list(3); assert l1 == [3]; val l2 = add_to_list(5); assert l1 == [3]; assert l2 == [5]; l2 = add_to_list(7,l2); assert l2 == [5,7]; assert l1 == [3]; } ================================================ FILE: tests/dir_entries.aria ================================================ # SPDX-License-Identifier: Apache-2.0 import aria.iterator.mixin; import Instant from aria.date.instant; import Path from aria.io.path; func is_this_test(path) { return path.get_filename()! == "dir_entries.aria"; } func main() { val path = getenv("ARIA_TEST_DIR").unwrap_Some(); val path = Path.new(path).new_canonical().unwrap_Ok(); val entries = path.entries(); entries = entries.where(is_this_test).to_list(); assert entries.len() == 1; assert entries[0] isa Path; assert entries[0].is_file(); assert entries[0].exists(); assert entries[0].get_extension()! == "aria"; val creation = entries[0].created()!; val modified = entries[0].modified()!; val accessed = entries[0].accessed()!; assert creation.year >= 2025; assert modified.year >= 2025; assert accessed.year >= 2025; assert accessed.utc_timestamp_ms >= modified.utc_timestamp_ms; assert modified.utc_timestamp_ms >= creation.utc_timestamp_ms; if creation.year == 2025 { assert creation.month >= 7; if creation.month == 7 { assert creation.day >= 4; } else { assert creation.day >= 1; } } else { assert creation.month >= 1; assert creation.day >= 1; } } ================================================ FILE: tests/div_by_zero_error.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func main() { val caught = false; try { println(3 / 0); } catch e { match e { isa RuntimeError and case DivisionByZero => { caught = true; } } } assert caught; } ================================================ FILE: tests/dot_write_of_local.aria ================================================ # SPDX-License-Identifier: Apache-2.0 struct Pair { type func new(x,y) = alloc(This){.x, .y}; func swap() { return Pair.new(this.y, this.x); } } func main() { val p = Pair.new(3,4); assert p.x == 3; assert p.y == 4; val q = p.swap(); assert q.x == 4; assert q.y == 3; } ================================================ FILE: tests/double_import_from.aria ================================================ # SPDX-License-Identifier: Apache-2.0 import Pair from example.pair.Pair; import Pair from example.pair.Pair; import Pair from example.pair.Pair; extension Pair { func min() { if this.x > this.y { return this.y; } else { return this.x; } } } func main() { val p = Pair.new(1,2); val q = Pair.new(3,4); assert p.max() == 2; assert q.max() == 4; assert p.min() == 1; assert q.min() == 3; } ================================================ FILE: tests/double_module_import.aria ================================================ # SPDX-License-Identifier: Apache-2.0 import example.pair.Pair; import example.pair.Pair; import example.pair.Pair; import Pair from example.pair.Pair; func main() { val p = Pair.new(1,2); assert p.x == 1; assert p.y == 2; } ================================================ FILE: tests/empty_expr_stmt.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func foo() { ;;;;;; } func bar() { if 1 == 1 { return true; };;;; return false;;;;;; } func main() { ; foo(); assert bar();;;;; } ================================================ FILE: tests/empty_func.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func foo() {} func main() { foo(); } ================================================ FILE: tests/enum_case_as_mixin.aria ================================================ # SPDX-License-Identifier: Apache-2.0 mixin A { func answer() = 42; } struct S { include A } enum E { case HasAnswer(A), case DefaultAnswer(Int), func answer() { match this { case HasAnswer(a) => { return a.answer(); }, case DefaultAnswer(n) => { return n; } } } } func main() { val e1 = E::HasAnswer(alloc(S)); assert e1.answer() == 42; val e2 = E::DefaultAnswer(7); assert e2.answer() == 7; } ================================================ FILE: tests/enum_case_check_no_payload.aria ================================================ # SPDX-License-Identifier: Apache-2.0 enum Foo { case A, case B, case C, case D, case E, } struct WhichCase { type func new() { return alloc(This){ .is_a = false, .is_b = false, .is_c = false, .is_d = false, }; } } func check_cases(x: Foo) { val wc: WhichCase = WhichCase.new(); match x { case A => { wc.is_a = true; }, case B => { wc.is_b = true; }, case C => { wc.is_c = true; }, case D => { wc.is_d = true; }, } return wc; } func main() { val a = Foo::A; val b = Foo::B; val c = Foo::C; val d = Foo::D; val e = Foo::E; val check: WhichCase = check_cases(a); assert check.is_a; assert !check.is_b; assert !check.is_c; assert !check.is_d; val check: WhichCase = check_cases(b); assert !check.is_a; assert check.is_b; assert !check.is_c; assert !check.is_d; val check: WhichCase = check_cases(c); assert !check.is_a; assert !check.is_b; assert check.is_c; assert !check.is_d; val check: WhichCase = check_cases(d); assert !check.is_a; assert !check.is_b; assert !check.is_c; assert check.is_d; val check: WhichCase = check_cases(e); assert !check.is_a; assert !check.is_b; assert !check.is_c; assert !check.is_d; } ================================================ FILE: tests/enum_equals.aria ================================================ # SPDX-License-Identifier: Apache-2.0 struct Integer { type func new(n: Int) { return alloc(This){ .n = n, }; } operator ==(rhs) { if rhs isa Integer { return rhs.n == this.n; } elsif rhs isa Int { return rhs == this.n; } else { throw alloc(Unimplemented); } } } enum Something { case WithPayload(Any), case WithoutPayload } func main() { val s1 = Something::WithoutPayload; assert s1 == Something::WithoutPayload; val s2 = Something::WithPayload(3); val s3 = Something::WithPayload(Integer.new(3)); val s4 = Something::WithPayload(4); assert s2 == s3; assert s3 == s2; assert s3 != s4; assert s2 != s4; assert s4 != s3; assert s4 != s2; assert s1 != s2; assert s2 != s1; assert s3 != s1; assert s1 != s3; assert s1 != s4; assert s4 != s1; } ================================================ FILE: tests/enum_extend_mixin.aria ================================================ # SPDX-License-Identifier: Apache-2.0 enum Enum { case A, case B, } mixin LogicalOps { func some_op() { return 123; } } extension Enum { include LogicalOps } extension LogicalOps { func some_other_op() { return 321; } } func main() { val e = Enum::A; assert e.some_op() == 123; assert e.some_other_op() == 321; } ================================================ FILE: tests/enum_in_struct.aria ================================================ # SPDX-License-Identifier: Apache-2.0 struct Parent { enum Child { case A, case B(Int) } } extension Parent.Child { func get_magic_value() { return 123; } } extension Parent { type func get_child_A() { return Parent.Child::A; } type func get_child_B(x: Int) { return Parent.Child::B(x); } } func main() { # cannot test match yet val a = Parent.get_child_A(); assert a.get_magic_value() == 123; val b = Parent.get_child_B(456); assert b.get_magic_value() == 123; } ================================================ FILE: tests/enum_isa_mixn.aria ================================================ # SPDX-License-Identifier: Apache-2.0 mixin M { func foo(x) { return x + 1; } } mixin MM { func bar(x) { return this.foo(x) + 1; } include M } enum IncludeM { case A, case B } extension IncludeM { include M } enum IncludeMM { case C, case D } extension IncludeMM { include MM } func main() { val m = IncludeM::A; val mm = IncludeMM::D; assert m isa M; assert mm isa MM; assert mm isa M; assert !(m isa MM); assert MM isa M; assert !(M isa MM); assert IncludeM isa M; assert !(IncludeM isa MM); assert IncludeMM isa MM; assert IncludeMM isa M; } ================================================ FILE: tests/enum_list_attributes.aria ================================================ # SPDX-License-Identifier: Apache-2.0 enum E1 { case A, case B } enum E2 { case A, case B(Int) } mixin PlusSeven { func f7(x) { return x + 7; } } extension E1 { include PlusSeven func f1(x) { return x + 1; } func f2(x) { return x * 2; } } extension E2 { func f3(x) { return x + 3; } func f4(x) { return x + 4; } } func main() { val e1 = E1::A; val e2 = E2::A; val attribs_e1 = listattrs(e1); val attribs_e2 = listattrs(e2); assert attribs_e1.contains("f1"); assert attribs_e1.contains("f2"); assert attribs_e1.contains("f7"); assert attribs_e1.contains("is_A"); assert attribs_e1.contains("is_B"); assert attribs_e1.len() == 5; assert attribs_e2.contains("f3"); assert attribs_e2.contains("f4"); assert attribs_e2.contains("is_A"); assert attribs_e2.contains("is_B"); assert attribs_e2.contains("unwrap_B"); assert attribs_e2.len() == 5; } ================================================ FILE: tests/enum_match_case_first_wins.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func main() { val x = Maybe::Some(123); val a = false; val b = false; match x { case Some(x: Int) => { a = true; }, case Some(x) => {assert(false);}, } else { assert(false); } match x { case Some(x) => {b = true;}, case Some(x: Int) => {assert(false);}, } else { assert(false); } assert a; assert b; } ================================================ FILE: tests/enum_match_case_typehint.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func main() { val x = Maybe::Some(123); val n = 0; match x { case Some(x: String) => {assert(false);}, case Some(x: List) => {assert(false);}, case None => {assert(false);}, case Some(x: Int) => { n = x; }, case Some(x) => {assert(false);}, } else { assert(false); } assert n == 123; } ================================================ FILE: tests/enum_op_equals.aria ================================================ # SPDX-License-Identifier: Apache-2.0 enum Something { case WithPayload(Any), case WithoutPayload } extension Something { # only doing this for test purposes, it's actually a terrible # definition of an equality comparison operator ==(rhs) { match rhs { isa Something => { return true; } } else { return false; } } } func main() { assert Something::WithPayload(3) == Something::WithoutPayload; assert 3 != Something::WithoutPayload; assert 3 != Something::WithPayload(3); } ================================================ FILE: tests/enum_prettyprint.aria ================================================ # SPDX-License-Identifier: Apache-2.0 enum Parity { case Even(Int), case Odd(Int), } extension Parity { type func new(n: Int) { if n % 2 == 0 { return Parity::Even(n); } else { return Parity::Odd(n); } } instance func prettyprint() { match this { case Even(x) => { return "{0} is an even number".format(x); }, case Odd(x) => { return "{0} is an odd number".format(x); } } } } func main() { val six = Parity.new(6); val eleven = Parity.new(11); val six_fmt = "{0}".format(six); val eleven_fmt = "{0}".format(eleven); assert six_fmt == "6 is an even number"; assert eleven_fmt == "11 is an odd number"; } ================================================ FILE: tests/enum_with_struct_case.aria ================================================ # SPDX-License-Identifier: Apache-2.0 enum Options { struct LotsOfThem { type func new(opt1, opt2, opt3) { return alloc(This) { .opt1 = opt1, .opt2 = opt2, .opt3 = opt3, }; } } struct FewerOfThem { type func new(opt1) { return alloc(This) { .opt1 = opt1, }; } } case Lots(Options.LotsOfThem) case Fewer(Options.FewerOfThem) func option1() { match this { case Lots(x) => { return x.opt1; }, case Fewer(x) => { return x.opt1; }, } } func option2() { match this { case Lots(x) => { return x.opt2; }, case Fewer => { return 42; }, } } func option3() { match this { case Lots(x) => { return x.opt3; }, case Fewer => { return 24; }, } } } func main() { val ol = Options::Lots(Options.LotsOfThem.new(1,2,3)); val of = Options::Fewer(Options.FewerOfThem.new(4)); assert ol.option1() == 1; assert ol.option2() == 2; assert ol.option3() == 3; assert of.option1() == 4; assert of.option2() == 42; assert of.option3() == 24; } ================================================ FILE: tests/enum_without_payload.aria ================================================ # SPDX-License-Identifier: Apache-2.0 enum E { case NoPayload, case Payload(Any) } func get_maybe_something(x: E) { match x { # NoPayload case should not extract payload, but it tries # it can't match (and if it does it's a bug in the compiler or in the VM) # but it also should just fail to match and move on to the next case case NoPayload(x) => { assert false; }, case Payload(x) => { return Maybe::Some(x); } case NoPayload => { return Maybe::None; } } assert false; } func main() { assert get_maybe_something(E::NoPayload) == Maybe::None; assert get_maybe_something(E::Payload(42))! == 42; } ================================================ FILE: tests/except_in_op_is_caught.aria ================================================ # SPDX-License-Identifier: Apache-2.0 struct InvalidArgument {} struct Divider { operator /(rhs) { if rhs == 0 { throw alloc(InvalidArgument); } else { return 1; } } } func main() { val caught = false; try { alloc(Divider) / 0; } catch e { caught = e isa InvalidArgument; } assert caught; } ================================================ FILE: tests/exception_backtrace.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func bar() { return foo(); } func foo() { throw 1; } func main() { try { bar(); } catch e { assert hasattr(e, "backtrace"); assert e.backtrace.len() >= 2; assert e.backtrace[0][0].contains("exception_backtrace.aria"); assert e.backtrace[0][1] == 6; assert e.backtrace[1][0].contains("exception_backtrace.aria"); assert e.backtrace[1][1] == 2; } } ================================================ FILE: tests/extend_imported.aria ================================================ # SPDX-License-Identifier: Apache-2.0 import Base from extensible.ext; import Base from extensible.base; func main() { val b = Base.new(2,3); b.one_right(); assert b.x == 2; assert b.y == 4; } ================================================ FILE: tests/extend_included_mixin.aria ================================================ # SPDX-License-Identifier: Apache-2.0 mixin FunStuff { func have_fun() { return 123; } } struct WantsFun { include FunStuff } extension FunStuff { func have_more_fun() { return 456; } } func main() { val wf = alloc(WantsFun); assert wf.have_fun() == 123; assert wf.have_more_fun() == 456; } ================================================ FILE: tests/extend_struct.aria ================================================ # SPDX-License-Identifier: Apache-2.0 struct Foo { func increment(x) { return x + 1; } } extension Foo { func double(x) { return x + x; } } extension Foo { func zero() { return 0; } func one() { return 1; } func two() { return 2; } } func main() { val foo = alloc(Foo); assert foo.increment(5) == 6; assert foo.double(12) == 24; assert foo.zero() == 0; assert foo.one() == 1; assert foo.two() == 2; } ================================================ FILE: tests/extension_nested_struct.aria ================================================ # SPDX-License-Identifier: Apache-2.0 struct A { struct B { struct C { struct D { } } } } extension A.B.C.D { type func new() { return alloc(This); } instance func answer() { return 42; } } extension A.B.C { instance func answer() { return 42; } } extension A.B { type func whoami() { return "A.B"; } } extension A { instance func getD() { return A.B.C.D.new(); } } val nested_struct = A.B.C; extension nested_struct { type func question() { return 24; } } extension A { struct OneMore { type func new(x) { return alloc(This){ .x = x }; } instance func increment() { this.x = this.x + 1; return this; } } } extension A.OneMore { instance func get() { return this.x; } } func main() { assert hasattr(A.B.C.D, "new"); assert hasattr(A.B, "whoami"); assert hasattr(A.B.C, "question"); assert hasattr(A, "OneMore"); assert alloc(A).getD().answer() == 42; assert A.B.C.D.new().answer() == 42; assert alloc(A.B.C).answer() == 42; assert A.B.C.question() == 24; assert A.B.whoami() == "A.B"; val aom = A.OneMore.new(12); assert aom.get() == 12; aom.increment().increment().increment(); assert aom.get() == 15; } ================================================ FILE: tests/extension_on_list.aria ================================================ # SPDX-License-Identifier: Apache-2.0 extension List { func head() { return this[0]; } } func main() { val list = [1,2,3,4,5,6]; assert list.head() == 1; } ================================================ FILE: tests/extension_type_func.aria ================================================ # SPDX-License-Identifier: Apache-2.0 extension List { type func empty() { return []; } } func main() { assert hasattr(List, "empty"); val l = List.empty(); assert l.len() == 0; } ================================================ FILE: tests/file_io.aria ================================================ # SPDX-License-Identifier: Apache-2.0 import File from aria.io.file; import guard from aria.utils.guard; func main() { val path = getenv("ARIA_TEST_DIR").unwrap_Some(); path = path + "/file_io.txt"; val msg = "First line of text.\nSecond line of text.\nThird line of text."; guard(File.open(path, File.OpenMode.new().write().truncate())).do(|file| => { file.write(msg); }); guard(File.open(path, File.OpenMode.new().read())).do(|file| => { assert file.get_position() == 0; val l1 = file.readln(); assert file.get_position() == 20; assert l1 == "First line of text."; val s = file.read_all(); assert s == "Second line of text.\nThird line of text."; file.set_position(1); s = file.read(2); assert file.get_position() == 3; assert s == "ir"; s = file.readln(); assert file.get_position() == 20; s == "st line of text."; file.seek(File.SeekMode::Start(1)); s = file.read(2); assert file.get_position() == 3; assert s == "ir"; file.seek(File.SeekMode::Current(2)); s = file.read(2); assert file.get_position() == 7; assert s == " l"; file.seek(File.SeekMode::Current(-3)); s = file.read(3); assert file.get_position() == 7; assert s == "t l"; file.seek(File.SeekMode::End(-4)); s = file.read(4); assert s == "ext."; }); } ================================================ FILE: tests/file_io.txt ================================================ First line of text. Second line of text. Third line of text. ================================================ FILE: tests/file_lines_iter.aria ================================================ # SPDX-License-Identifier: Apache-2.0 import File from aria.io.file; import Enumerate from aria.iterator.enumerate; import guard from aria.utils.guard; func main() { val path = getenv("ARIA_TEST_DIR").unwrap_Some(); path = path + "/file_lines_iter.txt"; val msg = "First line of text.\nSecond line of text.\n\nThird line of text.\nFourth line of text."; guard(File.open(path, File.OpenMode.new().write().truncate())).do(|file| => { file.write(msg); }); val lines = [ "First line of text.", "Second line of text.", "", "Third line of text.", "Fourth line of text." ]; guard(File.open(path, File.OpenMode.new().read())).do(|file| => { for idx_line in Enumerate.new(file.lines()) { val line = idx_line.value; val i = idx_line.index; assert line == lines[i]; } }); } ================================================ FILE: tests/file_lines_iter.txt ================================================ First line of text. Second line of text. Third line of text. Fourth line of text. ================================================ FILE: tests/flatten_results.aria ================================================ # SPDX-License-Identifier: Apache-2.0 import ok, err from aria.core.result; import aria.range.int_extension; func give_out_a_result(x) { if x % 2 == 0 { return ok(x); } else { return err("odd number: {0}".format(x)); } } func main() { val l = 1.to(4) .map(give_out_a_result) .flatten_results(); assert l == err("odd number: 1"); val l = 2.to(4) .map(|x| => x * 2) .map(give_out_a_result) .flatten_results(); assert l.is_Ok(); assert l.unwrap_Ok() == [4,6]; } ================================================ FILE: tests/float_atan.aria ================================================ # SPDX-License-Identifier: Apache-2.0 import aria.numerics.float.trig; func within_tolerance(expected: Float, got: Float, rel_tol: Float = 1.0e-9, abs_tol: Float = 1.0e-15) { val diff = (got - expected).abs(); val tol = expected.abs() * rel_tol; if tol < abs_tol { tol = abs_tol; } return diff <= tol; } assert within_tolerance(0.0, 0.0.arctan()); assert within_tolerance(Float.π / 4, 1.0.arctan()); assert within_tolerance(-Float.π / 4, (-1.0).arctan()); assert within_tolerance(0.4636476090008061, 0.5.arctan()); assert within_tolerance(-0.4636476090008061, (-0.5).arctan()); assert within_tolerance(1.0e-10, (1.0e-10).arctan()); assert within_tolerance(-1.0e-10, (-1.0e-10).arctan()); assert within_tolerance(Float.π / 2 - 1.0e-10, (1.0e10).arctan(), 1.0e-9); assert within_tolerance(-Float.π / 2 + 1.0e-10, (-1.0e10).arctan(), 1.0e-9); assert within_tolerance(0.7853981133974458, 0.9999999.arctan()); assert within_tolerance(0.19739555984988078, 0.2.arctan()); assert within_tolerance(-1.3258176636680326, (-4.0).arctan()); assert within_tolerance(0.4636476090008061, (0.5f).arctan()); assert within_tolerance(-0.7853981633974483, (-1.0f).arctan()); ================================================ FILE: tests/float_exp.aria ================================================ # SPDX-License-Identifier: Apache-2.0 import aria.numerics.float.exp; func within_tolerance(expected: Float, got: Float, rel_tol: Float = 1.0e-9, abs_tol: Float = 1.0e-15) { val diff = (got - expected).abs(); val tol = expected.abs() * rel_tol; if tol < abs_tol { tol = abs_tol; } return diff <= tol; } assert within_tolerance(1.0, 0.0.exp()); assert within_tolerance(2.718281828459045, 1.0.exp()); assert within_tolerance(0.36787944117144233, (-1.0).exp()); assert within_tolerance(4.851651954097903e8, 20.0.exp()); assert within_tolerance(1.9287498479639178e-22, (-50.0).exp()); ================================================ FILE: tests/float_ln.aria ================================================ # SPDX-License-Identifier: Apache-2.0 import aria.numerics.float.exp; func within_tolerance(expected: Float, got: Float, rel_tol: Float = 1.0e-9, abs_tol: Float = 1.0e-15) { val diff = (got - expected).abs(); val tol = expected.abs() * rel_tol; if tol < abs_tol { tol = abs_tol; } return diff <= tol; } assert within_tolerance(0.0, 1.0.ln()); assert within_tolerance(0.6931471805599453, 2.0.ln()); assert within_tolerance(69.07755278982138, (1.0e30).ln(), 1.0e-12); assert within_tolerance(-115.12925464970229, (1.0e-50).ln(), 1.0e-12); ================================================ FILE: tests/float_log_exp.aria ================================================ # SPDX-License-Identifier: Apache-2.0 import aria.numerics.float.exp; func within_tolerance(expected: Float, got: Float, rel_tol: Float = 1.0e-9, abs_tol: Float = 1.0e-15) { val diff = (got - expected).abs(); val tol = expected.abs() * rel_tol; if tol < abs_tol { tol = abs_tol; } return diff <= tol; } func roundtrip_le(x: Float) { return x.ln().exp(); } func roundtrip_el(x: Float) { return x.exp().ln(); } func check_roundtrip_el(x: Float) { val y = x.exp(); val z = y.ln(); return within_tolerance(x, z); } func check_roundtrip_le(x: Float) { val y = x.ln(); val z = y.exp(); return within_tolerance(x, z); } func main() { assert check_roundtrip_el(2.0f); assert check_roundtrip_le(2.0f); assert check_roundtrip_el(3.4635f); assert check_roundtrip_le(3.4635f); val had_error = false; try { (-1.1f).ln(); } catch e { had_error = e isa Float.DomainError; } assert had_error; } ================================================ FILE: tests/float_parse_scientific.aria ================================================ # SPDX-License-Identifier: Apache-2.0 val x1 = 1.0E3; val y1 = Float.parse("1.0E3")!; assert x1 == y1; assert y1 == 1000.0f; val x2 = 1.0e3; val y2 = Float.parse("1.0e3")!; assert x2 == y2; assert y2 == 1000.0f; val x3 = 1.0e-3; val y3 = Float.parse("1.0e-3")!; assert x3 == y3; assert y3 == 0.001f; val x4 = 1.0e+3; val y4 = Float.parse("1.0e+3")!; assert x4 == y4; assert y4 == 1000.0f; val x5 = 2.0e2; val y5 = Float.parse("2.0e2")!; assert x5 == y5; assert y5 == 200.0f; val x6 = 0.0e10; val y6 = Float.parse("0.0e10")!; assert x6 == y6; assert y6 == 0.0f; val x7 = -1.5e2; val y7 = Float.parse("-1.5e2")!; assert x7 == y7; assert y7 == -150.0f; ================================================ FILE: tests/float_pow.aria ================================================ # SPDX-License-Identifier: Apache-2.0 import aria.numerics.float.exp; func rough_approx_eq(x: Float, y: Float) { return (x-y).abs() <= 0.00001f; } func main() { assert((-2.0f).pow(2) == 4.0f); assert(3.0f.pow(2.0f) == 9.0f); assert(rough_approx_eq(3.7f.pow(2.12f), 16.01724f)); assert(rough_approx_eq(1245.0f.pow(0.73f), 181.74967f)); val caught_err = false; try { (-1.1f).pow(3.5f); } catch e { caught_err = e isa Float.DomainError; } assert caught_err; } ================================================ FILE: tests/float_pretyprint.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func main() { val f1 = 3.14159265359; assert "{0:.2}".format(f1) == "3.14"; assert "{0:.3}".format(f1) == "3.142"; assert "{0:.4}".format(f1) == "3.1416"; val f2 = 123456789.987654321; assert "{0:.E}".format(f2) == "1.2345678998765433e8"; assert "{0}".format(f1) == "3.14159265359"; assert "{0}".format(f2) == "123456789.98765433"; } ================================================ FILE: tests/float_sqrt.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func main() { assert (4.0f.sqrt() - 2.0f).abs() <= 0.0001f; assert (9.0f.sqrt() - 3.0f).abs() <= 0.0001f; } ================================================ FILE: tests/flt_attrib.aria ================================================ # SPDX-License-Identifier: Apache-2.0 extension Float { func double() { return this * 2; } } func main() { val f = 1.234f; f.zero = 0.0f; assert f.zero == 0.0f; assert f.double() == 2.468f; } ================================================ FILE: tests/for_else.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func main() { val l1 = [1,2,3,4]; val l2 = []; val count_l1 = 0; for x in l1 { count_l1 += 1; } else { assert false; # this should not execute } assert count_l1 == 4; val count_l2 = 0; val else_hit = false; for x in l2 { count_l2 += 1; } else { else_hit = true; } assert count_l2 == 0; assert else_hit == true; } ================================================ FILE: tests/for_loop_test.aria ================================================ # SPDX-License-Identifier: Apache-2.0 struct IteratorValue { type func end() = Maybe::None; type func more(v) = Maybe::Some(v); } struct GenValues { type func new(f,t) { return alloc(This){ .from = f, .to = t, }; } struct GenValuesIterator { type func new(gv) { return alloc(This) { .from = gv.from, .to = gv.to, .current = gv.from, }; } func next() { if this.current == this.to { return IteratorValue.end(); } else { val ret = IteratorValue.more(this.current); this.current = this.current + 1; return ret; } } } func iterator() { return GenValues.GenValuesIterator.new(this); } } func main() { val gv = GenValues.new(3,10); val sum = 0; for n in gv { sum = sum + n; } assert sum == 42; } ================================================ FILE: tests/format_of_nested_brace.aria ================================================ # SPDX-License-Identifier: Apache-2.0 assert "{{{0}}}".format("hello world") == "{hello world}"; ================================================ FILE: tests/format_with_opt_arg.aria ================================================ # SPDX-License-Identifier: Apache-2.0 struct PrettyPrintable { type func new() { return alloc(This); } func prettyprint(style="xyz") { return "PrettyPrintable({0})".format(style); } } func main() { val pp = PrettyPrintable.new(); val s1 = "{0}".format(pp); val s2 = "{0:abc}".format(pp); val s3 = "{0:}".format(pp); assert s1 == "PrettyPrintable(xyz)"; assert s2 == "PrettyPrintable(abc)"; assert s3 == "PrettyPrintable()"; } ================================================ FILE: tests/fp_arith.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func add() { val f1 = 1.25f; val f2 = 0.5f; assert f1 + f2 == 1.75f; } func sub() { val f1 = 1.25f; val f2 = 0.25f; assert f1 - f2 == 1.0f; } func mul() { val f1 = 1.25f; val f2 = 2.0f; assert f1 * f2 == 2.5f; } func div() { val f1 = 2.5f; val f2 = 1.25f; assert f1 / f2 == 2.0f; } func main() { add(); sub(); mul(); div(); } ================================================ FILE: tests/fp_cmp_greater.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func is_greater(x,y) { return x > y; } func main() { assert is_greater(3.14f, 0); assert is_greater(4, 1.1f); assert is_greater(1.1f, 0.1f); assert !is_greater(3.14f, 5.0f); assert !is_greater(1, 1.1f); assert !is_greater(2.0f, 4); } ================================================ FILE: tests/fp_cmp_gt_eq.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func greater_or_equal(x,y) { return x >= y; } func main() { assert greater_or_equal(1.0f, 1.0f); assert greater_or_equal(1.0f, 0); assert greater_or_equal(1, 0.1f); assert !greater_or_equal(1.1f, 3.14f); assert !greater_or_equal(2, 3.14f); assert !greater_or_equal(3.14f, 5); } ================================================ FILE: tests/fp_cmp_lt_eq.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func lesser_or_equal(x,y) { return x <= y; } func main() { assert lesser_or_equal(1.0f, 1.0f); assert !lesser_or_equal(1.0f, 0); assert !lesser_or_equal(1, 0.1f); assert lesser_or_equal(1.1f, 3.14f); assert lesser_or_equal(2, 3.14f); assert lesser_or_equal(3.14f, 5); } ================================================ FILE: tests/fp_cmp_smaller.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func is_smaller(x,y) { return x < y; } func main() { assert !is_smaller(3.14f, 0); assert !is_smaller(4, 1.1f); assert !is_smaller(1.1f, 0.1f); assert is_smaller(3.14f, 5.0f); assert is_smaller(1, 1.1f); assert is_smaller(2.0f, 4); } ================================================ FILE: tests/fp_consts.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func main() { assert hasattr(Float, "inf"); assert hasattr(Float, "nan"); assert hasattr(Float, "epsilon"); assert Float.inf > 1.0f; assert 1.0f > -Float.inf; assert Float.inf > -Float.inf; assert -Float.inf < Float.inf; assert Float.nan != Float.nan; } ================================================ FILE: tests/fp_eq.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func main() { val x = 1.25f; val y = 0.25f; val z = 1; assert x == x; assert y == y; assert (x - y) == z; } ================================================ FILE: tests/fp_ext_notation.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func main() { val a = 3.5e2f; val b = 31.4e-1f; assert a == 350; assert b == 3.14f; } ================================================ FILE: tests/fp_int_arith.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func add() { val x = 1; val y = 1.25f; assert x + y == 2.25f; assert y + x == 2.25f; } func sub() { val x = 1; val y = 1.25f; assert x - y == -0.25f; assert y - x == 0.25f; } func mul() { val x = 2; val y = 3.25f; assert x * y == 6.5f; assert y * x == 6.5f; } func div() { val x = 2; val y = 4.0f; assert x / y == 0.5f; assert y / x == 2.0f; } func main() { add(); sub(); mul(); div(); } ================================================ FILE: tests/fp_no_suffix.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func basic_parsing() { val x = 1.25; val y = 1.25f; assert x == y; } func arithmetic_add() { val a = 3.14; val b = 2.86f; assert a + b == 6.0f; val c = 1.5; val d = 0.5; assert c + d == 2.0f; } func arithmetic_sub() { val a = 3.14; val b = 1.14f; assert a - b == 2.0f; val c = 5.5; val d = 2.5f; assert c - d == 3.0f; } func arithmetic_mul() { val a = 2.5; val b = 2.0f; assert a * b == 5.0f; val c = 1.25; val d = 4.0f; assert c * d == 5.0f; } func arithmetic_div() { val a = 10.0; val b = 2.5f; assert a / b == 4.0f; val c = 7.5; val d = 2.5f; assert c / d == 3.0f; } func comparison_greater() { assert 3.14 > 3.0f; assert 4.2 > 1.1f; assert 1.5 > 0.5f; assert !(2.0 > 3.14f); assert !(1.5 > 2.0f); } func comparison_lesser() { assert 2.0 < 3.14f; assert 1.1 < 4.2f; assert 0.5 < 1.5f; assert !(3.14 < 2.0f); assert !(4.2 < 1.1f); } func comparison_greater_equal() { assert 3.14 >= 3.14f; assert 3.14 >= 3.0f; assert 4.2 >= 1.1f; assert !(2.0 >= 3.14f); assert !(1.1 >= 4.2f); } func comparison_lesser_equal() { assert 3.14 <= 3.14f; assert 3.0 <= 3.14f; assert 1.1 <= 4.2f; assert !(3.14 <= 2.0f); assert !(4.2 <= 1.1f); } func scientific_notation() { val a = 3.14e2; val b = 31.4e-1f; assert a == 314.0f; assert b == 3.14f; val c = 1.5e1; assert c == 15.0f; } func negative_numbers() { val x = -3.14; val y = -3.14f; assert x == y; val a = -2.5; val b = 5.5f; assert a + b == 3.0f; val c = -1.25; val d = -0.75f; assert c - d == -0.5f; } func mixed_with_integers() { val result1 = 1.5 + 2; assert result1 == 3.5f; val result2 = 3 - 1.5; assert result2 == 1.5f; val result3 = 2.5 * 3; assert result3 == 7.5f; val result4 = 7.5 / 3; assert result4 == 2.5f; } func mixed_suffix_operations() { val a = 1.25; val b = 0.75f; val c = 2.0; assert a + b == c; assert (a * 2.0f) == 2.5f; assert (b / 0.25) == 3.0f; } func main() { basic_parsing(); arithmetic_add(); arithmetic_sub(); arithmetic_mul(); arithmetic_div(); comparison_greater(); comparison_lesser(); comparison_greater_equal(); comparison_lesser_equal(); scientific_notation(); negative_numbers(); mixed_with_integers(); mixed_suffix_operations(); } ================================================ FILE: tests/from_import_two_things.aria ================================================ # SPDX-License-Identifier: Apache-2.0 import One from example.two.things; import Two from example.two.things; func main() { val t1 = One.new(4); assert t1.double() == 10; val t2 = Two.new(7); assert t2.half() == 3; } ================================================ FILE: tests/func_arg_type_mismatch.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func add(x: Int, y: Int) { return x + y; } func main() { val caught = false; try { add(1, "2"); assert false; } catch e { match e { isa RuntimeError and case UnexpectedType => { caught = true; } } } assert caught; } ================================================ FILE: tests/func_as_arg.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func double(x) { return x + x; } func perform_op(f,n) { return f(n); } func main() { assert perform_op(double,4) == 8; } ================================================ FILE: tests/func_has_multiple_optionals.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func test(a,b,c=2,d=5,e=7) { return a + b * c + d * e; } func main() { assert test(1,2) == 40; assert test(1,2,3) == 42; assert test(1,2,3,4) == 35; assert test(1,2,3,4,5) == 27; } ================================================ FILE: tests/func_has_only_vararg.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func add_numbers(...) { val ret = 0; for n in varargs { ret += n; } return ret; } func main() { assert add_numbers(1,2,3,4) == 10; assert add_numbers(5) == 5; assert add_numbers(5,6) == 11; assert add_numbers() == 0; } ================================================ FILE: tests/func_has_vararg.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func add_numbers(n, ...) { val ret = n; for n in varargs { ret += n; } return ret; } func main() { assert add_numbers(1,2,3,4) == 10; assert add_numbers(5) == 5; assert add_numbers(5,6) == 11; } ================================================ FILE: tests/func_multiple_fixed_vararg.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func add_numbers(x,y,z, ...) { val ret = x+y+z; for n in varargs { ret += n; } return ret; } func main() { assert add_numbers(1,2,3,4) == 10; assert add_numbers(5,3,2) == 10; assert add_numbers(1,2,3,4,5,6,7,8,9,10) == 55; } ================================================ FILE: tests/func_only_takes_opt.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func test(x=1,y=2) { return x * y + 1; } func main() { assert test() == 3; assert test(2) == 5; assert test(2, 3) == 7; } ================================================ FILE: tests/func_order_of_vararg.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func compare(l,...) { assert l == varargs; } func main() { compare([3],3); compare([3,4],3,4); compare([3,4,5,6],3,4,5,6); compare([]); } ================================================ FILE: tests/func_returns_int.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func foo() { return 1 + 2; } func main() { val n = foo(); assert n == 3; } ================================================ FILE: tests/func_returns_unit.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func no_return_value(x,y) { x + y; } func sometimes_returns(x,y) { if (x > y) { return x + y; } } func main() { val x = no_return_value(1, 2); assert x isa Unit; assert x.is_unit(); x = sometimes_returns(3, 2); assert x isa Int; assert x == 5; x = sometimes_returns(1, 2); assert x isa Unit; assert x.is_unit(); } ================================================ FILE: tests/func_takes_args.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func subtract(x,y) { return x-y; } func main() { val n = subtract(5,2); assert n == 3; } ================================================ FILE: tests/func_type_equals.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func f1(x) { return x + 1; } func f2(x,y) { return x + y + 1; } func f3(x, ...) { return x; } func f4(x) { return x - 1; } func f5(y,x) { return y - x; } func f6(...) { return false; } func f7(x, ...) { return 1; } func main() { assert f1 isa typeof(f4); assert !(f1 isa typeof(f2)); assert f4 isa typeof(f1); assert !(f4 isa typeof(f6)); assert f2 isa typeof(f5); assert f3 isa typeof(f7); assert !(f6 isa typeof(f3)); assert !(f7 isa typeof(f6)); assert f5 isa typeof(f2); assert !(f6 isa typeof(f1)); assert !(f6 isa typeof(f7)); } ================================================ FILE: tests/func_union_type_mismatch.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func id(x: Int|String) { x; } func main() { val caught = false; try { id(Box()); assert false; } catch e { match e { isa RuntimeError and case UnexpectedType => { caught = true; } } } assert caught; } ================================================ FILE: tests/func_with_opt_vararg.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func test(a,b=1,...) { val ret = a + b; for arg in varargs { ret += arg; } return ret; } func main() { assert test(5) == 6; assert test(5, 2) == 7; assert test(5, 2, 3) == 10; assert test(5, 2, 3, 4) == 14; } ================================================ FILE: tests/func_with_struct.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func foo(x,y) { struct Pair { type func new(x,y) { return alloc(This) { .x = x, .y = y, }; } func add() { return this.x + this.y; } func max() { if (this.x > this.y) { return this.x; } else { return this.y; } } } return Pair.new(x,y); } func main() { val p = foo(3,4); assert(p.add() == 7); assert(p.max() == 4); } ================================================ FILE: tests/function_arity.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func f1(x,y,z) {} func f2(x,y,z=1) {} func f3(x, ...) {} func f4(...) {} func f5(x,y=1,...) {} func f6(x=1,y=2) {} func f7(x=1,y=2,...) {} struct S { func f1(x,y=1) {} func f2(x=0,y=1,...) {} type func f3() {} func f4() {} } func check_arity(f, min_wanted, should_accept, should_not_accept, is_va) { val f_arity = arity(f); assert f_arity.min == min_wanted; assert f_arity.can_call_with_argc(should_accept); assert !f_arity.can_call_with_argc(should_not_accept); assert f_arity.is_Varargs() == is_va; } func main() { check_arity(f1, 3, # min argc wanted 3, # acceptable argc 4, # should not accept false); assert !arity(f1).has_receiver; check_arity(f2, 2, # min argc wanted 3, # acceptable argc 4, # should not accept false); check_arity(f2, 2, # min argc wanted 2, # acceptable argc 0, # should not accept false); assert !arity(f2).has_receiver; check_arity(f3, 1, # min argc wanted 2, # acceptable argc 0, # should not accept true); check_arity(f3, 1, # min argc wanted 4, # acceptable argc 0, # should not accept true); assert !arity(f3).has_receiver; check_arity(f4, 0, # min argc wanted 2, # acceptable argc -1, # should not accept true); check_arity(f4, 0, # min argc wanted 0, # acceptable argc -1, # should not accept true); check_arity(f4, 0, # min argc wanted 5, # acceptable argc -1, # should not accept true); assert !arity(f4).has_receiver; assert arity(f4).can_call_with_argc(250); check_arity(f5, 1, # min argc wanted 2, # acceptable argc -1, # should not accept true); check_arity(f5, 1, # min argc wanted 4, # acceptable argc -1, # should not accept true); assert !arity(f5).has_receiver; check_arity(f6, 0, # min argc wanted 0, # acceptable argc 3, # should not accept false); check_arity(f6, 0, # min argc wanted 1, # acceptable argc 3, # should not accept false); check_arity(f6, 0, # min argc wanted 2, # acceptable argc 4, # should not accept false); assert !arity(f6).has_receiver; check_arity(f7, 0, # min argc wanted 0, # acceptable argc -1, # should not accept true); check_arity(f7, 0, # min argc wanted 1, # acceptable argc -1, # should not accept true); check_arity(f7, 0, # min argc wanted 2, # acceptable argc -1, # should not accept true); check_arity(f7, 0, # min argc wanted 4, # acceptable argc -1, # should not accept true); assert !arity(f7).has_receiver; val s = alloc(S); check_arity(s.f1, 1, # min argc wanted 1, # acceptable argc 3, # should not accept false); check_arity(s.f1, 1, # min argc wanted 2, # acceptable argc 3, # should not accept false); assert arity(s.f1).has_receiver; check_arity(s.f2, 0, # min argc wanted 1, # acceptable argc -1, # should not accept true); check_arity(s.f2, 0, # min argc wanted 2, # acceptable argc -1, # should not accept true); check_arity(s.f2, 0, # min argc wanted 3, # acceptable argc -1, # should not accept true); assert arity(s.f2).has_receiver; check_arity(S.f3, 0, # min argc wanted 0, # acceptable argc 1, # should not accept false); assert arity(S.f3).has_receiver; check_arity(s.f4, 0, # min argc wanted 0, # acceptable argc 1, # should not accept false); assert arity(s.f4).has_receiver; } ================================================ FILE: tests/function_list_attributes.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func foo(x,y) { return x + y + foo.n; } foo.n = 123; func main() { val l = |x,y| => x + y; l.n = 456; val foo_attrs = listattrs(foo); assert foo_attrs.contains("n"); assert foo_attrs.len() >= 1; val l_attrs = listattrs(l); assert l_attrs.contains("n"); assert l_attrs.len() >= 1; } ================================================ FILE: tests/getenv.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func main() { val ARIA_LIB_DIR = getenv("ARIA_LIB_DIR"); assert ARIA_LIB_DIR.is_Some(); assert ARIA_LIB_DIR.unwrap_Some().len() > 0; assert ARIA_LIB_DIR.unwrap_Some()[0] == "/"; val NO_SUCH_ENV_VAR = getenv("THERESHOULDBENOSUCHVARIABLEANYWHERE"); assert NO_SUCH_ENV_VAR.is_None(); } ================================================ FILE: tests/guard_on_return.aria ================================================ # SPDX-License-Identifier: Apache-2.0 import guard from aria.utils.guard; struct Guard { type val COUNTER = 0; instance func guard_exit() { Guard.COUNTER = Guard.COUNTER + 1; } } func add(x,y) { return guard(alloc(Guard)).do(|g| => { return x + y; })?; } func main() { assert Guard.COUNTER == 0; val n = add(3,4); assert n == 7; assert Guard.COUNTER == 1; } ================================================ FILE: tests/guards_exit_on_throw.aria ================================================ # SPDX-License-Identifier: Apache-2.0 import guard from aria.utils.guard; struct Guard { type val COUNTER = 0; func guard_exit() { Guard.COUNTER = Guard.COUNTER + 1; } } func ths() { guard(alloc(Guard)).do(|g| => { throw 1; }); } func catches() { val caught = false; try { ths(); } catch e { caught = (e == 1); assert Guard.COUNTER == 1; } return caught; } func main() { assert catches() == true; assert Guard.COUNTER == 1; } ================================================ FILE: tests/has_attr.aria ================================================ # SPDX-License-Identifier: Apache-2.0 struct Foo { type func blah() { return 0; } func answer() { return 42; } } extension Foo { func question() { return "?"; } } extension List { instance func head() { return this[0]; } } func main() { assert hasattr(Foo, "blah"); assert !hasattr(Foo, "answer"); assert !hasattr(Foo, "question"); val foo = alloc(Foo); assert hasattr(foo, "answer"); assert hasattr(foo, "question"); val s = "hello"; assert hasattr(s, "len"); val l = [1,2,3,4]; assert hasattr(l, "len"); assert hasattr(l, "head"); assert !hasattr(List, "len"); assert !hasattr(List, "head"); } ================================================ FILE: tests/hash_builtins.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func string() { val s1 = "hello"; assert s1.hash() != 0; val s2 = "world"; assert s2.hash() != s1.hash(); } func int() { assert 123.hash() == 123; assert 5555.hash() == 5555; } func bool() { assert true.hash() != false.hash(); } func float() { val f1 = 3.14f; val f2 = 1.112f; assert f1.hash() != 0; assert f2.hash() != f1.hash(); assert f2.hash() != 0; } func main() { string(); int(); float(); bool(); } ================================================ FILE: tests/hash_instant.aria ================================================ # SPDX-License-Identifier: Apache-2.0 import Instant from aria.date.instant; func main() { val i1 = Instant.new_with_utc_timestamp(1234567890); val i2 = Instant.new_with_utc_timestamp(0); val i3 = Instant.new_with_utc_timestamp(1234567890).with_timezone_offset(1); # nowhere real should have a 1 minute TZ offset assert i1 != i2; assert i1 != i3; assert i3 != i2; assert i1.hash() == i1.hash(); assert i1.hash() != i2.hash(); assert i1.hash() != i3.hash(); assert i2.hash() != i3.hash(); } ================================================ FILE: tests/hash_maybe.aria ================================================ # SPDX-License-Identifier: Apache-2.0 struct Foo { func hash() { return 42; } } func main() { val a = Maybe::None; assert a.hash() == 0; a = Maybe::Some(alloc(Foo)); assert a.hash() == 42; } ================================================ FILE: tests/hex_escapes.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func main() { val s = "\x41bc\x20 \x42"; assert s == "Abc B"; val t = "\u{41}ria == \u{2764}"; assert t == "Aria == ❤"; } ================================================ FILE: tests/http_get_headers.aria ================================================ # SPDX-License-Identifier: Apache-2.0 ### TAGS: FLAKEY import Request from aria.network.request; import JsonValue from aria.json.parser; import * from aria.network.retry; func main() { val request = Request.new("https://httpbin.org/headers"); request.headers["User-Agent"] = "Aria"; request.headers["Custom-Header"] = "Answer_Is_42"; val result = retry(|| => request.get(), |result| => { match result { case Ok(response) => { val code = response.status_code; return code == 200 || code == 503; } } else { return false; } }); result = result.unwrap_Pass()!; if result.status_code == 503 { println("Service Unavailable, try again later"); return true; } val json_result = JsonValue.parse(result.content)!; val json_map = json_result.unwrap_Object(); val json_headers = json_map["headers"].unwrap_Object(); assert json_headers["User-Agent"].unwrap_String() == "Aria"; assert json_headers["Custom-Header"].unwrap_String() == "Answer_Is_42"; } ================================================ FILE: tests/http_post.aria ================================================ # SPDX-License-Identifier: Apache-2.0 ### TAGS: FLAKEY import Request from aria.network.request; import JsonValue from aria.json.parser; import * from aria.network.retry; func main() { val request = Request.new("https://httpbin.org/post"); val result = retry(|| => request.post("hello world"), |result| => { match result { case Ok(response) => { val code = response.status_code; return code == 200 || code == 503; } } else { return false; } }); result = result.unwrap_Pass()!; if result.status_code == 503 { println("Service Unavailable, try again later"); return true; } val json_result = JsonValue.parse(result.content)!; val json_map = json_result.unwrap_Object(); val json_data = json_map["data"].unwrap_String(); assert json_data == "hello world"; } ================================================ FILE: tests/http_post_json.aria ================================================ # SPDX-License-Identifier: Apache-2.0 ### TAGS: FLAKEY import Request from aria.network.request; import JsonValue from aria.json.parser; import Map from aria.structures.map; import * from aria.network.retry; func main() { val request = Request.new("https://httpbin.org/post"); val result = retry(|| => request.post_as_json(Map.new() { ["message"] = "hello world", }), |result| => { match result { case Ok(response) => { val code = response.status_code; return code == 200 || code == 503; } } else { return false; } }); result = result.unwrap_Pass()!; if result.status_code == 503 { println("Service Unavailable, try again later"); return true; } val json_result = JsonValue.parse(result.content)!.flatten(); assert json_result["json"]["message"] == "hello world"; } ================================================ FILE: tests/http_request_custom_status.aria ================================================ # SPDX-License-Identifier: Apache-2.0 ### TAGS: FLAKEY import Request from aria.network.request; import * from aria.network.retry; func main() { val request = Request.new("https://httpbin.org/status/418"); val result = retry(|| => request.get(), |result| => { match result { case Ok(response) => { val code = response.status_code; return code == 418 || code == 503; } } else { return false; } }); result = result.unwrap_Pass()!; if result.status_code == 503 { println("Service Unavailable, try again later"); return true; } } ================================================ FILE: tests/http_simple_get.aria ================================================ # SPDX-License-Identifier: Apache-2.0 ### TAGS: FLAKEY import Request from aria.network.request; import * from aria.network.retry; func main() { val request = Request.new("https://www.rust-lang.org/"); val response = retry(|| => request.get(), |result| => { match result { case Ok(response) => { val code = response.status_code; return code == 200 || code == 503; } } else { return false; } }); response = response.unwrap_Pass()!; if response.status_code == 503 { println("Service Unavailable, try again later"); return true; } assert response.headers["content-type"].contains("html"); assert response.content.contains(" { caught = n == 10; } } } assert caught; } ================================================ FILE: tests/index_set.aria ================================================ # SPDX-License-Identifier: Apache-2.0 struct StorePairs { type func new() { return alloc(This) { .pairs = [], }; } operator []=(key, val) { val i = 0; val append = true; while i < this.pairs.len() { if this.pairs[i][0] == key { this.pairs[i][1] = val; append = false; break; } i = i + 1; } if append { this.pairs.append([key,val]); } } operator [](key) { val i = 0; while i < this.pairs.len() { if this.pairs[i][0] == key { return this.pairs[i][1]; } i = i + 1; } return false; } } func main() { val p = StorePairs.new(); p[0] = 1; assert p[0] == 1; p[0] = 2; assert p[0] == 2; p[123] = "hi"; assert p[123] == "hi"; assert p[0] == 2; assert p[true] == false; } ================================================ FILE: tests/index_vararg.aria ================================================ # SPDX-License-Identifier: Apache-2.0 struct Foo { operator [](...) { return varargs.len(); } } func main() { val f = alloc(Foo); assert f[1,2,3] == 3; assert f[3,2,1] == 3; assert f[0] == 1; assert f[32, 33] == 2; } ================================================ FILE: tests/inner_function.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func main() { func foo(x,y) { return x + y - 1; } assert foo(3,4) == 6; } ================================================ FILE: tests/inner_function_redef.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func main() { func inner(a,b,c) { return a + b * c; } assert inner(3,4,5) == 23; func inner(a,b) { return a * b; } assert inner(3,4) == 12; func inner() { return 42; } assert inner() == 42; } ================================================ FILE: tests/inner_is_closure.aria ================================================ # SPDX-License-Identifier: Apache-2.0 val x = 123; val y = 100; func main() { val x = 321; func foo(n) { return n + x + y; } val bar = |n| => n + x + y; assert foo(3) == 424; assert bar(3) == 424; } ================================================ FILE: tests/inner_outer_loop.aria ================================================ # SPDX-License-Identifier: Apache-2.0 ### TAGS: XFAIL import aria.range.int_extension; val inner = 0; val outer = 0; for i in 0.to(12) { for i in 0.to(500) { inner += 1; } outer += 1; } assert inner == 6000; assert outer == 12; ================================================ FILE: tests/inner_val.aria ================================================ # SPDX-License-Identifier: Apache-2.0 val counter = 0; func next() { counter = counter + 1; return counter; } func new_val_decl() { val buffer = []; val n = next(); while true { buffer.append(n); val n = next(); if n == 5 { break; } } return buffer; } func reuse_val_decl() { val buffer = []; val n = next(); while true { buffer.append(n); n = next(); if n == 5 { break; } } return buffer; } func main() { val data = new_val_decl(); assert data == [1, 1, 1, 1]; counter = 0; data = reuse_val_decl(); assert data == [1, 2, 3, 4]; } ================================================ FILE: tests/instant_from_unix_2024_12_29.aria ================================================ # SPDX-License-Identifier: Apache-2.0 import Instant from aria.date.instant; func main() { val ts = 1735446958423; val instant = Instant.new_with_utc_timestamp(ts); assert instant.year == 2024; assert instant.month == 12; assert instant.day == 29; assert instant.hour == 4; assert instant.minute == 35; assert instant.second == 58; } ================================================ FILE: tests/instant_from_unix_ts.aria ================================================ # SPDX-License-Identifier: Apache-2.0 import Instant from aria.date.instant; func main() { val moment = Instant.new_with_utc_timestamp(1623602460000); assert moment.year == 2021; assert moment.month == 6; assert moment.day == 13; assert moment.hour == 16; assert moment.minute == 41; assert moment.second == 0; assert moment.millisecond == 0; assert "{0}".format(moment) == "Jun 13 2021 16:41:00.000"; moment = Instant.new_with_utc_timestamp(1736142835000); assert moment.year == 2025; assert moment.month == 1; assert moment.day == 6; assert moment.hour == 5; assert moment.minute == 53; assert moment.second == 55; assert moment.millisecond == 0; moment = Instant.new_with_utc_timestamp(-85399999000); assert moment.year == 1967; assert moment.month == 4; assert moment.day == 18; assert moment.hour == 13; assert moment.minute == 46; assert moment.second == 41; assert moment.millisecond == 0; moment = Instant.new_with_utc_timestamp(-783264174000); assert moment.year == 1945; assert moment.month == 3; assert moment.day == 7; assert moment.hour == 10; assert moment.minute == 37; assert moment.second == 6; assert moment.millisecond == 0; moment = Instant.new_with_utc_timestamp(-1); assert moment.year == 1969; assert moment.month == 12; assert moment.day == 31; assert moment.hour == 23; assert moment.minute == 59; assert moment.second == 59; assert moment.millisecond == 999; moment = Instant.new_with_utc_timestamp(-999); assert moment.year == 1969; assert moment.month == 12; assert moment.day == 31; assert moment.hour == 23; assert moment.minute == 59; assert moment.second == 59; assert moment.millisecond == 1; moment = Instant.new_with_utc_timestamp(-1000); assert moment.year == 1969; assert moment.month == 12; assert moment.day == 31; assert moment.hour == 23; assert moment.minute == 59; assert moment.second == 59; assert moment.millisecond == 0; moment = Instant.new_with_utc_timestamp(-1001); assert moment.year == 1969; assert moment.month == 12; assert moment.day == 31; assert moment.hour == 23; assert moment.minute == 59; assert moment.second == 58; assert moment.millisecond == 999; moment = Instant.new_with_utc_timestamp(-86400000); assert moment.year == 1969; assert moment.month == 12; assert moment.day == 31; assert moment.hour == 0; assert moment.minute == 0; assert moment.second == 0; assert moment.millisecond == 0; moment = Instant.new_with_utc_timestamp(-86400001); assert moment.year == 1969; assert moment.month == 12; assert moment.day == 30; assert moment.hour == 23; assert moment.minute == 59; assert moment.second == 59; assert moment.millisecond == 999; moment = Instant.new_with_utc_timestamp(-2678400000); assert moment.year == 1969; assert moment.month == 12; assert moment.day == 1; assert moment.hour == 0; assert moment.minute == 0; assert moment.second == 0; assert moment.millisecond == 0; moment = Instant.new_with_utc_timestamp(-1423503211); assert moment.year == 1969; assert moment.month == 12; assert moment.day == 15; assert moment.hour == 12; assert moment.minute == 34; assert moment.second == 56; assert moment.millisecond == 789; } ================================================ FILE: tests/instant_now.aria ================================================ # SPDX-License-Identifier: Apache-2.0 import Instant from aria.date.instant; func main() { val now = Instant.now(); assert now.year >= 2025; assert now.month >= 1 && now.month <= 12; assert now.day >= 1 && now.day <= 31; assert now.hour >= 0 && now.hour <= 23; assert now.minute >= 0 && now.minute <= 59; assert now.second >= 0 && now.second <= 59; assert now.millisecond >= 0 && now.millisecond <= 999; } ================================================ FILE: tests/instant_offset_breaks_eq.aria ================================================ # SPDX-License-Identifier: Apache-2.0 import Instant from aria.date.instant; val a = Instant.new_with_utc_timestamp(0).with_timezone_offset(60); val b = Instant.new_with_timestamp_and_offset(0, 60); assert a == b; ================================================ FILE: tests/instant_with_tz_offset.aria ================================================ # SPDX-License-Identifier: Apache-2.0 import Instant from aria.date.instant; func main() { val instant = Instant.new_with_timestamp_and_offset(1623602460000, -360); assert instant.year == 2021; assert instant.month == 6; assert instant.day == 13; assert instant.hour == 10; assert instant.minute == 41; assert instant.second == 0; assert instant.millisecond == 0; instant = Instant.new_with_timestamp_and_offset(1623602460000, 150); assert instant.year == 2021; assert instant.month == 6; assert instant.day == 13; assert instant.hour == 19; assert instant.minute == 11; assert instant.second == 0; assert instant.millisecond == 0; } ================================================ FILE: tests/int_abs.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func main() { val x = 3; val y = -3; assert y.abs() == x; assert x.abs() == x; } ================================================ FILE: tests/int_arith.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func addition() { assert 3 + 4 == 7; assert 2 + 2 == 4; } func subtraction() { assert 2 - 2 == 0; assert 12 - 3 == 9; assert 9 - 10 == -1; } func multiplication() { assert 3 * 2 == 6; assert 2 * 1 == 2; assert 6 * 7 == 42; } func division() { assert 8 / 4 == 2; assert 7 / 2 == 3; assert 5 / 1 == 5; } func remainder() { assert 8 % 2 == 0; assert 7 % 2 == 1; assert 21 % 9 == 3; } func main() { addition(); subtraction(); multiplication(); division(); remainder(); } ================================================ FILE: tests/int_fp_int.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func main() { val a = 3; assert a.float() == 3.0f; assert a.float() isa Float; a = 3.0f; assert a.int() == 3; assert a.int() isa Int; } ================================================ FILE: tests/int_index_operator.aria ================================================ # SPDX-License-Identifier: Apache-2.0 extension Int { operator[](index: Int) { val n = 1 << index; return (this & n) >> index; } } val n = 0b1111000011101; assert n[0] == 1; assert n[1] == 0; assert n[2] == 1; assert n[3] == 1; assert n[4] == 1; assert n[5] == 0; assert n[6] == 0; assert n[7] == 0; assert n[8] == 0; assert n[9] == 1; assert n[10] == 1; assert n[11] == 1; assert n[12] == 1; assert n[13] == 0; assert n[14] == 0; assert n[15] == 0; # ... and so on and so forth ... ================================================ FILE: tests/int_notations.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func main() { val a = 123_456 + 1; assert a == 1234_57; val a = 0xF - 0xD; assert a == 0b10; val a = 3 * 4; assert a == 12; } ================================================ FILE: tests/int_prettyprint_style.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func main() { val a = 1234; val b = -35; assert "{0}".format(a) == "1234"; assert "{0:6}".format(a) == "001234"; assert "{0:2}".format(a) == "1234"; assert "0x{0:x}".format(a) == "0x4d2"; assert "0x{0:5x}".format(a) == "0x004d2"; assert "{0}".format(b) == "-35"; assert "{0:6}".format(b) == "-00035"; } ================================================ FILE: tests/int_range.aria ================================================ # SPDX-License-Identifier: Apache-2.0 import Range from aria.range.range; import aria.iterator.mixin; func main() { val range = Range.from(3).through(5); assert range.contains(3); assert range.contains(4); assert range.contains(5); assert !range.contains(2); assert !range.contains(6); val sum = 0; for item in range { sum = sum + item; } assert sum == 12; val list = range.iterator().to_list(); assert list == [3,4,5]; } ================================================ FILE: tests/int_range_ops.aria ================================================ # SPDX-License-Identifier: Apache-2.0 import Range from aria.range.range; func main() { val r1 = Range.from(3).through(5); val r2 = Range.from(6).through(10); val r3 = Range.from(1).through(7); val r2_u_r3 = r2.union(r3); assert r2_u_r3.iterator().to_list() == [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; val r1_i_r2 = r1.intersection(r2); assert r1_i_r2.length() == 0; val r1_i_r3 = r1.intersection(r3); assert r1_i_r3.iterator().to_list() == [3, 4, 5]; val r1_u_3 = r1.union(r3); assert r1_u_3.iterator().to_list() == [1, 2, 3, 4, 5, 6, 7]; } ================================================ FILE: tests/int_range_step.aria ================================================ # SPDX-License-Identifier: Apache-2.0 import Range from aria.range.range; func main() { val range = Range.from(3).through(20); val sum = 0; for item in range.step(5) { sum = sum + item; } assert sum == 42; } ================================================ FILE: tests/int_range_where_iter.aria ================================================ # SPDX-License-Identifier: Apache-2.0 import Range from aria.range.range; func main() { val range = Range.from(3).through(20); val count = 0; for item in range.iterator().where(|x| => x == 10) { assert item == 10; count = count + 1; } assert count == 1; } ================================================ FILE: tests/int_shift_test.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func main() { val n = 0b0011001100010; val shl = n >> 3; assert shl == 0b0011001100; val shn = n << 4; assert shn == 0b00110011000100000; } ================================================ FILE: tests/int_wraps.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func main() { val a = 0x7FFFFFFFFFFFFFFF; assert(a + 1 < 0); assert(a * 2 == -2); assert(a-a*2 == -9223372036854775807); assert(a/2 == 4611686018427387903); assert(a % 37 == 5); } ================================================ FILE: tests/invalid_fileopen_throws.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func main() { val thrown = false; try { # this path should be invalid on pretty much any system that exists and matters val file = File.open("@:?/\.nonexistent_file.txt", File.OpenMode.new().read()); } catch e { thrown = true; } assert(thrown); } ================================================ FILE: tests/invalid_utf8_bytes.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func main() { try { val bytes = [240, 159, 150]; val str = String.new_with_bytes(bytes); assert false; } catch e { assert e isa String.EncodingError; assert e.msg == "invalid utf8"; } } ================================================ FILE: tests/isa_intersection.aria ================================================ # SPDX-License-Identifier: Apache-2.0 import ok,err from aria.core.result; mixin DefaultAlloc { type func new() { return alloc(This); } } mixin A { func double(x) { return x + x; } } mixin B { func triple(x) { return x + x + x; } } struct S { include A include B include DefaultAlloc } struct T { include A include DefaultAlloc } struct U { include B include DefaultAlloc } func do_math(x: A&B) { return x.double(2) + x.triple(3); } func try_doing_math(x) { try { return ok(do_math(x)); } catch e { return err(e); } } func main() { val s = S.new(); val t = T.new(); val u = U.new(); val s_math = try_doing_math(s); val t_math = try_doing_math(t); val u_math = try_doing_math(u); assert s_math.is_Ok(); assert s_math! == 13; assert u_math.is_Err(); assert t_math.is_Err(); } ================================================ FILE: tests/isa_match.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func main() { val x = 123; val hit = false; match x { isa Bool => { assert(false); }, isa List => { assert(false); }, isa Int => { hit = true; }, } else { assert(false); } assert hit; } ================================================ FILE: tests/isa_mixin_union.aria ================================================ # SPDX-License-Identifier: Apache-2.0 import ok,err from aria.core.result; mixin A { func double(x) { return x + x; } } mixin B { func double(x) { return x * 2; } } struct S { include A } struct T { include B } struct U {} func foo(x: A|B) { return x.double(5); } func try_double(x) { try { return ok(foo(x)); } catch e { return err(e); } } func main() { val s = alloc(S); val t = alloc(T); val u = alloc(U); val double_s = try_double(s); val double_t = try_double(t); val double_u = try_double(u); assert double_s.is_Ok(); assert double_s! == 10; assert double_t.is_Ok(); assert double_t! == 10; assert double_u.is_Err(); } ================================================ FILE: tests/isa_operator.aria ================================================ # SPDX-License-Identifier: Apache-2.0 struct Foo {} func main() { assert 3 isa Int; assert 3.14f isa Float; assert false isa Bool; assert !(false isa String); assert !("hello" isa Foo); assert alloc(Foo) isa (Int|Foo); assert false isa (Bool|String); } ================================================ FILE: tests/iter_enum.aria ================================================ # SPDX-License-Identifier: Apache-2.0 import Enumerate from aria.iterator.enumerate; func main() { val l = [1,2,3,4,5,6,7,8,9]; for item in Enumerate.new(l) { assert item.index + 1 == item.value; } } ================================================ FILE: tests/iter_zip.aria ================================================ # SPDX-License-Identifier: Apache-2.0 import Zip from aria.iterator.zip; import aria.iterator.mixin; func add(x,y) { return x + y; } func main() { val l1 = [1,2,3,4,5]; val l2 = [4,3,2,0]; val l3 = [3,3,3,4]; val count = 0; val z = Zip.new(l1,l2,l3); for item in z { val sum = item.reduce(add,0); assert sum == 8; count = count + 1; } assert count == 4; } ================================================ FILE: tests/iterable_skip.aria ================================================ # SPDX-License-Identifier: Apache-2.0 import aria.iterator.mixin; func main() { val l = [1,2,3,4,5,6,7,8,9,10]; assert l.iterator().skip(5).nth(0)! == 6; assert l.iterator().skip(5).nth(1)! == 7; assert l.iterator().skip(10).first() == Maybe::None; assert l.iterator().skip(15).first() == Maybe::None; assert l.iterator().skip(0).first()! == 1; assert l.iterator().skip(3).skip(4).first()! == 8; } ================================================ FILE: tests/iterable_truncate.aria ================================================ # SPDX-License-Identifier: Apache-2.0 import aria.iterator.mixin; func main() { val l = [1,2,3,4,5,6,7,8,9,10]; assert l.iterator().truncate(5).sum() == 15; assert l.iterator().truncate(0).sum() == 0; assert l.iterator().truncate(1000).sum() == 55; assert l.iterator().truncate(3).truncate(2).sum() == 3; } ================================================ FILE: tests/iterator_mixin.aria ================================================ # SPDX-License-Identifier: Apache-2.0 import aria.iterator.mixin; func is_even(x) { return x % 2 == 0; } func add_one(x) { return x + 1; } func main() { val l = [1,2,3,4,5,6,7,8,9,10]; val sum = 0; for item in l.iterator().where(is_even).map(add_one) { sum = sum + item; } assert sum == 35; assert (l.iterator().find(is_even) ?? -1) == 2; assert (l.iterator().position(is_even) ?? -1) == 1; assert l.iterator().sum() == 55; assert l.iterator().sum(10) == 65; assert l.iterator().product() == 3628800; assert l.iterator().product(2) == 7257600; assert (l.iterator().max() ?? -1) == 10; assert (l.iterator().min() ?? -1) == 1; assert l.iterator().count() == 10; val l = [42, 16, 55, 120, 5]; assert (l.iterator().first() ?? -1) == 42; assert (l.iterator().last() ?? -1) == 5; assert (l.iterator().nth(2) ?? -1) == 55; } ================================================ FILE: tests/iterator_type_mismatch.aria ================================================ # SPDX-License-Identifier: Apache-2.0 struct MyIterator { func next() { return 12; # not a Maybe :( } func iterator() = this; type func new() = alloc(This); } func main() { val caught = false; val it = MyIterator.new(); try { for number in it { assert false; # should never get here } } catch e { assert e isa RuntimeError; assert e.is_UnexpectedType(); caught = true; } assert caught; } ================================================ FILE: tests/json_flatten.aria ================================================ # SPDX-License-Identifier: Apache-2.0 import JsonValue from aria.json.value; import aria.json.parser; func main() { val json_string = '{ "key1": [1,2,3], "key2": {"a":1, "b":false, "c": "hello world"} }'; val json_object = JsonValue.parse(json_string)!; val json_flat = json_object.flatten(); assert json_flat["key1"][0] == 1; assert json_flat["key1"][1] == 2; assert json_flat["key1"][2] == 3; assert json_flat["key1"].len() == 3; assert json_flat["key2"]["a"] == 1; assert json_flat["key2"]["b"] == false; assert json_flat["key2"]["c"] == "hello world"; assert json_flat["key2"].len() == 3; assert json_flat.len() == 2; } ================================================ FILE: tests/json_parse_array.aria ================================================ # SPDX-License-Identifier: Apache-2.0 import JsonValue from aria.json.parser; func main() { val json_object = JsonValue.parse('[1, 2, "hello", 3.14]')!; assert json_object.is_Array(); val array = json_object.unwrap_Array(); assert array.len() == 4; assert array[0].is_Number(); assert array[0].unwrap_Number() == 1.0f; assert array[1].is_Number(); assert array[1].unwrap_Number() == 2.0f; assert array[2].is_String(); assert array[2].unwrap_String() == "hello"; assert array[3].is_Number(); assert array[3].unwrap_Number() == 3.14f; } ================================================ FILE: tests/json_parse_nested.aria ================================================ # SPDX-License-Identifier: Apache-2.0 import JsonValue from aria.json.parser; func main() { val json_object = JsonValue.parse('{"l": [1, 2, 3], "o": {"key1": 1, "key2": "value2", "key3": [4,5,6]}}')!; assert json_object.is_Object(); val map = json_object.unwrap_Object(); assert map["l"].is_Array(); val array = map["l"].unwrap_Array(); assert array.len() == 3; assert array[0].is_Number(); assert array[0].unwrap_Number() == 1.0f; assert array[1].is_Number(); assert array[1].unwrap_Number() == 2.0f; assert array[2].is_Number(); assert array[2].unwrap_Number() == 3.0f; assert map["o"].is_Object(); val inner_map = map["o"].unwrap_Object(); assert inner_map["key1"].is_Number(); assert inner_map["key1"].unwrap_Number() == 1.0f; assert inner_map["key2"].is_String(); assert inner_map["key2"].unwrap_String() == "value2"; assert inner_map["key3"].is_Array(); val inner_array = inner_map["key3"].unwrap_Array(); assert inner_array.len() == 3; assert inner_array[0].is_Number(); assert inner_array[0].unwrap_Number() == 4.0f; assert inner_array[1].is_Number(); assert inner_array[1].unwrap_Number() == 5.0f; assert inner_array[2].is_Number(); assert inner_array[2].unwrap_Number() == 6.0f; } ================================================ FILE: tests/json_parse_wellknown.aria ================================================ # SPDX-License-Identifier: Apache-2.0 import JsonValue from aria.json.parser; func main() { val json_object = JsonValue.parse('[true, false, null]')!; assert json_object.is_Array(); val array = json_object.unwrap_Array(); assert array.len() == 3; assert array[0].is_Boolean(); assert array[0].unwrap_Boolean() == true; assert array[1].is_Boolean(); assert array[1].unwrap_Boolean() == false; assert array[2].is_Null(); } ================================================ FILE: tests/lambda_f_block.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func main() { val f = |x,y| => { if x > y { return x; } else { return y; } }; assert f(3,4) == 4; assert f(2,0) == 2; } ================================================ FILE: tests/lambda_f_define.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func main() { val double = |x| => x * 2; assert double(3) == 6; assert double("a") == "aa"; } ================================================ FILE: tests/lambda_f_global.aria ================================================ # SPDX-License-Identifier: Apache-2.0 val n = 3; val foo = |x| => x + n; func main() { assert foo(4) == 7; n = 2; assert foo(4) == 6; assert foo(6) == 8; } ================================================ FILE: tests/lambda_refers_to_uplevel.aria ================================================ # SPDX-License-Identifier: Apache-2.0 val q = 1; func foo(x,y,z) { return |a| => a + y - z * q; } func main() { val f = foo(3,4,5); assert f(3) == 2; assert f(4) == 3; q = 2; assert f(5) == -1; } ================================================ FILE: tests/large_hex_int.aria ================================================ # SPDX-License-Identifier: Apache-2.0 val n = 0x94d049bb133111eb; assert n == -7723592293110705685; ================================================ FILE: tests/large_negative_literal.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func main() { val x = 0x7FFFFFFFFFFFFFFF; assert x==9223372036854775807; assert x+1==-9223372036854775808; } ================================================ FILE: tests/list_append.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func main() { val l = [1,2,3,4]; assert l.len() == 4; assert l[0] == 1; assert l[1] == 2; assert l[2] == 3; assert l[3] == 4; l.append(5).append(6); assert l.len() == 6; assert l[3] == 4; assert l[4] == 5; assert l[5] == 6; } ================================================ FILE: tests/list_as_map_key.aria ================================================ # SPDX-License-Identifier: Apache-2.0 import Map from aria.structures.map; import aria.structures.hash.list; func main() { val m = Map.new(); val l1 = [1,2,3]; val l2 = [4,5,6]; m[l1] = 1+2+3; m[l2] = 4+5+6; assert m[l1] == 6; assert m[l2] == 15; assert m.get([1,2,3])! == 6; assert m.get([4,5,6])! == 15; assert m.get([3,2,1]).is_None(); assert m.get([]).is_None(); assert m.len() == 2; } ================================================ FILE: tests/list_contains.aria ================================================ # SPDX-License-Identifier: Apache-2.0 struct Foo {} func main() { val l = ["hello", false, 123, alloc(Foo), 5]; assert l.contains(false); assert l.contains("hello"); assert !l.contains(true); assert !l.contains(456); assert l.contains(5); } ================================================ FILE: tests/list_custom_write.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func main() { val l = [1,2,3,5]; l.sum = 11; l.max = 5; assert l.sum == 11; assert l.max == 5; assert l.len() == 4; } ================================================ FILE: tests/list_drop.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func main() { val l = [1,2,3,4,5]; assert l.len() == 5; assert l.drop() == 5; assert l.len() == 4; assert l[0] == 1; assert l[1] == 2; assert l[2] == 3; assert l[3] == 4; assert l.drop() == 4; assert l.len() == 3; assert l[0] == 1; assert l[1] == 2; assert l[2] == 3; l.append(5); assert l.len() == 4; assert l[0] == 1; assert l[1] == 2; assert l[2] == 3; assert l[3] == 5; } ================================================ FILE: tests/list_equals.aria ================================================ # SPDX-License-Identifier: Apache-2.0 struct Integer { type func new(n: Int) { return alloc(This){ .n = n, }; } operator ==(rhs) { if rhs isa Integer { return rhs.n == this.n; } elsif rhs isa Int { return rhs == this.n; } else { throw alloc(Unimplemented); } } } func main() { val l1 = [1,2,3,4,5]; val l2 = [Integer.new(1), 2, 3, Integer.new(4), 5]; val l3 = [Integer.new(1), 2, 3, 5, Integer.new(5)]; assert l1 == l2; assert l2 == l1; assert l1 != l3; assert l3 != l1; assert l2 != l3; assert l3 != l2; } ================================================ FILE: tests/list_filled.aria ================================================ # SPDX-License-Identifier: Apache-2.0 val l = List.filled(false, 100); assert l.len() == 100; for item in l { assert item == false; } ================================================ FILE: tests/list_for_loop.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func main() { val sum = 0; val l = [1,2,3,4,5]; for item in l { sum = sum + item; } assert sum == 15; } ================================================ FILE: tests/list_functional.aria ================================================ # SPDX-License-Identifier: Apache-2.0 import aria.iterator.mixin; func is_gt_10(x) { return x > 10; } func test_any() { val l = [1,2,3,4,5,6]; assert l.iterator().any(|x| => x > 5) == true; assert l.iterator().any(is_gt_10) == false; } func is_lt_10(x) { return x < 10; } func test_all() { val l = [1,2,3,4,5,6]; assert l.iterator().all(is_lt_10) == true; assert l.iterator().all(|x| => x > 5) == false; } func test_where() { val l = [1,2,3,4,5,6]; assert l.where(is_gt_10).to_list() == []; assert l.where(|x| => x > 5).to_list() == [6]; } func do_the_thing(x) { return 2 * x + 1; } func test_map() { val l = [1,2,3,4,5,6]; assert l.map(do_the_thing).to_list() == [3,5,7,9,11,13]; assert l.map(|x| => x > 5).to_list() == [false,false,false,false,false,true]; } func main() { test_any(); test_all(); test_where(); test_map(); } ================================================ FILE: tests/list_hash.aria ================================================ # SPDX-License-Identifier: Apache-2.0 import aria.structures.hash.list; func main() { val l1 = [1,2,3]; val l2 = ["1", "2", "3"]; val l3 = [3,2,1]; val l4 = []; assert l1.hash() != l2.hash(); assert l1.hash() != l3.hash(); assert l1.hash() != l4.hash(); assert l2.hash() != l3.hash(); assert l2.hash() != l4.hash(); assert l3.hash() != l4.hash(); assert l1.hash() == l1.hash(); assert l2.hash() == l2.hash(); assert l3.hash() == l3.hash(); assert l4.hash() == l4.hash(); } ================================================ FILE: tests/list_iter_map.aria ================================================ # SPDX-License-Identifier: Apache-2.0 import Enumerate from aria.iterator.enumerate; import aria.iterator.mixin; func double(n) { return n + n; } func main() { val sum = 0; val list = [1,2,3,4,5,6]; for item in Enumerate.new(list.iterator().map(double)) { val original_number = list[item.index]; val new_number = item.value; assert new_number == double(original_number); sum += new_number; } assert sum == 42; } ================================================ FILE: tests/list_join.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func main() { val l = [1,2,3,4]; assert l.join() == "1, 2, 3, 4"; assert l.join("..") == "1..2..3..4"; assert l.join(" - ") == "1 - 2 - 3 - 4"; assert [].join() == ""; assert [1].join() == "1"; assert [].join("..") == ""; assert [1].join("..") == "1"; } ================================================ FILE: tests/list_length.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func main() { val lst_empty = []; val lst_one = [1]; val lst_three = [1,2,3]; val lst_nested = [lst_empty, lst_one, lst_three, false]; assert lst_empty.len() == 0; assert lst_one.len() == 1; assert lst_three.len() == 3; assert lst_nested.len() == 4; assert lst_nested[0].len() == 0; assert lst_nested[1].len() == 1; assert lst_nested[2].len() == 3; } ================================================ FILE: tests/list_mul_op.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func main() { val l = [1,2,3]; assert l * 0 == []; assert l * 1 == [1,2,3]; assert l * 2 == [1,2,3,1,2,3]; assert l * 3 == [1,2,3,1,2,3,1,2,3]; assert l * 4 == [1,2,3,1,2,3,1,2,3,1,2,3]; assert 0 * l == []; assert 1 * l == [1,2,3]; assert 2 * l == [1,2,3,1,2,3]; assert 3 * l == [1,2,3,1,2,3,1,2,3]; assert 4 * l == [1,2,3,1,2,3,1,2,3,1,2,3]; } ================================================ FILE: tests/list_negative_index.aria ================================================ # SPDX-License-Identifier: Apache-2.0 val x = [1,2,3,4,5]; assert x[-1] == 5; assert x[-2] == 4; assert x[-5] == 1; try { println(x[-6]); } catch e { assert e isa RuntimeError; assert e.is_IndexOutOfBounds(); } x[-1] = 10; assert x[4] == 10; x[-2] = 20; assert x[3] == 20; try { x[-10] = 50; } catch e { assert e isa RuntimeError; assert e.is_IndexOutOfBounds(); } ================================================ FILE: tests/list_op_add.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func main() { val l1 = [1,2,3,4]; val l2 = [3,2,1]; val l3 = l1 + l2; assert l3.len() == l1.len() + l2.len(); assert l3[0] == 1; assert l3[1] == 2; assert l3[2] == 3; assert l3[3] == 4; assert l3[4] == 3; assert l3[5] == 2; assert l3[6] == 1; } ================================================ FILE: tests/list_prettyprint.aria ================================================ # SPDX-License-Identifier: Apache-2.0 struct Foo { type val COUNTER = 1; type func new(x) { val f = alloc(This){ .counter = Foo.COUNTER, .x = x, }; Foo.COUNTER = Foo.COUNTER + 1; return f; } func prettyprint() { return "Foo({0},{1})".format(this.counter,this.x); } } func main() { val l = [Foo.new("a"),Foo.new("b"),Foo.new("c")]; val ls = "list of Foo = {0}".format(l); assert ls == "list of Foo = [Foo(1,a), Foo(2,b), Foo(3,c)]"; } ================================================ FILE: tests/list_product_negative.aria ================================================ # SPDX-License-Identifier: Apache-2.0 assert [1,2,3]*-1 == []; assert [[1,2,3],[4,5,6],1,2,3]*-5 == []; assert ["a","b","c"]*0 == []; ================================================ FILE: tests/list_search.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func main() { val list = [3,7,11,16,19,33,46,55,91,328,410,510,613]; assert list.binary_search(21).is_None(); assert list.binary_search(33).is_Some(); assert list.binary_search(33).unwrap_Some() == 5; assert list[5] == 33; } ================================================ FILE: tests/list_sorting.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func main() { val list = [6,7,2,5,12,21,78,32,1]; list.quicksort(); assert list[0] == 1; assert list[1] == 2; assert list[2] == 5; assert list[3] == 6; assert list[4] == 7; assert list[5] == 12; assert list[6] == 21; assert list[7] == 32; assert list[8] == 78; } ================================================ FILE: tests/list_sorting_with_cmp.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func main() { val list = [6,7,2,5,12,21,78,32,1]; list.quicksort_with_comparator(|x,y| => x > y); assert list[0] == 78; assert list[1] == 32; assert list[2] == 21; assert list[3] == 12; assert list[4] == 7; assert list[5] == 6; assert list[6] == 5; assert list[7] == 2; assert list[8] == 1; } ================================================ FILE: tests/list_where_iterator.aria ================================================ # SPDX-License-Identifier: Apache-2.0 import aria.iterator.mixin; func is_even(n) { return n % 2 == 0; } func main() { val l = [1,2,3,4,5,6,7,8,9,10]; val sum = 0; for item in l.iterator().where(is_even) { sum = sum + item; assert is_even(item); } assert sum == 30; } ================================================ FILE: tests/list_write_out_of_bounds.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func main() { try { [][10] = 42; } catch e { assert e isa RuntimeError; assert e.unwrap_IndexOutOfBounds() == 10; } } ================================================ FILE: tests/local_define_type_mismatch.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func main() { val caught = false; val x: Int = 1; try { x = false; println(x == 1); # need to use "x", otherwise it's dropped by the optimizer } catch e { match e { isa RuntimeError and case UnexpectedType => { caught = true; } } } assert caught; } ================================================ FILE: tests/local_typehint_any.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func main() { val x: Any = 1; assert x == 1; x = 2; assert x == 2; x = false; assert x == false; x = "hello"; assert x == "hello"; x = main; } ================================================ FILE: tests/local_write_type_mismatch.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func main() { val caught = false; try { val x: Int = "a"; println(x == 1); # need to use "x", otherwise it's dropped by the optimizer } catch e { match e { isa RuntimeError and case UnexpectedType => { caught = true; } } } assert caught; } ================================================ FILE: tests/lr_shift_custom_op.aria ================================================ # SPDX-License-Identifier: Apache-2.0 struct Shifter { type func new() { return alloc(This){ .offset = 0, }; } operator << (n: Int) { return alloc(Shifter) { .offset = this.offset - n, }; } operator >> (n: Int) { return alloc(Shifter) { .offset = this.offset + n, }; } } func main() { val s = Shifter.new(); s = s << 1; assert s.offset == -1; s = s >> 6; assert s.offset == 5; s = s << 3; assert s.offset == 2; s = (s << 3) >> 4; assert s.offset == 3; s = s << 10; assert s.offset == -7; } ================================================ FILE: tests/lt_gt_comp.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func main() { val x = 3; val y = 5; assert x < y; assert y > x; } ================================================ FILE: tests/lte_gte_comp.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func main() { val a = 5; val b = 8; assert a <= a; assert b >= b; assert a >= a; assert b <= b; assert a <= b; assert b >= a; } ================================================ FILE: tests/map_0_capacity.aria ================================================ # SPDX-License-Identifier: Apache-2.0 import Map from aria.structures.map; val m = Map.new_with_capacity(0); m["apple"] = 5; assert m["apple"] == 5; val m = Map.new_with_capacity(-5); m["pear"] = 4; assert m["pear"] == 4; ================================================ FILE: tests/map_frequency_map.aria ================================================ # SPDX-License-Identifier: Apache-2.0 import Map from aria.structures.map; func main() { val fm1 = Map.frequency_map(["apple", "banana", "apple", "orange", "banana", "apple"]); assert fm1["apple"] == 3; assert fm1["banana"] == 2; assert fm1["orange"] == 1; assert fm1.get("pear").is_None(); val fm2 = Map.frequency_map([1, 2, 2, 3, 3, 3, 4]); assert fm2[1] == 1; assert fm2[2] == 2; assert fm2[3] == 3; assert fm2[4] == 1; assert fm2.get(100).is_None(); } ================================================ FILE: tests/map_hash_negative.aria ================================================ # SPDX-License-Identifier: Apache-2.0 import Map from aria.structures.map; struct Foo { type func new(x) = alloc(This) { .x }; func hash() { return -1; } operator==(rhs: Foo) { return this.x == rhs.x; } } func main() { val m = Map.new(); val f = Foo.new(42); m[f] = "The answer"; assert m[f] == "The answer"; } ================================================ FILE: tests/map_index_init.aria ================================================ # SPDX-License-Identifier: Apache-2.0 import Map from aria.structures.map; func main() { val m = Map.new_with_capacity(5){ [123] = "test", [456] = "string", [false] = true, ["hello"] = "world", }; assert m[123] == "test"; assert m[456] == "string"; assert m[false] == true; assert m["hello"] == "world"; } ================================================ FILE: tests/map_insert.aria ================================================ # SPDX-License-Identifier: Apache-2.0 import Map from aria.structures.map; val map = Map.new(); assert map.set(1,2) == true; assert map.set(2,3) == true; assert map.set(1,4) == false; assert map[1] == 4; assert map[2] == 3; ================================================ FILE: tests/map_iter.aria ================================================ # SPDX-License-Identifier: Apache-2.0 import Map from aria.structures.map; func main() { val m = Map.new() { [1] = 2, [2] = 3, [3] = 4, [4] = 5, [5] = 6, [6] = 7, }; val key_total = 0; for kvp in m { assert kvp.value - kvp.key == 1; key_total = key_total + kvp.key; } assert key_total == 21; } ================================================ FILE: tests/map_iterator_where.aria ================================================ # SPDX-License-Identifier: Apache-2.0 import Map from aria.structures.map; func main() { val m = Map.new(){ ["hello"] = 123, ["A key"] = true, ["Another key"] = true, ["one more key"] = 321, }; val count = 0; for item in m.iterator().where(|kvp| => kvp.key[0] == "A") { assert item.value == true; count = count + 1; } assert count == 2; } ================================================ FILE: tests/map_key_ops.aria ================================================ # SPDX-License-Identifier: Apache-2.0 import Map from aria.structures.map; func main() { val m = Map.new(); m[123] = "test"; m[456] = "string"; m[false] = true; m["hello"] = "world"; assert m[123] == "test"; assert m[456] == "string"; assert m[false] == true; assert m["hello"] == "world"; } ================================================ FILE: tests/map_keys.aria ================================================ # SPDX-License-Identifier: Apache-2.0 import Map from aria.structures.map; func main() { val m = Map.new() { ["hello"] = "world", ["test"] = "value", ["123"] = "one hundred twenty three", [123] = 123, }; val keys = m.keys(); assert keys.len() == 4; assert keys.contains("hello"); assert keys.contains("test"); assert keys.contains("123"); assert keys.contains(123); } ================================================ FILE: tests/map_load_factor.aria ================================================ # SPDX-License-Identifier: Apache-2.0 import Map from aria.structures.map; func main() { val m = Map.new_with_capacity(5); m[0] = 1; m[1] = 2; m[2] = 3; m[3] = 4; m[4] = 5; m[5] = 6; m[6] = 7; m[7] = 8; m[8] = 9; m[9] = 10; m[10] = 11; m[11] = 12; m[12] = 13; m[13] = 14; m[14] = 15; m[15] = 16; m[16] = 17; m[17] = 18; m[18] = 19; m[19] = 20; assert m.len() == 20; for item in m { assert item.value == item.key + 1; } } ================================================ FILE: tests/map_remove.aria ================================================ # SPDX-License-Identifier: Apache-2.0 import Map from aria.structures.map; func main() { val m = Map.new(); m.set(123, "hello"); m.set(456, "world"); assert m.get(123).is_Some(); assert m.get(456).is_Some(); assert m.len() == 2; assert m.remove(123) == true; assert m.remove(500) == false; assert m.len() == 1; assert m.get(123).is_None(); assert m.get(456).is_Some(); m.set(123, "test string"); assert m.len() == 2; assert m.get(123).unwrap_Some() == "test string"; assert m.get(456).unwrap_Some() == "world"; assert m.remove(456) == true; assert m.get(456).is_None(); assert m.remove(456) == false; } ================================================ FILE: tests/map_set_get.aria ================================================ # SPDX-License-Identifier: Apache-2.0 import Map from aria.structures.map; func main() { val m = Map.new(); m.set(123, "hello"); m.set("hello", "world"); m.set(false, true); m.set(true, false); assert m.get(123).unwrap_Some() == "hello"; assert m.get("hello").unwrap_Some() == "world"; assert m.get(445566).is_None(); assert m.get("world").is_None(); } ================================================ FILE: tests/match_equals.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func is_even_digit(x) { match x { == 0 => { return true; }, == 2 => { return true; }, == 4 => { return true; }, == 6 => { return true; }, == 8 => { return true; }, } else { return false; } } func main() { assert is_even_digit(4); assert !is_even_digit(7); } ================================================ FILE: tests/match_extract_enum_payload.aria ================================================ # SPDX-License-Identifier: Apache-2.0 # this should be a real enum enum Optional { case Some(Any), case None, } extension Optional { instance func get_Some() { match this { case Some(x) => { return x; }, } else { assert(false); } } } func main() { val s = Optional::Some(123); val n = s.get_Some(); assert n == 123; } ================================================ FILE: tests/match_isa_case.aria ================================================ # SPDX-License-Identifier: Apache-2.0 enum X { case A, case B(String), case C(Int) } func main() { val b = X::B("hello world"); val str = "goodbye"; match b { isa Int => { assert(false); }, isa X and case A => { assert(false); }, isa X and case B(s) => { str = s; }, } else { assert(false); } assert str == "hello world"; } ================================================ FILE: tests/match_not_eq.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func main() { val check = false; match 5 { != 5 => { assert(false); }, == 4 => { assert false; }, != 4 => { check = true; }, } else { assert false; } assert check; } ================================================ FILE: tests/match_payload_fails_with_no_payload.aria ================================================ # SPDX-License-Identifier: Apache-2.0 enum Something { case HasPayload(Any), case HasNoPayload } func do_the_thing(x: Something) { match x { case HasPayload(x) => { return x; } } else { return 123456; } } func main() { val thing = do_the_thing(Something::HasNoPayload); assert thing == 123456; thing = do_the_thing(Something::HasPayload("hello")); assert thing == "hello"; } ================================================ FILE: tests/match_rel.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func main() { val x = 5; val hit = false; match x { > 10 => { assert false; }, < 0 => { assert false; }, >= 6 => { assert false; }, <= 2 => { assert false; } >= 3 => { hit = true; } } else { assert false; } assert hit; } ================================================ FILE: tests/match_uses_custom_op_equals.aria ================================================ # SPDX-License-Identifier: Apache-2.0 struct EqualsFive { operator ==(rhs) { return rhs == 5; } } func main() { val f = alloc(EqualsFive); val yes = false; match f { == 3 => { assert false; }, isa Int => { assert false; }, == 5 => { yes = true; }, case Foo => { assert false; }, } else { assert false; } assert yes; } ================================================ FILE: tests/match_without_commas.aria ================================================ # SPDX-License-Identifier: Apache-2.0 enum Foo { case A case B case C case D case E } extension Foo { func to_int() { match this { case A => { return 1; } case B => { return 2; } case C => { return 3; } case D => { return 4; } case E => { return 5; } } } } func main() { val a = Foo::A; val b = Foo::B; val c = Foo::C; val d = Foo::D; val e = Foo::E; assert a.to_int() == 1; assert b.to_int() == 2; assert c.to_int() == 3; assert d.to_int() == 4; assert e.to_int() == 5; } ================================================ FILE: tests/matrix.aria ================================================ # SPDX-License-Identifier: Apache-2.0 import Matrix from aria.numerics.matrix; func main() { val m = Matrix.new(3, 3); m.set(0, 0, 1.0f); m.set(1, 1, 2.0f); m[2,2] = 3.0f; m.set(0, 1, 4.0f); m[1,0] = 5.0f; assert m.get(0, 0) == 1.0f; assert m[1,1] == 2.0f; assert m.get(2, 2) == 3.0f; assert m[0,1] == 4.0f; assert m.get(1, 0) == 5.0f; assert m.get(0, 2) == 0.0f; val caught = false; try { m.set(3, 3, 10.0f); } catch e { assert e isa Matrix.DimensionMismatch; caught = true; } assert caught; val caught = false; try { m.get(4, 6); } catch e { assert e isa Matrix.DimensionMismatch; caught = true; } assert caught; } ================================================ FILE: tests/matrix_add.aria ================================================ # SPDX-License-Identifier: Apache-2.0 import Matrix from aria.numerics.matrix; func main() { val m1 = Matrix.new(3,3); m1.set(0, 0, 1.0f); m1.set(1, 0, 0.25f); m1.set(1, 1, 2.0f); m1.set(2, 2, 3.0f); val m2 = Matrix.new(3,3); m2.set(0, 1, 4.0f); m2.set(1, 0, 5); m2.set(2, 2, 6); val m3 = m1 + m2; assert m3.get(0, 0) == 1.0f; assert m3.get(1, 1) == 2.0f; assert m3.get(2, 2) == 9.0f; assert m3.get(0, 1) == 4.0f; assert m3.get(1, 0) == 5.25f; assert m3.get(0, 2) == 0.0f; assert m3.get(2, 0) == 0.0f; val m4 = m1 - m2; assert m4.get(0, 0) == 1.0f; assert m4.get(1, 1) == 2.0f; assert m4.get(2, 2) == -3.0f; assert m4.get(0, 1) == -4.0f; assert m4.get(1, 0) == -4.75f; assert m4.get(0, 2) == 0.0f; assert m4.get(2, 0) == 0.0f; } ================================================ FILE: tests/matrix_det.aria ================================================ # SPDX-License-Identifier: Apache-2.0 import Matrix from aria.numerics.matrix; func main() { val m = Matrix.new(3,3); m[0,0] = 3; m[0,1] = 3; m[0,2] = 3; m[1,0] = 4; m[1,1] = 2; m[1,2] = 5; m[2,0] = 1; m[2,1] = 6; m[2,2] = 2; assert m.determinant() == -21; m = Matrix.new(10,10); assert m.determinant() == 0; m[0,0] = 5; m[1,1] = 5; m[2,2] = 5; m[3,3] = 5; m[4,4] = 5; m[5,5] = 5; m[6,6] = 5; m[7,7] = 5; m[8,8] = 5; m[9,9] = 5; assert m.determinant() == 9765625; } ================================================ FILE: tests/matrix_mul.aria ================================================ # SPDX-License-Identifier: Apache-2.0 import Matrix from aria.numerics.matrix; func main() { val m1 = Matrix.new(2, 3); m1.set(0, 0, 1); m1.set(0, 1, 2); m1.set(0, 2, 3); m1.set(1, 0, 3); m1.set(1, 1, 2); m1.set(1, 2, 1); val m2 = Matrix.new(3, 2); m2.set(0, 0, 1); m2.set(0, 1, 2); m2.set(1, 0, 3); m2.set(1, 1, 2); m2.set(2, 0, 2); m2.set(2, 1, 1); val result = m1 * m2; assert result.rows == 2; assert result.cols == 2; assert result.get(0, 0) == 13; assert result.get(0, 1) == 9; assert result.get(1, 0) == 11; assert result.get(1, 1) == 11; } ================================================ FILE: tests/matrix_transpose.aria ================================================ # SPDX-License-Identifier: Apache-2.0 import Matrix from aria.numerics.matrix; func main() { val m = Matrix.new(3,3); m.set(0, 0, 1.0f); m.set(1, 0, 2.0f); m.set(1, 1, 3.0f); m.set(1, 2, 6.0f); m.set(2, 2, 4.0f); m.set(0, 1, 5.0f); m.set(2, 0, 7.0f); m.set(0, 2, 8.0f); m.set(2, 1, 9.0f); val mt = m.transpose(); assert mt.get(0, 0) == m.get(0, 0); assert mt.get(0, 1) == m.get(1, 0); assert mt.get(0, 2) == m.get(2, 0); assert mt.get(1, 0) == m.get(0, 1); assert mt.get(1, 1) == m.get(1, 1); assert mt.get(1, 2) == m.get(2, 1); assert mt.get(2, 0) == m.get(0, 2); assert mt.get(2, 1) == m.get(1, 2); assert mt.get(2, 2) == m.get(2, 2); } ================================================ FILE: tests/max_min_empty.aria ================================================ # SPDX-License-Identifier: Apache-2.0 import aria.iterator.mixin; assert [].max().is_None(); assert [].min().is_None(); ================================================ FILE: tests/maybe_unwrap.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func calculate(x: Maybe) = Maybe::Some(x? + 1); assert calculate(Maybe::Some(1)) == Maybe::Some(2); assert calculate(Maybe::None) == Maybe::None; assert calculate(Maybe::Some(10))! == 11; ================================================ FILE: tests/method_arg_type_mismatch.aria ================================================ # SPDX-License-Identifier: Apache-2.0 struct Adder { type func new(x) { return alloc(Adder){.x = x,}; } instance func add(x: Int) { this.x + x; } } func main() { val caught = false; val a = Adder.new(4); try { val n = a.add(false); assert false; } catch e { match e { isa RuntimeError and case UnexpectedType => { caught = true; } } } assert caught; } ================================================ FILE: tests/method_as_arg.aria ================================================ # SPDX-License-Identifier: Apache-2.0 struct AddNumber { type func new(n) { return alloc(This) { .n = n, }; } func add(x) { return this.n + x; } } func perform_op(f,n) { return f(n); } func main() { val add5 = AddNumber.new(5); assert perform_op(add5.add,4) == 9; } ================================================ FILE: tests/method_has_vararg.aria ================================================ # SPDX-License-Identifier: Apache-2.0 struct TakesVarArgs { type func new(){ return alloc(This){ .value = 0, }; } func add_at_least_one(n, ...) { this.value += n; for arg in varargs { this.value += arg; } } func add_any_count(...) { for arg in varargs { this.value += arg; } } func add_at_least_two(x,y, ...) { this.value += x+y; for arg in varargs { this.value += arg; } } } func main() { val va = TakesVarArgs.new(); va.add_at_least_one(3); assert va.value == 3; va.add_at_least_one(3,4,5); assert va.value == 15; va.add_at_least_one(5,2); assert va.value == 22; va.add_any_count(); assert va.value == 22; va.add_any_count(1); assert va.value == 23; va.add_any_count(3,1,1,2); assert va.value == 30; va.add_at_least_two(3,4); assert va.value == 37; va.add_at_least_two(3,5,4); assert va.value == 49; va.add_at_least_two(1,5,4,1,9,1); assert va.value == 70; } ================================================ FILE: tests/method_on_type.aria ================================================ # SPDX-License-Identifier: Apache-2.0 struct Foo { type func new(x,y,z) { val f = alloc(This); return f.set(x,y,z); } instance func set(x,y,z) { this.x = x; this.y = y; this.z = (x+y==z); return this; } } func main() { val f = Foo.new(1,2,4); assert f.x == 1; assert f.y == 2; assert f.z == false; f.set(2,3,5); assert f.x == 2; assert f.y == 3; assert f.z == true; } ================================================ FILE: tests/method_order_of_vararg.aria ================================================ # SPDX-License-Identifier: Apache-2.0 struct TakesVarArgs { func compare(l,...) { assert this isa TakesVarArgs; assert l == varargs; } } func main() { val va = alloc(TakesVarArgs); va.compare([3],3); va.compare([3,4],3,4); va.compare([3,4,5,6],3,4,5,6); va.compare([]); } ================================================ FILE: tests/mismatch_payload.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func main() { try { val some = Maybe::Some; } catch e { assert e isa RuntimeError; assert e.is_UnexpectedType(); } try { val none = Maybe::None(3); } catch e { assert e isa RuntimeError; assert e.is_UnexpectedType(); } } ================================================ FILE: tests/mix_int_fp_mod.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func main() { assert 2.5f % 1 == 0.5f; assert 2 % 1.0f == 0.0f; } ================================================ FILE: tests/mix_object_init.aria ================================================ # SPDX-License-Identifier: Apache-2.0 val x = 42; val l = [] { [0] = 1, [1] = 2, .foo = "bar", .bar = "hello", [2] = 3, .x, [3] = 4, }; assert l[0] == 1; assert l[1] == 2; assert l.foo == "bar"; assert l.bar == "hello"; assert l[2] == 3; assert l[3] == 4; assert l.x == 42; ================================================ FILE: tests/mixin_extension.aria ================================================ # SPDX-License-Identifier: Apache-2.0 mixin Foo { func bar() { return 1; } } struct UsesFoo { include Foo } extension Foo { func baz() { return 2; } } mixin Bar { func double() { return this * 2; } } extension Int : Bar { } func test_extension_shorthand() { assert 5.double() == 10; } func main() { val f = alloc(UsesFoo); assert f.bar() == 1; assert f.baz() == 2; test_extension_shorthand(); } ================================================ FILE: tests/mixin_func_This.aria ================================================ # SPDX-License-Identifier: Apache-2.0 struct S1 { type func new(x) { return alloc(This) { .x = x + 1, }; } } struct S2 { type func new(x) { return alloc(This) { .x = x + 2, }; } } mixin DoubleMe { func double() { val This = typeof(this); return This.new(this.x * 2); } } extension S1 { include DoubleMe } extension S2 { include DoubleMe } func main() { val s1 = S1.new(5); val s2 = S2.new(6); assert s1.x == 6; assert s2.x == 8; val ds1 = s1.double(); assert ds1.x == 13; assert ds1 isa S1; val ds2 = s2.double(); assert ds2.x == 18; assert ds2 isa S2; } ================================================ FILE: tests/mixin_has_enum.aria ================================================ # SPDX-License-Identifier: Apache-2.0 mixin Foo { struct Pair { type func new(x,y) = alloc(This) {.x, .y} ; } enum Either { case Left(Foo.Pair), case Right(Any), } } struct S1 { include Foo } func main() { val either_left = S1.Either::Left(S1.Pair.new(2,3)); val either_right = S1.Either::Right("hello"); assert either_left.is_Left(); assert either_right.is_Right(); assert either_left.unwrap_Left().x == 2; assert either_left.unwrap_Left().y == 3; assert either_right.unwrap_Right() == "hello"; } ================================================ FILE: tests/mixin_has_struct.aria ================================================ # SPDX-License-Identifier: Apache-2.0 mixin Foo { struct Bar { type func new(x) = alloc(This) {.x} ; func add(y) = this.x + y; } } struct S1 { include Foo } struct S2 { include Foo } func main() { val s1_bar = S1.Bar.new(2); val s2_bar = S2.Bar.new(3); assert s1_bar isa S2.Bar; assert s2_bar isa S1.Bar; assert s1_bar.add(3) == 5; assert s2_bar.add(3) == 6; } ================================================ FILE: tests/mixin_in_extension.aria ================================================ # SPDX-License-Identifier: Apache-2.0 mixin Double { # requires # this.value() # this.add(y) func double() { return this.add(this.value()); } } struct HasValue { type func new(x) { return alloc(This) { .x = x, }; } } extension HasValue { instance func value() { return this.x; } instance func add(y) { this.x += y; } include Double } func main() { val hv = HasValue.new(4); assert hv.value() == 4; hv.add(1); assert hv.value() == 5; hv.double(); assert hv.value() == 10; hv.double(); assert hv.value() == 20; hv.add(3); assert hv.value() == 23; } ================================================ FILE: tests/mixin_include_mixin.aria ================================================ # SPDX-License-Identifier: Apache-2.0 mixin Double { func double(n) { return n + n; } } mixin Triple { func triple(n) { return this.double(n) + n; } include Double } struct Test { include Triple } func main() { val t = alloc(Test); assert t.double(2) == 4; assert t.triple(4) == 12; } ================================================ FILE: tests/mixin_include_type_func.aria ================================================ # SPDX-License-Identifier: Apache-2.0 mixin HasTypeFunc { # requires # type func new_with_pair(x,y) type func new_with_duplicate(x) { return This.new_with_pair(x,x); } } struct TestStruct { type func new_with_pair(x,y) { return alloc(This){ .x = x, .y = y, }; } include HasTypeFunc } func main() { val t = TestStruct.new_with_duplicate(5); assert t.x == 5; assert t.y == 5; } ================================================ FILE: tests/mixin_multiple_commas.aria ================================================ # SPDX-License-Identifier: Apache-2.0 mixin A { func from_a() { return "A"; } } mixin B { func from_b() { return "B"; } } mixin C { func from_c() { return "C"; } } # Test trailing comma with single mixin struct Single : A, { type func new() { return alloc(This); } } # Test trailing comma with multiple mixins struct Multi : A, B, C, { type func new() { return alloc(This); } } # Test no trailing comma still works struct NoTrailing : A, B { type func new() { return alloc(This); } } # Test extension with trailing comma extension Int : A, B, { } func main() { val s = Single.new(); assert s.from_a() == "A"; val m = Multi.new(); assert m.from_a() == "A"; assert m.from_b() == "B"; assert m.from_c() == "C"; val n = NoTrailing.new(); assert n.from_a() == "A"; assert n.from_b() == "B"; assert 5.from_a() == "A"; assert 5.from_b() == "B"; } ================================================ FILE: tests/mixin_of_builtin_type.aria ================================================ # SPDX-License-Identifier: Apache-2.0 mixin Double { func double() { return this + this; } } extension Int { include Double } extension String { include Double } extension Float { include Double } extension Double { func triple() { return this + this + this; } } func main() { assert 3.double() == 6; assert "abc".double() == "abcabc"; assert 3.14f.double() == 6.28f; assert 3.triple() == 9; assert "abc".triple() == "abcabcabc"; assert 3.14f.triple() == 9.42f; } ================================================ FILE: tests/mixin_of_enum.aria ================================================ # SPDX-License-Identifier: Apache-2.0 enum Direction { case North, case South, case East, case West, } extension Direction { func prettyprint() { match this { case North => { return "North"; }, case South => { return "South"; }, case East => { return "East"; }, case West => { return "West"; }, } } } mixin Navigation { func navigate() { return "Head {0}".format(this); } } extension Direction : Navigation { } func main() { val d = Direction::East; assert d.navigate() == "Head East"; } ================================================ FILE: tests/mixin_order.aria ================================================ # SPDX-License-Identifier: Apache-2.0 mixin A { func answer() { return "Mixin A"; } } mixin B { func answer() { return "Mixin B"; } } struct A_Then_B { include A include B } struct B_Then_A { include B include A } struct C_Shorthand_Then_B : A { include B } func test_shorthand_order() { val c = alloc(C_Shorthand_Then_B); assert c.answer() == "Mixin B"; # should be B (last included) } func main() { val a_then_b = alloc(A_Then_B); val b_then_a = alloc(B_Then_A); assert a_then_b.answer() == "Mixin B"; assert b_then_a.answer() == "Mixin A"; test_shorthand_order(); } ================================================ FILE: tests/mixin_refers_to_self_method.aria ================================================ # SPDX-License-Identifier: Apache-2.0 mixin Double { # requires # this.value() # this.add(y) func double() { return this.add(this.value()); } } struct HasValue { type func new(x) { return alloc(This) { .x = x, }; } instance func value() { return this.x; } instance func add(y) { this.x += y; } include Double } func main() { val hv = HasValue.new(4); assert hv.value() == 4; hv.add(1); assert hv.value() == 5; hv.double(); assert hv.value() == 10; hv.double(); assert hv.value() == 20; hv.add(3); assert hv.value() == 23; } ================================================ FILE: tests/mixin_shared_between_types.aria ================================================ # SPDX-License-Identifier: Apache-2.0 mixin SomeBehavior { # requires # func input() func behavior() { return "input is {0}".format(this.input()); } } struct ProvidesInteger { func input() { return 42; } } struct ProvidesString { func input() { return "hello"; } } extension ProvidesInteger : SomeBehavior { } extension ProvidesString : SomeBehavior { } func main() { val pib = alloc(ProvidesInteger).behavior(); val psb = alloc(ProvidesString).behavior(); assert pib == "input is 42"; assert psb == "input is hello"; } ================================================ FILE: tests/mixin_val_decl.aria ================================================ # SPDX-License-Identifier: Apache-2.0 mixin HasSomeValue { func get_foo() { return this.FOO; } type val FOO = 1; } struct S1 { include HasSomeValue } struct S2 { include HasSomeValue } func main() { assert S1.FOO == 1; assert S2.FOO == 1; assert alloc(S1).get_foo() == 1; assert alloc(S2).get_foo() == 1; S1.FOO = 2; assert S1.FOO == 2; assert S2.FOO == 1; assert alloc(S1).get_foo() == 2; assert alloc(S2).get_foo() == 1; S2.FOO = 3; assert S1.FOO == 2; assert S2.FOO == 3; assert alloc(S1).get_foo() == 2; assert alloc(S2).get_foo() == 3; } ================================================ FILE: tests/mod_by_zero.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func test_mod(x,y) { try { val n = x % y; assert false; # should not reach here } catch e { return e isa RuntimeError && e.is_DivisionByZero(); } } assert test_mod(3, 0); assert test_mod(3, 0.0f); assert test_mod(3.0f, 0); assert test_mod(3.0f, 0.0f); assert test_mod(0, 0); assert test_mod(0, 0.0f); assert test_mod(0.0f, 0); assert test_mod(0.0f, 0.0f); ================================================ FILE: tests/module_level_val.aria ================================================ # SPDX-License-Identifier: Apache-2.0 val foo = 123; func bar() { foo = 321; } func baq(foo) { foo = 4; } func main() { assert foo == 123; bar(); assert foo == 321; baq(5); assert foo == 321; } ================================================ FILE: tests/module_level_var_fdeps.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func foo(n) { return 5+n; } val ten = foo(5); func main() { assert ten == 10; } ================================================ FILE: tests/module_list_attributes.aria ================================================ # SPDX-License-Identifier: Apache-2.0 import attributes.things; func main() { val m_attribs = listattrs(attributes.things); assert m_attribs.contains("foo"); assert m_attribs.contains("Bar"); assert m_attribs.contains("A"); assert m_attribs.contains("Something"); assert m_attribs.len() >= 4; } ================================================ FILE: tests/module_var_isa_mixin.aria ================================================ # SPDX-License-Identifier: Apache-2.0 mixin A { func answer() { return 42; } } struct S { include A } val x: A = alloc(S); func main() { assert x.answer() == 42; } ================================================ FILE: tests/msrng.aria ================================================ # SPDX-License-Identifier: Apache-2.0 import MiddleSquareRng from aria.rng.msws; import aria.iterator.mixin; func is_within_range(n) { return (n >= 1) && (n <= 6); } func main() { val rng = MiddleSquareRng.new(); # TODO: replace this with a proper verification, this is not exactly # guaranteed - just very very likely assert rng.next() != rng.next(); assert rng.next() != rng.next(); assert rng.next() != rng.next(); val n = 0; val l = []; while n < 100 { n = n + 1; l.append(rng.in_range(1,6)); } assert l.iterator().all(is_within_range); } ================================================ FILE: tests/mul_eq_ops.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func main() { val x = 3; x *= 4; assert x == 12; x /= 2; assert x == 6; x %= 4; assert x == 2; x <<= 3; # 2 << 3 = 16 assert x == 16; x >>= 2; # 16 >> 2 = 4 assert x == 4; } ================================================ FILE: tests/multidecl_order.aria ================================================ # SPDX-License-Identifier: Apache-2.0 val x = 1, y = x + 1, z = Box(){.x,.y}; assert x == 1; assert y == 2; assert z.x == 1; assert z.y == 2; val i = 0, a = []{[i] = 1, [i+1] = x}; assert a == [1,1]; ================================================ FILE: tests/multiple_imports_from.aria ================================================ # SPDX-License-Identifier: Apache-2.0 import one, two from multiple.module; func main() { assert one(3,4) == 7; assert two(3,4) == 12; } ================================================ FILE: tests/multiwrite_multiple.aria ================================================ # SPDX-License-Identifier: Apache-2.0 val x = 1, y = 2, z = 3, t = 4, q = 5, p = 6; x,y,z = 10,20,30; t,q,p = 40,50,60; assert x == 10; assert y == 20; assert z == 30; assert t == 40; assert q == 50; assert p == 60; x,y,z,t,q,p = 100,200,300,400,500,600; assert x == 100; assert y == 200; assert z == 300; assert t == 400; assert q == 500; assert p == 600; x,y,z = z,x,y; assert x == 300; assert y == 100; assert z == 200; ================================================ FILE: tests/multiwrite_nesting.aria ================================================ # SPDX-License-Identifier: Apache-2.0 val a = Box(); a.x = [Box()]; val b = [1, 2, 3, 4]; func z() = 1; func p() = 42; func q() = 99; a.x[0].y, b[z()] = p(), q(); assert a.x[0].y == 42; assert b[1] == 99; ================================================ FILE: tests/multiwrite_of_attribute.aria ================================================ # SPDX-License-Identifier: Apache-2.0 val b = Box(); b.x, b.y = 3, 4; assert b.x == 3; assert b.y == 4; b.x, b.y = b.y, b.x; assert b.x == 4; assert b.y == 3; ================================================ FILE: tests/multiwrite_repeat.aria ================================================ # SPDX-License-Identifier: Apache-2.0 val x = 1; x,x = 3,4; assert x == 4; ================================================ FILE: tests/multiwrite_side_effecting.aria ================================================ # SPDX-License-Identifier: Apache-2.0 val i = 0, a = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; func f() = 42; a[i], i = f(), 7; assert a[0] == 42; assert i == 7; i, a[i] = 6, f(); assert a[6] == 42; assert i == 6; ================================================ FILE: tests/multiwrite_swap.aria ================================================ # SPDX-License-Identifier: Apache-2.0 val x = 1, y = 2; x,y = y,x; assert x == 2; assert y == 1; ================================================ FILE: tests/naked_return.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func returns_unit(x: Bool, y: Any) { if x { return y; } else { return; } assert false; # this should never be reached } func returns_fallthrough(x: Bool, y: Any) { if x { return y; } } func main() { val five = returns_unit(true, 5); val unit = returns_unit(false, 5); assert five == 5; assert unit == Unit::unit; val five_again = returns_fallthrough(true, 5); val unit_again = returns_fallthrough(false, 5); assert five_again == 5; assert unit_again == Unit::unit; } ================================================ FILE: tests/neg.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func main() { val x = -3; val y = 3; assert x < 0; assert y > 0; assert y > x; assert x < y; assert (x+y == 0); assert x != 0; assert y != 0; assert y-x == 6; } ================================================ FILE: tests/nested_closure.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func top_level(arg0) { return |arg1| => |arg2| => arg0 + arg1 + arg2; } func main() { val add3 = top_level(3); val add3_and_4 = add3(4); val add3_and_2 = add3(2); assert add3_and_4(7) == 14; assert add3_and_2(7) == 12; assert add3_and_4(3) == 10; assert add3_and_2(1) == 6; } ================================================ FILE: tests/nested_enum_in_func.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func parity(x) { enum Parity { case Even, case Odd, } if (x % 2 == 0) { return Parity::Even; } else { return Parity::Odd; } } func main() { val p3 = parity(3); val p6 = parity(6); assert p3.is_Odd(); assert !p3.is_Even(); assert p6.is_Even(); assert !p6.is_Odd(); val hit = false; match p6 { case Even => { hit = true; } } assert hit; val hit = false; match p3 { case Odd => { hit = true; } } assert hit; } ================================================ FILE: tests/nested_enum_with_entries.aria ================================================ # SPDX-License-Identifier: Apache-2.0 struct A { enum B { case X func foo() { return 42; } } func b() { return A.B::X.foo(); } type func c() { return alloc(This).b(); } } func main() { assert A.c() == 42; assert alloc(A).b() == 42; assert A.B::X.foo() == 42; } ================================================ FILE: tests/nested_extension.aria ================================================ # SPDX-License-Identifier: Apache-2.0 import base_module.nested_module.content; extension base_module.nested_module.content.Foo { type func new(x) { return alloc(This) { .x = x, }; } func increment() { this.x += 1; } func answer_x() { return this.answer() + this.x; } } func main() { val f = base_module.nested_module.content.Foo.new(1); f.increment(); assert f.answer() == 42; assert f.answer_x() == 44; } ================================================ FILE: tests/nested_forloop.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func main() { val l = [1,2,3,4,5]; val total_loops = 0; val a_sum = 0; for a in l { total_loops = total_loops + 1; val b_sum = 0; for b in l { total_loops = total_loops + 1; b_sum = b_sum + b; } assert b_sum == 15; a_sum = a_sum + a; } assert a_sum == 15; assert total_loops == 30; # 5x outer loop + 5 times 5x inner loop } ================================================ FILE: tests/nested_guard.aria ================================================ # SPDX-License-Identifier: Apache-2.0 import guard from aria.utils.guard; struct Guard { type val COUNTER = 0; instance func guard_exit() { Guard.COUNTER = Guard.COUNTER + 1; } } func main() { val n = guard(alloc(Guard)).do(|x| => { val n = guard(alloc(Guard)).do(|y| => { return 1; })?; assert Guard.COUNTER == 1; return n + 1; })?; assert n == 2; assert Guard.COUNTER == 2; } ================================================ FILE: tests/nested_guards_order.aria ================================================ # SPDX-License-Identifier: Apache-2.0 import guard from aria.utils.guard; struct GuardOne { type val COUNTER = 1; func guard_exit() { GuardOne.COUNTER = GuardOne.COUNTER + GuardTwo.COUNTER; } } struct GuardTwo { type val COUNTER = 2; func guard_exit() { GuardTwo.COUNTER = GuardTwo.COUNTER + GuardOne.COUNTER; } } func add(x,y) { return guard(alloc(GuardOne)).do(|_| => { return guard(alloc(GuardTwo)).do(|_| => { return x + y; }); }); } func add_again(x,y) { return guard(alloc(GuardTwo)).do(|_| => { return guard(alloc(GuardOne)).do(|_| => { return x + y; }); }); } func main() { val n = add(3,4); assert n == 7; assert GuardTwo.COUNTER == 3; assert GuardOne.COUNTER == 4; GuardOne.COUNTER = 1; GuardTwo.COUNTER = 2; n = add_again(3,4); assert n == 7; assert GuardOne.COUNTER == 3; assert GuardTwo.COUNTER == 5; } ================================================ FILE: tests/nested_if.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func do_compare(x,a,y,b) { if x == a { if y == b { return 123; } elsif y == a { return 124; } else { return 125; } } elsif x == b { if y == a { return 321; } elsif y == b { return 324; } else { return 325; } } } func main() { assert do_compare(3,3,4,3) == 125; assert do_compare(3,3,4,4) == 123; assert do_compare(5,0,0,5) == 321; assert do_compare(2,1,2,2) == 324; } ================================================ FILE: tests/nested_lambda_f.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func top_level(q) { # this is not a closure as nothing in any of the inner # lexical scopes depends on anything in the outer scopes return |a| => { return |x,y| => x + y; }; } func main() { val c1 = top_level(3); val c2 = c1(4); assert c2(3,4) == 7; } ================================================ FILE: tests/nested_list.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func main() { val list = [[1,2,3],[4,5,6]]; val one = list[0][0]; val three = list[0][2]; val five = list[1][1]; val total = one + three + five; assert total == 9; } ================================================ FILE: tests/nested_obj_write.aria ================================================ # SPDX-License-Identifier: Apache-2.0 struct Pair { type func new(x,y) = alloc(This){.x, .y}; } struct Quartet { type func new(a,y,x,d) = alloc(This) { .a = alloc(Pair) { .x = a, .y, }, .c = alloc(Pair) { .x, .y = d } }; } func main() { val q = Quartet.new(1,2,3,4); assert q.a.x == 1; assert q.a.y == 2; assert q.c.x == 3; assert q.c.y == 4; } ================================================ FILE: tests/nested_struct_new.aria ================================================ # SPDX-License-Identifier: Apache-2.0 struct Top { struct Child { enum E { case A, case B, } type func foo() { return 42; } } } func main() { assert Top.Child.foo() == 42; assert Top.Child.E::A.is_A(); } ================================================ FILE: tests/new_path.aria ================================================ # SPDX-License-Identifier: Apache-2.0 import Path from aria.io.path; func main() { val p = Path.new("/usr/"); val q = p / "lib/libc.so"; p /= "bin/ls"; assert p.prettyprint() == "/usr/bin/ls"; assert q.prettyprint() == "/usr/lib/libc.so"; p.pop(); assert p.prettyprint() == "/usr/bin"; assert p.parent().prettyprint() == "/usr"; p.pop(); assert p.prettyprint() == "/usr"; p.pop(); assert p.prettyprint() == "/"; p.pop(); assert p.prettyprint() == "/"; val cwd = Path.new_with_current_directory(); assert cwd.is_absolute(); assert cwd.exists(); assert cwd.is_directory(); } ================================================ FILE: tests/new_range_api.aria ================================================ # SPDX-License-Identifier: Apache-2.0 import Range from aria.range.range; func increasing_exclusive_range() { val r = Range.from(1).to(10); val items = r.iterator().to_list(); assert items == [1, 2, 3, 4, 5, 6, 7, 8, 9]; assert r.contains(1) == true; assert r.contains(10) == false; assert r.length() == 9; } func increasing_inclusive_range() { val r = Range.from(1).through(10); val items = r.iterator().to_list(); assert items == [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; assert r.contains(1) == true; assert r.contains(10) == true; assert r.contains(11) == false; assert r.length() == 10; } func decreasing_exclusive_range() { val r = Range.from(1).to(10); val items = r.descending().to_list(); assert items == [9, 8, 7, 6, 5, 4, 3, 2, 1]; } func decreasing_inclusive_range() { val r = Range.from(1).through(10); val items = r.descending().to_list(); assert items == [10, 9, 8, 7, 6, 5, 4, 3, 2, 1]; } func increasing_exclusive_range_with_step() { val r = Range.from(1).to(11).step(2); val items = r.iterator().to_list(); assert items == [1, 3, 5, 7, 9]; val r = Range.from(1).to(10).step(2); val items = r.iterator().to_list(); assert items == [1, 3, 5, 7, 9]; } func increasing_inclusive_range_with_step() { val r = Range.from(1).through(11).step(2); val items = r.iterator().to_list(); assert items == [1, 3, 5, 7, 9, 11]; val r = Range.from(1).through(10).step(2); val items = r.iterator().to_list(); assert items == [1, 3, 5, 7, 9]; } func decreasing_exclusive_range_with_step() { val r = Range.from(0).to(10); val items = r.step(-2).to_list(); assert items == [9, 7, 5, 3, 1]; val r = Range.from(1).to(10); val items = r.step(-2).to_list(); assert items == [9, 7, 5, 3, 1]; } func decreasing_inclusive_range_with_step() { val r = Range.from(0).through(10); val items = r.step(-2).to_list(); assert items == [10, 8, 6, 4, 2, 0]; val r = Range.from(1).through(10); val items = r.step(-2).to_list(); assert items == [10, 8, 6, 4, 2]; } func union() { val r1 = Range.from(1).to(5); val r2 = Range.from(3).to(7); val r3 = r1.union(r2); assert r3.from == 1; assert r3.to == 7; val items = r3.iterator().to_list(); assert items == [1, 2, 3, 4, 5, 6]; } func intersection() { val r1 = Range.from(1).to(5); val r2 = Range.from(3).to(7); val r3 = r1.intersection(r2); assert r3.from == 3; assert r3.to == 5; val items = r3.iterator().to_list(); assert items == [3, 4]; } func main() { increasing_exclusive_range(); increasing_inclusive_range(); decreasing_exclusive_range(); decreasing_inclusive_range(); increasing_exclusive_range_with_step(); increasing_inclusive_range_with_step(); decreasing_exclusive_range_with_step(); decreasing_inclusive_range_with_step(); union(); intersection(); } ================================================ FILE: tests/no_such_case.aria ================================================ # SPDX-License-Identifier: Apache-2.0 enum E { case A, case B, } func main() { val caught = false; try { val foo = E::X; } catch e { match e { isa RuntimeError and case NoSuchCase(n) => { caught = n == "X"; } } } assert caught; } ================================================ FILE: tests/no_such_identifier.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func main() { val caught = false; try { val foo = value + 1; } catch e { match e { isa RuntimeError and case NoSuchIdentifier(n) => { caught = n == "value"; } } } assert caught; } ================================================ FILE: tests/not.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func main() { assert !false; assert !(!true); assert !false == true; assert !true == false; } ================================================ FILE: tests/nothing_type.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func main() { val v = Nothing; } ================================================ FILE: tests/now.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func main() { # assume the clock is moving reasonably # and that time travel does not exist val n = now(); assert n > 0; val mpy = 1000 * 60 * 60 * 24 * 365; assert n/mpy >= 55; assert now() >= n; } ================================================ FILE: tests/obj_box_read_write.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func make_pair(x,y) { val pair = Box(); pair.x = x; pair.y = y; return pair; } func symmetrical(p) { return make_pair(p.y, p.x); } func main() { val p = make_pair(4,5); assert p.x == 4; assert p.y == 5; val q = symmetrical(p); assert q.x == 5; assert q.y == 4; } ================================================ FILE: tests/obj_prettyprint.aria ================================================ # SPDX-License-Identifier: Apache-2.0 struct Pair { type func new(x,y) { return alloc(This) { .x = x, .y = y, }; } instance func prettyprint() { return "Pair({0},{1})".format(this.x, this.y); } } func main() { val p = Pair.new(3,4); val s = "I am a pair and my values are {0}".format(p); assert s == "I am a pair and my values are Pair(3,4)"; } ================================================ FILE: tests/obj_write_comprehensive.aria ================================================ # SPDX-License-Identifier: Apache-2.0 val t = []; func rec(i) { t.append(i); return i; } val o = [] { [rec(0)] = rec(1), [rec(1)] = rec(2) }; assert t == [0,1,1,2]; ================================================ FILE: tests/obj_write_in_expr.aria ================================================ # SPDX-License-Identifier: Apache-2.0 val s = "x"{.hello = "world"}.hello; assert s == "world"; ================================================ FILE: tests/obj_write_order.aria ================================================ # SPDX-License-Identifier: Apache-2.0 val o = Box() { .a = 1, .a = 2, .a = 3, }; assert o.a == 3; val p = [] { [0] = 1, [0] = 2, [0] = 3 }; assert p[0] == 3; ================================================ FILE: tests/one_guard.aria ================================================ # SPDX-License-Identifier: Apache-2.0 import guard from aria.utils.guard; struct Guard { type val COUNTER = 0; instance func guard_exit() { Guard.COUNTER = Guard.COUNTER + 1; } } func main() { val n = guard(alloc(Guard)).do(|x| => { return 1; })!; assert n == 1; assert Guard.COUNTER == 1; } ================================================ FILE: tests/one_line_function.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func sum(x, y) = x + y; func assign() = 42; struct TestStruct { type func new(x) { return alloc(This) { .x = x }; } func get_x() = this.x; func add_to_x(n) = this.x + n; func multiply_x(n) = this.x * n; operator + (other) = this.x + other.x; } func main() { assert 5 == sum(3,2); assert 42 == assign(); val obj = TestStruct.new(20); assert 20 == obj.get_x(); assert 25 == obj.add_to_x(5); assert 40 == obj.multiply_x(2); val obj2 = TestStruct.new(10); assert 30 == obj + obj2; } ================================================ FILE: tests/op_add.aria ================================================ # SPDX-License-Identifier: Apache-2.0 struct Integer { type func new(n) { return alloc(This){ .n = n, }; } } extension Integer { operator + (rhs) { if rhs isa Integer { return Integer.new(this.n + rhs.n); } elsif rhs isa Int { return Integer.new(this.n + rhs); } else { throw alloc(Unimplemented); } } reverse operator + (lhs) { if lhs isa Integer { return Integer.new(lhs.n + this.n); } elsif lhs isa Int { return Integer.new(lhs + this.n); } else { throw alloc(Unimplemented); } } operator ==(rhs) { if rhs isa Integer { return rhs.n == this.n; } elsif rhs isa Int { return this.n == rhs; } else { throw alloc(Unimplemented); } } func prettyprint() { return "{0}".format(this.n); } } func main() { val x = Integer.new(4); val y = 7; assert x + y == 11; assert y + x == 11; x += 2; assert x isa Integer; assert x == 6; } ================================================ FILE: tests/op_call.aria ================================================ # SPDX-License-Identifier: Apache-2.0 struct Double { operator ()(n) { return n + n; } } func main() { val d = alloc(Double); assert d(4) == 8; assert d("hi") == "hihi"; } ================================================ FILE: tests/op_div.aria ================================================ # SPDX-License-Identifier: Apache-2.0 struct Integer { type func new(n) { return alloc(This){ .n = n, }; } } extension Integer { operator /(rhs) { if rhs isa Integer { return Integer.new(this.n / rhs.n); } elsif rhs isa Int { return Integer.new(this.n / rhs); } else { throw alloc(Unimplemented); } } reverse operator /(lhs) { if lhs isa Integer { return Integer.new(lhs.n / this.n); } elsif lhs isa Int { return Integer.new(lhs / this.n); } else { throw alloc(Unimplemented); } } operator ==(rhs) { if rhs isa Integer { return rhs.n == this.n; } elsif rhs isa Int { return this.n == rhs; } else { throw alloc(Unimplemented); } } func prettyprint() { return "{0}".format(this.n); } } func main() { val x = Integer.new(26); val y = 4; assert x / y == 6; assert 9 / Integer.new(2) == 4; } ================================================ FILE: tests/op_equals.aria ================================================ # SPDX-License-Identifier: Apache-2.0 struct Integer { type func new(n: Int) { return alloc(This){ .n = n, }; } operator ==(rhs) { if rhs isa Integer { return rhs.n == this.n; } elsif rhs isa Int { return rhs == this.n; } else { throw alloc(Unimplemented); } } } func main() { val n1 = 6; val n2 = Integer.new(6); val n3 = 7; val n4 = Integer.new(7); val flt = 3.14f; assert n1 == n2; assert n2 == n2; assert n3 != n1; assert n3 != n2; assert n3 == n4; assert n4 == n3; assert n2 != flt; assert flt != n2; } ================================================ FILE: tests/op_gt.aria ================================================ # SPDX-License-Identifier: Apache-2.0 struct StoreFive { operator < (x) { if x isa Int { return 5 < x; } else { throw alloc(Unimplemented); } } operator > (x) { if x isa Int { return 5 > x; } else { throw alloc(Unimplemented); } } } func main() { assert alloc(StoreFive) > 3; assert !(alloc(StoreFive) > 7); assert 8 > alloc(StoreFive); assert !(4 > alloc(StoreFive)); } ================================================ FILE: tests/op_gteq.aria ================================================ # SPDX-License-Identifier: Apache-2.0 struct StoreFive { operator <= (x) { if x isa Int { return 5 <= x; } else { throw alloc(Unimplemented); } } operator >= (x) { if x isa Int { return 5 >= x; } else { throw alloc(Unimplemented); } } } func main() { assert alloc(StoreFive) >= 3; assert !(alloc(StoreFive) >= 7); assert alloc(StoreFive) >= 5; assert 8 >= alloc(StoreFive); assert !(4 >= alloc(StoreFive)); assert 5 >= alloc(StoreFive); } ================================================ FILE: tests/op_index_throws.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func expect_catch(f) { try { f(); } catch e { return Result::Ok(e); } return Result::Err("no exception thrown"); } struct Foo { type func new() = alloc(This); struct Error { type func new() = alloc(This); func prettyprint() = "Foo.Error"; } func get(x) { throw Foo.Error.new(); } operator [](x) { return this.get(x); } } func main() { val f = Foo.new(); val err = expect_catch(|| => f[1])!; assert err isa Foo.Error; val err = expect_catch(|| => f.get(1))!; assert err isa Foo.Error; } ================================================ FILE: tests/op_lt.aria ================================================ # SPDX-License-Identifier: Apache-2.0 struct StoreFive { operator < (x) { if x isa Int { return 5 < x; } else { throw alloc(Unimplemented); } } operator > (x) { if x isa Int { return 5 > x; } else { throw alloc(Unimplemented); } } } func main() { assert alloc(StoreFive) < 6; assert !(alloc(StoreFive) < 3); assert 3 < alloc(StoreFive); assert !(7 < alloc(StoreFive)); } ================================================ FILE: tests/op_lteq.aria ================================================ # SPDX-License-Identifier: Apache-2.0 struct StoreFive { operator <= (x) { if x isa Int { return 5 <= x; } else { throw alloc(Unimplemented); } } operator >= (x) { if x isa Int { return 5 >= x; } else { throw alloc(Unimplemented); } } } func main() { assert alloc(StoreFive) <= 6; assert !(alloc(StoreFive) <= 3); assert alloc(StoreFive) <= 5; assert 3 <= alloc(StoreFive); assert !(7 <= alloc(StoreFive)); assert 5 <= alloc(StoreFive); } ================================================ FILE: tests/op_mul.aria ================================================ # SPDX-License-Identifier: Apache-2.0 struct Integer { type func new(n) { return alloc(This){ .n = n, }; } } extension Integer { operator * (rhs) { if rhs isa Integer { return Integer.new(this.n * rhs.n); } elsif rhs isa Int { return Integer.new(this.n * rhs); } else { throw alloc(Unimplemented); } } reverse operator * (lhs) { if lhs isa Integer { return Integer.new(lhs.n * this.n); } elsif lhs isa Int { return Integer.new(lhs * this.n); } else { throw alloc(Unimplemented); } } operator ==(rhs) { if rhs isa Integer { return rhs.n == this.n; } elsif rhs isa Int { return this.n == rhs; } else { throw alloc(Unimplemented); } } func prettyprint() { return "{0}".format(this.n); } } func main() { val x = Integer.new(4); val y = 7; assert x * y == 28; assert y * x == 28; assert x * y == Integer.new(28); assert y * x == Integer.new(28); } ================================================ FILE: tests/op_rem.aria ================================================ # SPDX-License-Identifier: Apache-2.0 struct Integer { type func new(n) { return alloc(This){ .n = n, }; } } extension Integer { operator %(rhs) { if rhs isa Integer { return Integer.new(this.n % rhs.n); } elsif rhs isa Int { return Integer.new(this.n % rhs); } else { throw alloc(Unimplemented); } } reverse operator % (lhs) { if lhs isa Integer { return Integer.new(lhs.n % this.n); } elsif lhs isa Int { return Integer.new(lhs % this.n); } else { throw alloc(Unimplemented); } } operator ==(rhs) { if rhs isa Integer { return rhs.n == this.n; } elsif rhs isa Int { return this.n == rhs; } else { throw alloc(Unimplemented); } } func prettyprint() { return "{0}".format(this.n); } } func main() { val x = Integer.new(26); val y = 4; assert x % y == 2; assert 9 % Integer.new(2) == 1; } ================================================ FILE: tests/op_sub.aria ================================================ # SPDX-License-Identifier: Apache-2.0 struct Integer { type func new(n) { return alloc(This){ .n = n, }; } } extension Integer { operator - (rhs) { if rhs isa Integer { return Integer.new(this.n - rhs.n); } elsif rhs isa Int { return Integer.new(this.n - rhs); } else { throw alloc(Unimplemented); } } reverse operator - (lhs) { if lhs isa Integer { return Integer.new(lhs.n - this.n); } elsif lhs isa Int { return Integer.new(lhs - this.n); } else { throw alloc(Unimplemented); } } operator ==(rhs) { if rhs isa Integer { return rhs.n == this.n; } elsif rhs isa Int { return this.n == rhs; } else { throw alloc(Unimplemented); } } func prettyprint() { return "{0}".format(this.n); } } func main() { val x = Integer.new(6); val y = 4; assert x - y == 2; assert y - x == -2; x -= 1; assert x isa Integer; assert x == 5; x-= Integer.new(1); assert x isa Integer; assert x == 4; } ================================================ FILE: tests/operator_overload.aria ================================================ # SPDX-License-Identifier: Apache-2.0 struct Foo { type func new(n: Int) { return alloc(This) {.n = n}; } operator + (rhs: Int|Foo) { if rhs isa Int { return alloc(Foo) {.n = this.n + rhs}; } else { return alloc(Foo) {.n = this.n + rhs.n}; } } reverse operator + (lhs: Int|Foo) { if lhs isa Int { return alloc(Foo) {.n = this.n + lhs}; } else { return alloc(Foo) {.n = this.n + lhs.n}; } } operator - (rhs: Int|Foo) { if rhs isa Int { return alloc(Foo) {.n = this.n - rhs}; } else { return alloc(Foo) {.n = this.n - rhs.n}; } } reverse operator - (lhs: Int|Foo) { if lhs isa Int { return alloc(Foo) {.n = lhs - this.n}; } else { return alloc(Foo) {.n = lhs.n - this.n}; } } operator * (rhs: Int|Foo) { if rhs isa Int { return alloc(Foo) {.n = this.n * rhs}; } else { return alloc(Foo) {.n = this.n * rhs.n}; } } reverse operator * (lhs: Int|Foo) { if lhs isa Int { return alloc(Foo) {.n = this.n * lhs}; } else { return alloc(Foo) {.n = this.n * lhs.n}; } } operator / (rhs: Int|Foo) { if rhs isa Int { return alloc(Foo) {.n = this.n / rhs}; } else { return alloc(Foo) {.n = this.n / rhs.n}; } } reverse operator / (lhs: Int|Foo) { if lhs isa Int { return alloc(Foo) {.n = lhs / this.n}; } else { return alloc(Foo) {.n = lhs.n / this.n}; } } operator % (rhs: Int|Foo) { if rhs isa Int { return alloc(Foo) {.n = this.n % rhs}; } else { return alloc(Foo) {.n = this.n % rhs.n}; } } reverse operator % (lhs: Int|Foo) { if lhs isa Int { return alloc(Foo) {.n = lhs % this.n}; } else { return alloc(Foo) {.n = lhs.n % this.n}; } } operator ==(rhs: Int|Foo) { if rhs isa Int { return this.n == rhs; } else { return this.n == rhs.n; } } } func main() { val five = Foo.new(5); val ten = Foo.new(10); val six = 6; val three = Foo.new(3); assert five + ten == Foo.new(15); assert five + six == Foo.new(11); assert ten + five == Foo.new(15); assert six + five == Foo.new(11); assert five - ten == Foo.new(-5); assert five - six == Foo.new(-1); assert ten - five == Foo.new(5); assert six - five == Foo.new(1); assert five * ten == Foo.new(50); assert five * six == Foo.new(30); assert ten * five == Foo.new(50); assert six * five == Foo.new(30); assert (five + ten) / three == Foo.new(5); assert five / six == Foo.new(0); assert ten / five == Foo.new(2); assert six / five == Foo.new(1); assert five % three == Foo.new(2); assert five % six == Foo.new(5); assert ten % five == Foo.new(0); assert six % five == Foo.new(1); } ================================================ FILE: tests/opt_args_this_usage.aria ================================================ # SPDX-License-Identifier: Apache-2.0 struct S { func f(a=1,...) { return a + varargs.len(); } } func main() { val s = alloc(S); assert s.f() == 1; assert s.f(2) == 2; assert s.f(2,3,4) == 2+2; } ================================================ FILE: tests/or.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func boolean() { assert (true || true) == true; assert (true || false) == true; assert (false || true) == true; assert (false || false) == false; } func integer() { val a = 0b00101110101011110001; val b = 0b00010100001100011010; assert (a | b) == 0b00111110101111111011; } func main() { integer(); boolean(); } ================================================ FILE: tests/or_shortcircuit.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func main() { val x = [1,0]; assert true || (x[0] / x[1] == 4); } ================================================ FILE: tests/ordering_mixin.aria ================================================ # SPDX-License-Identifier: Apache-2.0 import CompareResult, TotalOrdering from aria.ordering.compare; struct Ordered { type func new(x: Int) { return alloc(This){ .x = x, }; } type func int_int_compare(lhs: Int, rhs: Int) { if lhs == rhs { return CompareResult::eq; } elsif lhs > rhs { return CompareResult::gt; } else { return CompareResult::lt; } } func comp(rhs) { if rhs isa Ordered { return Ordered.int_int_compare(this.x, rhs.x); } elsif rhs isa Int { return Ordered.int_int_compare(this.x, rhs); } else { throw alloc(Unimplemented); } } include TotalOrdering } func main() { val o3 = Ordered.new(3); val o4 = Ordered.new(4); assert (o3 == o3); assert (o3 != o4); assert (o4 == 4); assert (o4 != 5); assert (o3 < o4); assert (o4 > o3); assert (o3 < 5); assert (o4 > 2); assert (o3 <= 5); assert (o4 <= 4); assert (o3 <= o4); assert (o4 <= o4); assert (o3 >= 1); assert (o4 >= o3); } ================================================ FILE: tests/paren_expression.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func main() { val a = (3 + ((((4 + 1))))); assert (a == 8); } ================================================ FILE: tests/parse_enum_cases.aria ================================================ # SPDX-License-Identifier: Apache-2.0 struct Blah {} enum Foo { case A, case B(Int), case C, case D(Blah) } func main() { val f1 = Foo::A; val f2 = Foo::B(3); val f3 = Foo::C; val f4 = Foo::D(alloc(Blah)); } ================================================ FILE: tests/parse_fp.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func main() { assert(3.14f == Float.parse("3.14")!); assert(5.0f == Float.parse("5")!); assert(-6.28f == Float.parse("-6.28")!); assert Float.parse("").is_Err(); assert Float.parse("127.0.0.1").is_Err(); assert Float.parse("-abc.def").is_Err(); assert Float.parse("15a46").is_Err(); } ================================================ FILE: tests/parse_int.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func main() { assert(12345 == Int.parse("12345")!); assert(67890 == Int.parse("67890")!); assert(-12 == Int.parse("-12")!); assert Int.parse("-0xabcdef")! == -0xABCDEF; assert Int.parse("0b000110011")! == 51; assert(12345 == Int.parse("+12345")!); assert(0 == Int.parse("+0")!); assert(0 == Int.parse("-0")!); assert Int.parse("0xFF")! == 255; assert Int.parse("0B101")! == 5; assert Int.parse("0O377")! == 255; assert Int.parse("").is_Err(); assert Int.parse("-abcdef").is_Err(); assert Int.parse("15a46").is_Err(); assert Int.parse("0xG").is_Err(); assert Int.parse("0b2").is_Err(); assert Int.parse("0o8").is_Err(); assert Int.parse_radix("abcDEf", 16)! == 0xABCDEF; assert Int.parse("-0xabcDEf")! == -0xABCDEF; assert Int.parse_radix("011110111", 2)! == 0b011110111; assert Int.parse_radix("12345", 6)! == 1865; assert Int.parse_radix("1A", 31)! == 41; assert Int.parse_radix("1A", 2).is_Err(); assert Int.parse_radix("aBC", 10).is_Err(); assert Int.parse_radix("$#@!", 16).is_Err(); assert Int.parse_radix("123", 55).is_Err(); assert Int.parse_radix("123", 1).is_Err(); assert Int.parse("--10").is_Err(); assert Int.parse("++10").is_Err(); assert Int.parse("+-10").is_Err(); assert Int.parse("+").is_Err(); assert Int.parse("-").is_Err(); assert Int.parse("1234abc").is_Err(); } ================================================ FILE: tests/pass_lambda.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func foo(f,n) { return f(n) + f(n-1); } func main() { assert foo(|x| => x%5, 6) == 1; assert foo(|x| => x+2, 6) == 15; } ================================================ FILE: tests/path_canonical.aria ================================================ # SPDX-License-Identifier: Apache-2.0 import Path from aria.io.path; import Platform from aria.system.platform; func main() { val local_platform = Platform.local(); val p = Path.new( local_platform.is_Linux() ? "/usr/bin/../bin/../lib/../../usr/bin/ls" : local_platform.is_macOS() ? "/usr/bin/../bin/../lib/../../bin/ls" : "" ); val q = p.new_canonical().unwrap_Ok(); # on Linux, it's /usr/bin/ls; on mac it's /bin/ls # checking for a suffix and whether the file exists should # be sufficient assert q.prettyprint().has_suffix("/bin/ls"); assert q.exists(); val p = Path.new("/no/such/path/would/ever/exist/right/c:\makeit/really/confusing/too.txt"); assert p.new_canonical().is_Err(); } ================================================ FILE: tests/path_checks.aria ================================================ # SPDX-License-Identifier: Apache-2.0 import Path from aria.io.path; func main() { # assumes a standard Linux host val binls = Path.new("/bin/ls"); assert binls.is_file(); assert binls.is_absolute(); assert binls.exists(); assert binls.size()! > 0; assert binls.size().is_Ok(); assert binls.created().is_Ok(); assert binls.accessed().is_Ok(); assert binls.modified().is_Ok(); assert binls.get_filename().is_Some(); assert binls.get_extension().is_None(); val usrbin = Path.new("/usr/bin"); assert usrbin.is_directory(); assert usrbin.is_absolute(); assert usrbin.size().is_Ok(); assert usrbin.created().is_Ok(); assert usrbin.accessed().is_Ok(); assert usrbin.modified().is_Ok(); assert usrbin.get_filename().is_Some(); assert usrbin.get_extension().is_None(); val nodir = Path.new("thisfiledoesnotexist/.."); assert nodir.exists() == false; assert nodir.is_absolute() == false; assert nodir.size().is_Err(); assert nodir.created().is_Err(); assert nodir.accessed().is_Err(); assert nodir.modified().is_Err(); assert nodir.get_filename().is_None(); assert nodir.get_extension().is_None(); val dnsfile = Path.new("/etc/resolv.conf"); assert dnsfile.get_extension().is_Some(); } ================================================ FILE: tests/path_common_ancestor.aria ================================================ # SPDX-License-Identifier: Apache-2.0 import Path from aria.io.path; func main() { val p1 = Path.new("/a/b/c/d"); val p2 = Path.new("/a/b/e/f"); val ca = p1.common_ancestor(p2)!; assert ca == Path.new("/a/b"); val p3 = Path.new("/x/y/z/t"); val ca2 = p1.common_ancestor(p3)!; assert ca2 == Path.new("/"); } ================================================ FILE: tests/path_glob.aria ================================================ # SPDX-License-Identifier: Apache-2.0 import Path from aria.io.path; import Set from aria.structures.set; func main() { val glob_iter = Path.glob("**/*.aria")!; val expected_paths = Set.new_with_items( "tests/path_glob.aria", "lib/aria/io/path.aria", ); for path in glob_iter { expected_paths.remove(path.prettyprint()); if expected_paths.len() == 0 { break; } } assert expected_paths.len() == 0; val glob_iter = Path.glob("/tmp/**/*.pepepapa")!; assert glob_iter.count() == 0; val glob_iter = Path.glob("a**/b/*.yml"); assert glob_iter.is_Err(); } ================================================ FILE: tests/path_hash.aria ================================================ # SPDX-License-Identifier: Apache-2.0 import Path from aria.io.path; func main() { val p1 = Path.new("/some/test/path"); val p2 = Path.new("/some/test/path"); assert p1.hash() == p2.hash(); assert p1.hash() == p1.hash(); val p3 = p1 / "subdir" / "file.txt"; val p4 = Path.new("/some/test/path/subdir/file.txt"); assert p3.hash() == p4.hash(); assert p3.hash() != p1.hash(); } ================================================ FILE: tests/path_io.aria ================================================ # SPDX-License-Identifier: Apache-2.0 import Path from aria.io.path; import File from aria.io.file; func main() { val path = Path.new_with_environment_variable("ARIA_TEST_DIR").unwrap_Some(); path = path / "path_io.txt"; val msg1 = "First line of text.\nSecond line of text.\nThird line of text."; path.write(msg1); val msg2 = path.read(); assert msg1 == msg2; } ================================================ FILE: tests/path_io.txt ================================================ First line of text. Second line of text. Third line of text. ================================================ FILE: tests/path_manipulation.aria ================================================ # SPDX-License-Identifier: Apache-2.0 import Path from aria.io.path; import File from aria.io.file; func main() { val msg = "this is a test file"; val path = Path.new_with_environment_variable("ARIA_TEST_DIR").unwrap_Some(); val src_file = path / "path_manipulation.txt"; src_file.write(msg); val dst_file = path / "path_manipulation"; dst_file.mkdir(); dst_file /= "path_manipulation.txt"; src_file.copy_to(dst_file); assert dst_file.exists(); assert dst_file.is_file(); assert dst_file.read() == msg; dst_file.erase(); assert !dst_file.exists(); dst_file = dst_file.parent(); assert dst_file.exists(); assert dst_file.is_directory(); dst_file.rmdir(); assert !dst_file.exists(); } ================================================ FILE: tests/path_manipulation.txt ================================================ this is a test file ================================================ FILE: tests/phi.aria ================================================ # SPDX-License-Identifier: Apache-2.0 assert Float.phi >= 1.6; assert Float.phi <= 1.7; assert Float.φ == Float.phi; ================================================ FILE: tests/platform.aria ================================================ # SPDX-License-Identifier: Apache-2.0 import Platform from aria.system.platform; func main() { val platform = Platform.local(); assert platform.is_Linux() || platform.is_macOS(); match platform { case Linux(platform) => { assert platform.name() == "Linux"; assert platform.prettyprint().has_prefix("Linux"); } case macOS(platform) => { assert platform.name() == "macOS"; assert platform.prettyprint().has_prefix("macOS"); } } } ================================================ FILE: tests/plus_minus_eq.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func five() { return 5; } func main() { val x = 5; x += 1; assert x == 6; x -= 3; assert x == 3; x += 0; assert x == 3; x += five(); assert x == 8; x -= 2 * 2 + 1; assert x == 3; } ================================================ FILE: tests/postfix_obj_write.aria ================================================ # SPDX-License-Identifier: Apache-2.0 struct Foo { type func with_one_number(x) { return Foo.with_two_numbers(x,x); } type func with_two_numbers(x,y) { return alloc(This) { .x = x, .y = y, }; } } func main() { val pair = Foo.with_two_numbers(4,5); assert pair.x == 4; assert pair.y == 5; val pair = Foo.with_one_number(6); assert pair.x == 6; assert pair.y == 6; } ================================================ FILE: tests/prettyprint_two_arg.aria ================================================ # SPDX-License-Identifier: Apache-2.0 struct PrettyprintUnary { func prettyprint() { return ""; } } struct PrettyprintBinary { func prettyprint(x) { if x == "abc" { return "123"; } elsif x == "123" { return "abc"; } elsif x == "" { return ""; } else { assert(false); } } } func main() { val s = "unary = {0}, unary with style = {0:unused}, binary = {1}, binary with style = {1:abc}, binary with other style = {1:123}"; val t = s.format(alloc(PrettyprintUnary), alloc(PrettyprintBinary)); assert t == "unary = , unary with style = , binary = , binary with style = 123, binary with other style = abc"; } ================================================ FILE: tests/queue.aria ================================================ # SPDX-License-Identifier: Apache-2.0 import PriorityQueue from aria.structures.queue; func main() { val pq = PriorityQueue.new(); assert pq.len() == 0; pq.push(5); pq.push(3); assert pq.len() == 2; assert pq.pop() == 3; pq.push(4); assert pq.len() == 2; assert pq.pop() == 4; assert pq.pop() == 5; assert pq.len() == 0; assert pq.peek().is_None(); pq.push(7); pq.push(2); pq.push(6); assert pq.len() == 3; assert pq.peek().is_Some(); assert pq.peek().unwrap_Some() == 2; assert pq.pop() == 2; assert pq.len() == 2; assert pq.peek().is_Some(); assert pq.peek().unwrap_Some() == 6; assert pq.pop() == 6; assert pq.len() == 1; assert pq.peek().is_Some(); assert pq.peek().unwrap_Some() == 7; assert pq.pop() == 7; assert pq.len() == 0; assert pq.peek().is_None(); } ================================================ FILE: tests/queue_with_cmp.aria ================================================ # SPDX-License-Identifier: Apache-2.0 import PriorityQueue from aria.structures.queue; func main() { val pq = PriorityQueue.new_with_comparator(|x,y| => x > y); assert pq.len() == 0; pq.push(5); pq.push(3); assert pq.len() == 2; assert pq.pop() == 5; pq.push(4); assert pq.len() == 2; assert pq.pop() == 4; assert pq.pop() == 3; assert pq.len() == 0; assert pq.peek().is_None(); pq.push(7); pq.push(2); pq.push(6); assert pq.len() == 3; assert pq.peek().is_Some(); assert pq.peek().unwrap_Some() == 7; assert pq.pop() == 7; assert pq.len() == 2; assert pq.peek().is_Some(); assert pq.peek().unwrap_Some() == 6; assert pq.pop() == 6; assert pq.len() == 1; assert pq.peek().is_Some(); assert pq.peek().unwrap_Some() == 2; assert pq.pop() == 2; assert pq.len() == 0; assert pq.peek().is_None(); } ================================================ FILE: tests/range_hash.aria ================================================ # SPDX-License-Identifier: Apache-2.0 import Range from aria.range.range; func main() { val r1 = Range.from(5).to(10); val r2 = Range.from(6).to(10); val r3 = Range.from(5).to(11); assert r1.hash() != r2.hash(); assert r1.hash() != r3.hash(); assert r2.hash() != r3.hash(); assert r1.hash() == r1.hash(); assert r2.hash() == r2.hash(); assert r3.hash() == r3.hash(); val r4 = Range.from(6).to(10); assert r4.hash() == r2.hash(); assert r2 == r4; } ================================================ FILE: tests/range_to_list.aria ================================================ # SPDX-License-Identifier: Apache-2.0 import aria.range.int_extension; func main() { val r = 5.through(12); val l = r.iterator().to_list(); assert l == [5,6,7,8,9,10,11,12]; val r = 5.to(12); val l = r.iterator().to_list(); assert l == [5,6,7,8,9,10,11]; } ================================================ FILE: tests/read_index_multiple.aria ================================================ # SPDX-License-Identifier: Apache-2.0 struct Foo { type func new(x) = alloc(This) { .x }; operator [](a,b) { return this.x * a + b; } } func main() { val f = Foo.new(5); assert f[3,4] == 19; assert f[2,0] == 10; assert f[3,3] == 18; } ================================================ FILE: tests/read_list_index.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func main() { val list = [1,2,3,4,5]; val l0 = list[0]; assert l0 == 1; val l1 = list[1]; assert l1 == 2; val l2 = list[2]; assert l2 == 3; val l3 = list[3]; assert l3 == 4; val l4 = list[4]; assert l4 == 5; } ================================================ FILE: tests/read_write_val_of_function.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func foo(x) { foo.NUM_CALLS += 1; return x + 1; } foo.NUM_CALLS = 0; func main() { assert foo(3) == 4; assert foo.NUM_CALLS == 1; assert foo(4) == 5; assert foo.NUM_CALLS == 2; assert foo(foo(1)) == 3; assert foo.NUM_CALLS == 4; } ================================================ FILE: tests/readattr.aria ================================================ # SPDX-License-Identifier: Apache-2.0 struct Foo { type func new(x,y) { return alloc(This) { .x = x, .y = y, .z = x + y, }; } } func main() { val f = Foo.new(3,4); assert readattr(f, "x") == 3; assert readattr(f, "y") == 4; assert readattr(f, "z") == 7; } ================================================ FILE: tests/redundant_local_loads.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func do_fancy_math(x,y) { return x + x * (x + x + y + 1); } func main() { assert do_fancy_math(4,5) == 60; } ================================================ FILE: tests/redundant_named_loads.aria ================================================ # SPDX-License-Identifier: Apache-2.0 val x = 4; val y = 5; func do_fancy_math() { return x + x * (x + x + y + 1); } func main() { assert do_fancy_math() == 60; } ================================================ FILE: tests/regex_api.aria ================================================ # SPDX-License-Identifier: Apache-2.0 import Regex from aria.string.regex; func main() { val rgx = Regex.new("\d\d"); val matches = rgx.matches("1234567"); assert matches.len() == 3; assert matches[0].value == "12"; assert matches[1].value == "34"; assert matches[2].value == "56"; val replaced = rgx.replace("abc12def5gh78ijk", "?"); assert replaced == "abc?def5gh?ijk"; } ================================================ FILE: tests/result.aria ================================================ # SPDX-License-Identifier: Apache-2.0 import ok, err from aria.core.result; func divide_even(x: Int) { if x % 2 != 0 { return err("not even"); } return ok(x / 2); } func main() { val r1 = divide_even(4); val r2 = divide_even(5); assert r1.is_Ok(); assert r2.is_Err(); assert r1.unwrap_Ok() == 2; assert r2.unwrap_Err() == "not even"; assert Maybe.new_with_result(r1) == Maybe::Some(2); assert Maybe.new_with_result(r2) == Maybe::None; assert Result.new_with_maybe(Maybe::Some(3)) == Result::Ok(3); assert Result.new_with_maybe(Maybe::None) == Result::Err(Unit.new()); } ================================================ FILE: tests/result_helpers.aria ================================================ # SPDX-License-Identifier: Apache-2.0 import ok, err from aria.core.result; val r1 = ok(42); val r2 = err("blah"); func main() { assert r1.apply(|x| => x + 1) == ok(43); assert r2.apply(|x| => x + 1) == err("blah"); assert (r1 ?? 100) == 42; assert (r2 ?? 100) == 100; } ================================================ FILE: tests/result_to_exception.aria ================================================ # SPDX-License-Identifier: Apache-2.0 import ok, err from aria.core.result; func throws() { throw 123; } func id(x) { return x; } func main() { val r1 = Result.new_with_try(throws); val r2 = Result.new_with_try(|| => id(456)); assert r1.is_Err(); assert r2.is_Ok(); assert r1.unwrap_Err() == 123; assert r2.unwrap_Ok() == 456; assert r2.or_throw() == 456; try { r1.or_throw(); assert false; } catch e { assert e == 123; } } ================================================ FILE: tests/result_unwrap.aria ================================================ # SPDX-License-Identifier: Apache-2.0 import ok,err from aria.core.result; func calc_r(x: Result) = ok(x? + 1); assert calc_r(ok(1)) == ok(2); assert calc_r(err("e")) == err("e"); assert calc_r(ok(1))! == 2; ================================================ FILE: tests/retry_test.aria ================================================ # SPDX-License-Identifier: Apache-2.0 import * from aria.network.retry; val global = 3; func return_global() { if global < 0 { throw global; } global -= 1; return global; } func main() { val ok = retry(return_global, |x| => x == 1, 3, 10); assert ok.is_Pass(); assert ok.unwrap_Pass() == 1; assert ok! == 1; global = 5; val ok = retry(return_global, |x| => x == 1, 3, 10); assert ok.is_Fail(); assert ok.unwrap_Fail().is_Some(); assert ok.unwrap_Fail().unwrap_Some() == 2; assert global == 2; global = 0; val ok = retry(return_global, |x| => x == 1, 3, 10); assert ok.is_Exception(); assert ok.unwrap_Exception() == -1; global = 5; val ok = retry(return_global, |x| => { throw 42; }, 3, 10); assert ok.is_Exception(); assert ok.unwrap_Exception() == 42; val ok = retry(return_global, |x| => x == 1, 0, 10); assert ok.is_Fail(); assert ok.unwrap_Fail().is_None(); } ================================================ FILE: tests/return_paren_expr.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func returnisthree(x) { return (x == 3); } func compare(x,y) { # return was being treated as an identifier here, so this parsed as # (return(x==3)) && (y == 0); # as if func return(x) {...} was a callable return (x == 3) && (y == 0); } func main() { assert compare(3,0); assert returnisthree(3); } ================================================ FILE: tests/return_stops_eval.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func main() { return 0; assert 3 == 4; } ================================================ FILE: tests/rng_oneof.aria ================================================ # SPDX-License-Identifier: Apache-2.0 import XorshiftRng from aria.rng.xorshift; import MiddleSquareRng from aria.rng.msws; import Range from aria.range.range; func test_rng(rng) { val items = ["pick", "one", "word"]; val have_pick = false; val have_one = false; val have_word = false; for _ in Range.from(0).to(100) { val item = rng.one_of(items); assert items.contains(item); if item == "pick" { have_pick = true; } elsif item == "one" { have_one = true; } else { have_word = true; } } # This could theoretically fail, but hopefully with 100 values being # generated this possibility remains very very theoretical... assert have_pick && have_one && have_word; } func main() { test_rng(MiddleSquareRng.new()); test_rng(XorshiftRng.new()); } ================================================ FILE: tests/rw_int_attrib.aria ================================================ # SPDX-License-Identifier: Apache-2.0 extension Int { func foo(x) { return this + x; } func bar(y) { return this - y; } } func main() { val x = 3; val y = 4; assert x.foo(y) == 7; assert x.bar(1) == 2; x.foo = 5; assert x.foo == 5; assert x.bar(2) == 1; y.bar = 1; assert y.bar == 1; y.bar = x; assert y.bar == 3; } ================================================ FILE: tests/rw_str_attrib.aria ================================================ # SPDX-License-Identifier: Apache-2.0 extension String { func size() { return this.len(); } func double() { return this * 2; } } func b_double() { return "test"; } func main() { val a = "hello"; val b = "world"; assert a.size() == 5; assert b.size() == 5; a.size = a.size() + 1; assert a.size == 6; assert b.size() == 5; assert a.double() == "hellohello"; b.double = b_double(); assert b.double == "test"; assert a.double() == "hellohello"; assert b.size() == b.len(); } ================================================ FILE: tests/set.aria ================================================ # SPDX-License-Identifier: Apache-2.0 import Set from aria.structures.set; func main() { val s = Set.new(); assert s.len() == 0; s.set(123); assert s.len() == 1; assert s.contains(123); assert !s.contains("123"); s.set("hello"); assert s.len() == 2; assert s.contains("hello"); assert s.contains(123); s.remove(321); assert s.len() == 2; assert s.contains("hello"); assert s.contains(123); s.remove(123); assert s.len() == 1; assert s.contains("hello"); assert !s.contains(123); s = Set.new_with_items(1, 2, 3, 4, 5); assert s.len() == 5; assert s.contains(3); val count = 0; for x in s { count = count + x; } assert count == 15; } ================================================ FILE: tests/set_ops.aria ================================================ # SPDX-License-Identifier: Apache-2.0 import Set from aria.structures.set; func main() { val s1 = Set.new_with_items(1,2,3,4,5); val s2 = Set.new_with_items(2,4,6,8,10); val s3 = s1.union(s2); assert s3.len() == 8; assert s3.contains(1); assert s3.contains(2); assert s3.contains(3); assert s3.contains(4); assert s3.contains(5); assert s3.contains(6); assert s3.contains(8); assert s3.contains(10); val s4 = s1.intersection(s2); assert s4.len() == 2; assert s4.contains(2); assert s4.contains(4); val s5 = s1.difference(s2); assert s5.len() == 3; assert s5.contains(1); assert s5.contains(3); assert s5.contains(5); } ================================================ FILE: tests/setenv.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func main() { setenv("ARIA_SETENV_TEST_CASE", "it works"); assert getenv("ARIA_SETENV_TEST_CASE")! == "it works"; setenv("ARIA_SETENV_TEST_CASE", "it does not work"); } ================================================ FILE: tests/shape_failed_read_works.aria ================================================ # SPDX-License-Identifier: Apache-2.0 import aria.range.int_extension; struct Foo { type func new() = alloc(This) {.value = 1, .other = 2, }; } struct Bar { type func new() = alloc(This) {.other = 3, .value = 1, }; } struct Baz { type func new() = alloc(This) {.x = 3, .y = 5, .value = 1, }; } # this test is rather boring without taking shapes into account # it checks that this "obj.value" read eventually fails to specialize # but that it still works correctly from the user's point of view func get_value(obj) { return obj.value; } func foo(blah) { assert blah == 1; } # just enough to saturate the cache and then some for i in 0.to(100) { foo(get_value(Foo.new())); foo(get_value(Bar.new())); foo(get_value(Baz.new())); } ================================================ FILE: tests/shift_eq_ops.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func main() { val x = 8; x <<= 2; assert x == 32; val y = 32; y >>= 2; assert y == 8; val z = 4; z <<= 1; # 4 << 1 = 8 z <<= 2; # 8 << 2 = 32 assert z == 32; z >>= 3; # 32 >> 3 = 4 assert z == 4; val a = 1; a <<= 3; # 1 << 3 = 8 a += 4; # 8 + 4 = 12 a >>= 2; # 12 >> 2 = 3 assert a == 3; val b = 0b1010; # 10 in decimal b <<= 2; # 0b101000 = 40 assert b == 40; b >>= 3; # 0b101 = 5 assert b == 5; # Shift by zero (should be no-op) val c = 15; c <<= 0; assert c == 15; c >>= 0; assert c == 15; } ================================================ FILE: tests/simple_closure.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func make_adder(n) { return |x| => x + n; } func main() { val add1 = make_adder(1); val add2 = make_adder(2); assert add1(3) == 4; assert add2(4) == 6; assert add1(add1(3)) == add2(3); } ================================================ FILE: tests/simple_default_args.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func add(x: Int, y: Int = 1) { return x + y; } func main() { assert add(3) == 4; assert add(3,4) == 7; } ================================================ FILE: tests/simple_json_parse.aria ================================================ # SPDX-License-Identifier: Apache-2.0 import JsonValue from aria.json.parser; func main() { val json_object = JsonValue.parse('{"a":1,"b":2}')!; assert json_object.is_Object(); val map = json_object.unwrap_Object(); assert map["a"].is_Number(); assert map["a"].unwrap_Number() == 1.0f; assert map["b"].is_Number(); assert map["b"].unwrap_Number() == 2.0f; } ================================================ FILE: tests/simple_json_parse_err.aria ================================================ # SPDX-License-Identifier: Apache-2.0 import JsonValue from aria.json.parser; func main() { assert JsonValue.parse('nul').is_Err(); assert JsonValue.parse('{"a":1, b:"2"}').is_Err(); assert JsonValue.parse('[1,2,3,]').is_Err(); } ================================================ FILE: tests/simple_try_unwrap.aria ================================================ # SPDX-License-Identifier: Apache-2.0 import ok, err from aria.core.result; func generates_a_result(x) { if x % 2 == 0 { return ok(x/2); } else { return err("not divisible by two"); } } func try_double(x) { val x = generates_a_result(x)?; return ok(x * 4); } func main() { val a = try_double(10); val b = try_double(11); assert a.is_Ok(); assert a? == 20; assert b.is_Err(); assert b.unwrap_Err() == "not divisible by two"; } ================================================ FILE: tests/sip_hash_test.aria ================================================ # SPDX-License-Identifier: Apache-2.0 import SipHasher from aria.structures.hash.algo.sip; struct Foo { type func new(x,y,z) = alloc(This) { .x, .y, .z }; func hash() { val hasher = SipHasher.new(0xdeadbeef, 0xabad1dea); hasher.write(this.x).write(this.y).write(this.z); return hasher.finish(); } } func main() { val foo1 = Foo.new(1,2,3); val foo2 = Foo.new(4,5,6); assert foo1.hash() != foo2.hash(); assert foo1.hash() == foo1.hash(); assert foo2.hash() == foo2.hash(); foo1.x = foo2.x; foo1.y = foo2.y; foo1.z = foo2.z; assert foo1.hash() == foo2.hash(); } ================================================ FILE: tests/sleep.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func main() { val before = now(); sleep_ms(50); val after = now(); assert after - before >= 30; # allow some slack, but check that it didn't just return instantly val caught = false; try { sleep_ms(-100); } catch e { match e { isa RuntimeError and case OperationFailed(msg) => { caught = true; } } } assert caught; } ================================================ FILE: tests/stack.aria ================================================ # SPDX-License-Identifier: Apache-2.0 import Stack from aria.structures.stack; func main() { val s = Stack.new(); assert s.len() == 0; assert s.is_empty(); s.push(123); s.push(false); s.push("hello"); assert s.len() == 3; assert !s.is_empty(); assert s.peek().unwrap_Some() == "hello"; assert s.len() == 3; assert !s.is_empty(); assert s.peek_at(1).unwrap_Some() == false; assert s.peek_at(2).unwrap_Some() == 123; assert s.peek_at(3).is_None(); assert s.try_pop().unwrap_Some() == "hello"; assert s.len() == 2; assert !s.is_empty(); assert s.peek().unwrap_Some() == false; assert s.peek_at(1).unwrap_Some() == 123; assert s.peek_at(2).is_None(); assert s.pop() == false; assert s.len() == 1; assert !s.is_empty(); s.push(4*5); assert s.len() == 2; assert !s.is_empty(); assert s.peek_at(1).unwrap_Some() == 123; assert s.pop() == 20; assert s.pop() == 123; assert s.len() == 0; assert s.is_empty(); s.push(45); assert s.len() == 1; assert !s.is_empty(); } ================================================ FILE: tests/str_chr_bytes.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func main() { val s = "ABC"; val ch = s.chars(); val bt = s.bytes(); assert ch.len() == 3; assert bt.len() == 3; assert ch[0] == "A"; assert ch[1] == "B"; assert ch[2] == "C"; assert bt[0] == 65; assert bt[1] == 66; assert bt[2] == 67; } ================================================ FILE: tests/str_encoding.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func main() { val S = "ABC 123"; assert S[0].encoding() == 65; assert S[1].encoding() == 66; assert S[2].encoding() == 67; assert S[3].encoding() == 32; assert S[4].encoding() == 49; assert S[5].encoding() == 50; assert S[6].encoding() == 51; } ================================================ FILE: tests/str_equality.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func main() { val s1 = "hello world"; val s2 = "he" + "llo" + " wo" + "rld"; val s3 = "hello," + " world"; assert s1 == s2; assert s1 != s3; assert s2 != s3; } ================================================ FILE: tests/str_int_mul.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func main() { val s = "abc"; assert s * 0 == ""; assert s * 1 == s; assert 0 * s == ""; assert 1 * s == s; assert s * 2 == "abcabc"; assert 2 * s == "abcabc"; assert 2 * (s * 2) == 3 * s + s; assert s * 4 == "abcabcabcabc"; assert 4 * s == "abcabcabcabc"; } ================================================ FILE: tests/str_len_vs_index.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func main() { val message = "a😀😃😄 😁😆😅 😂🤣🥲 🥹z"; assert message.len() == 15; assert message[0] == 'a'; assert message[1] == '😀'; assert message[2] == '😃'; assert message[3] == '😄'; assert message[4] == ' '; assert message[5] == '😁'; assert message[6] == '😆'; assert message[7] == '😅'; assert message[8] == ' '; assert message[9] == '😂'; assert message[10] == '🤣'; assert message[11] == '🥲'; assert message[12] == ' '; assert message[13] == '🥹'; assert message[14] == 'z'; } ================================================ FILE: tests/string_classes.aria ================================================ # SPDX-License-Identifier: Apache-2.0 import aria.string.classes; func main() { assert "ϴ".is_uppercase_letter(); assert "A".is_letter(); assert "A".is_alphanumeric(); assert "Z".is_uppercase_letter(); assert "Z".is_letter(); assert "Z".is_alphanumeric(); assert "ɖ".is_lowercase_letter(); assert "a".is_letter(); assert "a".is_alphanumeric(); assert "ϣ".is_lowercase_letter(); assert "z".is_letter(); assert "z".is_alphanumeric(); assert "𑇳".is_digit(); assert "0".is_alphanumeric(); assert "9".is_digit(); assert "9".is_alphanumeric(); assert !"9".is_uppercase_letter(); assert !"9".is_lowercase_letter(); assert !",".is_alphanumeric(); assert !"*".is_alphanumeric(); assert !" ".is_alphanumeric(); assert " ".is_whitespace(); assert "\r".is_whitespace(); assert "\n".is_whitespace(); assert "\t".is_whitespace(); try { assert "".is_letter(); } catch e { assert e isa RuntimeError; assert e.is_IndexOutOfBounds(); assert e.unwrap_IndexOutOfBounds() == 0; } } ================================================ FILE: tests/string_concat.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func main() { val s1 = "hello"; val s2 = ", "; val s3 = "world"; assert (s1+s2+s3) == "hello, world"; } ================================================ FILE: tests/string_contains.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func main() { val s = "hello world"; assert s.contains("world"); assert s.contains("llo"); assert !s.contains("test"); assert !s.contains("world!"); } ================================================ FILE: tests/string_format.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func main() { val x = 1; val x_🇮🇹 = "uno"; val x_🇸🇴 = "mid"; val flag_it = "🇮🇹"; val flag_so = "🇸🇴"; val fmt_str = "The number {0} is written {1} in {2} and {3} in {4}"; val out = fmt_str.format(x,x_🇮🇹,flag_it,x_🇸🇴,flag_so); assert out == "The number 1 is written uno in 🇮🇹 and mid in 🇸🇴"; } ================================================ FILE: tests/string_format_errors.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func format_assert(x, y) { # println("actual: '{0}' expected: '{1}'".format(x, y)); assert x == y; } func main() { format_assert("{a}".format(), "{a}"); format_assert("{12a}".format(0), "{12a}"); format_assert("{0:".format(5), "{0:"); format_assert("{".format(), "{"); format_assert("}".format(), "}"); format_assert("{{{0}}}".format(7), "{7}"); format_assert("{0}{1}".format("a","b"), "ab"); format_assert("{2}".format(1,2), "{2}"); } ================================================ FILE: tests/string_from_bytes.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func main() { val bytes = [65, 66, 67, 68, 69]; val s = String.new_with_bytes(bytes); assert s == "ABCDE"; } ================================================ FILE: tests/string_index.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func main() { val s = "hello world"; assert s[0] == "h"; assert s[2] == s[3]; assert s[3] == s[9]; assert s[10] == "d"; } ================================================ FILE: tests/string_join.aria ================================================ # SPDX-License-Identifier: Apache-2.0 struct SampleIterator { type func new() = alloc(This) {.num = 0}; instance func iterator() = this; instance func next() { if this.num == 5 { return Maybe::None; } else { this.num += 1; return Maybe::Some(this.num); } } } func main() { val l = [1,2,3,4]; assert "".join(l) == "1234"; assert ", ".join(l) == "1, 2, 3, 4"; assert "-".join(l) == "1-2-3-4"; assert l.join() == "1, 2, 3, 4"; assert ",".join([]) == ""; assert ",".join([1]) == "1"; assert "".join([]) == ""; assert "::".join(SampleIterator.new()) == "1::2::3::4::5"; } ================================================ FILE: tests/string_negative_index.aria ================================================ # SPDX-License-Identifier: Apache-2.0 val x = "Hello"; assert x[-1] == "o"; assert x[-2] == "l"; assert x[-5] == "H"; try { println(x[-6]); } catch e { assert e isa RuntimeError; assert e.is_IndexOutOfBounds(); } ================================================ FILE: tests/string_prefix_suffix.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func main() { assert("hello".has_prefix("he")); assert("hello".has_suffix("lo")); assert !"hello".has_prefix("123"); assert !"hello".has_suffix("123"); } ================================================ FILE: tests/string_product_negative.aria ================================================ # SPDX-License-Identifier: Apache-2.0 assert "hello"*-3 == ""; assert "aria"*0 == ""; assert "test"*-2 == ""; ================================================ FILE: tests/string_remove.aria ================================================ # SPDX-License-Identifier: Apache-2.0 val s = "Hello, World! This is such a, lovely, wonderful even, day."; val s2 = s.remove(",").remove("!").remove("."); assert s2 == "Hello World This is such a lovely wonderful even day"; ================================================ FILE: tests/string_replace.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func main() { val s = "hello world"; s = s.replace("h", "H").replace(" ", ", ").replace("d", "d!").replace(" w", " W").replace("X", "Y"); assert s == "Hello, World!"; } ================================================ FILE: tests/string_split.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func main() { val s = "one two three four five words"; val l = s.split(" "); assert l.len() == 6; assert l[0] == "one"; assert l[1] == "two"; assert l[2] == "three"; assert l[3] == "four"; assert l[4] == "five"; assert l[5] == "words"; } ================================================ FILE: tests/string_trim.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func main() { val string = "\n Hello World! \n"; assert string.trim() == "Hello World!"; assert string.trim_head() == "Hello World! \n"; assert string.trim_tail() == "\n Hello World!"; } ================================================ FILE: tests/strings_anagram_hash.aria ================================================ # SPDX-License-Identifier: Apache-2.0 assert "listen".hash() != "silent".hash(); assert "".hash() == "".hash(); assert "a".hash() != "A".hash(); ================================================ FILE: tests/strlen.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func main() { val s = 'hello world'; val t = ''; assert s.len() == 11; assert t.len() == 0; } ================================================ FILE: tests/struct_field.aria ================================================ # SPDX-License-Identifier: Apache-2.0 struct Foo { type val MAX_VALUE = 3; type func new(n) { if n > Foo.MAX_VALUE { n = Foo.MAX_VALUE; } return alloc(This) { .n = n, }; } } func main() { val foo_2 = Foo.new(2); val foo_4 = Foo.new(4); Foo.MAX_VALUE = 5; val foo_5 = Foo.new(5); assert foo_2.n == 2; assert foo_4.n == 3; assert foo_5.n == 5; # should this actually work? assert foo_2.MAX_VALUE == 5; } ================================================ FILE: tests/struct_func_redecl.aria ================================================ # SPDX-License-Identifier: Apache-2.0 struct Test { func answer() { return "A"; } func answer() { return "B"; } } func main() { val test = alloc(Test); assert test.answer() == "B"; } ================================================ FILE: tests/struct_in_enum.aria ================================================ # SPDX-License-Identifier: Apache-2.0 enum X {} extension X { struct Pair { type func new(x,y) { return alloc(This) { .x=x, .y=y, }; } } } extension X.Pair { instance func swap() { return X.Pair.new(this.y,this.x); } } val Pair = X.Pair; func main() { val p = Pair.new(3,4); val q = p.swap(); assert q.x == 4; assert q.y == 3; } ================================================ FILE: tests/struct_in_struct.aria ================================================ # SPDX-License-Identifier: Apache-2.0 struct Outer { struct Inner { type func new(x,y) { return alloc(This) { .x = x, .y = y, }; } func i_add() { return this.x + this.y; } func i_sub() { return this.x - this.y; } func i_swap() { val x = this.x; val y = this.y; this.x = y; this.y = x; return this; } } type func new(x,y) { return alloc(This) { .impl = Outer.Inner.new(x,y), }; } func add() { return this.impl.i_add(); } func swap() { return this.impl.i_swap(); } func sub() { return this.impl.i_sub(); } } func main() { val o = Outer.new(8,2); assert o.add() == 10; o.swap(); assert o.sub() == -6; # check that names are unique between Outer and Inner assert !hasattr(o, "i_swap"); assert !hasattr(o.impl, "swap"); assert hasattr(Outer, "Inner"); } ================================================ FILE: tests/struct_isa_mixin.aria ================================================ # SPDX-License-Identifier: Apache-2.0 mixin M { func foo(x) { return x + 1; } } mixin MM { func bar(x) { return this.foo(x) + 1; } include M } struct IncludeM { include M } struct IncludeMM { include MM } func main() { val m = alloc(IncludeM); val mm = alloc(IncludeMM); assert m isa M; assert mm isa MM; assert mm isa M; assert !(m isa MM); assert MM isa M; assert !(M isa MM); assert IncludeM isa M; assert !(IncludeM isa MM); assert IncludeMM isa MM; assert IncludeMM isa M; } ================================================ FILE: tests/struct_list_attributes.aria ================================================ # SPDX-License-Identifier: Apache-2.0 struct Foo { func f1(x) { return x + 1; } func f2(x) { return x * 2; } func f3(x) { return x + 3; } } extension Foo { func f4(x) { return x + 4; } func f5(x) { return x + 5; } func f6(x) { return x + 6; } } struct Bar { func f1(x) { return x + 1; } func f2(x) { return x * 2; } func f3(x) { return x + 3; } } mixin PlusSeven { func f7(x) { return x + 7; } } extension Bar { include PlusSeven } func main() { val f = alloc(Foo); val b = alloc(Bar); val attribs_f = listattrs(f); val attribs_b = listattrs(b); assert attribs_f.contains("f1"); assert attribs_f.contains("f2"); assert attribs_f.contains("f3"); assert attribs_f.contains("f4"); assert attribs_f.contains("f5"); assert attribs_f.contains("f6"); assert attribs_f.len() == 6; assert attribs_b.contains("f1"); assert attribs_b.contains("f2"); assert attribs_b.contains("f3"); assert attribs_b.contains("f7"); assert attribs_b.len() == 4; val attribs_m = listattrs(PlusSeven); assert attribs_m.contains("f7"); assert attribs_m.len() == 1; } ================================================ FILE: tests/struct_methods_refer_each_other.aria ================================================ # SPDX-License-Identifier: Apache-2.0 struct Foo { func add_one(x) { return x + 1; } func add_two(x) { return this.add_one(this.add_one(x)); } } extension Foo { func add_three(x) { return this.add_two(this.add_one(x)); } } func main() { val foo = alloc(Foo); assert foo.add_one(3) == 4; assert foo.add_two(4) == 6; assert foo.add_three(6) == 9; } ================================================ FILE: tests/struct_methods_refer_outoforder.aria ================================================ # SPDX-License-Identifier: Apache-2.0 struct Foo { func add_two(x) { return this.add_one(this.add_one(x)); } func add_one(x) { return x + 1; } } extension Foo { func add_three(x) { return this.add_two(this.add_one(x)); } } func main() { val foo = alloc(Foo); assert foo.add_one(3) == 4; assert foo.add_two(4) == 6; assert foo.add_three(6) == 9; } ================================================ FILE: tests/struct_mixin_multiple.aria ================================================ # SPDX-License-Identifier: Apache-2.0 mixin A { func from_a() { return "A"; } } mixin B { func from_b() { return "B"; } } struct Multi : A, B { type func new() { return alloc(This); } } func main() { val m = Multi.new(); assert m.from_a() == "A"; assert m.from_b() == "B"; } ================================================ FILE: tests/struct_takes_self_arg.aria ================================================ # SPDX-License-Identifier: Apache-2.0 struct Foo { func take_myself(x: Foo) { return 42; } } func main() { val f = alloc(Foo); assert f.take_myself(f) == 42; } ================================================ FILE: tests/struct_with_opt_args.aria ================================================ # SPDX-License-Identifier: Apache-2.0 struct UseOptionalArguments { type func new(value: Int) { return alloc(This) { .value = value, }; } func only_optionals(x=1,y=2) { return x + y * this.value; } func some_optionals(x, y=3,z=4) { return x * y + this.value + z; } func opt_with_vararg(x,y=1,...) { val ret = x+y; for arg in varargs { ret *= arg; } return ret; } } func main() { val uoa = UseOptionalArguments.new(5); assert uoa.only_optionals() == 11; assert uoa.only_optionals(2) == 12; assert uoa.only_optionals(3,4) == 23; assert uoa.some_optionals(2) == 15; assert uoa.some_optionals(2, 5) == 19; assert uoa.some_optionals(2, 4, 3) == 16; assert uoa.opt_with_vararg(1) == 2; assert uoa.opt_with_vararg(1, 2) == 3; assert uoa.opt_with_vararg(1, 2, 3) == 9; assert uoa.opt_with_vararg(1, 2, 3, 4) == 36; } ================================================ FILE: tests/substring.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func main() { val str = "hello world"; assert str.substring(0,1) == "he"; assert str.substring(0,4) == "hello"; assert str.substring(6,100) == "world"; assert str.substring(5,6) == " w"; } ================================================ FILE: tests/successive_ifs.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func main() { val n = 3; val m = 4; if n == 3 { m = m + 1; } else { m = 2; } if m == 5 { n = 2; } else { n = 1; } assert n == 2; assert m == 5; if n != 2 { assert false; } elsif m != 5 { assert false; } else { assert m + n == 7; } } ================================================ FILE: tests/system_of_no_such_cmd_err.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func main() { val caught = false; try { val ok = system("this_command_does_not_exist.no-such-file"); caught = ok != 0; } catch e { match e { isa RuntimeError and case OperationFailed => { caught = true; } } } assert caught; } ================================================ FILE: tests/ternary_operator.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func main() { val x = true ? 123 : 456; assert x == 123; val y = false ? 123 : 456; assert y == 456; val z = 1 == 1 ? 789 : 1011; assert z == 789; val a = 1 != 1 ? 789 : 1011; assert a == 1011; } ================================================ FILE: tests/ternary_operator_nested.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func main() { val x = true ? (false ? 1 : 2) : 3; assert x == 2; val y = false ? 1 : (true ? 2 : 3); assert y == 2; val z = true ? (true ? (false ? 1 : 2) : 3) : 4; assert z == 2; val n = x == 1 ? "one" : x == 2 ? "two" : "three"; assert n == "two"; } ================================================ FILE: tests/ternary_operator_precedence.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func main() { val x = 1 + 2 == 3 ? 10 : 20; assert x == 10; val y = 1 + 2 != 3 ? 10 : 20; assert y == 20; val a = true && false ? 100 : 200; assert a == 200; val b = true || false ? 100 : 200; assert b == 100; } ================================================ FILE: tests/test_module.aria ================================================ # SPDX-License-Identifier: Apache-2.0 import TestSuite,TestCase from aria.test.test; struct SamplePassingTest { func test() { this.assert_equal(5, 5); } func prettyprint() { return "SamplePassingTest"; } include TestCase } struct SampleFailingTest { func test() { this.assert_equal("hi", "hello"); } func prettyprint() { return "SampleFailingTest"; } include TestCase } func main() { val suite = TestSuite.new("Sample Test Suite"); assert suite.add_test(SamplePassingTest.new()).add_test(SampleFailingTest.new()).run(true) == 1; } ================================================ FILE: tests/test_shell_command.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func main() { # only run a very minimal test # TODO: on macOS, this is nominally deprecated and it should be "id -un" instead # however, it appears to still work val whoami = system("whoami"); assert whoami == 0; assert whoami.stdout != ""; assert whoami.stderr == ""; } ================================================ FILE: tests/test_with_no_main.aria ================================================ # SPDX-License-Identifier: Apache-2.0 val x = 3; val y = x + 1; assert x == 3; assert y == 4; ================================================ FILE: tests/throw_in_catch.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func main() { val inner = false; val outer = false; try { try { throw 1; } catch e { inner = e; throw 2; } } catch e { outer = e; } assert inner == 1; assert outer == 2; } ================================================ FILE: tests/throws_func.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func throws() { return 1; } func main() { throws(); } ================================================ FILE: tests/to_json_string.aria ================================================ # SPDX-License-Identifier: Apache-2.0 import aria.json.writer; import aria.json.parser; import JsonValue, JsonNull from aria.json.value; import Map from aria.structures.map; func main() { val json_value = JsonValue::Object(Map.new() { ["pi"] = JsonValue::Number(3.14f), ["zero"] = JsonValue::Number(0.0f), ["false"] = JsonValue::Boolean(false), ["list"] = JsonValue::Array([ JsonValue::String("hello world"), JsonValue::Number(1.0f), JsonValue::Null(alloc(JsonNull)) ]), }); val json_as_string = json_value.to_json_string(); assert json_as_string.contains('"zero":0'); assert json_as_string.contains('"list":['); assert json_as_string.contains('"false":false'); val json_remade = JsonValue.parse(json_as_string)!.flatten(); assert json_remade["pi"] == 3.14f; assert json_remade["zero"] == 0.0f; assert json_remade["false"] == false; assert json_remade["list"].len() == 3; assert json_remade["list"][0] == "hello world"; assert json_remade["list"][1] == 1.0f; assert json_remade["list"][2] isa JsonNull; } ================================================ FILE: tests/to_json_value.aria ================================================ # SPDX-License-Identifier: Apache-2.0 import aria.json.writer; import JsonValue from aria.json.value; import Map from aria.structures.map; func main() { val map = Map.new(); map["hello"] = [1,2,3]; map["hi"] = false; map["foo"] = 3.14f; val json_map = JsonValue.new_with_value(map)!; assert json_map isa JsonValue; val unwrap_map = json_map.unwrap_Object(); assert unwrap_map isa Map; assert unwrap_map["hello"].is_Array(); val array = unwrap_map["hello"].flatten(); assert array.len() == 3; assert array[0] == 1; assert array[1] == 2; assert array[2] == 3; assert unwrap_map["hi"].is_Boolean(); assert unwrap_map["hi"].flatten() == false; assert unwrap_map["foo"].is_Number(); assert unwrap_map["foo"].flatten() == 3.14f; } ================================================ FILE: tests/top_level_assign.aria ================================================ # SPDX-License-Identifier: Apache-2.0 val x = 1; val y = 3; x = y + x; y = y + 2; assert x == 4; assert y == 5; func main() { assert x == 4; assert y == 5; } ================================================ FILE: tests/top_level_code_block.aria ================================================ # SPDX-License-Identifier: Apache-2.0 val worked = false; val q = 10; { val x = 1; val y = 2; assert x + y == 3; while q > 0 { if q == 3 { break; } q -= 1; } worked = (q == 3); } func main() { assert worked; assert q == 3; # right now, all things top level are visible } ================================================ FILE: tests/top_level_expr_stmt.aria ================================================ # SPDX-License-Identifier: Apache-2.0 val global = 0; func increase() { global += 1; } increase(); func main() { assert global == 1; } ================================================ FILE: tests/top_level_guard.aria ================================================ # SPDX-License-Identifier: Apache-2.0 import guard from aria.utils.guard; struct Guard { type val COUNTER = 0; instance func guard_exit() { Guard.COUNTER = Guard.COUNTER + 1; } } val in_guard = guard(alloc(Guard)).do(|g| => { assert 3 == 3; return true; }); func main() { assert Guard.COUNTER == 1; assert in_guard; } ================================================ FILE: tests/top_level_plus_eq.aria ================================================ # SPDX-License-Identifier: Apache-2.0 val x = 1; x += 2; func main() { assert x == 3; } ================================================ FILE: tests/top_level_shift_eq.aria ================================================ # SPDX-License-Identifier: Apache-2.0 val x = 4; x <<= 2; val y = x; y >>= 3; func main() { assert x == 16; assert y == 2; } ================================================ FILE: tests/top_level_try.aria ================================================ # SPDX-License-Identifier: Apache-2.0 val caught = false; val should_have_failed = false; try { println(3 / 0); should_have_failed = true; } catch e { match e { isa RuntimeError and case DivisionByZero => { caught = true; } } } func main() { assert caught; assert !should_have_failed; } ================================================ FILE: tests/trig.aria ================================================ # SPDX-License-Identifier: Apache-2.0 import aria.numerics.float.trig; val π = Float.pi; func rough_approx_eq(x: Float, y: Float) { return (x-y).abs() <= 0.00001f; } func main() { assert(rough_approx_eq((π/6.0f).sin(), 0.5f)); assert(rough_approx_eq((π/6.0f).cos(), 0.8660254f)); assert(rough_approx_eq((0.0f).sin(), 0.0f)); assert(rough_approx_eq((0.0f).cos(), 1.0f)); assert(rough_approx_eq((π/2.0f).sin(), 1.0f)); assert(rough_approx_eq((π/2.0f).cos(), 0.0f)); assert(rough_approx_eq(π.sin(), 0.0f)); assert(rough_approx_eq(π.cos(), -1.0f)); assert(rough_approx_eq(0.0f.arcsin(), 0.0f)); assert(rough_approx_eq(0.5f.arcsin(), π/6.0f)); assert(rough_approx_eq((-0.5f).arcsin(), -π/6.0f)); assert(rough_approx_eq(0.0f.arccos(), π/2.0f)); assert(rough_approx_eq(0.5f.arccos(), π/3)); assert(rough_approx_eq((-0.5f).arccos(), 2*π/3)); } ================================================ FILE: tests/trivial_if.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func main() { val x = 0; if true { for a in [1,2,3,4] { x = a; } } if false { x = 2; } assert x == 4; } ================================================ FILE: tests/trivial_try_block.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func main() { val x = 1; try { x = 2; throw 3; } catch e { assert e == 3; x = x + 1; } assert x == 3; } ================================================ FILE: tests/try_nothrow.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func main() { val x = 1; try { x = 3; } catch e { assert false; } assert x == 3; } ================================================ FILE: tests/try_unwinds_guard.aria ================================================ # SPDX-License-Identifier: Apache-2.0 import guard from aria.utils.guard; struct Guard { type func new(x: Int) { return alloc(This) { .counter = x, }; } func guard_exit() { this.counter = this.counter + 1; } } func main() { val g1 = Guard.new(1); val g2 = Guard.new(2); try { guard(g1).do(|_| => { guard(g2).do(|_| => { throw 4; }); }); } catch e { assert e == 4; assert g1.counter == 2; assert g2.counter == 3; } assert g1.counter == 2; assert g2.counter == 3; } ================================================ FILE: tests/try_unwrap_coalesce.aria ================================================ # SPDX-License-Identifier: Apache-2.0 import ok, err from aria.core.result; val called = false; func fallback() { called = true; return 99; } func main() { val ok_val = ok(5); val err_val = err("nope"); val a = ok_val ?? fallback(); assert a == 5; assert called == false; called = false; val b = err_val ?? fallback(); assert b == 99; assert called == true; assert (Maybe::Some(3) ?? 7) == 3; assert (Maybe::None ?? 7) == 7; val chained = err("bad") ?? ok(10) ?? 20; assert chained == 10; val chained = err("bad") ?? err(10) ?? 20; assert chained == 20; } ================================================ FILE: tests/try_unwrap_maybe.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func main() { val a = Maybe::Some(5); val b = Maybe::None; assert a? == 5; assert b?.is_Err(); } ================================================ FILE: tests/try_unwrap_non_result.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func main() { assert 5? == 5; assert false? == false; assert 3! == 3; assert "hello"! == "hello"; } ================================================ FILE: tests/type_func_takes_This.aria ================================================ # SPDX-License-Identifier: Apache-2.0 struct Pair{ type func new_with_duplicate(x) { assert hasattr(This, "new_with_items"); return This.new_with_items(x,x); } type func new_with_items(x,y) { return alloc(This){ .x = x, .y = y, }; } } func main() { val p = Pair.new_with_duplicate(5); assert p.x == 5; assert p.y == 5; } ================================================ FILE: tests/type_root.aria ================================================ # SPDX-License-Identifier: Apache-2.0 struct Foo { type func new() = alloc(This); }; func main() { val one = 1; val s = Maybe::Some(3); val f = Foo.new(); val t_one = typeof(one); val t_s = typeof(s); val t_f = typeof(f); assert t_one != t_s; assert t_one != t_f; assert t_s != t_f; val t_t_one = typeof(t_one); val t_t_s = typeof(t_s); val t_t_f = typeof(t_f); assert t_t_one == t_t_s; assert t_t_one == t_t_f; assert t_t_s == t_t_f; val t_t_t_one = typeof(t_t_one); val t_t_t_s = typeof(t_t_s); val t_t_t_f = typeof(t_t_f); assert t_t_t_one == t_t_t_s; assert t_t_t_one == t_t_t_f; assert t_t_t_s == t_t_t_f; assert t_t_t_one == t_t_one; assert t_t_t_s == t_t_s; assert t_t_t_f == t_t_f; } ================================================ FILE: tests/type_val_in_enum.aria ================================================ # SPDX-License-Identifier: Apache-2.0 enum Foo {} extension Foo { type val ANSWER = 42; } func main() { assert Foo.ANSWER == 42; } ================================================ FILE: tests/typecheck_as_struct.aria ================================================ # SPDX-License-Identifier: Apache-2.0 struct Foo { type func new() { return alloc(This); } instance func truth() { return true; } } func main() { val f: Foo = Foo.new(); assert(f.truth()); } ================================================ FILE: tests/unexpected_type_error.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func main() { val caught = false; try { assert 1 + "hello" == false; } catch e { match e { isa RuntimeError and case UnexpectedType => { caught = true; } } } assert caught; } ================================================ FILE: tests/union_type_passes.aria ================================================ # SPDX-License-Identifier: Apache-2.0 # this is not *exactly* right - ideally it would be # x: Int|String, y: typeof(x) - but we can't express that func foo(x: Int|String, y:Int|String) { assert typeof(x) == typeof(y); # this is the next best thing return x + y; } func main() { assert foo(4,5) == 9; assert foo("hello", "world") == "helloworld"; } ================================================ FILE: tests/unit_type.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func main() { val nu = Unit.new(); val uu = Unit::unit; assert nu == uu; assert nu.prettyprint() == "unit"; } ================================================ FILE: tests/unused_local_typechecks.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func foo(x: Int) { return 0; } func bar(y) { return 0; } func main() { foo(3); bar(3); val caught = false; try { foo("abc"); } catch e { match e { isa RuntimeError and case UnexpectedType => { caught = true; } } } assert caught; bar("abc"); } ================================================ FILE: tests/unused_local_value.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func foo(x) { val y = x + 1; return x; } func main() { assert foo(4) == 4; } ================================================ FILE: tests/unused_typed_local.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func foo(x: Int, y) { return y + 1; } func main() { assert foo(3,4) == 5; } ================================================ FILE: tests/unwrap_single_eval.aria ================================================ # SPDX-License-Identifier: Apache-2.0 val c = 0; func bump() { c = c + 1; return Maybe::Some(c); } bump()?; bump()?; assert c == 2; assert bump()? == 3; assert bump()! == 4; ================================================ FILE: tests/uplevel_can_write_attrib.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func main() { val variable = Box(); variable.foo = 1; val g = || => { variable.foo = 3; return variable; }; assert g().foo == 3; assert variable.foo == 3; } ================================================ FILE: tests/uplevel_write_before_read.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func main() { val variable = 10; val g = || => { variable = 11; return variable; }; assert g() == 11; assert variable == 10; } ================================================ FILE: tests/upper_lower.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func main() { val str = "Hello, World!"; val u = str.uppercase(); val l = str.lowercase(); assert u == "HELLO, WORLD!"; assert l == "hello, world!"; } ================================================ FILE: tests/while_break.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func main() { val i = 0; while i != 10 { i = i + 1; if i == 4 { break; } } assert i == 4; } ================================================ FILE: tests/while_continue.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func main() { val i = 0; while i != 10 { i = i + 1; continue; assert false; } assert i == 10; } ================================================ FILE: tests/while_else.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func main() { val x = 3; while x > 0 { x -= 1; } else { assert false; # this should not execute } assert x == 0; while x > 0 { assert false; # this should not execute } else { x = 5; } assert x == 5; } ================================================ FILE: tests/while_missed.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func loop_forever_or_never(b) { val counter = 721; while b { counter = counter + 1; } return counter; } func main() { val c = loop_forever_or_never(false); assert c == 721; } ================================================ FILE: tests/while_taken.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func add_them_up(n) { val counter = 0; val i = 0; while i != n { counter = counter + i; i = i + 1; } return counter + n; } func main() { val total = add_them_up(6); assert total == 21; } ================================================ FILE: tests/widget_test.aria ================================================ # SPDX-License-Identifier: Apache-2.0 import Paco from cool_widget.lib; import BWrapper from cool_widget.lib; import AWrapper from cool_widget.lib; import Buzz from cool_widget.buzz; func main() { val buzz = Paco.build_buzz(); val real_buzz = alloc(Buzz); assert(buzz.prettyprint() == real_buzz.prettyprint()); val a = AWrapper.new(); val b = BWrapper.new(); assert(a.prettyprint() == "A"); assert(b.prettyprint() == "InnerB"); } ================================================ FILE: tests/write_attrib_struct.aria ================================================ # SPDX-License-Identifier: Apache-2.0 struct Foo {} func main() { Foo{.x = 1}; assert Foo.x == 1; } ================================================ FILE: tests/write_index.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func main() { val arr = []{ [0] = 1, [1] = 2, [2] = 3, [3] = 4, }; assert arr.len() == 4; assert arr[0] == 1; assert arr[1] == 2; assert arr[2] == 3; assert arr[3] == 4; } ================================================ FILE: tests/write_index_multiple.aria ================================================ # SPDX-License-Identifier: Apache-2.0 struct Foo { type func new(x) = alloc(This) { .x }; operator []=(a,b,n) { this.x = this.x * a + b * n; } operator[](n) { return this.x - n; } } func main() { val f = Foo.new(5); assert f[0] == 5; f[3,4] = 5; assert f[1] == 34; assert f[0] == 35; f[2,0] = 10; assert f[0] == 70; assert f[10] == 60; } ================================================ FILE: tests/write_list_index.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func main() { val list = [1,2,3,4,5]; list[0] = list[4] + list[0]; val l0 = list[0]; assert l0 == 6; val l1 = list[1]; assert l1 == 2; list[1] = 3; assert l1 == 2; l1 = list[1]; assert l1 == 3; val l2 = list[2]; assert l2 == 3; val l3 = list[3]; assert l3 == 4; val l4 = list[4]; assert l4 == 5; } ================================================ FILE: tests/writeattr.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func foo(x,y) { return x + y + foo.n; } func main() { writeattr(foo, "n", 5); assert foo(3,4) == 12; assert readattr(foo, "n") == 5; assert foo.n == 5; writeattr(foo, "n", 10); assert foo(3,4) == 17; assert readattr(foo, "n") == 10; assert foo.n == 10; } ================================================ FILE: tests/xor.aria ================================================ # SPDX-License-Identifier: Apache-2.0 func boolean() { assert (true ^ true) == false; assert (true ^ false) == true; assert (false ^ true) == true; assert (false ^ false) == false; } func integer() { val a = 0b00101110101011110001; val b = 0b00010100001100011010; assert (a ^ b) == 0b00111010100111101011; } func main() { integer(); boolean(); } ================================================ FILE: tests/xorshift.aria ================================================ # SPDX-License-Identifier: Apache-2.0 import XorshiftRng from aria.rng.xorshift; import Range from aria.range.range; func main() { val rng = XorshiftRng.new(); # TODO: replace this with a proper verification, this is not exactly # guaranteed - just very very likely assert rng.next() != rng.next(); assert rng.next() != rng.next(); assert rng.next() != rng.next(); val die = Range.from(1).through(6).iterator().to_list(); for _ in Range.from(0).to(100) { val random = rng.one_of(die); assert random >= 1; assert random <= 6; } } ================================================ FILE: tree_check.sh ================================================ #!/usr/bin/env bash set -e SELF_DIR="$(dirname "$(readlink -f "${BASH_SOURCE[0]}")")" # Runs some checks on the source tree, to make sure the source tree is well-formed. # This includes: # - formatting of Rust code # - no warnings from clippy # - license markers in each source file # It is intended to be run in CI, but can also be run locally. ${SELF_DIR}/add_license_marker.sh --check && \ cargo fmt --check && \ cargo clippy --no-deps ================================================ FILE: vm-lib/Cargo.toml ================================================ [package] name = "vm-lib" version = "0.9.20251222" edition = "2024" [lib] name = "haxby_vm" path = "src/lib.rs" [dependencies] pest = "2.8.5" pest_derive = "2.8.5" parser-lib = { path = "../parser-lib" } compiler-lib = { path = "../compiler-lib" } opcodes-lib = { path = "../opcodes-lib" } enum-as-inner = "0.7.0" thiserror = "2.0.18" libloading = "0.9.0" libc = "0.2.180" rustc_data_structures = "0.1.2" [dev-dependencies] criterion = { version = "0.8.2" } [[bench]] name = "control_flow" harness = false ================================================ FILE: vm-lib/benches/control_flow.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use std::hint::black_box; use aria_compiler::compile_from_source; use aria_parser::ast::SourceBuffer; use criterion::{Criterion, criterion_group, criterion_main}; use haxby_vm::haxby_eval; fn bench_aria_code_aux(bench_name: &str, src: &str, c: &mut Criterion) { c.bench_function(&format!("{}/compile", bench_name), |b| { b.iter(|| { let sb = SourceBuffer::stdin(src); black_box( compile_from_source(&sb, &Default::default()).expect("module did not compile"), ); }) }); let sb = SourceBuffer::stdin(src); c.bench_function(&format!("{}/eval", bench_name), |b| { b.iter_batched( || compile_from_source(&sb, &Default::default()).expect("module did not compile"), |module| black_box(haxby_eval(module, Default::default()).unwrap()), criterion::BatchSize::SmallInput, ) }); } fn bench_if(c: &mut Criterion) { const INPUT: &str = r#" func main() { if true { } else { } if false { } else { } } "#; bench_aria_code_aux("control_flow/if", INPUT, c); } fn bench_for(c: &mut Criterion) { const INPUT: &str = r#" func main() { for i in Range.from(0).to(10) { println(i); } } "#; bench_aria_code_aux("control_flow/for", INPUT, c); } fn bench_while(c: &mut Criterion) { const INPUT: &str = r#" func main() { val i = 0; while i < 10 { i = i + 1; } } "#; bench_aria_code_aux("control_flow/while", INPUT, c); } fn bench_empty_function_call(c: &mut Criterion) { const INPUT: &str = r#" func foo() {} func main() { val i = 0; while i < 10 { foo(); i += 1; } } "#; bench_aria_code_aux("control_flow/empty_function_call", INPUT, c); } fn bench_list_read(c: &mut Criterion) { const INPUT: &str = r#" func foo(_) {} func main() { val x = [1,2,3,4,5,6,7,8,9,10]; val i = 0; while i < x.len() { foo(x[i]); i += 1; } } "#; bench_aria_code_aux("control_flow/list_read", INPUT, c); } fn bench_object_read(c: &mut Criterion) { const INPUT: &str = r#" func foo(_) {} func main() { val x = Box(){ .a = 1, .b = 2, .c = 3, .d = 4, .e = 5, .f = 6, .g = 7, .h = 8, .i = 9, .j = 10 }; foo(x.a); foo(x.b); foo(x.c); foo(x.d); foo(x.e); foo(x.f); foo(x.g); foo(x.h); foo(x.i); foo(x.j); } "#; bench_aria_code_aux("control_flow/object_read", INPUT, c); } criterion_group!( control_flow, bench_if, bench_for, bench_while, bench_empty_function_call, bench_list_read, bench_object_read, ); criterion_main!(control_flow); ================================================ FILE: vm-lib/src/arity.rs ================================================ // SPDX-License-Identifier: Apache-2.0 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct Arity { pub required: u8, pub optional: u8, } impl Arity { pub fn zero() -> Self { Self { required: 0, optional: 0, } } pub fn required(r: u8) -> Self { Self { required: r, optional: 0, } } } ================================================ FILE: vm-lib/src/builtins/alloc.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use crate::{ arity::Arity, builtins::VmGlobals, error::vm_error::VmErrorReason, frame::Frame, runtime_value::{ RuntimeValue, function::BuiltinFunctionImpl, kind::RuntimeValueType, object::Object, }, vm::RunloopExit, }; #[derive(Default)] struct Alloc {} impl BuiltinFunctionImpl for Alloc { fn eval( &self, frame: &mut Frame, _: &mut crate::vm::VirtualMachine, ) -> crate::vm::ExecutionResult { use crate::runtime_value::rust_native_type::RustNativeValueKind as BVK; let alloc_type = VmGlobals::extract_arg(frame, |x| x.as_type().cloned())?; match alloc_type { RuntimeValueType::RustNative(b) => { let rv = match b.get_tag() { BVK::Boolean => RuntimeValue::Boolean(false.into()), BVK::Integer => RuntimeValue::Integer(0.into()), BVK::Float => RuntimeValue::Float(0.0.into()), BVK::List => RuntimeValue::List(crate::runtime_value::list::List::from(&[])), BVK::String => RuntimeValue::String("".into()), BVK::Type => return Err(VmErrorReason::UnexpectedType.into()), }; frame.stack.push(rv); } RuntimeValueType::Struct(s) => { let obj = RuntimeValue::Object(Object::new(&s)); frame.stack.push(obj); } _ => { return Err(VmErrorReason::UnexpectedType.into()); } } Ok(RunloopExit::Ok(())) } fn arity(&self) -> Arity { Arity { required: 1, optional: 0, } } fn name(&self) -> &str { "alloc" } } pub(super) fn insert_builtins(builtins: &mut VmGlobals) { builtins.insert_builtin::(); } ================================================ FILE: vm-lib/src/builtins/arity.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use std::cell::OnceCell; use crate::{ builtins::VmGlobals, error::vm_error::{VmError, VmErrorReason}, frame::Frame, runtime_value::{RuntimeValue, function::BuiltinFunctionImpl, object::Object}, symbol::{INTERNED_CASE_BOUNDED, INTERNED_CASE_VARARGS, INTERNED_OP_IMPL_CALL}, vm::RunloopExit, }; struct Cache { arity_struct: crate::runtime_value::structure::Struct, upper_bound_enum: crate::runtime_value::enumeration::Enum, vararg_idx: usize, bounded_idx: usize, } #[derive(Default)] struct Arity { cache: OnceCell, } impl Arity { fn fill_in_cache(&self, vm: &mut crate::vm::VirtualMachine) -> Result<&Cache, VmError> { if let Some(cache) = self.cache.get() { Ok(cache) } else { let arity_mod = vm.find_imported_module("aria.core.arity").ok_or_else(|| { VmErrorReason::ImportNotAvailable( "aria.core.arity".to_owned(), "module not found".to_owned(), ) })?; let arity_struct = arity_mod.load_named_value("Arity").ok_or_else(|| { VmErrorReason::NoSuchIdentifier("aria.core.arity.Arity".to_owned()) })?; let arity_struct = arity_struct .as_struct() .ok_or(VmErrorReason::UnexpectedType)?; let upper_bound_sym = vm .globals .intern_symbol("UpperBound") .expect("too many symbols interned"); let upper_bound_enum = arity_struct .load_named_value(&vm.globals, upper_bound_sym) .ok_or_else(|| { VmErrorReason::NoSuchIdentifier("aria.core.arity.Arity.UpperBound".to_owned()) })?; let upper_bound_enum = upper_bound_enum .as_enum() .ok_or(VmErrorReason::UnexpectedType)?; let vararg_idx = upper_bound_enum .get_idx_of_case_by_symbol(&vm.globals, INTERNED_CASE_VARARGS) .ok_or_else(|| VmErrorReason::NoSuchCase("Varargs".to_owned()))?; let bounded_idx = upper_bound_enum .get_idx_of_case_by_symbol(&vm.globals, INTERNED_CASE_BOUNDED) .ok_or_else(|| VmErrorReason::NoSuchCase("Bounded".to_owned()))?; let cache = Cache { arity_struct: arity_struct.clone(), upper_bound_enum: upper_bound_enum.clone(), vararg_idx, bounded_idx, }; let _ = self.cache.set(cache); Ok(self.cache.get().unwrap()) } } } fn get_to_function_for_callable( val: &RuntimeValue, vm: &mut crate::vm::VirtualMachine, ) -> Option<(crate::runtime_value::function::Function, bool)> { if let Some(f) = val.as_function() { Some((f.clone(), false)) } else if let Some(bf) = val.as_bound_function() { Some((bf.func().clone(), true)) } else if let Ok(call) = val.read_attribute(INTERNED_OP_IMPL_CALL, &vm.globals) { get_to_function_for_callable(&call, vm) } else { None } } impl BuiltinFunctionImpl for Arity { fn eval( &self, frame: &mut Frame, vm: &mut crate::vm::VirtualMachine, ) -> crate::vm::ExecutionResult { let (f_this, has_receiver) = VmGlobals::extract_arg(frame, |val| get_to_function_for_callable(&val, vm))?; let arity_cache = self.fill_in_cache(vm)?; let f_arity = f_this.arity(); let is_vararg = f_this.attribute().is_vararg(); let argc_offset = if has_receiver { 1 } else { 0 }; let upper_bound_value = if is_vararg { arity_cache .upper_bound_enum .make_value(arity_cache.vararg_idx, None) } else { arity_cache.upper_bound_enum.make_value( arity_cache.bounded_idx, Some(RuntimeValue::Integer( ((f_arity.optional + f_arity.required - argc_offset) as i64).into(), )), ) } .ok_or(VmErrorReason::UnexpectedType)?; let upper_bound_value = RuntimeValue::EnumValue(upper_bound_value); let lower_bound_value = RuntimeValue::Integer(((f_arity.required - argc_offset) as i64).into()); let min_sym = vm .globals .intern_symbol("min") .expect("too many symbols interned"); let max_sym = vm .globals .intern_symbol("max") .expect("too many symbols interned"); let has_receiver_sym = vm .globals .intern_symbol("has_receiver") .expect("too many symbols interned"); let arity_object = Object::new(&arity_cache.arity_struct) .with_value(&mut vm.globals, min_sym, lower_bound_value) .with_value(&mut vm.globals, max_sym, upper_bound_value) .with_value( &mut vm.globals, has_receiver_sym, RuntimeValue::Boolean(has_receiver.into()), ); frame.stack.push(RuntimeValue::Object(arity_object)); Ok(RunloopExit::Ok(())) } fn arity(&self) -> crate::arity::Arity { crate::arity::Arity { required: 1, optional: 0, } } fn name(&self) -> &str { "arity" } } pub(super) fn insert_builtins(builtins: &mut VmGlobals) { builtins.insert_builtin::(); } ================================================ FILE: vm-lib/src/builtins/boolean.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use crate::runtime_value::{ RuntimeValue, kind::RuntimeValueType, rust_native_type::RustNativeType, }; use super::VmGlobals; pub(super) fn insert_boolean_builtins(builtins: &mut VmGlobals) { let bool_builtin = RustNativeType::new(crate::runtime_value::rust_native_type::RustNativeValueKind::Boolean); builtins.register_builtin_type( haxby_opcodes::BuiltinTypeId::Bool, RuntimeValueType::RustNative(bool_builtin), ); builtins.insert("true", RuntimeValue::Boolean(true.into())); builtins.insert("false", RuntimeValue::Boolean(false.into())); } ================================================ FILE: vm-lib/src/builtins/cmdline_args.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use crate::{ builtins::VmGlobals, frame::Frame, runtime_value::{RuntimeValue, function::BuiltinFunctionImpl}, vm::RunloopExit, }; #[derive(Default)] struct CmdlineArgs {} impl BuiltinFunctionImpl for CmdlineArgs { fn eval( &self, cur_frame: &mut Frame, vm: &mut crate::vm::VirtualMachine, ) -> crate::vm::ExecutionResult { let args = vm .options .vm_args .iter() .map(|arg| RuntimeValue::String(arg.as_str().into())) .collect::>(); let args_list = RuntimeValue::List(crate::runtime_value::list::List::from(&args)); cur_frame.stack.push(args_list); Ok(RunloopExit::Ok(())) } fn arity(&self) -> crate::arity::Arity { crate::arity::Arity::zero() } fn name(&self) -> &str { "cmdline_arguments" } } pub(super) fn insert_builtins(builtins: &mut VmGlobals) { builtins.insert_builtin::(); } ================================================ FILE: vm-lib/src/builtins/exit.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use crate::{ builtins::VmGlobals, frame::Frame, runtime_value::function::BuiltinFunctionImpl, vm::RunloopExit, }; #[derive(Default)] struct Exit {} impl BuiltinFunctionImpl for Exit { fn eval( &self, frame: &mut Frame, _: &mut crate::vm::VirtualMachine, ) -> crate::vm::ExecutionResult { let code = VmGlobals::extract_arg(frame, |x| x.as_integer().cloned())?; std::process::exit(*code.raw_value() as i32); } fn arity(&self) -> crate::arity::Arity { crate::arity::Arity::required(1) } fn name(&self) -> &str { "exit" } } pub(super) fn insert_builtins(builtins: &mut VmGlobals) { builtins.insert_builtin::(); } ================================================ FILE: vm-lib/src/builtins/float.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use haxby_opcodes::function_attribs::FUNC_IS_METHOD; use crate::{ frame::Frame, runtime_value::{ RuntimeValue, function::BuiltinFunctionImpl, kind::RuntimeValueType, rust_native_type::RustNativeType, }, vm::RunloopExit, }; use super::VmGlobals; #[derive(Default)] struct FpHash {} impl BuiltinFunctionImpl for FpHash { fn eval( &self, frame: &mut Frame, _: &mut crate::vm::VirtualMachine, ) -> crate::vm::ExecutionResult { let this = VmGlobals::extract_arg(frame, |x| x.as_float().cloned())?; let hv = unsafe { std::mem::transmute_copy::(this.raw_value()) }; frame.stack.push(RuntimeValue::Integer(hv.into())); Ok(RunloopExit::Ok(())) } fn attrib_byte(&self) -> u8 { FUNC_IS_METHOD } fn arity(&self) -> crate::arity::Arity { crate::arity::Arity::required(1) } fn name(&self) -> &str { "hash" } } #[derive(Default)] struct FpFloor {} impl BuiltinFunctionImpl for FpFloor { fn eval( &self, frame: &mut Frame, _: &mut crate::vm::VirtualMachine, ) -> crate::vm::ExecutionResult { let this = VmGlobals::extract_arg(frame, |x| x.as_float().cloned())?; let result = RuntimeValue::Float(this.raw_value().floor().into()); frame.stack.push(result); Ok(RunloopExit::Ok(())) } fn attrib_byte(&self) -> u8 { FUNC_IS_METHOD } fn arity(&self) -> crate::arity::Arity { crate::arity::Arity::required(1) } fn name(&self) -> &str { "floor" } } #[derive(Default)] struct FpCeil {} impl BuiltinFunctionImpl for FpCeil { fn eval( &self, frame: &mut Frame, _: &mut crate::vm::VirtualMachine, ) -> crate::vm::ExecutionResult { let this = VmGlobals::extract_arg(frame, |x| x.as_float().cloned())?; let result = RuntimeValue::Float(this.raw_value().ceil().into()); frame.stack.push(result); Ok(RunloopExit::Ok(())) } fn attrib_byte(&self) -> u8 { FUNC_IS_METHOD } fn arity(&self) -> crate::arity::Arity { crate::arity::Arity::required(1) } fn name(&self) -> &str { "ceil" } } #[derive(Default)] struct FpInt {} impl BuiltinFunctionImpl for FpInt { fn eval( &self, frame: &mut Frame, _: &mut crate::vm::VirtualMachine, ) -> crate::vm::ExecutionResult { let this = VmGlobals::extract_arg(frame, |x| x.as_float().cloned())?; let iv = *this.raw_value() as i64; frame.stack.push(RuntimeValue::Integer(iv.into())); Ok(RunloopExit::Ok(())) } fn attrib_byte(&self) -> u8 { FUNC_IS_METHOD } fn arity(&self) -> crate::arity::Arity { crate::arity::Arity::required(1) } fn name(&self) -> &str { "int" } } #[derive(Default)] struct FpPrettyprint {} impl BuiltinFunctionImpl for FpPrettyprint { fn eval( &self, frame: &mut Frame, _: &mut crate::vm::VirtualMachine, ) -> crate::vm::ExecutionResult { let this = VmGlobals::extract_arg(frame, |x| x.as_float().cloned())?; let format_opt = if !frame.stack.is_empty() { Some(VmGlobals::extract_arg(frame, |x| x.as_string().cloned())?) } else { None }; let result = if let Some(format_str) = format_opt { let format = format_str.raw_value(); if format == ".E" || format == ".e" { format!("{:e}", this.raw_value()) } else if format.starts_with('.') && format.len() > 1 { if let Ok(precision) = format[1..].parse::() { format!("{:.precision$}", this.raw_value(), precision = precision) } else { this.raw_value().to_string() } } else { this.raw_value().to_string() } } else { this.raw_value().to_string() }; frame.stack.push(RuntimeValue::String(result.into())); Ok(RunloopExit::Ok(())) } fn attrib_byte(&self) -> u8 { FUNC_IS_METHOD } fn arity(&self) -> crate::arity::Arity { crate::arity::Arity { required: 1, optional: 1, } } fn name(&self) -> &str { "prettyprint" } } pub(super) fn insert_float_builtins(builtins: &mut VmGlobals) { let fp_builtin = RustNativeType::new(crate::runtime_value::rust_native_type::RustNativeValueKind::Float); fp_builtin.insert_builtin::(builtins); fp_builtin.insert_builtin::(builtins); fp_builtin.insert_builtin::(builtins); fp_builtin.insert_builtin::(builtins); fp_builtin.insert_builtin::(builtins); let inf_sym = builtins .intern_symbol("inf") .expect("too many symbols interned"); let nan_sym = builtins .intern_symbol("nan") .expect("too many symbols interned"); let epsilon_sym = builtins .intern_symbol("epsilon") .expect("too many symbols interned"); fp_builtin.write(builtins, inf_sym, RuntimeValue::Float(f64::INFINITY.into())); fp_builtin.write(builtins, nan_sym, RuntimeValue::Float(f64::NAN.into())); fp_builtin.write( builtins, epsilon_sym, RuntimeValue::Float(f64::EPSILON.into()), ); builtins.register_builtin_type( haxby_opcodes::BuiltinTypeId::Float, RuntimeValueType::RustNative(fp_builtin), ); } ================================================ FILE: vm-lib/src/builtins/getenv.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use crate::{ builtins::VmGlobals, frame::Frame, runtime_value::{RuntimeValue, function::BuiltinFunctionImpl}, vm::RunloopExit, }; #[derive(Default)] struct Getenv {} impl BuiltinFunctionImpl for Getenv { fn eval( &self, frame: &mut Frame, vm: &mut crate::vm::VirtualMachine, ) -> crate::vm::ExecutionResult { let var_name = VmGlobals::extract_arg(frame, |x| x.as_string().cloned())?; match std::env::var(var_name.raw_value()).map(|s| RuntimeValue::String(s.into())) { Ok(s) => match vm.globals.create_maybe_some(s) { Ok(s) => { frame.stack.push(s); Ok(RunloopExit::Ok(())) } Err(e) => Err(e.into()), }, Err(_) => match vm.globals.create_maybe_none() { Ok(s) => { frame.stack.push(s); Ok(RunloopExit::Ok(())) } Err(e) => Err(e.into()), }, } } fn arity(&self) -> crate::arity::Arity { crate::arity::Arity::required(1) } fn name(&self) -> &str { "getenv" } } pub(super) fn insert_builtins(builtins: &mut VmGlobals) { builtins.insert_builtin::(); } ================================================ FILE: vm-lib/src/builtins/hasattr.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use crate::{ builtins::VmGlobals, frame::Frame, runtime_value::{RuntimeValue, function::BuiltinFunctionImpl}, vm::RunloopExit, }; #[derive(Default)] struct HasAttr {} impl BuiltinFunctionImpl for HasAttr { fn eval( &self, frame: &mut Frame, vm: &mut crate::vm::VirtualMachine, ) -> crate::vm::ExecutionResult { let the_value = frame.stack.pop(); let the_string = VmGlobals::extract_arg(frame, |x| x.as_string().cloned())?; if let Some(symbol) = vm.globals.lookup_symbol(the_string.raw_value()) { let has_attr = the_value.read_attribute(symbol, &vm.globals).is_ok(); frame.stack.push(RuntimeValue::Boolean(has_attr.into())); } else { frame.stack.push(RuntimeValue::Boolean(false.into())); } Ok(RunloopExit::Ok(())) } fn arity(&self) -> crate::arity::Arity { crate::arity::Arity::required(2) } fn name(&self) -> &str { "hasattr" } } pub(super) fn insert_builtins(builtins: &mut VmGlobals) { builtins.insert_builtin::(); } ================================================ FILE: vm-lib/src/builtins/integer.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use haxby_opcodes::function_attribs::FUNC_IS_METHOD; use crate::{ frame::Frame, runtime_value::{ RuntimeValue, function::BuiltinFunctionImpl, kind::RuntimeValueType, rust_native_type::RustNativeType, }, vm::RunloopExit, }; use super::VmGlobals; fn int_format(n: i64, fmt: &str) -> String { // Determine if format ends with 'x' or 'X' for hexadecimal formatting let (base, digits_spec) = if let Some(stripped) = fmt.strip_suffix('x') { (16, (stripped, false)) // lowercase hex } else if let Some(stripped) = fmt.strip_suffix('X') { (16, (stripped, true)) // uppercase hex } else { (10, (fmt, false)) // decimal }; // Parse width from digits (if any), default to 0 let width = digits_spec.0.parse::().unwrap_or(0); let uppercase = digits_spec.1; if base == 16 { // Format hex with padding and case if uppercase { format!("{n:0width$X}") } else { format!("{n:0width$x}") } } else { // Format decimal with padding format!("{n:0width$}") } } #[derive(Default)] struct Prettyprint {} impl BuiltinFunctionImpl for Prettyprint { fn eval( &self, frame: &mut Frame, _: &mut crate::vm::VirtualMachine, ) -> crate::vm::ExecutionResult { let this = VmGlobals::extract_arg(frame, |x| x.as_integer().cloned())?; let format_style = VmGlobals::extract_arg(frame, |x| x.as_string().cloned())?; let output_string = int_format(*this.raw_value(), format_style.raw_value()); frame.stack.push(RuntimeValue::String(output_string.into())); Ok(RunloopExit::Ok(())) } fn attrib_byte(&self) -> u8 { FUNC_IS_METHOD } fn arity(&self) -> crate::arity::Arity { crate::arity::Arity::required(2) } fn name(&self) -> &str { "prettyprint" } } pub(super) fn insert_integer_builtins(builtins: &mut VmGlobals) { let int_builtin = RustNativeType::new(crate::runtime_value::rust_native_type::RustNativeValueKind::Integer); int_builtin.insert_builtin::(builtins); builtins.register_builtin_type( haxby_opcodes::BuiltinTypeId::Int, RuntimeValueType::RustNative(int_builtin), ); } ================================================ FILE: vm-lib/src/builtins/list.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use haxby_opcodes::function_attribs::{FUNC_IS_METHOD, METHOD_ATTRIBUTE_TYPE}; use crate::{ error::vm_error::VmErrorReason, frame::Frame, runtime_value::{ RuntimeValue, function::BuiltinFunctionImpl, kind::RuntimeValueType, list::List, rust_native_type::RustNativeType, }, vm::RunloopExit, }; use super::VmGlobals; #[derive(Default)] struct ListLen {} impl BuiltinFunctionImpl for ListLen { fn eval( &self, frame: &mut Frame, _: &mut crate::vm::VirtualMachine, ) -> crate::vm::ExecutionResult { let this = VmGlobals::extract_arg(frame, |x| x.as_list().cloned())?; let len = this.len() as i64; frame.stack.push(RuntimeValue::Integer(len.into())); Ok(RunloopExit::Ok(())) } fn attrib_byte(&self) -> u8 { FUNC_IS_METHOD } fn arity(&self) -> crate::arity::Arity { crate::arity::Arity::required(1) } fn name(&self) -> &str { "len" } } #[derive(Default)] struct ListAppend {} impl BuiltinFunctionImpl for ListAppend { fn eval( &self, frame: &mut Frame, _: &mut crate::vm::VirtualMachine, ) -> crate::vm::ExecutionResult { let this = VmGlobals::extract_arg(frame, |x| x.as_list().cloned())?; let the_value = frame.stack.pop(); this.append(the_value); frame.stack.push(RuntimeValue::List(this)); Ok(RunloopExit::Ok(())) } fn attrib_byte(&self) -> u8 { FUNC_IS_METHOD } fn arity(&self) -> crate::arity::Arity { crate::arity::Arity::required(2) } fn name(&self) -> &str { "append" } } #[derive(Default)] struct Drop {} impl BuiltinFunctionImpl for Drop { fn eval( &self, frame: &mut Frame, _: &mut crate::vm::VirtualMachine, ) -> crate::vm::ExecutionResult { let this = VmGlobals::extract_arg(frame, |x| x.as_list().cloned())?; if this.is_empty() { Err(VmErrorReason::IndexOutOfBounds(0).into()) } else { let the_value = this.get_at(this.len() - 1).unwrap(); this.pop(); frame.stack.push(the_value); Ok(RunloopExit::Ok(())) } } fn attrib_byte(&self) -> u8 { FUNC_IS_METHOD } fn arity(&self) -> crate::arity::Arity { crate::arity::Arity::required(1) } fn name(&self) -> &str { "drop" } } #[derive(Default)] struct GetAt {} impl BuiltinFunctionImpl for GetAt { fn eval( &self, frame: &mut Frame, _: &mut crate::vm::VirtualMachine, ) -> crate::vm::ExecutionResult { let this = VmGlobals::extract_arg(frame, |x| x.as_list().cloned())?; let index = VmGlobals::extract_arg(frame, |x| x.as_integer().cloned())?; let index = *index.raw_value() as usize; match this.get_at(index) { Some(v) => { frame.stack.push(v); Ok(RunloopExit::Ok(())) } None => Err(VmErrorReason::IndexOutOfBounds(index).into()), } } fn attrib_byte(&self) -> u8 { FUNC_IS_METHOD } fn arity(&self) -> crate::arity::Arity { crate::arity::Arity::required(2) } fn name(&self) -> &str { "_get_at" } } #[derive(Default)] struct OpReadIndex {} impl BuiltinFunctionImpl for OpReadIndex { fn eval( &self, frame: &mut Frame, _: &mut crate::vm::VirtualMachine, ) -> crate::vm::ExecutionResult { let this = VmGlobals::extract_arg(frame, |x| x.as_list().cloned())?; let index = *VmGlobals::extract_arg(frame, |x| x.as_integer().cloned())?.raw_value(); let index = if index < 0 { index + this.len() as i64 } else { index } as usize; match this.get_at(index) { Some(v) => { frame.stack.push(v); Ok(RunloopExit::Ok(())) } None => Err(VmErrorReason::IndexOutOfBounds(index).into()), } } fn attrib_byte(&self) -> u8 { FUNC_IS_METHOD } fn arity(&self) -> crate::arity::Arity { crate::arity::Arity::required(2) } fn name(&self) -> &str { "_op_impl_read_index" } } #[derive(Default)] struct SetAt {} impl BuiltinFunctionImpl for SetAt { fn eval( &self, frame: &mut Frame, vm: &mut crate::vm::VirtualMachine, ) -> crate::vm::ExecutionResult { let this = VmGlobals::extract_arg(frame, |x| x.as_list().cloned())?; let index = VmGlobals::extract_arg(frame, |x| x.as_integer().cloned())?; let index = *index.raw_value() as usize; let value = frame.stack.pop(); match this.set_at(index, value) { Ok(_) => { frame.stack.push(vm.globals.create_unit_object()?); Ok(RunloopExit::Ok(())) } Err(e) => Err(e.into()), } } fn attrib_byte(&self) -> u8 { FUNC_IS_METHOD } fn arity(&self) -> crate::arity::Arity { crate::arity::Arity::required(3) } fn name(&self) -> &str { "_set_at" } } #[derive(Default)] struct OpWriteIndex {} impl BuiltinFunctionImpl for OpWriteIndex { fn eval( &self, frame: &mut Frame, vm: &mut crate::vm::VirtualMachine, ) -> crate::vm::ExecutionResult { let this = VmGlobals::extract_arg(frame, |x| x.as_list().cloned())?; let index = *VmGlobals::extract_arg(frame, |x| x.as_integer().cloned())?.raw_value(); let index = if index < 0 { index + this.len() as i64 } else { index } as usize; let value = frame.stack.pop(); match this.set_at(index, value) { Ok(_) => { frame.stack.push(vm.globals.create_unit_object()?); Ok(RunloopExit::Ok(())) } Err(e) => Err(e.into()), } } fn attrib_byte(&self) -> u8 { FUNC_IS_METHOD } fn arity(&self) -> crate::arity::Arity { crate::arity::Arity::required(3) } fn name(&self) -> &str { "_op_impl_write_index" } } #[derive(Default)] struct NewWithCapacity {} impl BuiltinFunctionImpl for NewWithCapacity { fn eval( &self, frame: &mut Frame, _: &mut crate::vm::VirtualMachine, ) -> crate::vm::ExecutionResult { let _ = frame.stack.pop(); // ignore List type, we know who we are let capacity = *VmGlobals::extract_arg(frame, |x| x.as_integer().cloned())?.raw_value(); let capacity = if capacity < 0 { 0 } else { capacity } as usize; let list = List::new_with_capacity(capacity); frame.stack.push(RuntimeValue::List(list)); Ok(RunloopExit::Ok(())) } fn attrib_byte(&self) -> u8 { FUNC_IS_METHOD | METHOD_ATTRIBUTE_TYPE } fn arity(&self) -> crate::arity::Arity { crate::arity::Arity::required(2) } fn name(&self) -> &str { "new_with_capacity" } } pub(super) fn insert_list_builtins(builtins: &mut VmGlobals) { let list_builtin = RustNativeType::new(crate::runtime_value::rust_native_type::RustNativeValueKind::List); list_builtin.insert_builtin::(builtins); list_builtin.insert_builtin::(builtins); list_builtin.insert_builtin::(builtins); list_builtin.insert_builtin::(builtins); list_builtin.insert_builtin::(builtins); list_builtin.insert_builtin::(builtins); list_builtin.insert_builtin::(builtins); list_builtin.insert_builtin::(builtins); builtins.register_builtin_type( haxby_opcodes::BuiltinTypeId::List, RuntimeValueType::RustNative(list_builtin), ); } ================================================ FILE: vm-lib/src/builtins/listattrs.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use crate::{ builtins::VmGlobals, frame::Frame, runtime_value::{RuntimeValue, function::BuiltinFunctionImpl, list::List}, vm::RunloopExit, }; #[derive(Default)] struct ListAttrs {} impl BuiltinFunctionImpl for ListAttrs { fn eval( &self, frame: &mut Frame, vm: &mut crate::vm::VirtualMachine, ) -> crate::vm::ExecutionResult { let the_value = frame.stack.pop(); let attrs = the_value.list_attributes(&vm.globals); frame.stack.push(RuntimeValue::List(List::from( &attrs .iter() .map(|x| RuntimeValue::String(x.clone().into())) .collect::>(), ))); Ok(RunloopExit::Ok(())) } fn arity(&self) -> crate::arity::Arity { crate::arity::Arity::required(1) } fn name(&self) -> &str { "listattrs" } } pub(super) fn insert_builtins(builtins: &mut VmGlobals) { builtins.insert_builtin::(); } ================================================ FILE: vm-lib/src/builtins/maybe.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use crate::runtime_value::{ enumeration::{Enum, EnumCase}, isa::IsaCheckable, kind::RuntimeValueType, }; use super::VmGlobals; pub(super) fn insert_maybe_builtins(builtins: &mut VmGlobals) { let some_sym = builtins .intern_symbol("Some") .expect("too many symbols interned"); let none_sym = builtins .intern_symbol("None") .expect("too many symbols interned"); let maybe_enum = Enum::new_with_cases( "Maybe", &[ EnumCase { name: some_sym, payload_type: Some(IsaCheckable::any()), }, EnumCase { name: none_sym, payload_type: None, }, ], builtins, ); builtins.register_builtin_type( haxby_opcodes::BuiltinTypeId::Maybe, RuntimeValueType::Enum(maybe_enum), ); } ================================================ FILE: vm-lib/src/builtins/mod.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use std::rc::Rc; use haxby_opcodes::BuiltinTypeId; use crate::{ error::vm_error::VmErrorReason, frame::Frame, runtime_value::{ RuntimeValue, function::{BuiltinFunctionImpl, Function}, kind::RuntimeValueType, object::ObjectBox, }, shape::Shapes, symbol::Interner, }; mod alloc; mod arity; mod boolean; mod cmdline_args; mod exit; mod float; mod getenv; mod hasattr; mod integer; mod list; mod listattrs; mod maybe; pub mod native_iterator; mod now; mod prettyprint; mod print; mod println; mod readattr; mod readln; mod result; pub(crate) mod runtime_error; mod setenv; mod sleep; mod string; mod system; mod typ; mod typeof_builtin; mod unimplemented; mod unit; mod writeattr; #[derive(Default)] pub struct AriaBuiltinTypes { types: Vec, } impl AriaBuiltinTypes { #[inline(always)] pub fn register_builtin_type(&mut self, bt: RuntimeValueType) -> BuiltinTypeId { self.types.push(bt); let ty_id = u8::try_from(self.types.len() - 1).expect("too many builtin types registered"); BuiltinTypeId::try_from(ty_id).expect("invalid builtin type id") } #[inline(always)] pub fn get_builtin_type(&self, id: BuiltinTypeId) -> RuntimeValueType { self.types .get(id as usize) .expect("invalid builtin type id") .clone() } } pub struct VmGlobals { values: Rc, builtin_types: AriaBuiltinTypes, interner: Interner, pub(crate) shapes: Shapes, } impl VmGlobals { pub fn insert_builtin(&mut self) where T: 'static + Default + BuiltinFunctionImpl, { let t = T::default(); let name = t.name().to_owned(); self.insert(&name, RuntimeValue::Function(Function::builtin_from(t))); } pub fn extract_arg(frame: &mut Frame, f: T) -> crate::vm::ExecutionResult where T: FnOnce(RuntimeValue) -> Option, { let val = match frame.stack.try_pop() { Some(v) => v, None => { return Err(VmErrorReason::EmptyStack.into()); } }; match f(val) { Some(v) => Ok(v), None => Err(VmErrorReason::UnexpectedType.into()), } } pub fn register_builtin_type(&mut self, id: BuiltinTypeId, ty: RuntimeValueType) { let name = id.name(); let registered_id = self.builtin_types.register_builtin_type(ty.clone()); assert!( id == registered_id, "Mismatched builtin type registration: expected {} [{}], got {} [{}]", id.to_u8(), id.name(), registered_id.to_u8(), registered_id.name() ); // catch mismatched registrations early self.insert(name, RuntimeValue::Type(ty)); } } impl Default for VmGlobals { fn default() -> Self { let mut this = Self { values: Default::default(), builtin_types: Default::default(), interner: Default::default(), shapes: Default::default(), }; this.register_builtin_type(BuiltinTypeId::Any, RuntimeValueType::Any); // Most anything needs Any this.register_builtin_type(BuiltinTypeId::Module, RuntimeValueType::Module); unit::insert_unit_builtins(&mut this); unimplemented::insert_unimplemented_builtins(&mut this); maybe::insert_maybe_builtins(&mut this); result::insert_result_builtins(&mut this); integer::insert_integer_builtins(&mut this); // RuntimeError needs Integer string::insert_string_builtins(&mut this); // and String runtime_error::insert_runtime_error_builtins(&mut this); // from here on out, any order is fine alloc::insert_builtins(&mut this); arity::insert_builtins(&mut this); boolean::insert_boolean_builtins(&mut this); cmdline_args::insert_builtins(&mut this); exit::insert_builtins(&mut this); float::insert_float_builtins(&mut this); getenv::insert_builtins(&mut this); hasattr::insert_builtins(&mut this); list::insert_list_builtins(&mut this); listattrs::insert_builtins(&mut this); now::insert_builtins(&mut this); prettyprint::insert_builtins(&mut this); print::insert_builtins(&mut this); println::insert_builtins(&mut this); readattr::insert_builtins(&mut this); readln::insert_builtins(&mut this); setenv::insert_builtins(&mut this); sleep::insert_builtins(&mut this); system::insert_builtins(&mut this); typ::insert_type_builtins(&mut this); typeof_builtin::insert_builtins(&mut this); writeattr::insert_builtins(&mut this); this } } impl VmGlobals { pub fn intern_symbol(&mut self, s: &str) -> Result { self.interner.intern(s).map_err(|e| match e { crate::symbol::InternError::TooManySymbols => VmErrorReason::TooManyInternedSymbols, }) } pub fn lookup_symbol(&self, s: &str) -> Option { self.interner.lookup(s) } pub fn resolve_symbol(&self, sym: crate::symbol::Symbol) -> Option<&str> { self.interner.resolve(sym) } pub fn load_named_value(&self, name: &str) -> Option { let sym = self.lookup_symbol(name)?; self.values.read(self, sym) } pub fn insert(&mut self, name: &str, val: RuntimeValue) { let sym = self.intern_symbol(name).expect("too many symbols interned"); let values = Rc::clone(&self.values); if values.contains(self, sym) { panic!("duplicate builtin {name}"); } values.write(self, sym, val); } #[deprecated(note = "use get_builtin_type_by_id instead")] pub fn get_builtin_type_by_name(&self, name: &str) -> Option { if let Some(bv) = self.load_named_value(name) { bv.as_type().cloned() } else { None } } pub fn get_builtin_type_by_id(&self, bt_id: BuiltinTypeId) -> RuntimeValueType { self.builtin_types.get_builtin_type(bt_id) } } impl VmGlobals { pub fn create_maybe_some(&self, x: RuntimeValue) -> Result { let rt_maybe = self.get_builtin_type_by_id(BuiltinTypeId::Maybe); let rt_maybe_enum = rt_maybe.as_enum().ok_or(VmErrorReason::UnexpectedType)?; let some_idx: usize = 0usize; let rv = rt_maybe_enum .make_value(some_idx, Some(x)) .ok_or(VmErrorReason::UnexpectedVmState)?; Ok(RuntimeValue::EnumValue(rv)) } pub fn create_result_ok(&self, x: RuntimeValue) -> Result { let rt_result = self.get_builtin_type_by_id(BuiltinTypeId::Result); let rt_result_enum = rt_result.as_enum().ok_or(VmErrorReason::UnexpectedType)?; let ok_idx = 0usize; let rv = rt_result_enum .make_value(ok_idx, Some(x)) .ok_or(VmErrorReason::UnexpectedVmState)?; Ok(RuntimeValue::EnumValue(rv)) } pub fn create_maybe_none(&self) -> Result { let rt_maybe = self.get_builtin_type_by_id(BuiltinTypeId::Maybe); let rt_maybe_enum = rt_maybe.as_enum().ok_or(VmErrorReason::UnexpectedType)?; let none_idx = 1usize; let rv = rt_maybe_enum .make_value(none_idx, None) .ok_or(VmErrorReason::UnexpectedVmState)?; Ok(RuntimeValue::EnumValue(rv)) } pub fn create_result_err(&self, x: RuntimeValue) -> Result { let rt_result = self.get_builtin_type_by_id(BuiltinTypeId::Result); let rt_result_enum = rt_result.as_enum().ok_or(VmErrorReason::UnexpectedType)?; let err_idx = 1usize; let rv = rt_result_enum .make_value(err_idx, Some(x)) .ok_or(VmErrorReason::UnexpectedVmState)?; Ok(RuntimeValue::EnumValue(rv)) } pub fn create_unit_object(&self) -> Result { let rt_unit = self.get_builtin_type_by_id(BuiltinTypeId::Unit); let rt_unit_enum = rt_unit.as_enum().ok_or(VmErrorReason::UnexpectedType)?; let unit_idx = 0usize; let rv = rt_unit_enum .make_value(unit_idx, None) .ok_or(VmErrorReason::UnexpectedVmState)?; Ok(RuntimeValue::EnumValue(rv)) } } ================================================ FILE: vm-lib/src/builtins/native_iterator.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use std::{cell::RefCell, rc::Rc}; use haxby_opcodes::function_attribs::FUNC_IS_METHOD; use crate::{ arity::Arity, builtins::VmGlobals, error::vm_error::VmErrorReason, frame::Frame, runtime_value::{ RuntimeValue, function::{BuiltinFunctionImpl, Function}, object::Object, opaque::OpaqueValue, structure::Struct, }, symbol::{INTERNED_ATTR_IMPL, INTERNED_ATTR_NEXT}, vm::RunloopExit, }; pub trait AriaNativeIterator { type Item; fn next(&mut self, _: &mut crate::vm::VirtualMachine) -> Option { None } } struct EmptyIterator {} impl AriaNativeIterator for EmptyIterator { type Item = RuntimeValue; } pub struct NativeIteratorImpl { iter: Rc>>, } impl NativeIteratorImpl { pub fn new(iter: T) -> Self where T: AriaNativeIterator + 'static, { Self { iter: Rc::new(RefCell::new(iter)), } } pub fn empty() -> Self { Self::new(EmptyIterator {}) } } impl AriaNativeIterator for NativeIteratorImpl { type Item = RuntimeValue; fn next(&mut self, vm: &mut crate::vm::VirtualMachine) -> Option { self.iter.borrow_mut().next(vm) } } #[derive(Default)] struct Next {} impl BuiltinFunctionImpl for Next { fn eval( &self, frame: &mut Frame, vm: &mut crate::vm::VirtualMachine, ) -> crate::vm::ExecutionResult { let aria_this = VmGlobals::extract_arg(frame, |x: RuntimeValue| x.as_object().cloned())?; let impl_sym = INTERNED_ATTR_IMPL; let iterator_impl = aria_this .read(&vm.globals, impl_sym) .ok_or(VmErrorReason::UnexpectedVmState)?; let rust_native_iter = iterator_impl .as_opaque_concrete::>() .ok_or(VmErrorReason::UnexpectedVmState)?; if let Some(next) = rust_native_iter.borrow_mut().next(vm) { frame.stack.push(vm.globals.create_maybe_some(next)?); } else { frame.stack.push(vm.globals.create_maybe_none()?); } Ok(RunloopExit::Ok(())) } fn attrib_byte(&self) -> u8 { FUNC_IS_METHOD } fn arity(&self) -> Arity { Arity::required(1) } fn name(&self) -> &str { "next" } } pub fn create_iterator_struct( iter_struct: &Struct, imp: NativeIteratorImpl, builtins: &mut VmGlobals, ) -> RuntimeValue { let obj = RuntimeValue::Object(Object::new(iter_struct)); let impl_attrib = OpaqueValue::new(RefCell::new(imp)); obj.write_attribute( INTERNED_ATTR_IMPL, RuntimeValue::Opaque(impl_attrib), builtins, ) .expect("failed to write iterator impl"); let next = Function::new_builtin::(); let bound_next = obj.bind(next); obj.write_attribute(INTERNED_ATTR_NEXT, bound_next, builtins) .expect("failed to write iterator next"); obj } ================================================ FILE: vm-lib/src/builtins/now.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use crate::{ builtins::VmGlobals, frame::Frame, runtime_value::{RuntimeValue, function::BuiltinFunctionImpl}, vm::RunloopExit, }; #[derive(Default)] struct Now {} impl BuiltinFunctionImpl for Now { fn eval( &self, cur_frame: &mut Frame, _: &mut crate::vm::VirtualMachine, ) -> crate::vm::ExecutionResult { let now = std::time::SystemTime::now() .duration_since(std::time::UNIX_EPOCH) .expect("before the epoch") .as_millis() as i64; cur_frame.stack.push(RuntimeValue::Integer(now.into())); Ok(RunloopExit::Ok(())) } fn arity(&self) -> crate::arity::Arity { crate::arity::Arity::zero() } fn name(&self) -> &str { "now" } } pub(super) fn insert_builtins(builtins: &mut VmGlobals) { builtins.insert_builtin::(); } ================================================ FILE: vm-lib/src/builtins/prettyprint.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use crate::{ builtins::VmGlobals, frame::Frame, runtime_value::{RuntimeValue, function::BuiltinFunctionImpl}, vm::RunloopExit, }; #[derive(Default)] struct Prettyprint {} impl BuiltinFunctionImpl for Prettyprint { fn eval( &self, cur_frame: &mut Frame, vm: &mut crate::vm::VirtualMachine, ) -> crate::vm::ExecutionResult { let the_value = cur_frame.stack.pop(); let pp = the_value.prettyprint(cur_frame, vm); cur_frame.stack.push(RuntimeValue::String(pp.into())); Ok(RunloopExit::Ok(())) } fn arity(&self) -> crate::arity::Arity { crate::arity::Arity::required(1) } fn name(&self) -> &str { "prettyprint" } } pub(super) fn insert_builtins(builtins: &mut VmGlobals) { builtins.insert_builtin::(); } ================================================ FILE: vm-lib/src/builtins/print.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use crate::{ builtins::VmGlobals, frame::Frame, runtime_value::function::BuiltinFunctionImpl, vm::RunloopExit, }; #[derive(Default)] struct Print {} impl BuiltinFunctionImpl for Print { fn eval( &self, cur_frame: &mut Frame, vm: &mut crate::vm::VirtualMachine, ) -> crate::vm::ExecutionResult { let the_value = cur_frame.stack.pop(); let fmt = the_value.prettyprint(cur_frame, vm); let mut console = vm.console().borrow_mut(); assert!(console.print(&fmt).is_ok()); cur_frame.stack.push(vm.globals.create_unit_object()?); Ok(RunloopExit::Ok(())) } fn arity(&self) -> crate::arity::Arity { crate::arity::Arity::required(1) } fn name(&self) -> &str { "print" } } pub(super) fn insert_builtins(builtins: &mut VmGlobals) { builtins.insert_builtin::(); } ================================================ FILE: vm-lib/src/builtins/println.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use crate::{ builtins::VmGlobals, frame::Frame, runtime_value::function::BuiltinFunctionImpl, vm::RunloopExit, }; #[derive(Default)] struct Println {} impl BuiltinFunctionImpl for Println { fn eval( &self, cur_frame: &mut Frame, vm: &mut crate::vm::VirtualMachine, ) -> crate::vm::ExecutionResult { if let Some(the_value) = cur_frame.stack.try_pop() { let fmt = the_value.prettyprint(cur_frame, vm); assert!(vm.console().borrow_mut().println(&fmt).is_ok()); } else { assert!(vm.console().borrow_mut().println("").is_ok()); } cur_frame.stack.push(vm.globals.create_unit_object()?); Ok(RunloopExit::Ok(())) } fn arity(&self) -> crate::arity::Arity { crate::arity::Arity { required: 0, optional: 1, } } fn name(&self) -> &str { "println" } } pub(super) fn insert_builtins(builtins: &mut VmGlobals) { builtins.insert_builtin::(); } ================================================ FILE: vm-lib/src/builtins/readattr.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use crate::{ builtins::VmGlobals, error::vm_error::VmErrorReason, frame::Frame, runtime_value::function::BuiltinFunctionImpl, vm::RunloopExit, }; #[derive(Default)] struct ReadAttr {} impl BuiltinFunctionImpl for ReadAttr { fn eval( &self, frame: &mut Frame, vm: &mut crate::vm::VirtualMachine, ) -> crate::vm::ExecutionResult { let the_value = frame.stack.pop(); let the_string = VmGlobals::extract_arg(frame, |x| x.as_string().cloned())?; if let Some(symbol) = vm.globals.lookup_symbol(the_string.raw_value()) && let Ok(the_attr) = the_value.read_attribute(symbol, &vm.globals) { frame.stack.push(the_attr); Ok(RunloopExit::Ok(())) } else { Err(VmErrorReason::NoSuchIdentifier(the_string.raw_value().to_owned()).into()) } } fn arity(&self) -> crate::arity::Arity { crate::arity::Arity::required(2) } fn name(&self) -> &str { "readattr" } } pub(super) fn insert_builtins(builtins: &mut VmGlobals) { builtins.insert_builtin::(); } ================================================ FILE: vm-lib/src/builtins/readln.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use std::io::Write; use crate::{ builtins::VmGlobals, error::vm_error::VmErrorReason, frame::Frame, runtime_value::{RuntimeValue, function::BuiltinFunctionImpl}, vm::RunloopExit, }; #[derive(Default)] struct Readln {} impl BuiltinFunctionImpl for Readln { fn eval( &self, cur_frame: &mut Frame, vm: &mut crate::vm::VirtualMachine, ) -> crate::vm::ExecutionResult { let the_value = cur_frame.stack.pop(); let the_value = the_value.prettyprint(cur_frame, vm); let _ = std::io::stdout().write(the_value.as_bytes()); let _ = std::io::stdout().flush(); let mut input = String::new(); let result = std::io::stdin().read_line(&mut input); match result { Ok(_) => { let input = input.trim(); cur_frame.stack.push(RuntimeValue::String(input.into())); Ok(RunloopExit::Ok(())) } Err(e) => Err(VmErrorReason::OperationFailed(e.to_string()).into()), } } fn arity(&self) -> crate::arity::Arity { crate::arity::Arity::required(1) } fn name(&self) -> &str { "readln" } } pub(super) fn insert_builtins(builtins: &mut VmGlobals) { builtins.insert_builtin::(); } ================================================ FILE: vm-lib/src/builtins/result.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use crate::runtime_value::{ enumeration::{Enum, EnumCase}, isa::IsaCheckable, kind::RuntimeValueType, }; use super::VmGlobals; pub(super) fn insert_result_builtins(builtins: &mut VmGlobals) { let ok_sym = builtins .intern_symbol("Ok") .expect("too many symbols interned"); let err_sym = builtins .intern_symbol("Err") .expect("too many symbols interned"); let result_enum = Enum::new_with_cases( "Result", &[ EnumCase { name: ok_sym, payload_type: Some(IsaCheckable::any()), }, EnumCase { name: err_sym, payload_type: Some(IsaCheckable::any()), }, ], builtins, ); builtins.register_builtin_type( haxby_opcodes::BuiltinTypeId::Result, RuntimeValueType::Enum(result_enum), ); } ================================================ FILE: vm-lib/src/builtins/runtime_error.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use haxby_opcodes::BuiltinTypeId; use crate::{ runtime_value::{ RuntimeValue, enumeration::{Enum, EnumCase}, isa::IsaCheckable, kind::RuntimeValueType, structure::Struct, }, symbol::INTERNED_ATTR_ARGC_MISMATCH, }; use super::VmGlobals; pub const RUNTIME_ERR_CASE_DIVISION_BY_ZERO_IDX: usize = 0; pub const RUNTIME_ERR_CASE_ENUM_WITHOUT_PAYLOAD_IDX: usize = 1; pub const RUNTIME_ERR_CASE_INDEX_OUT_OF_BOUNDS_IDX: usize = 2; pub const RUNTIME_ERR_CASE_MISMATCHED_ARGC_IDX: usize = 3; pub const RUNTIME_ERR_CASE_NO_SUCH_CASE_IDX: usize = 4; pub const RUNTIME_ERR_CASE_NO_SUCH_IDENTIFIER_IDX: usize = 5; pub const RUNTIME_ERR_CASE_OPERATION_FAILED_IDX: usize = 6; pub const RUNTIME_ERR_CASE_UNEXPECTED_TYPE_IDX: usize = 7; pub(super) fn insert_runtime_error_builtins(builtins: &mut VmGlobals) { let argc_mismatch = Struct::new("ArgcMismatch"); let int = builtins.get_builtin_type_by_id(BuiltinTypeId::Int); let str = builtins.get_builtin_type_by_id(BuiltinTypeId::String); let division_by_zero_sym = builtins .intern_symbol("DivisionByZero") .expect("too many symbols interned"); let enum_without_payload_sym = builtins .intern_symbol("EnumWithoutPayload") .expect("too many symbols interned"); let index_out_of_bounds_sym = builtins .intern_symbol("IndexOutOfBounds") .expect("too many symbols interned"); let mismatched_argc_sym = builtins .intern_symbol("MismatchedArgumentCount") .expect("too many symbols interned"); let no_such_case_sym = builtins .intern_symbol("NoSuchCase") .expect("too many symbols interned"); let no_such_identifier_sym = builtins .intern_symbol("NoSuchIdentifier") .expect("too many symbols interned"); let operation_failed_sym = builtins .intern_symbol("OperationFailed") .expect("too many symbols interned"); let unexpected_type_sym = builtins .intern_symbol("UnexpectedType") .expect("too many symbols interned"); let rt_err_enum = RuntimeValue::Type(RuntimeValueType::Enum(Enum::new_with_cases( "RuntimeError", &[ EnumCase { name: division_by_zero_sym, payload_type: None, }, EnumCase { name: enum_without_payload_sym, payload_type: None, }, EnumCase { name: index_out_of_bounds_sym, payload_type: Some(IsaCheckable::Type(int.clone())), }, EnumCase { name: mismatched_argc_sym, payload_type: Some(IsaCheckable::Type(RuntimeValueType::Struct( argc_mismatch.clone(), ))), }, EnumCase { name: no_such_case_sym, payload_type: Some(IsaCheckable::Type(str.clone())), }, EnumCase { name: no_such_identifier_sym, payload_type: Some(IsaCheckable::Type(str.clone())), }, EnumCase { name: operation_failed_sym, payload_type: Some(IsaCheckable::Type(str.clone())), }, EnumCase { name: unexpected_type_sym, payload_type: None, }, ], builtins, ))); let _ = rt_err_enum.write_attribute( INTERNED_ATTR_ARGC_MISMATCH, RuntimeValue::Type(RuntimeValueType::Struct(argc_mismatch)), builtins, ); builtins.register_builtin_type( haxby_opcodes::BuiltinTypeId::RuntimeError, rt_err_enum .as_type() .expect("RuntimeError is a type") .clone(), ); } ================================================ FILE: vm-lib/src/builtins/setenv.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use crate::{ builtins::VmGlobals, error::vm_error::VmErrorReason, frame::Frame, runtime_value::function::BuiltinFunctionImpl, vm::RunloopExit, }; #[derive(Default)] struct Setenv {} impl BuiltinFunctionImpl for Setenv { fn eval( &self, frame: &mut Frame, vm: &mut crate::vm::VirtualMachine, ) -> crate::vm::ExecutionResult { let var_name = VmGlobals::extract_arg(frame, |x| x.as_string().cloned())?; let var_value = VmGlobals::extract_arg(frame, |x| x.as_string().cloned())?; if var_name.is_empty() || var_value.is_empty() { return Err(VmErrorReason::OperationFailed("empty key or value".into()).into()); } if var_name.contains("=") || var_value.contains("=") { return Err(VmErrorReason::OperationFailed( "key or value contains invalid character '='".into(), ) .into()); } unsafe { std::env::set_var(var_name.raw_value(), var_value.raw_value()); } frame.stack.push(vm.globals.create_unit_object()?); Ok(RunloopExit::Ok(())) } fn arity(&self) -> crate::arity::Arity { crate::arity::Arity::required(2) } fn name(&self) -> &str { "setenv" } } pub(super) fn insert_builtins(builtins: &mut VmGlobals) { builtins.insert_builtin::(); } ================================================ FILE: vm-lib/src/builtins/sleep.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use std::time::Duration; use super::VmGlobals; use crate::{ error::vm_error::VmErrorReason, frame::Frame, runtime_value::function::BuiltinFunctionImpl, vm::RunloopExit, }; #[derive(Default)] struct Sleep {} impl BuiltinFunctionImpl for Sleep { fn eval( &self, cur_frame: &mut Frame, vm: &mut crate::vm::VirtualMachine, ) -> crate::vm::ExecutionResult { let duration = *VmGlobals::extract_arg(cur_frame, |x| x.as_integer().cloned())?.raw_value(); if duration >= 0 { std::thread::sleep(Duration::from_millis(duration as u64)); } else { return Err( VmErrorReason::OperationFailed("cannot sleep < 0 milliseconds".to_owned()).into(), ); } cur_frame.stack.push(vm.globals.create_unit_object()?); Ok(RunloopExit::Ok(())) } fn arity(&self) -> crate::arity::Arity { crate::arity::Arity::required(1) } fn name(&self) -> &str { "sleep_ms" } } pub(super) fn insert_builtins(builtins: &mut VmGlobals) { builtins.insert_builtin::(); } ================================================ FILE: vm-lib/src/builtins/string.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use haxby_opcodes::function_attribs::{FUNC_IS_METHOD, METHOD_ATTRIBUTE_TYPE}; use crate::{ error::vm_error::VmErrorReason, frame::Frame, runtime_value::{ RuntimeValue, function::BuiltinFunctionImpl, kind::RuntimeValueType, list::List, rust_native_type::RustNativeType, }, vm::RunloopExit, }; use super::VmGlobals; #[derive(Default)] struct StringLen {} impl BuiltinFunctionImpl for StringLen { fn eval( &self, frame: &mut Frame, _: &mut crate::vm::VirtualMachine, ) -> crate::vm::ExecutionResult { let the_value = frame.stack.pop(); if let Some(s) = the_value.as_string() { let len = s.len() as i64; frame.stack.push(RuntimeValue::Integer(len.into())); Ok(RunloopExit::Ok(())) } else { Err(VmErrorReason::UnexpectedType.into()) } } fn attrib_byte(&self) -> u8 { FUNC_IS_METHOD } fn arity(&self) -> crate::arity::Arity { crate::arity::Arity::required(1) } fn name(&self) -> &str { "len" } } #[derive(Default)] struct StringHasPrefix {} impl BuiltinFunctionImpl for StringHasPrefix { fn eval( &self, frame: &mut Frame, _: &mut crate::vm::VirtualMachine, ) -> crate::vm::ExecutionResult { let this = match frame.stack.pop_if(|x| RuntimeValue::as_string(&x).cloned()) { Some(x) => x, None => { return Err(VmErrorReason::UnexpectedType.into()); } }; let prefix = match frame.stack.pop_if(|x| RuntimeValue::as_string(&x).cloned()) { Some(x) => x, None => { return Err(VmErrorReason::UnexpectedType.into()); } }; let result = this.raw_value().starts_with(prefix.raw_value()); frame.stack.push(RuntimeValue::Boolean(result.into())); Ok(RunloopExit::Ok(())) } fn attrib_byte(&self) -> u8 { FUNC_IS_METHOD } fn arity(&self) -> crate::arity::Arity { crate::arity::Arity::required(2) } fn name(&self) -> &str { "has_prefix" } } #[derive(Default)] struct StringHasSuffix {} impl BuiltinFunctionImpl for StringHasSuffix { fn eval( &self, frame: &mut Frame, _: &mut crate::vm::VirtualMachine, ) -> crate::vm::ExecutionResult { let this = match frame.stack.pop_if(|x| RuntimeValue::as_string(&x).cloned()) { Some(x) => x, None => { return Err(VmErrorReason::UnexpectedType.into()); } }; let suffix = match frame.stack.pop_if(|x| RuntimeValue::as_string(&x).cloned()) { Some(x) => x, None => { return Err(VmErrorReason::UnexpectedType.into()); } }; let result = this.raw_value().ends_with(suffix.raw_value()); frame.stack.push(RuntimeValue::Boolean(result.into())); Ok(RunloopExit::Ok(())) } fn attrib_byte(&self) -> u8 { FUNC_IS_METHOD } fn arity(&self) -> crate::arity::Arity { crate::arity::Arity::required(2) } fn name(&self) -> &str { "has_suffix" } } #[derive(Default)] struct StringReplace {} impl BuiltinFunctionImpl for StringReplace { fn eval( &self, frame: &mut Frame, _: &mut crate::vm::VirtualMachine, ) -> crate::vm::ExecutionResult { let this = match frame.stack.pop_if(|x| RuntimeValue::as_string(&x).cloned()) { Some(x) => x, None => { return Err(VmErrorReason::UnexpectedType.into()); } }; let current = match frame.stack.pop_if(|x| RuntimeValue::as_string(&x).cloned()) { Some(x) => x, None => { return Err(VmErrorReason::UnexpectedType.into()); } }; let wanted = match frame.stack.pop_if(|x| RuntimeValue::as_string(&x).cloned()) { Some(x) => x, None => { return Err(VmErrorReason::UnexpectedType.into()); } }; let result = this .raw_value() .replace(current.raw_value(), wanted.raw_value()); frame.stack.push(RuntimeValue::String(result.into())); Ok(RunloopExit::Ok(())) } fn attrib_byte(&self) -> u8 { FUNC_IS_METHOD } fn arity(&self) -> crate::arity::Arity { crate::arity::Arity::required(3) } fn name(&self) -> &str { "replace" } } #[derive(Default)] struct StringSplit {} impl BuiltinFunctionImpl for StringSplit { fn eval( &self, frame: &mut Frame, _: &mut crate::vm::VirtualMachine, ) -> crate::vm::ExecutionResult { let this = match frame.stack.pop_if(|x| RuntimeValue::as_string(&x).cloned()) { Some(x) => x, None => { return Err(VmErrorReason::UnexpectedType.into()); } }; let marker = match frame.stack.pop_if(|x| RuntimeValue::as_string(&x).cloned()) { Some(x) => x, None => { return Err(VmErrorReason::UnexpectedType.into()); } }; let result = this .raw_value() .split(marker.raw_value()) .map(|x| RuntimeValue::String(x.to_owned().into())) .collect::>(); frame.stack.push(RuntimeValue::List(List::from(&result))); Ok(RunloopExit::Ok(())) } fn attrib_byte(&self) -> u8 { FUNC_IS_METHOD } fn arity(&self) -> crate::arity::Arity { crate::arity::Arity::required(2) } fn name(&self) -> &str { "split" } } #[derive(Default)] struct StringChars {} impl BuiltinFunctionImpl for StringChars { fn eval( &self, frame: &mut Frame, _: &mut crate::vm::VirtualMachine, ) -> crate::vm::ExecutionResult { let this = match frame.stack.pop_if(|x| RuntimeValue::as_string(&x).cloned()) { Some(x) => x, None => { return Err(VmErrorReason::UnexpectedType.into()); } }; let ret = List::default(); this.raw_value() .chars() .map(|c| RuntimeValue::String(c.to_string().into())) .for_each(|rv| ret.append(rv)); frame.stack.push(RuntimeValue::List(ret)); Ok(RunloopExit::Ok(())) } fn attrib_byte(&self) -> u8 { FUNC_IS_METHOD } fn arity(&self) -> crate::arity::Arity { crate::arity::Arity::required(1) } fn name(&self) -> &str { "chars" } } #[derive(Default)] struct StringBytes {} impl BuiltinFunctionImpl for StringBytes { fn eval( &self, frame: &mut Frame, _: &mut crate::vm::VirtualMachine, ) -> crate::vm::ExecutionResult { let this = match frame.stack.pop_if(|x| RuntimeValue::as_string(&x).cloned()) { Some(x) => x, None => { return Err(VmErrorReason::UnexpectedType.into()); } }; let ret = List::default(); this.raw_value() .bytes() .map(|c| RuntimeValue::Integer((c as i64).into())) .for_each(|rv| ret.append(rv)); frame.stack.push(RuntimeValue::List(ret)); Ok(RunloopExit::Ok(())) } fn attrib_byte(&self) -> u8 { FUNC_IS_METHOD } fn arity(&self) -> crate::arity::Arity { crate::arity::Arity::required(1) } fn name(&self) -> &str { "bytes" } } #[derive(Default)] struct FromBytes {} impl BuiltinFunctionImpl for FromBytes { fn eval( &self, frame: &mut Frame, vm: &mut crate::vm::VirtualMachine, ) -> crate::vm::ExecutionResult { let this_str_type = match frame .stack .pop_if(|x| RuntimeValue::as_rust_native(&x).cloned()) { Some(x) => x, None => { return Err(VmErrorReason::UnexpectedType.into()); } }; let list = match frame.stack.pop_if(|x| RuntimeValue::as_list(&x).cloned()) { Some(x) => x, None => { return Err(VmErrorReason::UnexpectedType.into()); } }; let mut bytes = vec![]; for i in 0..list.len() { let item = list.get_at(i).expect("invalid list"); if let Some(byte) = item.as_integer() { bytes.push(*byte.raw_value() as u8); } else { return Err(VmErrorReason::UnexpectedType.into()); } } let dest = match String::from_utf8(bytes) { Ok(s) => s, Err(_) => { let msg_sym = vm .globals .intern_symbol("msg") .expect("too many symbols interned"); let encoding_err_sym = vm .globals .intern_symbol("EncodingError") .expect("too many symbols interned"); let encoding_err_rv = this_str_type .read(&vm.globals, encoding_err_sym) .ok_or_else(|| VmErrorReason::NoSuchIdentifier("EncodingError".to_owned()))?; let encoding_err_struct = encoding_err_rv .as_struct() .ok_or(VmErrorReason::UnexpectedVmState)?; return Ok(RunloopExit::throw_struct( encoding_err_struct, &[(msg_sym, RuntimeValue::String("invalid utf8".into()))], &mut vm.globals, )); } }; frame.stack.push(RuntimeValue::String(dest.into())); Ok(RunloopExit::Ok(())) } fn attrib_byte(&self) -> u8 { FUNC_IS_METHOD | METHOD_ATTRIBUTE_TYPE } fn arity(&self) -> crate::arity::Arity { crate::arity::Arity::required(2) } fn name(&self) -> &str { "new_with_bytes" } } #[derive(Default)] struct ToNumericEncoding {} impl BuiltinFunctionImpl for ToNumericEncoding { fn eval( &self, frame: &mut Frame, _: &mut crate::vm::VirtualMachine, ) -> crate::vm::ExecutionResult { let this = match frame.stack.pop_if(|x| RuntimeValue::as_string(&x).cloned()) { Some(x) => x, None => { return Err(VmErrorReason::UnexpectedType.into()); } }; if let Some(char) = this.raw_value().chars().next() { let char = char as i64; frame.stack.push(RuntimeValue::Integer(char.into())); Ok(RunloopExit::Ok(())) } else { Err(VmErrorReason::UnexpectedType.into()) } } fn attrib_byte(&self) -> u8 { FUNC_IS_METHOD } fn arity(&self) -> crate::arity::Arity { crate::arity::Arity::required(1) } fn name(&self) -> &str { "encoding" } } #[derive(Default)] struct TrimHead {} impl BuiltinFunctionImpl for TrimHead { fn eval( &self, frame: &mut Frame, _: &mut crate::vm::VirtualMachine, ) -> crate::vm::ExecutionResult { let this = match frame.stack.pop_if(|x| RuntimeValue::as_string(&x).cloned()) { Some(x) => x, None => { return Err(VmErrorReason::UnexpectedType.into()); } }; let result = this.raw_value().trim_start().to_string(); frame.stack.push(RuntimeValue::String(result.into())); Ok(RunloopExit::Ok(())) } fn attrib_byte(&self) -> u8 { FUNC_IS_METHOD } fn arity(&self) -> crate::arity::Arity { crate::arity::Arity::required(1) } fn name(&self) -> &str { "trim_head" } } #[derive(Default)] struct TrimTail {} impl BuiltinFunctionImpl for TrimTail { fn eval( &self, frame: &mut Frame, _: &mut crate::vm::VirtualMachine, ) -> crate::vm::ExecutionResult { let this = match frame.stack.pop_if(|x| RuntimeValue::as_string(&x).cloned()) { Some(x) => x, None => { return Err(VmErrorReason::UnexpectedType.into()); } }; let result = this.raw_value().trim_end().to_string(); frame.stack.push(RuntimeValue::String(result.into())); Ok(RunloopExit::Ok(())) } fn attrib_byte(&self) -> u8 { FUNC_IS_METHOD } fn arity(&self) -> crate::arity::Arity { crate::arity::Arity::required(1) } fn name(&self) -> &str { "trim_tail" } } #[derive(Default)] struct Uppercase {} impl BuiltinFunctionImpl for Uppercase { fn eval( &self, frame: &mut Frame, _: &mut crate::vm::VirtualMachine, ) -> crate::vm::ExecutionResult { let this = match frame.stack.pop_if(|x| RuntimeValue::as_string(&x).cloned()) { Some(x) => x, None => { return Err(VmErrorReason::UnexpectedType.into()); } }; let result = this.raw_value().to_uppercase(); frame.stack.push(RuntimeValue::String(result.into())); Ok(RunloopExit::Ok(())) } fn attrib_byte(&self) -> u8 { FUNC_IS_METHOD } fn arity(&self) -> crate::arity::Arity { crate::arity::Arity::required(1) } fn name(&self) -> &str { "uppercase" } } #[derive(Default)] struct Lowercase {} impl BuiltinFunctionImpl for Lowercase { fn eval( &self, frame: &mut Frame, _: &mut crate::vm::VirtualMachine, ) -> crate::vm::ExecutionResult { let this = match frame.stack.pop_if(|x| RuntimeValue::as_string(&x).cloned()) { Some(x) => x, None => { return Err(VmErrorReason::UnexpectedType.into()); } }; let result = this.raw_value().to_lowercase(); frame.stack.push(RuntimeValue::String(result.into())); Ok(RunloopExit::Ok(())) } fn attrib_byte(&self) -> u8 { FUNC_IS_METHOD } fn arity(&self) -> crate::arity::Arity { crate::arity::Arity::required(1) } fn name(&self) -> &str { "lowercase" } } #[derive(Default)] struct Contains {} impl BuiltinFunctionImpl for Contains { fn eval( &self, frame: &mut Frame, _: &mut crate::vm::VirtualMachine, ) -> crate::vm::ExecutionResult { let this = VmGlobals::extract_arg(frame, |a| a.as_string().cloned())?; let that = VmGlobals::extract_arg(frame, |a| a.as_string().cloned())?; let contains = this.raw_value().contains(that.raw_value()); frame.stack.push(RuntimeValue::Boolean(contains.into())); Ok(RunloopExit::Ok(())) } fn attrib_byte(&self) -> u8 { FUNC_IS_METHOD } fn arity(&self) -> crate::arity::Arity { crate::arity::Arity::required(2) } fn name(&self) -> &str { "contains" } } #[derive(Default)] struct GetAt {} impl BuiltinFunctionImpl for GetAt { fn eval( &self, frame: &mut Frame, _: &mut crate::vm::VirtualMachine, ) -> crate::vm::ExecutionResult { let this = VmGlobals::extract_arg(frame, |x| x.as_string().cloned())?; let index = VmGlobals::extract_arg(frame, |x| x.as_integer().cloned())?; let index = *index.raw_value() as usize; match this.get_at(index) { Some(v) => { frame.stack.push(v); Ok(RunloopExit::Ok(())) } None => Err(VmErrorReason::IndexOutOfBounds(index).into()), } } fn attrib_byte(&self) -> u8 { FUNC_IS_METHOD } fn arity(&self) -> crate::arity::Arity { crate::arity::Arity::required(2) } fn name(&self) -> &str { "_get_at" } } pub(super) fn insert_string_builtins(builtins: &mut VmGlobals) { let string_builtin = RustNativeType::new(crate::runtime_value::rust_native_type::RustNativeValueKind::String); string_builtin.insert_builtin::(builtins); string_builtin.insert_builtin::(builtins); string_builtin.insert_builtin::(builtins); string_builtin.insert_builtin::(builtins); string_builtin.insert_builtin::(builtins); string_builtin.insert_builtin::(builtins); string_builtin.insert_builtin::(builtins); string_builtin.insert_builtin::(builtins); string_builtin.insert_builtin::(builtins); string_builtin.insert_builtin::(builtins); string_builtin.insert_builtin::(builtins); string_builtin.insert_builtin::(builtins); string_builtin.insert_builtin::(builtins); string_builtin.insert_builtin::(builtins); string_builtin.insert_builtin::(builtins); builtins.register_builtin_type( haxby_opcodes::BuiltinTypeId::String, RuntimeValueType::RustNative(string_builtin), ); } ================================================ FILE: vm-lib/src/builtins/system.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use super::VmGlobals; use crate::{ error::vm_error::VmErrorReason, frame::Frame, runtime_value::{RuntimeValue, function::BuiltinFunctionImpl, integer::IntegerValue}, symbol::{INTERNED_ATTR_STDERR, INTERNED_ATTR_STDOUT}, vm::RunloopExit, }; use std::process::Command; fn get_shell_path() -> String { // it's not like Aria is tested on Windows, but let's at least pretend to be nice if cfg!(target_os = "windows") { return std::env::var("COMSPEC").unwrap_or_else(|_| "cmd.exe".to_string()); } std::env::var("SHELL").unwrap_or_else(|_| "/bin/sh".to_string()) } #[derive(Default)] struct System {} impl BuiltinFunctionImpl for System { fn eval( &self, cur_frame: &mut Frame, vm: &mut crate::vm::VirtualMachine, ) -> crate::vm::ExecutionResult { let command = VmGlobals::extract_arg(cur_frame, |x| x.as_string().cloned())?; let output = Command::new(get_shell_path()) .arg("-c") .arg(command.raw_value()) .output(); match output { Ok(output) => { let result = RuntimeValue::Integer(IntegerValue::from( output.status.code().unwrap_or(-1) as i64, )); let _ = result.write_attribute( INTERNED_ATTR_STDOUT, RuntimeValue::String( String::from_utf8_lossy(&output.stdout).to_string().into(), ), &mut vm.globals, ); let _ = result.write_attribute( INTERNED_ATTR_STDERR, RuntimeValue::String( String::from_utf8_lossy(&output.stderr).to_string().into(), ), &mut vm.globals, ); cur_frame.stack.push(result); Ok(RunloopExit::Ok(())) } Err(e) => Err(VmErrorReason::OperationFailed(e.to_string()).into()), } } fn arity(&self) -> crate::arity::Arity { crate::arity::Arity::required(1) } fn name(&self) -> &str { "system" } } pub(super) fn insert_builtins(builtins: &mut VmGlobals) { builtins.insert_builtin::(); } ================================================ FILE: vm-lib/src/builtins/test_exit.aria ================================================ # SPDX-License-Identifier: Apache-2.0 exit(42); ================================================ FILE: vm-lib/src/builtins/typ.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use crate::runtime_value::{kind::RuntimeValueType, rust_native_type::RustNativeType}; use super::VmGlobals; pub(super) fn insert_type_builtins(builtins: &mut VmGlobals) { let type_builtin = RustNativeType::new(crate::runtime_value::rust_native_type::RustNativeValueKind::Type); builtins.register_builtin_type( haxby_opcodes::BuiltinTypeId::Type, RuntimeValueType::RustNative(type_builtin), ); } ================================================ FILE: vm-lib/src/builtins/typeof_builtin.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use crate::{ builtins::VmGlobals, frame::Frame, runtime_value::{RuntimeValue, function::BuiltinFunctionImpl, kind::RuntimeValueType}, vm::RunloopExit, }; #[derive(Default)] struct Typeof {} impl BuiltinFunctionImpl for Typeof { fn eval( &self, frame: &mut Frame, vm: &mut crate::vm::VirtualMachine, ) -> crate::vm::ExecutionResult { let the_value = frame.stack.pop(); let the_type = RuntimeValueType::get_type(&the_value, &vm.globals); frame.stack.push(RuntimeValue::Type(the_type)); Ok(RunloopExit::Ok(())) } fn arity(&self) -> crate::arity::Arity { crate::arity::Arity::required(1) } fn name(&self) -> &str { "typeof" } } pub(super) fn insert_builtins(builtins: &mut VmGlobals) { builtins.insert_builtin::(); } ================================================ FILE: vm-lib/src/builtins/unimplemented.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use crate::runtime_value::{kind::RuntimeValueType, structure::Struct}; use super::VmGlobals; pub(super) fn insert_unimplemented_builtins(builtins: &mut VmGlobals) { let unimplemented_struct = Struct::new("Unimplemented"); builtins.register_builtin_type( haxby_opcodes::BuiltinTypeId::Unimplemented, RuntimeValueType::Struct(unimplemented_struct.clone()), ); } ================================================ FILE: vm-lib/src/builtins/unit.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use crate::runtime_value::{ enumeration::{Enum, EnumCase}, kind::RuntimeValueType, }; use super::VmGlobals; pub(super) fn insert_unit_builtins(builtins: &mut VmGlobals) { let unit_sym = builtins .intern_symbol("unit") .expect("too many symbols interned"); let unit_enum = Enum::new_with_cases( "Unit", &[EnumCase { name: unit_sym, payload_type: None, }], builtins, ); builtins.register_builtin_type( haxby_opcodes::BuiltinTypeId::Unit, RuntimeValueType::Enum(unit_enum.clone()), ); } ================================================ FILE: vm-lib/src/builtins/writeattr.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use crate::{ builtins::VmGlobals, frame::Frame, runtime_value::function::BuiltinFunctionImpl, vm::RunloopExit, }; #[derive(Default)] struct WriteAttr {} impl BuiltinFunctionImpl for WriteAttr { fn eval( &self, frame: &mut Frame, vm: &mut crate::vm::VirtualMachine, ) -> crate::vm::ExecutionResult { let the_object = frame.stack.pop(); let the_string = VmGlobals::extract_arg(frame, |x| x.as_string().cloned())?; let the_symbol = vm.globals.intern_symbol(the_string.raw_value())?; let the_value = frame.stack.pop(); the_object .write_attribute(the_symbol, the_value, &mut vm.globals) .map_err(|e| e.to_vm_error_reason(the_string.raw_value()))?; frame.stack.push(vm.globals.create_unit_object()?); Ok(RunloopExit::Ok(())) } fn arity(&self) -> crate::arity::Arity { crate::arity::Arity::required(3) } fn name(&self) -> &str { "writeattr" } } pub(super) fn insert_builtins(builtins: &mut VmGlobals) { builtins.insert_builtin::(); } ================================================ FILE: vm-lib/src/console.rs ================================================ // SPDX-License-Identifier: Apache-2.0 pub trait Console: std::any::Any { fn print(&mut self, s: &str) -> std::io::Result<()> { print!("{}", s); Ok(()) } fn println(&mut self, s: &str) -> std::io::Result<()> { println!("{}", s); Ok(()) } fn eprintln(&mut self, s: &str) -> std::io::Result<()> { eprintln!("{}", s); Ok(()) } fn as_any(&self) -> &dyn std::any::Any; } #[derive(Default, Clone, Copy)] pub struct StdConsole; impl Console for StdConsole { fn as_any(&self) -> &dyn std::any::Any { self } } #[derive(Default, Clone)] pub struct TestConsole { pub stdout: String, pub stderr: String, } impl Console for TestConsole { fn print(&mut self, s: &str) -> std::io::Result<()> { self.stdout.push_str(s); Ok(()) } fn println(&mut self, s: &str) -> std::io::Result<()> { self.stdout.push_str(s); self.stdout.push('\n'); Ok(()) } fn eprintln(&mut self, s: &str) -> std::io::Result<()> { self.stderr.push_str(s); self.stderr.push('\n'); Ok(()) } fn as_any(&self) -> &dyn std::any::Any { self } } impl TestConsole { pub fn clear(&mut self) { self.stdout.clear(); self.stderr.clear(); } } impl std::io::Write for dyn Console { fn write(&mut self, buf: &[u8]) -> std::io::Result { let s = std::str::from_utf8(buf) .map_err(|_| std::io::Error::new(std::io::ErrorKind::InvalidData, "Invalid UTF-8"))?; self.print(s)?; Ok(buf.len()) } fn flush(&mut self) -> std::io::Result<()> { Ok(()) } } ================================================ FILE: vm-lib/src/error/backtrace.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use aria_parser::ast::SourcePointer; #[derive(Clone, Debug, Default)] pub struct Backtrace { entries: Vec, } impl Backtrace { pub fn first_entry(&self) -> Option { self.entries.first().cloned() } pub fn entries_iter(&self) -> std::slice::Iter<'_, SourcePointer> { self.entries.iter() } pub fn push(&mut self, loc: SourcePointer) { self.entries.push(loc); } pub fn len(&self) -> usize { self.entries.len() } pub fn is_empty(&self) -> bool { self.entries.is_empty() } } ================================================ FILE: vm-lib/src/error/dylib_load.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use std::ffi::{CString, c_char}; #[repr(C)] #[derive(Debug, Copy, Clone, PartialEq, Eq)] pub enum LoadStatus { Success = 0, Error = 1, } #[repr(C)] pub struct LoadResult { pub status: LoadStatus, pub message: *const c_char, } impl LoadResult { pub fn success() -> Self { Self { status: LoadStatus::Success, message: std::ptr::null(), } } pub fn error(message: &str) -> Self { Self { status: LoadStatus::Error, message: CString::new(message).unwrap().into_raw(), } } #[allow(unused)] pub(crate) fn free(self) { if !self.message.is_null() { unsafe { let _ = CString::from_raw(self.message as *mut c_char); } } } pub(crate) fn into_rust_string(self) -> String { assert!(!self.message.is_null()); let message = unsafe { CString::from_raw(self.message as *mut c_char) }; message.into_string().unwrap() } } ================================================ FILE: vm-lib/src/error/exception.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use aria_parser::ast::SourcePointer; use haxby_opcodes::BuiltinTypeId; use crate::{ builtins::VmGlobals, error::{ backtrace::Backtrace, vm_error::{VmError, VmErrorReason}, }, runtime_value::{RuntimeValue, list::List, object::Object}, symbol::{INTERNED_ATTR_ACTUAL, INTERNED_ATTR_BACKTRACE, INTERNED_ATTR_EXPECTED, Symbol}, vm::VirtualMachine, }; pub struct VmException { pub value: RuntimeValue, pub backtrace: Backtrace, } impl VmException { pub fn from_value(value: RuntimeValue) -> Self { Self { value, backtrace: Default::default(), } } pub fn from_value_and_loc(value: RuntimeValue, loc: Option) -> Self { let mut this = VmException::from_value(value); if let Some(loc) = loc { this = this.thrown_at(loc); } this } pub fn thrown_at(self, loc: SourcePointer) -> Self { if self.backtrace.len() == 1 && self.backtrace.first_entry().unwrap() == loc { self } else { let mut new_bt = self.backtrace.clone(); new_bt.push(loc); Self { value: self.value.clone(), backtrace: new_bt, } } } pub fn is_builtin_unimplemented(&self, vm: &mut VirtualMachine) -> bool { self.value.is_builtin_unimplemented(vm) } } impl VmException { pub(crate) fn fill_in_backtrace(&self, builtins: &mut VmGlobals) { let bt_list = List::from(&[]); for bt_entry in self.backtrace.entries_iter() { let buf_name = bt_entry.buffer.name.clone(); let buf_line = bt_entry .buffer .line_index_for_position(bt_entry.location.start); let buf_name = RuntimeValue::String(buf_name.into()); let buf_line = RuntimeValue::Integer((buf_line as i64).into()); bt_list.append(RuntimeValue::List(List::from(&[buf_name, buf_line]))); } let _ = self.value.write_attribute( INTERNED_ATTR_BACKTRACE, RuntimeValue::List(bt_list), builtins, ); } } impl VmException { pub fn from_vmerror(err: VmError, builtins: &mut VmGlobals) -> Result { macro_rules! some_or_err { ($opt:expr, $err:expr) => { match $opt { Some(val) => val, None => return Err($err), } }; } use crate::builtins::runtime_error::{ RUNTIME_ERR_CASE_DIVISION_BY_ZERO_IDX, RUNTIME_ERR_CASE_ENUM_WITHOUT_PAYLOAD_IDX, RUNTIME_ERR_CASE_INDEX_OUT_OF_BOUNDS_IDX, RUNTIME_ERR_CASE_MISMATCHED_ARGC_IDX, RUNTIME_ERR_CASE_NO_SUCH_CASE_IDX, RUNTIME_ERR_CASE_NO_SUCH_IDENTIFIER_IDX, RUNTIME_ERR_CASE_OPERATION_FAILED_IDX, RUNTIME_ERR_CASE_UNEXPECTED_TYPE_IDX, }; let rt_err_type = builtins.get_builtin_type_by_id(BuiltinTypeId::RuntimeError); let rt_err = some_or_err!(rt_err_type.as_enum(), err); struct ExceptionData { case: usize, payload: Option, } let e_data = match &err.reason { VmErrorReason::DivisionByZero => ExceptionData { case: RUNTIME_ERR_CASE_DIVISION_BY_ZERO_IDX, payload: None, }, VmErrorReason::EnumWithoutPayload => ExceptionData { case: RUNTIME_ERR_CASE_ENUM_WITHOUT_PAYLOAD_IDX, payload: None, }, VmErrorReason::IndexOutOfBounds(idx) => ExceptionData { case: RUNTIME_ERR_CASE_INDEX_OUT_OF_BOUNDS_IDX, payload: Some(RuntimeValue::Integer((*idx as i64).into())), }, VmErrorReason::MismatchedArgumentCount(expected, actual) => { let argc_mismatch_sym = builtins .intern_symbol("ArgcMismatch") .expect("too many symbols interned"); let argc_mismatch = some_or_err!(rt_err.load_named_value(builtins, argc_mismatch_sym), err); let argc_mismatch = some_or_err!(argc_mismatch.as_struct(), err); let argc_mismatch_obj = RuntimeValue::Object(Object::new(argc_mismatch)); let _ = argc_mismatch_obj.write_attribute( INTERNED_ATTR_EXPECTED, RuntimeValue::Integer((*expected as i64).into()), builtins, ); let _ = argc_mismatch_obj.write_attribute( INTERNED_ATTR_ACTUAL, RuntimeValue::Integer((*actual as i64).into()), builtins, ); ExceptionData { case: RUNTIME_ERR_CASE_MISMATCHED_ARGC_IDX, payload: Some(argc_mismatch_obj), } } VmErrorReason::NoSuchCase(s) => ExceptionData { case: RUNTIME_ERR_CASE_NO_SUCH_CASE_IDX, payload: Some(RuntimeValue::String(s.clone().into())), }, VmErrorReason::NoSuchIdentifier(s) => ExceptionData { case: RUNTIME_ERR_CASE_NO_SUCH_IDENTIFIER_IDX, payload: Some(RuntimeValue::String(s.clone().into())), }, VmErrorReason::NoSuchSymbol(n, kind) => { if let Some(name_for_sym) = builtins.resolve_symbol(Symbol(*n)) { ExceptionData { case: match kind { crate::error::vm_error::SymbolKind::Identifier => { RUNTIME_ERR_CASE_NO_SUCH_IDENTIFIER_IDX } crate::error::vm_error::SymbolKind::Case => { RUNTIME_ERR_CASE_NO_SUCH_CASE_IDX } }, payload: Some(RuntimeValue::String(name_for_sym.to_owned().into())), } } else { return Err(err); } } VmErrorReason::OperationFailed(s) => ExceptionData { case: RUNTIME_ERR_CASE_OPERATION_FAILED_IDX, payload: Some(RuntimeValue::String(s.clone().into())), }, VmErrorReason::UnexpectedType => ExceptionData { case: RUNTIME_ERR_CASE_UNEXPECTED_TYPE_IDX, payload: None, }, _ => { return Err(err); } }; let exception_value = RuntimeValue::EnumValue(some_or_err!( rt_err.make_value(e_data.case, e_data.payload), err )); Ok(VmException::from_value_and_loc(exception_value, err.loc)) } } ================================================ FILE: vm-lib/src/error/mod.rs ================================================ // SPDX-License-Identifier: Apache-2.0 pub mod backtrace; pub mod dylib_load; pub mod exception; pub mod vm_error; ================================================ FILE: vm-lib/src/error/vm_error.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use aria_compiler::bc_reader::DecodeError; use aria_parser::ast::{SourcePointer, prettyprint::printout_accumulator::PrintoutAccumulator}; use haxby_opcodes::Opcode; use thiserror::Error; use crate::{ error::backtrace::Backtrace, opcodes::prettyprint::opcode_prettyprint, runtime_module::RuntimeModule, }; #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] pub enum SymbolKind { Identifier, Case, } impl std::fmt::Display for SymbolKind { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { SymbolKind::Identifier => write!(f, "identifier"), SymbolKind::Case => write!(f, "case"), } } } #[derive(Clone, Error, PartialEq, Eq, Debug)] pub enum VmErrorReason { #[error("assertion failed: {0}")] AssertFailed(String), #[error("'{0}' is a circular import reference")] CircularImport(String), #[error("division by zero")] DivisionByZero, #[error("enum value has no payload")] EnumWithoutPayload, #[error("runtime stack is empty")] EmptyStack, #[error("index {0} out of bounds")] IndexOutOfBounds(usize), #[error("cannot import module at path '{0}': {1}")] ImportNotAvailable(String, String), #[error("instruction cannot be fully decoded")] IncompleteInstruction, #[error("bytecode ended without an explicit terminal instruction")] UnterminatedBytecode, #[error("invalid binding")] InvalidBinding, #[error("control instruction invalid")] InvalidControlInstruction, #[error("mismatched argument count, expected {0} actual {1}")] MismatchedArgumentCount(usize, usize), #[error("unknown named identifier: '{0}'")] NoSuchIdentifier(String), #[error("'{0}' is not a valid case for this enum")] NoSuchCase(String), #[error("unknown {1} symbol: '{0}'")] NoSuchSymbol(u32, SymbolKind), #[error("unknown module constant value: '{0}'")] NoSuchModuleConstant(u16), #[error("operation failed: {0}")] OperationFailed(String), #[error("unexpected value type")] UnexpectedType, #[error("VM execution is not a valid state")] UnexpectedVmState, #[error("The main function must have 0, 1 or variable arguments")] InvalidMainSignature, #[error("uplevel {0} not available")] UplevelOutOfBounds(usize), #[error("{0} is not a known opcode")] UnknownOpcode(u8), #[error("{1} is not a valid operand for opcode {0}")] InvalidVmOperand(u8, u8), #[error("bytecode exceeds maximum allowed size")] BytecodeTooLarge, #[error("too many symbols have been interned")] TooManyInternedSymbols, #[error("VM execution halted")] VmHalted, } impl From for VmErrorReason { fn from(value: DecodeError) -> Self { match value { DecodeError::DataTooLarge => VmErrorReason::BytecodeTooLarge, DecodeError::EndOfStream => VmErrorReason::UnterminatedBytecode, DecodeError::InsufficientData => VmErrorReason::IncompleteInstruction, DecodeError::UnknownOpcode(n) => VmErrorReason::UnknownOpcode(n), DecodeError::UnknownOperand(n, m) => VmErrorReason::InvalidVmOperand(n, m), } } } #[derive(Clone)] pub struct VmError { pub reason: VmErrorReason, pub opcode: Option, pub loc: Option, pub backtrace: Box, } impl VmError { pub fn prettyprint(&self, module: Option) -> String { let mut poa = PrintoutAccumulator::default(); poa = poa << "vm error: " << self.reason.to_string(); if let Some(opcode) = self.opcode && let Some(m) = module { poa = { let ropc = crate::opcodes::prettyprint::RuntimeOpcodePrinter { globals: None, module: Some(&m), }; opcode_prettyprint(opcode, &ropc, poa) }; } if let Some(loc) = &self.loc { poa = poa << " at " << loc.to_string(); } poa.value() } } impl std::fmt::Debug for VmError { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "{}", self.prettyprint(None)) } } impl From for VmError { fn from(reason: VmErrorReason) -> Self { Self { reason, opcode: None, loc: None, backtrace: Default::default(), } } } ================================================ FILE: vm-lib/src/frame.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use aria_compiler::line_table::LineTable; use aria_parser::ast::SourcePointer; use crate::{ runtime_value::{RuntimeValue, function::Function, isa::IsaCheckable}, stack::Stack, vm::VirtualMachine, }; pub struct LocalVariable { pub val: RuntimeValue, pub ty: IsaCheckable, } impl Default for LocalVariable { fn default() -> Self { Self { val: RuntimeValue::Integer(From::from(0)), ty: IsaCheckable::any(), } } } #[derive(Clone)] pub enum ControlBlock { Try(u16), } pub struct Frame { pub stack: Stack, pub(crate) line_table: Option, pub(crate) ctrl_blocks: Stack, pub(crate) locals: Vec, pub(crate) func: Option, pub argc: u8, } impl Frame { pub(crate) fn drop_to_first_try(&mut self, _: &mut VirtualMachine) -> Option { if let Some(block) = self.ctrl_blocks.try_pop() { match block { ControlBlock::Try(x) => { return Some(x); } } } None } } impl Frame { pub fn new_with_function(f: Function) -> Self { let mut this = Self::new_with_n_locals(f.frame_size()); this.set_line_table(f.line_table()); this.func = Some(f); this } pub(crate) fn new_with_n_locals(n: u8) -> Self { let mut this = Self { stack: Default::default(), line_table: None, ctrl_blocks: Default::default(), locals: Vec::with_capacity(n as usize), func: None, argc: 0, }; for _ in 0..n { this.locals.push(LocalVariable::default()) } this } pub(crate) fn set_argc(&mut self, argc: u8) -> &mut Self { self.argc = argc; self } pub(crate) fn set_line_table(&mut self, lt: Option<&LineTable>) -> &mut Self { self.line_table = lt.cloned(); self } pub(crate) fn get_line_table(&self) -> Option<&LineTable> { self.line_table.as_ref() } pub fn get_line_entry_at_pos(&self, pos: u16) -> Option { if let Some(lt) = &self.line_table { lt.get(pos) } else { None } } pub(crate) fn reset_for_function(&mut self, f: &Function) { self.stack.clear(); self.ctrl_blocks.clear(); self.func = Some(f.clone()); self.argc = 0; self.set_line_table(f.line_table()); let locals = f.frame_size() as usize; self.locals.clear(); self.locals.resize_with(locals, LocalVariable::default); } pub(crate) fn reset_for_pool(mut self) -> Self { self.stack.clear(); self.ctrl_blocks.clear(); self.locals.clear(); self.func = None; self.argc = 0; self.line_table = None; self } } impl Default for Frame { fn default() -> Self { Self::new_with_n_locals(0) } } ================================================ FILE: vm-lib/src/lib.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use aria_compiler::module::CompiledModule; use vm::{ExecutionResult, RunloopExit, VirtualMachine, VmOptions}; pub mod arity; pub mod builtins; pub mod console; pub mod error; pub mod frame; pub mod mixin_includer; pub mod opcodes; pub mod runtime_module; pub mod runtime_value; pub mod shape; pub mod stack; pub mod symbol; pub mod vm; #[cfg(test)] mod test; pub struct HaxbyEvalResult { pub exit: RunloopExit, pub vm: VirtualMachine, } pub fn haxby_eval(module: CompiledModule, options: VmOptions) -> ExecutionResult { let mut vm = VirtualMachine::with_options(options); let rle = vm.load_module("eval", module)?; let rm = match rle { RunloopExit::Ok(m) => m.module, RunloopExit::Exception(e) => { return Ok(HaxbyEvalResult { exit: RunloopExit::Exception(e), vm, }); } }; let rle = vm.execute_module(&rm)?; Ok(HaxbyEvalResult { exit: rle, vm }) } ================================================ FILE: vm-lib/src/mixin_includer.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use std::collections::HashSet; use crate::{ builtins::VmGlobals, runtime_value::{RuntimeValue, mixin::Mixin}, symbol::Symbol, }; #[derive(Default)] pub struct MixinIncluder { mixins: Vec, } impl MixinIncluder { pub fn load_named_value(&self, builtins: &VmGlobals, name: Symbol) -> Option { self.mixins .iter() .rev() .find_map(|mixin| mixin.load_named_value(builtins, name)) } pub fn include(&mut self, mixin: Mixin) { self.mixins.push(mixin); } pub fn contains(&self, mixin: &Mixin) -> bool { for m in &self.mixins { if m.isa_mixin(mixin) { return true; } } false } pub fn list_attributes(&self, builtins: &VmGlobals) -> HashSet { let mut attrs = HashSet::new(); for mixin in &self.mixins { attrs.extend(mixin.list_attributes(builtins)); } attrs } } ================================================ FILE: vm-lib/src/opcodes/mod.rs ================================================ // SPDX-License-Identifier: Apache-2.0 pub mod prettyprint; pub mod sidecar; ================================================ FILE: vm-lib/src/opcodes/prettyprint.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use aria_compiler::dump::StringResolver; use aria_parser::ast::prettyprint::printout_accumulator::PrintoutAccumulator; use haxby_opcodes::Opcode; use crate::{builtins::VmGlobals, runtime_module::RuntimeModule}; pub(crate) struct RuntimeOpcodePrinter<'a> { pub(crate) globals: Option<&'a VmGlobals>, pub(crate) module: Option<&'a RuntimeModule>, } impl<'a> StringResolver for RuntimeOpcodePrinter<'a> { fn resolve_compile_time_constant(&self, idx: u16) -> Option { if let Some(module) = &self.module { module .get_compiled_module() .resolve_compile_time_constant(idx) } else { None } } fn resolve_run_time_symbol(&self, idx: u32) -> Option { if let Some(globals) = &self.globals { globals .resolve_symbol(crate::symbol::Symbol(idx)) .map(|f| f.to_string()) } else { None } } } pub(crate) fn opcode_prettyprint( opcode: Opcode, ropc: &RuntimeOpcodePrinter, buffer: PrintoutAccumulator, ) -> PrintoutAccumulator { aria_compiler::dump::opcodes::opcode_prettyprint(opcode, ropc, buffer) } ================================================ FILE: vm-lib/src/opcodes/sidecar.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use std::cell::Cell; use enum_as_inner::EnumAsInner; use crate::shape::{ShapeId, SlotId}; #[derive(Clone, Copy)] pub struct ReadAttributeSidecar { pub misses: u8, pub shape_id: ShapeId, pub slot_id: SlotId, } impl ReadAttributeSidecar { pub const MAXIMUM_ALLOWED_MISSES: u8 = 16; } #[derive(Clone, Copy)] pub struct NewEnumValSidecar { pub misses: u8, pub shape_id: ShapeId, pub slot_id: SlotId, } #[derive(Clone, Copy)] pub struct EnumCheckIsCaseSidecar { pub misses: u8, pub shape_id: ShapeId, pub slot_id: SlotId, } impl NewEnumValSidecar { pub const MAXIMUM_ALLOWED_MISSES: u8 = 16; } #[derive(Clone, Copy, EnumAsInner)] pub enum OpcodeSidecar { ReadAttribute(ReadAttributeSidecar), NewEnumVal(NewEnumValSidecar), EnumCheckIsCase(EnumCheckIsCaseSidecar), } pub type SidecarCell = Cell>; pub type SidecarSlice = [SidecarCell]; #[cfg(debug_assertions)] pub(crate) fn sidecar_prettyprint( sidecar: OpcodeSidecar, buffer: aria_parser::ast::prettyprint::printout_accumulator::PrintoutAccumulator, ) -> aria_parser::ast::prettyprint::printout_accumulator::PrintoutAccumulator { match sidecar { OpcodeSidecar::ReadAttribute(sc) => { buffer << "[misses=" << sc.misses << " shape_id=" << sc.shape_id.0 << " slot_id=" << sc.slot_id.0 << "]" } OpcodeSidecar::NewEnumVal(sc) => { buffer << "[misses=" << sc.misses << " shape_id=" << sc.shape_id.0 << " slot_id=" << sc.slot_id.0 << "]" } OpcodeSidecar::EnumCheckIsCase(sc) => { buffer << "[misses=" << sc.misses << " shape_id=" << sc.shape_id.0 << " slot_id=" << sc.slot_id.0 << "]" } } } ================================================ FILE: vm-lib/src/runtime_module.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use std::{cell::RefCell, collections::HashSet, rc::Rc}; use aria_compiler::module::CompiledModule; use haxby_opcodes::Opcode; use rustc_data_structures::fx::FxHashMap; use crate::{ builtins::VmGlobals, error::vm_error::VmErrorReason, runtime_value::{ RuntimeValue, function::{BuiltinFunctionImpl, Function}, isa::IsaCheckable, }, vm::VirtualMachine, }; #[derive(Clone)] pub struct NamedValue { pub val: RuntimeValue, pub ty: IsaCheckable, } struct RuntimeModuleImpl { compiled_module: CompiledModule, indexed_constants: Vec, values: RefCell>, entry_co: crate::runtime_value::runtime_code_object::CodeObject, } fn byte_array_to_opcode_array(bytes: &[u8]) -> aria_compiler::bc_reader::DecodeResult> { let mut opcodes = Vec::new(); let mut decoder = aria_compiler::bc_reader::BytecodeReader::try_from(bytes)?; loop { let next = decoder.read_opcode(); match next { Ok(op) => opcodes.push(op), Err(err) => { return match err { aria_compiler::bc_reader::DecodeError::EndOfStream => Ok(opcodes), _ => Err(err), }; } } } } macro_rules! replace_const_with_symbol { ($vm:expr, $cm:expr, $n:expr, $opcode:expr, $target_variant:ident) => {{ let n_const = $cm.load_indexed_const($n).expect("missing constant"); let n_as_str = n_const.as_string().expect("expected string constant"); let n_as_sym = match $vm.globals.intern_symbol(&n_as_str) { Ok(s) => s, Err(_) => return Err(VmErrorReason::UnexpectedVmState), }; *$opcode = Opcode::$target_variant(n_as_sym.0); }}; ($vm:expr, $cm:expr, $arg0:expr, $n:expr, $opcode:expr, $target_variant:ident) => {{ let n_const = $cm.load_indexed_const($n).expect("missing constant"); let n_as_str = n_const.as_string().expect("expected string constant"); let n_as_sym = match $vm.globals.intern_symbol(&n_as_str) { Ok(s) => s, Err(_) => return Err(VmErrorReason::UnexpectedVmState), }; *$opcode = Opcode::$target_variant($arg0, n_as_sym.0); }}; } fn replace_attribute_access_with_interned( vm: &mut VirtualMachine, cm: &CompiledModule, opcodes: &mut Vec, ) -> Result<(), VmErrorReason> { for opcode in opcodes { match opcode { Opcode::ReadAttribute(n) => { replace_const_with_symbol!(vm, cm, *n, opcode, ReadAttributeSymbol) } Opcode::WriteAttribute(n) => { replace_const_with_symbol!(vm, cm, *n, opcode, WriteAttributeSymbol) } Opcode::ReadAttributeSymbol(_) | Opcode::WriteAttributeSymbol(_) => { // the compiler cannot generate these instructions because it does not know // what the VM will intern at runtime in what order - so if we see them in // the compiled module's byte stream, it's clearly bad and we should reject // loading this module return Err(VmErrorReason::UnexpectedVmState); } Opcode::BindCase(a, n) => { replace_const_with_symbol!(vm, cm, *a, *n, opcode, BindCaseSymbol) } Opcode::NewEnumVal(a, n) => { replace_const_with_symbol!(vm, cm, *a, *n, opcode, NewEnumValSymbol) } Opcode::EnumCheckIsCase(n) => { replace_const_with_symbol!(vm, cm, *n, opcode, EnumCheckIsCaseSymbol) } Opcode::BindCaseSymbol(..) | Opcode::NewEnumValSymbol(..) | Opcode::EnumCheckIsCaseSymbol(_) => { return Err(VmErrorReason::UnexpectedVmState); } _ => {} } } Ok(()) } fn compiled_code_object_to_runtime_code_object( vm: &mut VirtualMachine, cm: &CompiledModule, cco: aria_compiler::constant_value::CompiledCodeObject, ) -> Result { let mut ops = byte_array_to_opcode_array(cco.body.as_slice())?; replace_attribute_access_with_interned(vm, cm, &mut ops)?; let body: Rc<[Opcode]> = ops.into(); Ok(crate::runtime_value::runtime_code_object::CodeObject { name: cco.name.clone(), attribute: cco.attribute, body, required_argc: cco.required_argc, default_argc: cco.default_argc, frame_size: cco.frame_size, loc: cco.loc.clone(), line_table: Rc::from(cco.line_table.clone()), }) } fn compiled_constant_to_runtime_value( vm: &mut VirtualMachine, cm: &CompiledModule, value: aria_compiler::constant_value::ConstantValue, ) -> Result { use aria_compiler::constant_value::ConstantValue::{ CompiledCodeObject, Float, Integer, String, }; match value { Integer(n) => Ok(RuntimeValue::Integer(From::from(n))), String(s) => Ok(RuntimeValue::String(s.into())), CompiledCodeObject(cco) => Ok(RuntimeValue::CodeObject( compiled_code_object_to_runtime_code_object(vm, cm, cco)?, )), Float(f) => Ok(RuntimeValue::Float(f.raw_value().into())), } } impl RuntimeModuleImpl { fn new(vm: &mut VirtualMachine, cm: CompiledModule) -> Result { let entry_co = compiled_code_object_to_runtime_code_object(vm, &cm, cm.load_entry_code_object())?; let mut this = Self { compiled_module: cm, indexed_constants: Vec::new(), values: Default::default(), entry_co, }; let mut i = 0; while i < this.compiled_module.constants.len() { let c = this .compiled_module .load_indexed_const(i as u16) .expect("module has missing constant data"); let r = compiled_constant_to_runtime_value(vm, &this.compiled_module, c)?; this.indexed_constants.push(r); i += 1; } Ok(this) } fn named_values_of_this(&self) -> Vec<(String, NamedValue)> { let mut ret = vec![]; for (n, v) in self.values.borrow().iter() { ret.push((n.clone(), v.clone())); } ret } fn load_named_value(&self, name: &str) -> Option { self.values.borrow().get(name).map(|v| v.val.clone()) } fn typedef_named_value(&self, name: &str, ty: IsaCheckable) { let mut bm = self.values.borrow_mut(); if let Some(val) = bm.get_mut(name) { val.ty = ty; } else { bm.insert( name.to_owned(), NamedValue { val: RuntimeValue::Integer(0.into()), ty, }, ); } } fn store_typechecked_named_value( &self, name: &str, val: RuntimeValue, builtins: &VmGlobals, ) -> Result<(), VmErrorReason> { let mut bm = self.values.borrow_mut(); if let Some(nval) = bm.get_mut(name) { if !nval.ty.isa_check(&val, builtins) { Err(VmErrorReason::UnexpectedType) } else { nval.val = val; Ok(()) } } else { Err(VmErrorReason::NoSuchIdentifier(name.to_owned())) } } fn store_named_value(&self, name: &str, val: RuntimeValue) { let mut bm = self.values.borrow_mut(); if let Some(nval) = bm.get_mut(name) { nval.val = val; } else { bm.insert( name.to_owned(), NamedValue { val, ty: IsaCheckable::any(), }, ); } } fn load_indexed_const(&self, idx: u16) -> Option<&RuntimeValue> { self.indexed_constants.get(idx as usize) } fn list_named_values(&self) -> HashSet { self.values.borrow().keys().cloned().collect() } } #[derive(Clone)] pub struct RuntimeModule { imp: Rc, } impl RuntimeModule { pub fn new(vm: &mut VirtualMachine, cm: CompiledModule) -> Result { Ok(Self { imp: Rc::new(RuntimeModuleImpl::new(vm, cm)?), }) } pub fn load_entry_code_object(&self) -> &crate::runtime_value::runtime_code_object::CodeObject { &self.imp.entry_co } pub(crate) fn named_values_of_this(&self) -> Vec<(String, NamedValue)> { self.imp.named_values_of_this() } pub(crate) fn get_compiled_module(&self) -> &CompiledModule { &self.imp.compiled_module } pub fn load_named_value(&self, name: &str) -> Option { self.imp.load_named_value(name) } pub fn typedef_named_value(&self, name: &str, ty: IsaCheckable) { self.imp.typedef_named_value(name, ty) } pub fn store_named_value(&self, name: &str, val: RuntimeValue) { self.imp.store_named_value(name, val) } pub fn list_named_values(&self) -> HashSet { self.imp.list_named_values() } pub fn store_typechecked_named_value( &self, name: &str, val: RuntimeValue, builtins: &VmGlobals, ) -> Result<(), VmErrorReason> { self.imp.store_typechecked_named_value(name, val, builtins) } pub fn load_indexed_const(&self, idx: u16) -> Option<&RuntimeValue> { self.imp.load_indexed_const(idx) } pub fn lift_all_symbols_from_other( &self, prior_art: &Self, vm: &crate::VirtualMachine, ) -> Result<(), VmErrorReason> { for (name, val) in prior_art.named_values_of_this() { self.typedef_named_value(&name, val.ty.clone()); self.store_typechecked_named_value(&name, val.val.clone(), &vm.globals)?; } Ok(()) } pub fn extract_value(&self, name: &str, f: T) -> Option where T: FnOnce(RuntimeValue) -> Option, { f(self.load_named_value(name)?) } pub fn insert_builtin(&self) where T: 'static + Default + BuiltinFunctionImpl, { let t = T::default(); let name = t.name().to_owned(); self.store_named_value(&name, RuntimeValue::Function(Function::builtin_from(t))); } } impl PartialEq for RuntimeModule { fn eq(&self, other: &Self) -> bool { Rc::ptr_eq(&self.imp, &other.imp) } } impl Eq for RuntimeModule {} ================================================ FILE: vm-lib/src/runtime_value/boolean.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use super::builtin_value::BuiltinValue; pub type BooleanValue = BuiltinValue; impl PartialEq for BooleanValue { fn eq(&self, other: &BooleanValue) -> bool { self.raw_value() == other.raw_value() } } impl Eq for BooleanValue {} impl std::ops::Not for BooleanValue { type Output = BooleanValue; fn not(self) -> Self::Output { self.raw_value().not().into() } } impl std::ops::BitXor for &BooleanValue { type Output = BooleanValue; fn bitxor(self, rhs: Self) -> Self::Output { (self.raw_value() ^ rhs.raw_value()).into() } } impl std::ops::BitAnd for &BooleanValue { type Output = BooleanValue; fn bitand(self, rhs: Self) -> Self::Output { (*self.raw_value() && *rhs.raw_value()).into() } } impl std::ops::BitOr for &BooleanValue { type Output = BooleanValue; fn bitor(self, rhs: Self) -> Self::Output { (*self.raw_value() || *rhs.raw_value()).into() } } ================================================ FILE: vm-lib/src/runtime_value/bound_function.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use std::rc::Rc; use crate::{ frame::Frame, runtime_value::function::PartialFunctionApplication, vm::{ExecutionResult, VirtualMachine}, }; use super::{CallResult, RuntimeValue, function::Function}; struct BoundFunctionImpl { this: RuntimeValue, func: Function, } #[derive(Clone)] pub struct BoundFunction { imp: Rc, } impl BoundFunction { pub(super) fn bind(this: RuntimeValue, func: Function) -> Self { Self { imp: Rc::new(BoundFunctionImpl { this, func }), } } pub fn this(&self) -> &RuntimeValue { &self.imp.this } pub fn func(&self) -> &Function { &self.imp.func } pub fn eval( &self, argc: u8, cur_frame: &mut Frame, vm: &mut VirtualMachine, discard_result: bool, ) -> ExecutionResult { let partial_application = PartialFunctionApplication::default().with_suffix_arg(self.this().clone()); self.func() .eval(argc, cur_frame, vm, &partial_application, discard_result) } } impl PartialEq for BoundFunction { fn eq(&self, other: &Self) -> bool { Rc::ptr_eq(&self.imp, &other.imp) } } impl Eq for BoundFunction {} ================================================ FILE: vm-lib/src/runtime_value/builtin_value.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use std::rc::Rc; use haxby_opcodes::BuiltinTypeId; use rustc_data_structures::fx::FxHashSet; use crate::{builtins::VmGlobals, symbol::Symbol}; use super::object::ObjectBox; pub(crate) struct BuiltinValueImpl where T: Clone, { pub(crate) val: T, id: BuiltinTypeId, pub(crate) boxx: ObjectBox, } impl BuiltinValueImpl where T: Clone, { fn list_attributes(&self, builtins: &VmGlobals) -> FxHashSet { self.boxx.list_attributes(builtins) } } #[derive(Clone)] pub struct BuiltinValue where T: Clone, { pub(crate) imp: Rc>, } trait GetBuiltinTypeId { fn get_builtin_type_id() -> BuiltinTypeId; } impl GetBuiltinTypeId for i64 { #[inline] fn get_builtin_type_id() -> BuiltinTypeId { BuiltinTypeId::Int } } impl GetBuiltinTypeId for bool { #[inline] fn get_builtin_type_id() -> BuiltinTypeId { BuiltinTypeId::Bool } } impl GetBuiltinTypeId for String { #[inline] fn get_builtin_type_id() -> BuiltinTypeId { BuiltinTypeId::String } } impl GetBuiltinTypeId for f64 { #[inline] fn get_builtin_type_id() -> BuiltinTypeId { BuiltinTypeId::Float } } impl From for BuiltinValueImpl where T: Clone + GetBuiltinTypeId, { #[inline] fn from(val: T) -> Self { Self { val, id: T::get_builtin_type_id(), boxx: Default::default(), } } } impl From for BuiltinValue where T: Clone + GetBuiltinTypeId, { #[inline] fn from(val: T) -> Self { Self { imp: Rc::new(From::from(val)), } } } impl BuiltinValue where T: Clone, { #[inline] pub fn builtin_type_id(&self) -> BuiltinTypeId { self.imp.id } #[inline] pub fn raw_value(&self) -> &T { &self.imp.val } pub fn list_attributes(&self, builtins: &VmGlobals) -> FxHashSet { self.imp.list_attributes(builtins) } } ================================================ FILE: vm-lib/src/runtime_value/enum_case.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use std::rc::Rc; use crate::{builtins::VmGlobals, frame::Frame, vm::VirtualMachine}; use crate::symbol::Symbol; use super::{RuntimeValue, enumeration::Enum}; pub(super) struct EnumValueImpl { pub(super) enumm: Enum, pub(super) case: usize, pub(super) payload: Option, } #[derive(Clone)] pub struct EnumValue { pub(super) imp: Rc, } impl EnumValue { pub fn get_container_enum(&self) -> &Enum { &self.imp.enumm } pub fn get_case_index(&self) -> usize { self.imp.case } pub fn get_payload(&self) -> Option<&RuntimeValue> { self.imp.payload.as_ref() } pub fn read(&self, builtins: &VmGlobals, name: Symbol) -> Option { self.imp.enumm.load_named_value(builtins, name) } } impl EnumValueImpl { fn builtin_equals(&self, other: &Self, cur_frame: &mut Frame, vm: &mut VirtualMachine) -> bool { self.enumm == other.enumm && self.case == other.case && match (&self.payload, &other.payload) { (None, None) => true, (None, Some(_)) => false, (Some(_), None) => false, (Some(a), Some(b)) => RuntimeValue::equals(a, b, cur_frame, vm), } } } impl EnumValue { pub(super) fn builtin_equals( &self, other: &Self, cur_frame: &mut Frame, vm: &mut VirtualMachine, ) -> bool { Rc::ptr_eq(&self.imp, &other.imp) || self.imp.builtin_equals(&other.imp, cur_frame, vm) } } ================================================ FILE: vm-lib/src/runtime_value/enumeration.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use std::{ cell::{Cell, RefCell}, rc::Rc, }; use rustc_data_structures::fx::FxHashSet; use crate::{ builtins::VmGlobals, runtime_value::{ function::{BuiltinFunctionImpl, Function}, isa::IsaCheckable, object::ObjectBox, }, shape::{ShapeId, SlotId}, symbol::Symbol, }; use super::{ RuntimeValue, enum_case::{EnumValue, EnumValueImpl}, mixin::Mixin, }; #[derive(Clone)] pub struct EnumCase { pub name: Symbol, pub payload_type: Option, } pub struct EnumImpl { name: String, cases: RefCell>, case_shape: Cell, pub(super) entries: ObjectBox, mixins: RefCell, } impl EnumImpl { fn new(name: &str) -> Self { Self { name: name.to_owned(), cases: Default::default(), case_shape: Cell::new(crate::shape::Shapes::EMPTY_SHAPE_INDEX), entries: ObjectBox::default(), mixins: RefCell::new(crate::mixin_includer::MixinIncluder::default()), } } pub fn add_case(&self, builtins: &mut VmGlobals, case: EnumCase) -> usize { let (shape_id, slot_id) = builtins.shapes.transition(self.case_shape.get(), case.name); self.case_shape.set(shape_id); let slot_id = slot_id.0 as usize; let mut cases = self.cases.borrow_mut(); if slot_id == cases.len() { cases.push(case); } else if slot_id < cases.len() { cases[slot_id] = case; } else { panic!("enum cases should grow sequentially"); } slot_id } pub fn add_cases(&self, builtins: &mut VmGlobals, cases: &[EnumCase]) { for case in cases { self.add_case(builtins, case.clone()); } } fn get_case_by_idx(&self, idx: usize) -> Option { let b = self.cases.borrow(); b.get(idx).cloned() } fn get_idx_of_case_by_symbol(&self, builtins: &VmGlobals, name: Symbol) -> Option { builtins .shapes .resolve_slot(self.case_shape.get(), name) .map(|slot_id| slot_id.0 as usize) } fn load_named_value(&self, builtins: &VmGlobals, name: Symbol) -> Option { if let Some(nv) = self.entries.read(builtins, name) { Some(nv.clone()) } else { self.mixins.borrow().load_named_value(builtins, name) } } fn store_named_value(&self, builtins: &mut VmGlobals, name: Symbol, val: RuntimeValue) { self.entries.write(builtins, name, val); } fn include_mixin(&self, mixin: &Mixin) { self.mixins.borrow_mut().include(mixin.clone()); } fn isa_mixin(&self, mixin: &Mixin) -> bool { self.mixins.borrow().contains(mixin) } fn list_attributes(&self, builtins: &VmGlobals) -> FxHashSet { let mut attrs = self.entries.list_attributes(builtins); attrs.extend(self.mixins.borrow().list_attributes(builtins)); attrs } fn case_shape_id(&self) -> ShapeId { self.case_shape.get() } pub(super) fn resolve_to_slot( &self, builtins: &crate::builtins::VmGlobals, name: Symbol, ) -> Option<(ShapeId, SlotId)> { let sid = self.case_shape_id(); let slot_id = builtins.shapes.resolve_slot(sid, name)?; Some((sid, slot_id)) } } impl Default for EnumImpl { fn default() -> Self { Self::new("") } } #[derive(Clone)] pub struct Enum { pub(super) imp: Rc, } impl Enum { pub fn new(name: &str) -> Self { Self { imp: Rc::new(EnumImpl::new(name)), } } pub fn new_with_cases(name: &str, cases: &[EnumCase], builtins: &mut VmGlobals) -> Self { let enumm = Self::new(name); enumm.imp.add_cases(builtins, cases); enumm } pub fn name(&self) -> &str { &self.imp.name } pub fn add_case(&self, builtins: &mut VmGlobals, case: EnumCase) -> usize { self.imp.add_case(builtins, case) } pub fn get_idx_of_case_by_symbol(&self, builtins: &VmGlobals, name: Symbol) -> Option { self.imp.get_idx_of_case_by_symbol(builtins, name) } pub fn get_case_by_idx(&self, idx: usize) -> Option { self.imp.get_case_by_idx(idx) } pub fn load_named_value(&self, builtins: &VmGlobals, name: Symbol) -> Option { self.imp.load_named_value(builtins, name) } pub fn include_mixin(&self, mixin: &Mixin) { self.imp.include_mixin(mixin); } pub fn isa_mixin(&self, mixin: &Mixin) -> bool { self.imp.isa_mixin(mixin) } pub fn make_value(&self, cidx: usize, payload: Option) -> Option { match self.get_case_by_idx(cidx) { Some(case) => { if case.payload_type.is_some() == payload.is_some() { Some(EnumValue { imp: Rc::new(EnumValueImpl { enumm: self.clone(), case: cidx, payload, }), }) } else { None } } _ => None, } } pub fn list_attributes(&self, builtins: &VmGlobals) -> FxHashSet { self.imp.list_attributes(builtins) } pub(crate) fn case_shape_id(&self) -> ShapeId { self.imp.case_shape_id() } pub fn insert_builtin(&self, builtins: &mut VmGlobals) where T: 'static + Default + BuiltinFunctionImpl, { let t = T::default(); let name = builtins .intern_symbol(t.name()) .expect("too many symbols interned"); self.imp.store_named_value( builtins, name, RuntimeValue::Function(Function::builtin_from(t)), ); } pub fn resolve_to_slot( &self, builtins: &crate::builtins::VmGlobals, name: Symbol, ) -> Option<(ShapeId, SlotId)> { self.imp.resolve_to_slot(builtins, name) } } impl PartialEq for Enum { fn eq(&self, other: &Self) -> bool { Rc::ptr_eq(&self.imp, &other.imp) } } impl Eq for Enum {} ================================================ FILE: vm-lib/src/runtime_value/float.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use super::{builtin_value::BuiltinValue, integer::IntegerValue}; pub type FloatValue = BuiltinValue; impl PartialEq for FloatValue { fn eq(&self, other: &IntegerValue) -> bool { self.raw_value() == other.to_fp().raw_value() } } impl std::ops::Add<&FloatValue> for &FloatValue { type Output = FloatValue; fn add(self, rhs: &FloatValue) -> Self::Output { From::from(self.raw_value() + rhs.raw_value()) } } impl std::ops::Sub<&FloatValue> for &FloatValue { type Output = FloatValue; fn sub(self, rhs: &FloatValue) -> Self::Output { From::from(self.raw_value() - rhs.raw_value()) } } impl std::ops::Mul<&FloatValue> for &FloatValue { type Output = FloatValue; fn mul(self, rhs: &FloatValue) -> Self::Output { From::from(self.raw_value() * rhs.raw_value()) } } impl std::ops::Div<&FloatValue> for &FloatValue { type Output = FloatValue; fn div(self, rhs: &FloatValue) -> Self::Output { From::from(self.raw_value() / rhs.raw_value()) } } impl std::ops::Rem<&FloatValue> for &FloatValue { type Output = FloatValue; fn rem(self, rhs: &FloatValue) -> Self::Output { From::from(self.raw_value() % rhs.raw_value()) } } impl std::ops::Neg for &FloatValue { type Output = FloatValue; fn neg(self) -> Self::Output { From::from(-self.raw_value()) } } impl PartialEq for FloatValue { fn eq(&self, other: &FloatValue) -> bool { self.raw_value() == other.raw_value() } } impl Eq for FloatValue {} impl PartialOrd for FloatValue { fn partial_cmp(&self, other: &FloatValue) -> Option { Some(self.cmp(other)) } } impl Ord for FloatValue { fn cmp(&self, other: &Self) -> std::cmp::Ordering { self.raw_value() .partial_cmp(other.raw_value()) .unwrap_or(std::cmp::Ordering::Equal) } } ================================================ FILE: vm-lib/src/runtime_value/function.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use std::{collections::HashMap, rc::Rc}; use aria_compiler::line_table::LineTable; use aria_parser::ast::SourcePointer; use haxby_opcodes::{ Opcode, function_attribs::{FUNC_ACCEPTS_VARARG, FUNC_IS_METHOD, METHOD_ATTRIBUTE_TYPE}, }; use rustc_data_structures::fx::FxHashSet; use crate::{ arity::Arity, builtins::VmGlobals, frame::Frame, runtime_module::RuntimeModule, symbol::Symbol, vm::{ExecutionResult, RunloopExit, VirtualMachine}, }; use super::{ CallResult, RuntimeValue, list::List, object::ObjectBox, runtime_code_object::CodeObject, }; pub trait BuiltinFunctionImpl { fn eval(&self, frame: &mut Frame, vm: &mut VirtualMachine) -> ExecutionResult; fn arity(&self) -> Arity; fn attrib_byte(&self) -> u8 { 0 } fn name(&self) -> &str; } pub struct BuiltinFunction { pub body: Rc, pub(crate) boxx: ObjectBox, } impl BuiltinFunction { pub fn new(body: Rc) -> Self { Self { body, boxx: Default::default(), } } } pub struct BytecodeFunction { pub name: String, pub body: Rc<[Opcode]>, pub sidecar: Rc<[std::cell::Cell>]>, pub arity: Arity, pub frame_size: u8, pub line_table: Rc, pub loc: SourcePointer, pub attrib_byte: u8, pub module: RuntimeModule, pub(crate) boxx: ObjectBox, uplevels: std::cell::RefCell>, } impl BytecodeFunction { pub(crate) fn store_uplevel(&self, idx: u8, val: RuntimeValue) { self.uplevels.borrow_mut().insert(idx, val); } pub(crate) fn read_uplevel(&self, idx: u8) -> Option { self.uplevels.borrow().get(&idx).cloned() } } #[derive(enum_as_inner::EnumAsInner)] pub(crate) enum FunctionImpl { BytecodeFunction(BytecodeFunction), BuiltinFunction(BuiltinFunction), } #[derive(Clone)] pub struct Function { pub(crate) imp: Rc, } impl FunctionImpl { pub(crate) fn attribute(&self) -> FunctionAttribute { match self { Self::BytecodeFunction(bc) => FunctionAttribute::from(bc.attrib_byte), Self::BuiltinFunction(bf) => FunctionAttribute::from(bf.body.attrib_byte()), } } pub(crate) fn line_table(&self) -> Option<&LineTable> { match self { Self::BytecodeFunction(bc) => Some(&bc.line_table), Self::BuiltinFunction(_) => None, } } pub(crate) fn arity(&self) -> Arity { match self { Self::BytecodeFunction(bc) => bc.arity, Self::BuiltinFunction(bf) => bf.body.arity(), } } pub(crate) fn frame_size(&self) -> u8 { match self { Self::BytecodeFunction(bc) => bc.frame_size, Self::BuiltinFunction(_) => 0, } } pub(crate) fn name(&self) -> &str { match self { Self::BytecodeFunction(bc) => &bc.name, Self::BuiltinFunction(bf) => bf.body.name(), } } pub(crate) fn loc(&self) -> Option<&SourcePointer> { match self { Self::BytecodeFunction(bc) => Some(&bc.loc), Self::BuiltinFunction(_) => None, } } fn get_attribute_store(&self) -> &ObjectBox { match self { Self::BytecodeFunction(bc) => &bc.boxx, Self::BuiltinFunction(bf) => &bf.boxx, } } } impl Function { pub fn attribute(&self) -> FunctionAttribute { self.imp.attribute() } pub fn line_table(&self) -> Option<&LineTable> { self.imp.line_table() } pub fn arity(&self) -> Arity { self.imp.arity() } pub fn frame_size(&self) -> u8 { self.imp.frame_size() } pub fn varargs(&self) -> bool { self.attribute().is_vararg() } pub fn name(&self) -> &str { self.imp.name() } pub fn loc(&self) -> Option<&SourcePointer> { self.imp.loc() } pub(super) fn get_attribute_store(&self) -> &ObjectBox { self.imp.get_attribute_store() } } pub struct FunctionAttribute { val: u8, } impl From for FunctionAttribute { fn from(val: u8) -> Self { Self { val } } } impl FunctionAttribute { pub fn is_free(&self) -> bool { self.val & FUNC_IS_METHOD == 0 } pub fn is_vararg(&self) -> bool { self.val & FUNC_ACCEPTS_VARARG != 0 } pub fn is_method(&self) -> bool { self.val & FUNC_IS_METHOD == FUNC_IS_METHOD } pub fn is_instance_method(&self) -> bool { self.is_method() && (self.val & METHOD_ATTRIBUTE_TYPE == 0) } pub fn is_type_method(&self) -> bool { self.is_method() && (self.val & METHOD_ATTRIBUTE_TYPE == METHOD_ATTRIBUTE_TYPE) } } impl FunctionImpl { pub fn new_builtin() -> Self where T: 'static + BuiltinFunctionImpl + Default, { Self::BuiltinFunction(BuiltinFunction::new(Rc::new(T::default()))) } pub fn builtin_from(val: T) -> Self where T: 'static + BuiltinFunctionImpl + Default, { Self::BuiltinFunction(BuiltinFunction::new(Rc::new(val))) } pub fn from_code_object(co: &CodeObject, m: &RuntimeModule) -> Self { let rc = co.body.clone(); let sidecar = (0..rc.len()) .map(|_| std::cell::Cell::new(None)) .collect::>(); let lt = co.line_table.clone(); let bcf = BytecodeFunction { name: co.name.clone(), body: rc, sidecar: sidecar.into(), arity: Arity { required: co.required_argc, optional: co.default_argc, }, frame_size: co.frame_size, line_table: lt, loc: co.loc.clone(), attrib_byte: co.attribute, module: m.clone(), boxx: Default::default(), uplevels: Default::default(), }; Self::BytecodeFunction(bcf) } fn read(&self, builtins: &VmGlobals, name: Symbol) -> Option { match self { FunctionImpl::BytecodeFunction(b) => &b.boxx, FunctionImpl::BuiltinFunction(b) => &b.boxx, } .read(builtins, name) } fn list_attributes(&self, builtins: &VmGlobals) -> FxHashSet { match self { FunctionImpl::BytecodeFunction(b) => b.boxx.list_attributes(builtins), FunctionImpl::BuiltinFunction(b) => b.boxx.list_attributes(builtins), } } } #[derive(Default)] pub struct PartialFunctionApplication { suffix_args: Vec, } impl PartialFunctionApplication { pub fn with_suffix_arg(mut self, arg: RuntimeValue) -> Self { self.suffix_args.push(arg); self } } impl Function { pub fn new_builtin() -> Self where T: 'static + BuiltinFunctionImpl + Default, { Self { imp: Rc::new(FunctionImpl::new_builtin::()), } } pub fn builtin_from(val: T) -> Self where T: 'static + BuiltinFunctionImpl + Default, { Self { imp: Rc::new(FunctionImpl::builtin_from(val)), } } pub fn from_code_object(co: &CodeObject, m: &RuntimeModule) -> Self { Self { imp: Rc::new(FunctionImpl::from_code_object(co, m)), } } pub fn read(&self, builtins: &VmGlobals, name: Symbol) -> Option { self.imp.read(builtins, name) } pub fn list_attributes(&self, builtins: &VmGlobals) -> FxHashSet { self.imp.list_attributes(builtins) } // DO NOT CALL unless you are Function or BoundFunction pub(super) fn eval_in_frame( &self, argc: u8, target_frame: &mut Frame, vm: &mut VirtualMachine, ) -> ExecutionResult { match self.imp.as_ref() { FunctionImpl::BytecodeFunction(bcf) => { target_frame.set_argc(argc); vm.eval_bytecode_in_frame(&bcf.module, &bcf.body, &bcf.sidecar, target_frame) } FunctionImpl::BuiltinFunction(bnf) => bnf.body.eval(target_frame, vm), } } pub fn eval( &self, argc: u8, cur_frame: &mut Frame, vm: &mut VirtualMachine, other_args: &PartialFunctionApplication, discard_result: bool, ) -> ExecutionResult { let other_argc = other_args.suffix_args.len() as u8; let effective_argc = argc + other_argc; let fixed_arity = self.arity().required + self.arity().optional; if self.attribute().is_vararg() { if effective_argc < self.arity().required { return Err( crate::error::vm_error::VmErrorReason::MismatchedArgumentCount( self.arity().required as usize, effective_argc as usize, ) .into(), ); } } else { if effective_argc < self.arity().required { return Err( crate::error::vm_error::VmErrorReason::MismatchedArgumentCount( self.arity().required as usize, effective_argc as usize, ) .into(), ); } if effective_argc > fixed_arity { return Err( crate::error::vm_error::VmErrorReason::MismatchedArgumentCount( fixed_arity as usize, effective_argc as usize, ) .into(), ); } } let mut new_frame = vm.acquire_frame(self); if self.attribute().is_vararg() { let mut popped_args = cur_frame.stack.pop_count(argc as usize); let split_at = (fixed_arity - other_argc) as usize; let varargs = popped_args.split_off(split_at.min(popped_args.len())); let l = List::default(); for arg in varargs { l.append(arg); } new_frame.stack.push(super::RuntimeValue::List(l)); for arg in popped_args.into_iter().rev() { new_frame.stack.push(arg); } } else { for item in cur_frame.stack.pop_count(argc as usize).into_iter().rev() { new_frame.stack.push(item); } } for arg in &other_args.suffix_args { new_frame.stack.push(arg.clone()); } let eval_result = self.eval_in_frame(effective_argc, &mut new_frame, vm); let result = match eval_result { Ok(RunloopExit::Ok(_)) => match new_frame.stack.try_pop() { Some(ret) => { if !discard_result { cur_frame.stack.push(ret.clone()); } Ok(CallResult::Ok(ret)) } _ => panic!("functions must return a value"), }, Ok(RunloopExit::Exception(e)) => Ok(CallResult::Exception(e)), Err(err) => Err(err), }; vm.release_frame(new_frame); result } } impl PartialEq for FunctionImpl { fn eq(&self, other: &Self) -> bool { match (self, other) { (Self::BytecodeFunction(l0), Self::BytecodeFunction(r0)) => { Rc::ptr_eq(&l0.body, &r0.body) } (Self::BuiltinFunction(l0), Self::BuiltinFunction(r0)) => { Rc::ptr_eq(&l0.body, &r0.body) } _ => false, } } } impl Eq for FunctionImpl {} impl PartialEq for Function { fn eq(&self, other: &Self) -> bool { Rc::ptr_eq(&self.imp, &other.imp) || self.imp.eq(&other.imp) } } impl Eq for Function {} impl std::fmt::Debug for Function { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let name = self.name(); if let Some(loc) = self.loc() { write!(f, "") } else { write!(f, "") } } } ================================================ FILE: vm-lib/src/runtime_value/integer.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use super::{builtin_value::BuiltinValue, float::FloatValue}; pub type IntegerValue = BuiltinValue; impl IntegerValue { pub fn to_fp(&self) -> FloatValue { (*self.raw_value() as f64).into() } } impl PartialEq for IntegerValue { fn eq(&self, other: &FloatValue) -> bool { self.to_fp() == *other } } impl std::ops::Add<&IntegerValue> for &IntegerValue { type Output = IntegerValue; #[inline] fn add(self, rhs: &IntegerValue) -> Self::Output { From::from(self.raw_value().wrapping_add(*rhs.raw_value())) } } impl std::ops::Sub<&IntegerValue> for &IntegerValue { type Output = IntegerValue; #[inline] fn sub(self, rhs: &IntegerValue) -> Self::Output { From::from(self.raw_value().wrapping_sub(*rhs.raw_value())) } } impl std::ops::Mul<&IntegerValue> for &IntegerValue { type Output = IntegerValue; #[inline] fn mul(self, rhs: &IntegerValue) -> Self::Output { From::from(self.raw_value().wrapping_mul(*rhs.raw_value())) } } impl std::ops::Div<&IntegerValue> for &IntegerValue { type Output = IntegerValue; #[inline] fn div(self, rhs: &IntegerValue) -> Self::Output { From::from(self.raw_value().wrapping_div(*rhs.raw_value())) } } impl std::ops::Rem<&IntegerValue> for &IntegerValue { type Output = IntegerValue; #[inline] fn rem(self, rhs: &IntegerValue) -> Self::Output { From::from(self.raw_value().wrapping_rem(*rhs.raw_value())) } } impl std::ops::Neg for &IntegerValue { type Output = IntegerValue; #[inline] fn neg(self) -> Self::Output { From::from(-self.raw_value()) } } impl std::ops::BitAnd<&IntegerValue> for &IntegerValue { type Output = IntegerValue; #[inline] fn bitand(self, rhs: &IntegerValue) -> Self::Output { From::from(self.raw_value() & rhs.raw_value()) } } impl std::ops::BitOr<&IntegerValue> for &IntegerValue { type Output = IntegerValue; #[inline] fn bitor(self, rhs: &IntegerValue) -> Self::Output { From::from(self.raw_value() | rhs.raw_value()) } } impl std::ops::BitXor<&IntegerValue> for &IntegerValue { type Output = IntegerValue; #[inline] fn bitxor(self, rhs: &IntegerValue) -> Self::Output { From::from(self.raw_value() ^ rhs.raw_value()) } } impl std::ops::Shl<&IntegerValue> for &IntegerValue { type Output = IntegerValue; #[inline] fn shl(self, rhs: &IntegerValue) -> Self::Output { From::from(self.raw_value() << rhs.raw_value()) } } impl std::ops::Shr<&IntegerValue> for &IntegerValue { type Output = IntegerValue; #[inline] fn shr(self, rhs: &IntegerValue) -> Self::Output { From::from(self.raw_value() >> rhs.raw_value()) } } impl PartialEq for IntegerValue { #[inline] fn eq(&self, other: &IntegerValue) -> bool { self.raw_value() == other.raw_value() } } impl Eq for IntegerValue {} impl PartialOrd for IntegerValue { #[inline] fn partial_cmp(&self, other: &IntegerValue) -> Option { Some(self.cmp(other)) } } impl Ord for IntegerValue { #[inline] fn cmp(&self, other: &Self) -> std::cmp::Ordering { self.raw_value().cmp(other.raw_value()) } } impl PartialEq for IntegerValue { #[inline] fn eq(&self, other: &i64) -> bool { *self.raw_value() == *other } } ================================================ FILE: vm-lib/src/runtime_value/isa.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use crate::builtins::VmGlobals; use crate::runtime_value::mixin::Mixin; use crate::runtime_value::{RuntimeValue, RuntimeValueType}; #[derive(Clone, PartialEq, Eq)] pub enum IsaCheckable { Type(RuntimeValueType), Mixin(Mixin), Union(Vec), Intersection(Vec), } impl std::fmt::Debug for IsaCheckable { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { IsaCheckable::Type(t) => write!(f, "({:?})", t), IsaCheckable::Mixin(m) => write!(f, "", m.name()), IsaCheckable::Union(us) => { write!(f, "(")?; for (i, u) in us.iter().enumerate() { if i > 0 { write!(f, " | ")?; } write!(f, "{:?}", u)?; } write!(f, ")") } IsaCheckable::Intersection(is) => { write!(f, "(")?; for (i, u) in is.iter().enumerate() { if i > 0 { write!(f, " & ")?; } write!(f, "{:?}", u)?; } write!(f, ")") } } } } impl IsaCheckable { fn isa(val: &RuntimeValue, t: &RuntimeValueType, builtins: &VmGlobals) -> bool { match t { RuntimeValueType::Any => true, RuntimeValueType::Union(u) => { for u_k in u { if Self::isa(val, u_k, builtins) { return true; } } false } _ => RuntimeValueType::get_type(val, builtins) == *t, } } fn isa_mixin(val: &RuntimeValue, mixin: &Mixin, builtins: &VmGlobals) -> bool { if let Some(obj) = val.as_object() { obj.get_struct().isa_mixin(mixin) } else if let Some(env) = val.as_enum_value() { env.get_container_enum().isa_mixin(mixin) } else if let Some(m) = val.as_mixin() { m.isa_mixin(mixin) } else if let Some(st) = val.as_struct() { st.isa_mixin(mixin) } else if let Some(en) = val.as_enum() { en.isa_mixin(mixin) } else if let Some(btt) = RuntimeValueType::get_type(val, builtins).as_rust_native() { btt.isa_mixin(mixin) } else { false } } } impl IsaCheckable { pub fn isa_check(&self, other: &RuntimeValue, builtins: &VmGlobals) -> bool { match self { IsaCheckable::Type(t) => IsaCheckable::isa(other, t, builtins), IsaCheckable::Mixin(m) => IsaCheckable::isa_mixin(other, m, builtins), IsaCheckable::Union(us) => us.iter().any(|u| u.isa_check(other, builtins)), IsaCheckable::Intersection(is) => is.iter().all(|i| i.isa_check(other, builtins)), } } pub fn any() -> Self { IsaCheckable::Type(RuntimeValueType::Any) } } impl TryFrom<&RuntimeValue> for IsaCheckable { type Error = (); fn try_from(value: &RuntimeValue) -> Result { if let Some(mixin) = value.as_mixin() { Ok(IsaCheckable::Mixin(mixin.clone())) } else if let Some(t) = value.as_type() { Ok(IsaCheckable::Type(t.clone())) } else if let Some(c) = value.as_type_check() { Ok(c.clone()) } else { Err(()) } } } impl std::ops::BitOr<&IsaCheckable> for IsaCheckable { type Output = IsaCheckable; fn bitor(self, rhs: &IsaCheckable) -> Self::Output { match (self, rhs) { (IsaCheckable::Union(xs), IsaCheckable::Union(ys)) => { let mut combined = xs; for y in ys { if !combined.contains(y) { combined.push(y.clone()); } } IsaCheckable::Union(combined) } (IsaCheckable::Union(xs), y) => { let mut combined = xs; if !combined.contains(y) { combined.push(y.clone()); } IsaCheckable::Union(combined) } (x, IsaCheckable::Union(ys)) => { let mut combined = ys.clone(); if !combined.contains(&x) { combined.push(x); } IsaCheckable::Union(combined) } (x, y) => { if x == *y { x } else { IsaCheckable::Union(vec![x, y.clone()]) } } } } } impl std::ops::BitAnd<&IsaCheckable> for IsaCheckable { type Output = IsaCheckable; fn bitand(self, rhs: &IsaCheckable) -> Self::Output { match (self, rhs) { (IsaCheckable::Intersection(xs), IsaCheckable::Intersection(ys)) => { let mut combined = xs; for y in ys { if !combined.contains(y) { combined.push(y.clone()); } } IsaCheckable::Intersection(combined) } (IsaCheckable::Intersection(xs), y) => { let mut combined = xs; if !combined.contains(y) { combined.push(y.clone()); } IsaCheckable::Intersection(combined) } (x, IsaCheckable::Intersection(ys)) => { let mut combined = ys.clone(); if !combined.contains(&x) { combined.push(x); } IsaCheckable::Intersection(combined) } (x, y) => { if x == *y { x } else { IsaCheckable::Intersection(vec![x, y.clone()]) } } } } } ================================================ FILE: vm-lib/src/runtime_value/kind.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use enum_as_inner::EnumAsInner; use haxby_opcodes::BuiltinTypeId; use rustc_data_structures::fx::FxHashSet; use crate::{arity::Arity, builtins::VmGlobals, symbol::Symbol}; use super::{ AttributeError, RuntimeValue, enumeration::Enum, rust_native_type::RustNativeType, structure::Struct, }; #[derive(Clone, PartialEq, Eq)] pub struct FunctionType { pub arity: Arity, pub varargs: bool, } impl std::fmt::Debug for FunctionType { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!( f, "({}, {}{})", self.arity.required, self.arity.optional, if self.varargs { ", ..." } else { "" } ) } } #[derive(EnumAsInner, Clone)] pub enum RuntimeValueType { Any, RustNative(RustNativeType), CodeObject, Module, Function(FunctionType), BoundFunction(FunctionType), Mixin, Opaque, TypeCheck, Struct(Struct), Enum(Enum), Union(Vec), } impl PartialEq for RuntimeValueType { fn eq(&self, other: &Self) -> bool { match (self, other) { (Self::Function(f0), Self::Function(f1)) => f0 == f1, (Self::BoundFunction(f0), Self::BoundFunction(f1)) => f0 == f1, (Self::RustNative(l0), Self::RustNative(r0)) => l0 == r0, (Self::Struct(l0), Self::Struct(r0)) => l0 == r0, (Self::Enum(l0), Self::Enum(r0)) => l0 == r0, (Self::Union(l0), Self::Union(r0)) => { if l0.len() != r0.len() { false } else { for vk_a in l0 { if !r0.contains(vk_a) { return false; } } true } } _ => core::mem::discriminant(self) == core::mem::discriminant(other), } } } impl Eq for RuntimeValueType {} impl RuntimeValueType { pub fn get_type(value: &RuntimeValue, builtins: &VmGlobals) -> Self { match value { RuntimeValue::Object(obj) => Self::Struct(obj.get_struct().clone()), RuntimeValue::EnumValue(env) => Self::Enum(env.get_container_enum().clone()), RuntimeValue::CodeObject(_) => Self::CodeObject, RuntimeValue::Module(_) => Self::Module, RuntimeValue::Mixin(_) => Self::Mixin, RuntimeValue::Opaque(_) => Self::Opaque, RuntimeValue::TypeCheck(_) => Self::TypeCheck, RuntimeValue::Function(f) => Self::Function(FunctionType { arity: f.arity(), varargs: f.varargs(), }), RuntimeValue::BoundFunction(bf) => Self::Function(FunctionType { arity: bf.func().arity(), varargs: bf.func().varargs(), }), RuntimeValue::Type(_) => builtins.get_builtin_type_by_id(BuiltinTypeId::Type), RuntimeValue::Boolean(_) => builtins.get_builtin_type_by_id(BuiltinTypeId::Bool), RuntimeValue::Integer(_) => builtins.get_builtin_type_by_id(BuiltinTypeId::Int), RuntimeValue::Float(_) => builtins.get_builtin_type_by_id(BuiltinTypeId::Float), RuntimeValue::List(_) => builtins.get_builtin_type_by_id(BuiltinTypeId::List), RuntimeValue::String(_) => builtins.get_builtin_type_by_id(BuiltinTypeId::String), } } } impl std::fmt::Debug for RuntimeValueType { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { Self::Any => write!(f, "Any"), Self::RustNative(b) => write!(f, "{b:?}"), Self::CodeObject => write!(f, "CodeObject"), Self::Module => write!(f, "Module"), Self::Mixin => write!(f, "Mixin"), Self::Opaque => write!(f, "Opaque"), Self::TypeCheck => write!(f, "TypeCheck"), Self::Function(ft) => write!(f, "Function{ft:?}"), Self::BoundFunction(ft) => write!(f, "BoundFunction{ft:?}"), Self::Struct(s) => write!(f, "Struct {}", s.name()), Self::Enum(e) => write!(f, "Enum {}", e.name()), Self::Union(v) => { let us = v .iter() .map(|x| format!("{x:?}")) .collect::>() .join("|"); write!(f, "{us}") } } } } impl std::ops::BitOr<&RuntimeValueType> for &RuntimeValueType { type Output = RuntimeValueType; fn bitor(self, rhs: &RuntimeValueType) -> Self::Output { if *self == *rhs { return self.clone(); } match (self, rhs) { (RuntimeValueType::Any, _) | (_, RuntimeValueType::Any) => RuntimeValueType::Any, (RuntimeValueType::Union(a), RuntimeValueType::Union(b)) => { let mut uret = a.clone(); for b_vk in b { if !uret.contains(b_vk) { uret.push(b_vk.clone()) } } RuntimeValueType::Union(uret) } (RuntimeValueType::Union(a), _) => { if a.contains(rhs) { self.clone() } else { let mut uret = a.clone(); uret.push(rhs.clone()); RuntimeValueType::Union(uret) } } (_, RuntimeValueType::Union(b)) => { if b.contains(self) { rhs.clone() } else { let mut uret = b.clone(); uret.push(self.clone()); RuntimeValueType::Union(uret) } } _ => RuntimeValueType::Union(vec![self.clone(), rhs.clone()]), } } } impl RuntimeValueType { pub fn read_attribute( &self, builtins: &VmGlobals, attr_name: Symbol, ) -> Result { if let Some(struk) = self.as_struct() { match struk.load_named_value(builtins, attr_name) { Some(x) => Ok(x), None => Err(AttributeError::NoSuchAttribute), } } else if let Some(enumm) = self.as_enum() { match enumm.load_named_value(builtins, attr_name) { Some(x) => Ok(x), None => Err(AttributeError::NoSuchAttribute), } } else if let Some(bt) = self.as_rust_native() { match bt.read(builtins, attr_name) { Some(x) => Ok(x), None => Err(AttributeError::NoSuchAttribute), } } else { Err(AttributeError::ValueHasNoAttributes) } } pub(super) fn get_attribute_store(&self) -> Option<&super::object::ObjectBox> { match self { RuntimeValueType::RustNative(rt) => Some(rt.get_boxx().as_ref()), RuntimeValueType::Struct(st) => Some(&st.imp.as_ref().entries), RuntimeValueType::Enum(en) => Some(&en.imp.as_ref().entries), RuntimeValueType::Union(_) => None, RuntimeValueType::Function(_) => None, RuntimeValueType::BoundFunction(_) => None, RuntimeValueType::CodeObject => None, RuntimeValueType::Module => None, RuntimeValueType::Mixin => None, RuntimeValueType::Opaque => None, RuntimeValueType::TypeCheck => None, RuntimeValueType::Any => None, } } pub fn list_attributes(&self, builtins: &VmGlobals) -> FxHashSet { if let Some(struk) = self.as_struct() { struk.list_attributes(builtins) } else if let Some(enumm) = self.as_enum() { enumm.list_attributes(builtins) } else if let Some(bt) = self.as_rust_native() { bt.list_attributes(builtins) } else { Default::default() } } } ================================================ FILE: vm-lib/src/runtime_value/list.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use std::{cell::UnsafeCell, rc::Rc}; use rustc_data_structures::fx::FxHashSet; use crate::{ builtins::VmGlobals, error::vm_error::{VmError, VmErrorReason}, frame::Frame, runtime_value::object::ObjectBox, symbol::Symbol, vm::{ExecutionResult, VirtualMachine}, }; use super::RuntimeValue; #[derive(Default)] pub(super) struct ListImpl { values: UnsafeCell>, pub(super) boxx: ObjectBox, } impl ListImpl { #[allow(clippy::mut_from_ref)] #[inline] fn get(&self) -> &Vec { unsafe { &*self.values.get() } } #[allow(clippy::mut_from_ref)] #[inline] fn get_mut(&self) -> &mut Vec { unsafe { &mut *self.values.get() } } fn new_with_capacity(cap: usize) -> Self { Self { values: UnsafeCell::new(Vec::with_capacity(cap)), boxx: ObjectBox::default(), } } fn len(&self) -> usize { self.get().len() } fn is_empty(&self) -> bool { self.get().is_empty() } fn get_at(&self, idx: usize) -> Option { self.get().get(idx).cloned() } fn append(&self, val: RuntimeValue) { self.get_mut().push(val) } fn pop(&self) { self.get_mut().pop(); } fn set_at(&self, idx: usize, val: RuntimeValue) -> Result<(), VmErrorReason> { match idx.cmp(&self.len()) { std::cmp::Ordering::Less => { self.get_mut()[idx] = val; Ok(()) } std::cmp::Ordering::Equal => { self.append(val); Ok(()) } std::cmp::Ordering::Greater => Err(VmErrorReason::IndexOutOfBounds(idx)), } } fn read(&self, builtins: &VmGlobals, name: Symbol) -> Option { self.boxx.read(builtins, name) } fn list_attributes(&self, builtins: &VmGlobals) -> FxHashSet { self.boxx.list_attributes(builtins) } } impl std::fmt::Debug for ListImpl { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let li = self.get(); write!( f, "[{}]", li.iter() .map(|x| format!("{x:?}")) .collect::>() .join(",") ) } } #[derive(Clone, Default)] pub struct List { pub(super) imp: Rc, } impl List { pub fn from(values: &[RuntimeValue]) -> Self { let ret = Self::default(); values.iter().cloned().for_each(|v| ret.append(v)); ret } pub fn new_with_capacity(cap: usize) -> Self { Self { imp: Rc::new(ListImpl::new_with_capacity(cap)), } } pub fn len(&self) -> usize { self.imp.len() } pub fn is_empty(&self) -> bool { self.imp.is_empty() } pub fn get_at(&self, idx: usize) -> Option { self.imp.get_at(idx) } pub fn append(&self, val: RuntimeValue) { self.imp.append(val) } pub fn pop(&self) { self.imp.pop() } pub fn set_at(&self, idx: usize, val: RuntimeValue) -> Result<(), VmErrorReason> { self.imp.set_at(idx, val) } pub fn read_index( &self, idx: &RuntimeValue, _: &mut Frame, _: &mut VirtualMachine, ) -> Result { if let Some(i) = idx.as_integer() { match self.get_at(*i.raw_value() as usize) { Some(val) => Ok(val), _ => Err(VmErrorReason::IndexOutOfBounds(*i.raw_value() as usize).into()), } } else { Err(VmErrorReason::UnexpectedType.into()) } } pub fn write_index( &self, idx: &RuntimeValue, val: &RuntimeValue, _: &mut Frame, _: &mut VirtualMachine, ) -> ExecutionResult { if let Some(i) = idx.as_integer() { self.set_at(*i.raw_value() as usize, val.clone())?; Ok(()) } else { Err(VmErrorReason::UnexpectedType.into()) } } pub fn read(&self, builtins: &VmGlobals, name: Symbol) -> Option { self.imp.read(builtins, name) } pub fn list_attributes(&self, builtins: &VmGlobals) -> FxHashSet { self.imp.list_attributes(builtins) } } impl std::fmt::Debug for List { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "{:?}", self.imp) } } impl PartialEq for List { fn eq(&self, other: &Self) -> bool { Rc::ptr_eq(&self.imp, &other.imp) } } impl Eq for List {} ================================================ FILE: vm-lib/src/runtime_value/mixin.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use std::{cell::RefCell, rc::Rc}; use rustc_data_structures::fx::FxHashSet; use crate::{builtins::VmGlobals, runtime_value::object::ObjectBox, symbol::Symbol}; use super::RuntimeValue; pub(super) struct MixinImpl { name: String, pub(super) entries: ObjectBox, mixins: RefCell, } impl MixinImpl { fn new(name: &str) -> Self { Self { name: name.to_owned(), entries: ObjectBox::default(), mixins: RefCell::new(crate::mixin_includer::MixinIncluder::default()), } } fn load_named_value(&self, builtins: &VmGlobals, name: Symbol) -> Option { if let Some(val) = self.entries.read(builtins, name) { Some(val.clone()) } else { self.mixins.borrow().load_named_value(builtins, name) } } fn named_values(&self, builtins: &VmGlobals) -> Vec { self.entries.list_attributes(builtins).into_iter().collect() } fn include_mixin(&self, mixin: &Mixin) { self.mixins.borrow_mut().include(mixin.clone()); } fn isa_mixin(&self, mixin: &Mixin) -> bool { self.mixins.borrow().contains(mixin) } fn list_attributes(&self, builtins: &VmGlobals) -> FxHashSet { let mut attrs = self.entries.list_attributes(builtins); attrs.extend(self.mixins.borrow().list_attributes(builtins)); attrs } } #[derive(Clone)] pub struct Mixin { pub(super) imp: Rc, } impl Mixin { pub fn new(name: &str) -> Self { Self { imp: Rc::new(MixinImpl::new(name)), } } pub fn name(&self) -> &str { &self.imp.name } pub fn load_named_value(&self, builtins: &VmGlobals, name: Symbol) -> Option { self.imp.load_named_value(builtins, name) } pub fn named_values(&self, builtins: &VmGlobals) -> Vec { self.imp.named_values(builtins) } pub fn include_mixin(&self, mixin: &Mixin) { self.imp.include_mixin(mixin); } pub fn isa_mixin(&self, mixin: &Mixin) -> bool { self == mixin || self.imp.isa_mixin(mixin) } pub fn list_attributes(&self, builtins: &VmGlobals) -> FxHashSet { self.imp.list_attributes(builtins) } } impl PartialEq for Mixin { fn eq(&self, other: &Self) -> bool { Rc::ptr_eq(&self.imp, &other.imp) } } impl Eq for Mixin {} ================================================ FILE: vm-lib/src/runtime_value/mod.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use std::rc::Rc; use aria_compiler::constant_value::ConstantValue; use boolean::BooleanValue; use bound_function::BoundFunction; use enum_as_inner::EnumAsInner; use enum_case::EnumValue; use enumeration::Enum; use float::FloatValue; use function::Function; use haxby_opcodes::BuiltinTypeId; use integer::IntegerValue; use kind::RuntimeValueType; use list::List; use mixin::Mixin; use object::Object; use opaque::OpaqueValue; use runtime_code_object::CodeObject; use rust_native_type::RustNativeType; use string::StringValue; use structure::Struct; use crate::{ builtins::VmGlobals, error::vm_error::VmErrorReason, frame::Frame, runtime_module::RuntimeModule, runtime_value::isa::IsaCheckable, symbol::{ INTERNED_OP_IMPL_CALL, INTERNED_OP_IMPL_EQUALS, INTERNED_OP_IMPL_READ_INDEX, INTERNED_OP_IMPL_WRITE_INDEX, INTERNED_OP_PRETTYPRINT, Symbol, }, vm::{ExecutionResult, VirtualMachine}, }; pub mod boolean; pub mod bound_function; pub mod builtin_value; pub mod enum_case; pub mod enumeration; pub mod float; pub mod function; pub mod integer; pub mod isa; pub mod kind; pub mod list; pub mod mixin; pub mod object; pub mod opaque; pub mod runtime_code_object; pub mod rust_native_type; pub mod string; pub mod structure; #[derive(EnumAsInner, Clone)] pub enum RuntimeValue { Integer(IntegerValue), String(StringValue), Float(FloatValue), Boolean(BooleanValue), Object(Object), EnumValue(EnumValue), CodeObject(CodeObject), Function(Function), BoundFunction(BoundFunction), List(List), Mixin(Mixin), Type(RuntimeValueType), Module(RuntimeModule), Opaque(OpaqueValue), TypeCheck(IsaCheckable), } impl RuntimeValue { pub fn builtin_equals( &self, other: &Self, cur_frame: &mut Frame, vm: &mut VirtualMachine, ) -> bool { match (self, other) { (Self::Integer(l0), Self::Integer(r0)) => l0 == r0, (Self::Float(l0), Self::Float(r0)) => l0 == r0, (Self::Float(l0), Self::Integer(r0)) => l0 == r0, (Self::Integer(l0), Self::Float(r0)) => l0 == r0, (Self::Boolean(l0), Self::Boolean(r0)) => l0 == r0, (Self::String(l0), Self::String(r0)) => l0 == r0, (Self::Object(l0), Self::Object(r0)) => l0 == r0, (Self::Mixin(l0), Self::Mixin(r0)) => l0 == r0, (Self::Module(l0), Self::Module(r0)) => l0 == r0, (Self::EnumValue(l0), Self::EnumValue(r0)) => l0.builtin_equals(r0, cur_frame, vm), (Self::CodeObject(l0), Self::CodeObject(r0)) => l0 == r0, (Self::Function(l0), Self::Function(r0)) => l0 == r0, (Self::BoundFunction(l0), Self::BoundFunction(r0)) => l0 == r0, (Self::List(l0), Self::List(r0)) => l0 == r0, (Self::Type(l0), Self::Type(r0)) => l0 == r0, (Self::TypeCheck(l0), Self::TypeCheck(r0)) => l0 == r0, _ => false, } } } pub(crate) enum OperatorEvalAttemptOutcome { Ok(SuccessType), Exception(crate::error::exception::VmException), Error(crate::error::vm_error::VmError), NeedTryROperator, } pub(crate) enum OperatorEvalOutcome { Ok(SuccessType), Exception(crate::error::exception::VmException), Error(crate::error::vm_error::VmError), } impl RuntimeValue { pub(crate) fn is_builtin_unimplemented(&self, vm: &mut VirtualMachine) -> bool { if let Some(s) = self.as_object() { let unimp = vm .globals .get_builtin_type_by_id(BuiltinTypeId::Unimplemented); let unimplemented = unimp.as_struct().unwrap(); return s.get_struct() == unimplemented; } false } fn try_eval_rel_op( rel_op_obj: RuntimeValue, other_val: &RuntimeValue, cur_frame: &mut Frame, vm: &mut VirtualMachine, ) -> OperatorEvalAttemptOutcome { cur_frame.stack.push(other_val.clone()); match rel_op_obj.eval(1, cur_frame, vm, true) { Ok(cr) => match cr { CallResult::Ok(rv) => { if let Some(bl) = rv.as_boolean() { OperatorEvalAttemptOutcome::Ok(*bl.raw_value()) } else { OperatorEvalAttemptOutcome::NeedTryROperator } } CallResult::Exception(e) => { if e.is_builtin_unimplemented(vm) { OperatorEvalAttemptOutcome::NeedTryROperator } else { OperatorEvalAttemptOutcome::Exception(e) } } }, Err(err) => OperatorEvalAttemptOutcome::Error(err), } } fn try_eval_bin_op( op_equals: RuntimeValue, other_val: &RuntimeValue, cur_frame: &mut Frame, vm: &mut VirtualMachine, ) -> OperatorEvalAttemptOutcome { cur_frame.stack.push(other_val.clone()); match op_equals.eval(1, cur_frame, vm, true) { Ok(cr) => match cr { CallResult::Ok(rv) => OperatorEvalAttemptOutcome::Ok(rv), CallResult::Exception(e) => { if e.is_builtin_unimplemented(vm) { OperatorEvalAttemptOutcome::NeedTryROperator } else { OperatorEvalAttemptOutcome::Exception(e) } } }, Err(e) => OperatorEvalAttemptOutcome::Error(e), } } fn try_eval_unary_op( op: RuntimeValue, cur_frame: &mut Frame, vm: &mut VirtualMachine, ) -> OperatorEvalAttemptOutcome { match op.eval(0, cur_frame, vm, true) { Ok(cr) => match cr { CallResult::Ok(rv) => OperatorEvalAttemptOutcome::Ok(rv), CallResult::Exception(e) => { if e.is_builtin_unimplemented(vm) { OperatorEvalAttemptOutcome::NeedTryROperator } else { OperatorEvalAttemptOutcome::Exception(e) } } }, Err(e) => OperatorEvalAttemptOutcome::Error(e), } } pub fn equals( lhs: &RuntimeValue, rhs: &RuntimeValue, cur_frame: &mut Frame, vm: &mut VirtualMachine, ) -> bool { if let Ok(op_equals) = lhs.read_attribute(INTERNED_OP_IMPL_EQUALS, &vm.globals) { match RuntimeValue::try_eval_rel_op(op_equals, rhs, cur_frame, vm) { OperatorEvalAttemptOutcome::Ok(val) => { return val; } OperatorEvalAttemptOutcome::Exception(_) => { return lhs.builtin_equals(rhs, cur_frame, vm); } OperatorEvalAttemptOutcome::Error(_) => { return lhs.builtin_equals(rhs, cur_frame, vm); } OperatorEvalAttemptOutcome::NeedTryROperator => {} } } if RuntimeValueType::get_type(lhs, &vm.globals) == RuntimeValueType::get_type(rhs, &vm.globals) { return lhs.builtin_equals(rhs, cur_frame, vm); } if let Ok(op_equals) = rhs.read_attribute(INTERNED_OP_IMPL_EQUALS, &vm.globals) { return match RuntimeValue::try_eval_rel_op(op_equals, lhs, cur_frame, vm) { OperatorEvalAttemptOutcome::Ok(val) => val, OperatorEvalAttemptOutcome::Exception(_) | OperatorEvalAttemptOutcome::Error(_) | OperatorEvalAttemptOutcome::NeedTryROperator => { lhs.builtin_equals(rhs, cur_frame, vm) } }; } lhs.builtin_equals(rhs, cur_frame, vm) } } macro_rules! rel_op_impl { ($rust_fn_name: ident, $aria_fwd_sym: expr, $aria_rev_sym: expr) => { impl RuntimeValue { pub(crate) fn $rust_fn_name( lhs: &RuntimeValue, rhs: &RuntimeValue, cur_frame: &mut Frame, vm: &mut VirtualMachine, ) -> OperatorEvalOutcome { if let Ok(op) = lhs.read_attribute($aria_fwd_sym, &vm.globals) { match RuntimeValue::try_eval_rel_op(op, rhs, cur_frame, vm) { OperatorEvalAttemptOutcome::Ok(rv) => { return OperatorEvalOutcome::Ok(RuntimeValue::Boolean(rv.into())); } OperatorEvalAttemptOutcome::Exception(e) => { return OperatorEvalOutcome::Exception(e); } OperatorEvalAttemptOutcome::Error(e) => { return OperatorEvalOutcome::Error(e); } OperatorEvalAttemptOutcome::NeedTryROperator => {} } } if RuntimeValueType::get_type(lhs, &vm.globals) == RuntimeValueType::get_type(rhs, &vm.globals) { return OperatorEvalOutcome::Error(VmErrorReason::UnexpectedType.into()); } if let Ok(op) = rhs.read_attribute($aria_rev_sym, &vm.globals) { match RuntimeValue::try_eval_rel_op(op, lhs, cur_frame, vm) { OperatorEvalAttemptOutcome::Ok(rv) => { return OperatorEvalOutcome::Ok(RuntimeValue::Boolean(rv.into())); } OperatorEvalAttemptOutcome::Exception(e) => { OperatorEvalOutcome::Exception(e) } OperatorEvalAttemptOutcome::Error(e) => OperatorEvalOutcome::Error(e), OperatorEvalAttemptOutcome::NeedTryROperator => { OperatorEvalOutcome::Error(VmErrorReason::UnexpectedType.into()) } } } else { OperatorEvalOutcome::Error(VmErrorReason::UnexpectedType.into()) } } } }; } macro_rules! bin_op_impl { ($rust_fn_name: ident, $aria_fwd_sym: expr, $aria_rev_sym: expr) => { impl RuntimeValue { pub(crate) fn $rust_fn_name( lhs: &RuntimeValue, rhs: &RuntimeValue, cur_frame: &mut Frame, vm: &mut VirtualMachine, ) -> OperatorEvalOutcome { if let Ok(op) = lhs.read_attribute($aria_fwd_sym, &vm.globals) { match RuntimeValue::try_eval_bin_op(op, rhs, cur_frame, vm) { OperatorEvalAttemptOutcome::Ok(rv) => { return OperatorEvalOutcome::Ok(rv); } OperatorEvalAttemptOutcome::Exception(e) => { return OperatorEvalOutcome::Exception(e); } OperatorEvalAttemptOutcome::Error(e) => { return OperatorEvalOutcome::Error(e); } OperatorEvalAttemptOutcome::NeedTryROperator => {} } } if RuntimeValueType::get_type(lhs, &vm.globals) == RuntimeValueType::get_type(rhs, &vm.globals) { return OperatorEvalOutcome::Error(VmErrorReason::UnexpectedType.into()); } if let Ok(op) = rhs.read_attribute($aria_rev_sym, &vm.globals) { match RuntimeValue::try_eval_bin_op(op, lhs, cur_frame, vm) { OperatorEvalAttemptOutcome::Ok(rv) => OperatorEvalOutcome::Ok(rv), OperatorEvalAttemptOutcome::Exception(e) => { OperatorEvalOutcome::Exception(e) } OperatorEvalAttemptOutcome::Error(e) => OperatorEvalOutcome::Error(e), OperatorEvalAttemptOutcome::NeedTryROperator => { OperatorEvalOutcome::Error(VmErrorReason::UnexpectedType.into()) } } } else { OperatorEvalOutcome::Error(VmErrorReason::UnexpectedType.into()) } } } }; } macro_rules! unary_op_impl { ($rust_fn_name: ident, $aria_sym: expr) => { impl RuntimeValue { pub(crate) fn $rust_fn_name( obj: &RuntimeValue, cur_frame: &mut Frame, vm: &mut VirtualMachine, ) -> OperatorEvalOutcome { if let Ok(op) = obj.read_attribute($aria_sym, &vm.globals) { match RuntimeValue::try_eval_unary_op(op, cur_frame, vm) { OperatorEvalAttemptOutcome::Ok(rv) => OperatorEvalOutcome::Ok(rv), OperatorEvalAttemptOutcome::Exception(e) => { OperatorEvalOutcome::Exception(e) } OperatorEvalAttemptOutcome::Error(e) => OperatorEvalOutcome::Error(e), OperatorEvalAttemptOutcome::NeedTryROperator => { OperatorEvalOutcome::Error(VmErrorReason::UnexpectedType.into()) } } } else { OperatorEvalOutcome::Error(VmErrorReason::UnexpectedType.into()) } } } }; } bin_op_impl!( add, crate::symbol::INTERNED_OP_IMPL_ADD, crate::symbol::INTERNED_OP_IMPL_RADD ); bin_op_impl!( sub, crate::symbol::INTERNED_OP_IMPL_SUB, crate::symbol::INTERNED_OP_IMPL_RSUB ); bin_op_impl!( mul, crate::symbol::INTERNED_OP_IMPL_MUL, crate::symbol::INTERNED_OP_IMPL_RMUL ); bin_op_impl!( div, crate::symbol::INTERNED_OP_IMPL_DIV, crate::symbol::INTERNED_OP_IMPL_RDIV ); bin_op_impl!( rem, crate::symbol::INTERNED_OP_IMPL_REM, crate::symbol::INTERNED_OP_IMPL_RREM ); bin_op_impl!( leftshift, crate::symbol::INTERNED_OP_IMPL_LSHIFT, crate::symbol::INTERNED_OP_IMPL_RLSHIFT ); bin_op_impl!( rightshift, crate::symbol::INTERNED_OP_IMPL_RSHIFT, crate::symbol::INTERNED_OP_IMPL_RRSHIFT ); bin_op_impl!( bitwise_and, crate::symbol::INTERNED_OP_IMPL_BWAND, crate::symbol::INTERNED_OP_IMPL_RBWAND ); bin_op_impl!( bitwise_or, crate::symbol::INTERNED_OP_IMPL_BWOR, crate::symbol::INTERNED_OP_IMPL_RBWOR ); bin_op_impl!( xor, crate::symbol::INTERNED_OP_IMPL_XOR, crate::symbol::INTERNED_OP_IMPL_RXOR ); rel_op_impl!( less_than, crate::symbol::INTERNED_OP_IMPL_LT, crate::symbol::INTERNED_OP_IMPL_GT ); rel_op_impl!( greater_than, crate::symbol::INTERNED_OP_IMPL_GT, crate::symbol::INTERNED_OP_IMPL_LT ); rel_op_impl!( less_than_equal, crate::symbol::INTERNED_OP_IMPL_LTEQ, crate::symbol::INTERNED_OP_IMPL_GTEQ ); rel_op_impl!( greater_than_equal, crate::symbol::INTERNED_OP_IMPL_GTEQ, crate::symbol::INTERNED_OP_IMPL_LTEQ ); unary_op_impl!(neg, crate::symbol::INTERNED_OP_IMPL_NEG); impl std::fmt::Debug for RuntimeValue { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { Self::Integer(x) => write!(f, "{}", x.raw_value()), Self::Float(x) => write!(f, "{}", x.raw_value()), Self::Boolean(x) => write!(f, "{}", x.raw_value()), Self::String(s) => write!(f, "\"{}\"", s.raw_value()), Self::Object(o) => write!(f, "", o.get_struct().name()), Self::Opaque(_) => write!(f, ""), Self::Mixin(m) => write!(f, "", m.name()), Self::Module(_) => write!(f, ""), Self::EnumValue(v) => { write!( f, "", v.get_container_enum().name(), v.get_case_index(), ) } Self::CodeObject(co) => write!(f, "{co:?}"), Self::Function(fnc) => write!(f, "{fnc:?}"), Self::BoundFunction(_) => write!(f, ""), Self::List(lt) => write!(f, "{lt:?}"), Self::Type(t) => write!(f, "type<{t:?}>"), Self::TypeCheck(t) => write!(f, "type-check({t:?})"), } } } impl std::fmt::Display for RuntimeValue { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { RuntimeValue::String(s) => write!(f, "{}", s.raw_value()), _ => (self as &dyn std::fmt::Debug).fmt(f), } } } impl TryFrom<&ConstantValue> for RuntimeValue { type Error = aria_compiler::bc_reader::DecodeError; fn try_from(value: &ConstantValue) -> Result { match value { ConstantValue::Integer(n) => Ok(RuntimeValue::Integer(From::from(*n))), ConstantValue::String(s) => Ok(RuntimeValue::String(s.to_owned().into())), ConstantValue::CompiledCodeObject(s) => { Ok(RuntimeValue::CodeObject(TryFrom::try_from(s)?)) } ConstantValue::Float(f) => Ok(RuntimeValue::Float(f.raw_value().into())), } } } #[derive(Debug)] pub enum AttributeError { NoSuchAttribute, InvalidFunctionBinding, ValueHasNoAttributes, } impl AttributeError { pub fn to_vm_error_reason(&self, name: &str) -> VmErrorReason { match self { Self::NoSuchAttribute => VmErrorReason::NoSuchIdentifier(name.to_owned()), Self::InvalidFunctionBinding => VmErrorReason::InvalidBinding, Self::ValueHasNoAttributes => VmErrorReason::UnexpectedType, } } } macro_rules! val_or_bound_func { ($val: expr, $self: expr) => { if let Some(rf) = $val.as_function() { if rf.attribute().is_type_method() { Err(AttributeError::InvalidFunctionBinding) } else { Ok($self.bind(rf.clone())) } } else { Ok($val) } }; } pub type CallResult = crate::vm::RunloopExit; impl RuntimeValue { pub fn bind(&self, f: Function) -> RuntimeValue { RuntimeValue::BoundFunction(BoundFunction::bind(self.clone(), f)) } pub fn as_struct(&self) -> Option<&Struct> { self.as_type().and_then(|rt| rt.as_struct()) } pub fn as_enum(&self) -> Option<&Enum> { self.as_type().and_then(|rt| rt.as_enum()) } pub fn is_struct(&self) -> bool { self.as_struct().is_some() } pub fn is_enum(&self) -> bool { self.as_enum().is_some() } pub fn as_rust_native(&self) -> Option<&RustNativeType> { self.as_type().and_then(|rt| rt.as_rust_native()) } pub fn as_opaque_concrete(&self) -> Option> { self.as_opaque().and_then(|c| c.as_concrete_object::()) } pub fn is_builtin_type(&self) -> bool { match self { Self::Integer(_) | Self::String(_) | Self::Float(_) | Self::Boolean(_) => true, Self::Object(_) | Self::EnumValue(_) | Self::CodeObject(_) | Self::Function(_) | Self::BoundFunction(_) | Self::List(_) | Self::Mixin(_) | Self::Type(_) | Self::Module(_) | Self::Opaque(_) | Self::TypeCheck(_) => false, } } pub fn get_builtin_type_id(&self) -> Option { match self { Self::Integer(x) => Some(x.builtin_type_id()), Self::String(x) => Some(x.builtin_type_id()), Self::Float(x) => Some(x.builtin_type_id()), Self::Boolean(x) => Some(x.builtin_type_id()), Self::Object(_) | Self::EnumValue(_) | Self::CodeObject(_) | Self::Function(_) | Self::BoundFunction(_) | Self::List(_) | Self::Mixin(_) | Self::Type(_) | Self::Module(_) | Self::Opaque(_) | Self::TypeCheck(_) => None, } } pub fn eval( &self, argc: u8, cur_frame: &mut Frame, vm: &mut VirtualMachine, discard_result: bool, ) -> ExecutionResult { if let Some(f) = self.as_function() { f.eval(argc, cur_frame, vm, &Default::default(), discard_result) } else if let Some(bf) = self.as_bound_function() { bf.eval(argc, cur_frame, vm, discard_result) } else { match self.read_attribute(INTERNED_OP_IMPL_CALL, &vm.globals) { Ok(op_call) => op_call.eval(argc, cur_frame, vm, discard_result), _ => Err(crate::error::vm_error::VmErrorReason::UnexpectedType.into()), } } } pub fn prettyprint(&self, cur_frame: &mut Frame, vm: &mut VirtualMachine) -> String { if let Ok(ppf) = self.read_attribute(INTERNED_OP_PRETTYPRINT, &vm.globals) && ppf.eval(0, cur_frame, vm, false).is_ok() { // either check that the stack is doing ok - or have eval return the value if let Some(val) = cur_frame.stack.try_pop() && let Some(sv) = val.as_string() { return sv.raw_value().clone(); } } format!("{self}") } fn get_attribute_store(&self) -> Option<&object::ObjectBox> { match self { RuntimeValue::Integer(bv) => Some(&bv.imp.as_ref().boxx), RuntimeValue::String(bv) => Some(&bv.imp.as_ref().boxx), RuntimeValue::Float(bv) => Some(&bv.imp.as_ref().boxx), RuntimeValue::Boolean(bv) => Some(&bv.imp.as_ref().boxx), RuntimeValue::Object(obj) => Some(&obj.imp.as_ref().boxx), RuntimeValue::EnumValue(_) => None, RuntimeValue::CodeObject(_) => None, RuntimeValue::Function(f) => Some(f.get_attribute_store()), RuntimeValue::BoundFunction(_) => None, RuntimeValue::List(l) => Some(&l.imp.as_ref().boxx), RuntimeValue::Mixin(m) => Some(&m.imp.as_ref().entries), RuntimeValue::Type(t) => t.get_attribute_store(), RuntimeValue::Module(_) => None, RuntimeValue::Opaque(_) => None, RuntimeValue::TypeCheck(_) => None, } } pub fn write_attribute( &self, attrib_sym: Symbol, val: RuntimeValue, builtins: &mut VmGlobals, ) -> Result<(), AttributeError> { if let Some(rm) = self.as_module() && let Some(attr_name) = builtins.resolve_symbol(attrib_sym) { rm.store_named_value(attr_name, val); Ok(()) } else if let Some(ob) = self.get_attribute_store() { ob.write(builtins, attrib_sym, val); Ok(()) } else { Err(AttributeError::ValueHasNoAttributes) } } pub fn list_attributes(&self, builtins: &VmGlobals) -> Vec { let mut resolved = rustc_data_structures::fx::FxHashSet::default(); let mut push_resolved = |symbols: rustc_data_structures::fx::FxHashSet| { for sym in symbols { if let Some(name) = builtins.resolve_symbol(sym) { resolved.insert(name.to_owned()); } } }; if let Some(obj) = self.as_object() { let mut attrs = obj.list_attributes(builtins); attrs.extend(obj.get_struct().list_attributes(builtins)); push_resolved(attrs); } else if let Some(mixin) = self.as_mixin() { push_resolved(mixin.list_attributes(builtins)); } else if let Some(enumm) = self.as_enum_value() { push_resolved(enumm.get_container_enum().list_attributes(builtins)); } else if let Some(i) = self.as_integer() { let mut attrs = i.list_attributes(builtins); let bt = builtins.get_builtin_type_by_id(BuiltinTypeId::Int); attrs.extend(bt.list_attributes(builtins)); push_resolved(attrs); } else if let Some(i) = self.as_float() { let mut attrs = i.list_attributes(builtins); let bt = builtins.get_builtin_type_by_id(BuiltinTypeId::Float); attrs.extend(bt.list_attributes(builtins)); push_resolved(attrs); } else if let Some(s) = self.as_string() { let mut attrs = s.list_attributes(builtins); let bt = builtins.get_builtin_type_by_id(BuiltinTypeId::String); attrs.extend(bt.list_attributes(builtins)); push_resolved(attrs); } else if let Some(b) = self.as_boolean() { let mut attrs = b.list_attributes(builtins); let bt = builtins.get_builtin_type_by_id(BuiltinTypeId::Bool); attrs.extend(bt.list_attributes(builtins)); push_resolved(attrs); } else if let Some(l) = self.as_list() { let mut attrs = l.list_attributes(builtins); let bt = builtins.get_builtin_type_by_id(BuiltinTypeId::List); attrs.extend(bt.list_attributes(builtins)); push_resolved(attrs); } else if let Some(f) = self.as_function() { push_resolved(f.list_attributes(builtins)); } else if let Some(m) = self.as_module() { resolved.extend(m.list_named_values()); } else { return vec![]; } resolved.into_iter().collect() } pub(crate) fn read_slot( &self, builtins: &crate::builtins::VmGlobals, slot_id: crate::shape::SlotId, sid: crate::shape::ShapeId, ) -> Option { match self { RuntimeValue::Object(object) => match object.read_slot(slot_id, sid) { Some(val) => Some(val), None => val_or_bound_func!(object.get_struct().read_slot(slot_id, sid)?, self).ok(), }, RuntimeValue::Mixin(mixin) => mixin.imp.as_ref().entries.read_slot(slot_id, sid), RuntimeValue::EnumValue(enumm) => { let val = enumm .get_container_enum() .imp .as_ref() .entries .read_slot(slot_id, sid)?; val_or_bound_func!(val, self).ok() } RuntimeValue::Integer(bv) => match bv.imp.as_ref().boxx.read_slot(slot_id, sid) { Some(val) => val_or_bound_func!(val, self).ok(), None => { let bt = builtins.get_builtin_type_by_id(BuiltinTypeId::Int); Self::read_slot_from_type(&bt, slot_id, sid) .and_then(|val| val_or_bound_func!(val, self).ok()) } }, RuntimeValue::String(bv) => match bv.imp.as_ref().boxx.read_slot(slot_id, sid) { Some(val) => val_or_bound_func!(val, self).ok(), None => { let bt = builtins.get_builtin_type_by_id(BuiltinTypeId::String); Self::read_slot_from_type(&bt, slot_id, sid) .and_then(|val| val_or_bound_func!(val, self).ok()) } }, RuntimeValue::Float(bv) => match bv.imp.as_ref().boxx.read_slot(slot_id, sid) { Some(val) => val_or_bound_func!(val, self).ok(), None => { let bt = builtins.get_builtin_type_by_id(BuiltinTypeId::Float); Self::read_slot_from_type(&bt, slot_id, sid) .and_then(|val| val_or_bound_func!(val, self).ok()) } }, RuntimeValue::Boolean(bv) => match bv.imp.as_ref().boxx.read_slot(slot_id, sid) { Some(val) => val_or_bound_func!(val, self).ok(), None => { let bt = builtins.get_builtin_type_by_id(BuiltinTypeId::Bool); Self::read_slot_from_type(&bt, slot_id, sid) .and_then(|val| val_or_bound_func!(val, self).ok()) } }, RuntimeValue::Function(f) => f.get_attribute_store().read_slot(slot_id, sid), RuntimeValue::List(l) => match l.imp.as_ref().boxx.read_slot(slot_id, sid) { Some(val) => Some(val), None => { let bt = builtins.get_builtin_type_by_id(BuiltinTypeId::List); Self::read_slot_from_type(&bt, slot_id, sid) .and_then(|val| val_or_bound_func!(val, self).ok()) } }, RuntimeValue::Type(t) => { let val = Self::read_slot_from_type(t, slot_id, sid)?; if let Some(rf) = val.as_function() { if !rf.attribute().is_type_method() { None } else { Some(self.bind(rf.clone())) } } else { Some(val) } } _ => None, } } fn read_slot_from_type( ty: &RuntimeValueType, slot_id: crate::shape::SlotId, sid: crate::shape::ShapeId, ) -> Option { match ty { RuntimeValueType::Struct(st) => st.imp.as_ref().entries.read_slot(slot_id, sid), RuntimeValueType::Enum(en) => en.imp.as_ref().entries.read_slot(slot_id, sid), RuntimeValueType::RustNative(rt) => rt.get_boxx().as_ref().read_slot(slot_id, sid), _ => None, } } fn resolve_to_slot_from_type( ty: &RuntimeValueType, builtins: &crate::builtins::VmGlobals, name: Symbol, ) -> Option<(RuntimeValue, crate::shape::ShapeId, crate::shape::SlotId)> { match ty { RuntimeValueType::Struct(st) => st.imp.as_ref().entries.resolve_to_slot(builtins, name), RuntimeValueType::Enum(en) => en.imp.as_ref().entries.resolve_to_slot(builtins, name), RuntimeValueType::RustNative(rt) => { rt.get_boxx().as_ref().resolve_to_slot(builtins, name) } _ => None, } } pub(crate) fn resolve_to_slot( &self, builtins: &crate::builtins::VmGlobals, name: Symbol, ) -> Option<(RuntimeValue, crate::shape::ShapeId, crate::shape::SlotId)> { match self { RuntimeValue::Object(object) => match object.resolve_to_slot(builtins, name) { Some(val) => Some(val), None => { let val = object.get_struct().resolve_to_slot(builtins, name)?; val_or_bound_func!(val.0, self) .ok() .map(|v| (v, val.1, val.2)) } }, RuntimeValue::Mixin(mixin) => { mixin.imp.as_ref().entries.resolve_to_slot(builtins, name) } RuntimeValue::EnumValue(enumm) => { let val = enumm .get_container_enum() .imp .as_ref() .entries .resolve_to_slot(builtins, name)?; val_or_bound_func!(val.0, self) .ok() .map(|v| (v, val.1, val.2)) } RuntimeValue::Integer(bv) => match bv.imp.as_ref().boxx.resolve_to_slot(builtins, name) { Some(val) => val_or_bound_func!(val.0, self) .ok() .map(|v| (v, val.1, val.2)), None => { let bt = builtins.get_builtin_type_by_id(BuiltinTypeId::Int); let val = Self::resolve_to_slot_from_type(&bt, builtins, name)?; val_or_bound_func!(val.0, self) .ok() .map(|v| (v, val.1, val.2)) } }, RuntimeValue::String(bv) => { match bv.imp.as_ref().boxx.resolve_to_slot(builtins, name) { Some(val) => val_or_bound_func!(val.0, self) .ok() .map(|v| (v, val.1, val.2)), None => { let bt = builtins.get_builtin_type_by_id(BuiltinTypeId::String); let val = Self::resolve_to_slot_from_type(&bt, builtins, name)?; val_or_bound_func!(val.0, self) .ok() .map(|v| (v, val.1, val.2)) } } } RuntimeValue::Float(bv) => match bv.imp.as_ref().boxx.resolve_to_slot(builtins, name) { Some(val) => val_or_bound_func!(val.0, self) .ok() .map(|v| (v, val.1, val.2)), None => { let bt = builtins.get_builtin_type_by_id(BuiltinTypeId::Float); let val = Self::resolve_to_slot_from_type(&bt, builtins, name)?; val_or_bound_func!(val.0, self) .ok() .map(|v| (v, val.1, val.2)) } }, RuntimeValue::Boolean(bv) => match bv.imp.as_ref().boxx.resolve_to_slot(builtins, name) { Some(val) => val_or_bound_func!(val.0, self) .ok() .map(|v| (v, val.1, val.2)), None => { let bt = builtins.get_builtin_type_by_id(BuiltinTypeId::Bool); let val = Self::resolve_to_slot_from_type(&bt, builtins, name)?; val_or_bound_func!(val.0, self) .ok() .map(|v| (v, val.1, val.2)) } }, RuntimeValue::Function(f) => f.get_attribute_store().resolve_to_slot(builtins, name), RuntimeValue::List(l) => match l.imp.as_ref().boxx.resolve_to_slot(builtins, name) { Some(val) => Some(val), None => { let bt = builtins.get_builtin_type_by_id(BuiltinTypeId::List); let val = Self::resolve_to_slot_from_type(&bt, builtins, name)?; val_or_bound_func!(val.0, self) .ok() .map(|v| (v, val.1, val.2)) } }, RuntimeValue::Type(t) => { let val = Self::resolve_to_slot_from_type(t, builtins, name)?; if let Some(rf) = val.0.as_function() { if !rf.attribute().is_type_method() { None } else { Some((self.bind(rf.clone()), val.1, val.2)) } } else { Some(val) } } _ => None, } } pub fn read_attribute( &self, attrib_sym: Symbol, builtins: &VmGlobals, ) -> Result { if let Some(m) = self.as_module() && let Some(attrib_name) = builtins.resolve_symbol(attrib_sym) { return match m.load_named_value(attrib_name) { Some(v) => Ok(v), None => Err(AttributeError::NoSuchAttribute), }; } if let Some(obj) = self.as_object() { match obj.read(builtins, attrib_sym) { Some(val) => Ok(val), _ => match obj.get_struct().load_named_value(builtins, attrib_sym) { Some(val) => { val_or_bound_func!(val, self) } _ => Err(AttributeError::NoSuchAttribute), }, } } else if let Some(mixin) = self.as_mixin() { match mixin.load_named_value(builtins, attrib_sym) { Some(val) => Ok(val), _ => Err(AttributeError::NoSuchAttribute), } } else if let Some(enumm) = self.as_enum_value() { match enumm.read(builtins, attrib_sym) { Some(val) => { val_or_bound_func!(val, self) } _ => Err(AttributeError::NoSuchAttribute), } } else if let Some(bt_id) = self.get_builtin_type_id() { if let Some(attr_store) = self.get_attribute_store() && let Some(val) = attr_store.read(builtins, attrib_sym) { val_or_bound_func!(val, self) } else { let bt = builtins.get_builtin_type_by_id(bt_id); match bt.read_attribute(builtins, attrib_sym) { Ok(val) => { val_or_bound_func!(val, self) } _ => Err(AttributeError::NoSuchAttribute), } } } else if let Some(f) = self.as_function() { match f.read(builtins, attrib_sym) { Some(val) => Ok(val), _ => Err(AttributeError::NoSuchAttribute), } } else if let Some(l) = self.as_list() { match l.read(builtins, attrib_sym) { Some(val) => Ok(val), _ => { let bt = builtins.get_builtin_type_by_id(BuiltinTypeId::List); match bt.read_attribute(builtins, attrib_sym) { Ok(val) => { val_or_bound_func!(val, self) } _ => Err(AttributeError::NoSuchAttribute), } } } } else if let Some(t) = self.as_type() { let val = t.read_attribute(builtins, attrib_sym)?; if let Some(rf) = val.as_function() { if !rf.attribute().is_type_method() { Err(AttributeError::InvalidFunctionBinding) } else { Ok(self.bind(rf.clone())) } } else { Ok(val) } } else { Err(AttributeError::ValueHasNoAttributes) } } pub fn read_index( &self, indices: &[RuntimeValue], cur_frame: &mut Frame, vm: &mut VirtualMachine, ) -> ExecutionResult { match self.read_attribute(INTERNED_OP_IMPL_READ_INDEX, &vm.globals) { Ok(read_index) => { for idx in indices.iter().rev() { cur_frame.stack.push(idx.clone()); } read_index.eval(indices.len() as u8, cur_frame, vm, false) } _ => Err(VmErrorReason::UnexpectedType.into()), } } pub fn write_index( &self, indices: &[RuntimeValue], val: &RuntimeValue, cur_frame: &mut Frame, vm: &mut VirtualMachine, ) -> ExecutionResult { match self.read_attribute(INTERNED_OP_IMPL_WRITE_INDEX, &vm.globals) { Ok(write_index) => { cur_frame.stack.push(val.clone()); for idx in indices.iter().rev() { cur_frame.stack.push(idx.clone()); } write_index.eval(1 + indices.len() as u8, cur_frame, vm, true) } _ => Err(VmErrorReason::UnexpectedType.into()), } } } ================================================ FILE: vm-lib/src/runtime_value/object.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use std::{ cell::{Cell, UnsafeCell}, rc::Rc, }; use rustc_data_structures::fx::FxHashSet; use crate::{error::vm_error::VmErrorReason, shape::ShapeId}; use crate::{shape::SlotId, symbol::Symbol}; use super::{RuntimeValue, structure::Struct}; pub struct ObjectBox { shape: Cell, slots: UnsafeCell>, } impl Default for ObjectBox { fn default() -> Self { Self { shape: Cell::new(crate::shape::Shapes::EMPTY_SHAPE_INDEX), slots: UnsafeCell::new(Vec::new()), } } } impl ObjectBox { #[allow(clippy::mut_from_ref)] #[inline] fn get(&self) -> &Vec { unsafe { &*self.slots.get() } } #[allow(clippy::mut_from_ref)] #[inline] fn get_mut(&self) -> &mut Vec { unsafe { &mut *self.slots.get() } } pub fn write( &self, builtins: &mut crate::builtins::VmGlobals, name: Symbol, val: RuntimeValue, ) { let (shape_id, slot_id) = builtins.shapes.transition(self.shape.get(), name); self.shape.set(shape_id); let slot_id = slot_id.0 as usize; let slot_count = self.get().len(); if slot_id == slot_count { self.get_mut().push(val); } else if slot_id < slot_count { self.get_mut()[slot_id] = val; } else { panic!("slots should grow sequentially"); } } pub fn read( &self, builtins: &crate::builtins::VmGlobals, name: Symbol, ) -> Option { let slot_id = builtins.shapes.resolve_slot(self.shape.get(), name)?; self.get().get(slot_id.0 as usize).cloned() } pub(super) fn read_slot(&self, slot_id: SlotId, sid: ShapeId) -> Option { if self.shape.get() != sid { return None; } self.get().get(slot_id.0 as usize).cloned() } pub(super) fn resolve_to_slot( &self, builtins: &crate::builtins::VmGlobals, name: Symbol, ) -> Option<(RuntimeValue, ShapeId, SlotId)> { let sid = self.shape.get(); let slot_id = builtins.shapes.resolve_slot(sid, name)?; let val = self.get().get(slot_id.0 as usize)?.clone(); Some((val, sid, slot_id)) } pub(super) fn list_attributes( &self, builtins: &crate::builtins::VmGlobals, ) -> FxHashSet { let mut ret = FxHashSet::::default(); let shape = match builtins.shapes.get_shape(self.shape.get()) { Some(s) => s, None => return ret, }; assert_eq!(self.get().len(), shape.reverse_slots.len()); shape.reverse_slots.iter().for_each(|&sym| { ret.insert(sym); }); ret } pub(crate) fn contains(&self, builtins: &crate::builtins::VmGlobals, name: Symbol) -> bool { let slot_count = self.get().len(); if let Some(slot_id) = builtins.shapes.resolve_slot(self.shape.get(), name) { (slot_id.0 as usize) < slot_count } else { false } } } pub(super) struct ObjectImpl { pub(super) boxx: ObjectBox, kind: Struct, } #[derive(Clone)] pub struct Object { pub(super) imp: Rc, } impl ObjectImpl { fn new(kind: &Struct) -> Self { Self { boxx: Default::default(), kind: kind.clone(), } } fn read_slot(&self, slot_id: SlotId, sid: ShapeId) -> Option { self.boxx.read_slot(slot_id, sid) } fn resolve_to_slot( &self, builtins: &crate::builtins::VmGlobals, name: Symbol, ) -> Option<(RuntimeValue, ShapeId, SlotId)> { self.boxx.resolve_to_slot(builtins, name) } fn write(&self, builtins: &mut crate::builtins::VmGlobals, name: Symbol, val: RuntimeValue) { self.boxx.write(builtins, name, val) } fn read(&self, builtins: &crate::builtins::VmGlobals, name: Symbol) -> Option { self.boxx.read(builtins, name) } fn list_attributes(&self, builtins: &crate::builtins::VmGlobals) -> FxHashSet { self.boxx.list_attributes(builtins) } } impl Object { pub fn new(kind: &Struct) -> Self { Self { imp: Rc::new(ObjectImpl::new(kind)), } } pub(crate) fn read_slot(&self, slot_id: SlotId, sid: ShapeId) -> Option { self.imp.read_slot(slot_id, sid) } pub(crate) fn resolve_to_slot( &self, builtins: &crate::builtins::VmGlobals, name: Symbol, ) -> Option<(RuntimeValue, ShapeId, SlotId)> { self.imp.resolve_to_slot(builtins, name) } pub fn read( &self, builtins: &crate::builtins::VmGlobals, name: Symbol, ) -> Option { self.imp.read(builtins, name) } pub fn write( &self, builtins: &mut crate::builtins::VmGlobals, name: Symbol, val: RuntimeValue, ) { self.imp.write(builtins, name, val) } pub fn list_attributes(&self, builtins: &crate::builtins::VmGlobals) -> FxHashSet { self.imp.list_attributes(builtins) } pub fn get_struct(&self) -> &Struct { &self.imp.kind } pub fn with_value( self, builtins: &mut crate::builtins::VmGlobals, name: Symbol, val: RuntimeValue, ) -> Self { self.imp.write(builtins, name, val); self } } impl PartialEq for Object { fn eq(&self, other: &Self) -> bool { Rc::ptr_eq(&self.imp, &other.imp) } } impl Eq for Object {} impl Object { pub fn extract_field( &self, builtins: &crate::builtins::VmGlobals, name: Symbol, f: FnType, ) -> Result where FnType: FnOnce(RuntimeValue) -> Option, { let val = match self.read(builtins, name) { Some(v) => v, None => { return Err(VmErrorReason::NoSuchIdentifier(name.to_string())); } }; match f(val) { Some(v) => Ok(v), None => Err(VmErrorReason::UnexpectedType), } } } ================================================ FILE: vm-lib/src/runtime_value/opaque.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use std::{any::Any, rc::Rc}; #[derive(Clone)] struct OpaqueValueImpl { val: Rc, } #[derive(Clone)] pub struct OpaqueValue { imp: OpaqueValueImpl, } impl std::fmt::Debug for OpaqueValue { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "") } } impl std::fmt::Display for OpaqueValue { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "") } } impl OpaqueValue { pub(crate) fn as_concrete_object(&self) -> Option> { self.imp.val.clone().downcast::().ok() } pub fn new(x: T) -> Self { Self { imp: OpaqueValueImpl { val: Rc::new(x) }, } } } ================================================ FILE: vm-lib/src/runtime_value/runtime_code_object.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use std::rc::Rc; use aria_compiler::{ bc_reader::{BytecodeReader, DecodeResult}, constant_value::CompiledCodeObject, line_table::LineTable, }; use aria_parser::ast::SourcePointer; use haxby_opcodes::Opcode; #[derive(Clone)] pub struct CodeObject { pub name: String, pub attribute: u8, pub body: Rc<[Opcode]>, pub required_argc: u8, pub default_argc: u8, pub frame_size: u8, pub loc: SourcePointer, pub line_table: Rc, } impl PartialEq for CodeObject { fn eq(&self, other: &Self) -> bool { Rc::ptr_eq(&self.body, &other.body) } } fn byte_array_to_opcode_array(bytes: &[u8]) -> DecodeResult> { let mut opcodes = Vec::new(); let mut decoder = BytecodeReader::try_from(bytes)?; loop { let next = decoder.read_opcode(); match next { Ok(op) => opcodes.push(op), Err(err) => { return match err { aria_compiler::bc_reader::DecodeError::EndOfStream => Ok(opcodes), _ => Err(err), }; } } } } impl TryFrom<&CompiledCodeObject> for CodeObject { type Error = aria_compiler::bc_reader::DecodeError; fn try_from(value: &CompiledCodeObject) -> Result { let ops = byte_array_to_opcode_array(value.body.as_slice())?; let body: Rc<[Opcode]> = ops.into(); Ok(Self { name: value.name.clone(), attribute: value.attribute, body, required_argc: value.required_argc, default_argc: value.default_argc, frame_size: value.frame_size, loc: value.loc.clone(), line_table: Rc::from(value.line_table.clone()), }) } } impl std::fmt::Debug for CodeObject { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "", self.name, self.loc) } } ================================================ FILE: vm-lib/src/runtime_value/rust_native_type.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use std::{cell::RefCell, rc::Rc}; use enum_as_inner::EnumAsInner; use rustc_data_structures::fx::FxHashSet; use crate::{builtins::VmGlobals, symbol::Symbol}; use super::{ RuntimeValue, function::{BuiltinFunctionImpl, Function}, mixin::Mixin, object::ObjectBox, }; #[derive(EnumAsInner, Clone, PartialEq, Eq)] pub enum RustNativeValueKind { Boolean, Integer, Float, List, String, Type, } struct RustNativeTypeImpl { tag: RustNativeValueKind, boxx: Rc, mixins: RefCell, } impl RustNativeTypeImpl { fn write(&self, builtins: &mut VmGlobals, name: Symbol, val: RuntimeValue) { self.boxx.write(builtins, name, val) } fn read(&self, builtins: &VmGlobals, name: Symbol) -> Option { match self.boxx.read(builtins, name) { Some(nv) => Some(nv), _ => self.mixins.borrow().load_named_value(builtins, name), } } fn include_mixin(&self, mixin: &Mixin) { self.mixins.borrow_mut().include(mixin.clone()); } fn isa_mixin(&self, mixin: &Mixin) -> bool { self.mixins.borrow().contains(mixin) } fn list_attributes(&self, builtins: &VmGlobals) -> FxHashSet { let mut attrs = self.boxx.list_attributes(builtins); attrs.extend(self.mixins.borrow().list_attributes(builtins)); attrs } } #[derive(Clone)] pub struct RustNativeType { imp: Rc, } impl RustNativeType { pub fn new(rvt: RustNativeValueKind) -> Self { Self { imp: Rc::new(RustNativeTypeImpl { tag: rvt, boxx: Rc::new(Default::default()), mixins: Default::default(), }), } } pub fn get_tag(&self) -> &RustNativeValueKind { &self.imp.tag } pub fn get_boxx(&self) -> &Rc { &self.imp.boxx } pub(crate) fn write(&self, builtins: &mut VmGlobals, name: Symbol, val: RuntimeValue) { self.imp.write(builtins, name, val); } pub fn read(&self, builtins: &VmGlobals, name: Symbol) -> Option { self.imp.read(builtins, name) } pub fn include_mixin(&self, mixin: &Mixin) { self.imp.include_mixin(mixin); } pub fn isa_mixin(&self, mixin: &Mixin) -> bool { self.imp.isa_mixin(mixin) } pub fn insert_builtin(&self, builtins: &mut VmGlobals) where T: 'static + Default + BuiltinFunctionImpl, { let t = T::default(); let name = builtins .intern_symbol(t.name()) .expect("too many symbols interned"); self.get_boxx().write( builtins, name, RuntimeValue::Function(Function::builtin_from(t)), ); } pub fn list_attributes(&self, builtins: &VmGlobals) -> FxHashSet { self.imp.list_attributes(builtins) } } impl PartialEq for RustNativeType { fn eq(&self, other: &Self) -> bool { Rc::ptr_eq(&self.imp, &other.imp) || self.imp.tag == other.imp.tag } } impl Eq for RustNativeType {} impl std::fmt::Debug for RustNativeType { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self.get_tag() { RustNativeValueKind::Boolean => write!(f, "Bool"), RustNativeValueKind::Integer => write!(f, "Int"), RustNativeValueKind::Float => write!(f, "Float"), RustNativeValueKind::List => write!(f, "List"), RustNativeValueKind::String => write!(f, "String"), RustNativeValueKind::Type => write!(f, "Type"), } } } ================================================ FILE: vm-lib/src/runtime_value/string.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use crate::{error::vm_error::VmErrorReason, frame::Frame, vm::VirtualMachine}; use super::{RuntimeValue, builtin_value::BuiltinValue}; pub type StringValue = BuiltinValue; impl From<&str> for StringValue { fn from(value: &str) -> Self { From::from(value.to_owned()) } } impl StringValue { pub fn len(&self) -> usize { self.imp.val.chars().count() } pub fn is_empty(&self) -> bool { self.imp.val.is_empty() } pub fn contains(&self, pat: &str) -> bool { self.imp.val.contains(pat) } } impl std::ops::Add<&StringValue> for &StringValue { type Output = StringValue; fn add(self, rhs: &StringValue) -> Self::Output { From::from(format!("{}{}", self.raw_value(), rhs.raw_value())) } } impl PartialEq for StringValue { fn eq(&self, other: &StringValue) -> bool { self.raw_value() == other.raw_value() } } impl Eq for StringValue {} impl PartialOrd for StringValue { fn partial_cmp(&self, other: &StringValue) -> Option { Some(self.cmp(other)) } } impl Ord for StringValue { fn cmp(&self, other: &Self) -> std::cmp::Ordering { self.raw_value().cmp(other.raw_value()) } } impl PartialEq for StringValue { fn eq(&self, other: &str) -> bool { self.raw_value() == other } } impl StringValue { pub fn get_at(&self, idx: usize) -> Option { self.raw_value() .chars() .nth(idx) .map(|c| RuntimeValue::String(c.to_string().into())) } pub fn read_index( &self, idx: &RuntimeValue, _: &mut Frame, _: &mut VirtualMachine, ) -> Result { if let Some(i) = idx.as_integer() { match self.get_at(*i.raw_value() as usize) { Some(val) => Ok(val), _ => Err(VmErrorReason::IndexOutOfBounds(*i.raw_value() as usize)), } } else { Err(VmErrorReason::UnexpectedType) } } } ================================================ FILE: vm-lib/src/runtime_value/structure.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use std::{cell::RefCell, rc::Rc}; use rustc_data_structures::fx::FxHashSet; use crate::{ builtins::VmGlobals, error::vm_error::VmErrorReason, runtime_value::object::ObjectBox, shape::{ShapeId, SlotId}, symbol::Symbol, }; use super::{ RuntimeValue, function::{BuiltinFunctionImpl, Function}, mixin::Mixin, }; pub(super) struct StructImpl { name: String, pub(super) entries: ObjectBox, mixins: RefCell, } impl StructImpl { fn new(name: &str) -> Self { Self { name: name.to_owned(), entries: ObjectBox::default(), mixins: RefCell::new(crate::mixin_includer::MixinIncluder::default()), } } fn isa_mixin(&self, mixin: &Mixin) -> bool { self.mixins.borrow().contains(mixin) } fn read_slot(&self, slot_id: SlotId, sid: ShapeId) -> Option { self.entries.read_slot(slot_id, sid) } fn resolve_to_slot( &self, builtins: &crate::builtins::VmGlobals, name: Symbol, ) -> Option<(RuntimeValue, ShapeId, SlotId)> { self.entries.resolve_to_slot(builtins, name) } fn load_named_value(&self, builtins: &VmGlobals, name: Symbol) -> Option { if let Some(nv) = self.entries.read(builtins, name) { Some(nv.clone()) } else { self.mixins.borrow().load_named_value(builtins, name) } } fn store_named_value(&self, builtins: &mut VmGlobals, name: Symbol, val: RuntimeValue) { self.entries.write(builtins, name, val); } fn include_mixin(&self, mixin: &Mixin) { self.mixins.borrow_mut().include(mixin.clone()); } fn list_attributes(&self, builtins: &VmGlobals) -> FxHashSet { let mut attrs = self.entries.list_attributes(builtins); attrs.extend(self.mixins.borrow().list_attributes(builtins)); attrs } } #[derive(Clone)] pub struct Struct { pub(super) imp: Rc, } impl Struct { pub fn new(name: &str) -> Self { Self { imp: Rc::new(StructImpl::new(name)), } } pub fn name(&self) -> &str { &self.imp.name } pub fn load_named_value(&self, builtins: &VmGlobals, name: Symbol) -> Option { self.imp.load_named_value(builtins, name) } pub fn include_mixin(&self, mixin: &Mixin) { self.imp.include_mixin(mixin); } pub fn isa_mixin(&self, mixin: &Mixin) -> bool { self.imp.isa_mixin(mixin) } pub fn list_attributes(&self, builtins: &VmGlobals) -> FxHashSet { self.imp.list_attributes(builtins) } } impl PartialEq for Struct { fn eq(&self, other: &Self) -> bool { Rc::ptr_eq(&self.imp, &other.imp) } } impl Eq for Struct {} impl Struct { pub(crate) fn read_slot(&self, slot_id: SlotId, sid: ShapeId) -> Option { self.imp.read_slot(slot_id, sid) } pub(crate) fn resolve_to_slot( &self, builtins: &crate::builtins::VmGlobals, name: Symbol, ) -> Option<(RuntimeValue, ShapeId, SlotId)> { self.imp.resolve_to_slot(builtins, name) } pub fn insert_builtin(&self, builtins: &mut VmGlobals) where T: 'static + Default + BuiltinFunctionImpl, { let t = T::default(); let name = builtins .intern_symbol(t.name()) .expect("too many symbols interned"); self.imp.store_named_value( builtins, name, RuntimeValue::Function(Function::builtin_from(t)), ); } pub fn extract_field( &self, builtins: &VmGlobals, name: Symbol, f: FnType, ) -> Result where FnType: FnOnce(RuntimeValue) -> Option, { let val = match self.load_named_value(builtins, name) { Some(v) => v, None => { return Err(VmErrorReason::NoSuchIdentifier(name.to_string())); } }; match f(val) { Some(v) => Ok(v), None => Err(VmErrorReason::UnexpectedType), } } } ================================================ FILE: vm-lib/src/shape.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use rustc_data_structures::fx::FxHashMap; use crate::symbol::Symbol; #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] pub struct ShapeId(pub u32); #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] pub struct SlotId(pub u32); pub struct Shape { #[allow(unused)] pub(crate) id: ShapeId, pub(crate) slots: FxHashMap, pub(crate) reverse_slots: Vec, pub(crate) transitions: FxHashMap, } impl Shape { pub fn empty() -> Self { Shape { id: Shapes::EMPTY_SHAPE_INDEX, slots: Default::default(), reverse_slots: Vec::default(), transitions: Default::default(), } } } pub struct Shapes { shapes: Vec, } impl Default for Shapes { fn default() -> Self { Self { shapes: vec![Shape::empty()], } } } impl Shapes { pub const EMPTY_SHAPE_INDEX: ShapeId = ShapeId(0); pub fn transition(&mut self, cur_sid: ShapeId, name: Symbol) -> (ShapeId, SlotId) { let cur_shape = &self.shapes[cur_sid.0 as usize]; if let Some(cur_slot) = cur_shape.slots.get(&name) { return (cur_sid, *cur_slot); } if let Some(next_sid) = cur_shape.transitions.get(&name) { let slot_id = self.shapes[next_sid.0 as usize] .slots .get(&name) .expect("transition shape missing slot"); return (*next_sid, *slot_id); } let new_slot_id = SlotId(cur_shape.slots.len() as u32); let mut new_shape_slots = cur_shape.slots.clone(); new_shape_slots.insert(name, new_slot_id); let mut new_shape_reverse_slots = cur_shape.reverse_slots.clone(); assert_eq!(new_shape_reverse_slots.len(), new_slot_id.0 as usize); new_shape_reverse_slots.push(name); let new_sid = ShapeId(self.shapes.len() as u32); let new_shape = Shape { id: new_sid, slots: new_shape_slots, reverse_slots: new_shape_reverse_slots, transitions: FxHashMap::default(), }; self.shapes.push(new_shape); let cur_shape = &mut self.shapes[cur_sid.0 as usize]; cur_shape.transitions.insert(name, new_sid); (new_sid, new_slot_id) } pub fn resolve_slot(&self, sid: ShapeId, name: Symbol) -> Option { self.shapes .get(sid.0 as usize) .and_then(|shape| shape.slots.get(&name).copied()) } pub fn resolve_symbol(&self, sid: ShapeId, slot_id: SlotId) -> Option { self.shapes .get(sid.0 as usize) .and_then(|shape| shape.reverse_slots.get(slot_id.0 as usize).copied()) } pub(crate) fn get_shape(&self, sid: ShapeId) -> Option<&Shape> { self.shapes.get(sid.0 as usize) } } ================================================ FILE: vm-lib/src/stack.rs ================================================ // SPDX-License-Identifier: Apache-2.0 pub struct Stack where T: Clone, { values: Vec, } impl Default for Stack where T: Clone, { fn default() -> Self { Self { values: Default::default(), } } } impl Stack where T: Clone, { pub fn push(&mut self, val: T) { self.values.push(val); } pub fn peek(&mut self) -> Option<&T> { self.values.last() } pub fn try_pop(&mut self) -> Option { self.values.pop() } pub fn pop(&mut self) -> T { self.try_pop().expect("empty stack") } pub fn pop_count(&mut self, count: usize) -> Vec { let mut result = Vec::with_capacity(count); for _ in 0..count { if let Some(v) = self.try_pop() { result.push(v); } else { break; } } result } pub fn try_pop_if(&mut self, f: F) -> Option where F: FnOnce(T) -> Option, { match self.try_pop() { Some(t) => f(t), None => None, } } pub fn pop_if(&mut self, f: F) -> Option where F: FnOnce(T) -> Option, { f(self.pop()) } pub fn len(&self) -> usize { self.values.len() } pub fn is_empty(&self) -> bool { self.values.is_empty() } pub fn clear(&mut self) { self.values.clear(); } pub fn peek_at_offset(&mut self, i: usize) -> Option<&T> { let idx = self.len() - 1 - i; self.values.get(idx) } pub fn contains(&self, val: &T) -> bool where T: PartialEq, { self.values.iter().any(|x| val.eq(x)) } } impl Stack where T: Clone + std::fmt::Debug, { pub fn dump(&self) { let mut first = true; self.values.iter().rev().for_each(|f| { if first { first = false; println!("--> {f:?}") } else { println!("{f:?}") }; }); } } ================================================ FILE: vm-lib/src/symbol.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use rustc_data_structures::fx::FxHashMap; use thiserror::Error; #[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] pub struct Symbol(pub u32); impl std::fmt::Display for Symbol { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "Symbol({})", self.0) } } pub const INTERNED_OP_IMPL_CALL: Symbol = Symbol(0); pub const INTERNED_OP_IMPL_EQUALS: Symbol = Symbol(1); pub const INTERNED_OP_IMPL_READ_INDEX: Symbol = Symbol(2); pub const INTERNED_OP_IMPL_WRITE_INDEX: Symbol = Symbol(3); pub const INTERNED_OP_IMPL_ADD: Symbol = Symbol(4); pub const INTERNED_OP_IMPL_RADD: Symbol = Symbol(5); pub const INTERNED_OP_IMPL_SUB: Symbol = Symbol(6); pub const INTERNED_OP_IMPL_RSUB: Symbol = Symbol(7); pub const INTERNED_OP_IMPL_MUL: Symbol = Symbol(8); pub const INTERNED_OP_IMPL_RMUL: Symbol = Symbol(9); pub const INTERNED_OP_IMPL_DIV: Symbol = Symbol(10); pub const INTERNED_OP_IMPL_RDIV: Symbol = Symbol(11); pub const INTERNED_OP_IMPL_REM: Symbol = Symbol(12); pub const INTERNED_OP_IMPL_RREM: Symbol = Symbol(13); pub const INTERNED_OP_IMPL_LSHIFT: Symbol = Symbol(14); pub const INTERNED_OP_IMPL_RLSHIFT: Symbol = Symbol(15); pub const INTERNED_OP_IMPL_RSHIFT: Symbol = Symbol(16); pub const INTERNED_OP_IMPL_RRSHIFT: Symbol = Symbol(17); pub const INTERNED_OP_IMPL_BWAND: Symbol = Symbol(18); pub const INTERNED_OP_IMPL_RBWAND: Symbol = Symbol(19); pub const INTERNED_OP_IMPL_BWOR: Symbol = Symbol(20); pub const INTERNED_OP_IMPL_RBWOR: Symbol = Symbol(21); pub const INTERNED_OP_IMPL_XOR: Symbol = Symbol(22); pub const INTERNED_OP_IMPL_RXOR: Symbol = Symbol(23); pub const INTERNED_OP_IMPL_LT: Symbol = Symbol(24); pub const INTERNED_OP_IMPL_GT: Symbol = Symbol(25); pub const INTERNED_OP_IMPL_LTEQ: Symbol = Symbol(26); pub const INTERNED_OP_IMPL_GTEQ: Symbol = Symbol(27); pub const INTERNED_OP_IMPL_NEG: Symbol = Symbol(28); pub const INTERNED_OP_PRETTYPRINT: Symbol = Symbol(29); pub const INTERNED_ATTR_BACKTRACE: Symbol = Symbol(30); pub const INTERNED_ATTR_IMPL: Symbol = Symbol(31); pub const INTERNED_ATTR_NEXT: Symbol = Symbol(32); pub const INTERNED_ATTR_MSG: Symbol = Symbol(33); pub const INTERNED_ATTR_ARGC_MISMATCH: Symbol = Symbol(34); pub const INTERNED_ATTR_STDOUT: Symbol = Symbol(35); pub const INTERNED_ATTR_STDERR: Symbol = Symbol(36); pub const INTERNED_ATTR_EXPECTED: Symbol = Symbol(37); pub const INTERNED_ATTR_ACTUAL: Symbol = Symbol(38); pub const INTERNED_CASE_VARARGS: Symbol = Symbol(39); pub const INTERNED_CASE_BOUNDED: Symbol = Symbol(40); pub struct Interner { map: FxHashMap, strings: Vec, } #[derive(Clone, Error, PartialEq, Eq, Debug)] pub enum InternError { #[error("too many symbols have been interned")] TooManySymbols, } impl Default for Interner { fn default() -> Self { let mut this = Self { map: FxHashMap::default(), strings: Vec::new(), }; // do not alter the order of these initial interned symbols // without altering the corresponding constants above assert!(this.intern("_op_impl_call").unwrap() == INTERNED_OP_IMPL_CALL); assert!(this.intern("_op_impl_equals").unwrap() == INTERNED_OP_IMPL_EQUALS); assert!(this.intern("_op_impl_read_index").unwrap() == INTERNED_OP_IMPL_READ_INDEX); assert!(this.intern("_op_impl_write_index").unwrap() == INTERNED_OP_IMPL_WRITE_INDEX); assert!(this.intern("_op_impl_add").unwrap() == INTERNED_OP_IMPL_ADD); assert!(this.intern("_op_impl_radd").unwrap() == INTERNED_OP_IMPL_RADD); assert!(this.intern("_op_impl_sub").unwrap() == INTERNED_OP_IMPL_SUB); assert!(this.intern("_op_impl_rsub").unwrap() == INTERNED_OP_IMPL_RSUB); assert!(this.intern("_op_impl_mul").unwrap() == INTERNED_OP_IMPL_MUL); assert!(this.intern("_op_impl_rmul").unwrap() == INTERNED_OP_IMPL_RMUL); assert!(this.intern("_op_impl_div").unwrap() == INTERNED_OP_IMPL_DIV); assert!(this.intern("_op_impl_rdiv").unwrap() == INTERNED_OP_IMPL_RDIV); assert!(this.intern("_op_impl_rem").unwrap() == INTERNED_OP_IMPL_REM); assert!(this.intern("_op_impl_rrem").unwrap() == INTERNED_OP_IMPL_RREM); assert!(this.intern("_op_impl_lshift").unwrap() == INTERNED_OP_IMPL_LSHIFT); assert!(this.intern("_op_impl_rlshift").unwrap() == INTERNED_OP_IMPL_RLSHIFT); assert!(this.intern("_op_impl_rshift").unwrap() == INTERNED_OP_IMPL_RSHIFT); assert!(this.intern("_op_impl_rrshift").unwrap() == INTERNED_OP_IMPL_RRSHIFT); assert!(this.intern("_op_impl_bwand").unwrap() == INTERNED_OP_IMPL_BWAND); assert!(this.intern("_op_impl_rbwand").unwrap() == INTERNED_OP_IMPL_RBWAND); assert!(this.intern("_op_impl_bwor").unwrap() == INTERNED_OP_IMPL_BWOR); assert!(this.intern("_op_impl_rbwor").unwrap() == INTERNED_OP_IMPL_RBWOR); assert!(this.intern("_op_impl_xor").unwrap() == INTERNED_OP_IMPL_XOR); assert!(this.intern("_op_impl_rxor").unwrap() == INTERNED_OP_IMPL_RXOR); assert!(this.intern("_op_impl_lt").unwrap() == INTERNED_OP_IMPL_LT); assert!(this.intern("_op_impl_gt").unwrap() == INTERNED_OP_IMPL_GT); assert!(this.intern("_op_impl_lteq").unwrap() == INTERNED_OP_IMPL_LTEQ); assert!(this.intern("_op_impl_gteq").unwrap() == INTERNED_OP_IMPL_GTEQ); assert!(this.intern("_op_impl_neg").unwrap() == INTERNED_OP_IMPL_NEG); assert!(this.intern("prettyprint").unwrap() == INTERNED_OP_PRETTYPRINT); assert!(this.intern("backtrace").unwrap() == INTERNED_ATTR_BACKTRACE); assert!(this.intern("__impl").unwrap() == INTERNED_ATTR_IMPL); assert!(this.intern("next").unwrap() == INTERNED_ATTR_NEXT); assert!(this.intern("msg").unwrap() == INTERNED_ATTR_MSG); assert!(this.intern("ArgcMismatch").unwrap() == INTERNED_ATTR_ARGC_MISMATCH); assert!(this.intern("stdout").unwrap() == INTERNED_ATTR_STDOUT); assert!(this.intern("stderr").unwrap() == INTERNED_ATTR_STDERR); assert!(this.intern("expected").unwrap() == INTERNED_ATTR_EXPECTED); assert!(this.intern("actual").unwrap() == INTERNED_ATTR_ACTUAL); assert!(this.intern("Varargs").unwrap() == INTERNED_CASE_VARARGS); assert!(this.intern("Bounded").unwrap() == INTERNED_CASE_BOUNDED); this } } impl Interner { pub fn intern(&mut self, s: &str) -> Result { if let Some(&sym) = self.map.get(s) { return Ok(sym); } let id = self.strings.len(); if id >= u32::MAX as usize { return Err(InternError::TooManySymbols); } let s = s.to_string(); let sym = Symbol(id as u32); self.strings.push(s.clone()); self.map.insert(s, sym); Ok(sym) } pub fn lookup(&self, s: &str) -> Option { self.map.get(s).copied() } pub fn resolve(&self, sym: Symbol) -> Option<&str> { self.strings.get(sym.0 as usize).map(|s| s.as_str()) } } ================================================ FILE: vm-lib/src/test.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use aria_compiler::compile_from_source; use aria_parser::ast::SourceBuffer; use crate::{ HaxbyEvalResult, builtins::runtime_error::RUNTIME_ERR_CASE_UNEXPECTED_TYPE_IDX, error::vm_error::VmErrorReason, haxby_eval, vm::{ExecutionResult, VmOptions}, }; fn exec_code(src: &'static str) -> ExecutionResult { exec_code_with_vm_options(src, Default::default()) } fn exec_code_with_vm_options( src: &'static str, vm_opts: VmOptions, ) -> ExecutionResult { let sb = SourceBuffer::stdin(src); let module = compile_from_source(&sb, &Default::default()).expect("module did not compile"); haxby_eval(module, vm_opts) } #[test] fn test_assert_can_pass() { let input = r##" func main() { val x = 1; assert x == 1; } "##; assert!(exec_code(input).is_ok()); } #[test] fn test_assert_can_fail() { let input = r##" func main() { val x = 1; assert x == 2; } "##; assert!( exec_code(input) .is_err_and(|err| err.reason == VmErrorReason::AssertFailed("x == 2".to_owned())) ); } #[test] fn test_toplevel_assert_can_fail() { let input = r##" val x = 1; assert x == 2; "##; assert!( exec_code(input) .is_err_and(|err| err.reason == VmErrorReason::AssertFailed("x == 2".to_owned())) ); } #[test] fn test_circular_import_detected() { let input = r##" import circular.zero; func main() { assert false; } "##; assert!( exec_code(input).is_err_and( |err| err.reason == VmErrorReason::CircularImport("circular.zero".to_owned()) ) ); } #[test] fn test_module_val_typecheck_fails() { let input = r##" val x: Int = 1; func main() { x = "false"; assert false; } "##; let result = exec_code(input); match result { Ok(result) => match result.exit { crate::vm::RunloopExit::Ok(_) => { panic!("expected typecheck to fail"); } crate::vm::RunloopExit::Exception(e) => { let enum_value = e .value .as_enum_value() .expect("exception should be an enum value"); assert!(enum_value.get_case_index() == RUNTIME_ERR_CASE_UNEXPECTED_TYPE_IDX); } }, Err(_) => { panic!("expected exception to be thrown"); } } } #[test] fn test_err_in_op_is_caught() { let input = r##" struct Foo { operator + (rhs) { assert false; } } func main() { return alloc(Foo) + 1; } "##; assert!( exec_code(input) .is_err_and(|err| err.reason == VmErrorReason::AssertFailed("false".to_owned())) ); } #[test] fn test_err_in_rop_is_caught() { let input = r##" struct Foo { reverse operator + (lhs) { assert false; } } func main() { return 1 + alloc(Foo); } "##; assert!( exec_code(input) .is_err_and(|err| err.reason == VmErrorReason::AssertFailed("false".to_owned())) ); } #[test] fn test_uncaught_exception_bubbles_up() { let input = r##" func main() { throw 1; } "##; match exec_code(input).expect("ok result expected").exit { crate::vm::RunloopExit::Ok(_) => { panic!("expected exception to be thrown"); } crate::vm::RunloopExit::Exception(e) => { assert_eq!( 1, *e.value .as_integer() .expect("integer value thrown") .raw_value() ) } } } #[test] fn test_cmdline_arguments() { let input = r##" func main() { val args = cmdline_arguments(); assert args.len() == 2; assert args[0] == "foo"; assert args[1] == "bar"; } "##; assert!( exec_code_with_vm_options( input, VmOptions { vm_args: vec!["foo".to_owned(), "bar".to_owned()], ..Default::default() } ) .is_ok() ); } #[test] fn test_force_unwrap_asserts() { let input = r##" func main() { val x = Result::Err("fail"); assert x! == 3; } "##; assert!(exec_code(input).is_err_and( |err| err.reason == VmErrorReason::AssertFailed("force unwrap failed".to_owned()) )); } #[test] fn test_cmdline_args_list() { let input = r##" func main(args) { assert args.len() == 2; assert args[0] == "arg1"; assert args[1] == "arg2"; } "##; let vm_opts = VmOptions { vm_args: vec!["arg1".to_owned(), "arg2".to_owned()], ..Default::default() }; assert!(exec_code_with_vm_options(input, vm_opts).is_ok()); } #[test] fn test_cmdline_args_va() { let input = r##" func main(...) { assert varargs.len() == 2; assert varargs[0] == "arg1"; assert varargs[1] == "arg2"; } "##; let vm_opts = VmOptions { vm_args: vec!["arg1".to_owned(), "arg2".to_owned()], ..Default::default() }; assert!(exec_code_with_vm_options(input, vm_opts).is_ok()); } #[test] fn test_cmdline_args_mismatch() { let input = r##" func main(x,y,z,...) { val x = Result::Err("fail"); assert x! == 3; } "##; let vm_opts = VmOptions { vm_args: vec!["arg1".to_owned(), "arg2".to_owned()], ..Default::default() }; assert!( exec_code_with_vm_options(input, vm_opts) .is_err_and(|err| err.reason == VmErrorReason::InvalidMainSignature) ); } ================================================ FILE: vm-lib/src/vm.rs ================================================ // SPDX-License-Identifier: Apache-2.0 use std::{ cell::RefCell, collections::HashMap, path::{Path, PathBuf}, rc::Rc, }; use aria_compiler::{compile_from_source, module::CompiledModule}; use aria_parser::ast::SourceBuffer; use haxby_opcodes::{ BuiltinTypeId, OPCODE_BIND_CASE, OPCODE_ENUM_CHECK_IS_CASE, OPCODE_NEW_ENUM_VAL, OPCODE_READ_ATTRIBUTE, OPCODE_WRITE_ATTRIBUTE, Opcode, enum_case_attribs::CASE_HAS_PAYLOAD, }; use std::sync::OnceLock; use crate::{ builtins::VmGlobals, console::{Console, StdConsole}, error::{ dylib_load::{LoadResult, LoadStatus}, exception::VmException, vm_error::{SymbolKind, VmError, VmErrorReason}, }, frame::Frame, opcodes::sidecar::{ EnumCheckIsCaseSidecar, NewEnumValSidecar, OpcodeSidecar, ReadAttributeSidecar, SidecarCell, SidecarSlice, }, runtime_module::RuntimeModule, runtime_value::{ RuntimeValue, enumeration::{Enum, EnumCase}, function::Function, isa::IsaCheckable, kind::RuntimeValueType, list::List, mixin::Mixin, object::Object, structure::Struct, }, stack::Stack, }; pub type ConsoleHandle = Rc>; #[derive(Clone)] pub struct VmOptions { #[cfg(debug_assertions)] pub tracing: bool, #[cfg(debug_assertions)] pub dump_stack: bool, pub vm_args: Vec, pub console: ConsoleHandle, } impl Default for VmOptions { fn default() -> Self { Self { #[cfg(debug_assertions)] tracing: Default::default(), #[cfg(debug_assertions)] dump_stack: Default::default(), vm_args: Default::default(), console: Rc::new(RefCell::new(StdConsole {})), } } } pub struct VirtualMachine { pub modules: HashMap, pub options: VmOptions, pub globals: VmGlobals, pub import_stack: Stack, pub imported_modules: HashMap, pub loaded_dylibs: HashMap, frame_pool: Vec, } impl VirtualMachine { pub fn console(&self) -> &ConsoleHandle { &self.options.console } pub(crate) fn acquire_frame(&mut self, f: &Function) -> Frame { let mut frame = self.frame_pool.pop().unwrap_or_default(); frame.reset_for_function(f); frame } pub(crate) fn release_frame(&mut self, frame: Frame) { self.frame_pool.push(frame.reset_for_pool()); } fn load_version_into_globals(mut self) -> Self { let aria_version = env!("CARGO_PKG_VERSION"); assert!(!aria_version.is_empty()); self.globals .insert("ARIA_VERSION", RuntimeValue::String(aria_version.into())); self } } impl Default for VirtualMachine { fn default() -> Self { let options = Default::default(); VirtualMachine::with_options(options) } } impl VirtualMachine { pub fn with_options(options: VmOptions) -> Self { Self { modules: Default::default(), options, globals: Default::default(), import_stack: Default::default(), imported_modules: Default::default(), loaded_dylibs: Default::default(), frame_pool: Default::default(), } .load_version_into_globals() } } macro_rules! build_vm_error { ($reason: expr, $next: expr, $frame: expr, $idx: expr) => {{ let lt = if let Some(lt) = $frame.get_line_table() { lt.get(*$idx as u16) } else { None }; Err($crate::error::vm_error::VmError { reason: $reason, opcode: Some($next), loc: lt, backtrace: Default::default(), }) }}; } macro_rules! pop_or_err { ($next: expr, $frame: expr, $idx: expr) => { if let Some(val) = $frame.stack.try_pop() { val } else { return build_vm_error!(VmErrorReason::EmptyStack, $next, $frame, $idx); } }; } pub type ExecutionResult = Result; pub struct ModuleLoadInfo { pub module: RuntimeModule, } pub enum RunloopExit { Ok(T), Exception(crate::error::exception::VmException), } impl RunloopExit { pub fn throw_object(value: RuntimeValue) -> Self { Self::Exception(VmException { value, backtrace: Default::default(), }) } pub fn throw_struct( struk: &Struct, values: &[(crate::symbol::Symbol, RuntimeValue)], builtins: &mut VmGlobals, ) -> Self { let object = RuntimeValue::Object(Object::new(struk)); for value in values { let _ = object.write_attribute(value.0, value.1.clone(), builtins); } Self::throw_object(object) } } enum OpcodeRunExit { Continue, Return, Exception(VmException), } macro_rules! binop_eval { ( ($op_expr: expr), $next: expr, $frame: expr, $op_idx: expr) => { match $op_expr { crate::runtime_value::OperatorEvalOutcome::Ok(val) => $frame.stack.push(val), crate::runtime_value::OperatorEvalOutcome::Exception(e) => { return Ok(OpcodeRunExit::Exception(e)); } crate::runtime_value::OperatorEvalOutcome::Error(err) => { if err.loc.is_some() { return Err(err); } else { return build_vm_error!(err.reason, $next, $frame, $op_idx); } } } }; } macro_rules! unaryop_eval { ( ($op_expr: expr), $next: expr, $frame: expr, $op_idx: expr) => { match $op_expr { crate::runtime_value::OperatorEvalOutcome::Ok(val) => $frame.stack.push(val), crate::runtime_value::OperatorEvalOutcome::Exception(e) => { return Ok(OpcodeRunExit::Exception(e)); } crate::runtime_value::OperatorEvalOutcome::Error(err) => { if err.loc.is_some() { return Err(err); } else { return build_vm_error!(err.reason, $next, $frame, $op_idx); } } } }; } fn get_lib_path(lib_name: &str) -> PathBuf { let exe_path = std::env::current_exe().expect("failed to get current exe path"); let exe_dir = exe_path.parent().expect("failed to get exe directory"); let lib_name = libloading::library_filename(lib_name); exe_dir.join(lib_name) } fn unique_insert(vec: &mut Vec, item: T) -> &Vec where T: PartialEq, { if !vec.contains(&item) { vec.push(item); } vec } impl VirtualMachine { fn get_system_import_paths() -> Vec { if let Ok(env_var) = std::env::var("ARIA_LIB_DIR") { let mut paths = Vec::new(); for candidate_dir in std::env::split_paths(env_var.as_str()) { if candidate_dir.exists() && candidate_dir.is_dir() { paths.push(candidate_dir); } } if !paths.is_empty() { return paths; } } if let Ok(exe_path) = std::env::current_exe() && let Some(exe_dir) = exe_path.parent() { let lib_aria_path = exe_dir.join("lib"); if lib_aria_path.join("aria").is_dir() { return vec![lib_aria_path]; } if let Some(exe_parent_dir) = exe_dir.parent() { let lib_aria_path = exe_parent_dir.join("lib"); if lib_aria_path.join("aria").is_dir() { return vec![lib_aria_path]; } } } let version = env!("CARGO_PKG_VERSION"); #[cfg(target_os = "linux")] { let system_lib_path = PathBuf::from(format!("/usr/local/aria{}/lib", version)); if system_lib_path.join("aria").is_dir() { return vec![system_lib_path]; } let system_lib_path = PathBuf::from("/usr/local/aria/lib"); if system_lib_path.join("aria").is_dir() { return vec![system_lib_path]; } let system_lib_path = PathBuf::from(format!("/usr/lib/aria{}", version)); if system_lib_path.join("aria").is_dir() { return vec![system_lib_path]; } let system_lib_path = PathBuf::from("/usr/lib/aria"); if system_lib_path.join("aria").is_dir() { return vec![system_lib_path]; } } #[cfg(target_os = "macos")] { let system_lib_path = PathBuf::from(format!("/opt/homebrew/opt/aria{}/lib", version)); if system_lib_path.join("aria").is_dir() { return vec![system_lib_path]; } let system_lib_path = PathBuf::from("/opt/homebrew/opt/aria/lib"); if system_lib_path.join("aria").is_dir() { return vec![system_lib_path]; } let version = env!("CARGO_PKG_VERSION"); let system_lib_path = PathBuf::from(format!("/usr/local/opt/aria{}/lib", version)); if system_lib_path.join("aria").is_dir() { return vec![system_lib_path]; } let system_lib_path = PathBuf::from("/usr/local/opt/aria/lib"); if system_lib_path.join("aria").is_dir() { return vec![system_lib_path]; } } Vec::new() } pub fn get_aria_library_paths() -> &'static Vec { static ARIA_LIBRARY_PATHS: OnceLock> = OnceLock::new(); ARIA_LIBRARY_PATHS.get_or_init(|| { let mut paths = Self::get_system_import_paths(); if let Ok(env_var) = std::env::var("ARIA_LIB_DIR_EXTRA") { for candidate_dir in std::env::split_paths(env_var.as_str()) { if candidate_dir.exists() && candidate_dir.is_dir() { paths.push(candidate_dir); } } } let mut ret_paths = vec![]; for path in paths { if let Ok(can) = std::fs::canonicalize(path) { unique_insert(&mut ret_paths, can); } } ret_paths }) } fn try_get_import_path_from_name( aria_lib_dir: impl AsRef, ipath: &str, ) -> Option { let mut module_path = aria_lib_dir.as_ref().to_path_buf(); module_path.push(ipath); if module_path.exists() { Some(module_path) } else { None } } fn resolve_import_path_to_path( ipath: &str, widget_root_path: Option<&PathBuf>, ) -> Result { if let Some(ipath) = ipath.strip_prefix("widget.") { return if let Some(widget_root_path) = widget_root_path { let ipath = format!("{}.aria", ipath.replace(".", "/")); Self::try_get_import_path_from_name(widget_root_path, &ipath).ok_or_else(|| { VmErrorReason::ImportNotAvailable( ipath.to_owned(), "import not found in widget".to_owned(), ) }) } else { Err(VmErrorReason::ImportNotAvailable( ipath.to_owned(), "tried to import from widget without a widget.json".to_owned(), )) }; } let ipath = format!("{}.aria", ipath.replace(".", "/")); let aria_lib_dirs = VirtualMachine::get_aria_library_paths(); for aria_lib_dir in aria_lib_dirs { if let Some(path) = Self::try_get_import_path_from_name(aria_lib_dir, &ipath) { return Ok(path); } } Err(VmErrorReason::ImportNotAvailable( ipath.to_owned(), "no such path".to_owned(), )) } fn create_import_model_from_path( module: &RuntimeModule, builtins: &mut VmGlobals, ipath: &str, leaf: RuntimeValue, ) -> Result { let components = ipath.split(".").collect::>(); if components.len() == 1 { let cmp_last = components[0]; module.store_named_value(cmp_last, leaf.clone()); return Ok(leaf); } let cmp0 = components[0]; let root = if let Some(cmp0_obj) = module.load_named_value(cmp0) && cmp0_obj.is_enum() { cmp0_obj } else { let cmp0_struct = Enum::new(cmp0); let cmp0_val = RuntimeValue::Type(RuntimeValueType::Enum(cmp0_struct.clone())); module.store_named_value(cmp0, cmp0_val); RuntimeValue::Type(RuntimeValueType::Enum(cmp0_struct)) }; let mut current_struct = root.clone(); fn get_or_create_empty_enum( current_struct: &RuntimeValue, name: &str, builtins: &mut VmGlobals, ) -> Result { let sym = builtins.intern_symbol(name)?; if let Ok(existing_val) = current_struct.read_attribute(sym, builtins) && existing_val.is_enum() { Ok(existing_val) } else { let new_val = RuntimeValue::Type(RuntimeValueType::Enum(Enum::new(name))); let _ = current_struct.write_attribute(sym, new_val.clone(), builtins); Ok(new_val) } } for cmp in components.iter().take(components.len() - 1).skip(1) { current_struct = get_or_create_empty_enum(¤t_struct, cmp, builtins)? } let cmp_last = components.last().unwrap(); let sym = builtins.intern_symbol(cmp_last)?; let _ = current_struct.write_attribute(sym, leaf.clone(), builtins); Ok(root) } pub fn load_into_module( &mut self, name: &str, r_mod: RuntimeModule, ) -> ExecutionResult> { if !name.is_empty() { self.modules.insert(name.to_owned(), r_mod.clone()); } let entry_co = r_mod.load_entry_code_object(); let entry_f = Function::from_code_object(entry_co, &r_mod); let mut entry_frame: Frame = Default::default(); let entry_result = entry_f.eval(0, &mut entry_frame, self, &Default::default(), true); match entry_result { Ok(ok) => match ok { crate::runtime_value::CallResult::Exception(e) => Ok(RunloopExit::Exception(e)), _ => Ok(RunloopExit::Ok(ModuleLoadInfo { module: r_mod })), }, Err(err) => Err(err), } } pub fn load_module( &mut self, name: &str, entry_cm: CompiledModule, ) -> ExecutionResult> { let r_mod = RuntimeModule::new(self, entry_cm)?; self.load_into_module(name, r_mod) } pub fn get_module_by_name(&self, name: &str) -> Option { self.modules.get(name).cloned() } pub(crate) fn find_imported_module(&self, name: &str) -> Option { self.imported_modules .get(name) .map(|mli| mli.module.clone()) } pub fn inject_imported_module(&mut self, name: &str, module: RuntimeModule) { self.imported_modules .insert(name.to_owned(), ModuleLoadInfo { module }); } pub fn execute_module(&mut self, m: &RuntimeModule) -> ExecutionResult { let main_f = match m.load_named_value("main") { Some(RuntimeValue::Function(f)) => f, _ => return Ok(RunloopExit::Ok(())), }; let mut main_frame = Frame::default(); let main_arity = main_f.arity(); let req = main_arity.required; let opt = main_arity.optional; let va = main_f.varargs(); let main_argc = if req == 0 && opt == 0 && !va { 0 } else if req == 1 && opt == 0 && !va { let cmdline_args = RuntimeValue::List(List::from( &self .options .vm_args .iter() .map(|arg| RuntimeValue::String(arg.as_str().into())) .collect::>(), )); main_frame.stack.push(cmdline_args); 1 } else if req == 0 && opt == 0 && va { self.options .vm_args .iter() .rev() .map(|arg| RuntimeValue::String(arg.as_str().into())) .for_each(|arg| main_frame.stack.push(arg)); self.options.vm_args.len() as u8 } else { return Err(VmErrorReason::InvalidMainSignature.into()); }; match main_f.eval(main_argc, &mut main_frame, self, &Default::default(), true)? { crate::runtime_value::CallResult::Ok(_) => Ok(RunloopExit::Ok(())), crate::runtime_value::CallResult::Exception(e) => Ok(RunloopExit::Exception(e)), } } fn read_named_symbol( &self, module: &RuntimeModule, name: &str, ) -> Result { match module.load_named_value(name) { Some(nv) => Ok(nv), _ => match self.globals.load_named_value(name) { Some(nv) => Ok(nv), _ => Err(VmErrorReason::NoSuchIdentifier(name.to_owned())), }, } } pub(crate) fn eval_bytecode_in_frame( &mut self, module: &RuntimeModule, bc: &[Opcode], sidecar: &SidecarSlice, target_frame: &mut Frame, ) -> ExecutionResult { self.runloop(bc, sidecar, module, target_frame) } fn run_opcode( &mut self, next: Opcode, next_sidecar: &SidecarCell, op_idx: &mut usize, this_module: &RuntimeModule, frame: &mut Frame, ) -> ExecutionResult { match next { Opcode::Nop => {} Opcode::Push(n) => match this_module.load_indexed_const(n) { Some(rv) => { frame.stack.push(rv.clone()); } None => { return build_vm_error!( VmErrorReason::NoSuchModuleConstant(n), next, frame, op_idx ); } }, Opcode::Push0 => frame.stack.push(RuntimeValue::Integer(0.into())), Opcode::Push1 => frame.stack.push(RuntimeValue::Integer(1.into())), Opcode::PushTrue => frame.stack.push(RuntimeValue::Boolean(true.into())), Opcode::PushFalse => frame.stack.push(RuntimeValue::Boolean(false.into())), Opcode::PushBuiltinTy(n) => frame .stack .push(RuntimeValue::Type(self.globals.get_builtin_type_by_id(n))), Opcode::PushRuntimeValue(n) => match n { haxby_opcodes::BuiltinValueId::ThisModule => { frame.stack.push(RuntimeValue::Module(this_module.clone())) } }, Opcode::Pop => { pop_or_err!(next, frame, op_idx); } Opcode::Dup => { if let Some(val) = frame.stack.peek() { let val = val.clone(); frame.stack.push(val); } } Opcode::Swap => { let x = pop_or_err!(next, frame, op_idx); let y = pop_or_err!(next, frame, op_idx); frame.stack.push(x); frame.stack.push(y); } Opcode::Copy(n) => { let val = frame.stack.peek_at_offset(n as usize); if let Some(val) = val { let val = val.clone(); frame.stack.push(val); } } Opcode::Add => { let x = pop_or_err!(next, frame, op_idx); let y = pop_or_err!(next, frame, op_idx); if let (RuntimeValue::Integer(a), RuntimeValue::Integer(b)) = (&x, &y) { frame.stack.push(RuntimeValue::Integer(b + a)); } else if let (RuntimeValue::Integer(a), RuntimeValue::Float(b)) = (&x, &y) { frame.stack.push(RuntimeValue::Float(b + &a.to_fp())); } else if let (RuntimeValue::Float(a), RuntimeValue::Integer(b)) = (&x, &y) { frame.stack.push(RuntimeValue::Float(&b.to_fp() + a)); } else if let (RuntimeValue::String(a), RuntimeValue::String(b)) = (&x, &y) { frame.stack.push(RuntimeValue::String(b + a)); } else if let (RuntimeValue::Float(a), RuntimeValue::Float(b)) = (&x, &y) { frame.stack.push(RuntimeValue::Float(b + a)) } else { binop_eval!( (RuntimeValue::add(&y, &x, frame, self)), next, frame, op_idx ) } } Opcode::Sub => { let x = pop_or_err!(next, frame, op_idx); let y = pop_or_err!(next, frame, op_idx); if let (RuntimeValue::Integer(a), RuntimeValue::Integer(b)) = (&x, &y) { frame.stack.push(RuntimeValue::Integer(b - a)); } else if let (RuntimeValue::Float(a), RuntimeValue::Float(b)) = (&x, &y) { frame.stack.push(RuntimeValue::Float(b - a)) } else if let (RuntimeValue::Integer(a), RuntimeValue::Float(b)) = (&x, &y) { frame.stack.push(RuntimeValue::Float(b - &a.to_fp())); } else if let (RuntimeValue::Float(a), RuntimeValue::Integer(b)) = (&x, &y) { frame.stack.push(RuntimeValue::Float(&b.to_fp() - a)); } else { binop_eval!( (RuntimeValue::sub(&y, &x, frame, self)), next, frame, op_idx ) } } Opcode::Mul => { let x = pop_or_err!(next, frame, op_idx); let y = pop_or_err!(next, frame, op_idx); if let (RuntimeValue::Integer(a), RuntimeValue::Integer(b)) = (&x, &y) { frame.stack.push(RuntimeValue::Integer(b * a)); } else if let (RuntimeValue::Float(a), RuntimeValue::Float(b)) = (&x, &y) { frame.stack.push(RuntimeValue::Float(b * a)) } else if let (RuntimeValue::Integer(a), RuntimeValue::Float(b)) = (&x, &y) { frame.stack.push(RuntimeValue::Float(b * &a.to_fp())); } else if let (RuntimeValue::Float(a), RuntimeValue::Integer(b)) = (&x, &y) { frame.stack.push(RuntimeValue::Float(&b.to_fp() * a)); } else { binop_eval!( (RuntimeValue::mul(&y, &x, frame, self)), next, frame, op_idx ) } } Opcode::Div => { let x = pop_or_err!(next, frame, op_idx); let y = pop_or_err!(next, frame, op_idx); if let (RuntimeValue::Integer(a), RuntimeValue::Integer(b)) = (&x, &y) { if *a.raw_value() == 0 { return build_vm_error!(VmErrorReason::DivisionByZero, next, frame, op_idx); } frame.stack.push(RuntimeValue::Integer(b / a)); } else if let (RuntimeValue::Float(a), RuntimeValue::Float(b)) = (&x, &y) { if *a.raw_value() == 0.0 { return build_vm_error!(VmErrorReason::DivisionByZero, next, frame, op_idx); } frame.stack.push(RuntimeValue::Float(b / a)) } else if let (RuntimeValue::Integer(a), RuntimeValue::Float(b)) = (&x, &y) { if *a.raw_value() == 0 { return build_vm_error!(VmErrorReason::DivisionByZero, next, frame, op_idx); } frame.stack.push(RuntimeValue::Float(b / &a.to_fp())); } else if let (RuntimeValue::Float(a), RuntimeValue::Integer(b)) = (&x, &y) { if *a.raw_value() == 0.0 { return build_vm_error!(VmErrorReason::DivisionByZero, next, frame, op_idx); } frame.stack.push(RuntimeValue::Float(&b.to_fp() / a)); } else { binop_eval!( (RuntimeValue::div(&y, &x, frame, self)), next, frame, op_idx ) } } Opcode::Rem => { let x = pop_or_err!(next, frame, op_idx); let y = pop_or_err!(next, frame, op_idx); if let (RuntimeValue::Integer(a), RuntimeValue::Integer(b)) = (&x, &y) { if *a.raw_value() == 0 { return build_vm_error!(VmErrorReason::DivisionByZero, next, frame, op_idx); } frame.stack.push(RuntimeValue::Integer(b % a)); } else if let (RuntimeValue::Float(a), RuntimeValue::Float(b)) = (&x, &y) { if *a.raw_value() == 0.0 { return build_vm_error!(VmErrorReason::DivisionByZero, next, frame, op_idx); } frame.stack.push(RuntimeValue::Float(b % a)) } else if let (RuntimeValue::Integer(a), RuntimeValue::Float(b)) = (&x, &y) { if *a.raw_value() == 0 { return build_vm_error!(VmErrorReason::DivisionByZero, next, frame, op_idx); } frame.stack.push(RuntimeValue::Float(b % &a.to_fp())) } else if let (RuntimeValue::Float(a), RuntimeValue::Integer(b)) = (&x, &y) { if *a.raw_value() == 0.0 { return build_vm_error!(VmErrorReason::DivisionByZero, next, frame, op_idx); } frame.stack.push(RuntimeValue::Float(&b.to_fp() % a)) } else { binop_eval!( (RuntimeValue::rem(&y, &x, frame, self)), next, frame, op_idx ) } } Opcode::Neg => { let n = pop_or_err!(next, frame, op_idx); if let RuntimeValue::Integer(i) = &n { frame.stack.push(RuntimeValue::Integer(-i)); } else if let RuntimeValue::Float(i) = &n { frame.stack.push(RuntimeValue::Float(-i)); } else { unaryop_eval!((RuntimeValue::neg(&n, frame, self)), next, frame, op_idx) } } Opcode::ShiftLeft => { let by = pop_or_err!(next, frame, op_idx); let n = pop_or_err!(next, frame, op_idx); if let (RuntimeValue::Integer(n), RuntimeValue::Integer(by)) = (&n, &by) { frame.stack.push(RuntimeValue::Integer(n << by)); } else { binop_eval!( (RuntimeValue::leftshift(&n, &by, frame, self)), next, frame, op_idx ) } } Opcode::ShiftRight => { let by = pop_or_err!(next, frame, op_idx); let n = pop_or_err!(next, frame, op_idx); if let (RuntimeValue::Integer(n), RuntimeValue::Integer(by)) = (&n, &by) { frame.stack.push(RuntimeValue::Integer(n >> by)); } else { binop_eval!( (RuntimeValue::rightshift(&n, &by, frame, self)), next, frame, op_idx ) } } Opcode::Not => { let b = pop_or_err!(next, frame, op_idx); if let RuntimeValue::Boolean(b) = b { frame.stack.push(RuntimeValue::Boolean(!b)); } else { return build_vm_error!(VmErrorReason::UnexpectedType, next, frame, op_idx); } } Opcode::Equal => { let x = pop_or_err!(next, frame, op_idx); let y = pop_or_err!(next, frame, op_idx); let eq_result = RuntimeValue::Boolean(Into::into(RuntimeValue::equals(&y, &x, frame, self))); frame.stack.push(eq_result); } Opcode::LessThan => { let x = pop_or_err!(next, frame, op_idx); let y = pop_or_err!(next, frame, op_idx); if let (RuntimeValue::Integer(a), RuntimeValue::Integer(b)) = (&x, &y) { frame.stack.push(RuntimeValue::Boolean(Into::into(b < a))); } else if let (RuntimeValue::Float(a), RuntimeValue::Float(b)) = (&x, &y) { frame.stack.push(RuntimeValue::Boolean(Into::into(b < a))); } else if let (RuntimeValue::Integer(a), RuntimeValue::Float(b)) = (&x, &y) { frame .stack .push(RuntimeValue::Boolean(Into::into(*b < a.to_fp()))); } else if let (RuntimeValue::Float(a), RuntimeValue::Integer(b)) = (&x, &y) { frame .stack .push(RuntimeValue::Boolean(Into::into(b.to_fp() < *a))); } else { binop_eval!( (RuntimeValue::less_than(&y, &x, frame, self)), next, frame, op_idx ) } } Opcode::LessThanEqual => { let x = pop_or_err!(next, frame, op_idx); let y = pop_or_err!(next, frame, op_idx); if let (RuntimeValue::Integer(a), RuntimeValue::Integer(b)) = (&x, &y) { frame.stack.push(RuntimeValue::Boolean(Into::into(b <= a))); } else if let (RuntimeValue::Float(a), RuntimeValue::Float(b)) = (&x, &y) { frame.stack.push(RuntimeValue::Boolean(Into::into(b <= a))); } else if let (RuntimeValue::Integer(a), RuntimeValue::Float(b)) = (&x, &y) { frame .stack .push(RuntimeValue::Boolean(Into::into(*b <= a.to_fp()))); } else if let (RuntimeValue::Float(a), RuntimeValue::Integer(b)) = (&x, &y) { frame .stack .push(RuntimeValue::Boolean(Into::into(b.to_fp() <= *a))); } else { binop_eval!( (RuntimeValue::less_than_equal(&y, &x, frame, self)), next, frame, op_idx ) } } Opcode::GreaterThan => { let x = pop_or_err!(next, frame, op_idx); let y = pop_or_err!(next, frame, op_idx); if let (RuntimeValue::Integer(a), RuntimeValue::Integer(b)) = (&x, &y) { frame.stack.push(RuntimeValue::Boolean(Into::into(b > a))); } else if let (RuntimeValue::Float(a), RuntimeValue::Float(b)) = (&x, &y) { frame.stack.push(RuntimeValue::Boolean(Into::into(b > a))); } else if let (RuntimeValue::Integer(a), RuntimeValue::Float(b)) = (&x, &y) { frame .stack .push(RuntimeValue::Boolean(Into::into(*b > a.to_fp()))); } else if let (RuntimeValue::Float(a), RuntimeValue::Integer(b)) = (&x, &y) { frame .stack .push(RuntimeValue::Boolean(Into::into(b.to_fp() > *a))); } else { binop_eval!( (RuntimeValue::greater_than(&y, &x, frame, self)), next, frame, op_idx ) } } Opcode::GreaterThanEqual => { let x = pop_or_err!(next, frame, op_idx); let y = pop_or_err!(next, frame, op_idx); if let (RuntimeValue::Integer(a), RuntimeValue::Integer(b)) = (&x, &y) { frame.stack.push(RuntimeValue::Boolean(Into::into(b >= a))); } else if let (RuntimeValue::Float(a), RuntimeValue::Float(b)) = (&x, &y) { frame.stack.push(RuntimeValue::Boolean(Into::into(b >= a))); } else if let (RuntimeValue::Integer(a), RuntimeValue::Float(b)) = (&x, &y) { frame .stack .push(RuntimeValue::Boolean(Into::into(*b >= a.to_fp()))); } else if let (RuntimeValue::Float(a), RuntimeValue::Integer(b)) = (&x, &y) { frame .stack .push(RuntimeValue::Boolean(Into::into(b.to_fp() >= *a))); } else { binop_eval!( (RuntimeValue::greater_than_equal(&y, &x, frame, self)), next, frame, op_idx ) } } Opcode::ReadLocal(n) => { let local = frame.locals[n as usize].val.clone(); frame.stack.push(local); } Opcode::ReadUplevel(n) => { if let Some(f) = &frame.func { if let Some(bcf) = f.imp.as_bytecode_function() { match bcf.read_uplevel(n) { Some(ulv) => { frame.stack.push(ulv); } _ => { return build_vm_error!( VmErrorReason::UplevelOutOfBounds(n as usize), next, frame, op_idx ); } } } else { return build_vm_error!(VmErrorReason::UnexpectedType, next, frame, op_idx); } } else { return build_vm_error!(VmErrorReason::UnexpectedType, next, frame, op_idx); } } Opcode::StoreUplevel(n) => { let x = pop_or_err!(next, frame, op_idx); if let Some(f) = x.as_function() { if let Some(bcf) = f.imp.as_bytecode_function() { let local = frame.locals[n as usize].val.clone(); bcf.store_uplevel(n, local); } else { return build_vm_error!(VmErrorReason::UnexpectedType, next, frame, op_idx); } } else { return build_vm_error!(VmErrorReason::UnexpectedType, next, frame, op_idx); } frame.stack.push(x); } Opcode::WriteLocal(n) => { let x = pop_or_err!(next, frame, op_idx); let local = &mut frame.locals[n as usize]; if !local.ty.isa_check(&x, &self.globals) { return build_vm_error!(VmErrorReason::UnexpectedType, next, frame, op_idx); } else { local.val = x; } } Opcode::TypedefLocal(n) => { let t = pop_or_err!(next, frame, op_idx); if let Ok(isa_check) = IsaCheckable::try_from(&t) { frame.locals[n as usize].ty = isa_check; } else { return build_vm_error!(VmErrorReason::UnexpectedType, next, frame, op_idx); } } Opcode::ReadNamed(n) => { if let Some(ct) = this_module.load_indexed_const(n) && let Some(sv) = ct.as_string() { frame .stack .push(self.read_named_symbol(this_module, sv.raw_value())?); } } Opcode::WriteNamed(n) => { let x = pop_or_err!(next, frame, op_idx); if let Some(ct) = this_module.load_indexed_const(n) && let Some(sv) = ct.as_string() { let write_result = this_module.store_typechecked_named_value(sv.raw_value(), x, &self.globals); match write_result { Ok(_) => {} Err(e) => { return build_vm_error!(e, next, frame, op_idx); } } } } Opcode::TypedefNamed(n) => { let t = pop_or_err!(next, frame, op_idx); if let Ok(t) = IsaCheckable::try_from(&t) { if let Some(ct) = this_module.load_indexed_const(n) && let Some(sv) = ct.as_string() { this_module.typedef_named_value(sv.raw_value(), t); } } else { return build_vm_error!(VmErrorReason::UnexpectedType, next, frame, op_idx); } } Opcode::ReadIndex(n) => { let mut indices = Vec::<_>::with_capacity(n as usize); for _ in 0..n { let idx = pop_or_err!(next, frame, op_idx); indices.push(idx); } indices.reverse(); let cnt = pop_or_err!(next, frame, op_idx); match cnt.read_index(&indices, frame, self) { Ok(crate::runtime_value::CallResult::Ok(_)) => {} Ok(crate::runtime_value::CallResult::Exception(e)) => { return Ok(OpcodeRunExit::Exception(e)); } Err(e) => { return if e.loc.is_none() { build_vm_error!(e.reason, next, frame, op_idx) } else { Err(e) }; } } } Opcode::WriteIndex(n) => { let val = pop_or_err!(next, frame, op_idx); let mut indices = Vec::<_>::with_capacity(n as usize); for _ in 0..n { let idx = pop_or_err!(next, frame, op_idx); indices.push(idx); } indices.reverse(); let cnt = pop_or_err!(next, frame, op_idx); match cnt.write_index(&indices, &val, frame, self) { Ok(crate::runtime_value::CallResult::Ok(_)) => {} Ok(crate::runtime_value::CallResult::Exception(e)) => { return Ok(OpcodeRunExit::Exception(e)); } Err(e) => { return if e.loc.is_none() { build_vm_error!(e.reason, next, frame, op_idx) } else { Err(e) }; } } } Opcode::ReadAttribute(_) => { return build_vm_error!( VmErrorReason::UnknownOpcode(OPCODE_READ_ATTRIBUTE), next, frame, op_idx ); } Opcode::WriteAttribute(_) => { return build_vm_error!( VmErrorReason::UnknownOpcode(OPCODE_WRITE_ATTRIBUTE), next, frame, op_idx ); } Opcode::ReadAttributeSymbol(n) => { let n = crate::symbol::Symbol(n); let val_obj = pop_or_err!(next, frame, op_idx); let current_sidecar = next_sidecar .get() .and_then(|sc| sc.as_read_attribute().copied()); let mut current_misses = current_sidecar .as_ref() .map(|sc| sc.misses) .unwrap_or_default(); if let Some(sc) = current_sidecar && current_misses < ReadAttributeSidecar::MAXIMUM_ALLOWED_MISSES { if let Some(v) = val_obj.read_slot(&self.globals, sc.slot_id, sc.shape_id) { frame.stack.push(v); return Ok(OpcodeRunExit::Continue); } else { current_misses = current_misses .saturating_add(1) .clamp(0, ReadAttributeSidecar::MAXIMUM_ALLOWED_MISSES); } } if current_misses < ReadAttributeSidecar::MAXIMUM_ALLOWED_MISSES && let Some((v, sid, slot)) = val_obj.resolve_to_slot(&self.globals, n) { next_sidecar.set(Some(OpcodeSidecar::ReadAttribute(ReadAttributeSidecar { misses: current_misses, shape_id: sid, slot_id: slot, }))); frame.stack.push(v); return Ok(OpcodeRunExit::Continue); } // if you're here, either you had no sidecar, or you did but your sidecar failed and you didn't get a valid // alternative slot to try (or you would have returned in the earlier if) - record where you're at (if you had a // sidecar to begin with), and then do a full slow path attribute read if let Some(sc) = current_sidecar { next_sidecar.set(Some(OpcodeSidecar::ReadAttribute(ReadAttributeSidecar { misses: current_misses, shape_id: sc.shape_id, slot_id: sc.slot_id, }))); } match val_obj.read_attribute(n, &self.globals) { Ok(val) => { frame.stack.push(val); } Err(err) => { return build_vm_error!( match err { crate::runtime_value::AttributeError::NoSuchAttribute => { VmErrorReason::NoSuchSymbol(n.0, SymbolKind::Identifier) } crate::runtime_value::AttributeError::InvalidFunctionBinding => { VmErrorReason::InvalidBinding } crate::runtime_value::AttributeError::ValueHasNoAttributes => { VmErrorReason::UnexpectedType } }, next, frame, op_idx ); } } } Opcode::WriteAttributeSymbol(n) => { let val = pop_or_err!(next, frame, op_idx); let obj = pop_or_err!(next, frame, op_idx); match obj.write_attribute(crate::symbol::Symbol(n), val, &mut self.globals) { Ok(_) => {} Err(err) => { return build_vm_error!( match err { crate::runtime_value::AttributeError::NoSuchAttribute => { VmErrorReason::NoSuchSymbol(n, SymbolKind::Identifier) } crate::runtime_value::AttributeError::InvalidFunctionBinding => { VmErrorReason::InvalidBinding } crate::runtime_value::AttributeError::ValueHasNoAttributes => { VmErrorReason::UnexpectedType } }, next, frame, op_idx ); } } } Opcode::LogicalAnd => { let x = pop_or_err!(next, frame, op_idx); let y = pop_or_err!(next, frame, op_idx); if let (RuntimeValue::Boolean(a), RuntimeValue::Boolean(b)) = (&x, &y) { frame.stack.push(RuntimeValue::Boolean(a & b)); } else { return build_vm_error!(VmErrorReason::UnexpectedType, next, frame, op_idx); } } Opcode::LogicalOr => { let x = pop_or_err!(next, frame, op_idx); let y = pop_or_err!(next, frame, op_idx); if let (RuntimeValue::Boolean(a), RuntimeValue::Boolean(b)) = (&x, &y) { frame.stack.push(RuntimeValue::Boolean(a | b)); } else { return build_vm_error!(VmErrorReason::UnexpectedType, next, frame, op_idx); } } Opcode::Xor => { let x = pop_or_err!(next, frame, op_idx); let y = pop_or_err!(next, frame, op_idx); if let (RuntimeValue::Boolean(a), RuntimeValue::Boolean(b)) = (&x, &y) { frame.stack.push(RuntimeValue::Boolean(a ^ b)); } else if let (RuntimeValue::Integer(a), RuntimeValue::Integer(b)) = (&x, &y) { frame.stack.push(RuntimeValue::Integer(a ^ b)); } else { binop_eval!( (RuntimeValue::xor(&y, &x, frame, self)), next, frame, op_idx ) } } Opcode::BitwiseAnd => { let x = pop_or_err!(next, frame, op_idx); let y = pop_or_err!(next, frame, op_idx); if let (RuntimeValue::Integer(a), RuntimeValue::Integer(b)) = (&x, &y) { frame.stack.push(RuntimeValue::Integer(a & b)); } else if let Ok(x) = IsaCheckable::try_from(&x) && let Ok(y) = IsaCheckable::try_from(&y) { frame.stack.push(RuntimeValue::TypeCheck(x & &y)); } else { binop_eval!( (RuntimeValue::bitwise_and(&y, &x, frame, self)), next, frame, op_idx ) } } Opcode::BitwiseOr => { let x = pop_or_err!(next, frame, op_idx); let y = pop_or_err!(next, frame, op_idx); if let (RuntimeValue::Integer(a), RuntimeValue::Integer(b)) = (&x, &y) { frame.stack.push(RuntimeValue::Integer(a | b)); } else if let Ok(x) = IsaCheckable::try_from(&x) && let Ok(y) = IsaCheckable::try_from(&y) { frame.stack.push(RuntimeValue::TypeCheck(x | &y)); } else { binop_eval!( (RuntimeValue::bitwise_or(&y, &x, frame, self)), next, frame, op_idx ) } } Opcode::JumpTrue(n) => { let x = pop_or_err!(next, frame, op_idx); if let RuntimeValue::Boolean(v) = x { if *v.raw_value() { *op_idx = n as usize; } } else { return build_vm_error!(VmErrorReason::UnexpectedType, next, frame, op_idx); } } Opcode::JumpFalse(n) => { let x = pop_or_err!(next, frame, op_idx); if let RuntimeValue::Boolean(v) = x { if !v.raw_value() { *op_idx = n as usize; } } else { return build_vm_error!(VmErrorReason::UnexpectedType, next, frame, op_idx); } } Opcode::JumpConditionally(t, f) => { let x = pop_or_err!(next, frame, op_idx); if let Some(b) = x.as_boolean() { *op_idx = if *b.raw_value() { t } else { f } as usize; } else { return build_vm_error!(VmErrorReason::UnexpectedType, next, frame, op_idx); } } Opcode::Jump(n) => { *op_idx = n as usize; } Opcode::JumpIfArgSupplied(arg, dest) => { if frame.argc > arg { *op_idx = dest as usize; } } Opcode::Call(argc) => { let x = pop_or_err!(next, frame, op_idx); match x.eval(argc, frame, self, false) { Ok(crate::runtime_value::CallResult::Ok(_)) => {} Ok(crate::runtime_value::CallResult::Exception(e)) => { return Ok(OpcodeRunExit::Exception(e)); } Err(err) => { if err.loc.is_some() { return Err(err); } else { return build_vm_error!(err.reason, next, frame, op_idx); } } } } Opcode::Return => { return Ok(OpcodeRunExit::Return); } Opcode::ReturnUnit => { return match self.globals.create_unit_object() { Ok(unit) => { frame.stack.push(unit); Ok(OpcodeRunExit::Return) } Err(e) => { build_vm_error!(e, next, frame, op_idx) } }; } Opcode::TryEnter(offset) => { frame .ctrl_blocks .push(crate::frame::ControlBlock::Try(offset)); } Opcode::TryExit => match frame.ctrl_blocks.try_pop() { Some(block) => match block { crate::frame::ControlBlock::Try(_) => {} }, _ => { return build_vm_error!(VmErrorReason::EmptyStack, next, frame, op_idx); } }, Opcode::Throw => { let ev = pop_or_err!(next, frame, op_idx); match frame.drop_to_first_try(self) { Some(catch_offset) => { *op_idx = catch_offset as usize; frame.stack.push(ev); } None => { let e = VmException::from_value(ev); return Ok(OpcodeRunExit::Exception(e)); } }; } Opcode::BuildList(n) => { let values = (0..n).map(|_| frame.stack.try_pop()).collect::>(); let list = List::default(); for value in values.iter().rev() { list.append(match value { Some(x) => x.clone(), None => { return build_vm_error!(VmErrorReason::EmptyStack, next, frame, op_idx); } }); } let list = RuntimeValue::List(list); frame.stack.push(list); } Opcode::BuildFunction => { let val = pop_or_err!(next, frame, op_idx); if let Some(co) = val.as_code_object() { let f = Function::from_code_object(co, this_module); frame.stack.push(RuntimeValue::Function(f)); } else { return build_vm_error!(VmErrorReason::UnexpectedType, next, frame, op_idx); } } Opcode::BuildStruct => { let name = pop_or_err!(next, frame, op_idx); if let Some(name) = name.as_string() { frame .stack .push(RuntimeValue::Type(RuntimeValueType::Struct(Struct::new( name.raw_value(), )))); } else { return build_vm_error!(VmErrorReason::UnexpectedType, next, frame, op_idx); } } Opcode::BuildEnum => { let name = pop_or_err!(next, frame, op_idx); if let Some(name) = name.as_string() { frame .stack .push(RuntimeValue::Type(RuntimeValueType::Enum(Enum::new( name.raw_value(), )))); } else { return build_vm_error!(VmErrorReason::UnexpectedType, next, frame, op_idx); } } Opcode::BuildMixin => { let name = pop_or_err!(next, frame, op_idx); if let Some(name) = name.as_string() { frame .stack .push(RuntimeValue::Mixin(Mixin::new(name.raw_value()))); } else { return build_vm_error!(VmErrorReason::UnexpectedType, next, frame, op_idx); } } Opcode::IncludeMixin => { let mixin = pop_or_err!(next, frame, op_idx); let struk = pop_or_err!(next, frame, op_idx); if let (Some(mixin), Some(strukt)) = (mixin.as_mixin(), struk.as_struct()) { strukt.include_mixin(mixin); } else if let (Some(mixin), Some(enumm)) = (mixin.as_mixin(), struk.as_enum()) { enumm.include_mixin(mixin); } else if let (Some(mixin), Some(btt)) = (mixin.as_mixin(), struk.as_rust_native()) { btt.include_mixin(mixin); } else if let (Some(src_mixin), Some(dst_mixin)) = (mixin.as_mixin(), struk.as_mixin()) { dst_mixin.include_mixin(src_mixin); } else { return build_vm_error!(VmErrorReason::UnexpectedType, next, frame, op_idx); } } Opcode::BindCase(..) => { return build_vm_error!( VmErrorReason::UnknownOpcode(OPCODE_BIND_CASE), next, frame, op_idx ); } Opcode::BindCaseSymbol(a, n) => { let payload_type = if (a & CASE_HAS_PAYLOAD) == CASE_HAS_PAYLOAD { let t = pop_or_err!(next, frame, op_idx); if let Ok(t) = IsaCheckable::try_from(&t) { Some(t) } else { return build_vm_error!(VmErrorReason::UnexpectedType, next, frame, op_idx); } } else { None }; let new_case = EnumCase { name: crate::symbol::Symbol(n), payload_type, }; let enumm = pop_or_err!(next, frame, op_idx); match enumm.as_enum() { Some(enumm) => { enumm.add_case(&mut self.globals, new_case); } _ => { return build_vm_error!(VmErrorReason::UnexpectedType, next, frame, op_idx); } } } Opcode::NewEnumVal(..) => { return build_vm_error!( VmErrorReason::UnknownOpcode(OPCODE_NEW_ENUM_VAL), next, frame, op_idx ); } Opcode::EnumCheckIsCase(_) => { return build_vm_error!( VmErrorReason::UnknownOpcode(OPCODE_ENUM_CHECK_IS_CASE), next, frame, op_idx ); } Opcode::NewEnumValSymbol(a, n) => { let has_payload = (a & CASE_HAS_PAYLOAD) == CASE_HAS_PAYLOAD; let case_sym = crate::symbol::Symbol(n); let enumm = pop_or_err!(next, frame, op_idx); let enumm = if let Some(enumm) = enumm.as_enum() { enumm } else { return build_vm_error!(VmErrorReason::UnexpectedType, next, frame, op_idx); }; let mut create_enum_payload = |case: &EnumCase, cidx, has_payload| -> ExecutionResult { if case.payload_type.is_some() != has_payload { return build_vm_error!( VmErrorReason::UnexpectedType, next, frame, op_idx ); } let payload = match &case.payload_type { Some(pt) => { let pv = pop_or_err!(next, frame, op_idx); if !pt.isa_check(&pv, &self.globals) { return build_vm_error!( VmErrorReason::UnexpectedType, next, frame, op_idx ); } else { Some(pv) } } None => None, }; let ev = enumm.make_value(cidx, payload).unwrap(); frame.stack.push(RuntimeValue::EnumValue(ev)); Ok(OpcodeRunExit::Continue) }; let current_sidecar = next_sidecar .get() .and_then(|sc| sc.as_new_enum_val().copied()); let mut current_misses = current_sidecar .as_ref() .map(|sc| sc.misses) .unwrap_or_default(); let case_shape = enumm.case_shape_id(); if let Some(sc) = current_sidecar && current_misses < NewEnumValSidecar::MAXIMUM_ALLOWED_MISSES && sc.shape_id == case_shape && let Some(case) = enumm.get_case_by_idx(sc.slot_id.0 as usize) { return create_enum_payload(&case, sc.slot_id.0 as usize, has_payload); } else { current_misses = current_misses .saturating_add(1) .clamp(0, NewEnumValSidecar::MAXIMUM_ALLOWED_MISSES); } if current_misses < NewEnumValSidecar::MAXIMUM_ALLOWED_MISSES && let Some((shape_id, slot_id)) = enumm.resolve_to_slot(&self.globals, case_sym) { let cidx = slot_id.0 as usize; if let Some(case) = enumm.get_case_by_idx(cidx) { next_sidecar.set(Some(OpcodeSidecar::NewEnumVal(NewEnumValSidecar { misses: current_misses, shape_id, slot_id, }))); return create_enum_payload(&case, cidx, has_payload); } } // if you're here, either you had no sidecar, or you did but your sidecar failed and you didn't get a valid // alternative slot to try (or you would have returned in the earlier if) - record where you're at (if you had a // sidecar to begin with), and then do a full slow path attribute read if let Some(sc) = current_sidecar { next_sidecar.set(Some(OpcodeSidecar::NewEnumVal(NewEnumValSidecar { misses: current_misses, shape_id: sc.shape_id, slot_id: sc.slot_id, }))); } if let Some(cidx) = enumm.get_idx_of_case_by_symbol(&self.globals, case_sym) && let Some(case) = enumm.get_case_by_idx(cidx) { return create_enum_payload(&case, cidx, has_payload); } else { return build_vm_error!( VmErrorReason::NoSuchSymbol(case_sym.0, SymbolKind::Case), next, frame, op_idx ); } } Opcode::EnumCheckIsCaseSymbol(n) => { let case_sym = crate::symbol::Symbol(n); let ev = pop_or_err!(next, frame, op_idx); let ev = if let Some(ev) = ev.as_enum_value() { ev } else { return build_vm_error!(VmErrorReason::UnexpectedType, next, frame, op_idx); }; let current_sidecar = next_sidecar .get() .and_then(|sc| sc.as_enum_check_is_case().copied()); let mut current_misses = current_sidecar .as_ref() .map(|sc| sc.misses) .unwrap_or_default(); let case_shape = ev.get_container_enum().case_shape_id(); if let Some(sc) = current_sidecar && current_misses < NewEnumValSidecar::MAXIMUM_ALLOWED_MISSES && sc.shape_id == case_shape && sc.slot_id.0 as usize == ev.get_case_index() { frame.stack.push(RuntimeValue::Boolean(true.into())); return Ok(OpcodeRunExit::Continue); } else { current_misses = current_misses .saturating_add(1) .clamp(0, NewEnumValSidecar::MAXIMUM_ALLOWED_MISSES); } if current_misses < NewEnumValSidecar::MAXIMUM_ALLOWED_MISSES && let Some((shape_id, slot_id)) = ev .get_container_enum() .resolve_to_slot(&self.globals, case_sym) && slot_id.0 as usize == ev.get_case_index() { next_sidecar.set(Some(OpcodeSidecar::EnumCheckIsCase( EnumCheckIsCaseSidecar { misses: current_misses, shape_id, slot_id, }, ))); frame.stack.push(RuntimeValue::Boolean(true.into())); return Ok(OpcodeRunExit::Continue); } // if you're here, either you had no sidecar, or you did but your sidecar failed and you didn't get a valid // alternative slot to try (or you would have returned in the earlier if) - record where you're at (if you had a // sidecar to begin with), and then do a full slow path attribute read if let Some(sc) = current_sidecar { next_sidecar.set(Some(OpcodeSidecar::EnumCheckIsCase( EnumCheckIsCaseSidecar { misses: current_misses, shape_id: sc.shape_id, slot_id: sc.slot_id, }, ))); } let is_case = match ev .get_container_enum() .get_idx_of_case_by_symbol(&self.globals, case_sym) { Some(idx) => idx == ev.get_case_index(), None => false, }; frame.stack.push(RuntimeValue::Boolean(is_case.into())); } Opcode::EnumTryExtractPayload => { let ev = pop_or_err!(next, frame, op_idx); if let Some(ev) = ev.as_enum_value() { let p = ev.get_payload(); match p { None => { frame.stack.push(RuntimeValue::Boolean(false.into())); } Some(p) => { frame.stack.push(p.clone()); frame.stack.push(RuntimeValue::Boolean(true.into())); } } } else { frame.stack.push(RuntimeValue::Boolean(false.into())); } } Opcode::TryUnwrapProtocol(mode) => { let result_enum = if let Some(re) = self .globals .get_builtin_type_by_id(BuiltinTypeId::Result) .as_enum() { re.clone() } else { return build_vm_error!(VmErrorReason::UnexpectedVmState, next, frame, op_idx); }; let maybe_enum = if let Some(re) = self .globals .get_builtin_type_by_id(BuiltinTypeId::Maybe) .as_enum() { re.clone() } else { return build_vm_error!(VmErrorReason::UnexpectedVmState, next, frame, op_idx); }; let val = pop_or_err!(next, frame, op_idx); let ev = if let Some(ev) = val.as_enum_value() { if ev.get_container_enum() == &maybe_enum || ev.get_container_enum() == &result_enum { ev.clone() } else { return build_vm_error!(VmErrorReason::UnexpectedType, next, frame, op_idx); } } else { return build_vm_error!(VmErrorReason::UnexpectedType, next, frame, op_idx); }; let case_index = ev.get_case_index(); match case_index { 0 => { // Ok/Some if let Some(case_value) = ev.get_payload() { frame.stack.push(case_value.clone()); if mode == haxby_opcodes::try_unwrap_protocol_mode::FLAG_TO_CALLER { frame.stack.push(RuntimeValue::Boolean(true.into())); } } else { return build_vm_error!( VmErrorReason::EnumWithoutPayload, next, frame, op_idx ); } } 1 => { // Err/None match mode { haxby_opcodes::try_unwrap_protocol_mode::PROPAGATE_ERROR => { frame.stack.push(val.clone()); return Ok(OpcodeRunExit::Return); // implement a Return } haxby_opcodes::try_unwrap_protocol_mode::FLAG_TO_CALLER => { frame.stack.push(val.clone()); frame.stack.push(RuntimeValue::Boolean(false.into())); } haxby_opcodes::try_unwrap_protocol_mode::ASSERT_ERROR => { return build_vm_error!( VmErrorReason::AssertFailed("force unwrap failed".to_string()), next, frame, op_idx ); } _ => { // should never happen return build_vm_error!( VmErrorReason::IncompleteInstruction, next, frame, op_idx ); } } } _ => { // should never happen return build_vm_error!(VmErrorReason::UnexpectedType, next, frame, op_idx); } } } Opcode::Isa => { let t = pop_or_err!(next, frame, op_idx); let val = pop_or_err!(next, frame, op_idx); if let Ok(isa_check) = IsaCheckable::try_from(&t) { frame.stack.push(RuntimeValue::Boolean( isa_check.isa_check(&val, &self.globals).into(), )); } else { return build_vm_error!(VmErrorReason::UnexpectedType, next, frame, op_idx); } } Opcode::Assert(n) => { let assert_msg = if let Some(ct) = this_module.load_indexed_const(n) { if let Some(sv) = ct.as_string() { sv.raw_value() } else { return build_vm_error!(VmErrorReason::UnexpectedType, next, frame, op_idx); } } else { return build_vm_error!(VmErrorReason::UnexpectedType, next, frame, op_idx); }; let x = pop_or_err!(next, frame, op_idx); if let Some(b) = x.as_boolean() { if !*b.raw_value() { return build_vm_error!( VmErrorReason::AssertFailed(assert_msg.to_owned()), next, frame, op_idx ); } } else { return build_vm_error!( VmErrorReason::AssertFailed(assert_msg.to_owned()), next, frame, op_idx ); } } Opcode::Halt => { return build_vm_error!(VmErrorReason::VmHalted, next, frame, op_idx); } Opcode::LoadDylib(n) => { let module = pop_or_err!(next, frame, op_idx); let module = match module.as_module() { Some(m) => m, None => { return build_vm_error!(VmErrorReason::UnexpectedType, next, frame, op_idx); } }; let lib_name = if let Some(ct) = this_module.load_indexed_const(n) { if let Some(sv) = ct.as_string() { sv.raw_value() } else { return build_vm_error!(VmErrorReason::UnexpectedType, next, frame, op_idx); } } else { return build_vm_error!(VmErrorReason::UnexpectedType, next, frame, op_idx); }; // this means that one cannot use the same dylib for multiple modules! #[allow(clippy::map_entry)] if !self.loaded_dylibs.contains_key(lib_name) { unsafe { let dylib_path = get_lib_path(lib_name); let dylib = match libloading::Library::new(&dylib_path) { Ok(d) => d, Err(e) => { return build_vm_error!( VmErrorReason::ImportNotAvailable( dylib_path.into_os_string().into_string().unwrap(), e.to_string() ), next, frame, op_idx ); } }; let symbol: libloading::Symbol< unsafe extern "C" fn( *mut VirtualMachine, *const RuntimeModule, ) -> LoadResult, > = match dylib.get(b"dylib_haxby_inject") { Ok(f) => f, Err(e) => { return build_vm_error!( VmErrorReason::ImportNotAvailable( dylib_path.into_os_string().into_string().unwrap(), e.to_string() ), next, frame, op_idx ); } }; let load_result = symbol(self as *mut VirtualMachine, module as *const RuntimeModule); if load_result.status == LoadStatus::Success { self.loaded_dylibs.insert(lib_name.to_owned(), dylib); } else { let msg = load_result.into_rust_string(); return build_vm_error!( VmErrorReason::ImportNotAvailable(lib_name.to_owned(), msg), next, frame, op_idx ); } } } } Opcode::LiftModule => { let dest = pop_or_err!(next, frame, op_idx); let dest = if let Some(m) = dest.as_module() { m } else { return build_vm_error!(VmErrorReason::UnexpectedType, next, frame, op_idx); }; let src = pop_or_err!(next, frame, op_idx); let src = if let Some(m) = src.as_module() { m } else { return build_vm_error!(VmErrorReason::UnexpectedType, next, frame, op_idx); }; match dest.lift_all_symbols_from_other(src, self) { Ok(_) => {} Err(e) => { return build_vm_error!(e, next, frame, op_idx); } } } Opcode::Import(n) => { let ipath = if let Some(ct) = this_module.load_indexed_const(n) { if let Some(sv) = ct.as_string() { sv.raw_value() } else { return build_vm_error!(VmErrorReason::UnexpectedType, next, frame, op_idx); } } else { return build_vm_error!(VmErrorReason::UnexpectedType, next, frame, op_idx); }; if let Some(mli) = self.imported_modules.get(ipath) { if let Err(e) = Self::create_import_model_from_path( this_module, &mut self.globals, ipath, RuntimeValue::Module(mli.module.clone()), ) { return build_vm_error!(e, next, frame, op_idx); } frame.stack.push(RuntimeValue::Module(mli.module.clone())); } else { let import_path = match Self::resolve_import_path_to_path( ipath, this_module.get_compiled_module().widget_root_path.as_ref(), ) { Ok(ipath) => ipath, Err(err) => { return build_vm_error!(err, next, frame, op_idx); } }; let sb = match SourceBuffer::from_path(&import_path) { Ok(sb) => sb, Err(_) => { return build_vm_error!( VmErrorReason::ImportNotAvailable( ipath.to_owned(), "no such file".to_owned() ), next, frame, op_idx ); } }; if self.import_stack.contains(ipath) { return build_vm_error!( VmErrorReason::CircularImport(ipath.to_owned()), next, frame, op_idx ); } else { self.import_stack.push(ipath.clone()); } let c_module = match compile_from_source(&sb, &Default::default()) { Ok(cm) => cm, Err(ces) => { let err_msg = ces .iter() .map(|x| format!("error: {x}")) .collect::>() .join("\n"); assert!(*ipath == self.import_stack.pop()); return build_vm_error!( VmErrorReason::ImportNotAvailable( ipath.to_owned(), format!("module failed to compile: {err_msg}") ), next, frame, op_idx ); } }; let mli = match self.load_module(&sb.name, c_module)? { RunloopExit::Ok(mli) => mli, RunloopExit::Exception(e) => { assert!(*ipath == self.import_stack.pop()); return Ok(OpcodeRunExit::Exception(e)); } }; if let Err(e) = Self::create_import_model_from_path( this_module, &mut self.globals, ipath, RuntimeValue::Module(mli.module.clone()), ) { return build_vm_error!(e, next, frame, op_idx); } assert!(*ipath == self.import_stack.pop()); frame.stack.push(RuntimeValue::Module(mli.module.clone())); self.imported_modules.insert(ipath.to_owned(), mli); }; } } Ok(OpcodeRunExit::Continue) } fn runloop( &mut self, bc: &[Opcode], sidecar: &SidecarSlice, module: &RuntimeModule, frame: &mut Frame, ) -> ExecutionResult { let mut op_counter = 0; loop { #[cfg(debug_assertions)] if self.options.tracing && self.options.dump_stack { frame.stack.dump(); } let next = match bc.get(op_counter) { Some(op) => *op, None => { return Err(VmErrorReason::UnterminatedBytecode.into()); } }; let next_sidecar = match sidecar.get(op_counter) { Some(sc) => sc, None => { return Err(VmErrorReason::UnterminatedBytecode.into()); } }; #[cfg(debug_assertions)] if self.options.tracing { let poa = aria_parser::ast::prettyprint::printout_accumulator::PrintoutAccumulator::default(); let next = { let ropc = crate::opcodes::prettyprint::RuntimeOpcodePrinter { globals: Some(&self.globals), module: Some(module), }; crate::opcodes::prettyprint::opcode_prettyprint(next, &ropc, poa).value() }; let next_sidecar = { if let Some(sc) = next_sidecar.get() { let poa = aria_parser::ast::prettyprint::printout_accumulator::PrintoutAccumulator::default(); crate::opcodes::sidecar::sidecar_prettyprint(sc, poa).value() } else { "".to_string() } }; let wrote_lt = if let Some(lt) = frame.get_line_entry_at_pos(op_counter as u16) { println!("{op_counter:05}: {next} {next_sidecar} --> {lt}"); true } else { false }; if !wrote_lt { println!("{op_counter:05}: {next} {next_sidecar}"); } } // we save the original counter (the current instruction) for two reasons: // - if an exception occurs, we need to figure out where we came from to build the backtrace // - run_opcode does not advance the counter unless it's jumping, so we need to know if it changed // and if not advance it ourselves let current_op_counter = op_counter; // some errors can be converted into exceptions, so reserve the right to postpone exception handling let mut need_handle_exception: Option = None; match self.run_opcode(next, next_sidecar, &mut op_counter, module, frame) { Ok(OpcodeRunExit::Continue) => {} Ok(OpcodeRunExit::Return) => { return Ok(RunloopExit::Ok(())); } Ok(OpcodeRunExit::Exception(except)) => { need_handle_exception = Some(except); } Err(x) => match VmException::from_vmerror(x, &mut self.globals) { Ok(exception) => { need_handle_exception = Some(exception); } Err(err) => { let err = if let Some(lt) = frame.get_line_entry_at_pos(current_op_counter as u16) { let mut new_err = err.clone(); new_err.backtrace.push(lt); new_err } else { err }; return Err(err); } }, } if op_counter == current_op_counter { op_counter += 1; } if let Some(except) = need_handle_exception { except.fill_in_backtrace(&mut self.globals); match frame.drop_to_first_try(self) { Some(o) => { op_counter = o as usize; frame.stack.push(except.value); } None => { let new_except = if let Some(lt) = frame.get_line_entry_at_pos(current_op_counter as u16) { except.thrown_at(lt) } else { except }; return Ok(RunloopExit::Exception(new_except)); } } } } } } ================================================ FILE: vscode/aria/.vscodeignore ================================================ .env build.sh src/ ================================================ FILE: vscode/aria/LICENSE ================================================ Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright 2024 Enrico Granata Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ================================================ FILE: vscode/aria/README.md ================================================ # Aria This is the VSCode syntax highlighter extension for the Aria language ## Known Issues * No cross-file go to definition support * Only displays parse errors and messages could be clearer **Enjoy!** ================================================ FILE: vscode/aria/build.sh ================================================ #!/bin/sh [ -f ./.env ] && . ./.env EDITOR_CLI="${EDITOR_CLI:-${EDITOR_CMD:-${EDITOR:-${VSCODE_CLI:-code}}}}" cargo build --manifest-path ../../lsp/Cargo.toml && \ vsce package --allow-missing-repository && \ "$EDITOR_CLI" --install-extension ./aria-0.0.1.vsix # sadly, the vscode window will still need to be reloaded after running this ================================================ FILE: vscode/aria/language-configuration.json ================================================ { "comments": { // symbol used for single line comment. Remove this entry if your language does not support line comments "lineComment": "#", }, // symbols used as brackets "brackets": [ ["{", "}"], ["[", "]"], ["(", ")"] ], // symbols that are auto closed when typing "autoClosingPairs": [ ["{", "}"], ["[", "]"], ["(", ")"], ["\"", "\""], ["'", "'"] ], // symbols that can be used to surround a selection "surroundingPairs": [ ["{", "}"], ["[", "]"], ["(", ")"], ["\"", "\""], ["'", "'"] ] } ================================================ FILE: vscode/aria/package.json ================================================ { "name": "aria", "displayName": "Aria", "description": "Aria Language Support", "version": "0.0.1", "engines": { "vscode": "^1.100.0" }, "categories": [ "Programming Languages" ], "main": "./out/extension.js", "contributes": { "languages": [ { "id": "aria", "aliases": [ "Aria", "aria" ], "extensions": [ ".aria" ], "configuration": "./language-configuration.json" } ], "configuration": { "title": "Aria", "properties": { "aria.lsp.serverPath": { "type": "string", "default": "", "description": "Path to Aria LSP executable. Leave empty to use ../target/debug/lsp relative to this extension." } } }, "grammars": [ { "language": "aria", "scopeName": "source.aria", "path": "./syntaxes/aria.tmLanguage.json" } ] }, "dependencies": { "glob": "^11.1.0", "vscode-languageclient": "^9.0.1" }, "devDependencies": { "@types/vscode": "^1.100.0", "@vscode/test-electron": "^2.3.9", "typescript": "^5.9.2", "typescript-eslint": "^8.39.0", "@types/mocha": "^10.0.6", "@types/node": "^22" }, "scripts": { "vscode:prepublish": "npm run compile", "compile": "tsc -b", "watch": "tsc -b -w", "lint": "eslint", "test": "sh ./scripts/e2e.sh" } } ================================================ FILE: vscode/aria/src/extension.ts ================================================ import { workspace, EventEmitter, ExtensionContext, Uri } from "vscode"; import { Disposable, Executable, LanguageClient, LanguageClientOptions, ServerOptions, } from "vscode-languageclient/node"; let client: LanguageClient; export async function activate(context: ExtensionContext) { const configuredPath = workspace.getConfiguration('aria').get('lsp.serverPath')?.trim(); const envPath = process.env.ARIA_LSP_PATH?.trim(); const defaultUri = Uri.joinPath(context.extensionUri, '..', '..', 'target', 'debug', 'lsp'); const command = configuredPath || envPath || defaultUri.fsPath; const run: Executable = { command, options: { env: { ...process.env, RUST_LOG: "debug", }, }, }; const serverOptions: ServerOptions = { run, debug: run, }; const clientOptions: LanguageClientOptions = { documentSelector: [{ scheme: "file", language: "aria" }], synchronize: { fileEvents: workspace.createFileSystemWatcher("**/.clientrc"), } }; client = new LanguageClient("aria-language-server", "aria language server", serverOptions, clientOptions); client.start(); } export function deactivate(): Thenable | undefined { if (!client) { return undefined; } return client.stop(); } export function activateInlayHints(ctx: ExtensionContext) { const maybeUpdater = { hintsProvider: null as Disposable | null, updateHintsEventEmitter: new EventEmitter(), async onConfigChange() { this.dispose(); // TODO: reload the lsp connection if path changed }, dispose() { this.hintsProvider?.dispose(); this.hintsProvider = null; this.updateHintsEventEmitter.dispose(); }, }; workspace.onDidChangeConfiguration(maybeUpdater.onConfigChange, maybeUpdater, ctx.subscriptions); maybeUpdater.onConfigChange().catch(console.error); } ================================================ FILE: vscode/aria/syntaxes/aria.tmLanguage.json ================================================ { "$schema": "https://raw.githubusercontent.com/martinring/tmlanguage/master/tmlanguage.json", "name": "Aria", "patterns": [ { "include": "#keywords" }, { "include": "#strings" }, { "include": "#booleans" }, { "include": "#numbers" }, { "include": "#identifiers" } ], "repository": { "keywords": { "patterns": [ { "name": "comment.line.double-slash.aria", "match": "#.*$" }, { "name": "keyword.control.aria", "match": "\\b(and|assert|break|case|catch|continue|enum|else|elsif|extension|for|from|guard|if|import|in|include|isa|func|match|mixin|operator|return|struct|throw|try|val|while)\\b" }, { "name": "keyword.control.contextual.func.aria", "match": "\\b(instance|type)\\b(?=\\s+func)" }, { "name": "keyword.control.contextual.op.aria", "match": "\\b(reverse)\\b(?=\\s+operator)" }, { "name": "keyword.control.type-val.aria", "match": "\\btype\\s+val\\b" } ] }, "booleans": { "patterns": [ { "name": "constant.language.boolean.aria", "match": "\\b(false|true)\\b" } ] }, "strings": { "patterns": [ { "name": "string.quoted.double.aria", "begin": "\"", "end": "\"", "patterns": [ { "name": "constant.character.escape.aria", "match": "\\\\." } ] }, { "name": "string.quoted.single.aria", "begin": "'", "end": "'", "patterns": [ { "name": "constant.character.escape.aria", "match": "\\\\." } ] } ] }, "numbers": { "patterns": [ { "match": "\\b\\d+\\.\\d+f\\b", "name": "constant.numeric.float.aria" }, { "name": "constant.numeric.decimal.aria", "match": "\\b\\d[\\d_]*\\b" }, { "name": "constant.numeric.hexadecimal.aria", "match": "\\b0x[0-9a-fA-F][0-9a-fA-F_]*\\b" }, { "name": "constant.numeric.binary.aria", "match": "\\b0b[01][01_]*\\b" } ] }, "identifiers": { "patterns": [ { "name": "variable.other.aria", "match": "\\b[_\\p{L}][_\\p{L}\\p{M}\\p{Nd}\\p{Pc}\\p{Nl}]*\\b" } ] } }, "scopeName": "source.aria" } ================================================ FILE: vscode/aria/tsconfig.json ================================================ { "compilerOptions": { "module": "commonjs", "target": "ES2024", "lib": [ "ES2024" ], "outDir": "out", "rootDir": "src", "sourceMap": true }, "include": [ "src" ], "exclude": [ "node_modules", ".vscode-test" ] } ================================================ FILE: vscode/aria/tsconfig.tsbuildinfo ================================================ {"root":["./src/extension.ts"],"version":"5.9.3"}