Repository: eirproject/eir Branch: master Commit: a615a9d41563 Files: 339 Total size: 3.2 MB Directory structure: gitextract_fonefwfl/ ├── .gitignore ├── .gitmodules ├── DOCS.md ├── LICENSE.md ├── README.md ├── ROADMAP.org ├── azure-pipelines.yml ├── ci/ │ ├── azure-clone-patch-otp.yml │ ├── azure-install-dependencies.yml │ ├── azure-install-rust.yml │ └── azure-test.yml ├── deny.toml ├── libeir_diagnostics/ │ ├── Cargo.toml │ └── src/ │ ├── codemap.rs │ ├── filename.rs │ ├── index.rs │ ├── lib.rs │ ├── source.rs │ └── span.rs ├── libeir_frontend/ │ ├── Cargo.toml │ ├── README.md │ └── src/ │ ├── abstr_erlang.rs │ ├── eir.rs │ ├── erlang.rs │ └── lib.rs ├── libeir_intern/ │ ├── Cargo.toml │ └── src/ │ ├── arena.rs │ ├── lib.rs │ └── symbol.rs ├── libeir_interpreter/ │ ├── Cargo.toml │ ├── README.md │ └── src/ │ ├── erl_lib/ │ │ ├── erlang.rs │ │ ├── file.rs │ │ ├── lists.rs │ │ ├── maps.rs │ │ ├── math.rs │ │ ├── mod.rs │ │ └── os.rs │ ├── erl_tests/ │ │ └── mod.rs │ ├── lib.rs │ ├── mailbox.rs │ ├── module.rs │ ├── pattern.rs │ ├── process/ │ │ ├── match.rs │ │ └── mod.rs │ ├── receive.rs │ ├── term.rs │ ├── trace/ │ │ ├── dummy.rs │ │ ├── mod.rs │ │ └── trace.rs │ └── vm.rs ├── libeir_ir/ │ ├── Cargo.toml │ ├── build.rs │ └── src/ │ ├── algo/ │ │ ├── equality.rs │ │ ├── func_tree.rs │ │ ├── live.rs │ │ ├── mangle/ │ │ │ ├── datatypes.rs │ │ │ ├── mod.rs │ │ │ ├── receiver.rs │ │ │ └── tests.rs │ │ ├── mod.rs │ │ ├── op_branches.rs │ │ └── validate.rs │ ├── binary.rs │ ├── constant/ │ │ ├── atomic.rs │ │ ├── float.rs │ │ └── mod.rs │ ├── dialect/ │ │ └── mod.rs │ ├── function/ │ │ ├── builder/ │ │ │ ├── mod.rs │ │ │ ├── op.rs │ │ │ └── primop.rs │ │ ├── format.rs │ │ ├── location.rs │ │ ├── mod.rs │ │ ├── op.rs │ │ ├── pool_container.rs │ │ ├── primop.rs │ │ ├── serialize.rs │ │ └── value.rs │ ├── graph/ │ │ ├── block_graph.rs │ │ ├── control_flow_graph.rs │ │ ├── live_block_graph.rs │ │ └── mod.rs │ ├── ir_construct_macro.rs │ ├── lib.rs │ ├── module.rs │ ├── operation/ │ │ ├── binary_construct.rs │ │ ├── case.rs │ │ ├── mod.rs │ │ └── receive.rs │ ├── pattern/ │ │ ├── fmt.rs │ │ └── mod.rs │ ├── text/ │ │ ├── ast/ │ │ │ ├── mod.rs │ │ │ └── raise.rs │ │ ├── dot_printer.rs │ │ ├── lower/ │ │ │ ├── location.rs │ │ │ └── mod.rs │ │ ├── mod.rs │ │ ├── parse_dyn/ │ │ │ └── mod.rs │ │ ├── parser/ │ │ │ ├── errors.rs │ │ │ ├── grammar.lalrpop │ │ │ ├── lexer.rs │ │ │ └── mod.rs │ │ ├── printer/ │ │ │ ├── constant.rs │ │ │ ├── mod.rs │ │ │ └── operation.rs │ │ └── printer.old.rs │ └── traits/ │ ├── mod.rs │ ├── op_branches.rs │ ├── parser.rs │ └── printer.rs ├── libeir_lowerutils/ │ ├── Cargo.toml │ └── src/ │ ├── lib.rs │ └── tests.rs ├── libeir_passes/ │ ├── Cargo.toml │ └── src/ │ ├── compile_pattern/ │ │ ├── erlang_pattern_provider.rs │ │ ├── lower_cfg.rs │ │ ├── mod.rs │ │ └── tests.rs │ ├── dummy_location.rs │ ├── lib.rs │ ├── naive_inline_closures/ │ │ ├── mod.rs │ │ └── tests.rs │ ├── simplify_cfg/ │ │ ├── analyze/ │ │ │ ├── call.rs │ │ │ ├── if_bool.rs │ │ │ ├── mod.rs │ │ │ └── unpack_value_list.rs │ │ ├── chain_graph/ │ │ │ ├── mod.rs │ │ │ └── synthesis/ │ │ │ ├── compound.rs │ │ │ ├── mod.rs │ │ │ ├── simple.rs │ │ │ ├── single.rs │ │ │ └── terminating_target.rs │ │ ├── mod.rs │ │ ├── rewrite.rs │ │ └── tests.rs │ ├── util.rs │ └── validate.rs ├── libeir_syntax_core/ │ ├── Cargo.toml │ ├── build.rs │ └── src/ │ ├── ast.rs │ ├── lexer.rs │ ├── lib.rs │ ├── lower_hir.rs │ └── parser/ │ ├── grammar.lalrpop │ ├── grammar.rs │ └── mod.rs ├── libeir_syntax_erl/ │ ├── .gitignore │ ├── Cargo.toml │ ├── build.rs │ └── src/ │ ├── abstr/ │ │ ├── lower.rs │ │ └── mod.rs │ ├── evaluator.rs │ ├── lexer/ │ │ ├── errors.rs │ │ ├── lexer.rs │ │ ├── mod.rs │ │ └── token.rs │ ├── lib.rs │ ├── lower/ │ │ ├── errors.rs │ │ ├── exception_handler_stack.rs │ │ ├── expr/ │ │ │ ├── binary.rs │ │ │ ├── binary_expr.rs │ │ │ ├── case.rs │ │ │ ├── catch.rs │ │ │ ├── comprehension.rs │ │ │ ├── literal.rs │ │ │ ├── map.rs │ │ │ ├── mod.rs │ │ │ ├── receive.rs │ │ │ └── record.rs │ │ ├── mod.rs │ │ ├── pattern/ │ │ │ ├── mod.rs │ │ │ └── tree/ │ │ │ ├── from_expr.rs │ │ │ ├── lower.rs │ │ │ ├── merge.rs │ │ │ ├── mod.rs │ │ │ └── promote_values.rs │ │ ├── scope.rs │ │ └── tests.rs │ ├── parser/ │ │ ├── ast/ │ │ │ ├── attributes.rs │ │ │ ├── expr.rs │ │ │ ├── functions.rs │ │ │ ├── mod.rs │ │ │ ├── module.rs │ │ │ └── types.rs │ │ ├── binary.rs │ │ ├── errors.rs │ │ ├── grammar.lalrpop │ │ ├── macros.rs │ │ └── mod.rs │ ├── preprocessor/ │ │ ├── directive.rs │ │ ├── directives.rs │ │ ├── errors.rs │ │ ├── macros.rs │ │ ├── mod.rs │ │ ├── preprocessor.rs │ │ ├── token_reader.rs │ │ ├── token_stream.rs │ │ └── types.rs │ └── util/ │ ├── binary/ │ │ ├── mod.rs │ │ └── static.rs │ ├── encoding.rs │ ├── escape_stm.rs │ ├── mod.rs │ ├── string.rs │ └── string_tokenizer.rs ├── libeir_tests/ │ ├── Cargo.toml │ ├── shadowing.erl │ └── src/ │ ├── control_flow/ │ │ ├── accumulate_list.rs │ │ ├── fib.rs │ │ ├── get_values.rs │ │ ├── mod.rs │ │ ├── nth_root.rs │ │ └── shadowing.rs │ ├── ct_runner.rs │ ├── errors.rs │ ├── lib.rs │ ├── list_comprehensions.rs │ ├── otp/ │ │ └── mod.rs │ ├── patterns.rs │ └── records.rs ├── otp_build/ │ ├── bs_match_SUITE.erl │ ├── bs_match_SUITE.erl.patch │ ├── bs_match_SUITE_patched.erl │ ├── otp_build_core.patch │ ├── patch_build_otp.sh │ └── patch_tests.sh ├── test_data/ │ ├── Elixir.Enum.erl │ ├── README.md │ ├── application_controller.core │ ├── basic_module.core │ ├── basic_module.erl │ ├── basic_regress/ │ │ ├── enum_aggregate.core │ │ ├── function_capture_1.core │ │ ├── line_annotation_fail_1.core │ │ └── type_construction_fail_1.core │ ├── compile.core │ ├── compile_messages_per_file.core │ ├── compile_stripped.core │ ├── compile_stripped_small.core │ ├── factorial.core │ ├── factorial.erl │ ├── function_capture.core │ ├── function_capture.erl │ ├── gen_server.core │ ├── language_test.core │ ├── language_test.erl │ ├── long_strings.core │ ├── long_strings.core.bak │ ├── map_test.core │ ├── map_test.erl │ ├── maps.abstr │ ├── maps.erl │ ├── match.core │ ├── match.erl │ ├── match_SUITE.abstr │ ├── match_SUITE.erl │ ├── test.core │ ├── test.erl │ ├── testing.core │ └── testing.erl ├── tools/ │ ├── Cargo.toml │ └── src/ │ └── compile.rs └── util/ ├── any_map/ │ ├── Cargo.toml │ └── src/ │ ├── any_any_map.rs │ ├── any_map.rs │ └── lib.rs ├── libeir_etf/ │ ├── Cargo.toml │ ├── src/ │ │ ├── constants.rs │ │ ├── decoder.rs │ │ ├── encoder.rs │ │ ├── lib.rs │ │ ├── reader.rs │ │ ├── term.rs │ │ ├── test/ │ │ │ └── mod.rs │ │ └── writer.rs │ └── test_data/ │ ├── basic_list.etf │ ├── generate.exs │ ├── int_tuple.etf │ ├── test_1.etf │ └── test_2.etf ├── libeir_util_binary/ │ ├── Cargo.toml │ └── src/ │ ├── bitvec.rs │ ├── extend.rs │ ├── impls.rs │ ├── integer.rs │ ├── lib.rs │ └── slice.rs ├── libeir_util_datastructures/ │ ├── Cargo.toml │ └── src/ │ ├── aux_hash_map.rs │ ├── aux_traits/ │ │ ├── bforest_impl.rs │ │ ├── entity_impl.rs │ │ ├── mod.rs │ │ └── std_impl/ │ │ └── mod.rs │ ├── dedup_aux_primary_map.rs │ ├── forest.rs │ ├── hashmap_stack.rs │ ├── lib.rs │ └── pooled_entity_set.rs ├── libeir_util_dot_graph/ │ ├── Cargo.toml │ └── src/ │ ├── lib.rs │ └── tablegen.rs ├── libeir_util_number/ │ ├── Cargo.toml │ └── src/ │ ├── bigint_to_float.rs │ ├── binary.rs │ ├── float.rs │ ├── integer.rs │ ├── lib.rs │ └── number.rs ├── libeir_util_parse/ │ ├── Cargo.toml │ └── src/ │ ├── errors.rs │ ├── lib.rs │ ├── parser.rs │ ├── result.rs │ ├── scanner.rs │ ├── source.rs │ └── util.rs ├── libeir_util_parse_listing/ │ ├── Cargo.toml │ ├── build.rs │ └── src/ │ ├── ast.rs │ ├── grammar.lalrpop │ ├── lib.rs │ ├── parser.rs │ └── token.rs ├── libeir_util_pattern_compiler/ │ ├── Cargo.toml │ ├── README.md │ └── src/ │ ├── cfg/ │ │ ├── generate_dot.rs │ │ └── mod.rs │ ├── lib.rs │ ├── matrix.rs │ ├── pattern.rs │ └── simple_pattern/ │ ├── mod.rs │ └── test.rs ├── libeir_util_prof/ │ ├── Cargo.toml │ └── src/ │ └── lib.rs ├── meta_table/ │ ├── Cargo.toml │ └── src/ │ └── lib.rs └── scoped_cell/ ├── Cargo.toml └── src/ └── lib.rs ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitignore ================================================ target/ **/*.rs.bk Cargo.lock *.dot *.dot.pdf *.core *.eir *.png !test_data/**/*.core test_data/**/.*.core *.swp compiler/src/parser/grammar.rs trace.html trace.json *.ll *.bc *.so *.ll.old *.o *.s !gen_nif/src/target/ ================================================ FILE: .gitmodules ================================================ [submodule "otp"] path = otp url = https://github.com/erlang/otp.git ================================================ FILE: DOCS.md ================================================ # Type system There are two parallel type systems: * Pessimistic types * Optimistic types Pessimistic types are what we can statically infer from the code itself. Using only this type system, the code would behave like it would in normal Erlang. As an example, we know that `erlang:+/2` returns a number, so this type check can be elided in code that follows it. Pessimistic types should only infer details from with the function itself. Optimistic types are informed by annotations from the user. If the user annotates that a function `foo/1` should only receive a number as an input, we can optimize the code for this case. The compiler is allowed to optionally insert type assertions for supplied optimistic type hints. ## Type tree It should be noted that everything here is under construction and subject to change. This especially applies to the pseudo-types (`mapclass`, `tupclass` and `contlist`). * `any` * `atom` * `boolean` * `number` * `integer` * `smallint` * `bigint` * `float` * `pid` * `reference` * `map` * `list` * `tuple` * `n-tuple` * `nil` * `mapclass` * `contlist` ### Pseudo-types #### The `mapclass` pseudo-type `mapclass` is a special "pseudo-type". When the compiler infers or gets informed that a map will always adhere to a given type signature at a location, it can promote the given `map` into its pseudo-type. When these types leave the locations where their type can be inferred, they get transparently demoted into their normal types. A normal use-case for `mapclass` would be Elixirs structs. From the host language, these look completely identical to their non-pseudo counterparts. #### The `contlist` pseudo-type `contlist` stands for continuous list. When a `list` gets promoted into this pseudo-type, it will not be stored as a linked list, but rather as a (possibly chunked and linked?) array. Not very well thought out yet, but it is to be expected that the cache locality of storing a list in a continuous block of memory could improve performance in some cases. I have a sneaking unconfirmed suspicion that this could be especially useful in places where a list is constructed recursively and then reversed. ### Type modifiers # Intrinsics The module that contains all these intrinsics functions is `eir_intrinsics`. All of these functions are directly handled by the compiler. Defining a `eir_intrinsics` module could be done for compatibility with the BEAM, but it will always be overridden in this project. It should be noted that no intrinsics are dynamically callable. ## Types * `type_tag(T)` Returns the type tag of the type in the form of an atom. * `atom` * `float` * `smallint` * `bigint` * `annotate_type(Variable, EirTypeSpec)` Inserts an annotation that the given variable should be the given type spec. The compiler might insert assertions if it decides so, but can also choose not to. When annotating types, this should be used most often. The second argument is required to be known at compile-time. * `assert_type(Variable, EirTypeSpec)` Same as above, but the compiler is required to insert assertions. This can potentially result in a performance impact over `annotate_type`. The second argument is required to be known at compile-time. ## Message passing ### Receiving TODO: Finish updating `receive_start` the start of a receive structure, must jump to a block containing a single `receive_wait`. No further `receive_start` or function termination is allowed before control flow is passed through a `receive_finish` or exited the structure through the timeout edge. ``` [eir_intrinsics:receive_start()] | v ----------[eir_intrinsics:receive_wait()]<-------- v | | [Timeout ] | | [Other control flow] | | v | -----[Match logic ]--------------------- | | | ----->[eir_intrinsics:receive_finish()] | [Other ] v [eir_intrinsics:receive_finish()] [Other ] ``` ``` #start: ... %receive_context = ReceiveStart(%timeout, #receive_loop) #receive_loop: ReceiveWait(%receive_context, #match_body, #timeout_body) #match_body: %message = ReceiveGetMessage() // Jump to #receive_loop if message does not match // Jump to #message_1_match if a message matches // Jump to #message_2_match if another message matches #timeout_body: ... #message_1_match: ReceiveFinish(%receive_context) ... #message_2_match: ReceiveFinish(%receive_context) ... ``` ReceiveStart, Central node of match loop of a receive structure. Must be the only op in its basic block. Jumps to edge 0 when a message has been received. Jumps to edge 1 when a timeout has occured. ReceiveWait, This must be the first instruction on edge 0 from ReceiveWait. Peeks at the message in the mailbox, not removed unless ReceiveFinish is passed through on this iteration ReceiveGetMessage, When jumped to from edge 0 from a ReceiveWait, control flow either needs to (eventually) return to ReceiveWait or needs to pass through ReceiveFinish on its way out. Returning while inside a receive structure is a hard error! This will actually consume the message from the mailbox. ReceiveFinish, ================================================ FILE: LICENSE.md ================================================ 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 2018 Paul Schoenfelder 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 ================================================ # Eir Project Erlang compiler and IR implemented in Rust ## Details Current features: * Unified Thorin based IR representation named Eir * Erlang frontend * Core frontend * Pattern match compilation passes * Basic optimization and cleanup passes * Naive interpreter used for testing The project is split into several crates: * `libeir_ir` - Contains the core Eir IR data structures, validation, printing * `libeir_syntax_erl` - Frontend for Erlang, lowers to Eir. * `libeir_syntax_core` - Frontend for Core Erlang, lowers to Eir. * `libeir_passes` - Compiler passes operating on Eir. * `libeir_lowerutils` - Utilities for lowering Eir to SSA form. * `libeir_interpreter` - Naive interpreter for Eir. Used to run OTP test suites. * `libeir_intern` - Symbol interning. Used by most other crates. * `libeir_diagnostics` - Source span handling and diagnostics printing. * `libeir_util` - Kitchen sink of utilities used by other crates. * `pattern-compiler` - A generic pattern matching tree compiler. * `tools` - CLI tools used to work with the IR. ================================================ FILE: ROADMAP.org ================================================ * Roadmap ** 1. Cleanup *** Includes fixing all tech dept created leading up to the conference *** Setting up infrastructure for writing integration tests using the interpreter **** Ease work for Luke, Paul, improve confidence in high levels of compiler and the runtime ** 2. Basic passes *** Unified cleanup pass **** Includes removal of call chains, tail call promotion, closure inlining in one pass. *** Simple branch elimination pass **** Removes superfluous branches ** 3. Lower utilities *** Introduce a barebones more traditional IR (LIR) **** No passes operate on this (at least for now), eases lowering to other IRs ** 4. Documentation *** Write gitbook-like documentation for EIR **** Critical for enabling others to work with the project efficiently ** 5. BEAM assembly target *** Target BEAM assembly from LIR **** Enables more easy testing of compiler **** Comparing our optimization passes with the BEAM compiler ***** Proves our approach of using a Thorin-like IR is beneficial ** 6. Typing infrastructure *** This is critical for doing good native codegen ================================================ FILE: azure-pipelines.yml ================================================ variables: nightly: nightly-2020-08-15 RUSTFLAGS: jobs: # Test crates - template: ci/azure-test.yml parameters: name: test_eir displayName: Test Eir rust: $(nightly) cross: true crates: util/libeir_util_binary: [] util/libeir_util_datastructures: [] util/libeir_util_number: [] util/libeir_util_parse: [] util/libeir_util_parse_listing: [] util/libeir_util_pattern_compiler: [] libeir_intern: [] libeir_diagnostics: [] libeir_interpreter: [] libeir_ir: [] libeir_passes: [] libeir_lowerutils: [] libeir_syntax_erl: [] libeir_tests: [] ================================================ FILE: ci/azure-clone-patch-otp.yml ================================================ steps: - script: | set -e cd $(Build.SourcesDirectory) git submodule update --init --recursive cd otp_build bash patch_tests.sh displayName: Clone and patch OTP ================================================ FILE: ci/azure-install-dependencies.yml ================================================ steps: # Windows only: Install m4 #- script: | # choco install msys2 # refreshenv # pacman -S --noconfirm m4 # displayName: Install dependencies (windows) # condition: eq(variables['Agent.OS'], 'Windows_NT') ================================================ FILE: ci/azure-install-rust.yml ================================================ steps: # Linux and macOS. - script: | set -e curl https://sh.rustup.rs -sSf | sh -s -- -y --default-toolchain none export PATH=$PATH:$HOME/.cargo/bin rustup toolchain install $RUSTUP_TOOLCHAIN rustup default $RUSTUP_TOOLCHAIN echo "##vso[task.setvariable variable=PATH;]$PATH:$HOME/.cargo/bin" env: RUSTUP_TOOLCHAIN: ${{parameters.rust_version}} displayName: "Install rust (*nix)" condition: not(eq(variables['Agent.OS'], 'Windows_NT')) # Windows. - script: | curl -sSf -o rustup-init.exe https://win.rustup.rs rustup-init.exe -y --default-toolchain none set PATH=%PATH%;%USERPROFILE%\.cargo\bin rustup toolchain install %RUSTUP_TOOLCHAIN% rustup default %RUSTUP_TOOLCHAIN% echo "##vso[task.setvariable variable=PATH;]%PATH%;%USERPROFILE%\.cargo\bin" env: RUSTUP_TOOLCHAIN: ${{parameters.rust_version}}-gnu displayName: "Install rust (windows)" condition: eq(variables['Agent.OS'], 'Windows_NT') # All platforms. # Add components - ${{ each component in parameters.components }}: - script: rustup component add ${{ component }} displayName: "Add rust component: ${{ component }}" # Print versions - script: | rustup toolchain list rustc -Vv cargo -V displayName: Query rust and cargo versions ================================================ FILE: ci/azure-test.yml ================================================ jobs: - job: ${{ parameters.name }} displayName: ${{ parameters.displayName }} strategy: matrix: Linux: vmImage: ubuntu-16.04 ${{ if parameters.cross }}: MacOs: vmImage: macOS-10.13 Windows: vmImage: vs2017-win2016 pool: vmImage: $(vmImage) steps: - template: azure-install-rust.yml parameters: rust_version: ${{ parameters.rust }} # - template: azure-install-dependencies.yml - template: azure-clone-patch-otp.yml - script: cargo build --tests env: CI: 'True' displayName: cargo build --tests - ${{ each crate in parameters.crates }}: - script: cargo test env: CI: 'True' displayName: ${{ crate.key }} - cargo test workingDirectory: $(Build.SourcesDirectory)/${{ crate.key }} ================================================ FILE: deny.toml ================================================ [licenses] # This section is considered when running `cargo deny check license` # More documentation for the licenses section can be found here: # https://github.com/EmbarkStudios/cargo-deny#the-licenses-section # Uncomment the following line to change the lint level for unlicensed crates # [possible values: "deny", "allow" or "warn"]. #unlicensed = "deny" # Uncomment the following line to explictly allow certain licenses # See https://spdx.org/licenses/ for list of possible licenses # [possible values: any SPDX 3.7 short identifier (+ optional exception)]. allow = ["MIT", "Apache-2.0", "Apache-2.0 WITH LLVM-exception", "ISC", "BSD-3-Clause", "BSD-2-Clause", "CC0-1.0"] # Uncomment the following line to explictly disallow certain licenses # See https://spdx.org/licenses/ for list of possible licenses # [possible values: any SPDX 3.7 short identifier (+ optional exception)]. #deny = [] # Uncomment the following line to change the lint level for licenses considered copyleft # [possible values: "deny", "allow" or "warn"]. #copyleft = "warn" # Uncomment the following line to approve or deny OSI-approved or FSF Free/Libre licenses # [possible values: "both", "either", "osi-only", "fsf-only" or "neither"]. #allow-osi-fsf-free = "neither" # Uncomment the following line to change the confidence threshold. The higher the value, # the more closely the license text must be to the canonical license text of a valid # SPDX license file. # [possible values: any between 0.0 and 1.0]. #confidence-threshold = 0.8 [bans] # This section is considered when running `cargo deny check ban`. # More documentation about the 'bans' section can be found here: # https://github.com/EmbarkStudios/cargo-deny#crate-bans-cargo-deny-check-ban # Uncomment the following line to change what happens when multiple versions of the same # crate are encountered # [possible values: "deny", "warn" or "allow"]. #multiple-versions = "warn" # Uncomment the following line to change the highlighting variant used to multiple versions # of the same crate when creating a dotgraph of your crates dependencies # [possible values: "lowest-version", "simplest-path" or "all"]. #highlight = "all" # Uncomment the following line to allow specific crates. #allow = [] # Uncomment the following line to deny specific crates. #deny = [] # Uncomment the following line to skip specific crates. #skip = [] # Uncomment the following line to skip specific crates (including different versions of the # same crate down the dependency tree). By default, the depth is infinite, but you can also # specify `depth = ` to limit it. #skip-tree = [] ================================================ FILE: libeir_diagnostics/Cargo.toml ================================================ [package] name = "libeir_diagnostics" version = "0.1.0" authors = ["Paul Schoenfelder ", "Luke Imhoff "] edition = "2018" license = "MIT OR Apache-2.0" [dependencies] anyhow = "1.0" thiserror = "1.0" itertools = "0.8" unicode-width = "0.1" codespan = "0.9" codespan-reporting = "0.9" dashmap = "3.11" [dev-dependencies] pretty_assertions = "0.5" ================================================ FILE: libeir_diagnostics/src/codemap.rs ================================================ use std::ops::Range; use std::path::PathBuf; use std::sync::atomic::{AtomicU32, Ordering}; use std::sync::Arc; use dashmap::DashMap; use super::*; #[derive(Debug)] pub struct CodeMap { files: DashMap>, names: DashMap, seen: DashMap, next_file_id: AtomicU32, } impl CodeMap { /// Creates an empty `CodeMap`. pub fn new() -> Self { Self { files: DashMap::new(), names: DashMap::new(), seen: DashMap::new(), next_file_id: AtomicU32::new(1), } } /// Add a file to the map, returning the handle that can be used to /// refer to it again. pub fn add(&self, name: impl Into, source: String) -> SourceId { // De-duplicate real files on add; it _may_ be possible for concurrent // adds to add the same file more than once, since we're working across // two maps; but since DashMap uses read/write locks internally to lock // buckets, the sequence of locks required here should prevent that from // happening // // We don't de-duplicate virtual files, because the same name could be used // for different content, and its unlikely that we'd be adding the same content // over and over again with the same virtual file name let name = name.into(); if let FileName::Real(ref path) = name { let seen_ref = self .seen .entry(path.clone()) .or_insert_with(|| self.insert_file(name, source, None)); *seen_ref.value() } else { self.insert_file(name, source, None) } } /// Add a file to the map with the given source span as a parent. /// This will not deduplicate the file in the map. pub fn add_child( &self, name: impl Into, source: String, parent: SourceSpan, ) -> SourceId { self.insert_file(name.into(), source, Some(parent)) } fn insert_file(&self, name: FileName, source: String, parent: Option) -> SourceId { let file_id = self.next_file_id(); let filename = name.clone(); self.files.insert( file_id, Arc::new(SourceFile::new(file_id, name.into(), source, parent)), ); self.names.insert(filename, file_id); file_id } /// Get the file corresponding to the given id. pub fn get(&self, file_id: SourceId) -> Option> { if file_id == SourceId::UNKNOWN { None } else { self.files.get(&file_id).map(|r| r.value().clone()) } } pub fn parent(&self, file_id: SourceId) -> Option { self.get(file_id).and_then(|f| f.parent()) } /// Get the file id corresponding to the given FileName pub fn get_file_id(&self, filename: &FileName) -> Option { self.names.get(filename).map(|id| *id) } /// Get the file corresponding to the given FileName pub fn get_by_name(&self, filename: &FileName) -> Option> { self.get_file_id(filename).and_then(|id| self.get(id)) } pub fn name(&self, file_id: SourceId) -> Option { self.get(file_id).map(|f| f.name().clone()) } pub fn iter<'a>(&'a self) -> impl Iterator> + 'a { self.files.iter().map(|r| r.value().clone()) } pub fn line_span( &self, file_id: SourceId, line_index: impl Into, ) -> Option> { let f = self.get(file_id)?; Some(f.line_span(line_index.into())) } pub fn line_index( &self, file_id: SourceId, byte_index: impl Into, ) -> Option { let f = self.get(file_id)?; Some(f.line_index(byte_index.into())) } pub fn location( &self, file_id: SourceId, byte_index: impl Into, ) -> Option> { let f = self.get(file_id)?; Some(f.location(byte_index.into())) } pub fn source_span(&self, file_id: SourceId) -> Option { let f = self.get(file_id)?; Some(f.source_span()) } pub fn source_slice<'a>( &'a self, file_id: SourceId, span: impl Into, ) -> Option> { let f = self.get(file_id)?; match f.source_slice(span.into()) { Err(err) => Some(Err(err)), Ok(slice) => unsafe { Some(Ok(std::mem::transmute::<&str, &'a str>(slice))) }, } } #[inline(always)] fn next_file_id(&self) -> SourceId { let id = self.next_file_id.fetch_add(1, Ordering::Relaxed); SourceId::new(id) } } impl Default for CodeMap { fn default() -> Self { Self::new() } } impl<'a> Files<'a> for CodeMap { type FileId = SourceId; type Name = String; type Source = &'a str; fn name(&self, file_id: Self::FileId) -> Option { Some(format!("{}", self.get(file_id)?.name())) } fn source(&self, file_id: Self::FileId) -> Option<&'a str> { use std::mem; let f = self.get(file_id)?; Some(unsafe { mem::transmute::<&str, &'a str>(f.source()) }) } fn line_index(&self, file_id: Self::FileId, byte_index: usize) -> Option { Some(self.line_index(file_id, byte_index as u32)?.to_usize()) } fn line_range(&self, file_id: Self::FileId, line_index: usize) -> Option> { let span = self.line_span(file_id, line_index as u32)?.ok()?; Some(span.start().to_usize()..span.end().to_usize()) } } ================================================ FILE: libeir_diagnostics/src/filename.rs ================================================ //! Various source mapping utilities use std::borrow::Cow; use std::fmt; use std::path::{Path, PathBuf}; #[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)] pub enum FileName { /// A real file on disk Real(PathBuf), /// A synthetic file, eg. from the REPL Virtual(Cow<'static, str>), } impl From for FileName { fn from(name: PathBuf) -> FileName { FileName::real(name) } } impl From for PathBuf { fn from(name: FileName) -> PathBuf { match name { FileName::Real(path) => path, FileName::Virtual(Cow::Owned(owned)) => PathBuf::from(owned), FileName::Virtual(Cow::Borrowed(borrowed)) => PathBuf::from(borrowed), } } } impl<'a> From<&'a FileName> for &'a Path { fn from(name: &'a FileName) -> &'a Path { match *name { FileName::Real(ref path) => path, FileName::Virtual(ref cow) => Path::new(cow.as_ref()), } } } impl<'a> From<&'a Path> for FileName { fn from(name: &Path) -> FileName { FileName::real(name) } } impl From for FileName { fn from(name: String) -> FileName { FileName::virtual_(name) } } impl From<&'static str> for FileName { fn from(name: &'static str) -> FileName { FileName::virtual_(name) } } impl AsRef for FileName { fn as_ref(&self) -> &Path { match *self { FileName::Real(ref path) => path.as_ref(), FileName::Virtual(ref cow) => Path::new(cow.as_ref()), } } } impl PartialEq for FileName { fn eq(&self, other: &Path) -> bool { self.as_ref() == other } } impl PartialEq for FileName { fn eq(&self, other: &PathBuf) -> bool { self.as_ref() == other.as_path() } } impl FileName { pub fn real>(name: T) -> FileName { FileName::Real(name.into()) } pub fn virtual_>>(name: T) -> FileName { FileName::Virtual(name.into()) } pub fn to_string(&self) -> String { match *self { FileName::Real(ref path) => match path.to_str() { None => path.to_string_lossy().into_owned(), Some(s) => s.to_owned(), }, FileName::Virtual(ref s) => s.clone().into_owned(), } } } impl fmt::Display for FileName { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { match *self { FileName::Real(ref path) => write!(fmt, "{}", path.display()), FileName::Virtual(ref name) => write!(fmt, "<{}>", name), } } } ================================================ FILE: libeir_diagnostics/src/index.rs ================================================ use std::num::NonZeroUsize; use std::ops::{Add, AddAssign, Sub, SubAssign}; use codespan::{ByteIndex, ByteOffset, RawIndex, RawOffset}; use super::SourceId; #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct SourceIndex(NonZeroUsize); impl SourceIndex { const INDEX_MASK: usize = u32::max_value() as usize; const UNKNOWN_SRC_ID: usize = (SourceId::UNKNOWN_SOURCE_ID as usize) << 32; pub const UNKNOWN: Self = Self(unsafe { NonZeroUsize::new_unchecked(Self::UNKNOWN_SRC_ID) }); #[inline] pub fn new(source: SourceId, index: ByteIndex) -> Self { let source = (source.get() as usize) << 32; Self(NonZeroUsize::new(source | index.0 as usize).unwrap()) } #[inline] pub fn source_id(&self) -> SourceId { let source_id_part = (self.0.get() >> 32) as u32; if source_id_part == SourceId::UNKNOWN_SOURCE_ID { SourceId::UNKNOWN } else { SourceId::new(source_id_part) } } #[inline] pub fn index(&self) -> ByteIndex { ByteIndex((self.0.get() & Self::INDEX_MASK) as u32) } pub fn to_usize(&self) -> usize { self.0.get() } } impl Default for SourceIndex { fn default() -> Self { Self::UNKNOWN } } impl Add for SourceIndex { type Output = SourceIndex; #[inline] fn add(self, rhs: usize) -> Self { if self == Self::UNKNOWN { return Self::UNKNOWN; } let source = self.source_id(); let index = self.index(); let new_index = index.0 as RawOffset + rhs as RawOffset; Self::new(source, ByteIndex(new_index as RawIndex)) } } impl Add for SourceIndex { type Output = SourceIndex; #[inline] fn add(self, rhs: ByteOffset) -> Self { if self == Self::UNKNOWN { return Self::UNKNOWN; } let source = self.source_id(); let index = self.index(); let new_index = ByteIndex(index.0) + rhs; Self::new(source, new_index) } } impl AddAssign for SourceIndex { #[inline] fn add_assign(&mut self, rhs: usize) { *self = *self + rhs; } } impl AddAssign for SourceIndex { #[inline] fn add_assign(&mut self, rhs: ByteOffset) { *self = *self + rhs; } } impl Sub for SourceIndex { type Output = SourceIndex; #[inline] fn sub(self, rhs: usize) -> Self { if self == Self::UNKNOWN { return Self::UNKNOWN; } let source = self.source_id(); let index = self.index(); let new_index = index.0 as RawOffset - rhs as RawOffset; Self::new(source, ByteIndex(new_index as RawIndex)) } } impl SubAssign for SourceIndex { #[inline] fn sub_assign(&mut self, rhs: usize) { *self = *self - rhs; } } ================================================ FILE: libeir_diagnostics/src/lib.rs ================================================ #![feature(crate_visibility_modifier)] mod codemap; mod filename; mod index; mod source; mod span; pub use codespan::{ByteIndex, ByteOffset}; pub use codespan::{ColumnIndex, ColumnNumber, ColumnOffset}; pub use codespan::{Index, Offset}; pub use codespan::{LineIndex, LineNumber, LineOffset}; pub use codespan::{LineIndexOutOfBoundsError, LocationError, SpanOutOfBoundsError}; pub use codespan::{Location, Span}; pub use codespan::{RawIndex, RawOffset}; pub use codespan_reporting::diagnostic::{LabelStyle, Severity}; pub use codespan_reporting::files::Files; pub use codespan_reporting::term; pub use self::codemap::CodeMap; pub use self::filename::FileName; pub use self::index::SourceIndex; pub use self::source::{SourceFile, SourceId}; pub use self::span::SourceSpan; pub type Diagnostic = codespan_reporting::diagnostic::Diagnostic; pub type Label = codespan_reporting::diagnostic::Label; pub trait ToDiagnostic { fn to_diagnostic(&self) -> Diagnostic; } ================================================ FILE: libeir_diagnostics/src/source.rs ================================================ use std::convert::Into; use std::num::NonZeroU32; use std::ops::Range; use super::*; /// A handle that points to a file in the database. #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct SourceId(crate NonZeroU32); impl SourceId { crate const UNKNOWN_SOURCE_ID: u32 = u32::max_value(); pub const UNKNOWN: Self = Self(unsafe { NonZeroU32::new_unchecked(Self::UNKNOWN_SOURCE_ID) }); crate fn new(index: u32) -> Self { assert!(index > 0); assert!(index < Self::UNKNOWN_SOURCE_ID); Self(NonZeroU32::new(index).unwrap()) } #[inline] crate fn get(self) -> u32 { self.0.get() } } /// The representation of a source file in the database. #[derive(Debug, Clone)] pub struct SourceFile { id: SourceId, name: FileName, source: String, line_starts: Vec, parent: Option, } impl SourceFile { crate fn new(id: SourceId, name: FileName, source: String, parent: Option) -> Self { let line_starts = codespan_reporting::files::line_starts(source.as_str()) .map(|i| ByteIndex::from(i as u32)) .collect(); Self { id, name, source, line_starts, parent, } } pub fn name(&self) -> &FileName { &self.name } pub fn id(&self) -> SourceId { self.id } pub fn parent(&self) -> Option { self.parent } pub fn line_start( &self, line_index: LineIndex, ) -> Result { use std::cmp::Ordering; match line_index.cmp(&self.last_line_index()) { Ordering::Less => Ok(self.line_starts[line_index.to_usize()]), Ordering::Equal => Ok(self.source_span().end_index()), Ordering::Greater => Err(LineIndexOutOfBoundsError { given: line_index, max: self.last_line_index(), }), } } pub fn last_line_index(&self) -> LineIndex { LineIndex::from(self.line_starts.len() as RawIndex) } pub fn line_span(&self, line_index: LineIndex) -> Result { let line_start = self.line_start(line_index)?; let next_line_start = self.line_start(line_index + LineOffset::from(1))?; Ok(Span::new(line_start, next_line_start)) } pub fn line_index(&self, byte_index: ByteIndex) -> LineIndex { match self.line_starts.binary_search(&byte_index) { // Found the start of a line Ok(line) => LineIndex::from(line as u32), Err(next_line) => LineIndex::from(next_line as u32 - 1), } } pub fn location(&self, byte_index: ByteIndex) -> Result { let line_index = self.line_index(byte_index); let line_start_index = self.line_start(line_index) .map_err(|_| LocationError::OutOfBounds { given: byte_index, span: self.source_span().as_span(), })?; let line_src = self .source .as_str() .get(line_start_index.to_usize()..byte_index.to_usize()) .ok_or_else(|| { let given = byte_index; if given >= self.source_span().end_index() { let span = self.source_span(); LocationError::OutOfBounds { given, span: span.as_span(), } } else { LocationError::InvalidCharBoundary { given } } })?; Ok(Location { line: line_index, column: ColumnIndex::from(line_src.chars().count() as u32), }) } #[inline(always)] pub fn source(&self) -> &str { self.source.as_str() } pub fn source_span(&self) -> SourceSpan { SourceSpan { source_id: self.id, start: ByteIndex(0), end: ByteIndex(self.source.len() as u32), } } pub fn source_slice( &self, span: impl Into>, ) -> Result<&str, SpanOutOfBoundsError> { let span = span.into(); let start = span.start; let end = span.end; self.source().get(start..end).ok_or_else(|| { let given = Span::new(start as u32, end as u32); let span = Span::from_str(self.source()); SpanOutOfBoundsError { given, span } }) } } ================================================ FILE: libeir_diagnostics/src/span.rs ================================================ use std::ops::Range; use codespan::{ByteIndex, ByteOffset, Span}; use super::{CodeMap, SourceId, SourceIndex}; #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct SourceSpan { crate source_id: SourceId, crate start: ByteIndex, crate end: ByteIndex, } impl SourceSpan { pub const UNKNOWN: Self = Self { source_id: SourceId::UNKNOWN, start: ByteIndex(0), end: ByteIndex(0), }; #[inline] pub fn new(start: SourceIndex, end: SourceIndex) -> Self { let source_id = start.source_id(); assert_eq!( source_id, end.source_id(), "source spans cannot start and end in different files!" ); let start = start.index(); let end = end.index(); Self { source_id, start, end, } } pub fn new_align( start: SourceIndex, end: SourceIndex, get_codemap: &dyn Fn(&mut dyn FnOnce(&CodeMap)), ) -> SourceSpan { let start_source = start.source_id(); let end_source = end.source_id(); if start_source == end_source { Self::new(start, end) } else { let mut result = None; get_codemap(&mut |codemap: &CodeMap| { let mut idx = start_source; loop { if let Some(parent) = codemap.parent(idx) { if idx == end_source { result = Some(Self::new(parent.start(), end)); return; } idx = parent.source_id(); } else { break; } } let mut idx = end_source; loop { if let Some(parent) = codemap.parent(idx) { if idx == start_source { result = Some(Self::new(start, parent.end())); return; } idx = parent.source_id(); } else { break; } } }); result.expect("source spans cannot be aligned!") } } #[inline(always)] pub fn source_id(&self) -> SourceId { self.source_id } #[inline(always)] pub fn start(&self) -> SourceIndex { SourceIndex::new(self.source_id, self.start) } #[inline(always)] pub fn start_index(&self) -> ByteIndex { self.start } pub fn shrink_front(mut self, offset: ByteOffset) -> Self { self.start += offset; self } #[inline(always)] pub fn end(&self) -> SourceIndex { SourceIndex::new(self.source_id, self.end) } #[inline(always)] pub fn end_index(&self) -> ByteIndex { self.end } pub fn as_span(&self) -> Span { Span::new(self.start, self.end) } } impl From for Range { fn from(span: SourceSpan) -> Range { span.start.into()..span.end.into() } } impl From for Range { fn from(span: SourceSpan) -> Range { let start = SourceIndex::new(span.source_id, span.start); let end = SourceIndex::new(span.source_id, span.end); start..end } } ================================================ FILE: libeir_frontend/Cargo.toml ================================================ [package] name = "libeir_frontend" version = "0.1.0" authors = ["Hans Elias B. Josephsen "] edition = "2018" license = "MIT OR Apache-2.0" [dependencies] libeir_ir = { path = "../libeir_ir" } libeir_syntax_erl = { path = "../libeir_syntax_erl" } libeir_util_parse = { path = "../util/libeir_util_parse" } libeir_diagnostics = { path = "../libeir_diagnostics" } libeir_util_parse_listing = { path = "../util/libeir_util_parse_listing" } [features] default = ["frontend_erlang", "frontend_abstr_erlang", "frontend_eir"] frontend_erlang = [] frontend_abstr_erlang = [] frontend_eir = [] ================================================ FILE: libeir_frontend/README.md ================================================ # libeir_frontend Wrapper crate for all the different frontends in this project. Currently includes: * eir frontend * erlang frontend * abstract erlang frontend ================================================ FILE: libeir_frontend/src/abstr_erlang.rs ================================================ use std::path::Path; use std::sync::Arc; use libeir_diagnostics::*; use libeir_ir::Module; use libeir_syntax_erl::{lower_abstr, lower_module, LowerError}; use libeir_util_parse::{error_tee, Parse, Parser}; use libeir_util_parse_listing::{ast::Root, parser::ParseError}; use super::{Frontend, FrontendErrorReceiver}; pub enum Error { Parse(ParseError), Lower(LowerError), } impl ToDiagnostic for Error { fn to_diagnostic(&self) -> Diagnostic { match self { Error::Parse(err) => err.to_diagnostic(), Error::Lower(err) => err.to_diagnostic(), } } } impl From for Error { fn from(err: ParseError) -> Error { Error::Parse(err) } } impl From for Error { fn from(err: LowerError) -> Error { Error::Lower(err) } } pub struct AbstrErlangFrontend { parser: Parser<()>, } impl AbstrErlangFrontend { pub fn new(codemap: Arc) -> Self { Self { parser: Parser::new((), codemap), } } } impl Frontend for AbstrErlangFrontend { type Error = Error; fn parse_source<'a>( &self, errors: &'a mut FrontendErrorReceiver<'a, Self::Error>, source: Arc, ) -> Result { error_tee(errors, |mut errors| { let root = self .parser .parse::(&mut errors.make_into_adapter(), source)?; let ast = lower_abstr(&root); let eir = lower_module( &mut errors.make_into_adapter(), self.parser.codemap.clone(), &ast, )?; Ok(eir) }) } fn parse_string<'a>( &self, errors: &'a mut FrontendErrorReceiver<'a, Self::Error>, source: &str, ) -> Result { let id = self.parser.codemap.add("nofile", source.to_string()); let file = self.parser.codemap.get(id).unwrap(); self.parse_source(errors, file) } fn parse_file<'a>( &self, errors: &'a mut FrontendErrorReceiver<'a, Self::Error>, path: &Path, ) -> Result { match std::fs::read_to_string(path) { Err(err) => { errors.error(>::root_file_error(err, path.to_owned()).into()); Err(()) } Ok(content) => { let id = self.parser.codemap.add(path, content); let file = self.parser.codemap.get(id).unwrap(); self.parse_source(errors, file) } } } } ================================================ FILE: libeir_frontend/src/eir.rs ================================================ use std::path::Path; use std::sync::Arc; use libeir_diagnostics::*; use libeir_ir::{ text::{ast::Module as ModuleAst, parser::ParserError, LowerError}, Module, }; use libeir_util_parse::{error_tee, Parse, Parser}; use super::{Frontend, FrontendErrorReceiver}; pub enum Error { Parser(ParserError), Lower(LowerError), } impl ToDiagnostic for Error { fn to_diagnostic(&self) -> Diagnostic { match self { Error::Parser(err) => err.to_diagnostic(), Error::Lower(err) => err.to_diagnostic(), } } } impl From for Error { fn from(err: ParserError) -> Self { Error::Parser(err) } } impl From for Error { fn from(err: LowerError) -> Self { Error::Lower(err) } } pub struct EirFrontend { parser: Parser<()>, } impl EirFrontend { pub fn new(codemap: Arc) -> Self { Self { parser: Parser::new((), codemap), } } } impl Frontend for EirFrontend { type Error = Error; fn parse_source<'a>( &self, errors: &'a mut FrontendErrorReceiver<'a, Self::Error>, source: Arc, ) -> Result { error_tee(errors, |mut errors| { let ast = self .parser .parse::(&mut errors.make_into_adapter(), source)?; let eir = ast.lower(&mut errors.make_into_adapter())?; Ok(eir) }) } fn parse_string<'a>( &self, errors: &'a mut FrontendErrorReceiver<'a, Self::Error>, source: &str, ) -> Result { let id = self.parser.codemap.add("nofile", source.to_owned()); let file = self.parser.codemap.get(id).unwrap(); self.parse_source(errors, file) } fn parse_file<'a>( &self, errors: &'a mut FrontendErrorReceiver<'a, Self::Error>, path: &Path, ) -> Result { match std::fs::read_to_string(path) { Err(err) => { errors.error(>::root_file_error(err, path.to_owned()).into()); Err(()) } Ok(content) => { let id = self.parser.codemap.add(path, content); let file = self.parser.codemap.get(id).unwrap(); self.parse_source(errors, file) } } } } ================================================ FILE: libeir_frontend/src/erlang.rs ================================================ use std::path::Path; use std::sync::Arc; use libeir_diagnostics::*; use libeir_ir::Module; use libeir_syntax_erl::{ ast::Module as ModuleAst, lower_module, LowerError, ParseConfig, ParserError, }; use libeir_util_parse::{error_tee, Parse, Parser}; use super::{Frontend, FrontendErrorReceiver}; pub enum Error { Parser(ParserError), Lower(LowerError), } impl ToDiagnostic for Error { fn to_diagnostic(&self) -> Diagnostic { match self { Error::Parser(err) => err.to_diagnostic(), Error::Lower(err) => err.to_diagnostic(), } } } impl Into for ParserError { fn into(self) -> Error { Error::Parser(self) } } impl Into for LowerError { fn into(self) -> Error { Error::Lower(self) } } pub struct ErlangFrontend { parser: Parser, } impl ErlangFrontend { pub fn new(config: ParseConfig, codemap: Arc) -> Self { Self { parser: Parser::new(config, codemap), } } } impl Frontend for ErlangFrontend { type Error = Error; fn parse_source<'a>( &self, errors: &'a mut FrontendErrorReceiver<'a, Self::Error>, source: Arc, ) -> Result { error_tee(errors, |mut errors| { let ast = self .parser .parse::(&mut errors.make_into_adapter(), source)?; let eir = lower_module( &mut errors.make_into_adapter(), self.parser.codemap.clone(), &ast, )?; Ok(eir) }) } fn parse_string<'a>( &self, errors: &'a mut FrontendErrorReceiver<'a, Self::Error>, source: &str, ) -> Result { let id = self.parser.codemap.add("nofile", source.to_owned()); let file = self.parser.codemap.get(id).unwrap(); self.parse_source(errors, file) } fn parse_file<'a>( &self, errors: &'a mut FrontendErrorReceiver<'a, Self::Error>, path: &Path, ) -> Result { match std::fs::read_to_string(path) { Err(err) => { errors.error(>::root_file_error(err, path.to_owned()).into()); Err(()) } Ok(content) => { let id = self.parser.codemap.add(path, content); let file = self.parser.codemap.get(id).unwrap(); self.parse_source(errors, file) } } } } ================================================ FILE: libeir_frontend/src/lib.rs ================================================ #[cfg(feature = "frontend_abstr_erlang")] pub mod abstr_erlang; #[cfg(feature = "frontend_eir")] pub mod eir; #[cfg(feature = "frontend_erlang")] pub mod erlang; use std::path::Path; use std::sync::Arc; use libeir_diagnostics::{Diagnostic, SourceFile, ToDiagnostic}; use libeir_ir::Module; use libeir_util_parse::ErrorReceiver; pub type FrontendErrorReceiver<'a, E> = dyn ErrorReceiver + 'a; pub trait DynFrontend { fn parse_source_dyn<'a>( &self, source: Arc, ) -> (Result, Vec); fn parse_string_dyn<'a>(&self, source: &str) -> (Result, Vec); fn parse_file_dyn<'a>(&self, source: &Path) -> (Result, Vec); } pub trait Frontend { type Error; fn parse_source<'a>( &self, errors: &'a mut FrontendErrorReceiver<'a, Self::Error>, source: Arc, ) -> Result; fn parse_string<'a>( &self, errors: &'a mut FrontendErrorReceiver<'a, Self::Error>, source: &str, ) -> Result; fn parse_file<'a>( &self, errors: &'a mut FrontendErrorReceiver<'a, Self::Error>, source: &Path, ) -> Result; } impl DynFrontend for F where F: Frontend, E: ToDiagnostic, { fn parse_source_dyn<'a>( &self, source: Arc, ) -> (Result, Vec) { let mut errors = libeir_util_parse::Errors::new(); let res = self.parse_source(&mut errors, source); (res, errors.iter_diagnostics().collect()) } fn parse_string_dyn<'a>(&self, source: &str) -> (Result, Vec) { let mut errors = libeir_util_parse::Errors::new(); let res = self.parse_string(&mut errors, source); (res, errors.iter_diagnostics().collect()) } fn parse_file_dyn<'a>(&self, source: &Path) -> (Result, Vec) { let mut errors = libeir_util_parse::Errors::new(); let res = self.parse_file(&mut errors, source); (res, errors.iter_diagnostics().collect()) } } pub enum AnyFrontend { #[cfg(feature = "frontend_erlang")] Erlang(erlang::ErlangFrontend), #[cfg(feature = "frontend_abstr_erlang")] AbstrErlang(abstr_erlang::AbstrErlangFrontend), #[cfg(feature = "frontend_eir")] Eir(eir::EirFrontend), } impl DynFrontend for AnyFrontend { fn parse_source_dyn<'a>( &self, source: Arc, ) -> (Result, Vec) { match self { #[cfg(feature = "frontend_erlang")] AnyFrontend::Erlang(front) => front.parse_source_dyn(source), #[cfg(feature = "frontend_abstr_erlang")] AnyFrontend::AbstrErlang(front) => front.parse_source_dyn(source), #[cfg(feature = "frontend_eir")] AnyFrontend::Eir(front) => front.parse_source_dyn(source), } } fn parse_string_dyn<'a>(&self, source: &str) -> (Result, Vec) { match self { #[cfg(feature = "frontend_erlang")] AnyFrontend::Erlang(front) => front.parse_string_dyn(source), #[cfg(feature = "frontend_abstr_erlang")] AnyFrontend::AbstrErlang(front) => front.parse_string_dyn(source), #[cfg(feature = "frontend_eir")] AnyFrontend::Eir(front) => front.parse_string_dyn(source), } } fn parse_file_dyn<'a>(&self, source: &Path) -> (Result, Vec) { match self { #[cfg(feature = "frontend_erlang")] AnyFrontend::Erlang(front) => front.parse_file_dyn(source), #[cfg(feature = "frontend_abstr_erlang")] AnyFrontend::AbstrErlang(front) => front.parse_file_dyn(source), #[cfg(feature = "frontend_eir")] AnyFrontend::Eir(front) => front.parse_file_dyn(source), } } } impl From for AnyFrontend { fn from(f: erlang::ErlangFrontend) -> Self { AnyFrontend::Erlang(f) } } impl From for AnyFrontend { fn from(f: abstr_erlang::AbstrErlangFrontend) -> Self { AnyFrontend::AbstrErlang(f) } } impl From for AnyFrontend { fn from(f: eir::EirFrontend) -> Self { AnyFrontend::Eir(f) } } ================================================ FILE: libeir_intern/Cargo.toml ================================================ [package] name = "libeir_intern" version = "0.1.0" authors = ["Hans Elias B. Josephsen "] edition = "2018" license = "MIT OR Apache-2.0" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] libeir_diagnostics = { path = "../libeir_diagnostics" } rustc-hash = "1.0" lazy_static = "1.2" ================================================ FILE: libeir_intern/src/arena.rs ================================================ #![allow(unused)] //! NOTE: Modified version of impl in rustc //! //! The arena, a fast but limited type of allocator. //! //! Arenas are a type of allocator that destroy the objects within, all at //! once, once the arena itself is destroyed. They do not support deallocation //! of individual objects while the arena itself is still alive. The benefit //! of an arena is very fast allocation; just a pointer bump. //! //! This crate implements `TypedArena`, a simple arena that can only hold //! objects of a single type. use core::cell::{Cell, RefCell}; use core::cmp; use core::intrinsics; use core::marker::{PhantomData, Send}; use core::mem; use core::ptr; use core::slice; use alloc::raw_vec::RawVec; use alloc::vec::Vec; /// An arena that can hold objects of only one type. pub struct TypedArena { /// A pointer to the next object to be allocated. ptr: Cell<*mut T>, /// A pointer to the end of the allocated area. When this pointer is /// reached, a new chunk is allocated. end: Cell<*mut T>, /// A vector of arena chunks. chunks: RefCell>>, /// Marker indicating that dropping the arena causes its owned /// instances of `T` to be dropped. _own: PhantomData, } struct TypedArenaChunk { /// The raw storage for the arena chunk. storage: RawVec, } impl TypedArenaChunk { #[inline] unsafe fn new(capacity: usize) -> TypedArenaChunk { TypedArenaChunk { storage: RawVec::with_capacity(capacity), } } /// Destroys this arena chunk. #[inline] unsafe fn destroy(&mut self, len: usize) { // The branch on needs_drop() is an -O1 performance optimization. // Without the branch, dropping TypedArena takes linear time. if mem::needs_drop::() { let mut start = self.start(); // Destroy all allocated objects. for _ in 0..len { ptr::drop_in_place(start); start = start.offset(1); } } } // Returns a pointer to the first allocated object. #[inline] fn start(&self) -> *mut T { self.storage.ptr() } // Returns a pointer to the end of the allocated space. #[inline] fn end(&self) -> *mut T { unsafe { if mem::size_of::() == 0 { // A pointer as large as possible for zero-sized elements. !0 as *mut T } else { self.start().add(self.storage.capacity()) } } } } #[cfg(not(target_arch = "wasm32"))] const PAGE: usize = 4 * 1024; #[cfg(target_arch = "wasm32")] const PAGE: usize = 64 * 1024; impl Default for TypedArena { /// Creates a new `TypedArena`. fn default() -> TypedArena { TypedArena { // We set both `ptr` and `end` to 0 so that the first call to // alloc() will trigger a grow(). ptr: Cell::new(0 as *mut T), end: Cell::new(0 as *mut T), chunks: RefCell::new(Vec::new()), _own: PhantomData, } } } impl TypedArena { pub fn in_arena(&self, ptr: *const T) -> bool { let ptr = ptr as *const T as *mut T; self.chunks .borrow() .iter() .any(|chunk| chunk.start() <= ptr && ptr < chunk.end()) } /// Allocates an object in the `TypedArena`, returning a reference to it. #[inline] pub fn alloc(&self, object: T) -> &mut T { if self.ptr == self.end { self.grow(1) } unsafe { if mem::size_of::() == 0 { self.ptr .set(intrinsics::arith_offset(self.ptr.get() as *mut u8, 1) as *mut T); let ptr = mem::align_of::() as *mut T; // Don't drop the object. This `write` is equivalent to `forget`. ptr::write(ptr, object); &mut *ptr } else { let ptr = self.ptr.get(); // Advance the pointer. self.ptr.set(self.ptr.get().offset(1)); // Write into uninitialized memory. ptr::write(ptr, object); &mut *ptr } } } /// Allocates a slice of objects that are copied into the `TypedArena`, returning a mutable /// reference to it. Will panic if passed a zero-sized types. /// /// Panics: /// /// - Zero-sized types /// - Zero-length slices #[inline] pub fn alloc_slice(&self, slice: &[T]) -> &mut [T] where T: Copy, { assert!(mem::size_of::() != 0); assert!(slice.len() != 0); let available_capacity_bytes = self.end.get() as usize - self.ptr.get() as usize; let at_least_bytes = slice.len() * mem::size_of::(); if available_capacity_bytes < at_least_bytes { self.grow(slice.len()); } unsafe { let start_ptr = self.ptr.get(); let arena_slice = slice::from_raw_parts_mut(start_ptr, slice.len()); self.ptr.set(start_ptr.add(arena_slice.len())); arena_slice.copy_from_slice(slice); arena_slice } } /// Grows the arena. #[inline(never)] #[cold] fn grow(&self, n: usize) { unsafe { let mut chunks = self.chunks.borrow_mut(); let (chunk, mut new_capacity); if let Some(last_chunk) = chunks.last_mut() { let used_bytes = self.ptr.get() as usize - last_chunk.start() as usize; let currently_used_cap = used_bytes / mem::size_of::(); new_capacity = last_chunk.storage.capacity(); loop { new_capacity = new_capacity.checked_mul(2).unwrap(); if new_capacity >= currently_used_cap + n { break; } } } else { let elem_size = cmp::max(1, mem::size_of::()); new_capacity = cmp::max(n, PAGE / elem_size); } chunk = TypedArenaChunk::::new(new_capacity); self.ptr.set(chunk.start()); self.end.set(chunk.end()); chunks.push(chunk); } } /// Clears the arena. Deallocates all but the longest chunk which may be reused. pub fn clear(&mut self) { unsafe { // Clear the last chunk, which is partially filled. let mut chunks_borrow = self.chunks.borrow_mut(); if let Some(mut last_chunk) = chunks_borrow.last_mut() { self.clear_last_chunk(&mut last_chunk); let len = chunks_borrow.len(); // If `T` is ZST, code below has no effect. for mut chunk in chunks_borrow.drain(..len - 1) { let cap = chunk.storage.capacity(); chunk.destroy(cap); } } } } // Drops the contents of the last chunk. The last chunk is partially empty, unlike all other // chunks. fn clear_last_chunk(&self, last_chunk: &mut TypedArenaChunk) { // Determine how much was filled. let start = last_chunk.start() as usize; // We obtain the value of the pointer to the first uninitialized element. let end = self.ptr.get() as usize; // We then calculate the number of elements to be dropped in the last chunk, // which is the filled area's length. let diff = if mem::size_of::() == 0 { // `T` is ZST. It can't have a drop flag, so the value here doesn't matter. We get // the number of zero-sized values in the last and only chunk, just out of caution. // Recall that `end` was incremented for each allocated value. end - start } else { (end - start) / mem::size_of::() }; // Pass that to the `destroy` method. unsafe { last_chunk.destroy(diff); } // Reset the chunk. self.ptr.set(last_chunk.start()); } } unsafe impl<#[may_dangle] T> Drop for TypedArena { fn drop(&mut self) { unsafe { // Determine how much was filled. let mut chunks_borrow = self.chunks.borrow_mut(); if let Some(mut last_chunk) = chunks_borrow.pop() { // Drop the contents of the last chunk. self.clear_last_chunk(&mut last_chunk); // The last chunk will be dropped. Destroy all other chunks. for chunk in chunks_borrow.iter_mut() { let cap = chunk.storage.capacity(); chunk.destroy(cap); } } // RawVec handles deallocation of `last_chunk` and `self.chunks`. } } } unsafe impl Send for TypedArena {} pub struct DroplessArena { /// A pointer to the next object to be allocated. ptr: Cell<*mut u8>, /// A pointer to the end of the allocated area. When this pointer is /// reached, a new chunk is allocated. end: Cell<*mut u8>, /// A vector of arena chunks. chunks: RefCell>>, } unsafe impl Send for DroplessArena {} impl Default for DroplessArena { #[inline] fn default() -> DroplessArena { DroplessArena { ptr: Cell::new(0 as *mut u8), end: Cell::new(0 as *mut u8), chunks: Default::default(), } } } impl DroplessArena { pub fn in_arena(&self, ptr: *const T) -> bool { let ptr = ptr as *const u8 as *mut u8; self.chunks .borrow() .iter() .any(|chunk| chunk.start() <= ptr && ptr < chunk.end()) } #[inline] fn align(&self, align: usize) { let final_address = ((self.ptr.get() as usize) + align - 1) & !(align - 1); self.ptr.set(final_address as *mut u8); assert!(self.ptr <= self.end); } #[inline(never)] #[cold] fn grow(&self, needed_bytes: usize) { unsafe { let mut chunks = self.chunks.borrow_mut(); let (chunk, mut new_capacity); if let Some(last_chunk) = chunks.last_mut() { let used_bytes = self.ptr.get() as usize - last_chunk.start() as usize; new_capacity = last_chunk.storage.capacity(); loop { new_capacity = new_capacity.checked_mul(2).unwrap(); if new_capacity >= used_bytes + needed_bytes { break; } } } else { new_capacity = cmp::max(needed_bytes, PAGE); } chunk = TypedArenaChunk::::new(new_capacity); self.ptr.set(chunk.start()); self.end.set(chunk.end()); chunks.push(chunk); } } #[inline] pub unsafe fn alloc_raw(&self, bytes: usize, align: usize) -> *mut u8 { assert!(bytes != 0); self.align(align); let future_end = intrinsics::arith_offset(self.ptr.get(), bytes as isize); if (future_end as *mut u8) >= self.end.get() { self.grow(bytes); } let ptr = self.ptr.get(); // Set the pointer past ourselves self.ptr .set(intrinsics::arith_offset(self.ptr.get(), bytes as isize) as *mut u8); ptr } #[inline] pub fn alloc_copy(&self, object: T) -> &mut T { assert!(!mem::needs_drop::()); unsafe { let mem = self.alloc_raw(mem::size_of::(), mem::align_of::()) as *mut T; // Write into uninitialized memory. ptr::write(mem, object); &mut *mem } } /// Allocates a slice of objects that are copied into the `DroplessArena`, returning a mutable /// reference to it. Will panic if passed a zero-sized type. /// /// Panics: /// /// - Zero-sized types /// - Zero-length slices #[inline] pub fn alloc_slice(&self, slice: &[T]) -> &mut [T] where T: Copy, { assert!(!mem::needs_drop::()); assert!(mem::size_of::() != 0); assert!(!slice.is_empty()); unsafe { let mem = self.alloc_raw(slice.len() * mem::size_of::(), mem::align_of::()) as *mut _ as *mut T; let arena_slice = slice::from_raw_parts_mut(mem, slice.len()); arena_slice.copy_from_slice(slice); arena_slice } } } #[cfg(test)] mod tests { use super::TypedArena; use alloc::boxed::Box; use alloc::string::String; use alloc::vec; use alloc::vec::Vec; use core::cell::Cell; use core::sync::atomic::{AtomicUsize, Ordering}; use test::Bencher; #[allow(dead_code)] #[derive(Debug, Eq, PartialEq)] struct Point { x: i32, y: i32, z: i32, } #[test] pub fn test_unused() { let arena: TypedArena = TypedArena::default(); assert!(arena.chunks.borrow().is_empty()); } #[test] fn test_arena_alloc_nested() { struct Inner { value: u8, } struct Outer<'a> { inner: &'a Inner, } enum EI<'e> { I(Inner), O(Outer<'e>), } struct Wrap<'a>(TypedArena>); impl<'a> Wrap<'a> { fn alloc_inner Inner>(&self, f: F) -> &Inner { let r: &EI = self.0.alloc(EI::I(f())); if let &EI::I(ref i) = r { i } else { panic!("mismatch"); } } fn alloc_outer Outer<'a>>(&self, f: F) -> &Outer { let r: &EI = self.0.alloc(EI::O(f())); if let &EI::O(ref o) = r { o } else { panic!("mismatch"); } } } let arena = Wrap(TypedArena::default()); let result = arena.alloc_outer(|| Outer { inner: arena.alloc_inner(|| Inner { value: 10 }), }); assert_eq!(result.inner.value, 10); } #[test] pub fn test_copy() { let arena = TypedArena::default(); for _ in 0..100000 { arena.alloc(Point { x: 1, y: 2, z: 3 }); } } #[bench] pub fn bench_copy(b: &mut Bencher) { let arena = TypedArena::default(); b.iter(|| arena.alloc(Point { x: 1, y: 2, z: 3 })) } #[bench] pub fn bench_copy_nonarena(b: &mut Bencher) { b.iter(|| { let _: Box<_> = Box::new(Point { x: 1, y: 2, z: 3 }); }) } #[allow(dead_code)] struct Noncopy { string: String, array: Vec, } #[test] pub fn test_noncopy() { let arena = TypedArena::default(); for _ in 0..100000 { arena.alloc(Noncopy { string: String::from("hello world"), array: vec![1, 2, 3, 4, 5], }); } } #[test] pub fn test_typed_arena_zero_sized() { let arena = TypedArena::default(); for _ in 0..100000 { arena.alloc(()); } } #[test] pub fn test_typed_arena_clear() { let mut arena = TypedArena::default(); for _ in 0..10 { arena.clear(); for _ in 0..10000 { arena.alloc(Point { x: 1, y: 2, z: 3 }); } } } #[bench] pub fn bench_typed_arena_clear(b: &mut Bencher) { let mut arena = TypedArena::default(); b.iter(|| { arena.alloc(Point { x: 1, y: 2, z: 3 }); arena.clear(); }) } // Drop tests struct DropCounter<'a> { count: &'a Cell, } impl<'a> Drop for DropCounter<'a> { fn drop(&mut self) { self.count.set(self.count.get() + 1); } } #[test] fn test_typed_arena_drop_count() { let counter = Cell::new(0); { let arena: TypedArena = TypedArena::default(); for _ in 0..100 { // Allocate something with drop glue to make sure it doesn't leak. arena.alloc(DropCounter { count: &counter }); } }; assert_eq!(counter.get(), 100); } #[test] fn test_typed_arena_drop_on_clear() { let counter = Cell::new(0); let mut arena: TypedArena = TypedArena::default(); for i in 0..10 { for _ in 0..100 { // Allocate something with drop glue to make sure it doesn't leak. arena.alloc(DropCounter { count: &counter }); } arena.clear(); assert_eq!(counter.get(), i * 100 + 100); } } static DROP_COUNTER: AtomicUsize = AtomicUsize::new(0); struct SmallDroppable; impl Drop for SmallDroppable { fn drop(&mut self) { DROP_COUNTER.fetch_add(1, Ordering::SeqCst); } } #[test] fn test_typed_arena_drop_small_count() { DROP_COUNTER.store(0, Ordering::SeqCst); { let arena: TypedArena = TypedArena::default(); for _ in 0..100 { // Allocate something with drop glue to make sure it doesn't leak. arena.alloc(SmallDroppable); } // dropping }; assert_eq!(DROP_COUNTER.load(Ordering::SeqCst), 100); } #[bench] pub fn bench_noncopy(b: &mut Bencher) { let arena = TypedArena::default(); b.iter(|| { arena.alloc(Noncopy { string: String::from("hello world"), array: vec![1, 2, 3, 4, 5], }) }) } #[bench] pub fn bench_noncopy_nonarena(b: &mut Bencher) { b.iter(|| { let _: Box<_> = Box::new(Noncopy { string: String::from("hello world"), array: vec![1, 2, 3, 4, 5], }); }) } } ================================================ FILE: libeir_intern/src/lib.rs ================================================ #![feature(core_intrinsics)] #![feature(dropck_eyepatch)] #![feature(raw_vec_internals)] #![feature(test)] extern crate alloc; #[cfg(any(test, bench))] extern crate test; pub mod arena; pub mod symbol; pub use symbol::{Ident, InternedString, LocalInternedString, Symbol}; #[cfg(test)] mod tests { #[test] fn it_works() { assert_eq!(2 + 2, 4); } } ================================================ FILE: libeir_intern/src/symbol.rs ================================================ //! An "interner" is a data structure that associates values with usize tags and //! allows bidirectional lookup; i.e., given a value, one can easily find the //! type, and vice versa. #![allow(unused)] use std::cell::RefCell; use std::cmp::{Ord, Ordering, PartialEq, PartialOrd}; use std::fmt; use std::hash::{Hash, Hasher}; use std::marker::PhantomData; use std::str; use std::sync::{Arc, RwLock}; use lazy_static::lazy_static; use rustc_hash::FxHashMap; use crate::arena::DroplessArena; use libeir_diagnostics::SourceSpan; lazy_static! { /// A globally accessible symbol table pub static ref SYMBOL_TABLE: SymbolTable = { SymbolTable::new() }; } pub struct SymbolTable { interner: RwLock, } impl SymbolTable { pub fn new() -> Self { SymbolTable { interner: RwLock::new(Interner::fresh()), } } } unsafe impl Sync for SymbolTable {} #[derive(Copy, Clone, Eq)] pub struct Ident { pub name: Symbol, pub span: SourceSpan, } impl Ident { #[inline] pub const fn new(name: Symbol, span: SourceSpan) -> Ident { Ident { name, span } } #[inline] pub const fn with_empty_span(name: Symbol) -> Ident { Ident::new(name, SourceSpan::UNKNOWN) } /// Maps an interned string to an identifier with an empty syntax context. pub fn from_interned_str(string: InternedString) -> Ident { Ident::with_empty_span(string.as_symbol()) } /// Maps a string to an identifier with an empty syntax context. pub fn from_str(string: &str) -> Ident { Ident::with_empty_span(Symbol::intern(string)) } pub fn unquote_string(self) -> Ident { Ident::new(Symbol::intern(self.as_str().trim_matches('"')), self.span) } pub fn unquote_atom(self) -> Ident { Ident::new(Symbol::intern(self.as_str().trim_matches('\'')), self.span) } pub fn gensym(self) -> Ident { Ident::new(self.name.gensymed(), self.span) } pub fn as_str(self) -> LocalInternedString { self.name.as_str() } pub fn as_interned_str(self) -> InternedString { self.name.as_interned_str() } } impl PartialOrd for Ident { fn partial_cmp(&self, other: &Self) -> Option { self.name.partial_cmp(&other.name) } } impl PartialEq for Ident { fn eq(&self, rhs: &Self) -> bool { self.name == rhs.name } } impl Hash for Ident { fn hash(&self, state: &mut H) { self.name.hash(state); } } impl fmt::Debug for Ident { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "Ident<{} {:?}>", self.name, self.span) } } impl fmt::Display for Ident { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Display::fmt(&self.name, f) } } #[derive(Debug, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct SymbolIndex(u32); impl Clone for SymbolIndex { fn clone(&self) -> Self { *self } } impl From for u32 { #[inline] fn from(v: SymbolIndex) -> u32 { v.as_u32() } } impl From for usize { #[inline] fn from(v: SymbolIndex) -> usize { v.as_usize() } } impl SymbolIndex { // shave off 256 indices at the end to allow space for packing these indices into enums pub const MAX_AS_U32: u32 = 0xFFFF_FF00; pub const MAX: SymbolIndex = SymbolIndex::new(0xFFFF_FF00); #[inline] const fn new(n: u32) -> Self { // This will fail at const eval time unless `value <= // max` is true (in which case we get the index 0). // It will also fail at runtime, of course, but in a // kind of wacky way. let _ = ["out of range value used"][!(n <= Self::MAX_AS_U32) as usize]; SymbolIndex(n) } #[inline] pub fn as_u32(self) -> u32 { self.0 } #[inline] pub fn as_usize(self) -> usize { self.0 as usize } } /// A symbol is an interned or gensymed string. #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct Symbol(SymbolIndex); impl Symbol { const fn new(n: u32) -> Self { Symbol(SymbolIndex::new(n)) } /// Maps a string to its interned representation. pub fn intern(string: &str) -> Self { with_interner(|interner| interner.intern(string)) } pub fn interned(self) -> Self { with_interner(|interner| interner.interned(self)) } /// Gensyms a new usize, using the current interner. pub fn gensym(string: &str) -> Self { with_interner(|interner| interner.gensym(string)) } pub fn gensymed(self) -> Self { with_interner(|interner| interner.gensymed(self)) } pub fn as_str(self) -> LocalInternedString { with_interner(|interner| unsafe { LocalInternedString { string: ::std::mem::transmute::<&str, &str>(interner.get(self)), dummy: PhantomData, } }) } pub fn as_interned_str(self) -> InternedString { with_interner(|interner| InternedString { symbol: interner.interned(self), }) } #[inline] pub fn as_u32(self) -> u32 { self.0.as_u32() } #[inline] pub fn as_usize(self) -> usize { self.0.as_usize() } } impl fmt::Debug for Symbol { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let is_gensymed = with_interner(|interner| interner.is_gensymed(*self)); if is_gensymed { write!(f, "{}({:?})", self, self.0) } else { write!(f, "{}({:?})", self, self.0) } } } impl fmt::Display for Symbol { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Display::fmt(&self.as_str(), f) } } impl> PartialEq for Symbol { fn eq(&self, other: &T) -> bool { self.as_str() == other.deref() } } // The `&'static str`s in this type actually point into the arena. // // Note that normal symbols are indexed upward from 0, and gensyms are indexed // downward from SymbolIndex::MAX_AS_U32. #[derive(Default)] pub struct Interner { arena: DroplessArena, pub names: FxHashMap<&'static str, Symbol>, pub strings: Vec<&'static str>, gensyms: Vec, } impl Interner { fn prefill(init: &[&str]) -> Self { let mut this = Interner::default(); for &string in init { if string == "" { // We can't allocate empty strings in the arena, so handle this here. let name = Symbol::new(this.strings.len() as u32); this.names.insert("", name); this.strings.push(""); } else { this.intern(string); } } this } pub fn intern(&mut self, string: &str) -> Symbol { if let Some(&name) = self.names.get(string) { return name; } let name = Symbol::new(self.strings.len() as u32); // `from_utf8_unchecked` is safe since we just allocated a `&str` which is known to be // UTF-8. let string: &str = unsafe { str::from_utf8_unchecked(self.arena.alloc_slice(string.as_bytes())) }; // It is safe to extend the arena allocation to `'static` because we only access // these while the arena is still alive. let string: &'static str = unsafe { &*(string as *const str) }; self.strings.push(string); self.names.insert(string, name); name } pub fn interned(&self, symbol: Symbol) -> Symbol { if (symbol.0.as_usize()) < self.strings.len() { symbol } else { self.interned(self.gensyms[(SymbolIndex::MAX_AS_U32 - symbol.0.as_u32()) as usize]) } } fn gensym(&mut self, string: &str) -> Symbol { let symbol = self.intern(string); self.gensymed(symbol) } fn gensymed(&mut self, symbol: Symbol) -> Symbol { self.gensyms.push(symbol); Symbol::new(SymbolIndex::MAX_AS_U32 - self.gensyms.len() as u32 + 1) } fn is_gensymed(&mut self, symbol: Symbol) -> bool { symbol.0.as_usize() >= self.strings.len() } pub fn get(&self, symbol: Symbol) -> &str { match self.strings.get(symbol.0.as_usize()) { Some(string) => string, None => self.get(self.gensyms[(SymbolIndex::MAX_AS_U32 - symbol.0.as_u32()) as usize]), } } } // In this macro, there is the requirement that the name (the number) must be monotonically // increasing by one in the special identifiers, starting at 0; the same holds for the keywords, // except starting from the next number instead of zero. macro_rules! declare_atoms {( $( ($index: expr, $konst: ident, $string: expr) )* ) => { pub mod symbols { use super::Symbol; $( #[allow(non_upper_case_globals)] pub const $konst: Symbol = super::Symbol::new($index); )* /// Used *only* for testing that the declared atoms have no gaps /// NOTE: The length must be static, so it must be changed when new /// declared keywords are added to the list pub(super) static DECLARED: [(Symbol, &'static str); 60] = [$(($konst, $string),)*]; } impl Interner { pub fn fresh() -> Self { let interner = Interner::prefill(&[$($string,)*]); interner } } }} // NOTE: When determining whether an Ident is a keyword or not, we compare against // the ident table index, but if a hole is left in the table, then non-keyword idents // will be interned with an id in the keyword range. It is important to ensure there are // no holes, which means you have to adjust the indexes when adding a new keyword earlier // in the table declare_atoms! { // We want true/false to correspond to 1/0 respectively for convenience (0, False, "false") (1, True, "true") // Special reserved identifiers used internally, such as for error recovery (2, Invalid, "") // Keywords that are used in Erlang (3, After, "after") (4, Begin, "begin") (5, Case, "case") (6, Try, "try") (7, Catch, "catch") (8, End, "end") (9, Fun, "fun") (10, If, "if") (11, Of, "of") (12, Receive, "receive") (13, When, "when") (14, AndAlso, "andalso") (15, OrElse, "orelse") (16, Bnot, "bnot") (17, Not, "not") (18, Div, "div") (19, Rem, "rem") (20, Band, "band") (21, And, "and") (22, Bor, "bor") (23, Bxor, "bxor") (24, Bsl, "bsl") (25, Bsr, "bsr") (26, Or, "or") (27, Xor, "xor") // Not reserved words, but used in attributes or preprocessor directives (28, Module, "module") (29, Export, "export") (30, Import, "import") (31, Compile, "compile") (32, Vsn, "vsn") (33, OnLoad, "on_load") (34, Behaviour, "behaviour") (35, Spec, "spec") (36, Callback, "callback") (37, Include, "include") (38, IncludeLib, "include_lib") (39, Define, "define") (40, Undef, "undef") (41, Ifdef, "ifdef") (42, Ifndef, "ifndef") (43, Else, "else") (44, Elif, "elif") (45, Endif, "endif") (46, Error, "error") (47, Warning, "warning") (48, File, "file") // Common words (49, ModuleInfo, "module_info") (50, RecordInfo, "record_info") (51, BehaviourInfo,"behaviour_info") (52, Exports, "exports") (53, Attributes, "attributes") (54, Native, "native") (55, Deprecated, "deprecated") (56, ModuleCapital,"MODULE") (57, ModuleStringCapital,"MODULE_STRING") (58, Throw, "throw") (59, Exit, "exit") } impl Symbol { /// Returns `true` if the token is a keyword, reserved in all name positions pub fn is_keyword(self) -> bool { self > symbols::Invalid && self <= symbols::Xor } /// Returns `true` if the token is a reserved attribute name pub fn is_reserved_attr(self) -> bool { self >= symbols::Module && self <= symbols::Warning } /// Returns `true` if the token is a preprocessor directive name pub fn is_preprocessor_directive(self) -> bool { self >= symbols::Include && self <= symbols::Warning } } impl Ident { pub fn is_keyword(self) -> bool { self.name.is_keyword() } pub fn is_reserved_attr(self) -> bool { self.name.is_reserved_attr() } pub fn is_preprocessor_directive(self) -> bool { self.name.is_preprocessor_directive() } } // If an interner exists, return it. Otherwise, prepare a fresh one. #[inline] fn with_interner T>(f: F) -> T { let mut r = SYMBOL_TABLE .interner .write() .expect("unable to acquire write lock for symbol table"); f(&mut *r) //GLOBALS.with(|globals| { //f(&mut *globals.symbol_interner.lock().expect("symbol interner lock was held")) //}) } #[inline] fn with_read_only_interner T>(f: F) -> T { let r = SYMBOL_TABLE .interner .read() .expect("unable to acquire read lock for symbol table"); f(&*r) } /// Represents a string stored in the interner. Because the interner outlives any thread /// which uses this type, we can safely treat `string` which points to interner data, /// as an immortal string, as long as this type never crosses between threads. #[derive(Clone, Copy, Hash, PartialOrd, Eq, Ord)] pub struct LocalInternedString { string: &'static str, /// This type cannot be sent across threads, this emulates the /// behavior of !impl without the unsafe feature flag. dummy: PhantomData<*const u8>, } impl LocalInternedString { pub fn as_interned_str(self) -> InternedString { InternedString { symbol: Symbol::intern(self.string), } } pub fn get(&self) -> &'static str { self.string } } impl ::std::convert::AsRef for LocalInternedString where str: ::std::convert::AsRef, { fn as_ref(&self) -> &U { self.string.as_ref() } } impl> ::std::cmp::PartialEq for LocalInternedString { fn eq(&self, other: &T) -> bool { self.string == other.deref() } } impl ::std::cmp::PartialEq for str { fn eq(&self, other: &LocalInternedString) -> bool { self == other.string } } impl<'a> ::std::cmp::PartialEq for &'a str { fn eq(&self, other: &LocalInternedString) -> bool { *self == other.string } } impl ::std::cmp::PartialEq for String { fn eq(&self, other: &LocalInternedString) -> bool { self == other.string } } impl<'a> ::std::cmp::PartialEq for &'a String { fn eq(&self, other: &LocalInternedString) -> bool { *self == other.string } } //impl !Send for LocalInternedString {} //impl !Sync for LocalInternedString {} impl ::std::ops::Deref for LocalInternedString { type Target = str; fn deref(&self) -> &str { self.string } } impl fmt::Debug for LocalInternedString { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Debug::fmt(self.string, f) } } impl fmt::Display for LocalInternedString { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Display::fmt(self.string, f) } } /// Represents a string stored in the string interner. #[derive(Clone, Copy, Eq)] pub struct InternedString { symbol: Symbol, } impl InternedString { pub fn with R, R>(self, f: F) -> R { let str = with_interner(|interner| interner.get(self.symbol) as *const str); // This is safe because the interner keeps string alive until it is dropped. // We can access it because we know the interner is still alive since we use a // scoped thread local to access it, and it was alive at the beginning of this scope unsafe { f(&*str) } } pub fn as_symbol(self) -> Symbol { self.symbol } pub fn as_str(self) -> LocalInternedString { self.symbol.as_str() } } impl Hash for InternedString { fn hash(&self, state: &mut H) { self.with(|str| str.hash(state)) } } impl PartialOrd for InternedString { fn partial_cmp(&self, other: &InternedString) -> Option { if self.symbol == other.symbol { return Some(Ordering::Equal); } self.with(|self_str| other.with(|other_str| self_str.partial_cmp(other_str))) } } impl Ord for InternedString { fn cmp(&self, other: &InternedString) -> Ordering { if self.symbol == other.symbol { return Ordering::Equal; } self.with(|self_str| other.with(|other_str| self_str.cmp(&other_str))) } } impl> PartialEq for InternedString { fn eq(&self, other: &T) -> bool { self.with(|string| string == other.deref()) } } impl PartialEq for InternedString { fn eq(&self, other: &InternedString) -> bool { self.symbol == other.symbol } } impl PartialEq for str { fn eq(&self, other: &InternedString) -> bool { other.with(|string| self == string) } } impl<'a> PartialEq for &'a str { fn eq(&self, other: &InternedString) -> bool { other.with(|string| *self == string) } } impl PartialEq for String { fn eq(&self, other: &InternedString) -> bool { other.with(|string| self == string) } } impl<'a> PartialEq for &'a String { fn eq(&self, other: &InternedString) -> bool { other.with(|string| *self == string) } } impl ::std::convert::From for String { fn from(val: InternedString) -> String { val.as_symbol().to_string() } } impl fmt::Debug for InternedString { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { self.with(|str| fmt::Debug::fmt(&str, f)) } } impl fmt::Display for InternedString { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { self.with(|str| fmt::Display::fmt(&str, f)) } } #[cfg(test)] mod tests { use super::*; #[test] fn interner_tests() { let mut i: Interner = Interner::default(); // first one is zero: assert_eq!(i.intern("dog"), Symbol::new(0)); // re-use gets the same entry: assert_eq!(i.intern("dog"), Symbol::new(0)); // different string gets a different #: assert_eq!(i.intern("cat"), Symbol::new(1)); assert_eq!(i.intern("cat"), Symbol::new(1)); // dog is still at zero assert_eq!(i.intern("dog"), Symbol::new(0)); assert_eq!(i.gensym("zebra"), Symbol::new(SymbolIndex::MAX_AS_U32)); // gensym of same string gets new number: assert_eq!(i.gensym("zebra"), Symbol::new(SymbolIndex::MAX_AS_U32 - 1)); // gensym of *existing* string gets new number: assert_eq!(i.gensym("dog"), Symbol::new(SymbolIndex::MAX_AS_U32 - 2)); } #[test] fn interned_keywords_no_gaps() { let mut i = Interner::fresh(); // Should already be interned with matching indexes for (sym, s) in symbols::DECLARED.iter() { assert_eq!(i.intern(&s), *sym) } // Should create a new symbol resulting in an index equal to the last entry in the table assert_eq!(i.intern("foo").as_u32(), (i.names.len() - 1) as u32); } #[test] fn unquote_string() { let i = Ident::from_str("\"after\""); assert_eq!(i.unquote_string().name, symbols::After); } #[test] fn unquote_atom() { let i = Ident::from_str("'after'"); assert_eq!(i.unquote_atom().name, symbols::After); } } ================================================ FILE: libeir_interpreter/Cargo.toml ================================================ [package] name = "libeir_interpreter" version = "0.1.0" authors = ["hansihe"] edition = "2018" license = "MIT OR Apache-2.0" [features] default = ["trace"] trace = [] [dependencies] num = "0.2" num-traits = "0.2" tempdir = "0.3" lazy_static = "1.2" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" libeir_ir = { path = "../libeir_ir" } libeir_intern = { path = "../libeir_intern" } libeir_util_binary = { path = "../util/libeir_util_binary" } libeir_util_number = { path = "../util/libeir_util_number" } num-bigint = { git = "https://github.com/hansihe/num-bigint.git" } pretty = "0.7" #[dependencies.rug] #version = "1.2" #default-features = false #features = ["integer", "float", "rand"] ================================================ FILE: libeir_interpreter/README.md ================================================ # libeir_interpreter **This interpreter is really basic and unfinished. It is only meant to aid testing.** ================================================ FILE: libeir_interpreter/src/erl_lib/erlang.rs ================================================ use libeir_intern::Symbol; use libeir_util_number::bigint_to_double; use crate::module::{NativeModule, NativeReturn}; use crate::process::ProcessContext; use crate::vm::VMState; use crate::term::ListIteratorItem; use crate::term::Term; use crate::term::{ErlEq, ErlExactEq, ErlOrd}; use ::num_traits::Signed; use std::rc::Rc; fn abs(_vm: &VMState, _proc: &mut ProcessContext, args: &[Rc]) -> NativeReturn { if args.len() != 1 { panic!() } let a1 = &*args[0]; let ret = match a1 { Term::Integer(ref int) => Term::Integer(int.clone().abs()), Term::Float(flt) => Term::Float(flt.0.abs().into()), _ => panic!(), }; NativeReturn::Return { term: ret.into() } } fn add(_vm: &VMState, _proc: &mut ProcessContext, args: &[Rc]) -> NativeReturn { // TODO: Verify semantics if args.len() != 2 { panic!(); } let a1 = &*args[0]; let a2 = &*args[1]; match (a1, a2) { (Term::Integer(ref i1), Term::Integer(ref i2)) => NativeReturn::Return { term: Term::Integer(i1.clone() + i2).into(), }, (Term::Integer(ref i1), Term::Float(f2)) => { let f1 = bigint_to_double(i1); NativeReturn::Return { term: Term::Float((f1 + f2.0).into()).into(), } } (Term::Float(f1), Term::Integer(ref i2)) => { let f2 = bigint_to_double(i2); NativeReturn::Return { term: Term::Float((f1.0 + f2).into()).into(), } } (Term::Float(f1), Term::Float(f2)) => NativeReturn::Return { term: Term::Float((f1.0 + f2.0).into()).into(), }, _ => NativeReturn::Throw { typ: Term::new_atom("error").into(), reason: Term::new_atom("badarith").into(), }, } } fn sub(_vm: &VMState, _proc: &mut ProcessContext, args: &[Rc]) -> NativeReturn { if args.len() != 2 { panic!(); } let a1 = &*args[0]; let a2 = &*args[1]; match (a1, a2) { (Term::Integer(ref i1), Term::Integer(ref i2)) => NativeReturn::Return { term: Term::Integer(i1.clone() - i2).into(), }, (Term::Integer(ref int), Term::Float(ref flt)) => { let flt_c = bigint_to_double(int); NativeReturn::Return { term: Term::Float((flt_c - flt.0).into()).into(), } } (Term::Float(ref flt), Term::Integer(ref int)) => { let flt_c = bigint_to_double(int); NativeReturn::Return { term: Term::Float((flt.0 - flt_c).into()).into(), } } (Term::Float(flt1), Term::Float(flt2)) => NativeReturn::Return { term: Term::Float((flt1.0 - flt2.0).into()).into(), }, _ => NativeReturn::Throw { typ: Term::new_atom("error").into(), reason: Term::new_atom("badarith").into(), }, } } fn invert(_vm: &VMState, _proc: &mut ProcessContext, args: &[Rc]) -> NativeReturn { if args.len() != 1 { panic!(); } match &*args[0] { Term::Integer(ref i1) => NativeReturn::Return { term: Term::Integer(-i1.clone()).into(), }, Term::Float(ref f1) => NativeReturn::Return { term: Term::Float((-f1.0).into()).into(), }, _ => unimplemented!(), } } fn mul(_vm: &VMState, _proc: &mut ProcessContext, args: &[Rc]) -> NativeReturn { if args.len() != 2 { panic!(); } let a1 = &*args[0]; let a2 = &*args[1]; match (a1, a2) { (Term::Integer(ref i1), Term::Integer(ref i2)) => NativeReturn::Return { term: Term::Integer(i1.clone() * i2).into(), }, _ => unimplemented!(), } } fn div(_vm: &VMState, _proc: &mut ProcessContext, args: &[Rc]) -> NativeReturn { if args.len() != 2 { panic!(); } let a1 = match &*args[0] { Term::Integer(i1) => bigint_to_double(i1), Term::Float(flt) => flt.0, _ => panic!(), }; let a2 = match &*args[1] { Term::Integer(i1) => bigint_to_double(i1), Term::Float(flt) => flt.0, _ => panic!(), }; NativeReturn::Return { term: Term::Float((a1 / a2).into()).into(), } } fn is_list(_vm: &VMState, _proc: &mut ProcessContext, args: &[Rc]) -> NativeReturn { if args.len() != 1 { panic!(); } let a1 = &*args[0]; match a1 { Term::ListCell(_, _) => NativeReturn::Return { term: Term::new_atom("true").into(), }, Term::Nil => NativeReturn::Return { term: Term::new_atom("true").into(), }, _ => NativeReturn::Return { term: Term::new_atom("false").into(), }, } } fn is_atom(_vm: &VMState, _proc: &mut ProcessContext, args: &[Rc]) -> NativeReturn { if args.len() != 1 { panic!(); } let a1 = &*args[0]; match a1 { Term::Atom(_) => NativeReturn::Return { term: Term::new_bool(true).into(), }, _ => NativeReturn::Return { term: Term::new_bool(false).into(), }, } } fn is_integer(_vm: &VMState, _proc: &mut ProcessContext, args: &[Rc]) -> NativeReturn { assert!(args.len() == 1); let a1 = &*args[0]; match a1 { Term::Integer(_) => NativeReturn::Return { term: Term::new_bool(true).into(), }, _ => NativeReturn::Return { term: Term::new_bool(false).into(), }, } } fn is_pid(_vm: &VMState, _proc: &mut ProcessContext, args: &[Rc]) -> NativeReturn { assert!(args.len() == 1); let a1 = &*args[0]; match a1 { Term::Pid(_) => NativeReturn::Return { term: Term::new_bool(true).into(), }, _ => NativeReturn::Return { term: Term::new_bool(false).into(), }, } } fn is_tuple(_vm: &VMState, _proc: &mut ProcessContext, args: &[Rc]) -> NativeReturn { assert!(args.len() == 1); let a1 = &*args[0]; match a1 { Term::Tuple(_) => NativeReturn::Return { term: Term::new_bool(true).into(), }, _ => NativeReturn::Return { term: Term::new_bool(false).into(), }, } } fn is_map(_vm: &VMState, _proc: &mut ProcessContext, args: &[Rc]) -> NativeReturn { assert!(args.len() == 1); let a1 = &*args[0]; match a1 { Term::Map(_) => NativeReturn::Return { term: Term::new_bool(true).into(), }, _ => NativeReturn::Return { term: Term::new_bool(false).into(), }, } } //fn list_append(_vm: &VMState, _proc: &mut ProcessContext, args: &[Rc]) -> NativeReturn { // // TODO: Validate semantics // assert!(args.len() == 2); // match (&*args[0], &*args[1]) { // (Term::Nil, Term::Nil) => NativeReturn::Return { term: Term::Nil.into() }, // (Term::Nil, Term::List(_, _)) => NativeReturn::Return { term: args[1].clone() }, // (Term::List(_, ref tail), Term::Nil) if tail.erl_eq(&Term::Nil) // => NativeReturn::Return { term: args[0].clone() }, // (Term::List(ref _f_head, ref _f_tail), Term::List(ref b_head, ref b_tail)) => { // let (mut f_head_terms, f_tail_term) = args[0].as_inproper_list(); // if let Term::Nil = f_tail_term { // f_head_terms.extend(b_head.iter().cloned()); // NativeReturn::Return { term: Term::List(f_head_terms, b_tail.clone()).into() } // } else { // NativeReturn::Throw // } // } // _ => NativeReturn::Throw, // } //} fn list_subtract(_vm: &VMState, _proc: &mut ProcessContext, args: &[Rc]) -> NativeReturn { let (mut to_remove_vec, tail) = Term::as_inproper_list(&args[1]); assert!(tail.erl_eq(&Term::Nil)); let mut out = Vec::new(); for item in Term::list_iter(&args[0]) { match item { ListIteratorItem::Elem(elem) => { if let Some(idx) = to_remove_vec .iter() .enumerate() .find(|(_, term)| elem.erl_eq(term)) .map(|(idx, _)| idx) { to_remove_vec.remove(idx); } else { out.push(elem); } } ListIteratorItem::Tail(tail) => { assert!(tail.erl_eq(&Term::Nil)); return NativeReturn::Return { term: Term::slice_to_list(&out, tail.clone()), }; } } } unreachable!() } fn exact_eq(_vm: &VMState, _proc: &mut ProcessContext, args: &[Rc]) -> NativeReturn { assert!(args.len() == 2); NativeReturn::Return { term: Term::new_bool(args[0].erl_exact_eq(&*args[1])).into(), } } fn exact_not_eq(_vm: &VMState, _proc: &mut ProcessContext, args: &[Rc]) -> NativeReturn { assert!(args.len() == 2); NativeReturn::Return { term: Term::new_bool(!args[0].erl_exact_eq(&*args[1])).into(), } } fn and(_vm: &VMState, _proc: &mut ProcessContext, args: &[Rc]) -> NativeReturn { assert!(args.len() == 2); if let (Some(a1), Some(a2)) = (args[0].as_boolean(), args[1].as_boolean()) { NativeReturn::Return { term: Term::new_bool(a1 && a2).into(), } } else { panic!() } } fn or(_vm: &VMState, _proc: &mut ProcessContext, args: &[Rc]) -> NativeReturn { assert!(args.len() == 2); if let (Some(a1), Some(a2)) = (args[0].as_boolean(), args[1].as_boolean()) { NativeReturn::Return { term: Term::new_bool(a1 || a2).into(), } } else { panic!() } } fn tuple_size(_vm: &VMState, _proc: &mut ProcessContext, args: &[Rc]) -> NativeReturn { assert!(args.len() == 1); if let Term::Tuple(ref terms) = &*args[0] { NativeReturn::Return { term: Term::new_i64(terms.len() as i64).into(), } } else { panic!() } } fn is_function(_vm: &VMState, _proc: &mut ProcessContext, args: &[Rc]) -> NativeReturn { assert!(args.len() == 1 || args.len() == 2); let arity_ref = if args.len() == 2 { if let Some(int) = args[1].as_i64() { Some(int) } else { panic!() } } else { None }; if let Term::CapturedFunction { ident, .. } = &*args[0] { let res = arity_ref.map(|a| a == ident.arity as i64).unwrap_or(true); NativeReturn::Return { term: Term::new_bool(res).into(), } } else if let Term::BoundLambda { ident, .. } = &*args[0] { let res = arity_ref.map(|a| a == ident.arity as i64).unwrap_or(true); NativeReturn::Return { term: Term::new_bool(res).into(), } } else { NativeReturn::Return { term: Term::new_bool(false).into(), } } } //fn base_spawn(vm: &VMState, ident: &FunctionIdent, args: Vec) -> Pid { // let new_pid = { // let mut processes = vm.processes.borrow(); // Pid(processes.len()) // }; // // let process = ProcessContext::new(new_pid); // // let orig_pid = crate::trace::get_pid(); // crate::trace::set_pid(new_pid); // let frame = process.make_call_stackframe( // vm, // ident.module.clone(), // ident.clone(), // args // ); // crate::trace::set_pid(orig_pid); // // let stack_i = process.stack.clone(); // let mut stack = stack_i.borrow_mut(); // stack.push(frame); // // { // let mut processes = vm.processes.borrow_mut(); // processes.push(Rc::new(RefCell::new(process))); // } // // { // let mut mailboxes = vm.mailboxes.borrow_mut(); // mailboxes.insert(new_pid, ::mailbox::Mailbox::new()); // } // // new_pid //} // //fn base_spawn_term(vm: &VMState, callable: &Term, mut args: Vec) -> Pid { // match callable { // Term::CapturedFunction { module, fun_name, arity } => { // let ident = FunctionIdent { // module: module.clone(), // name: fun_name.clone(), // arity: *arity, // lambda: None, // }; // base_spawn(vm, &ident, args) // } // Term::BoundLambda { module, fun_name, arity, lambda, bound_env } => { // let ident = FunctionIdent { // module: module.clone(), // name: fun_name.clone(), // arity: *arity, // lambda: Some(*lambda), // }; // args.insert(0, Term::LambdaEnv(bound_env.clone())); // base_spawn(vm, &ident, args) // }, // _ => panic!(), // } //} // //fn base_monitor(vm: &VMState, proc: &mut ProcessContext, other: Pid) -> Reference { // let monitor_ref = vm.ref_gen.borrow_mut().next(); // let mut watches = vm.watches.borrow_mut(); // // if !watches.contains_key(&other) { // watches.insert(other, Vec::new()); // } // let for_proc = watches.get_mut(&other).unwrap(); // // for_proc.push((proc.pid, WatchType::Monitor(monitor_ref))); // // monitor_ref //} // //fn spawn_1(vm: &VMState, _proc: &mut ProcessContext, args: &[Rc]) -> NativeReturn { // assert!(args.len() == 1); // let fun_term = &*args[0]; // // let new_pid = base_spawn_term(vm, fun_term, vec![]); // NativeReturn::Return { term: Term::Pid(new_pid) } //} // //fn spawn_monitor_1(vm: &VMState, proc: &mut ProcessContext, args: &[Rc]) -> NativeReturn { // assert!(args.len() == 1); // let fun_term = &*args[0]; // // let new_pid = base_spawn_term(vm, fun_term, vec![]); // let monitor_ref = base_monitor(vm, proc, new_pid); // // let term = Term::Tuple(vec![ // Term::Pid(new_pid), // Term::Reference(monitor_ref), // ]); // NativeReturn::Return { term: term } //} // //fn monitor_2(vm: &VMState, proc: &mut ProcessContext, args: &[Rc]) -> NativeReturn { // assert!(args.len() == 2); // if args[0].erl_eq(&Term::new_atom("process")) { // if let Term::Pid(pid) = args[1] { // let monitor_ref = base_monitor(vm, proc, pid); // NativeReturn::Return { term: Term::Reference(monitor_ref) } // } else { // NativeReturn::Throw // } // } else { // unimplemented!() // } //} fn not(_vm: &VMState, _proc: &mut ProcessContext, args: &[Rc]) -> NativeReturn { assert!(args.len() == 1); if let Some(b) = args[0].as_boolean() { NativeReturn::Return { term: Term::new_bool(!b).into(), } } else { panic!() } } fn is_binary(_vm: &VMState, _proc: &mut ProcessContext, args: &[Rc]) -> NativeReturn { assert!(args.len() == 1); let a1 = &*args[0]; match a1 { Term::Binary(_) => NativeReturn::Return { term: Term::new_bool(true).into(), }, Term::BinarySlice { .. } => NativeReturn::Return { term: Term::new_bool(true).into(), }, _ => NativeReturn::Return { term: Term::new_bool(false).into(), }, } } fn atom_to_list(_vm: &VMState, _proc: &mut ProcessContext, args: &[Rc]) -> NativeReturn { assert!(args.len() == 1); let a1 = &*args[0]; match a1 { Term::Atom(atom) => { let chars: Vec<_> = atom .as_str() .chars() .map(|c| Term::new_i64(c as i64).into()) .collect(); NativeReturn::Return { term: Term::slice_to_list(&chars, Term::Nil.into()).into(), } } _ => panic!(), } } fn less_than_or_equal( _vm: &VMState, _proc: &mut ProcessContext, args: &[Rc], ) -> NativeReturn { assert!(args.len() == 2); let a1 = &*args[0]; let a2 = &*args[1]; let ord = a1.erl_ord(a2); NativeReturn::Return { term: Term::new_bool(ord != std::cmp::Ordering::Greater).into(), } } fn less_than(_vm: &VMState, _proc: &mut ProcessContext, args: &[Rc]) -> NativeReturn { assert!(args.len() == 2); let a1 = &*args[0]; let a2 = &*args[1]; let ord = a1.erl_ord(a2); NativeReturn::Return { term: Term::new_bool(ord == std::cmp::Ordering::Less).into(), } } fn greater_than_or_equal( _vm: &VMState, _proc: &mut ProcessContext, args: &[Rc], ) -> NativeReturn { assert!(args.len() == 2); let a1 = &*args[0]; let a2 = &*args[1]; let ord = a1.erl_ord(a2); NativeReturn::Return { term: Term::new_bool(ord != std::cmp::Ordering::Less).into(), } } fn greater_than(_vm: &VMState, _proc: &mut ProcessContext, args: &[Rc]) -> NativeReturn { assert!(args.len() == 2); let a1 = &*args[0]; let a2 = &*args[1]; let ord = a1.erl_ord(a2); NativeReturn::Return { term: Term::new_bool(ord == std::cmp::Ordering::Greater).into(), } } fn setelement(_vm: &VMState, _proc: &mut ProcessContext, args: &[Rc]) -> NativeReturn { assert!(args.len() == 3); let idx = if let Some(num) = args[0].as_usize() { num } else { panic!() }; let value = args[2].clone(); if let Term::Tuple(vals) = &*args[1] { if idx == 0 || idx > vals.len() { panic!() } else { let mut vals = vals.clone(); vals[idx - 1] = value; NativeReturn::Return { term: Term::Tuple(vals).into(), } } } else { panic!() } } fn element(_vm: &VMState, _proc: &mut ProcessContext, args: &[Rc]) -> NativeReturn { assert!(args.len() == 2); let idx = if let Some(num) = args[0].as_usize() { num } else { panic!() }; if let Term::Tuple(vals) = &*args[1] { if idx == 0 || idx > vals.len() { panic!() } else { NativeReturn::Return { term: vals[idx - 1].clone(), } } } else { panic!() } } fn erl_self(_vm: &VMState, proc: &mut ProcessContext, args: &[Rc]) -> NativeReturn { assert!(args.len() == 0); NativeReturn::Return { term: Term::Pid(proc.pid).into(), } } //fn process_flag(vm: &VMState, proc: &mut ProcessContext, args: &[Rc]) -> NativeReturn { // assert!(args.len() == 2); // if args[0].erl_eq(&Term::new_atom("trap_exit")) { // let mut mailboxes = vm.mailboxes.borrow_mut(); // let mailbox = &mut mailboxes.get_mut(&proc.pid).unwrap(); // let old_trap_exits = mailbox.get_trap_exits(); // mailbox.set_trap_exits(args[1].as_boolean().unwrap()); // NativeReturn::Return { term: Term::new_bool(old_trap_exits).into() } // } else { // unimplemented!() // } //} fn put(_vm: &VMState, proc: &mut ProcessContext, args: &[Rc]) -> NativeReturn { assert!(args.len() == 2); if let Some(entry) = proc.dict.iter_mut().find(|e| e.0.erl_exact_eq(&args[0])) { let old = entry.1.clone(); entry.1 = args[1].clone(); NativeReturn::Return { term: old } } else { proc.dict.push((args[0].clone(), args[1].clone())); NativeReturn::Return { term: Term::new_atom("undefined").into(), } } } fn get(_vm: &VMState, proc: &mut ProcessContext, args: &[Rc]) -> NativeReturn { assert!(args.len() == 1); if let Some(entry) = proc.dict.iter().find(|e| e.0.erl_exact_eq(&args[0])) { NativeReturn::Return { term: entry.1.clone(), } } else { NativeReturn::Return { term: Term::new_atom("undefined").into(), } } } fn erase(_vm: &VMState, proc: &mut ProcessContext, args: &[Rc]) -> NativeReturn { assert!(args.len() == 1); let idx = proc .dict .iter() .enumerate() .find(|e| (e.1).0.erl_exact_eq(&args[0])) .map(|(idx, _)| idx); if let Some(entry) = idx { let (_key, val) = proc.dict.remove(entry); NativeReturn::Return { term: val } } else { NativeReturn::Return { term: Term::new_atom("undefined").into(), } } } fn length(_vm: &VMState, _proc: &mut ProcessContext, args: &[Rc]) -> NativeReturn { assert!(args.len() == 1); let mut len = 0; for item in Term::list_iter(&args[0]) { match item { ListIteratorItem::Elem(_) => { len += 1; } ListIteratorItem::Tail(tail) => { if tail.erl_eq(&Term::Nil) { return NativeReturn::Return { term: Term::new_i64(len as i64).into(), }; } else { return NativeReturn::Throw { typ: Term::new_atom("error").into(), reason: Term::new_atom("badarg").into(), }; } } } } unreachable!() } fn hd(_vm: &VMState, _proc: &mut ProcessContext, args: &[Rc]) -> NativeReturn { if args.len() != 1 { panic!(); } let a1 = &*args[0]; match a1 { Term::ListCell(hd, _) => NativeReturn::Return { term: hd.clone() }, _ => NativeReturn::Throw { typ: Term::new_atom("error").into(), reason: Term::new_atom("badarg").into(), }, } } fn tl(_vm: &VMState, _proc: &mut ProcessContext, args: &[Rc]) -> NativeReturn { if args.len() != 1 { panic!(); } let a1 = &*args[0]; match a1 { Term::ListCell(_, tl) => NativeReturn::Return { term: tl.clone() }, _ => NativeReturn::Throw { typ: Term::new_atom("error").into(), reason: Term::new_atom("badarg").into(), }, } } fn map_size(_vm: &VMState, _proc: &mut ProcessContext, args: &[Rc]) -> NativeReturn { assert!(args.len() == 1); if let Some(map) = args[0].as_map() { NativeReturn::Return { term: Term::new_usize(map.len()).into(), } } else { unimplemented!() } } pub fn make_erlang() -> NativeModule { let mut module = NativeModule::new(Symbol::intern("erlang")); module.add_fun(Symbol::intern("+"), 2, Box::new(add)); module.add_fun(Symbol::intern("-"), 1, Box::new(invert)); module.add_fun(Symbol::intern("-"), 2, Box::new(sub)); module.add_fun(Symbol::intern("*"), 2, Box::new(mul)); module.add_fun(Symbol::intern("/"), 2, Box::new(div)); module.add_fun(Symbol::intern("abs"), 1, Box::new(abs)); //module.add_fun(Symbol::intern("++"), 2, Box::new(list_append)); module.add_fun(Symbol::intern("--"), 2, Box::new(list_subtract)); module.add_fun(Symbol::intern("=:="), 2, Box::new(exact_eq)); module.add_fun(Symbol::intern("=/="), 2, Box::new(exact_not_eq)); module.add_fun(Symbol::intern("=<"), 2, Box::new(less_than_or_equal)); module.add_fun(Symbol::intern("<"), 2, Box::new(less_than)); module.add_fun(Symbol::intern(">="), 2, Box::new(greater_than_or_equal)); module.add_fun(Symbol::intern(">"), 2, Box::new(greater_than)); module.add_fun(Symbol::intern("is_list"), 1, Box::new(is_list)); module.add_fun(Symbol::intern("is_atom"), 1, Box::new(is_atom)); module.add_fun(Symbol::intern("is_binary"), 1, Box::new(is_binary)); module.add_fun(Symbol::intern("is_integer"), 1, Box::new(is_integer)); module.add_fun(Symbol::intern("is_pid"), 1, Box::new(is_pid)); module.add_fun(Symbol::intern("is_tuple"), 1, Box::new(is_tuple)); module.add_fun(Symbol::intern("is_map"), 1, Box::new(is_map)); module.add_fun(Symbol::intern("and"), 2, Box::new(and)); module.add_fun(Symbol::intern("or"), 2, Box::new(or)); module.add_fun(Symbol::intern("tuple_size"), 1, Box::new(tuple_size)); module.add_fun(Symbol::intern("is_function"), 1, Box::new(is_function)); module.add_fun(Symbol::intern("is_function"), 2, Box::new(is_function)); //module.add_fun(Symbol::intern("spawn_monitor"), 1, Box::new(spawn_monitor_1)); module.add_fun(Symbol::intern("not"), 1, Box::new(not)); module.add_fun(Symbol::intern("atom_to_list"), 1, Box::new(atom_to_list)); module.add_fun(Symbol::intern("setelement"), 3, Box::new(setelement)); module.add_fun(Symbol::intern("element"), 2, Box::new(element)); module.add_fun(Symbol::intern("length"), 1, Box::new(length)); module.add_fun(Symbol::intern("self"), 0, Box::new(erl_self)); module.add_fun(Symbol::intern("put"), 2, Box::new(put)); module.add_fun(Symbol::intern("get"), 1, Box::new(get)); module.add_fun(Symbol::intern("erase"), 1, Box::new(erase)); module.add_fun(Symbol::intern("hd"), 1, Box::new(hd)); module.add_fun(Symbol::intern("tl"), 1, Box::new(tl)); module.add_fun(Symbol::intern("map_size"), 1, Box::new(map_size)); //module.add_fun(Symbol::intern("spawn"), 1, Box::new(spawn_1)); //module.add_fun(Symbol::intern("monitor"), 2, Box::new(monitor_2)); //module.add_fun(Symbol::intern("process_flag"), 2, Box::new(process_flag)); module } ================================================ FILE: libeir_interpreter/src/erl_lib/file.rs ================================================ use ::module::NativeModule; use ::vm::VMState; use ::term::Term; use ::process::{ CallReturn, ProcessContext }; fn delete(_vm: &VMState, _proc: &mut ProcessContext, args: &[Term]) -> CallReturn { assert!(args.len() == 1); // TODO let n = vec![Term::new_atom("error"), Term::new_atom("enoent")]; CallReturn::Return { term: Term::Tuple(n) } } pub fn make_time() -> NativeModule { let mut module = NativeModule::new("file".to_string()); module.add_fun("delete".to_string(), 1, Box::new(delete)); module } ================================================ FILE: libeir_interpreter/src/erl_lib/lists.rs ================================================ use std::rc::Rc; use crate::module::{NativeModule, NativeReturn}; use crate::process::ProcessContext; use crate::term::{ErlEq, Term}; use crate::vm::VMState; use libeir_intern::Symbol; //fn member_list(item: &Term, list: &Term) -> NativeReturn { // if let Term::Nil = list { // NativeReturn::Return { term: Term::new_bool(false).into() } // } else if let Term::List(ref head, ref tail) = list { // for l_item in head { // if item.erl_exact_eq(l_item) { // return NativeReturn::Return { term: Term::new_bool(true).into() }; // } // } // member_list(item, tail) // } else { // NativeReturn::Throw // } //} // //fn member(_vm: &VMState, _proc: &mut ProcessContext, args: &[Rc]) -> NativeReturn { // assert!(args.len() == 2); // member_list(&args[0], &args[1]) //} // fn reverse_2(_vm: &VMState, _proc: &mut ProcessContext, args: &[Rc]) -> NativeReturn { assert!(args.len() == 2); let (mut head, tail) = Term::as_inproper_list(&args[0]); assert!(tail.erl_eq(&Term::Nil)); head.reverse(); NativeReturn::Return { term: Term::slice_to_list(&head, args[1].clone()), } } fn reverse_1(vm: &VMState, proc: &mut ProcessContext, args: &[Rc]) -> NativeReturn { assert!(args.len() == 1); reverse_2(vm, proc, &[args[0].clone(), Term::Nil.into()]) } //fn keyfind(_vm: &VMState, _proc: &mut ProcessContext, args: &[Rc]) -> NativeReturn { // assert!(args.len() == 3); // let key = &*args[0]; // let pos = if let Some(int) = args[1].as_i64() { // int // } else { // return NativeReturn::Throw; // }; // let list_term = &*args[2]; // let (list, list_tail) = list_term.as_inproper_list(); // for term in list.iter() { // if let Term::Tuple(values) = &**term { // if let Some(val_term) = values.get(pos as usize) { // if val_term.erl_eq(key) { // return NativeReturn::Return { term: term.clone() }; // } // } // } // } // if let Term::Nil = list_tail { // NativeReturn::Return { term: Term::new_bool(false).into() } // } else { // NativeReturn::Throw // } //} pub fn make_lists() -> NativeModule { let mut module = NativeModule::new(Symbol::intern("lists")); //module.add_fun(Symbol::intern("member"), 2, Box::new(member)); module.add_fun(Symbol::intern("reverse"), 1, Box::new(reverse_1)); module.add_fun(Symbol::intern("reverse"), 2, Box::new(reverse_2)); //module.add_fun(Symbol::intern("keyfind"), 3, Box::new(keyfind)); module } ================================================ FILE: libeir_interpreter/src/erl_lib/maps.rs ================================================ use libeir_intern::Symbol; use crate::module::{NativeModule, NativeReturn}; use crate::process::ProcessContext; use crate::vm::VMState; use crate::term::{ListIteratorItem, MapTerm, Term}; use std::rc::Rc; fn new_0(_vm: &VMState, _proc: &mut ProcessContext, args: &[Rc]) -> NativeReturn { assert!(args.len() == 0); NativeReturn::Return { term: Term::Map(MapTerm::new()).into(), } } fn from_list_1(_vm: &VMState, _proc: &mut ProcessContext, args: &[Rc]) -> NativeReturn { assert!(args.len() == 1); let mut map = MapTerm::new(); for elem in Term::list_iter(&args[0]) { match elem { ListIteratorItem::Elem(tup_term) => { let tup = tup_term.as_tuple().unwrap(); assert!(tup.len() == 2); map.insert(tup[0].clone(), tup[1].clone()); } ListIteratorItem::Tail(term) => { assert!(term.is_nil()); } } } NativeReturn::Return { term: Term::Map(map).into(), } } pub fn make_maps() -> NativeModule { let mut module = NativeModule::new(Symbol::intern("maps")); module.add_fun(Symbol::intern("new"), 0, Box::new(new_0)); module.add_fun(Symbol::intern("from_list"), 1, Box::new(from_list_1)); module } ================================================ FILE: libeir_interpreter/src/erl_lib/math.rs ================================================ use std::rc::Rc; use crate::module::{NativeModule, NativeReturn}; use crate::process::ProcessContext; use crate::term::Term; use crate::vm::VMState; use libeir_intern::Symbol; use num_traits::{Pow, ToPrimitive}; fn pow(_vm: &VMState, _proc: &mut ProcessContext, args: &[Rc]) -> NativeReturn { assert!(args.len() == 2); let a1 = &*args[0]; let a2 = &*args[1]; let ret = match (a1, a2) { (Term::Integer(ref i1), Term::Integer(ref i2)) => { Term::Integer(i1.clone().pow(i2.to_u32().unwrap())) } //Term::Integer(num::pow::pow(i1.clone(), i2.to_usize().unwrap())), _ => unimplemented!(), }; NativeReturn::Return { term: ret.into() } } pub fn make_math() -> NativeModule { let mut module = NativeModule::new(Symbol::intern("math")); module.add_fun(Symbol::intern("pow"), 2, Box::new(pow)); module } ================================================ FILE: libeir_interpreter/src/erl_lib/mod.rs ================================================ mod erlang; pub use self::erlang::make_erlang; //mod os; //pub use self::os::make_os; mod lists; pub use self::lists::make_lists; mod math; pub use self::math::make_math; //mod file; //pub use self::file::make_time; mod maps; pub use self::maps::make_maps; ================================================ FILE: libeir_interpreter/src/erl_lib/os.rs ================================================ use ::vm::VMState; use ::module::NativeModule; use ::term::Term; use ::process::{ CallReturn, ProcessContext }; fn getenv(_vm: &VMState, _proc: &mut ProcessContext, args: &[Term]) -> CallReturn { if args.len() == 1 { CallReturn::Return { term: Term::new_bool(false) } } else { CallReturn::Throw } } fn os_type(_vm: &VMState, _proc: &mut ProcessContext, args: &[Term]) -> CallReturn { assert!(args.len() == 0); // TODO let family = Term::new_atom("unix"); let name = Term::new_atom("linux"); CallReturn::Return { term: Term::Tuple(vec![family, name]) } } pub fn make_os() -> NativeModule { let mut module = NativeModule::new("os".to_string()); module.add_fun("getenv".to_string(), 1, Box::new(getenv)); module.add_fun("type".to_string(), 0, Box::new(os_type)); module } ================================================ FILE: libeir_interpreter/src/erl_tests/mod.rs ================================================ extern crate tempdir; use ::std::io::{ Read, Write }; use ::{ VMState, Term }; use eir::Module; use ::term::ErlEq; fn erl_to_core(erlang_code: &str) -> String { let temp = tempdir::TempDir::new("core_erlang_crate_tests").unwrap(); let temp_dir = temp.path(); println!("Compilation dir: {:?}", temp_dir); { let in_file_name = temp_dir.join("code.erl"); let mut in_file = ::std::fs::File::create(in_file_name).unwrap(); in_file.write_all(erlang_code.as_bytes()).unwrap(); } let out = ::std::process::Command::new("erlc") .arg("+to_core") .arg("code.erl") .current_dir(temp_dir.clone()) .output() .expect("failed to execute erlc"); println!("{:?}", out); assert!(out.status.success()); let out_file_name = temp_dir.join("code.core"); let mut out_file = ::std::fs::File::open(out_file_name).unwrap(); let mut out_core = String::new(); out_file.read_to_string(&mut out_core).unwrap(); println!("====== Core ======\n{}\n==================\n\n", out_core); out_core } fn erl_to_ir(erlang_code: &str) -> Module { let core = erl_to_core(erlang_code); let parsed = ::core_erlang_compiler::parser::parse(&core).unwrap(); let ir = ::core_erlang_compiler::ir::from_parsed(&parsed.0); //println!("Ir:\n{:?}", ir); ir } fn ctx_from_erl(erlang_code: &str) -> VMState { let module = erl_to_ir(erlang_code); let mut ctx = VMState::new(); ctx.add_native_module(::erl_lib::make_erlang()); ctx.add_erlang_module(module); ctx } const TEST_ERL_1: &str = r##" -module(test). -export([add/2, add_two/3, return_closure/1]). add(A, B) -> A + B. add_two(A, B, C) -> I = add(A, B), add(I, C). return_closure(I) -> O = 1, fun(A) -> add(add(I, A), O) end. add_with_closure(A, B) -> F = return_closure(A), F(B). matching([], []) -> one; matching([], _) -> two; matching(_, []) -> three; matching(A, B) -> {A, B}. "##; #[test] fn simple_add() { let mut ctx = ctx_from_erl(TEST_ERL_1); let args = vec![Term::new_i64(1), Term::new_i64(2)]; let result = ctx.call("test", "add", args); assert!(result.unwrap_return().erl_eq(&Term::Integer(3.into()))); } #[test] fn simple_function_call() { let mut ctx = ctx_from_erl(TEST_ERL_1); let args = vec![Term::new_i64(1), Term::new_i64(2), Term::new_i64(3)]; let result = ctx.call("test", "add_two", args); assert!(result.unwrap_return().erl_eq(&Term::Integer(6.into()))); } #[test] fn simple_lambda() { let mut ctx = ctx_from_erl(TEST_ERL_1); let args = vec![Term::new_i64(1), Term::new_i64(2)]; let result = ctx.call("test", "add_with_closure", args); assert!(result.unwrap_return().erl_eq(&Term::Integer(4.into()))); } #[test] fn simple_pattern_match() { let mut ctx = ctx_from_erl(TEST_ERL_1); let args = vec![Term::new_i64(1), Term::new_i64(2)]; let result = ctx.call("test", "matching", args); assert!(result.unwrap_return().erl_eq(&Term::Tuple(vec![ Term::new_i64(1), Term::new_i64(2), ]))); let args = vec![Term::Nil, Term::Nil]; let result = ctx.call("test", "matching", args); assert!(result.unwrap_return().erl_eq(&Term::new_atom("one"))); } const FACTORIAL_ERL: &str = r##" -module(test). -export([factorial/1]). factorial(0) -> 1; factorial(N) -> N * factorial(N-1). "##; #[test] fn factorial() { let mut ctx = ctx_from_erl(FACTORIAL_ERL); let args = vec![Term::new_i64(10)]; let result = ctx.call("test", "factorial", args); println!("Res: {:?}", result); } //#[test] fn long_strings() { let mut ctx = VMState::new(); let mut f = ::std::fs::File::open("../test_data/long_strings.core") .unwrap(); let mut core = String::new(); f.read_to_string(&mut core).unwrap(); println!("Parsing"); let parsed = ::core_erlang_compiler::parser::parse(&core).unwrap(); } fn compile_core_file(path: &str) -> Module { let mut f = ::std::fs::File::open(path) .unwrap(); let mut core = String::new(); f.read_to_string(&mut core).unwrap(); let parsed = ::core_erlang_compiler::parser::parse(&core).unwrap(); ::core_erlang_compiler::ir::from_parsed(&parsed.0) } #[test] fn compiler() { let result = std::panic::catch_unwind(|| { let mut ctx = VMState::new(); ctx.add_native_module(::erl_lib::make_erlang()); ctx.add_native_module(::erl_lib::make_os()); ctx.add_native_module(::erl_lib::make_time()); ctx.add_erlang_module(compile_core_file( "../otp/lib/compiler/ebin/compile.core")); ctx.add_erlang_module(compile_core_file( "../otp/lib/stdlib/ebin/proplists.core")); //"/home/hansihe/proj/checkout/otp/lib/stdlib/ebin/proplists.core")); ctx.add_erlang_module(compile_core_file( "../otp/lib/stdlib/ebin/filename.core")); //"/home/hansihe/proj/checkout/otp/lib/stdlib/ebin/filename.core")); ctx.add_erlang_module(compile_core_file( "../otp/lib/stdlib/ebin/epp.core")); ctx.add_erlang_module(compile_core_file( "../otp/lib/stdlib/ebin/lists.core")); //"/home/hansihe/proj/checkout/otp/lib/stdlib/ebin/lists.core")); ctx.add_nif_overlay(::erl_lib::make_lists()); let args = vec![Term::new_atom("foo.erl")]; ctx.call("compile", "file", args); }); ::trace::dump_trace("trace.json".to_string()); assert!(result.is_ok()); } ================================================ FILE: libeir_interpreter/src/lib.rs ================================================ //#![deny(warnings)] //! LIR interpreter with zero consideration of performance. //! Made as an experiment to narrow down relevant implementation //! details. mod term; pub use term::{ErlEq, ErlExactEq, ErlOrd, Pid, Reference, Term, TermType}; pub mod erl_lib; mod vm; pub use vm::{VMState, WatchType}; mod process; mod module; //mod trace; ================================================ FILE: libeir_interpreter/src/mailbox.rs ================================================ use ::term::{ Term, Pid }; #[derive(Debug)] pub struct Mailbox { trap_exits: bool, messages: Vec<(Pid, Term)>, } impl Mailbox { pub fn new() -> Self { Mailbox { trap_exits: false, messages: vec![], } } pub fn get_trap_exits(&self) -> bool { self.trap_exits } pub fn set_trap_exits(&mut self, val: bool) { self.trap_exits = val; } } ================================================ FILE: libeir_interpreter/src/module.rs ================================================ use std::collections::HashMap; use std::rc::Rc; use crate::process::ProcessContext; use crate::{Term, VMState}; use libeir_intern::Symbol; use libeir_ir::{Function, FunctionIdent, LiveValues, Module}; pub enum NativeReturn { Return { term: Rc }, Throw { typ: Rc, reason: Rc }, } pub struct NativeModule { pub name: Symbol, pub functions: HashMap< (Symbol, usize), Box]) -> NativeReturn>, >, } impl NativeModule { pub fn new(name: Symbol) -> Self { NativeModule { name: name, functions: HashMap::new(), } } pub fn add_fun( &mut self, name: Symbol, arity: usize, fun: Box]) -> NativeReturn>, ) { self.functions.insert((name, arity), fun); } pub fn has_fun(&self, ident: &FunctionIdent) -> bool { self.functions.contains_key(&(ident.name.name, ident.arity)) } } pub struct ErlangFunction { pub fun: Function, pub live: LiveValues, } pub struct ErlangModule { pub name: Symbol, pub functions: HashMap, } impl ErlangModule { pub fn from_eir(module: Module) -> Self { let functions = module .index_iter() .map(|idx| { let fun_def = &module[idx]; let fun = fun_def.function(); let nfun = ErlangFunction { live: fun.live_values(), fun: fun.clone(), }; (fun.ident().clone(), nfun) }) .collect(); ErlangModule { name: module.name().name, functions, } } } pub enum ModuleType { Erlang(ErlangModule, Option), Native(NativeModule), } ================================================ FILE: libeir_interpreter/src/pattern.rs ================================================ use std::collections::HashMap; use ::term::Term; use eir::Clause; use eir::pattern::PatternNode; use eir::AtomicTerm; use eir::SSAVariable; #[derive(Debug, Copy, Clone)] pub enum MatchState { MatchClause(usize), GuardWait(usize), Finished, } impl MatchState { fn clause_num(&self) -> usize { match self { MatchState::MatchClause(num) => *num, MatchState::GuardWait(num) => *num, _ => panic!(), } } fn clause_num_mut(&mut self) -> &mut usize { match self { MatchState::MatchClause(num) => num, _ => panic!(), } } fn into_guard(&mut self) { match *self { MatchState::MatchClause(num) => *self = MatchState::GuardWait(num), _ => unreachable!(), } } fn into_body(&mut self) { match *self { MatchState::GuardWait(num) => *self = MatchState::MatchClause(num+1), _ => unreachable!(), } } fn into_finished(&mut self) { *self = MatchState::Finished; } } #[derive(Debug, Clone)] pub struct CaseContext { pub state: MatchState, pub vars: Vec, pub clauses: Vec, pub last_binds: Option>, } fn match_node(term: &Term, node: &PatternNode, binds: &mut HashMap) -> bool { //println!(" MATCH_NODE: {:?} {:?}", term, node); match (term, node) { // Wildcard and purely recursive (_, PatternNode::Wildcard) => true, (_, PatternNode::Bind(ssa, i_node)) => { binds.insert( *ssa, //binds_ref.iter().find(|(k, _)| k == var_name).unwrap().1, term.clone() ); match_node(term, i_node, binds) }, // Lists (Term::List(ref t_head, ref t_tail), PatternNode::List(ref p_head, ref p_tail)) => { if t_head.len() < p_head.len() { for (pat, term) in p_head.iter().zip(t_head.iter()) { if !match_node(term, pat, binds) { return false; } } let n_p_head: Vec<_> = p_head.iter().skip(t_head.len()) .cloned().collect(); let n_pat = PatternNode::List(n_p_head, p_tail.clone()); return match_node(t_tail, &n_pat, binds); } else if t_head.len() == p_head.len() { for (pat, term) in p_head.iter().zip(t_head.iter()) { if !match_node(term, pat, binds) { return false; } } return match_node(t_tail, p_tail, binds); } else { // > assert!(t_head.len() > p_head.len()); for (pat, term) in p_head.iter().zip(t_head.iter()) { if !match_node(term, pat, binds) { return false; } } let head_rest: Vec<_> = t_head.iter().skip(p_head.len()) .cloned().collect(); let rest_term = Term::List(head_rest, t_tail.clone()); let a = match_node(&rest_term, p_tail, binds); return a; } } // List with empty head (_, PatternNode::List(ref list, ref tail)) if list.len() == 0 => match_node(term, tail, binds), // Nil ([]) (Term::Nil, PatternNode::Atomic(AtomicTerm::Nil)) => true, (Term::Nil, _) => false, (_, PatternNode::Atomic(AtomicTerm::Nil)) => false, // Tuple (Term::Tuple(t_entries), PatternNode::Tuple(p_entries)) => { if t_entries.len() != p_entries.len() { return false; } for (term, pat) in t_entries.iter().zip(p_entries) { if !match_node(term, pat, binds) { return false; } } true } (_, PatternNode::Tuple(_)) => false, // Atom (Term::Atom(v1), PatternNode::Atomic(AtomicTerm::Atom(v2))) => v1 == v2, (Term::Atom(_), _) => false, (_, PatternNode::Atomic(AtomicTerm::Atom(_))) => false, (Term::Integer(ref int), PatternNode::Atomic(AtomicTerm::Integer(ref pat_int))) => { println!(" Int pattern {} {}", int, pat_int); int == pat_int } _ => { ::trace::warning("WARNING: Pattern matching incomplete".to_string()); println!(" Warning: Pattern matching incomplete"); false }, } } impl CaseContext { pub fn new(vars: Vec, clauses: Vec) -> Self { CaseContext { state: MatchState::MatchClause(0), vars: vars, clauses: clauses, last_binds: None, } } pub fn do_body(&mut self) -> usize { let (matched, values) = { let clause = &self.clauses[self.state.clause_num()]; assert!(clause.patterns.len() == self.vars.len()); //println!("{:?}", clause); //println!(" {:?}", self.vars); let mut values: HashMap = HashMap::new(); let matched = self.vars.iter() .zip(&clause.patterns) .enumerate() .all(|(idx, (term, pattern))| { let r = match_node(term, &pattern.node, &mut values); println!(" Pattern num: {} {}", idx, r); r }); (matched, values) }; if matched { let clause_num = self.state.clause_num(); self.state.into_guard(); self.last_binds = Some(values); clause_num + 1 } else { *self.state.clause_num_mut() += 1; if self.state.clause_num() >= self.clauses.len() { 0 } else { self.do_body() } } //println!("PAT: {:?}", self.clauses[0]); //println!("TERMS: {:?}", terms); } pub fn case_values(&self) -> HashMap { self.last_binds.as_ref().unwrap().clone() } pub fn guard_ok(&mut self) { self.state.into_finished(); } pub fn guard_fail(&mut self, clause_num: usize) { assert!(clause_num == self.state.clause_num()); self.state.into_body(); } } ================================================ FILE: libeir_interpreter/src/process/match.rs ================================================ use libeir_ir::{BasicType, BinaryEntrySpecifier, Block, Endianness, MatchKind}; use libeir_util_binary::BitCarrier; use libeir_util_binary::{carrier_to_integer, BitSlice, BitVec, Endian}; use crate::module::ErlangFunction; use crate::term::ErlExactEq; use crate::Term; use super::{CallExecutor, TermCall}; pub fn match_op( exec: &mut CallExecutor, fun: &ErlangFunction, branches: &[MatchKind], block: Block, ) -> TermCall { let reads = fun.fun.block_reads(block); let branches_elems = Term::as_value_list(&exec.make_term(fun, reads[0])); let unpack_term = exec.make_term(fun, reads[1]); for (idx, kind) in branches.iter().enumerate() { let branch_args = Term::as_value_list(&exec.make_term(fun, reads[idx + 2])); match kind { MatchKind::Value => { assert!(branch_args.len() == 1); if unpack_term.erl_exact_eq(&*branch_args[0]) { return TermCall { fun: branches_elems[idx].clone(), args: vec![], }; } } MatchKind::ListCell => { assert!(branch_args.len() == 0); match &*unpack_term { Term::ListCell(head, tail) => { return TermCall { fun: branches_elems[idx].clone(), args: vec![head.clone(), tail.clone()], }; } _ => (), } } MatchKind::Tuple(len) => { assert!(branch_args.len() == 0); match &*unpack_term { Term::Tuple(elems) if elems.len() == *len => { return TermCall { fun: branches_elems[idx].clone(), args: elems.clone(), }; } _ => (), } } MatchKind::Type(BasicType::Map) => { assert!(branch_args.len() == 0); match &*unpack_term { Term::Map(_) => { return TermCall { fun: branches_elems[idx].clone(), args: vec![], }; } _ => (), } } MatchKind::MapItem => { assert!(branch_args.len() == 1); match &*unpack_term { Term::Map(map) => { if let Some(v) = map.get(&branch_args[0]) { return TermCall { fun: branches_elems[idx].clone(), args: vec![v.clone()], }; } } _ => unreachable!(), } } MatchKind::Binary(BinaryEntrySpecifier::Integer { unit, endianness, signed, }) => { let size = branch_args[0].as_usize().unwrap(); let bit_len = (*unit as usize) * size; let ret = match &*unpack_term { Term::Binary(bin) => { if (bin.len() * 8) < bit_len { continue; } let int_slice = BitSlice::with_offset_length(&**bin, 0, bit_len); let endian = match *endianness { Endianness::Big => Endian::Big, Endianness::Little => Endian::Little, Endianness::Native => Endian::Big, }; let int = carrier_to_integer(int_slice, *signed, endian); TermCall { fun: branches_elems[idx].clone(), args: vec![ Term::Integer(int).into(), Term::BinarySlice { buf: bin.clone(), bit_offset: bit_len, bit_length: bin.bit_len() - bit_len, } .into(), ], } } Term::BinarySlice { buf, bit_offset, bit_length, } => { if *bit_length < bit_len { continue; } let int_slice = BitSlice::with_offset_length(&**buf, *bit_offset, bit_len); let endian = match *endianness { Endianness::Big => Endian::Big, Endianness::Little => Endian::Little, Endianness::Native => Endian::Big, }; let int = carrier_to_integer(int_slice, *signed, endian); TermCall { fun: branches_elems[idx].clone(), args: vec![ Term::Integer(int).into(), Term::BinarySlice { buf: buf.clone(), bit_offset: *bit_offset + bit_len, bit_length: *bit_length - bit_len, } .into(), ], } } _ => continue, }; return ret; } MatchKind::Binary(BinaryEntrySpecifier::Bytes { unit }) => { let size = branch_args[0].as_usize().unwrap_or(1); let byte_len = (*unit as usize) * size; match &*unpack_term { Term::Binary(bin) => { //if bin.bit_len() % 8 != 0 { // continue; //} return TermCall { fun: branches_elems[idx].clone(), args: vec![ unpack_term.clone(), Term::Binary(BitVec::new().into()).into(), ], }; } Term::BinarySlice { bit_length, .. } => { //if *bit_length % 8 != 0 { // continue; //} return TermCall { fun: branches_elems[idx].clone(), args: vec![ unpack_term.clone(), Term::Binary(BitVec::new().into()).into(), ], }; } _ => (), } }, MatchKind::Wildcard => { assert!(branch_args.len() == 0); return TermCall { fun: branches_elems[idx].clone(), args: vec![], }; } kind => unimplemented!("{:?}", kind), } } panic!() } ================================================ FILE: libeir_interpreter/src/process/mod.rs ================================================ use std::any::TypeId; use std::collections::HashMap; use std::rc::Rc; use num_traits::cast::ToPrimitive; use libeir_intern::Ident; use libeir_ir::constant::{AtomicTerm, Const, ConstKind}; use libeir_ir::operation::binary_construct::{ BinaryConstructFinish, BinaryConstructPush, BinaryConstructStart, }; use libeir_ir::MapPutUpdate; use libeir_ir::{BinOp, Block, FunctionIdent, LogicOp, OpKind, PrimOpKind, Value, ValueKind}; use libeir_ir::{BinaryEntrySpecifier, Endianness}; use libeir_util_binary::{integer_to_carrier, BitSlice, BitVec, Endian}; use crate::module::{ErlangFunction, ErlangModule, ModuleType, NativeModule, NativeReturn}; use crate::term::{ErlEq, MapTerm, Pid, Term}; use crate::vm::VMState; mod r#match; #[derive(Debug)] pub struct TermCall { pub fun: Rc, pub args: Vec>, } pub enum Continuation { Term(TermCall), ReturnOk(Rc), ReturnThrow(Rc, Rc, Rc), } pub struct CallExecutor { binds: HashMap>, } impl CallExecutor { pub fn new() -> Self { CallExecutor { binds: HashMap::new(), } } pub fn run(&mut self, vm: &VMState, proc: &mut ProcessContext, call: TermCall) -> Continuation { self.binds.clear(); match &*call.fun { Term::BoundLambda { ident, block, environment, } => { let module = &vm.modules[&ident.module.name]; match module { ModuleType::Erlang(erl, _overlay) => Continuation::Term( self.run_erlang(vm, erl, ident, Some((*block, &*environment)), &call.args) .unwrap(), ), ModuleType::Native(_native) => unreachable!(), } } Term::CapturedFunction { ident } => { let module = &vm.modules[&ident.module.name]; println!("{}", ident); match module { ModuleType::Erlang(erl, overlay) => { if let Some(native) = overlay { if let Some(res) = self.run_native(vm, proc, native, ident, &call.args) { return Continuation::Term(res); } } Continuation::Term( self.run_erlang(vm, erl, ident, None, &call.args).unwrap(), ) } ModuleType::Native(native) => Continuation::Term( if let Some(res) = self.run_native(vm, proc, native, ident, &call.args) { res } else { panic!("Could not find native function {}", ident); }, ), } } Term::ReturnOk => { assert!(call.args.len() == 1); Continuation::ReturnOk(call.args[0].clone()) } Term::ReturnThrow => { assert!(call.args.len() == 3); Continuation::ReturnThrow( call.args[0].clone(), call.args[1].clone(), call.args[2].clone(), ) } // TODO can't call term type, throw exception _ => unimplemented!(), } } pub fn run_native( &mut self, vm: &VMState, proc: &mut ProcessContext, native: &NativeModule, ident: &FunctionIdent, args: &[Rc], ) -> Option { if let Some(n_fun) = native.functions.get(&(ident.name.name, ident.arity)) { match n_fun(vm, proc, &args[2..]) { NativeReturn::Return { term } => Some(TermCall { fun: args[0].clone(), args: vec![term], }), NativeReturn::Throw { typ, reason } => Some(TermCall { fun: args[1].clone(), args: vec![typ, reason, Term::Nil.into()], }), } } else { None } } pub fn run_erlang( &mut self, vm: &VMState, module: &ErlangModule, ident: &FunctionIdent, state: Option<(Block, &[Rc])>, args: &[Rc], ) -> Option { if let Some(fun) = module.functions.get(&ident) { // Environment let block = if let Some((block, env)) = state { let live = &fun.live.live_at(block); for (v, t) in live.iter().zip(env.iter()) { self.binds.insert(v, t.clone()); } assert!(live.iter().count() == env.len()); block } else { fun.fun.block_entry() }; // Insert arguments let block_arg_vals = fun.fun.block_args(block); assert!(block_arg_vals.len() == args.len()); for (v, t) in block_arg_vals.iter().zip(args.iter()) { self.binds.insert(*v, t.clone()); } // Execute operation Some(self.run_erlang_op(vm, fun, block)) } else { None } } fn make_const_term(&self, fun: &ErlangFunction, const_val: Const) -> Rc { match fun.fun.cons().const_kind(const_val) { ConstKind::Atomic(AtomicTerm::Atom(atom)) => Term::Atom(atom.0).into(), ConstKind::Atomic(AtomicTerm::Int(int)) => Term::Integer(int.0.into()).into(), ConstKind::Atomic(AtomicTerm::BigInt(int)) => Term::Integer(int.0.clone()).into(), ConstKind::Atomic(AtomicTerm::Float(flt)) => Term::Float(flt.0.inner().into()).into(), ConstKind::Atomic(AtomicTerm::Binary(bin)) => { Term::Binary(Rc::new(bin.0.clone().into())).into() } ConstKind::Atomic(AtomicTerm::Nil) => Term::Nil.into(), ConstKind::ListCell { head, tail } => Term::ListCell( self.make_const_term(fun, *head), self.make_const_term(fun, *tail), ) .into(), ConstKind::Tuple { entries } => { let vec = entries .as_slice(&fun.fun.cons().const_pool) .iter() .map(|e| self.make_const_term(fun, *e)) .collect::>(); Term::Tuple(vec).into() } ConstKind::Map { keys, values } => { assert!( keys.len(&fun.fun.cons().const_pool) == values.len(&fun.fun.cons().const_pool) ); let mut map = MapTerm::new(); for (key, val) in keys .as_slice(&fun.fun.cons().const_pool) .iter() .zip(values.as_slice(&fun.fun.cons().const_pool).iter()) { let key_v = self.make_const_term(fun, *key); let val_v = self.make_const_term(fun, *val); map.insert(key_v, val_v); } Term::Map(map).into() } } } fn make_term(&self, fun: &ErlangFunction, value: Value) -> Rc { match fun.fun.value_kind(value) { ValueKind::Block(block) => { let live = &fun.live.live_at(block); let mut env = Vec::new(); for v in live.iter() { assert!(fun.fun.value_argument(v).is_some()); env.push(self.make_term(fun, v)); } Term::BoundLambda { ident: fun.fun.ident().clone(), block, environment: env, } .into() } ValueKind::Argument(_, _) => self.binds[&value].clone(), ValueKind::Const(cons) => self.make_const_term(fun, cons), ValueKind::PrimOp(prim) => { let reads = fun.fun.primop_reads(prim); match fun.fun.primop_kind(prim) { PrimOpKind::ValueList => { let terms: Vec<_> = reads.iter().map(|r| self.make_term(fun, *r)).collect(); Term::ValueList(terms).into() } PrimOpKind::Tuple => { let terms: Vec<_> = reads.iter().map(|r| self.make_term(fun, *r)).collect(); Term::Tuple(terms).into() } PrimOpKind::ListCell => { assert!(reads.len() == 2); let head = self.make_term(fun, reads[0]); let tail = self.make_term(fun, reads[1]); Term::ListCell(head, tail).into() } PrimOpKind::BinOp(BinOp::Equal) => { assert!(reads.len() == 2); let lhs = self.make_term(fun, reads[0]); let rhs = self.make_term(fun, reads[1]); Term::new_bool(lhs.erl_eq(&*rhs)).into() } PrimOpKind::LogicOp(LogicOp::And) => { let mut acc = true; for read in reads.iter() { let term = self.make_term(fun, *read); let res = term.as_boolean().unwrap(); acc = acc & res; } Term::new_bool(acc).into() } PrimOpKind::LogicOp(LogicOp::Or) => { let mut acc = false; for read in reads.iter() { let term = self.make_term(fun, *read); let res = term.as_boolean().unwrap(); acc = acc | res; } Term::new_bool(acc).into() } PrimOpKind::CaptureFunction => { let module = self.make_term(fun, reads[0]).as_atom().unwrap(); let name = self.make_term(fun, reads[1]).as_atom().unwrap(); let arity = self.make_term(fun, reads[2]).as_usize().unwrap(); let ident = FunctionIdent { module: Ident::with_empty_span(module), name: Ident::with_empty_span(name), arity, }; Term::CapturedFunction { ident }.into() } kind => unimplemented!("{:?}", kind), } } } } pub fn run_erlang_op(&mut self, _vm: &VMState, fun: &ErlangFunction, block: Block) -> TermCall { let reads = fun.fun.block_reads(block); println!("OP: {:?}", fun.fun.block_kind(block).unwrap()); match fun.fun.block_kind(block).unwrap() { OpKind::Call(_) => TermCall { fun: self.make_term(fun, reads[0]), args: reads .iter() .skip(1) .map(|r| self.make_term(fun, *r)) .collect(), }, OpKind::UnpackValueList(num) => { assert!(reads.len() == 2); let term = self.make_term(fun, reads[1]); match &*term { Term::ValueList(items) => { assert!(items.len() == *num); TermCall { fun: self.make_term(fun, reads[0]), args: items.clone(), } } _ => TermCall { fun: self.make_term(fun, reads[0]), args: vec![term], }, } } OpKind::IfBool => { let call_n = if reads.len() == 4 { let bool_term = self.make_term(fun, reads[3]); match bool_term.as_boolean() { Some(true) => 0, Some(false) => 1, None => 2, } } else if reads.len() == 3 { let bool_term = self.make_term(fun, reads[2]); match bool_term.as_boolean() { Some(true) => 0, Some(false) => 1, None => unreachable!(), } } else { unreachable!() }; TermCall { fun: self.make_term(fun, reads[call_n]), args: vec![], } } OpKind::TraceCaptureRaw => TermCall { fun: self.make_term(fun, reads[0]), args: vec![Term::Nil.into()], }, OpKind::Match { branches } => self::r#match::match_op(self, fun, branches, block), OpKind::Dyn(dyn_op) => { let tid = dyn_op.type_id(); match () { _ if tid == TypeId::of::() => TermCall { fun: self.make_term(fun, reads[0]), args: vec![Term::Binary(Default::default()).into()], }, _ if tid == TypeId::of::() => { let ok_cont = reads[0]; let err_cont = reads[1]; let bin_ref = reads[2]; let value = reads[3]; let size = reads.get(4); let bin_push = dyn_op.downcast_ref::().unwrap(); let specifier = bin_push.specifier; let bin_term = self.make_term(fun, bin_ref); let mut bin = match &*bin_term { Term::Binary(bin) => (**bin).clone(), Term::BinarySlice { buf, bit_offset, bit_length, } => { let slice = BitSlice::with_offset_length(&**buf, *bit_offset, *bit_length); let mut new = BitVec::new(); new.push(slice); new } _ => panic!(), }; let val_term = self.make_term(fun, reads[3]); assert!(reads.len() == 4 || reads.len() == 5); let size_term = reads.get(4).map(|r| self.make_term(fun, *r)); match specifier { BinaryEntrySpecifier::Integer { signed: _, unit, endianness, } => { let size = size_term.unwrap().as_usize().unwrap(); let bit_size = unit as usize * size; let endian = match endianness { Endianness::Big => Endian::Big, Endianness::Little => Endian::Little, Endianness::Native => Endian::Big, }; let val = val_term.as_integer().unwrap().clone(); let carrier = integer_to_carrier(val, bit_size, endian); bin.push(carrier); } BinaryEntrySpecifier::Float { endianness: Endianness::Big, unit, } => { let size = size_term.unwrap().as_usize().unwrap(); let bit_size = unit as usize * size; assert!(bit_size == 32 || bit_size == 64); let num = match &*val_term { Term::Float(flt) => flt.0, Term::Integer(int) => { let int_f = int.to_i64().unwrap(); int_f as f64 } _ => panic!(), }; match bit_size { 32 => bin.push(&num), 64 => bin.push(&num), _ => unreachable!(), } } BinaryEntrySpecifier::Bytes { unit: 1 } => { let binary = val_term.as_binary().unwrap(); if let Some(size_term) = size_term { dbg!(&size_term, &binary); assert!(size_term.as_usize().unwrap() == binary.len()); } bin.push(binary); } BinaryEntrySpecifier::Bits { unit: 1 } => { let binary = val_term.as_binary().unwrap(); // TODO validate size bin.push(binary); } k => unimplemented!("{:?}", k), } return TermCall { fun: self.make_term(fun, ok_cont), args: vec![Term::Binary(bin.into()).into()], }; } _ if tid == TypeId::of::() => { TermCall { fun: self.make_term(fun, reads[0]), args: vec![self.make_term(fun, reads[1])], } }, _ => unimplemented!(), } } //OpKind::BinaryPush { specifier } => { // let bin_term = self.make_term(fun, reads[2]); // let mut bin = match &*bin_term { // Term::Binary(bin) => (**bin).clone(), // Term::BinarySlice { buf, bit_offset, bit_length } => { // let slice = BitSlice::with_offset_length( // &**buf, *bit_offset, *bit_length); // let mut new = BitVec::new(); // new.push(slice); // new // } // _ => panic!(), // }; // let val_term = self.make_term(fun, reads[3]); // assert!(reads.len() == 4 || reads.len() == 5); // let size_term = reads.get(4).map(|r| self.make_term(fun, *r)); // match specifier { // BinaryEntrySpecifier::Integer { // signed: _, unit, endianness } => // { // let size = size_term.unwrap().as_usize().unwrap(); // let bit_size = *unit as usize * size; // let endian = match *endianness { // Endianness::Big => Endian::Big, // Endianness::Little => Endian::Little, // Endianness::Native => Endian::Big, // }; // let val = val_term.as_integer().unwrap().clone(); // let carrier = integer_to_carrier( // val, bit_size, endian); // bin.push(carrier); // } // BinaryEntrySpecifier::Float { // endianness: Endianness::Big, unit } => // { // let size = size_term.unwrap().as_usize().unwrap(); // let bit_size = *unit as usize * size; // assert!(bit_size == 32 || bit_size == 64); // let num = match &*val_term { // Term::Float(flt) => flt.0, // Term::Integer(int) => { // let int_f = int.to_i64().unwrap(); // int_f as f64 // } // _ => panic!(), // }; // match bit_size { // 32 => bin.push(&num), // 64 => bin.push(&num), // _ => unreachable!(), // } // } // BinaryEntrySpecifier::Bytes { unit: 1 } => { // let binary = val_term.as_binary().unwrap(); // if let Some(size_term) = size_term { // dbg!(&size_term, &binary); // assert!(size_term.as_usize().unwrap() == binary.len()); // } // bin.push(binary); // } // k => unimplemented!("{:?}", k), // } // return TermCall { // fun: self.make_term(fun, reads[0]), // args: vec![Term::Binary(bin.into()).into()], // }; //} OpKind::MapPut { action } => { let map_term = self.make_term(fun, reads[2]); println!("{:#?}", map_term); let mut map = map_term.as_map().unwrap().clone(); let mut idx = 3; for action in action.iter() { let key = self.make_term(fun, reads[idx]); let val = self.make_term(fun, reads[idx + 1]); idx += 2; let replaced = map.insert(key, val); if *action == MapPutUpdate::Update { assert!(replaced) } } TermCall { fun: self.make_term(fun, reads[0]), args: vec![Term::Map(map).into()], } } OpKind::Unreachable => { println!("==== Reached OpKind::Unreachable! ===="); println!("Fun: {} Block: {}", fun.fun.ident(), block); unreachable!(); } kind => unimplemented!("{:?}", kind), } } } pub struct ProcessContext { pub pid: Pid, pub dict: Vec<(Rc, Rc)>, } impl ProcessContext { pub fn new(pid: Pid) -> Self { ProcessContext { pid, dict: Vec::new(), } } } ================================================ FILE: libeir_interpreter/src/receive.rs ================================================ use ::term::Term; #[derive(Debug)] pub struct ReceiveContext { } impl ReceiveContext { pub fn new(timeout: Term) -> Self { // TODO: Timeout ReceiveContext { } } } ================================================ FILE: libeir_interpreter/src/term.rs ================================================ use std::cmp::{Ord, Ordering}; use std::collections::HashMap; use std::hash::{Hash, Hasher}; use std::rc::Rc; use libeir_intern::{LocalInternedString, Symbol}; use libeir_ir::{Block, FunctionIdent}; use libeir_util_binary::{BitSlice, BitVec}; use num_bigint::BigInt; use num_traits::cast::ToPrimitive; #[derive(Debug, Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Hash)] pub struct Pid(pub usize); #[derive(Debug, Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Hash)] pub struct Reference(pub usize); #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] pub enum TermType { Nil, Integer, Float, Atom, Tuple, ListCell, Map, Pid, Reference, Binary, BoundLambda, CapturedFunction, // Internal ValueList, ReturnOk, ReturnThrow, } #[derive(Debug, Copy, Clone, PartialOrd)] pub struct FloatTerm(pub f64); impl PartialEq for FloatTerm { fn eq(&self, other: &FloatTerm) -> bool { self.0.to_bits() == other.0.to_bits() } } impl Ord for FloatTerm { fn cmp(&self, other: &FloatTerm) -> Ordering { self.partial_cmp(other).unwrap() } } impl Eq for FloatTerm {} impl Hash for FloatTerm { fn hash(&self, state: &mut T) { self.0.to_bits().hash(state) } } impl From for FloatTerm { fn from(src: f64) -> Self { FloatTerm(src) } } #[derive(Debug, Clone)] pub struct MapTerm { map: HashMap, Rc>, sorted: Vec<(Rc, Rc)>, } impl MapTerm { pub fn new() -> MapTerm { MapTerm { map: HashMap::new(), sorted: Vec::new(), } } pub fn insert(&mut self, key: Rc, val: Rc) -> bool { self.map.insert(key.clone(), val.clone()); match self.sorted.binary_search_by(|(k, _)| k.cmp(&key)) { Ok(idx) => { self.sorted[idx] = (key, val); true } Err(idx) => { self.sorted.insert(idx, (key, val)); false } } } pub fn get(&self, key: &Rc) -> Option> { self.map.get(key).cloned() } pub fn len(&self) -> usize { self.map.len() } } impl PartialEq for MapTerm { fn eq(&self, other: &MapTerm) -> bool { self.sorted == other.sorted } } impl Eq for MapTerm {} impl PartialOrd for MapTerm { fn partial_cmp(&self, other: &MapTerm) -> Option { self.sorted.partial_cmp(&other.sorted) } } impl Ord for MapTerm { fn cmp(&self, other: &MapTerm) -> Ordering { self.partial_cmp(other).unwrap() } } impl Hash for MapTerm { fn hash(&self, state: &mut H) { self.sorted.hash(state) } } #[derive(Debug, Clone)] pub enum Term { Nil, Integer(BigInt), Float(FloatTerm), Atom(Symbol), Tuple(Vec>), ListCell(Rc, Rc), Map(MapTerm), Pid(Pid), Reference(Reference), Binary(Rc), BinarySlice { buf: Rc, bit_offset: usize, bit_length: usize, }, BoundLambda { ident: FunctionIdent, block: Block, environment: Vec>, }, CapturedFunction { ident: FunctionIdent, }, // Internal ValueList(Vec>), ReturnOk, ReturnThrow, } impl Term { fn order_idx(&self) -> usize { // number < atom < reference < fun < port < pid // < tuple < map < nil < list < bit string match self { Term::Integer(_) => 1, Term::Float(_) => 1, Term::Atom(_) => 2, Term::Reference(_) => 3, Term::BoundLambda { .. } => 4, Term::CapturedFunction { .. } => 4, //Term::Port(_) => 5, Term::Pid(_) => 6, Term::Tuple(_) => 7, Term::Map(_) => 8, Term::Nil => 9, Term::ListCell(_, _) => 10, Term::Binary(_) => 11, Term::BinarySlice { .. } => 11, _ => panic!(), } } } impl Eq for Term {} impl PartialEq for Term { fn eq(&self, other: &Self) -> bool { use Term::*; match (self, other) { (Nil, Nil) => true, (Integer(l), Integer(r)) => l == r, (Float(l), Float(r)) => l == r, (Atom(l), Atom(r)) => l == r, (Tuple(l), Tuple(r)) => l == r, (ListCell(lh, lt), ListCell(rh, rt)) => lh == rh && lt == rt, (Map(l), Map(r)) => l == r, (Pid(l), Pid(r)) => l == r, (Reference(l), Reference(r)) => l == r, (Binary(l), Binary(r)) => l == r, ( Binary(l), BinarySlice { buf, bit_offset, bit_length, }, ) => { let rs = BitSlice::with_offset_length(&**buf, *bit_offset, *bit_length); &**l == &rs } ( BinarySlice { buf, bit_offset, bit_length, }, Binary(r), ) => { let ls = BitSlice::with_offset_length(&**buf, *bit_offset, *bit_length); &ls == &**r } ( BinarySlice { buf: lb, bit_offset: lo, bit_length: ll, }, BinarySlice { buf: rb, bit_offset: ro, bit_length: rl, }, ) => { let ls = BitSlice::with_offset_length(&**lb, *lo, *ll); let rs = BitSlice::with_offset_length(&**rb, *ro, *rl); &ls == &rs } ( BoundLambda { ident: li, block: lb, environment: le, }, BoundLambda { ident: ri, block: rb, environment: re, }, ) => li == ri && lb == rb && le == re, (CapturedFunction { ident: li }, CapturedFunction { ident: ri }) => li == ri, (ValueList(l), ValueList(r)) => l == r, (ReturnOk, ReturnOk) => true, (ReturnThrow, ReturnThrow) => true, _ => false, } } } impl Ord for Term { fn cmp(&self, other: &Self) -> Ordering { self.partial_cmp(other).unwrap() } } impl PartialOrd for Term { fn partial_cmp(&self, other: &Self) -> Option { use Term::*; match (self, other) { (Nil, Nil) => Some(Ordering::Equal), (Integer(l), Integer(r)) => l.partial_cmp(r), (Float(l), Float(r)) => l.partial_cmp(r), (Atom(l), Atom(r)) => l.partial_cmp(r), (Tuple(l), Tuple(r)) => l.partial_cmp(r), (ListCell(lh, lt), ListCell(rh, rt)) => match lh.partial_cmp(rh) { Some(Ordering::Equal) | None => lt.partial_cmp(rt), non_eq => non_eq, }, (Map(l), Map(r)) => l.partial_cmp(r), (Pid(l), Pid(r)) => l.partial_cmp(r), (Reference(l), Reference(r)) => l.partial_cmp(r), (Binary(l), Binary(r)) => l.partial_cmp(r), ( Binary(l), BinarySlice { buf, bit_offset, bit_length, }, ) => { let rs = BitSlice::with_offset_length(&**buf, *bit_offset, *bit_length); (&**l).partial_cmp(&rs) } ( BinarySlice { buf, bit_offset, bit_length, }, Binary(r), ) => { let ls = BitSlice::with_offset_length(&**buf, *bit_offset, *bit_length); ls.partial_cmp(&**r) } ( BinarySlice { buf: lb, bit_offset: lo, bit_length: ll, }, BinarySlice { buf: rb, bit_offset: ro, bit_length: rl, }, ) => { let ls = BitSlice::with_offset_length(&**lb, *lo, *ll); let rs = BitSlice::with_offset_length(&**rb, *ro, *rl); ls.partial_cmp(&rs) } ( BoundLambda { ident: li, block: lb, environment: le, }, BoundLambda { ident: ri, block: rb, environment: re, }, ) => match li.partial_cmp(ri) { Some(Ordering::Equal) | None => match lb.partial_cmp(rb) { Some(Ordering::Equal) | None => le.partial_cmp(re), non_eq => non_eq, }, non_eq => non_eq, }, (CapturedFunction { ident: li }, CapturedFunction { ident: ri }) => li.partial_cmp(ri), (ValueList(l), ValueList(r)) => l.partial_cmp(r), (ReturnOk, ReturnOk) => Some(Ordering::Equal), (ReturnThrow, ReturnThrow) => Some(Ordering::Equal), (l, r) => l.order_idx().partial_cmp(&r.order_idx()), } } } impl Hash for Term { fn hash(&self, state: &mut H) { use Term::*; self.get_type().hash(state); match self { Nil => (), Integer(i) => i.hash(state), Float(f) => f.hash(state), Atom(a) => a.hash(state), Tuple(t) => t.hash(state), ListCell(h, t) => { h.hash(state); t.hash(state); } Map(t) => t.hash(state), Pid(t) => t.hash(state), Reference(t) => t.hash(state), Binary(t) => t.hash(state), BinarySlice { buf, bit_offset, bit_length, } => { let ls = BitSlice::with_offset_length(&**buf, *bit_offset, *bit_length); ls.hash(state); } BoundLambda { ident, block, environment, } => { ident.hash(state); block.hash(state); environment.hash(state); } CapturedFunction { ident } => ident.hash(state), ValueList(i) => i.hash(state), ReturnOk => (), ReturnThrow => (), } } } impl From for Term { fn from(num: i64) -> Self { Term::Integer(num.into()) } } pub enum ListIteratorItem { Elem(Rc), Tail(Rc), } pub struct ListTermIterator { term: Option>, } impl Iterator for ListTermIterator { type Item = ListIteratorItem; fn next(&mut self) -> Option { if let Some(term) = self.term.take() { match &*term { Term::ListCell(head, tail) => { self.term = Some(tail.clone()); Some(ListIteratorItem::Elem(head.clone())) } _ => { self.term = None; Some(ListIteratorItem::Tail(term.clone())) } } } else { None } } } impl Term { pub fn new_i64(num: i64) -> Self { Term::Integer(num.into()) } pub fn new_usize(num: usize) -> Self { Term::Integer(num.into()) } pub fn new_atom(string: &str) -> Self { Term::Atom(Symbol::intern(string)) } pub fn new_bool(val: bool) -> Self { if val { Term::new_atom("true") } else { Term::new_atom("false") } } pub fn slice_to_list(head: &[Rc], tail: Rc) -> Rc { let mut acc = tail; for term in head.iter().rev() { acc = Term::ListCell(term.clone(), acc).into(); } acc } fn extend_erl_string(&self, buf: &mut String) -> bool { match self { Term::Integer(val) => { buf.push(val.to_u8().unwrap() as char); true } Term::ListCell(_head, _tail) => { unimplemented!() //for item in head { // if !item.extend_erl_string(buf) { // return false; // } //} //return tail.extend_erl_string(buf); } Term::Nil => true, _ => false, } } pub fn get_erl_string(&self) -> Option { let mut buf = String::new(); if self.extend_erl_string(&mut buf) { Some(buf) } else { None } } pub fn atom_str<'a>(&'a self) -> LocalInternedString { if let Term::Atom(ref atom) = *self { atom.as_str() } else { panic!(); } } pub fn is_nil(&self) -> bool { match self { Term::Nil => true, _ => false, } } pub fn get_type(&self) -> TermType { match self { Term::Binary(_) => TermType::Binary, Term::BinarySlice { .. } => TermType::Binary, Term::Nil => TermType::Nil, Term::Pid(_) => TermType::Pid, Term::Reference(_) => TermType::Reference, Term::Integer(_) => TermType::Integer, Term::Float(_) => TermType::Float, Term::Atom(_) => TermType::Atom, Term::Tuple(_) => TermType::Tuple, Term::ListCell(_, _) => TermType::ListCell, Term::Map(_) => TermType::Map, Term::BoundLambda { .. } => TermType::BoundLambda, Term::CapturedFunction { .. } => TermType::CapturedFunction, Term::ValueList(_) => TermType::ValueList, Term::ReturnOk => TermType::ReturnOk, Term::ReturnThrow => TermType::ReturnThrow, } } pub fn as_boolean(&self) -> Option { if let Term::Atom(ref val) = self { let is_truthy = *val == Symbol::intern("true"); let is_falsey = *val == Symbol::intern("false"); if is_truthy ^ is_falsey { Some(is_truthy) } else { None } } else { None } } pub fn as_i64(&self) -> Option { if let Term::Integer(ref bigint) = self { Some(bigint.to_i64().unwrap()) } else { None } } pub fn as_usize(&self) -> Option { if let Term::Integer(ref bigint) = self { Some(bigint.to_usize().unwrap()) } else { None } } pub fn as_integer(&self) -> Option<&BigInt> { if let Term::Integer(ref bigint) = self { Some(bigint) } else { None } } pub fn as_atom(&self) -> Option { if let Term::Atom(ref atom) = self { Some(atom.clone()) } else { None } } pub fn as_tuple(&self) -> Option<&[Rc]> { if let Term::Tuple(tup) = self { Some(tup) } else { None } } pub fn as_binary(&self) -> Option<&BitVec> { if let Term::Binary(bin) = self { Some(bin) } else { None } } pub fn as_map(&self) -> Option<&MapTerm> { if let Term::Map(bin) = self { Some(bin) } else { None } } pub fn list_iter(term: &Rc) -> ListTermIterator { ListTermIterator { term: Some(term.clone()), } } //fn join_list(&self, list: &mut Vec>) -> Term { // match self { // Term::ListCell(head, tail) => { // list.extend(head.iter().cloned()); // tail.join_list(list) // } // _ => self.clone() // } //} pub fn as_inproper_list(term: &Rc) -> (Vec>, Rc) { let mut list = Vec::new(); for item in Term::list_iter(term) { match item { ListIteratorItem::Elem(elem) => list.push(elem), ListIteratorItem::Tail(tail) => return (list, tail), } } unreachable!() } pub fn as_list(term: &Rc) -> Option>> { let (list, tail) = Term::as_inproper_list(term); if let Term::Nil = &*tail { Some(list) } else { None } } pub fn as_value_list(term: &Rc) -> Vec> { match &**term { Term::ValueList(val) => val.clone(), _ => vec![term.clone()], } } pub fn to_doc(_term: Rc) -> pretty::Doc<'static, pretty::BoxDoc<'static>> { unimplemented!() //use pretty::{ Doc }; //match &*term { // Term::Nil => Doc::text("[]"), // Term::Integer(int) => Doc::text(int.to_string()), // Term::Float(num) => Doc::text(num.0.to_string()), // Term::Atom(atom) => Doc::text(atom.to_string()), // Term::Tuple(items) => { // let docs: Vec<_> = items.iter().map(|i| Term::to_doc(i.clone())).collect(); // Doc::text("{") // .append(Doc::intersperse(docs, Doc::text(","))) // .append(Doc::text("}")) // }, // Term::ListCell(_, _) => { // let (head, tail) = Term::as_inproper_list(&term); // let head_docs: Vec<_> = head.iter().map(|i| Term::to_doc(i.clone())).collect(); // let tail_doc = Term::to_doc(tail); // Doc::text("[") // .append(Doc::intersperse(head_docs, Doc::text(","))) // .append(Doc::text("|")) // .append(tail_doc) // .append(Doc::text("]")) // }, // //Term::ListCell(head, tail) if head.len() == 0 => tail.to_doc(), // //Term::ListCell(head, tail) => { // // let head_docs: Vec<_> = head.iter().map(|i| i.to_doc()).collect(); // // let tail_doc = tail.to_doc(); // // Doc::text("[") // // .append(Doc::intersperse(head_docs, Doc::text(","))) // // .append(Doc::text("|")) // // .append(tail_doc) // // .append(Doc::text("]")) // //}, // Term::Map(map) => { // let entries_doc: Vec<_> = map.sorted.iter() // .map(|(k, v)| { // Doc::group( // Term::to_doc(k.clone()) // .append(Doc::text("=>")) // .append(Term::to_doc(v.clone())) // ) // }).collect(); // Doc::text("%{") // .append(Doc::intersperse(entries_doc, Doc::text(","))) // .append(Doc::text("}")) // }, // Term::Pid(pid) => Doc::text(format!("Pid<{}>", pid.0)), // Term::Reference(refe) => Doc::text(format!("Reference<{}>", refe.0)), // Term::Binary(bin) => { // if let Some(slice) = bin.try_as_byte_aligned_slice() { // if let Ok(utf) = std::str::from_utf8(slice) { // return Doc::text("\"") // .append(Doc::text(utf.to_string())) // .append(Doc::text("\"")); // } // } // // TODO bit length // let items: Vec<_> = bin.iter_bytes() // .map(|v| Doc::text(v.to_string())) // .collect(); // Doc::text("<") // .append(Doc::intersperse(items, Doc::text(","))) // .append(Doc::text(">")) // }, // Term::BinarySlice { buf, bit_offset, bit_length } => { // if bit_length % 8 == 0 { // let from = BitSlice::with_offset_length( // &**buf, *bit_offset, *bit_length); // let byte_len = bit_length / 8; // let mut bin = vec![0; byte_len]; // bit_copy(&from, &mut bin as &mut [u8]); // if let Ok(utf) = std::str::from_utf8(&bin) { // return Doc::text("\"") // .append(Doc::text(utf.to_string())) // .append(Doc::text("\"")); // } else { // let items: Vec<_> = bin.iter() // .map(|v| Doc::text(v.to_string())) // .collect(); // Doc::text("<") // .append(Doc::intersperse(items, Doc::text(","))) // .append(Doc::text(">")) // } // } else { // let items: Vec<_> = buf.iter_words() // .map(|v| Doc::text(v.to_string())) // .collect(); // Doc::text("<") // .append(Doc::intersperse(items, Doc::text(","))) // .append(Doc::text(">")) // } // }, // Term::BoundLambda { ident, block, .. } => { // Doc::text(format!("Bound<{}:{}/{}@{}>", ident.module.name, ident.name.name, // ident.arity, block)) // }, // Term::CapturedFunction { ident } => { // Doc::text(format!("Captured<{}:{}/{}>", ident.module.name, ident.name.name, ident.arity)) // }, // Term::ValueList(items) => { // let docs: Vec<_> = items.iter().map(|i| Term::to_doc(i.clone())).collect(); // Doc::text("<") // .append(Doc::intersperse(docs, Doc::text(","))) // .append(Doc::text(">")) // } // Term::ReturnOk => { // Doc::text(format!("ReturnOk")) // } // Term::ReturnThrow => { // Doc::text(format!("ReturnThrow")) // } //} } } pub trait ErlEq { fn erl_eq(&self, other: &Rhs) -> bool; } pub trait ErlExactEq { fn erl_exact_eq(&self, other: &Rhs) -> bool; } pub trait ErlOrd { fn erl_ord(&self, other: &Rhs) -> ::std::cmp::Ordering; } impl ErlEq for f64 { fn erl_eq(&self, other: &f64) -> bool { (*self) == (*other) } } impl ErlEq for Term { fn erl_eq(&self, other: &Term) -> bool { match (self, other) { (Term::BoundLambda { .. }, _) => unreachable!(), (_, Term::BoundLambda { .. }) => unreachable!(), (Term::ValueList(_), _) => unimplemented!(), (_, Term::ValueList(_)) => unimplemented!(), (Term::Nil, Term::Nil) => true, (Term::ListCell(h1, t1), Term::ListCell(h2, t2)) => h1.erl_eq(h2) && t1.erl_eq(t2), //(Term::List(h1, t1), Term::Nil) if h1.len() == 0 => // if let Term::Nil = **t1 { true } else { false }, //(Term::Nil, Term::List(h2, t2)) if h2.len() == 0 => // if let Term::Nil = **t2 { true } else { false }, //(Term::List(h1, t1), Term::List(h2, t2)) => { // let head_ok = h1.iter().zip(h2.iter()) // .all(|(v1, v2)| v1.erl_eq(v2)); // if !head_ok { return false; } // if h1.len() == h2.len() { // t1.erl_eq(t2) // } else if h1.len() > h2.len() { // let h1_new_head: Vec<_> = h1.iter().skip(h2.len()) // .cloned().collect(); // let h1_new = Term::List(h1_new_head, t1.clone()); // h1_new.erl_eq(t2) // } else { // let h2_new_head: Vec<_> = h2.iter().skip(h1.len()) // .cloned().collect(); // let h2_new = Term::List(h2_new_head, t2.clone()); // t1.erl_eq(&h2_new) // } //} (Term::Nil, _) => false, (_, Term::Nil) => false, (Term::Integer(ref i1), Term::Integer(ref i2)) => i1 == i2, (Term::Float(ref f1), Term::Float(ref f2)) => f1 == f2, (Term::Integer(_), Term::Float(_)) => unimplemented!(), (Term::Float(_), Term::Integer(_)) => unimplemented!(), (Term::Atom(ref a1), Term::Atom(ref a2)) => a1 == a2, (Term::Tuple(ref v1), Term::Tuple(ref v2)) => { v1.iter().zip(v2).all(|(e1, e2)| e1.erl_eq(e2)) } ( Term::CapturedFunction { ident: ref ident1 }, Term::CapturedFunction { ident: ref ident2 }, ) => ident1 == ident2, _ => { //crate::trace::warning_args( // "WARNING: ErlEq might be unimplemented".to_string(), // || { // let mut event_args = std::collections::HashMap::new(); // event_args.insert( // "lhs".to_string(), // ::serde_json::Value::String(format!("{:?}", self)) // ); // event_args.insert( // "rhs".to_string(), // ::serde_json::Value::String(format!("{:?}", other)) // ); // event_args // } //); println!("WARNING: ErlEq might be unimplemented"); println!(" {:?} == {:?}", self, other); false } } } } impl ErlExactEq for Term { fn erl_exact_eq(&self, other: &Term) -> bool { self == other } } impl ErlOrd for Term { fn erl_ord(&self, other: &Term) -> ::std::cmp::Ordering { match (self, other) { (Term::Integer(val1), Term::Integer(val2)) => val1.cmp(val2), //(Term::Float(val1), Term::Float(val2)) => // val1.cmp(val2), (_, _) => unimplemented!(), } } } ================================================ FILE: libeir_interpreter/src/trace/dummy.rs ================================================ use std::rc::Rc; use std::collections::HashMap; use crate::term::{ Term, Pid }; use libeir_ir::{ FunctionIdent, Block }; pub fn set_pid(_pid: Pid) {} pub fn enter_function(_ident: &FunctionIdent, _lambda: Option, _args: &[Rc]) {} //pub fn exit_function(ident: &FunctionIdent, ret: Option<&CallReturn>) {} //pub fn start_basic_block(module: &Atom, ident: &FunctionIdent, block: LabelN) { //pub fn end_basic_block() { pub fn warning(_text: String) {} pub fn warning_args(_text: String, _make_args: F) where F: FnOnce() -> HashMap {} ================================================ FILE: libeir_interpreter/src/trace/mod.rs ================================================ //#[cfg(not(feature = "trace"))] //#[macro_use] mod dummy; //#[cfg(not(feature = "trace"))] use self::dummy as trace; //#[cfg(feature = "trace")] //#[macro_use] //mod trace; pub use self::trace::*; ================================================ FILE: libeir_interpreter/src/trace/trace.rs ================================================ use std::rc::Rc; use crate::term::{ Term, Pid }; use libeir_ir::{ FunctionIdent, Block, Value }; use libeir_intern::Symbol; use std::sync::{ Mutex, RwLock }; use std::collections::HashMap; use std::borrow::BorrowMut; use ::serde::{ Serialize }; #[derive(Serialize)] #[serde(tag = "ph")] enum TraceEntry { #[serde(rename = "B")] DurationStart { name: String, #[serde(rename = "cat")] categories: String, #[serde(rename = "ts")] timestamp: u64, pid: u64, tid: u64, cname: Option, args: HashMap, }, #[serde(rename = "E")] DurationEnd { #[serde(rename = "ts")] timestamp: u64, pid: u64, tid: u64, args: HashMap, }, #[serde(rename = "i")] Instant { name: String, #[serde(rename = "ts")] timestamp: u64, pid: u64, tid: u64, #[serde(rename = "s")] scope: &'static str, args: HashMap, } } lazy_static::lazy_static! { static ref VM_ID_COUNTER: Mutex = Mutex::new(0); } std::thread_local! { static VM_ID: RwLock> = RwLock::new(None); static TRACE_COLLECTOR: Mutex = Mutex::new(TraceCollector::new()); } pub fn gen_vm_id() { let counter = VM_ID_COUNTER.lock().unwrap(); VM_ID.with(|v| { let mut vm_id = v.write().unwrap(); *vm_id = Some(*counter); }); } fn vm_id() -> usize { VM_ID.with(|v| { v.read().unwrap().unwrap() }) } struct StackEntry { pid: Pid, module: Symbol, ident: FunctionIdent, args: Vec, } struct TraceEvent { pid: Pid, typ: TraceEventType, } enum TraceEventType { FunctionEnter { ident: FunctionIdent, lambda: Option, args: Vec>, }, FunctionTailCall, FunctionReturn { kind: usize, ret: Rc, }, BlockStart { ident: FunctionIdent, block: Block, }, BlockEnd, Warning { text: String, args: HashMap, }, } struct TraceCollector { current_pid: Pid, pid_stacks: HashMap>, events: Vec, } impl TraceCollector { fn new() -> Self { TraceCollector { current_pid: Pid(0), pid_stacks: HashMap::new(), events: Vec::new(), } } } pub fn set_pid(pid: Pid) { TRACE_COLLECTOR.with(|c| { let mut c = c.lock().unwrap(); c.current_pid = pid; }) } pub fn get_pid() -> Pid { TRACE_COLLECTOR.with(|c| { let c = c.lock().unwrap(); c.current_pid }) } pub fn enter_function(ident: &FunctionIdent, lambda: Option, args: &[Rc]) { TRACE_COLLECTOR.with(|c| { let mut c = c.lock().unwrap(); let pid = c.current_pid; if !c.pid_stacks.contains_key(&pid) { c.pid_stacks.insert(pid, Vec::new()); } { let stack = c.pid_stacks.get_mut(&pid).unwrap(); stack.push(StackEntry { pid: pid, module: module.clone(), ident: ident.clone(), args: args.to_vec(), }); } c.events.push(TraceEvent { pid: pid, typ: TraceEventType::FunctionEnter { ident: ident.clone(), args: args.to_vec(), }, }); }) } pub fn exit_function(ident: &FunctionIdent, ret: Option<&CallReturn>) { TRACE_COLLECTOR.with(|c| { let mut c = c.lock().unwrap(); let pid = c.current_pid; { let stack = c.pid_stacks.get_mut(&pid).unwrap(); let removed = stack.pop().unwrap(); assert!(&removed.module == module); assert!(&removed.ident == ident); } c.events.push(TraceEvent { pid: pid, typ: TraceEventType::FunctionExit { ret: ret.cloned(), }, }); }) } pub fn start_basic_block(module: &Atom, ident: &FunctionIdent, block: LabelN) { TRACE_COLLECTOR.with(|c| { let mut c = c.lock().unwrap(); let pid = c.current_pid; c.events.push(TraceEvent{ pid: pid, typ: TraceEventType::BasicBlockStart { module: module.clone(), ident: ident.clone(), block: block, }, }); }) } pub fn end_basic_block() { TRACE_COLLECTOR.with(|c| { let mut c = c.lock().unwrap(); let pid = c.current_pid; c.events.push(TraceEvent{ pid: pid, typ: TraceEventType::BasicBlockEnd, }); }) } pub fn warning(text: String) { TRACE_COLLECTOR.with(|c| { let mut c = c.lock().unwrap(); let pid = c.current_pid; c.events.push(TraceEvent { pid: pid, typ: TraceEventType::Warning { text: text, args: HashMap::new(), } }); }) } pub fn warning_args(text: String, make_args: F) where F: FnOnce() -> HashMap { TRACE_COLLECTOR.with(|c| { let mut c = c.lock().unwrap(); let pid = c.current_pid; c.events.push(TraceEvent { pid: pid, typ: TraceEventType::Warning { text: text, args: (make_args)() } }); }) } pub fn dump_trace(filename: String) { let json = TRACE_COLLECTOR.with(|c| { let c = c.lock().unwrap(); let mut idx = 0; let json_events: Vec<_> = c.events.iter() .map(|event| { match &event.typ { TraceEventType::FunctionEnter { ident, args, .. } => { let mut event_args = HashMap::new(); let fun_args: Vec<_> = args.iter() .map(|a| ::serde_json::Value::String( format!("{}", a.to_doc().pretty(40)))) .collect(); event_args.insert( "Call Arguments".to_string(), ::serde_json::Value::Array(fun_args) ); TraceEntry::DurationStart { timestamp: idx as u64, pid: event.pid.0 as u64, tid: 0, cname: None, args: event_args, name: format!("{}", ident), categories: "".to_string(), } } TraceEventType::FunctionExit { ret } => { if ret.is_some() { idx += 1; } let mut event_args = HashMap::new(); event_args.insert( "Call Return".to_string(), match ret { None => ::serde_json::Value::String( "TailCall".to_string()), Some(CallReturn::Return{ term: val }) => ::serde_json::Value::String( format!("{}", val.to_doc().pretty(40))), Some(CallReturn::Throw) => ::serde_json::Value::String("Throw".to_string()), } ); TraceEntry::DurationEnd { timestamp: idx as u64, pid: event.pid.0 as u64, tid: 0, args: event_args, } } TraceEventType::BasicBlockStart { module, ident, block } => { TraceEntry::DurationStart { timestamp: idx as u64, pid: event.pid.0 as u64, tid: 1, cname: None, args: HashMap::new(), name: format!("{} ({}:{})", block, module, ident), categories: "".to_string(), } } TraceEventType::BasicBlockEnd => { idx += 1; TraceEntry::DurationEnd { timestamp: idx as u64, pid: event.pid.0 as u64, tid: 1, args: HashMap::new(), } } TraceEventType::Warning { text, args } => { TraceEntry::Instant { name: text.clone(), timestamp: idx as u64, pid: event.pid.0 as u64, tid: 0, scope: "p", args: args.clone(), } } } }).collect(); serde_json::to_string(&json_events) }); ::std::fs::write(filename, json.unwrap()).unwrap(); } ================================================ FILE: libeir_interpreter/src/vm.rs ================================================ use std::cell::RefCell; use std::collections::HashMap; use std::rc::Rc; use crate::module::{ErlangModule, ModuleType, NativeModule}; use crate::process::{CallExecutor, Continuation, ProcessContext, TermCall}; use crate::term::{Pid, Reference, Term}; use libeir_intern::Symbol; use libeir_ir::{FunctionIdent, Module}; #[derive(Debug, Clone, Copy, Eq, PartialEq)] pub enum WatchType { Link, Monitor(Reference), } #[derive(Debug)] pub struct ReferenceGenerator(Reference); impl ReferenceGenerator { fn new() -> Self { ReferenceGenerator(Reference(0)) } pub fn next(&mut self) -> Reference { let r = self.0; (self.0).0 += 1; r } } pub struct VMState { pub modules: HashMap, pub processes: RefCell>>>, pub ref_gen: RefCell, // Hashmap of all watches a process has placed on it. //pub watches: RefCell>>, //pub mailboxes: RefCell>, } impl VMState { pub fn new() -> Self { VMState { modules: HashMap::new(), processes: RefCell::new(Vec::new()), ref_gen: RefCell::new(ReferenceGenerator::new()), //watches: RefCell::new(HashMap::new()), //mailboxes: RefCell::new(HashMap::new()), } } pub fn add_erlang_module(&mut self, module: Module) { let erl_mod = ErlangModule::from_eir(module); match self.modules.remove(&erl_mod.name) { None => { self.modules .insert(erl_mod.name, ModuleType::Erlang(erl_mod, None)); } Some(ModuleType::Native(native)) => { self.modules .insert(erl_mod.name, ModuleType::Erlang(erl_mod, Some(native))); } _ => panic!(), } } pub fn add_native_module(&mut self, module: NativeModule) { match self.modules.remove(&module.name) { None => { self.modules.insert(module.name, ModuleType::Native(module)); } Some(ModuleType::Erlang(erl, None)) => { self.modules .insert(module.name, ModuleType::Erlang(erl, Some(module))); } _ => panic!(), } } pub fn add_nif_overlay(&mut self, module: NativeModule) { let existing = self.modules.get_mut(&module.name).unwrap(); if let ModuleType::Erlang(_, ref mut overlay) = existing { assert!(overlay.is_none()); *overlay = Some(module); } else { panic!(); } } pub fn add_builtin_modules(&mut self) { self.add_native_module(crate::erl_lib::make_erlang()); self.add_native_module(crate::erl_lib::make_lists()); self.add_native_module(crate::erl_lib::make_math()); self.add_native_module(crate::erl_lib::make_maps()); } pub fn call( &mut self, fun: &FunctionIdent, args: &[Term], ) -> Result, (Rc, Rc, Rc)> { let self_pid = { let processes = self.processes.borrow(); Pid(processes.len()) }; let mut process = ProcessContext::new(self_pid); let fun_term = Term::CapturedFunction { ident: fun.clone() }; let mut n_args = Vec::new(); n_args.push(Term::ReturnOk.into()); n_args.push(Term::ReturnThrow.into()); n_args.extend(args.iter().cloned().map(|v| v.into())); let mut continuation = TermCall { fun: fun_term.into(), args: n_args, }; let mut executor = CallExecutor::new(); loop { match executor.run(self, &mut process, continuation) { Continuation::Term(call) => continuation = call, Continuation::ReturnOk(ret) => return Ok(ret), Continuation::ReturnThrow(r1, r2, r3) => return Err((r1, r2, r3)), } } } //pub fn call(&mut self, module_name: &str, fun_name: &str, args: Vec) // -> CallReturn { // let fun_ident = FunctionIdent { // module: Atom::from_str(module_name), // name: Atom::from_str(fun_name), // arity: args.len(), // lambda: None, // }; // let self_pid = { // let processes = self.processes.borrow(); // Pid(processes.len()) // }; // ::trace::set_pid(self_pid); // let process = ProcessContext::new(self_pid); // let frame = process.make_call_stackframe( // self, // Atom::from_str(module_name), // fun_ident, // args // ); // { // let mut processes = self.processes.borrow_mut(); // { // let mut stack = process.stack.borrow_mut(); // stack.push(frame); // } // processes.push(Rc::new(RefCell::new(process))); // } // { // let mut mailboxes = self.mailboxes.borrow_mut(); // mailboxes.insert(self_pid, ::mailbox::Mailbox::new()); // } // loop { // let processes_len = self.processes.borrow().len(); // for process_num in 0..processes_len { // println!("====================================="); // println!("======== SWITCH TO PROCESS {} ========", process_num); // println!("====================================="); // ::trace::set_pid(Pid(process_num)); // let process_rc = self.processes.borrow()[process_num].clone(); // let mut process = process_rc.borrow_mut(); // process.run_reductions(self, 4000); // } // let processes_borrow = self.processes.borrow(); // let process_borrow = processes_borrow[self_pid.0].borrow(); // if process_borrow.stack.borrow().len() == 0 { // break; // } // } // let processes_borrow = self.processes.borrow(); // let mut process = processes_borrow[self_pid.0].borrow_mut(); // process.return_val.take().unwrap() //} } ================================================ FILE: libeir_ir/Cargo.toml ================================================ [package] name = "libeir_ir" version = "0.1.0" authors = ["Hans Elias B. Josephsen "] edition = "2018" build = "build.rs" license = "MIT OR Apache-2.0" [features] binary_serialization = ["bincode"] [dependencies] libeir_intern = { path = "../libeir_intern" } libeir_diagnostics = { path = "../libeir_diagnostics" } libeir_util_datastructures = { path = "../util/libeir_util_datastructures" } libeir_util_parse = { path = "../util/libeir_util_parse" } libeir_util_number = { path = "../util/libeir_util_number" } libeir_util_binary = { path = "../util/libeir_util_binary" } libeir_util_dot_graph = { path = "../util/libeir_util_dot_graph" } meta_table = { path = "../util/meta_table" } stack_dst = { version = "0.6.0", features = ["unsize"] } string-intern = { version = "0.1.7", default-features = false } pretty = "0.7" lazy_static = "1.2.0" itertools = "0.8.0" log = "0.4" cranelift-entity = "0.56.0" cranelift-bforest = { git = "https://github.com/hansihe/wasmtime.git", branch = "main" } bumpalo = { git = "https://github.com/hansihe/bumpalo", branch = "master", features = ["nightly"] } petgraph = "0.4" matches = "0.1.8" regex = "1" serde = { version = "1.0", features = ["derive"] } bincode = { version = "1.1", optional = true } lalrpop-util = "0.17" snafu = "0.5" fnv = "1.0.3" hashbrown = { git = "https://github.com/rust-lang/hashbrown.git", features = ["raw", "nightly"] } [dev-dependencies] pretty_assertions = "0.6" [build-dependencies] lalrpop = "0.17" #[dependencies.rug] #version = "1.2" #default-features = false #features = ["integer", "float", "rand"] ================================================ FILE: libeir_ir/build.rs ================================================ extern crate lalrpop; fn main() { lalrpop::Configuration::new() .use_cargo_dir_conventions() .process_file("src/text/parser/grammar.lalrpop") .unwrap(); println!("cargo:rerun-if-changed=src/text/parser/grammar.lalrpop"); } ================================================ FILE: libeir_ir/src/algo/equality.rs ================================================ use std::collections::{BTreeMap, VecDeque}; use snafu::Snafu; use crate::Function; use crate::ValueKind; use crate::{Block, Const, Location, PrimOp, Value}; #[derive(Snafu, Debug, PartialEq, Eq)] pub enum EqualityFail { BlockArity { left: Block, right: Block, }, BlockOp { left: Block, right: Block, }, BlockReadsLength { left: Block, right: Block, }, MismatchingValue { left: Value, right: Value, }, PrimReadsLength { left: PrimOp, right: PrimOp, }, MismatchingConst { left: Const, right: Const, }, MismatchingBlockLocation { left_block: Block, right_block: Block, left_loc: Location, right_loc: Location, left_desc: String, right_desc: String, }, } struct EqCtx<'a> { lf: &'a Function, rf: &'a Function, to_walk: VecDeque<(Block, Block)>, to_check: Vec<(Value, Value)>, map: BTreeMap, } #[derive(Debug, Copy, Clone)] pub struct GraphEqOptions { pub check_block_locations: bool, } impl Default for GraphEqOptions { fn default() -> Self { GraphEqOptions { check_block_locations: false, } } } impl Function { pub fn graph_eq_opts( &self, lhs_block: Block, rhs: &Function, rhs_block: Block, opts: &GraphEqOptions, ) -> Result<(), EqualityFail> { let mut ctx = EqCtx { lf: self, rf: rhs, map: BTreeMap::new(), to_walk: VecDeque::new(), to_check: Vec::new(), }; // 1. // Walk block graph and validate basic cfg isomorphism. // We can't just use normal block graph DFS when iterating here // because search order is not defined. // In this case we need to discover the mapping between blocks // in the two block scopes we are comparing, so order of values // is critical. ctx.to_walk.push_back((lhs_block, rhs_block)); ctx.map .insert(ctx.lf.block_value(lhs_block), ctx.rf.block_value(rhs_block)); while let Some((l_b, r_b)) = ctx.to_walk.pop_front() { // The mapping for the blocks should always have been created // when inserting it into the `to_walk` list. let l_block_val = ctx.lf.block_value(l_b); let r_block_val = ctx.rf.block_value(r_b); debug_assert_eq!(ctx.map.get(&l_block_val), Some(&r_block_val)); // Insert mappings between the block args. let l_args = ctx.lf.block_args(l_b); let r_args = ctx.rf.block_args(r_b); if l_args.len() != r_args.len() { return Result::Err(EqualityFail::BlockArity { left: l_b, right: r_b, }); } for (l, r) in l_args.iter().zip(r_args.iter()) { ctx.map.insert(*l, *r); } // Check equality between the operations themselves if !ctx.lf.block_op_eq(l_b, &ctx.rf, r_b) { return Result::Err(EqualityFail::BlockOp { left: l_b, right: r_b, }); } // Traverse the block OP read values let l_reads = ctx.lf.block_reads(l_b); let r_reads = ctx.rf.block_reads(r_b); if l_reads.len() != r_reads.len() { return Result::Err(EqualityFail::BlockReadsLength { left: l_b, right: r_b, }); } for (l, r) in l_reads.iter().zip(r_reads.iter()) { traverse_value(&mut ctx, *l, *r)?; } } // 2. Check all remaining values that are arguments for (l, r) in ctx.to_check.iter() { if ctx.map.get(l) != Some(r) { return Result::Err(EqualityFail::MismatchingValue { left: *l, right: *r, }); } } for (lhs_v, rhs_v) in ctx.map.iter() { match (self.value_block(*lhs_v), rhs.value_block(*rhs_v)) { (Some(lhs_b), Some(rhs_b)) => { if opts.check_block_locations { let l_loc = self.block_location(lhs_b); let r_loc = rhs.block_location(rhs_b); if !self.locations.location_eq(l_loc, &rhs.locations, r_loc) { return Result::Err(EqualityFail::MismatchingBlockLocation { left_block: lhs_b, right_block: rhs_b, left_loc: l_loc, right_loc: r_loc, left_desc: self.locations.format_loc(l_loc), right_desc: rhs.locations.format_loc(r_loc), }); } } } _ => (), } } Ok(()) } pub fn graph_eq( &self, lhs_block: Block, rhs: &Function, rhs_block: Block, ) -> Result<(), EqualityFail> { self.graph_eq_opts(lhs_block, rhs, rhs_block, &GraphEqOptions::default()) } } fn traverse_value<'a>(ctx: &mut EqCtx<'a>, l: Value, r: Value) -> Result<(), EqualityFail> { if let Some(nr) = ctx.map.get(&l) { if *nr == r { return Ok(()); } else { return Err(EqualityFail::MismatchingValue { left: l, right: r }); } } match (ctx.lf.value_kind(l), ctx.rf.value_kind(r)) { (ValueKind::Block(lb), ValueKind::Block(rb)) => { ctx.map.insert(l, r); ctx.to_walk.push_back((lb, rb)); Ok(()) } (ValueKind::Argument(_, _), ValueKind::Argument(_, _)) => { ctx.to_check.push((l, r)); Ok(()) } (ValueKind::Const(lc), ValueKind::Const(rc)) => { if !ctx.lf.cons().eq_other(lc, ctx.rf.cons(), rc) { return Err(EqualityFail::MismatchingConst { left: lc, right: rc, }); } Ok(()) } (ValueKind::PrimOp(lp), ValueKind::PrimOp(rp)) => { let l_reads = ctx.lf.primop_reads(lp); let r_reads = ctx.rf.primop_reads(rp); if l_reads.len() != r_reads.len() { return Err(EqualityFail::PrimReadsLength { left: lp, right: rp, }); } for (l, r) in l_reads.iter().zip(r_reads.iter()) { traverse_value(ctx, *l, *r)?; } Ok(()) } _ => Err(EqualityFail::MismatchingValue { left: l, right: r }), } } #[cfg(test)] mod tests { use crate::parse_function_unwrap; #[test] fn basic_equality() { let ir1 = parse_function_unwrap( " a'foo':a'bar'/1 { entry(%ret, %thr, %arg1): block2(%arg1); block2(%b): block3(%b); block3(%a): %ret(%a); } ", ); let ir2 = parse_function_unwrap( " a'a':a'b'/1 { entry(%ret, %thr, %arg1): block2(%arg1); block3(%a): %ret(%a); block2(%b): block3(%b); } ", ); assert!(ir1 .graph_eq(ir1.block_entry(), &ir2, ir2.block_entry()) .is_ok()); } #[test] fn args_length_inequality() { let ir1 = parse_function_unwrap( " a'foo':a'bar'/2 { entry(%ret, %thr, %arg1, %arg2): %ret(%arg1); } ", ); let ir2 = parse_function_unwrap( " a'foo':a'bar'/1 { entry(%ret, %thr, %arg1): %ret(%arg1); } ", ); assert!(ir1 .graph_eq(ir1.block_entry(), &ir2, ir2.block_entry()) .is_err()); } #[test] fn args_read_inequality() { let ir1 = parse_function_unwrap( " a'foo':a'bar'/2 { entry(%ret, %thr, %arg1, %arg2): %ret(%arg1); } ", ); let ir2 = parse_function_unwrap( " a'foo':a'bar'/2 { entry(%ret, %thr, %arg1, %arg2): %ret(%arg2); } ", ); assert!(ir1 .graph_eq(ir1.block_entry(), &ir2, ir2.block_entry()) .is_err()); } #[test] fn args_read_const_equality() { let ir1 = parse_function_unwrap( " a'foo':a'bar'/2 { entry(%ret, %thr, %arg1, %arg2): %ret(a'a'); } ", ); let ir2 = parse_function_unwrap( " a'foo':a'bar'/2 { entry(%ret, %thr, %arg1, %arg2): %ret(a'a'); } ", ); assert!(ir1 .graph_eq(ir1.block_entry(), &ir2, ir2.block_entry()) .is_ok()); } #[test] fn args_read_const_inequality() { let ir1 = parse_function_unwrap( " a'foo':a'bar'/2 { entry(%ret, %thr, %arg1, %arg2): %ret(a'a'); } ", ); let ir2 = parse_function_unwrap( " a'foo':a'bar'/2 { entry(%ret, %thr, %arg1, %arg2): %ret(a'b'); } ", ); assert!(ir1 .graph_eq(ir1.block_entry(), &ir2, ir2.block_entry()) .is_err()); } #[test] fn args_prim_inequality() { let ir1 = parse_function_unwrap( " a'foo':a'bar'/1 { entry(%ret, %thr, %arg1): %fun = a'a':a'a'/1; %fun(%ret, %thr, %arg1); } ", ); let ir2 = parse_function_unwrap( " a'foo':a'bar'/1 { entry(%ret, %thr, %arg1): %fun = a'a':a'b'/1; %fun(%ret, %thr, %arg1); } ", ); assert!(ir1 .graph_eq(ir1.block_entry(), &ir2, ir2.block_entry()) .is_err()); } #[test] fn block_location_equality() { let opts = super::GraphEqOptions { check_block_locations: true, }; let ir1 = parse_function_unwrap( " a'foo':a'bar'/1 { !location [\"foo\":\"bar\"@\"foo.erl\":12]; entry(%ret, %thr, %arg1): %ret(%arg1); } ", ); let ir2 = parse_function_unwrap( " a'foo':a'bar'/1 { !location [\"foo\":\"bar\"@\"foo.erl\":12]; entry(%ret, %thr, %arg1): %ret(%arg1); } ", ); assert!(ir1 .graph_eq_opts(ir1.block_entry(), &ir2, ir2.block_entry(), &opts) .is_ok()); } } ================================================ FILE: libeir_ir/src/algo/func_tree.rs ================================================ use std::collections::{BTreeMap, BTreeSet}; use petgraph::visit::{Dfs, DfsPostOrder}; use petgraph::visit::{GraphBase, IntoNeighbors, Visitable, Walker}; use crate::graph::EntityVisitMap; use crate::{Block, CallKind, Function, LiveValues, OpKind, Value}; #[derive(Debug, Clone)] pub struct FunctionTree { /// The root function, specified by the entry block of the function /// container. pub root_fun: Block, /// The descriptions of the different functions contained within this /// container. /// This is guaranteed to contain at least one entry, the root function. pub functions: BTreeMap, } #[derive(Debug, Clone)] pub struct FunctionEntry { /// The entry point of the function. /// The continuations are always the first arguments of this block. /// * If both `ret` and `thr` are `Some`, the first two are those /// continuations respectively. /// * If only one of `ret` and `thr` are `Some`, only the first argument /// is that continuation. /// * If both are `None`, this function never returns. /// At the moment both will always be `Some`, but this may change in the /// future. pub entry: Block, /// The return continuation for this function. /// This value is always either: /// * Called with a `CallKind::ControlFlow` operation, this is a return. /// * Passed as argument 1 to a `CallKind::Function`, this is a tail call. pub ret: Option, /// The throw continuation for this function. /// This value is always either: /// * Called with a `CallKind::ControlFlow` operation, this is a throw. /// * Passed as argument 2 to a `CallKind::Function`, this is a tail call. pub thr: Option, /// This is the scope of the function. /// This includes all blocks that can be reached by control flow within /// the current stack frame. /// Does not include calls to functions, those create a new stack frame. pub scope: BTreeSet, /// The children function entries of this function. pub children: BTreeSet, } enum Escape { Return, Throw, } impl Function { pub fn func_tree(&self, live: &LiveValues, resolve_continuations: bool) -> FunctionTree { let graph = self.block_graph(); // Identify which blocks get captured. // At at least one location in the IR, these are not branched to directly // by an operation, but instead captured as a value. // For a capture to be valid, it needs to only return through one of its // arguments. let mut blocks = BTreeSet::new(); let mut captured_blocks = BTreeSet::new(); captured_blocks.insert(self.block_entry()); { let mut branched = BTreeSet::new(); for block in graph.dfs_iter() { blocks.insert(block); branched.clear(); branched.extend(self.op_branch_iter(block)); self.block_walk_nested_values::<_, Result<(), ()>>(block, &mut |v| { if let Some(v_block) = self.value_block(v) { if !branched.contains(&v) { captured_blocks.insert(v_block); } } Ok(()) }) .unwrap(); } } if resolve_continuations { // Find all escape continuations for all captures let mut escapes = BTreeMap::new(); for block in captured_blocks.iter() { let args = self.block_args(*block); assert!(args.len() >= 2); escapes.insert(args[0], Escape::Return); escapes.insert(args[1], Escape::Throw); } // Validate that at every point only the escape continuations for // the current functions are live. for block in captured_blocks.iter() { let live_at = live.live_at(*block); for live_val in live_at.iter() { assert!(!escapes.contains_key(&live_val)); } } // Validate that escapes are only either: // * Called as control flow // * Passed as an escape to a function call // More specifically, escapes should NEVER be: // * Passed as a regular argument to a function call // * Passed as an argument to a control flow call for (value, escape) in escapes.iter() { for usage in self.value_usages(*value).iter() { if !blocks.contains(&usage) { continue; } let check: &dyn Fn(&[Value]) = &|values| { for read in values.iter() { self.value_walk_nested_values::<_, Result<(), ()>>(*read, &mut |v| { assert!(v != *value); Ok(()) }) .unwrap(); } }; let reads = self.block_reads(usage); match self.block_kind(usage).unwrap() { OpKind::Call(CallKind::ControlFlow) => { assert!(reads[0] == *value); check(&reads[1..]); } OpKind::Call(CallKind::Function) => { check(&[reads[0]]); match *escape { Escape::Return => { assert!(reads[1] == *value); check(&[reads[2]]); } Escape::Throw => { check(&[reads[1]]); assert!(reads[2] == *value); } } check(&reads[3..]); } _ => (), } } } } // Generate the scopes for all of the functions let mut functions = BTreeMap::new(); let mut cfg_graph = self.control_flow_graph(); for block in captured_blocks.iter() { cfg_graph.calculate(self, self.block_value(*block)); let mut function_scope = BTreeSet::new(); let mut to_walk = Vec::new(); to_walk.push(*block); while let Some(block) = to_walk.pop() { if function_scope.contains(&block) { continue; } function_scope.insert(block); let block_val = self.block_value(block); for out in cfg_graph.neighbors(block_val) { if let Some(out_block) = self.value_block(out) { if !captured_blocks.contains(&out_block) { to_walk.push(out_block); } } } } let args = self.block_args(*block); let mut children = function_scope .intersection(&captured_blocks) .cloned() .collect::>(); children.remove(block); let mut ret = None; let mut thr = None; if resolve_continuations { ret = Some(args[0]); thr = Some(args[1]); } functions.insert( *block, FunctionEntry { entry: *block, ret, thr, children, scope: function_scope, }, ); } let tree = FunctionTree { root_fun: self.block_entry(), functions, }; assert!(tree .validate_no_cycles(tree.root_fun, 0, tree.functions.len()) .is_some()); tree } } impl FunctionTree { fn validate_no_cycles(&self, entry: Block, mut curr: usize, limit: usize) -> Option { if curr > limit { return None; } for child in self.functions[&entry].children.iter() { curr = self.validate_no_cycles(*child, curr + 1, limit)?; } Some(curr) } pub fn dfs(&self) -> Dfs> { Dfs::new(self, self.root_fun) } pub fn dfs_iter<'a>(&'a self) -> impl Iterator + 'a { self.dfs().iter(self) } pub fn dfs_post_order(&self) -> DfsPostOrder> { DfsPostOrder::new(self, self.root_fun) } pub fn dfs_post_order_iter<'a>(&'a self) -> impl Iterator + 'a { self.dfs_post_order().iter(self) } } impl GraphBase for FunctionTree { type NodeId = Block; type EdgeId = (Block, Block); } impl<'a> IntoNeighbors for &'a FunctionTree { type Neighbors = std::iter::Cloned>; fn neighbors(self, block: Block) -> Self::Neighbors { self.functions[&block].children.iter().cloned() } } impl Visitable for FunctionTree { type Map = EntityVisitMap; fn visit_map(&self) -> EntityVisitMap { EntityVisitMap::new(self.functions.len()) } fn reset_map(&self, map: &mut EntityVisitMap) { map.reset(self.functions.len()); } } ================================================ FILE: libeir_ir/src/algo/live.rs ================================================ use std::collections::HashMap; use crate::Function; use crate::{Block, Value}; use cranelift_bforest::{BoundSet, Set, SetForest}; use libeir_util_datastructures::aux_traits::{AuxDebug, AuxImpl, HasAux}; impl Function { pub fn live_values(&self) -> LiveValues { calculate_live_values(self) } } /// # Value liveness calculation /// Utility for calculating live values at every point in a functions /// CFG. /// /// TODO /// Right now this uses a (probably) bad algorithm I made up on the spot. /// I am sure there are better and more efficient ways of doing this, /// but this should work for now. /// For CFGs that are acyclic, this algorithm will complete in a single /// iteration. For cyclic CFGs, this should take (around) 1 extra iteration /// for every additional nested cycle. #[derive(Clone)] pub struct LiveValues { /// Values that need to exist at every block. /// Before block arguments. live_at: HashMap>, /// Values that need to exist within every block. /// After block arguments, before operation. live_in: HashMap>, /// The pool where `ebb_live` and `flow_live` is allocated. forest: SetForest, } impl HasAux> for LiveValues { fn get_aux(&self) -> &SetForest { &self.forest } } impl>> AuxDebug for LiveValues { fn aux_fmt(&self, f: &mut std::fmt::Formatter<'_>, _aux: &C) -> std::fmt::Result { let mut b = f.debug_struct("LiveValues"); b.field("live_at", &AuxImpl(&self.live_at, self)); b.field("live_in", &AuxImpl(&self.live_in, self)); b.finish() } } impl std::fmt::Debug for LiveValues { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { self.aux_fmt(f, self) } } impl LiveValues { pub fn live_at<'a>(&'a self, block: Block) -> BoundSet<'a, Value, ()> { self.live_at[&block].bind(&self.forest, &()) } pub fn live_in<'a>(&'a self, block: Block) -> BoundSet<'a, Value, ()> { self.live_in[&block].bind(&self.forest, &()) } pub fn is_live_at(&self, block: Block, value: Value) -> bool { self.live_at[&block].contains(value, &self.forest, &()) } pub fn is_live_in(&self, block: Block, value: Value) -> bool { self.live_in[&block].contains(value, &self.forest, &()) } } fn dataflow_pass( fun: &Function, pool: &mut SetForest, live: &mut HashMap>, live_in: &mut HashMap>, ) -> bool { let graph = fun.block_graph(); let mut visitor = graph.dfs_post_order(); let mut stable = true; // For each Op node in the cfg while let Some(block) = visitor.next(&graph) { let mut set: Set = Set::new(); // For each of the outgoing branches, add its live values to the current set for branch in graph.outgoing(block) { if let Some(vals) = live.get(&branch) { set.union_from(vals, pool, &()); } } // Add the reads for the block OP to the current set for read in fun.block_reads(block) { // Only insert if it actually is a variable, not a block or constant fun.value_walk_nested_values::<_, ()>(*read, &mut |v| { if fun.value_argument(v).is_some() { set.insert(v, pool, &()); } Ok(()) }) .unwrap(); } // Update the live_after values if !live_in.contains_key(&block) { live_in.insert(block, Set::new()); } live_in.get_mut(&block).unwrap().union_from(&set, pool, &()); // Remove the block arguments from the current set for arg in fun.block_args(block) { set.remove(*arg, pool, &()); } // If we don't have a previous live calculation for this block, or if // the live set has changed, we are not yet stable. if let Some(mut old_set) = live.remove(&block) { if !old_set.iter(pool).eq(set.iter(pool)) { stable = false; } old_set.clear(pool); } else { stable = false; } // Insert the new calculated live variables live.insert(block, set); } stable } pub fn calculate_live_values(fun: &Function) -> LiveValues { let mut forest = SetForest::new(); let mut live_at: HashMap> = HashMap::new(); let mut live_in: HashMap> = HashMap::new(); // Iterate dataflow until all dependencies have been resolved loop { let res = dataflow_pass(fun, &mut forest, &mut live_at, &mut live_in); if res { break; } } // Validate that the live set at entry is empty { let entry = fun.block_entry(); assert!( live_at[&entry].iter(&forest).count() == 0, "{:?}", live_at[&entry].bind(&forest, &()) ); } LiveValues { forest, live_at, live_in, } } #[cfg(test)] mod tests { #[test] fn test_simple() { let (ir, map) = crate::parse_function_map_unwrap( " a'foo':a'bar'/1 { b1(%ret, %thr): b2(); b2(): b3(); b3(): %ret([]); } ", ); let b1 = map.get_block("b1"); let b2 = map.get_block("b2"); let b3 = map.get_block("b3"); let b1_ret = map.get_value("ret"); let live = ir.live_values(); let b1_live = live.live_at(b1); assert!(b1_live.iter().count() == 0); let b2_live = live.live_at(b2); assert!(b2_live.iter().count() == 1); assert!(b2_live.contains(b1_ret)); let b3_live = live.live_at(b3); assert!(b3_live.iter().count() == 1); assert!(b3_live.contains(b1_ret)); } #[test] fn test_cycle() { let (ir, map) = crate::parse_function_map_unwrap( " a'foo':a'bar'/1 { b1(%ret, %thr, %a): b2(%a, []); b2(%b, %c): b3(); b3(): b4(); b4(): b5(b6, %c); b5(%e, %f): b2(%e, %f); b6(): %ret(); } ", ); let b1 = map.get_block("b1"); let b3 = map.get_block("b3"); let b5 = map.get_block("b5"); let b6 = map.get_block("b6"); let b1_ret = map.get_value("ret"); let b2_c = map.get_value("c"); let live = ir.live_values(); let b1_live = live.live_at(b1); assert!(b1_live.iter().count() == 0); let b3_live = live.live_at(b3); assert!(b3_live.iter().count() == 2); assert!(b3_live.contains(b1_ret)); assert!(b3_live.contains(b2_c)); let b5_live = live.live_at(b5); assert!(b5_live.iter().count() == 1); assert!(b5_live.contains(b1_ret)); let b6_live = live.live_at(b6); assert!(b6_live.iter().count() == 1); assert!(b6_live.contains(b1_ret)); } } ================================================ FILE: libeir_ir/src/algo/mangle/datatypes.rs ================================================ #![allow(dead_code)] use crate::Function; use crate::{Block, Value}; use super::MangleReceiver; #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] pub struct FromT(pub T); impl FromT { pub(super) fn map_fun<'a, 'b, R, F, V>(self, recv: &'a R, mut f: F) -> FromT where R: MangleReceiver<'b>, F: FnMut(&Function, T) -> V + 'a, { let fun = recv.from(); let val = f(fun, self.inner()); FromT(val) } pub fn inner(self) -> T { self.0 } } impl From for FromT { fn from(f: T) -> Self { FromT(f) } } impl std::fmt::Display for FromT where T: std::fmt::Display, { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { write!(f, "From({})", self.0) } } pub(super) type FromValue = FromT; pub(super) type FromBlock = FromT; #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] pub struct ToT(pub T); impl ToT { pub(super) fn map_fun<'a, 'b, R, F, V>(self, recv: &'a R, mut f: F) -> ToT where R: MangleReceiver<'b>, F: FnMut(&Function, T) -> V + 'a, { let fun = recv.to_fun(); let val = f(fun, self.inner()); ToT(val) } pub fn inner(self) -> T { self.0 } } impl From for ToT { fn from(f: T) -> Self { ToT(f) } } impl std::fmt::Display for ToT where T: std::fmt::Display, { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { write!(f, "To({})", self.0) } } pub type ToValue = ToT; pub type ToBlock = ToT; /// Because the mangler code supports operating across function containers, /// we need a mechanism to keep track of when a value is referenced in the /// old container or when it is referenced in the new one. #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] pub enum MangleTarget { From(FromT), To(ToT), } impl std::fmt::Display for MangleTarget where T: std::fmt::Display, { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { write!(f, "To({})", self.inner_ref()) } } impl MangleTarget { pub fn inner(self) -> T { match self { MangleTarget::From(i) => i.0, MangleTarget::To(i) => i.0, } } pub fn inner_ref(&self) -> &T { match self { MangleTarget::From(i) => &i.0, MangleTarget::To(i) => &i.0, } } pub(super) fn fun<'a, 'b, R>(&self, recv: &'a R) -> &'a Function where R: MangleReceiver<'b>, { match self { MangleTarget::From(_) => recv.from(), MangleTarget::To(_) => recv.to_fun(), } } pub fn map(self, mut f: F) -> MangleTarget where F: FnMut(T) -> V, { match self { MangleTarget::From(i) => { let val = f(i.inner()); MangleTarget::From(val.into()) } MangleTarget::To(i) => { let val = f(i.inner()); MangleTarget::To(val.into()) } } } pub(super) fn map_fun<'a, 'b, R, F, V>(self, recv: &'a R, mut f: F) -> MangleTarget where R: MangleReceiver<'b>, F: FnMut(&Function, T) -> V + 'a, { let fun = self.fun(recv); match self { MangleTarget::From(i) => { let val = f(fun, i.inner()); MangleTarget::From(val.into()) } MangleTarget::To(i) => { let val = f(fun, i.inner()); MangleTarget::To(val.into()) } } } pub fn new_with(&self, new: N) -> MangleTarget { match self { MangleTarget::From(_) => MangleTarget::From(FromT(new)), MangleTarget::To(_) => MangleTarget::To(ToT(new)), } } pub fn from(self) -> Option> { match self { MangleTarget::From(inner) => Some(inner), MangleTarget::To(_) => None, } } pub fn to(self) -> Option> { match self { MangleTarget::From(_) => None, MangleTarget::To(inner) => Some(inner), } } } impl MangleTarget> { pub fn transpose_opt(self) -> Option> { match self { MangleTarget::From(FromT(None)) => None, MangleTarget::To(ToT(None)) => None, MangleTarget::From(FromT(Some(v))) => Some(MangleTarget::From(v.into())), MangleTarget::To(ToT(Some(v))) => Some(MangleTarget::To(v.into())), } } } impl MangleTarget<&T> where T: Clone, { pub fn cloned(&self) -> MangleTarget { self.map(|v| v.clone()) } } impl MangleTarget where I: IntoIterator, { pub fn transpose_iter(self) -> impl Iterator> { let constructor = match self { MangleTarget::From(_) => { fn a(v: V) -> MangleTarget { MangleTarget::From(FromT(v)) } a } MangleTarget::To(_) => { fn a(v: V) -> MangleTarget { MangleTarget::To(ToT(v)) } a } }; self.inner().into_iter().map(constructor) } } impl From> for MangleTarget { fn from(i: FromT) -> MangleTarget { MangleTarget::From(i) } } impl From> for MangleTarget { fn from(i: ToT) -> MangleTarget { MangleTarget::To(i) } } pub(super) type MangleValue = MangleTarget; pub(super) type MangleBlock = MangleTarget; ================================================ FILE: libeir_ir/src/algo/mangle/mod.rs ================================================ use std::collections::{BTreeMap, BTreeSet}; use bumpalo::Bump; use libeir_diagnostics::SourceSpan; use crate::Block; use crate::ValueKind; use crate::{Function, FunctionBuilder}; mod receiver; use receiver::MangleReceiver; mod datatypes; #[allow(unused_imports)] use datatypes::{FromBlock, FromT, FromValue, MangleBlock, MangleValue, ToBlock, ToT, ToValue}; pub use datatypes::FromT as MangleFrom; pub use datatypes::MangleTarget; pub use datatypes::ToT as MangleTo; #[cfg(test)] mod tests; /// Utility struct implementing the lambda mangling primitive. /// Supports both mangling within a single function container, and /// across function containers, implemented by `run` and `run_across` /// respectively. pub struct Mangler { entry: Option, new_entry: Option, /// Cache to reduce time complexity of `Self::map` actually_mapped: BTreeMap, pub values_map: BTreeMap, value_buf: Vec, values: Option>, scope: Option>, to_walk: Vec, bump: Option, } impl Mangler { pub fn new() -> Self { Mangler { entry: None, new_entry: None, actually_mapped: BTreeMap::new(), values_map: BTreeMap::new(), value_buf: Vec::new(), values: Some(BTreeSet::new()), scope: Some(BTreeSet::new()), to_walk: Vec::new(), bump: Some(Bump::new()), } } /// Clears the mangler for a new use. /// This is automatically done by the `start` method. fn clear(&mut self) { self.entry = None; self.new_entry = None; self.actually_mapped.clear(); self.values_map.clear(); self.value_buf.clear(); self.values.as_mut().unwrap().clear(); self.scope.as_mut().unwrap().clear(); self.to_walk.clear(); self.bump.as_mut().unwrap().reset(); } pub fn value_map<'a>(&'a self) -> &'a BTreeMap { &self.values_map } /// Clears the mangler of all existing data, and starts a new transaction /// for the given entry block. pub fn start(&mut self, from_block: F) where F: Into, { self.clear(); self.entry = Some(from_block.into()); } pub fn add_rename(&mut self, old: O, new: N) where O: Into, N: Into, { self.values_map.insert(old.into(), (new.into(), true)); } /// Adds a value rename that should not be followed in the mangling process. /// This is extremely useful in that it allows you to limit the scope of the /// mangle. /// An example would be allowing you to only mangle the relevant parts when /// inlining a closure. pub fn add_rename_nofollow(&mut self, old: O, new: N) where O: Into, N: Into, { self.values_map.insert(old.into(), (new.into(), false)); } /// Runs lambda mangling on a single function container pub fn run(&mut self, fun: &mut FunctionBuilder) -> Block { let mut recv = receiver::SingleMangleReceiver { fun }; self.run_inner(&mut recv) } // Runs lambda mangling while copying across function containers pub fn run_across(&mut self, from: &Function, to: &mut FunctionBuilder) -> Block { let mut recv = receiver::CopyMangleReceiver { from, to }; self.run_inner(&mut recv) } fn propagate_values(&mut self) { self.value_buf.clear(); self.value_buf.extend(self.values_map.keys()); for key in self.value_buf.iter() { let mut acc = *key; let mut follow = true; while let Some((target, n_follow)) = self.values_map.get(&acc) { if acc == *target { break; } acc = *target; follow = follow && *n_follow; } if *key == acc { self.values_map.remove(key); } else { *self.values_map.get_mut(key).unwrap() = (acc, follow); } } } fn run_inner<'a, 'b, R>(&mut self, recv: &'a mut R) -> Block where R: MangleReceiver<'b>, { let bump = self.bump.take().unwrap(); let mut scope = self.scope.take().unwrap(); let mut to_map_values = self.values.take().unwrap(); // Propagate values self.propagate_values(); // Get the mapped entry block let mut entry = self.entry.unwrap(); if let Some((value, follow)) = self .values_map .get(&entry.map_fun(recv, |f, v| f.block_value(v))) { if !follow { panic!("WARNING: Mangle mapped to entry block due to no-follow"); //return entry; } if let Some(b) = value.map_fun(recv, |f, v| f.value_block(v)).transpose_opt() { entry = b; } else { // TODO: In this case, we need to directly return the value the // entry block has been mapped to. unimplemented!(); } } // Walk scope { self.to_walk.push(entry); while let Some(start_block) = self.to_walk.pop() { if scope.contains(&start_block) { continue; } let block_value = start_block.map_fun(recv, |f, v| f.block_value(v)); let block_value_mapped = self .values_map .get(&block_value) .map(|(v, _)| *v) .unwrap_or(block_value); let block_mapped_opt = block_value_mapped .map_fun(recv, |f, v| f.value_block(v)) .transpose_opt(); if block_mapped_opt.is_none() { continue; } let block = block_mapped_opt.unwrap(); if scope.contains(&block) { continue; } scope.insert(block); let block_fun = block.fun(recv); for read in block_fun .block_reads(block.inner()) .iter() .map(|b| block.new_with(b)) { let fun = read.fun(recv); fun.value_walk_nested_values::<_, ()>(*read.inner(), &mut |val| { let val = read.new_with(val); if let Some((mapped, follow)) = self.values_map.get(&val) { if *follow { if let Some(block) = mapped .map_fun(recv, |f, v| f.value_block(v)) .transpose_opt() { self.to_walk.push(block); } } } to_map_values.insert(val); Ok(()) }) .unwrap(); } let block_fun = block.fun(recv); for out in block_fun.block_graph().outgoing(block.inner()) { self.to_walk.push(block.new_with(out)); } } } // Insert new blocks { for block in scope.iter().cloned() { let block_val = block.map_fun(recv, |f, b| f.block_value(b)); assert!(!self.values_map.contains_key(&block_val)); let new_block = recv.to().block_insert(); let new_block_val = ToT(recv.to().fun().block_value(new_block)); self.values_map .insert(block_val, (new_block_val.into(), true)); self.value_buf.clear(); let block_fun = block.fun(recv); self.value_buf.extend( block_fun .block_args(block.inner()) .iter() .map(|v| block.new_with(*v)), ); // Insert new arguments let to = recv.to(); for arg in self.value_buf.iter().cloned() { let new_arg = to.block_arg_insert(new_block); if !self.values_map.contains_key(&arg) { self.values_map.insert(arg, (ToT(new_arg).into(), true)); } } } } // Propagate values self.propagate_values(); // Map values to_map_values.extend(self.values_map.values().map(|(v, _)| *v)); for val in to_map_values.iter() { self.map(&bump, recv, *val); } // Propagate values self.propagate_values(); let copy_body = |mang: &mut Mangler, recv: &mut R, from_block: MangleBlock, to_block: ToBlock| { let to_op = recv.map_block_op(from_block); let loc = from_block.map_fun(recv, |f, b| f.block_location(b)).inner(); // Get and map reads to new values mang.value_buf.clear(); let from_block_fun = from_block.fun(recv); mang.value_buf.extend( from_block_fun .block_reads(from_block.inner()) .iter() .map(|v| from_block.new_with(*v)), ); for n in 0..mang.value_buf.len() { let v = mang.value_buf[n]; let mapped = mang.values_map.get(&v).map(|v| v.0).unwrap_or(v); mang.value_buf[n] = mapped; } // Update the new block with kind, span and reads let to = recv.to(); let to_fun = to.fun_mut(); let data = &mut to_fun.blocks[to_block.inner()]; data.op = Some(to_op); data.location = loc; for read in mang.value_buf.iter() { data.reads .push(read.to().unwrap().inner(), &mut to_fun.pool.value); } recv.to().graph_update_block(to_block.inner()); }; // Set new bodies for block in scope.iter().cloned() { let block_val = block.map_fun(recv, |f, b| f.block_value(b)); let new_block_val_either = self.values_map.get(&block_val).unwrap().0; let new_block_val = new_block_val_either .to() .expect("attempted to set body on from block"); let new_block = new_block_val.map_fun(recv, |f, b| f.value_block(b).unwrap()); copy_body(self, recv, block, new_block); } let entry = self.entry.unwrap(); let entry_val = entry.map_fun(recv, |f, v| f.block_value(v)); let new_entry_val = self .values_map .get(&entry_val) .map(|v| v.0) .unwrap_or(entry_val) .to() .unwrap(); let new_entry = new_entry_val.map_fun(recv, |f, v| f.value_block(v).unwrap()); self.values = Some(to_map_values); self.scope = Some(scope); self.bump = Some(bump); self.clear(); new_entry.inner() } fn map<'a, 'b, R>(&mut self, bump: &Bump, recv: &'a mut R, mut val: MangleValue) -> ToValue where R: MangleReceiver<'b>, { if let Some(to) = self.actually_mapped.get(&val) { return *to; } if let Some(to) = self.values_map.get(&val) { val = to.0; } let kind = val.map_fun(recv, |f, v| f.value_kind(v)); let locs = val.map_fun(recv, |f, v| f.value_locations(v)); let dest: ToValue = match kind.inner() { ValueKind::Const(_) => recv.map_const(val), ValueKind::PrimOp(prim) => { let prim = val.new_with(prim); let kind = prim .map_fun(recv, |f, _v| *f.primop_kind(prim.inner())) .inner(); let span = locs .inner() .map(|spans| spans.first().copied().unwrap_or(SourceSpan::UNKNOWN)) .unwrap_or(SourceSpan::UNKNOWN); let mut buf = Vec::new_in(bump); { let fun = prim.fun(recv); buf.extend(fun.primop_reads(prim.inner()).iter().cloned()) } for value in buf.iter_mut() { let value_m = prim.new_with(*value); *value = self.map(bump, recv, value_m).inner(); } recv.to().prim_from_kind(span, kind, &buf).into() } ValueKind::Block(block) => { let block = val.new_with(block); let block_val = block.map_fun(recv, |f, b| f.block_value(b)); let new = if let Some((new_block_val, _)) = self.values_map.get(&block_val).cloned() { new_block_val } else { block.map_fun(recv, |f, b| f.block_value(b)) }; new.to() .expect("mangle reached block in target with nofollow and no replacement") } ValueKind::Argument(_block, _num) => recv.map_free_value(val).into(), }; self.values_map.insert(val, (dest.into(), true)); self.actually_mapped.insert(val, dest); dest } } ================================================ FILE: libeir_ir/src/algo/mangle/receiver.rs ================================================ use crate::OpKind; use crate::{Function, FunctionBuilder}; use super::{MangleBlock, MangleValue, ToValue}; /// Trait used to generalize a single mangling implementation over /// both mangling within a single function container, and across /// two different containers. /// Not exposed to user, only used internally. pub(super) trait MangleReceiver<'b> { // NOTE: Would like to do some things differently here, mainly // generalizing the either/from/to variants, but not having // GATs makes this way to painful. /// The function container that is the source of the mangle. fn from<'a>(&'a self) -> &'a Function; /// The function builder that is the destination of the mangle. fn to<'a>(&'a mut self) -> &'a mut FunctionBuilder<'b>; fn to_fun<'a>(&'a self) -> &'a Function; /// Maps a constant. /// This should return a value that is usable in the destination /// function. fn map_const(&mut self, val: MangleValue) -> ToValue; /// Maps a free value. /// A free value in this context is a value from outside /// the scope of the mangle. fn map_free_value(&mut self, val: MangleValue) -> ToValue; /// Maps a block operation. This should return an OpKind that is /// usable in the destination function. fn map_block_op(&mut self, block: MangleBlock) -> OpKind; } /// This receiver performs a mangle within a single function container. pub(super) struct SingleMangleReceiver<'a, 'b> { pub fun: &'a mut FunctionBuilder<'b>, } impl<'b, 'c> MangleReceiver<'b> for SingleMangleReceiver<'c, 'b> { fn from<'a>(&'a self) -> &'a Function { // Since only the `To` branch should ever be used here, // this should never be called. unreachable!() } fn to<'a>(&'a mut self) -> &'a mut FunctionBuilder<'b> { self.fun } fn to_fun<'a>(&'a self) -> &'a Function { self.fun.fun() } fn map_const(&mut self, val: MangleValue) -> ToValue { val.to().unwrap() } fn map_free_value(&mut self, val: MangleValue) -> ToValue { val.to().unwrap() } fn map_block_op(&mut self, block: MangleBlock) -> OpKind { let block = block.to().unwrap().inner(); self.fun.fun().block_kind(block).unwrap().clone() } } /// This receiver performs a mangle across to another function container. /// In the basic case, this is simply a copy across function containers. pub(super) struct CopyMangleReceiver<'a, 'b> { pub from: &'a Function, pub to: &'a mut FunctionBuilder<'b>, } impl<'b, 'c> MangleReceiver<'b> for CopyMangleReceiver<'c, 'b> { fn from<'a>(&'a self) -> &'a Function { self.from } fn to<'a>(&'a mut self) -> &'a mut FunctionBuilder<'b> { self.to } fn to_fun<'a>(&'a self) -> &'a Function { self.to.fun() } fn map_const(&mut self, _val: MangleValue) -> ToValue { unimplemented!() } fn map_free_value(&mut self, _val: MangleValue) -> ToValue { panic!() } fn map_block_op(&mut self, _block: MangleBlock) -> OpKind { unimplemented!() } } ================================================ FILE: libeir_ir/src/algo/mangle/tests.rs ================================================ use crate::{NilTerm, StandardFormatConfig}; use super::Mangler; use super::ToT; #[test] fn simple_mangle() { let (mut ir, map) = crate::parse_function_map_unwrap( " a'foo':a'bar'/1 { entry(%ret, %thr, %a): b1(); b1(): %ret(%a); } ", ); let mut b = ir.builder(); let mut mangler = Mangler::new(); let b1 = map.get_block("entry"); let b1_ret = map.get_value("ret"); let b1_arg = map.get_value("a"); let new_entry = b.block_insert(); let ret_narg = b.block_arg_insert(new_entry); let nil_term = b.value(NilTerm); b.block_copy_body_map(b1, new_entry, |v| Some(v)); mangler.start(ToT(new_entry)); mangler.add_rename(ToT(b1_ret), ToT(ret_narg)); mangler.add_rename(ToT(b1_arg), ToT(nil_term)); let new_b1 = mangler.run(&mut b); b.block_set_entry(new_b1); let after = crate::parse_function_unwrap( " a'foo':a'bar'/1 { entry(%ret): b1(); b1(): %ret([]); } ", ); assert!(b .fun() .graph_eq(new_b1, &after, after.block_entry()) .is_ok()); } #[test] fn preserves_block_locations() { let eir_str = " a'foo':a'bar'/1 { !location [\"foo\":\"foo\"@\"foo.erl\":1]; entry(%ret): b1(); !location [\"foo\":\"foo\"@\"foo.erl\":2]; b1(): %ret([]); } "; let (mut ir, map) = crate::parse_function_map_unwrap(eir_str); let mut b = ir.builder(); let mut mangler = Mangler::new(); let b1 = map.get_block("entry"); let b1_ret = map.get_value("ret"); mangler.start(ToT(b1)); let new_b1 = mangler.run(&mut b); b.block_set_entry(new_b1); let after = crate::parse_function_unwrap(eir_str); let opts = crate::GraphEqOptions { check_block_locations: true, }; let res = b .fun() .graph_eq_opts(b.fun().block_entry(), &after, after.block_entry(), &opts); println!("{:?}", res); assert!(res.is_ok()); } #[test] fn mangle_primop() { let (mut ir, map) = crate::parse_function_map_unwrap( " a'foo':a'bar'/1 { entry(%ret, %thr, %a): %ret({%a}); } ", ); let mut b = ir.builder(); let mut mangler = Mangler::new(); let b1 = map.get_block("entry"); let b1_arg = map.get_value("a"); let nil_term = b.value(NilTerm); mangler.start(ToT(b1)); mangler.add_rename(ToT(b1_arg), ToT(nil_term)); let new_b1 = mangler.run(&mut b); let after = crate::parse_function_unwrap( " a'foo':a'bar'/1 { entry(%ret, %thr, %a): %ret({[]}); } ", ); assert!(b .fun() .graph_eq(new_b1, &after, after.block_entry()) .is_ok()); } #[test] fn mangle_recursive() { let (mut ir, map) = crate::parse_function_map_unwrap( " a'foo':a'bar'/2 { entry(%ret, %thr, %a, %b): b2(%a); b1(%m): %ret(%t); b2(%p): %ret(%p); # This just exists to have a dummy variable available dummy(%t): %t(); } ", ); let mut b = ir.builder(); println!("{}", b.fun().to_text(&mut StandardFormatConfig::default())); let mut mangler = Mangler::new(); let entry = map.get_block("entry"); let b1 = map.get_block("b1"); let b1_val = b.fun().block_value(b1); let b2 = map.get_block("b2"); let b2_val = b.fun().block_value(b2); let vb = map.get_value("b"); let vt = map.get_value("t"); mangler.start(ToT(entry)); mangler.add_rename(ToT(b2_val), ToT(b1_val)); mangler.add_rename(ToT(vt), ToT(vb)); let new_entry = mangler.run(&mut b); b.block_set_entry(new_entry); println!("{}", b.fun().to_text(&mut StandardFormatConfig::default())); let after = crate::parse_function_unwrap( " a'foo':a'bar'/2 { entry(%ret, %thr, %a, %b): b1(%a); b1(%m): %ret(%b); } ", ); assert!(b .fun() .graph_eq(new_entry, &after, after.block_entry()) .is_ok()); } #[test] fn mangle_entry() { let (mut ir, map) = crate::parse_function_map_unwrap( " a'foo':a'bar'/0 { block0(%1, %2): unreachable; block1(%4, %5): block2(%5); block2(%7): %4(); } ", ); let entry = map.get_block("block0"); let mut b = ir.builder(); let mut mangler = Mangler::new(); mangler.start(ToT(entry)); mangler.add_rename( ToT(b.fun().block_value(map.get_block("block0"))), ToT(b.fun().block_value(map.get_block("block1"))), ); let new_entry = mangler.run(&mut b); b.block_set_entry(new_entry); println!("{}", b.fun().to_text(&mut StandardFormatConfig::default())); let mut errors = Vec::new(); b.fun().validate(&mut errors); assert_eq!(errors.len(), 0, "{:#?}", errors); let after = crate::parse_function_unwrap( " a'foo':a'bar'/0 { block3(%9, %10): block4(%10); block4(%12): %9(); } ", ); assert!(b .fun() .graph_eq(new_entry, &after, after.block_entry()) .is_ok()); //{ // value0#block0: ( // value17#block5, // true, // ), //# value1#block0[0]: ( //# value26#block7[0], //# true, //# ), //# value2#block0[1]: ( //# value27#block7[1], //# true, //# ), //# value3#block0[2]: ( //# value28#block7[2], //# true, //# ), // value5#block1[0]: ( // value15#block4[0], // true, // ), // value6#block1[1]: ( // value16#block4[1], // true, // ), // value8#block3: ( // value21#block6, // true, // ), //} } ================================================ FILE: libeir_ir/src/algo/mod.rs ================================================ pub mod equality; pub mod func_tree; pub mod live; pub mod mangle; pub mod op_branches; pub mod validate; ================================================ FILE: libeir_ir/src/algo/op_branches.rs ================================================ use crate::Function; use crate::{Block, CallKind, OpKind, Value}; pub struct BranchIter<'a> { fun: &'a Function, block: Block, num: usize, len: usize, } impl<'a> Iterator for BranchIter<'a> { type Item = Value; fn next(&mut self) -> Option { if self.num == self.len { None } else { let res = self.fun.op_branch_target(self.block, self.num); self.num += 1; Some(res) } } } /// These functions provide knowledge about what branches an operation can /// perform at specific locations in the IR. /// /// This is different from the information you get from the block graph in /// several ways: /// * If one operation has several branches to the same destination block, /// the block graph tells us nothing about that. /// * The block graph can contain an outgoing edge to a block that is not /// truly a direct call, but instead a function capture, this looks only /// at direct branches. /// * Likewise, the block graph will not have edges for calls to values, /// this does. /// * The block graph gives no information about the expected arity of the /// destination, and has no information about what those arguments are. impl Function { pub fn op_branch_iter<'a>(&'a self, block: Block) -> BranchIter<'a> { BranchIter { fun: self, block, num: 0, len: self.op_branch_len(block).unwrap(), } } pub fn op_branch_len(&self, block: Block) -> Option { let res = match self.block_kind(block)? { OpKind::Call(CallKind::ControlFlow) => 1, OpKind::Call(CallKind::Function) => 2, OpKind::Unreachable => 0, OpKind::IfBool => { let reads = self.block_reads(block); match reads.len() { 3 => 2, 4 => 3, _ => unreachable!(), } } OpKind::TraceCaptureRaw => 1, OpKind::TraceConstruct => 1, OpKind::UnpackValueList(_) => 1, OpKind::MapPut { .. } => 2, OpKind::Match { branches } => branches.len(), OpKind::Dyn(dyn_op) => { let op_branches = self.dialect().get_op_branches(&**dyn_op).unwrap(); op_branches.branches_len() } }; Some(res) } pub fn op_branch_target(&self, block: Block, n: usize) -> Value { let reads = self.block_reads(block); match (self.block_kind(block).unwrap(), reads.len(), n) { // For a control flow call, the only control flow branch // is the target. (OpKind::Call(CallKind::ControlFlow), _, 0) => reads[0], // For a function call, the only control flow branches are // the return and escape continuations. (OpKind::Call(CallKind::Function), _, 0) => reads[1], (OpKind::Call(CallKind::Function), _, 1) => reads[2], (OpKind::IfBool, 3, n) if n < 2 => reads[n], (OpKind::IfBool, 4, n) if n < 3 => reads[n], (OpKind::TraceCaptureRaw, _, 0) => reads[0], (OpKind::TraceConstruct, _, 0) => reads[0], (OpKind::UnpackValueList(_), _, 0) => reads[0], (OpKind::MapPut { .. }, _, n) if n < 2 => reads[n], (OpKind::Match { .. }, _, n) => self.value_list_get_n(reads[0], n).unwrap(), (OpKind::Dyn(dyn_op), _, _) => { let op_branches = self.dialect().get_op_branches(&**dyn_op).unwrap(); op_branches.branch_num(self, block, n) } _ => panic!(), } } } ================================================ FILE: libeir_ir/src/algo/validate.rs ================================================ use std::collections::HashSet; use fnv::FnvBuildHasher; use hashbrown::HashMap; type FnvHashMap = HashMap; use petgraph::algo::dominators::Dominators; use cranelift_bforest::{Set, SetForest}; use crate::{Block, Value}; use crate::{CallKind, Function, MatchKind, OpKind}; #[derive(Debug)] pub enum ValidationError { /// There was an empty block in the function, this is illegal EmptyBlock { block: Block, }, /// Tried to call a block with wrong arity BlockCallArity { caller: Block, callee: Block, attempted: usize, actual: usize, }, ValueCallArity { caller: Block, callee: Value, attempted: usize, actual: usize, }, /// The arity of the block marked as entry did not match with the identifier EntryArityMismatch, /// Tried to read a SSA variable that was not visible. InvalidRead { value: Value, block: Block, }, UnfinishedBlock { block: Block, }, } fn get_value_list<'a>(fun: &'a Function, value: Value) -> Option<&'a [Value]> { if let Some(prim) = fun.value_primop(value) { match fun.primop_kind(prim) { crate::PrimOpKind::ValueList => return Some(fun.primop_reads(prim)), _ => (), } } None } impl Function { pub fn validate(&self, errors: &mut Vec) { let block_graph = self.block_graph(); let doms = petgraph::algo::dominators::simple_fast(&block_graph, self.block_entry()); // Validate internal graph invariants self.graph_validate_global(); self.validate_entry_invariants(errors); self.validate_blocks(errors); self.validate_ssa_visibility(&doms, errors); } fn validate_call_to( &self, errors: &mut Vec, caller: Block, val: Value, arity: usize, ) { if let Some(block) = self.value_block(val) { let actual = self.block_args(block).len(); if actual != arity { errors.push(ValidationError::BlockCallArity { caller, callee: block, attempted: arity, actual, }); } } } fn validate_blocks(&self, errors: &mut Vec) { let block_graph = self.block_graph(); let entry = self.block_entry(); let ret_val = self.block_args(entry)[0]; let thr_val = self.block_args(entry)[1]; let mut dfs = block_graph.dfs(); while let Some(block) = dfs.next(&block_graph) { if let Some(kind) = self.block_kind(block) { let reads = self.block_reads(block); match kind { OpKind::Call(CallKind::ControlFlow) => { self.validate_call_to(errors, block, reads[0], reads.len() - 1); } OpKind::Call(CallKind::Function) => { self.validate_call_to(errors, block, reads[0], reads.len() - 1); self.validate_call_to(errors, block, reads[1], 1); self.validate_call_to(errors, block, reads[2], 3); if reads[0] == ret_val { if reads.len() != 2 { errors.push(ValidationError::ValueCallArity { caller: block, callee: ret_val, attempted: reads.len() - 1, actual: 1, }); } } if reads[0] == thr_val { if reads.len() != 4 { errors.push(ValidationError::ValueCallArity { caller: block, callee: thr_val, attempted: reads.len() - 1, actual: 3, }); } } } OpKind::IfBool => { self.validate_call_to(errors, block, reads[0], 0); self.validate_call_to(errors, block, reads[1], 0); if reads.len() == 4 { self.validate_call_to(errors, block, reads[2], 0); } else { assert!(reads.len() == 3); } } OpKind::UnpackValueList(n) => { self.validate_call_to(errors, block, reads[0], *n); } OpKind::Match { branches } => { let targets_opt = get_value_list(self, reads[0]); let other_targets = &[reads[0]]; let targets = targets_opt.unwrap_or(other_targets); assert!(targets.len() == branches.len()); for (branch, target) in branches.iter().zip(targets.iter()) { match branch { MatchKind::ListCell => { self.validate_call_to(errors, block, *target, 2); } MatchKind::MapItem => { self.validate_call_to(errors, block, *target, 1); } MatchKind::Tuple(n) => { self.validate_call_to(errors, block, *target, *n); } MatchKind::Type(_) => { self.validate_call_to(errors, block, *target, 0); } MatchKind::Value => { self.validate_call_to(errors, block, *target, 0); } MatchKind::Wildcard => { self.validate_call_to(errors, block, *target, 0); } _ => (), } } } _ => (), // TODO validate more types } } else { errors.push(ValidationError::EmptyBlock { block }); } } } fn validate_entry_invariants(&self, errors: &mut Vec) { let entry = self.block_entry(); let arity = self.block_args(entry).len(); // In the calling convention, the first two arguments are (ok_cont, err_cont) if arity != self.ident().arity + 2 { errors.push(ValidationError::EntryArityMismatch); } } } impl Function { /// Strictly validate SSA visibility /// /// It operates on the following principle: /// * The set of SSA variables visible at the beginning of a block is /// (the SSA variables visible at its immediate dominator) /// + (the set of SSA variables declared in the arguments). /// /// More specifically: /// * Seed the live variable map with the entry node. /// * While there are basic blocks missing from our live variable map: /// * Loop through the set of missing blocks: /// * Calculate the live variables in the block if its /// immediate dominator has already been calculated, otherwise /// skip. /// * Go through each basic block in the cfg and validate that it only /// references live variables. fn validate_ssa_visibility(&self, doms: &Dominators, errors: &mut Vec) { let entry_block = self.block_entry(); let mut pool = SetForest::new(); // Live variables on block entry and exit let mut live_variables: FnvHashMap> = FnvHashMap::with_hasher(Default::default()); // Seed entry node let entry_vals = Set::new(); self.insert_live_for_node(entry_block, entry_vals, &mut pool, &mut live_variables); // Iterate until all calculated let mut missing_nodes: HashSet<_> = self.block_graph().dfs_iter().collect(); missing_nodes.remove(&entry_block); let mut processed = Vec::new(); while !missing_nodes.is_empty() { for node in missing_nodes.iter() { if let Some(idom) = doms.immediate_dominator(*node) { // If the immediate dominator is already processed, process this block. if let Some(idom_live) = live_variables.get(&idom) { let live = idom_live.make_copy(&mut pool); self.insert_live_for_node(*node, live, &mut pool, &mut live_variables); processed.push(*node); } } else { // Since we only go through nodes that are alive, that is, reachable // from the entry point, all nodes (except the entry itself), should // have an idom unreachable!() } } // Remove processed if !missing_nodes.is_empty() { assert!(!processed.is_empty()); } for proc in processed.iter() { missing_nodes.remove(proc); } processed.clear(); } // Go through all blocks and validate visibility for block in self.block_graph().dfs_iter() { let visible = &live_variables[&block]; for read in self.block_reads(block) { self.value_walk_nested_values::<_, ()>(*read, &mut |val| { if self.value_argument(val).is_some() && !visible.contains(val, &pool, &()) { errors.push(ValidationError::InvalidRead { value: val, block }); } Ok(()) }) .unwrap(); } } } fn insert_live_for_node( &self, block: Block, mut base_set: Set, pool: &mut SetForest, live: &mut FnvHashMap>, ) { for arg in self.block_args(block) { base_set.insert(*arg, pool, &()); } live.insert(block, base_set); } } ================================================ FILE: libeir_ir/src/binary.rs ================================================ use serde::{Deserialize, Serialize}; use std::default::Default; #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] pub enum Endianness { Big, Little, Native, } #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] pub enum BinaryEntrySpecifier { Integer { signed: bool, endianness: Endianness, unit: i64, }, Float { endianness: Endianness, unit: i64, }, Bytes { unit: i64, }, Bits { unit: i64, }, Utf8, Utf16 { endianness: Endianness, }, Utf32 { endianness: Endianness, }, } impl BinaryEntrySpecifier { pub fn has_size(&self) -> bool { match self { BinaryEntrySpecifier::Utf8 => false, BinaryEntrySpecifier::Utf16 { .. } => false, BinaryEntrySpecifier::Utf32 { .. } => false, _ => true, } } pub fn is_native_endian(&self) -> bool { match self { BinaryEntrySpecifier::Integer { endianness: Endianness::Native, .. } => true, BinaryEntrySpecifier::Float { endianness: Endianness::Native, .. } => true, BinaryEntrySpecifier::Utf16 { endianness: Endianness::Native, .. } => true, BinaryEntrySpecifier::Utf32 { endianness: Endianness::Native, .. } => true, _ => false, } } } impl Default for BinaryEntrySpecifier { fn default() -> Self { BinaryEntrySpecifier::Integer { signed: false, endianness: Endianness::Big, unit: 1, } } } ================================================ FILE: libeir_ir/src/constant/atomic.rs ================================================ use std::fmt::{Display, Formatter, Result as FmtResult}; use std::hash::{Hash, Hasher}; use libeir_util_number::{cast, BigInt, Float, NumCast, Number}; use libeir_util_binary::BitVec; use libeir_intern::Symbol; use super::float::raw_double_bits; use super::Integer; impl From for AtomicTerm { fn from(int: Integer) -> AtomicTerm { match int { Integer::Big(n) => AtomicTerm::BigInt(BigIntTerm(n)), Integer::Small(n) => AtomicTerm::Int(IntTerm(n)), } } } #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct BigIntTerm(pub BigInt); impl BigIntTerm { #[inline] pub fn value(&self) -> &BigInt { &self.0 } } impl Into for BigIntTerm { #[inline] fn into(self) -> BigInt { self.0 } } impl From for AtomicTerm { fn from(data: BigIntTerm) -> Self { AtomicTerm::BigInt(data) } } impl From for AtomicTerm { fn from(data: BigInt) -> Self { AtomicTerm::BigInt(BigIntTerm(data)) } } impl Display for BigIntTerm { fn fmt(&self, fmt: &mut Formatter) -> FmtResult { write!(fmt, "{}", self.0) } } #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct IntTerm(pub i64); impl IntTerm { #[inline] pub fn value(&self) -> i64 { self.0 } } impl Into for IntTerm { #[inline] fn into(self) -> i64 { self.0 } } impl From for AtomicTerm { fn from(data: IntTerm) -> Self { AtomicTerm::Int(data) } } impl Display for IntTerm { fn fmt(&self, fmt: &mut Formatter) -> FmtResult { write!(fmt, "{}", self.0) } } fn from_num(n: N) -> AtomicTerm where N: NumCast, { if let Some(int) = cast(n) { AtomicTerm::Int(IntTerm(int)) } else { // TODO bigint unimplemented!() } } macro_rules! impl_from_num { ($typ:ty) => { impl From<$typ> for AtomicTerm { fn from(data: $typ) -> Self { from_num(data) } } }; } impl_from_num!(usize); impl_from_num!(i32); impl_from_num!(i64); impl_from_num!(u32); impl_from_num!(u64); impl From for AtomicTerm { fn from(data: char) -> Self { from_num(data as i64) } } #[derive(Debug, Clone, PartialEq)] pub struct FloatTerm(pub Float); impl FloatTerm { #[inline] pub fn value(&self) -> f64 { self.0.inner() } } impl Eq for FloatTerm {} #[allow(clippy::derive_hash_xor_eq)] impl Hash for FloatTerm { fn hash(&self, state: &mut H) where H: Hasher, { raw_double_bits(&self.value()).hash(state) } } impl From for AtomicTerm { fn from(data: FloatTerm) -> Self { AtomicTerm::Float(data) } } impl From for AtomicTerm { fn from(data: f64) -> Self { AtomicTerm::Float(FloatTerm(Float::new(data).unwrap())) } } impl From for AtomicTerm { fn from(data: Float) -> Self { AtomicTerm::Float(FloatTerm(data)) } } impl From for AtomicTerm { fn from(data: Number) -> Self { match data { Number::Float(float) => float.into(), Number::Integer(int) => int.into(), } } } impl Display for FloatTerm { fn fmt(&self, fmt: &mut Formatter) -> FmtResult { write!(fmt, "f{}", self.0) } } #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] pub struct AtomTerm(pub Symbol); impl From for AtomicTerm { fn from(data: AtomTerm) -> Self { AtomicTerm::Atom(data) } } impl From for AtomicTerm { fn from(data: Symbol) -> Self { AtomTerm(data).into() } } impl From for AtomicTerm { fn from(data: bool) -> Self { let sym = if data { Symbol::intern("true") } else { Symbol::intern("false") }; AtomTerm(sym).into() } } impl PartialEq for AtomTerm { fn eq(&self, other: &str) -> bool { self.0 == other } } impl Display for AtomTerm { fn fmt(&self, fmt: &mut Formatter) -> FmtResult { write!(fmt, "a'{}'", self.0) // TODO escape } } #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct BinaryTerm(pub BitVec); impl BinaryTerm { #[inline] pub fn value(&self) -> &BitVec { &self.0 } } impl From for AtomicTerm { fn from(data: BinaryTerm) -> Self { AtomicTerm::Binary(data) } } impl From> for AtomicTerm { fn from(data: Vec) -> Self { AtomicTerm::Binary(BinaryTerm(data.into())) } } impl From for AtomicTerm { fn from(data: BitVec) -> Self { AtomicTerm::Binary(BinaryTerm(data)) } } #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct NilTerm; impl From for AtomicTerm { fn from(_data: NilTerm) -> Self { AtomicTerm::Nil } } #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub enum AtomicTerm { Int(IntTerm), BigInt(BigIntTerm), Float(FloatTerm), Atom(AtomTerm), Binary(BinaryTerm), Nil, } impl Display for AtomicTerm { fn fmt(&self, fmt: &mut Formatter) -> FmtResult { match self { AtomicTerm::Int(int) => write!(fmt, "{}", int), AtomicTerm::BigInt(int) => write!(fmt, "{}", int), AtomicTerm::Float(float) => write!(fmt, "{}", float), AtomicTerm::Atom(atom) => write!(fmt, "{}", atom), AtomicTerm::Nil => write!(fmt, "[]"), AtomicTerm::Binary(_bin) => write!(fmt, "bin"), } } } ================================================ FILE: libeir_ir/src/constant/float.rs ================================================ use libeir_util_number::traits::Float; // Copied from https://github.com/reem/rust-ordered-float // masks for the parts of the IEEE 754 float const SIGN_MASK: u64 = 0x8000_0000_0000_0000u64; const EXP_MASK: u64 = 0x7ff0_0000_0000_0000u64; const MAN_MASK: u64 = 0x000f_ffff_ffff_ffffu64; // canonical raw bit patterns (for hashing) const CANONICAL_NAN_BITS: u64 = 0x7ff8_0000_0000_0000u64; const CANONICAL_ZERO_BITS: u64 = 0x0u64; #[inline] pub fn raw_double_bits(f: &F) -> u64 { if f.is_nan() { return CANONICAL_NAN_BITS; } let (man, exp, sign) = f.integer_decode(); if man == 0 { return CANONICAL_ZERO_BITS; } //let exp_u64 = unsafe { mem::transmute::(exp) } as u64; let exp_u64 = exp as u64; let sign_u64 = if sign > 0 { 1u64 } else { 0u64 }; (man & MAN_MASK) | ((exp_u64 << 52) & EXP_MASK) | ((sign_u64 << 63) & SIGN_MASK) } ================================================ FILE: libeir_ir/src/constant/mod.rs ================================================ use std::hash::{Hash, Hasher}; use libeir_intern::Ident; use libeir_util_datastructures::aux_hash_map::AuxHashMap; use libeir_util_datastructures::aux_traits::{AuxEq, AuxHash}; use cranelift_entity::{entity_impl, EntityList, ListPool, PrimaryMap}; mod atomic; pub use atomic::*; mod float; pub use libeir_util_number::{FromPrimitive, Integer, ToPrimitive}; /// These entities has the property that if they are equal, they /// represent the same value. #[derive(Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] pub struct Const(u32); entity_impl!(Const, "const_value"); #[derive(Debug, Clone)] pub enum ConstKind { Atomic(AtomicTerm), ListCell { head: Const, tail: Const, }, Tuple { entries: EntityList, }, Map { /// Key/value pairs are ALWAYS ordered by key constant index keys: EntityList, values: EntityList, }, } impl AuxHash> for ConstKind { fn aux_hash(&self, state: &mut H, container: &ListPool) { match self { ConstKind::Atomic(atomic) => { 0.hash(state); atomic.hash(state); } ConstKind::ListCell { head, tail } => { 1.hash(state); head.hash(state); tail.hash(state); } ConstKind::Tuple { entries } => { 2.hash(state); entries.as_slice(container).hash(state); } ConstKind::Map { keys, values } => { 3.hash(state); keys.as_slice(container).hash(state); values.as_slice(container).hash(state); } } } } impl AuxEq> for ConstKind { fn aux_eq( &self, rhs: &ConstKind, self_aux: &ListPool, other_aux: &ListPool, ) -> bool { match (self, rhs) { (ConstKind::Atomic(l), ConstKind::Atomic(r)) => l == r, ( ConstKind::ListCell { head: lh, tail: lt }, ConstKind::ListCell { head: rh, tail: rt }, ) => lh == rh && lt == rt, (ConstKind::Tuple { entries: l }, ConstKind::Tuple { entries: r }) => { l.as_slice(self_aux) == r.as_slice(other_aux) } ( ConstKind::Map { keys: lk, values: lv, }, ConstKind::Map { keys: rk, values: rv, }, ) => { lk.as_slice(self_aux) == rk.as_slice(other_aux) && lv.as_slice(self_aux) == rv.as_slice(other_aux) } _ => false, } } } impl ConstKind { pub fn is_map(&self) -> bool { match self { ConstKind::Map { .. } => true, _ => false, } } } #[derive(Debug, Clone)] pub struct ConstantContainer { const_values: PrimaryMap, value_map: AuxHashMap>, pub const_pool: ListPool, } impl Default for ConstantContainer { fn default() -> Self { ConstantContainer { const_values: PrimaryMap::new(), value_map: AuxHashMap::new(), const_pool: ListPool::new(), } } } impl ConstantContainer { pub fn new() -> Self { Self::default() } pub fn const_kind(&self, value: Const) -> &ConstKind { &self.const_values[value] } pub fn list_cell(&mut self, head: Const, tail: Const) -> Const { self.from(ConstKind::ListCell { head, tail }) } pub fn nil(&mut self) -> Const { self.from(NilTerm) } pub fn from(&mut self, val: T) -> Const where T: IntoConst, { val.into_const(self) } pub fn get(&self, val: T) -> Option where T: IntoConst, { val.get_const(self) } //pub fn print(&self, val: Const, fmt: &mut T) //where T: crate::text::TextFormatter //{ // match &self.const_values[val] { // ConstKind::Atomic(atomic) => { // fmt.write(&format!("{}", atomic)); // } // _ => unimplemented!() // } //} pub fn as_bool(&self, val: Const) -> Option { let kind = &self.const_values[val]; match kind { ConstKind::Atomic(AtomicTerm::Atom(atom)) if atom == "true" => Some(true), ConstKind::Atomic(AtomicTerm::Atom(atom)) if atom == "false" => Some(false), _ => None, } } pub fn write(&self, val: Const, out: &mut dyn std::io::Write) { match &self.const_values[val] { ConstKind::Atomic(atomic) => { write!(out, "{}", atomic).unwrap(); } ConstKind::ListCell { head, tail } => { write!(out, "[").unwrap(); self.write(*head, out); write!(out, " | ").unwrap(); self.write(*tail, out); write!(out, "]").unwrap(); } ConstKind::Tuple { entries } => { write!(out, "{{").unwrap(); for (n, entry) in entries.as_slice(&self.const_pool).iter().enumerate() { if n != 0 { write!(out, ", ").unwrap(); } self.write(*entry, out); } write!(out, "}}").unwrap(); } ConstKind::Map { keys, values } => { write!(out, "%{{").unwrap(); for (n, (key, val)) in keys .as_slice(&self.const_pool) .iter() .zip(values.as_slice(&self.const_pool)) .enumerate() { if n != 0 { write!(out, ", ").unwrap(); } self.write(*key, out); write!(out, ": ").unwrap(); self.write(*val, out); } write!(out, "}}").unwrap(); } } } pub fn tuple_builder(&self) -> TupleBuilder { TupleBuilder::new() } pub fn eq_other(&self, l: Const, r_cont: &ConstantContainer, r: Const) -> bool { match (&self.const_values[l], &r_cont.const_values[r]) { (ConstKind::Atomic(la), ConstKind::Atomic(ra)) if la == ra => true, (ConstKind::Atomic(_), ConstKind::Atomic(_)) => false, (ConstKind::Tuple { entries: t1 }, ConstKind::Tuple { entries: t2 }) => { let s1 = t1.as_slice(&self.const_pool); let s2 = t2.as_slice(&r_cont.const_pool); if s1.len() != s2.len() { return false; } for (e1, e2) in s1.iter().zip(s2.iter()) { if !self.eq_other(*e1, r_cont, *e2) { return false; } } true } l => unimplemented!("{:?}", l), } } } pub trait IntoConst { fn into_const(self, c: &mut ConstantContainer) -> Const; fn get_const(self, fun: &ConstantContainer) -> Option; } pub struct EmptyMap; impl IntoConst for EmptyMap { fn into_const(self, c: &mut ConstantContainer) -> Const { c.from(ConstKind::Map { keys: EntityList::new(), values: EntityList::new(), }) } fn get_const(self, c: &ConstantContainer) -> Option { c.get(ConstKind::Map { keys: EntityList::new(), values: EntityList::new(), }) } } impl IntoConst for T where T: Into, { fn into_const(self, c: &mut ConstantContainer) -> Const { c.from(ConstKind::Atomic(self.into())) } fn get_const(self, c: &ConstantContainer) -> Option { c.get(ConstKind::Atomic(self.into())) } } impl IntoConst for ConstKind { fn into_const(self, c: &mut ConstantContainer) -> Const { if let Some(val) = c.value_map.get(&self, &c.const_pool) { *val } else { let val = c.const_values.push(self.clone()); c.value_map.try_insert(self, val, &c.const_pool).unwrap(); val } } fn get_const(self, c: &ConstantContainer) -> Option { c.value_map.get(&self, &c.const_pool).cloned() } } impl IntoConst for Const { fn into_const(self, _c: &mut ConstantContainer) -> Const { self } fn get_const(self, _c: &ConstantContainer) -> Option { Some(self) } } impl IntoConst for Ident { fn into_const(self, c: &mut ConstantContainer) -> Const { self.name.into_const(c) } fn get_const(self, c: &ConstantContainer) -> Option { self.name.get_const(c) } } pub struct TupleBuilder { elements: EntityList, } impl TupleBuilder { pub fn new() -> Self { TupleBuilder { elements: EntityList::new(), } } pub fn push(&mut self, elem: Const, c: &mut ConstantContainer) { self.elements.push(elem, &mut c.const_pool); } pub fn clear(mut self, c: &mut ConstantContainer) { self.elements.clear(&mut c.const_pool); } pub fn finish(self, c: &mut ConstantContainer) -> Const { c.from(ConstKind::Tuple { entries: self.elements, }) } } //struct TupleTerm>(I); //impl> IntoConst for TupleTerm { // fn into_const(self, c: &mut ConstantContainer) -> Const { // for typ // } //} ================================================ FILE: libeir_ir/src/dialect/mod.rs ================================================ use std::any::TypeId; use std::collections::{HashMap, HashSet}; use std::fmt::{self, Debug, Formatter}; use std::sync::Arc; use lazy_static::lazy_static; use libeir_intern::Symbol; use meta_table::{MetaEntry, MetaTable}; use crate::operation::{self as op, Op}; use crate::traits::{OpBranches, OpParser, OpPrinter}; lazy_static! { pub static ref NORMAL: ArcDialect = { let mut d = Dialect::new(); op::receive::register(&mut d); op::binary_construct::register(&mut d); op::case::register(&mut d); Arc::new(d) }; } pub type ArcDialect = Arc; // TODO: Expose better interface for registering trait implementations. pub struct Dialect { /// This is the full set of operations that are registered for this dialect. operations: HashSet, op_branches: MetaTable, op_printer: MetaTable, op_parser: HashMap>, } impl Debug for Dialect { fn fmt(&self, fmt: &mut Formatter) -> Result<(), fmt::Error> { write!(fmt, "{:?}", self.operations) } } impl Dialect { pub fn new() -> Self { Self { operations: HashSet::new(), op_branches: MetaTable::new(), op_printer: MetaTable::new(), op_parser: HashMap::new(), } } pub fn contains_op(&self) -> bool { self.operations.contains(&TypeId::of::()) } pub fn register_op(&mut self) { self.operations.insert(TypeId::of::()); } pub fn register_op_branches_impl(&mut self) { assert!(self.operations.contains(&TypeId::of::())); self.op_branches.register::(); } pub fn get_op_branches<'a>(&self, obj: &'a dyn Op) -> Option<&'a dyn OpBranches> { self.op_branches.get(obj.meta_entry()) } pub fn register_op_printer_impl(&mut self) { assert!(self.operations.contains(&TypeId::of::())); self.op_printer.register::(); } pub fn get_op_printer<'a>(&self, obj: &'a dyn Op) -> Option<&'a dyn OpPrinter> { self.op_printer.get(obj.meta_entry()) } pub fn register_op_parser(&mut self, sym: Symbol, parser: Box) { self.op_parser.insert(sym, parser); } pub fn get_op_parser(&self, sym: Symbol) -> Option<&dyn OpParser> { self.op_parser.get(&sym).map(|v| &**v) } } ================================================ FILE: libeir_ir/src/function/builder/mod.rs ================================================ use libeir_diagnostics::SourceSpan; use super::Function; use super::ValueKind; use super::{Block, Const, Location, OpKind, PrimOp, Value}; use super::{PrimOpData, PrimOpKind}; use crate::constant::{ConstantContainer, IntoConst}; use crate::BinOp; use cranelift_entity::EntityList; mod op; mod primop; impl Function { pub fn builder(&mut self) -> FunctionBuilder<'_> { FunctionBuilder::new(self) } } pub trait IntoValue { fn into_value<'a>(self, b: &mut FunctionBuilder<'a>) -> Value; fn get_value(self, fun: &Function) -> Option; } impl IntoValue for Value { fn into_value<'a>(self, _b: &mut FunctionBuilder<'a>) -> Value { self } fn get_value(self, _fun: &Function) -> Option { Some(self) } } impl IntoValue for Block { fn into_value<'a>(self, b: &mut FunctionBuilder<'a>) -> Value { b.fun.values.push(ValueKind::Block(self)) } fn get_value(self, fun: &Function) -> Option { fun.values.get(ValueKind::Block(self)) } } impl IntoValue for PrimOp { fn into_value<'a>(self, b: &mut FunctionBuilder<'a>) -> Value { b.fun.values.push(ValueKind::PrimOp(self)) } fn get_value(self, fun: &Function) -> Option { fun.values.get(ValueKind::PrimOp(self)) } } impl IntoValue for T where T: IntoConst, { fn into_value<'a>(self, b: &mut FunctionBuilder<'a>) -> Value { let constant = b.fun.constant_container.from(self); let value = b.fun.values.push(ValueKind::Const(constant)); b.fun.constant_values.insert(value); value } fn get_value(self, fun: &Function) -> Option { let constant = fun.constant_container.get(self); constant.and_then(|v| fun.values.get(ValueKind::Const(v))) } } pub enum DynValue { Value(Value), Block(Block), PrimOp(PrimOp), Const(Const), } impl Into for Value { fn into(self) -> DynValue { DynValue::Value(self) } } impl Into for Block { fn into(self) -> DynValue { DynValue::Block(self) } } impl Into for PrimOp { fn into(self) -> DynValue { DynValue::PrimOp(self) } } impl Into for Const { fn into(self) -> DynValue { DynValue::Const(self) } } impl IntoValue for DynValue { fn into_value<'a>(self, b: &mut FunctionBuilder<'a>) -> Value { match self { DynValue::Value(val) => val, DynValue::Block(block) => b.value(block), DynValue::PrimOp(prim) => b.value(prim), DynValue::Const(cons) => b.value(cons), } } fn get_value(self, fun: &Function) -> Option { match self { DynValue::Value(val) => Some(val), DynValue::Block(block) => fun.value_get(block), DynValue::PrimOp(prim) => fun.value_get(prim), DynValue::Const(cons) => fun.value_get(cons), } } } pub struct FunctionBuilder<'a> { fun: &'a mut Function, block_buf: Option>, value_buf: Option>, const_pair_buf: Option>, value_pair_buf: Option>, //mangler: Mangler, } impl<'a> FunctionBuilder<'a> { pub fn new(fun: &'a mut Function) -> FunctionBuilder<'a> { // TODO separate allocated data structures into separate // reusable struct FunctionBuilder { fun, block_buf: Some(Vec::new()), value_buf: Some(Vec::new()), const_pair_buf: Some(Vec::new()), value_pair_buf: Some(Vec::new()), } } pub fn fun(&self) -> &Function { &self.fun } pub fn fun_mut(&mut self) -> &mut Function { &mut self.fun } pub fn cons(&self) -> &ConstantContainer { &self.fun.constant_container } pub fn cons_mut(&mut self) -> &mut ConstantContainer { &mut self.fun.constant_container } } /// Values impl<'a> FunctionBuilder<'a> { pub fn value(&mut self, v: T) -> Value where T: IntoValue, { v.into_value(self) } pub fn value_map(&mut self, mut value: Value, map: &mut F) -> Value where F: FnMut(Value) -> Option, { if let Some(new) = map(value) { value = new; } match self.fun().value_kind(value) { ValueKind::PrimOp(prim) => { let mut values = self.fun().primop_reads(prim).to_owned(); for val in values.iter_mut() { debug_assert!(*val != value); let new_val = self.value_map(*val, map); *val = new_val; } let kind = self.fun().primop_kind(prim).clone(); let span = self .fun() .value_locations(value) .map(|spans| spans.first().copied().unwrap_or(SourceSpan::UNKNOWN)) .unwrap_or(SourceSpan::UNKNOWN); self.prim_from_kind(span, kind, &values) } _ => value, } } } /// Graph impl<'a> FunctionBuilder<'a> { /// Updates the successors in the graph from the reads. /// Mainly used in the builder. pub(crate) fn graph_update_block(&mut self, block: Block) { let mut block_buf = self.block_buf.take().unwrap(); let mut value_buf = self.value_buf.take().unwrap(); debug_assert!(block_buf.is_empty()); debug_assert!(value_buf.is_empty()); // 1. Remove the block from all previous successors predecessor sets { let block_data = &self.fun.blocks[block]; for successor in block_data.successors.iter(&self.fun.pool.block_set) { block_buf.push(successor); } } for successor in block_buf.iter() { let block_data = &mut self.fun.blocks[*successor]; block_data .predecessors .remove(*successor, &mut self.fun.pool.block_set, &()); } // 2. Add new successors to block block_buf.clear(); { self.fun .block_walk_nested_values::<_, ()>(block, &mut |val| { value_buf.push(val); Ok(()) }) .unwrap(); let block_data = &mut self.fun.blocks[block]; block_data.successors.clear(&mut self.fun.pool.block_set); for value in value_buf.iter() { let value_data = &mut self.fun.values[*value]; // Insert block as usage of value value_data .usages .insert(block, &mut self.fun.pool.block_set, &()); // If the value is a block capture, insert into successors // for current block if let ValueKind::Block(dest_block) = &value_data.kind { block_data .successors .insert(*dest_block, &mut self.fun.pool.block_set, &()); block_buf.push(*dest_block); } } } // 3. Add block as predecessor to all successors for dest_block in block_buf.iter() { let block_data = &mut self.fun.blocks[*dest_block]; block_data .predecessors .insert(block, &mut self.fun.pool.block_set, &()); } block_buf.clear(); value_buf.clear(); self.block_buf = Some(block_buf); self.value_buf = Some(value_buf); } } /// Block modifiers impl<'a> FunctionBuilder<'a> { pub fn block_insert(&mut self) -> Block { self.fun.block_insert() } pub fn block_insert_with_span(&mut self, span: Option) -> Block { self.fun.block_insert_with_span(span) } /// Inserts a new block and get its value pub fn block_insert_get_val(&mut self) -> (Block, Value) { let block = self.block_insert(); let val = self.value(block); (block, val) } pub fn block_arg_insert(&mut self, block: Block) -> Value { self.fun.block_arg_insert(block) } pub fn block_args(&self, block: Block) -> &[Value] { self.fun.block_args(block) } pub fn block_reads(&self, block: Block) -> &[Value] { self.fun.block_reads(block) } pub fn block_set_entry(&mut self, block: Block) { self.fun.entry_block = Some(block); } pub fn block_set_location(&mut self, block: Block, loc: Location) { self.fun.blocks[block].location = loc; } pub fn block_clear_take(&mut self, block: Block) -> Option { #[cfg(debug_assertions)] self.fun().graph_validate_block(block); let mut value_buf = self.value_buf.take().unwrap(); debug_assert!(value_buf.is_empty()); let op; { let data = self.fun.blocks.get_mut(block).unwrap(); op = data.op.take(); for read in data.reads.as_slice(&self.fun.pool.value) { value_buf.push(*read); } data.successors.clear(&mut self.fun.pool.block_set); data.reads.clear(&mut self.fun.pool.value); } for value in value_buf.iter() { let data = &mut self.fun.values[*value]; data.usages.remove(block, &mut self.fun.pool.block_set, &()); if let ValueKind::Block(successor_block) = data.kind { let data = self.fun.blocks.get_mut(successor_block).unwrap(); data.predecessors .remove(block, &mut self.fun.pool.block_set, &()); } } value_buf.clear(); self.value_buf = Some(value_buf); op } /// This will explicitly clear the operation contained in the /// block. This will remove all successors, and will cause /// this block to be removed from their predecessors. pub fn block_clear(&mut self, block: Block) { self.block_clear_take(block); } pub fn block_value_map(&mut self, block: Block, mut map: F) where F: FnMut(Value) -> Value, { let num_reads = self.fun.block_reads(block).len(); let mut new_reads = EntityList::new(); for val_num in 0..num_reads { let val = self.fun.block_reads(block)[val_num]; let new_val = self.value_map(val, &mut |v| Some(map(v))); new_reads.push(new_val, &mut self.fun.pool.value); } self.fun.blocks[block].reads = new_reads; } pub fn block_copy_body_map(&mut self, from: Block, to: Block, mut map: F) where F: FnMut(Value) -> Option, { let op; let loc; { let from_data = &self.fun.blocks[from]; op = from_data.op.clone(); loc = from_data.location; } let mut reads = EntityList::new(); { let len = self.fun.block_reads(from).len(); for n in 0..len { let val = self.fun.block_reads(from)[n]; let new = self.value_map(val, &mut map); reads.push(new, &mut self.fun.pool.value); } } let to_data = &mut self.fun.blocks[to]; to_data.op = op; to_data.reads = reads; to_data.location = loc; self.graph_update_block(to); } } #[cfg(test)] mod tests { use super::*; use crate::FunctionIdent; use libeir_diagnostics::SourceSpan; use libeir_intern::Ident; #[test] fn graph_impl() { let ident = FunctionIdent { module: Ident::from_str("test"), name: Ident::from_str("test"), arity: 1, }; let mut fun = Function::new(SourceSpan::UNKNOWN, ident); let mut b = fun.builder(); { let ba = b.block_insert(); let bb = b.block_insert(); b.op_call_flow(ba, bb, &[]); b.block_clear(ba); b.fun().graph_validate_global(); let bc = b.block_insert(); b.op_call_flow(ba, bc, &[]); b.fun().graph_validate_global(); } } } ================================================ FILE: libeir_ir/src/function/builder/op.rs ================================================ use cranelift_entity::EntityList; use libeir_diagnostics::SourceSpan; use crate::binary::BinaryEntrySpecifier; use crate::operation::{DynOp, OpBuild}; use crate::IntoValue; use crate::{BasicType, CallKind, MapPutUpdate, MatchKind, OpKind}; use crate::{Block, Value}; use super::FunctionBuilder; /// Operation constructors impl<'a> FunctionBuilder<'a> { pub fn op_call_flow<'b, V>(&'b mut self, block: Block, target: V, args: &[Value]) where V: IntoValue, { let target_val = self.value(target); let data = self.fun.blocks.get_mut(block).unwrap(); assert!(data.op.is_none()); assert!(data.reads.is_empty()); data.op = Some(OpKind::Call(CallKind::ControlFlow)); data.reads.push(target_val, &mut self.fun.pool.value); data.reads .extend(args.iter().cloned(), &mut self.fun.pool.value); self.graph_update_block(block); } pub fn op_call_function_next<'b, V>( &'b mut self, span: SourceSpan, block: Block, target: V, ret: Value, thr: Value, args: &[Value], ) where V: IntoValue, { let target_val = self.value(target); let data = self.fun.blocks.get_mut(block).unwrap(); assert!(data.op.is_none()); assert!(data.reads.is_empty()); data.op = Some(OpKind::Call(CallKind::Function)); data.reads.push(target_val, &mut self.fun.pool.value); data.reads.push(ret, &mut self.fun.pool.value); data.reads.push(thr, &mut self.fun.pool.value); data.reads .extend(args.iter().cloned(), &mut self.fun.pool.value); self.graph_update_block(block); } pub fn op_call_function<'b, V>( &'b mut self, span: SourceSpan, block: Block, target: V, args: &[Value], ) -> (Block, Block) where V: IntoValue, { let (ret, ret_val) = self.block_insert_get_val(); self.block_arg_insert(ret); let (thr, thr_val) = self.block_insert_get_val(); self.block_arg_insert(thr); self.block_arg_insert(thr); self.block_arg_insert(thr); self.op_call_function_next(span, block, target, ret_val, thr_val, args); (ret, thr) } pub fn op_trace_capture_raw_next(&mut self, span: SourceSpan, block: Block, next: Value) { let data = self.fun.blocks.get_mut(block).unwrap(); assert!(data.op.is_none()); assert!(data.reads.is_empty()); data.op = Some(OpKind::TraceCaptureRaw); data.reads.push(next, &mut self.fun.pool.value); self.graph_update_block(block); } pub fn op_trace_capture_raw(&mut self, span: SourceSpan, block: Block) -> Block { let cont = self.fun.block_insert(); let cont_val = self.value(cont); self.fun.block_arg_insert(cont); self.op_trace_capture_raw_next(span, block, cont_val); cont } pub fn op_intrinsic<'b, O: OpBuild>( &'b mut self, block: Block, op: O, args: &[Value], _token: O::Token, ) { assert!(self.fun.dialect.contains_op::()); let data = self.fun.blocks.get_mut(block).unwrap(); assert!(data.op.is_none()); assert!(data.reads.is_empty()); let dyn_op = DynOp::new(op); data.op = Some(OpKind::Dyn(dyn_op)); data.reads .extend(args.iter().cloned(), &mut self.fun.pool.value); self.graph_update_block(block); } pub fn op_map_put_build(&mut self, span: SourceSpan, value: Value) -> MapPutBuilder { MapPutBuilder::new(span, value, self) } pub fn op_unpack_value_list_next( &mut self, block: Block, target: Value, list: Value, num: usize, ) { let data = self.fun.blocks.get_mut(block).unwrap(); assert!(data.op.is_none()); assert!(data.reads.is_empty()); data.op = Some(OpKind::UnpackValueList(num)); data.reads.push(target, &mut self.fun.pool.value); data.reads.push(list, &mut self.fun.pool.value); self.graph_update_block(block); } pub fn op_unpack_value_list(&mut self, block: Block, list: Value, num: usize) -> Block { let cont = self.fun.block_insert(); let cont_val = self.value(cont); for _ in 0..num { self.fun.block_arg_insert(cont); } self.op_unpack_value_list_next(block, cont_val, list, num); cont } pub fn op_if_bool_next( &mut self, span: SourceSpan, block: Block, t: Value, f: Value, o: Value, value: Value, ) { let data = self.fun.blocks.get_mut(block).unwrap(); assert!(data.op.is_none()); assert!(data.reads.is_empty()); data.op = Some(OpKind::IfBool); data.reads.push(t, &mut self.fun.pool.value); data.reads.push(f, &mut self.fun.pool.value); data.reads.push(o, &mut self.fun.pool.value); data.reads.push(value, &mut self.fun.pool.value); self.graph_update_block(block); } pub fn op_if_bool( &mut self, span: SourceSpan, block: Block, value: Value, ) -> (Block, Block, Block) { let true_cont = self.fun.block_insert(); let true_cont_val = self.value(true_cont); let false_cont = self.fun.block_insert(); let false_cont_val = self.value(false_cont); let non_cont = self.fun.block_insert(); let non_cont_val = self.value(non_cont); self.op_if_bool_next( span, block, true_cont_val, false_cont_val, non_cont_val, value, ); (true_cont, false_cont, non_cont) } pub fn op_if_bool_strict_next( &mut self, span: SourceSpan, block: Block, t: Value, f: Value, value: Value, ) { let data = self.fun.blocks.get_mut(block).unwrap(); assert!(data.op.is_none()); assert!(data.reads.is_empty()); data.op = Some(OpKind::IfBool); data.reads.push(t, &mut self.fun.pool.value); data.reads.push(f, &mut self.fun.pool.value); data.reads.push(value, &mut self.fun.pool.value); self.graph_update_block(block); } pub fn op_if_bool_strict( &mut self, span: SourceSpan, block: Block, value: Value, ) -> (Block, Block) { let true_cont = self.fun.block_insert(); let true_cont_val = self.value(true_cont); let false_cont = self.fun.block_insert(); let false_cont_val = self.value(false_cont); self.op_if_bool_strict_next(span, block, true_cont_val, false_cont_val, value); (true_cont, false_cont) } pub fn op_unreachable(&mut self, span: SourceSpan, block: Block) { let data = self.fun.blocks.get_mut(block).unwrap(); assert!(data.op.is_none()); assert!(data.reads.is_empty()); data.op = Some(OpKind::Unreachable); self.graph_update_block(block); } pub fn op_match_build(&mut self, span: SourceSpan) -> MatchBuilder { MatchBuilder::new(span) } } pub struct MatchBuilder { span: SourceSpan, branches: EntityList, branch_args: EntityList, kinds: Vec, } impl Default for MatchBuilder { fn default() -> Self { MatchBuilder { span: SourceSpan::UNKNOWN, branches: EntityList::new(), branch_args: EntityList::new(), kinds: Vec::new(), } } } impl MatchBuilder { pub fn new(span: SourceSpan) -> Self { let mut this = Self::default(); this.span = span; this } pub fn push_value_next(&mut self, next: Value, val: Value, b: &mut FunctionBuilder) { self.kinds.push(MatchKind::Value); self.branches.push(next, &mut b.fun.pool.value); let args = b.prim_value_list(&[val]); self.branch_args.push(args, &mut b.fun.pool.value); } pub fn push_value(&mut self, val: Value, b: &mut FunctionBuilder) -> Block { let (block, block_val) = b.block_insert_get_val(); self.push_value_next(block_val, val, b); block } pub fn push_type_next(&mut self, next: Value, typ: BasicType, b: &mut FunctionBuilder) { self.kinds.push(MatchKind::Type(typ)); self.branches.push(next, &mut b.fun.pool.value); let args = b.prim_value_list(&[]); self.branch_args.push(args, &mut b.fun.pool.value); } pub fn push_type(&mut self, typ: BasicType, b: &mut FunctionBuilder) -> Block { let (block, block_val) = b.block_insert_get_val(); self.push_type_next(block_val, typ, b); block } pub fn push_tuple_next(&mut self, next: Value, arity: usize, b: &mut FunctionBuilder) { self.kinds.push(MatchKind::Tuple(arity)); self.branches.push(next, &mut b.fun.pool.value); let args = b.prim_value_list(&[]); self.branch_args.push(args, &mut b.fun.pool.value); } pub fn push_tuple(&mut self, arity: usize, b: &mut FunctionBuilder) -> Block { let (block, block_val) = b.block_insert_get_val(); for _ in 0..arity { b.block_arg_insert(block); } self.push_tuple_next(block_val, arity, b); block } pub fn push_binary( &mut self, specifier: BinaryEntrySpecifier, size: Option, b: &mut FunctionBuilder, ) -> Block { let (block, block_val) = b.block_insert_get_val(); b.block_arg_insert(block); b.block_arg_insert(block); self.kinds.push(MatchKind::Binary(specifier)); self.branches.push(block_val, &mut b.fun.pool.value); let args = if let Some(size) = size { b.prim_value_list(&[size]) } else { b.prim_value_list(&[]) }; self.branch_args.push(args, &mut b.fun.pool.value); block } pub fn push_list_cell_next(&mut self, next: Value, b: &mut FunctionBuilder) { self.kinds.push(MatchKind::ListCell); self.branches.push(next, &mut b.fun.pool.value); let args = b.prim_value_list(&[]); self.branch_args.push(args, &mut b.fun.pool.value); } pub fn push_list_cell(&mut self, b: &mut FunctionBuilder) -> Block { let (block, block_val) = b.block_insert_get_val(); b.block_arg_insert(block); b.block_arg_insert(block); self.push_list_cell_next(block_val, b); block } pub fn push_map_item_next(&mut self, next: Value, key: Value, b: &mut FunctionBuilder) { self.kinds.push(MatchKind::MapItem); self.branches.push(next, &mut b.fun.pool.value); let args = b.prim_value_list(&[key]); self.branch_args.push(args, &mut b.fun.pool.value); } pub fn push_map_item(&mut self, key: Value, b: &mut FunctionBuilder) -> Block { let (block, block_val) = b.block_insert_get_val(); b.block_arg_insert(block); self.push_map_item_next(block_val, key, b); block } pub fn push_wildcard_next(&mut self, next: Value, b: &mut FunctionBuilder) { self.kinds.push(MatchKind::Wildcard); self.branches.push(next, &mut b.fun.pool.value); let args = b.prim_value_list(&[]); self.branch_args.push(args, &mut b.fun.pool.value); } pub fn push_wildcard(&mut self, span: SourceSpan, b: &mut FunctionBuilder) -> Block { let (block, block_val) = b.block_insert_get_val(); { let mut block_data = b.fun.blocks.get_mut(block).unwrap(); } self.push_wildcard_next(block_val, b); block } pub fn finish(self, block: Block, value: Value, b: &mut FunctionBuilder) { let branches = b.prim_value_list_from_entity_list(self.branches); let data = b.fun.blocks.get_mut(block).unwrap(); assert!(data.op.is_none()); assert!(data.reads.is_empty()); let mut reads = EntityList::new(); reads.push(branches, &mut b.fun.pool.value); reads.push(value, &mut b.fun.pool.value); let branches_num = self.branch_args.len(&b.fun.pool.value); for n in 0..branches_num { let branch_val = self.branch_args.get(n, &b.fun.pool.value).unwrap(); reads.push(branch_val, &mut b.fun.pool.value); } data.op = Some(OpKind::Match { branches: self.kinds, }); data.reads = reads; b.graph_update_block(block); b.fun.graph_validate_block(block); } } pub struct MapPutBuilder { span: SourceSpan, ok: Block, fail: Block, reads: EntityList, actions: Vec, } impl MapPutBuilder { pub fn new(span: SourceSpan, value: Value, b: &mut FunctionBuilder) -> Self { let (ok, ok_val) = b.block_insert_get_val(); b.block_arg_insert(ok); let (fail, fail_val) = b.block_insert_get_val(); b.block_arg_insert(fail); let mut reads = EntityList::new(); reads.push(ok_val, &mut b.fun.pool.value); reads.push(fail_val, &mut b.fun.pool.value); reads.push(value, &mut b.fun.pool.value); MapPutBuilder { span, ok, fail, reads, actions: Vec::new(), } } pub fn push_kv( &mut self, key: Value, val: Value, action: MapPutUpdate, b: &mut FunctionBuilder, ) { self.actions.push(action); self.reads.push(key, &mut b.fun.pool.value); self.reads.push(val, &mut b.fun.pool.value); } pub fn finish(self, block: Block, b: &mut FunctionBuilder) -> (Block, Block) { let data = b.fun.blocks.get_mut(block).unwrap(); assert!(data.op.is_none()); assert!(data.reads.is_empty()); data.op = Some(OpKind::MapPut { action: self.actions, }); data.reads = self.reads; b.graph_update_block(block); (self.ok, self.fail) } } ================================================ FILE: libeir_ir/src/function/builder/primop.rs ================================================ use cranelift_entity::EntityList; use libeir_diagnostics::SourceSpan; use super::{BinOp, FunctionBuilder, PrimOpData, PrimOpKind}; use crate::{ConstKind, IntoValue, LogicOp, Value, ValueKind}; /// PrimOp constructors impl<'a> FunctionBuilder<'a> { pub fn prim_binop(&mut self, span: SourceSpan, op: BinOp, lhs: Value, rhs: Value) -> Value { let loc = self.fun.locations.location(None, None, None, None, span); let mut reads = EntityList::new(); if op.symmetric() && lhs >= rhs { reads.extend([rhs, lhs].iter().cloned(), &mut self.fun.pool.value); } else { reads.extend([lhs, rhs].iter().cloned(), &mut self.fun.pool.value); } let primop = self.fun.primops.push( PrimOpData { op: PrimOpKind::BinOp(op), reads, }, &self.fun.pool, ); self.fun .values .push_with_location(ValueKind::PrimOp(primop), Some(loc)) } /// This will construct a tuple. /// If all values are constants, a constant tuple is created. /// Otherwise, a tuple PrimOp is created. pub fn prim_tuple(&mut self, span: SourceSpan, values: &[Value]) -> Value { if values.iter().all(|v| self.fun.value_const(*v).is_some()) { let mut entries = EntityList::new(); for val in values { let cons = self.fun.value_const(*val).unwrap(); entries.push(cons, &mut self.fun.constant_container.const_pool); } let cons = self.cons_mut().from(ConstKind::Tuple { entries }); self.value(cons) } else { let loc = self.fun.locations.location(None, None, None, None, span); let mut reads = EntityList::new(); for val in values { reads.push(*val, &mut self.fun.pool.value); } let primop = self.fun.primops.push( PrimOpData { op: PrimOpKind::Tuple, reads, }, &self.fun.pool, ); self.fun .values .push_with_location(ValueKind::PrimOp(primop), Some(loc)) } } /// This will construct a new map. /// If all values are constants, a constant map is created. /// Otherwise, a map PrimOp is created. pub fn prim_map(&mut self, span: SourceSpan, keys: &[Value], values: &[Value]) -> Value { if keys.iter().all(|v| self.fun.value_const(*v).is_some()) && values.iter().all(|v| self.fun.value_const(*v).is_some()) { let mut const_pair = self.const_pair_buf.take().unwrap(); assert!(const_pair.is_empty()); const_pair.extend( keys.iter() .map(|v| self.fun.value_const(*v).unwrap()) .zip(values.iter().map(|v| self.fun.value_const(*v).unwrap())) .map(|(k, v)| [k, v]), ); const_pair.sort_by(|[k1, _], [k2, _]| k1.cmp(k2)); let mut key_list = EntityList::new(); key_list.extend( const_pair.iter().map(|[k, _]| *k), &mut self.cons_mut().const_pool, ); let mut val_list = EntityList::new(); val_list.extend( const_pair.iter().map(|[_, v]| *v), &mut self.cons_mut().const_pool, ); const_pair.clear(); self.const_pair_buf = Some(const_pair); let cons = self.cons_mut().from(ConstKind::Map { keys: key_list, values: val_list, }); self.value(cons) } else { let loc = self.fun.locations.location(None, None, None, None, span); let mut value_pair = self.value_pair_buf.take().unwrap(); assert!(value_pair.is_empty()); value_pair.extend( keys.iter() .cloned() .zip(values.iter().cloned()) .map(|(k, v)| [k, v]), ); value_pair.sort_by(|[k1, _], [k2, _]| k1.cmp(k2)); let mut entries_list = EntityList::new(); entries_list.extend( value_pair.iter().flatten().cloned(), &mut self.fun.pool.value, ); value_pair.clear(); self.value_pair_buf = Some(value_pair); let primop = self.fun.primops.push( PrimOpData { op: PrimOpKind::Map, reads: entries_list, }, &self.fun.pool, ); self.fun .values .push_with_location(ValueKind::PrimOp(primop), Some(loc)) } } pub fn prim_list_cell(&mut self, span: SourceSpan, head: Value, tail: Value) -> Value { if let (Some(head_v), Some(tail_v)) = (self.fun.value_const(head), self.fun.value_const(tail)) { let cons = self.cons_mut().from(ConstKind::ListCell { head: head_v, tail: tail_v, }); self.value(cons) } else { let loc = self.fun.locations.location(None, None, None, None, span); let mut entries_list = EntityList::new(); entries_list.push(head, &mut self.fun.pool.value); entries_list.push(tail, &mut self.fun.pool.value); let primop = self.fun.primops.push( PrimOpData { op: PrimOpKind::ListCell, reads: entries_list, }, &self.fun.pool, ); self.fun .values .push_with_location(ValueKind::PrimOp(primop), Some(loc)) } } pub fn prim_value_list(&mut self, values: &[Value]) -> Value { assert!(values.iter().all(|v| { self.fun.value_primop(*v).map(|p| self.fun.primop_kind(p)) != Some(&PrimOpKind::ValueList) })); if values.len() == 1 { return values[0]; } let mut entries_list = EntityList::new(); entries_list.extend(values.iter().cloned(), &mut self.fun.pool.value); let primop = self.fun.primops.push( PrimOpData { op: PrimOpKind::ValueList, reads: entries_list, }, &self.fun.pool, ); self.fun.values.push(ValueKind::PrimOp(primop)) } pub(crate) fn prim_value_list_from_entity_list(&mut self, values: EntityList) -> Value { let num = values.len(&self.fun.pool.value); if num == 1 { return values.get(0, &self.fun.pool.value).unwrap(); } for n in 0..num { let val = values.get(n, &self.fun.pool.value).unwrap(); if let Some(prim) = self.fun.value_primop(val) { assert!(self.fun.primop_kind(prim) != &PrimOpKind::ValueList); } } let primop = self.fun.primops.push( PrimOpData { op: PrimOpKind::ValueList, reads: values, }, &self.fun.pool, ); self.fun.values.push(ValueKind::PrimOp(primop)) } pub fn prim_logic_op(&mut self, span: SourceSpan, op: LogicOp, values: &[Value]) -> Value { match (op, values.len()) { (LogicOp::And, 0) => return self.value(true), (LogicOp::And, 1) => return values[0], (LogicOp::Or, 0) => return self.value(false), (LogicOp::Or, 1) => return values[0], (LogicOp::Eq, 0) => return self.value(true), (LogicOp::Eq, 1) => return self.value(true), _ => (), } if values.iter().all(|v| self.fun.value_const(*v).is_some()) { let true_const = self.value(true); let false_const = self.value(false); match op { LogicOp::And => { let mut acc = true; for val in values { if *val == false_const { acc = false; } else { assert!(*val == true_const); } } self.value(acc) } LogicOp::Or => { let mut acc = false; for val in values { if *val == true_const { acc = true; } else { assert!(*val == false_const); } } self.value(acc) } LogicOp::Eq => unimplemented!(), } } else { let loc = self.fun.locations.location(None, None, None, None, span); let mut entries_list = EntityList::new(); entries_list.extend(values.iter().cloned(), &mut self.fun.pool.value); let primop = self.fun.primops.push( PrimOpData { op: PrimOpKind::LogicOp(op), reads: entries_list, }, &self.fun.pool, ); self.fun .values .push_with_location(ValueKind::PrimOp(primop), Some(loc)) } } pub fn prim_capture_function(&mut self, span: SourceSpan, m: M, f: F, a: A) -> Value where M: IntoValue, F: IntoValue, A: IntoValue, { let m_val = self.value(m); let f_val = self.value(f); let a_val = self.value(a); let mut entries_list = EntityList::new(); entries_list.push(m_val, &mut self.fun.pool.value); entries_list.push(f_val, &mut self.fun.pool.value); entries_list.push(a_val, &mut self.fun.pool.value); let loc = self.fun.locations.location(None, None, None, None, span); let primop = self.fun.primops.push( PrimOpData { op: PrimOpKind::CaptureFunction, reads: entries_list, }, &self.fun.pool, ); self.fun .values .push_with_location(ValueKind::PrimOp(primop), Some(loc)) } pub fn prim_from_kind(&mut self, span: SourceSpan, op: PrimOpKind, vals: &[Value]) -> Value { match op { PrimOpKind::ValueList => self.prim_value_list(vals), PrimOpKind::Tuple => self.prim_tuple(span, vals), PrimOpKind::CaptureFunction => { assert!(vals.len() == 3); self.prim_capture_function(span, vals[0], vals[1], vals[2]) } PrimOpKind::LogicOp(op) => self.prim_logic_op(span, op, vals), PrimOpKind::BinOp(op) => { assert!(vals.len() == 2); self.prim_binop(span, op, vals[0], vals[1]) } PrimOpKind::ListCell => { assert!(vals.len() == 2); self.prim_list_cell(span, vals[0], vals[1]) } p => unimplemented!("{:?}", p), } } } ================================================ FILE: libeir_ir/src/function/format.rs ================================================ #[macro_export] macro_rules! function_format { ($fun:expr, $str:expr, $($arg:expr),*) => { format!($str, $($crate::ContainerDebugAdapter { container: $fun, value: $arg }),*) }; } use std::fmt::{Debug, Formatter, Result}; use std::hash::Hash; use std::collections::{BTreeMap, HashMap}; use std::collections::{BTreeSet, HashSet}; use super::{Function, Value, ValueKind}; pub trait ContainerDebug: Debug { fn fmt(&self, container: &C, f: &mut Formatter) -> Result; } pub struct ContainerDebugAdapter<'a, C, V> { pub container: &'a C, pub value: &'a V, } impl Debug for ContainerDebugAdapter<'_, C, V> where V: ContainerDebug, { fn fmt(&self, f: &mut Formatter) -> Result { ContainerDebug::fmt(self.value, self.container, f) } } default impl ContainerDebug for V { fn fmt(&self, _con: &C, f: &mut Formatter) -> Result { std::fmt::Debug::fmt(self, f) } } impl ContainerDebug for Value { fn fmt(&self, fun: &Function, f: &mut Formatter) -> Result { match fun.value_kind(*self) { ValueKind::PrimOp(prim) => write!(f, "{}#{}", self, prim), ValueKind::Block(block) => write!(f, "{}#{}", self, block), ValueKind::Argument(block, num) => write!(f, "{}#{}[{}]", self, block, num), ValueKind::Const(cons) => write!(f, "{}#{}", self, cons), } } } impl ContainerDebug for &[Value] { fn fmt(&self, fun: &Function, f: &mut Formatter) -> Result { let values = self.as_ref(); let mut builder = f.debug_list(); builder .entries(values.iter().map(|v| ContainerDebugAdapter { container: fun, value: v, })) .finish() } } impl ContainerDebug for HashMap where K: ContainerDebug + Hash + Eq, V: ContainerDebug, { fn fmt(&self, con: &C, f: &mut Formatter) -> Result { let mut builder = f.debug_map(); builder .entries(self.iter().map(|(k, v)| { ( ContainerDebugAdapter { container: con, value: k, }, ContainerDebugAdapter { container: con, value: v, }, ) })) .finish() } } impl ContainerDebug for BTreeMap where K: ContainerDebug + Hash, V: ContainerDebug, { fn fmt(&self, con: &C, f: &mut Formatter) -> Result { let mut builder = f.debug_map(); builder .entries(self.iter().map(|(k, v)| { ( ContainerDebugAdapter { container: con, value: k, }, ContainerDebugAdapter { container: con, value: v, }, ) })) .finish() } } impl ContainerDebug for HashSet where V: ContainerDebug + Hash + Eq, { fn fmt(&self, con: &C, f: &mut Formatter) -> Result { let mut builder = f.debug_set(); builder .entries(self.iter().map(|v| ContainerDebugAdapter { container: con, value: v, })) .finish() } } impl ContainerDebug for BTreeSet where V: ContainerDebug + Hash + Eq, { fn fmt(&self, con: &C, f: &mut Formatter) -> Result { let mut builder = f.debug_set(); builder .entries(self.iter().map(|v| ContainerDebugAdapter { container: con, value: v, })) .finish() } } impl ContainerDebug for bool { fn fmt(&self, _con: &C, f: &mut Formatter) -> Result { write!(f, "{}", self) } } macro_rules! impl_tuple { ($(($typ:ident, $n:tt)),*) => { #[allow(unused_variables)] impl ContainerDebug for ($($typ,)*) where $($typ: ContainerDebug,)* { fn fmt(&self, con: &Container, f: &mut Formatter) -> Result { let mut builder = f.debug_tuple(""); $( builder.field(&ContainerDebugAdapter { container: con, value: &self.$n }); )* builder.finish() } } } } impl_tuple!(); impl_tuple!((A, 0)); impl_tuple!((A, 0), (B, 1)); impl_tuple!((A, 0), (B, 1), (C, 2)); impl_tuple!((A, 0), (B, 1), (C, 2), (D, 3)); impl_tuple!((A, 0), (B, 1), (C, 2), (D, 3), (E, 4)); impl_tuple!((A, 0), (B, 1), (C, 2), (D, 3), (E, 4), (F, 5)); impl_tuple!((A, 0), (B, 1), (C, 2), (D, 3), (E, 4), (F, 5), (G, 6)); impl_tuple!( (A, 0), (B, 1), (C, 2), (D, 3), (E, 4), (F, 5), (G, 6), (H, 7) ); ================================================ FILE: libeir_ir/src/function/location.rs ================================================ use std::hash::{Hash, Hasher}; use libeir_util_datastructures::dedup_aux_primary_map::DedupPrimaryMap; use libeir_util_datastructures::{ aux_traits::{AuxEq, AuxHash}, dedup_aux_primary_map::DedupAuxPrimaryMap, }; use cranelift_entity::{entity_impl, EntityList, ListPool}; use libeir_diagnostics::{CodeMap, SourceSpan}; #[derive(Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] pub struct Location(u32); entity_impl!(Location, "loc"); #[derive(Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] pub struct LocationTerminal(u32); entity_impl!(LocationTerminal, "loc_terminal"); #[derive(Debug, Clone, PartialEq, Eq, Hash)] struct LocationTerminalData { /// Path to display for the origin file file: Option, /// Line number in origin file line: Option, /// Name of module module: Option, /// Name of function/stack entity entity: Option, /// Span in the file this was read from. /// While the `file`, `line` and `name` files are /// meant to be preserved when reading/writing /// to textual Eir, this span is meant to be the /// direct file it was read from. span: SourceSpan, } impl AuxHash<()> for LocationTerminalData { fn aux_hash(&self, state: &mut H, _container: &()) { self.hash(state) } } impl AuxEq<()> for LocationTerminalData { fn aux_eq(&self, rhs: &Self, _self_aux: &(), _rhs_aux: &()) -> bool { self.eq(rhs) } } #[derive(Debug, Clone)] struct LocationData { terminals: EntityList, } impl AuxHash> for LocationData { fn aux_hash(&self, state: &mut H, container: &ListPool) { self.terminals.as_slice(container).hash(state) } } impl AuxEq> for LocationData { fn aux_eq( &self, other: &Self, self_aux: &ListPool, other_aux: &ListPool, ) -> bool { self.terminals.as_slice(self_aux) == other.terminals.as_slice(other_aux) } } #[derive(Debug, Clone)] pub struct LocationContainer { terminals: DedupPrimaryMap, locations: DedupAuxPrimaryMap>, terminal_pool: ListPool, } impl LocationContainer { pub fn new() -> Self { let locations = DedupAuxPrimaryMap::new(); let terminals = DedupPrimaryMap::new(); let terminal_pool = ListPool::new(); LocationContainer { locations, terminals, terminal_pool, } } pub fn lookup(&self, location: &Location) -> Vec { let terminals = self.locations[*location] .terminals .as_slice(&self.terminal_pool); let mut locs = Vec::with_capacity(terminals.len()); for terminal in terminals.iter().cloned() { let terminal_data = &self.terminals[terminal]; locs.push(terminal_data.span.clone()); } locs } pub fn location_empty(&mut self) -> Location { self.locations.push( LocationData { terminals: EntityList::new(), }, &mut self.terminal_pool, ) } pub fn location_unknown(&mut self) -> Location { let terminal = self.terminals.push( LocationTerminalData { file: None, line: None, module: None, entity: None, span: SourceSpan::UNKNOWN, }, &mut (), ); let mut terminals = EntityList::new(); terminals.push(terminal, &mut self.terminal_pool); self.locations.push( LocationData { terminals: EntityList::new(), }, &mut self.terminal_pool, ) } pub fn terminal( &mut self, file: Option, line: Option, module: Option, entity: Option, span: SourceSpan, ) -> LocationTerminal { self.terminals.push( LocationTerminalData { file, line, module, entity, span, }, &mut (), ) } pub fn location( &mut self, file: Option, line: Option, module: Option, entity: Option, span: SourceSpan, ) -> Location { let terminal = self.terminal(file, line, module, entity, span); let mut terminals = EntityList::new(); terminals.push(terminal, &mut self.terminal_pool); self.locations .push(LocationData { terminals }, &mut self.terminal_pool) } pub fn terminal_from_bytespan( &mut self, codemap: &CodeMap, span: SourceSpan, module: Option, entity: Option, ) -> LocationTerminal { let mut file = None; let mut line = None; let start_idx = span.start_index(); if let Some(filemap) = codemap.get(span.source_id()) { file = Some(filemap.name().to_string()); let line_idx = filemap.line_index(start_idx); line = Some(line_idx.0); } self.terminal(file, line, module, entity, span) } pub fn from_bytespan( &mut self, codemap: &CodeMap, span: SourceSpan, module: Option, entity: Option, ) -> Location { let terminal = self.terminal_from_bytespan(codemap, span, module, entity); let mut terminals = EntityList::new(); terminals.push(terminal, &mut self.terminal_pool); self.locations .push(LocationData { terminals }, &mut self.terminal_pool) } pub fn from_terminals(&mut self, terminals: &[LocationTerminal]) -> Location { let mut n_terminals = EntityList::new(); n_terminals.extend(terminals.iter().cloned(), &mut self.terminal_pool); self.locations.push( LocationData { terminals: n_terminals, }, &mut self.terminal_pool, ) } pub fn concat_locations(&mut self, bottom: Location, top: Location) -> Location { let mut terminals = Vec::new(); terminals.extend( self.locations[bottom] .terminals .as_slice(&self.terminal_pool) .iter() .cloned(), ); terminals.extend( self.locations[top] .terminals .as_slice(&self.terminal_pool) .iter() .cloned(), ); let mut new_terminals = EntityList::new(); new_terminals.extend(terminals.iter().cloned(), &mut self.terminal_pool); self.locations.push( LocationData { terminals: new_terminals, }, &mut self.terminal_pool, ) } pub fn location_eq(&self, l_loc: Location, r: &Self, r_loc: Location) -> bool { let l_n = &self.locations[l_loc]; let r_n = &r.locations[r_loc]; let l_ts = l_n.terminals.as_slice(&self.terminal_pool); let r_ts = r_n.terminals.as_slice(&r.terminal_pool); if l_ts.len() != r_ts.len() { return false; } for (l_t, r_t) in l_ts.iter().zip(r_ts.iter()) { let l_i = &self.terminals[*l_t]; let r_i = &r.terminals[*r_t]; if l_i.file != r_i.file || l_i.module != r_i.module || l_i.entity != r_i.entity || l_i.line != r_i.line { return false; } } return true; } pub fn format_loc(&self, loc: Location) -> String { use std::fmt::Write; let loc_inner = &self.locations[loc]; let mut out = String::new(); write!(&mut out, "[").unwrap(); for term in loc_inner.terminals.as_slice(&self.terminal_pool) { let term_inner = &self.terminals[*term]; if let Some(file) = &term_inner.file { write!(&mut out, "{:?}:", file).unwrap(); } else { write!(&mut out, "nil:").unwrap(); } if let Some(line) = &term_inner.line { write!(&mut out, "{:?}@", line).unwrap(); } else { write!(&mut out, "nil@").unwrap(); } if let Some(module) = &term_inner.module { write!(&mut out, "{:?}:", module).unwrap(); } else { write!(&mut out, "nil:").unwrap(); } if let Some(entity) = &term_inner.entity { write!(&mut out, "{:?}", entity).unwrap(); } else { write!(&mut out, "nil").unwrap(); } write!(&mut out, ", ").unwrap(); } write!(&mut out, "]").unwrap(); out } } ================================================ FILE: libeir_ir/src/function/mod.rs ================================================ use std::cmp::Eq; use std::collections::HashSet; use std::hash::{Hash, Hasher}; use cranelift_bforest::{BoundSet, Set, SetForest}; use cranelift_entity::packed_option::ReservedValue; use cranelift_entity::{entity_impl, EntityList, ListPool, PrimaryMap}; use libeir_util_datastructures::aux_traits::{AuxDebug, AuxEq, AuxHash, HasAux}; use libeir_util_datastructures::dedup_aux_primary_map::DedupAuxPrimaryMap; use libeir_diagnostics::SourceSpan; use crate::constant::{Const, ConstKind, ConstantContainer}; use crate::{ArcDialect, FunctionIdent}; pub mod builder; use builder::IntoValue; mod pool_container; use pool_container::PoolContainer; mod op; pub use op::{BasicType, CallKind, MapPutUpdate, MatchKind, OpKind}; mod primop; pub use primop::{BinOp, LogicOp, PrimOpKind}; mod value; use value::ValueMap; pub use value::{Value, ValueKind}; mod location; pub use location::{Location, LocationContainer}; mod format; pub use format::{ContainerDebug, ContainerDebugAdapter}; //mod serialize; /// Block/continuation #[derive(Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] pub struct Block(u32); entity_impl!(Block, "block"); impl Default for Block { fn default() -> Self { Block::reserved_value() } } impl AuxDebug for Block { fn aux_fmt(&self, f: &mut std::fmt::Formatter<'_>, _aux: &C) -> std::fmt::Result { std::fmt::Debug::fmt(self, f) } } #[derive(Copy, Clone, Hash, PartialEq, Eq)] pub struct Argument(u32); entity_impl!(Argument, "argument"); /// Reference to other function #[derive(Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] pub struct FunRef(u32); entity_impl!(FunRef, "fun_ref"); #[derive(Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] pub struct PrimOp(u32); entity_impl!(PrimOp, "prim_op"); #[derive(Clone)] pub struct BlockData { pub(crate) arguments: EntityList, pub(crate) op: Option, pub(crate) reads: EntityList, pub(crate) location: Location, // Auxilary data for graph implementation // These will contain all the connected blocks, regardless // of whether they are actually alive or not. pub(crate) predecessors: Set, pub(crate) successors: Set, } #[derive(Debug, Clone)] pub struct PrimOpData { op: PrimOpKind, reads: EntityList, } impl AuxHash for PrimOpData { fn aux_hash(&self, state: &mut H, container: &PoolContainer) { self.op.hash(state); self.reads.as_slice(&container.value).hash(state); } } impl AuxEq for PrimOpData { fn aux_eq( &self, rhs: &PrimOpData, self_aux: &PoolContainer, other_aux: &PoolContainer, ) -> bool { if self.op != rhs.op { return false; } self.reads.as_slice(&self_aux.value) == rhs.reads.as_slice(&other_aux.value) } } #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] pub enum AttributeKey { Continuation, } #[derive(Debug, Clone, PartialEq, Eq)] pub enum AttributeValue { None, } #[derive(Clone)] pub struct Function { // Meta ident: FunctionIdent, entry_block: Option, span: SourceSpan, dialect: ArcDialect, pub(crate) blocks: PrimaryMap, pub(crate) values: ValueMap, pub(crate) primops: DedupAuxPrimaryMap, pub pool: PoolContainer, constant_container: ConstantContainer, // Auxiliary information pub constant_values: HashSet, pub locations: LocationContainer, } impl Function { pub fn dialect(&self) -> &ArcDialect { &self.dialect } pub fn span(&self) -> SourceSpan { self.span } pub fn cons(&self) -> &ConstantContainer { &self.constant_container } } impl HasAux> for Function { fn get_aux(&self) -> &ListPool { &self.pool.value } } impl HasAux> for Function { fn get_aux(&self) -> &SetForest { &self.pool.block_set } } impl> AuxDebug for Function { fn aux_fmt(&self, _f: &mut std::fmt::Formatter<'_>, _container: &C) -> std::fmt::Result { unimplemented!() } } impl std::fmt::Debug for Function { fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result { self.aux_fmt(fmt, self) } } /// Values impl Function { pub fn value_get(&self, v: T) -> Option where T: IntoValue, { v.get_value(self) } pub fn iter_constants(&self) -> std::collections::hash_set::Iter<'_, Value> { self.constant_values.iter() } pub fn const_kind(&self, constant: Const) -> &ConstKind { self.constant_container.const_kind(constant) } pub fn const_entries<'f>(&'f self, entries: &'f EntityList) -> &'f [Const] { entries.as_slice(&self.constant_container.const_pool) } pub fn value_kind(&self, value: Value) -> ValueKind { self.values[value].kind } pub fn value_locations(&self, value: Value) -> Option> { self.values[value] .location .as_ref() .map(|loc| self.locations.lookup(loc)) } pub fn value_is_constant(&self, value: Value) -> bool { self.constant_values.contains(&value) } pub fn value_list_length(&self, value: Value) -> usize { match self.value_kind(value) { ValueKind::PrimOp(prim) => { if let PrimOpKind::ValueList = self.primop_kind(prim) { return self.primop_reads(prim).len(); } } _ => (), } 1 } pub fn value_list_get_n(&self, value: Value, n: usize) -> Option { match self.value_kind(value) { ValueKind::PrimOp(prim) => { if let PrimOpKind::ValueList = self.primop_kind(prim) { let reads = self.primop_reads(prim); return reads.get(n).cloned(); } } _ => (), } if n == 0 { Some(value) } else { None } } /// If the value is a variable, get its definition block and argument position pub fn value_argument(&self, value: Value) -> Option<(Block, usize)> { if let ValueKind::Argument(block, arg) = self.values[value].kind { Some((block, arg)) } else { None } } pub fn value_block(&self, value: Value) -> Option { if let ValueKind::Block(block) = self.values[value].kind { Some(block) } else { None } } pub fn value_const(&self, value: Value) -> Option { if let ValueKind::Const(con) = &self.values[value].kind { Some(*con) } else { None } } pub fn value_primop(&self, value: Value) -> Option { if let ValueKind::PrimOp(prim) = &self.values[value].kind { Some(*prim) } else { None } } pub fn value_usages(&self, value: Value) -> BoundSet { self.values[value].usages.bind(&self.pool.block_set, &()) } /// Walks all nested values contained within /// the tree of potential PrimOps. pub fn value_walk_nested_values(&self, value: Value, visit: &mut F) -> Result<(), R> where F: FnMut(Value) -> Result<(), R>, { visit(value)?; if let ValueKind::PrimOp(primop) = self.values[value].kind { self.primop_walk_nested_values(primop, visit)?; } Ok(()) } pub fn value_walk_nested_values_mut( &mut self, value: Value, visit: &mut F, ) -> Result<(), R> where F: FnMut(&mut Function, Value) -> Result<(), R>, { visit(self, value)?; if let ValueKind::PrimOp(primop) = self.values[value].kind { self.primop_walk_nested_values_mut(primop, visit)?; } Ok(()) } } /// PrimOps impl Function { pub fn primop_kind(&self, primop: PrimOp) -> &PrimOpKind { &self.primops[primop].op } pub fn primop_reads(&self, primop: PrimOp) -> &[Value] { &self.primops[primop].reads.as_slice(&self.pool.value) } pub fn primop_walk_nested_values(&self, primop: PrimOp, visit: &mut F) -> Result<(), R> where F: FnMut(Value) -> Result<(), R>, { let data = &self.primops[primop]; for read in data.reads.as_slice(&self.pool.value) { self.value_walk_nested_values(*read, visit)?; } Ok(()) } pub fn primop_walk_nested_values_mut( &mut self, primop: PrimOp, visit: &mut F, ) -> Result<(), R> where F: FnMut(&mut Function, Value) -> Result<(), R>, { let len = self.primops[primop].reads.as_slice(&self.pool.value).len(); for n in 0..len { let read = self.primops[primop].reads.as_slice(&self.pool.value)[n]; self.value_walk_nested_values_mut(read, visit)?; } Ok(()) } } /// Blocks impl Function { #[inline(always)] fn block_insert(&mut self) -> Block { self.block_insert_with_span(None) } fn block_insert_with_span(&mut self, span: Option) -> Block { let location = span .map(|s| self.locations.location(None, None, None, None, s)) .unwrap_or_else(|| self.locations.location_empty()); let block = self.blocks.push(BlockData { arguments: EntityList::new(), op: None, reads: EntityList::new(), predecessors: Set::new(), successors: Set::new(), location, }); self.values.push(ValueKind::Block(block)); block } fn block_arg_insert(&mut self, block: Block) -> Value { let arg_num = self.blocks[block].arguments.len(&self.pool.value); let val = self.values.push(ValueKind::Argument(block, arg_num)); self.blocks[block].arguments.push(val, &mut self.pool.value); val } pub fn block_arg_n(&self, block: Block, num: usize) -> Option { self.blocks[block].arguments.get(num, &self.pool.value) } pub fn block_kind(&self, block: Block) -> Option<&OpKind> { self.blocks[block].op.as_ref() } pub fn block_location(&self, block: Block) -> Location { self.blocks[block].location } pub fn block_locations(&self, block: Block) -> Vec { let loc = self.blocks[block].location; self.locations.lookup(&loc) } pub fn block_entry(&self) -> Block { self.entry_block.expect("Entry block not set on function") } pub fn block_args(&self, block: B) -> &[Value] where B: Into, { let block: Block = block.into(); self.blocks[block].arguments.as_slice(&self.pool.value) } pub fn block_reads(&self, block: Block) -> &[Value] { self.blocks[block].reads.as_slice(&self.pool.value) } pub fn block_value(&self, block: Block) -> Value { self.values.get(ValueKind::Block(block)).unwrap() } pub fn block_walk_nested_values(&self, block: Block, visit: &mut F) -> Result<(), R> where F: FnMut(Value) -> Result<(), R>, { let reads_len = self.blocks[block].reads.as_slice(&self.pool.value).len(); for n in 0..reads_len { let read = self.blocks[block].reads.get(n, &self.pool.value).unwrap(); self.value_walk_nested_values(read, visit)?; } Ok(()) } pub fn block_walk_nested_values_mut( &mut self, block: Block, visit: &mut F, ) -> Result<(), R> where F: FnMut(&mut Function, Value) -> Result<(), R>, { let reads_len = self.blocks[block].reads.as_slice(&self.pool.value).len(); for n in 0..reads_len { let read = self.blocks[block].reads.get(n, &self.pool.value).unwrap(); self.value_walk_nested_values_mut(read, visit)?; } Ok(()) } pub fn block_op_eq(&self, lb: Block, r_fun: &Function, rb: Block) -> bool { match (self.block_kind(lb).unwrap(), r_fun.block_kind(rb).unwrap()) { (OpKind::Call(l), OpKind::Call(r)) => l == r, (OpKind::IfBool, OpKind::IfBool) => true, (OpKind::Dyn(l), OpKind::Dyn(r)) => l.op_eq(&**r), (OpKind::TraceCaptureRaw, OpKind::TraceCaptureRaw) => true, (OpKind::TraceConstruct, OpKind::TraceConstruct) => true, (OpKind::MapPut { action: a1 }, OpKind::MapPut { action: a2 }) if a1 == a2 => true, (OpKind::UnpackValueList(n1), OpKind::UnpackValueList(n2)) if n1 == n2 => true, (OpKind::Match { branches: b1 }, OpKind::Match { branches: b2 }) if b1 == b2 => true, (OpKind::Unreachable, OpKind::Unreachable) => true, _ => false, } } // Iterates through ALL blocks in the function container pub fn block_iter(&self) -> impl Iterator { self.blocks.keys() } } /// Graph impl Function { /// Validates graph invariants for the block. /// Relatively inexpensive, for debug assertions. pub(crate) fn graph_validate_block(&self, block: Block) { let block_data = &self.blocks[block]; let mut successors_set = HashSet::new(); self.block_walk_nested_values::<_, ()>(block, &mut |val| { if let ValueKind::Block(succ_block) = self.value_kind(val) { assert!(block_data .successors .contains(succ_block, &self.pool.block_set, &())); assert!(self.blocks[succ_block].predecessors.contains( block, &self.pool.block_set, &() )); successors_set.insert(succ_block); } Ok(()) }) .unwrap(); assert!(block_data.successors.iter(&self.pool.block_set).count() == successors_set.len()); } /// Validates graph invariants globally, for the whole /// function. /// Relatively expensive. Should only be used in tests. pub fn graph_validate_global(&self) { for block in self.blocks.keys() { self.graph_validate_block(block); } } } pub trait GeneralSet { fn contains(&self, key: &V, fun: &Function) -> bool; fn insert(&mut self, key: V, fun: &mut Function) -> bool; } impl GeneralSet for HashSet where V: Hash + Eq, { fn contains(&self, key: &V, _fun: &Function) -> bool { HashSet::contains(self, key) } fn insert(&mut self, key: V, _fun: &mut Function) -> bool { HashSet::insert(self, key) } } impl GeneralSet for Set where V: Copy + Ord + SetPoolProvider, { fn contains(&self, key: &V, fun: &Function) -> bool { Set::contains(self, *key, V::pool(fun), &()) } fn insert(&mut self, key: V, fun: &mut Function) -> bool { Set::insert(self, key, V::pool_mut(fun), &()) } } pub trait SetPoolProvider: Sized + Copy { fn pool(fun: &Function) -> &SetForest; fn pool_mut(fun: &mut Function) -> &mut SetForest; } impl SetPoolProvider for Block { fn pool(fun: &Function) -> &SetForest { &fun.pool.block_set } fn pool_mut(fun: &mut Function) -> &mut SetForest { &mut fun.pool.block_set } } impl Function { pub fn new(span: SourceSpan, ident: FunctionIdent) -> Self { Function { ident, span, dialect: crate::dialect::NORMAL.clone(), blocks: PrimaryMap::new(), values: ValueMap::new(), primops: DedupAuxPrimaryMap::new(), entry_block: None, pool: PoolContainer { value: ListPool::new(), block_set: SetForest::new(), }, constant_container: ConstantContainer::new(), constant_values: HashSet::new(), locations: LocationContainer::new(), } } pub fn ident(&self) -> &FunctionIdent { &self.ident } pub fn entry_arg_num(&self) -> usize { self.block_args(self.block_entry()).len() } } ================================================ FILE: libeir_ir/src/function/op.rs ================================================ use crate::binary::BinaryEntrySpecifier; use crate::operation::{DynOp, Op}; use serde::{Deserialize, Serialize}; #[derive(Debug, Copy, Clone, PartialEq, Eq, Serialize, Deserialize)] pub enum CallKind { /// Control flow includes flow within a function and calls to /// escape values. ControlFlow, /// Call to a function, should generate a stack frame. /// The first two arguments MUST be the return and throw /// continuations respectively. Function, } #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] pub enum BasicType { // Contains both ListCell and Nil List, ListCell, Nil, /// Arity is part of the type Tuple(usize), Map, /// Contains both Float and Integer Number, Float, /// Contains both SmallInt and BigInt Integer, SmallInteger, BigInteger, } #[derive(Debug, Copy, Clone, PartialEq, Eq, Serialize, Deserialize)] pub enum MatchKind { /// One read, the value to test it against /// No arguments. Value, /// No reads. /// No writes. Type(BasicType), /// One optional read, the size. /// Two arguments, the decoded value, and the tail. Binary(BinaryEntrySpecifier), /// No reads. /// N arguments, the unpacked values. Tuple(usize), /// No reads. /// Two arguments, the head and the tail. ListCell, /// One read, the key. /// One argument, the value. MapItem, /// No reads. /// No arguments. Wildcard, } #[derive(Debug, Copy, Clone, PartialEq, Eq, Serialize, Deserialize)] pub enum MapPutUpdate { /// Value is put into map, regardless of already existing Put, /// Value is updated, fails if not in map Update, } #[derive(Debug, Clone)] pub enum OpKind { // Control flow/functions /// (call: fn(..), ..) /// This is the calling primitive, /// doing everything from returns to local calls, /// to external calls. Call(CallKind), /// (true: fn(), false: fn(), else: fn(), value) /// (true: fn(), false: fn(), value) implies else is unreachable /// Strict truth check, only 'true' is true, 'false' is false IfBool, // Stack traces /// This captures the current stack trace. /// Returns an implementation specific value that can only be /// used with `TraceConstruct`. Can not be exposed to the user /// or used with any other operation. TraceCaptureRaw, /// This gets the stack trace from a raw trace. TraceConstruct, /// (ok: fn(new_map), err: fn(), map: map, keys: (keys..), values: (value..)) /// Puts a new value in the map, replacing the old key /// if it exists. MapPut { // TODO: don't do allocation action: Vec, }, /// (cont: fn(terms..), l: valuelist) /// Value lists are not an actual type in the program. /// A value list of length 1 is semantically identical /// to the value itself. /// A value list may only exist as a SSA value directly, /// no other types may contain a value list. Value lists /// may not contain value lists. /// /// A value list of length 0 may be used as a empty set /// value. It may not be used in any reads, except a /// UnpackValueList with no writes. /// /// Only high level Eur may contain value lists. Codegen /// should not be concerned with these operations. UnpackValueList(usize), /// Match on a single value. /// Branches are tested in order, first matched is branched to. /// ```ignore /// ( /// branches: (fn(..), ..), /// value: term, /// branch1_args: (..), /// .. /// ) /// ``` Match { branches: Vec, }, /// () /// Something that should not happen. The VM could be left in an /// invalid state, should raise an unrecoverable runtime error. Unreachable, Dyn(DynOp), } impl OpKind { pub fn is_call(&self) -> bool { match self { OpKind::Call(_) => true, _ => false, } } pub fn get_dyn(&self) -> Option<&O> { match self { OpKind::Dyn(d) => d.downcast_ref(), _ => None, } } } ================================================ FILE: libeir_ir/src/function/pool_container.rs ================================================ use cranelift_bforest::SetForest; use cranelift_entity::ListPool; use super::{Block, Value}; #[derive(Clone)] pub struct PoolContainer { pub value: ListPool, pub block_set: SetForest, } ================================================ FILE: libeir_ir/src/function/primop.rs ================================================ use serde::{Deserialize, Serialize}; #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] pub enum BinOp { /// == Equal, /// /= NotEqual, /// =< LessEqual, /// < Less, /// >= GreaterEqual, /// > Greater, /// =:= ExactEqual, /// =/= ExactNotEqual, } impl BinOp { pub fn symmetric(self) -> bool { match self { BinOp::Equal => true, BinOp::NotEqual => true, BinOp::ExactEqual => true, BinOp::ExactNotEqual => true, _ => false, } } } #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] pub enum LogicOp { /// All arguments are equal Eq, And, Or, } #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] pub enum PrimOpKind { /// Corresponds the eir_intrinsics:type_tag. /// Required to be eliminated before lowering. /// TODO: Document returns /// (value) TypeTag, /// (value) IsType(super::op::BasicType), /// (lhs, rhs) BinOp(BinOp), /// (terms..) LogicOp(LogicOp), /// (terms..) Tuple, /// (head, tail) ListCell, /// (k1, v1, ... kn, vn) Map, /// (terms..) ValueList, /// Returns a function of arity `a`. /// If the function does not exists, this must return a function that /// throws badarg when called. /// For function capture semantics, the `CaptureFunction` op should be /// used instead. This will throw badarg at capture time. /// `(m, f, a)` CaptureFunction, } ================================================ FILE: libeir_ir/src/function/serialize.rs ================================================ use super::Function; use serde::{ Serialize, Serializer, Deserialize }; impl Serialize for Function { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let mut value_n = 0; let mut block_n = 0; } } ================================================ FILE: libeir_ir/src/function/value.rs ================================================ use std::collections::HashMap; use std::ops::{Index, IndexMut}; use super::{Block, Const, Location, PrimOp}; use cranelift_bforest::Set; use cranelift_entity::packed_option::ReservedValue; use cranelift_entity::{entity_impl, PrimaryMap}; use libeir_util_datastructures::aux_traits::AuxDebug; #[derive(Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] pub struct Value(u32); entity_impl!(Value, "value"); impl Default for Value { fn default() -> Self { Value::reserved_value() } } impl AuxDebug for Value { fn aux_fmt(&self, f: &mut std::fmt::Formatter<'_>, _aux: &C) -> std::fmt::Result { std::fmt::Debug::fmt(self, f) } } use libeir_util_dot_graph::NodeId; impl NodeId for Value { fn make_id(&self, out: &mut String) { use std::fmt::Write; write!(out, "{}", self).unwrap(); } } #[derive(Clone)] pub struct ValueData { pub(crate) kind: ValueKind, pub(crate) location: Option, pub(crate) usages: Set, } #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] pub enum ValueKind { Argument(Block, usize), Block(Block), Const(Const), PrimOp(PrimOp), } impl ValueKind { pub fn is_arg(&self) -> bool { match self { ValueKind::Argument(_, _) => true, _ => false, } } } #[derive(Clone)] pub struct ValueMap { primary: PrimaryMap, back: HashMap, } impl ValueMap { pub fn new() -> Self { ValueMap { primary: PrimaryMap::new(), back: HashMap::new(), } } pub fn push(&mut self, kind: ValueKind) -> Value { self.push_with_location(kind, None) } pub fn push_with_location(&mut self, kind: ValueKind, location: Option) -> Value { if let Some(key) = self.back.get(&kind) { *key } else { let val = self.primary.push(ValueData { kind, location, usages: Set::new(), }); self.back.insert(kind, val); val } } pub fn get(&self, kind: ValueKind) -> Option { self.back.get(&kind).cloned() } } impl Index for ValueMap { type Output = ValueData; fn index(&self, key: Value) -> &ValueData { &self.primary[key] } } impl IndexMut for ValueMap { fn index_mut(&mut self, key: Value) -> &mut ValueData { &mut self.primary[key] } } ================================================ FILE: libeir_ir/src/graph/block_graph.rs ================================================ use petgraph::visit::{Dfs, DfsPostOrder}; use petgraph::visit::{ GraphBase, IntoNeighbors, IntoNeighborsDirected, VisitMap, Visitable, Walker, }; use petgraph::Direction; use cranelift_entity::{EntityRef, EntitySet}; use itertools::Either; use cranelift_bforest::SetIter; use crate::Block; use crate::Function; impl Function { pub fn block_graph(&self) -> BlockGraph<'_> { BlockGraph::new(self) } } /// This is a newtype that contains implementations of petgraphs graph traits. /// /// The semantics of the below graph are as follows: /// - Nodes are blocks /// - Block capture values in blocks are edges /// - Back edges exist to non-live blocks /// /// The last point may cause some graph algorithms to produce undesirable results. /// `LiveBlockGraph` does not have this feature, but is slightly more expensive to /// construct. pub struct BlockGraph<'a> { pub(crate) fun: &'a Function, } impl<'a> BlockGraph<'a> { pub fn new(fun: &'a Function) -> Self { BlockGraph { fun } } pub fn dfs(&self) -> Dfs> { Dfs::new(self, self.fun.block_entry()) } pub fn dfs_iter(&'a self) -> impl Iterator + 'a { self.dfs().iter(self) } pub fn dfs_post_order(&self) -> DfsPostOrder> { DfsPostOrder::new(self, self.fun.block_entry()) } pub fn dfs_post_order_iter(&'a self) -> impl Iterator + 'a { self.dfs_post_order().iter(self) } pub fn outgoing(&'a self, block: Block) -> impl Iterator + 'a { self.fun.blocks[block] .successors .iter(&self.fun.pool.block_set) } } #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] pub struct BlockEdge(Block, usize); pub struct BlockSuccessors<'a> { iter: SetIter<'a, Block>, } impl<'a> Iterator for BlockSuccessors<'a> { type Item = Block; #[inline] fn next(&mut self) -> Option { self.iter.next() } } pub struct BlockPredecessors<'a> { iter: SetIter<'a, Block>, } impl<'a> BlockPredecessors<'a> { fn new(graph: &'a BlockGraph, block: Block) -> Self { BlockPredecessors { iter: graph.fun.blocks[block] .predecessors .iter(&graph.fun.pool.block_set), } } } impl<'a> Iterator for BlockPredecessors<'a> { type Item = Block; #[inline] fn next(&mut self) -> Option { self.iter.next() } } impl<'a> GraphBase for BlockGraph<'a> { type NodeId = Block; type EdgeId = BlockEdge; } impl<'a> IntoNeighbors for &'a BlockGraph<'a> { type Neighbors = BlockSuccessors<'a>; #[inline] fn neighbors(self, block: Block) -> Self::Neighbors { BlockSuccessors { iter: self.fun.blocks[block] .successors .iter(&self.fun.pool.block_set), } } } impl<'a> IntoNeighborsDirected for &'a BlockGraph<'a> { type NeighborsDirected = Either, BlockPredecessors<'a>>; #[inline] fn neighbors_directed(self, block: Block, dir: Direction) -> Self::NeighborsDirected { match dir { Direction::Outgoing => Either::Left(self.neighbors(block)), Direction::Incoming => Either::Right(BlockPredecessors::new(self, block)), } } } pub struct EntityVisitMap where E: EntityRef, { set: EntitySet, } impl EntityVisitMap where E: EntityRef, { pub fn new(size: usize) -> Self { let mut set = EntitySet::new(); set.resize(size); EntityVisitMap { set } } pub fn reset(&mut self, size: usize) { self.set.clear(); self.set.resize(size); } } impl VisitMap for EntityVisitMap where E: EntityRef, { #[inline] fn visit(&mut self, a: E) -> bool { self.set.insert(a) } #[inline] fn is_visited(&self, a: &E) -> bool { self.set.contains(*a) } } impl<'a> Visitable for BlockGraph<'a> { type Map = EntityVisitMap; #[inline] fn visit_map(&self) -> EntityVisitMap { EntityVisitMap::new(self.fun.blocks.len()) } #[inline] fn reset_map(&self, map: &mut EntityVisitMap) { map.reset(self.fun.blocks.len()); } } #[cfg(test)] mod tests { use crate::{Function, FunctionBuilder, FunctionIdent}; use libeir_diagnostics::SourceSpan; use libeir_intern::Ident; use petgraph::visit::IntoNeighborsDirected; use petgraph::Direction; #[test] fn test_edge() { let ident = FunctionIdent { module: Ident::from_str("woo"), name: Ident::from_str("woo"), arity: 1, }; let mut fun = Function::new(SourceSpan::UNKNOWN, ident); let mut b = FunctionBuilder::new(&mut fun); let b1 = b.block_insert(); b.block_set_entry(b1); let b1_ret = b.block_arg_insert(b1); let b2 = b.block_insert(); let b3 = b.block_insert(); b.op_call_flow(b1, b2, &[]); b.op_call_flow(b2, b1_ret, &[]); b.op_call_flow(b3, b2, &[]); let graph = b.fun().block_graph(); assert!( &graph .neighbors_directed(b1, Direction::Outgoing) .collect::>() == &[b2] ); assert!( &graph .neighbors_directed(b2, Direction::Outgoing) .collect::>() == &[] ); assert!( &graph .neighbors_directed(b3, Direction::Outgoing) .collect::>() == &[b2] ); assert!( &graph .neighbors_directed(b1, Direction::Incoming) .collect::>() == &[] ); assert!( &graph .neighbors_directed(b2, Direction::Incoming) .collect::>() == &[b1, b3] ); assert!( &graph .neighbors_directed(b3, Direction::Incoming) .collect::>() == &[] ); } } ================================================ FILE: libeir_ir/src/graph/control_flow_graph.rs ================================================ use std::collections::BTreeSet; use petgraph::visit::{Dfs, DfsPostOrder}; use petgraph::visit::{GraphBase, IntoNeighbors, IntoNeighborsDirected, Visitable, Walker}; use petgraph::Direction; use cranelift_entity::{EntityList, ListPool, SecondaryMap}; use itertools::Either; use super::block_graph::EntityVisitMap; use crate::Function; use crate::Value; impl Function { pub fn control_flow_graph(&self) -> ControlFlowGraph { ControlFlowGraph::new() } } #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct CfgBranch(pub usize); /// This is a newtype that contains implementations of petgraphs graph traits. /// /// The semantics of the below graph are as follows: /// - Nodes are values /// - Only explicit control flow are graph edges #[derive(Debug)] pub struct ControlFlowGraph { entry: Option, forward: SecondaryMap>, back: SecondaryMap>, pool: ListPool, } impl ControlFlowGraph { pub fn new() -> Self { ControlFlowGraph { entry: None, forward: SecondaryMap::new(), back: SecondaryMap::new(), pool: ListPool::new(), } } pub fn calculate(&mut self, fun: &Function, entry: Value) { self.entry = Some(entry); self.forward.clear(); self.back.clear(); self.pool.clear(); let mut to_walk = Vec::new(); to_walk.push(entry); let mut walked = BTreeSet::new(); while let Some(val) = to_walk.pop() { if walked.contains(&val) { continue; } walked.insert(val); if let Some(block) = fun.value_block(val) { let forward = &mut self.forward[val]; for out in fun.op_branch_iter(block) { forward.push(out, &mut self.pool); self.back[out].push(val, &mut self.pool); if !walked.contains(&out) { to_walk.push(out); } } } } } pub fn dfs(&self) -> Dfs> { Dfs::new(self, self.entry.unwrap()) } pub fn dfs_iter<'a>(&'a self) -> impl Iterator + 'a { self.dfs().iter(self) } pub fn dfs_post_order(&self) -> DfsPostOrder> { DfsPostOrder::new(self, self.entry.unwrap()) } pub fn dfs_post_order_iter<'a>(&'a self) -> impl Iterator + 'a { self.dfs_post_order().iter(self) } } impl GraphBase for ControlFlowGraph { type NodeId = Value; type EdgeId = CfgBranch; } pub struct ControlFlowSuccessors<'a> { graph: &'a ControlFlowGraph, value: Value, curr: usize, } impl<'a> Iterator for ControlFlowSuccessors<'a> { type Item = Value; fn next(&mut self) -> Option { if let Some(val) = self.graph.forward[self.value].get(self.curr, &self.graph.pool) { self.curr += 1; Some(val) } else { None } } } pub struct ControlFlowPredecessors<'a> { graph: &'a ControlFlowGraph, value: Value, curr: usize, } impl<'a> ControlFlowPredecessors<'a> { pub fn new(graph: &'a ControlFlowGraph, value: Value) -> Self { ControlFlowPredecessors { graph, value, curr: 0, } } } impl<'a> Iterator for ControlFlowPredecessors<'a> { type Item = Value; fn next(&mut self) -> Option { if let Some(val) = self.graph.back[self.value].get(self.curr, &self.graph.pool) { self.curr += 1; Some(val) } else { None } } } impl<'a> IntoNeighbors for &'a ControlFlowGraph { type Neighbors = ControlFlowSuccessors<'a>; fn neighbors(self, value: Value) -> Self::Neighbors { ControlFlowSuccessors { graph: self, value, curr: 0, } } } impl<'a> IntoNeighborsDirected for &'a ControlFlowGraph { type NeighborsDirected = Either, ControlFlowPredecessors<'a>>; fn neighbors_directed(self, value: Value, dir: Direction) -> Self::NeighborsDirected { match dir { Direction::Outgoing => Either::Left(self.neighbors(value)), Direction::Incoming => Either::Right(ControlFlowPredecessors::new(self, value)), } } } impl<'a> Visitable for ControlFlowGraph { type Map = EntityVisitMap; #[inline] fn visit_map(&self) -> EntityVisitMap { EntityVisitMap::new(self.forward.capacity()) } #[inline] fn reset_map(&self, map: &mut EntityVisitMap) { map.reset(self.forward.capacity()); } } ================================================ FILE: libeir_ir/src/graph/live_block_graph.rs ================================================ use std::collections::HashSet; use petgraph::visit::{Dfs, DfsPostOrder}; use petgraph::visit::{ GraphBase, IntoNeighbors, IntoNeighborsDirected, IntoNodeIdentifiers, Visitable, }; use petgraph::Direction; use itertools::Either; use cranelift_bforest::SetIter; use crate::Block; use crate::Function; use super::block_graph::EntityVisitMap; use super::block_graph::{BlockEdge, BlockSuccessors}; use super::BlockGraph; impl Function { pub fn live_block_graph(&self) -> LiveBlockGraph<'_> { LiveBlockGraph::new(self) } } /// This is a newtype that contains implementations of petgraphs graph traits. /// /// This has identical semantics to `BlockGraph`, with the following difference: /// - Back edges do not exist to non-live blocks /// /// If back edges to non-live blocks are acceptable, it is recommended to use /// `BlockGraph` instead. pub struct LiveBlockGraph<'a> { pub graph: BlockGraph<'a>, pub live: HashSet, } impl<'a> LiveBlockGraph<'a> { pub fn new(fun: &'a Function) -> Self { let graph = fun.block_graph(); let mut live = HashSet::new(); for block in graph.dfs_iter() { live.insert(block); } LiveBlockGraph { graph, live } } pub fn dfs(&self) -> Dfs> { self.graph.dfs() } pub fn dfs_iter(&'a self) -> impl Iterator + 'a { self.graph.dfs_iter() } pub fn dfs_post_order(&self) -> DfsPostOrder> { self.graph.dfs_post_order() } pub fn dfs_post_order_iter(&'a self) -> impl Iterator + 'a { self.graph.dfs_post_order_iter() } pub fn outgoing(&'a self, block: Block) -> impl Iterator + 'a { self.graph.outgoing(block) } pub fn incoming(&'a self, block: Block) -> impl Iterator + 'a { self.graph.fun.blocks[block] .predecessors .iter(&self.graph.fun.pool.block_set) .filter(move |b| self.live.contains(b)) } } pub struct LiveBlockPredecessors<'a> { graph: &'a LiveBlockGraph<'a>, iter: SetIter<'a, Block>, } impl<'a> LiveBlockPredecessors<'a> { fn new(graph: &'a LiveBlockGraph, block: Block) -> Self { LiveBlockPredecessors { graph, iter: graph.graph.fun.blocks[block] .predecessors .iter(&graph.graph.fun.pool.block_set), } } } impl<'a> Iterator for LiveBlockPredecessors<'a> { type Item = Block; #[inline] fn next(&mut self) -> Option { while let Some(block) = self.iter.next() { if self.graph.live.contains(&block) { return Some(block); } } None } } impl<'a> GraphBase for LiveBlockGraph<'a> { type NodeId = Block; type EdgeId = BlockEdge; } impl<'a> IntoNeighbors for &'a LiveBlockGraph<'a> { type Neighbors = BlockSuccessors<'a>; #[inline] fn neighbors(self, block: Block) -> Self::Neighbors { self.graph.neighbors(block) } } impl<'a> IntoNeighborsDirected for &'a LiveBlockGraph<'a> { type NeighborsDirected = Either, LiveBlockPredecessors<'a>>; #[inline] fn neighbors_directed(self, block: Block, dir: Direction) -> Self::NeighborsDirected { match dir { Direction::Outgoing => Either::Left(self.graph.neighbors(block)), Direction::Incoming => Either::Right(LiveBlockPredecessors::new(self, block)), } } } impl<'a> Visitable for &'a LiveBlockGraph<'a> { type Map = EntityVisitMap; #[inline] fn visit_map(&self) -> EntityVisitMap { Visitable::visit_map(&self.graph) } #[inline] fn reset_map(&self, map: &mut EntityVisitMap) { Visitable::reset_map(&self.graph, map) } } pub struct NodeIterator(Vec, usize); impl Iterator for NodeIterator { type Item = Block; fn next(&mut self) -> Option { let val = self.0.get(self.1).cloned(); self.1 += 1; val } } impl<'a> IntoNodeIdentifiers for &'a LiveBlockGraph<'a> { type NodeIdentifiers = NodeIterator; fn node_identifiers(self) -> Self::NodeIdentifiers { let live = self.live.iter().cloned().collect::>(); NodeIterator(live, 0) } } #[cfg(test)] mod tests { use crate::{Function, FunctionBuilder, FunctionIdent}; use libeir_diagnostics::SourceSpan; use libeir_intern::Ident; use petgraph::visit::IntoNeighborsDirected; use petgraph::Direction; #[test] fn test_back_edge() { let ident = FunctionIdent { module: Ident::from_str("woo"), name: Ident::from_str("woo"), arity: 1, }; let mut fun = Function::new(SourceSpan::UNKNOWN, ident); let mut b = FunctionBuilder::new(&mut fun); let b1 = b.block_insert(); b.block_set_entry(b1); let b1_ret = b.block_arg_insert(b1); let b2 = b.block_insert(); let b3 = b.block_insert(); b.op_call_flow(b1, b2, &[]); b.op_call_flow(b2, b1_ret, &[]); b.op_call_flow(b3, b2, &[]); let graph = b.fun().live_block_graph(); assert!( &graph .neighbors_directed(b1, Direction::Outgoing) .collect::>() == &[b2] ); assert!( &graph .neighbors_directed(b2, Direction::Outgoing) .collect::>() == &[] ); assert!( &graph .neighbors_directed(b3, Direction::Outgoing) .collect::>() == &[b2] ); assert!( &graph .neighbors_directed(b1, Direction::Incoming) .collect::>() == &[] ); assert!( &graph .neighbors_directed(b2, Direction::Incoming) .collect::>() == &[b1] ); assert!( &graph .neighbors_directed(b3, Direction::Incoming) .collect::>() == &[] ); } } ================================================ FILE: libeir_ir/src/graph/mod.rs ================================================ pub use petgraph::visit::IntoNeighborsDirected; pub use petgraph::Direction; mod block_graph; pub use block_graph::{BlockGraph, EntityVisitMap}; mod live_block_graph; pub use live_block_graph::LiveBlockGraph; mod control_flow_graph; pub use control_flow_graph::ControlFlowGraph; ================================================ FILE: libeir_ir/src/ir_construct_macro.rs ================================================ #![allow(unused_macros)] macro_rules! build_ir { ($module:ident : $name:ident / $arity:expr => $body:tt) => { #[allow(unused_variables, unused_mut, unused_assignments, redundant_semicolon)] { use libeir_intern::Ident; let ident = $crate::FunctionIdent { module: Ident::from_str(std::stringify!($module).into()), name: Ident::from_str(std::stringify!($name).into()), arity: $arity, }; let mut fun = $crate::Function::new(ident); { let mut b = fun.builder(); build_ir!(INTERNAL_MACRO; BLOCKS; &mut b; $body); } fun } }; (INTERNAL_MACRO; BLOCKS; $b:expr; { $( $block_name:ident ( $($block_arg:ident),* ) { $( $($body_item:tt)*; )* }; )* }) => { { use std::stringify; use std::collections::HashMap; use $crate::{Block, Value}; let mut b = $b; let mut entry = None; let mut block_map: HashMap<&'static str, Block> = HashMap::new(); let mut value_map: HashMap<&'static str, Value> = HashMap::new(); // First pass, create blocks and arguments $( let block_name = stringify!($block_name); let block = b.block_insert(); if entry.is_none() { entry = Some(block); } assert!(!value_map.contains_key(&block_name)); block_map.insert(block_name, block); value_map.insert(block_name, b.value(block)); $( let arg_name = stringify!($block_arg); let arg_value = b.block_arg_insert(block); assert!(!value_map.contains_key(&arg_name)); value_map.insert(arg_name, arg_value); )*; )*; // Second pass, create primops, constants and bodies $( let block_name = stringify!($block_name); let block = block_map[block_name]; $( build_ir!(INTERNAL_MACRO; BLOCK_ITEM; $b; value_map; block; $($body_item_part)*); )*; )*; } }; (INTERNAL_MACRO; BLOCK_ITEM; $b:expr; $value_map:expr; $block:expr; $var_name:ident = $($var_tts:tt)*) => { }; (INTERNAL_MACRO; BLOCK_ITEM; $b:expr; $value_map:expr; $block:expr; call $call_name:ident ( $($call_arg:ident),* )) => { { let call_dest = build_ir!( INTERNAL_MACRO; VALUE; $value_map; $call_name); let call_args = &[$(build_ir!( INTERNAL_MACRO; VALUE; $value_map; $call_arg)),*]; $b.op_call($block, call_dest, call_args); } }; (INTERNAL_MACRO; VALUE; $value_map:expr; $value_name:ident) => { { let value_name = stringify!($value_name); *$value_map.get(value_name).unwrap() } }; } #[cfg(test)] mod tests { #[test] fn basic_ir_build() { build_ir!( test:test/0 => { b_entry(ret, exc) { call b_1(c_true); }; b_1() { call ret(b_1); }; } ); } } ================================================ FILE: libeir_ir/src/lib.rs ================================================ #![feature(specialization, raw, allocator_api)] //#![deny(warnings)] use std::cmp::Ordering; use std::fmt::{Display, Formatter}; use libeir_intern::Ident; mod function; mod dialect; pub use dialect::{ArcDialect, Dialect}; pub mod operation; pub mod traits; // Auxiliary utilities mod algo; pub use algo::equality::GraphEqOptions; pub use algo::func_tree::{FunctionEntry, FunctionTree}; pub use algo::live::LiveValues; pub use algo::mangle::{MangleFrom, MangleTarget, MangleTo, Mangler}; pub use algo::validate::ValidationError; pub mod text; pub mod graph; pub use graph::LiveBlockGraph; // Subcontainers pub mod constant; pub mod pattern; pub use function::ValueKind; pub use function::{AttributeKey, AttributeValue}; pub use function::{ BasicType, BinOp, CallKind, LogicOp, MapPutUpdate, MatchKind, OpKind, PrimOpKind, }; pub use function::{Block, Function, Location, PrimOp, Value}; pub use function::{ContainerDebug, ContainerDebugAdapter}; pub use function::builder::{DynValue, FunctionBuilder, IntoValue}; pub use constant::EmptyMap; pub use constant::{AtomTerm, BigIntTerm, BinaryTerm, FloatTerm, IntTerm, NilTerm}; pub use constant::{AtomicTerm, Const, ConstKind, ConstantContainer}; pub use constant::{FromPrimitive, Integer, ToPrimitive}; pub use pattern::{PatternClause, PatternContainer, PatternNode, PatternValue}; pub use text::printer::{FormatConfig, StandardFormatConfig}; pub use text::{ parse_function, parse_function_map, parse_function_map_unwrap, parse_function_unwrap, parse_module, parse_module_unwrap, }; pub mod binary; pub use binary::{BinaryEntrySpecifier, Endianness}; mod module; pub use module::{FunctionDefinition, FunctionIndex, Module}; #[derive(Debug, Copy, Clone, Hash, Eq, PartialEq, PartialOrd)] pub struct FunctionIdent { pub module: Ident, pub name: Ident, pub arity: usize, } impl Ord for FunctionIdent { fn cmp(&self, other: &FunctionIdent) -> Ordering { self.partial_cmp(other).unwrap() } } impl Display for FunctionIdent { fn fmt(&self, f: &mut Formatter) -> std::fmt::Result { write!(f, "{}:{}/{}", self.module, self.name, self.arity) } } ================================================ FILE: libeir_ir/src/module.rs ================================================ use std::collections::BTreeMap; use std::ops::{Index, IndexMut}; use cranelift_entity::{entity_impl, PrimaryMap}; use crate::{Function, FunctionIdent}; use libeir_diagnostics::SourceSpan; use libeir_intern::{Ident, Symbol}; pub struct FunctionDefinition { index: FunctionIndex, fun: Function, } impl FunctionDefinition { pub fn index(&self) -> FunctionIndex { self.index } pub fn function(&self) -> &Function { &self.fun } pub fn function_mut(&mut self) -> &mut Function { &mut self.fun } } #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct FunctionIndex(u32); entity_impl!(FunctionIndex, "function_index"); pub struct Module { name: Ident, span: SourceSpan, functions: PrimaryMap, name_map: BTreeMap<(Symbol, usize), FunctionIndex>, } impl Module { pub fn new(name: Ident) -> Self { Self { name, span: SourceSpan::UNKNOWN, functions: PrimaryMap::new(), name_map: BTreeMap::new(), } } pub fn new_with_span(name: Ident, span: SourceSpan) -> Self { Self { name, span, functions: PrimaryMap::new(), name_map: BTreeMap::new(), } } pub fn name(&self) -> Ident { self.name } pub fn span(&self) -> SourceSpan { self.span } pub fn add_function( &mut self, span: SourceSpan, name: Ident, arity: usize, ) -> &mut FunctionDefinition { let ident = FunctionIdent { module: self.name, name, arity, }; assert!(!self.name_map.contains_key(&(name.name, arity))); let fun = Function::new(span, ident); let def = FunctionDefinition { index: FunctionIndex(0), fun, }; let index = self.functions.push(def); self.name_map.insert((name.name, arity), index); let def_mut = self.functions.get_mut(index).unwrap(); def_mut.index = index; def_mut } pub fn ident_index(&self, ident: &FunctionIdent) -> Option { self.name_map.get(&(ident.name.name, ident.arity)).cloned() } pub fn name_arity_index(&self, name: Symbol, arity: usize) -> Option { self.name_map.get(&(name, arity)).cloned() } pub fn function_iter(&self) -> impl Iterator { self.functions.values() } pub fn function_iter_mut(&mut self) -> impl Iterator { self.functions.values_mut() } pub fn index_iter(&self) -> impl Iterator { self.functions.keys() } } impl Clone for Module { fn clone(&self) -> Self { let mut functions: PrimaryMap = PrimaryMap::new(); let mut name_map = BTreeMap::new(); for def in self.function_iter() { let fun = def.function(); let ident = fun.ident(); let def = FunctionDefinition { index: FunctionIndex(0), fun: fun.clone(), }; let index = functions.push(def); name_map.insert((ident.name.name, ident.arity), index); } Self { name: self.name.clone(), span: self.span, functions, name_map, } } } impl Index for Module { type Output = FunctionDefinition; fn index(&self, idx: FunctionIndex) -> &FunctionDefinition { &self.functions[idx] } } impl IndexMut for Module { fn index_mut(&mut self, idx: FunctionIndex) -> &mut FunctionDefinition { &mut self.functions[idx] } } impl Index<&FunctionIdent> for Module { type Output = FunctionDefinition; fn index(&self, ident: &FunctionIdent) -> &FunctionDefinition { let idx = self .ident_index(ident) .expect("function ident not in module"); &self.functions[idx] } } ================================================ FILE: libeir_ir/src/operation/binary_construct.rs ================================================ //! # Binary construction construct //! Binary construction is represented as several intrinsics that interact //! to represent binary construction. //! //! Binary construction always consists of a single //! `binary_construct_start`, any number of `binary_construct_push`, //! finishing off with a single `binary_construct_finish`. //! //! `binary_construct_start` returns a opaque handle that is used to refer //! to the binary construction in subsequent interactions. //! //! Once control flow enters through a `binary_construct_start`, it must //! ALWAYS exit through a `binary_construct_finish`. //! //! Several binary constructions may happen concurrently, as long as they //! are all eventually finished. //! //! A binary construction may contain arbitrary control flow, and as such //! the number of pushes may vary from run to run. //! //! ```ignore //! v //! binary_construct_start //! | //! v //! binary_construct_push //! | //! ...<------------- //! v | //! binary_construct_push | //! | | //! ...-------------- //! | //! v //! binary_construct_push //! | //! v //! binary_construct_finish //! //! ```` use std::any::TypeId; use std::default::Default; use meta_table::{impl_meta_entry, MetaEntry}; use super::{DynOp, Op, OpBuild}; use crate::dialect::Dialect; use crate::traits::OpBranches; use crate::{BinaryEntrySpecifier, Block, Function, FunctionBuilder, Value}; pub struct BinaryConstructToken(()); /// ## `binary_construct_start` /// (cont: fn(bin_ref)) #[derive(Debug, Clone)] pub struct BinaryConstructStart; impl_meta_entry!(BinaryConstructStart); impl_op!(BinaryConstructStart, "binary_construct_start"); impl OpBranches for BinaryConstructStart { fn branches_len(&self) -> usize { 1 } fn branch_num(&self, fun: &Function, block: Block, branch_n: usize) -> Value { match branch_n { 0 => fun.block_reads(block)[0], _ => unreachable!(), } } } impl BinaryConstructStart { pub fn build(builder: &mut FunctionBuilder, block: Block) -> Block { let target = builder.block_insert(); let _arg = builder.block_arg_insert(target); Self::build_target(builder, block, target); target } pub fn build_target(builder: &mut FunctionBuilder, block: Block, target: Block) { let target_val = builder.value(target); builder.op_intrinsic( block, BinaryConstructStart, &[target_val], BinaryConstructToken(()), ); } } impl OpBuild for BinaryConstructStart { type Token = BinaryConstructToken; } /// ## `binary_construct_push` /// (ok: fn(bin_ref), fail: fn(), bin_ref, value) /// (ok: fn(bin_ref), fail: fn(), bin_ref, value, size) #[derive(Debug, Default, Clone, PartialEq)] pub struct BinaryConstructPush { pub specifier: BinaryEntrySpecifier, } impl_meta_entry!(BinaryConstructPush); impl Op for BinaryConstructPush { fn name(&self) -> &str { "binary_construct_push" } fn dyn_clone(&self) -> DynOp { DynOp::new(self.clone()) } fn type_id(&self) -> TypeId { TypeId::of::() } fn meta_entry(&self) -> &dyn MetaEntry { self } fn op_eq(&self, other: &dyn Op) -> bool { if let Some(other_i) = other.downcast_ref::() { self == other_i } else { false } } } impl OpBranches for BinaryConstructPush { fn branches_len(&self) -> usize { 2 } fn branch_num(&self, fun: &Function, block: Block, branch_n: usize) -> Value { match branch_n { 0 => fun.block_reads(block)[0], 1 => fun.block_reads(block)[1], _ => unreachable!(), } } } impl BinaryConstructPush { pub fn build( builder: &mut FunctionBuilder, block: Block, bin_ref: Value, value: Value, spec: BinaryEntrySpecifier, size: Option, ) -> (Block, Block) { let ok = builder.block_insert(); let _bin_ref = builder.block_arg_insert(ok); let fail = builder.block_insert(); Self::build_target(builder, block, bin_ref, value, spec, size, ok, fail); (ok, fail) } pub fn build_target( builder: &mut FunctionBuilder, block: Block, bin_ref: Value, value: Value, spec: BinaryEntrySpecifier, size: Option, ok: Block, fail: Block, ) { let ok_val = builder.value(ok); let fail_val = builder.value(fail); if let Some(size) = size { builder.op_intrinsic( block, BinaryConstructPush { specifier: spec }, &[ok_val, fail_val, bin_ref, value, size], BinaryConstructToken(()), ); } else { builder.op_intrinsic( block, BinaryConstructPush { specifier: spec }, &[ok_val, fail_val, bin_ref, value], BinaryConstructToken(()), ); }; } } impl OpBuild for BinaryConstructPush { type Token = BinaryConstructToken; } /// ## `binary_construct_finish` /// (cont: fn(result), ref) #[derive(Debug, Clone)] pub struct BinaryConstructFinish; impl_meta_entry!(BinaryConstructFinish); impl Op for BinaryConstructFinish { fn name(&self) -> &str { "binary_construct_finish" } fn dyn_clone(&self) -> DynOp { DynOp::new(self.clone()) } fn type_id(&self) -> TypeId { TypeId::of::() } fn meta_entry(&self) -> &dyn MetaEntry { self } } impl OpBranches for BinaryConstructFinish { fn branches_len(&self) -> usize { 1 } fn branch_num(&self, fun: &Function, block: Block, branch_n: usize) -> Value { match branch_n { 0 => fun.block_reads(block)[0], _ => unreachable!(), } } } impl BinaryConstructFinish { pub fn build(builder: &mut FunctionBuilder, block: Block, bin_ref: Value) -> Block { let target = builder.block_insert(); let _arg = builder.block_arg_insert(target); Self::build_target(builder, block, bin_ref, target); target } pub fn build_target( builder: &mut FunctionBuilder, block: Block, bin_ref: Value, target: Block, ) { let target_val = builder.value(target); builder.op_intrinsic( block, BinaryConstructFinish, &[target_val, bin_ref], BinaryConstructToken(()), ); } } impl OpBuild for BinaryConstructFinish { type Token = BinaryConstructToken; } pub fn register(dialect: &mut Dialect) { dialect.register_op::(); dialect.register_op_branches_impl::(); dialect.register_op::(); dialect.register_op_branches_impl::(); dialect.register_op::(); dialect.register_op_branches_impl::(); } ================================================ FILE: libeir_ir/src/operation/case.rs ================================================ use std::any::TypeId; use libeir_diagnostics::SourceSpan; use libeir_intern::Symbol; use meta_table::{impl_meta_entry, MetaEntry}; use pretty::{DocAllocator, RefDoc}; use super::{DynOp, Op, OpBuild}; use crate::pattern::{PatternClause, PatternContainer}; use crate::text::ast::DynToken; use crate::text::parse_dyn::{DynParserError, ParseCtx}; use crate::text::LowerContext; use crate::traits::{FormatOpCtx, OpBranches, OpParser, OpPrinter}; use crate::{Block, Dialect, Function, FunctionBuilder, Value}; pub struct CaseToken(()); /// Case structure /// ```ignore /// ( /// no_match: fn(), /// ( /// guard: fn(ok: fn(), fail: fn(), pat_refs..), /// body: fn(pat_refs..), /// ).., /// match_val: , /// match_values: term.., /// ) /// ``` /// /// High level matching construct, lowered to explicit control flow /// in a Eir compiler pass. Only allowed in high level Eir dialect. /// This OP indicates the start of a case structure. /// A guard is strictly required to return through either the ok /// or fail continuation. #[derive(Debug, Clone)] pub struct Case { inner: Box, } impl_meta_entry!(Case); impl Case { pub fn pat<'a>(&'a self) -> &'a PatternContainer { &self.inner.container } pub fn clauses<'a>(&'a self) -> &'a [PatternClause] { &self.inner.clauses } } #[derive(Debug, Clone)] struct Inner { container: PatternContainer, clauses: Vec, } impl Op for Case { fn name(&self) -> &str { "case" } fn dyn_clone(&self) -> DynOp { DynOp::new(self.clone()) } fn type_id(&self) -> TypeId { TypeId::of::() } fn meta_entry(&self) -> &dyn MetaEntry { self } fn op_eq(&self, other: &dyn Op) -> bool { if let Some(_other_i) = other.downcast_ref::() { unimplemented!() } else { false } } } impl OpBranches for Case { fn branches_len(&self) -> usize { 1 + self.inner.clauses.len() } fn branch_num(&self, fun: &Function, block: Block, branch_n: usize) -> Value { // [no_branch, guard_1, body_1, guard_2, body_2, ..] // guards are not control flow, they are lambda calls let reads = fun.block_reads(block); if branch_n == 0 { reads[0] } else { let n = branch_n - 1; reads[2 + n * 2] } } } impl OpPrinter for Case { fn to_doc<'doc>(&self, ctx: &mut dyn FormatOpCtx<'doc>, _block: Block) -> RefDoc<'doc, ()> { let arena = ctx.arena(); let inner = &*self.inner; //let block = arena.concat(inner.clauses.iter().map(|clause| { // let root_nodes = inner.container.clause_root_nodes(clause); //})); arena .nil() .append(arena.text("case")) .append(arena.space()) //.append(block.nest(1).braces()) .into_doc() } } impl Case { pub fn builder() -> CaseBuilder { CaseBuilder::default() } } pub struct CaseBuilder { span: SourceSpan, pub container: PatternContainer, pub match_on: Option, pub no_match: Option, clauses: Vec, clauses_b: Vec, values: Vec, } impl Default for CaseBuilder { fn default() -> Self { CaseBuilder { span: SourceSpan::UNKNOWN, container: PatternContainer::new(), match_on: None, no_match: None, clauses: Vec::new(), clauses_b: Vec::new(), values: Vec::new(), } } } impl CaseBuilder { pub fn new(span: SourceSpan) -> Self { let mut this = Self::default(); this.span = span; this } pub fn set_span(&mut self, span: SourceSpan) { self.span = span; } pub fn push_clause<'a>( &mut self, clause: PatternClause, guard: Value, body: Value, _b: &mut FunctionBuilder<'a>, ) { self.clauses.push(clause); self.clauses_b.extend([guard, body].iter().cloned()); } pub fn push_value<'a>(&mut self, value: Value, _b: &mut FunctionBuilder<'a>) { self.values.push(value); } pub fn finish<'a>(self, block: Block, b: &mut FunctionBuilder<'a>) { // Validate that the number of values matches between the // clauses and reads let mut num_values = 0; for clause in &self.clauses { num_values += self.container.clause_values(*clause).len(); } let num_value_reads = self.values.len(); assert!(num_values == num_value_reads); let op = Case { inner: Box::new(Inner { container: self.container, clauses: self.clauses, }), }; let mut args = vec![self.no_match.unwrap()]; args.extend(self.clauses_b.iter().cloned()); args.push(self.match_on.unwrap()); args.extend(self.values.iter().cloned()); b.op_intrinsic(block, op, &args, CaseToken(())); //let data = b.fun_mut().blocks.get_mut(block).unwrap(); //assert!(data.op.is_none()); //assert!(data.reads.is_empty()); //b.op_intrinsic(block, op, args, _token) //data.op = Some(OpKind::Case { // clauses: self.clauses, //}); //data.location = b.fun_mut().locations.location(None, None, None, self.span); //let mut buf = b.value_buf.take().unwrap(); //buf.clear(); //data.reads // .push(self.no_match.unwrap(), &mut b.fun.pool.value); //// Guard and body blocks for clauses //for c in self.clauses_b.as_slice(&b.fun.pool.value) { // buf.push(*c); //} //data.reads // .extend(buf.iter().cloned(), &mut b.fun.pool.value); //// Match value //data.reads // .push(self.match_on.unwrap(), &mut b.fun.pool.value); //// Values //buf.clear(); //for c in self.values.as_slice(&b.fun.pool.value) { // buf.push(*c); //} //data.reads // .extend(buf.iter().cloned(), &mut b.fun.pool.value); //buf.clear(); //b.value_buf = Some(buf); //self.clauses_b.clear(&mut b.fun.pool.value); //self.values.clear(&mut b.fun.pool.value); //b.graph_update_block(block); //b.fun.graph_validate_block(block); } } impl OpBuild for Case { type Token = CaseToken; } macro_rules! parser_fail { ($context:expr, $value:expr) => { match $value { Ok(value) => value, Err(error) => { $context.error(error); return Err(()); } } }; } struct CaseParser; impl OpParser for CaseParser { fn parse( &self, context: &mut LowerContext, block: Block, tokens: &[DynToken], ) -> Result<(), ()> { use crate::text::parse_dyn::val; let mut ctx = ParseCtx::new(tokens, SourceSpan::UNKNOWN); let value = parser_fail!(context, val(&mut ctx)); parser_fail!(context, parse_case_body(&mut ctx)); parser_fail!(context, ctx.eof()); unimplemented!() } } fn parse_case_body(ctx: &mut ParseCtx) -> Result<(), DynParserError> { let (tokens, span) = ctx.tok_braces()?; let mut ictx = ParseCtx::new(tokens, span); Ok(()) } pub fn register(dialect: &mut Dialect) { dialect.register_op::(); dialect.register_op_branches_impl::(); dialect.register_op_printer_impl::(); dialect.register_op_parser(Symbol::intern("casen"), Box::new(CaseParser)); } #[cfg(test)] mod tests { #[ignore] #[test] fn basic_parse() { let fun = crate::text::parse_function_unwrap( " a'foo':a'bar'/1 { entry(%ret, %thr, %a): @casen <%a> {}; } ", ); } } ================================================ FILE: libeir_ir/src/operation/mod.rs ================================================ use std::ops::Deref; use std::any::TypeId; use std::fmt::{Debug, Formatter, Result as FmtResult}; use std::raw::TraitObject; use meta_table::MetaEntry; use stack_dst::Value; macro_rules! impl_op { ($typ:ident, $name:expr) => { impl Op for $typ { fn name(&self) -> &str { $name } fn dyn_clone(&self) -> DynOp { DynOp::new(self.clone()) } fn type_id(&self) -> TypeId { TypeId::of::() } fn meta_entry(&self) -> &dyn MetaEntry { self } } }; } pub mod binary_construct; pub mod case; pub mod receive; pub trait Op: MetaEntry + Send { fn name(&self) -> &str; fn dyn_clone(&self) -> DynOp; fn type_id(&self) -> TypeId; fn meta_entry(&self) -> &dyn MetaEntry; /// Tests for semantic equality between the two operations. /// The default implementation assumes no inner state, and simply compares /// TypeIds. fn op_eq(&self, other: &dyn Op) -> bool { self.type_id() == other.type_id() } fn debug_fmt(&self, formatter: &mut Formatter) -> FmtResult { write!(formatter, "Op[{}]", self.name()) } } impl dyn Op { pub fn try_cast(&self) -> Option<&T> { unimplemented!() } /// Returns some reference to the boxed value if it is of type `T`, or /// `None` if it isn't. #[inline] pub fn downcast_ref(&self) -> Option<&T> { // TODO: `type_id` is implemented by the user, if the user returns the // wrong TypeId, this is unsafe. if self.type_id() == TypeId::of::() { unsafe { Some(self.downcast_ref_unchecked()) } } else { None } } /// Returns a reference to the boxed value, blindly assuming it to be of type `T`. /// If you are not *absolutely certain* of `T`, you *must not* call this. #[inline] pub unsafe fn downcast_ref_unchecked(&self) -> &T { let trait_object: TraitObject = ::std::mem::transmute(self); std::mem::transmute(trait_object.data) } } pub trait OpBuild: Op { /// In order to allow the operation implementation to have control over /// invariants for the operaion in the IR, each buildable operation /// has a token that must be provided to the function builder when adding /// it to the IR. /// The operation implementation has control over how this token type is /// created, and may restrict it in order to ensure that only it is able /// to build itself. type Token; } pub struct DynOp(Value); impl DynOp { pub fn new(value: T) -> Self { DynOp(Value::new_stable(value, |v| v as _).ok().unwrap()) } } impl Deref for DynOp { type Target = dyn Op; fn deref(&self) -> &dyn Op { &*self.0 } } impl Clone for DynOp { fn clone(&self) -> Self { self.0.dyn_clone() } } impl Debug for DynOp { fn fmt(&self, formatter: &mut Formatter) -> FmtResult { self.0.debug_fmt(formatter) } } ================================================ FILE: libeir_ir/src/operation/receive.rs ================================================ //! # Receive construct //! A receive statement is represented as several intrinsics that //! interact to represent the receive operation semantics of erlang. //! //! It consists of 3 operations, `receive_start`, `receive_wait` //! and `receive_done`. They are always called in this pattern: //! //! ```ignore //! v //! receive_start //! | //! v //! receive_wait <------------ //! | | | //! timeout check_msg no match on //! | | message //! v v | //! control flow to ---- //! match on message //! | //! message matches //! | //! v //! receive_done //! | //! ``` use std::any::TypeId; use meta_table::{impl_meta_entry, MetaEntry}; use super::{DynOp, Op, OpBuild}; use crate::dialect::Dialect; use crate::traits::{FormatOpCtx, OpBranches, OpPrinter}; use crate::{Block, Function, FunctionBuilder, Value}; use pretty::{DocAllocator, RefDoc}; pub struct ReceiveToken(()); /// ## `receive_start` /// (cont: fn(recv_ref), timeout) /// /// `recv_ref` is an opaque value that represents the current /// receive operation. It is up to the runtime implementor /// to decide what this stores, if anything at all. /// Since receive constructs can never be nested, storing receive /// state globally is also a valid strategy. /// This value can only ever be passed to `receive_wait` or /// `receive_done`. /// /// `timeout` is either an atom, `infinity`, or a number. #[derive(Debug, Clone)] pub struct ReceiveStart; impl_meta_entry!(ReceiveStart); impl Op for ReceiveStart { fn name(&self) -> &str { "receive_start" } fn dyn_clone(&self) -> DynOp { DynOp::new(self.clone()) } fn type_id(&self) -> TypeId { TypeId::of::() } fn meta_entry(&self) -> &dyn MetaEntry { self } fn op_eq(&self, other: &dyn Op) -> bool { self.type_id() == other.type_id() } } impl OpBranches for ReceiveStart { fn branches_len(&self) -> usize { 1 } fn branch_num(&self, fun: &Function, block: Block, branch_n: usize) -> Value { match branch_n { 0 => fun.block_reads(block)[0], _ => unreachable!(), } } } impl OpPrinter for ReceiveStart { fn to_doc<'doc>(&self, ctx: &mut dyn FormatOpCtx<'doc>, block: Block) -> RefDoc<'doc, ()> { let arena = ctx.arena(); arena .nil() .append(arena.text("@")) .append(arena.text("receive_start")) .append(arena.space()) .into_doc() } } impl ReceiveStart { pub fn build(builder: &mut FunctionBuilder, block: Block, timeout: Value) -> Block { let target = builder.block_insert(); let _arg = builder.block_arg_insert(target); Self::build_target(builder, block, timeout, target); target } pub fn build_target( builder: &mut FunctionBuilder, block: Block, timeout: Value, target: Block, ) { let target_val = builder.value(target); builder.op_intrinsic( block, ReceiveStart, &[target_val, timeout], ReceiveToken(()), ); } } impl OpBuild for ReceiveStart { type Token = ReceiveToken; } /// ## `receive_wait` /// (timeout: fn(), check_message: fn(msg), recv_ref) /// /// This increments the mailbox pointer, fetches it, and calls /// `check_message` with that message. The value passed to /// `check_message` can not escape the current receive construct /// without being mapped through `receive_done`, so it is safe for /// this to be an off-heap value as long as it's guaranteed to be /// alive until the receive construct is exited by `receive_done`. /// /// If there are no more messages, this should yield until there is. /// /// If there is a timeout, `timeout` should be called. When `timeout` /// is called, the receive construct should be considered finished, /// that is, `receive_done` should not be called. #[derive(Debug, Clone)] pub struct ReceiveWait; impl_meta_entry!(ReceiveWait); impl Op for ReceiveWait { fn name(&self) -> &str { "receive_wait" } fn dyn_clone(&self) -> DynOp { DynOp::new(self.clone()) } fn type_id(&self) -> TypeId { TypeId::of::() } fn meta_entry(&self) -> &dyn MetaEntry { self } fn op_eq(&self, other: &dyn Op) -> bool { self.type_id() == other.type_id() } } impl OpBranches for ReceiveWait { fn branches_len(&self) -> usize { 2 } fn branch_num(&self, fun: &Function, block: Block, branch_n: usize) -> Value { match branch_n { 0 => fun.block_reads(block)[0], 1 => fun.block_reads(block)[1], _ => unreachable!(), } } } impl ReceiveWait { pub fn build(builder: &mut FunctionBuilder, block: Block, recv_ref: Value) -> (Block, Block) { let timeout = builder.block_insert(); let check_message = builder.block_insert(); let _message = builder.block_arg_insert(check_message); Self::build_target(builder, block, recv_ref, timeout, check_message); (timeout, check_message) } pub fn build_target( builder: &mut FunctionBuilder, block: Block, recv_ref: Value, timeout: Block, check_message: Block, ) { let timeout_val = builder.value(timeout); let check_message_val = builder.value(check_message); builder.op_intrinsic( block, ReceiveWait, &[timeout_val, check_message_val, recv_ref], ReceiveToken(()), ); } } impl OpBuild for ReceiveWait { type Token = ReceiveToken; } /// ## `receive_done` /// (next: fn(...), recv_ref, ...) /// /// Called when the message under the mailbox pointer is successfully /// matched, and should be removed from the mailbox. /// /// Called with an arbitrary amount of arguments, these are the values /// that have been extracted from that message. If these are off-heap /// references, this operation would presumably copy them to the current /// process heap, and ensure that they are under juristiction of the /// process GC. The potentially copied values are then passed on as /// arguments to `next`. /// /// After this operation is completed, there will be no live references /// to the value originally passed to `check_message`, they will have /// all been mapped through `receive_done`. #[derive(Debug, Clone)] pub struct ReceiveDone; impl_meta_entry!(ReceiveDone); impl Op for ReceiveDone { fn name(&self) -> &str { "receive_done" } fn dyn_clone(&self) -> DynOp { DynOp::new(self.clone()) } fn type_id(&self) -> TypeId { TypeId::of::() } fn meta_entry(&self) -> &dyn MetaEntry { self } fn op_eq(&self, other: &dyn Op) -> bool { self.type_id() == other.type_id() } } impl OpBranches for ReceiveDone { fn branches_len(&self) -> usize { 1 } fn branch_num(&self, fun: &Function, block: Block, branch_n: usize) -> Value { match branch_n { 0 => fun.block_reads(block)[0], _ => unreachable!(), } } } impl ReceiveDone { pub fn build( builder: &mut FunctionBuilder, block: Block, recv_ref: Value, values: &[Value], ) -> Block { let next = builder.block_insert(); for _ in values.iter() { builder.block_arg_insert(next); } Self::build_target(builder, block, recv_ref, values, next); next } pub fn build_target( builder: &mut FunctionBuilder, block: Block, recv_ref: Value, values: &[Value], next: Block, ) { let next_val = builder.value(next); let mut tmp = Vec::with_capacity(values.len() + 1); tmp.push(next_val); tmp.push(recv_ref); tmp.extend(values.iter().cloned()); builder.op_intrinsic(block, ReceiveDone, &tmp, ReceiveToken(())); } } impl OpBuild for ReceiveDone { type Token = ReceiveToken; } pub fn register(dialect: &mut Dialect) { dialect.register_op::(); dialect.register_op_branches_impl::(); //dialect.register_op_printer_impl(&ReceiveStart); dialect.register_op::(); dialect.register_op_branches_impl::(); //dialect.register_op_printer_impl(&ReceiveWait); dialect.register_op::(); dialect.register_op_branches_impl::(); //dialect.register_op_printer_impl(&ReceiveDone); } ================================================ FILE: libeir_ir/src/pattern/fmt.rs ================================================ use std::fmt; use super::PatternNode; impl fmt::Display for PatternNode { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { PatternNode::Wildcard => write!(f, "_")?, PatternNode::Assign(var, pat) => write!(f, "({:?} = {})", var, pat)?, PatternNode::Atomic(lit) => write!(f, "{:?}", lit)?, PatternNode::Tuple(nodes) => { write!(f, "{{")?; for node in nodes { write!(f, "{}, ", node)?; } write!(f, "}}")?; }, PatternNode::List(head_values, tail) => { write!(f, "[")?; for val in head_values { write!(f, "{}, ", val)?; } write!(f, " | {}", tail)?; write!(f, "]")?; }, PatternNode::Map(values) => { write!(f, "~{{")?; for (key_num, val) in values { write!(f, "V{}; {}, ", key_num.0, val)?; } write!(f, "}}~")?; }, PatternNode::Binary(elems) => { write!(f, "#<")?; for elem in elems.iter() { write!(f, "{}:{:?}, ", elem.node, elem.args)?; } write!(f, ">#")?; }, //PatternNode::Binary(elems) => { // write!(f, "#<")?; // for elem in elems { // write!(f, "#<{}>(", elem.0)?; // for attr in &elem.1 { // write!(f, "{}, ", attr)?; // } // write!(f, ")#")?; // } // write!(f, ">#")?; //}, } Ok(()) } } ================================================ FILE: libeir_ir/src/pattern/mod.rs ================================================ use std::collections::HashMap; use cranelift_entity::{entity_impl, EntityList, ListPool, PrimaryMap}; use libeir_diagnostics::SourceSpan; use crate::binary::BinaryEntrySpecifier; use crate::constant::ConstantContainer; use crate::Const; #[derive(Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] pub struct PatternNode(u32); entity_impl!(PatternNode, "pattern_node"); /// A input value for a pattern, used in map matching /// and binary matching #[derive(Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] pub struct PatternValue(u32); entity_impl!(PatternValue, "pattern_value"); #[derive(Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] pub struct PatternClause(u32); entity_impl!(PatternClause, "pattern_clause"); #[derive(Debug, Clone)] pub struct PatternContainer { nodes: PrimaryMap, values: PrimaryMap, clauses: PrimaryMap, pub node_pool: ListPool, pub value_pool: ListPool, /// Temporary map used for copies tmp_val_map: Option>, tmp_node_map: Option>, } impl Default for PatternContainer { fn default() -> PatternContainer { PatternContainer { nodes: PrimaryMap::new(), values: PrimaryMap::new(), clauses: PrimaryMap::new(), node_pool: ListPool::new(), value_pool: ListPool::new(), tmp_val_map: Some(HashMap::new()), tmp_node_map: Some(HashMap::new()), } } } #[derive(Debug, Clone)] struct PatternClauseData { span: SourceSpan, root_nodes: EntityList, node_binds_keys: EntityList, node_binds_vals: EntityList, /// This is the set of nodes that are bound from the pattern. /// This will correspond to another list of the same length stored /// outside of the container, the two will together form a pair. /// This way of doing things enables this single representation /// of patterns to work through several IRs. binds: EntityList, /// This is the set of values that are accessible from the pattern. /// Same as `binds`, except for external values used within the clause. values: EntityList, finished: bool, } #[derive(Debug, Clone)] struct PatternNodeData { kind: Option, finished: bool, span: SourceSpan, } #[derive(Debug, Clone)] pub enum PatternNodeKind { Wildcard, Const(Const), Value(PatternValue), Binary { specifier: BinaryEntrySpecifier, value: PatternNode, size: Option, remaining: Option, }, Tuple(EntityList), List { head: PatternNode, tail: PatternNode, }, Map { keys: EntityList, values: EntityList, }, } #[derive(Debug, Clone)] pub struct PatternBinaryEntryData {} pub enum PatternMergeFail { /// The two patterns are disjoint, they can never match at the /// same time. /// The two nodes are the reason for this. Disjoint { left: Option, right: PatternNode, }, /// Merging is not supported. Only happens with binaries /// The two nodes are the reason for this. Failure { left: Option, right: PatternNode, }, } impl PatternContainer { pub fn new() -> Self { Self::default() } pub fn clause_value(&mut self, clause: PatternClause) -> PatternValue { let val = self.values.push(()); self.clauses[clause].values.push(val, &mut self.value_pool); val } pub fn clause_node_value(&mut self, clause: PatternClause, node: PatternNode) -> PatternValue { let val = self.values.push(()); let data = &mut self.clauses[clause]; data.node_binds_keys.push(node, &mut self.node_pool); data.node_binds_vals.push(val, &mut self.value_pool); val } pub fn node_empty(&mut self, span: Option) -> PatternNode { self.nodes.push(PatternNodeData { kind: None, finished: false, span: span.unwrap_or(SourceSpan::UNKNOWN), }) } pub fn binary( &mut self, node: PatternNode, specifier: BinaryEntrySpecifier, value: PatternNode, size: Option, remaining: Option, ) { let mut data = &mut self.nodes[node]; assert!(data.kind.is_none()); data.kind = Some(PatternNodeKind::Binary { specifier, value, size, remaining, }); data.finished = true; } pub fn wildcard(&mut self, node: PatternNode) { let mut data = &mut self.nodes[node]; assert!(data.kind.is_none()); data.kind = Some(PatternNodeKind::Wildcard); data.finished = true; } pub fn constant(&mut self, node: PatternNode, val: Const) { let mut data = &mut self.nodes[node]; assert!(data.kind.is_none()); data.kind = Some(PatternNodeKind::Const(val)); data.finished = true; } pub fn value(&mut self, node: PatternNode, val: PatternValue) { let mut data = &mut self.nodes[node]; assert!(data.kind.is_none()); data.kind = Some(PatternNodeKind::Value(val)); data.finished = true; } pub fn tuple(&mut self, node: PatternNode) { let mut data = &mut self.nodes[node]; assert!(data.kind.is_none()); data.kind = Some(PatternNodeKind::Tuple(EntityList::new())); } pub fn tuple_elem_push(&mut self, tup: PatternNode, node: PatternNode) { let data = &mut self.nodes[tup]; assert!(!data.finished); assert!(data.kind.is_some()); if let PatternNodeKind::Tuple(ref mut list) = data.kind.as_mut().unwrap() { list.push(node, &mut self.node_pool); } else { panic!(); } } pub fn list(&mut self, node: PatternNode, head: PatternNode, tail: PatternNode) { let mut data = &mut self.nodes[node]; assert!(data.kind.is_none()); data.kind = Some(PatternNodeKind::List { head, tail }); data.finished = true; } pub fn map(&mut self, node: PatternNode) { let mut data = &mut self.nodes[node]; assert!(data.kind.is_none()); data.kind = Some(PatternNodeKind::Map { keys: EntityList::new(), values: EntityList::new(), }); } pub fn map_push(&mut self, map: PatternNode, key: PatternValue, value: PatternNode) { let data = &mut self.nodes[map]; assert!(!data.finished); assert!(data.kind.is_some()); if let PatternNodeKind::Map { ref mut keys, ref mut values, } = data.kind.as_mut().unwrap() { keys.push(key, &mut self.value_pool); values.push(value, &mut self.node_pool); } else { panic!(); } } pub fn node_finish(&mut self, node: PatternNode) { let data = &mut self.nodes[node]; assert!(data.kind.is_some()); data.finished = true; } pub fn node_set_span(&mut self, node: PatternNode, span: SourceSpan) { self.nodes[node].span = span; } pub fn clause_start(&mut self, span: SourceSpan) -> PatternClause { self.clauses.push(PatternClauseData { span, root_nodes: EntityList::new(), node_binds_keys: EntityList::new(), node_binds_vals: EntityList::new(), binds: EntityList::new(), values: EntityList::new(), finished: false, }) } pub fn clause_node_push(&mut self, clause: PatternClause, node: PatternNode) { let data = &mut self.clauses[clause]; assert!(!data.finished); data.root_nodes.push(node, &mut self.node_pool); } pub fn clause_bind_push(&mut self, clause: PatternClause, node: PatternNode) { let data = &mut self.clauses[clause]; assert!(!data.finished); data.binds.push(node, &mut self.node_pool); } pub fn clause_value_push(&mut self, clause: PatternClause, val: PatternValue) { let data = &mut self.clauses[clause]; assert!(!data.finished); data.values.push(val, &mut self.value_pool); } pub fn clause_finish(&mut self, clause: PatternClause) { let data = &mut self.clauses[clause]; assert!(!data.finished); data.finished = true; } pub fn copy_from(&mut self, clause: PatternClause, from: &PatternContainer) -> PatternClause { let from_clause = &from.clauses[clause]; let mut value_map = self.tmp_val_map.take().unwrap(); let mut node_map = self.tmp_node_map.take().unwrap(); let mut new_values = EntityList::new(); for from_val in from_clause.values.as_slice(&from.value_pool) { let new_val = self.values.push(()); new_values.push(new_val, &mut self.value_pool); value_map.insert(*from_val, new_val); } let mut new_roots = EntityList::new(); for node in from_clause.root_nodes.as_slice(&from.node_pool) { let new = copy_pattern_node(&value_map, &mut node_map, *node, from, self); new_roots.push(new, &mut self.node_pool); } let mut new_binds = EntityList::new(); for bind in from_clause.binds.as_slice(&from.node_pool) { new_binds.push(node_map[bind], &mut self.node_pool); } value_map.clear(); self.tmp_val_map = Some(value_map); node_map.clear(); self.tmp_node_map = Some(node_map); unimplemented!() //self.clauses.push(PatternClauseData { // root_nodes: new_roots, // node_binds_keys: unimplemented!(), // node_binds_vals: unimplemented!(), // binds: new_binds, // values: new_values, // finished: true, //}) } /// Given a HashMap containing the mapping, this will go through all the /// binds of a clause and update them. Useful when merging nodes while /// constructing patterns. pub fn update_binds(&mut self, clause: PatternClause, map: &HashMap) { let clause_d = &mut self.clauses[clause]; let len = clause_d.binds.len(&self.node_pool); for n in 0..len { let entry = clause_d.binds.get_mut(n, &mut self.node_pool).unwrap(); if let Some(new) = map.get(&*entry) { *entry = *new; } } } } impl PatternContainer { pub fn clause_root_nodes(&self, clause: PatternClause) -> &[PatternNode] { let data = &self.clauses[clause]; data.root_nodes.as_slice(&self.node_pool) } pub fn clause_binds(&self, clause: PatternClause) -> &[PatternNode] { let data = &self.clauses[clause]; data.binds.as_slice(&self.node_pool) } pub fn clause_values(&self, clause: PatternClause) -> &[PatternValue] { let data = &self.clauses[clause]; data.values.as_slice(&self.value_pool) } pub fn clause_node_binds_iter<'a>( &'a self, clause: PatternClause, ) -> impl Iterator + 'a { let data = &self.clauses[clause]; data.node_binds_vals .as_slice(&self.value_pool) .iter() .cloned() .zip( data.node_binds_keys .as_slice(&self.node_pool) .iter() .cloned(), ) } pub fn node_span(&self, node: PatternNode) -> SourceSpan { self.nodes[node].span } pub fn node_kind(&self, node: PatternNode) -> &PatternNodeKind { self.nodes[node].kind.as_ref().unwrap() } } fn copy_pattern_node( value_map: &HashMap, node_map: &mut HashMap, node: PatternNode, from: &PatternContainer, to: &mut PatternContainer, ) -> PatternNode { let data = &from.nodes[node]; match data.kind.as_ref().unwrap() { PatternNodeKind::Wildcard => { let new = to.node_empty(Some(data.span)); to.wildcard(new); node_map.insert(node, new); new } PatternNodeKind::Value(val) => { let new = to.node_empty(Some(data.span)); to.value(new, *val); node_map.insert(node, new); new } PatternNodeKind::Tuple(elems) => { let new = to.node_empty(Some(data.span)); to.tuple(new); for elem in elems.as_slice(&from.node_pool) { let copied = copy_pattern_node(value_map, node_map, *elem, from, to); to.tuple_elem_push(new, copied); } to.node_finish(new); node_map.insert(node, new); new } PatternNodeKind::List { head, tail } => { let head_copied = copy_pattern_node(value_map, node_map, *head, from, to); let tail_copied = copy_pattern_node(value_map, node_map, *tail, from, to); let new = to.node_empty(Some(data.span)); to.list(new, head_copied, tail_copied); node_map.insert(node, new); new } PatternNodeKind::Map { keys, values } => { let new = to.node_empty(Some(data.span)); to.map(new); for (key, val) in keys .as_slice(&from.value_pool) .iter() .zip(values.as_slice(&from.node_pool)) { let copied = copy_pattern_node(value_map, node_map, *val, from, to); to.map_push(new, value_map[key], copied); } to.node_finish(new); node_map.insert(node, new); new } _ => unimplemented!("{:?}", data.kind), } } impl PatternContainer { pub fn merge_patterns( &mut self, cons: &ConstantContainer, map: &mut HashMap, lhs: PatternNode, rhs: PatternNode, ) -> Result { // This clone is really cheap since entitylists are basically just an usize let lhs_kind = self.nodes[lhs].kind.clone().unwrap(); let rhs_kind = self.nodes[rhs].kind.clone().unwrap(); // TODO: Fuse locations let fused_span = self.nodes[lhs].span; match (lhs_kind, rhs_kind) { (PatternNodeKind::Value(l_val), PatternNodeKind::Value(r_val)) if l_val == r_val => { map.insert(rhs, lhs); Ok(lhs) } (PatternNodeKind::Const(l), _) => { self.merge_pattern_constant(cons, map, fused_span, rhs, l) } (_, PatternNodeKind::Const(r)) => { self.merge_pattern_constant(cons, map, fused_span, lhs, r) } (PatternNodeKind::Wildcard, _) => { map.insert(lhs, rhs); Ok(rhs) } (_, PatternNodeKind::Wildcard) => { map.insert(rhs, lhs); Ok(lhs) } (PatternNodeKind::Tuple(l1), PatternNodeKind::Tuple(l2)) => { let l1_len = l1.len(&self.node_pool); let l2_len = l2.len(&self.node_pool); if l1_len == l2_len { let new_tup = self.node_empty(Some(fused_span)); self.tuple(new_tup); for idx in 0..l1_len { let ln = l1.get(idx, &self.node_pool).unwrap(); let rn = l2.get(idx, &self.node_pool).unwrap(); let merged = self.merge_patterns(cons, map, ln, rn)?; self.tuple_elem_push(new_tup, merged); } self.node_finish(new_tup); map.insert(lhs, new_tup); map.insert(rhs, new_tup); Ok(new_tup) } else { Err(PatternMergeFail::Disjoint { left: Some(lhs), right: rhs, }) } } ( PatternNodeKind::Map { keys: k1, values: v1, }, PatternNodeKind::Map { keys: k2, values: v2, }, ) => { let new_map = self.node_empty(Some(fused_span)); self.map(new_map); for idx in 0..(k1.len(&self.value_pool)) { let k = k1.get(idx, &self.value_pool).unwrap(); let v = v1.get(idx, &self.node_pool).unwrap(); self.map_push(new_map, k, v); } for idx in 0..(k2.len(&self.value_pool)) { let k = k2.get(idx, &self.value_pool).unwrap(); let v = v2.get(idx, &self.node_pool).unwrap(); self.map_push(new_map, k, v); } self.node_finish(new_map); map.insert(lhs, new_map); map.insert(rhs, new_map); Ok(new_map) } ( PatternNodeKind::List { head: h1, tail: t1 }, PatternNodeKind::List { head: h2, tail: t2 }, ) => { let new_head = self.merge_patterns(cons, map, h1, h2)?; let new_tail = self.merge_patterns(cons, map, t1, t2)?; let list = self.node_empty(Some(fused_span)); self.list(list, new_head, new_tail); map.insert(lhs, list); map.insert(rhs, list); Ok(list) } // Patterns are incompatible _ => Err(PatternMergeFail::Disjoint { left: Some(lhs), right: rhs, }), } } pub fn merge_pattern_constant( &mut self, cons: &ConstantContainer, map: &mut HashMap, fused_span: SourceSpan, lhs: PatternNode, rhs: Const, ) -> Result { let lhs_kind = self.nodes[lhs].kind.clone().unwrap(); let rhs_kind = cons.const_kind(rhs).clone(); use crate::{AtomicTerm, ConstKind}; match (lhs_kind, rhs_kind) { (PatternNodeKind::Const(l_const), _) if l_const == rhs => Ok(lhs), (PatternNodeKind::Const(_), _) => Err(PatternMergeFail::Disjoint { left: None, right: lhs, }), (PatternNodeKind::Wildcard, _) => { let node = self.node_empty(Some(fused_span)); self.constant(node, rhs); map.insert(lhs, node); Ok(node) } ( PatternNodeKind::Tuple(pat_entries), ConstKind::Tuple { entries: const_entries, }, ) => { let pat_len = pat_entries.len(&self.node_pool); let const_len = const_entries.len(&cons.const_pool); if pat_len != const_len { return Err(PatternMergeFail::Disjoint { left: None, right: lhs, }); } let node = self.node_empty(Some(fused_span)); self.tuple(node); for n in 0..pat_len { let pat_node = pat_entries.get(n, &self.node_pool).unwrap(); let const_node = const_entries.get(n, &cons.const_pool).unwrap(); // TODO: Fuse locations let fspan = self.nodes[pat_node].span; let new = self.merge_pattern_constant(cons, map, fspan, pat_node, const_node)?; self.tuple_elem_push(node, new); } self.node_finish(node); map.insert(lhs, node); Ok(node) } (PatternNodeKind::Tuple(_), _) => Err(PatternMergeFail::Disjoint { left: None, right: lhs, }), ( PatternNodeKind::List { head: pat_head, tail: pat_tail, }, ConstKind::ListCell { head: cons_head, tail: cons_tail, }, ) => { let head = self.merge_pattern_constant(cons, map, fused_span, pat_head, cons_head)?; let tail = self.merge_pattern_constant(cons, map, fused_span, pat_tail, cons_tail)?; let node = self.node_empty(Some(fused_span)); self.list(node, head, tail); map.insert(lhs, node); Ok(node) } (PatternNodeKind::List { .. }, _) => Err(PatternMergeFail::Disjoint { left: None, right: lhs, }), (PatternNodeKind::Binary { .. }, ConstKind::Atomic(AtomicTerm::Binary(_))) => { Err(PatternMergeFail::Failure { left: None, right: lhs, }) } (PatternNodeKind::Binary { .. }, _) => Err(PatternMergeFail::Disjoint { left: None, right: lhs, }), (a, b) => unimplemented!("{:?} {:?}", a, b), } } /// Makes a structural variant of the given pattern clause. /// /// A structural pattern is a pattern which matches on a term of the same /// structure, but with all atomic matches removed. /// /// This is currently only defined for binary nodes, and will panic if /// any other pattern is given. pub fn make_structural(&mut self, clause: PatternClause) -> PatternClause { use PatternNodeKind as PNK; let clause_data = &self.clauses[clause]; let mut bind_mapping: HashMap = HashMap::new(); for bind in clause_data.binds.as_slice(&self.node_pool).iter() { bind_mapping.insert(*bind, *bind); } for bind in clause_data.node_binds_keys.as_slice(&self.node_pool).iter() { bind_mapping.insert(*bind, *bind); } let mut value_mapping: HashMap = HashMap::new(); let values = &mut self.values; let mut map_value = |val: PatternValue| -> PatternValue { *value_mapping.entry(val).or_insert_with(|| values.push(())) }; let mut root_nodes: Vec<_> = clause_data .root_nodes .as_slice(&self.node_pool) .iter() .cloned() .collect(); fn make_node_structural( nodes: &mut PrimaryMap, node_pool: &mut ListPool, value_pool: &mut ListPool, bind_mapping: &mut HashMap, mut map_value: &mut impl FnMut(PatternValue) -> PatternValue, node: PatternNode, ) -> PatternNode { let mut node_data = nodes[node].clone(); assert!(node_data.finished); println!("{:?}", node_data.kind); let new_kind = match node_data.kind.unwrap() { PNK::Wildcard => PNK::Wildcard, PNK::Const(_) => PNK::Wildcard, PNK::Value(_) => PNK::Wildcard, PNK::Binary{ specifier, value, size, remaining, } => { let remaining = remaining.map(|n| make_node_structural(nodes, node_pool, value_pool, bind_mapping, map_value, n)); PNK::Binary { specifier, value: make_node_structural(nodes, node_pool, value_pool, bind_mapping, map_value, value), size: size.map(&mut map_value), remaining, } }, PNK::Tuple(nodes_list) => { let mut nodes_buf: Vec<_> = nodes_list.as_slice(node_pool).iter().cloned().collect(); for node in nodes_buf.iter_mut() { *node = make_node_structural(nodes, node_pool, value_pool, bind_mapping, map_value, *node); } let mut nodes_new = EntityList::new(); for node in nodes_buf.iter() { nodes_new.push(*node, node_pool); } PNK::Tuple(nodes_new) }, PNK::List { head, tail } => { PNK::List { head: make_node_structural(nodes, node_pool, value_pool, bind_mapping, map_value, head), tail: make_node_structural(nodes, node_pool, value_pool, bind_mapping, map_value, tail), } }, PNK::Map { keys, values } => { let keys_buf: Vec<_> = keys.as_slice(value_pool).iter().cloned().collect(); let mut keys_new = EntityList::new(); for value in keys_buf.iter() { keys_new.push(map_value(*value), value_pool); } let mut values_buf: Vec<_> = values.as_slice(node_pool).iter().cloned().collect(); for node in values_buf.iter_mut() { *node = make_node_structural(nodes, node_pool, value_pool, bind_mapping, map_value, *node); } let mut values_new = EntityList::new(); for node in values_buf.iter() { values_new.push(*node, node_pool); } PNK::Map { keys, values: values_new, } } }; node_data.kind = Some(new_kind); let new_node = nodes.push(node_data); if let Some(entry) = bind_mapping.get_mut(&node) { *entry = new_node; } new_node } for node in root_nodes.iter_mut() { *node = make_node_structural(&mut self.nodes, &mut self.node_pool, &mut self.value_pool, &mut bind_mapping, &mut map_value, *node); } let mut root_nodes_new = EntityList::new(); for node in root_nodes.iter() { root_nodes_new.push(*node, &mut self.node_pool); } let new_data = PatternClauseData { span: clause_data.span, root_nodes: root_nodes_new, node_binds_keys: { let mut new = EntityList::new(); let len = clause_data.node_binds_keys.as_slice(&self.node_pool).len(); for idx in 0..len { let node = clause_data.node_binds_keys.as_slice(&self.node_pool)[idx]; new.push(bind_mapping[&node], &mut self.node_pool); } new }, node_binds_vals: { let mut new = EntityList::new(); let len = clause_data.node_binds_vals.as_slice(&self.value_pool).len(); for idx in 0..len { let value = clause_data.node_binds_vals.as_slice(&self.value_pool)[idx]; new.push(map_value(value), &mut self.value_pool); } new }, binds: { let mut new = EntityList::new(); let len = clause_data.binds.as_slice(&self.node_pool).len(); for idx in 0..len { let node = clause_data.binds.as_slice(&self.node_pool)[idx]; new.push(bind_mapping[&node], &mut self.node_pool); } new }, values: { let mut new = EntityList::new(); let len = clause_data.values.as_slice(&self.value_pool).len(); for idx in 0..len { let value = clause_data.values.as_slice(&self.value_pool)[idx]; new.push(map_value(value), &mut self.value_pool); } new }, finished: true, }; self.clauses.push(new_data) } } ================================================ FILE: libeir_ir/src/text/ast/mod.rs ================================================ use libeir_diagnostics::SourceSpan; use libeir_intern::Ident; use crate::constant::Integer; use crate::{BasicType, BinOp, BinaryEntrySpecifier}; #[derive(Debug, PartialEq, Eq)] pub enum DynToken { Parens(Vec, SourceSpan), Braces(Vec, SourceSpan), MapBraces(Vec, SourceSpan), SquareBrackets(Vec, SourceSpan), AngleBrackets(Vec, SourceSpan), Ident(Ident), Variable(Ident), Atom(Ident), Integer(Integer, SourceSpan), Float(Ident), String(Ident), Percent(SourceSpan), Colon(SourceSpan), SemiColon(SourceSpan), Comma(SourceSpan), Question(SourceSpan), ForwardSlash(SourceSpan), Equals(SourceSpan), EqualsEquals(SourceSpan), FatArrow(SourceSpan), Underscore(SourceSpan), Pipe(SourceSpan), At(SourceSpan), Bang(SourceSpan), Unpack(SourceSpan), Unreachable(SourceSpan), Arity(SourceSpan), IfBool(SourceSpan), TraceCaptureRaw(SourceSpan), Value(SourceSpan), Match(SourceSpan), Type(SourceSpan), Case(SourceSpan), Guard(SourceSpan), Except(SourceSpan), } impl DynToken { pub fn span(&self) -> SourceSpan { use DynToken::*; match self { Parens(_, span) => *span, Braces(_, span) => *span, MapBraces(_, span) => *span, SquareBrackets(_, span) => *span, AngleBrackets(_, span) => *span, Ident(ident) => ident.span, Variable(ident) => ident.span, Atom(ident) => ident.span, Integer(_, span) => *span, Float(ident) => ident.span, String(ident) => ident.span, Percent(span) => *span, Colon(span) => *span, SemiColon(span) => *span, Comma(span) => *span, Question(span) => *span, ForwardSlash(span) => *span, Equals(span) => *span, EqualsEquals(span) => *span, FatArrow(span) => *span, Underscore(span) => *span, Pipe(span) => *span, At(span) => *span, Bang(span) => *span, Unpack(span) => *span, Unreachable(span) => *span, Arity(span) => *span, IfBool(span) => *span, TraceCaptureRaw(span) => *span, Value(span) => *span, Match(span) => *span, Type(span) => *span, Case(span) => *span, Guard(span) => *span, Except(span) => *span, } } } #[derive(Debug, PartialEq, Eq)] pub struct Module { pub span: SourceSpan, pub name: Ident, pub items: Vec, } #[derive(Debug, PartialEq, Eq)] pub enum ModuleItem { Function(Function), } #[derive(Debug, PartialEq, Eq)] pub struct Function { pub span: SourceSpan, pub name: Ident, pub arity: Integer, pub items: Vec, } #[derive(Debug, PartialEq, Eq)] pub enum FunctionItem { Label(Label), Meta(Meta), Assignment(Assignment), Op(Op), } #[derive(Debug, PartialEq, Eq)] pub struct Meta { pub span: SourceSpan, pub name: Ident, pub tokens: Vec, } #[derive(Debug, PartialEq, Eq)] pub struct Label { pub span: SourceSpan, pub name: Value, // Only Value::Value is supported here pub args: Vec, } #[derive(Debug, PartialEq, Eq)] pub struct Assignment { pub span: SourceSpan, pub lhs: Value, pub rhs: Value, } #[derive(Debug, PartialEq, Eq)] pub enum Op { Dyn(Ident, Vec), UnpackValueList(UnpackValueListOp), CallControlFlow(CallControlFlowOp), CallFunction(CallFunctionOp), IfBool(IfBoolOp), TraceCaptureRaw(TraceCaptureRawOp), Match(MatchOp), Case(CaseOp), Unreachable, } #[derive(Debug, PartialEq, Eq)] pub struct CaseOp { pub span: SourceSpan, pub value: Value, pub entries: Vec, pub no_match: Option, } #[derive(Debug, PartialEq, Eq)] pub struct CaseEntry { pub span: SourceSpan, pub patterns: Vec, pub args: Vec, pub guard: Value, pub target: Value, } #[derive(Debug, PartialEq, Eq)] pub enum CasePattern { Value(Value), Binding { name: Ident, pattern: Box, }, ListCell { head: Box, tail: Box, }, Tuple { elements: Vec, }, Wildcard, } #[derive(Debug, PartialEq, Eq)] pub struct MatchOp { pub span: SourceSpan, pub value: Value, pub entries: Vec, } #[derive(Debug, PartialEq, Eq)] pub struct MatchEntry { pub span: SourceSpan, pub target: Value, pub kind: MatchKind, } #[derive(Debug, PartialEq, Eq)] pub enum MatchKind { Value(Value), Type(BasicType), Binary(BinaryEntrySpecifier, Option), Tuple(usize), ListCell, MapItem(Value), Wildcard, } #[derive(Debug, PartialEq, Eq)] pub struct UnpackValueListOp { pub span: SourceSpan, pub arity: usize, pub value: Value, pub block: Value, } #[derive(Debug, PartialEq, Eq)] pub struct CallControlFlowOp { pub span: SourceSpan, pub target: Value, pub args: Vec, } #[derive(Debug, PartialEq, Eq)] pub struct CallFunctionOp { pub span: SourceSpan, pub target: Value, pub ret: Value, pub thr: Value, pub args: Vec, } #[derive(Debug, PartialEq, Eq)] pub struct IfBoolOp { pub span: SourceSpan, pub value: Value, pub tru: Value, pub fal: Value, pub or: Option, } #[derive(Debug, PartialEq, Eq)] pub struct TraceCaptureRawOp { pub span: SourceSpan, pub then: Value, } #[derive(Debug, PartialEq, Eq)] pub enum Value { // Atomics Value(Ident), Block(Ident), Atom(Ident), Integer(Integer), Nil, // Composites ValueList(Vec), Tuple(Vec), List(Vec, Option>), CaptureFunction(Box, Box, Box), BinOp(Box, BinOp, Box), } impl Value { pub fn value(&self) -> Option { match self { Value::Value(sym) => Some(*sym), _ => None, } } pub fn block(&self) -> Option { match self { Value::Block(sym) => Some(*sym), _ => None, } } } ================================================ FILE: libeir_ir/src/text/ast/raise.rs ================================================ use std::collections::BTreeMap; use libeir_intern::Ident; use crate::Function; use crate::{Block, Value}; //use crate::OpKind; use crate::text::ast; #[allow(dead_code)] struct RaiseCtx { block_names: BTreeMap, value_names: BTreeMap, } impl RaiseCtx { pub fn block_name(&mut self, _block: Block) -> Ident { unimplemented!() } pub fn value_name(&mut self, _value: Value) -> Ident { unimplemented!() } } impl Function { pub fn raise(&self) -> ast::Function { let graph = self.block_graph(); let mut ctx = RaiseCtx { block_names: BTreeMap::new(), value_names: BTreeMap::new(), }; let mut items = Vec::new(); for block in graph.dfs_iter() { // Block label items.push(ast::FunctionItem::Label(ast::Label { name: ast::Value::Block(ctx.block_name(block)), args: self .block_args(block) .iter() .map(|v| ast::Value::Value(ctx.value_name(*v))) .collect(), })); //if let Some(kind) = self.block_kind(block) { // match kind { // OpKind::Call => { // //items.push(ast::FunctionItem::Op(ast::Op::Call(ast::CallOp { // // // //}))); // } // _ => unimplemented!(), // } //} } ast::Function { name: self.ident().name, arity: self.ident().arity.into(), items, } } } ================================================ FILE: libeir_ir/src/text/dot_printer.rs ================================================ use std::marker::PhantomData; use super::printer as pr; use super::printer::{FormatState, FunctionFormatData}; use crate::Function; use pretty::Arena; use libeir_util_dot_graph::GraphPrinter; use petgraph::visit::{Dfs, IntoNeighbors}; pub fn function_into_graph_printer(fun: &Function, g: &mut GraphPrinter) where O: std::fmt::Write, { let mut buf = String::new(); let mut config = pr::FormatConfig { width: 80, print_locations: true, block_iterator_config: pr::DfsBlockIteratorConfig, value_formatter: pr::StandardValueFormatter, block_value_layout: pr::ReferencePrimopBlockValueLayout::default(), }; let mut state = FormatState { function: fun, nesting: 0, }; let arena = Arena::new(); let mut ctx = FunctionFormatData { arena: &arena, buf: String::new(), value_buf: Vec::new(), config: PhantomData, }; let block_graph = fun.block_graph(); let mut block_dfs = Dfs::new(&block_graph, fun.block_entry()); while let Some(block) = block_dfs.next(&block_graph) { let block_val = fun.block_value(block); let doc = ctx.block_to_doc(&mut config, &mut state, block); buf.clear(); doc.render_fmt(80, &mut buf).unwrap(); g.node(block_val, &buf); for out in block_graph.neighbors(block) { let out_val = fun.block_value(out); g.edge(block_val, out_val, ""); } } } pub fn function_to_dot(fun: &Function) -> String { let mut g = GraphPrinter::new(); function_into_graph_printer(fun, &mut g); g.finish().unwrap() } ================================================ FILE: libeir_ir/src/text/lower/location.rs ================================================ use crate::text::parse_dyn::{DynParserError, ParseCtx}; use libeir_intern::Symbol; use libeir_util_number::ToPrimitive; use std::convert::TryInto; pub struct ParsedTerminalLocation { pub file: Option, pub line: Option, pub module: Option, pub function: Option, } pub struct ParsedLocation { pub terminals: Vec, } pub fn parse_terminal_location( ctx: &mut ParseCtx, ) -> Result { let mut module = None; let mut function = None; let mut file = None; let mut line = None; if let Ok(module_i) = ctx.try_parse(|ctx| ctx.tok_string()) { module = Some(module_i.name); if ctx.try_parse(|ctx| ctx.tok_colon()).is_ok() { function = Some(ctx.tok_string()?.name); } } if ctx.try_parse(|ctx| ctx.tok_at()).is_ok() { file = Some(ctx.tok_string()?.name); if ctx.try_parse(|ctx| ctx.tok_colon()).is_ok() { line = Some(ctx.tok_integer()?.0); } } Ok(ParsedTerminalLocation { file, line: line.map(|i| i.to_u32().unwrap()), module, function, }) } pub fn parse_location(ctx: &mut ParseCtx) -> Result { let (toks, span) = ctx.tok_square_brackets()?; let mut ictx = ParseCtx::new(toks, span); let locs = ictx.comma(parse_terminal_location)?; ictx.eof()?; ctx.eof()?; Ok(ParsedLocation { terminals: locs }) } ================================================ FILE: libeir_ir/src/text/lower/mod.rs ================================================ use std::collections::HashMap; use libeir_diagnostics::{Diagnostic, Label, SourceSpan, ToDiagnostic}; use libeir_intern::Ident; use libeir_util_datastructures::hashmap_stack::HashMapStack; use libeir_util_parse::ErrorReceiver; use snafu::Snafu; use crate::text::ast; use crate::{Block, Value}; use crate::{Function, FunctionBuilder, FunctionIdent, Module}; use crate::{PatternContainer, PatternNode}; mod location; type ErrCollector<'a> = &'a mut dyn ErrorReceiver; pub struct LowerContext<'a, 'b> { builder: &'a mut FunctionBuilder<'b>, errors: ErrCollector<'a>, scope: &'a mut HashMapStack, } impl<'a, 'b> LowerContext<'a, 'b> { pub fn error(&mut self, diag: T) { self.errors.error(LowerError::DynError { diagnostic: diag.to_diagnostic(), }) } } #[derive(Debug, Snafu)] pub enum LowerError { DuplicateDefinititon { previous: SourceSpan, current: SourceSpan, }, LabelNotFinalized { span: SourceSpan, }, OpOutsideOfLabel {}, UndefinedVariable { span: SourceSpan, }, UndefinedBlock { span: SourceSpan, }, UndefinedBind { span: SourceSpan, }, UnknownMeta { span: SourceSpan, name: Ident, }, UnknownDyn { span: SourceSpan, }, DynError { diagnostic: Diagnostic, }, } impl ToDiagnostic for LowerError { fn to_diagnostic(&self) -> Diagnostic { let msg = self.to_string(); match self { LowerError::DuplicateDefinititon { previous, current } => Diagnostic::error() .with_message("duplicate identifier definition") .with_labels(vec![ Label::primary(current.source_id(), *current) .with_message("attempted redefinition"), Label::secondary(previous.source_id(), *previous) .with_message("previously defined here"), ]), LowerError::LabelNotFinalized { span } => Diagnostic::error() .with_message("label not finalized") .with_labels(vec![Label::primary(span.source_id(), *span) .with_message("block does not end with an operation")]), LowerError::UndefinedVariable { span } => Diagnostic::error() .with_message("undefined variable name") .with_labels(vec![Label::primary(span.source_id(), *span) .with_message("variable name was not defined in the IR")]), LowerError::UndefinedBlock { span } => Diagnostic::error() .with_message("undefined block name") .with_labels(vec![Label::primary(span.source_id(), *span) .with_message("block name was not defined in the IR")]), LowerError::UnknownMeta { name, .. } => Diagnostic::error() .with_message("unknown meta entry") .with_labels(vec![Label::primary(name.span.source_id(), name.span) .with_message("meta entry is unknown to the compiler")]), LowerError::UnknownDyn { span } => Diagnostic::error() .with_message("unknown dynop identifier") .with_labels(vec![Label::primary(span.source_id(), *span) .with_message("no parser exists for dynop in current dialect")]), LowerError::DynError { diagnostic } => diagnostic.clone(), _ => Diagnostic::error().with_message(msg), } } } pub struct LowerMap { map: HashMap, block_map: HashMap, } impl LowerMap { pub fn get_value(&self, ident: &str) -> Value { self.map[&Name::Value(Ident::from_str(ident))] } pub fn get_block(&self, ident: &str) -> Block { self.block_map[&Ident::from_str(ident)] } } impl ast::Module { pub fn lower(&self, errors: ErrCollector) -> Result { let mut module = Module::new(self.name); for item in self.items.iter() { match item { ast::ModuleItem::Function(fun) => { let fun_ir = module.add_function( SourceSpan::UNKNOWN, fun.name, fun.arity.to_usize().unwrap(), ); let mut b = fun_ir.function_mut().builder(); fun.lower_into(errors, &mut b)?; } } } Ok(module) } } #[derive(Debug, Eq, PartialEq, Hash, Copy, Clone)] pub enum Name { Value(Ident), Block(Ident), } impl Name { pub fn span(&self) -> SourceSpan { match self { Name::Value(ident) => ident.span, Name::Block(ident) => ident.span, } } } fn insert_check_duplicate( errors: ErrCollector, scope: &mut HashMapStack, name: Name, value: Value, ) -> Result<(), ()> { if let Some((span, _)) = scope.get(&name) { errors.error(LowerError::DuplicateDefinititon { previous: *span, current: name.span(), }); Err(()) } else { scope.insert(name, (name.span(), value)); Ok(()) } } impl ast::Function { pub fn lower(&self, errors: ErrCollector, module: Ident) -> Result<(Function, LowerMap), ()> { let ident = FunctionIdent { module, name: self.name, arity: self.arity.to_usize().unwrap(), }; let mut fun = Function::new(SourceSpan::UNKNOWN, ident); let mut b = fun.builder(); let map = self.lower_into(errors, &mut b)?; Ok((fun, map)) } pub fn lower_into( &self, errors: ErrCollector, b: &mut FunctionBuilder, ) -> Result { let mut blocks: HashMap = HashMap::new(); let mut scope: HashMapStack = HashMapStack::new(); scope.push(); let mut location = None; // 1. Create blocks and their args let mut first_block = None; for item in self.items.iter() { match item { ast::FunctionItem::Label(label) => { let block_name = label.name.block().unwrap(); let block = b.block_insert(); if let Some(loc) = location { b.block_set_location(block, loc); location = None; } insert_check_duplicate( errors, &mut scope, Name::Block(block_name), b.value(block), )?; scope.insert(Name::Block(block_name), (block_name.span, b.value(block))); blocks.insert(block_name, (block_name.span, block)); for arg in label.args.iter() { let arg_name = arg.value().unwrap(); let arg = b.block_arg_insert(block); insert_check_duplicate(errors, &mut scope, Name::Value(arg_name), arg)?; scope.insert(Name::Value(arg_name), (block_name.span, arg)); } if first_block.is_none() { first_block = Some(block); } } ast::FunctionItem::Meta(meta) => match &*meta.name.as_str() { "location" => { let mut ctx = super::parse_dyn::ParseCtx::new(&meta.tokens, meta.span); match self::location::parse_location(&mut ctx) { Ok(loc_desc) => { let mut terminals = vec![]; for term_desc in loc_desc.terminals.iter() { let term = b.fun_mut().locations.terminal( term_desc.file.map(|v| v.to_string()), term_desc.line, term_desc.module.map(|v| v.to_string()), term_desc.function.map(|v| v.to_string()), meta.span, ); terminals.push(term); } let loc = b.fun_mut().locations.from_terminals(&terminals); location = Some(loc); } Err(err) => errors.error(LowerError::DynError { diagnostic: err.to_diagnostic(), }), } } _ => errors.error(LowerError::UnknownMeta { span: meta.span, name: meta.name, }), }, _ => (), } } b.block_set_entry(first_block.unwrap()); // 2. Create assignments and bodies let mut current_block: Option<(SourceSpan, Block)> = None; for item in self.items.iter() { match item { ast::FunctionItem::Label(label) => { let block_name = label.name.block().unwrap(); if let Some((span, _)) = current_block { errors.error(LowerError::LabelNotFinalized { span }); return Err(()); } current_block = Some((block_name.span, blocks[&block_name].1)); scope.push(); } ast::FunctionItem::Meta(meta) => match &*meta.name.as_str() { "location" => {} _ => errors.error(LowerError::UnknownMeta { span: meta.span, name: meta.name, }), }, ast::FunctionItem::Assignment(assign) => { let lhs = assign.lhs.value().unwrap(); let value = lower_value(errors, b, &mut scope, &assign.rhs)?; scope.insert(Name::Value(lhs), (lhs.span, value)); } ast::FunctionItem::Op(op) => { if let Some((_, block)) = current_block { lower_operation(b, errors, &mut scope, block, op)?; } else { errors.error(LowerError::OpOutsideOfLabel {}); return Err(()); } scope.pop(); current_block = None; } } } if let Some((span, _)) = current_block { errors.error(LowerError::LabelNotFinalized { span }); return Err(()); } assert!(scope.height() == 1); let top = scope.layer(0); Ok(LowerMap { map: top.iter().map(|(k, (_, v))| (*k, *v)).collect(), block_map: blocks.iter().map(|(k, (_, v))| (*k, *v)).collect(), }) } } fn lower_operation( b: &mut FunctionBuilder, errors: ErrCollector, scope: &mut HashMapStack, block: Block, op: &ast::Op, ) -> Result<(), ()> { match op { ast::Op::Dyn(ident, opts) => { let mut ctx = LowerContext { builder: b, errors, scope, }; if let Some(parser) = crate::dialect::NORMAL.get_op_parser(ident.name) { parser.parse(&mut ctx, block, opts)?; } else { errors.error(LowerError::UnknownDyn { span: ident.span }); } } ast::Op::CallControlFlow(call) => { let target = lower_value(errors, b, scope, &call.target)?; let args: Result, _> = call .args .iter() .map(|v| lower_value(errors, b, scope, v)) .collect(); b.op_call_flow(block, target, &args?); } ast::Op::CallFunction(call) => { let target = lower_value(errors, b, scope, &call.target)?; let ret = lower_value(errors, b, scope, &call.ret)?; let thr = lower_value(errors, b, scope, &call.thr)?; let args: Result, _> = call .args .iter() .map(|v| lower_value(errors, b, scope, v)) .collect(); b.op_call_function_next(SourceSpan::UNKNOWN, block, target, ret, thr, &args?); } ast::Op::UnpackValueList(list) => { let target = lower_value(errors, b, scope, &list.block)?; let value = lower_value(errors, b, scope, &list.value)?; b.op_unpack_value_list_next(block, target, value, list.arity); } ast::Op::IfBool(if_bool) => { let value = lower_value(errors, b, scope, &if_bool.value)?; let tru = lower_value(errors, b, scope, &if_bool.tru)?; let fal = lower_value(errors, b, scope, &if_bool.fal)?; if let Some(or) = &if_bool.or { let or = lower_value(errors, b, scope, or)?; b.op_if_bool_next(SourceSpan::UNKNOWN, block, tru, fal, or, value); } else { b.op_if_bool_strict_next(SourceSpan::UNKNOWN, block, tru, fal, value); } } ast::Op::TraceCaptureRaw(trace_op) => { let then = lower_value(errors, b, scope, &trace_op.then)?; b.op_trace_capture_raw_next(SourceSpan::UNKNOWN, block, then); } ast::Op::Match(match_op) => { let mut builder = b.op_match_build(SourceSpan::UNKNOWN); for entry in match_op.entries.iter() { let next = lower_value(errors, b, scope, &entry.target)?; match &entry.kind { ast::MatchKind::Value(v) => { let v_v = lower_value(errors, b, scope, v)?; builder.push_value_next(next, v_v, b); } ast::MatchKind::ListCell => { builder.push_list_cell_next(next, b); } ast::MatchKind::Wildcard => { builder.push_wildcard_next(next, b); } ast::MatchKind::Type(typ) => { builder.push_type_next(next, *typ, b); } ast::MatchKind::MapItem(k) => { let k_v = lower_value(errors, b, scope, k)?; builder.push_map_item_next(next, k_v, b); } ast::MatchKind::Tuple(n) => { builder.push_tuple_next(next, *n, b); } s => unimplemented!("{:?}", s), } } let match_val = lower_value(errors, b, scope, &match_op.value)?; builder.finish(block, match_val, b); } ast::Op::Unreachable => { b.op_unreachable(SourceSpan::UNKNOWN, block); } ast::Op::Case(case_op) => { use crate::operation::case::Case; let value = lower_value(errors, b, scope, &case_op.value)?; let mut binds = HashMap::new(); let mut case_b = Case::builder(); for entry in case_op.entries.iter() { binds.clear(); let clause = case_b.container.clause_start(SourceSpan::UNKNOWN); for pattern in entry.patterns.iter() { let pat = lower_case_pattern( errors, &mut case_b.container, b, scope, &mut binds, pattern, )?; case_b.container.clause_node_push(clause, pat); } for bind in entry.args.iter() { if let Some(node) = binds.get(bind) { case_b.container.clause_bind_push(clause, node.1); } else { errors.error(LowerError::UndefinedBind { span: bind.span }); return Err(()); } } case_b.container.clause_finish(clause); let guard = lower_value(errors, b, scope, &entry.guard)?; let target = lower_value(errors, b, scope, &entry.target)?; case_b.push_clause(clause, guard, target, b); } if let Some(no_match) = case_op.no_match.as_ref() { let val = lower_value(errors, b, scope, no_match)?; case_b.no_match = Some(val); } case_b.match_on = Some(value); case_b.finish(block, b); } } Ok(()) } fn lower_case_pattern( errors: ErrCollector, pat: &mut PatternContainer, b: &mut FunctionBuilder, scope: &mut HashMapStack, binds: &mut HashMap, pattern: &ast::CasePattern, ) -> Result { match pattern { ast::CasePattern::Binding { name, pattern } => { let child = lower_case_pattern(errors, pat, b, scope, binds, pattern)?; if binds.contains_key(name) { errors.error(LowerError::DuplicateDefinititon { current: name.span, previous: binds[name].0, }); return Err(()); } binds.insert(*name, (name.span, child)); Ok(child) } ast::CasePattern::Wildcard => { let node = pat.node_empty(Some(SourceSpan::UNKNOWN)); pat.wildcard(node); Ok(node) } _ => unimplemented!(), } } fn lower_value( errors: ErrCollector, b: &mut FunctionBuilder, scope: &mut HashMapStack, val: &ast::Value, ) -> Result { match val { ast::Value::Value(i) => { if let Some((_, val)) = scope.get(&Name::Value(*i)) { Ok(*val) } else { errors.error(LowerError::UndefinedVariable { span: i.span }); return Err(()); } } ast::Value::Block(b) => { if let Some((_, val)) = scope.get(&Name::Block(*b)) { Ok(*val) } else { errors.error(LowerError::UndefinedBlock { span: b.span }); return Err(()); } } ast::Value::Atom(atom) => { // TODO escapes Ok(b.value(crate::constant::AtomTerm(atom.name))) } ast::Value::Integer(int) => match int { crate::constant::Integer::Small(int) => Ok(b.value(*int)), crate::constant::Integer::Big(int) => Ok(b.value(int.clone())), }, ast::Value::Nil => Ok(b.value(crate::constant::NilTerm)), ast::Value::ValueList(list) => { let v_buf: Result, _> = list .iter() .map(|v| lower_value(errors, b, scope, v)) .collect(); Ok(b.prim_value_list(&v_buf?)) } ast::Value::Tuple(tup) => { let v_buf: Result, _> = tup .iter() .map(|v| lower_value(errors, b, scope, v)) .collect(); Ok(b.prim_tuple(SourceSpan::UNKNOWN, &v_buf?)) } ast::Value::CaptureFunction(m, f, a) => { let m_v = lower_value(errors, b, scope, &*m)?; let f_v = lower_value(errors, b, scope, &*f)?; let a_v = lower_value(errors, b, scope, &*a)?; Ok(b.prim_capture_function(SourceSpan::UNKNOWN, m_v, f_v, a_v)) } ast::Value::BinOp(lhs, op, rhs) => { let lhs_v = lower_value(errors, b, scope, &*lhs)?; let rhs_v = lower_value(errors, b, scope, &*rhs)?; Ok(b.prim_binop(SourceSpan::UNKNOWN, *op, lhs_v, rhs_v)) } ast::Value::List(head, tail) => { let mut acc = tail .as_ref() .map(|v| lower_value(errors, b, scope, &*v)) .transpose()? .unwrap_or(b.value(crate::constant::NilTerm)); for v in head.iter().rev() { let new_val = lower_value(errors, b, scope, &*v)?; acc = b.prim_list_cell(SourceSpan::UNKNOWN, new_val, acc); } Ok(acc) } } } ================================================ FILE: libeir_ir/src/text/mod.rs ================================================ //pub mod printer; //pub use printer::{ ToEirText, ToEirTextFun, ToEirTextContext }; pub mod printer; pub mod dot_printer; pub use dot_printer::function_to_dot; mod lower; pub use lower::{LowerContext, LowerError, LowerMap}; pub mod parse_dyn; //pub trait TextFormatter { // // TODO add result // fn write(&mut self, text: &str); // fn newline(&mut self); // // fn enter_indent(&mut self, dist: usize); // fn exit_indent(&mut self, dist: usize); //} // //pub struct BufferTextFormatter { // indent: usize, // buf: String, //} // //impl Default for BufferTextFormatter { // fn default() -> Self { // BufferTextFormatter { // indent: 0, // buf: String::new(), // } // } //} // //impl BufferTextFormatter { // // pub fn new() -> Self { // Self::default() // } // // pub fn clear(&mut self) { // self.indent = 0; // self.buf.clear(); // } // //} // //impl TextFormatter for BufferTextFormatter { // // fn write(&mut self, text: &str) { // self.buf.push_str(text); // } // fn newline(&mut self) { // self.buf.push('\n'); // for _ in 0..self.indent { // self.buf.push(' '); // } // } // // fn enter_indent(&mut self, _dist: usize) { // self.indent += 1; // } // fn exit_indent(&mut self, _dist: usize) { // self.indent -= 1; // } // //} pub mod parser; pub use parser::{ function as parse_function, function_map as parse_function_map, function_map_unwrap as parse_function_map_unwrap, function_unwrap as parse_function_unwrap, module as parse_module, module_unwrap as parse_module_unwrap, }; pub mod ast; ================================================ FILE: libeir_ir/src/text/parse_dyn/mod.rs ================================================ use libeir_diagnostics::{Diagnostic, Label, SourceSpan, ToDiagnostic}; use libeir_intern::{Ident, Symbol}; use snafu::Snafu; use crate::constant::Integer; use super::ast::{DynToken, Value}; #[derive(Copy, Clone)] pub enum Nesting { Top, Parens(SourceSpan), Braces(SourceSpan), MapBraces(SourceSpan), SquareBrackets(SourceSpan), AngleBrackets(SourceSpan), } pub enum Token { ParenOpen, ParenClose, BraceOpen, BraceClose, MapBraceOpen, SquareBracketOpen, SquareBracketClose, AngleBracketOpen, AngleBracketClose, Ident(Symbol), Variable(Symbol), Atom(Symbol), Integer(Integer), Float(Symbol), String(Symbol), Percent, Colon, SemiColon, Comma, Question, ForwardSlash, Equals, EqualsEquals, FatArrow, Underscore, Pipe, At, Bang, Unpack, Unreachable, Arity, IfBool, TraceCaptureRaw, Value, Match, Type, Case, Guard, Except, EOF, } pub fn flatten_dyn_token(tok: &[DynToken]) -> Vec<(Token, SourceSpan)> { fn flatten(toks: &[DynToken], out: &mut Vec<(Token, SourceSpan)>) { for tok in toks { match tok { DynToken::Parens(inner, span) => { out.push((Token::ParenOpen, *span)); flatten(inner, out); out.push((Token::ParenClose, *span)); } DynToken::Braces(inner, span) => { out.push((Token::BraceOpen, *span)); flatten(inner, out); out.push((Token::BraceClose, *span)); } DynToken::MapBraces(inner, span) => { out.push((Token::MapBraceOpen, *span)); flatten(inner, out); out.push((Token::BraceClose, *span)); } DynToken::SquareBrackets(inner, span) => { out.push((Token::SquareBracketOpen, *span)); flatten(inner, out); out.push((Token::SquareBracketClose, *span)); } DynToken::AngleBrackets(inner, span) => { out.push((Token::AngleBracketOpen, *span)); flatten(inner, out); out.push((Token::AngleBracketClose, *span)); } DynToken::Ident(ident) => out.push((Token::Ident(ident.name), ident.span)), DynToken::Variable(ident) => out.push((Token::Variable(ident.name), ident.span)), DynToken::Atom(ident) => out.push((Token::Atom(ident.name), ident.span)), DynToken::Integer(int, span) => out.push((Token::Integer(int.clone()), *span)), DynToken::Float(ident) => out.push((Token::Float(ident.name), ident.span)), DynToken::String(ident) => out.push((Token::String(ident.name), ident.span)), DynToken::Percent(span) => out.push((Token::Percent, *span)), DynToken::Colon(span) => out.push((Token::Colon, *span)), DynToken::SemiColon(span) => out.push((Token::SemiColon, *span)), DynToken::Comma(span) => out.push((Token::Comma, *span)), DynToken::Question(span) => out.push((Token::Question, *span)), DynToken::ForwardSlash(span) => out.push((Token::ForwardSlash, *span)), DynToken::Equals(span) => out.push((Token::Equals, *span)), DynToken::EqualsEquals(span) => out.push((Token::EqualsEquals, *span)), DynToken::FatArrow(span) => out.push((Token::FatArrow, *span)), DynToken::Underscore(span) => out.push((Token::Underscore, *span)), DynToken::Pipe(span) => out.push((Token::Pipe, *span)), DynToken::At(span) => out.push((Token::At, *span)), DynToken::Bang(span) => out.push((Token::Bang, *span)), DynToken::Unpack(span) => out.push((Token::Unpack, *span)), DynToken::Unreachable(span) => out.push((Token::Unreachable, *span)), DynToken::Arity(span) => out.push((Token::Arity, *span)), DynToken::IfBool(span) => out.push((Token::IfBool, *span)), DynToken::TraceCaptureRaw(span) => out.push((Token::TraceCaptureRaw, *span)), DynToken::Value(span) => out.push((Token::Value, *span)), DynToken::Match(span) => out.push((Token::Match, *span)), DynToken::Type(span) => out.push((Token::Type, *span)), DynToken::Case(span) => out.push((Token::Case, *span)), DynToken::Guard(span) => out.push((Token::Guard, *span)), DynToken::Except(span) => out.push((Token::Except, *span)), } } } let mut out = vec![]; flatten(tok, &mut out); out } //pub struct DynTokenLexer { // stack: Vec<(Nesting, &'a [DynToken], usize)>, // containing: SourceSpan, //} // //impl<'a> DynTokenLexer<'a> { // pub fn new(tokens: &'a [DynToken], containing: SourceSpan) -> Self { // DynTokenLexer { // stack: vec![Nesting::Top, tokens, 0], // containing, // } // } //} // //impl Iterator for DynTokenLexer { // type Item = (SourceIndex, Token, SourceIndex); // fn next(&mut self) -> Option { // enum Action<'b> { // PopLex(Nesting), // PushLex(Nesting, &'b [DynToken]), // } // // let action = match self.stack.last_mut() { // Some((nesting, tokens, cursor)) if cursor >= tokens.len() => Action::PopLex(*nesting), // Some((_, tokens, cursor)) => match &tokens[cursor] { // DynToken::Parens(children, span) => { // Action::PushLex(Nesting::Parens(*span), children) // } // DynToken::Braces(children, span) => { // Action::PushLex(Nesting::Braces(*span), children) // } // DynToken::MapBraces(children, span) => { // Action::PushLex(Nesting::MapBraces(*span), children) // } // DynToken::SquareBrackets(children, span) => { // Action::PushLex(Nesting::SquareBrackets(*span), children) // } // DynToken::AngleBrackets(children, span) // _ => unimplemented!(), // }, // None => unreachable!(), // }; // // match action { // Action::PopLex(Nesting::Top) => { // (self.containing.end(), Token::Eof, self.containing.end()) // } // Action::PopLex(Nesting::Parens(span)) => { // self.stack.pop(); // (span.start(), Token::ParenClose, span.end()) // } // Action::PopLex(Nesting::Braces(span)) => { // self.stack.pop(); // (span.start(), Token::BraceClose, span.end()) // } // Action::PopLex(Nesting::MapBraces(span)) => { // self.stack.pop(); // (span.start(), Token::BraceClose, span.end()) // } // Action::PopLex(Nesting::SquareBrackets(span)) => { // self.stack.pop(); // (span.start(), Token::SquareBracketClose, span.end()) // } // Action::PopLex(Nesting::AngleBrackets(span)) => { // self.stack.pop(); // (span.start(), Token::AngleBracketClose, span.end()) // } // } // } //} macro_rules! try_seq { ($ctx:expr) => {}; } macro_rules! container_token { ($name:ident, $ident:ident) => { pub fn $name(&mut self) -> Result<(&'a [DynToken], SourceSpan), DynParserError> { match self.pop()? { DynToken::$ident(inner, span) => Ok((inner, *span)), other => Err(DynParserError::UnexpectedToken { span: other.span() }), } } }; } pub struct ParseCtx<'a> { containing: SourceSpan, tokens: &'a [DynToken], pos: usize, } #[derive(Debug, Snafu)] #[snafu(visibility = "pub")] pub enum DynParserError { UnexpectedToken { span: SourceSpan }, UnexpectedEnd { span: SourceSpan }, } impl ToDiagnostic for DynParserError { fn to_diagnostic(&self) -> Diagnostic { match self { DynParserError::UnexpectedEnd { span } => Diagnostic::error() .with_message("unexpected end") .with_labels(vec![Label::primary(span.source_id(), *span)]), DynParserError::UnexpectedToken { span } => Diagnostic::error() .with_message("unexpected token") .with_labels(vec![Label::primary(span.source_id(), *span)]), } } } impl<'a> ParseCtx<'a> { pub fn new(tokens: &'a [DynToken], span: SourceSpan) -> Self { ParseCtx { containing: span, tokens, pos: 0, } } pub fn pop(&mut self) -> Result<&'a DynToken, DynParserError> { if self.pos < self.tokens.len() { let tok = &self.tokens[self.pos]; self.pos += 1; Ok(tok) } else { UnexpectedEnd { span: self .tokens .last() .map(|tok| tok.span()) .unwrap_or(self.containing), } .fail()? } } pub fn peek(&self) -> Option<&'a DynToken> { self.tokens.get(self.pos) } pub fn try_parse( &mut self, fun: impl FnOnce(&mut ParseCtx) -> Result, ) -> Result { let pos = self.pos; match fun(self) { Ok(res) => Ok(res), Err(err) => { self.pos = pos; Err(err) } } } pub fn comma( &mut self, fun: impl Fn(&mut ParseCtx) -> Result, ) -> Result, E> { let mut res = vec![]; loop { match fun(self) { Ok(val) => res.push(val), Err(err) => break, } match self.peek() { Some(&DynToken::Comma(_)) => (), _ => break, None => break, } } return Ok(res); } pub fn repeat_any(&mut self, fun: impl Fn(&mut ParseCtx) -> Result) -> Vec { let mut res = vec![]; loop { match fun(self) { Ok(val) => res.push(val), Err(err) => break, } } return res; } pub fn eof(&mut self) -> Result<(), DynParserError> { match self.peek() { Some(tok) => Err(DynParserError::UnexpectedToken { span: tok.span() }), None => Ok(()), } } pub fn tok_string(&mut self) -> Result { match self.pop()? { DynToken::String(string) => Ok(*string), tok => Err(DynParserError::UnexpectedToken { span: tok.span() }), } } pub fn tok_integer(&mut self) -> Result<(&'a Integer, SourceSpan), DynParserError> { match self.pop()? { DynToken::Integer(int, span) => Ok((int, *span)), tok => Err(DynParserError::UnexpectedToken { span: tok.span() }), } } pub fn tok_colon(&mut self) -> Result { match self.pop()? { DynToken::Colon(span) => Ok(*span), tok => Err(DynParserError::UnexpectedToken { span: tok.span() }), } } pub fn tok_at(&mut self) -> Result { match self.pop()? { DynToken::At(span) => Ok(*span), tok => Err(DynParserError::UnexpectedToken { span: tok.span() }), } } container_token!(tok_parens, Parens); container_token!(tok_braces, Braces); container_token!(tok_map_braces, MapBraces); container_token!(tok_square_brackets, SquareBrackets); container_token!(tok_angle_brackets, AngleBrackets); } pub struct ParsePos(usize); pub fn val(ctx: &mut ParseCtx) -> Result { println!("val PEEK {:?}", ctx.peek()); match ctx.peek() { Some(DynToken::SquareBrackets(_, _)) => val_list(ctx), Some(DynToken::AngleBrackets(_, _)) => val_value_list(ctx), _ => val_atomic(ctx), } } //pub fn value_max(ctx: &mut ParseCtx) -> Result { // ctx.try_parse(|ctx| match ctx.pop() { // DynToken::SquareBrackets(inner, span) => unimplemented!(), // _ => panic!(), // }) //} pub fn val_value_list(ctx: &mut ParseCtx) -> Result { ctx.try_parse(|ctx| { let (inner, span) = ctx.tok_angle_brackets()?; let mut ictx = ParseCtx::new(inner, span); let vec = ictx.comma(val)?; println!("{:?}", vec); println!("before value list eof"); ictx.eof()?; println!("after value list eof"); Ok(Value::ValueList(vec)) }) } pub fn val_list(ctx: &mut ParseCtx) -> Result { ctx.try_parse(|ctx| { let (inner, span) = ctx.tok_square_brackets()?; let mut ictx = ParseCtx::new(inner, span); let vec = ictx.comma(val)?; match ictx.pop() { Err(_) => Ok(Value::List(vec, None)), Ok(DynToken::Pipe(_span)) => { let tail = val(&mut ictx)?; ictx.eof()?; Ok(Value::List(vec, Some(Box::new(tail)))) } Ok(other) => Err(DynParserError::UnexpectedToken { span: other.span() }), } }) } pub fn val_atomic(ctx: &mut ParseCtx) -> Result { println!("val_atomic PEEK {:?}", ctx.peek()); ctx.try_parse(|ctx| match ctx.pop()? { DynToken::Atom(atom) => Ok(Value::Atom(*atom)), DynToken::Integer(int, span) => Ok(Value::Integer(int.clone())), DynToken::Ident(block) => Ok(Value::Block(*block)), DynToken::Variable(var) => Ok(Value::Value(*var)), tok => { println!("unexpected tok {:?}", tok); UnexpectedToken { span: tok.span() }.fail()? } }) } //pub fn value(ctx: &mut ParseCtx) -> Result { // if let Ok(head_val) = value(ctx) { // } else { // unimplemented!() // } //} ================================================ FILE: libeir_ir/src/text/parser/errors.rs ================================================ use snafu::Snafu; use std::path::PathBuf; use libeir_diagnostics::{Diagnostic, Label, SourceIndex, SourceSpan, ToDiagnostic}; use libeir_util_parse::SourceError; use super::lexer::Token; use crate::text::LowerError; pub type ParseError = lalrpop_util::ParseError; pub type Errors = libeir_util_parse::Errors; #[derive(Debug, Snafu)] #[snafu(visibility = "pub(super)")] pub enum ParserError { #[snafu(display("{} occurred while reading {:?}", source, path))] RootFileError { source: std::io::Error, path: PathBuf, }, #[snafu(display("{}", source))] Source { source: SourceError, }, Lower { source: LowerError, }, InvalidToken { span: SourceSpan, }, UnexpectedEOF { span: SourceSpan, expected: Vec, }, UnexpectedToken { span: SourceSpan, expected: Vec, }, UnrecognizedToken { span: SourceSpan, expected: Vec, }, ExtraToken { span: SourceSpan, }, ShowDiagnostic { diagnostic: Diagnostic, }, } impl ParserError { pub fn span(&self) -> Option { match self { ParserError::InvalidToken { span } => Some(*span), ParserError::UnrecognizedToken { span, .. } => Some(*span), ParserError::ExtraToken { span } => Some(*span), _ => None, } } } impl ToDiagnostic for ParserError { fn to_diagnostic(&self) -> Diagnostic { let span = self.span(); let msg = self.to_string(); match self { ParserError::ShowDiagnostic { diagnostic } => diagnostic.clone(), ParserError::Source { source } => source.to_diagnostic(), ParserError::Lower { source } => source.to_diagnostic(), ParserError::UnrecognizedToken { expected, .. } => { let span = span.unwrap(); Diagnostic::error() .with_message(format!("expected: {}", expected.join(", "))) .with_labels(vec![ Label::primary(span.source_id(), span).with_message(msg) ]) } _ if span.is_some() => { let span = span.unwrap(); Diagnostic::error() .with_message(msg) .with_labels(vec![Label::primary(span.source_id(), span)]) } _ => Diagnostic::error().with_message(msg), } } } impl From for ParserError { fn from(err: LowerError) -> ParserError { ParserError::Lower { source: err } } } impl From for ParserError { fn from(err: ParseError) -> ParserError { use lalrpop_util::ParseError as E; match err { E::InvalidToken { location } => ParserError::InvalidToken { span: SourceSpan::new(location, location), }, E::UnrecognizedEOF { location, expected } => ParserError::UnexpectedEOF { span: SourceSpan::new(location, location), expected, }, E::UnrecognizedToken { token: (start, _tok, end), expected, } => ParserError::UnrecognizedToken { span: SourceSpan::new(start, end), expected, }, E::ExtraToken { token: (start, _, end), } => ParserError::ExtraToken { span: SourceSpan::new(start, end), }, E::User { error } => error, } } } impl From for ParserError { fn from(diagnostic: Diagnostic) -> ParserError { ParserError::ShowDiagnostic { diagnostic } } } ================================================ FILE: libeir_ir/src/text/parser/grammar.lalrpop ================================================ //-*- mode: rust -*- use libeir_diagnostics::{SourceIndex, SourceSpan, Diagnostic, Label as DiagLabel}; use libeir_intern::{Ident, Symbol}; use libeir_util_parse::ErrorReceiver; use libeir_util_number::ToPrimitive; use crate::{BasicType, BinOp}; use crate::constant::Integer; use crate::text::parser::lexer::Token; use crate::text::ast::{Module, ModuleItem, Function, FunctionItem, Label, Op, CallControlFlowOp, CallFunctionOp, Value, Assignment, UnpackValueListOp, IfBoolOp, TraceCaptureRawOp, MatchEntry, MatchKind, MatchOp, CaseOp, CaseEntry, CasePattern, Meta, DynToken}; use super::ParserErrorReceiver; use super::errors::{ParserError, Errors}; grammar<'a>(errors: &'a mut ParserErrorReceiver<'a>); #[inline] Comma: Vec = { ",")*> => { let mut v = v; if let Some(n) = e { v.push(n); } v } }; pub Module: Module = { "{" "}" => { Module { span: span!(l, r), name: name, items, } } }; ModuleItem: ModuleItem = { => ModuleItem::Function(<>), }; pub StandaloneFunction: (Ident, Function) = { ":" "/" "{" "}" => { ( module, Function { span: span!(l, r), name: name, arity: arity, items, } ) } }; Function: Function = { "/" "{" "}" => { Function { span: span!(l, r), name: name, arity: arity, items, } } }; FunctionItem: FunctionItem = { // Assignments ";" => <>, // Operations ";" => FunctionItem::Op(<>), // Meta "!" ";" => { FunctionItem::Meta(Meta { span: SourceSpan::new(l, r), name, tokens, }) }, // Label "(" > ")" ":" => { let span = SourceSpan::new(l, r); if name.block().is_none() { errors.error( Diagnostic::error() .with_message("label name must be block") .with_labels(vec![DiagLabel::primary(span.source_id(), span)]) .into() ); } for arg in args.iter() { if arg.value().is_none() { errors.error( Diagnostic::error() .with_message("argument to label must be value") .with_labels(vec![DiagLabel::primary(span.source_id(), span)]) .into() ); } } FunctionItem::Label(Label { span: span!(l, r), name: name, args }) }, }; #[inline] FunctionAssignItem: FunctionItem = { "=" => { if lhs.value().is_none() { let span = SourceSpan::new(l, r); errors.error( Diagnostic::error() .with_message("assignment must be to a value") .with_labels(vec![DiagLabel::primary(span.source_id(), span)]) .into() ); } FunctionItem::Assignment(Assignment { span: span!(l, r), lhs, rhs, }) } }; DynToken: DynToken = { => <>, }; DynTokenInner: DynToken = { ";" => DynToken::SemiColon(span!(l, r)), => <>, }; DynToken100: DynToken = { "(" ")" => DynToken::Parens(i, span!(l, r)), "{" "}" => DynToken::Braces(i, span!(l, r)), "%{" "}" => DynToken::MapBraces(i, span!(l, r)), "[" "]" => DynToken::SquareBrackets(i, span!(l, r)), "<" ">" => DynToken::AngleBrackets(i, span!(l, r)), => DynToken::Ident(i), => DynToken::Variable(i), => DynToken::Atom(i), => DynToken::Integer(i, span!(l, r)), => DynToken::Float(i), => DynToken::String(s), "%" => DynToken::Percent(span!(l, r)), ":" => DynToken::Colon(span!(l, r)), "," => DynToken::Comma(span!(l, r)), "?" => DynToken::Question(span!(l, r)), "/" => DynToken::ForwardSlash(span!(l, r)), "=" => DynToken::Equals(span!(l, r)), "==" => DynToken::EqualsEquals(span!(l, r)), "=>" => DynToken::FatArrow(span!(l, r)), "_" => DynToken::Underscore(span!(l, r)), "|" => DynToken::Pipe(span!(l, r)), "@" => DynToken::At(span!(l, r)), "!" => DynToken::Bang(span!(l, r)), "unpack" => DynToken::Unpack(span!(l, r)), "unreachable" => DynToken::Unreachable(span!(l, r)), "arity" => DynToken::Arity(span!(l, r)), "if_bool" => DynToken::IfBool(span!(l, r)), "trace_capture_raw" => DynToken::TraceCaptureRaw(span!(l, r)), "value" => DynToken::Value(span!(l, r)), "match" => DynToken::Match(span!(l, r)), "type" => DynToken::Type(span!(l, r)), "case" => DynToken::Case(span!(l, r)), "guard" => DynToken::Guard(span!(l, r)), "except" => DynToken::Except(span!(l, r)), }; #[inline] FunctionOp: Op = { // Intrinsic/Dynop "@" => { Op::Dyn(name, tokens) }, // Call "(" > ")" "=>" "except" => { Op::CallFunction(CallFunctionOp { span: span!(l, r), target, ret, thr, args, }) }, "(" > ")" => { Op::CallControlFlow(CallControlFlowOp { span: span!(l, r), target, args, }) }, // UnpackValueList "unpack" "arity" "=>" => { Op::UnpackValueList(UnpackValueListOp { span: span!(l, r), arity: arity.to_usize().unwrap(), value, block, }) }, "if_bool" => { Op::IfBool(IfBoolOp { span: span!(l, r), value, tru, fal, or, }) }, "trace_capture_raw" => { Op::TraceCaptureRaw(TraceCaptureRawOp { span: span!(l, r), then, }) }, "match" "{" "}" => { Op::Match(MatchOp { span: span!(l, r), value, entries, }) }, "case" "{" "}" => { Op::Case(CaseOp { span: span!(l, r), value, entries, no_match, }) }, // Unreachable "unreachable" => Op::Unreachable, }; CaseEntry: CaseEntry = { "<" > ">" "guard" "=>" "(" > ")" ";" => { CaseEntry { span: span!(l, r), patterns, args, guard, target, } }, "guard" "=>" "(" > ")" ";" => { CaseEntry { span: span!(l, r), patterns: vec![pattern], args, guard, target, } }, }; CaseNoMatch: Value = { "_" "=>" ";" => <>, }; CasePattern: CasePattern = { "(" ")" => <>, "{" > "}" => { CasePattern::Tuple { elements, } }, "[" > )?> "]" => { let mut acc = tail.unwrap_or(CasePattern::Value(Value::Nil)); for elem in heads.drain(..).rev() { acc = CasePattern::ListCell { head: Box::new(elem), tail: Box::new(acc), }; } acc }, "@" => { CasePattern::Binding { name, pattern: Box::new(pat), } }, "_" => { CasePattern::Wildcard } }; MatchEntry: MatchEntry = { "=>" ";" => { MatchEntry { span: span!(l, r), target, kind, } } }; MatchKind: MatchKind = { "value" => MatchKind::Value(value), "type" "%{" "}" => MatchKind::Type(BasicType::Map), "{" "}" "arity" => MatchKind::Tuple(arity.to_usize().unwrap()), "[" "]" => MatchKind::ListCell, "%{" "}" => MatchKind::MapItem(key), "_" => MatchKind::Wildcard, }; Value: Value = { ":" "/" => Value::CaptureFunction(Box::new(m), Box::new(f), Box::new(a)), => Value::BinOp(Box::new(left), op, Box::new(right)), Value100, }; Value100: Value = { ValueMax }; ValueMax: Value = { "[" > )?> "]" => { if head.len() == 0 { if let Some(tail) = tail { tail } else { Value::Nil } } else { Value::List(head, tail.map(Box::new)) } }, "{" > "}" => Value::Tuple(<>), "<" > ">" => Value::ValueList(<>), => <>, }; AtomicValue: Value = { => Value::Atom(<>), => Value::Integer(<>), => Value::Block(<>), => Value::Value(<>), }; BinOp: BinOp = { "==" => BinOp::Equal, }; Block: Ident = { => <>, "type" => Ident::new(Symbol::intern("type"), SourceSpan::new(l, r)), }; extern { type Location = SourceIndex; type Error = ParserError; enum Token { "EOF" => Token::EOF, ident => Token::Ident(), variable => Token::Variable(), atom => Token::Atom(), integer => Token::Integer(), float => Token::Float(), string => Token::String(), "(" => Token::ParenOpen, ")" => Token::ParenClose, "{" => Token::CurlyOpen, "}" => Token::CurlyClose, "[" => Token::SquareOpen, "]" => Token::SquareClose, "<" => Token::Less, ">" => Token::Greater, "%" => Token::Percent, "%{" => Token::MapOpen, ":" => Token::Colon, ";" => Token::Semicolon, "," => Token::Comma, "?" => Token::Question, "/" => Token::ForwardSlash, "=" => Token::Equals, "==" => Token::EqualsEquals, "=>" => Token::FatArrow, "_" => Token::Underscore, "|" => Token::Pipe, "@" => Token::At, "!" => Token::Bang, "unpack" => Token::UnpackValueList, "unreachable" => Token::Unreachable, "arity" => Token::Arity, "if_bool" => Token::IfBool, "trace_capture_raw" => Token::TraceCaptureRaw, "value" => Token::Value, "match" => Token::Match, "type" => Token::Type, "case" => Token::Case, "guard" => Token::Guard, "except" => Token::Except, } } ================================================ FILE: libeir_ir/src/text/parser/lexer.rs ================================================ #![allow( dead_code, unreachable_code, unused_mut, unused_variables, unused_macros )] use std::collections::HashMap; use std::ops::Range; use lazy_static::lazy_static; use libeir_diagnostics::{ByteOffset, SourceIndex, SourceSpan}; use libeir_intern::{Ident, Symbol}; use libeir_util_parse::{Scanner, Source}; use super::errors::ParserError; use crate::constant::Integer; macro_rules! pop { ($lex:ident) => {{ $lex.skip(); }}; ($lex:ident, $code:expr) => {{ $lex.skip(); $code }}; } macro_rules! pop2 { ($lex:ident) => {{ $lex.skip(); $lex.skip(); }}; ($lex:ident, $code:expr) => {{ $lex.skip(); $lex.skip(); $code }}; } macro_rules! pop3 { ($lex:ident) => {{ $lex.skip(); $lex.skip(); $lex.skip() }}; ($lex:ident, $code:expr) => {{ $lex.skip(); $lex.skip(); $lex.skip(); $code }}; } #[derive(Clone, Debug, PartialEq)] pub struct LexicalError; #[derive(Debug, Clone, PartialEq)] pub struct LexicalToken(pub SourceIndex, pub Token, pub SourceIndex); impl LexicalToken { pub fn token(&self) -> Token { self.1.clone() } pub fn span(&self) -> SourceSpan { SourceSpan::new(self.0, self.2) } } #[derive(Clone, PartialEq, Eq, Debug)] pub enum Token { EOF, // Identifiers /// something Ident(Ident), Variable(Ident), // Atomics /// a'true' Atom(Ident), /// 12 Integer(Integer), /// 12.2 Float(Ident), String(Ident), // Symbols ParenOpen, ParenClose, CurlyOpen, CurlyClose, SquareOpen, SquareClose, Less, Greater, MapOpen, Colon, Semicolon, Comma, Question, ForwardSlash, Percent, Equals, EqualsEquals, FatArrow, Underscore, Pipe, At, Bang, // Keywords Unreachable, IfBool, UnpackValueList, ValueList, Tuple, Arity, TraceCaptureRaw, Value, Match, Type, Case, Guard, Except, } lazy_static! { static ref KEYWORDS: HashMap = { let mut map = HashMap::new(); map.insert(Symbol::intern("unreachable"), Token::Unreachable); map.insert(Symbol::intern("if_bool"), Token::IfBool); map.insert(Symbol::intern("unpack_value_list"), Token::UnpackValueList); map.insert(Symbol::intern("value_list"), Token::ValueList); map.insert(Symbol::intern("tuple"), Token::Tuple); map.insert(Symbol::intern("unpack"), Token::UnpackValueList); map.insert(Symbol::intern("arity"), Token::Arity); map.insert(Symbol::intern("trace_capture_raw"), Token::TraceCaptureRaw); map.insert(Symbol::intern("value"), Token::Value); map.insert(Symbol::intern("match"), Token::Match); map.insert(Symbol::intern("type"), Token::Type); map.insert(Symbol::intern("case"), Token::Case); map.insert(Symbol::intern("except"), Token::Except); map.insert(Symbol::intern("guard"), Token::Guard); map }; } fn is_escapechar(c: char) -> bool { c == 'b' || c == 'd' || c == 'e' || c == 'f' || c == 'n' || c == 'r' || c == 's' || c == 't' || c == 'v' || c == '"' || c == '\'' || c == '\\' } fn is_control(c: char) -> bool { c >= '\u{0000}' && c <= '\u{001f}' } fn is_inputchar(c: char) -> bool { c != '\n' && c != '\r' } fn is_digit(c: char) -> bool { c >= '0' && c <= '9' } fn is_octal(c: char) -> bool { c >= '0' && c <= '7' } fn is_uppercase(c: char) -> bool { (c >= 'A' && c <= 'Z') || (c >= '\u{00c0}' && c <= '\u{00d6}') || (c >= '\u{00d8}' && c <= '\u{00de}') } fn is_lowercase(c: char) -> bool { (c >= 'a' && c <= 'z') || (c >= '\u{00df}' && c <= '\u{00f6}') || (c >= '\u{00f8}' && c <= '\u{00ff}') } fn is_namechar(c: char) -> bool { is_uppercase(c) || is_lowercase(c) || is_digit(c) || (c == '@') || (c == '_') } pub struct Lexer { scanner: Scanner, token: Token, token_start: SourceIndex, token_end: SourceIndex, eof: bool, } impl Lexer where S: Source, { pub fn new(scanner: Scanner) -> Self { let start = scanner.start(); let mut lexer = Lexer { scanner, token: Token::EOF, token_start: start + ByteOffset(0), token_end: start + ByteOffset(0), eof: false, }; lexer.advance(); lexer } pub fn lex(&mut self) -> Option<::Item> { if self.eof && self.token == Token::EOF { return None; } let token = std::mem::replace(&mut self.token, Token::EOF); //let result = if let Token::Error(err) = token { // Some(Err(err)) //} else { let result = Some(Ok(( self.token_start.clone(), token, self.token_end.clone(), ))); //}; self.advance(); result } fn advance(&mut self) { self.advance_start(); self.token = self.tokenize(); } fn advance_start(&mut self) { let mut position: SourceIndex; loop { let (pos, c) = self.scanner.read(); position = pos; if c == '\0' { self.eof = true; return; } if c.is_whitespace() { self.scanner.advance(); continue; } if c == '#' { 'inner: loop { let (pos, c) = self.scanner.read(); if c == '\n' { break 'inner; } if c == '\0' { self.eof = true; return; } self.skip(); } continue; } break; } self.token_start = position; } fn pop(&mut self) -> char { let (pos, c) = self.scanner.pop(); self.token_end = pos + ByteOffset::from_char_len(c); c } fn peek(&mut self) -> char { self.scanner.peek().1 } fn peek_next(&mut self) -> char { self.scanner.peek_next().1 } fn read(&mut self) -> char { self.scanner.read().1 } fn skip(&mut self) { self.pop(); } pub fn span(&self) -> SourceSpan { SourceSpan::new(self.token_start, self.token_end) } fn slice(&self) -> &str { self.scanner.slice(self.span()) } fn slice_span(&self, span: impl Into>) -> &str { self.scanner.slice(span) } fn ident(&self) -> Ident { let symbol = Symbol::intern(self.slice()); Ident::new(symbol, self.span()) } fn skip_whitespace(&mut self) { let mut c: char; while self.read().is_whitespace() { self.skip(); } } fn tokenize(&mut self) -> Token { let mut c = self.read(); if c == '\0' { self.eof = true; return Token::EOF; } if c.is_whitespace() { self.skip_whitespace(); } match self.read() { '(' => pop!(self, Token::ParenOpen), ')' => pop!(self, Token::ParenClose), '{' => pop!(self, Token::CurlyOpen), '}' => pop!(self, Token::CurlyClose), '[' => pop!(self, Token::SquareOpen), ']' => pop!(self, Token::SquareClose), '<' => pop!(self, Token::Less), '>' => pop!(self, Token::Greater), '%' => match self.peek() { '{' => pop2!(self, Token::MapOpen), c if c.is_alphanumeric() => self.lex_variable(), _ => unimplemented!(), }, ',' => pop!(self, Token::Comma), ':' => pop!(self, Token::Colon), ';' => pop!(self, Token::Semicolon), '/' => pop!(self, Token::ForwardSlash), '|' => pop!(self, Token::Pipe), '=' => match self.peek() { '>' => pop2!(self, Token::FatArrow), '=' => pop2!(self, Token::EqualsEquals), _ => pop!(self, Token::Equals), }, '_' => pop!(self, Token::Underscore), '@' => pop!(self, Token::At), '!' => pop!(self, Token::Bang), c if c == 'a' => match self.peek() { '\'' => self.lex_atom(), _ => self.lex_ident(), }, c if c.is_alphabetic() => self.lex_ident(), c if c.is_numeric() => self.lex_integer(), '"' => self.lex_string(), c => unimplemented!("{}", c), } } fn lex_ident(&mut self) -> Token { let c = self.pop(); debug_assert!(c.is_alphabetic()); loop { match self.read() { '_' => self.skip(), '0'..='9' => self.skip(), c if c.is_alphabetic() => self.skip(), _ => break, } } let ident = self.ident(); if let Some(tok) = KEYWORDS.get(&ident.name) { tok.clone() } else { Token::Ident(ident) } } fn lex_string(&mut self) -> Token { let c = self.pop(); debug_assert!(c == '"'); loop { match self.read() { '\\' => { self.skip(); self.skip(); } '"' => { break; } _ => self.skip(), } } let symbol = Symbol::intern(&self.slice()[1..]); self.skip(); let ident = Ident::new(symbol, self.span()); Token::String(ident) } fn lex_variable(&mut self) -> Token { let c = self.pop(); debug_assert!(c == '%'); loop { match self.read() { '_' => self.skip(), '0'..='9' => self.skip(), c if c.is_alphabetic() => self.skip(), _ => break, } } let symbol = Symbol::intern(&self.slice()[1..]); let ident = Ident::new(symbol, self.span()); Token::Variable(ident) } fn lex_integer(&mut self) -> Token { let c = self.pop(); debug_assert!(c.is_numeric() || c == '-'); loop { match self.read() { c if c.is_numeric() => self.skip(), _ => break, } } let int = self.slice().parse().unwrap(); Token::Integer(int) } fn lex_atom(&mut self) -> Token { debug_assert!(self.pop() == 'a'); debug_assert!(self.pop() == '\''); loop { match self.read() { '\'' => { self.skip(); break; } '\\' => { self.skip(); self.skip(); } c => { self.skip(); } } } let slice = self.slice(); let inner_slice = &self.slice()[2..(slice.len() - 1)]; let ident = Ident::new(Symbol::intern(inner_slice), self.span()); Token::Atom(ident) } } impl Iterator for Lexer where S: Source, { type Item = Result<(SourceIndex, Token, SourceIndex), ParserError>; fn next(&mut self) -> Option { let t = self.lex(); t } } ================================================ FILE: libeir_ir/src/text/parser/mod.rs ================================================ use std::sync::Arc; use libeir_diagnostics::{CodeMap, SourceIndex}; use libeir_intern::Ident; use libeir_util_parse::{ self as parse, error_tee, ErrorReceiver, Parse, Scanner, Source, SourceError, }; use crate::FunctionIdent; mod lexer; use lexer::{Lexer, Token}; mod errors; use self::errors::Errors; pub use self::errors::ParserError; use super::lower::LowerMap; pub type Parser = parse::Parser<()>; type ParserErrorReceiver<'a> = dyn ErrorReceiver + 'a; /// Used in the grammar for easy span creation macro_rules! span { ($l:expr, $r:expr) => { SourceSpan::new($l, $r) }; ($i:expr) => { SourceSpan::new($i, $i) }; } #[cfg_attr(rustfmt, rustfmt_skip)] #[allow(unknown_lints)] #[allow(clippy)] #[allow(unused_variables, dead_code, unused_imports, unused_parens)] pub(crate) mod grammar { // During the build step, `build.rs` will output the generated parser to `OUT_DIR` to avoid // adding it to the source directory, so we just directly include the generated parser here. // // Even with `.gitignore` and the `exclude` in the `Cargo.toml`, the generated parser can still // end up in the source directory. This could happen when `cargo build` builds the file out of // the Cargo cache (`$HOME/.cargo/registrysrc`), and the build script would then put its output // in that cached source directory because of https://github.com/lalrpop/lalrpop/issues/280. // Later runs of `cargo vendor` then copy the source from that directory, including the // generated file. include!(concat!(env!("OUT_DIR"), "/text/parser/grammar.rs")); } pub struct NamedFunction { pub name: Ident, pub function: super::ast::Function, } impl Parse for super::ast::Module { type Parser = self::grammar::ModuleParser; type Error = ParserError; type Config = (); type Token = std::result::Result<(SourceIndex, Token, SourceIndex), ParserError>; fn root_file_error(source: std::io::Error, path: std::path::PathBuf) -> Self::Error { ParserError::RootFileError { source, path } } fn parse_tokens(errors: &mut ParserErrorReceiver, tokens: S) -> Result where S: IntoIterator>, { let result = self::grammar::ModuleParser::new().parse(errors, tokens); let ret; match result { Ok(ok) => ret = ok, Err(err) => { errors.error(err.into()); return Err(()); } } if (*errors).is_failed() { Err(()) } else { Ok(ret) } } fn parse(_parser: &Parser, errors: &mut ParserErrorReceiver, source: S) -> Result where S: Source, { let scanner = Scanner::new(source); let lexer = Lexer::new(scanner); Self::parse_tokens(errors, lexer) } } impl Parse for NamedFunction { type Parser = self::grammar::StandaloneFunctionParser; type Error = ParserError; type Config = (); type Token = std::result::Result<(SourceIndex, Token, SourceIndex), ParserError>; fn root_file_error(source: std::io::Error, path: std::path::PathBuf) -> Self::Error { ParserError::RootFileError { source, path } } fn parse_tokens(errors: &mut ParserErrorReceiver, tokens: S) -> Result where S: IntoIterator>, { let result = self::grammar::StandaloneFunctionParser::new().parse(errors, tokens); let name; let function; match result { std::result::Result::Ok((i, f)) => { name = i; function = f; } std::result::Result::Err(err) => { errors.error(err.into()); return Err(()); } } if (*errors).is_failed() { Err(()) } else { Ok(NamedFunction { name, function }) } } fn parse<'a, S>( _parser: &Parser, errors: &'a mut ParserErrorReceiver<'a>, source: S, ) -> Result where S: Source, { let scanner = Scanner::new(source); let lexer = Lexer::new(scanner); Self::parse_tokens(errors, lexer) } } impl FunctionIdent { pub fn parse(string: &str) -> std::result::Result { lazy_static::lazy_static! { static ref FUNCTION_IDENT_RE: regex::Regex = { regex::Regex::new("^([^/]+):([^:]+)/(\\d+)$").unwrap() }; } let captures = FUNCTION_IDENT_RE .captures(string) .map(Ok) .unwrap_or(Err(()))?; let res = FunctionIdent { module: Ident::from_str(&captures[1]), name: Ident::from_str(&captures[2]), arity: captures[3].parse().unwrap(), }; Ok(res) } pub fn parse_with_module(string: &str, module: Ident) -> std::result::Result { lazy_static::lazy_static! { static ref FUNCTION_IDENT_RE: regex::Regex = { regex::Regex::new("^([^:]+)/(\\d+)$").unwrap() }; } let captures = FUNCTION_IDENT_RE .captures(string) .map(Ok) .unwrap_or(Err(()))?; let res = FunctionIdent { module, name: Ident::from_str(&captures[1]), arity: captures[2].parse().unwrap(), }; Ok(res) } } pub fn module_codemap(text: &str, codemap: Arc) -> (Result, Errors) { let mut errors = Errors::new(); let parser = Parser::new((), codemap); let res = match parser.parse_string(&mut errors, text) { Ok(module) => { let module: super::ast::Module = module; error_tee(&mut errors, |mut errors| { let mut adapter = errors.make_into_adapter(); match module.lower(&mut adapter) { Ok(module) => Ok(module), Err(()) => Err(()), } }) } Err(()) => Err(()), }; (res, errors) } pub fn module(text: &str) -> (Result, Errors) { module_codemap(text, Arc::new(CodeMap::new())) } pub fn module_unwrap(text: &str) -> crate::Module { let codemap = Arc::new(CodeMap::new()); match module_codemap(text, codemap.clone()) { (Ok(module), errors) => { errors.print(&codemap); module } (Err(()), errors) => { errors.print(&codemap); panic!(); } } } pub fn function_map_codemap( text: &str, codemap: Arc, ) -> (Result<(crate::Function, LowerMap), ()>, Errors) { let mut errors = Errors::new(); let parser = Parser::new((), codemap); let ret = match parser.parse_string(&mut errors, text) { Ok(named) => { let named: NamedFunction = named; error_tee(&mut errors, |mut errors| { let mut adapter = errors.make_into_adapter(); match named.function.lower(&mut adapter, named.name) { Ok(res) => Ok(res), Err(()) => Err(()), } }) } Err(()) => Err(()), }; (ret, errors) } pub fn function_map(text: &str) -> (Result<(crate::Function, LowerMap), ()>, Errors) { function_map_codemap(text, Arc::new(CodeMap::new())) } pub fn function_codemap( text: &str, codemap: Arc, ) -> (Result, Errors) { match function_map_codemap(text, codemap) { (Ok((fun, _)), errors) => (Ok(fun), errors), (Err(()), errors) => (Err(()), errors), } } pub fn function(text: &str) -> (Result, Errors) { match function_map(text) { (Ok((fun, _)), errors) => (Ok(fun), errors), (Err(()), errors) => (Err(()), errors), } } pub fn function_unwrap(text: &str) -> crate::Function { let codemap = Arc::new(CodeMap::new()); match function_codemap(text, codemap.clone()) { (Ok(fun), errors) => { errors.print(&codemap); fun } (Err(()), errors) => { errors.print(&codemap); panic!(); } } } pub fn function_map_unwrap(text: &str) -> (crate::Function, LowerMap) { let codemap = Arc::new(CodeMap::new()); match function_map_codemap(text, codemap.clone()) { (Ok(fun), errors) => { errors.print(&codemap); fun } (Err(()), errors) => { errors.print(&codemap); panic!(); } } } #[cfg(test)] mod test { use std::sync::Arc; use super::function_unwrap; use super::{NamedFunction, Parser}; use crate::text::ast; use libeir_diagnostics::{CodeMap, SourceSpan}; use libeir_intern::Ident; use libeir_util_parse::Errors; use pretty_assertions::assert_eq; #[test] fn parse_empty_function() { let codemap = Arc::new(CodeMap::new()); let mut errors = Errors::new(); let parser = Parser::new((), codemap); let _module: NamedFunction = parser .parse_string(&mut errors, "a'foo':a'foo'/1 {}") .unwrap(); } #[test] #[should_panic] fn lower_empty_function_fails() { function_unwrap("a'foo':a'foo'/1 {}"); } #[test] fn parse_kitchen_sink() { let codemap = Arc::new(CodeMap::new()); let mut errors = Errors::new(); let parser = Parser::new((), codemap); let module: ast::Module = parser .parse_string( &mut errors, " a'kitchen_sink' { a'something'/1 { entry(%return, %throw, %num): %something = a'true'; %fun = a'a':a'b'/a'c'; %foobar(%woo, %hoo); } a'second_fun'/0 {} } ", ) .unwrap(); //let ref_module = ast::Module { // span: SourceSpan::UNKNOWN, // name: Ident::from_str("kitchen_sink"), // items: vec![ // ast::ModuleItem::Function(ast::Function { // span: SourceSpan::UNKNOWN, // name: Ident::from_str("something"), // arity: 1.into(), // items: vec![ // ast::FunctionItem::Label(ast::Label { // span: SourceSpan::UNKNOWN, // name: ast::Value::Block(Ident::from_str("entry")), // args: vec![ // ast::Value::Value(Ident::from_str("return")), // ast::Value::Value(Ident::from_str("throw")), // ast::Value::Value(Ident::from_str("num")), // ], // }), // ast::FunctionItem::Assignment(ast::Assignment { // span: SourceSpan::UNKNOWN, // lhs: ast::Value::Value(Ident::from_str("something")), // rhs: ast::Value::Atom(Ident::from_str("true")), // }), // ast::FunctionItem::Assignment(ast::Assignment { // span: SourceSpan::UNKNOWN, // lhs: ast::Value::Value(Ident::from_str("fun")), // rhs: ast::Value::CaptureFunction( // Box::new(ast::Value::Atom(Ident::from_str("a"))), // Box::new(ast::Value::Atom(Ident::from_str("b"))), // Box::new(ast::Value::Atom(Ident::from_str("c"))), // ), // }), // ast::FunctionItem::Op(ast::Op::CallControlFlow(ast::CallControlFlowOp { // span: SourceSpan::UNKNOWN, // target: ast::Value::Value(Ident::from_str("foobar")), // args: vec![ // ast::Value::Value(Ident::from_str("woo")), // ast::Value::Value(Ident::from_str("hoo")), // ], // })), // ], // }), // ast::ModuleItem::Function(ast::Function { // span: SourceSpan::UNKNOWN, // name: Ident::from_str("second_fun"), // arity: 0.into(), // items: vec![], // }), // ], //}; //assert_eq!(module, ref_module); } #[test] fn lower_add_one() { let _fun = function_unwrap( " a'foo':a'add_one'/1 { entry(%return, %throw, %num): %add_fun = a'erlang':a'+'/2; %add_fun(%return, %throw, %num, 1); } ", ); } #[test] fn location() { let _fun = function_unwrap( " a'foo':a'bar'/1 { !location [\"foo\":\"bar\"@\"foo.erl\":12]; entry(%ret, %thr, %num): %ret(%num); } ", ); } } ================================================ FILE: libeir_ir/src/text/printer/constant.rs ================================================ use pretty::{Arena, DocAllocator, RefDoc}; use crate::{AtomicTerm, Const, ConstKind, ConstantContainer}; pub fn constant_to_doc<'a>( arena: &'a Arena<'a>, container: &ConstantContainer, constant: Const, ) -> RefDoc<'a, ()> { constant_to_doc_state(arena, container, constant, ConstantState::Normal) } #[derive(Debug, Copy, Clone)] enum ConstantState { Normal, ListTail, } macro_rules! norm_state { ($arena:expr, $state:expr) => { match $state { ConstantState::Normal => $arena.nil(), ConstantState::ListTail => $arena .space() .append($arena.text("|")) .append($arena.space()), } }; } fn constant_to_doc_state<'a>( arena: &'a Arena<'a>, container: &ConstantContainer, constant: Const, state: ConstantState, ) -> RefDoc<'a, ()> { match container.const_kind(constant) { ConstKind::Atomic(atomic) => norm_state!(arena, state) .append(atomic_to_doc(arena, atomic)) .into_doc(), ConstKind::ListCell { head, tail } => match state { ConstantState::Normal => arena .nil() .append(arena.text("[")) .append(constant_to_doc_state( arena, container, *head, ConstantState::Normal, )) .append(constant_to_doc_state( arena, container, *tail, ConstantState::ListTail, )) .append(arena.text("]")) .into_doc(), ConstantState::ListTail => arena .nil() .append(arena.text(",")) .append(arena.space()) .append(constant_to_doc_state( arena, container, *head, ConstantState::Normal, )) .append(constant_to_doc_state( arena, container, *tail, ConstantState::ListTail, )) .into_doc(), }, ConstKind::Tuple { entries } => { norm_state!(arena, state) .append(arena.text("{")) .append(arena.intersperse( entries.as_slice(&container.const_pool).iter().map(|c| { constant_to_doc_state(arena, container, *c, ConstantState::Normal) }), arena.text(",").append(arena.space()), )) .append(arena.text("}")) .into_doc() } ConstKind::Map { keys, values } => norm_state!(arena, state) .append(arena.text("%{")) .append( arena.intersperse( keys.as_slice(&container.const_pool) .iter() .zip(values.as_slice(&container.const_pool).iter()) .map(|(k, v)| { arena .nil() .append(constant_to_doc_state( arena, container, *k, ConstantState::Normal, )) .append(arena.space()) .append(arena.text("=>")) .append(arena.space()) .append(constant_to_doc_state( arena, container, *v, ConstantState::Normal, )) }), arena.text(",").append(arena.space()), ), ) .append(arena.text("}")) .into_doc(), } } fn atomic_to_doc<'a>(arena: &'a Arena<'a>, atomic: &AtomicTerm) -> RefDoc<'a, ()> { arena.text(format!("{}", atomic)).into_doc() } ================================================ FILE: libeir_ir/src/text/printer/mod.rs ================================================ #![allow(unused)] use std::collections::BTreeMap; use std::error::Error; use std::fmt::Write; use std::marker::PhantomData; use cranelift_entity::EntityRef; use petgraph::visit::Dfs; use pretty::{Arena, DocAllocator, RefDoc}; use crate::graph::EntityVisitMap; use crate::{ BinOp, Block, CallKind, Const, Function, LogicOp, Module, OpKind, PrimOpKind, Value, ValueKind, }; mod constant; mod operation; type DynError = Box; //pub trait EirPrint //where // B: BlockIteratorConfig, // V: ValueFormatter, // L: BlockValueLayout, //{ // type Context; // fn to_eir_text(&self, config: &FormatConfig, context: &Self::Context) -> String; //} //impl EirPrint for Block //where // B: BlockIteratorConfig, // V: ValueFormatter, // L: BlockValueLayout, //{ //} fn get_value_list<'a>(fun: &'a Function, value: Value) -> Option<&'a [Value]> { if let Some(prim) = fun.value_primop(value) { match fun.primop_kind(prim) { crate::PrimOpKind::ValueList => return Some(fun.primop_reads(prim)), _ => (), } } None } pub struct FormatConfig where B: BlockIteratorConfig, V: ValueFormatter, L: BlockValueLayout, { pub width: usize, pub print_locations: bool, /// Encapsulates the iteration order for blocks within a function. pub block_iterator_config: B, /// Formatter for values within a function. pub value_formatter: V, /// Layout for values within a function. pub block_value_layout: L, } pub type StandardFormatConfig = FormatConfig; impl Default for StandardFormatConfig { fn default() -> Self { FormatConfig { width: 80, print_locations: true, block_iterator_config: DfsBlockIteratorConfig, value_formatter: StandardValueFormatter, block_value_layout: ReferencePrimopBlockValueLayout::default(), } } } pub struct FormatState<'a> { pub function: &'a Function, pub nesting: usize, } /// Iteration strategy for blocks within a function pub trait BlockIteratorConfig { type Iter: BlockIterator; fn new(&self, fun: &Function) -> Self::Iter; } /// Implementation of block iteration strategy. /// ## Invariants /// * Each block MUST be returned at most once. pub trait BlockIterator { fn next(&mut self, fun: &Function) -> Option; } pub struct DfsBlockIteratorConfig; impl BlockIteratorConfig for DfsBlockIteratorConfig { type Iter = DfsBlockIterator; fn new(&self, fun: &Function) -> Self::Iter { let graph = fun.block_graph(); let entry = fun.block_entry(); let dfs = Dfs::new(&graph, entry); DfsBlockIterator { dfs } } } pub struct DfsBlockIterator { dfs: Dfs>, } impl BlockIterator for DfsBlockIterator { fn next(&mut self, fun: &Function) -> Option { self.dfs.next(&fun.block_graph()) } } #[derive(Debug, Copy, Clone, Eq, PartialEq)] #[allow(dead_code)] pub enum ValueSite { Decl, Use, } pub trait ValueFormatter { fn value(&self, out: &mut String, fun: &Function, site: ValueSite, value: Value); } /// This value formatter prints values in the format supported by the /// parser, and is considered the standard format. pub struct StandardValueFormatter; impl ValueFormatter for StandardValueFormatter { fn value(&self, out: &mut String, fun: &Function, _site: ValueSite, value: Value) { match fun.value_kind(value) { ValueKind::Block(block) => write!(out, "{}", block).unwrap(), _ => write!(out, "%{}", value.index()).unwrap(), } } } pub trait BlockValueLayout { /// Lays out the root scope for the module. This is called once /// at the beginning of processing a module. fn layout_module(&mut self, fun: &Function); /// Lays out the given block. This will be called once for each block. fn layout(&mut self, fun: &Function, block: Block); /// Values for the current layout. fn values(&self) -> &[Value]; /// Queries whether the given value should be laid out inline, or if /// it should be referenced by value. fn should_layout(&self, value: Value, within: Option) -> bool; } pub struct ReferencePrimopBlockValueLayout { values: Vec, values_set: BTreeMap, } impl Default for ReferencePrimopBlockValueLayout { fn default() -> Self { ReferencePrimopBlockValueLayout { values: Vec::new(), values_set: BTreeMap::new(), } } } impl BlockValueLayout for ReferencePrimopBlockValueLayout { fn layout_module(&mut self, fun: &Function) {} fn layout(&mut self, fun: &Function, block: Block) { self.values.clear(); self.values_set.clear(); fun.block_walk_nested_values::<_, ()>(block, &mut |value| { if fun.value_primop(value).is_some() { self.values.push(value); } Ok(()) }); for (idx, value) in self.values.iter().enumerate() { self.values_set.insert(*value, idx); } let mut idx = 0; let values_set = &self.values_set; self.values.retain(|val| { let ret = values_set[val] == idx; idx += 1; ret }); } fn values(&self) -> &[Value] { &self.values } fn should_layout(&self, value: Value, within: Option) -> bool { !self.values_set.contains_key(&value) } } pub trait BlockFormatSink { type LineIndex: Copy; fn write_indent(&mut self, num: usize) -> Result<(), DynError> { for _ in 0..num { self.write_str(" ")?; } Ok(()) } fn write_str(&mut self, string: &str) -> Result<(), DynError>; fn commit_line(&mut self) -> Result; /// Informs the sink that the given range of lines /// contains the given blocks. /// Blocks will never overlap, and this will be called /// at most once for each block. fn block_lines(&mut self, _block: Block, _range: (Self::LineIndex, Self::LineIndex)) {} } pub struct StringSink { string: String, } impl StringSink { pub fn new() -> Self { StringSink { string: String::new(), } } pub fn finalize(self) -> String { self.string } } impl BlockFormatSink for StringSink { type LineIndex = (); fn write_str(&mut self, string: &str) -> Result<(), DynError> { self.string.push_str(string); Ok(()) } fn commit_line(&mut self) -> Result<(), DynError> { self.string.push('\n'); Ok(()) } } pub(crate) struct FunctionFormatData<'a, B, V, L> where B: BlockIteratorConfig, V: ValueFormatter, L: BlockValueLayout, { pub arena: &'a Arena<'a>, pub buf: String, pub value_buf: Vec, pub config: PhantomData>, } impl<'a, B, V, L> FunctionFormatData<'a, B, V, L> where B: BlockIteratorConfig, V: ValueFormatter, L: BlockValueLayout, { pub(crate) fn block_to_doc( &mut self, config: &mut FormatConfig, state: &mut FormatState, block: Block, ) -> RefDoc<'a, ()> { let arena = self.arena; let pre; if config.print_locations { let loc = state.function.block_location(block); let loc_str = state.function.locations.format_loc(loc); pre = arena .nil() .append(arena.text("!location")) .append(arena.space()) .append(arena.as_string(loc)) .append(arena.space()) .append(arena.as_string(loc_str)) .append(arena.text(";")) .append(arena.hardline()); } else { pre = arena.nil(); } let ident = arena.as_string(block); let args = arena .intersperse( state.function.block_args(block).iter().map(|v| { self.buf.clear(); config.value_formatter.value( &mut self.buf, state.function, ValueSite::Decl, *v, ); arena.as_string(&self.buf) }), arena.text(", "), ) .parens(); let header = ident.append(args).append(":").group(); let body = self.block_body_to_doc(config, state, block); pre.append(header) .append(arena.hardline().append(body).nest(2)) .into_doc() } pub(crate) fn block_body_to_doc( &mut self, config: &mut FormatConfig, state: &mut FormatState, block: Block, ) -> RefDoc<'a, ()> { let arena = self.arena; //let mut value_buf = Vec::new(); //state.function.block_walk_nested_values::<_, ()>(block, &mut |val| { // match state.function.value_kind(val) { // ValueKind::PrimOp(prim) => { // value_buf.push(val); // }, // _ => (), // } // Ok(()) //}); //println!("value buf: {:?}", value_buf); config.block_value_layout.layout(state.function, block); let value_buf = config.block_value_layout.values(); let values = arena.concat( value_buf .iter() .rev() .map(|v| self.value_assign_to_doc(config, state, *v)) .map(|v| arena.nil().append(v).append(arena.hardline())), ); let op = self.block_op_to_doc(config, state, block); values.append(op).into_doc() } pub(crate) fn value_assign_to_doc( &mut self, config: &FormatConfig, state: &mut FormatState, value: Value, ) -> RefDoc<'a, ()> { let arena = self.arena; let value_kind = state.function.value_kind(value); let doc = match value_kind { ValueKind::PrimOp(prim) => { let prim_kind = state.function.primop_kind(prim); let reads = state.function.primop_reads(prim); match prim_kind { PrimOpKind::CaptureFunction => { assert!(reads.len() == 3); arena.nil().append(self.format_callee(config, state, reads)) } PrimOpKind::Tuple => arena .intersperse( reads .iter() .map(|r| self.value_use(config, state, *r, Some(value))), arena.text(",").append(arena.space()), ) .enclose(arena.text("{"), arena.text("}")), PrimOpKind::ValueList => arena .intersperse( reads .iter() .map(|r| self.value_use(config, state, *r, Some(value))), arena.text(",").append(arena.space()), ) .enclose(arena.text("<"), arena.text(">")), PrimOpKind::ListCell => { assert!(reads.len() == 2); arena .nil() .append(arena.text("[")) .append(self.value_use(config, state, reads[0], Some(value))) .append(arena.space()) .append(arena.text("|")) .append(arena.space()) .append(self.value_use(config, state, reads[1], Some(value))) .append(arena.text("]")) } PrimOpKind::BinOp(BinOp::Equal) => { assert!(reads.len() == 2); arena .nil() .append(self.value_use(config, state, reads[0], Some(value))) .append(arena.space()) .append(arena.text("==")) .append(arena.space()) .append(self.value_use(config, state, reads[1], Some(value))) } PrimOpKind::LogicOp(LogicOp::And) => arena .intersperse( reads .iter() .map(|r| self.value_use(config, state, *r, Some(value))), arena.text(",").append(arena.space()), ) .enclose("and[", "]"), PrimOpKind::LogicOp(LogicOp::Or) => arena .intersperse( reads .iter() .map(|r| self.value_use(config, state, *r, Some(value))), arena.text(",").append(arena.space()), ) .enclose("or[", "]"), _ => unimplemented!("{:?}", prim_kind), } } _ => unimplemented!("{:?}", value_kind), }; self.buf.clear(); config .value_formatter .value(&mut self.buf, state.function, ValueSite::Decl, value); let value_doc = arena.as_string(&self.buf); arena .nil() .append(value_doc) .append(arena.space()) .append(arena.text("=")) .append(arena.space()) .append(doc) .append(arena.text(";")) .into_doc() } fn constant( &mut self, _config: &FormatConfig, state: &mut FormatState, constant: Const, ) -> RefDoc<'a, ()> { self::constant::constant_to_doc(&self.arena, state.function.cons(), constant) } fn value_use_only( &mut self, config: &FormatConfig, state: &mut FormatState, value: Value, ) -> RefDoc<'a, ()> { self.buf.clear(); config .value_formatter .value(&mut self.buf, state.function, ValueSite::Use, value); self.arena.as_string(&self.buf).into_doc() } fn value_use( &mut self, config: &FormatConfig, state: &mut FormatState, value: Value, within: Option, ) -> RefDoc<'a, ()> { if config.block_value_layout.should_layout(value, within) { match state.function.value_kind(value) { ValueKind::Const(cons) => self.constant(config, state, cons), _ => self.value_use_only(config, state, value), } } else { self.value_use_only(config, state, value) } } fn format_callee( &mut self, config: &FormatConfig, state: &mut FormatState, reads: &[Value], ) -> RefDoc<'a, ()> { let arena = self.arena; // Resolve arity first, since we should always know arity let ac = state.function.value_const(reads[2]).unwrap(); let arity = self.constant(config, state, ac); let m = reads[0]; let f = reads[1]; let mk = state.function.value_kind(m); if let ValueKind::Const(mc) = mk { let doc = self.constant(config, state, mc); let fk = state.function.value_kind(f); if let ValueKind::Const(fc) = fk { arena .nil() .append(doc) .append(arena.text(":")) .append(self.constant(config, state, fc)) .append(arena.text("/")) .append(arity) .into_doc() } else { arena .nil() .append(doc) .append(arena.text(":")) .append(self.value_use_only(config, state, f)) .append(arena.text("/")) .append(arity) .into_doc() } } else { arena .nil() .append(self.value_use_only(config, state, m)) .append(arena.text(":")) .append(self.value_use_only(config, state, f)) .append(arena.text("/")) .append(arity) .into_doc() } } } fn format_function_body_state( config: &mut FormatConfig, state: &mut FormatState, sink: &mut S, ) -> Result<(), DynError> where B: BlockIteratorConfig, V: ValueFormatter, L: BlockValueLayout, S: BlockFormatSink, { let function = state.function; let mut block_iter = config.block_iterator_config.new(function); let arena = Arena::new(); let mut ctx = FunctionFormatData { arena: &arena, buf: String::new(), value_buf: Vec::new(), config: PhantomData, }; let inner_width = config.width - (state.nesting * 2); while let Some(block) = block_iter.next(function) { let doc = ctx.block_to_doc(config, state, block); ctx.buf.clear(); doc.render_fmt(inner_width, &mut ctx.buf).unwrap(); let mut first_line = None; let mut last_line = None; for line in ctx.buf.lines() { sink.write_indent(state.nesting)?; sink.write_str(line)?; let line = sink.commit_line()?; first_line = Some(first_line.unwrap_or(line)); last_line = Some(line); } sink.block_lines(block, (first_line.unwrap(), last_line.unwrap())); } Ok(()) } pub fn format_function_body( function: &Function, config: &mut FormatConfig, sink: &mut S, ) -> Result<(), DynError> where B: BlockIteratorConfig, V: ValueFormatter, L: BlockValueLayout, S: BlockFormatSink, { let mut state = FormatState { function, nesting: 0, }; format_function_body_state(config, &mut state, sink) } pub fn format_module( module: &Module, config: &mut FormatConfig, sink: &mut S, ) -> Result<(), DynError> where B: BlockIteratorConfig, V: ValueFormatter, L: BlockValueLayout, S: BlockFormatSink, { sink.write_str(&format!("{} {{\n", module.name().name.as_str().get())); let num_functions = module.function_iter().count(); for (i, fun) in module.function_iter().enumerate() { let function = fun.function(); let ident = function.ident(); sink.write_str(&format!(" {}/{} {{\n", &ident.name, ident.arity)); let mut state = FormatState { function, nesting: 2, }; format_function_body_state(config, &mut state, sink)?; if i + 1 < num_functions { sink.write_str(" }\n\n"); } else { sink.write_str(" }\n"); } } sink.write_str("}\n"); Ok(()) } impl Function { pub fn to_text(&self, config: &mut FormatConfig) -> String where B: BlockIteratorConfig, V: ValueFormatter, L: BlockValueLayout, { let mut sink = StringSink::new(); format_function_body(self, config, &mut sink).unwrap(); sink.finalize() } pub fn to_text_standard(&self) -> String { self.to_text(&mut StandardFormatConfig::default()) } pub fn block_to_text(&self, block: Block, config: &mut FormatConfig) -> String where B: BlockIteratorConfig, V: ValueFormatter, L: BlockValueLayout, { let mut sink = StringSink::new(); let arena = Arena::new(); let mut ctx = FunctionFormatData { arena: &arena, buf: String::new(), value_buf: Vec::new(), config: PhantomData, }; let mut state = FormatState { function: self, nesting: 0, }; let doc = ctx.block_to_doc(config, &mut state, block); ctx.buf.clear(); doc.render_fmt(config.width, &mut ctx.buf).unwrap(); ctx.buf } } impl Module { pub fn to_text(&self, config: &mut FormatConfig) -> String where B: BlockIteratorConfig, V: ValueFormatter, L: BlockValueLayout, { let mut sink = StringSink::new(); format_module(self, config, &mut sink).unwrap(); sink.finalize() } pub fn to_text_standard(&self) -> String { self.to_text(&mut StandardFormatConfig::default()) } } #[cfg(test)] mod tests { use super::{format_function_body, FormatConfig, StandardFormatConfig, StringSink}; #[test] fn woo() { let ir = crate::parse_function_unwrap( " a'woo':a'hoo'/1 { entry(%ret, %thr, %a): %f1 = a'erlang':a'+'/2; %f1(%a, 2) => b2 except %thr; b2(%b): %f2 = a'erlang':a'/'/2; %f2(%b, 2) => %ret except %thr; } ", ); let text = ir.to_text(&mut StandardFormatConfig::default()); println!("{}", text); } } ================================================ FILE: libeir_ir/src/text/printer/operation.rs ================================================ use log::warn; use pretty::{DocAllocator, RefDoc}; use crate::binary::{BinaryEntrySpecifier, Endianness}; use crate::traits::FormatOpCtx; use crate::{BasicType, Block, CallKind, DynValue, MatchKind, OpKind, Value}; use super::{ get_value_list, BlockIteratorConfig, BlockValueLayout, FormatConfig, FormatState, FunctionFormatData, ValueFormatter, }; pub struct FormatOpCtxImpl<'a, 'b, 'doc, B, V, L> where B: BlockIteratorConfig, V: ValueFormatter, L: BlockValueLayout, { format_data: &'a mut FunctionFormatData<'doc, B, V, L>, config: &'a FormatConfig, state: &'a mut FormatState<'b>, } impl<'a, 'b, 'doc, B, V, L> FormatOpCtx<'doc> for FormatOpCtxImpl<'a, 'b, 'doc, B, V, L> where B: BlockIteratorConfig, V: ValueFormatter, L: BlockValueLayout, { fn arena(&self) -> &'doc pretty::Arena<'doc> { self.format_data.arena } fn value_use_to_doc(&mut self, value: DynValue) -> RefDoc<'doc, ()> { let val = self.state.function.value_get(value).unwrap(); self.format_data .value_use(self.config, self.state, val, None) } } fn binary_specifier_to_doc<'a>( arena: &'a pretty::Arena<'a>, spec: &BinaryEntrySpecifier, ) -> RefDoc<'a, ()> { let f_endianness = |end| match end { &Endianness::Big => arena.text("big"), &Endianness::Little => arena.text("little"), &Endianness::Native => arena.text("native"), }; let f_signed = |signed| match signed { true => arena.text("signed"), false => arena.text("unsigned"), }; match spec { BinaryEntrySpecifier::Integer { signed, endianness, unit, } => { let items = [ f_signed(*signed), f_endianness(endianness), arena.as_string(unit), ]; arena .text("integer") .append( arena .intersperse(items.iter().cloned(), arena.text(",")) .parens(), ) .into_doc() } BinaryEntrySpecifier::Float { endianness, unit } => { let items = [f_endianness(endianness), arena.as_string(unit)]; arena .text("float") .append( arena .intersperse(items.iter().cloned(), arena.text(",")) .parens(), ) .into_doc() } BinaryEntrySpecifier::Bytes { unit } => arena .text("bytes") .append(arena.as_string(unit).parens()) .into_doc(), BinaryEntrySpecifier::Bits { unit } => arena .text("bits") .append(arena.as_string(unit).parens()) .into_doc(), BinaryEntrySpecifier::Utf8 => arena.text("utf8").append(arena.nil().parens()).into_doc(), BinaryEntrySpecifier::Utf16 { endianness } => arena .text("utf16") .append(f_endianness(endianness)) .into_doc(), BinaryEntrySpecifier::Utf32 { endianness } => arena .text("utf32") .append(f_endianness(endianness)) .into_doc(), } } impl<'a, B, V, L> FunctionFormatData<'a, B, V, L> where B: BlockIteratorConfig, V: ValueFormatter, L: BlockValueLayout, { pub fn block_op_to_doc( &mut self, config: &FormatConfig, state: &mut FormatState, block: Block, ) -> RefDoc<'a, ()> { let arena = self.arena; let op_opt = state.function.block_kind(block); if op_opt.is_none() { return arena.text("EMPTY_BLOCK").into_doc(); } let op = op_opt.unwrap(); let reads = state.function.block_reads(block); let op_doc = match op { OpKind::Match { branches } => { let dests = reads[0]; let num_dests = state.function.value_list_length(dests); let num_branches = branches.len(); let mut branches_formatted = Vec::with_capacity(num_branches); for (i, kind) in branches.iter().enumerate() { let block = state.function.value_list_get_n(dests, i).unwrap(); let block_val = self.value_use(config, state, block, None); let args_vl = reads[i + 2]; let num_args = state.function.value_list_length(args_vl); let mut args = Vec::with_capacity(num_args); for n in 0..num_args { args.push(state.function.value_list_get_n(args_vl, n).unwrap()); } let formatted = match kind { MatchKind::Value => { let val = self.value_use(config, state, args[0], None); let block_args = arena .intersperse( args.iter() .skip(1) .map(|v| self.value_use(config, state, *v, None)), arena.text(",").append(arena.softline()), ) .nest(1) .parens(); let body = arena.nil().append(block_val).append(block_args); arena .nil() .append(arena.text("value")) .append(arena.space()) .append(val) .append(arena.space()) .append(arena.text("=>")) .append(arena.space()) .append(arena.nil().append(body)) } MatchKind::Type(ty) => { let block_args = arena .intersperse( args.iter().map(|v| self.value_use(config, state, *v, None)), arena.text(",").append(arena.softline()), ) .nest(1) .parens(); let body = arena.nil().append(block_val).append(block_args); arena .nil() .append(arena.text("is_type")) .append(arena.space()) .append(arena.text(type_to_text(ty))) .append(arena.space()) .append(arena.text("=>")) .append(arena.space()) .append(arena.nil().append(body)) } MatchKind::Binary(ref spec) => { let doc = binary_specifier_to_doc(arena, spec); arena.nil().append(doc) } MatchKind::Tuple(arity) => { let block_args = arena .intersperse( args.iter().map(|v| self.value_use(config, state, *v, None)), arena.text(",").append(arena.softline()), ) .nest(1) .parens(); let body = arena.nil().append(block_val).append(block_args); arena .nil() .append(arena.text("{}")) .append(arena.space()) .append(arena.text(format!("arity {}", arity))) .append(arena.space()) .append(arena.text("=>")) .append(arena.space()) .append(arena.nil().append(body)) } MatchKind::ListCell => { let block_args = arena .intersperse( args.iter().map(|v| self.value_use(config, state, *v, None)), arena.text(",").append(arena.softline()), ) .nest(1) .parens(); let body = arena.nil().append(block_val).append(block_args); arena .nil() .append(arena.text("[]")) .append(arena.space()) .append(arena.text("=>")) .append(arena.space()) .append(arena.nil().append(body)) } MatchKind::MapItem => { let val = self.value_use(config, state, args[0], None); let block_args = arena .intersperse( args.iter() .skip(1) .map(|v| self.value_use(config, state, *v, None)), arena.text(",").append(arena.softline()), ) .nest(1) .parens(); let body = arena.nil().append(block_val).append(block_args); arena .nil() .append(val) .append(arena.space()) .append(arena.text("=>")) .append(arena.space()) .append(arena.nil().append(body)) } MatchKind::Wildcard => { let block_args = arena .intersperse( args.iter().map(|v| self.value_use(config, state, *v, None)), arena.text(",").append(arena.softline()), ) .nest(1) .parens(); let body = arena.nil().append(block_val).append(block_args); arena .nil() .append(arena.text("_")) .append(arena.space()) .append(arena.text("=>")) .append(arena.space()) .append(arena.nil().append(body)) } }; branches_formatted.push(formatted.indent(2)); } let selector = self.value_use(config, state, reads[1], None); arena .nil() .append(arena.text("match")) .append(arena.space()) .append(selector) .append(arena.space()) .append( arena .hardline() .append(arena.intersperse(branches_formatted, arena.hardline())) .append(arena.hardline()) .braces(), ) } OpKind::Call(CallKind::Function) => { let callee_val = self.value_use(config, state, reads[0], None); let call_args = arena .intersperse( reads .iter() .skip(3) .map(|v| self.value_use(config, state, *v, None)), arena.text(",").append(arena.softline()), ) .nest(1) .parens(); let flow_val = self.value_use(config, state, reads[1], None); let exc_val = self.value_use(config, state, reads[2], None); arena .nil() .append(callee_val) .append(call_args) .append(arena.space()) .append(arena.text("=>")) .append(arena.space()) .append(flow_val) .append(arena.space()) .append(arena.text("except")) .append(arena.space()) .append(exc_val) } OpKind::Call(CallKind::ControlFlow) => { let fun_val = self.value_use(config, state, reads[0], None); let call_args = arena .intersperse( reads .iter() .skip(1) .map(|v| self.value_use(config, state, *v, None)), arena.text(",").append(arena.softline()), ) .nest(1) .parens(); arena.nil().append(fun_val).append(call_args) } OpKind::TraceCaptureRaw => { assert!(reads.len() == 1); let arg = self.value_use(config, state, reads[0], None); arena .nil() .append(arena.text("trace_capture_raw")) .append(arena.space()) .append(arg) } OpKind::UnpackValueList(n) => { assert!(reads.len() == 2); let block = self.value_use(config, state, reads[0], None); let val = self.value_use(config, state, reads[1], None); arena .nil() .append(arena.text("unpack")) .append(arena.space()) .append(val) .append(arena.space()) .append(arena.text("arity")) .append(arena.space()) .append(arena.as_string(&format!("{}", n))) .append(arena.space()) .append(arena.text("=>")) .append(arena.space()) .append(block) } OpKind::IfBool => match reads.len() { 3 => arena .nil() .append(arena.text("if_bool")) .append(arena.space()) .append(self.value_use(config, state, reads[2], None)) .append(arena.space()) .append(self.value_use(config, state, reads[0], None)) .append(arena.space()) .append(self.value_use(config, state, reads[1], None)), 4 => arena .nil() .append(arena.text("if_bool")) .append(arena.space()) .append(self.value_use(config, state, reads[3], None)) .append(arena.space()) .append(self.value_use(config, state, reads[0], None)) .append(arena.space()) .append(self.value_use(config, state, reads[1], None)) .append(arena.space()) .append(self.value_use(config, state, reads[2], None)), _ => panic!(), }, OpKind::Unreachable => arena.text("unreachable"), OpKind::Dyn(op) => { if let Some(printer) = state.function.dialect().get_op_printer(&**op) { let mut ctx_impl = FormatOpCtxImpl { format_data: self, config, state, }; let doc = printer.to_doc(&mut ctx_impl, block); arena.nil().append(doc) } else { let call_args = arena .intersperse( reads .iter() .map(|v| self.value_use(config, state, *v, None)), arena.text(",").append(arena.softline()), ) .nest(1) .parens(); arena.as_string(op.name()).append(call_args) } } _ => { warn!("Unimplemented printer for OP: {:?}", op); arena.text("unknown") } }; op_doc.append(arena.text(";")).into_doc() } } fn type_to_text(ty: &BasicType) -> String { match ty { BasicType::List => "list".to_owned(), BasicType::ListCell => "cons".to_owned(), BasicType::Nil => "nil".to_owned(), BasicType::Tuple(arity) => format!("tuple({})", arity), BasicType::Map => "map".to_owned(), BasicType::Number => "number".to_owned(), BasicType::Float => "float".to_owned(), BasicType::Integer => "integer".to_owned(), BasicType::SmallInteger => "smallint".to_owned(), BasicType::BigInteger => "bigint".to_owned(), } } ================================================ FILE: libeir_ir/src/text/printer.old.rs ================================================ #![allow(clippy::write_with_newline)] use std::io::{ Write, Error as IoError }; use crate::{ Module, Function, FunctionIdent }; use crate::{ Block, Value }; use crate::{ OpKind, PrimOpKind, BinOp, MatchKind, BasicType, BinaryEntrySpecifier, Endianness, CallKind }; use crate::AtomTerm; use crate::ValueKind; use crate::pattern::{ PatternContainer, PatternNode, PatternNodeKind }; use cranelift_entity::EntityRef; use std::collections::{HashSet, VecDeque, BTreeSet}; // Desired syntax: // ``` // something { // // something:something/2@1.1 { // entry(%0, %1): // %2, %3 = call woo:hoo(%0) except l0(%3); // tombstone %3; // jump l1(%2); // // l0(%4): // tombstone %2; // return_error %4; // // l1(%5): // return_ok %5; // // l2(): // %6 = match_start on: %1, values: [%0] { // clause { // pattern [$0 = 0 | []]; // }; // }; // jump l3(); // l3(): // match_body %6 fail err() leaves [clause1()]; // // err(): // return_error a'nil'; // // clause1(): // %7 = case_calues [$0]; // case_guard_ok %7; // // } // // } // ``` pub trait EirAnnotator { fn annotate_function(&mut self, out: &mut String, fun: &Function); fn annotate_block(&mut self, out: &mut String, fun: &Function, block: Block); } //pub struct EirLiveValuesAnnotator { // live: Option, //} //impl EirLiveValuesAnnotator { // pub fn new() -> Self { // EirLiveValuesAnnotator { // live: None, // } // } //} //impl EirAnnotator for EirLiveValuesAnnotator { // fn annotate_function(&mut self, out: &mut String, fun: &Function) { // self.live = Some(fun.live_values()); // } // fn annotate_op(&mut self, out: &mut String, fun: &Function, op: Op) { // let live = self.live.as_ref().unwrap(); // if let Some(l) = live.flow_live.get(&op) { // out.push_str(" live:"); // println!("LVLEN: {:?}", live); // for var in l.iter(&live.pool) { // out.push_str(&format!(" %{}", var.index())); // } // } // } // fn annotate_ebb(&mut self, out: &mut String, fun: &Function, ebb: Ebb) { // let live = self.live.as_ref().unwrap(); // let l = &live.ebb_live[&ebb]; // out.push_str("yay!"); // } //} #[derive(Default)] pub struct ToEirTextContext { out_buf: String, annotators: Vec>, } impl ToEirTextContext { pub fn new() -> Self { Self::default() } pub fn add_annotator(&mut self, ann: T) where T: EirAnnotator + 'static { self.annotators.push(Box::new(ann)); } pub fn annotate_function(&mut self, fun: &Function) { for ann in self.annotators.iter_mut() { ann.annotate_function(&mut self.out_buf, fun); } } pub fn annotate_block(&mut self, fun: &Function, block: Block) -> Option { self.out_buf.clear(); for ann in self.annotators.iter_mut() { ann.annotate_block(&mut self.out_buf, fun, block); } if !self.out_buf.is_empty() { Some(self.out_buf.to_string()) } else { None } } } pub trait ToEirText { fn to_eir_text(&self, ctx: &mut ToEirTextContext, indent: usize, out: &mut dyn Write) -> std::io::Result<()>; } pub trait ToEirTextFun { fn to_eir_text_fun(&self, ctx: &mut ToEirTextContext, fun: &Function, indent: usize, out: &mut dyn Write) -> std::io::Result<()>; } fn write_indent(out: &mut dyn Write, indent: usize) -> std::io::Result<()> { for _ in 0..indent { write!(out, " ")?; } Ok(()) } impl ToEirText for FunctionIdent { fn to_eir_text(&self, _ctx: &mut ToEirTextContext, indent: usize, out: &mut dyn Write) -> std::io::Result<()> { write_indent(out, indent)?; write!(out, "{}:{}/{}", self.module, self.name, self.arity)?; Ok(()) } } pub fn print_constants(_ctx: &mut ToEirTextContext, _fun: &Function, _indent: usize, _out: &mut dyn Write) -> std::io::Result<()> { // TODO //let mut used_values = HashSet::new(); //fun.used_values(&mut used_values); //let mut values: Vec<_> = used_values.iter().cloned().collect(); //values.sort(); //for value in values.iter() { // let typ = fun.value(*value); // match typ { // ValueType::Constant(cons) => { // write_indent(out, indent)?; // write!(out, "%{} = ", value.index())?; // cons.to_eir_text(ctx, indent+1, out)?; // write!(out, ";\n")?; // }, // ValueType::Variable => (), // } //} Ok(()) } impl ToEirText for Module { fn to_eir_text(&self, ctx: &mut ToEirTextContext, indent: usize, out: &mut dyn Write) -> std::io::Result<()> { let funs: Vec<_> = self.index_iter().collect(); write_indent(out, indent)?; write!(out, "{} {{\n\n", AtomTerm(self.name().name))?; for idx in funs.iter() { let fun_def = &self[*idx]; let fun = fun_def.function(); fun.to_eir_text(ctx, indent+1, out)?; write!(out, "\n\n")?; } write_indent(out, indent)?; write!(out, "}}")?; Ok(()) } } impl ToEirText for Function { fn to_eir_text(&self, ctx: &mut ToEirTextContext, indent: usize, out: &mut dyn Write) -> std::io::Result<()> { ctx.annotate_function(self); let ident = self.ident(); write_indent(out, indent)?; write!(out, "{}/{} {{\n", AtomTerm(ident.name.name), ident.arity)?; // Constants print_constants(ctx, self, indent+1, out)?; write!(out, "\n")?; // Blocks let mut walked = BTreeSet::new(); let mut to_walk = VecDeque::new(); to_walk.push_back(self.block_entry()); while let Some(block) = to_walk.pop_front() { if walked.contains(&block) { continue; } walked.insert(block); self.block_walk_nested_values::<_, Result<(), ()>>(block, &mut |v| { if let Some(inner) = self.value_block(v) { to_walk.push_back(inner); } Ok(()) }).unwrap(); block.to_eir_text_fun(ctx, self, indent+1, out)?; write!(out, "\n")?; } write_indent(out, indent)?; write!(out, "}}")?; Ok(()) } } fn format_pattern(_ctx: &mut ToEirTextContext, pat: &PatternContainer, _indent: usize, annotated_nodes: &HashSet, node: PatternNode, out: &mut dyn Write) -> std::io::Result<()> { if annotated_nodes.contains(&node) { write!(out, "n{} @ ", node.index())?; } match pat.node_kind(node) { PatternNodeKind::Wildcard => write!(out, "_")?, _ => write!(out, "?")?, } Ok(()) } fn get_value_list<'a>(fun: &'a Function, value: Value) -> Option<&'a [Value]> { if let Some(prim) = fun.value_primop(value) { match fun.primop_kind(prim) { crate::PrimOpKind::ValueList => return Some(fun.primop_reads(prim)), _ => (), } } None } impl ToEirTextFun for Block { fn to_eir_text_fun(&self, ctx: &mut ToEirTextContext, fun: &Function, indent: usize, out: &mut dyn Write) -> std::io::Result<()> { write_indent(out, indent)?; write!(out, "{}(", self)?; format_value_list(fun.block_args(*self), fun, out)?; write!(out, "):\n")?; fun.block_walk_nested_values::<_, IoError>(*self, &mut |value| { match fun.value_kind(value) { ValueKind::PrimOp(prim) => { write_indent(out, indent+1)?; write!(out, "%{} = ", value.index())?; let reads = fun.primop_reads(prim); match fun.primop_kind(prim) { PrimOpKind::CaptureFunction => { assert!(reads.len() == 3); format_value(reads[0], fun, out)?; write!(out, ":")?; format_value(reads[1], fun, out)?; write!(out, "/")?; format_value(reads[2], fun, out)?; } PrimOpKind::ListCell => { assert!(reads.len() == 2); write!(out, "[")?; format_value(reads[0], fun, out)?; write!(out, " | ")?; format_value(reads[1], fun, out)?; write!(out, "]")?; } PrimOpKind::ValueList => { write!(out, "<")?; format_value_list(reads, fun, out)?; write!(out, ">")?; } PrimOpKind::BinOp(BinOp::Equal) => { assert!(reads.len() == 2); format_value(reads[0], fun, out)?; write!(out, " == ")?; format_value(reads[1], fun, out)?; } PrimOpKind::Tuple => { write!(out, "{{")?; for (i, value) in reads.iter().enumerate() { if i != 0 { write!(out, ", ")?; } format_value(*value, fun, out)?; } write!(out, "}}")?; } kind => { write!(out, "{:?}", kind)?; write!(out, "(")?; format_value_list(reads, fun, out)?; write!(out, ")")?; }, } write!(out, ";\n")?; } _ => (), } Ok(()) })?; let args = fun.block_reads(*self); if let Some(kind) = fun.block_kind(*self) { write_indent(out, indent+1)?; match kind { OpKind::Case { clauses } => { let clauses_num = clauses.len(&fun.pool.clause); let values_start = 1 + (clauses_num * 2); write!(out, "case ")?; format_value(args[values_start], fun, out)?; write!(out, " {{")?; write!(out, "\n")?; for clause_num in 0..clauses_num { let clause = clauses.get(0, &fun.pool.clause).unwrap(); let clause_nodes = fun.pat().clause_root_nodes(clause); let base = 1 + (2 * clause_num); let guard = args[base]; let body = args[base + 1]; let mut annotated_nodes = HashSet::new(); for bind in fun.pat().clause_binds(clause) { annotated_nodes.insert(*bind); } // Pattern body write_indent(out, indent + 2)?; write!(out, "(")?; if !clause_nodes.is_empty() { write!(out, "\n")?; } for node in clause_nodes { write_indent(out, indent + 3)?; format_pattern(ctx, fun.pat(), indent+3, &annotated_nodes, *node, out)?; write!(out, "\n")?; } if !clause_nodes.is_empty() { write_indent(out, indent + 2)?; } write!(out, ")")?; // Guard write!(out, " guard ")?; format_value(guard, fun, out)?; // Body write!(out, " => ")?; format_value(body, fun, out)?; write!(out, "(")?; let mut first = true; for bind in fun.pat().clause_binds(clause) { if !first { write!(out, ", ")?; } first = false; write!(out, "n{}", bind.index())?; } write!(out, ");")?; write!(out, "\n")?; } write_indent(out, indent + 2)?; write!(out, "_ => ")?; format_value(args[0], fun, out)?; write!(out, ";")?; write!(out, "\n")?; write_indent(out, indent + 1)?; write!(out, "}}")?; } OpKind::Match { branches } => { let targets_opt = get_value_list(fun, args[0]); let targets_one = &[args[0]]; let targets = targets_opt.unwrap_or(targets_one); write!(out, "match ")?; format_value(args[1], fun, out)?; write!(out, " {{\n")?; for ((kind, arg), target) in branches.iter() .zip(args[2..].iter()) .zip(targets.iter()) { write_indent(out, indent + 2)?; match kind { MatchKind::Value => { write!(out, "value ")?; format_value(*arg, fun, out)?; } MatchKind::ListCell => { write!(out, "[]")?; } MatchKind::Wildcard => { write!(out, "_")?; } MatchKind::Tuple(n) => { write!(out, "{{}} arity {}", n)?; } MatchKind::Type(BasicType::Map) => { write!(out, "type %{{}}")?; } MatchKind::Type(_) => { unimplemented!() } MatchKind::MapItem => { write!(out, "%{{ ")?; format_value(*arg, fun, out)?; write!(out, "}}")?; } MatchKind::Binary(spec) => { write!(out, "binary ")?; match spec { BinaryEntrySpecifier::Integer { signed, endianness, unit } => { if *signed { write!(out, "signed ")?; } else { write!(out, "unsigned ")?; } match *endianness { Endianness::Big => write!(out, "big ")?, Endianness::Little => write!(out, "little ")?, Endianness::Native => write!(out, "native ")?, } write!(out, "unit {} ", unit)?; write!(out, "size ")?; format_value(*arg, fun, out)?; } BinaryEntrySpecifier::Bytes { unit } => { write!(out, "unit {} ", unit)?; write!(out, "size ")?; format_value(*arg, fun, out)?; } _ => unimplemented!("{:?}", spec), } } } write!(out, " => ")?; format_value(*target, fun, out)?; write!(out, ";\n")?; } write_indent(out, indent + 1)?; write!(out, "}}")?; } OpKind::Call(CallKind::ControlFlow) => { format_value(args[0], fun, out)?; write!(out, "(")?; format_value_list(&args[1..], fun, out)?; write!(out, ")")?; } OpKind::Call(CallKind::Function) => { format_value(args[0], fun, out)?; write!(out, "(")?; format_value_list(&args[3..], fun, out)?; write!(out, ") => ")?; format_value(args[1], fun, out)?; write!(out, " except ")?; format_value(args[2], fun, out)?; } OpKind::Intrinsic(name) => { write!(out, "intrinsic {}(", name)?; format_value_list(args, fun, out)?; write!(out, ")")?; } OpKind::Unreachable => { write!(out, "unreachable")?; } OpKind::IfBool => { match args.len() { 3 => { write!(out, "if_bool ")?; format_value(args[2], fun, out)?; write!(out, " ")?; format_value(args[0], fun, out)?; write!(out, " ")?; format_value(args[1], fun, out)?; } 4 => { write!(out, "if_bool ")?; format_value(args[3], fun, out)?; write!(out, " ")?; format_value(args[0], fun, out)?; write!(out, " ")?; format_value(args[1], fun, out)?; write!(out, " ")?; format_value(args[2], fun, out)?; } _ => panic!(), } } OpKind::TraceCaptureRaw => { assert!(args.len() == 1); write!(out, "trace_capture_raw ")?; format_value(args[0], fun, out)?; } OpKind::UnpackValueList(n) => { assert!(args.len() == 2); write!(out, "unpack ")?; format_value(args[1], fun, out)?; write!(out, " arity {} => ", n)?; format_value(args[0], fun, out)?; } _ => { write!(out, "{:?}(", kind)?; format_value_list(args, fun, out)?; write!(out, ")")?; } } write!(out, ";")?; } Ok(()) } } fn format_value(value: Value, fun: &Function, out: &mut dyn Write) -> std::io::Result<()> { match fun.value_kind(value) { ValueKind::Block(block) => write!(out, "{}", block)?, ValueKind::Const(cons) => { fun.cons().write(cons, out); }, _ => write!(out, "%{}", value.index())?, } Ok(()) } fn format_value_list(values: &[Value], fun: &Function, out: &mut dyn Write) -> std::io::Result<()> { for (idx, value) in values.iter().enumerate() { if idx != 0 { write!(out, ", ")?; } format_value(*value, fun, out)?; } Ok(()) } ================================================ FILE: libeir_ir/src/traits/mod.rs ================================================ mod op_branches; pub use op_branches::OpBranches; mod printer; pub use printer::{FormatOpCtx, OpPrinter}; mod parser; pub use parser::OpParser; ================================================ FILE: libeir_ir/src/traits/op_branches.rs ================================================ use crate::{Block, Function, Value}; use meta_table::impl_cast_from; /// When an operation implements this trait, it has knowledge about some/all of /// its outgoing control flow branches. pub trait OpBranches { /// The number of branches this specific instance of the operation has. /// This may be dynamic, but needs to be solely decided by the operation /// itself. fn branches_len(&self) -> usize; /// Returns the target of `branch_n`. /// This may not be called with a `branch_n` >= `branch_len`. fn branch_num(&self, fun: &Function, block: Block, branch_n: usize) -> Value; } impl_cast_from!(OpBranches); ================================================ FILE: libeir_ir/src/traits/parser.rs ================================================ use crate::text::ast::DynToken; use crate::text::LowerContext; use crate::Block; pub trait OpParser: Send + Sync { fn parse( &self, context: &mut LowerContext, block: Block, tokens: &[DynToken], ) -> Result<(), ()>; } ================================================ FILE: libeir_ir/src/traits/printer.rs ================================================ use crate::{Block, DynValue}; use meta_table::impl_cast_from; use pretty::RefDoc; pub trait FormatOpCtx<'doc> { fn arena(&self) -> &'doc pretty::Arena<'doc>; fn value_use_to_doc(&mut self, value: DynValue) -> RefDoc<'doc, ()>; } pub trait OpPrinter { fn to_doc<'doc>(&self, ctx: &mut dyn FormatOpCtx<'doc>, block: Block) -> RefDoc<'doc, ()>; } impl_cast_from!(OpPrinter); ================================================ FILE: libeir_lowerutils/Cargo.toml ================================================ [package] name = "libeir_lowerutils" version = "0.1.0" authors = ["Hans Elias B. Josephsen "] edition = "2018" license = "MIT OR Apache-2.0" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] libeir_ir = { path = "../libeir_ir" } cranelift-entity = "0.56.0" petgraph = "0.4" ================================================ FILE: libeir_lowerutils/src/lib.rs ================================================ use std::collections::{BTreeMap, BTreeSet}; use libeir_ir::{Block, Function, Value}; use libeir_ir::{CallKind, OpKind}; use libeir_ir::{FunctionTree, LiveValues}; use petgraph::visit::IntoNeighbors; #[cfg(test)] mod tests; #[derive(Debug, Clone)] pub struct LowerData { /// The live value set is generated as part of the analysis. /// It is returned so this calculation doesn't need to happen several /// times. pub live: LiveValues, pub func_tree: FunctionTree, } enum Escape { Return, Throw, } pub fn analyze(fun: &Function) -> LowerData { let live = fun.live_values(); let func_tree = fun.func_tree(&live, true); LowerData { live, func_tree } } ================================================ FILE: libeir_lowerutils/src/tests.rs ================================================ use libeir_ir::parse_function_unwrap; #[test] fn simple_function() { let fun = parse_function_unwrap( " a'foo':a'bar'/1 { entry(%ret, %thr, %a): if_bool %a one two; one(): %ret(a'true'); two(): %ret(a'foo'); } ", ); let analyzed = super::analyze(&fun); dbg!(analyzed); } #[test] fn nested_functions() { let fun = parse_function_unwrap( " a'foo':a'bar'/1 { entry(%ret, %thr, %a): %ret(inner); inner(%iret, %ithr): %iret(%a); } ", ); let analyzed = super::analyze(&fun); dbg!(analyzed); } ================================================ FILE: libeir_passes/Cargo.toml ================================================ [package] name = "libeir_passes" version = "0.1.0" authors = ["Hans Elias B. Josephsen "] edition = "2018" license = "MIT OR Apache-2.0" [dependencies] matches = "0.1.8" cranelift-entity = "0.56.0" cranelift-bforest = { git = "https://github.com/hansihe/wasmtime.git", branch = "main" } petgraph = "0.4" bumpalo = { git = "https://github.com/hansihe/bumpalo", branch = "master", features = ["nightly"] } fnv = "1.0.3" log = "0.4" hashbrown = { git = "https://github.com/rust-lang/hashbrown.git", features = ["raw", "nightly"] } libeir_ir = { path = "../libeir_ir" } libeir_intern = { path = "../libeir_intern" } libeir_util_pattern_compiler = { path = "../util/libeir_util_pattern_compiler" } libeir_util_dot_graph = { path = "../util/libeir_util_dot_graph" } libeir_diagnostics = { path = "../libeir_diagnostics" } libeir_util_datastructures = { path = "../util/libeir_util_datastructures" } [dev-dependencies] env_logger = "0.7" ================================================ FILE: libeir_passes/src/compile_pattern/erlang_pattern_provider.rs ================================================ use cranelift_entity::{entity_impl, EntityList, ListPool, PrimaryMap}; use libeir_util_pattern_compiler::{ExpandedClauseNodes, PatternProvider}; use hashbrown::HashMap; use std::collections::BTreeMap; use libeir_ir::constant::Const; use libeir_ir::pattern::{ PatternClause, PatternContainer, PatternNode, PatternNodeKind, PatternValue, }; use libeir_ir::BinaryEntrySpecifier; use libeir_ir::{Function, PrimOp, Value, ValueKind}; use super::ValueBind; #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, PartialOrd, Ord)] pub enum ValueOrConst { Value(Value), Const(Const), PrimOp(PrimOp), Node(PatternNode), } impl ValueOrConst { fn from_value(val_bind: ValueBind, fun: &Function) -> Self { match val_bind { ValueBind::Value(val) => match fun.value_kind(val) { ValueKind::Const(cons) => ValueOrConst::Const(cons), ValueKind::Argument(_, _) => ValueOrConst::Value(val), ValueKind::PrimOp(prim) => ValueOrConst::PrimOp(prim), kind => panic!("{:?}", kind), }, ValueBind::Node(node) => ValueOrConst::Node(node), } } } #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] pub enum NodeKind { /// Matched on equality to value Value(ValueOrConst), /// Binary operations take an optional size value. /// When expanded, it expands to the value node, and the tail of the /// binary. Binary { specifier: BinaryEntrySpecifier, size: Option, has_tail: bool, }, /// Tuple is matched its length TupleSize(usize), /// A list cell is a singleton ListCell, /// Matches that the value is a map. /// If there are matches on items within the map, /// those are expanded to several MapItems. Map, /// A map is matched by an interned value. /// This matches only a single k=>v mapping in a map. MapItem(ValueOrConst), // Meta ValueList, Wildcard, } impl NodeKind { pub fn num_children(self) -> usize { match self { NodeKind::Value(_) => 0, NodeKind::TupleSize(num) => num, NodeKind::ListCell => 2, NodeKind::Map => panic!(), NodeKind::MapItem(_) => 1, NodeKind::ValueList => panic!(), NodeKind::Wildcard => 0, NodeKind::Binary { has_tail: true, .. } => 2, NodeKind::Binary { has_tail: false, .. } => 1, } } } #[derive(Debug, Clone)] pub struct NodeData { kind: NodeKind, children: EntityList, } #[derive(Debug, Clone)] pub struct ErlangPatternProvider<'a> { fun: Option<&'a Function>, nodes: PrimaryMap, vars: PrimaryMap, /// Root node for each clause root_nodes: Vec, /// Root variable in the match root_var: Var, wildcard: Node, node_pool: ListPool, node_map: BTreeMap, } #[derive(Copy, Clone, Eq, PartialEq, Hash, PartialOrd, Ord)] pub struct Node(u32); entity_impl!(Node, "node"); #[derive(Copy, Clone, Eq, PartialEq, Hash, PartialOrd, Ord)] pub struct Var(u32); entity_impl!(Var, "var"); impl<'a> ErlangPatternProvider<'a> { pub fn new() -> Self { let mut nodes = PrimaryMap::new(); let wildcard = nodes.push(NodeData { kind: NodeKind::Wildcard, children: EntityList::new(), }); let mut vars = PrimaryMap::new(); let root_var = vars.push(()); ErlangPatternProvider { fun: None, nodes, vars, root_nodes: Vec::new(), root_var, wildcard, node_pool: ListPool::new(), node_map: BTreeMap::new(), } } pub fn add_child(&mut self, node: Node, kind: NodeKind, pat_node: PatternNode) -> Node { let next = self.nodes.push(NodeData { kind, children: EntityList::new(), }); self.nodes[node].children.push(next, &mut self.node_pool); self.node_map.insert(pat_node, next); next } pub fn add_clause(&mut self) -> Node { let next = self.nodes.push(NodeData { kind: NodeKind::ValueList, children: EntityList::new(), }); self.root_nodes.push(next); next } fn wildcard(&self) -> Node { self.wildcard } pub fn pattern_node_to_cfg_node(&self, pat: PatternNode) -> Node { *self.node_map.get(&pat).unwrap() } } impl<'a> PatternProvider for ErlangPatternProvider<'a> { type PatternNodeKey = Node; type PatternNodeKind = NodeKind; type CfgVariable = Var; const WILDCARD: NodeKind = NodeKind::Wildcard; fn get_root(&self) -> ExpandedClauseNodes { ExpandedClauseNodes { variables: vec![self.root_var], clauses: self.root_nodes.len(), nodes: self.root_nodes.clone(), } } fn kind_includes(&self, kind: NodeKind, key: Node) -> bool { let node_kind = self.nodes[key].kind; if node_kind == kind { return true; } //match (kind, node_kind) { // (NodeKind::Value(l), NodeKind::Value(r)) => // if l // _ => false, //} false } fn get_kind(&self, key: Node) -> NodeKind { self.nodes[key].kind } fn get_wildcard_node(&self) -> Node { self.wildcard } fn expand_clause_nodes( &mut self, clause_nodes: Vec, kind: NodeKind, ) -> ExpandedClauseNodes { if clause_nodes.len() == 0 { return ExpandedClauseNodes { clauses: 0, variables: vec![], nodes: vec![], }; } for node in clause_nodes.iter() { let node_kind = self.nodes[*node].kind; assert!(node_kind == kind); } //let typ = &self.nodes[clause_nodes[0]]; //let kind = typ.kind; //let base_len = typ.children.len(&self.node_pool); //for node in &clause_nodes { // assert!(self.nodes[*node].kind == kind); //} match kind { NodeKind::ValueList => { let len = self.nodes[clause_nodes[0]].children.len(&self.node_pool); let mut exp = ExpandedClauseNodes { clauses: clause_nodes.len(), variables: { let vars = &mut self.vars; (0..len).map(|_| vars.push(())).collect() }, nodes: vec![], }; for node_id in clause_nodes { let node = &self.nodes[node_id]; let children = node.children.as_slice(&self.node_pool); assert!(children.len() == len); for child in children { exp.nodes.push(*child); } } exp } NodeKind::Map => { // Map is a special case in expansion. // We want to expand each value into a separate column. let mut values_map = HashMap::new(); for node in &clause_nodes { let sub = &self.nodes[*node]; for child_id in sub.children.as_slice(&self.node_pool) { let child = &self.nodes[*child_id]; if let NodeKind::MapItem(idx) = child.kind { let key = (*node, idx); if !values_map.contains_key(&key) { values_map.insert(key, Vec::new()); } values_map.get_mut(&key).unwrap().push(*child_id); } else { unreachable!(); } } } let mut values = BTreeMap::new(); for ((_node, key_value), val) in values_map.iter() { if let Some(max) = values.get_mut(key_value) { let n_max = val.len(); if n_max > *max { *max = n_max; } } else { values.insert(*key_value, val.len()); } } let value_map = self.vars.push(()); let mut exp = ExpandedClauseNodes { clauses: clause_nodes.len(), variables: values .values() .flat_map(|num| 0..*num) .map(|_| value_map) .collect(), nodes: vec![], }; for node in clause_nodes.iter() { for (value, num) in values.iter() { let vals = values_map.get(&(*node, *value)); for n in 0..*num { if let Some(child_id) = vals.and_then(|v| v.get(n)) { exp.nodes.push(*child_id); } else { exp.nodes.push(self.wildcard()); } } } } exp } _ => { let expected_children = kind.num_children(); let mut exp = ExpandedClauseNodes { clauses: clause_nodes.len(), variables: { let vars = &mut self.vars; (0..expected_children).map(|_| vars.push(())).collect() }, nodes: vec![], }; for node_id in clause_nodes { let node = &self.nodes[node_id]; println!("{:?}", node); let children = node.children.as_slice(&self.node_pool); assert_eq!(children.len(), expected_children); for child in children { exp.nodes.push(*child); } } exp } } } } fn pattern_node_to_provider( fun: &Function, pat: &PatternContainer, //node_map: &mut HashMap, value_map: &HashMap, provider: &mut ErlangPatternProvider, node: PatternNode, parent: Node, n: usize, ) -> Node { // Cheap and safe since we don't modify any patterns let kind = pat.node_kind(node).clone(); match &kind { PatternNodeKind::Wildcard => provider.add_child(parent, NodeKind::Wildcard, node), PatternNodeKind::Tuple(entries) => { let tuple = provider.add_child( parent, NodeKind::TupleSize(entries.len(&pat.node_pool)), node, ); for entry_num in 0..(entries.len(&pat.node_pool)) { let entry = entries.get(entry_num, &pat.node_pool).unwrap(); pattern_node_to_provider(fun, pat, value_map, provider, entry, tuple, n + 1); } tuple } PatternNodeKind::List { head, tail } => { let node = provider.add_child(parent, NodeKind::ListCell, node); pattern_node_to_provider(fun, pat, value_map, provider, *head, node, n + 1); pattern_node_to_provider(fun, pat, value_map, provider, *tail, node, n + 1); node } PatternNodeKind::Map { keys, values } => { let map_parent = provider.add_child(parent, NodeKind::Map, node); let len = keys.len(&pat.value_pool); assert!(values.len(&pat.node_pool) == len); let mut dedup = HashMap::new(); for n in 0..len { let key = keys.get(n, &pat.value_pool).unwrap(); let key_val_or_const = ValueOrConst::from_value(value_map[&key], fun); let val = values.get(n, &pat.node_pool).unwrap(); if !dedup.contains_key(&key_val_or_const) { dedup.insert(key_val_or_const, Vec::new()); } dedup.get_mut(&key_val_or_const).unwrap().push(val); } // TODO: Currently we just give up here and put duplicate // values in separate columns. We most likely want to take // care of merging these in a separate stage within pattern // match compilation. for (key, values) in dedup.iter() { for value in values { let entry_parent = provider.add_child(map_parent, NodeKind::MapItem(*key), node); pattern_node_to_provider( fun, pat, value_map, provider, *value, entry_parent, n + 1, ); } } map_parent } PatternNodeKind::Const(cons) => { let val = ValueOrConst::Const(*cons); provider.add_child(parent, NodeKind::Value(val), node) } PatternNodeKind::Value(pat_val) => { let val = value_map[&pat_val]; let val_or_const = ValueOrConst::from_value(val, fun); provider.add_child(parent, NodeKind::Value(val_or_const), node) } PatternNodeKind::Binary { specifier, value, size, remaining, } => { let size_val = size.map(|v| ValueOrConst::from_value(value_map[&v], fun)); let binary_entry = provider.add_child( parent, NodeKind::Binary { specifier: *specifier, size: size_val, has_tail: remaining.is_some(), }, node, ); pattern_node_to_provider(fun, pat, value_map, provider, *value, binary_entry, n + 1); if let Some(remaining) = *remaining { pattern_node_to_provider( fun, pat, value_map, provider, remaining, binary_entry, n + 1, ); } binary_entry } } } pub(super) fn pattern_to_provider<'a>( fun: &Function, pat: &PatternContainer, clauses: &[PatternClause], //node_map: &mut HashMap, value_map: &HashMap, ) -> ErlangPatternProvider<'a> { let mut provider = ErlangPatternProvider::new(); let mut roots = Vec::new(); for clause in clauses { let node = provider.add_clause(); roots.push(node); for value_num in 0..pat.clause_root_nodes(*clause).len() { let value = pat.clause_root_nodes(*clause)[value_num]; pattern_node_to_provider(fun, pat, value_map, &mut provider, value, node, 0); } } provider } ================================================ FILE: libeir_passes/src/compile_pattern/lower_cfg.rs ================================================ use bumpalo::Bump; use libeir_ir::pattern::{PatternClause, PatternContainer, PatternNode}; use libeir_ir::FunctionBuilder; use libeir_ir::{BasicType, Block, Value}; use libeir_util_pattern_compiler::{CfgNodeKind, EdgeRef, NodeIndex, PatternCfg}; use libeir_diagnostics::SourceSpan; use super::erlang_pattern_provider::{ErlangPatternProvider, NodeKind, ValueOrConst, Var}; use super::BFnvHashMap; pub struct DecisionTreeDestinations<'bump> { pub fail: Value, pub guards: Vec, pub bodies: Vec, } struct LowerCtx<'a, 'b, 'bump> { provider: &'a ErlangPatternProvider<'b>, destinations: &'a DecisionTreeDestinations<'bump>, mapping: BFnvHashMap<'bump, Var, Value>, } impl<'a, 'b, 'bump> LowerCtx<'a, 'b, 'bump> { fn node_to_value( &self, node: PatternNode, idx: NodeIndex, cfg: &PatternCfg, ) -> Value { // PatternNode => PatternCfg Node let prov_node = self.provider.pattern_node_to_cfg_node(node); // PatternCfg Node => PatternCfg Var let prov_var = cfg.leaf_bindings[&idx][&prov_node]; // PatternCfg Var => Value self.mapping[&prov_var] } fn value_or_const_to_value( &self, bind: ValueOrConst, idx: NodeIndex, b: &mut FunctionBuilder, cfg: &PatternCfg, ) -> Value { match bind { ValueOrConst::Value(val) => val, ValueOrConst::Const(cons) => b.value(cons), ValueOrConst::PrimOp(prim) => b.value(prim), ValueOrConst::Node(node) => self.node_to_value(node, idx, cfg), } } fn get_var_value(&self, var: Var) -> Value { self.mapping[&var] } fn bind(&mut self, var: Var, val: Value) { self.mapping.insert(var, val); } } pub fn lower_cfg( bump: &Bump, b: &mut FunctionBuilder, pat: &PatternContainer, provider: &ErlangPatternProvider, cfg: &PatternCfg, clauses: &[PatternClause], destinations: &DecisionTreeDestinations, ) -> Block { assert!(destinations.guards.len() == destinations.bodies.len()); let entry_kind = &cfg.graph[cfg.entry]; assert!(*entry_kind == CfgNodeKind::Root); let mut ctx = LowerCtx { provider, mapping: BFnvHashMap::with_hasher_in(Default::default(), &bump), destinations, }; let entry_block = b.block_insert(); let entry_arg = b.block_arg_insert(entry_block); let mut block = entry_block; // First node is a dummy root node let value_list_node = { let mut edges = cfg.graph.edges(cfg.entry); let edge = edges.next().unwrap(); assert!(edges.next().is_none()); let edge_weight = edge.weight(); assert!(edge_weight.kind == Some(NodeKind::Wildcard)); assert!(edge_weight.variable_binds.len() == 1); ctx.bind(edge_weight.variable_binds[0], entry_arg); edge.target() }; let outgoing: Vec<_> = cfg.graph.edges(value_list_node).collect(); if outgoing.len() == 2 { // This will always be a ValueList and a Wildcard let val_list_target = outgoing .iter() .find(|o| o.weight().kind == Some(NodeKind::ValueList)) .unwrap(); assert!(outgoing .iter() .find(|o| o.weight().kind == Some(NodeKind::Wildcard)) .is_some()); if let CfgNodeKind::Match(var) = cfg.graph[value_list_node] { let var_list_len = val_list_target.weight().variable_binds.len(); block = b.op_unpack_value_list(block, ctx.get_var_value(var), var_list_len); } else { unreachable!() } // Insert variable binds for all value list elements for (idx, var) in val_list_target.weight().variable_binds.iter().enumerate() { let val = b.fun().block_args(block)[idx]; ctx.bind(*var, val); } lower_cfg_rec( bump, b, pat, &mut ctx, cfg, clauses, block, val_list_target.target(), ); } else if outgoing.len() == 0 { // Fail immediately b.op_call_flow(block, destinations.fail, &[]); } else { unreachable!(); } entry_block } fn lower_cfg_rec( bump: &Bump, b: &mut FunctionBuilder, pat: &PatternContainer, ctx: &mut LowerCtx, cfg: &PatternCfg, clauses: &[PatternClause], block: Block, node: NodeIndex, ) { let block_value = b.fun().block_value(block); let block_span = b .fun() .value_locations(block_value) .map(|spans| spans.first().copied().unwrap_or(SourceSpan::UNKNOWN)) .unwrap_or(SourceSpan::UNKNOWN); match cfg.graph[node] { CfgNodeKind::Root => unreachable!(), CfgNodeKind::Match(var) => { let match_val = ctx.get_var_value(var); let span = b .fun() .value_locations(match_val) .map(|spans| spans.first().copied().unwrap_or(SourceSpan::UNKNOWN)) .unwrap_or(SourceSpan::UNKNOWN); let mut wildcard_node = None; let mut match_builder = b.op_match_build(span); for outgoing in cfg.graph.edges(node) { let weight = outgoing.weight(); let kind = weight.kind.unwrap(); match kind { NodeKind::Wildcard => { assert!(wildcard_node.is_none()); wildcard_node = Some(outgoing); } NodeKind::Binary { specifier, size, has_tail } => { if has_tail { assert!(weight.variable_binds.len() == 2); } else { assert!(weight.variable_binds.len() == 1); } let size = size.map(|v| ctx.value_or_const_to_value(v, outgoing.target(), b, cfg)); let mut ok = match_builder.push_binary(specifier, size, b); let args = b.block_args(ok); assert!(args.len() == 2); let arg0 = args[0]; let arg1 = args[1]; ctx.bind(weight.variable_binds[0], arg0); if has_tail { ctx.bind(weight.variable_binds[1], arg1); } else { let mut inner_builder = b.op_match_build(span); let empty_binary = b.value(Vec::::new()); let next = inner_builder.push_value(empty_binary, b); inner_builder.finish(ok, arg1, b); ok = next; } lower_cfg_rec(bump, b, pat, ctx, cfg, clauses, ok, outgoing.target()); } NodeKind::TupleSize(size) => { assert!(size == weight.variable_binds.len()); let ok = match_builder.push_tuple(size, b); { let args = b.block_args(ok); assert!(args.len() == size); for (var, val) in weight.variable_binds.iter().zip(args.iter()) { ctx.bind(*var, *val); } } // Ok lower_cfg_rec(bump, b, pat, ctx, cfg, clauses, ok, outgoing.target()); } NodeKind::ListCell => { assert!(weight.variable_binds.len() == 2); let ok = match_builder.push_list_cell(b); { let args = b.block_args(ok); assert!(args.len() == 2); ctx.bind(weight.variable_binds[0], args[0]); ctx.bind(weight.variable_binds[1], args[1]); } // Ok lower_cfg_rec(bump, b, pat, ctx, cfg, clauses, ok, outgoing.target()); } NodeKind::Map => { let ok = match_builder.push_type(BasicType::Map, b); for bind in weight.variable_binds.iter() { ctx.bind(*bind, match_val); } lower_cfg_rec(bump, b, pat, ctx, cfg, clauses, ok, outgoing.target()); } NodeKind::MapItem(val_or_const) => { assert!(weight.variable_binds.len() == 1); let val = ctx.value_or_const_to_value(val_or_const, node, b, cfg); let ok = match_builder.push_map_item(val, b); let ok_arg = b.block_args(ok)[0]; ctx.bind(weight.variable_binds[0], ok_arg); lower_cfg_rec(bump, b, pat, ctx, cfg, clauses, ok, outgoing.target()); } NodeKind::Value(val_or_const) => { let val = ctx.value_or_const_to_value(val_or_const, node, b, cfg); let ok = match_builder.push_value(val, b); lower_cfg_rec(bump, b, pat, ctx, cfg, clauses, ok, outgoing.target()); } _ => unimplemented!("{:?}", kind), } } let wildcard_edge = wildcard_node.unwrap(); assert!(wildcard_edge.weight().variable_binds.len() == 0); let wildcard_block = match_builder.push_wildcard(span, b); lower_cfg_rec( bump, b, pat, ctx, cfg, clauses, wildcard_block, wildcard_edge.target(), ); match_builder.finish(block, match_val, b); } CfgNodeKind::Fail => { b.op_call_flow(block, ctx.destinations.fail, &[]); } CfgNodeKind::Leaf(leaf_num) => { let clause = clauses[leaf_num]; let mut args = vec![]; let num_binds = pat.clause_binds(clause).len(); for bind_num in 0..num_binds { let bind_node = pat.clause_binds(clause)[bind_num]; let val = ctx.node_to_value(bind_node, node, cfg); args.push(val); } // Call to guard lambda let (ok_block, thr_block) = b.op_call_function(block_span, block, ctx.destinations.guards[leaf_num], &args); let ok_ret = b.block_args(ok_block)[0]; // Throw is unreachable b.op_unreachable(block_span, thr_block); // Conditional on return let (true_block, false_block, non_block) = b.op_if_bool(block_span, ok_block, ok_ret); b.op_unreachable(block_span, non_block); // If guard succeeds, we enter the body b.op_call_flow(true_block, ctx.destinations.bodies[leaf_num], &args); // If guard fails, continue in CFG { let mut edges = cfg.graph.edges(node); let edge = edges.next().unwrap(); assert!(edges.next().is_none()); lower_cfg_rec(bump, b, pat, ctx, cfg, clauses, false_block, edge.target()); } } } } ================================================ FILE: libeir_passes/src/compile_pattern/mod.rs ================================================ use bumpalo::Bump; use hashbrown::HashMap; use fnv::FnvBuildHasher; type BFnvHashMap<'bump, K, V> = HashMap; use libeir_ir::operation::case::Case; use libeir_ir::FunctionBuilder; use libeir_ir::PatternNode; use libeir_ir::Value; use libeir_util_pattern_compiler::to_decision_tree; mod erlang_pattern_provider; use self::erlang_pattern_provider::pattern_to_provider; mod lower_cfg; use self::lower_cfg::lower_cfg; use self::lower_cfg::DecisionTreeDestinations; use super::FunctionPass; #[cfg(test)] mod tests; pub struct CompilePatternPass { bump: Option, } impl CompilePatternPass { pub fn new() -> Self { CompilePatternPass { bump: Some(Bump::new()), } } } impl FunctionPass for CompilePatternPass { fn name(&self) -> &str { "compile_pattern" } fn run_function_pass(&mut self, b: &mut FunctionBuilder) { self.compile_pattern(b); } } impl CompilePatternPass { pub fn compile_pattern(&mut self, b: &mut FunctionBuilder) { let mut bump = self.bump.take().unwrap(); { // Find all pattern matching constructs let case_blocks = { let fun = b.fun(); let mut case_blocks = Vec::new_in(&bump); let graph = fun.block_graph(); for block in graph.dfs_iter() { if fun.block_kind(block).unwrap().get_dyn::().is_some() { case_blocks.push(block); } } case_blocks }; for block in case_blocks.iter().cloned() { let no_match; let mut guards = Vec::new_in(&bump); let mut bodies = Vec::new_in(&bump); let match_val; let mut values = Vec::new_in(&bump); //let mut clauses = Vec::new_in(&bump); let case = b .fun() .block_kind(block) .unwrap() .get_dyn::() .unwrap(); let num_clauses = case.clauses().len(); // Extract arguments from block reads { let reads = b.fun().block_reads(block); let mut r_iter = reads.iter(); // First entry is always no_match no_match = *r_iter.next().unwrap(); // Guards and bodies for _ in 0..num_clauses { guards.push(*r_iter.next().unwrap()); bodies.push(*r_iter.next().unwrap()); } // Match value match_val = *r_iter.next().unwrap(); // Values while let Some(val) = r_iter.next() { values.push(*val); } } let op = b.block_clear_take(block).unwrap(); let case = op.get_dyn::().unwrap(); let destinations = DecisionTreeDestinations { fail: no_match, guards, bodies, }; // Get/validate number of roots let mut roots_num = None; for clause in case.clauses().iter() { let num = case.pat().clause_root_nodes(*clause).len(); if let Some(num_old) = roots_num { assert!(num == num_old); } else { roots_num = Some(num); } } let mut value_map = HashMap::new(); { // Create map of PatternValue => Value let mut value_idx = 0; for clause in case.clauses().iter() { for value in case.pat().clause_values(*clause) { value_map.insert(*value, ValueBind::Value(values[value_idx])); value_idx += 1; } } assert!(values.len() == value_idx); // Create map of PatternValue => PatternNode value_map.extend( case.clauses() .iter() .flat_map(|clause| case.pat().clause_node_binds_iter(*clause)) .map(|(k, v)| (k, ValueBind::Node(v))), ); } let mut provider = pattern_to_provider(b.fun(), case.pat(), case.clauses(), &value_map); let decision_tree = to_decision_tree(&mut provider); let mut out = Vec::new(); decision_tree.to_dot(&mut out).unwrap(); let cfg_entry = lower_cfg( &bump, b, case.pat(), &provider, &decision_tree, case.clauses(), &destinations, ); b.block_clear(block); b.op_call_flow(block, cfg_entry, &[match_val]); } } bump.reset(); self.bump = Some(bump); } } #[derive(Debug, Copy, Clone)] pub(super) enum ValueBind { Value(Value), Node(PatternNode), } ================================================ FILE: libeir_passes/src/compile_pattern/tests.rs ================================================ ================================================ FILE: libeir_passes/src/dummy_location.rs ================================================ ================================================ FILE: libeir_passes/src/lib.rs ================================================ #![deny(warnings)] #![feature(allocator_api)] use log::{info, trace}; use libeir_ir::{FunctionBuilder, Module}; pub mod util; mod compile_pattern; pub use self::compile_pattern::CompilePatternPass; mod naive_inline_closures; pub use self::naive_inline_closures::NaiveInlineClosuresPass; mod simplify_cfg; pub use self::simplify_cfg::SimplifyCfgPass; mod validate; pub use self::validate::ValidatePass; pub trait FunctionPass { fn name(&self) -> &str; fn run_function_pass(&mut self, b: &mut FunctionBuilder); } enum PassType { Function(Box), } pub struct PassManager { passes: Vec, } impl PassManager { pub fn new() -> Self { PassManager { passes: Vec::new() } } pub fn push_function_pass

(&mut self, pass: P) where P: FunctionPass + 'static, { self.passes.push(PassType::Function(Box::new(pass))); } pub fn run(&mut self, module: &mut Module) { for fun_def in module.function_iter_mut() { let fun = fun_def.function_mut(); let ident = *fun.ident(); let mut b = FunctionBuilder::new(fun); b.fun().graph_validate_global(); trace!("{}", b.fun().to_text_standard()); for pass in self.passes.iter_mut() { match pass { PassType::Function(fun_pass) => { info!("======== {} FUNCTION_PASS: {}", ident, fun_pass.name()); fun_pass.run_function_pass(&mut b); trace!("{}", b.fun().to_text_standard()); } } b.fun().graph_validate_global(); } } } } impl Default for PassManager { fn default() -> Self { let mut man = PassManager::new(); //man.push_function_pass(SimplifyCfgPass::new()); man.push_function_pass(ValidatePass::new()); man.push_function_pass(CompilePatternPass::new()); man.push_function_pass(ValidatePass::new()); man.push_function_pass(NaiveInlineClosuresPass::new()); man.push_function_pass(ValidatePass::new()); man.push_function_pass(SimplifyCfgPass::new()); man.push_function_pass(ValidatePass::new()); man.push_function_pass(NaiveInlineClosuresPass::new()); man.push_function_pass(ValidatePass::new()); man } } ================================================ FILE: libeir_passes/src/naive_inline_closures/mod.rs ================================================ use std::collections::BTreeSet; use libeir_ir::FunctionBuilder; use libeir_ir::{Block, OpKind}; use libeir_ir::{MangleTo, Mangler}; use super::FunctionPass; #[cfg(test)] mod tests; /// Very basic closure inlining pass. pub struct NaiveInlineClosuresPass { calls_buf: Vec<(Block, Block)>, mangler: Mangler, } impl NaiveInlineClosuresPass { pub fn new() -> Self { NaiveInlineClosuresPass { calls_buf: Vec::new(), mangler: Mangler::new(), } } } impl FunctionPass for NaiveInlineClosuresPass { fn name(&self) -> &str { "naive_inline_closures" } fn run_function_pass(&mut self, b: &mut FunctionBuilder) { self.inline_closures(b); } } impl NaiveInlineClosuresPass { pub fn inline_closures(&mut self, b: &mut FunctionBuilder) { self.calls_buf.clear(); let live_block_graph = b.fun().live_block_graph(); let sccs = petgraph::algo::kosaraju_scc(&live_block_graph); let mut in_big_scc = BTreeSet::new(); for scc in sccs.iter() { if scc.len() > 1 { for node in scc.iter() { in_big_scc.insert(*node); } } } for block in b.fun().block_graph().dfs_post_order_iter() { // We perform inlining if the block satisfies the following // conditions: // 1. The block is a call operation // 2. The target of the call operation is another block // 3. There is at least one block argument to the block // 4. The target block does not form a cycle to itself in the block graph // OP must be Call if let OpKind::Call(_) = b.fun().block_kind(block).unwrap() { let reads = b.fun().block_reads(block); // Call target must be block let target = match b.fun().value_block(reads[0]) { Some(t) => t, None => continue, }; // Arguments must contain block let contains_block = reads[1..].iter().any(|a| b.fun().value_block(*a).is_some()); if !contains_block { continue; } // Check if the target block is in a SCC with other nodes than // just itself. If this is the case, then it might call itself, // and we can't do inlining naively. // TODO: This might have false positives? if in_big_scc.contains(&target) { continue; } self.calls_buf.push((block, target)); } } for (block, target) in self.calls_buf.iter().cloned() { // Signature of new entry block has no arguments let new_target = b.block_insert(); b.block_copy_body_map(target, new_target, |v| Some(v)); self.mangler.start(MangleTo(new_target)); // Add renames to current call arguments { let source_args = &b.fun().block_reads(block)[1..]; let target_args = b.fun().block_args(target); assert!(source_args.len() == target_args.len()); for (from, to) in target_args.iter().zip(source_args.iter()) { self.mangler .add_rename_nofollow(MangleTo(*from), MangleTo(*to)); } } // Run mangling on the scope let new_block = self.mangler.run(b); // Clear the current block and insert a call to the new block b.block_clear(block); b.op_call_flow(block, new_block, &[]); } } } ================================================ FILE: libeir_passes/src/naive_inline_closures/tests.rs ================================================ use libeir_ir::{parse_function_unwrap, StandardFormatConfig}; use crate::FunctionPass; #[test] fn inline_basic_function() { let mut fun = parse_function_unwrap( " a'foo':a'fun_shadowing'/1 { entry(%ret, %thr, %A): b1(); b1(): inner(ret, thr, %A); inner(%iret, %ithr, %B): %iret(%B); ret(%rv): %ret(%rv); thr(%rt1, %rt2, %rt3): %thr(%rt1, %rt2, %rt3); } ", ); let mut b = fun.builder(); let mut pass = super::NaiveInlineClosuresPass::new(); pass.run_function_pass(&mut b); let after = parse_function_unwrap( " a'foo':a'fun_shadowing'/1 { entry(%ret, %thr, %A): b1(); b1(): b2(); b2(): ret(%A); ret(%rv): %ret(%rv); } ", ); assert!(b .fun() .graph_eq(b.fun().block_entry(), &after, after.block_entry()) .is_ok()); } #[test] fn inline_nested_functions() { let mut fun = parse_function_unwrap( " a'foo':a'fun_shadowing'/1 { entry(%ret, %thr, %A): b1(); b1(): ainner(ret, thr, %A); ainner(%iret, %ithr, %B): anext(); anext(): binner(aret, athr, %B); aret(%aretv): %iret(%aretv); athr(%athr1, %athr2, %athr3): %ithr(%athr1, %athr2, %athr3); binner(%bret, %bthr, %C): bnext(); bnext(): %bret(%C); ret(%rv): %ret(%rv); thr(%rt1, %rt2, %rt3): %thr(%rt1, %rt2, %rt3); } ", ); let mut b = fun.builder(); let mut pass = super::NaiveInlineClosuresPass::new(); pass.run_function_pass(&mut b); println!("{}", b.fun().to_text(&mut StandardFormatConfig::default())); let after = parse_function_unwrap( " a'foo':a'fun_shadowing'/1 { entry(%ret, %thr, %A): b1(); b1(): b2(); b2(): b3(); b3(): b4(); b4(): b5(); b5(): ret1(%A); ret1(%B): ret(%B); ret(%rv): %ret(%rv); } ", ); assert!(b .fun() .graph_eq(b.fun().block_entry(), &after, after.block_entry()) .is_ok()); } ================================================ FILE: libeir_passes/src/simplify_cfg/analyze/call.rs ================================================ use libeir_ir::Block; use super::AnalysisContext; pub(super) fn propagate(ctx: &mut AnalysisContext, block: Block) -> bool { let reads = ctx.fun.block_reads(block); let target = ctx.follow(reads[0]); ctx.set_branch(target); if let Some(target_block) = ctx.fun.value_block(target) { for ((idx, read), _arg) in reads .iter() .skip(1) .enumerate() .zip(ctx.fun.block_args(target_block)) { ctx.add_rename(target_block, *read, idx); } true } else { false } } ================================================ FILE: libeir_passes/src/simplify_cfg/analyze/if_bool.rs ================================================ use libeir_ir::Block; use super::AnalysisContext; pub(super) fn propagate(ctx: &mut AnalysisContext, block: Block) -> bool { let reads = ctx.fun.block_reads(block); let val = match reads.len() { 3 => reads[2], 4 => reads[3], _ => panic!(), }; let val = ctx.follow(val); if let Some(cons) = ctx.fun.value_const(val) { let branch = match ctx.fun.cons().as_bool(cons) { Some(true) => 0, Some(false) => 1, None => { if reads.len() == 3 { panic!("IfBool without fallback branch on non-bool value") } else { 2 } } }; let target = reads[branch]; ctx.set_branch(target); true } else { false } } ================================================ FILE: libeir_passes/src/simplify_cfg/analyze/mod.rs ================================================ use std::collections::{BTreeMap, BTreeSet, VecDeque}; use bumpalo::Bump; use libeir_util_datastructures::pooled_entity_set::{EntitySet, EntitySetPool}; use super::BFnvHashMap; use libeir_ir::{Block, CallKind, OpKind, Value, ValueKind}; use libeir_ir::{Function, LiveBlockGraph, LiveValues}; use log::trace; use super::chain_graph::{Chain, Node}; mod call; mod if_bool; mod unpack_value_list; type BlockEdge = (Block, Block); #[derive(Debug)] pub struct GraphAnalysis<'bump> { pub entry: Block, pub static_branches: BFnvHashMap<'bump, Block, Value>, pub static_branches_blocks: BFnvHashMap<'bump, Block, Block>, pub trees: BFnvHashMap<'bump, Block, TreeData<'bump>>, pub phis: BFnvHashMap<'bump, Value, CondValue<'bump>>, pub static_renames: BFnvHashMap<'bump, Value, Value>, } #[derive(Debug)] pub struct TreeData<'bump> { pub entry_edges: BFnvHashMap<'bump, Block, ()>, pub edges: BFnvHashMap<'bump, BlockEdge, ()>, pub blocks: BFnvHashMap<'bump, Block, ()>, pub entry_values: BFnvHashMap<'bump, Value, (Block, usize)>, } impl<'bump> GraphAnalysis<'bump> { fn is_before(&self, lhs: Block, rhs: Block) -> bool { let mut curr = lhs; loop { if let Some(prev) = self.static_branches_blocks.get(&curr) { curr = *prev; } else { return false; } if curr == rhs { return true; } } } fn is_value_relevant(&self, tree_target: Block, value: Value) -> bool { if let Some(cond) = self.phis.get(&value) { let tree = &self.trees[&tree_target]; // Check if it's instead relevant to another tree if !tree.blocks.contains_key(&cond.block) && cond.block != tree_target { false } else { true } } else { false } } } #[derive(Debug)] pub struct ChainAnalysis<'bump> { pub target: Block, pub blocks: BFnvHashMap<'bump, Block, ()>, pub edges: BFnvHashMap<'bump, BlockEdge, ()>, pub entry_edges: BFnvHashMap<'bump, Block, ()>, //pub orig_args: BTreeSet, pub args: BFnvHashMap<'bump, Value, ()>, pub cond_map: BFnvHashMap<'bump, Value, CondValue<'bump>>, pub static_map: BFnvHashMap<'bump, Value, Value>, pub renames_required: bool, } #[derive(Debug)] pub struct CondValue<'bump> { pub value: Value, pub value_index: usize, pub block: Block, pub sources: BFnvHashMap<'bump, Block, PhiSource>, } #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] pub struct PhiSource { /// The value on the other side of the phi. /// If this is None, then this is an anonymous entry edge. value: Option, /// The block calling the phi. /// If this is None, then this is an anonymous entry edge. caller: Option, /// The block that is called as the entry edge. /// This MUST be part of the chain. called: Block, /// The index of the argment on the called block. arg_index: usize, /// The argument value itself. arg: Value, } #[derive(Debug)] pub struct EntryEdgeAnalysis<'bump> { //pub caller: Block, pub callee: Block, // The mappings that are specific for this entry edge. // Should not be inserted into the global map, the args should be // `map_value`d through this map. pub mappings: BFnvHashMap<'bump, Value, PhiSource>, // The arguments that should be used when calling the target block. // These need to be called with `map_value` in case the value is a primop. pub args: Vec, //pub looping_vars: BTreeSet, } struct AnalysisContext<'bump, 'a> { bump: &'bump Bump, pub fun: &'a Function, pub graph: &'a LiveBlockGraph<'a>, current: Option, static_renames: &'a mut BFnvHashMap<'bump, Value, Value>, static_branches: &'a mut BFnvHashMap<'bump, Block, Value>, phis: &'a mut BFnvHashMap<'bump, Value, CondValue<'bump>>, } impl<'bump, 'a> AnalysisContext<'bump, 'a> { fn init_block(&mut self, block: Block) { self.current = Some(block); } /// Follows the provided value according to the current static mappings pub fn follow(&self, mut val: Value) -> Value { while let Some(next) = self.static_renames.get(&val) { val = *next; } val } /// The current block statically branches to the target value pub fn set_branch(&mut self, target: Value) { self.static_branches.insert(self.current.unwrap(), target); } pub fn add_rename(&mut self, callee: Block, caller_read: Value, callee_arg_num: usize) { let caller = self.current.unwrap(); let callee_arg = self.fun.block_args(callee)[callee_arg_num]; #[cfg(debug)] { if let Some(p) = self.static_branches.get(caller) { assert!(self.fun.value_block(*p) == Some(callee)); } else { panic!(); } } let incoming_count = self.graph.incoming(callee).count(); let incoming = self.graph.incoming(callee).next(); assert!(incoming_count > 0); if incoming_count == 1 && incoming.unwrap() == caller { self.static_renames.insert(callee_arg, caller_read); } if !self.phis.contains_key(&callee_arg) { let cond = CondValue { block: callee, value: callee_arg, value_index: callee_arg_num, sources: BFnvHashMap::with_hasher_in(Default::default(), self.bump), }; self.phis.insert(callee_arg, cond); } let phi_source = PhiSource { value: Some(caller_read), caller: Some(caller), called: callee, arg_index: callee_arg_num, arg: callee_arg, }; self.phis .get_mut(&callee_arg) .unwrap() .sources .insert(caller, phi_source); } } pub fn analyze_graph<'bump, 'fun>( bump: &'bump Bump, fun: &'fun Function, graph: &'fun LiveBlockGraph, ) -> GraphAnalysis<'bump> { let entry = fun.block_entry(); let mut static_branches = BFnvHashMap::with_hasher_in(Default::default(), bump); let mut phis = BFnvHashMap::with_hasher_in(Default::default(), bump); let mut static_renames = BFnvHashMap::with_hasher_in(Default::default(), bump); // Find all blocks we care about, these are the ones we iterate over let mut relevant_blocks = BTreeSet::new(); for block in graph.dfs_iter() { match fun.block_kind(block).unwrap() { OpKind::Call(CallKind::ControlFlow) => { relevant_blocks.insert(block); } OpKind::IfBool => { relevant_blocks.insert(block); } OpKind::UnpackValueList(_) => { relevant_blocks.insert(block); } _ => (), } } let mut ctx = AnalysisContext { bump, fun, graph, current: None, static_renames: &mut static_renames, static_branches: &mut static_branches, phis: &mut phis, }; // Propagate value renames until we reach an equilibrium. // This will perform branch elimination and constant propagation // in one single step. let mut handled_blocks = BTreeSet::new(); loop { let mut changed = false; for block in relevant_blocks.iter() { // If the block is already statically resolved, we can skip it. if handled_blocks.contains(block) { continue; } ctx.init_block(*block); let res = match fun.block_kind(*block).unwrap() { OpKind::Call(CallKind::ControlFlow) => self::call::propagate(&mut ctx, *block), OpKind::IfBool => self::if_bool::propagate(&mut ctx, *block), OpKind::UnpackValueList(n) => { self::unpack_value_list::propagate(&mut ctx, *block, *n) } _ => unreachable!(), }; // If the propagation implementation indicated that it has been // resolved, then we have a change in this iteration. if res { changed = true; handled_blocks.insert(*block); } } // If this iteration contains no changes, then we are done. if !changed { break; } } trace!("======== Results after initial traversal:"); trace!("Phis: {:?}", ctx.phis); trace!("Static renames: {:?}", ctx.static_renames); trace!("========"); // Populate incoming edges in phis for phi in ctx.phis.values_mut() { for incoming in graph.incoming(phi.block) { if !phi.sources.contains_key(&incoming) { phi.sources.insert( incoming, PhiSource { // Not relevant since the edge is not part of the tree value: None, caller: None, called: phi.block, arg_index: phi.value_index, arg: phi.value, }, ); } } } // Generate `static_branches_blocks` let mut static_branches_blocks = BFnvHashMap::with_hasher_in(Default::default(), bump); for (from, to) in static_branches.iter() { if let Some(to_block) = fun.value_block(*to) { static_branches_blocks.insert(*from, to_block); } } // Group chains // TODO: Handle cycles let mut trees = BFnvHashMap::with_hasher_in(Default::default(), bump); for (from, to) in static_branches.iter() { let mut next_target_value = *to; let mut target_block = *from; let mut to_has_block = None; // Walk chain of branches until target is reached loop { // If the next value is a block if let Some(to_block) = fun.value_block(next_target_value) { // .. the target is that block target_block = to_block; if to_has_block.is_none() { to_has_block = Some(to_block); } // If that block has an outgoing branch, // walk that next and continue if let Some(next) = static_branches.get(&to_block) { next_target_value = *next; continue; } } // If the chains map doesn't contain the target, seed it if !trees.contains_key(&target_block) { let mut tree = TreeData { edges: BFnvHashMap::with_hasher_in(Default::default(), bump), blocks: BFnvHashMap::with_hasher_in(Default::default(), bump), entry_edges: BFnvHashMap::with_hasher_in(Default::default(), bump), entry_values: BFnvHashMap::with_hasher_in(Default::default(), bump), }; tree.blocks.insert(target_block, ()); trees.insert(target_block, tree); } // Update the current chain with this edge let tree = trees.get_mut(&target_block).unwrap(); tree.blocks.insert(*from, ()); if let Some(to_block) = to_has_block { tree.edges.insert((*from, to_block), ()); } break; } } // Find incoming edges into the chain for tree in trees.values_mut() { for block in tree.blocks.keys() { if *block == entry { tree.entry_edges.insert(*block, ()); for (arg_idx, arg) in fun.block_args(*block).iter().enumerate() { tree.entry_values.insert(*arg, (*block, arg_idx)); } } for incoming in graph.incoming(*block) { let edge = (incoming, *block); if tree.edges.contains_key(&edge) { continue; } tree.entry_edges.insert(*block, ()); for (arg_idx, arg) in fun.block_args(*block).iter().enumerate() { tree.entry_values.insert(*arg, (*block, arg_idx)); } } } } let analysis = GraphAnalysis { entry, static_branches, static_branches_blocks, phis, static_renames, trees, }; trace!("GRAPH ANALYSIS: {:?}", analysis); analysis } pub struct ChainMapping { entry_to_chain: BTreeMap, block_to_entries: BTreeMap>, } impl ChainMapping { pub fn iter_entries_for<'a>(&'a self, block: Block) -> impl Iterator + 'a { self.block_to_entries[&block].iter().cloned() } pub fn entry_to_chain(&self, entry: Block) -> Chain { self.entry_to_chain[&entry] } } pub fn build_node<'bump>( bump: &'bump Bump, fun: &Function, //graph: &LiveBlockGraph, live: &LiveValues, analysis: &'bump GraphAnalysis, target: Block, block_graph: &ChainMapping, last_loc: Block, value: Value, chain_graph: &mut super::chain_graph::ChainGraph, existing_nodes: &mut BTreeMap, ) -> (bool, Node) { trace!("{:?} {:?}", value, fun.value_kind(value)); let tree = &analysis.trees[&target]; match fun.value_kind(value) { ValueKind::Argument(block, arg_index) => { trace!("ARGUMENT {} {}", block, arg_index); trace!("A1"); // If it's not an argument of a block in the chain, we simply refer // to the scope. if !tree.blocks.contains_key(&block) { return (false, chain_graph.insert_scoped(value)); } if !(block == last_loc || analysis.is_before(block, last_loc)) { return (false, chain_graph.insert_scoped(value)); } trace!("A2 last_loc: {}", last_loc); // Look up existing node if let Some(existing) = existing_nodes.get(&value) { return (true, *existing); } trace!("A6"); // If the value is a phi, we build recursively let v_phi = chain_graph.insert_phi(0, value); // If there exists a phi for the value, add those to phi if let Some(phi) = analysis.phis.get(&value) { for (from_block, source) in phi.sources.iter() { if let Some(from_val) = source.value { let (_req, node) = build_node( bump, fun, //graph, live, analysis, target, block_graph, *from_block, from_val, chain_graph, existing_nodes, ); for entry in block_graph.iter_entries_for(*from_block) { let chain = block_graph.entry_to_chain(entry); chain_graph.phi_add_entry(v_phi, chain, node); } } } } // If current block is an entry, add that to the phi if tree.entry_edges.contains_key(&block) { let chain = block_graph.entry_to_chain(block); let node = chain_graph.insert_chain_entry_arg(chain, arg_index, value); chain_graph.phi_add_entry(v_phi, chain, node); } existing_nodes.insert(value, v_phi); (true, v_phi) } ValueKind::Block(block) => { // Look up existing node if let Some(existing) = existing_nodes.get(&value) { return (true, *existing); } let env = live.live_at(block); let v_block = chain_graph.insert_block_capture(value, block); for dep_value in env.iter() { let (_req, node) = build_node( bump, fun, //graph, live, analysis, target, block_graph, last_loc, dep_value, chain_graph, existing_nodes, ); chain_graph.add_dep(v_block, node, dep_value); } existing_nodes.insert(value, v_block); (true, v_block) } ValueKind::PrimOp(prim) => { // Look up existing node if let Some(existing) = existing_nodes.get(&value) { return (true, *existing); } let v_prim = chain_graph.insert_prim(value); let mut required = false; for p_read in fun.primop_reads(prim) { let (req, dep_node) = build_node( bump, fun, //graph, live, analysis, target, block_graph, last_loc, *p_read, chain_graph, existing_nodes, ); chain_graph.add_dep(v_prim, dep_node, *p_read); if req { required = true; } } existing_nodes.insert(value, v_prim); (required, v_prim) } ValueKind::Const(_) => (false, chain_graph.insert_scoped(value)), } } pub fn analyze_chain<'bump>( bump: &'bump Bump, target: Block, fun: &Function, graph: &LiveBlockGraph, live: &LiveValues, analysis: &'bump GraphAnalysis, ) -> super::chain_graph::ChainGraph { let tree = &analysis.trees[&target]; let mut chain_graph = super::chain_graph::ChainGraph::new(target); // Mapping from entry `Block`s to its `Chain`. let mut entry_to_chain: BTreeMap = BTreeMap::new(); // Mapping from all `Block`s to all `Chain`s each is part of. let mut block_to_entries: BTreeMap> = BTreeMap::new(); for (entry_block, _) in tree.entry_edges.iter() { let mut block_chain = Vec::new(); block_chain.push(*entry_block); // Walk blocks in order, adding to chain list let mut curr = *entry_block; loop { if let Some(next) = analysis.static_branches_blocks.get(&curr) { curr = *next; block_chain.push(curr); if curr == target { break; } } else { break; } } let num_args = fun.block_args(*entry_block).len(); // Create map of `Block` to all `Chain`s it's part of. for block in block_chain.iter() { block_to_entries .entry(*block) .or_insert_with(|| BTreeSet::new()) .insert(*entry_block); } // Create chain in graph let chain = chain_graph.entry_chain(num_args, block_chain.clone()); assert!(!entry_to_chain.contains_key(entry_block)); entry_to_chain.insert(*entry_block, chain); } let chain_mapping = ChainMapping { entry_to_chain, block_to_entries, }; let mut existing_nodes = BTreeMap::new(); for root_value in live.live_in(target).iter() { let (required, node) = build_node( bump, fun, live, analysis, target, &chain_mapping, target, root_value, &mut chain_graph, &mut existing_nodes, ); if required { chain_graph.mark_root(root_value, node); } } //chain_graph.gen_dot(&std::path::Path::new("woo_bef.png")); chain_graph.process(); //chain_graph.gen_dot(&std::path::Path::new("woo.png")); chain_graph } ================================================ FILE: libeir_passes/src/simplify_cfg/analyze/unpack_value_list.rs ================================================ use libeir_ir::{Block, PrimOpKind}; use super::AnalysisContext; pub(super) fn propagate(ctx: &mut AnalysisContext, block: Block, n: usize) -> bool { let reads = ctx.fun.block_reads(block); assert!(reads.len() == 2); let target = ctx.follow(reads[0]); let list = ctx.follow(reads[1]); if let Some(target_block) = ctx.fun.value_block(target) { let target_args = ctx.fun.block_args(target_block); assert!(n == target_args.len()); // Value list of length 1 can't exist, always the value itself if n == 1 { ctx.set_branch(target); ctx.add_rename(target_block, reads[1], 0); return true; } if let Some(prim) = ctx.fun.value_primop(list) { if let PrimOpKind::ValueList = ctx.fun.primop_kind(prim) { let prim_reads = ctx.fun.primop_reads(prim); assert!(target_args.len() == prim_reads.len()); ctx.set_branch(target); for (idx, read) in prim_reads.iter().enumerate() { ctx.add_rename(target_block, *read, idx); } return true; } else { panic!() } } } false } ================================================ FILE: libeir_passes/src/simplify_cfg/chain_graph/mod.rs ================================================ use log::trace; use std::collections::{BTreeMap, BTreeSet}; use cranelift_entity::{entity_impl, PrimaryMap}; use libeir_ir::{Block, PrimOp, Value}; use libeir_util_datastructures::pooled_entity_set::{EntitySet, EntitySetPool}; use libeir_util_dot_graph::{DisplayNid, GraphPrinter, NodeId, PrefixedNid}; use super::analyze::PhiSource; use crate::util::Walker; pub mod synthesis; /// Disambiguate between a value that originates within the tree, and one that /// is referenced externally. /// /// This is required because of tight loops, a member value may also be accessed /// from the last iteration as scoped. #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] pub enum ValueRef { Member(Value), Scope(Value), } #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct Node(u32); entity_impl!(Node, "node"); impl NodeId for Node { fn make_id(&self, out: &mut String) { use std::fmt::Write; write!(out, "{}", self).unwrap(); } } #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct Chain(u32); entity_impl!(Chain, "chain"); impl NodeId for Chain { fn make_id(&self, out: &mut String) { use std::fmt::Write; write!(out, "{}", self).unwrap(); } } /// Graph representing value uses in a single static call chain. /// /// Graph has 5 node types: /// * Root value. These are externally referencable nodes. They are always tied /// to a single source cfg value. /// They have a single outgoing edge and no incoming edges. /// * Leaf value. These are nodes referencing external values in the source CFG. /// They have N incoming edges and no outgoing edges. /// * Phi node. Phi nodes perform selection on values from incoming blocks. /// They have N incoming edges and M outgoing edges. /// * PrimOp node. These construct a primop from M referenced values. /// They have N incoming edges and M outgoing edges. /// * BlockCapture node. These capture a block as a closure with M referenced /// values in the environment. /// They have B incoming edges and M outgoing edges. /// /// The primary purpose of this graph is to do reduction of the value use graph /// independently of the original control flow. This enables us to later /// synthesize a new CFG that performs the same semantically while potentially /// being more optimal. /// /// The graph is operated on with a couple of main operations, usually in order: /// 1. Graph construction. See public helper functions on the graph. /// 2. Graph reduction. See `reduce_phis` function. /// 3. CFG synthesis. Generates a new CFG from the reduced value use graph, /// according to the strategy used. The strategy needs to decide to schedule /// a node before or after phi selection. /// * When scheduled after phi selection, the node will only occur once in /// the target CFG, but the resulting CFG may be more complex. /// * Scheduling a node before phi selection may result in radically simpler /// target CFGs from the perspective of the chain itself, but will perform /// specialization on the different nodes and can thus result in larger /// CFG size overall. pub struct ChainGraph { target_block: Block, /// Which nodes in the graph are currently active. /// This is mainly maintained for printing. active_nodes: BTreeSet, values: BTreeMap, terminal_values: BTreeMap, nodes: PrimaryMap, /// These are the roots of the chain graph, the entry edges. entry_edges: BTreeMap, /// These are entry edges that has been found to map to a single terminal. uniform_mappings: BTreeMap, chains: PrimaryMap, back_edges: BTreeMap, aliases: BTreeMap, node_pool: EntitySetPool, } pub struct ChainData { /// Only there for debug printing. blocks: Vec, /// The arguments to the chain entry block. /// If `Some(Node)`, this is the `ChainEntry` node with this index. args: Vec>, } /// Public API impl ChainGraph { pub fn new(target_block: Block) -> Self { ChainGraph { target_block, active_nodes: BTreeSet::new(), values: BTreeMap::new(), terminal_values: BTreeMap::new(), nodes: PrimaryMap::new(), entry_edges: BTreeMap::new(), chains: PrimaryMap::new(), back_edges: BTreeMap::new(), uniform_mappings: BTreeMap::new(), aliases: BTreeMap::new(), node_pool: EntitySetPool::new(), } } pub fn propagate_alias(&self, mut node: Node) -> Node { loop { if let Some(nnode) = self.aliases.get(&node) { node = *nnode; } else { break node; } } } pub fn get_terminal_value_node(&self, value: Value) -> Option { let mut node = *self.terminal_values.get(&value)?; Some(self.propagate_alias(node)) } pub fn get_member_value_node(&self, value: Value) -> Option { let mut node = *self.values.get(&value)?; Some(self.propagate_alias(node)) } pub fn get_member_or_terminal(&self, value: Value) -> Option { self.get_member_value_node(value) .or_else(|| self.get_terminal_value_node(value)) } //pub fn node_is_value(&self, node: Node) -> bool { // self.nodes[node].is_value() //} //pub fn mark_root(&mut self, value: Value) { // // TODO change to take node? // let node = self.get_value_node(value).unwrap(); // self.entry_edges.insert(value, node); //} pub fn mark_root(&mut self, value: Value, node: Node) { if let Some(old) = self.entry_edges.get(&value) { assert!(node == *old); } self.entry_edges.insert(value, node); } pub fn get_root(&self, value: Value) -> Option { self.entry_edges.get(&value).cloned() } pub fn get_uniform(&self, value: Value) -> Option { self.uniform_mappings.get(&value).cloned() } pub fn iter_roots<'a>(&'a self) -> impl Iterator + 'a { self.entry_edges.iter().map(|(k, v)| (*k, *v)) } pub fn iter_uniform_mappings<'a>(&'a self) -> impl Iterator + 'a { self.uniform_mappings.iter().map(|(k, v)| (*k, *v)) } pub fn insert_scoped(&mut self, value: Value) -> Node { //if let Some(node) = self.terminal_values.get(&value) { // assert!(self.active_nodes.contains(&node)); // // TODO assert same // return *node; //} let node = self.nodes.push(NodeKind::Scope(value)); self.active_nodes.insert(node); self.terminal_values.insert(value, node); node } pub fn insert_chain_entry_arg(&mut self, chain: Chain, arg_index: usize, arg: Value) -> Node { //if let Some(node) = self.terminal_values.get(&arg) { // assert!(self.active_nodes.contains(&node)); // // TODO assert same // return *node; //} let entry_arg = EntryArg { chain, arg_index, arg, }; let node = self.nodes.push(NodeKind::EntryArg(entry_arg)); self.active_nodes.insert(node); self.terminal_values.insert(arg, node); let slot = &mut self.chains[chain].args[arg_index]; assert!(slot.is_none()); *slot = Some(node); node } pub fn insert_phi(&mut self, tier: usize, value: Value) -> Node { if let Some(node) = self.values.get(&value) { assert!(self.active_nodes.contains(node)); assert!(self.nodes[*node].is_phi()); return *node; } let scope_node = self.insert_scoped(value); let node = self.nodes.push(NodeKind::Phi(Phi { value: Some((value, scope_node)), tier: Some(tier), entries: BTreeMap::new(), })); self.active_nodes.insert(node); self.values.insert(value, node); node } pub fn phi_add_entry(&mut self, node: Node, chain: Chain, dep: Node) { match &mut self.nodes[node] { NodeKind::Phi(phi) => { phi.entries.insert(chain, dep); } _ => panic!(), } } pub fn insert_prim(&mut self, value: Value) -> Node { if let Some(node) = self.values.get(&value) { assert!(self.active_nodes.contains(node)); assert!(self.nodes[*node].is_prim()); return *node; } let node = self.nodes.push(NodeKind::Prim(Prim { prim: value, dependencies: BTreeMap::new(), })); self.active_nodes.insert(node); self.values.insert(value, node); node } pub fn insert_block_capture(&mut self, value: Value, block: Block) -> Node { if let Some(node) = self.values.get(&value) { assert!(self.active_nodes.contains(node)); assert!(self.nodes[*node].is_block_capture()); return *node; } let node = self.nodes.push(NodeKind::BlockCapture(BlockCapture { value, capture: block, dependencies: BTreeMap::new(), })); self.active_nodes.insert(node); self.values.insert(value, node); node } pub fn add_dep(&mut self, node: Node, dep: Node, value: Value) { match &mut self.nodes[node] { NodeKind::Prim(prim) => { prim.dependencies.insert(value, dep); } NodeKind::BlockCapture(cap) => { cap.dependencies.insert(value, dep); } _ => panic!(), } } pub fn gen_dot(&self, out: &std::path::Path) { let mut g = GraphPrinter::new(); for (node, node_data) in self.nodes.iter() { if !self.active_nodes.contains(&node) { continue; } g.node(node, &format!("{}: {:#?}", node, node_data)); match node_data { NodeKind::Scope(_) => {} NodeKind::EntryArg(_) => {} NodeKind::Phi(phi) => { for (block, from_node) in phi.entries.iter() { g.edge(node, *from_node, &format!("{:#?}", (block, from_node))); } } NodeKind::Prim(prim) => { for (dep_value, dep_node) in prim.dependencies.iter() { g.edge(node, *dep_node, &format!("{:#?}", (dep_value, dep_node))); } } NodeKind::BlockCapture(cap) => { for (dep_value, dep_node) in cap.dependencies.iter() { g.edge(node, *dep_node, &format!("{:#?}", (dep_value, dep_node))); } } } } for (val, node) in self.entry_edges.iter() { let nid = PrefixedNid("entry_", DisplayNid(val)); g.node(nid, &format!("root dep: {}", val)); g.edge(nid, DisplayNid(node), ""); } let mut added_blocks = BTreeSet::new(); for (chain, chain_data) in self.chains.iter() { for block in chain_data.blocks.iter() { if !added_blocks.contains(block) { added_blocks.insert(block); g.node(DisplayNid(*block), &format!("{}", block)); } } for (from, to) in chain_data .blocks .iter() .zip(chain_data.blocks.iter().skip(1)) { g.edge(DisplayNid(from), DisplayNid(to), ""); } g.edge( DisplayNid(chain), DisplayNid(chain_data.blocks[0]), &format!("{:?}", chain_data.args), ); } g.finish_run_dot(out); } pub fn chain_count(&self) -> usize { self.chains.len() } pub fn entry_chain(&mut self, arity: usize, blocks: Vec) -> Chain { self.chains.push(ChainData { args: vec![None; arity], blocks, }) } pub fn get_chain_entry_block(&self, chain: Chain) -> Block { self.chains[chain].blocks[0] } pub fn node(&self, node: Node) -> &NodeKind { &self.nodes[node] } pub fn follow_chain(&self, mut node: Node, chain: Chain) -> Node { //println!("Follow {} {}", node, chain); loop { match &self.nodes[node] { NodeKind::Phi(phi) => { node = phi.entries[&chain]; } _ => break, } } node } pub fn follow_chain_maybe(&self, mut node: Node, chain: Chain) -> Option { //println!("Follow {} {}", node, chain); loop { match &self.nodes[node] { NodeKind::Phi(phi) => { if let Some(next) = phi.entries.get(&chain) { node = *next; } else { return None; } } _ => break, } } Some(node) } pub fn dfs(&self, start: Node, order: &mut Vec) { order.clear(); let mut walker = Walker::with(self.entry_edges.values().cloned().collect()); while let Some(node) = walker.next() { let node_data = &self.nodes[node]; for dep in node_data.dependencies() { walker.put(dep); } order.push(node); } } pub fn process(&mut self) { self.expand_phis(); self.remove_uniform(); self.reduce_phis2(); //chain_graph.decycle(); //chain_graph.expand_phis(); //chain_graph.remove_uniform(); //chain_graph.reduce_phis(); } } /// Private API impl ChainGraph { fn propagate_graph_aliases(&mut self) { let mut tmp = Vec::new(); for node in self.entry_edges.values_mut() { if let Some(to) = self.aliases.get(&*node) { *node = *to; } } for node in self.nodes.values_mut() { match node { NodeKind::Scope(_) => (), NodeKind::EntryArg(_) => (), NodeKind::Phi(phi) => { for entry_node in phi.entries.values_mut() { if let Some(to) = self.aliases.get(&*entry_node) { *entry_node = *to; } } } NodeKind::Prim(prim) => { tmp.clear(); tmp.extend(prim.dependencies.iter().map(|(k, v)| (*k, *v))); prim.dependencies.clear(); for (dep_value, dep_node) in tmp.iter() { if let Some(to) = self.aliases.get(dep_node) { prim.dependencies.insert(*dep_value, *to); } else { prim.dependencies.insert(*dep_value, *dep_node); } } } NodeKind::BlockCapture(bc) => { tmp.clear(); tmp.extend(bc.dependencies.iter().map(|(k, v)| (*k, *v))); bc.dependencies.clear(); for (dep_value, dep_node) in tmp.iter() { if let Some(to) = self.aliases.get(dep_node) { bc.dependencies.insert(*dep_value, *to); } else { bc.dependencies.insert(*dep_value, *dep_node); } } } } } } fn insert_anon_phi(&mut self) -> Node { let node = self.nodes.push(NodeKind::Phi(Phi { value: None, tier: None, entries: BTreeMap::new(), })); self.active_nodes.insert(node); node } } impl ChainGraph { pub fn remove_uniform(&mut self) { 'outer: for (entry_value, entry_node) in self.entry_edges.iter() { let mut terminal = None; for chain in self.chains.keys() { let end = self.follow_chain(*entry_node, chain); let end_kind = &self.nodes[end]; if !end_kind.is_terminal() { continue 'outer; } if let Some(prev) = terminal { let prev_value = self.nodes[prev].terminal_value(); let curr_value = self.nodes[end].terminal_value(); if prev_value != curr_value { continue 'outer; } if self.nodes[end].is_entry_arg() { terminal = Some(end); } } else { terminal = Some(end); } } self.uniform_mappings .insert(*entry_value, terminal.unwrap()); } for entry in self.uniform_mappings.keys() { self.entry_edges.remove(entry); } } pub fn expand_phis(&mut self) { for entry_node in self.entry_edges.values() { match &mut self.nodes[*entry_node] { NodeKind::Phi(phi) => { let (_value, scoped_node) = phi.value.unwrap(); for chain in self.chains.keys() { if !phi.entries.contains_key(&chain) { phi.entries.insert(chain, scoped_node); } } } _ => (), } } } pub fn reduce_phis2(&mut self) { fn collect_relevant_phis( graph: &ChainGraph, relevant: &mut BTreeSet, node: Node, parent_relevant: bool, ) { match &graph.nodes[node] { NodeKind::Phi(phi) => { if parent_relevant { relevant.insert(node); } for dep_node in phi.entries.values() { collect_relevant_phis(graph, relevant, *dep_node, false); } } kind => { for dep_node in kind.dependencies() { collect_relevant_phis(graph, relevant, dep_node, true); } } } } let mut relevant = BTreeSet::new(); for entry in self.entry_edges.values() { collect_relevant_phis(self, &mut relevant, *entry, true); } for phi in relevant.iter() { let new = self.insert_anon_phi(); let mut a_node = None; let mut is_mono = true; for chain in self.chains.keys() { if let Some(end) = self.follow_chain_maybe(*phi, chain) { if let Some(prev) = a_node { if end != prev { is_mono = false; } } else { a_node = Some(end); } self.phi_add_entry(new, chain, end); } } if is_mono { self.aliases.insert(*phi, a_node.unwrap()); } else { self.aliases.insert(*phi, new); } } self.propagate_graph_aliases(); } } /// Graph decycle //impl ChainGraph { // // pub fn decycle(&mut self) { // // #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] // enum EdgeRef { // Chain(Chain), // Value(Value), // } // impl EdgeRef { // fn chain(&self) -> Chain { // match self { // EdgeRef::Chain(chain) => *chain, // _ => unreachable!(), // } // } // fn value(&self) -> Value { // match self { // EdgeRef::Value(value) => *value, // _ => unreachable!(), // } // } // } // // let mut updates = BTreeMap::new(); // let mut new_value_nodes = BTreeSet::new(); // // fn rec( // cg: &ChainGraph, // updates: &mut BTreeMap<(Node, EdgeRef), Value>, // new_value_nodes: &mut BTreeSet, // last_tier: Option, // last_edge: Option<(Node, EdgeRef)>, // node: Node, // ) { // match &cg.nodes[node] { // NodeKind::Scope(_value) => (), // NodeKind::EntryArg(_entry_arg) => (), // NodeKind::Phi(phi) => { // let tier = phi.tier.unwrap(); // // if let Some(last_tier) = last_tier { // println!("{} <= {}", tier, last_tier); // } // // match last_tier { // Some(last_tier) if tier <= last_tier => { // println!("!!!! {} <= {}", tier, last_tier); // // let curr_value = phi.value.unwrap(); // new_value_nodes.insert(curr_value); // updates.insert(last_edge.unwrap(), curr_value); // }, // _ => { // for (from_block, value_node) in phi.entries.iter() { // rec( // cg, // updates, // new_value_nodes, // Some(tier), // Some((node, EdgeRef::Chain(*from_block))), // *value_node, // ); // } // }, // } // // }, // NodeKind::Prim(prim) => { // for (from_value, value_node) in prim.dependencies.iter() { // rec( // cg, // updates, // new_value_nodes, // last_tier, // Some((node, EdgeRef::Value(*from_value))), // *value_node, // ); // } // }, // NodeKind::BlockCapture(bc) => { // for (from_value, value_node) in bc.dependencies.iter() { // rec( // cg, // updates, // new_value_nodes, // last_tier, // Some((node, EdgeRef::Value(*from_value))), // *value_node, // ); // } // }, // } // } // // for entry_node in self.entry_edges.values() { // rec(self, &mut updates, &mut new_value_nodes, None, None, *entry_node); // } // // println!("UPDATES: {:?}", updates); // // let mut new_values = BTreeMap::new(); // // for value in new_value_nodes.iter() { // if let Some(existing) = self.get_terminal_value_node(*value) { // new_values.insert(*value, existing); // } else { // let node = self.nodes.push(NodeKind::Scope(*value)); // self.active_nodes.insert(node); // self.terminal_values.insert(*value, node); // new_values.insert(*value, node); // } // } // // for ((node, edge), value) in updates.iter() { // let new_target = new_values[value]; // // let node = &mut self.nodes[*node]; // match node { // NodeKind::Scope(_) => unreachable!(), // NodeKind::EntryArg(_) => unreachable!(), // NodeKind::Phi(phi) => { // let chain = edge.chain(); // phi.entries.insert(chain, new_target); // } // NodeKind::Prim(prim) => { // let value = edge.value(); // prim.dependencies.insert(value, new_target); // } // NodeKind::BlockCapture(bc) => { // let value = edge.value(); // bc.dependencies.insert(value, new_target); // } // } // } // // } // //} /// Graph reduction impl ChainGraph { /// This will reduce complex chains of phis into either: /// * A single phi block. This is done when selection between several /// incoming paths is required. /// * No phi blocks. This is done when there is only one value selected /// reducing the phis. pub fn reduce_phis(&mut self) { #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] pub struct Group(u32); entity_impl!(Group, "group"); let mut node_pool = EntitySetPool::new(); let mut active_phi_groups: BTreeSet = BTreeSet::new(); let mut phi_groups: PrimaryMap> = PrimaryMap::new(); let mut phi_groups_back: BTreeMap = BTreeMap::new(); // Walk the graph while identifying all phi node groups. let mut walker = Walker::with(self.entry_edges.values().cloned().collect()); while let Some(node) = walker.next() { let node_data = &self.nodes[node]; for dep in node_data.dependencies() { walker.put(dep); } if node_data.is_phi() { let group = if let Some(group) = phi_groups_back.get(&node) { // The node is part of an already identified group. *group } else { // We create a new phi group for this node. let mut set = EntitySet::new(); set.insert(node, &mut node_pool); let group = phi_groups.push(set); active_phi_groups.insert(group); phi_groups_back.insert(node, group); group }; for dep in node_data.dependencies() { if self.nodes[dep].is_phi() { if let Some(other_group) = phi_groups_back.get(&dep).cloned() { // We can hit a node that's already present in a // group if the graph joins from two different root // nodes. In this case we simply merge the two. // We disregard `group`. active_phi_groups.remove(&group); let s_group = phi_groups[group].clone(); // Union into `other_group` phi_groups[other_group].union(&s_group, &mut node_pool); // Update back mappings for all entries in `group` for s_node in s_group.iter(&node_pool) { phi_groups_back.insert(s_node, other_group); } } else { // Normal case, node is not assigned to a group. // Insert it into the current group, create a back // mapping. phi_groups[group].insert(dep, &mut node_pool); phi_groups_back.insert(dep, group); } } } } } // These are used to update graph edges let mut final_entries: Vec<(Chain, Node)> = Vec::new(); for group in active_phi_groups.iter() { final_entries.clear(); let group_set = &phi_groups[*group]; for node in group_set.iter(&node_pool) { match &self.nodes[node] { NodeKind::Phi(phi) => { // For each entry in the phi.. for (block, block_node) in phi.entries.iter() { // if the entry is not to another node in the group. if !self.nodes[*block_node].is_phi() { // add the entry to the new phi final_entries.push((*block, *block_node)); } } } _ => unreachable!(), } } let new_target; trace!("FINAL ENTRIES: {:?}", final_entries); // If there is only one target node, we can completely omit the phi. assert!(final_entries.len() > 0); let first_node = final_entries[0].1; if final_entries.iter().all(|(_b, n)| *n == first_node) { new_target = first_node; } else { // The new phi node that encompasses the entire group let new_phi = self.insert_anon_phi(); // Add entries to new phi for (chain, from_node) in final_entries.iter() { // If the from node is not a phi itself, then it's always // from outside the group. if !self.nodes[*from_node].is_phi() { //self.phi_add_entry(new_phi, *entry_block, *block_node); match &mut self.nodes[new_phi] { NodeKind::Phi(phi) => { // Sanity check, chain will never occur more // than once. assert!(!phi.entries.contains_key(chain)); phi.entries.insert(*chain, *from_node); } _ => panic!(), } } } new_target = new_phi; } for node in group_set.iter(&node_pool) { // Update all nodes in the graph so they reference the new phi // instead of entries in the old group self.aliases.insert(node, new_target); self.active_nodes.remove(&node); } } // Propagate all aliases, this will update the graph with our changes. self.propagate_graph_aliases(); } } #[derive(Debug)] pub enum NodeKind { /// External value Scope(Value), /// Value on entry point of a chain EntryArg(EntryArg), /// Phi within chain Phi(Phi), /// Prim with dependencies Prim(Prim), /// Block capture with dependencies BlockCapture(BlockCapture), } impl NodeKind { pub fn is_phi(&self) -> bool { match self { NodeKind::Phi(_) => true, _ => false, } } pub fn is_prim(&self) -> bool { match self { NodeKind::Prim(_) => true, _ => false, } } pub fn is_block_capture(&self) -> bool { match self { NodeKind::BlockCapture(_) => true, _ => false, } } pub fn is_scope(&self) -> bool { match self { NodeKind::Scope(_) => true, _ => false, } } pub fn is_entry_arg(&self) -> bool { match self { NodeKind::EntryArg(_) => true, _ => false, } } pub fn is_terminal(&self) -> bool { match self { NodeKind::Scope(_) => true, NodeKind::EntryArg(_) => true, _ => false, } } pub fn terminal_value(&self) -> Value { match self { NodeKind::Scope(value) => *value, NodeKind::EntryArg(entry_arg) => entry_arg.arg, _ => unreachable!(), } } pub fn dependencies<'a>(&'a self) -> impl Iterator + 'a { enum EIter where A: Iterator, B: Iterator, C: Iterator, { A(A), B(B), C(C), None, } impl Iterator for EIter where A: Iterator, B: Iterator, C: Iterator, { type Item = T; fn next(&mut self) -> Option { match self { EIter::A(a) => a.next(), EIter::B(b) => b.next(), EIter::C(c) => c.next(), EIter::None => None, } } } match self { NodeKind::Phi(i) => EIter::A(i.entries.values().cloned()), NodeKind::Prim(i) => EIter::B(i.dependencies.values().cloned()), NodeKind::BlockCapture(i) => EIter::C(i.dependencies.values().cloned()), NodeKind::Scope(_) => EIter::None, NodeKind::EntryArg(_) => EIter::None, } } } /// A value on the entry point on a chain. #[derive(Debug)] pub struct EntryArg { pub chain: Chain, pub arg_index: usize, pub arg: Value, } /// Selects a value depending on the block it passes through. #[derive(Debug)] pub struct Phi { pub value: Option<(Value, Node)>, pub tier: Option, pub entries: BTreeMap, } /// Composition using primop #[derive(Debug)] pub struct Prim { /// The value referencing the original PrimOp. /// Used when synthesizing the new CFG. pub prim: Value, /// Mapping from used value => node pub dependencies: BTreeMap, } /// Composition using closure capture #[derive(Debug)] pub struct BlockCapture { /// Mainly for debugging. pub value: Value, /// The block being captured. /// Used when synthesizing the new CFG. pub capture: Block, /// Mapping from used value => node pub dependencies: BTreeMap, } ================================================ FILE: libeir_passes/src/simplify_cfg/chain_graph/synthesis/compound.rs ================================================ use log::trace; use super::super::ChainGraph; use super::{Synthesis, SynthesisStrategy}; use libeir_ir::{Function, LiveValues}; /// Synthesis strategy that dispatches to any number of other strategies /// depending on the chain graph. pub struct CompoundStrategy; impl SynthesisStrategy for CompoundStrategy { fn try_run(&self, graph: &ChainGraph, fun: &Function, live: &LiveValues) -> Option { trace!("Trying single entry strategy..."); // Try the single strategy. // Will only succeed if there is a single entry. let single_strategy = super::single::SingleStrategy; if let Some(s) = single_strategy.try_run(graph, fun, live) { trace!("Single entry strategy succeeded!"); return Some(s); } trace!("Trying terminating target strategy..."); let single_strategy = super::terminating_target::TerminatingTargetStrategy; if let Some(s) = single_strategy.try_run(graph, fun, live) { trace!("Terminating target strategy succeeded!"); return Some(s); } trace!("Falling back to simple strategy..."); // Fall back to simple strategy. // This will work in every case (except for single entry, this is // handled by SingleStrategy above). let simple_strategy = super::simple::SimpleStrategy; Some(simple_strategy.try_run(graph, fun, live).unwrap()) } } ================================================ FILE: libeir_passes/src/simplify_cfg/chain_graph/synthesis/mod.rs ================================================ #![allow(dead_code)] use std::collections::BTreeMap; use super::{Chain, ChainGraph, Node}; use cranelift_entity::{entity_impl, EntityList, ListPool, PrimaryMap, SecondaryMap}; use libeir_ir::{Function, LiveValues, Value}; use libeir_util_datastructures::aux_traits::{AuxDebug, AuxImpl}; use libeir_util_datastructures::pooled_entity_set::{EntitySet, EntitySetPool}; pub mod compound; pub mod simple; pub mod single; pub mod terminating_target; pub struct Synthesis { pub segments: PrimaryMap, pub order: Vec, pub instances: PrimaryMap, pub substitutions: BTreeMap, pub segments_back: Option>>, pub chain_set_pool: EntitySetPool, pub node_pool: ListPool, pub instance_pool: ListPool, pub segment_set_pool: Option>, } impl std::fmt::Debug for Synthesis { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let mut b = f.debug_struct("Synthesis"); b.field("segments", &AuxImpl(&self.segments, self)); b.field("order", &self.order); b.field("instances", &self.instances); b.field("substitutions", &self.substitutions); match &self.segments_back { None => { let none: Option<()> = None; b.field("segments_back", &none) } Some(inner) => b.field( "segments_back", &AuxImpl(inner, self.segment_set_pool.as_ref().unwrap()), ), }; b.finish() } } impl Synthesis { pub fn new() -> Self { Synthesis { segments: PrimaryMap::new(), order: Vec::new(), instances: PrimaryMap::new(), substitutions: BTreeMap::new(), segments_back: None, chain_set_pool: EntitySetPool::new(), node_pool: ListPool::new(), instance_pool: ListPool::new(), segment_set_pool: None, } } fn create_segment(&mut self, head: SegmentHeadKind) -> Segment { self.segments.push(SegmentData { head, in_args: EntityList::new(), externals: EntityList::new(), instances: EntityList::new(), body: SegmentBodyKind::None, chains: EntitySet::new(), node_ord: EntityList::new(), }) } pub fn create_entry_segment(&mut self, chain: Chain, graph: &ChainGraph) -> Segment { let segment = self.create_segment(SegmentHeadKind::Entry { chain }); let mut in_args = EntityList::new(); for arg in graph.chains[chain].args.iter() { let instance = match arg { Some(arg_node) => self.instances.push(InstanceKind::Arg { node: *arg_node, by: segment, }), None => self.instances.push(InstanceKind::NotRelevant), }; in_args.push(instance, &mut self.instance_pool); } self.segments[segment].in_args = in_args; segment } pub fn create_intermediate_segment(&mut self) -> Segment { self.create_segment(SegmentHeadKind::Intermediate) } pub fn segment<'a>(&'a mut self, segment: Segment) -> SegmentBuilder<'a> { SegmentBuilder { synthesis: self, segment, out_args: EntityList::new(), } } pub fn visit_segment(&mut self, segment: Segment) { self.order.push(segment); } pub fn substitute(&mut self, chain: Chain, value: Value) { if let Some(prev_val) = self.substitutions.get(&chain) { assert!(*prev_val == value); } else { self.substitutions.insert(chain, value); } } /// This will perform necessary postprocessing of the synthesis. /// Does things like populate chains to segments, generate node order. pub fn postprocess(&mut self, graph: &ChainGraph) { let mut pool = EntitySetPool::new(); let mut back: SecondaryMap> = SecondaryMap::new(); let mut walker = crate::util::Walker::new(); for segment_id in self.order.iter() { let segment = &self.segments[*segment_id]; match segment.body { SegmentBodyKind::None => panic!(), SegmentBodyKind::Terminal { .. } => { walker.put(*segment_id); } SegmentBodyKind::ToIntermediate { to, .. } => { back[to].insert(*segment_id, &mut pool); } } } let mut segment_order = Vec::new(); while let Some(segment_id) = walker.next() { let segment = &self.segments[segment_id]; segment_order.push(segment_id); for pred in back[segment_id].iter(&pool) { walker.put(pred); } } for segment_id in segment_order.iter().rev() { let segment = &self.segments[*segment_id]; let mut chains = segment.chains.clone(); match &segment.head { SegmentHeadKind::Entry { chain } => { chains.insert(*chain, &mut self.chain_set_pool); } _ => (), } for pred in back[*segment_id].iter(&pool) { chains.union(&self.segments[pred].chains, &mut self.chain_set_pool); } self.segments[*segment_id].chains = chains; } self.segment_set_pool = Some(pool); self.segments_back = Some(back); } } pub struct SegmentBuilder<'a> { synthesis: &'a mut Synthesis, segment: Segment, out_args: EntityList, } impl<'a> SegmentBuilder<'a> { fn create_arg_instance(&mut self, node: Node) -> Instance { self.synthesis.instances.push(InstanceKind::Arg { node, by: self.segment, }) } fn create_creation_instance(&mut self, node: Node) -> Instance { self.synthesis.instances.push(InstanceKind::BaseCreation { node, by: self.segment, }) } pub fn push_in_arg(&mut self, node: Node) -> Instance { let instance = self.create_arg_instance(node); let seg = &mut self.synthesis.segments[self.segment]; assert!(seg.head.is_intermediate()); assert!(seg.body.is_none()); seg.in_args .push(instance, &mut self.synthesis.instance_pool); instance } pub fn push_external(&mut self, instance: Instance) { let seg = &mut self.synthesis.segments[self.segment]; assert!(seg.body.is_none()); seg.externals .push(instance, &mut self.synthesis.instance_pool); } pub fn push_instance(&mut self, node: Node) -> Instance { let instance = self.create_creation_instance(node); let seg = &mut self.synthesis.segments[self.segment]; assert!(seg.body.is_none()); seg.instances .push(instance, &mut self.synthesis.instance_pool); instance } pub fn push_out_arg(&mut self, instance: Instance) { // TODO validate instance in scope? self.out_args .push(instance, &mut self.synthesis.instance_pool); } pub fn finish_to(&mut self, segment: Segment) { let seg = &mut self.synthesis.segments[self.segment]; assert!(seg.body.is_none()); seg.body = SegmentBodyKind::ToIntermediate { to: segment, out_args: self.out_args.clone(), }; } pub fn finish_target(&mut self, single: bool) { let seg = &mut self.synthesis.segments[self.segment]; assert!(seg.body.is_none()); seg.body = SegmentBodyKind::Terminal { single }; } } /// An instance of a node in the syntheized CFG. /// Can only be created once, in a single segment. /// This is a node that is instantiated in a set of chains. /// This is used as an unique id for a node instantiation when rewriting the /// EIR. #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] pub struct Instance(u32); entity_impl!(Instance, "instance"); #[derive(Debug)] pub enum InstanceKind { BaseCreation { /// The node this is an instance of. node: Node, /// The segment that created this instance. by: Segment, }, Arg { /// The node this is an instance of. node: Node, /// The segment that created this instance. by: Segment, }, NotRelevant, } impl InstanceKind { pub fn is_relevant(&self) -> bool { match self { InstanceKind::NotRelevant => false, _ => true, } } pub fn node(&self) -> Node { match self { InstanceKind::BaseCreation { node, .. } => *node, InstanceKind::Arg { node, .. } => *node, InstanceKind::NotRelevant => unreachable!(), } } } /// Synthesized segment, mostly equivalent to a block in the resulting EIR. #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] pub struct Segment(u32); entity_impl!(Segment, "segment"); /// This will: /// 1. Select a block according to the `head` /// 2. Insert `in_args` and `externals` into the local scope /// 3. Map all `instances` to the local scope, insert them into the local scope /// 4. Generate the body of the selected block according to `body` #[derive(Debug)] pub struct SegmentData { /// The head of the segment, how the block is created, how control flow /// enters this segment. pub head: SegmentHeadKind, /// The instances that are created by arguments on the head. /// * If the head is a chain entry, the count must be equal to the entry /// argument count. /// * If the head is an intermediate block, this length will specify the /// argument count. pub in_args: EntityList, /// The externals of this segment, instances that are asserted to be in /// scope, but does not enter the segment through the head. pub externals: EntityList, /// The instances created by this segment. pub instances: EntityList, /// The body of the segment, how control flow leaves this segment. pub body: SegmentBodyKind, /// All chains that pass through this segment. /// This should not be generated by the strategy, it will be populated /// afterwards. pub chains: EntitySet, /// A valid lowering order for nodes in the segment. /// This should not be generated by the strategy, it will be populated /// afterwards. pub node_ord: EntityList, } impl AuxDebug for SegmentData { fn aux_fmt(&self, f: &mut std::fmt::Formatter<'_>, aux: &Synthesis) -> std::fmt::Result { let mut b = f.debug_struct("SegmentData"); b.field("head", &self.head); b.field("in_args", &AuxImpl(&self.in_args, &aux.instance_pool)); b.field("externals", &AuxImpl(&self.externals, &aux.instance_pool)); b.field("instances", &AuxImpl(&self.instances, &aux.instance_pool)); b.field("body", &AuxImpl(&self.body, aux)); b.field("chains", &AuxImpl(&self.chains, &aux.chain_set_pool)); b.field("node_ord", &AuxImpl(&self.node_ord, &aux.instance_pool)); b.finish() } } #[derive(Debug)] pub enum SegmentHeadKind { /// The entry point of a chain. /// There must be exactly one of these for each chain. /// The arity of this block is always the same as on the original entry /// block. /// /// This will: /// 1. Create a new block /// 2. Add arguments matching arity of orignal entry /// 3. Insert mapping "old entry => this (new entry)" Entry { chain: Chain }, /// An intermediate block in the synthesized CFG. /// This can be reached from any number of chains. /// /// This will: /// 1. Create a new block /// 2. Create `in_args` on block Intermediate, } impl SegmentHeadKind { pub fn is_intermediate(&self) -> bool { match self { SegmentHeadKind::Intermediate => true, _ => false, } } } #[derive(Debug)] pub enum SegmentBodyKind { /// Not populated None, /// This will call an intermediate block in the synthesized CFG. /// /// This will: /// 1. Create a control flow call within the selected block with `out_args` /// as arguments. ToIntermediate { to: Segment, out_args: EntityList, }, /// This will specialize the target block into the selected block. /// /// Specialization will occur with the full local scope. All root value /// nodes must be in the local scope for this to be valid. /// /// Note: Specialization will ONLY happen on the operation within the target /// block. This needs to be taken into account by the synthesis strategy, as /// incorrect IR will be generated if any successor blocks attempt to access /// instances that are not Terminal { /// There can only ever exist a single segment with `single: true`. /// /// * If this is true, all result mappings from this will be applied /// globally. This is the general and safe mode. This usually means /// there will only be a single target segment. /// /// A notable exception to this is having one `single: true` segment /// and one or more `single: false` segments. This can be valid in /// very specific cases. /// /// * If this is false, no result mappings are applied globally, only /// when specializing the target operation. /// /// This is a useful mode when no values from the chain are accessed /// in successors of the target block. A trivial example of this is /// when a return call is performed in the target block. single: bool, }, } impl AuxDebug for SegmentBodyKind { fn aux_fmt(&self, f: &mut std::fmt::Formatter<'_>, aux: &Synthesis) -> std::fmt::Result { match self { SegmentBodyKind::None => f.debug_struct("None").finish(), SegmentBodyKind::ToIntermediate { to, out_args } => { let mut b = f.debug_struct("ToIntermediate"); b.field("to", to); b.field("out_args", &AuxImpl(out_args, &aux.instance_pool)); b.finish() } SegmentBodyKind::Terminal { single } => { let mut b = f.debug_struct("Terminal"); b.field("single", single); b.finish() } } } } impl SegmentBodyKind { pub fn is_none(&self) -> bool { match self { SegmentBodyKind::None => true, _ => false, } } } pub trait SynthesisStrategy { /// If the strategy is compatible with the given graph, returns the /// synthesized CFG. fn try_run(&self, graph: &ChainGraph, fun: &Function, live: &LiveValues) -> Option; } ================================================ FILE: libeir_passes/src/simplify_cfg/chain_graph/synthesis/simple.rs ================================================ use log::trace; use std::collections::BTreeSet; use cranelift_entity::EntityList; use libeir_ir::{Function, LiveValues}; use libeir_util_datastructures::pooled_entity_set::EntitySet; use super::super::{ChainGraph, NodeKind}; use super::{SegmentHeadKind, Synthesis, SynthesisStrategy}; use crate::util::Walker; /// A dead simple synthesis strategy. Works in every case. /// All nodes before the first phi will be specialized. /// /// Will always generate CFGs of this form: /// /// Entry1 Entry2 Entry3 /// | | | /// --------| | |-------- /// v v v /// Target pub struct SimpleStrategy; impl SynthesisStrategy for SimpleStrategy { fn try_run( &self, graph: &ChainGraph, _fun: &Function, _live: &LiveValues, ) -> Option { trace!("SIMPLE STRATEGY"); let mut synthesis = Synthesis::new(); let mut visited_set = BTreeSet::new(); let mut before_ord = EntityList::new(); let mut border_set = BTreeSet::new(); // Walk and find all nodes we schedule in the target block, along with // the set of nodes that need actual phi nodes/call arguments. let mut walker = Walker::with(graph.entry_edges.values().cloned().collect()); while let Some(node) = walker.next() { let node_data = &graph.nodes[node]; visited_set.insert(node); before_ord.push(node, &mut synthesis.node_pool); if node_data.is_phi() { border_set.insert(node); } else { for dep in node_data.dependencies() { walker.put(dep); } } } let out_segment = synthesis.create_intermediate_segment(); { let mut osb = synthesis.segment(out_segment); // The border set are the arguments on the new target block for arg in border_set.iter() { osb.push_in_arg(*arg); } // Create the root values in the block for target in graph.entry_edges.values() { osb.push_instance(*target); } // This is the single target block, full mappings osb.finish_target(true); // Order doesn't matter, strategy doesn't use externals synthesis.visit_segment(out_segment); } for (chain, _chain_data) in graph.chains.iter() { let segment = synthesis.create_entry_segment(chain, graph); let mut sb = synthesis.segment(segment); for out in border_set.iter() { let instance = sb.push_instance(*out); sb.push_out_arg(instance); } sb.finish_to(out_segment); synthesis.visit_segment(segment); } Some(synthesis) } } ================================================ FILE: libeir_passes/src/simplify_cfg/chain_graph/synthesis/single.rs ================================================ use super::super::{Chain, ChainGraph}; use super::{Synthesis, SynthesisStrategy}; use libeir_ir::{Function, LiveValues}; pub fn can_subsitute(graph: &ChainGraph, fun: &Function, chain: Chain) -> bool { let target = graph.target_block; let target_reads = fun.block_reads(target); let chain_data = &graph.chains[chain]; if fun.block_kind(target).unwrap().is_call() && chain_data.args.len() == target_reads.len() - 1 { chain_data .args .iter() .zip(target_reads.iter().skip(1)) .map(|(ch, val)| -> Option<()> { let ch = (*ch)?; let node; if let Some(to) = graph.get_uniform(*val) { node = to; } else { let start_node = graph.get_root(*val)?; node = graph.follow_chain(start_node, chain); } if node == ch { Some(()) } else { None } }) .all(|v| v.is_some()) } else { false } } /// A synthesis strategy that only handles the case of a single entry. /// This will inline the destination into the entry. /// /// Entry: /// Target OP /// pub struct SingleStrategy; impl SynthesisStrategy for SingleStrategy { fn try_run(&self, graph: &ChainGraph, fun: &Function, _live: &LiveValues) -> Option { if graph.chains.len() != 1 { return None; } let chain = graph.chains.keys().next().unwrap(); let mut synthesis = Synthesis::new(); let target = graph.target_block; let target_reads = fun.block_reads(target); if can_subsitute(graph, fun, chain) { // If the operation in the target is a call, and all arguments passed to // the call are equal to the entry edge, we can do a simple // substitution. synthesis.substitute(chain, target_reads[0]); } else { let segment = synthesis.create_entry_segment(chain, graph); let mut sb = synthesis.segment(segment); for target in graph.entry_edges.values() { sb.push_instance(*target); } sb.finish_target(true); synthesis.visit_segment(segment); } Some(synthesis) } } ================================================ FILE: libeir_passes/src/simplify_cfg/chain_graph/synthesis/terminating_target.rs ================================================ use log::trace; use libeir_ir::{Function, LiveValues}; use super::super::ChainGraph; use super::single::can_subsitute; use super::{Synthesis, SynthesisStrategy}; /// A synthesis strategy that specializes the target into every entry. /// This is only valid for target blocks that terminate/don't use any values /// from the chain. /// /// Entry1: Entry2: /// Target OP Target OP /// pub struct TerminatingTargetStrategy; impl SynthesisStrategy for TerminatingTargetStrategy { fn try_run(&self, graph: &ChainGraph, fun: &Function, live: &LiveValues) -> Option { // TODO change this to check outgoing values instead let target = graph.target_block; let target_reads = fun.block_reads(target); // This strategy can only be run if NONE of the values defined // conditionally in the graph are used outside of the target block. // We validate this by going through all outgoing edges, and checking // that none of the graph entry edges are live at those block heads. let bg = fun.block_graph(); for outgoing in bg.outgoing(target) { for val in live.live_at(outgoing).iter() { if graph.entry_edges.contains_key(&val) { return None; } } } // If the body has no reads from the chain, specialization is useless, // don't do it. fun.block_walk_nested_values::<_, ()>(target, &mut |val| { if graph.entry_edges.contains_key(&val) { Err(()) } else { Ok(()) } }) .err()?; trace!("TERMINATING TARGET STRATEGY"); let mut synthesis = Synthesis::new(); for chain in graph.chains.keys() { if can_subsitute(graph, fun, chain) { synthesis.substitute(chain, target_reads[0]); } else { let segment = synthesis.create_entry_segment(chain, graph); let mut sb = synthesis.segment(segment); for target in graph.entry_edges.values() { sb.push_instance(*target); } sb.finish_target(false); synthesis.visit_segment(segment); } } Some(synthesis) } } ================================================ FILE: libeir_passes/src/simplify_cfg/mod.rs ================================================ #![warn(warnings)] use std::collections::BTreeMap; use log::{debug, trace}; use bumpalo::Bump; use fnv::FnvBuildHasher; use hashbrown::HashMap; type BFnvHashMap<'bump, K, V> = HashMap; use libeir_ir::Value; use libeir_ir::{FunctionBuilder, MangleTo, Mangler, StandardFormatConfig}; use super::FunctionPass; mod analyze; mod chain_graph; mod rewrite; use chain_graph::synthesis::SynthesisStrategy; #[cfg(test)] mod tests; /// This pass is a powerful cleanup pass, it will do the following: /// - Inline closures /// - Remove needless call chains pub struct SimplifyCfgPass { map: BTreeMap, mangler: Mangler, bump: Option, } // Observations about the pass: // * A call to a block can serve "two purposes" from the point of view of this pass. // 1. A temporary rename within the call chain we are operating on. We don't really // care about the value in this case, it can be removed. // 2. A bind that blocks in the scope of the target block use. In this case we need // to make sure the value is always bound to a singular value that the code after // uses. // 3. Both. Needs to be handled exactly the same as 2. // // // The functionality of the pass (rewriting call chains), operates as follows: // 1. CFG analysis: // Locates subgraphs of the CFG that are call chains. // These call chains can take one of two forms: // * A cyclic graph: // This call chain ends in a cycle. This means there is a cycle without // control flow or side effects. Any entry edges to the call chain should // be rewritten to a call to a operation that sleeps the process forever. // * A tree: // This is a normal call chain ending in a single target block. // // The algorithm proceeds as follows for each tree: // 1. Value rename analysis: // Each edge in a call chain can have any number of value renames. // These form a set of conceptual "phi nodes", // `phi_map: Map>`. // 2. Let target_live be the live value set of the target block // 3. Generate rename map: // Repeat until stable: // * For every key k in the union between phi_nodes and target_live: // * For every entry (_, v) in the target set: // * If v is in phi_nodes: // * Add the entries of v to the entries in k // 4. Rewrite target: // Let there be two variables, call_target and call_args // * If the body of the target block is a call to a value // and // the set of args in the call is equal to the live set of the target: // Set call_target to the value of the call, and call_args to the args. // * Else: // Insert a new block with n arguments // where n is the number of elements in the rename map // Insert renames for the args into the mangler // Set call_target to the new block, and call_args to the elements in the // rename map // Copy target body to the new block // 5. Rewrite calls // * If: // * The call target is a value // * and for every read in the call that is a block, none of the phi // values for the chain are live in that block // Then: // * Replace any callee blocks directly with the value if the sigature matches // * Else, replace the body of callee blocks a call to the value // * Else, generate a new target block with all the chain phis as arguments, // insert mangle mappings for those new arguments. // For every entry edge into the chain, clear the body of the callee and // generate a call to the new target block impl SimplifyCfgPass { pub fn new() -> Self { SimplifyCfgPass { map: BTreeMap::new(), mangler: Mangler::new(), bump: Some(Bump::new()), } } } impl FunctionPass for SimplifyCfgPass { fn name(&self) -> &str { "simplify_cfg" } fn run_function_pass(&mut self, b: &mut FunctionBuilder) { self.simplify_cfg(b); } } impl SimplifyCfgPass { fn simplify_cfg(&mut self, b: &mut FunctionBuilder) { let mut bump = self.bump.take().unwrap(); let entry = b.fun().block_entry(); let graph = b.fun().live_block_graph(); let live = b.fun().live_values(); let block_order: Vec<_> = graph.dfs_post_order_iter().collect(); trace!("BLOCK ORDER {:?}", block_order); trace!("{}", b.fun().to_text(&mut StandardFormatConfig::default())); { let analysis = analyze::analyze_graph(&bump, b.fun(), &graph); trace!("analysis = {:#?}", analysis); trace!("analysis done"); for block in block_order.iter() { if let Some(_blocks) = analysis.trees.get(block) { let target = block; // Synthesize CFG for chain let graph = b.fun().live_block_graph(); let chain_graph = analyze::analyze_chain(&bump, *target, &b.fun(), &graph, &live, &analysis); let synthesis_impl = chain_graph::synthesis::compound::CompoundStrategy; let mut synthesis = synthesis_impl .try_run(&chain_graph, b.fun(), &live) .unwrap(); synthesis.postprocess(&chain_graph); trace!("{:#?}", synthesis); //// .. and apply it to the CFG. rewrite::rewrite(b, &mut self.map, *target, &chain_graph, &synthesis); trace!("{}", b.fun().to_text_standard()); } } trace!("rewrite done"); self.mangler.start(MangleTo(entry)); for (from, to) in self.map.iter() { self.mangler.add_rename(MangleTo(*from), MangleTo(*to)); } let new_entry = self.mangler.run(b); b.block_set_entry(new_entry); trace!("{}", b.fun().to_text_standard()); } self.map.clear(); bump.reset(); self.bump = Some(bump); } } ================================================ FILE: libeir_passes/src/simplify_cfg/rewrite.rs ================================================ use log::trace; use std::collections::BTreeMap; use libeir_ir::{Block, FunctionBuilder, Value}; use libeir_ir::{MangleTo, Mangler}; use libeir_util_datastructures::aux_traits::AuxImpl; use super::chain_graph::{ synthesis::{Instance, InstanceKind, SegmentBodyKind, SegmentHeadKind, Synthesis}, Chain, ChainGraph, Node, NodeKind, }; pub fn rewrite( b: &mut FunctionBuilder, map: &mut BTreeMap, target: Block, graph: &ChainGraph, synthesis: &Synthesis, ) { //let segment_set_pool = synthesis.segment_set_pool.as_ref().unwrap(); //let segments_back = synthesis.segments_back.as_ref().unwrap(); trace!("REWRITE {}", target); //println!("{:#?}", synthesis); //assert!(synthesis.segments[synthesis.order[0]].kind.is_out()); //assert!( // synthesis // .order // .iter() // .map(|s| &synthesis.segments[*s]) // .filter(|s| s.kind.is_out()) // .count() == 1 //); let mut segment_map = BTreeMap::new(); let mut global_map: BTreeMap = BTreeMap::new(); let mut local_map: BTreeMap = BTreeMap::new(); let mut entry_map: BTreeMap<(Chain, usize), Value> = BTreeMap::new(); let mut arg_buf = Vec::new(); let mut walker = crate::util::Walker::new(); let mut mangler = Mangler::new(); for (chain, to_value) in synthesis.substitutions.iter() { let chain_entry = graph.get_chain_entry_block(*chain); let from_value = b.value(chain_entry); map.insert(from_value, *to_value); } let loc = b.fun().block_location(target); for segment_id in synthesis.order.iter() { let segment = &synthesis.segments[*segment_id]; let block = b.block_insert(); b.block_set_location(block, loc); segment_map.insert(*segment_id, block); match segment.head { SegmentHeadKind::Entry { chain } => { let in_args = segment.in_args.as_slice(&synthesis.instance_pool); for (idx, in_arg) in in_args.iter().enumerate() { let instance = &synthesis.instances[*in_arg]; let key = (chain, idx); let arg = b.block_arg_insert(block); assert!(!entry_map.contains_key(&key)); entry_map.insert(key, arg); global_map.insert(*in_arg, arg); if instance.is_relevant() { let node = instance.node(); let node_kind = graph.node(node); match node_kind { NodeKind::EntryArg(entry_arg) => { assert!(entry_arg.chain == chain); assert!(entry_arg.arg_index == idx); } _ => unreachable!(), } } } } SegmentHeadKind::Intermediate => {} } } trace!("ENTRY MAP {:?}", entry_map); for (from, to) in graph.iter_uniform_mappings() { let to_kind = graph.node(to); match to_kind { NodeKind::Scope(value) => { trace!("Uniform mapping: {} -> {} ({})", from, to, value); map.insert(from, *value); } NodeKind::EntryArg(entry_arg) => { if synthesis.substitutions.contains_key(&entry_arg.chain) { continue; } let key = (entry_arg.chain, entry_arg.arg_index); trace!("Entry {:?}", key); let to_value = entry_map[&key]; trace!("Uniform mapping: {} -> {} ({})", from, to, to_value); map.insert(from, to_value); } _ => unreachable!(), } } for segment_id in synthesis.order.iter() { local_map.clear(); let segment = &synthesis.segments[*segment_id]; let segment_chains = segment.chains.bind(&synthesis.chain_set_pool); let all_chains = segment_chains.size() == graph.chain_count(); trace!("SEGMENT {} {:?}", segment_id, AuxImpl(segment, synthesis)); let block = segment_map[segment_id]; let block_val = b.value(block); let in_args = segment.in_args.as_slice(&synthesis.instance_pool); trace!("IN ARGS {:?}", in_args); match segment.head { SegmentHeadKind::Entry { chain } => { let old_block = graph.get_chain_entry_block(chain); let old_block_val = b.value(old_block); assert!(!map.contains_key(&old_block_val)); map.insert(old_block_val, block_val); for (idx, in_arg) in in_args.iter().enumerate() { let key = (chain, idx); let instance = &synthesis.instances[*in_arg]; match instance { InstanceKind::NotRelevant => (), // TODO InstanceKind::Arg { node, .. } => { let node = instance.node(); let arg = entry_map[&key]; global_map.insert(*in_arg, arg); local_map.insert(node, arg); } _ => unreachable!(), } } } SegmentHeadKind::Intermediate => { for (idx, in_arg) in in_args.iter().enumerate() { let instance = &synthesis.instances[*in_arg]; let arg = b.block_arg_insert(block); match instance { InstanceKind::NotRelevant => (), // TODO InstanceKind::Arg { node, .. } => { let node = instance.node(); global_map.insert(*in_arg, arg); local_map.insert(node, arg); } _ => unreachable!(), } } } } for external in segment.externals.as_slice(&synthesis.instance_pool) { let val = global_map[external]; let instance = &synthesis.instances[*external]; local_map.insert(instance.node(), val); } walker.clear(); for instance_id in segment.instances.as_slice(&synthesis.instance_pool) { let instance = &synthesis.instances[*instance_id]; walker.put(instance.node()); } let mut order: Vec = Vec::new(); while let Some(node_id) = walker.next() { if local_map.contains_key(&node_id) { continue; } order.push(node_id); let node = graph.node(node_id); match node { NodeKind::Phi(phi) => { let mut pred_node = None; for (chain, n_pred_node) in phi.entries.iter() { if segment_chains.contains(*chain) { if let Some(old_pred_node) = pred_node { assert!(*n_pred_node == old_pred_node); } pred_node = Some(*n_pred_node); } } if let Some(pred_node) = pred_node { walker.put(pred_node); } } _ => { for pred_node in graph.node(node_id).dependencies() { walker.put(pred_node); } } } } trace!("ORDER {:?}", order); for node_id in order.iter().rev() { match graph.node(*node_id) { NodeKind::Scope(value) => { local_map.insert(*node_id, *value); } NodeKind::EntryArg(entry_arg) => { assert!(local_map.contains_key(node_id)); //let key = (entry_arg.chain, entry_arg.arg_index); //if !local_map.contains_key(node_id) { // let new_entry_arg = entry_map[&key]; // local_map.insert(*node_id, new_entry_arg); //} } NodeKind::Phi(phi) => { trace!("PHI {:#?}, {:?}", phi, segment_chains); if let Some(select_node) = phi .entries .iter() .find(|(chain, _node)| segment_chains.contains(**chain)) .map(|(_chain, node)| *node) { let from_value = local_map[&select_node]; local_map.insert(*node_id, from_value); } else { unreachable!() //let from_value = phi.value.unwrap(); //local_map.insert(*node_id, from_value); } } NodeKind::Prim(prim) => { let mut map_value = |val| -> Option { let node = prim.dependencies.get(&val); node.map(|node| local_map[node]) }; let new_prim = b.value_map(prim.prim, &mut map_value); local_map.insert(*node_id, new_prim); } NodeKind::BlockCapture(bc) => { let capture; if all_chains || bc.dependencies.len() == 0 { for (from_val, to_node) in bc.dependencies.iter() { let to_val = local_map[to_node]; map.insert(*from_val, to_val); } capture = bc.capture; } else { mangler.start(MangleTo(bc.capture)); for (from_val, to_node) in bc.dependencies.iter() { let to_val = local_map[to_node]; mangler.add_rename(MangleTo(*from_val), MangleTo(to_val)); } trace!("blockcapturemangle!"); capture = mangler.run(b); } let capture_val = b.value(capture); local_map.insert(*node_id, capture_val); } } } for instance_id in segment.instances.as_slice(&synthesis.instance_pool) { let instance = &synthesis.instances[*instance_id]; global_map.insert(*instance_id, local_map[&instance.node()]); } match &segment.body { SegmentBodyKind::None => unreachable!(), SegmentBodyKind::Terminal { single: true } => { let mut map_value = |val| -> Option { let node = graph.get_root(val); node.map(|node| local_map[&node]) }; b.block_copy_body_map(target, block, &mut map_value); for (root_val, root_node) in graph.iter_roots() { let to_val = local_map[&root_node]; map.insert(root_val, to_val); } } SegmentBodyKind::Terminal { single: false } => { let mut map_value = |val| -> Option { let node = graph.get_root(val); node.map(|node| local_map[&node]) }; b.block_copy_body_map(target, block, &mut map_value); } SegmentBodyKind::ToIntermediate { to, out_args } => { let to_block = segment_map[to]; arg_buf.clear(); for instance_id in out_args.as_slice(&synthesis.instance_pool) { arg_buf.push(global_map[instance_id]); } b.op_call_flow(block, to_block, &arg_buf); } } } } ================================================ FILE: libeir_passes/src/simplify_cfg/tests.rs ================================================ use super::SimplifyCfgPass; use crate::FunctionPass; use libeir_ir::{parse_function_map_unwrap, parse_function_unwrap, StandardFormatConfig}; #[test] fn primop_in_chain() { let _ = env_logger::try_init(); let mut fun = parse_function_unwrap( " a'foo':a'bar'/1 { entry(%ret, %thr, %a): b2(%a); b2(%b): %prim = {%b}; b3(%prim); b3(%c): %ret(%c); } ", ); let mut b = fun.builder(); let mut simplify_cfg_pass = SimplifyCfgPass::new(); simplify_cfg_pass.run_function_pass(&mut b); let after = parse_function_unwrap( " a'foo':a'bar'/1 { entry(%ret, %thr, %a): %ret({%a}); } ", ); assert!(b .fun() .graph_eq(b.fun().block_entry(), &after, after.block_entry()) .is_ok()); } #[test] fn double_primop_in_chain() { let _ = env_logger::try_init(); let mut fun = parse_function_unwrap( " a'foo':a'bar'/1 { entry(%ret, %thr, %a): b2(%a); b2(%b): b3({%b}); b3(%c): b4({%c}); b4(%d): %ret(%d); } ", ); let mut b = fun.builder(); let mut simplify_cfg_pass = SimplifyCfgPass::new(); simplify_cfg_pass.run_function_pass(&mut b); let after = parse_function_unwrap( " a'foo':a'bar'/1 { entry(%ret, %thr, %a): %ret({{%a}}); } ", ); assert!(b .fun() .graph_eq(b.fun().block_entry(), &after, after.block_entry()) .is_ok()); } #[test] fn split_primop_in_chain() { let _ = env_logger::try_init(); let mut fun = parse_function_unwrap( " a'foo':a'bar'/3 { entry(%ret, %thr, %a, %b, %c): if_bool %a b_true b_false; b_true(): b_true1(%b); b_true1(%bb): b_join({%bb}); b_false(): b_false1(%c); b_false1(%cc): b_join({%cc}); b_join(%d): b_join1({%d}); b_join1(%dd): %ret(%dd); } ", ); let mut b = fun.builder(); let mut simplify_cfg_pass = SimplifyCfgPass::new(); simplify_cfg_pass.run_function_pass(&mut b); let after = parse_function_unwrap( " a'foo':a'bar'/3 { entry(%ret, %thr, %a, %b, %c): if_bool %a b_true b_false; b_true(): %ret({{%b}}); b_false(): %ret({{%c}}); } ", ); assert!(b .fun() .graph_eq(b.fun().block_entry(), &after, after.block_entry()) .is_ok()); } #[test] fn two_split_primop_in_chain() { let _ = env_logger::try_init(); let mut fun = parse_function_unwrap( " a'foo':a'bar'/5 { entry(%ret, %thr, %a, %b, %c, %B, %C): if_bool %a b_true b_false; b_true(): b_true1(%b, %B); b_true1(%bb, %BB): b_join({{%bb}, %BB}, {%BB}); b_false(): b_false1(%c, %C); b_false1(%cc, %CC): b_join({%cc}, {%CC}); b_join(%d, %e): b_join1({%d}, {%e}); b_join1(%dd, %ee): %ret({%dd, %ee}); } ", ); let mut b = fun.builder(); let mut simplify_cfg_pass = SimplifyCfgPass::new(); simplify_cfg_pass.run_function_pass(&mut b); let after = parse_function_unwrap( " a'foo':a'bar'/5 { entry(%ret, %thr, %a, %b, %c, %B, %C): if_bool %a b_true b_false; b_true(): %ret({{{{%b}, %B}}, {{%B}}}); b_false(): %ret({{{%c}}, {{%C}}}); } ", ); assert!(b .fun() .graph_eq(b.fun().block_entry(), &after, after.block_entry()) .is_ok()); } #[test] fn simple_tail_call_elimination() { let _ = env_logger::try_init(); let mut fun = parse_function_unwrap( " a'foo':a'bar'/0 { entry(%ret, %thr): a'foo':a'foo'/0(b2, b3); b2(%ret_arg): %ret(%ret_arg); b3(%thr_a, %thr_b, %thr_c): %thr(%thr_a, %thr_b, %thr_c); } ", ); let mut b = fun.builder(); let mut simplify_cfg_pass = SimplifyCfgPass::new(); simplify_cfg_pass.run_function_pass(&mut b); let after = parse_function_unwrap( " a'foo':a'bar'/0 { entry(%ret, %thr): a'foo':a'foo'/0(%ret, %thr); } ", ); assert!(b .fun() .graph_eq(b.fun().block_entry(), &after, after.block_entry()) .is_ok()); } #[test] fn tail_call_elimination() { let _ = env_logger::try_init(); let mut fun = parse_function_unwrap( " a'foo':a'bar'/0 { entry(%ret, %thr): b1(a'foo':a'foo'/0); b1(%fun): %fun(b2, b3); b2(%ret_arg): %ret(%ret_arg); b3(%thr_a, %thr_b, %thr_c): %thr(%thr_a, %thr_b, %thr_c); } ", ); let mut b = fun.builder(); let mut simplify_cfg_pass = SimplifyCfgPass::new(); simplify_cfg_pass.run_function_pass(&mut b); let after = parse_function_unwrap( " a'foo':a'bar'/0 { entry(%ret, %thr): a'foo':a'foo'/0(%ret, %thr); } ", ); assert!(b .fun() .graph_eq(b.fun().block_entry(), &after, after.block_entry()) .is_ok()); } #[test] fn recursive_simplification() { let _ = env_logger::try_init(); let mut fun = parse_function_unwrap( " a'foo':a'bar'/0 { entry(%ret, %thr): b(a'true'); b(%sec): if_bool %sec b_true b_false; b_false(): unreachable; b_true(): %ret(a'yay'); } ", ); let mut b = fun.builder(); let mut simplify_cfg_pass = SimplifyCfgPass::new(); simplify_cfg_pass.run_function_pass(&mut b); let after = parse_function_unwrap( " a'foo':a'bar'/0 { entry(%ret, %thr): %ret(a'yay'); } ", ); assert!(b .fun() .graph_eq(b.fun().block_entry(), &after, after.block_entry()) .is_ok()); } #[test] fn value_list_removal() { let _ = env_logger::try_init(); let mut fun = parse_function_unwrap( " a'foo':a'bar'/2 { entry(%ret, %thr, %a, %b): unpack <%a, %b> arity 2 => cont; cont(%aa, %bb): %ret(%aa); } ", ); let mut b = fun.builder(); let mut simplify_cfg_pass = SimplifyCfgPass::new(); simplify_cfg_pass.run_function_pass(&mut b); let after = parse_function_unwrap( " a'foo':a'bar'/2 { entry(%ret, %thr, %a, %b): %ret(%a); } ", ); assert!(b .fun() .graph_eq(b.fun().block_entry(), &after, after.block_entry()) .is_ok()); } #[test] fn partial_loop() { let _ = env_logger::try_init(); let mut fun = parse_function_unwrap( " a'foo':a'bar'/1 { block1(%3, %4, %5): block8(%5, []); block8(%30, %31): match %30 { [] => block11; }; block11(%36, %37): block28(%36); block28(%81): block17(%81); block17(%53): %54 = [%53 | %31]; block8(%37, %54); } ", ); let mut b = fun.builder(); let mut simplify_cfg_pass = SimplifyCfgPass::new(); simplify_cfg_pass.run_function_pass(&mut b); let after = parse_function_unwrap( " a'foo':a'bar'/1 { block1(%3, %4, %5): block8(%5, []); block8(%30, %31): match %30 { [] => block11; }; block11(%36, %37): %54 = [%36 | %31]; block8(%37, %54); } ", ); assert!(b .fun() .graph_eq(b.fun().block_entry(), &after, after.block_entry()) .is_ok()); } #[test] fn tight_partial_loop() { let _ = env_logger::try_init(); let mut fun = parse_function_unwrap( " a'foo':a'perms'/1 { block0(%1, %2, %3): block1(%3, []); block1(%5, %6): block2(); block2(): match %5 { [] => block3; }; block3(%9, %10): %14 = [%9 | %6]; block1(%10, %14); } ", ); let mut b = fun.builder(); let mut simplify_cfg_pass = SimplifyCfgPass::new(); simplify_cfg_pass.run_function_pass(&mut b); // let after = parse_function_unwrap(" //a'foo':a'perms'/1 { // block0(%1, %2, %3): // block1(%3, []); // block1(%5, %6): // match %5 { // [] => block3; // }; // block3(%9, %10): // %14 = [%9 | %6]; // block1(%10, %14); //} //"); let after = parse_function_unwrap( " a'foo':a'perms'/1 { block0(%1, %2, %3): block1(%3, []); block1(%5, %6): match %5 { [] => block3; }; block3(%9, %10): %14 = [%9 | %6]; block1(%10, %14); } ", ); assert!(b .fun() .graph_eq(b.fun().block_entry(), &after, after.block_entry()) .is_ok()); } #[test] fn deep_primop_rename_single_branch() { let _ = env_logger::try_init(); let mut fun = parse_function_unwrap( " a'foo':a'do_map_vars_used'/1 { block0(%1, %2, %3): block1(%3); block1(%5): block2(%5); block2(%7): %12 = {%7}; block3(%12); block3(%9): block4(%9); block4(%11): %13 = <>; match %11 {}; } ", ); let mut b = fun.builder(); let mut simplify_cfg_pass = SimplifyCfgPass::new(); simplify_cfg_pass.run_function_pass(&mut b); let after = parse_function_unwrap( " a'foo':a'do_map_vars_used'/1 { entry(%1, %2, %3): %4 = {%3}; match %4 {}; } ", ); assert!(b .fun() .graph_eq(b.fun().block_entry(), &after, after.block_entry()) .is_ok()); } #[test] fn deep_primop_rename_after_entry_single_branch() { let _ = env_logger::try_init(); let mut fun = parse_function_unwrap( " a'foo':a'do_map_vars_used'/1 { block0(%1, %2, %3): block1(%3); block1(%5): block2(%5); block2(%7): %15 = {%7}; block3(%15); block3(%9): block4(%9); block4(%11): %18 = ; %16 = <>; match [] { type %{} => block5; }; block5(): %19 = ; match [] { %{ %11} => block6; }; block6(%14): unreachable; } ", ); let mut b = fun.builder(); let mut simplify_cfg_pass = SimplifyCfgPass::new(); simplify_cfg_pass.run_function_pass(&mut b); let after = parse_function_unwrap( " a'foo':a'do_map_vars_used'/1 { entry(%1, %2, %3): match [] { type %{} => block1; }; block1(): %4 = {%3}; match [] { %{%4} => block2; }; block2(%5): unreachable; } ", ); assert!(b .fun() .graph_eq(b.fun().block_entry(), &after, after.block_entry()) .is_ok()); } #[test] fn converging_from_single() { let _ = env_logger::try_init(); let mut fun = parse_function_unwrap( " a'fib':a'fib'/1 { block21(%77, %78, %114): %64 = a'erlang':a'<'/2; %64(%114, 2) => block36 except block50; block50(%144, %145, %146): block36(a'false'); block36(%116): if_bool %116 block38 block39; block38(): unreachable; block39(): unreachable; } ", ); let mut b = fun.builder(); let mut simplify_cfg_pass = SimplifyCfgPass::new(); simplify_cfg_pass.run_function_pass(&mut b); let after = parse_function_unwrap( " a'fib':a'fib'/1 { block8(%26, %27, %28): %15 = a'erlang':a'<'/2; %15(%28, 2) => block13 except block12; block13(%38): if_bool %38 block9 block10; block12(%34, %35, %36): if_bool a'false' block9 block10; block9(): unreachable; block10(): unreachable; } ", ); assert!(b .fun() .graph_eq(b.fun().block_entry(), &after, after.block_entry()) .is_ok()); } #[test] fn basic_locations() { let _ = env_logger::try_init(); let opts = libeir_ir::GraphEqOptions { check_block_locations: true, }; // !location [\"foo\":\"foo\"@\"foo.erl\":1]; let mut fun = parse_function_unwrap( " a'foo':a'bar'/1 { !location [\"foo\":\"foo\"@\"foo.erl\":1]; entry(%ret, %thr, %a): b2(%a); !location [\"foo\":\"foo\"@\"foo.erl\":2]; b2(%b): b3({%b}); !location [\"foo\":\"foo\"@\"foo.erl\":3]; b3(%c): b4({%c}); !location [\"foo\":\"foo\"@\"foo.erl\":4]; b4(%d): %ret(%d); } ", ); let mut b = fun.builder(); let mut simplify_cfg_pass = SimplifyCfgPass::new(); simplify_cfg_pass.run_function_pass(&mut b); let after = parse_function_unwrap( " a'foo':a'bar'/1 { !location [\"foo\":\"foo\"@\"foo.erl\":4]; entry(%ret, %thr, %a): %ret({{%a}}); } ", ); let res = b .fun() .graph_eq_opts(b.fun().block_entry(), &after, after.block_entry(), &opts); assert!(res.is_ok()); } //#[test] //fn basic_locations() { // let _ = env_logger::try_init(); // // let opts = libeir_ir::GraphEqOptions { // check_block_locations: true, // }; // // // !location [\"foo\":\"foo\"@\"foo.erl\":1]; // // let mut fun = parse_function_unwrap( // " //a'foo':a'bar'/1 { // !location [\"foo\":\"foo\"@\"foo.erl\":1]; // entry(%ret, %thr, %a): // b2(%a); // !location [\"foo\":\"foo\"@\"foo.erl\":2]; // b2(%b): // b3({%b}); // !location [\"foo\":\"foo\"@\"foo.erl\":3]; // b3(%c): // b4({%c}); // !location [\"foo\":\"foo\"@\"foo.erl\":4]; // b4(%d): // %ret(%d); //} //", // ); // println!( // "before: \n {}========", // fun.to_text(&mut StandardFormatConfig::default()) // ); // let mut b = fun.builder(); // // let mut simplify_cfg_pass = SimplifyCfgPass::new(); // simplify_cfg_pass.run_function_pass(&mut b); // // let after = parse_function_unwrap( // " //a'foo':a'bar'/1 { // !location [\"foo\":\"foo\"@\"foo.erl\":4]; // entry(%ret, %thr, %a): // %ret({{%a}}); //} //", // ); // let res = b // .fun() // .graph_eq_opts(b.fun().block_entry(), &after, after.block_entry(), &opts); // // println!("{}", b.fun().to_text(&mut StandardFormatConfig::default())); // println!("============"); // println!("{}", after.to_text(&mut StandardFormatConfig::default())); // // println!("{:?}", res); // assert!(res.is_ok()); //} // Fails because of https://github.com/eirproject/eir/issues/24 #[test] fn block_capture_with_scope_in_chain() { let _ = env_logger::try_init(); let mut fun = parse_function_unwrap( " a'a':a'get_values'/1 { block1(%3, %4, %5): bn(%5); bn(%6): block7(%6); block7(%27): block58(block49); block58(%136): %3(%136); block49(%116, %117, %118): %47 = a'erlang':a'=:='/2; %47({%27, 1}, %118) => %116 except %117; } ", ); let mut b = fun.builder(); let mut simplify_cfg_pass = SimplifyCfgPass::new(); simplify_cfg_pass.run_function_pass(&mut b); b.fun().live_values(); } #[test] fn dynamic_ops() { use libeir_intern::Symbol; use libeir_ir::operation::binary_construct::{BinaryConstructFinish, BinaryConstructStart}; use libeir_ir::AtomTerm; use libeir_ir::{Function, FunctionBuilder, FunctionIdent, StandardFormatConfig}; let (mut fun, map) = parse_function_map_unwrap( " a'a':a'a'/1 { block1(%1, %2, %3): match %3 { value a'yay' => block2; }; block2(): block3(); block3(): block4(a'true'); block4(%4): if_bool %4 bt bf be; bf(): unreachable; be(): unreachable; bt(): block5(); block5(): unreachable; block6(%binref): unreachable; block7(%bin): unreachable; } ", ); let mut b = FunctionBuilder::new(&mut fun); let block5 = map.get_block("block5"); let block6 = map.get_block("block6"); let block7 = map.get_block("block7"); b.block_clear(block5); BinaryConstructStart::build_target(&mut b, block5, block6); let bin_ref = b.block_args(block6)[0]; b.block_clear(block6); BinaryConstructFinish::build_target(&mut b, block6, bin_ref, block7); println!("{}", b.fun().to_text(&mut StandardFormatConfig::default())); let mut simplify_cfg_pass = SimplifyCfgPass::new(); simplify_cfg_pass.run_function_pass(&mut b); println!("{}", b.fun().to_text(&mut StandardFormatConfig::default())); //@binary_construct_start(block6); //@binary_construct_finish(block7, %binref); } #[test] fn bbbb() { let _ = env_logger::try_init(); let mut fun = parse_function_unwrap( " a'a':a'a'/1 { block1(%3, %4, %5): block33(%5); block33(%101): unpack %101 arity 1 => block34; block34(%103): %47 = <>; %133 = ; match %103 { [] => block35; _ => block46; }; block46(): block71(); block71(): block47(a'true'); block47(%125): if_bool %125 block49 block50 block51; block51(): unreachable; block50(): block3(); block3(): trace_capture_raw block4; block4(%12): %4(a'error', a'function_clause', %12); block49(): block10(%103); block10(%37): block11(%37, []); block11(%39, %40): %41 = [] == %39; if_bool %41 block12 block13; block13(): %47 = <>; %49 = ; match %39 { [] => block14; _ => block15; }; block15(): trace_capture_raw block16; block16(%51): %4(a'error', a'function_clause', %51); block14(%45, %46): block52(%45); block52(%135): unpack %135 arity 1 => block53; block53(%137): block69(); block69(): block54(a'true'); block54(%139): if_bool %139 block56 block57 block58; block58(): unreachable; block57(): block17(); block17(): block11(%46, []); block56(): block20(%137); block20(%62): block21(%37, %40); block21(%64, %65): %66 = [] == %64; if_bool %66 block22 block23; block23(): %47 = <>; %73 = ; match %64 { [] => block24; _ => block25; }; block25(): trace_capture_raw block26; block26(%75): %4(a'error', a'function_clause', %75); block24(%70, %71): block59(%70); block59(%148): unpack %148 arity 1 => block60; block60(%150): block67(); block67(): block61(a'true'); block61(%152): if_bool %152 block63 block64 block65; block65(): unreachable; block64(): block27(); block27(): block21(%71, %40); block63(): block30(%150); block30(%86): %87 = [%86 | []]; %88 = [%62 | %87]; %89 = [%88 | %65]; block21(%71, %89); block22(): block11(%46, %65); block12(): %93 = a'lists':a'reverse'/1; %93(%40) => block31 except block32; block32(%97, %98, %99): %4(%97, %98, %99); block31(%95): block2(%95); block2(%7): %3(%7); block35(): block75(); block75(): block36(a'true'); block36(%106): if_bool %106 block38 block39 block40; block40(): unreachable; block39(): block73(); block73(): block41(a'true'); block41(%115): if_bool %115 block43 block44 block45; block45(): unreachable; block44(): block3(); block43(): block10(%103); block38(): block7(); block7(): block2([[] | []]); } ", ); let mut b = fun.builder(); let dot = libeir_ir::text::function_to_dot(b.fun()); println!("{}", dot); let mut simplify_cfg_pass = SimplifyCfgPass::new(); simplify_cfg_pass.run_function_pass(&mut b); } #[test] fn cccc() { let _ = env_logger::try_init(); let mut fun = parse_function_unwrap( " a'a':a'underscore'/1 { block55(%154, %155, %156): block83(%156); block83(%214): unpack %214 arity 1 => block84; block84(%216): block138(); block138(): %27 = a'erlang':a'is_list'/1; %27(%216) => block85 except block137; block137(%307, %308, %309): block85(a'false'); block85(%218): if_bool %218 block87 block88 block89; block89(): unreachable; block88(): block56(); block56(): trace_capture_raw block82; block82(%208): %155(a'error', a'function_clause', %208); block87(): block58(%216); block58(%163): block90(%163); block90(%227): unpack %227 arity 1 => block91; block91(%229): %233 = <>; %255 = ; match %229 { [] => block92; value [] => block98; _ => block104; }; block104(): block59(); block59(): trace_capture_raw block80; block80(%202): %209 = {a'case_clause', %163}; %155(a'error', %209, %202); block98(): block131(); block131(): block99(a'true'); block99(%246): if_bool %246 block101 block102 block103; block103(): unreachable; block102(): block59(); block101(): block60(); block60(): %51 = a'erlang':a'length'/1; %51(%163) => block61 except %155; block61(%167): block119(%167); block119(%283): unpack %283 arity 1 => block120; block120(%285): block129(); block129(): block121(a'true'); block121(%287): if_bool %287 block123 block124 block125; block125(): unreachable; block124(): block62(); block62(): trace_capture_raw block78; block78(%197): %210 = {a'badmatch', %167}; %155(a'error', %210, %197); block123(): block72(); block72(): block71(); block71(): %27 = a'erlang':a'is_list'/1; %27(%163) => block66 except %155; block66(%174): block112(%174); block112(%270): unpack %270 arity 1 => block113; block113(%272): block127(); block127(): block114(a'true'); block114(%274): if_bool %274 block116 block117 block118; block118(): unreachable; block117(): block67(); block67(): trace_capture_raw block70; block70(%181): %212 = {a'badmatch', %174}; %155(a'error', %212, %181); block116(): block68(); block68(): %154(a'ok'); block92(%231, %232): block135(); block135(): block93(a'true'); block93(%235): if_bool %235 block95 block96 block97; block97(): unreachable; block96(): block59(); block95(): block63(); block63(): %80 = a'erlang':a'list_to_tuple'/1; %80(%163) => block64 except %155; block64(%171): block105(%171); block105(%257): unpack %257 arity 1 => block106; block106(%259): block133(); block133(): block107(a'true'); block107(%261): if_bool %261 block109 block110 block111; block111(): unreachable; block110(): block65(); block65(): trace_capture_raw block75; block75(%189): %211 = {a'badmatch', %171}; %155(a'error', %211, %189); block109(): block73(); block73(): block71(); } ", ); let mut b = fun.builder(); let mut simplify_cfg_pass = SimplifyCfgPass::new(); simplify_cfg_pass.run_function_pass(&mut b); let mut errs = Vec::new(); b.fun().validate(&mut errs); println!("{:?}", errs); assert!(errs.len() == 0) } #[test] fn terminating_strategy_checks_live_in_outgoing() { let _ = env_logger::try_init(); let mut fun = parse_function_unwrap( r#" a'a':a'a'/2 { block1(%3, %4, %5, %6): if_bool %5 block16 block17; block16(): block10(1); block17(): block10(2); block10(%41): %6() => block11 except unr3; block11(%44): %3(%41); unr3(%a, %b, %c): unreachable; } "#, ); let mut b = fun.builder(); let mut errs = Vec::new(); b.fun().validate(&mut errs); println!("{:?}", errs); assert!(errs.len() == 0); let mut simplify_cfg_pass = SimplifyCfgPass::new(); simplify_cfg_pass.run_function_pass(&mut b); let mut errs = Vec::new(); b.fun().validate(&mut errs); println!("{:?}", errs); assert!(errs.len() == 0); } ================================================ FILE: libeir_passes/src/util.rs ================================================ use std::collections::{BTreeMap, BTreeSet}; #[derive(Debug)] pub struct EdgeSet(pub BTreeMap); impl EdgeSet { pub fn new() -> Self { Self(BTreeMap::new()) } pub fn insert(&mut self, key: T, val: T) { self.0.insert(key, val); } pub fn propagate_edges(&mut self) { let froms: Vec<_> = self.0.keys().cloned().collect(); loop { let mut change = false; for from in froms.iter() { let first = *self.0.get(from).unwrap(); if let Some(second) = self.0.get(&first).cloned() { self.0.insert(*from, second); change = true; } } if !change { break; } } } } pub struct Walker { pub walked: BTreeSet, pub to_walk: Vec, } impl Walker where T: Ord, { pub fn new() -> Self { Walker::with(Vec::new()) } pub fn with(to_walk: Vec) -> Self { Self { walked: BTreeSet::new(), to_walk, } } pub fn clear(&mut self) { self.walked.clear(); self.to_walk.clear(); } pub fn put(&mut self, t: T) { if !self.walked.contains(&t) { self.to_walk.push(t); } } pub fn next(&mut self) -> Option { while let Some(t) = self.to_walk.pop() { if self.walked.contains(&t) { continue; } return Some(t); } None } } ================================================ FILE: libeir_passes/src/validate.rs ================================================ use super::FunctionPass; use libeir_ir::{FunctionBuilder, ValidationError}; use log::error; pub struct ValidatePass { err_buf: Vec, } impl ValidatePass { pub fn new() -> Self { ValidatePass { err_buf: Vec::new(), } } } impl FunctionPass for ValidatePass { fn name(&self) -> &str { "validate" } fn run_function_pass(&mut self, b: &mut FunctionBuilder) { self.err_buf.clear(); b.fun().validate(&mut self.err_buf); for err in self.err_buf.iter() { error!("Validation pass error: {:?}", err); } assert!(self.err_buf.len() == 0); } } ================================================ FILE: libeir_syntax_core/Cargo.toml ================================================ [package] name = "libeir_syntax_core" version = "0.1.0" authors = ["Hans Elias B. Josephsen "] edition = "2018" build = "build.rs" [build-dependencies] lalrpop = "0.16.3" [dependencies] libeir_ir = { path = "../libeir_ir" } lalrpop-util = "0.16.3" lazy_static = "1.1.0" regex = "0.2.0" num = "0.2" num-traits = "0.2" num-bigint = "0.2" ================================================ FILE: libeir_syntax_core/build.rs ================================================ //extern crate peg; extern crate lalrpop; fn main() { lalrpop::Configuration::new() .force_build(true) .generate_in_source_tree() .process_file("src/parser/grammar.lalrpop") .unwrap(); //lalrpop::process_root().unwrap(); //peg::cargo_build("src/parser/grammar.rustpeg", true); println!("cargo:rerun-if-changed=src/parser/grammar.lalrpop"); } ================================================ FILE: libeir_syntax_core/src/ast.rs ================================================ use eir::{ Atom, Variable }; #[derive(Debug, Copy, Clone)] pub enum MapExactAssoc { Exact, Assoc, } #[derive(Debug, Clone)] pub struct Annotated(pub I, pub Vec<()>); impl Annotated { pub fn empty(inner: I) -> Self { Annotated(inner, Vec::new()) } } #[derive(Debug, Clone)] pub struct Module { pub name: Atom, pub declarations: Vec, pub attributes: Vec<(Atom, Constant)>, pub definitions: Vec, } #[derive(Debug, Clone, Hash, PartialEq, Eq)] pub struct FunctionName { pub name: Atom, pub arity: usize, } //impl FunctionName { // pub fn to_eir(&self, module: Atom) -> FunctionIdent { // FunctionIdent { // module: module, // name: self.name.clone(), // arity: self.arity, // lambda: None, // } // } //} #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct Integer { pub sign: bool, pub digits: String, } impl Integer { pub fn as_u32(&self) -> u32 { assert!(self.sign); self.digits.parse().unwrap() } pub fn as_usize(&self) -> usize { assert!(self.sign); self.digits.parse().unwrap() } } use eir::{ AtomicTerm, ConstantTerm }; type AtomicLiteral = AtomicTerm; //#[derive(Debug, Clone, PartialEq, Eq, Hash)] //pub enum AtomicLiteral { // Integer(Integer), // Float, // Atom(Atom), // Nil, // Char(char), // String(String), //} //impl Display for AtomicLiteral { // fn fmt(&self, f: &mut Formatter) -> Result<(), ::std::fmt::Error> { // match self { // &AtomicLiteral::Integer(ref int) => write!(f, "{}{}", int.sign, int.digits), // _ => write!(f, "unimpl"), // } // } //} #[derive(Debug, Clone)] pub enum Constant { Atomic(AtomicLiteral), Tuple(Vec), List(Vec, Box), } //impl Constant { // pub fn to_eir(&self) -> ConstantTerm { // match self { // Constant::Atomic(atomic) => ConstantTerm::Atomic(atomic.clone()), // Constant::List(head, tail) => // ConstantTerm::List( // head.iter().map(|c| c.to_eir()).collect(), // Box::new(tail.to_eir()), // ), // _ => unimplemented!(), // } // } //} //impl Display for Constant { // fn fmt(&self, f: &mut Formatter) -> Result<(), ::std::fmt::Error> { // match self { // &Constant::Atomic(ref lit) => write!(f, "{}", lit), // _ => write!(f, "unimpl"), // } // } //} #[derive(Debug, Clone)] pub struct FunctionDefinition { pub name: Annotated, pub fun: Annotated, } #[derive(Debug, Clone)] pub enum SingleExpression { // Env reading FunctionName(FunctionName), ExternalFunctionName { module: Atom, name: FunctionName }, Variable(Variable), // Control flow Let { vars: Vec>, val: Box, body: Box }, Catch(Box), Case { val: Box, clauses: Vec> }, Do(Box, Box), Try { body: Box, then_vars: Vec>, then: Box, catch_vars: Vec>, catch: Box }, Receive { clauses: Vec>, timeout_time: Box, timeout_body: Box }, // Calling PrimOpCall(PrimOpCall), ApplyCall { fun: Box, args: Vec }, InterModuleCall { module: Box, name: Box, args: Vec }, // Lambda creation Fun(Box), LetRec { funs: Vec<(FunctionName, Function)>, body: Box }, // Term constructors AtomicLiteral(AtomicLiteral), Tuple(Vec), List { head: Vec, tail: Box }, Map(Vec>, Option), Binary(Vec<(Expression, Vec)>), } #[derive(Debug, Clone)] pub struct CaseClause { pub patterns: Vec>, pub guard: Expression, pub body: Expression, } #[derive(Debug, Clone)] pub enum Pattern { Wildcard, BindVar(Annotated, Box>), Atomic(AtomicLiteral), Binary(Vec<(Annotated, Vec>)>), Tuple(Vec>), List(Vec>, Box>), Map(Vec, Annotated)>>), } impl Pattern { pub fn nil() -> Annotated { Annotated::empty(Pattern::Atomic(AtomicTerm::Nil)) } } pub type Expression = Annotated>>; impl Expression { pub fn nil() -> Self { Annotated::empty(vec![Annotated::empty(SingleExpression::AtomicLiteral( AtomicTerm::Nil))]) } } #[derive(Debug, Clone)] pub struct Function { pub vars: Vec>, pub body: Expression, } #[derive(Debug, Clone)] pub struct PrimOpCall { pub name: Annotated, pub args: Vec, } ================================================ FILE: libeir_syntax_core/src/lexer.rs ================================================ use regex::Regex; use std::str::CharIndices; use lazy_static::lazy_static; lazy_static! { static ref TEST: Regex = Regex::new("...").unwrap(); } #[derive(Clone, PartialEq, Eq, Debug)] pub enum Tok<'input> { // Keywords Module, Attributes, Fun, Case, Call, Apply, When, End, Catch, Do, Let, In, Of, Primop, Try, Receive, After, Letrec, // Identifiers/atomics Atom(&'input str), Variable(&'input str), Integer((bool, &'input str)), Float(&'input str), Char(char), String(&'input str), // Symbols ParenOpen, ParenClose, CurlyOpen, CurlyClose, SquareOpen, SquareClose, TriOpen, TriClose, MapOpen, MapMatch, MapClose, BitstringOpen, BitstringClose, BitstringPatternOpen, BitstringPatternSep, Annotation, Colon, Comma, ForwardSlash, Equals, Pipe, Arrow, HashRocket, } const KEYWORDS: &'static [(&'static str, Tok<'static>)] = &[ ("module", Tok::Module), ("attributes", Tok::Attributes), ("fun", Tok::Fun), ("case", Tok::Case), ("call", Tok::Call), ("apply", Tok::Apply), ("when", Tok::When), ("end", Tok::End), ("catch", Tok::Catch), ("do", Tok::Do), ("let", Tok::Let), ("in", Tok::In), ("of", Tok::Of), ("primop", Tok::Primop), ("try", Tok::Try), ("receive", Tok::Receive), ("after", Tok::After), ("letrec", Tok::Letrec), ]; fn is_escapechar(c: char) -> bool { c == 'b' || c == 'd' || c == 'e' || c == 'f' || c == 'n' || c == 'r' || c == 's' || c == 't' || c == 'v' || c == '"' || c == '\'' || c == '\\' } fn is_control(c: char) -> bool { c >= '\u{0000}' && c <= '\u{001f}' } fn is_inputchar(c: char) -> bool { c != '\n' && c != '\r' } fn is_digit(c: char) -> bool { c >= '0' && c <= '9' } fn is_octal(c: char) -> bool { c >= '0' && c <= '7' } fn is_uppercase(c: char) -> bool { (c >= 'A' && c <= 'Z') || (c >= '\u{00c0}' && c <= '\u{00d6}') || (c >= '\u{00d8}' && c <= '\u{00de}') } fn is_lowercase(c: char) -> bool { (c >= 'a' && c <= 'z') || (c >= '\u{00df}' && c <= '\u{00f6}') || (c >= '\u{00f8}' && c <= '\u{00ff}') } fn is_namechar(c: char) -> bool { is_uppercase(c) || is_lowercase(c) || is_digit(c) || (c == '@') || (c == '_') } pub struct Tokenizer<'input> { text: &'input str, chars: CharIndices<'input>, next: Option<(usize, char)>, } impl<'input> Tokenizer<'input> { pub fn new(text: &'input str) -> Self { let mut t = Tokenizer { text: text, chars: text.char_indices(), next: None, }; t.bump(); t } fn bump(&mut self) -> Option<(usize, char)> { self.next = self.chars.next(); self.next } fn bump_escape(&mut self) -> Result<(), ()> { match self.bump() { Some((_idx0, '^')) => { match self.bump() { Some((_idx1, c)) if c >= '\u{0040}' && c <= '\u{005f}' => { self.bump(); Ok(()) } _ => Err(()), } } Some((_idx0, c)) if is_octal(c) => { match self.bump() { Some((_idx1, c)) if is_octal(c) => { match self.bump() { Some((_idx1, c)) if is_octal(c) => { self.bump(); Ok(()) } _ => Ok(()), } } _ => Ok(()), } }, Some((_idx0, c)) if is_escapechar(c) => { self.bump(); Ok(()) } _ => Err(()), } } fn take_while(&mut self, fun: F) -> &'input str where F: Fn(char) -> bool { let start = self.next.unwrap().0; let mut end = self.next.unwrap().0; loop { match self.next { Some((idx0, c)) if fun(c) => { end = idx0; self.bump(); } Some((idx0, _c)) => { end = idx0; break; } None => { end += 1; // TODO: Very wrong for unicode break; } } } return &self.text[start..end]; } fn next_token(&mut self) -> Option, usize), ()>> { 'outer: loop { return match self.next { // Keywords and variables Some((idx0, c)) if is_namechar(c) && !is_digit(c) => { let mut end = idx0; 'inner: loop { match self.bump() { Some((idx1, c)) if is_namechar(c) => { end = idx1; } Some((idx1, _)) => { end = idx1; break 'inner; } None => { end += 1; break 'inner; } } } let word = &self.text[idx0..end]; // Check for keywords let kw = KEYWORDS.iter() .filter(|&&(w, _)| w == word) .next(); if let Some((_, kw)) = kw { return Some(Ok((idx0, kw.clone(), end))); } // Variable if is_uppercase(c) || c == '_' { return Some(Ok((idx0, Tok::Variable(word), end))); } Some(Err(())) } // Atoms Some((idx0, '\'')) => { self.bump(); let end; loop { match self.next { Some((_idx1, '\\')) => { match self.bump_escape() { Ok(()) => (), Err(()) => return Some(Err(())), } } Some((idx1, '\'')) => { self.bump(); end = idx1 + 1; // TODO: Very very wrong for unicode break; } Some((_idx1, c)) if is_control(c) => return Some(Err(())), Some((_idx1, c)) if is_inputchar(c) => { self.bump(); } _ => return Some(Err(())), } } let atom = &self.text[idx0+1..end-1]; Some(Ok((idx0, Tok::Atom(atom), end))) } // Numbers Some((idx0, c)) if is_digit(c) => { let string = self.take_while(is_digit); Some(Ok((idx0, Tok::Integer((true, string)), idx0+1))) } Some((idx0, '+')) => { match self.bump() { Some((idx1, c)) if is_digit(c) => { let string = self.take_while(is_digit); Some(Ok((idx0, Tok::Integer((true, string)), idx1+1))) } _ => return Some(Err(())), } } // Symbols Some((idx0, '(')) => { self.bump(); Some(Ok((idx0, Tok::ParenOpen, idx0+1))) } Some((idx0, ')')) => { self.bump(); Some(Ok((idx0, Tok::ParenClose, idx0+1))) } Some((idx0, '{')) => { self.bump(); Some(Ok((idx0, Tok::CurlyOpen, idx0+1))) } Some((idx0, '~')) => { match self.bump() { Some((idx1, '{')) => { self.bump(); Some(Ok((idx0, Tok::MapOpen, idx1+1))) } _ => return Some(Err(())), } } Some((idx0, '}')) => { match self.bump() { Some((idx1, '#')) => { self.bump(); Some(Ok((idx0, Tok::BitstringClose, idx1+1))) } Some((idx1, '~')) => { self.bump(); Some(Ok((idx0, Tok::MapClose, idx1+1))) } _ => { Some(Ok((idx0, Tok::CurlyClose, idx0+1))) } } } Some((idx0, '[')) => { self.bump(); Some(Ok((idx0, Tok::SquareOpen, idx0+1))) } Some((idx0, ']')) => { self.bump(); Some(Ok((idx0, Tok::SquareClose, idx0+1))) } Some((idx0, '#')) => { match self.bump() { Some((idx1, '{')) => { self.bump(); Some(Ok((idx0, Tok::BitstringOpen, idx1+1))) } Some((idx1, '<')) => { self.bump(); Some(Ok((idx0, Tok::BitstringPatternOpen, idx1+1))) } _ => Some(Err(())), } } Some((idx0, '>')) => { match self.bump() { Some((idx1, '(')) => { self.bump(); Some(Ok((idx0, Tok::BitstringPatternSep, idx1+1))) } _ => Some(Ok((idx0, Tok::TriClose, idx0+1))), } } Some((idx0, '<')) => { self.bump(); Some(Ok((idx0, Tok::TriOpen, idx0+1))) } Some((idx0, ':')) => { match self.bump() { Some((idx1, '=')) => { self.bump(); Some(Ok((idx0, Tok::MapMatch, idx1+1))) } _ => Some(Ok((idx0, Tok::Colon, idx0+1))) } } Some((idx0, '-')) => { match self.bump() { Some((idx1, '|')) => { self.bump(); Some(Ok((idx0, Tok::Annotation, idx1+1))) } Some((idx1, '>')) => { self.bump(); Some(Ok((idx0, Tok::Arrow, idx1+1))) } Some((idx1, c)) if is_digit(c) => { let string = self.take_while(is_digit); Some(Ok((idx0, Tok::Integer((false, string)), idx1+1))) } _ => Some(Err(())), } } Some((idx0, ',')) => { self.bump(); Some(Ok((idx0, Tok::Comma, idx0+1))) } Some((idx0, '/')) => { self.bump(); Some(Ok((idx0, Tok::ForwardSlash, idx0+1))) } Some((idx0, '=')) => { match self.bump() { Some((idx1, '>')) => { self.bump(); Some(Ok((idx0, Tok::HashRocket, idx1+1))) } _ => Some(Ok((idx0, Tok::Equals, idx0+1))), } } Some((idx0, '|')) => { self.bump(); Some(Ok((idx0, Tok::Pipe, idx0+1))) } // Supressed Some((_idx0, '%')) => { loop { match self.bump() { Some((_idx1, '\n')) => { continue 'outer; } Some((_idx1, '\r')) => { continue 'outer; } _ => (), } } } Some((_idx0, c)) if c == ' ' || c == '\t' => { loop { match self.bump() { Some((_idx1, ' ')) => (), Some((_idx1, '\t')) => (), _ => continue 'outer, } } } Some((_idx1, '\n')) => { self.bump(); continue 'outer; } Some((_idx1, '\r')) => { match self.bump() { Some((_idx2, '\n')) => { self.bump(); continue 'outer; } _ => continue 'outer, } } None => None, c => unimplemented!("{:?}", c), } } } } impl<'input> Iterator for Tokenizer<'input> { type Item = Result<(usize, Tok<'input>, usize), ()>; fn next(&mut self) -> Option, usize), ()>> { self.next_token() } } #[test] fn test_symbols() { let text = "( ) { } [ ] #{ }# #< >( -| , / ="; let mut tok = Tokenizer::new(&text); assert!(tok.next_token().unwrap().unwrap().1 == Tok::ParenOpen); assert!(tok.next_token().unwrap().unwrap().1 == Tok::ParenClose); assert!(tok.next_token().unwrap().unwrap().1 == Tok::CurlyOpen); assert!(tok.next_token().unwrap().unwrap().1 == Tok::CurlyClose); assert!(tok.next_token().unwrap().unwrap().1 == Tok::SquareOpen); assert!(tok.next_token().unwrap().unwrap().1 == Tok::SquareClose); assert!(tok.next_token().unwrap().unwrap().1 == Tok::BitstringOpen); assert!(tok.next_token().unwrap().unwrap().1 == Tok::BitstringClose); assert!(tok.next_token().unwrap().unwrap().1 == Tok::BitstringPatternOpen); assert!(tok.next_token().unwrap().unwrap().1 == Tok::BitstringPatternSep); assert!(tok.next_token().unwrap().unwrap().1 == Tok::Annotation); assert!(tok.next_token().unwrap().unwrap().1 == Tok::Comma); assert!(tok.next_token().unwrap().unwrap().1 == Tok::ForwardSlash); assert!(tok.next_token().unwrap().unwrap().1 == Tok::Equals); assert!(tok.next_token() == None); } #[test] fn test_keywords() { // Common path, don't bother testing all let text = "module attributes fun case call of primop"; let mut tok = Tokenizer::new(&text); assert!(tok.next_token().unwrap().unwrap().1 == Tok::Module); assert!(tok.next_token().unwrap().unwrap().1 == Tok::Attributes); assert!(tok.next_token().unwrap().unwrap().1 == Tok::Fun); assert!(tok.next_token().unwrap().unwrap().1 == Tok::Case); assert!(tok.next_token().unwrap().unwrap().1 == Tok::Call); assert!(tok.next_token().unwrap().unwrap().1 == Tok::Of); assert!(tok.next_token().unwrap().unwrap().1 == Tok::Primop); assert!(tok.next_token() == None); } #[test] fn test_atoms() { let text = "'something' '\\'' '\\5' '\\55' '\\555' '\\n' '\\^@' '\\^H' '\\^_'"; let mut tok = Tokenizer::new(&text); assert!(tok.next_token().unwrap().unwrap().1 == Tok::Atom("something")); assert!(tok.next_token().unwrap().unwrap().1 == Tok::Atom("\\'")); assert!(tok.next_token().unwrap().unwrap().1 == Tok::Atom("\\5")); assert!(tok.next_token().unwrap().unwrap().1 == Tok::Atom("\\55")); assert!(tok.next_token().unwrap().unwrap().1 == Tok::Atom("\\555")); assert!(tok.next_token().unwrap().unwrap().1 == Tok::Atom("\\n")); assert!(tok.next_token().unwrap().unwrap().1 == Tok::Atom("\\^@")); assert!(tok.next_token().unwrap().unwrap().1 == Tok::Atom("\\^H")); assert!(tok.next_token().unwrap().unwrap().1 == Tok::Atom("\\^_")); assert!(tok.next_token() == None); } #[test] fn test_variables() { let text = "Abc ABC _abcd A@_cD"; let mut tok = Tokenizer::new(&text); assert!(tok.next_token().unwrap().unwrap().1 == Tok::Variable("Abc")); assert!(tok.next_token().unwrap().unwrap().1 == Tok::Variable("ABC")); assert!(tok.next_token().unwrap().unwrap().1 == Tok::Variable("_abcd")); assert!(tok.next_token().unwrap().unwrap().1 == Tok::Variable("A@_cD")); assert!(tok.next_token() == None); } #[test] fn test_lex_compile_core_file() { use ::std::io::Read; let mut f = ::std::fs::File::open("../test_data/compile.core").unwrap(); let mut s = String::new(); f.read_to_string(&mut s); let mut tok = Tokenizer::new(&s); loop { let res = tok.next_token(); println!("{:?}", res); assert!(res != Some(Err(()))); if (res == None) { break; } } } ================================================ FILE: libeir_syntax_core/src/lib.rs ================================================ pub use eir::Atom; use eir::FunctionIdent; mod lexer; mod parser; mod ast; mod lower_hir; ================================================ FILE: libeir_syntax_core/src/lower_hir.rs ================================================ use ::std::collections::HashSet; use ::{ Atom }; use ::ir::{ Module, AVariable, AFunctionName, FunctionDefinition, FunctionVisibility, FunctionIdent }; use ::ir::hir::{ SingleExpression, SingleExpressionKind, Function, Pattern, PatternNode, Closure }; use ::ssa::INVALID_SSA; impl Module { fn from_parsed(module: &::parser::Module) -> Self { let exported: HashSet<(Atom, usize)> = module.declarations.iter() .map(|f| (f.name.clone(), f.arity)).collect(); Module { name: module.name.clone(), attributes: module.attributes.clone(), functions: module.definitions.iter() .map(|f| { let name = f.name.0.name.clone(); let arity = f.name.0.arity; let is_visible = exported.contains(&(name.clone(), arity)); let fun_ident = FunctionIdent { module: module.name.clone(), name: name, arity: arity, lambda: None, }; FunctionDefinition { visibility: if is_visible { FunctionVisibility::Public } else { FunctionVisibility::Private }, hir_fun: ::ir::hir::Function::from_parsed(&f.fun.0, &fun_ident), ident: fun_ident, lambda_env_idx: None, eir_fun: None, } }).collect(), envs: None, } } } impl Function { fn from_parsed(fun: &::parser::Function, fun_ident: &FunctionIdent) -> Self { Function { args: fun.vars.iter().map(|a| AVariable::new(a.0.clone())).collect(), body: SingleExpression::from_parsed(&fun.body, fun_ident), } } } fn pat_node_from_parsed(node: &::parser::Pattern, values: &mut Vec, fun_ident: &FunctionIdent) -> PatternNode { let wildcard: ::parser::Variable = Atom::from("_"); use ::parser::Pattern as PP; match *node { PP::Atomic(ref a) => PatternNode::Atomic(a.clone()), PP::Wildcard => PatternNode::Wildcard, PP::BindVar(ref var, ref pat) if var.0 == wildcard => pat_node_from_parsed(&pat.0, values, fun_ident), PP::BindVar(ref var, ref pat) => PatternNode::BindVar(var.0.clone(), Box::new( pat_node_from_parsed(&pat.0, values, fun_ident))), PP::Binary(ref elems) => { PatternNode::Binary( elems.iter().map(|(pat, opts)| { let opts_n = opts.iter().map(|o| { let curr_val_num = values.len(); values.push(SingleExpression::from_parsed_single(&o.0, fun_ident)); curr_val_num }).collect(); (pat_node_from_parsed(&pat.0, values, fun_ident), opts_n) }).collect(), ) }, PP::Tuple(ref pats) => PatternNode::Tuple( pats.iter().map(|p| pat_node_from_parsed(&p.0, values, fun_ident)).collect() ), PP::List(ref pats, ref tail) => PatternNode::List( pats.iter().map(|p| pat_node_from_parsed(&p.0, values, fun_ident)).collect(), Box::new(pat_node_from_parsed(&tail.0, values, fun_ident)) ), PP::Map(ref kvs) => { PatternNode::Map( kvs.iter().map(|kv| { let curr_val_num = values.len(); values.push(SingleExpression::from_parsed_single(&((kv.0).0).0, fun_ident)); ( curr_val_num, Box::new(pat_node_from_parsed(&((kv.0).1).0, values, fun_ident)) ) }).collect(), ) }, } } impl Pattern { fn from_parsed(pat: &::parser::Pattern, values: &mut Vec, fun_ident: &FunctionIdent) -> Self { let node = pat_node_from_parsed(pat, values, fun_ident); let binds = node.get_bind_vars(); Pattern { binds: binds.iter().map(|v| (v.clone(), INVALID_SSA)).collect(), node: node, } } } use ::parser::SingleExpression as PSE; impl SingleExpression { fn from_parsed_single(expr: &PSE, fun_ident: &FunctionIdent) -> SingleExpression { let kind = match *expr { PSE::Variable(ref v) => SingleExpressionKind::Variable(AVariable::new(v.clone())), PSE::FunctionName(ref f) => { let ident = FunctionIdent { module: fun_ident.module.clone(), name: f.name.clone(), arity: f.arity, lambda: None, }; SingleExpressionKind::NamedFunction { name: AFunctionName::new(ident), is_lambda: false, } }, PSE::ExternalFunctionName { ref module, ref name } => { SingleExpressionKind::ExternalNamedFunction { name: AFunctionName::new(name.to_eir(module.clone())), } } PSE::AtomicLiteral(ref a) => SingleExpressionKind::Atomic(a.clone()), PSE::InterModuleCall { ref module, ref name, ref args } => SingleExpressionKind::InterModuleCall { module: Box::new(SingleExpression::from_parsed(&module, fun_ident)), name: Box::new(SingleExpression::from_parsed(&name, fun_ident)), args: args.iter() .map(|a| SingleExpression::from_parsed(a, fun_ident)) .collect(), }, PSE::Let { ref vars, ref val, ref body } => SingleExpressionKind::Let { vars: vars.iter().map(|v| AVariable::new(v.0.clone())).collect(), val: Box::new(SingleExpression::from_parsed(val, fun_ident)), body: Box::new(SingleExpression::from_parsed(body, fun_ident)), }, PSE::ApplyCall { ref fun, ref args } => SingleExpressionKind::ApplyCall { fun: Box::new(SingleExpression::from_parsed(fun, fun_ident)), args: args.iter() .map(|v| SingleExpression::from_parsed(v, fun_ident)) .collect(), }, PSE::Catch(ref body) => { SingleExpressionKind::Catch { body: Box::new(SingleExpression::from_parsed(body, fun_ident)), } }, PSE::Case { ref val, ref clauses } => { //let cfg = pattern::match_from_parsed(val.0.len(), clauses.as_slice()); let mut values = Vec::new(); SingleExpressionKind::Case { val: Box::new(SingleExpression::from_parsed(val, fun_ident)), clauses: clauses.iter() .map(|c| { ::ir::hir::Clause { patterns: c.0.patterns.iter() .map(|p| { Pattern::from_parsed(&p.0, &mut values, fun_ident) }).collect(), guard: SingleExpression::from_parsed(&c.0.guard, fun_ident), body: SingleExpression::from_parsed(&c.0.body, fun_ident), } }).collect(), values: values, //cfg: cfg, } }, PSE::Tuple(ref items) => { SingleExpressionKind::Tuple( items.iter() .map(|i| SingleExpression::from_parsed(i, fun_ident)) .collect()) }, PSE::List { ref head, ref tail } => { SingleExpressionKind::List { head: head.iter() .map(|i| SingleExpression::from_parsed(i, fun_ident)) .collect(), tail: Box::new(SingleExpression::from_parsed(tail, fun_ident)), } }, PSE::PrimOpCall(ref op) => { SingleExpressionKind::PrimOp { name: op.name.0.clone(), args: op.args.iter() .map(|a| SingleExpression::from_parsed(a, fun_ident)) .collect(), } }, PSE::Do(ref d1, ref d2) => { SingleExpressionKind::Do( Box::new(SingleExpression::from_parsed(d1, fun_ident)), Box::new(SingleExpression::from_parsed(d2, fun_ident)) ) }, PSE::Try { ref body, ref catch_vars, ref catch, ref then_vars, ref then } => { SingleExpressionKind::Try { body: Box::new(SingleExpression::from_parsed(body, fun_ident)), then_vars: then_vars.iter().map(|v| { AVariable { ssa: INVALID_SSA, var: v.0.clone(), } }).collect(), then: Box::new(SingleExpression::from_parsed(then, fun_ident)), catch_vars: catch_vars.iter().map(|v| { AVariable { ssa: INVALID_SSA, var: v.0.clone(), } }).collect(), catch: Box::new(SingleExpression::from_parsed(catch, fun_ident)), } }, PSE::Receive { ref clauses, ref timeout_time, ref timeout_body } => { let mut values = Vec::new(); SingleExpressionKind::Receive { clauses: clauses.iter().map(|c| { ::ir::hir::Clause { patterns: c.0.patterns.iter() .map(|p| { Pattern::from_parsed(&p.0, &mut values, fun_ident) }).collect(), guard: SingleExpression::from_parsed(&c.0.guard, fun_ident), body: SingleExpression::from_parsed(&c.0.body, fun_ident), } }).collect(), pattern_values: values, timeout_time: Box::new(SingleExpression::from_parsed( timeout_time, fun_ident)), timeout_body: Box::new(SingleExpression::from_parsed( timeout_body, fun_ident)), } }, PSE::Fun(ref fun) => { SingleExpressionKind::BindClosure { closure: Closure { alias: None, ident: None, parent_ident: fun_ident.clone(), fun: Some(Box::new(Function::from_parsed(fun, fun_ident))), env: None, }, lambda_env: None, env_ssa: INVALID_SSA, } }, PSE::LetRec { ref funs, ref body } => { SingleExpressionKind::BindClosures { closures: funs.iter().map(|f| { Closure { alias: Some(AFunctionName::new( f.0.to_eir(fun_ident.module.clone()))), ident: None, parent_ident: fun_ident.clone(), fun: Some(Box::new(Function::from_parsed(&f.1, fun_ident))), env: None, } }).collect(), body: Box::new(SingleExpression::from_parsed(body, fun_ident)), lambda_env: None, env_ssa: INVALID_SSA, } }, PSE::Map(ref kv, ref merge) => { let kv_h = kv.iter() .map(|ref ann| { let (ref k, assoc, ref v) = ann.0; (SingleExpression::from_parsed(k, fun_ident), SingleExpression::from_parsed(v, fun_ident), assoc) }).collect(); let merge = merge.as_ref().map( |v| Box::new(SingleExpression::from_parsed(&v, fun_ident))); SingleExpressionKind::Map { values: kv_h, merge: merge, } }, PSE::Binary(ref elems) => { SingleExpressionKind::Binary( elems.iter().map(|(ref value, ref opts)| { (SingleExpression::from_parsed(value, fun_ident), opts.iter().map(|o| SingleExpression::from_parsed(o, fun_ident)).collect()) }).collect() ) }, //ref e => panic!("Unhandled: {:?}", e), }; SingleExpression { ssa: INVALID_SSA, kind, } } fn from_parsed(fun: &::parser::Expression, fun_ident: &FunctionIdent) -> SingleExpression { let values: Vec<_> = fun.0.iter() .map(|val| SingleExpression::from_parsed_single(&val.0, fun_ident)) .collect(); SingleExpression { ssa: INVALID_SSA, kind: SingleExpressionKind::ValueList(values), } } } pub fn from_parsed(parsed: &::parser::Module) -> Module { Module::from_parsed(parsed) } ================================================ FILE: libeir_syntax_core/src/parser/grammar.lalrpop ================================================ //-*- mode: rust -*- use crate::ast::{ Module, Annotated, FunctionName, Constant, Function, FunctionDefinition, Expression, SingleExpression, Pattern, CaseClause, PrimOpCall, MapExactAssoc }; use crate::lexer::Tok; use eir::Atom; use eir::AtomicTerm; use ::num_bigint::BigInt; use ::num_traits::ToPrimitive; grammar<'input>(text: &'input str); Integer: BigInt = => { let mut num = BigInt::parse_bytes(i.1.as_bytes(), 10).unwrap(); if !i.0 { num = -num; } num }; Atom: Atom = <"Atom"> => Atom::from_str(<>); Variable: Atom = <"Variable"> => Atom::from_str(<>); // ========================= // ======== Modules ======== // ========================= pub AnnotatedModule: Annotated = { > => <>, }; Module: Module = { "module" "attributes" "end" => Module { name: module_name, declarations: functions, attributes: attributes, definitions: definitions, } }; ModuleFunctions: Vec = "[" > "]" => n; ModuleAttributes: Vec<(Atom, Constant)> = "[" "=" )>> "]"; // =========================== // ======== Functions ======== // =========================== FunctionName: FunctionName = { "/" => FunctionName { name: a, arity: i.to_usize().unwrap() }, }; FunctionDefinition: FunctionDefinition = { > "=" > => FunctionDefinition { name: n, fun: f }, }; Fun: Function = { "fun" "(" >> ")" "->" => Function { vars: a, body: e }, }; // ============================= // ======== Expressions ======== // ============================= ExactAssoc: MapExactAssoc = { ":=" => MapExactAssoc::Exact, "=>" => MapExactAssoc::Assoc, }; Expression: Expression = { > => a, > => Annotated::empty(vec![s]), }; ValueList: Vec> = { "<" >> ">" => <>, }; SingleExpression: SingleExpression = { "[" > )?> "]" => SingleExpression::List { head: e, tail: Box::new(t.unwrap_or(Expression::nil())) }, => SingleExpression::FunctionName(<>), "fun" ":" => SingleExpression::ExternalFunctionName { module: m, name:f }, => SingleExpression::AtomicLiteral(a), => SingleExpression::Variable(v), => SingleExpression::Binary(b), "{" > "}" => SingleExpression::Tuple(t), "~{" )>>> )?> "}~" => SingleExpression::Map(v, m), "let" "=" "in" => SingleExpression::Let { vars: v, val: Box::new(e), body: Box::new(i) }, "call" ":" "(" > ")" => SingleExpression::InterModuleCall { module: Box::new(a), name: Box::new(b), args: c }, "catch" => SingleExpression::Catch(Box::new(e)), "case" "of" *> "end" => SingleExpression::Case { val: Box::new(e), clauses: a }, "primop" > "(" > ")" => SingleExpression::PrimOpCall(PrimOpCall { name: n, args: a }), "do" => SingleExpression::Do(Box::new(e1), Box::new(e2)), "apply" "(" > ")" => SingleExpression::ApplyCall { fun: Box::new(f), args: a }, "try" "of" "->" "catch" "->" => SingleExpression::Try { body: Box::new(t), then_vars: av, then: Box::new(a), catch_vars: cv, catch: Box::new(c) }, "receive" *> "after" "->" => SingleExpression::Receive { clauses: c, timeout_time: Box::new(t), timeout_body: Box::new(b) }, => SingleExpression::Fun(Box::new(f)), "letrec" "=" )+> "in" => SingleExpression::LetRec { funs: f, body: Box::new(e) }, }; Clause: CaseClause = { "->" => CaseClause { patterns: p, guard: g, body: b }, }; Guard: Expression = { "when" => <>, }; Variables: Vec> = { > => vec![a], "<" >> ">" => a, }; // ========================== // ======== Patterns ======== // ========================== Patterns: Vec> = { => vec![p], "<" > ">" => p, }; AnnotatedPattern: Annotated = > => p; PatternMapEntry: (Annotated, Annotated) = { > ":=" => (k, v), }; AnnotatedPatternMapEntry: Annotated<(Annotated, Annotated)> = { > => <>, }; #[inline] Pattern: Pattern = { > "=" => Pattern::BindVar(v, Box::new(p)), => Pattern::BindVar(Annotated::empty(v), Box::new(Annotated::empty(Pattern::Wildcard))), => Pattern::Atomic(a), => Pattern::Binary(b), "{" > "}" => Pattern::Tuple(t), "~{" > "}~" => Pattern::Map(m), "[" > )?> "]" => Pattern::List(l, Box::new(t.unwrap_or(Pattern::nil()))), // => Pattern::List(l.0, Box::new(l.1)), // => Pattern::Map(m), }; //PatternMap: Vec<(SingleExpression, Annotated)> = { //}; // ========================== // ======== Binaries ======== // ========================== //ConstantOrVariable: ConstantOrVariable = { // => ConstantOrVariable::Constant(c), // => ConstantOrVariable::Variable(v), //}; PatternBinary: Vec<(Annotated, Vec>)> = { "#{" > "}#" => b, }; PatternBinaryElem: (Annotated, Vec>) = { "#<" ">(" >> ")" => (p, a), }; Binary: Vec<(Expression, Vec)> = { "#{" > "}#" => b, }; BinaryElem: (Expression, Vec) = { "#<" ">(" > ")" => (b, a), }; // =========================== // ======== Constants ======== // =========================== Constant: Constant = { "{" Comma "}" => Constant::Tuple(vec![]), "[" Comma ("|" Constant)? "]" => Constant::List(vec![], Box::new(Constant::Atomic(AtomicTerm::Nil))), => Constant::Atomic(<>), }; AtomicTerm: AtomicTerm = { => AtomicTerm::Integer(i), // => AtomicTerm::Float(f), => AtomicTerm::Atom(a), //"[" "]" => AtomicTerm::Nil, => AtomicTerm::Char(c), => AtomicTerm::String(s.to_string()), }; ConstantTuple: () = "{" Comma "}" => (); ConstantList: () = "[" Comma ("|" Constant)? "]" => (); // ======================= // ======== Utils ======== // ======================= Annotated: Annotated = { => Annotated(i, vec![]), "(" Annotations ")" => Annotated(i, vec![]), }; Annotations: () = { "-|" "[" > "]" => (), }; Comma: Vec = ",")*> => { let mut rules = rules; rules.extend(last); rules }; extern { type Location = usize; type Error = (); enum Tok<'input> { "module" => Tok::Module, "attributes" => Tok::Attributes, "fun" => Tok::Fun, "case" => Tok::Case, "call" => Tok::Call, "apply" => Tok::Apply, "when" => Tok::When, "end" => Tok::End, "catch" => Tok::Catch, "do" => Tok::Do, "let" => Tok::Let, "in" => Tok::In, "of" => Tok::Of, "primop" => Tok::Primop, "try" => Tok::Try, "receive" => Tok::Receive, "after" => Tok::After, "letrec" => Tok::Letrec, "Atom" => Tok::Atom(<&'input str>), "Variable" => Tok::Variable(<&'input str>), "Integer" => Tok::Integer(<(bool, &'input str)>), "Float" => Tok::Float(<&'input str>), "Char" => Tok::Char(), "String" => Tok::String(<&'input str>), "(" => Tok::ParenOpen, ")" => Tok::ParenClose, "{" => Tok::CurlyOpen, "}" => Tok::CurlyClose, "[" => Tok::SquareOpen, "]" => Tok::SquareClose, "<" => Tok::TriOpen, ">" => Tok::TriClose, "~{" => Tok::MapOpen, ":=" => Tok::MapMatch, "}~" => Tok::MapClose, "#{" => Tok::BitstringOpen, "}#" => Tok::BitstringClose, "#<" => Tok::BitstringPatternOpen, ">(" => Tok::BitstringPatternSep, "-|" => Tok::Annotation, ":" => Tok::Colon, "," => Tok::Comma, "/" => Tok::ForwardSlash, "=" => Tok::Equals, "|" => Tok::Pipe, "->" => Tok::Arrow, "=>" => Tok::HashRocket, } } ================================================ FILE: libeir_syntax_core/src/parser/grammar.rs ================================================ // auto-generated: "lalrpop 0.16.3" // sha256: dc56de9177595febc2b12f8c47a9639b9cb9f823fc7527e3133dcd8cafc3efb use crate::ast::{ Module, Annotated, FunctionName, Constant, Function, FunctionDefinition, Expression, SingleExpression, Pattern, CaseClause, PrimOpCall, MapExactAssoc }; use crate::lexer::Tok; use eir::Atom; use eir::AtomicTerm; use ::num_bigint::BigInt; use ::num_traits::ToPrimitive; #[allow(unused_extern_crates)] extern crate lalrpop_util as __lalrpop_util; #[allow(unused_imports)] use self::__lalrpop_util::state_machine as __state_machine; #[cfg_attr(rustfmt, rustfmt_skip)] mod __parse__AnnotatedModule { #![allow(non_snake_case, non_camel_case_types, unused_mut, unused_variables, unused_imports, unused_parens)] use crate::ast::{ Module, Annotated, FunctionName, Constant, Function, FunctionDefinition, Expression, SingleExpression, Pattern, CaseClause, PrimOpCall, MapExactAssoc }; use crate::lexer::Tok; use eir::Atom; use eir::AtomicTerm; use ::num_bigint::BigInt; use ::num_traits::ToPrimitive; #[allow(unused_extern_crates)] extern crate lalrpop_util as __lalrpop_util; #[allow(unused_imports)] use self::__lalrpop_util::state_machine as __state_machine; use super::__ToTriple; #[allow(dead_code)] pub enum __Symbol<'input> { Variant0(Tok<'input>), Variant1(&'input str), Variant2(char), Variant3((bool, &'input str)), Variant4(Annotated), Variant5(::std::option::Option>), Variant6(Expression), Variant7(::std::option::Option), Variant8((Tok<'input>, Constant)), Variant9(::std::option::Option<(Tok<'input>, Constant)>), Variant10((Atom, Constant)), Variant11(::std::vec::Vec<(Atom, Constant)>), Variant12(Annotated<(Expression, MapExactAssoc, Expression)>), Variant13(::std::vec::Vec>), Variant14(Annotated), Variant15(::std::vec::Vec>), Variant16(Annotated), Variant17(::std::vec::Vec>), Variant18(::std::vec::Vec>), Variant19(Annotated<(Annotated, Annotated)>), Variant20(::std::vec::Vec, Annotated)>>), Variant21(::std::option::Option<(Atom, Constant)>), Variant22((Expression, Vec)), Variant23(::std::vec::Vec<(Expression, Vec)>), Variant24(Constant), Variant25(::std::vec::Vec), Variant26(::std::vec::Vec), Variant27((Expression, MapExactAssoc, Expression)), Variant28(FunctionName), Variant29(::std::vec::Vec), Variant30((FunctionName, Function)), Variant31(::std::vec::Vec<(FunctionName, Function)>), Variant32((Annotated, Vec>)), Variant33(::std::vec::Vec<(Annotated, Vec>)>), Variant34(::std::option::Option>), Variant35(Annotated), Variant36(::std::vec::Vec>), Variant37(Annotated), Variant38(Annotated), Variant39(Annotated), Variant40(::std::option::Option>), Variant41(Annotated>>), Variant42(::std::option::Option>), Variant43(::std::option::Option, Annotated)>>), Variant44(()), Variant45(Atom), Variant46(AtomicTerm), Variant47(Vec<(Expression, Vec)>), Variant48(::std::option::Option<(Expression, Vec)>), Variant49(CaseClause), Variant50(Vec<(Atom, Constant)>), Variant51(Vec>), Variant52(Vec>), Variant53(Vec>), Variant54(Vec>), Variant55(Vec, Annotated)>>), Variant56(Vec), Variant57(Vec), Variant58(Vec), Variant59(Vec<(Annotated, Vec>)>), Variant60(::std::option::Option), Variant61(MapExactAssoc), Variant62(Function), Variant63(FunctionDefinition), Variant64(::std::vec::Vec), Variant65(::std::option::Option), Variant66(BigInt), Variant67(Module), Variant68(Pattern), Variant69(::std::option::Option<(Annotated, Vec>)>), Variant70((Annotated, Annotated)), Variant71(SingleExpression), } const __ACTION: &'static [i16] = &[ // State 0 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 1 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 2 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 3 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 4 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 5 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 6 0, 0, 0, 0, 0, 0, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 7 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 8 0, -126, -126, -126, -126, -126, -126, -126, -126, -126, -126, -126, -126, -126, -126, -126, -126, 0, -126, -126, -126, -126, -126, -126, -126, 0, -126, -126, -126, -126, -126, -126, -126, -126, -126, 0, -126, -126, -126, -126, -126, -126, -126, -126, 0, -126, -126, // State 9 0, 0, 0, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 10 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 11 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 12 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, -173, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 13 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 14 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 27, 0, 28, 29, 0, 30, -165, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 31, 0, 0, 0, 0, 0, // State 15 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 33, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 16 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, -175, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 17 0, 0, 0, 0, 0, 0, 0, 35, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 18 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 36, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 19 0, 0, 0, 0, 37, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -172, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 20 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 27, 0, 28, 29, 0, 30, -167, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 31, -167, -167, 0, 0, 0, // State 21 0, 0, 0, 0, -128, 0, -128, 0, 0, 0, 0, 0, 0, -128, -128, 0, 0, 0, 0, 0, 0, 0, -128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -128, 0, -128, -128, 0, -128, 0, // State 22 0, 0, 0, 0, -183, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -183, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -183, -183, 0, 0, 0, // State 23 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 39, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 24 0, 0, 0, 0, 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -164, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -164, -164, 0, 0, 0, // State 25 0, -127, -127, -127, -127, -127, -127, 0, -127, -127, -127, 0, -127, -127, -127, -127, -127, 0, -127, -127, -127, -127, -127, -127, -127, 0, -127, -127, -127, -127, -127, -127, -127, -127, -127, 0, -127, -127, -127, -127, -127, -127, -127, -127, 0, -127, -127, // State 26 0, -129, -129, -129, -129, -129, -129, 0, -129, -129, -129, 0, -129, -129, -129, -129, -129, 0, -129, -129, -129, -129, -129, -129, -129, 0, -129, -129, -129, -129, -129, -129, -129, -129, -129, 0, -129, -129, -129, -129, -129, -129, -129, -129, 0, -129, -129, // State 27 0, -205, -205, -205, -205, -205, -205, 0, -205, -205, -205, -205, -205, -205, -205, -205, -205, 0, -205, -205, -205, -205, -205, -205, -205, 0, -205, -205, -205, -205, -205, -205, -205, -205, -205, 0, -205, -205, -205, -205, -205, -205, -205, -205, 0, -205, -205, // State 28 0, -130, -130, -130, -130, -130, -130, 0, -130, -130, -130, 0, -130, -130, -130, -130, -130, 0, -130, -130, -130, -130, -130, -130, -130, 0, -130, -130, -130, -130, -130, -130, -130, -130, -130, 0, -130, -130, -130, -130, -130, -130, -130, -130, 0, -130, -130, // State 29 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 27, 0, 28, 29, 0, 30, -165, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 31, -165, 0, 0, 0, 0, // State 30 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 27, 0, 28, 29, 0, 30, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 31, 0, -165, 0, 0, 0, // State 31 0, 0, 47, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 32 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, -137, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 33 0, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -174, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 34 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 28, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 35 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 36 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -62, 0, 0, 0, 0, 0, 0, -62, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 37 0, 0, 0, 0, 54, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -166, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -166, -166, 0, 0, 0, // State 38 0, 0, 0, -125, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 39 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -51, -51, 0, -51, -51, 0, -51, -51, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -51, -51, -51, 0, 0, 0, // State 40 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 55, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 56, 0, 0, 0, 0, // State 41 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 57, 0, 0, 0, // State 42 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 58, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 43 0, 0, -199, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -199, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -199, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 44 0, 0, 47, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 60, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 45 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -86, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 46 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 47 0, 0, 0, 0, 0, 0, -206, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 48 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, -139, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 49 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 50 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 51 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -63, 0, 0, 0, 0, 0, 0, -63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 52 0, -201, -201, -201, -201, -201, -201, 0, -201, -201, -201, -201, -201, -201, -201, -201, -201, 0, -201, -201, -201, -201, -201, -201, -201, 0, -201, -201, -201, -201, -201, -201, -201, -201, -201, 0, -201, -201, -201, -201, 0, -201, -201, -201, 0, -201, -201, // State 53 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -52, -52, 0, -52, -52, 0, -52, -52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -52, -52, -52, 0, 0, 0, // State 54 0, 0, 0, 0, -182, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -182, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -182, -182, 0, 0, 0, // State 55 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 27, 0, 28, 29, 0, 30, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 31, 0, 0, 0, 0, 0, // State 56 0, 0, 0, 0, -180, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -180, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -180, -180, 0, 0, 0, // State 57 0, 0, 68, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 69, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 58 0, 0, -200, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -200, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -200, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 59 0, 0, 0, 0, 0, 0, -207, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 60 0, 0, 0, 0, 0, 0, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 61 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 71, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 62 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 27, 0, 28, 29, 0, 30, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 31, 0, 0, 0, 0, 0, // State 63 0, 0, -208, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -208, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -208, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 64 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 73, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 65 0, 0, -196, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -196, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -196, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 66 0, 0, -84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 67 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 69, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 68 0, 0, 75, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 69 0, 0, 0, 76, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 70 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 27, 0, 28, 29, 0, 30, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 31, 0, 0, 0, 0, 0, // State 71 0, 0, 0, 0, 78, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -136, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 72 0, 0, 0, 0, -181, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -181, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -181, -181, 0, 0, 0, // State 73 0, 0, 0, 0, 0, 0, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 74 0, 0, 84, -149, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 75 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -87, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 76 0, 0, 0, 0, 86, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -138, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 77 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -13, 0, 0, 0, 0, 0, 0, -13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 78 0, 0, 0, 87, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 79 0, 0, 84, -151, 0, 0, 0, 0, 0, 0, 0, 0, 0, -151, 0, 0, 0, 0, 0, 0, 85, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 80 0, 0, 0, -148, 89, 0, 0, 0, 0, 0, 0, 0, 0, -148, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 81 0, 0, 0, 90, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 82 0, 0, 0, -114, -114, -114, 0, 0, 0, 0, 0, -114, 0, -114, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 83 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 84 0, -249, -249, -249, -249, -249, -249, 0, -249, -249, -249, -249, -249, -249, -249, -249, -249, 0, -249, -249, -249, -249, -249, -249, -249, 0, -249, -249, -249, -249, -249, -249, -249, -249, -249, 0, -249, -249, -249, -249, -249, -249, -249, -249, 0, -249, -249, // State 85 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -14, 0, 0, 0, 0, 0, 0, -14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 86 0, 0, -85, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -85, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -85, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 87 0, 0, 0, -150, 92, 0, 0, 0, 0, 0, 0, 0, 0, -150, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 88 0, 0, -28, -28, 0, 0, 0, 0, 0, 0, 0, 0, 0, -28, 0, 0, 0, 0, 0, 0, -28, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 89 0, 0, 0, 0, 0, 93, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 90 0, 0, 0, 0, 0, 0, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 91 0, 0, -29, -29, 0, 0, 0, 0, 0, 0, 0, 0, 0, -29, 0, 0, 0, 0, 0, 0, -29, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 92 0, 106, 107, 0, 0, 0, 0, 0, 0, 0, 108, 0, 0, 0, 0, 9, 27, 0, 28, 29, 85, 109, 0, 0, 110, 0, 111, 112, 113, 114, 0, 115, 0, 116, 117, 0, 0, 118, 119, 120, 0, 121, 0, 0, 0, 0, 122, // State 93 0, 0, 0, 123, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 94 0, -192, -192, -192, -192, -192, -192, 0, -192, -192, -192, 0, -192, -192, -192, -192, -192, 0, -192, -192, -192, -192, -192, -192, -192, 0, -192, -192, -192, -192, -192, -192, -192, -192, -192, 0, -192, -192, -192, -192, 0, -192, -192, -192, 0, -192, -192, // State 95 0, -191, -191, -191, -191, -191, -191, 0, -191, -191, -191, 0, -191, -191, -191, -191, -191, 0, -191, -191, -191, -191, -191, -191, -191, 0, -191, -191, -191, -191, -191, -191, -191, -191, -191, 0, -191, -191, -191, -191, 0, -191, -191, -191, 0, -191, -191, // State 96 0, -128, -128, -128, -128, -128, -128, 35, -128, -128, -128, 0, -128, -128, -128, -128, -128, 0, -128, -128, -128, -128, -128, -128, -128, 0, -128, -128, -128, -128, -128, -128, -128, -128, -128, 0, -128, -128, -128, -128, 0, -128, -128, -128, 0, -128, -128, // State 97 0, -229, -229, -229, -229, -229, -229, 0, -229, -229, -229, 0, -229, -229, -229, -229, -229, 0, -229, -229, -229, -229, -229, -229, -229, 0, -229, -229, -229, -229, -229, -229, -229, -229, -229, 0, -229, -229, -229, -229, 0, -229, -229, -229, 0, -229, -229, // State 98 0, -231, -231, -231, -231, -231, -231, 0, -231, -231, -231, 0, -231, -231, -231, -231, -231, 0, -231, -231, -231, -231, -231, -231, -231, 0, -231, -231, -231, -231, -231, -231, -231, -231, -231, 0, -231, -231, -231, -231, 0, -231, -231, -231, 0, -231, -231, // State 99 0, -195, -195, -195, -195, -195, -195, 0, -195, -195, -195, 0, -195, -195, -195, -195, -195, 0, -195, -195, -195, -195, -195, -195, -195, 0, -195, -195, -195, -195, -195, -195, -195, -195, -195, 0, -195, -195, -195, -195, 0, -195, -195, -195, 0, -195, -195, // State 100 0, -246, -246, -246, -246, -246, -246, 0, -246, -246, -246, 0, -246, -246, -246, -246, -246, 0, -246, -246, -246, -246, -246, -246, -246, 0, -246, -246, -246, -246, -246, -246, -246, -246, -246, 0, -246, -246, -246, -246, 0, -246, -246, -246, 0, -246, -246, // State 101 0, -227, -227, -227, -227, -227, -227, 0, -227, -227, -227, 0, -227, -227, -227, -227, -227, 0, -227, -227, -227, -227, -227, -227, -227, 0, -227, -227, -227, -227, -227, -227, -227, -227, -227, 0, -227, -227, -227, -227, 0, -227, -227, -227, 0, -227, -227, // State 102 0, -108, -108, -108, -108, -108, -108, 0, -108, -108, -108, 0, -108, -108, -108, -108, -108, 0, -108, -108, -108, -108, -108, -108, -108, 0, -108, -108, -108, -108, -108, -108, -108, -108, -108, 0, -108, -108, -108, -108, 0, -108, -108, -108, 0, -108, -108, // State 103 0, -112, -112, -112, -112, -112, -112, 0, -112, -112, -112, 0, -112, -112, -112, -112, -112, 0, -112, -112, -112, -112, -112, -112, -112, 0, -112, -112, -112, -112, -112, -112, -112, -112, -112, 0, -112, -112, -112, -112, 0, -112, -112, -112, 0, -112, -112, // State 104 0, -230, -230, -230, -230, -230, -230, 0, -230, -230, -230, 0, -230, -230, -230, -230, -230, 0, -230, -230, -230, -230, -230, -230, -230, 0, -230, -230, -230, -230, -230, -230, -230, -230, -230, 0, -230, -230, -230, -230, 0, -230, -230, -230, 0, -230, -230, // State 105 127, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -161, 0, 0, // State 106 0, 106, 0, 0, 0, 0, 0, 0, 0, 0, 108, 0, 0, 0, 0, 9, 27, 0, 28, 29, 85, 109, 0, 0, 110, 0, 111, 112, 113, 114, 0, 115, 0, 116, 117, 0, 0, 118, 119, 120, 0, 121, 0, 0, 0, 0, 122, // State 107 0, 106, 133, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -145, 0, 9, 27, 0, 28, 29, 85, 109, 0, 0, 110, 0, 111, 112, 113, 114, 0, 115, 0, 116, 117, 0, 0, 118, 119, 120, 0, 121, 0, 0, 0, 0, 122, // State 108 0, 106, 107, 0, 0, 0, 0, 0, 0, 0, 108, 0, 0, 0, 0, 9, 27, 0, 28, 29, 85, 109, -169, 0, 110, 0, 111, 112, 113, 114, 0, 115, 0, 116, 117, 0, 0, 118, 119, 120, 0, 121, -169, 0, 0, 0, 122, // State 109 0, 106, 107, 0, 0, 0, 0, 0, 0, 0, 108, 0, 0, 0, 0, 9, 27, 0, 28, 29, 85, 109, 0, 0, 110, 0, 111, 112, 113, 114, 0, 115, 0, 116, 117, 0, 0, 118, 119, 120, 0, 121, 0, 0, 0, 0, 122, // State 110 0, 106, 107, 0, 0, 0, 0, 0, 0, 0, 108, 0, 0, 0, 0, 9, 27, 0, 28, 29, 85, 109, 0, 0, 110, 0, 111, 112, 113, 114, 0, 115, 0, 116, 117, 0, 0, 118, 119, 120, 0, 121, 0, 0, 0, 0, 122, // State 111 0, 106, 107, 0, 0, 0, 0, 0, 0, 0, 108, 0, 0, 0, 0, 9, 27, 0, 28, 29, 85, 109, 0, 0, 110, 0, 111, 112, 113, 114, 0, 115, 0, 116, 117, 0, 0, 118, 119, 120, 0, 121, 0, 0, 0, 0, 122, // State 112 0, 106, 107, 0, 0, 0, 0, 0, 0, 0, 108, 0, 0, 0, 0, 9, 27, 0, 28, 29, 85, 109, 0, 0, 110, 0, 111, 112, 113, 114, 0, 115, 0, 116, 117, 0, 0, 118, 119, 120, 0, 121, 0, 0, 0, 0, 122, // State 113 0, 106, 107, 0, 0, 0, 0, 0, 0, 0, 108, 0, 0, 0, 0, 9, 27, 0, 28, 29, 85, 109, 0, 0, 110, 0, 111, 112, 113, 114, 0, 115, 0, 116, 117, 0, 0, 118, 119, 120, 0, 121, 0, 0, 0, 0, 122, // State 114 0, 0, 75, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 115 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 145, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 116 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 117 0, 0, 150, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 118 0, 161, 162, 0, 0, 0, 0, 0, 0, 0, 163, 0, 0, 0, 0, 9, 27, 0, 28, 29, 85, 164, 0, 165, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 166, 0, 0, 0, 0, 167, // State 119 0, 106, 107, 0, 0, 0, 0, 0, 0, 0, 108, 0, 0, 0, 0, 9, 27, 0, 28, 29, 85, 109, 0, 0, 110, 0, 111, 112, 113, 114, 0, 115, 0, 116, 117, 0, 0, 118, 119, 120, 0, 121, 0, 0, 0, 0, 122, // State 120 0, 106, 107, 0, 0, 0, 0, 0, 0, 0, 108, 0, 0, 0, 0, 9, 27, 0, 28, 29, 85, 109, 0, 0, 110, 0, 111, 112, 113, 114, 0, 115, 0, 116, 117, 0, 0, 118, 119, 120, 0, 121, 0, -169, 0, 0, 122, // State 121 0, 106, 174, 0, 0, 0, 0, 0, 0, 0, 108, 0, 0, 0, 0, 9, 27, 0, 28, 29, 85, 109, 0, 0, 110, 0, 111, 112, 113, 114, 0, 115, 0, 116, 117, 0, 0, 118, 119, 120, 0, 121, -141, 0, 0, -141, 122, // State 122 0, 0, 0, -115, -115, -115, 0, 0, 0, 0, 0, -115, 0, -115, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 123 127, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -163, 0, 0, // State 124 0, 0, 0, 0, 176, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -160, 0, 0, // State 125 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 177, 0, 0, // State 126 0, 106, 107, 0, 0, 0, 0, 0, 0, 0, 108, 0, 0, 0, 0, 9, 27, 0, 28, 29, 85, 109, 0, 0, 110, 0, 111, 112, 113, 114, 0, 115, 0, 116, 117, 0, 0, 118, 119, 120, 0, 121, 0, 0, 0, 0, 122, // State 127 0, 0, 0, 0, 0, 0, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 128 0, 0, 0, 0, 0, 0, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 129 0, 106, 133, -147, 0, 0, 0, 0, 0, 0, 0, 0, 0, -147, 0, 9, 27, 0, 28, 29, 85, 109, 0, 0, 110, 0, 111, 112, 113, 114, 0, 115, 0, 116, 117, 0, 0, 118, 119, 120, 0, 121, 0, 0, 0, 0, 122, // State 130 0, 0, 0, -144, 182, 0, 0, 0, 0, 0, 0, 0, 0, -144, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 131 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 183, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 132 0, 106, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 27, 0, 28, 29, 85, 109, 0, 0, 110, 0, 111, 112, 113, 114, 0, 115, 0, 116, 117, 0, 0, 118, 119, 120, 0, 121, 0, 0, 0, 0, 122, // State 133 0, 106, 107, -171, 0, 0, 0, 0, 0, 0, 108, 0, 0, 0, 0, 9, 27, 0, 28, 29, 85, 109, -171, 0, 110, 0, 111, 112, 113, 114, 0, 115, 0, 116, 117, 0, 0, 118, 119, 120, 0, 121, -171, -171, 0, 0, 122, // State 134 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 185, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 186, 0, 0, 0, 0, // State 135 0, 0, 0, -168, 187, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -168, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -168, -168, 0, 0, 0, // State 136 0, 0, 188, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 137 0, 0, 0, 0, 0, 0, 0, 0, 189, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 138 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 190, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 139 0, -237, -237, -237, -237, -237, -237, 0, -237, -237, -237, 0, -237, -237, -237, -237, -237, 0, -237, -237, -237, -237, -237, -237, -237, 0, -237, -237, -237, -237, -237, -237, -237, -237, -237, 0, -237, -237, -237, -237, 0, -237, -237, -237, 0, -237, -237, // State 140 0, 106, 107, 0, 0, 0, 0, 0, 0, 0, 108, 0, 0, 0, 0, 9, 27, 0, 28, 29, 85, 109, 0, 0, 110, 0, 111, 112, 113, 114, 0, 115, 0, 116, 117, 0, 0, 118, 119, 120, 0, 121, 0, 0, 0, 0, 122, // State 141 0, 0, 0, 0, 0, 0, 0, 0, 192, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 142 0, 0, 0, 0, 0, -250, 0, 0, 0, 0, 0, -250, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 143 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 193, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 144 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -149, 0, 0, 0, 0, 0, 0, 85, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 145 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 196, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 146 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 197, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 147 0, 0, 198, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 148 0, 0, -76, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 149 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 150 0, -82, -82, 0, 0, 0, 0, 0, 0, 0, -82, 0, 0, 0, 0, -82, -82, 0, -82, -82, -82, -82, 0, -82, 0, 0, 0, 0, 0, 0, -82, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -82, 0, 0, 0, 0, -82, // State 151 0, 161, 162, 0, 0, 0, 0, 0, 0, 0, 163, 0, 0, 0, 0, 9, 27, 0, 28, 29, 85, 164, 0, 201, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 166, 0, 0, 0, 0, 167, // State 152 0, 0, 0, 0, -119, 0, -119, 0, 0, 0, 0, 0, 0, -119, -119, 0, 0, 0, 0, 0, 0, 0, -119, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -119, 0, -119, -119, 0, -119, 0, // State 153 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 202, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 154 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -223, 0, 0, 0, 0, 0, 0, // State 155 0, 0, 0, 0, -92, 0, -92, 0, 0, 0, 0, 0, 0, -92, -92, 0, 0, 0, 0, 0, 0, 0, -92, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -92, 0, -92, -92, 0, -92, 0, // State 156 0, -78, -78, 0, 0, 0, 0, 0, 0, 0, -78, 0, 0, 0, 0, -78, -78, 0, -78, -78, -78, -78, 0, -78, 0, 0, 0, 0, 0, 0, -78, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -78, 0, 0, 0, 0, -78, // State 157 0, 0, 0, 0, -93, 0, -93, 0, 0, 0, 0, 0, 0, -93, -93, 0, 0, 0, 0, 0, 0, 0, -93, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -93, 0, -93, -93, 0, -93, 0, // State 158 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 204, 0, 0, 0, 0, 0, 0, // State 159 0, 0, 0, 0, -91, 0, -91, 0, 0, 0, 0, -114, 0, -91, -91, 0, 0, 0, 0, 0, 0, 0, -91, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -91, 0, -91, -91, 0, -91, 0, // State 160 208, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -177, 0, 0, // State 161 0, 161, 214, 0, 0, 0, 0, 0, 0, 0, 163, 0, 0, 0, 0, 9, 27, 0, 28, 29, 85, 215, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 216, 0, 0, 0, 0, 217, // State 162 0, 161, 214, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -153, 0, 9, 27, 0, 28, 29, 85, 164, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 166, 0, 0, 0, 0, 167, // State 163 0, 161, 214, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 27, 0, 28, 29, 85, 164, -153, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 166, -153, 0, 0, 0, 167, // State 164 0, 106, 107, 0, 0, 0, 0, 0, 0, 0, 108, 0, 0, 0, 0, 9, 27, 0, 28, 29, 85, 109, 0, 0, 110, 0, 111, 112, 113, 114, 0, 115, 0, 116, 117, 0, 0, 118, 119, 120, 0, 121, 0, 0, 0, 0, 122, // State 165 0, 161, 214, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 27, 0, 28, 29, 85, 164, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 166, 0, -153, 0, 0, 167, // State 166 0, 106, 230, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 27, 0, 28, 29, 85, 109, 0, 0, 110, 0, 111, 112, 113, 114, 0, 115, 0, 116, 117, 0, 0, 118, 119, 120, 0, 121, 0, 0, 0, -157, 122, // State 167 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 231, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 168 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 232, 0, 0, 0, // State 169 0, 106, 174, 0, 0, 0, 0, 0, 0, 0, 108, 0, 0, 0, 0, 9, 27, 0, 28, 29, 85, 109, 0, 0, 110, 0, 111, 112, 113, 114, 0, 115, 0, 116, 117, 0, 0, 118, 119, 120, 0, 121, -143, 0, 0, -143, 122, // State 170 0, 0, 0, 0, 234, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -140, 0, 0, -140, 0, // State 171 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 235, 0, 0, 236, 0, // State 172 0, 0, 0, 0, 0, 0, 0, 0, 0, 238, 0, 0, 239, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 173 0, 106, 107, 0, 0, 0, 0, 0, 0, 0, 108, 0, 0, 0, 0, 9, 27, 0, 28, 29, 85, 109, 0, 0, 110, 0, 111, 112, 113, 114, 0, 115, 0, 116, 117, 0, 0, 118, 119, 120, 0, 121, 0, 0, 0, 0, 122, // State 174 0, 0, 0, 0, 243, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -162, 0, 0, // State 175 -46, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -46, 0, 0, // State 176 0, -131, -131, -131, -131, -131, -131, 0, -131, -131, -131, 0, -131, -131, -131, -131, -131, 0, -131, -131, -131, -131, -131, -131, -131, 0, -131, -131, -131, -131, -131, -131, -131, -131, -131, 0, -131, -131, -131, -131, 0, -131, -131, -131, 0, -131, -131, // State 177 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 244, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 178 0, 0, 0, 245, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 179 0, 0, 0, 246, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 180 0, 0, 0, -146, 247, 0, 0, 0, 0, 0, 0, 0, 0, -146, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 181 0, -23, -23, -23, 0, 0, 0, 0, 0, 0, 0, 0, 0, -23, 0, -23, -23, 0, -23, -23, -23, -23, 0, 0, -23, 0, -23, -23, -23, -23, 0, -23, 0, -23, -23, 0, 0, -23, -23, -23, 0, -23, 0, 0, 0, 0, -23, // State 182 0, -248, -248, -248, -248, -248, -248, 0, -248, -248, -248, 0, -248, -248, -248, -248, -248, 0, -248, -248, -248, -248, -248, -248, -248, 0, -248, -248, -248, -248, -248, -248, -248, -248, -248, 0, -248, -248, -248, -248, 0, -248, -248, -248, 0, -248, -248, // State 183 0, 0, 0, -170, 248, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -170, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -170, -170, 0, 0, 0, // State 184 0, -226, -226, -226, -226, -226, -226, 0, -226, -226, -226, 0, -226, -226, -226, -226, -226, 0, -226, -226, -226, -226, -226, -226, -226, 0, -226, -226, -226, -226, -226, -226, -226, -226, -226, 0, -226, -226, -226, -226, 0, -226, -226, -226, 0, -226, -226, // State 185 0, 106, 107, 0, 0, 0, 0, 0, 0, 0, 108, 0, 0, 0, 0, 9, 27, 0, 28, 29, 85, 109, 0, 0, 110, 0, 111, 112, 113, 114, 0, 115, 0, 116, 117, 0, 0, 118, 119, 120, 0, 121, 0, 0, 0, 0, 122, // State 186 0, -56, -56, -56, 0, 0, 0, 0, 0, 0, -56, 0, 0, 0, 0, -56, -56, 0, -56, -56, -56, -56, -56, 0, -56, 0, -56, -56, -56, -56, 0, -56, 0, -56, -56, 0, 0, -56, -56, -56, 0, -56, -56, -56, 0, 0, -56, // State 187 0, 106, 107, -169, 0, 0, 0, 0, 0, 0, 108, 0, 0, 0, 0, 9, 27, 0, 28, 29, 85, 109, 0, 0, 110, 0, 111, 112, 113, 114, 0, 115, 0, 116, 117, 0, 0, 118, 119, 120, 0, 121, 0, 0, 0, 0, 122, // State 188 0, 106, 107, 0, 0, 0, 0, 0, 0, 0, 108, 0, 0, 0, 0, 9, 27, 0, 28, 29, 85, 109, 0, 0, 110, 0, 111, 112, 113, 114, 0, 115, 0, 116, 117, 0, 0, 118, 119, 120, 0, 121, 0, 0, 0, 0, 122, // State 189 0, 161, 162, 0, 0, 0, 0, 0, 0, 0, 163, 0, 0, 0, 0, 9, 27, 0, 28, 29, 85, 164, 0, 0, 0, 0, 0, 0, 0, 0, 253, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 166, 0, 0, 0, 0, 167, // State 190 0, -241, -241, -241, -241, -241, -241, 0, -241, -241, -241, 0, -241, -241, -241, -241, -241, 0, -241, -241, -241, -241, -241, -241, -241, 0, -241, -241, -241, -241, -241, -241, -241, -241, -241, 0, -241, -241, -241, -241, 0, -241, -241, -241, 0, -241, -241, // State 191 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 192 0, 106, 107, 0, 0, 0, 0, 0, 0, 0, 108, 0, 0, 0, 0, 9, 27, 0, 28, 29, 85, 109, 0, 0, 110, 0, 111, 112, 113, 114, 0, 115, 0, 116, 117, 0, 0, 118, 119, 120, 0, 121, 0, 0, 0, 0, 122, // State 193 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 256, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 194 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 257, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 195 0, 106, 107, 0, 0, 0, 0, 0, 0, 0, 108, 0, 0, 0, 0, 9, 27, 0, 28, 29, 85, 109, 0, 0, 110, 0, 111, 112, 113, 114, 0, 115, 0, 116, 117, 0, 0, 118, 119, 120, 0, 121, 0, 0, 0, 0, 122, // State 196 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 69, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 197 0, 106, 107, -169, 0, 0, 0, 0, 0, 0, 108, 0, 0, 0, 0, 9, 27, 0, 28, 29, 85, 109, 0, 0, 110, 0, 111, 112, 113, 114, 0, 115, 0, 116, 117, 0, 0, 118, 119, 120, 0, 121, 0, 0, 0, 0, 122, // State 198 0, 0, 0, 0, 0, 0, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 199 0, -83, -83, 0, 0, 0, 0, 0, 0, 0, -83, 0, 0, 0, 0, -83, -83, 0, -83, -83, -83, -83, 0, -83, 0, 0, 0, 0, 0, 0, -83, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -83, 0, 0, 0, 0, -83, // State 200 0, 106, 107, 0, 0, 0, 0, 0, 0, 0, 108, 0, 0, 0, 0, 9, 27, 0, 28, 29, 85, 109, 0, 0, 110, 0, 111, 112, 113, 114, 0, 115, 0, 116, 117, 0, 0, 118, 119, 120, 0, 121, 0, 0, 0, 0, 122, // State 201 0, 161, 214, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 27, 0, 28, 29, 85, 164, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 166, 0, 0, 0, 0, 167, // State 202 0, 0, 0, 0, 0, 264, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 203 0, 106, 107, 0, 0, 0, 0, 0, 0, 0, 108, 0, 0, 0, 0, 9, 27, 0, 28, 29, 85, 109, 0, 0, 110, 0, 111, 112, 113, 114, 0, 115, 0, 116, 117, 0, 0, 118, 119, 120, 0, 121, 0, 0, 0, 0, 122, // State 204 208, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -179, 0, 0, // State 205 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 267, 0, 0, // State 206 0, 0, 0, 0, 268, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -176, 0, 0, // State 207 0, 161, 214, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 27, 0, 28, 29, 85, 164, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 166, 0, 0, 0, 0, 167, // State 208 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 270, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 209 0, 0, 0, 0, 0, 0, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -92, 0, 0, 0, 0, 0, 0, // State 210 0, 0, 0, 0, 0, 0, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 211 0, 0, 0, 0, 0, 0, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -93, 0, 0, 0, 0, 0, 0, // State 212 0, 0, 0, 0, 0, 0, 11, 0, 0, 0, 0, -114, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -91, 0, 0, 0, 0, 0, 0, // State 213 0, 161, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 27, 0, 28, 29, 85, 279, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 280, 0, 0, 0, 0, 281, // State 214 0, 161, 214, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 27, 0, 28, 29, 85, 164, -153, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 166, -153, 0, 0, 0, 167, // State 215 0, 161, 214, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 27, 0, 28, 29, 85, 164, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 166, 0, -153, 0, 0, 167, // State 216 0, 106, 230, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 27, 0, 28, 29, 85, 109, 0, 0, 110, 0, 111, 112, 113, 114, 0, 115, 0, 116, 117, 0, 0, 118, 119, 120, 0, 121, 0, 0, 0, -157, 122, // State 217 0, 161, 214, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -155, 0, 9, 27, 0, 28, 29, 85, 164, -155, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 166, -155, -155, 0, 0, 167, // State 218 0, 0, 0, 0, 286, 0, 0, 0, 0, 0, 0, 0, 0, -152, 0, 0, 0, 0, 0, 0, 0, 0, -152, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -152, -152, 0, 0, 0, // State 219 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 287, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 220 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 288, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 289, 0, 0, 0, 0, // State 221 0, 0, 0, 0, 0, 290, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 222 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 291, 0, 0, 0, // State 223 0, 106, 230, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 27, 0, 28, 29, 85, 109, 0, 0, 110, 0, 111, 112, 113, 114, 0, 115, 0, 116, 117, 0, 0, 118, 119, 120, 0, 121, 0, 0, 0, -159, 122, // State 224 0, 0, 0, 0, -122, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -122, 0, // State 225 0, 0, 0, 0, 0, 0, 0, 0, 0, 293, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 226 0, 0, 0, 0, 294, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -156, 0, // State 227 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 295, 0, // State 228 0, 0, 0, 0, -106, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -106, 0, // State 229 0, 106, 133, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 27, 0, 28, 29, 85, 109, 0, 0, 110, 0, 111, 112, 113, 114, 0, 115, 0, 116, 117, 0, 0, 118, 119, 120, 0, 121, 0, 0, 0, 0, 122, // State 230 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 145, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 231 0, -232, -232, -232, -232, -232, -232, 0, -232, -232, -232, 0, -232, -232, -232, -232, -232, 0, -232, -232, -232, -232, -232, -232, -232, 0, -232, -232, -232, -232, -232, -232, -232, -232, -232, 0, -232, -232, -232, -232, 0, -232, -232, -232, 0, -232, -232, // State 232 0, 0, 0, 0, 298, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -142, 0, 0, -142, 0, // State 233 0, -18, -18, 0, 0, 0, 0, 0, 0, 0, -18, 0, 0, 0, 0, -18, -18, 0, -18, -18, -18, -18, 0, 0, -18, 0, -18, -18, -18, -18, 0, -18, 0, -18, -18, 0, 0, -18, -18, -18, 0, -18, -18, 0, 0, -18, -18, // State 234 0, 106, 107, 0, 0, 0, 0, 0, 0, 0, 108, 0, 0, 0, 0, 9, 27, 0, 28, 29, 85, 109, 0, 0, 110, 0, 111, 112, 113, 114, 0, 115, 0, 116, 117, 0, 0, 118, 119, 120, 0, 121, 0, 0, 0, 0, 122, // State 235 0, -234, -234, -234, -234, -234, -234, 0, -234, -234, -234, 0, -234, -234, -234, -234, -234, 0, -234, -234, -234, -234, -234, -234, -234, 0, -234, -234, -234, -234, -234, -234, -234, -234, -234, 0, -234, -234, -234, -234, 0, -234, -234, -234, 0, -234, -234, // State 236 0, 106, 107, 0, 0, 0, 0, 0, 0, 0, 108, 0, 0, 0, 0, 9, 27, 0, 28, 29, 85, 109, 0, 0, 110, 0, 111, 112, 113, 114, 0, 115, 0, 116, 117, 0, 0, 118, 119, 120, 0, 121, 0, 0, 0, 0, 122, // State 237 0, -189, -189, 0, 0, 0, 0, 0, 0, 0, -189, 0, 0, 0, 0, -189, -189, 0, -189, -189, -189, -189, 0, 0, -189, 0, -189, -189, -189, -189, 0, -189, 0, -189, -189, 0, 0, -189, -189, -189, 0, -189, 0, 0, 0, 0, -189, // State 238 0, -190, -190, 0, 0, 0, 0, 0, 0, 0, -190, 0, 0, 0, 0, -190, -190, 0, -190, -190, -190, -190, 0, 0, -190, 0, -190, -190, -190, -190, 0, -190, 0, -190, -190, 0, 0, -190, -190, -190, 0, -190, 0, 0, 0, 0, -190, // State 239 0, 0, 0, 0, 0, 0, 0, 0, 0, 238, 0, 0, 239, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 240 0, 0, 0, 0, 0, 0, 11, 0, 0, -108, 0, 0, -108, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 241 0, 0, 0, 0, 0, 0, 11, 0, 0, -112, 0, 0, -112, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 242 -47, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -47, 0, 0, // State 243 0, 106, 107, -169, 0, 0, 0, 0, 0, 0, 108, 0, 0, 0, 0, 9, 27, 0, 28, 29, 85, 109, 0, 0, 110, 0, 111, 112, 113, 114, 0, 115, 0, 116, 117, 0, 0, 118, 119, 120, 0, 121, 0, 0, 0, 0, 122, // State 244 0, -109, -109, -109, -109, -109, -109, 0, -109, -109, -109, 0, -109, -109, -109, -109, -109, 0, -109, -109, -109, -109, -109, -109, -109, 0, -109, -109, -109, -109, -109, -109, -109, -109, -109, 0, -109, -109, -109, -109, 0, -109, -109, -109, 0, -109, -109, // State 245 0, -113, -113, -113, -113, -113, -113, 0, -113, -113, -113, 0, -113, -113, -113, -113, -113, 0, -113, -113, -113, -113, -113, -113, -113, 0, -113, -113, -113, -113, -113, -113, -113, -113, -113, 0, -113, -113, -113, -113, 0, -113, -113, -113, 0, -113, -113, // State 246 0, -24, -24, -24, 0, 0, 0, 0, 0, 0, 0, 0, 0, -24, 0, -24, -24, 0, -24, -24, -24, -24, 0, 0, -24, 0, -24, -24, -24, -24, 0, -24, 0, -24, -24, 0, 0, -24, -24, -24, 0, -24, 0, 0, 0, 0, -24, // State 247 0, -57, -57, -57, 0, 0, 0, 0, 0, 0, -57, 0, 0, 0, 0, -57, -57, 0, -57, -57, -57, -57, -57, 0, -57, 0, -57, -57, -57, -57, 0, -57, 0, -57, -57, 0, 0, -57, -57, -57, 0, -57, -57, -57, 0, 0, -57, // State 248 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 303, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 249 0, 0, 0, 304, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 250 0, 0, 305, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 251 0, 161, 162, 0, 0, 0, 0, 0, 0, 0, 163, 0, 0, 0, 0, 9, 27, 0, 28, 29, 85, 164, 0, 0, 0, 0, 0, 0, 0, 0, 306, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 166, 0, 0, 0, 0, 167, // State 252 0, -238, -238, -238, -238, -238, -238, 0, -238, -238, -238, 0, -238, -238, -238, -238, -238, 0, -238, -238, -238, -238, -238, -238, -238, 0, -238, -238, -238, -238, -238, -238, -238, -238, -238, 0, -238, -238, -238, -238, 0, -238, -238, -238, 0, -238, -238, // State 253 0, -228, -228, -228, -228, -228, -228, 0, -228, -228, -228, 0, -228, -228, -228, -228, -228, 0, -228, -228, -228, -228, -228, -228, -228, 0, -228, -228, -228, -228, -228, -228, -228, -228, -228, 0, -228, -228, -228, -228, 0, -228, -228, -228, 0, -228, -228, // State 254 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 307, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 255 0, 0, 0, 0, 0, -251, 0, 0, 0, 0, 0, -251, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 256 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 69, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 257 0, -247, -247, -247, -247, -247, -247, 0, -247, -247, -247, 0, -247, -247, -247, -247, -247, 0, -247, -247, -247, -247, -247, -247, -247, 0, -247, -247, -247, -247, -247, -247, -247, -247, -247, 0, -247, -247, -247, -247, 0, -247, -247, -247, 0, -247, -247, // State 258 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -65, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -65, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 259 0, 0, 0, 309, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 260 0, 0, 0, 310, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 261 0, 0, 0, 0, 0, 311, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 262 0, 0, 0, 0, -90, 0, -90, 0, 0, 0, 0, 0, 0, -90, -90, 0, 0, 0, 0, 0, 0, 0, -90, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -90, 0, -90, -90, 0, -90, 0, // State 263 0, 106, 107, 0, 0, 0, 0, 0, 0, 0, 108, 0, 0, 0, 0, 9, 27, 0, 28, 29, 85, 109, 0, 0, 110, 0, 111, 112, 113, 114, 0, 115, 0, 116, 117, 0, 0, 118, 119, 120, 0, 121, 0, 0, 0, 0, 122, // State 264 0, 0, 0, 0, 0, -204, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 265 0, 0, 0, 0, 313, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -178, 0, 0, // State 266 0, 0, 0, 0, -218, 0, -218, 0, 0, 0, 0, 0, 0, -218, -218, 0, 0, 0, 0, 0, 0, 0, -218, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -218, 0, -218, -218, 0, -218, 0, // State 267 -70, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -70, 0, 0, // State 268 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 314, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 269 0, 161, 214, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 27, 0, 28, 29, 85, 164, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 166, 0, 0, 0, 0, 167, // State 270 0, 0, 0, 316, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 271 0, 0, 0, 317, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 272 0, 0, 0, 318, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 273 0, 0, 0, 319, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 274 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 320, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 275 0, 0, 0, 0, 0, 0, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 276 0, 0, 0, 0, 0, 0, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 277 0, 0, 0, 0, 0, 0, 11, 0, 0, 0, 0, -114, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 278 0, 161, 214, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 27, 0, 28, 29, 85, 164, -153, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 166, -153, 0, 0, 0, 167, // State 279 0, 161, 214, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 27, 0, 28, 29, 85, 164, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 166, 0, -153, 0, 0, 167, // State 280 0, 106, 230, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 27, 0, 28, 29, 85, 109, 0, 0, 110, 0, 111, 112, 113, 114, 0, 115, 0, 116, 117, 0, 0, 118, 119, 120, 0, 121, 0, 0, 0, -157, 122, // State 281 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 324, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 325, 0, 0, 0, 0, // State 282 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 326, 0, 0, 0, // State 283 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 327, 0, // State 284 0, 0, 0, 0, 328, 0, 0, 0, 0, 0, 0, 0, 0, -154, 0, 0, 0, 0, 0, 0, 0, 0, -154, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -154, -154, 0, 0, 0, // State 285 0, -33, -33, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -33, 0, -33, -33, 0, -33, -33, -33, -33, -33, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -33, -33, -33, 0, 0, -33, // State 286 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -224, 0, 0, 0, 0, 0, 0, // State 287 0, 0, 0, 0, -97, 0, -97, 0, 0, 0, 0, 0, 0, -97, -97, 0, 0, 0, 0, 0, 0, 0, -97, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -97, 0, -97, -97, 0, -97, 0, // State 288 0, 161, 214, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 27, 0, 28, 29, 85, 164, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 166, 0, 0, 0, 0, 167, // State 289 0, 106, 107, 0, 0, 0, 0, 0, 0, 0, 108, 0, 0, 0, 0, 9, 27, 0, 28, 29, 85, 109, 0, 0, 110, 0, 111, 112, 113, 114, 0, 115, 0, 116, 117, 0, 0, 118, 119, 120, 0, 121, 0, 0, 0, 0, 122, // State 290 0, 0, 0, 0, -94, 0, -94, 0, 0, 0, 0, 0, 0, -94, -94, 0, 0, 0, 0, 0, 0, 0, -94, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -94, 0, -94, -94, 0, -94, 0, // State 291 0, 0, 0, 0, 331, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -158, 0, // State 292 0, 161, 214, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 27, 0, 28, 29, 85, 164, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 166, 0, 0, 0, 0, 167, // State 293 0, -38, -38, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -38, -38, 0, -38, -38, -38, -38, 0, 0, -38, 0, -38, -38, -38, -38, 0, -38, 0, -38, -38, 0, 0, -38, -38, -38, 0, -38, 0, 0, 0, -38, -38, // State 294 0, 0, 0, 0, -95, 0, -95, 0, 0, 0, 0, 0, 0, -95, -95, 0, 0, 0, 0, 0, 0, 0, -95, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -95, 0, -95, -95, 0, -95, 0, // State 295 0, 0, 0, 0, 0, 0, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 296 0, 0, 0, 0, 0, 334, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 297 0, -19, -19, 0, 0, 0, 0, 0, 0, 0, -19, 0, 0, 0, 0, -19, -19, 0, -19, -19, -19, -19, 0, 0, -19, 0, -19, -19, -19, -19, 0, -19, 0, -19, -19, 0, 0, -19, -19, -19, 0, -19, -19, 0, 0, -19, -19, // State 298 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 335, 0, // State 299 0, 0, 0, 0, -72, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -72, 0, 0, -72, 0, // State 300 0, 106, 107, 0, 0, 0, 0, 0, 0, 0, 108, 0, 0, 0, 0, 9, 27, 0, 28, 29, 85, 109, 0, 0, 110, 0, 111, 112, 113, 114, 0, 115, 0, 116, 117, 0, 0, 118, 119, 120, 0, 121, 0, 0, 0, 0, 122, // State 301 0, 0, 0, 337, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 302 0, -225, -225, -225, -225, -225, -225, 0, -225, -225, -225, 0, -225, -225, -225, -225, -225, 0, -225, -225, -225, -225, -225, -225, -225, 0, -225, -225, -225, -225, -225, -225, -225, -225, -225, 0, -225, -225, -225, -225, 0, -225, -225, -225, 0, -225, -225, // State 303 0, -242, -242, -242, -242, -242, -242, 0, -242, -242, -242, 0, -242, -242, -242, -242, -242, 0, -242, -242, -242, -242, -242, -242, -242, 0, -242, -242, -242, -242, -242, -242, -242, -242, -242, 0, -242, -242, -242, -242, 0, -242, -242, -242, 0, -242, -242, // State 304 0, 106, 107, -169, 0, 0, 0, 0, 0, 0, 108, 0, 0, 0, 0, 9, 27, 0, 28, 29, 85, 109, 0, 0, 110, 0, 111, 112, 113, 114, 0, 115, 0, 116, 117, 0, 0, 118, 119, 120, 0, 121, 0, 0, 0, 0, 122, // State 305 0, -239, -239, -239, -239, -239, -239, 0, -239, -239, -239, 0, -239, -239, -239, -239, -239, 0, -239, -239, -239, -239, -239, -239, -239, 0, -239, -239, -239, -239, -239, -239, -239, -239, -239, 0, -239, -239, -239, -239, 0, -239, -239, -239, 0, -239, -239, // State 306 0, 106, 107, 0, 0, 0, 0, 0, 0, 0, 108, 0, 0, 0, 0, 9, 27, 0, 28, 29, 85, 109, 0, 0, 110, 0, 111, 112, 113, 114, 0, 115, 0, 116, 117, 0, 0, 118, 119, 120, 0, 121, 0, 0, 0, 0, 122, // State 307 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -66, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -66, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 308 0, -240, -240, -240, -240, -240, -240, 0, -240, -240, -240, 0, -240, -240, -240, -240, -240, 0, -240, -240, -240, -240, -240, -240, -240, 0, -240, -240, -240, -240, -240, -240, -240, -240, -240, 0, -240, -240, -240, -240, 0, -240, -240, -240, 0, -240, -240, // State 309 0, 0, -77, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 310 0, 106, 107, 0, 0, 0, 0, 0, 0, 0, 108, 0, 0, 0, 0, 9, 27, 0, 28, 29, 85, 109, 0, 0, 110, 0, 111, 112, 113, 114, 0, 115, 0, 116, 117, 0, 0, 118, 119, 120, 0, 121, 0, 0, 0, 0, 122, // State 311 0, -135, -135, 0, 0, 0, -135, 0, 0, 0, -135, 0, 0, 0, 0, -135, -135, 0, -135, -135, -135, -135, 0, -135, 0, 0, 0, 0, 0, 0, -135, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -135, 0, 0, 0, 0, -135, // State 312 -71, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -71, 0, 0, // State 313 0, 106, 133, -145, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 27, 0, 28, 29, 85, 109, 0, 0, 110, 0, 111, 112, 113, 114, 0, 115, 0, 116, 117, 0, 0, 118, 119, 120, 0, 121, 0, 0, 0, 0, 122, // State 314 0, 0, 0, 0, 0, 0, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -90, 0, 0, 0, 0, 0, 0, // State 315 0, 0, 0, 0, -100, 0, -100, 0, 0, 0, 0, 0, 0, -100, -100, 0, 0, 0, 0, 0, 0, 0, -100, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -100, 0, -100, -100, 0, -100, 0, // State 316 0, -79, -79, 0, 0, 0, 0, 0, 0, 0, -79, 0, 0, 0, 0, -79, -79, 0, -79, -79, -79, -79, 0, -79, 0, 0, 0, 0, 0, 0, -79, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -79, 0, 0, 0, 0, -79, // State 317 0, 0, 0, 0, -101, 0, -101, 0, 0, 0, 0, 0, 0, -101, -101, 0, 0, 0, 0, 0, 0, 0, -101, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -101, 0, -101, -101, 0, -101, 0, // State 318 0, 0, 0, 0, -99, 0, -99, 0, 0, 0, 0, -115, 0, -99, -99, 0, 0, 0, 0, 0, 0, 0, -99, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -99, 0, -99, -99, 0, -99, 0, // State 319 0, 161, 214, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 27, 0, 28, 29, 85, 164, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 166, 0, 0, 0, 0, 167, // State 320 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 344, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 345, 0, 0, 0, 0, // State 321 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 346, 0, 0, 0, // State 322 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 347, 0, // State 323 0, 0, 0, 0, 0, 0, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -97, 0, 0, 0, 0, 0, 0, // State 324 0, 161, 214, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 27, 0, 28, 29, 85, 164, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 166, 0, 0, 0, 0, 167, // State 325 0, 0, 0, 0, 0, 0, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -94, 0, 0, 0, 0, 0, 0, // State 326 0, 0, 0, 0, 0, 0, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -95, 0, 0, 0, 0, 0, 0, // State 327 0, -34, -34, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -34, 0, -34, -34, 0, -34, -34, -34, -34, -34, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -34, -34, -34, 0, 0, -34, // State 328 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 352, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 329 0, -244, -244, -244, -244, -244, -244, 0, -244, -244, -244, 0, -244, -244, -244, -244, -244, 0, -244, -244, -244, -244, -244, -244, -244, 0, -244, -244, -244, -244, -244, -244, -244, -244, -244, 0, -244, -244, -244, -244, 0, -244, -244, -244, 0, -244, -244, // State 330 0, -39, -39, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -39, -39, 0, -39, -39, -39, -39, 0, 0, -39, 0, -39, -39, -39, -39, 0, -39, 0, -39, -39, 0, 0, -39, -39, -39, 0, -39, 0, 0, 0, -39, -39, // State 331 0, 0, 0, 0, -222, 0, -222, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -222, 0, // State 332 0, 0, 0, 353, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 333 0, 106, 107, 0, 0, 0, 0, 0, 0, 0, 108, 0, 0, 0, 0, 9, 27, 0, 28, 29, 85, 109, 0, 0, 110, 0, 111, 112, 113, 114, 0, 115, 0, 116, 117, 0, 0, 118, 119, 120, 0, 121, 0, 0, 0, 0, 122, // State 334 0, -233, -233, -233, -233, -233, -233, 0, -233, -233, -233, 0, -233, -233, -233, -233, -233, 0, -233, -233, -233, -233, -233, -233, -233, 0, -233, -233, -233, -233, -233, -233, -233, -233, -233, 0, -233, -233, -233, -233, 0, -233, -233, -233, 0, -233, -233, // State 335 0, 0, 0, 0, 0, 0, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 336 0, 0, 0, 0, -132, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -132, 0, 0, // State 337 0, 0, 0, 356, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 338 0, -235, -235, -235, -235, -235, -235, 0, -235, -235, -235, 0, -235, -235, -235, -235, -235, 0, -235, -235, -235, -235, -235, -235, -235, 0, -235, -235, -235, -235, -235, -235, -235, -235, -235, 0, -235, -235, -235, -235, 0, -235, -235, -235, 0, -235, -235, // State 339 0, -245, -245, -245, -245, -245, -245, 0, -245, -245, -245, 0, -245, -245, -245, -245, -245, 0, -245, -245, -245, -245, -245, -245, -245, 0, -245, -245, -245, -245, -245, -245, -245, -245, -245, 0, -245, -245, -245, -245, 0, -245, -245, -245, 0, -245, -245, // State 340 0, 0, 0, 357, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 341 0, 0, 0, 358, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 342 0, 0, 0, 0, 0, 0, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 343 0, 0, 0, 0, 0, 0, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 344 0, 161, 214, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 27, 0, 28, 29, 85, 164, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 166, 0, 0, 0, 0, 167, // State 345 0, 0, 0, 0, 0, 0, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 346 0, 0, 0, 0, 0, 0, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 347 0, 0, 0, 360, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 348 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 361, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 349 0, 0, 0, 362, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 350 0, 0, 0, 363, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 351 0, 0, 0, 0, -96, 0, -96, 0, 0, 0, 0, 0, 0, -96, -96, 0, 0, 0, 0, 0, 0, 0, -96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -96, 0, -96, -96, 0, -96, 0, // State 352 0, 0, 0, 0, -107, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -107, 0, // State 353 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 364, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 354 0, 0, 0, 365, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 355 0, -236, -236, -236, -236, -236, -236, 0, -236, -236, -236, 0, -236, -236, -236, -236, -236, 0, -236, -236, -236, -236, -236, -236, -236, 0, -236, -236, -236, -236, -236, -236, -236, -236, -236, 0, -236, -236, -236, -236, 0, -236, -236, -236, 0, -236, -236, // State 356 0, 0, 0, 0, -219, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -219, 0, 0, // State 357 0, 0, 0, 0, -98, 0, -98, 0, 0, 0, 0, 0, 0, -98, -98, 0, 0, 0, 0, 0, 0, 0, -98, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -98, 0, -98, -98, 0, -98, 0, // State 358 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 366, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 359 0, 0, 0, 0, -105, 0, -105, 0, 0, 0, 0, 0, 0, -105, -105, 0, 0, 0, 0, 0, 0, 0, -105, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -105, 0, -105, -105, 0, -105, 0, // State 360 0, 0, 0, 0, 0, 0, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -96, 0, 0, 0, 0, 0, 0, // State 361 0, 0, 0, 0, -102, 0, -102, 0, 0, 0, 0, 0, 0, -102, -102, 0, 0, 0, 0, 0, 0, 0, -102, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -102, 0, -102, -102, 0, -102, 0, // State 362 0, 0, 0, 0, -103, 0, -103, 0, 0, 0, 0, 0, 0, -103, -103, 0, 0, 0, 0, 0, 0, 0, -103, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -103, 0, -103, -103, 0, -103, 0, // State 363 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 145, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 364 0, 0, 0, 0, -73, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -73, 0, 0, -73, 0, // State 365 0, 0, 0, 0, 0, 0, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 366 0, 0, 0, 369, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 367 0, 0, 0, 0, 0, 370, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 368 0, 0, 0, 0, -104, 0, -104, 0, 0, 0, 0, 0, 0, -104, -104, 0, 0, 0, 0, 0, 0, 0, -104, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -104, 0, -104, -104, 0, -104, 0, // State 369 0, 106, 107, 0, 0, 0, 0, 0, 0, 0, 108, 0, 0, 0, 0, 9, 27, 0, 28, 29, 85, 109, 0, 0, 110, 0, 111, 112, 113, 114, 0, 115, 0, 116, 117, 0, 0, 118, 119, 120, 0, 121, 0, 0, 0, 0, 122, // State 370 0, -243, -243, -243, -243, -243, -243, 0, -243, -243, -243, 0, -243, -243, -243, -243, -243, 0, -243, -243, -243, -243, -243, -243, -243, 0, -243, -243, -243, -243, -243, -243, -243, -243, -243, 0, -243, -243, -243, -243, 0, -243, -243, -243, 0, -243, -243, ]; const __EOF_ACTION: &'static [i16] = &[ // State 0 0, // State 1 -118, // State 2 -252, // State 3 -88, // State 4 0, // State 5 0, // State 6 0, // State 7 0, // State 8 0, // State 9 0, // State 10 0, // State 11 0, // State 12 0, // State 13 -89, // State 14 0, // State 15 0, // State 16 0, // State 17 0, // State 18 0, // State 19 0, // State 20 0, // State 21 0, // State 22 0, // State 23 0, // State 24 0, // State 25 0, // State 26 0, // State 27 0, // State 28 0, // State 29 0, // State 30 0, // State 31 0, // State 32 0, // State 33 0, // State 34 0, // State 35 0, // State 36 0, // State 37 0, // State 38 0, // State 39 0, // State 40 0, // State 41 0, // State 42 0, // State 43 0, // State 44 0, // State 45 0, // State 46 0, // State 47 -206, // State 48 0, // State 49 0, // State 50 0, // State 51 0, // State 52 0, // State 53 0, // State 54 0, // State 55 0, // State 56 0, // State 57 0, // State 58 0, // State 59 -207, // State 60 0, // State 61 0, // State 62 0, // State 63 0, // State 64 0, // State 65 0, // State 66 0, // State 67 0, // State 68 0, // State 69 0, // State 70 0, // State 71 0, // State 72 0, // State 73 0, // State 74 0, // State 75 0, // State 76 0, // State 77 0, // State 78 0, // State 79 0, // State 80 0, // State 81 0, // State 82 0, // State 83 0, // State 84 0, // State 85 0, // State 86 0, // State 87 0, // State 88 0, // State 89 0, // State 90 0, // State 91 0, // State 92 0, // State 93 0, // State 94 0, // State 95 0, // State 96 0, // State 97 0, // State 98 0, // State 99 0, // State 100 0, // State 101 0, // State 102 0, // State 103 0, // State 104 0, // State 105 0, // State 106 0, // State 107 0, // State 108 0, // State 109 0, // State 110 0, // State 111 0, // State 112 0, // State 113 0, // State 114 0, // State 115 0, // State 116 0, // State 117 0, // State 118 0, // State 119 0, // State 120 0, // State 121 0, // State 122 0, // State 123 0, // State 124 0, // State 125 0, // State 126 0, // State 127 0, // State 128 0, // State 129 0, // State 130 0, // State 131 0, // State 132 0, // State 133 0, // State 134 0, // State 135 0, // State 136 0, // State 137 0, // State 138 0, // State 139 0, // State 140 0, // State 141 0, // State 142 0, // State 143 0, // State 144 0, // State 145 0, // State 146 0, // State 147 0, // State 148 0, // State 149 0, // State 150 0, // State 151 0, // State 152 0, // State 153 0, // State 154 0, // State 155 0, // State 156 0, // State 157 0, // State 158 0, // State 159 0, // State 160 0, // State 161 0, // State 162 0, // State 163 0, // State 164 0, // State 165 0, // State 166 0, // State 167 0, // State 168 0, // State 169 0, // State 170 0, // State 171 0, // State 172 0, // State 173 0, // State 174 0, // State 175 0, // State 176 0, // State 177 0, // State 178 0, // State 179 0, // State 180 0, // State 181 0, // State 182 0, // State 183 0, // State 184 0, // State 185 0, // State 186 0, // State 187 0, // State 188 0, // State 189 0, // State 190 0, // State 191 0, // State 192 0, // State 193 0, // State 194 0, // State 195 0, // State 196 0, // State 197 0, // State 198 0, // State 199 0, // State 200 0, // State 201 0, // State 202 0, // State 203 0, // State 204 0, // State 205 0, // State 206 0, // State 207 0, // State 208 0, // State 209 0, // State 210 0, // State 211 0, // State 212 0, // State 213 0, // State 214 0, // State 215 0, // State 216 0, // State 217 0, // State 218 0, // State 219 0, // State 220 0, // State 221 0, // State 222 0, // State 223 0, // State 224 0, // State 225 0, // State 226 0, // State 227 0, // State 228 0, // State 229 0, // State 230 0, // State 231 0, // State 232 0, // State 233 0, // State 234 0, // State 235 0, // State 236 0, // State 237 0, // State 238 0, // State 239 0, // State 240 0, // State 241 0, // State 242 0, // State 243 0, // State 244 0, // State 245 0, // State 246 0, // State 247 0, // State 248 0, // State 249 0, // State 250 0, // State 251 0, // State 252 0, // State 253 0, // State 254 0, // State 255 0, // State 256 0, // State 257 0, // State 258 0, // State 259 0, // State 260 0, // State 261 0, // State 262 0, // State 263 0, // State 264 0, // State 265 0, // State 266 0, // State 267 0, // State 268 0, // State 269 0, // State 270 0, // State 271 0, // State 272 0, // State 273 0, // State 274 0, // State 275 0, // State 276 0, // State 277 0, // State 278 0, // State 279 0, // State 280 0, // State 281 0, // State 282 0, // State 283 0, // State 284 0, // State 285 0, // State 286 0, // State 287 0, // State 288 0, // State 289 0, // State 290 0, // State 291 0, // State 292 0, // State 293 0, // State 294 0, // State 295 0, // State 296 0, // State 297 0, // State 298 0, // State 299 0, // State 300 0, // State 301 0, // State 302 0, // State 303 0, // State 304 0, // State 305 0, // State 306 0, // State 307 0, // State 308 0, // State 309 0, // State 310 0, // State 311 0, // State 312 0, // State 313 0, // State 314 0, // State 315 0, // State 316 0, // State 317 0, // State 318 0, // State 319 0, // State 320 0, // State 321 0, // State 322 0, // State 323 0, // State 324 0, // State 325 0, // State 326 0, // State 327 0, // State 328 0, // State 329 0, // State 330 0, // State 331 0, // State 332 0, // State 333 0, // State 334 0, // State 335 0, // State 336 0, // State 337 0, // State 338 0, // State 339 0, // State 340 0, // State 341 0, // State 342 0, // State 343 0, // State 344 0, // State 345 0, // State 346 0, // State 347 0, // State 348 0, // State 349 0, // State 350 0, // State 351 0, // State 352 0, // State 353 0, // State 354 0, // State 355 0, // State 356 0, // State 357 0, // State 358 0, // State 359 0, // State 360 0, // State 361 0, // State 362 0, // State 363 0, // State 364 0, // State 365 0, // State 366 0, // State 367 0, // State 368 0, // State 369 0, // State 370 0, ]; const __GOTO: &'static [i16] = &[ // State 0 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 1 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 2 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 3 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 4 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 5 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 6 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 7 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 8 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 9 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 10 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 11 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 12 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 13 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 14 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 22, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 24, 0, 0, 0, 25, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 15 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 16 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 34, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 17 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 18 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 19 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 20 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 22, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 38, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 21 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 22 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 23 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 24 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 25 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 26 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 27 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 28 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 29 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 22, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 41, 0, 0, 0, 25, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 30 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 22, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 42, 0, 0, 0, 25, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 31 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 43, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 44, 0, 45, 46, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 32 0, 0, 0, 0, 0, 0, 0, 0, 49, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 50, 0, 0, 0, 0, 0, 51, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 33 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 34 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 53, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 35 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 36 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 37 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 38 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 39 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 40 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 41 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 42 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 43 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 44 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 43, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 59, 0, 0, 46, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 45 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 46 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 61, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 47 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 48 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 62, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 49 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 50 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 51 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 52 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 53 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 54 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 55 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 22, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 65, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 56 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 57 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 66, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 67, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 58 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 59 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 60 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 70, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 61 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 62 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 22, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 72, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 63 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 64 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 65 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 66 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 67 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 74, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 68 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 69 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 70 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 22, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 77, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 71 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 72 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 73 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 79, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 74 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 81, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 82, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 83, 0, 0, // State 75 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 76 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 77 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 78 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 79 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 88, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 83, 0, 0, // State 80 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 81 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 82 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 83 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 91, 0, 0, // State 84 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 85 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 86 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 87 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 88 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 89 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 90 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 94, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 91 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 92 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 95, 0, 96, 0, 0, 0, 0, 0, 0, 0, 0, 97, 98, 99, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 100, 0, 101, 0, 0, 0, 102, 0, 0, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 103, 104, 105, 0, 0, // State 93 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 94 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 95 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 96 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 97 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 98 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 99 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 100 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 101 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 102 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 103 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 104 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 105 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 124, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 125, 0, 0, 0, 0, 0, 0, 0, 0, 126, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 106 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 97, 98, 99, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 101, 0, 0, 0, 102, 0, 0, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 129, 105, 0, 0, // State 107 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 130, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 131, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 97, 98, 99, 0, 0, 0, 0, 0, 132, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 101, 0, 0, 0, 102, 0, 0, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 103, 0, 105, 0, 0, // State 108 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 134, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 95, 0, 96, 0, 0, 0, 0, 0, 0, 0, 0, 97, 98, 99, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 135, 0, 0, 0, 0, 0, 0, 0, 136, 0, 101, 0, 0, 0, 102, 0, 0, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 103, 104, 105, 0, 0, // State 109 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 95, 0, 96, 0, 0, 0, 0, 0, 0, 0, 0, 97, 98, 99, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 137, 0, 101, 0, 0, 0, 102, 0, 0, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 103, 104, 105, 0, 0, // State 110 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 95, 0, 96, 0, 0, 0, 0, 0, 0, 0, 0, 97, 98, 99, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 138, 0, 101, 0, 0, 0, 102, 0, 0, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 103, 104, 105, 0, 0, // State 111 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 95, 0, 96, 0, 0, 0, 0, 0, 0, 0, 0, 97, 98, 99, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 139, 0, 101, 0, 0, 0, 102, 0, 0, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 103, 104, 105, 0, 0, // State 112 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 95, 0, 96, 0, 0, 0, 0, 0, 0, 0, 0, 97, 98, 99, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 140, 0, 101, 0, 0, 0, 102, 0, 0, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 103, 104, 105, 0, 0, // State 113 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 95, 0, 96, 0, 0, 0, 0, 0, 0, 0, 0, 97, 98, 99, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 141, 0, 101, 0, 0, 0, 102, 0, 0, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 103, 104, 105, 0, 0, // State 114 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 142, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 115 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 143, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 83, 144, 0, // State 116 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 146, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 147, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 117 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 148, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 149, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 118 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 151, 0, 152, 0, 0, 0, 153, 0, 0, 0, 0, 154, 0, 0, 155, 0, 0, 0, 0, 22, 156, 0, 0, 0, 157, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 26, 0, 0, 0, 0, 158, 0, 0, 0, 159, 0, 0, 160, 0, 0, // State 119 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 95, 0, 96, 0, 0, 0, 0, 0, 0, 0, 0, 97, 98, 99, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 168, 0, 101, 0, 0, 0, 102, 0, 0, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 103, 104, 105, 0, 0, // State 120 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 134, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 95, 0, 96, 0, 0, 0, 0, 0, 0, 0, 0, 97, 98, 99, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 169, 0, 0, 0, 0, 0, 0, 0, 136, 0, 101, 0, 0, 0, 102, 0, 0, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 103, 104, 105, 0, 0, // State 121 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 170, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 171, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 95, 0, 96, 0, 0, 0, 0, 0, 0, 0, 0, 97, 98, 99, 0, 0, 0, 0, 172, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 173, 0, 101, 0, 0, 0, 102, 0, 0, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 103, 104, 105, 0, 0, // State 122 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 123 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 175, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 124 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 125 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 126 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 95, 0, 96, 0, 0, 0, 0, 0, 0, 0, 0, 97, 98, 99, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 178, 0, 101, 0, 0, 0, 102, 0, 0, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 103, 104, 105, 0, 0, // State 127 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 179, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 128 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 180, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 129 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 181, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 97, 98, 99, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 101, 0, 0, 0, 102, 0, 0, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 103, 0, 105, 0, 0, // State 130 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 131 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 132 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 97, 98, 99, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 101, 0, 0, 0, 102, 0, 0, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 0, 105, 0, 0, // State 133 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 95, 0, 96, 0, 0, 0, 0, 0, 0, 0, 0, 97, 98, 99, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 184, 0, 101, 0, 0, 0, 102, 0, 0, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 103, 104, 105, 0, 0, // State 134 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 135 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 136 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 137 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 138 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 139 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 140 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 95, 0, 96, 0, 0, 0, 0, 0, 0, 0, 0, 97, 98, 99, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 191, 0, 101, 0, 0, 0, 102, 0, 0, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 103, 104, 105, 0, 0, // State 141 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 142 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 143 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 144 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 81, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 194, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 83, 0, 0, // State 145 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 195, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 146 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 147 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 148 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 149 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 199, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 150 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 151 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 200, 0, 0, 0, 0, 0, 153, 0, 0, 0, 0, 154, 0, 0, 155, 0, 0, 0, 0, 22, 156, 0, 0, 0, 157, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 26, 0, 0, 0, 0, 158, 0, 0, 0, 159, 0, 0, 160, 0, 0, // State 152 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 153 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 154 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 155 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 156 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 157 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 158 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 203, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 159 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 160 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 205, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 206, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 207, 0, 0, 0, 0, 0, 0, 0, 0, // State 161 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 153, 0, 0, 0, 0, 209, 0, 0, 155, 0, 0, 0, 0, 22, 210, 0, 0, 0, 211, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 26, 0, 0, 0, 0, 212, 0, 0, 0, 159, 0, 0, 213, 0, 0, // State 162 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 218, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 153, 0, 0, 0, 0, 154, 0, 0, 219, 0, 0, 0, 0, 22, 156, 0, 0, 0, 0, 0, 0, 0, 0, 220, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 26, 0, 0, 0, 0, 158, 0, 0, 0, 0, 0, 0, 160, 0, 0, // State 163 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 218, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 153, 0, 0, 0, 0, 154, 0, 0, 219, 0, 0, 0, 0, 22, 156, 0, 0, 0, 0, 0, 0, 0, 0, 221, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 26, 0, 0, 0, 0, 158, 0, 0, 0, 0, 0, 0, 160, 0, 0, // State 164 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 95, 0, 96, 0, 0, 0, 0, 0, 0, 0, 0, 97, 98, 99, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 222, 0, 101, 0, 0, 0, 102, 0, 0, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 103, 104, 105, 0, 0, // State 165 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 218, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 153, 0, 0, 0, 0, 154, 0, 0, 219, 0, 0, 0, 0, 22, 156, 0, 0, 0, 0, 0, 0, 0, 0, 223, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 26, 0, 0, 0, 0, 158, 0, 0, 0, 0, 0, 0, 160, 0, 0, // State 166 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 225, 226, 0, 0, 0, 0, 0, 0, 0, 227, 0, 0, 97, 98, 99, 0, 0, 0, 0, 0, 0, 0, 0, 228, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 101, 0, 0, 0, 102, 0, 0, 26, 0, 0, 0, 0, 0, 0, 0, 229, 0, 103, 0, 105, 0, 0, // State 167 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 168 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 169 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 233, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 95, 0, 96, 0, 0, 0, 0, 0, 0, 0, 0, 97, 98, 99, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 173, 0, 101, 0, 0, 0, 102, 0, 0, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 103, 104, 105, 0, 0, // State 170 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 171 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 172 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 237, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 173 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 95, 0, 96, 0, 0, 0, 0, 0, 0, 0, 0, 97, 98, 99, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 240, 0, 101, 0, 0, 0, 102, 0, 0, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 241, 242, 105, 0, 0, // State 174 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 175 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 176 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 177 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 178 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 179 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 180 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 181 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 182 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 183 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 184 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 185 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 95, 0, 96, 0, 0, 0, 0, 0, 0, 0, 0, 97, 98, 99, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 249, 0, 101, 0, 0, 0, 102, 0, 0, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 103, 104, 105, 0, 0, // State 186 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 187 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 134, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 95, 0, 96, 0, 0, 0, 0, 0, 0, 0, 0, 97, 98, 99, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 250, 0, 0, 0, 0, 0, 0, 0, 136, 0, 101, 0, 0, 0, 102, 0, 0, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 103, 104, 105, 0, 0, // State 188 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 95, 0, 96, 0, 0, 0, 0, 0, 0, 0, 0, 97, 98, 99, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 251, 0, 101, 0, 0, 0, 102, 0, 0, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 103, 104, 105, 0, 0, // State 189 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 151, 0, 252, 0, 0, 0, 153, 0, 0, 0, 0, 154, 0, 0, 155, 0, 0, 0, 0, 22, 156, 0, 0, 0, 157, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 26, 0, 0, 0, 0, 158, 0, 0, 0, 159, 0, 0, 160, 0, 0, // State 190 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 191 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 192 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 95, 0, 96, 0, 0, 0, 0, 0, 0, 0, 0, 97, 98, 99, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 0, 101, 0, 0, 0, 102, 0, 0, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 103, 104, 105, 0, 0, // State 193 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 194 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 195 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 95, 0, 96, 0, 0, 0, 0, 0, 0, 0, 0, 97, 98, 99, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 258, 0, 101, 0, 0, 0, 102, 0, 0, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 103, 104, 105, 0, 0, // State 196 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 259, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 197 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 134, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 95, 0, 96, 0, 0, 0, 0, 0, 0, 0, 0, 97, 98, 99, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 260, 0, 0, 0, 0, 0, 0, 0, 136, 0, 101, 0, 0, 0, 102, 0, 0, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 103, 104, 105, 0, 0, // State 198 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 261, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 199 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 200 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 95, 0, 96, 0, 0, 0, 0, 0, 0, 0, 0, 97, 98, 99, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 262, 0, 101, 0, 0, 0, 102, 0, 0, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 103, 104, 105, 0, 0, // State 201 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 153, 0, 0, 0, 0, 154, 0, 0, 263, 0, 0, 0, 0, 22, 156, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 26, 0, 0, 0, 0, 158, 0, 0, 0, 0, 0, 0, 160, 0, 0, // State 202 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 203 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 95, 0, 96, 0, 0, 0, 0, 0, 0, 0, 0, 97, 98, 99, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 265, 0, 101, 0, 0, 0, 102, 0, 0, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 103, 104, 105, 0, 0, // State 204 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 266, 0, 0, 0, 0, 0, 0, 0, 0, // State 205 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 206 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 207 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 153, 0, 0, 0, 0, 154, 0, 0, 269, 0, 0, 0, 0, 22, 156, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 26, 0, 0, 0, 0, 158, 0, 0, 0, 0, 0, 0, 160, 0, 0, // State 208 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 209 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 271, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 210 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 272, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 211 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 273, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 212 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 274, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 213 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 275, 0, 0, 0, 0, 0, 0, 0, 22, 276, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 26, 0, 0, 0, 0, 277, 0, 0, 0, 0, 0, 0, 278, 0, 0, // State 214 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 218, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 153, 0, 0, 0, 0, 154, 0, 0, 219, 0, 0, 0, 0, 22, 156, 0, 0, 0, 0, 0, 0, 0, 0, 282, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 26, 0, 0, 0, 0, 158, 0, 0, 0, 0, 0, 0, 160, 0, 0, // State 215 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 218, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 153, 0, 0, 0, 0, 154, 0, 0, 219, 0, 0, 0, 0, 22, 156, 0, 0, 0, 0, 0, 0, 0, 0, 283, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 26, 0, 0, 0, 0, 158, 0, 0, 0, 0, 0, 0, 160, 0, 0, // State 216 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 225, 226, 0, 0, 0, 0, 0, 0, 0, 227, 0, 0, 97, 98, 99, 0, 0, 0, 0, 0, 0, 0, 0, 284, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 101, 0, 0, 0, 102, 0, 0, 26, 0, 0, 0, 0, 0, 0, 0, 229, 0, 103, 0, 105, 0, 0, // State 217 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 153, 0, 0, 0, 0, 154, 0, 0, 285, 0, 0, 0, 0, 22, 156, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 26, 0, 0, 0, 0, 158, 0, 0, 0, 0, 0, 0, 160, 0, 0, // State 218 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 219 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 220 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 221 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 222 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 223 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 225, 226, 0, 0, 0, 0, 0, 0, 0, 292, 0, 0, 97, 98, 99, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 101, 0, 0, 0, 102, 0, 0, 26, 0, 0, 0, 0, 0, 0, 0, 229, 0, 103, 0, 105, 0, 0, // State 224 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 225 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 226 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 227 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 228 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 229 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 226, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 97, 98, 99, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 101, 0, 0, 0, 102, 0, 0, 26, 0, 0, 0, 0, 0, 0, 0, 296, 0, 241, 0, 105, 0, 0, // State 230 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 143, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 83, 297, 0, // State 231 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 232 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 233 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 234 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 95, 0, 96, 0, 0, 0, 0, 0, 0, 0, 0, 97, 98, 99, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 299, 0, 101, 0, 0, 0, 102, 0, 0, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 103, 104, 105, 0, 0, // State 235 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 236 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 95, 0, 96, 0, 0, 0, 0, 0, 0, 0, 0, 97, 98, 99, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 300, 0, 101, 0, 0, 0, 102, 0, 0, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 103, 104, 105, 0, 0, // State 237 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 238 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 239 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 301, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 240 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 179, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 241 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 180, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 242 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 243 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 134, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 95, 0, 96, 0, 0, 0, 0, 0, 0, 0, 0, 97, 98, 99, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 302, 0, 0, 0, 0, 0, 0, 0, 136, 0, 101, 0, 0, 0, 102, 0, 0, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 103, 104, 105, 0, 0, // State 244 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 245 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 246 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 247 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 248 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 249 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 250 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 251 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 200, 0, 0, 0, 0, 0, 153, 0, 0, 0, 0, 154, 0, 0, 155, 0, 0, 0, 0, 22, 156, 0, 0, 0, 157, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 26, 0, 0, 0, 0, 158, 0, 0, 0, 159, 0, 0, 160, 0, 0, // State 252 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 253 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 254 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 255 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 256 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 308, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 257 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 258 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 259 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 260 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 261 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 262 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 263 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 95, 0, 96, 0, 0, 0, 0, 0, 0, 0, 0, 97, 98, 99, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 312, 0, 101, 0, 0, 0, 102, 0, 0, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 103, 104, 105, 0, 0, // State 264 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 265 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 266 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 267 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 268 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 269 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 153, 0, 0, 0, 0, 154, 0, 0, 315, 0, 0, 0, 0, 22, 156, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 26, 0, 0, 0, 0, 158, 0, 0, 0, 0, 0, 0, 160, 0, 0, // State 270 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 271 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 272 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 273 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 274 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 275 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 271, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 276 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 273, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 277 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 274, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 278 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 218, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 153, 0, 0, 0, 0, 154, 0, 0, 219, 0, 0, 0, 0, 22, 156, 0, 0, 0, 0, 0, 0, 0, 0, 321, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 26, 0, 0, 0, 0, 158, 0, 0, 0, 0, 0, 0, 160, 0, 0, // State 279 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 218, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 153, 0, 0, 0, 0, 154, 0, 0, 219, 0, 0, 0, 0, 22, 156, 0, 0, 0, 0, 0, 0, 0, 0, 322, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 26, 0, 0, 0, 0, 158, 0, 0, 0, 0, 0, 0, 160, 0, 0, // State 280 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 225, 226, 0, 0, 0, 0, 0, 0, 0, 227, 0, 0, 97, 98, 99, 0, 0, 0, 0, 0, 0, 0, 0, 323, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 101, 0, 0, 0, 102, 0, 0, 26, 0, 0, 0, 0, 0, 0, 0, 229, 0, 103, 0, 105, 0, 0, // State 281 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 282 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 283 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 284 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 285 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 286 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 287 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 288 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 153, 0, 0, 0, 0, 154, 0, 0, 329, 0, 0, 0, 0, 22, 156, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 26, 0, 0, 0, 0, 158, 0, 0, 0, 0, 0, 0, 160, 0, 0, // State 289 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 95, 0, 96, 0, 0, 0, 0, 0, 0, 0, 0, 97, 98, 99, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 330, 0, 101, 0, 0, 0, 102, 0, 0, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 103, 104, 105, 0, 0, // State 290 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 291 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 292 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 153, 0, 0, 0, 0, 154, 0, 0, 332, 0, 0, 0, 0, 22, 156, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 26, 0, 0, 0, 0, 158, 0, 0, 0, 0, 0, 0, 160, 0, 0, // State 293 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 294 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 295 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 333, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 296 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 297 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 298 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 299 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 300 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 95, 0, 96, 0, 0, 0, 0, 0, 0, 0, 0, 97, 98, 99, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 336, 0, 101, 0, 0, 0, 102, 0, 0, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 103, 104, 105, 0, 0, // State 301 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 302 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 303 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 304 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 134, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 95, 0, 96, 0, 0, 0, 0, 0, 0, 0, 0, 97, 98, 99, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 338, 0, 0, 0, 0, 0, 0, 0, 136, 0, 101, 0, 0, 0, 102, 0, 0, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 103, 104, 105, 0, 0, // State 305 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 306 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 95, 0, 96, 0, 0, 0, 0, 0, 0, 0, 0, 97, 98, 99, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 339, 0, 101, 0, 0, 0, 102, 0, 0, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 103, 104, 105, 0, 0, // State 307 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 308 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 309 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 310 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 95, 0, 96, 0, 0, 0, 0, 0, 0, 0, 0, 97, 98, 99, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 340, 0, 101, 0, 0, 0, 102, 0, 0, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 103, 104, 105, 0, 0, // State 311 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 312 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 313 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 130, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 131, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 97, 98, 99, 0, 0, 0, 0, 0, 341, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 101, 0, 0, 0, 102, 0, 0, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 103, 0, 105, 0, 0, // State 314 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 342, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 315 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 316 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 317 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 318 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 319 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 153, 0, 0, 0, 0, 154, 0, 0, 343, 0, 0, 0, 0, 22, 156, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 26, 0, 0, 0, 0, 158, 0, 0, 0, 0, 0, 0, 160, 0, 0, // State 320 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 321 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 322 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 323 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 348, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 324 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 153, 0, 0, 0, 0, 154, 0, 0, 349, 0, 0, 0, 0, 22, 156, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 26, 0, 0, 0, 0, 158, 0, 0, 0, 0, 0, 0, 160, 0, 0, // State 325 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 350, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 326 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 351, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 327 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 328 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 329 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 330 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 331 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 332 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 333 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 95, 0, 96, 0, 0, 0, 0, 0, 0, 0, 0, 97, 98, 99, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 354, 0, 101, 0, 0, 0, 102, 0, 0, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 103, 104, 105, 0, 0, // State 334 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 335 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 355, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 336 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 337 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 338 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 339 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 340 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 341 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 342 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 342, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 343 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 348, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 344 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 153, 0, 0, 0, 0, 154, 0, 0, 359, 0, 0, 0, 0, 22, 156, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 26, 0, 0, 0, 0, 158, 0, 0, 0, 0, 0, 0, 160, 0, 0, // State 345 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 350, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 346 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 351, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 347 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 348 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 349 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 350 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 351 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 352 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 353 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 354 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 355 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 356 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 357 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 358 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 359 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 360 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 367, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 361 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 362 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 363 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 143, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 83, 368, 0, // State 364 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 365 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 367, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 366 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 367 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 368 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 369 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 95, 0, 96, 0, 0, 0, 0, 0, 0, 0, 0, 97, 98, 99, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 371, 0, 101, 0, 0, 0, 102, 0, 0, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 103, 104, 105, 0, 0, // State 370 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ]; fn __expected_tokens(__state: usize) -> Vec<::std::string::String> { const __TERMINAL: &'static [&'static str] = &[ r###""#<""###, r###""#{""###, r###""(""###, r###"")""###, r###"",""###, r###""->""###, r###""-|""###, r###""/""###, r###"":""###, r###"":=""###, r###""<""###, r###""=""###, r###""=>""###, r###"">""###, r###"">(""###, r###""Atom""###, r###""Char""###, r###""Float""###, r###""Integer""###, r###""String""###, r###""Variable""###, r###""[""###, r###""]""###, r###""after""###, r###""apply""###, r###""attributes""###, r###""call""###, r###""case""###, r###""catch""###, r###""do""###, r###""end""###, r###""fun""###, r###""in""###, r###""let""###, r###""letrec""###, r###""module""###, r###""of""###, r###""primop""###, r###""receive""###, r###""try""###, r###""when""###, r###""{""###, r###""|""###, r###""}""###, r###""}#""###, r###""}~""###, r###""~{""###, ]; __ACTION[(__state * 47)..].iter().zip(__TERMINAL).filter_map(|(&state, terminal)| { if state == 0 { None } else { Some(terminal.to_string()) } }).collect() } pub struct __StateMachine<'input> where { text: &'input str, __phantom: ::std::marker::PhantomData<(&'input ())>, } impl<'input> __state_machine::ParserDefinition for __StateMachine<'input> where { type Location = usize; type Error = (); type Token = Tok<'input>; type TokenIndex = usize; type Symbol = __Symbol<'input>; type Success = Annotated; type StateIndex = i16; type Action = i16; type ReduceIndex = i16; type NonterminalIndex = usize; #[inline] fn start_location(&self) -> Self::Location { Default::default() } #[inline] fn start_state(&self) -> Self::StateIndex { 0 } #[inline] fn token_to_index(&self, token: &Self::Token) -> Option { __token_to_integer(token, ::std::marker::PhantomData::<(&())>) } #[inline] fn action(&self, state: i16, integer: usize) -> i16 { __ACTION[(state as usize) * 47 + integer] } #[inline] fn error_action(&self, state: i16) -> i16 { __ACTION[(state as usize) * 47 + (47 - 1)] } #[inline] fn eof_action(&self, state: i16) -> i16 { __EOF_ACTION[state as usize] } #[inline] fn goto(&self, state: i16, nt: usize) -> i16 { __GOTO[(state as usize) * 112 + nt] - 1 } fn token_to_symbol(&self, token_index: usize, token: Self::Token) -> Self::Symbol { __token_to_symbol(token_index, token, ::std::marker::PhantomData::<(&())>) } fn expected_tokens(&self, state: i16) -> Vec { __expected_tokens(state as usize) } #[inline] fn uses_error_recovery(&self) -> bool { false } #[inline] fn error_recovery_symbol( &self, recovery: __state_machine::ErrorRecovery, ) -> Self::Symbol { panic!("error recovery not enabled for this grammar") } fn reduce( &mut self, action: i16, start_location: Option<&Self::Location>, states: &mut Vec, symbols: &mut Vec<__state_machine::SymbolTriple>, ) -> Option<__state_machine::ParseResult> { __reduce( self.text, action, start_location, states, symbols, ::std::marker::PhantomData::<(&())>, ) } fn simulate_reduce(&self, action: i16) -> __state_machine::SimulatedReduce { __simulate_reduce(action, ::std::marker::PhantomData::<(&())>) } } fn __token_to_integer< 'input, >( __token: &Tok<'input>, _: ::std::marker::PhantomData<(&'input ())>, ) -> Option { match *__token { Tok::BitstringPatternOpen if true => Some(0), Tok::BitstringOpen if true => Some(1), Tok::ParenOpen if true => Some(2), Tok::ParenClose if true => Some(3), Tok::Comma if true => Some(4), Tok::Arrow if true => Some(5), Tok::Annotation if true => Some(6), Tok::ForwardSlash if true => Some(7), Tok::Colon if true => Some(8), Tok::MapMatch if true => Some(9), Tok::TriOpen if true => Some(10), Tok::Equals if true => Some(11), Tok::HashRocket if true => Some(12), Tok::TriClose if true => Some(13), Tok::BitstringPatternSep if true => Some(14), Tok::Atom(_) if true => Some(15), Tok::Char(_) if true => Some(16), Tok::Float(_) if true => Some(17), Tok::Integer(_) if true => Some(18), Tok::String(_) if true => Some(19), Tok::Variable(_) if true => Some(20), Tok::SquareOpen if true => Some(21), Tok::SquareClose if true => Some(22), Tok::After if true => Some(23), Tok::Apply if true => Some(24), Tok::Attributes if true => Some(25), Tok::Call if true => Some(26), Tok::Case if true => Some(27), Tok::Catch if true => Some(28), Tok::Do if true => Some(29), Tok::End if true => Some(30), Tok::Fun if true => Some(31), Tok::In if true => Some(32), Tok::Let if true => Some(33), Tok::Letrec if true => Some(34), Tok::Module if true => Some(35), Tok::Of if true => Some(36), Tok::Primop if true => Some(37), Tok::Receive if true => Some(38), Tok::Try if true => Some(39), Tok::When if true => Some(40), Tok::CurlyOpen if true => Some(41), Tok::Pipe if true => Some(42), Tok::CurlyClose if true => Some(43), Tok::BitstringClose if true => Some(44), Tok::MapClose if true => Some(45), Tok::MapOpen if true => Some(46), _ => None, } } fn __token_to_symbol< 'input, >( __token_index: usize, __token: Tok<'input>, _: ::std::marker::PhantomData<(&'input ())>, ) -> __Symbol<'input> { match __token_index { 0 => match __token { __tok @ Tok::BitstringPatternOpen => __Symbol::Variant0((__tok)), _ => unreachable!(), }, 1 => match __token { __tok @ Tok::BitstringOpen => __Symbol::Variant0((__tok)), _ => unreachable!(), }, 2 => match __token { __tok @ Tok::ParenOpen => __Symbol::Variant0((__tok)), _ => unreachable!(), }, 3 => match __token { __tok @ Tok::ParenClose => __Symbol::Variant0((__tok)), _ => unreachable!(), }, 4 => match __token { __tok @ Tok::Comma => __Symbol::Variant0((__tok)), _ => unreachable!(), }, 5 => match __token { __tok @ Tok::Arrow => __Symbol::Variant0((__tok)), _ => unreachable!(), }, 6 => match __token { __tok @ Tok::Annotation => __Symbol::Variant0((__tok)), _ => unreachable!(), }, 7 => match __token { __tok @ Tok::ForwardSlash => __Symbol::Variant0((__tok)), _ => unreachable!(), }, 8 => match __token { __tok @ Tok::Colon => __Symbol::Variant0((__tok)), _ => unreachable!(), }, 9 => match __token { __tok @ Tok::MapMatch => __Symbol::Variant0((__tok)), _ => unreachable!(), }, 10 => match __token { __tok @ Tok::TriOpen => __Symbol::Variant0((__tok)), _ => unreachable!(), }, 11 => match __token { __tok @ Tok::Equals => __Symbol::Variant0((__tok)), _ => unreachable!(), }, 12 => match __token { __tok @ Tok::HashRocket => __Symbol::Variant0((__tok)), _ => unreachable!(), }, 13 => match __token { __tok @ Tok::TriClose => __Symbol::Variant0((__tok)), _ => unreachable!(), }, 14 => match __token { __tok @ Tok::BitstringPatternSep => __Symbol::Variant0((__tok)), _ => unreachable!(), }, 15 => match __token { Tok::Atom(__tok0) => __Symbol::Variant1((__tok0)), _ => unreachable!(), }, 16 => match __token { Tok::Char(__tok0) => __Symbol::Variant2((__tok0)), _ => unreachable!(), }, 17 => match __token { Tok::Float(__tok0) => __Symbol::Variant1((__tok0)), _ => unreachable!(), }, 18 => match __token { Tok::Integer(__tok0) => __Symbol::Variant3((__tok0)), _ => unreachable!(), }, 19 => match __token { Tok::String(__tok0) => __Symbol::Variant1((__tok0)), _ => unreachable!(), }, 20 => match __token { Tok::Variable(__tok0) => __Symbol::Variant1((__tok0)), _ => unreachable!(), }, 21 => match __token { __tok @ Tok::SquareOpen => __Symbol::Variant0((__tok)), _ => unreachable!(), }, 22 => match __token { __tok @ Tok::SquareClose => __Symbol::Variant0((__tok)), _ => unreachable!(), }, 23 => match __token { __tok @ Tok::After => __Symbol::Variant0((__tok)), _ => unreachable!(), }, 24 => match __token { __tok @ Tok::Apply => __Symbol::Variant0((__tok)), _ => unreachable!(), }, 25 => match __token { __tok @ Tok::Attributes => __Symbol::Variant0((__tok)), _ => unreachable!(), }, 26 => match __token { __tok @ Tok::Call => __Symbol::Variant0((__tok)), _ => unreachable!(), }, 27 => match __token { __tok @ Tok::Case => __Symbol::Variant0((__tok)), _ => unreachable!(), }, 28 => match __token { __tok @ Tok::Catch => __Symbol::Variant0((__tok)), _ => unreachable!(), }, 29 => match __token { __tok @ Tok::Do => __Symbol::Variant0((__tok)), _ => unreachable!(), }, 30 => match __token { __tok @ Tok::End => __Symbol::Variant0((__tok)), _ => unreachable!(), }, 31 => match __token { __tok @ Tok::Fun => __Symbol::Variant0((__tok)), _ => unreachable!(), }, 32 => match __token { __tok @ Tok::In => __Symbol::Variant0((__tok)), _ => unreachable!(), }, 33 => match __token { __tok @ Tok::Let => __Symbol::Variant0((__tok)), _ => unreachable!(), }, 34 => match __token { __tok @ Tok::Letrec => __Symbol::Variant0((__tok)), _ => unreachable!(), }, 35 => match __token { __tok @ Tok::Module => __Symbol::Variant0((__tok)), _ => unreachable!(), }, 36 => match __token { __tok @ Tok::Of => __Symbol::Variant0((__tok)), _ => unreachable!(), }, 37 => match __token { __tok @ Tok::Primop => __Symbol::Variant0((__tok)), _ => unreachable!(), }, 38 => match __token { __tok @ Tok::Receive => __Symbol::Variant0((__tok)), _ => unreachable!(), }, 39 => match __token { __tok @ Tok::Try => __Symbol::Variant0((__tok)), _ => unreachable!(), }, 40 => match __token { __tok @ Tok::When => __Symbol::Variant0((__tok)), _ => unreachable!(), }, 41 => match __token { __tok @ Tok::CurlyOpen => __Symbol::Variant0((__tok)), _ => unreachable!(), }, 42 => match __token { __tok @ Tok::Pipe => __Symbol::Variant0((__tok)), _ => unreachable!(), }, 43 => match __token { __tok @ Tok::CurlyClose => __Symbol::Variant0((__tok)), _ => unreachable!(), }, 44 => match __token { __tok @ Tok::BitstringClose => __Symbol::Variant0((__tok)), _ => unreachable!(), }, 45 => match __token { __tok @ Tok::MapClose => __Symbol::Variant0((__tok)), _ => unreachable!(), }, 46 => match __token { __tok @ Tok::MapOpen => __Symbol::Variant0((__tok)), _ => unreachable!(), }, _ => unreachable!(), } } fn __simulate_reduce< 'input, >( __reduce_index: i16, _: ::std::marker::PhantomData<(&'input ())>, ) -> __state_machine::SimulatedReduce<__StateMachine<'input>> { match __reduce_index { 0 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 2, nonterminal_produced: 0, } } 1 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 2, nonterminal_produced: 1, } } 2 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 0, nonterminal_produced: 1, } } 3 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 2, nonterminal_produced: 2, } } 4 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 2, nonterminal_produced: 3, } } 5 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 0, nonterminal_produced: 3, } } 6 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 2, nonterminal_produced: 4, } } 7 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 2, nonterminal_produced: 5, } } 8 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 0, nonterminal_produced: 5, } } 9 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 4, nonterminal_produced: 6, } } 10 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 0, nonterminal_produced: 7, } } 11 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 1, nonterminal_produced: 7, } } 12 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 4, nonterminal_produced: 8, } } 13 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 5, nonterminal_produced: 8, } } 14 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 2, nonterminal_produced: 9, } } 15 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 0, nonterminal_produced: 10, } } 16 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 1, nonterminal_produced: 10, } } 17 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 2, nonterminal_produced: 11, } } 18 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 3, nonterminal_produced: 11, } } 19 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 2, nonterminal_produced: 12, } } 20 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 0, nonterminal_produced: 13, } } 21 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 1, nonterminal_produced: 13, } } 22 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 2, nonterminal_produced: 14, } } 23 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 3, nonterminal_produced: 14, } } 24 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 2, nonterminal_produced: 15, } } 25 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 0, nonterminal_produced: 16, } } 26 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 1, nonterminal_produced: 16, } } 27 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 2, nonterminal_produced: 17, } } 28 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 3, nonterminal_produced: 17, } } 29 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 2, nonterminal_produced: 18, } } 30 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 0, nonterminal_produced: 19, } } 31 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 1, nonterminal_produced: 19, } } 32 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 2, nonterminal_produced: 20, } } 33 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 3, nonterminal_produced: 20, } } 34 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 2, nonterminal_produced: 21, } } 35 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 0, nonterminal_produced: 22, } } 36 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 1, nonterminal_produced: 22, } } 37 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 2, nonterminal_produced: 23, } } 38 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 3, nonterminal_produced: 23, } } 39 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 3, nonterminal_produced: 24, } } 40 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 3, nonterminal_produced: 25, } } 41 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 0, nonterminal_produced: 25, } } 42 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 2, nonterminal_produced: 26, } } 43 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 0, nonterminal_produced: 27, } } 44 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 1, nonterminal_produced: 27, } } 45 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 2, nonterminal_produced: 28, } } 46 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 3, nonterminal_produced: 28, } } 47 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 2, nonterminal_produced: 29, } } 48 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 0, nonterminal_produced: 30, } } 49 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 1, nonterminal_produced: 30, } } 50 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 2, nonterminal_produced: 31, } } 51 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 3, nonterminal_produced: 31, } } 52 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 2, nonterminal_produced: 32, } } 53 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 0, nonterminal_produced: 33, } } 54 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 1, nonterminal_produced: 33, } } 55 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 2, nonterminal_produced: 34, } } 56 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 3, nonterminal_produced: 34, } } 57 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 3, nonterminal_produced: 35, } } 58 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 2, nonterminal_produced: 36, } } 59 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 0, nonterminal_produced: 37, } } 60 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 1, nonterminal_produced: 37, } } 61 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 2, nonterminal_produced: 38, } } 62 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 3, nonterminal_produced: 38, } } 63 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 3, nonterminal_produced: 39, } } 64 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 3, nonterminal_produced: 40, } } 65 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 4, nonterminal_produced: 40, } } 66 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 2, nonterminal_produced: 41, } } 67 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 0, nonterminal_produced: 42, } } 68 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 1, nonterminal_produced: 42, } } 69 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 2, nonterminal_produced: 43, } } 70 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 3, nonterminal_produced: 43, } } 71 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 3, nonterminal_produced: 44, } } 72 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 6, nonterminal_produced: 44, } } 73 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 1, nonterminal_produced: 45, } } 74 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 0, nonterminal_produced: 45, } } 75 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 1, nonterminal_produced: 46, } } 76 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 4, nonterminal_produced: 46, } } 77 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 1, nonterminal_produced: 47, } } 78 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 4, nonterminal_produced: 47, } } 79 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 0, nonterminal_produced: 48, } } 80 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 1, nonterminal_produced: 48, } } 81 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 1, nonterminal_produced: 49, } } 82 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 2, nonterminal_produced: 49, } } 83 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 1, nonterminal_produced: 50, } } 84 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 4, nonterminal_produced: 50, } } 85 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 1, nonterminal_produced: 51, } } 86 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 4, nonterminal_produced: 51, } } 87 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 1, nonterminal_produced: 52, } } 88 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 4, nonterminal_produced: 52, } } 89 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 3, nonterminal_produced: 53, } } 90 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 1, nonterminal_produced: 53, } } 91 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 1, nonterminal_produced: 53, } } 92 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 1, nonterminal_produced: 53, } } 93 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 3, nonterminal_produced: 53, } } 94 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 3, nonterminal_produced: 53, } } 95 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 5, nonterminal_produced: 53, } } 96 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 3, nonterminal_produced: 53, } } 97 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 6, nonterminal_produced: 53, } } 98 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 4, nonterminal_produced: 53, } } 99 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 4, nonterminal_produced: 53, } } 100 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 4, nonterminal_produced: 53, } } 101 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 6, nonterminal_produced: 53, } } 102 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 6, nonterminal_produced: 53, } } 103 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 8, nonterminal_produced: 53, } } 104 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 6, nonterminal_produced: 53, } } 105 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 1, nonterminal_produced: 54, } } 106 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 4, nonterminal_produced: 54, } } 107 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 1, nonterminal_produced: 55, } } 108 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 4, nonterminal_produced: 55, } } 109 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 1, nonterminal_produced: 56, } } 110 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 0, nonterminal_produced: 56, } } 111 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 1, nonterminal_produced: 57, } } 112 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 4, nonterminal_produced: 57, } } 113 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 1, nonterminal_produced: 58, } } 114 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 4, nonterminal_produced: 58, } } 115 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 1, nonterminal_produced: 59, } } 116 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 0, nonterminal_produced: 59, } } 117 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 1, nonterminal_produced: 60, } } 118 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 1, nonterminal_produced: 61, } } 119 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 1, nonterminal_produced: 62, } } 120 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 0, nonterminal_produced: 62, } } 121 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 1, nonterminal_produced: 63, } } 122 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 1, nonterminal_produced: 64, } } 123 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 0, nonterminal_produced: 64, } } 124 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 4, nonterminal_produced: 65, } } 125 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 1, nonterminal_produced: 66, } } 126 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 1, nonterminal_produced: 67, } } 127 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 1, nonterminal_produced: 67, } } 128 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 1, nonterminal_produced: 67, } } 129 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 1, nonterminal_produced: 67, } } 130 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 3, nonterminal_produced: 68, } } 131 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 5, nonterminal_produced: 69, } } 132 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 1, nonterminal_produced: 70, } } 133 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 0, nonterminal_produced: 70, } } 134 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 4, nonterminal_produced: 71, } } 135 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 3, nonterminal_produced: 72, } } 136 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 0, nonterminal_produced: 72, } } 137 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 4, nonterminal_produced: 72, } } 138 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 1, nonterminal_produced: 72, } } 139 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 1, nonterminal_produced: 73, } } 140 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 0, nonterminal_produced: 73, } } 141 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 2, nonterminal_produced: 73, } } 142 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 1, nonterminal_produced: 73, } } 143 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 1, nonterminal_produced: 74, } } 144 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 0, nonterminal_produced: 74, } } 145 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 2, nonterminal_produced: 74, } } 146 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 1, nonterminal_produced: 74, } } 147 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 1, nonterminal_produced: 75, } } 148 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 0, nonterminal_produced: 75, } } 149 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 2, nonterminal_produced: 75, } } 150 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 1, nonterminal_produced: 75, } } 151 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 1, nonterminal_produced: 76, } } 152 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 0, nonterminal_produced: 76, } } 153 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 2, nonterminal_produced: 76, } } 154 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 1, nonterminal_produced: 76, } } 155 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 1, nonterminal_produced: 77, } } 156 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 0, nonterminal_produced: 77, } } 157 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 2, nonterminal_produced: 77, } } 158 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 1, nonterminal_produced: 77, } } 159 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 1, nonterminal_produced: 78, } } 160 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 0, nonterminal_produced: 78, } } 161 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 2, nonterminal_produced: 78, } } 162 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 1, nonterminal_produced: 78, } } 163 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 1, nonterminal_produced: 79, } } 164 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 0, nonterminal_produced: 79, } } 165 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 2, nonterminal_produced: 79, } } 166 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 1, nonterminal_produced: 79, } } 167 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 1, nonterminal_produced: 80, } } 168 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 0, nonterminal_produced: 80, } } 169 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 2, nonterminal_produced: 80, } } 170 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 1, nonterminal_produced: 80, } } 171 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 1, nonterminal_produced: 81, } } 172 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 0, nonterminal_produced: 81, } } 173 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 2, nonterminal_produced: 81, } } 174 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 1, nonterminal_produced: 81, } } 175 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 1, nonterminal_produced: 82, } } 176 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 0, nonterminal_produced: 82, } } 177 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 2, nonterminal_produced: 82, } } 178 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 1, nonterminal_produced: 82, } } 179 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 3, nonterminal_produced: 83, } } 180 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 5, nonterminal_produced: 83, } } 181 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 3, nonterminal_produced: 83, } } 182 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 1, nonterminal_produced: 83, } } 183 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 1, nonterminal_produced: 84, } } 184 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 0, nonterminal_produced: 84, } } 185 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 5, nonterminal_produced: 85, } } 186 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 3, nonterminal_produced: 85, } } 187 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 3, nonterminal_produced: 86, } } 188 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 1, nonterminal_produced: 87, } } 189 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 1, nonterminal_produced: 87, } } 190 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 1, nonterminal_produced: 88, } } 191 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 1, nonterminal_produced: 88, } } 192 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 1, nonterminal_produced: 89, } } 193 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 0, nonterminal_produced: 89, } } 194 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 6, nonterminal_produced: 90, } } 195 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 3, nonterminal_produced: 91, } } 196 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 0, nonterminal_produced: 92, } } 197 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 1, nonterminal_produced: 92, } } 198 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 1, nonterminal_produced: 93, } } 199 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 2, nonterminal_produced: 93, } } 200 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 3, nonterminal_produced: 94, } } 201 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 1, nonterminal_produced: 95, } } 202 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 0, nonterminal_produced: 95, } } 203 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 2, nonterminal_produced: 96, } } 204 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 1, nonterminal_produced: 97, } } 205 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 6, nonterminal_produced: 98, } } 206 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 7, nonterminal_produced: 98, } } 207 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 3, nonterminal_produced: 99, } } 208 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 3, nonterminal_produced: 100, } } 209 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 3, nonterminal_produced: 101, } } 210 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 1, nonterminal_produced: 101, } } 211 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 1, nonterminal_produced: 101, } } 212 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 1, nonterminal_produced: 101, } } 213 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 3, nonterminal_produced: 101, } } 214 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 3, nonterminal_produced: 101, } } 215 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 5, nonterminal_produced: 101, } } 216 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 3, nonterminal_produced: 101, } } 217 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 3, nonterminal_produced: 102, } } 218 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 5, nonterminal_produced: 103, } } 219 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 1, nonterminal_produced: 104, } } 220 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 0, nonterminal_produced: 104, } } 221 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 3, nonterminal_produced: 105, } } 222 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 1, nonterminal_produced: 106, } } 223 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 3, nonterminal_produced: 106, } } 224 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 5, nonterminal_produced: 107, } } 225 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 3, nonterminal_produced: 107, } } 226 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 1, nonterminal_produced: 107, } } 227 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 4, nonterminal_produced: 107, } } 228 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 1, nonterminal_produced: 107, } } 229 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 1, nonterminal_produced: 107, } } 230 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 1, nonterminal_produced: 107, } } 231 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 3, nonterminal_produced: 107, } } 232 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 5, nonterminal_produced: 107, } } 233 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 3, nonterminal_produced: 107, } } 234 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 6, nonterminal_produced: 107, } } 235 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 7, nonterminal_produced: 107, } } 236 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 2, nonterminal_produced: 107, } } 237 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 4, nonterminal_produced: 107, } } 238 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 5, nonterminal_produced: 107, } } 239 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 5, nonterminal_produced: 107, } } 240 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 3, nonterminal_produced: 107, } } 241 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 5, nonterminal_produced: 107, } } 242 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 10, nonterminal_produced: 107, } } 243 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 5, nonterminal_produced: 107, } } 244 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 6, nonterminal_produced: 107, } } 245 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 1, nonterminal_produced: 107, } } 246 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 4, nonterminal_produced: 107, } } 247 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 3, nonterminal_produced: 108, } } 248 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 1, nonterminal_produced: 109, } } 249 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 1, nonterminal_produced: 110, } } 250 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 3, nonterminal_produced: 110, } } 251 => __state_machine::SimulatedReduce::Accept, _ => panic!("invalid reduction index {}", __reduce_index) } } pub struct AnnotatedModuleParser { _priv: (), } impl AnnotatedModuleParser { pub fn new() -> AnnotatedModuleParser { AnnotatedModuleParser { _priv: (), } } #[allow(dead_code)] pub fn parse< 'input, __TOKEN: __ToTriple<'input, >, __TOKENS: IntoIterator, >( &self, text: &'input str, __tokens0: __TOKENS, ) -> Result, __lalrpop_util::ParseError, ()>> { let __tokens = __tokens0.into_iter(); let mut __tokens = __tokens.map(|t| __ToTriple::to_triple(t)); let __r = __state_machine::Parser::drive( __StateMachine { text, __phantom: ::std::marker::PhantomData::<(&())>, }, __tokens, ); __r } } pub(crate) fn __reduce< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> Option,__lalrpop_util::ParseError, ()>>> { let (__pop_states, __nonterminal) = match __action { 0 => { __reduce0(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 1 => { __reduce1(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 2 => { __reduce2(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 3 => { __reduce3(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 4 => { __reduce4(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 5 => { __reduce5(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 6 => { __reduce6(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 7 => { __reduce7(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 8 => { __reduce8(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 9 => { __reduce9(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 10 => { __reduce10(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 11 => { __reduce11(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 12 => { __reduce12(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 13 => { __reduce13(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 14 => { __reduce14(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 15 => { __reduce15(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 16 => { __reduce16(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 17 => { __reduce17(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 18 => { __reduce18(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 19 => { __reduce19(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 20 => { __reduce20(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 21 => { __reduce21(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 22 => { __reduce22(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 23 => { __reduce23(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 24 => { __reduce24(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 25 => { __reduce25(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 26 => { __reduce26(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 27 => { __reduce27(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 28 => { __reduce28(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 29 => { __reduce29(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 30 => { __reduce30(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 31 => { __reduce31(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 32 => { __reduce32(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 33 => { __reduce33(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 34 => { __reduce34(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 35 => { __reduce35(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 36 => { __reduce36(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 37 => { __reduce37(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 38 => { __reduce38(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 39 => { __reduce39(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 40 => { __reduce40(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 41 => { __reduce41(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 42 => { __reduce42(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 43 => { __reduce43(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 44 => { __reduce44(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 45 => { __reduce45(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 46 => { __reduce46(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 47 => { __reduce47(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 48 => { __reduce48(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 49 => { __reduce49(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 50 => { __reduce50(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 51 => { __reduce51(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 52 => { __reduce52(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 53 => { __reduce53(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 54 => { __reduce54(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 55 => { __reduce55(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 56 => { __reduce56(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 57 => { __reduce57(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 58 => { __reduce58(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 59 => { __reduce59(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 60 => { __reduce60(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 61 => { __reduce61(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 62 => { __reduce62(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 63 => { __reduce63(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 64 => { __reduce64(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 65 => { __reduce65(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 66 => { __reduce66(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 67 => { __reduce67(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 68 => { __reduce68(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 69 => { __reduce69(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 70 => { __reduce70(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 71 => { __reduce71(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 72 => { __reduce72(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 73 => { __reduce73(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 74 => { __reduce74(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 75 => { __reduce75(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 76 => { __reduce76(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 77 => { __reduce77(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 78 => { __reduce78(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 79 => { __reduce79(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 80 => { __reduce80(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 81 => { __reduce81(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 82 => { __reduce82(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 83 => { __reduce83(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 84 => { __reduce84(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 85 => { __reduce85(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 86 => { __reduce86(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 87 => { __reduce87(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 88 => { __reduce88(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 89 => { __reduce89(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 90 => { __reduce90(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 91 => { __reduce91(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 92 => { __reduce92(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 93 => { __reduce93(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 94 => { __reduce94(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 95 => { __reduce95(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 96 => { __reduce96(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 97 => { __reduce97(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 98 => { __reduce98(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 99 => { __reduce99(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 100 => { __reduce100(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 101 => { __reduce101(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 102 => { __reduce102(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 103 => { __reduce103(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 104 => { __reduce104(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 105 => { __reduce105(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 106 => { __reduce106(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 107 => { __reduce107(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 108 => { __reduce108(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 109 => { __reduce109(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 110 => { __reduce110(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 111 => { __reduce111(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 112 => { __reduce112(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 113 => { __reduce113(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 114 => { __reduce114(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 115 => { __reduce115(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 116 => { __reduce116(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 117 => { __reduce117(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 118 => { __reduce118(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 119 => { __reduce119(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 120 => { __reduce120(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 121 => { __reduce121(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 122 => { __reduce122(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 123 => { __reduce123(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 124 => { __reduce124(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 125 => { __reduce125(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 126 => { __reduce126(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 127 => { __reduce127(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 128 => { __reduce128(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 129 => { __reduce129(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 130 => { __reduce130(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 131 => { __reduce131(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 132 => { __reduce132(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 133 => { __reduce133(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 134 => { __reduce134(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 135 => { __reduce135(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 136 => { __reduce136(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 137 => { __reduce137(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 138 => { __reduce138(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 139 => { __reduce139(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 140 => { __reduce140(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 141 => { __reduce141(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 142 => { __reduce142(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 143 => { __reduce143(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 144 => { __reduce144(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 145 => { __reduce145(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 146 => { __reduce146(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 147 => { __reduce147(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 148 => { __reduce148(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 149 => { __reduce149(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 150 => { __reduce150(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 151 => { __reduce151(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 152 => { __reduce152(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 153 => { __reduce153(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 154 => { __reduce154(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 155 => { __reduce155(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 156 => { __reduce156(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 157 => { __reduce157(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 158 => { __reduce158(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 159 => { __reduce159(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 160 => { __reduce160(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 161 => { __reduce161(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 162 => { __reduce162(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 163 => { __reduce163(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 164 => { __reduce164(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 165 => { __reduce165(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 166 => { __reduce166(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 167 => { __reduce167(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 168 => { __reduce168(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 169 => { __reduce169(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 170 => { __reduce170(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 171 => { __reduce171(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 172 => { __reduce172(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 173 => { __reduce173(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 174 => { __reduce174(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 175 => { __reduce175(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 176 => { __reduce176(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 177 => { __reduce177(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 178 => { __reduce178(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 179 => { __reduce179(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 180 => { __reduce180(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 181 => { __reduce181(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 182 => { __reduce182(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 183 => { __reduce183(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 184 => { __reduce184(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 185 => { __reduce185(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 186 => { __reduce186(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 187 => { __reduce187(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 188 => { __reduce188(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 189 => { __reduce189(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 190 => { __reduce190(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 191 => { __reduce191(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 192 => { __reduce192(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 193 => { __reduce193(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 194 => { __reduce194(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 195 => { __reduce195(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 196 => { __reduce196(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 197 => { __reduce197(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 198 => { __reduce198(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 199 => { __reduce199(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 200 => { __reduce200(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 201 => { __reduce201(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 202 => { __reduce202(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 203 => { __reduce203(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 204 => { __reduce204(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 205 => { __reduce205(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 206 => { __reduce206(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 207 => { __reduce207(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 208 => { __reduce208(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 209 => { __reduce209(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 210 => { __reduce210(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 211 => { __reduce211(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 212 => { __reduce212(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 213 => { __reduce213(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 214 => { __reduce214(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 215 => { __reduce215(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 216 => { __reduce216(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 217 => { __reduce217(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 218 => { __reduce218(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 219 => { __reduce219(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 220 => { __reduce220(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 221 => { __reduce221(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 222 => { __reduce222(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 223 => { __reduce223(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 224 => { __reduce224(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 225 => { __reduce225(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 226 => { __reduce226(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 227 => { __reduce227(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 228 => { __reduce228(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 229 => { __reduce229(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 230 => { __reduce230(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 231 => { __reduce231(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 232 => { __reduce232(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 233 => { __reduce233(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 234 => { __reduce234(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 235 => { __reduce235(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 236 => { __reduce236(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 237 => { __reduce237(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 238 => { __reduce238(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 239 => { __reduce239(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 240 => { __reduce240(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 241 => { __reduce241(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 242 => { __reduce242(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 243 => { __reduce243(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 244 => { __reduce244(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 245 => { __reduce245(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 246 => { __reduce246(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 247 => { __reduce247(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 248 => { __reduce248(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 249 => { __reduce249(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 250 => { __reduce250(text, __action, __lookahead_start, __states, __symbols, ::std::marker::PhantomData::<(&())>) } 251 => { // __AnnotatedModule = AnnotatedModule => ActionFn(0); let __sym0 = __pop_Variant39(__symbols); let __start = __sym0.0.clone(); let __end = __sym0.2.clone(); let __nt = super::__action0::<>(text, __sym0); return Some(Ok(__nt)); } _ => panic!("invalid action code {}", __action) }; let __states_len = __states.len(); __states.truncate(__states_len - __pop_states); let __state = *__states.last().unwrap() as usize; let __next_state = __GOTO[__state * 112 + __nonterminal] - 1; __states.push(__next_state); None } fn __pop_Variant44< 'input, >( __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)> ) -> (usize, (), usize) { match __symbols.pop().unwrap() { (__l, __Symbol::Variant44(__v), __r) => (__l, __v, __r), _ => panic!("symbol type mismatch") } } fn __pop_Variant32< 'input, >( __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)> ) -> (usize, (Annotated, Vec>), usize) { match __symbols.pop().unwrap() { (__l, __Symbol::Variant32(__v), __r) => (__l, __v, __r), _ => panic!("symbol type mismatch") } } fn __pop_Variant70< 'input, >( __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)> ) -> (usize, (Annotated, Annotated), usize) { match __symbols.pop().unwrap() { (__l, __Symbol::Variant70(__v), __r) => (__l, __v, __r), _ => panic!("symbol type mismatch") } } fn __pop_Variant10< 'input, >( __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)> ) -> (usize, (Atom, Constant), usize) { match __symbols.pop().unwrap() { (__l, __Symbol::Variant10(__v), __r) => (__l, __v, __r), _ => panic!("symbol type mismatch") } } fn __pop_Variant27< 'input, >( __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)> ) -> (usize, (Expression, MapExactAssoc, Expression), usize) { match __symbols.pop().unwrap() { (__l, __Symbol::Variant27(__v), __r) => (__l, __v, __r), _ => panic!("symbol type mismatch") } } fn __pop_Variant22< 'input, >( __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)> ) -> (usize, (Expression, Vec), usize) { match __symbols.pop().unwrap() { (__l, __Symbol::Variant22(__v), __r) => (__l, __v, __r), _ => panic!("symbol type mismatch") } } fn __pop_Variant30< 'input, >( __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)> ) -> (usize, (FunctionName, Function), usize) { match __symbols.pop().unwrap() { (__l, __Symbol::Variant30(__v), __r) => (__l, __v, __r), _ => panic!("symbol type mismatch") } } fn __pop_Variant8< 'input, >( __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)> ) -> (usize, (Tok<'input>, Constant), usize) { match __symbols.pop().unwrap() { (__l, __Symbol::Variant8(__v), __r) => (__l, __v, __r), _ => panic!("symbol type mismatch") } } fn __pop_Variant3< 'input, >( __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)> ) -> (usize, (bool, &'input str), usize) { match __symbols.pop().unwrap() { (__l, __Symbol::Variant3(__v), __r) => (__l, __v, __r), _ => panic!("symbol type mismatch") } } fn __pop_Variant19< 'input, >( __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)> ) -> (usize, Annotated<(Annotated, Annotated)>, usize) { match __symbols.pop().unwrap() { (__l, __Symbol::Variant19(__v), __r) => (__l, __v, __r), _ => panic!("symbol type mismatch") } } fn __pop_Variant12< 'input, >( __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)> ) -> (usize, Annotated<(Expression, MapExactAssoc, Expression)>, usize) { match __symbols.pop().unwrap() { (__l, __Symbol::Variant12(__v), __r) => (__l, __v, __r), _ => panic!("symbol type mismatch") } } fn __pop_Variant16< 'input, >( __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)> ) -> (usize, Annotated, usize) { match __symbols.pop().unwrap() { (__l, __Symbol::Variant16(__v), __r) => (__l, __v, __r), _ => panic!("symbol type mismatch") } } fn __pop_Variant35< 'input, >( __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)> ) -> (usize, Annotated, usize) { match __symbols.pop().unwrap() { (__l, __Symbol::Variant35(__v), __r) => (__l, __v, __r), _ => panic!("symbol type mismatch") } } fn __pop_Variant37< 'input, >( __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)> ) -> (usize, Annotated, usize) { match __symbols.pop().unwrap() { (__l, __Symbol::Variant37(__v), __r) => (__l, __v, __r), _ => panic!("symbol type mismatch") } } fn __pop_Variant38< 'input, >( __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)> ) -> (usize, Annotated, usize) { match __symbols.pop().unwrap() { (__l, __Symbol::Variant38(__v), __r) => (__l, __v, __r), _ => panic!("symbol type mismatch") } } fn __pop_Variant39< 'input, >( __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)> ) -> (usize, Annotated, usize) { match __symbols.pop().unwrap() { (__l, __Symbol::Variant39(__v), __r) => (__l, __v, __r), _ => panic!("symbol type mismatch") } } fn __pop_Variant4< 'input, >( __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)> ) -> (usize, Annotated, usize) { match __symbols.pop().unwrap() { (__l, __Symbol::Variant4(__v), __r) => (__l, __v, __r), _ => panic!("symbol type mismatch") } } fn __pop_Variant14< 'input, >( __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)> ) -> (usize, Annotated, usize) { match __symbols.pop().unwrap() { (__l, __Symbol::Variant14(__v), __r) => (__l, __v, __r), _ => panic!("symbol type mismatch") } } fn __pop_Variant41< 'input, >( __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)> ) -> (usize, Annotated>>, usize) { match __symbols.pop().unwrap() { (__l, __Symbol::Variant41(__v), __r) => (__l, __v, __r), _ => panic!("symbol type mismatch") } } fn __pop_Variant45< 'input, >( __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)> ) -> (usize, Atom, usize) { match __symbols.pop().unwrap() { (__l, __Symbol::Variant45(__v), __r) => (__l, __v, __r), _ => panic!("symbol type mismatch") } } fn __pop_Variant46< 'input, >( __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)> ) -> (usize, AtomicTerm, usize) { match __symbols.pop().unwrap() { (__l, __Symbol::Variant46(__v), __r) => (__l, __v, __r), _ => panic!("symbol type mismatch") } } fn __pop_Variant66< 'input, >( __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)> ) -> (usize, BigInt, usize) { match __symbols.pop().unwrap() { (__l, __Symbol::Variant66(__v), __r) => (__l, __v, __r), _ => panic!("symbol type mismatch") } } fn __pop_Variant49< 'input, >( __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)> ) -> (usize, CaseClause, usize) { match __symbols.pop().unwrap() { (__l, __Symbol::Variant49(__v), __r) => (__l, __v, __r), _ => panic!("symbol type mismatch") } } fn __pop_Variant24< 'input, >( __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)> ) -> (usize, Constant, usize) { match __symbols.pop().unwrap() { (__l, __Symbol::Variant24(__v), __r) => (__l, __v, __r), _ => panic!("symbol type mismatch") } } fn __pop_Variant6< 'input, >( __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)> ) -> (usize, Expression, usize) { match __symbols.pop().unwrap() { (__l, __Symbol::Variant6(__v), __r) => (__l, __v, __r), _ => panic!("symbol type mismatch") } } fn __pop_Variant62< 'input, >( __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)> ) -> (usize, Function, usize) { match __symbols.pop().unwrap() { (__l, __Symbol::Variant62(__v), __r) => (__l, __v, __r), _ => panic!("symbol type mismatch") } } fn __pop_Variant63< 'input, >( __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)> ) -> (usize, FunctionDefinition, usize) { match __symbols.pop().unwrap() { (__l, __Symbol::Variant63(__v), __r) => (__l, __v, __r), _ => panic!("symbol type mismatch") } } fn __pop_Variant28< 'input, >( __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)> ) -> (usize, FunctionName, usize) { match __symbols.pop().unwrap() { (__l, __Symbol::Variant28(__v), __r) => (__l, __v, __r), _ => panic!("symbol type mismatch") } } fn __pop_Variant61< 'input, >( __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)> ) -> (usize, MapExactAssoc, usize) { match __symbols.pop().unwrap() { (__l, __Symbol::Variant61(__v), __r) => (__l, __v, __r), _ => panic!("symbol type mismatch") } } fn __pop_Variant67< 'input, >( __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)> ) -> (usize, Module, usize) { match __symbols.pop().unwrap() { (__l, __Symbol::Variant67(__v), __r) => (__l, __v, __r), _ => panic!("symbol type mismatch") } } fn __pop_Variant68< 'input, >( __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)> ) -> (usize, Pattern, usize) { match __symbols.pop().unwrap() { (__l, __Symbol::Variant68(__v), __r) => (__l, __v, __r), _ => panic!("symbol type mismatch") } } fn __pop_Variant71< 'input, >( __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)> ) -> (usize, SingleExpression, usize) { match __symbols.pop().unwrap() { (__l, __Symbol::Variant71(__v), __r) => (__l, __v, __r), _ => panic!("symbol type mismatch") } } fn __pop_Variant0< 'input, >( __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)> ) -> (usize, Tok<'input>, usize) { match __symbols.pop().unwrap() { (__l, __Symbol::Variant0(__v), __r) => (__l, __v, __r), _ => panic!("symbol type mismatch") } } fn __pop_Variant59< 'input, >( __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)> ) -> (usize, Vec<(Annotated, Vec>)>, usize) { match __symbols.pop().unwrap() { (__l, __Symbol::Variant59(__v), __r) => (__l, __v, __r), _ => panic!("symbol type mismatch") } } fn __pop_Variant50< 'input, >( __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)> ) -> (usize, Vec<(Atom, Constant)>, usize) { match __symbols.pop().unwrap() { (__l, __Symbol::Variant50(__v), __r) => (__l, __v, __r), _ => panic!("symbol type mismatch") } } fn __pop_Variant47< 'input, >( __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)> ) -> (usize, Vec<(Expression, Vec)>, usize) { match __symbols.pop().unwrap() { (__l, __Symbol::Variant47(__v), __r) => (__l, __v, __r), _ => panic!("symbol type mismatch") } } fn __pop_Variant55< 'input, >( __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)> ) -> (usize, Vec, Annotated)>>, usize) { match __symbols.pop().unwrap() { (__l, __Symbol::Variant55(__v), __r) => (__l, __v, __r), _ => panic!("symbol type mismatch") } } fn __pop_Variant51< 'input, >( __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)> ) -> (usize, Vec>, usize) { match __symbols.pop().unwrap() { (__l, __Symbol::Variant51(__v), __r) => (__l, __v, __r), _ => panic!("symbol type mismatch") } } fn __pop_Variant53< 'input, >( __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)> ) -> (usize, Vec>, usize) { match __symbols.pop().unwrap() { (__l, __Symbol::Variant53(__v), __r) => (__l, __v, __r), _ => panic!("symbol type mismatch") } } fn __pop_Variant54< 'input, >( __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)> ) -> (usize, Vec>, usize) { match __symbols.pop().unwrap() { (__l, __Symbol::Variant54(__v), __r) => (__l, __v, __r), _ => panic!("symbol type mismatch") } } fn __pop_Variant52< 'input, >( __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)> ) -> (usize, Vec>, usize) { match __symbols.pop().unwrap() { (__l, __Symbol::Variant52(__v), __r) => (__l, __v, __r), _ => panic!("symbol type mismatch") } } fn __pop_Variant56< 'input, >( __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)> ) -> (usize, Vec, usize) { match __symbols.pop().unwrap() { (__l, __Symbol::Variant56(__v), __r) => (__l, __v, __r), _ => panic!("symbol type mismatch") } } fn __pop_Variant57< 'input, >( __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)> ) -> (usize, Vec, usize) { match __symbols.pop().unwrap() { (__l, __Symbol::Variant57(__v), __r) => (__l, __v, __r), _ => panic!("symbol type mismatch") } } fn __pop_Variant58< 'input, >( __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)> ) -> (usize, Vec, usize) { match __symbols.pop().unwrap() { (__l, __Symbol::Variant58(__v), __r) => (__l, __v, __r), _ => panic!("symbol type mismatch") } } fn __pop_Variant2< 'input, >( __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)> ) -> (usize, char, usize) { match __symbols.pop().unwrap() { (__l, __Symbol::Variant2(__v), __r) => (__l, __v, __r), _ => panic!("symbol type mismatch") } } fn __pop_Variant69< 'input, >( __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)> ) -> (usize, ::std::option::Option<(Annotated, Vec>)>, usize) { match __symbols.pop().unwrap() { (__l, __Symbol::Variant69(__v), __r) => (__l, __v, __r), _ => panic!("symbol type mismatch") } } fn __pop_Variant21< 'input, >( __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)> ) -> (usize, ::std::option::Option<(Atom, Constant)>, usize) { match __symbols.pop().unwrap() { (__l, __Symbol::Variant21(__v), __r) => (__l, __v, __r), _ => panic!("symbol type mismatch") } } fn __pop_Variant48< 'input, >( __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)> ) -> (usize, ::std::option::Option<(Expression, Vec)>, usize) { match __symbols.pop().unwrap() { (__l, __Symbol::Variant48(__v), __r) => (__l, __v, __r), _ => panic!("symbol type mismatch") } } fn __pop_Variant9< 'input, >( __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)> ) -> (usize, ::std::option::Option<(Tok<'input>, Constant)>, usize) { match __symbols.pop().unwrap() { (__l, __Symbol::Variant9(__v), __r) => (__l, __v, __r), _ => panic!("symbol type mismatch") } } fn __pop_Variant43< 'input, >( __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)> ) -> (usize, ::std::option::Option, Annotated)>>, usize) { match __symbols.pop().unwrap() { (__l, __Symbol::Variant43(__v), __r) => (__l, __v, __r), _ => panic!("symbol type mismatch") } } fn __pop_Variant34< 'input, >( __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)> ) -> (usize, ::std::option::Option>, usize) { match __symbols.pop().unwrap() { (__l, __Symbol::Variant34(__v), __r) => (__l, __v, __r), _ => panic!("symbol type mismatch") } } fn __pop_Variant42< 'input, >( __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)> ) -> (usize, ::std::option::Option>, usize) { match __symbols.pop().unwrap() { (__l, __Symbol::Variant42(__v), __r) => (__l, __v, __r), _ => panic!("symbol type mismatch") } } fn __pop_Variant5< 'input, >( __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)> ) -> (usize, ::std::option::Option>, usize) { match __symbols.pop().unwrap() { (__l, __Symbol::Variant5(__v), __r) => (__l, __v, __r), _ => panic!("symbol type mismatch") } } fn __pop_Variant40< 'input, >( __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)> ) -> (usize, ::std::option::Option>, usize) { match __symbols.pop().unwrap() { (__l, __Symbol::Variant40(__v), __r) => (__l, __v, __r), _ => panic!("symbol type mismatch") } } fn __pop_Variant60< 'input, >( __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)> ) -> (usize, ::std::option::Option, usize) { match __symbols.pop().unwrap() { (__l, __Symbol::Variant60(__v), __r) => (__l, __v, __r), _ => panic!("symbol type mismatch") } } fn __pop_Variant7< 'input, >( __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)> ) -> (usize, ::std::option::Option, usize) { match __symbols.pop().unwrap() { (__l, __Symbol::Variant7(__v), __r) => (__l, __v, __r), _ => panic!("symbol type mismatch") } } fn __pop_Variant65< 'input, >( __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)> ) -> (usize, ::std::option::Option, usize) { match __symbols.pop().unwrap() { (__l, __Symbol::Variant65(__v), __r) => (__l, __v, __r), _ => panic!("symbol type mismatch") } } fn __pop_Variant33< 'input, >( __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)> ) -> (usize, ::std::vec::Vec<(Annotated, Vec>)>, usize) { match __symbols.pop().unwrap() { (__l, __Symbol::Variant33(__v), __r) => (__l, __v, __r), _ => panic!("symbol type mismatch") } } fn __pop_Variant11< 'input, >( __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)> ) -> (usize, ::std::vec::Vec<(Atom, Constant)>, usize) { match __symbols.pop().unwrap() { (__l, __Symbol::Variant11(__v), __r) => (__l, __v, __r), _ => panic!("symbol type mismatch") } } fn __pop_Variant23< 'input, >( __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)> ) -> (usize, ::std::vec::Vec<(Expression, Vec)>, usize) { match __symbols.pop().unwrap() { (__l, __Symbol::Variant23(__v), __r) => (__l, __v, __r), _ => panic!("symbol type mismatch") } } fn __pop_Variant31< 'input, >( __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)> ) -> (usize, ::std::vec::Vec<(FunctionName, Function)>, usize) { match __symbols.pop().unwrap() { (__l, __Symbol::Variant31(__v), __r) => (__l, __v, __r), _ => panic!("symbol type mismatch") } } fn __pop_Variant20< 'input, >( __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)> ) -> (usize, ::std::vec::Vec, Annotated)>>, usize) { match __symbols.pop().unwrap() { (__l, __Symbol::Variant20(__v), __r) => (__l, __v, __r), _ => panic!("symbol type mismatch") } } fn __pop_Variant13< 'input, >( __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)> ) -> (usize, ::std::vec::Vec>, usize) { match __symbols.pop().unwrap() { (__l, __Symbol::Variant13(__v), __r) => (__l, __v, __r), _ => panic!("symbol type mismatch") } } fn __pop_Variant17< 'input, >( __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)> ) -> (usize, ::std::vec::Vec>, usize) { match __symbols.pop().unwrap() { (__l, __Symbol::Variant17(__v), __r) => (__l, __v, __r), _ => panic!("symbol type mismatch") } } fn __pop_Variant36< 'input, >( __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)> ) -> (usize, ::std::vec::Vec>, usize) { match __symbols.pop().unwrap() { (__l, __Symbol::Variant36(__v), __r) => (__l, __v, __r), _ => panic!("symbol type mismatch") } } fn __pop_Variant18< 'input, >( __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)> ) -> (usize, ::std::vec::Vec>, usize) { match __symbols.pop().unwrap() { (__l, __Symbol::Variant18(__v), __r) => (__l, __v, __r), _ => panic!("symbol type mismatch") } } fn __pop_Variant15< 'input, >( __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)> ) -> (usize, ::std::vec::Vec>, usize) { match __symbols.pop().unwrap() { (__l, __Symbol::Variant15(__v), __r) => (__l, __v, __r), _ => panic!("symbol type mismatch") } } fn __pop_Variant25< 'input, >( __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)> ) -> (usize, ::std::vec::Vec, usize) { match __symbols.pop().unwrap() { (__l, __Symbol::Variant25(__v), __r) => (__l, __v, __r), _ => panic!("symbol type mismatch") } } fn __pop_Variant26< 'input, >( __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)> ) -> (usize, ::std::vec::Vec, usize) { match __symbols.pop().unwrap() { (__l, __Symbol::Variant26(__v), __r) => (__l, __v, __r), _ => panic!("symbol type mismatch") } } fn __pop_Variant64< 'input, >( __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)> ) -> (usize, ::std::vec::Vec, usize) { match __symbols.pop().unwrap() { (__l, __Symbol::Variant64(__v), __r) => (__l, __v, __r), _ => panic!("symbol type mismatch") } } fn __pop_Variant29< 'input, >( __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)> ) -> (usize, ::std::vec::Vec, usize) { match __symbols.pop().unwrap() { (__l, __Symbol::Variant29(__v), __r) => (__l, __v, __r), _ => panic!("symbol type mismatch") } } fn __pop_Variant1< 'input, >( __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)> ) -> (usize, &'input str, usize) { match __symbols.pop().unwrap() { (__l, __Symbol::Variant1(__v), __r) => (__l, __v, __r), _ => panic!("symbol type mismatch") } } pub(crate) fn __reduce0< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // ("|" ) = "|", AnnotatedPattern => ActionFn(73); let __sym1 = __pop_Variant4(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0.clone(); let __end = __sym1.2.clone(); let __nt = super::__action73::<>(text, __sym0, __sym1); __symbols.push((__start, __Symbol::Variant4(__nt), __end)); (2, 0) } pub(crate) fn __reduce1< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // ("|" )? = "|", AnnotatedPattern => ActionFn(197); let __sym1 = __pop_Variant4(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0.clone(); let __end = __sym1.2.clone(); let __nt = super::__action197::<>(text, __sym0, __sym1); __symbols.push((__start, __Symbol::Variant5(__nt), __end)); (2, 1) } pub(crate) fn __reduce2< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // ("|" )? = => ActionFn(72); let __start = __symbols.last().map(|s| s.2.clone()).unwrap_or_default(); let __end = __lookahead_start.cloned().unwrap_or_else(|| __start.clone()); let __nt = super::__action72::<>(text, &__start, &__end); __symbols.push((__start, __Symbol::Variant5(__nt), __end)); (0, 1) } pub(crate) fn __reduce3< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // ("|" ) = "|", Expression => ActionFn(95); let __sym1 = __pop_Variant6(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0.clone(); let __end = __sym1.2.clone(); let __nt = super::__action95::<>(text, __sym0, __sym1); __symbols.push((__start, __Symbol::Variant6(__nt), __end)); (2, 2) } pub(crate) fn __reduce4< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // ("|" )? = "|", Expression => ActionFn(200); let __sym1 = __pop_Variant6(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0.clone(); let __end = __sym1.2.clone(); let __nt = super::__action200::<>(text, __sym0, __sym1); __symbols.push((__start, __Symbol::Variant7(__nt), __end)); (2, 3) } pub(crate) fn __reduce5< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // ("|" )? = => ActionFn(94); let __start = __symbols.last().map(|s| s.2.clone()).unwrap_or_default(); let __end = __lookahead_start.cloned().unwrap_or_else(|| __start.clone()); let __nt = super::__action94::<>(text, &__start, &__end); __symbols.push((__start, __Symbol::Variant7(__nt), __end)); (0, 3) } pub(crate) fn __reduce6< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // ("|" Constant) = "|", Constant => ActionFn(67); let __sym1 = __pop_Variant24(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0.clone(); let __end = __sym1.2.clone(); let __nt = super::__action67::<>(text, __sym0, __sym1); __symbols.push((__start, __Symbol::Variant8(__nt), __end)); (2, 4) } pub(crate) fn __reduce7< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // ("|" Constant)? = "|", Constant => ActionFn(205); let __sym1 = __pop_Variant24(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0.clone(); let __end = __sym1.2.clone(); let __nt = super::__action205::<>(text, __sym0, __sym1); __symbols.push((__start, __Symbol::Variant9(__nt), __end)); (2, 5) } pub(crate) fn __reduce8< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // ("|" Constant)? = => ActionFn(66); let __start = __symbols.last().map(|s| s.2.clone()).unwrap_or_default(); let __end = __lookahead_start.cloned().unwrap_or_else(|| __start.clone()); let __nt = super::__action66::<>(text, &__start, &__end); __symbols.push((__start, __Symbol::Variant9(__nt), __end)); (0, 5) } pub(crate) fn __reduce9< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // (<( "=" )> ",") = Atom, "=", Constant, "," => ActionFn(210); let __sym3 = __pop_Variant0(__symbols); let __sym2 = __pop_Variant24(__symbols); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant45(__symbols); let __start = __sym0.0.clone(); let __end = __sym3.2.clone(); let __nt = super::__action210::<>(text, __sym0, __sym1, __sym2, __sym3); __symbols.push((__start, __Symbol::Variant10(__nt), __end)); (4, 6) } pub(crate) fn __reduce10< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // (<( "=" )> ",")* = => ActionFn(125); let __start = __symbols.last().map(|s| s.2.clone()).unwrap_or_default(); let __end = __lookahead_start.cloned().unwrap_or_else(|| __start.clone()); let __nt = super::__action125::<>(text, &__start, &__end); __symbols.push((__start, __Symbol::Variant11(__nt), __end)); (0, 7) } pub(crate) fn __reduce11< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // (<( "=" )> ",")* = (<( "=" )> ",")+ => ActionFn(126); let __sym0 = __pop_Variant11(__symbols); let __start = __sym0.0.clone(); let __end = __sym0.2.clone(); let __nt = super::__action126::<>(text, __sym0); __symbols.push((__start, __Symbol::Variant11(__nt), __end)); (1, 7) } pub(crate) fn __reduce12< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // (<( "=" )> ",")+ = Atom, "=", Constant, "," => ActionFn(212); let __sym3 = __pop_Variant0(__symbols); let __sym2 = __pop_Variant24(__symbols); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant45(__symbols); let __start = __sym0.0.clone(); let __end = __sym3.2.clone(); let __nt = super::__action212::<>(text, __sym0, __sym1, __sym2, __sym3); __symbols.push((__start, __Symbol::Variant11(__nt), __end)); (4, 8) } pub(crate) fn __reduce13< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // (<( "=" )> ",")+ = (<( "=" )> ",")+, Atom, "=", Constant, "," => ActionFn(213); let __sym4 = __pop_Variant0(__symbols); let __sym3 = __pop_Variant24(__symbols); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant45(__symbols); let __sym0 = __pop_Variant11(__symbols); let __start = __sym0.0.clone(); let __end = __sym4.2.clone(); let __nt = super::__action213::<>(text, __sym0, __sym1, __sym2, __sym3, __sym4); __symbols.push((__start, __Symbol::Variant11(__nt), __end)); (5, 8) } pub(crate) fn __reduce14< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // ( )>> ",") = Annotated<( )>, "," => ActionFn(147); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant12(__symbols); let __start = __sym0.0.clone(); let __end = __sym1.2.clone(); let __nt = super::__action147::<>(text, __sym0, __sym1); __symbols.push((__start, __Symbol::Variant12(__nt), __end)); (2, 9) } pub(crate) fn __reduce15< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // ( )>> ",")* = => ActionFn(145); let __start = __symbols.last().map(|s| s.2.clone()).unwrap_or_default(); let __end = __lookahead_start.cloned().unwrap_or_else(|| __start.clone()); let __nt = super::__action145::<>(text, &__start, &__end); __symbols.push((__start, __Symbol::Variant13(__nt), __end)); (0, 10) } pub(crate) fn __reduce16< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // ( )>> ",")* = ( )>> ",")+ => ActionFn(146); let __sym0 = __pop_Variant13(__symbols); let __start = __sym0.0.clone(); let __end = __sym0.2.clone(); let __nt = super::__action146::<>(text, __sym0); __symbols.push((__start, __Symbol::Variant13(__nt), __end)); (1, 10) } pub(crate) fn __reduce17< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // ( )>> ",")+ = Annotated<( )>, "," => ActionFn(216); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant12(__symbols); let __start = __sym0.0.clone(); let __end = __sym1.2.clone(); let __nt = super::__action216::<>(text, __sym0, __sym1); __symbols.push((__start, __Symbol::Variant13(__nt), __end)); (2, 11) } pub(crate) fn __reduce18< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // ( )>> ",")+ = ( )>> ",")+, Annotated<( )>, "," => ActionFn(217); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant12(__symbols); let __sym0 = __pop_Variant13(__symbols); let __start = __sym0.0.clone(); let __end = __sym2.2.clone(); let __nt = super::__action217::<>(text, __sym0, __sym1, __sym2); __symbols.push((__start, __Symbol::Variant13(__nt), __end)); (3, 11) } pub(crate) fn __reduce19< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // (> ",") = Annotated, "," => ActionFn(137); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant14(__symbols); let __start = __sym0.0.clone(); let __end = __sym1.2.clone(); let __nt = super::__action137::<>(text, __sym0, __sym1); __symbols.push((__start, __Symbol::Variant14(__nt), __end)); (2, 12) } pub(crate) fn __reduce20< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // (> ",")* = => ActionFn(135); let __start = __symbols.last().map(|s| s.2.clone()).unwrap_or_default(); let __end = __lookahead_start.cloned().unwrap_or_else(|| __start.clone()); let __nt = super::__action135::<>(text, &__start, &__end); __symbols.push((__start, __Symbol::Variant15(__nt), __end)); (0, 13) } pub(crate) fn __reduce21< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // (> ",")* = (> ",")+ => ActionFn(136); let __sym0 = __pop_Variant15(__symbols); let __start = __sym0.0.clone(); let __end = __sym0.2.clone(); let __nt = super::__action136::<>(text, __sym0); __symbols.push((__start, __Symbol::Variant15(__nt), __end)); (1, 13) } pub(crate) fn __reduce22< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // (> ",")+ = Annotated, "," => ActionFn(220); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant14(__symbols); let __start = __sym0.0.clone(); let __end = __sym1.2.clone(); let __nt = super::__action220::<>(text, __sym0, __sym1); __symbols.push((__start, __Symbol::Variant15(__nt), __end)); (2, 14) } pub(crate) fn __reduce23< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // (> ",")+ = (> ",")+, Annotated, "," => ActionFn(221); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant14(__symbols); let __sym0 = __pop_Variant15(__symbols); let __start = __sym0.0.clone(); let __end = __sym2.2.clone(); let __nt = super::__action221::<>(text, __sym0, __sym1, __sym2); __symbols.push((__start, __Symbol::Variant15(__nt), __end)); (3, 14) } pub(crate) fn __reduce24< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // (> ",") = Annotated, "," => ActionFn(132); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant16(__symbols); let __start = __sym0.0.clone(); let __end = __sym1.2.clone(); let __nt = super::__action132::<>(text, __sym0, __sym1); __symbols.push((__start, __Symbol::Variant16(__nt), __end)); (2, 15) } pub(crate) fn __reduce25< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // (> ",")* = => ActionFn(130); let __start = __symbols.last().map(|s| s.2.clone()).unwrap_or_default(); let __end = __lookahead_start.cloned().unwrap_or_else(|| __start.clone()); let __nt = super::__action130::<>(text, &__start, &__end); __symbols.push((__start, __Symbol::Variant17(__nt), __end)); (0, 16) } pub(crate) fn __reduce26< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // (> ",")* = (> ",")+ => ActionFn(131); let __sym0 = __pop_Variant17(__symbols); let __start = __sym0.0.clone(); let __end = __sym0.2.clone(); let __nt = super::__action131::<>(text, __sym0); __symbols.push((__start, __Symbol::Variant17(__nt), __end)); (1, 16) } pub(crate) fn __reduce27< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // (> ",")+ = Annotated, "," => ActionFn(224); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant16(__symbols); let __start = __sym0.0.clone(); let __end = __sym1.2.clone(); let __nt = super::__action224::<>(text, __sym0, __sym1); __symbols.push((__start, __Symbol::Variant17(__nt), __end)); (2, 17) } pub(crate) fn __reduce28< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // (> ",")+ = (> ",")+, Annotated, "," => ActionFn(225); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant16(__symbols); let __sym0 = __pop_Variant17(__symbols); let __start = __sym0.0.clone(); let __end = __sym2.2.clone(); let __nt = super::__action225::<>(text, __sym0, __sym1, __sym2); __symbols.push((__start, __Symbol::Variant17(__nt), __end)); (3, 17) } pub(crate) fn __reduce29< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // ( ",") = AnnotatedPattern, "," => ActionFn(154); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant4(__symbols); let __start = __sym0.0.clone(); let __end = __sym1.2.clone(); let __nt = super::__action154::<>(text, __sym0, __sym1); __symbols.push((__start, __Symbol::Variant4(__nt), __end)); (2, 18) } pub(crate) fn __reduce30< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // ( ",")* = => ActionFn(152); let __start = __symbols.last().map(|s| s.2.clone()).unwrap_or_default(); let __end = __lookahead_start.cloned().unwrap_or_else(|| __start.clone()); let __nt = super::__action152::<>(text, &__start, &__end); __symbols.push((__start, __Symbol::Variant18(__nt), __end)); (0, 19) } pub(crate) fn __reduce31< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // ( ",")* = ( ",")+ => ActionFn(153); let __sym0 = __pop_Variant18(__symbols); let __start = __sym0.0.clone(); let __end = __sym0.2.clone(); let __nt = super::__action153::<>(text, __sym0); __symbols.push((__start, __Symbol::Variant18(__nt), __end)); (1, 19) } pub(crate) fn __reduce32< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // ( ",")+ = AnnotatedPattern, "," => ActionFn(228); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant4(__symbols); let __start = __sym0.0.clone(); let __end = __sym1.2.clone(); let __nt = super::__action228::<>(text, __sym0, __sym1); __symbols.push((__start, __Symbol::Variant18(__nt), __end)); (2, 20) } pub(crate) fn __reduce33< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // ( ",")+ = ( ",")+, AnnotatedPattern, "," => ActionFn(229); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant4(__symbols); let __sym0 = __pop_Variant18(__symbols); let __start = __sym0.0.clone(); let __end = __sym2.2.clone(); let __nt = super::__action229::<>(text, __sym0, __sym1, __sym2); __symbols.push((__start, __Symbol::Variant18(__nt), __end)); (3, 20) } pub(crate) fn __reduce34< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // ( ",") = AnnotatedPatternMapEntry, "," => ActionFn(159); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant19(__symbols); let __start = __sym0.0.clone(); let __end = __sym1.2.clone(); let __nt = super::__action159::<>(text, __sym0, __sym1); __symbols.push((__start, __Symbol::Variant19(__nt), __end)); (2, 21) } pub(crate) fn __reduce35< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // ( ",")* = => ActionFn(157); let __start = __symbols.last().map(|s| s.2.clone()).unwrap_or_default(); let __end = __lookahead_start.cloned().unwrap_or_else(|| __start.clone()); let __nt = super::__action157::<>(text, &__start, &__end); __symbols.push((__start, __Symbol::Variant20(__nt), __end)); (0, 22) } pub(crate) fn __reduce36< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // ( ",")* = ( ",")+ => ActionFn(158); let __sym0 = __pop_Variant20(__symbols); let __start = __sym0.0.clone(); let __end = __sym0.2.clone(); let __nt = super::__action158::<>(text, __sym0); __symbols.push((__start, __Symbol::Variant20(__nt), __end)); (1, 22) } pub(crate) fn __reduce37< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // ( ",")+ = AnnotatedPatternMapEntry, "," => ActionFn(232); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant19(__symbols); let __start = __sym0.0.clone(); let __end = __sym1.2.clone(); let __nt = super::__action232::<>(text, __sym0, __sym1); __symbols.push((__start, __Symbol::Variant20(__nt), __end)); (2, 23) } pub(crate) fn __reduce38< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // ( ",")+ = ( ",")+, AnnotatedPatternMapEntry, "," => ActionFn(233); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant19(__symbols); let __sym0 = __pop_Variant20(__symbols); let __start = __sym0.0.clone(); let __end = __sym2.2.clone(); let __nt = super::__action233::<>(text, __sym0, __sym1, __sym2); __symbols.push((__start, __Symbol::Variant20(__nt), __end)); (3, 23) } pub(crate) fn __reduce39< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // ( "=" ) = Atom, "=", Constant => ActionFn(110); let __sym2 = __pop_Variant24(__symbols); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant45(__symbols); let __start = __sym0.0.clone(); let __end = __sym2.2.clone(); let __nt = super::__action110::<>(text, __sym0, __sym1, __sym2); __symbols.push((__start, __Symbol::Variant10(__nt), __end)); (3, 24) } pub(crate) fn __reduce40< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // ( "=" )? = Atom, "=", Constant => ActionFn(211); let __sym2 = __pop_Variant24(__symbols); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant45(__symbols); let __start = __sym0.0.clone(); let __end = __sym2.2.clone(); let __nt = super::__action211::<>(text, __sym0, __sym1, __sym2); __symbols.push((__start, __Symbol::Variant21(__nt), __end)); (3, 25) } pub(crate) fn __reduce41< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // ( "=" )? = => ActionFn(124); let __start = __symbols.last().map(|s| s.2.clone()).unwrap_or_default(); let __end = __lookahead_start.cloned().unwrap_or_else(|| __start.clone()); let __nt = super::__action124::<>(text, &__start, &__end); __symbols.push((__start, __Symbol::Variant21(__nt), __end)); (0, 25) } pub(crate) fn __reduce42< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // ( ",") = BinaryElem, "," => ActionFn(169); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant22(__symbols); let __start = __sym0.0.clone(); let __end = __sym1.2.clone(); let __nt = super::__action169::<>(text, __sym0, __sym1); __symbols.push((__start, __Symbol::Variant22(__nt), __end)); (2, 26) } pub(crate) fn __reduce43< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // ( ",")* = => ActionFn(167); let __start = __symbols.last().map(|s| s.2.clone()).unwrap_or_default(); let __end = __lookahead_start.cloned().unwrap_or_else(|| __start.clone()); let __nt = super::__action167::<>(text, &__start, &__end); __symbols.push((__start, __Symbol::Variant23(__nt), __end)); (0, 27) } pub(crate) fn __reduce44< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // ( ",")* = ( ",")+ => ActionFn(168); let __sym0 = __pop_Variant23(__symbols); let __start = __sym0.0.clone(); let __end = __sym0.2.clone(); let __nt = super::__action168::<>(text, __sym0); __symbols.push((__start, __Symbol::Variant23(__nt), __end)); (1, 27) } pub(crate) fn __reduce45< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // ( ",")+ = BinaryElem, "," => ActionFn(240); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant22(__symbols); let __start = __sym0.0.clone(); let __end = __sym1.2.clone(); let __nt = super::__action240::<>(text, __sym0, __sym1); __symbols.push((__start, __Symbol::Variant23(__nt), __end)); (2, 28) } pub(crate) fn __reduce46< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // ( ",")+ = ( ",")+, BinaryElem, "," => ActionFn(241); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant22(__symbols); let __sym0 = __pop_Variant23(__symbols); let __start = __sym0.0.clone(); let __end = __sym2.2.clone(); let __nt = super::__action241::<>(text, __sym0, __sym1, __sym2); __symbols.push((__start, __Symbol::Variant23(__nt), __end)); (3, 28) } pub(crate) fn __reduce47< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // ( ",") = Constant, "," => ActionFn(174); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant24(__symbols); let __start = __sym0.0.clone(); let __end = __sym1.2.clone(); let __nt = super::__action174::<>(text, __sym0, __sym1); __symbols.push((__start, __Symbol::Variant24(__nt), __end)); (2, 29) } pub(crate) fn __reduce48< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // ( ",")* = => ActionFn(172); let __start = __symbols.last().map(|s| s.2.clone()).unwrap_or_default(); let __end = __lookahead_start.cloned().unwrap_or_else(|| __start.clone()); let __nt = super::__action172::<>(text, &__start, &__end); __symbols.push((__start, __Symbol::Variant25(__nt), __end)); (0, 30) } pub(crate) fn __reduce49< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // ( ",")* = ( ",")+ => ActionFn(173); let __sym0 = __pop_Variant25(__symbols); let __start = __sym0.0.clone(); let __end = __sym0.2.clone(); let __nt = super::__action173::<>(text, __sym0); __symbols.push((__start, __Symbol::Variant25(__nt), __end)); (1, 30) } pub(crate) fn __reduce50< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // ( ",")+ = Constant, "," => ActionFn(244); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant24(__symbols); let __start = __sym0.0.clone(); let __end = __sym1.2.clone(); let __nt = super::__action244::<>(text, __sym0, __sym1); __symbols.push((__start, __Symbol::Variant25(__nt), __end)); (2, 31) } pub(crate) fn __reduce51< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // ( ",")+ = ( ",")+, Constant, "," => ActionFn(245); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant24(__symbols); let __sym0 = __pop_Variant25(__symbols); let __start = __sym0.0.clone(); let __end = __sym2.2.clone(); let __nt = super::__action245::<>(text, __sym0, __sym1, __sym2); __symbols.push((__start, __Symbol::Variant25(__nt), __end)); (3, 31) } pub(crate) fn __reduce52< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // ( ",") = Expression, "," => ActionFn(142); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant6(__symbols); let __start = __sym0.0.clone(); let __end = __sym1.2.clone(); let __nt = super::__action142::<>(text, __sym0, __sym1); __symbols.push((__start, __Symbol::Variant6(__nt), __end)); (2, 32) } pub(crate) fn __reduce53< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // ( ",")* = => ActionFn(140); let __start = __symbols.last().map(|s| s.2.clone()).unwrap_or_default(); let __end = __lookahead_start.cloned().unwrap_or_else(|| __start.clone()); let __nt = super::__action140::<>(text, &__start, &__end); __symbols.push((__start, __Symbol::Variant26(__nt), __end)); (0, 33) } pub(crate) fn __reduce54< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // ( ",")* = ( ",")+ => ActionFn(141); let __sym0 = __pop_Variant26(__symbols); let __start = __sym0.0.clone(); let __end = __sym0.2.clone(); let __nt = super::__action141::<>(text, __sym0); __symbols.push((__start, __Symbol::Variant26(__nt), __end)); (1, 33) } pub(crate) fn __reduce55< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // ( ",")+ = Expression, "," => ActionFn(248); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant6(__symbols); let __start = __sym0.0.clone(); let __end = __sym1.2.clone(); let __nt = super::__action248::<>(text, __sym0, __sym1); __symbols.push((__start, __Symbol::Variant26(__nt), __end)); (2, 34) } pub(crate) fn __reduce56< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // ( ",")+ = ( ",")+, Expression, "," => ActionFn(249); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant6(__symbols); let __sym0 = __pop_Variant26(__symbols); let __start = __sym0.0.clone(); let __end = __sym2.2.clone(); let __nt = super::__action249::<>(text, __sym0, __sym1, __sym2); __symbols.push((__start, __Symbol::Variant26(__nt), __end)); (3, 34) } pub(crate) fn __reduce57< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // ( ) = Expression, ExactAssoc, Expression => ActionFn(92); let __sym2 = __pop_Variant6(__symbols); let __sym1 = __pop_Variant61(__symbols); let __sym0 = __pop_Variant6(__symbols); let __start = __sym0.0.clone(); let __end = __sym2.2.clone(); let __nt = super::__action92::<>(text, __sym0, __sym1, __sym2); __symbols.push((__start, __Symbol::Variant27(__nt), __end)); (3, 35) } pub(crate) fn __reduce58< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // ( ",") = FunctionName, "," => ActionFn(122); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant28(__symbols); let __start = __sym0.0.clone(); let __end = __sym1.2.clone(); let __nt = super::__action122::<>(text, __sym0, __sym1); __symbols.push((__start, __Symbol::Variant28(__nt), __end)); (2, 36) } pub(crate) fn __reduce59< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // ( ",")* = => ActionFn(120); let __start = __symbols.last().map(|s| s.2.clone()).unwrap_or_default(); let __end = __lookahead_start.cloned().unwrap_or_else(|| __start.clone()); let __nt = super::__action120::<>(text, &__start, &__end); __symbols.push((__start, __Symbol::Variant29(__nt), __end)); (0, 37) } pub(crate) fn __reduce60< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // ( ",")* = ( ",")+ => ActionFn(121); let __sym0 = __pop_Variant29(__symbols); let __start = __sym0.0.clone(); let __end = __sym0.2.clone(); let __nt = super::__action121::<>(text, __sym0); __symbols.push((__start, __Symbol::Variant29(__nt), __end)); (1, 37) } pub(crate) fn __reduce61< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // ( ",")+ = FunctionName, "," => ActionFn(254); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant28(__symbols); let __start = __sym0.0.clone(); let __end = __sym1.2.clone(); let __nt = super::__action254::<>(text, __sym0, __sym1); __symbols.push((__start, __Symbol::Variant29(__nt), __end)); (2, 38) } pub(crate) fn __reduce62< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // ( ",")+ = ( ",")+, FunctionName, "," => ActionFn(255); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant28(__symbols); let __sym0 = __pop_Variant29(__symbols); let __start = __sym0.0.clone(); let __end = __sym2.2.clone(); let __nt = super::__action255::<>(text, __sym0, __sym1, __sym2); __symbols.push((__start, __Symbol::Variant29(__nt), __end)); (3, 38) } pub(crate) fn __reduce63< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // ( "=" ) = FunctionName, "=", Fun => ActionFn(82); let __sym2 = __pop_Variant62(__symbols); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant28(__symbols); let __start = __sym0.0.clone(); let __end = __sym2.2.clone(); let __nt = super::__action82::<>(text, __sym0, __sym1, __sym2); __symbols.push((__start, __Symbol::Variant30(__nt), __end)); (3, 39) } pub(crate) fn __reduce64< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // ( "=" )+ = FunctionName, "=", Fun => ActionFn(258); let __sym2 = __pop_Variant62(__symbols); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant28(__symbols); let __start = __sym0.0.clone(); let __end = __sym2.2.clone(); let __nt = super::__action258::<>(text, __sym0, __sym1, __sym2); __symbols.push((__start, __Symbol::Variant31(__nt), __end)); (3, 40) } pub(crate) fn __reduce65< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // ( "=" )+ = ( "=" )+, FunctionName, "=", Fun => ActionFn(259); let __sym3 = __pop_Variant62(__symbols); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant28(__symbols); let __sym0 = __pop_Variant31(__symbols); let __start = __sym0.0.clone(); let __end = __sym3.2.clone(); let __nt = super::__action259::<>(text, __sym0, __sym1, __sym2, __sym3); __symbols.push((__start, __Symbol::Variant31(__nt), __end)); (4, 40) } pub(crate) fn __reduce66< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // ( ",") = PatternBinaryElem, "," => ActionFn(164); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant32(__symbols); let __start = __sym0.0.clone(); let __end = __sym1.2.clone(); let __nt = super::__action164::<>(text, __sym0, __sym1); __symbols.push((__start, __Symbol::Variant32(__nt), __end)); (2, 41) } pub(crate) fn __reduce67< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // ( ",")* = => ActionFn(162); let __start = __symbols.last().map(|s| s.2.clone()).unwrap_or_default(); let __end = __lookahead_start.cloned().unwrap_or_else(|| __start.clone()); let __nt = super::__action162::<>(text, &__start, &__end); __symbols.push((__start, __Symbol::Variant33(__nt), __end)); (0, 42) } pub(crate) fn __reduce68< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // ( ",")* = ( ",")+ => ActionFn(163); let __sym0 = __pop_Variant33(__symbols); let __start = __sym0.0.clone(); let __end = __sym0.2.clone(); let __nt = super::__action163::<>(text, __sym0); __symbols.push((__start, __Symbol::Variant33(__nt), __end)); (1, 42) } pub(crate) fn __reduce69< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // ( ",")+ = PatternBinaryElem, "," => ActionFn(260); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant32(__symbols); let __start = __sym0.0.clone(); let __end = __sym1.2.clone(); let __nt = super::__action260::<>(text, __sym0, __sym1); __symbols.push((__start, __Symbol::Variant33(__nt), __end)); (2, 43) } pub(crate) fn __reduce70< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // ( ",")+ = ( ",")+, PatternBinaryElem, "," => ActionFn(261); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant32(__symbols); let __sym0 = __pop_Variant33(__symbols); let __start = __sym0.0.clone(); let __end = __sym2.2.clone(); let __nt = super::__action261::<>(text, __sym0, __sym1, __sym2); __symbols.push((__start, __Symbol::Variant33(__nt), __end)); (3, 43) } pub(crate) fn __reduce71< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // Annotated<( )> = Expression, ExactAssoc, Expression => ActionFn(252); let __sym2 = __pop_Variant6(__symbols); let __sym1 = __pop_Variant61(__symbols); let __sym0 = __pop_Variant6(__symbols); let __start = __sym0.0.clone(); let __end = __sym2.2.clone(); let __nt = super::__action252::<>(text, __sym0, __sym1, __sym2); __symbols.push((__start, __Symbol::Variant12(__nt), __end)); (3, 44) } pub(crate) fn __reduce72< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // Annotated<( )> = "(", Expression, ExactAssoc, Expression, Annotations, ")" => ActionFn(253); let __sym5 = __pop_Variant0(__symbols); let __sym4 = __pop_Variant44(__symbols); let __sym3 = __pop_Variant6(__symbols); let __sym2 = __pop_Variant61(__symbols); let __sym1 = __pop_Variant6(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0.clone(); let __end = __sym5.2.clone(); let __nt = super::__action253::<>(text, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5); __symbols.push((__start, __Symbol::Variant12(__nt), __end)); (6, 44) } pub(crate) fn __reduce73< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // Annotated<( )>? = Annotated<( )> => ActionFn(143); let __sym0 = __pop_Variant12(__symbols); let __start = __sym0.0.clone(); let __end = __sym0.2.clone(); let __nt = super::__action143::<>(text, __sym0); __symbols.push((__start, __Symbol::Variant34(__nt), __end)); (1, 45) } pub(crate) fn __reduce74< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // Annotated<( )>? = => ActionFn(144); let __start = __symbols.last().map(|s| s.2.clone()).unwrap_or_default(); let __end = __lookahead_start.cloned().unwrap_or_else(|| __start.clone()); let __nt = super::__action144::<>(text, &__start, &__end); __symbols.push((__start, __Symbol::Variant34(__nt), __end)); (0, 45) } pub(crate) fn __reduce75< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // Annotated = Atom => ActionFn(83); let __sym0 = __pop_Variant45(__symbols); let __start = __sym0.0.clone(); let __end = __sym0.2.clone(); let __nt = super::__action83::<>(text, __sym0); __symbols.push((__start, __Symbol::Variant16(__nt), __end)); (1, 46) } pub(crate) fn __reduce76< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // Annotated = "(", Atom, Annotations, ")" => ActionFn(84); let __sym3 = __pop_Variant0(__symbols); let __sym2 = __pop_Variant44(__symbols); let __sym1 = __pop_Variant45(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0.clone(); let __end = __sym3.2.clone(); let __nt = super::__action84::<>(text, __sym0, __sym1, __sym2, __sym3); __symbols.push((__start, __Symbol::Variant16(__nt), __end)); (4, 46) } pub(crate) fn __reduce77< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // Annotated = Clause => ActionFn(87); let __sym0 = __pop_Variant49(__symbols); let __start = __sym0.0.clone(); let __end = __sym0.2.clone(); let __nt = super::__action87::<>(text, __sym0); __symbols.push((__start, __Symbol::Variant35(__nt), __end)); (1, 47) } pub(crate) fn __reduce78< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // Annotated = "(", Clause, Annotations, ")" => ActionFn(88); let __sym3 = __pop_Variant0(__symbols); let __sym2 = __pop_Variant44(__symbols); let __sym1 = __pop_Variant49(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0.clone(); let __end = __sym3.2.clone(); let __nt = super::__action88::<>(text, __sym0, __sym1, __sym2, __sym3); __symbols.push((__start, __Symbol::Variant35(__nt), __end)); (4, 47) } pub(crate) fn __reduce79< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // Annotated* = => ActionFn(85); let __start = __symbols.last().map(|s| s.2.clone()).unwrap_or_default(); let __end = __lookahead_start.cloned().unwrap_or_else(|| __start.clone()); let __nt = super::__action85::<>(text, &__start, &__end); __symbols.push((__start, __Symbol::Variant36(__nt), __end)); (0, 48) } pub(crate) fn __reduce80< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // Annotated* = Annotated+ => ActionFn(86); let __sym0 = __pop_Variant36(__symbols); let __start = __sym0.0.clone(); let __end = __sym0.2.clone(); let __nt = super::__action86::<>(text, __sym0); __symbols.push((__start, __Symbol::Variant36(__nt), __end)); (1, 48) } pub(crate) fn __reduce81< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // Annotated+ = Annotated => ActionFn(148); let __sym0 = __pop_Variant35(__symbols); let __start = __sym0.0.clone(); let __end = __sym0.2.clone(); let __nt = super::__action148::<>(text, __sym0); __symbols.push((__start, __Symbol::Variant36(__nt), __end)); (1, 49) } pub(crate) fn __reduce82< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // Annotated+ = Annotated+, Annotated => ActionFn(149); let __sym1 = __pop_Variant35(__symbols); let __sym0 = __pop_Variant36(__symbols); let __start = __sym0.0.clone(); let __end = __sym1.2.clone(); let __nt = super::__action149::<>(text, __sym0, __sym1); __symbols.push((__start, __Symbol::Variant36(__nt), __end)); (2, 49) } pub(crate) fn __reduce83< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // Annotated = Fun => ActionFn(105); let __sym0 = __pop_Variant62(__symbols); let __start = __sym0.0.clone(); let __end = __sym0.2.clone(); let __nt = super::__action105::<>(text, __sym0); __symbols.push((__start, __Symbol::Variant37(__nt), __end)); (1, 50) } pub(crate) fn __reduce84< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // Annotated = "(", Fun, Annotations, ")" => ActionFn(106); let __sym3 = __pop_Variant0(__symbols); let __sym2 = __pop_Variant44(__symbols); let __sym1 = __pop_Variant62(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0.clone(); let __end = __sym3.2.clone(); let __nt = super::__action106::<>(text, __sym0, __sym1, __sym2, __sym3); __symbols.push((__start, __Symbol::Variant37(__nt), __end)); (4, 50) } pub(crate) fn __reduce85< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // Annotated = FunctionName => ActionFn(107); let __sym0 = __pop_Variant28(__symbols); let __start = __sym0.0.clone(); let __end = __sym0.2.clone(); let __nt = super::__action107::<>(text, __sym0); __symbols.push((__start, __Symbol::Variant38(__nt), __end)); (1, 51) } pub(crate) fn __reduce86< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // Annotated = "(", FunctionName, Annotations, ")" => ActionFn(108); let __sym3 = __pop_Variant0(__symbols); let __sym2 = __pop_Variant44(__symbols); let __sym1 = __pop_Variant28(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0.clone(); let __end = __sym3.2.clone(); let __nt = super::__action108::<>(text, __sym0, __sym1, __sym2, __sym3); __symbols.push((__start, __Symbol::Variant38(__nt), __end)); (4, 51) } pub(crate) fn __reduce87< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // Annotated = Module => ActionFn(114); let __sym0 = __pop_Variant67(__symbols); let __start = __sym0.0.clone(); let __end = __sym0.2.clone(); let __nt = super::__action114::<>(text, __sym0); __symbols.push((__start, __Symbol::Variant39(__nt), __end)); (1, 52) } pub(crate) fn __reduce88< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // Annotated = "(", Module, Annotations, ")" => ActionFn(115); let __sym3 = __pop_Variant0(__symbols); let __sym2 = __pop_Variant44(__symbols); let __sym1 = __pop_Variant67(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0.clone(); let __end = __sym3.2.clone(); let __nt = super::__action115::<>(text, __sym0, __sym1, __sym2, __sym3); __symbols.push((__start, __Symbol::Variant39(__nt), __end)); (4, 52) } pub(crate) fn __reduce89< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // Annotated = Annotated, "=", AnnotatedPattern => ActionFn(306); let __sym2 = __pop_Variant4(__symbols); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant16(__symbols); let __start = __sym0.0.clone(); let __end = __sym2.2.clone(); let __nt = super::__action306::<>(text, __sym0, __sym1, __sym2); __symbols.push((__start, __Symbol::Variant4(__nt), __end)); (3, 53) } pub(crate) fn __reduce90< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // Annotated = Variable => ActionFn(307); let __sym0 = __pop_Variant45(__symbols); let __start = __sym0.0.clone(); let __end = __sym0.2.clone(); let __nt = super::__action307::<>(text, __sym0); __symbols.push((__start, __Symbol::Variant4(__nt), __end)); (1, 53) } pub(crate) fn __reduce91< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // Annotated = AtomicTerm => ActionFn(308); let __sym0 = __pop_Variant46(__symbols); let __start = __sym0.0.clone(); let __end = __sym0.2.clone(); let __nt = super::__action308::<>(text, __sym0); __symbols.push((__start, __Symbol::Variant4(__nt), __end)); (1, 53) } pub(crate) fn __reduce92< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // Annotated = PatternBinary => ActionFn(309); let __sym0 = __pop_Variant59(__symbols); let __start = __sym0.0.clone(); let __end = __sym0.2.clone(); let __nt = super::__action309::<>(text, __sym0); __symbols.push((__start, __Symbol::Variant4(__nt), __end)); (1, 53) } pub(crate) fn __reduce93< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // Annotated = "{", Comma, "}" => ActionFn(310); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant54(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0.clone(); let __end = __sym2.2.clone(); let __nt = super::__action310::<>(text, __sym0, __sym1, __sym2); __symbols.push((__start, __Symbol::Variant4(__nt), __end)); (3, 53) } pub(crate) fn __reduce94< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // Annotated = "~{", Comma, "}~" => ActionFn(311); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant55(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0.clone(); let __end = __sym2.2.clone(); let __nt = super::__action311::<>(text, __sym0, __sym1, __sym2); __symbols.push((__start, __Symbol::Variant4(__nt), __end)); (3, 53) } pub(crate) fn __reduce95< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // Annotated = "[", Comma, "|", AnnotatedPattern, "]" => ActionFn(312); let __sym4 = __pop_Variant0(__symbols); let __sym3 = __pop_Variant4(__symbols); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant54(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0.clone(); let __end = __sym4.2.clone(); let __nt = super::__action312::<>(text, __sym0, __sym1, __sym2, __sym3, __sym4); __symbols.push((__start, __Symbol::Variant4(__nt), __end)); (5, 53) } pub(crate) fn __reduce96< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // Annotated = "[", Comma, "]" => ActionFn(313); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant54(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0.clone(); let __end = __sym2.2.clone(); let __nt = super::__action313::<>(text, __sym0, __sym1, __sym2); __symbols.push((__start, __Symbol::Variant4(__nt), __end)); (3, 53) } pub(crate) fn __reduce97< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // Annotated = "(", Annotated, "=", AnnotatedPattern, Annotations, ")" => ActionFn(314); let __sym5 = __pop_Variant0(__symbols); let __sym4 = __pop_Variant44(__symbols); let __sym3 = __pop_Variant4(__symbols); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant16(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0.clone(); let __end = __sym5.2.clone(); let __nt = super::__action314::<>(text, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5); __symbols.push((__start, __Symbol::Variant4(__nt), __end)); (6, 53) } pub(crate) fn __reduce98< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // Annotated = "(", Variable, Annotations, ")" => ActionFn(315); let __sym3 = __pop_Variant0(__symbols); let __sym2 = __pop_Variant44(__symbols); let __sym1 = __pop_Variant45(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0.clone(); let __end = __sym3.2.clone(); let __nt = super::__action315::<>(text, __sym0, __sym1, __sym2, __sym3); __symbols.push((__start, __Symbol::Variant4(__nt), __end)); (4, 53) } pub(crate) fn __reduce99< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // Annotated = "(", AtomicTerm, Annotations, ")" => ActionFn(316); let __sym3 = __pop_Variant0(__symbols); let __sym2 = __pop_Variant44(__symbols); let __sym1 = __pop_Variant46(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0.clone(); let __end = __sym3.2.clone(); let __nt = super::__action316::<>(text, __sym0, __sym1, __sym2, __sym3); __symbols.push((__start, __Symbol::Variant4(__nt), __end)); (4, 53) } pub(crate) fn __reduce100< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // Annotated = "(", PatternBinary, Annotations, ")" => ActionFn(317); let __sym3 = __pop_Variant0(__symbols); let __sym2 = __pop_Variant44(__symbols); let __sym1 = __pop_Variant59(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0.clone(); let __end = __sym3.2.clone(); let __nt = super::__action317::<>(text, __sym0, __sym1, __sym2, __sym3); __symbols.push((__start, __Symbol::Variant4(__nt), __end)); (4, 53) } pub(crate) fn __reduce101< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // Annotated = "(", "{", Comma, "}", Annotations, ")" => ActionFn(318); let __sym5 = __pop_Variant0(__symbols); let __sym4 = __pop_Variant44(__symbols); let __sym3 = __pop_Variant0(__symbols); let __sym2 = __pop_Variant54(__symbols); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0.clone(); let __end = __sym5.2.clone(); let __nt = super::__action318::<>(text, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5); __symbols.push((__start, __Symbol::Variant4(__nt), __end)); (6, 53) } pub(crate) fn __reduce102< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // Annotated = "(", "~{", Comma, "}~", Annotations, ")" => ActionFn(319); let __sym5 = __pop_Variant0(__symbols); let __sym4 = __pop_Variant44(__symbols); let __sym3 = __pop_Variant0(__symbols); let __sym2 = __pop_Variant55(__symbols); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0.clone(); let __end = __sym5.2.clone(); let __nt = super::__action319::<>(text, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5); __symbols.push((__start, __Symbol::Variant4(__nt), __end)); (6, 53) } pub(crate) fn __reduce103< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // Annotated = "(", "[", Comma, "|", AnnotatedPattern, "]", Annotations, ")" => ActionFn(320); let __sym7 = __pop_Variant0(__symbols); let __sym6 = __pop_Variant44(__symbols); let __sym5 = __pop_Variant0(__symbols); let __sym4 = __pop_Variant4(__symbols); let __sym3 = __pop_Variant0(__symbols); let __sym2 = __pop_Variant54(__symbols); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0.clone(); let __end = __sym7.2.clone(); let __nt = super::__action320::<>(text, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6, __sym7); __symbols.push((__start, __Symbol::Variant4(__nt), __end)); (8, 53) } pub(crate) fn __reduce104< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // Annotated = "(", "[", Comma, "]", Annotations, ")" => ActionFn(321); let __sym5 = __pop_Variant0(__symbols); let __sym4 = __pop_Variant44(__symbols); let __sym3 = __pop_Variant0(__symbols); let __sym2 = __pop_Variant54(__symbols); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0.clone(); let __end = __sym5.2.clone(); let __nt = super::__action321::<>(text, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5); __symbols.push((__start, __Symbol::Variant4(__nt), __end)); (6, 53) } pub(crate) fn __reduce105< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // Annotated = PatternMapEntry => ActionFn(75); let __sym0 = __pop_Variant70(__symbols); let __start = __sym0.0.clone(); let __end = __sym0.2.clone(); let __nt = super::__action75::<>(text, __sym0); __symbols.push((__start, __Symbol::Variant19(__nt), __end)); (1, 54) } pub(crate) fn __reduce106< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // Annotated = "(", PatternMapEntry, Annotations, ")" => ActionFn(76); let __sym3 = __pop_Variant0(__symbols); let __sym2 = __pop_Variant44(__symbols); let __sym1 = __pop_Variant70(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0.clone(); let __end = __sym3.2.clone(); let __nt = super::__action76::<>(text, __sym0, __sym1, __sym2, __sym3); __symbols.push((__start, __Symbol::Variant19(__nt), __end)); (4, 54) } pub(crate) fn __reduce107< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // Annotated = SingleExpression => ActionFn(98); let __sym0 = __pop_Variant71(__symbols); let __start = __sym0.0.clone(); let __end = __sym0.2.clone(); let __nt = super::__action98::<>(text, __sym0); __symbols.push((__start, __Symbol::Variant14(__nt), __end)); (1, 55) } pub(crate) fn __reduce108< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // Annotated = "(", SingleExpression, Annotations, ")" => ActionFn(99); let __sym3 = __pop_Variant0(__symbols); let __sym2 = __pop_Variant44(__symbols); let __sym1 = __pop_Variant71(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0.clone(); let __end = __sym3.2.clone(); let __nt = super::__action99::<>(text, __sym0, __sym1, __sym2, __sym3); __symbols.push((__start, __Symbol::Variant14(__nt), __end)); (4, 55) } pub(crate) fn __reduce109< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // Annotated? = Annotated => ActionFn(133); let __sym0 = __pop_Variant14(__symbols); let __start = __sym0.0.clone(); let __end = __sym0.2.clone(); let __nt = super::__action133::<>(text, __sym0); __symbols.push((__start, __Symbol::Variant40(__nt), __end)); (1, 56) } pub(crate) fn __reduce110< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // Annotated? = => ActionFn(134); let __start = __symbols.last().map(|s| s.2.clone()).unwrap_or_default(); let __end = __lookahead_start.cloned().unwrap_or_else(|| __start.clone()); let __nt = super::__action134::<>(text, &__start, &__end); __symbols.push((__start, __Symbol::Variant40(__nt), __end)); (0, 56) } pub(crate) fn __reduce111< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // Annotated = ValueList => ActionFn(100); let __sym0 = __pop_Variant52(__symbols); let __start = __sym0.0.clone(); let __end = __sym0.2.clone(); let __nt = super::__action100::<>(text, __sym0); __symbols.push((__start, __Symbol::Variant41(__nt), __end)); (1, 57) } pub(crate) fn __reduce112< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // Annotated = "(", ValueList, Annotations, ")" => ActionFn(101); let __sym3 = __pop_Variant0(__symbols); let __sym2 = __pop_Variant44(__symbols); let __sym1 = __pop_Variant52(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0.clone(); let __end = __sym3.2.clone(); let __nt = super::__action101::<>(text, __sym0, __sym1, __sym2, __sym3); __symbols.push((__start, __Symbol::Variant41(__nt), __end)); (4, 57) } pub(crate) fn __reduce113< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // Annotated = Variable => ActionFn(103); let __sym0 = __pop_Variant45(__symbols); let __start = __sym0.0.clone(); let __end = __sym0.2.clone(); let __nt = super::__action103::<>(text, __sym0); __symbols.push((__start, __Symbol::Variant16(__nt), __end)); (1, 58) } pub(crate) fn __reduce114< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // Annotated = "(", Variable, Annotations, ")" => ActionFn(104); let __sym3 = __pop_Variant0(__symbols); let __sym2 = __pop_Variant44(__symbols); let __sym1 = __pop_Variant45(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0.clone(); let __end = __sym3.2.clone(); let __nt = super::__action104::<>(text, __sym0, __sym1, __sym2, __sym3); __symbols.push((__start, __Symbol::Variant16(__nt), __end)); (4, 58) } pub(crate) fn __reduce115< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // Annotated? = Annotated => ActionFn(128); let __sym0 = __pop_Variant16(__symbols); let __start = __sym0.0.clone(); let __end = __sym0.2.clone(); let __nt = super::__action128::<>(text, __sym0); __symbols.push((__start, __Symbol::Variant42(__nt), __end)); (1, 59) } pub(crate) fn __reduce116< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // Annotated? = => ActionFn(129); let __start = __symbols.last().map(|s| s.2.clone()).unwrap_or_default(); let __end = __lookahead_start.cloned().unwrap_or_else(|| __start.clone()); let __nt = super::__action129::<>(text, &__start, &__end); __symbols.push((__start, __Symbol::Variant42(__nt), __end)); (0, 59) } pub(crate) fn __reduce117< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // AnnotatedModule = Annotated => ActionFn(4); let __sym0 = __pop_Variant39(__symbols); let __start = __sym0.0.clone(); let __end = __sym0.2.clone(); let __nt = super::__action4::<>(text, __sym0); __symbols.push((__start, __Symbol::Variant39(__nt), __end)); (1, 60) } pub(crate) fn __reduce118< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // AnnotatedPattern = Annotated => ActionFn(41); let __sym0 = __pop_Variant4(__symbols); let __start = __sym0.0.clone(); let __end = __sym0.2.clone(); let __nt = super::__action41::<>(text, __sym0); __symbols.push((__start, __Symbol::Variant4(__nt), __end)); (1, 61) } pub(crate) fn __reduce119< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // AnnotatedPattern? = AnnotatedPattern => ActionFn(150); let __sym0 = __pop_Variant4(__symbols); let __start = __sym0.0.clone(); let __end = __sym0.2.clone(); let __nt = super::__action150::<>(text, __sym0); __symbols.push((__start, __Symbol::Variant5(__nt), __end)); (1, 62) } pub(crate) fn __reduce120< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // AnnotatedPattern? = => ActionFn(151); let __start = __symbols.last().map(|s| s.2.clone()).unwrap_or_default(); let __end = __lookahead_start.cloned().unwrap_or_else(|| __start.clone()); let __nt = super::__action151::<>(text, &__start, &__end); __symbols.push((__start, __Symbol::Variant5(__nt), __end)); (0, 62) } pub(crate) fn __reduce121< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // AnnotatedPatternMapEntry = Annotated => ActionFn(43); let __sym0 = __pop_Variant19(__symbols); let __start = __sym0.0.clone(); let __end = __sym0.2.clone(); let __nt = super::__action43::<>(text, __sym0); __symbols.push((__start, __Symbol::Variant19(__nt), __end)); (1, 63) } pub(crate) fn __reduce122< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // AnnotatedPatternMapEntry? = AnnotatedPatternMapEntry => ActionFn(155); let __sym0 = __pop_Variant19(__symbols); let __start = __sym0.0.clone(); let __end = __sym0.2.clone(); let __nt = super::__action155::<>(text, __sym0); __symbols.push((__start, __Symbol::Variant43(__nt), __end)); (1, 64) } pub(crate) fn __reduce123< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // AnnotatedPatternMapEntry? = => ActionFn(156); let __start = __symbols.last().map(|s| s.2.clone()).unwrap_or_default(); let __end = __lookahead_start.cloned().unwrap_or_else(|| __start.clone()); let __nt = super::__action156::<>(text, &__start, &__end); __symbols.push((__start, __Symbol::Variant43(__nt), __end)); (0, 64) } pub(crate) fn __reduce124< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // Annotations = "-|", "[", Comma, "]" => ActionFn(64); let __sym3 = __pop_Variant0(__symbols); let __sym2 = __pop_Variant56(__symbols); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0.clone(); let __end = __sym3.2.clone(); let __nt = super::__action64::<>(text, __sym0, __sym1, __sym2, __sym3); __symbols.push((__start, __Symbol::Variant44(__nt), __end)); (4, 65) } pub(crate) fn __reduce125< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // Atom = "Atom" => ActionFn(2); let __sym0 = __pop_Variant1(__symbols); let __start = __sym0.0.clone(); let __end = __sym0.2.clone(); let __nt = super::__action2::<>(text, __sym0); __symbols.push((__start, __Symbol::Variant45(__nt), __end)); (1, 66) } pub(crate) fn __reduce126< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // AtomicTerm = Integer => ActionFn(58); let __sym0 = __pop_Variant66(__symbols); let __start = __sym0.0.clone(); let __end = __sym0.2.clone(); let __nt = super::__action58::<>(text, __sym0); __symbols.push((__start, __Symbol::Variant46(__nt), __end)); (1, 67) } pub(crate) fn __reduce127< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // AtomicTerm = Atom => ActionFn(59); let __sym0 = __pop_Variant45(__symbols); let __start = __sym0.0.clone(); let __end = __sym0.2.clone(); let __nt = super::__action59::<>(text, __sym0); __symbols.push((__start, __Symbol::Variant46(__nt), __end)); (1, 67) } pub(crate) fn __reduce128< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // AtomicTerm = "Char" => ActionFn(60); let __sym0 = __pop_Variant2(__symbols); let __start = __sym0.0.clone(); let __end = __sym0.2.clone(); let __nt = super::__action60::<>(text, __sym0); __symbols.push((__start, __Symbol::Variant46(__nt), __end)); (1, 67) } pub(crate) fn __reduce129< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // AtomicTerm = "String" => ActionFn(61); let __sym0 = __pop_Variant1(__symbols); let __start = __sym0.0.clone(); let __end = __sym0.2.clone(); let __nt = super::__action61::<>(text, __sym0); __symbols.push((__start, __Symbol::Variant46(__nt), __end)); (1, 67) } pub(crate) fn __reduce130< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // Binary = "#{", Comma, "}#" => ActionFn(53); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant47(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0.clone(); let __end = __sym2.2.clone(); let __nt = super::__action53::<>(text, __sym0, __sym1, __sym2); __symbols.push((__start, __Symbol::Variant47(__nt), __end)); (3, 68) } pub(crate) fn __reduce131< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // BinaryElem = "#<", Expression, ">(", Comma, ")" => ActionFn(54); let __sym4 = __pop_Variant0(__symbols); let __sym3 = __pop_Variant57(__symbols); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant6(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0.clone(); let __end = __sym4.2.clone(); let __nt = super::__action54::<>(text, __sym0, __sym1, __sym2, __sym3, __sym4); __symbols.push((__start, __Symbol::Variant22(__nt), __end)); (5, 69) } pub(crate) fn __reduce132< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // BinaryElem? = BinaryElem => ActionFn(165); let __sym0 = __pop_Variant22(__symbols); let __start = __sym0.0.clone(); let __end = __sym0.2.clone(); let __nt = super::__action165::<>(text, __sym0); __symbols.push((__start, __Symbol::Variant48(__nt), __end)); (1, 70) } pub(crate) fn __reduce133< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // BinaryElem? = => ActionFn(166); let __start = __symbols.last().map(|s| s.2.clone()).unwrap_or_default(); let __end = __lookahead_start.cloned().unwrap_or_else(|| __start.clone()); let __nt = super::__action166::<>(text, &__start, &__end); __symbols.push((__start, __Symbol::Variant48(__nt), __end)); (0, 70) } pub(crate) fn __reduce134< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // Clause = Patterns, Guard, "->", Expression => ActionFn(35); let __sym3 = __pop_Variant6(__symbols); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant6(__symbols); let __sym0 = __pop_Variant54(__symbols); let __start = __sym0.0.clone(); let __end = __sym3.2.clone(); let __nt = super::__action35::<>(text, __sym0, __sym1, __sym2, __sym3); __symbols.push((__start, __Symbol::Variant49(__nt), __end)); (4, 71) } pub(crate) fn __reduce135< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // Comma<( "=" )> = Atom, "=", Constant => ActionFn(236); let __sym2 = __pop_Variant24(__symbols); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant45(__symbols); let __start = __sym0.0.clone(); let __end = __sym2.2.clone(); let __nt = super::__action236::<>(text, __sym0, __sym1, __sym2); __symbols.push((__start, __Symbol::Variant50(__nt), __end)); (3, 72) } pub(crate) fn __reduce136< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // Comma<( "=" )> = => ActionFn(237); let __start = __symbols.last().map(|s| s.2.clone()).unwrap_or_default(); let __end = __lookahead_start.cloned().unwrap_or_else(|| __start.clone()); let __nt = super::__action237::<>(text, &__start, &__end); __symbols.push((__start, __Symbol::Variant50(__nt), __end)); (0, 72) } pub(crate) fn __reduce137< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // Comma<( "=" )> = (<( "=" )> ",")+, Atom, "=", Constant => ActionFn(238); let __sym3 = __pop_Variant24(__symbols); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant45(__symbols); let __sym0 = __pop_Variant11(__symbols); let __start = __sym0.0.clone(); let __end = __sym3.2.clone(); let __nt = super::__action238::<>(text, __sym0, __sym1, __sym2, __sym3); __symbols.push((__start, __Symbol::Variant50(__nt), __end)); (4, 72) } pub(crate) fn __reduce138< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // Comma<( "=" )> = (<( "=" )> ",")+ => ActionFn(239); let __sym0 = __pop_Variant11(__symbols); let __start = __sym0.0.clone(); let __end = __sym0.2.clone(); let __nt = super::__action239::<>(text, __sym0); __symbols.push((__start, __Symbol::Variant50(__nt), __end)); (1, 72) } pub(crate) fn __reduce139< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // Comma )>> = Annotated<( )> => ActionFn(264); let __sym0 = __pop_Variant12(__symbols); let __start = __sym0.0.clone(); let __end = __sym0.2.clone(); let __nt = super::__action264::<>(text, __sym0); __symbols.push((__start, __Symbol::Variant51(__nt), __end)); (1, 73) } pub(crate) fn __reduce140< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // Comma )>> = => ActionFn(265); let __start = __symbols.last().map(|s| s.2.clone()).unwrap_or_default(); let __end = __lookahead_start.cloned().unwrap_or_else(|| __start.clone()); let __nt = super::__action265::<>(text, &__start, &__end); __symbols.push((__start, __Symbol::Variant51(__nt), __end)); (0, 73) } pub(crate) fn __reduce141< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // Comma )>> = ( )>> ",")+, Annotated<( )> => ActionFn(266); let __sym1 = __pop_Variant12(__symbols); let __sym0 = __pop_Variant13(__symbols); let __start = __sym0.0.clone(); let __end = __sym1.2.clone(); let __nt = super::__action266::<>(text, __sym0, __sym1); __symbols.push((__start, __Symbol::Variant51(__nt), __end)); (2, 73) } pub(crate) fn __reduce142< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // Comma )>> = ( )>> ",")+ => ActionFn(267); let __sym0 = __pop_Variant13(__symbols); let __start = __sym0.0.clone(); let __end = __sym0.2.clone(); let __nt = super::__action267::<>(text, __sym0); __symbols.push((__start, __Symbol::Variant51(__nt), __end)); (1, 73) } pub(crate) fn __reduce143< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // Comma> = Annotated => ActionFn(272); let __sym0 = __pop_Variant14(__symbols); let __start = __sym0.0.clone(); let __end = __sym0.2.clone(); let __nt = super::__action272::<>(text, __sym0); __symbols.push((__start, __Symbol::Variant52(__nt), __end)); (1, 74) } pub(crate) fn __reduce144< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // Comma> = => ActionFn(273); let __start = __symbols.last().map(|s| s.2.clone()).unwrap_or_default(); let __end = __lookahead_start.cloned().unwrap_or_else(|| __start.clone()); let __nt = super::__action273::<>(text, &__start, &__end); __symbols.push((__start, __Symbol::Variant52(__nt), __end)); (0, 74) } pub(crate) fn __reduce145< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // Comma> = (> ",")+, Annotated => ActionFn(274); let __sym1 = __pop_Variant14(__symbols); let __sym0 = __pop_Variant15(__symbols); let __start = __sym0.0.clone(); let __end = __sym1.2.clone(); let __nt = super::__action274::<>(text, __sym0, __sym1); __symbols.push((__start, __Symbol::Variant52(__nt), __end)); (2, 74) } pub(crate) fn __reduce146< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // Comma> = (> ",")+ => ActionFn(275); let __sym0 = __pop_Variant15(__symbols); let __start = __sym0.0.clone(); let __end = __sym0.2.clone(); let __nt = super::__action275::<>(text, __sym0); __symbols.push((__start, __Symbol::Variant52(__nt), __end)); (1, 74) } pub(crate) fn __reduce147< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // Comma> = Annotated => ActionFn(276); let __sym0 = __pop_Variant16(__symbols); let __start = __sym0.0.clone(); let __end = __sym0.2.clone(); let __nt = super::__action276::<>(text, __sym0); __symbols.push((__start, __Symbol::Variant53(__nt), __end)); (1, 75) } pub(crate) fn __reduce148< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // Comma> = => ActionFn(277); let __start = __symbols.last().map(|s| s.2.clone()).unwrap_or_default(); let __end = __lookahead_start.cloned().unwrap_or_else(|| __start.clone()); let __nt = super::__action277::<>(text, &__start, &__end); __symbols.push((__start, __Symbol::Variant53(__nt), __end)); (0, 75) } pub(crate) fn __reduce149< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // Comma> = (> ",")+, Annotated => ActionFn(278); let __sym1 = __pop_Variant16(__symbols); let __sym0 = __pop_Variant17(__symbols); let __start = __sym0.0.clone(); let __end = __sym1.2.clone(); let __nt = super::__action278::<>(text, __sym0, __sym1); __symbols.push((__start, __Symbol::Variant53(__nt), __end)); (2, 75) } pub(crate) fn __reduce150< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // Comma> = (> ",")+ => ActionFn(279); let __sym0 = __pop_Variant17(__symbols); let __start = __sym0.0.clone(); let __end = __sym0.2.clone(); let __nt = super::__action279::<>(text, __sym0); __symbols.push((__start, __Symbol::Variant53(__nt), __end)); (1, 75) } pub(crate) fn __reduce151< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // Comma = AnnotatedPattern => ActionFn(280); let __sym0 = __pop_Variant4(__symbols); let __start = __sym0.0.clone(); let __end = __sym0.2.clone(); let __nt = super::__action280::<>(text, __sym0); __symbols.push((__start, __Symbol::Variant54(__nt), __end)); (1, 76) } pub(crate) fn __reduce152< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // Comma = => ActionFn(281); let __start = __symbols.last().map(|s| s.2.clone()).unwrap_or_default(); let __end = __lookahead_start.cloned().unwrap_or_else(|| __start.clone()); let __nt = super::__action281::<>(text, &__start, &__end); __symbols.push((__start, __Symbol::Variant54(__nt), __end)); (0, 76) } pub(crate) fn __reduce153< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // Comma = ( ",")+, AnnotatedPattern => ActionFn(282); let __sym1 = __pop_Variant4(__symbols); let __sym0 = __pop_Variant18(__symbols); let __start = __sym0.0.clone(); let __end = __sym1.2.clone(); let __nt = super::__action282::<>(text, __sym0, __sym1); __symbols.push((__start, __Symbol::Variant54(__nt), __end)); (2, 76) } pub(crate) fn __reduce154< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // Comma = ( ",")+ => ActionFn(283); let __sym0 = __pop_Variant18(__symbols); let __start = __sym0.0.clone(); let __end = __sym0.2.clone(); let __nt = super::__action283::<>(text, __sym0); __symbols.push((__start, __Symbol::Variant54(__nt), __end)); (1, 76) } pub(crate) fn __reduce155< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // Comma = AnnotatedPatternMapEntry => ActionFn(284); let __sym0 = __pop_Variant19(__symbols); let __start = __sym0.0.clone(); let __end = __sym0.2.clone(); let __nt = super::__action284::<>(text, __sym0); __symbols.push((__start, __Symbol::Variant55(__nt), __end)); (1, 77) } pub(crate) fn __reduce156< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // Comma = => ActionFn(285); let __start = __symbols.last().map(|s| s.2.clone()).unwrap_or_default(); let __end = __lookahead_start.cloned().unwrap_or_else(|| __start.clone()); let __nt = super::__action285::<>(text, &__start, &__end); __symbols.push((__start, __Symbol::Variant55(__nt), __end)); (0, 77) } pub(crate) fn __reduce157< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // Comma = ( ",")+, AnnotatedPatternMapEntry => ActionFn(286); let __sym1 = __pop_Variant19(__symbols); let __sym0 = __pop_Variant20(__symbols); let __start = __sym0.0.clone(); let __end = __sym1.2.clone(); let __nt = super::__action286::<>(text, __sym0, __sym1); __symbols.push((__start, __Symbol::Variant55(__nt), __end)); (2, 77) } pub(crate) fn __reduce158< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // Comma = ( ",")+ => ActionFn(287); let __sym0 = __pop_Variant20(__symbols); let __start = __sym0.0.clone(); let __end = __sym0.2.clone(); let __nt = super::__action287::<>(text, __sym0); __symbols.push((__start, __Symbol::Variant55(__nt), __end)); (1, 77) } pub(crate) fn __reduce159< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // Comma = BinaryElem => ActionFn(288); let __sym0 = __pop_Variant22(__symbols); let __start = __sym0.0.clone(); let __end = __sym0.2.clone(); let __nt = super::__action288::<>(text, __sym0); __symbols.push((__start, __Symbol::Variant47(__nt), __end)); (1, 78) } pub(crate) fn __reduce160< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // Comma = => ActionFn(289); let __start = __symbols.last().map(|s| s.2.clone()).unwrap_or_default(); let __end = __lookahead_start.cloned().unwrap_or_else(|| __start.clone()); let __nt = super::__action289::<>(text, &__start, &__end); __symbols.push((__start, __Symbol::Variant47(__nt), __end)); (0, 78) } pub(crate) fn __reduce161< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // Comma = ( ",")+, BinaryElem => ActionFn(290); let __sym1 = __pop_Variant22(__symbols); let __sym0 = __pop_Variant23(__symbols); let __start = __sym0.0.clone(); let __end = __sym1.2.clone(); let __nt = super::__action290::<>(text, __sym0, __sym1); __symbols.push((__start, __Symbol::Variant47(__nt), __end)); (2, 78) } pub(crate) fn __reduce162< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // Comma = ( ",")+ => ActionFn(291); let __sym0 = __pop_Variant23(__symbols); let __start = __sym0.0.clone(); let __end = __sym0.2.clone(); let __nt = super::__action291::<>(text, __sym0); __symbols.push((__start, __Symbol::Variant47(__nt), __end)); (1, 78) } pub(crate) fn __reduce163< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // Comma = Constant => ActionFn(292); let __sym0 = __pop_Variant24(__symbols); let __start = __sym0.0.clone(); let __end = __sym0.2.clone(); let __nt = super::__action292::<>(text, __sym0); __symbols.push((__start, __Symbol::Variant56(__nt), __end)); (1, 79) } pub(crate) fn __reduce164< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // Comma = => ActionFn(293); let __start = __symbols.last().map(|s| s.2.clone()).unwrap_or_default(); let __end = __lookahead_start.cloned().unwrap_or_else(|| __start.clone()); let __nt = super::__action293::<>(text, &__start, &__end); __symbols.push((__start, __Symbol::Variant56(__nt), __end)); (0, 79) } pub(crate) fn __reduce165< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // Comma = ( ",")+, Constant => ActionFn(294); let __sym1 = __pop_Variant24(__symbols); let __sym0 = __pop_Variant25(__symbols); let __start = __sym0.0.clone(); let __end = __sym1.2.clone(); let __nt = super::__action294::<>(text, __sym0, __sym1); __symbols.push((__start, __Symbol::Variant56(__nt), __end)); (2, 79) } pub(crate) fn __reduce166< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // Comma = ( ",")+ => ActionFn(295); let __sym0 = __pop_Variant25(__symbols); let __start = __sym0.0.clone(); let __end = __sym0.2.clone(); let __nt = super::__action295::<>(text, __sym0); __symbols.push((__start, __Symbol::Variant56(__nt), __end)); (1, 79) } pub(crate) fn __reduce167< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // Comma = Expression => ActionFn(296); let __sym0 = __pop_Variant6(__symbols); let __start = __sym0.0.clone(); let __end = __sym0.2.clone(); let __nt = super::__action296::<>(text, __sym0); __symbols.push((__start, __Symbol::Variant57(__nt), __end)); (1, 80) } pub(crate) fn __reduce168< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // Comma = => ActionFn(297); let __start = __symbols.last().map(|s| s.2.clone()).unwrap_or_default(); let __end = __lookahead_start.cloned().unwrap_or_else(|| __start.clone()); let __nt = super::__action297::<>(text, &__start, &__end); __symbols.push((__start, __Symbol::Variant57(__nt), __end)); (0, 80) } pub(crate) fn __reduce169< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // Comma = ( ",")+, Expression => ActionFn(298); let __sym1 = __pop_Variant6(__symbols); let __sym0 = __pop_Variant26(__symbols); let __start = __sym0.0.clone(); let __end = __sym1.2.clone(); let __nt = super::__action298::<>(text, __sym0, __sym1); __symbols.push((__start, __Symbol::Variant57(__nt), __end)); (2, 80) } pub(crate) fn __reduce170< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // Comma = ( ",")+ => ActionFn(299); let __sym0 = __pop_Variant26(__symbols); let __start = __sym0.0.clone(); let __end = __sym0.2.clone(); let __nt = super::__action299::<>(text, __sym0); __symbols.push((__start, __Symbol::Variant57(__nt), __end)); (1, 80) } pub(crate) fn __reduce171< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // Comma = FunctionName => ActionFn(302); let __sym0 = __pop_Variant28(__symbols); let __start = __sym0.0.clone(); let __end = __sym0.2.clone(); let __nt = super::__action302::<>(text, __sym0); __symbols.push((__start, __Symbol::Variant58(__nt), __end)); (1, 81) } pub(crate) fn __reduce172< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // Comma = => ActionFn(303); let __start = __symbols.last().map(|s| s.2.clone()).unwrap_or_default(); let __end = __lookahead_start.cloned().unwrap_or_else(|| __start.clone()); let __nt = super::__action303::<>(text, &__start, &__end); __symbols.push((__start, __Symbol::Variant58(__nt), __end)); (0, 81) } pub(crate) fn __reduce173< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // Comma = ( ",")+, FunctionName => ActionFn(304); let __sym1 = __pop_Variant28(__symbols); let __sym0 = __pop_Variant29(__symbols); let __start = __sym0.0.clone(); let __end = __sym1.2.clone(); let __nt = super::__action304::<>(text, __sym0, __sym1); __symbols.push((__start, __Symbol::Variant58(__nt), __end)); (2, 81) } pub(crate) fn __reduce174< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // Comma = ( ",")+ => ActionFn(305); let __sym0 = __pop_Variant29(__symbols); let __start = __sym0.0.clone(); let __end = __sym0.2.clone(); let __nt = super::__action305::<>(text, __sym0); __symbols.push((__start, __Symbol::Variant58(__nt), __end)); (1, 81) } pub(crate) fn __reduce175< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // Comma = PatternBinaryElem => ActionFn(322); let __sym0 = __pop_Variant32(__symbols); let __start = __sym0.0.clone(); let __end = __sym0.2.clone(); let __nt = super::__action322::<>(text, __sym0); __symbols.push((__start, __Symbol::Variant59(__nt), __end)); (1, 82) } pub(crate) fn __reduce176< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // Comma = => ActionFn(323); let __start = __symbols.last().map(|s| s.2.clone()).unwrap_or_default(); let __end = __lookahead_start.cloned().unwrap_or_else(|| __start.clone()); let __nt = super::__action323::<>(text, &__start, &__end); __symbols.push((__start, __Symbol::Variant59(__nt), __end)); (0, 82) } pub(crate) fn __reduce177< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // Comma = ( ",")+, PatternBinaryElem => ActionFn(324); let __sym1 = __pop_Variant32(__symbols); let __sym0 = __pop_Variant33(__symbols); let __start = __sym0.0.clone(); let __end = __sym1.2.clone(); let __nt = super::__action324::<>(text, __sym0, __sym1); __symbols.push((__start, __Symbol::Variant59(__nt), __end)); (2, 82) } pub(crate) fn __reduce178< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // Comma = ( ",")+ => ActionFn(325); let __sym0 = __pop_Variant33(__symbols); let __start = __sym0.0.clone(); let __end = __sym0.2.clone(); let __nt = super::__action325::<>(text, __sym0); __symbols.push((__start, __Symbol::Variant59(__nt), __end)); (1, 82) } pub(crate) fn __reduce179< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // Constant = "{", Comma, "}" => ActionFn(55); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant56(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0.clone(); let __end = __sym2.2.clone(); let __nt = super::__action55::<>(text, __sym0, __sym1, __sym2); __symbols.push((__start, __Symbol::Variant24(__nt), __end)); (3, 83) } pub(crate) fn __reduce180< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // Constant = "[", Comma, "|", Constant, "]" => ActionFn(206); let __sym4 = __pop_Variant0(__symbols); let __sym3 = __pop_Variant24(__symbols); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant56(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0.clone(); let __end = __sym4.2.clone(); let __nt = super::__action206::<>(text, __sym0, __sym1, __sym2, __sym3, __sym4); __symbols.push((__start, __Symbol::Variant24(__nt), __end)); (5, 83) } pub(crate) fn __reduce181< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // Constant = "[", Comma, "]" => ActionFn(207); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant56(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0.clone(); let __end = __sym2.2.clone(); let __nt = super::__action207::<>(text, __sym0, __sym1, __sym2); __symbols.push((__start, __Symbol::Variant24(__nt), __end)); (3, 83) } pub(crate) fn __reduce182< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // Constant = AtomicTerm => ActionFn(57); let __sym0 = __pop_Variant46(__symbols); let __start = __sym0.0.clone(); let __end = __sym0.2.clone(); let __nt = super::__action57::<>(text, __sym0); __symbols.push((__start, __Symbol::Variant24(__nt), __end)); (1, 83) } pub(crate) fn __reduce183< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // Constant? = Constant => ActionFn(170); let __sym0 = __pop_Variant24(__symbols); let __start = __sym0.0.clone(); let __end = __sym0.2.clone(); let __nt = super::__action170::<>(text, __sym0); __symbols.push((__start, __Symbol::Variant60(__nt), __end)); (1, 84) } pub(crate) fn __reduce184< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // Constant? = => ActionFn(171); let __start = __symbols.last().map(|s| s.2.clone()).unwrap_or_default(); let __end = __lookahead_start.cloned().unwrap_or_else(|| __start.clone()); let __nt = super::__action171::<>(text, &__start, &__end); __symbols.push((__start, __Symbol::Variant60(__nt), __end)); (0, 84) } pub(crate) fn __reduce185< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // ConstantList = "[", Comma, "|", Constant, "]" => ActionFn(208); let __sym4 = __pop_Variant0(__symbols); let __sym3 = __pop_Variant24(__symbols); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant56(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0.clone(); let __end = __sym4.2.clone(); let __nt = super::__action208::<>(text, __sym0, __sym1, __sym2, __sym3, __sym4); __symbols.push((__start, __Symbol::Variant44(__nt), __end)); (5, 85) } pub(crate) fn __reduce186< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // ConstantList = "[", Comma, "]" => ActionFn(209); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant56(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0.clone(); let __end = __sym2.2.clone(); let __nt = super::__action209::<>(text, __sym0, __sym1, __sym2); __symbols.push((__start, __Symbol::Variant44(__nt), __end)); (3, 85) } pub(crate) fn __reduce187< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // ConstantTuple = "{", Comma, "}" => ActionFn(62); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant56(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0.clone(); let __end = __sym2.2.clone(); let __nt = super::__action62::<>(text, __sym0, __sym1, __sym2); __symbols.push((__start, __Symbol::Variant44(__nt), __end)); (3, 86) } pub(crate) fn __reduce188< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // ExactAssoc = ":=" => ActionFn(11); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0.clone(); let __end = __sym0.2.clone(); let __nt = super::__action11::<>(text, __sym0); __symbols.push((__start, __Symbol::Variant61(__nt), __end)); (1, 87) } pub(crate) fn __reduce189< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // ExactAssoc = "=>" => ActionFn(12); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0.clone(); let __end = __sym0.2.clone(); let __nt = super::__action12::<>(text, __sym0); __symbols.push((__start, __Symbol::Variant61(__nt), __end)); (1, 87) } pub(crate) fn __reduce190< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // Expression = Annotated => ActionFn(13); let __sym0 = __pop_Variant41(__symbols); let __start = __sym0.0.clone(); let __end = __sym0.2.clone(); let __nt = super::__action13::<>(text, __sym0); __symbols.push((__start, __Symbol::Variant6(__nt), __end)); (1, 88) } pub(crate) fn __reduce191< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // Expression = Annotated => ActionFn(14); let __sym0 = __pop_Variant14(__symbols); let __start = __sym0.0.clone(); let __end = __sym0.2.clone(); let __nt = super::__action14::<>(text, __sym0); __symbols.push((__start, __Symbol::Variant6(__nt), __end)); (1, 88) } pub(crate) fn __reduce192< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // Expression? = Expression => ActionFn(138); let __sym0 = __pop_Variant6(__symbols); let __start = __sym0.0.clone(); let __end = __sym0.2.clone(); let __nt = super::__action138::<>(text, __sym0); __symbols.push((__start, __Symbol::Variant7(__nt), __end)); (1, 89) } pub(crate) fn __reduce193< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // Expression? = => ActionFn(139); let __start = __symbols.last().map(|s| s.2.clone()).unwrap_or_default(); let __end = __lookahead_start.cloned().unwrap_or_else(|| __start.clone()); let __nt = super::__action139::<>(text, &__start, &__end); __symbols.push((__start, __Symbol::Variant7(__nt), __end)); (0, 89) } pub(crate) fn __reduce194< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // Fun = "fun", "(", Comma>, ")", "->", Expression => ActionFn(10); let __sym5 = __pop_Variant6(__symbols); let __sym4 = __pop_Variant0(__symbols); let __sym3 = __pop_Variant0(__symbols); let __sym2 = __pop_Variant53(__symbols); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0.clone(); let __end = __sym5.2.clone(); let __nt = super::__action10::<>(text, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5); __symbols.push((__start, __Symbol::Variant62(__nt), __end)); (6, 90) } pub(crate) fn __reduce195< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // FunctionDefinition = Annotated, "=", Annotated => ActionFn(9); let __sym2 = __pop_Variant37(__symbols); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant38(__symbols); let __start = __sym0.0.clone(); let __end = __sym2.2.clone(); let __nt = super::__action9::<>(text, __sym0, __sym1, __sym2); __symbols.push((__start, __Symbol::Variant63(__nt), __end)); (3, 91) } pub(crate) fn __reduce196< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // FunctionDefinition* = => ActionFn(112); let __start = __symbols.last().map(|s| s.2.clone()).unwrap_or_default(); let __end = __lookahead_start.cloned().unwrap_or_else(|| __start.clone()); let __nt = super::__action112::<>(text, &__start, &__end); __symbols.push((__start, __Symbol::Variant64(__nt), __end)); (0, 92) } pub(crate) fn __reduce197< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // FunctionDefinition* = FunctionDefinition+ => ActionFn(113); let __sym0 = __pop_Variant64(__symbols); let __start = __sym0.0.clone(); let __end = __sym0.2.clone(); let __nt = super::__action113::<>(text, __sym0); __symbols.push((__start, __Symbol::Variant64(__nt), __end)); (1, 92) } pub(crate) fn __reduce198< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // FunctionDefinition+ = FunctionDefinition => ActionFn(116); let __sym0 = __pop_Variant63(__symbols); let __start = __sym0.0.clone(); let __end = __sym0.2.clone(); let __nt = super::__action116::<>(text, __sym0); __symbols.push((__start, __Symbol::Variant64(__nt), __end)); (1, 93) } pub(crate) fn __reduce199< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // FunctionDefinition+ = FunctionDefinition+, FunctionDefinition => ActionFn(117); let __sym1 = __pop_Variant63(__symbols); let __sym0 = __pop_Variant64(__symbols); let __start = __sym0.0.clone(); let __end = __sym1.2.clone(); let __nt = super::__action117::<>(text, __sym0, __sym1); __symbols.push((__start, __Symbol::Variant64(__nt), __end)); (2, 93) } pub(crate) fn __reduce200< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // FunctionName = Atom, "/", Integer => ActionFn(8); let __sym2 = __pop_Variant66(__symbols); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant45(__symbols); let __start = __sym0.0.clone(); let __end = __sym2.2.clone(); let __nt = super::__action8::<>(text, __sym0, __sym1, __sym2); __symbols.push((__start, __Symbol::Variant28(__nt), __end)); (3, 94) } pub(crate) fn __reduce201< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // FunctionName? = FunctionName => ActionFn(118); let __sym0 = __pop_Variant28(__symbols); let __start = __sym0.0.clone(); let __end = __sym0.2.clone(); let __nt = super::__action118::<>(text, __sym0); __symbols.push((__start, __Symbol::Variant65(__nt), __end)); (1, 95) } pub(crate) fn __reduce202< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // FunctionName? = => ActionFn(119); let __start = __symbols.last().map(|s| s.2.clone()).unwrap_or_default(); let __end = __lookahead_start.cloned().unwrap_or_else(|| __start.clone()); let __nt = super::__action119::<>(text, &__start, &__end); __symbols.push((__start, __Symbol::Variant65(__nt), __end)); (0, 95) } pub(crate) fn __reduce203< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // Guard = "when", Expression => ActionFn(36); let __sym1 = __pop_Variant6(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0.clone(); let __end = __sym1.2.clone(); let __nt = super::__action36::<>(text, __sym0, __sym1); __symbols.push((__start, __Symbol::Variant6(__nt), __end)); (2, 96) } pub(crate) fn __reduce204< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // Integer = "Integer" => ActionFn(1); let __sym0 = __pop_Variant3(__symbols); let __start = __sym0.0.clone(); let __end = __sym0.2.clone(); let __nt = super::__action1::<>(text, __sym0); __symbols.push((__start, __Symbol::Variant66(__nt), __end)); (1, 97) } pub(crate) fn __reduce205< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // Module = "module", Atom, ModuleFunctions, "attributes", ModuleAttributes, "end" => ActionFn(300); let __sym5 = __pop_Variant0(__symbols); let __sym4 = __pop_Variant50(__symbols); let __sym3 = __pop_Variant0(__symbols); let __sym2 = __pop_Variant58(__symbols); let __sym1 = __pop_Variant45(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0.clone(); let __end = __sym5.2.clone(); let __nt = super::__action300::<>(text, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5); __symbols.push((__start, __Symbol::Variant67(__nt), __end)); (6, 98) } pub(crate) fn __reduce206< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // Module = "module", Atom, ModuleFunctions, "attributes", ModuleAttributes, FunctionDefinition+, "end" => ActionFn(301); let __sym6 = __pop_Variant0(__symbols); let __sym5 = __pop_Variant64(__symbols); let __sym4 = __pop_Variant50(__symbols); let __sym3 = __pop_Variant0(__symbols); let __sym2 = __pop_Variant58(__symbols); let __sym1 = __pop_Variant45(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0.clone(); let __end = __sym6.2.clone(); let __nt = super::__action301::<>(text, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6); __symbols.push((__start, __Symbol::Variant67(__nt), __end)); (7, 98) } pub(crate) fn __reduce207< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // ModuleAttributes = "[", Comma<( "=" )>, "]" => ActionFn(7); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant50(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0.clone(); let __end = __sym2.2.clone(); let __nt = super::__action7::<>(text, __sym0, __sym1, __sym2); __symbols.push((__start, __Symbol::Variant50(__nt), __end)); (3, 99) } pub(crate) fn __reduce208< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // ModuleFunctions = "[", Comma, "]" => ActionFn(6); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant58(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0.clone(); let __end = __sym2.2.clone(); let __nt = super::__action6::<>(text, __sym0, __sym1, __sym2); __symbols.push((__start, __Symbol::Variant58(__nt), __end)); (3, 100) } pub(crate) fn __reduce209< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // Pattern = Annotated, "=", AnnotatedPattern => ActionFn(44); let __sym2 = __pop_Variant4(__symbols); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant16(__symbols); let __start = __sym0.0.clone(); let __end = __sym2.2.clone(); let __nt = super::__action44::<>(text, __sym0, __sym1, __sym2); __symbols.push((__start, __Symbol::Variant68(__nt), __end)); (3, 101) } pub(crate) fn __reduce210< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // Pattern = Variable => ActionFn(45); let __sym0 = __pop_Variant45(__symbols); let __start = __sym0.0.clone(); let __end = __sym0.2.clone(); let __nt = super::__action45::<>(text, __sym0); __symbols.push((__start, __Symbol::Variant68(__nt), __end)); (1, 101) } pub(crate) fn __reduce211< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // Pattern = AtomicTerm => ActionFn(46); let __sym0 = __pop_Variant46(__symbols); let __start = __sym0.0.clone(); let __end = __sym0.2.clone(); let __nt = super::__action46::<>(text, __sym0); __symbols.push((__start, __Symbol::Variant68(__nt), __end)); (1, 101) } pub(crate) fn __reduce212< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // Pattern = PatternBinary => ActionFn(47); let __sym0 = __pop_Variant59(__symbols); let __start = __sym0.0.clone(); let __end = __sym0.2.clone(); let __nt = super::__action47::<>(text, __sym0); __symbols.push((__start, __Symbol::Variant68(__nt), __end)); (1, 101) } pub(crate) fn __reduce213< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // Pattern = "{", Comma, "}" => ActionFn(48); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant54(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0.clone(); let __end = __sym2.2.clone(); let __nt = super::__action48::<>(text, __sym0, __sym1, __sym2); __symbols.push((__start, __Symbol::Variant68(__nt), __end)); (3, 101) } pub(crate) fn __reduce214< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // Pattern = "~{", Comma, "}~" => ActionFn(49); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant55(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0.clone(); let __end = __sym2.2.clone(); let __nt = super::__action49::<>(text, __sym0, __sym1, __sym2); __symbols.push((__start, __Symbol::Variant68(__nt), __end)); (3, 101) } pub(crate) fn __reduce215< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // Pattern = "[", Comma, "|", AnnotatedPattern, "]" => ActionFn(198); let __sym4 = __pop_Variant0(__symbols); let __sym3 = __pop_Variant4(__symbols); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant54(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0.clone(); let __end = __sym4.2.clone(); let __nt = super::__action198::<>(text, __sym0, __sym1, __sym2, __sym3, __sym4); __symbols.push((__start, __Symbol::Variant68(__nt), __end)); (5, 101) } pub(crate) fn __reduce216< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // Pattern = "[", Comma, "]" => ActionFn(199); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant54(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0.clone(); let __end = __sym2.2.clone(); let __nt = super::__action199::<>(text, __sym0, __sym1, __sym2); __symbols.push((__start, __Symbol::Variant68(__nt), __end)); (3, 101) } pub(crate) fn __reduce217< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // PatternBinary = "#{", Comma, "}#" => ActionFn(51); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant59(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0.clone(); let __end = __sym2.2.clone(); let __nt = super::__action51::<>(text, __sym0, __sym1, __sym2); __symbols.push((__start, __Symbol::Variant59(__nt), __end)); (3, 102) } pub(crate) fn __reduce218< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // PatternBinaryElem = "#<", AnnotatedPattern, ">(", Comma>, ")" => ActionFn(52); let __sym4 = __pop_Variant0(__symbols); let __sym3 = __pop_Variant52(__symbols); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant4(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0.clone(); let __end = __sym4.2.clone(); let __nt = super::__action52::<>(text, __sym0, __sym1, __sym2, __sym3, __sym4); __symbols.push((__start, __Symbol::Variant32(__nt), __end)); (5, 103) } pub(crate) fn __reduce219< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // PatternBinaryElem? = PatternBinaryElem => ActionFn(160); let __sym0 = __pop_Variant32(__symbols); let __start = __sym0.0.clone(); let __end = __sym0.2.clone(); let __nt = super::__action160::<>(text, __sym0); __symbols.push((__start, __Symbol::Variant69(__nt), __end)); (1, 104) } pub(crate) fn __reduce220< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // PatternBinaryElem? = => ActionFn(161); let __start = __symbols.last().map(|s| s.2.clone()).unwrap_or_default(); let __end = __lookahead_start.cloned().unwrap_or_else(|| __start.clone()); let __nt = super::__action161::<>(text, &__start, &__end); __symbols.push((__start, __Symbol::Variant69(__nt), __end)); (0, 104) } pub(crate) fn __reduce221< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // PatternMapEntry = Annotated, ":=", AnnotatedPattern => ActionFn(42); let __sym2 = __pop_Variant4(__symbols); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant14(__symbols); let __start = __sym0.0.clone(); let __end = __sym2.2.clone(); let __nt = super::__action42::<>(text, __sym0, __sym1, __sym2); __symbols.push((__start, __Symbol::Variant70(__nt), __end)); (3, 105) } pub(crate) fn __reduce222< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // Patterns = AnnotatedPattern => ActionFn(39); let __sym0 = __pop_Variant4(__symbols); let __start = __sym0.0.clone(); let __end = __sym0.2.clone(); let __nt = super::__action39::<>(text, __sym0); __symbols.push((__start, __Symbol::Variant54(__nt), __end)); (1, 106) } pub(crate) fn __reduce223< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // Patterns = "<", Comma, ">" => ActionFn(40); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant54(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0.clone(); let __end = __sym2.2.clone(); let __nt = super::__action40::<>(text, __sym0, __sym1, __sym2); __symbols.push((__start, __Symbol::Variant54(__nt), __end)); (3, 106) } pub(crate) fn __reduce224< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // SingleExpression = "[", Comma, "|", Expression, "]" => ActionFn(201); let __sym4 = __pop_Variant0(__symbols); let __sym3 = __pop_Variant6(__symbols); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant57(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0.clone(); let __end = __sym4.2.clone(); let __nt = super::__action201::<>(text, __sym0, __sym1, __sym2, __sym3, __sym4); __symbols.push((__start, __Symbol::Variant71(__nt), __end)); (5, 107) } pub(crate) fn __reduce225< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // SingleExpression = "[", Comma, "]" => ActionFn(202); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant57(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0.clone(); let __end = __sym2.2.clone(); let __nt = super::__action202::<>(text, __sym0, __sym1, __sym2); __symbols.push((__start, __Symbol::Variant71(__nt), __end)); (3, 107) } pub(crate) fn __reduce226< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // SingleExpression = FunctionName => ActionFn(17); let __sym0 = __pop_Variant28(__symbols); let __start = __sym0.0.clone(); let __end = __sym0.2.clone(); let __nt = super::__action17::<>(text, __sym0); __symbols.push((__start, __Symbol::Variant71(__nt), __end)); (1, 107) } pub(crate) fn __reduce227< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // SingleExpression = "fun", Atom, ":", FunctionName => ActionFn(18); let __sym3 = __pop_Variant28(__symbols); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant45(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0.clone(); let __end = __sym3.2.clone(); let __nt = super::__action18::<>(text, __sym0, __sym1, __sym2, __sym3); __symbols.push((__start, __Symbol::Variant71(__nt), __end)); (4, 107) } pub(crate) fn __reduce228< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // SingleExpression = AtomicTerm => ActionFn(19); let __sym0 = __pop_Variant46(__symbols); let __start = __sym0.0.clone(); let __end = __sym0.2.clone(); let __nt = super::__action19::<>(text, __sym0); __symbols.push((__start, __Symbol::Variant71(__nt), __end)); (1, 107) } pub(crate) fn __reduce229< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // SingleExpression = Variable => ActionFn(20); let __sym0 = __pop_Variant45(__symbols); let __start = __sym0.0.clone(); let __end = __sym0.2.clone(); let __nt = super::__action20::<>(text, __sym0); __symbols.push((__start, __Symbol::Variant71(__nt), __end)); (1, 107) } pub(crate) fn __reduce230< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // SingleExpression = Binary => ActionFn(21); let __sym0 = __pop_Variant47(__symbols); let __start = __sym0.0.clone(); let __end = __sym0.2.clone(); let __nt = super::__action21::<>(text, __sym0); __symbols.push((__start, __Symbol::Variant71(__nt), __end)); (1, 107) } pub(crate) fn __reduce231< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // SingleExpression = "{", Comma, "}" => ActionFn(22); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant57(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0.clone(); let __end = __sym2.2.clone(); let __nt = super::__action22::<>(text, __sym0, __sym1, __sym2); __symbols.push((__start, __Symbol::Variant71(__nt), __end)); (3, 107) } pub(crate) fn __reduce232< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // SingleExpression = "~{", Comma )>>, "|", Expression, "}~" => ActionFn(203); let __sym4 = __pop_Variant0(__symbols); let __sym3 = __pop_Variant6(__symbols); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant51(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0.clone(); let __end = __sym4.2.clone(); let __nt = super::__action203::<>(text, __sym0, __sym1, __sym2, __sym3, __sym4); __symbols.push((__start, __Symbol::Variant71(__nt), __end)); (5, 107) } pub(crate) fn __reduce233< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // SingleExpression = "~{", Comma )>>, "}~" => ActionFn(204); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant51(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0.clone(); let __end = __sym2.2.clone(); let __nt = super::__action204::<>(text, __sym0, __sym1, __sym2); __symbols.push((__start, __Symbol::Variant71(__nt), __end)); (3, 107) } pub(crate) fn __reduce234< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // SingleExpression = "let", Variables, "=", Expression, "in", Expression => ActionFn(24); let __sym5 = __pop_Variant6(__symbols); let __sym4 = __pop_Variant0(__symbols); let __sym3 = __pop_Variant6(__symbols); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant53(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0.clone(); let __end = __sym5.2.clone(); let __nt = super::__action24::<>(text, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5); __symbols.push((__start, __Symbol::Variant71(__nt), __end)); (6, 107) } pub(crate) fn __reduce235< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // SingleExpression = "call", Expression, ":", Expression, "(", Comma, ")" => ActionFn(25); let __sym6 = __pop_Variant0(__symbols); let __sym5 = __pop_Variant57(__symbols); let __sym4 = __pop_Variant0(__symbols); let __sym3 = __pop_Variant6(__symbols); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant6(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0.clone(); let __end = __sym6.2.clone(); let __nt = super::__action25::<>(text, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6); __symbols.push((__start, __Symbol::Variant71(__nt), __end)); (7, 107) } pub(crate) fn __reduce236< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // SingleExpression = "catch", Expression => ActionFn(26); let __sym1 = __pop_Variant6(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0.clone(); let __end = __sym1.2.clone(); let __nt = super::__action26::<>(text, __sym0, __sym1); __symbols.push((__start, __Symbol::Variant71(__nt), __end)); (2, 107) } pub(crate) fn __reduce237< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // SingleExpression = "case", Expression, "of", "end" => ActionFn(268); let __sym3 = __pop_Variant0(__symbols); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant6(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0.clone(); let __end = __sym3.2.clone(); let __nt = super::__action268::<>(text, __sym0, __sym1, __sym2, __sym3); __symbols.push((__start, __Symbol::Variant71(__nt), __end)); (4, 107) } pub(crate) fn __reduce238< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // SingleExpression = "case", Expression, "of", Annotated+, "end" => ActionFn(269); let __sym4 = __pop_Variant0(__symbols); let __sym3 = __pop_Variant36(__symbols); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant6(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0.clone(); let __end = __sym4.2.clone(); let __nt = super::__action269::<>(text, __sym0, __sym1, __sym2, __sym3, __sym4); __symbols.push((__start, __Symbol::Variant71(__nt), __end)); (5, 107) } pub(crate) fn __reduce239< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // SingleExpression = "primop", Annotated, "(", Comma, ")" => ActionFn(28); let __sym4 = __pop_Variant0(__symbols); let __sym3 = __pop_Variant57(__symbols); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant16(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0.clone(); let __end = __sym4.2.clone(); let __nt = super::__action28::<>(text, __sym0, __sym1, __sym2, __sym3, __sym4); __symbols.push((__start, __Symbol::Variant71(__nt), __end)); (5, 107) } pub(crate) fn __reduce240< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // SingleExpression = "do", Expression, Expression => ActionFn(29); let __sym2 = __pop_Variant6(__symbols); let __sym1 = __pop_Variant6(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0.clone(); let __end = __sym2.2.clone(); let __nt = super::__action29::<>(text, __sym0, __sym1, __sym2); __symbols.push((__start, __Symbol::Variant71(__nt), __end)); (3, 107) } pub(crate) fn __reduce241< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // SingleExpression = "apply", Expression, "(", Comma, ")" => ActionFn(30); let __sym4 = __pop_Variant0(__symbols); let __sym3 = __pop_Variant57(__symbols); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant6(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0.clone(); let __end = __sym4.2.clone(); let __nt = super::__action30::<>(text, __sym0, __sym1, __sym2, __sym3, __sym4); __symbols.push((__start, __Symbol::Variant71(__nt), __end)); (5, 107) } pub(crate) fn __reduce242< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // SingleExpression = "try", Expression, "of", Variables, "->", Expression, "catch", Variables, "->", Expression => ActionFn(31); let __sym9 = __pop_Variant6(__symbols); let __sym8 = __pop_Variant0(__symbols); let __sym7 = __pop_Variant53(__symbols); let __sym6 = __pop_Variant0(__symbols); let __sym5 = __pop_Variant6(__symbols); let __sym4 = __pop_Variant0(__symbols); let __sym3 = __pop_Variant53(__symbols); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant6(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0.clone(); let __end = __sym9.2.clone(); let __nt = super::__action31::<>(text, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6, __sym7, __sym8, __sym9); __symbols.push((__start, __Symbol::Variant71(__nt), __end)); (10, 107) } pub(crate) fn __reduce243< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // SingleExpression = "receive", "after", Expression, "->", Expression => ActionFn(270); let __sym4 = __pop_Variant6(__symbols); let __sym3 = __pop_Variant0(__symbols); let __sym2 = __pop_Variant6(__symbols); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0.clone(); let __end = __sym4.2.clone(); let __nt = super::__action270::<>(text, __sym0, __sym1, __sym2, __sym3, __sym4); __symbols.push((__start, __Symbol::Variant71(__nt), __end)); (5, 107) } pub(crate) fn __reduce244< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // SingleExpression = "receive", Annotated+, "after", Expression, "->", Expression => ActionFn(271); let __sym5 = __pop_Variant6(__symbols); let __sym4 = __pop_Variant0(__symbols); let __sym3 = __pop_Variant6(__symbols); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant36(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0.clone(); let __end = __sym5.2.clone(); let __nt = super::__action271::<>(text, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5); __symbols.push((__start, __Symbol::Variant71(__nt), __end)); (6, 107) } pub(crate) fn __reduce245< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // SingleExpression = Fun => ActionFn(33); let __sym0 = __pop_Variant62(__symbols); let __start = __sym0.0.clone(); let __end = __sym0.2.clone(); let __nt = super::__action33::<>(text, __sym0); __symbols.push((__start, __Symbol::Variant71(__nt), __end)); (1, 107) } pub(crate) fn __reduce246< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // SingleExpression = "letrec", ( "=" )+, "in", Expression => ActionFn(34); let __sym3 = __pop_Variant6(__symbols); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant31(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0.clone(); let __end = __sym3.2.clone(); let __nt = super::__action34::<>(text, __sym0, __sym1, __sym2, __sym3); __symbols.push((__start, __Symbol::Variant71(__nt), __end)); (4, 107) } pub(crate) fn __reduce247< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // ValueList = "<", Comma>, ">" => ActionFn(15); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant52(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0.clone(); let __end = __sym2.2.clone(); let __nt = super::__action15::<>(text, __sym0, __sym1, __sym2); __symbols.push((__start, __Symbol::Variant52(__nt), __end)); (3, 108) } pub(crate) fn __reduce248< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // Variable = "Variable" => ActionFn(3); let __sym0 = __pop_Variant1(__symbols); let __start = __sym0.0.clone(); let __end = __sym0.2.clone(); let __nt = super::__action3::<>(text, __sym0); __symbols.push((__start, __Symbol::Variant45(__nt), __end)); (1, 109) } pub(crate) fn __reduce249< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // Variables = Annotated => ActionFn(37); let __sym0 = __pop_Variant16(__symbols); let __start = __sym0.0.clone(); let __end = __sym0.2.clone(); let __nt = super::__action37::<>(text, __sym0); __symbols.push((__start, __Symbol::Variant53(__nt), __end)); (1, 110) } pub(crate) fn __reduce250< 'input, >( text: &'input str, __action: i16, __lookahead_start: Option<&usize>, __states: &mut ::std::vec::Vec, __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, _: ::std::marker::PhantomData<(&'input ())>, ) -> (usize, usize) { // Variables = "<", Comma>, ">" => ActionFn(38); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant53(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0.clone(); let __end = __sym2.2.clone(); let __nt = super::__action38::<>(text, __sym0, __sym1, __sym2); __symbols.push((__start, __Symbol::Variant53(__nt), __end)); (3, 110) } } pub use self::__parse__AnnotatedModule::AnnotatedModuleParser; #[allow(unused_variables)] fn __action0< 'input, >( text: &'input str, (_, __0, _): (usize, Annotated, usize), ) -> Annotated { (__0) } #[allow(unused_variables)] fn __action1< 'input, >( text: &'input str, (_, i, _): (usize, (bool, &'input str), usize), ) -> BigInt { { let mut num = BigInt::parse_bytes(i.1.as_bytes(), 10).unwrap(); if !i.0 { num = -num; } num } } #[allow(unused_variables)] fn __action2< 'input, >( text: &'input str, (_, __0, _): (usize, &'input str, usize), ) -> Atom { Atom::from_str(__0) } #[allow(unused_variables)] fn __action3< 'input, >( text: &'input str, (_, __0, _): (usize, &'input str, usize), ) -> Atom { Atom::from_str(__0) } #[allow(unused_variables)] fn __action4< 'input, >( text: &'input str, (_, __0, _): (usize, Annotated, usize), ) -> Annotated { __0 } #[allow(unused_variables)] fn __action5< 'input, >( text: &'input str, (_, _, _): (usize, Tok<'input>, usize), (_, module_name, _): (usize, Atom, usize), (_, functions, _): (usize, Vec, usize), (_, _, _): (usize, Tok<'input>, usize), (_, attributes, _): (usize, Vec<(Atom, Constant)>, usize), (_, definitions, _): (usize, ::std::vec::Vec, usize), (_, _, _): (usize, Tok<'input>, usize), ) -> Module { Module { name: module_name, declarations: functions, attributes: attributes, definitions: definitions, } } #[allow(unused_variables)] fn __action6< 'input, >( text: &'input str, (_, _, _): (usize, Tok<'input>, usize), (_, n, _): (usize, Vec, usize), (_, _, _): (usize, Tok<'input>, usize), ) -> Vec { n } #[allow(unused_variables)] fn __action7< 'input, >( text: &'input str, (_, _, _): (usize, Tok<'input>, usize), (_, __0, _): (usize, Vec<(Atom, Constant)>, usize), (_, _, _): (usize, Tok<'input>, usize), ) -> Vec<(Atom, Constant)> { (__0) } #[allow(unused_variables)] fn __action8< 'input, >( text: &'input str, (_, a, _): (usize, Atom, usize), (_, _, _): (usize, Tok<'input>, usize), (_, i, _): (usize, BigInt, usize), ) -> FunctionName { FunctionName { name: a, arity: i.to_usize().unwrap() } } #[allow(unused_variables)] fn __action9< 'input, >( text: &'input str, (_, n, _): (usize, Annotated, usize), (_, _, _): (usize, Tok<'input>, usize), (_, f, _): (usize, Annotated, usize), ) -> FunctionDefinition { FunctionDefinition { name: n, fun: f } } #[allow(unused_variables)] fn __action10< 'input, >( text: &'input str, (_, _, _): (usize, Tok<'input>, usize), (_, _, _): (usize, Tok<'input>, usize), (_, a, _): (usize, Vec>, usize), (_, _, _): (usize, Tok<'input>, usize), (_, _, _): (usize, Tok<'input>, usize), (_, e, _): (usize, Expression, usize), ) -> Function { Function { vars: a, body: e } } #[allow(unused_variables)] fn __action11< 'input, >( text: &'input str, (_, __0, _): (usize, Tok<'input>, usize), ) -> MapExactAssoc { MapExactAssoc::Exact } #[allow(unused_variables)] fn __action12< 'input, >( text: &'input str, (_, __0, _): (usize, Tok<'input>, usize), ) -> MapExactAssoc { MapExactAssoc::Assoc } #[allow(unused_variables)] fn __action13< 'input, >( text: &'input str, (_, a, _): (usize, Annotated>>, usize), ) -> Expression { a } #[allow(unused_variables)] fn __action14< 'input, >( text: &'input str, (_, s, _): (usize, Annotated, usize), ) -> Expression { Annotated::empty(vec![s]) } #[allow(unused_variables)] fn __action15< 'input, >( text: &'input str, (_, _, _): (usize, Tok<'input>, usize), (_, __0, _): (usize, Vec>, usize), (_, _, _): (usize, Tok<'input>, usize), ) -> Vec> { __0 } #[allow(unused_variables)] fn __action16< 'input, >( text: &'input str, (_, _, _): (usize, Tok<'input>, usize), (_, e, _): (usize, Vec, usize), (_, t, _): (usize, ::std::option::Option, usize), (_, _, _): (usize, Tok<'input>, usize), ) -> SingleExpression { SingleExpression::List { head: e, tail: Box::new(t.unwrap_or(Expression::nil())) } } #[allow(unused_variables)] fn __action17< 'input, >( text: &'input str, (_, __0, _): (usize, FunctionName, usize), ) -> SingleExpression { SingleExpression::FunctionName(__0) } #[allow(unused_variables)] fn __action18< 'input, >( text: &'input str, (_, _, _): (usize, Tok<'input>, usize), (_, m, _): (usize, Atom, usize), (_, _, _): (usize, Tok<'input>, usize), (_, f, _): (usize, FunctionName, usize), ) -> SingleExpression { SingleExpression::ExternalFunctionName { module: m, name:f } } #[allow(unused_variables)] fn __action19< 'input, >( text: &'input str, (_, a, _): (usize, AtomicTerm, usize), ) -> SingleExpression { SingleExpression::AtomicLiteral(a) } #[allow(unused_variables)] fn __action20< 'input, >( text: &'input str, (_, v, _): (usize, Atom, usize), ) -> SingleExpression { SingleExpression::Variable(v) } #[allow(unused_variables)] fn __action21< 'input, >( text: &'input str, (_, b, _): (usize, Vec<(Expression, Vec)>, usize), ) -> SingleExpression { SingleExpression::Binary(b) } #[allow(unused_variables)] fn __action22< 'input, >( text: &'input str, (_, _, _): (usize, Tok<'input>, usize), (_, t, _): (usize, Vec, usize), (_, _, _): (usize, Tok<'input>, usize), ) -> SingleExpression { SingleExpression::Tuple(t) } #[allow(unused_variables)] fn __action23< 'input, >( text: &'input str, (_, _, _): (usize, Tok<'input>, usize), (_, v, _): (usize, Vec>, usize), (_, m, _): (usize, ::std::option::Option, usize), (_, _, _): (usize, Tok<'input>, usize), ) -> SingleExpression { SingleExpression::Map(v, m) } #[allow(unused_variables)] fn __action24< 'input, >( text: &'input str, (_, _, _): (usize, Tok<'input>, usize), (_, v, _): (usize, Vec>, usize), (_, _, _): (usize, Tok<'input>, usize), (_, e, _): (usize, Expression, usize), (_, _, _): (usize, Tok<'input>, usize), (_, i, _): (usize, Expression, usize), ) -> SingleExpression { SingleExpression::Let { vars: v, val: Box::new(e), body: Box::new(i) } } #[allow(unused_variables)] fn __action25< 'input, >( text: &'input str, (_, _, _): (usize, Tok<'input>, usize), (_, a, _): (usize, Expression, usize), (_, _, _): (usize, Tok<'input>, usize), (_, b, _): (usize, Expression, usize), (_, _, _): (usize, Tok<'input>, usize), (_, c, _): (usize, Vec, usize), (_, _, _): (usize, Tok<'input>, usize), ) -> SingleExpression { SingleExpression::InterModuleCall { module: Box::new(a), name: Box::new(b), args: c } } #[allow(unused_variables)] fn __action26< 'input, >( text: &'input str, (_, _, _): (usize, Tok<'input>, usize), (_, e, _): (usize, Expression, usize), ) -> SingleExpression { SingleExpression::Catch(Box::new(e)) } #[allow(unused_variables)] fn __action27< 'input, >( text: &'input str, (_, _, _): (usize, Tok<'input>, usize), (_, e, _): (usize, Expression, usize), (_, _, _): (usize, Tok<'input>, usize), (_, a, _): (usize, ::std::vec::Vec>, usize), (_, _, _): (usize, Tok<'input>, usize), ) -> SingleExpression { SingleExpression::Case { val: Box::new(e), clauses: a } } #[allow(unused_variables)] fn __action28< 'input, >( text: &'input str, (_, _, _): (usize, Tok<'input>, usize), (_, n, _): (usize, Annotated, usize), (_, _, _): (usize, Tok<'input>, usize), (_, a, _): (usize, Vec, usize), (_, _, _): (usize, Tok<'input>, usize), ) -> SingleExpression { SingleExpression::PrimOpCall(PrimOpCall { name: n, args: a }) } #[allow(unused_variables)] fn __action29< 'input, >( text: &'input str, (_, _, _): (usize, Tok<'input>, usize), (_, e1, _): (usize, Expression, usize), (_, e2, _): (usize, Expression, usize), ) -> SingleExpression { SingleExpression::Do(Box::new(e1), Box::new(e2)) } #[allow(unused_variables)] fn __action30< 'input, >( text: &'input str, (_, _, _): (usize, Tok<'input>, usize), (_, f, _): (usize, Expression, usize), (_, _, _): (usize, Tok<'input>, usize), (_, a, _): (usize, Vec, usize), (_, _, _): (usize, Tok<'input>, usize), ) -> SingleExpression { SingleExpression::ApplyCall { fun: Box::new(f), args: a } } #[allow(unused_variables)] fn __action31< 'input, >( text: &'input str, (_, _, _): (usize, Tok<'input>, usize), (_, t, _): (usize, Expression, usize), (_, _, _): (usize, Tok<'input>, usize), (_, av, _): (usize, Vec>, usize), (_, _, _): (usize, Tok<'input>, usize), (_, a, _): (usize, Expression, usize), (_, _, _): (usize, Tok<'input>, usize), (_, cv, _): (usize, Vec>, usize), (_, _, _): (usize, Tok<'input>, usize), (_, c, _): (usize, Expression, usize), ) -> SingleExpression { SingleExpression::Try { body: Box::new(t), then_vars: av, then: Box::new(a), catch_vars: cv, catch: Box::new(c) } } #[allow(unused_variables)] fn __action32< 'input, >( text: &'input str, (_, _, _): (usize, Tok<'input>, usize), (_, c, _): (usize, ::std::vec::Vec>, usize), (_, _, _): (usize, Tok<'input>, usize), (_, t, _): (usize, Expression, usize), (_, _, _): (usize, Tok<'input>, usize), (_, b, _): (usize, Expression, usize), ) -> SingleExpression { SingleExpression::Receive { clauses: c, timeout_time: Box::new(t), timeout_body: Box::new(b) } } #[allow(unused_variables)] fn __action33< 'input, >( text: &'input str, (_, f, _): (usize, Function, usize), ) -> SingleExpression { SingleExpression::Fun(Box::new(f)) } #[allow(unused_variables)] fn __action34< 'input, >( text: &'input str, (_, _, _): (usize, Tok<'input>, usize), (_, f, _): (usize, ::std::vec::Vec<(FunctionName, Function)>, usize), (_, _, _): (usize, Tok<'input>, usize), (_, e, _): (usize, Expression, usize), ) -> SingleExpression { SingleExpression::LetRec { funs: f, body: Box::new(e) } } #[allow(unused_variables)] fn __action35< 'input, >( text: &'input str, (_, p, _): (usize, Vec>, usize), (_, g, _): (usize, Expression, usize), (_, _, _): (usize, Tok<'input>, usize), (_, b, _): (usize, Expression, usize), ) -> CaseClause { CaseClause { patterns: p, guard: g, body: b } } #[allow(unused_variables)] fn __action36< 'input, >( text: &'input str, (_, _, _): (usize, Tok<'input>, usize), (_, __0, _): (usize, Expression, usize), ) -> Expression { __0 } #[allow(unused_variables)] fn __action37< 'input, >( text: &'input str, (_, a, _): (usize, Annotated, usize), ) -> Vec> { vec![a] } #[allow(unused_variables)] fn __action38< 'input, >( text: &'input str, (_, _, _): (usize, Tok<'input>, usize), (_, a, _): (usize, Vec>, usize), (_, _, _): (usize, Tok<'input>, usize), ) -> Vec> { a } #[allow(unused_variables)] fn __action39< 'input, >( text: &'input str, (_, p, _): (usize, Annotated, usize), ) -> Vec> { vec![p] } #[allow(unused_variables)] fn __action40< 'input, >( text: &'input str, (_, _, _): (usize, Tok<'input>, usize), (_, p, _): (usize, Vec>, usize), (_, _, _): (usize, Tok<'input>, usize), ) -> Vec> { p } #[allow(unused_variables)] fn __action41< 'input, >( text: &'input str, (_, p, _): (usize, Annotated, usize), ) -> Annotated { p } #[allow(unused_variables)] fn __action42< 'input, >( text: &'input str, (_, k, _): (usize, Annotated, usize), (_, _, _): (usize, Tok<'input>, usize), (_, v, _): (usize, Annotated, usize), ) -> (Annotated, Annotated) { (k, v) } #[allow(unused_variables)] fn __action43< 'input, >( text: &'input str, (_, __0, _): (usize, Annotated<(Annotated, Annotated)>, usize), ) -> Annotated<(Annotated, Annotated)> { __0 } #[allow(unused_variables)] fn __action44< 'input, >( text: &'input str, (_, v, _): (usize, Annotated, usize), (_, _, _): (usize, Tok<'input>, usize), (_, p, _): (usize, Annotated, usize), ) -> Pattern { Pattern::BindVar(v, Box::new(p)) } #[allow(unused_variables)] fn __action45< 'input, >( text: &'input str, (_, v, _): (usize, Atom, usize), ) -> Pattern { Pattern::BindVar(Annotated::empty(v), Box::new(Annotated::empty(Pattern::Wildcard))) } #[allow(unused_variables)] fn __action46< 'input, >( text: &'input str, (_, a, _): (usize, AtomicTerm, usize), ) -> Pattern { Pattern::Atomic(a) } #[allow(unused_variables)] fn __action47< 'input, >( text: &'input str, (_, b, _): (usize, Vec<(Annotated, Vec>)>, usize), ) -> Pattern { Pattern::Binary(b) } #[allow(unused_variables)] fn __action48< 'input, >( text: &'input str, (_, _, _): (usize, Tok<'input>, usize), (_, t, _): (usize, Vec>, usize), (_, _, _): (usize, Tok<'input>, usize), ) -> Pattern { Pattern::Tuple(t) } #[allow(unused_variables)] fn __action49< 'input, >( text: &'input str, (_, _, _): (usize, Tok<'input>, usize), (_, m, _): (usize, Vec, Annotated)>>, usize), (_, _, _): (usize, Tok<'input>, usize), ) -> Pattern { Pattern::Map(m) } #[allow(unused_variables)] fn __action50< 'input, >( text: &'input str, (_, _, _): (usize, Tok<'input>, usize), (_, l, _): (usize, Vec>, usize), (_, t, _): (usize, ::std::option::Option>, usize), (_, _, _): (usize, Tok<'input>, usize), ) -> Pattern { Pattern::List(l, Box::new(t.unwrap_or(Pattern::nil()))) } #[allow(unused_variables)] fn __action51< 'input, >( text: &'input str, (_, _, _): (usize, Tok<'input>, usize), (_, b, _): (usize, Vec<(Annotated, Vec>)>, usize), (_, _, _): (usize, Tok<'input>, usize), ) -> Vec<(Annotated, Vec>)> { b } #[allow(unused_variables)] fn __action52< 'input, >( text: &'input str, (_, _, _): (usize, Tok<'input>, usize), (_, p, _): (usize, Annotated, usize), (_, _, _): (usize, Tok<'input>, usize), (_, a, _): (usize, Vec>, usize), (_, _, _): (usize, Tok<'input>, usize), ) -> (Annotated, Vec>) { (p, a) } #[allow(unused_variables)] fn __action53< 'input, >( text: &'input str, (_, _, _): (usize, Tok<'input>, usize), (_, b, _): (usize, Vec<(Expression, Vec)>, usize), (_, _, _): (usize, Tok<'input>, usize), ) -> Vec<(Expression, Vec)> { b } #[allow(unused_variables)] fn __action54< 'input, >( text: &'input str, (_, _, _): (usize, Tok<'input>, usize), (_, b, _): (usize, Expression, usize), (_, _, _): (usize, Tok<'input>, usize), (_, a, _): (usize, Vec, usize), (_, _, _): (usize, Tok<'input>, usize), ) -> (Expression, Vec) { (b, a) } #[allow(unused_variables)] fn __action55< 'input, >( text: &'input str, (_, __0, _): (usize, Tok<'input>, usize), (_, __1, _): (usize, Vec, usize), (_, __2, _): (usize, Tok<'input>, usize), ) -> Constant { Constant::Tuple(vec![]) } #[allow(unused_variables)] fn __action56< 'input, >( text: &'input str, (_, __0, _): (usize, Tok<'input>, usize), (_, __1, _): (usize, Vec, usize), (_, __2, _): (usize, ::std::option::Option<(Tok<'input>, Constant)>, usize), (_, __3, _): (usize, Tok<'input>, usize), ) -> Constant { Constant::List(vec![], Box::new(Constant::Atomic(AtomicTerm::Nil))) } #[allow(unused_variables)] fn __action57< 'input, >( text: &'input str, (_, __0, _): (usize, AtomicTerm, usize), ) -> Constant { Constant::Atomic(__0) } #[allow(unused_variables)] fn __action58< 'input, >( text: &'input str, (_, i, _): (usize, BigInt, usize), ) -> AtomicTerm { AtomicTerm::Integer(i) } #[allow(unused_variables)] fn __action59< 'input, >( text: &'input str, (_, a, _): (usize, Atom, usize), ) -> AtomicTerm { AtomicTerm::Atom(a) } #[allow(unused_variables)] fn __action60< 'input, >( text: &'input str, (_, c, _): (usize, char, usize), ) -> AtomicTerm { AtomicTerm::Char(c) } #[allow(unused_variables)] fn __action61< 'input, >( text: &'input str, (_, s, _): (usize, &'input str, usize), ) -> AtomicTerm { AtomicTerm::String(s.to_string()) } #[allow(unused_variables)] fn __action62< 'input, >( text: &'input str, (_, __0, _): (usize, Tok<'input>, usize), (_, __1, _): (usize, Vec, usize), (_, __2, _): (usize, Tok<'input>, usize), ) -> () { () } #[allow(unused_variables)] fn __action63< 'input, >( text: &'input str, (_, __0, _): (usize, Tok<'input>, usize), (_, __1, _): (usize, Vec, usize), (_, __2, _): (usize, ::std::option::Option<(Tok<'input>, Constant)>, usize), (_, __3, _): (usize, Tok<'input>, usize), ) -> () { () } #[allow(unused_variables)] fn __action64< 'input, >( text: &'input str, (_, _, _): (usize, Tok<'input>, usize), (_, _, _): (usize, Tok<'input>, usize), (_, c, _): (usize, Vec, usize), (_, _, _): (usize, Tok<'input>, usize), ) -> () { () } #[allow(unused_variables)] fn __action65< 'input, >( text: &'input str, (_, __0, _): (usize, (Tok<'input>, Constant), usize), ) -> ::std::option::Option<(Tok<'input>, Constant)> { Some(__0) } #[allow(unused_variables)] fn __action66< 'input, >( text: &'input str, __lookbehind: &usize, __lookahead: &usize, ) -> ::std::option::Option<(Tok<'input>, Constant)> { None } #[allow(unused_variables)] fn __action67< 'input, >( text: &'input str, (_, __0, _): (usize, Tok<'input>, usize), (_, __1, _): (usize, Constant, usize), ) -> (Tok<'input>, Constant) { (__0, __1) } #[allow(unused_variables)] fn __action68< 'input, >( text: &'input str, (_, rules, _): (usize, ::std::vec::Vec, usize), (_, last, _): (usize, ::std::option::Option, usize), ) -> Vec { { let mut rules = rules; rules.extend(last); rules } } #[allow(unused_variables)] fn __action69< 'input, >( text: &'input str, (_, rules, _): (usize, ::std::vec::Vec<(Expression, Vec)>, usize), (_, last, _): (usize, ::std::option::Option<(Expression, Vec)>, usize), ) -> Vec<(Expression, Vec)> { { let mut rules = rules; rules.extend(last); rules } } #[allow(unused_variables)] fn __action70< 'input, >( text: &'input str, (_, rules, _): (usize, ::std::vec::Vec<(Annotated, Vec>)>, usize), (_, last, _): (usize, ::std::option::Option<(Annotated, Vec>)>, usize), ) -> Vec<(Annotated, Vec>)> { { let mut rules = rules; rules.extend(last); rules } } #[allow(unused_variables)] fn __action71< 'input, >( text: &'input str, (_, __0, _): (usize, Annotated, usize), ) -> ::std::option::Option> { Some(__0) } #[allow(unused_variables)] fn __action72< 'input, >( text: &'input str, __lookbehind: &usize, __lookahead: &usize, ) -> ::std::option::Option> { None } #[allow(unused_variables)] fn __action73< 'input, >( text: &'input str, (_, _, _): (usize, Tok<'input>, usize), (_, __0, _): (usize, Annotated, usize), ) -> Annotated { (__0) } #[allow(unused_variables)] fn __action74< 'input, >( text: &'input str, (_, rules, _): (usize, ::std::vec::Vec, Annotated)>>, usize), (_, last, _): (usize, ::std::option::Option, Annotated)>>, usize), ) -> Vec, Annotated)>> { { let mut rules = rules; rules.extend(last); rules } } #[allow(unused_variables)] fn __action75< 'input, >( text: &'input str, (_, i, _): (usize, (Annotated, Annotated), usize), ) -> Annotated<(Annotated, Annotated)> { Annotated(i, vec![]) } #[allow(unused_variables)] fn __action76< 'input, >( text: &'input str, (_, _, _): (usize, Tok<'input>, usize), (_, i, _): (usize, (Annotated, Annotated), usize), (_, _, _): (usize, (), usize), (_, _, _): (usize, Tok<'input>, usize), ) -> Annotated<(Annotated, Annotated)> { Annotated(i, vec![]) } #[allow(unused_variables)] fn __action77< 'input, >( text: &'input str, (_, i, _): (usize, Pattern, usize), ) -> Annotated { Annotated(i, vec![]) } #[allow(unused_variables)] fn __action78< 'input, >( text: &'input str, (_, _, _): (usize, Tok<'input>, usize), (_, i, _): (usize, Pattern, usize), (_, _, _): (usize, (), usize), (_, _, _): (usize, Tok<'input>, usize), ) -> Annotated { Annotated(i, vec![]) } #[allow(unused_variables)] fn __action79< 'input, >( text: &'input str, (_, rules, _): (usize, ::std::vec::Vec>, usize), (_, last, _): (usize, ::std::option::Option>, usize), ) -> Vec> { { let mut rules = rules; rules.extend(last); rules } } #[allow(unused_variables)] fn __action80< 'input, >( text: &'input str, (_, __0, _): (usize, (FunctionName, Function), usize), ) -> ::std::vec::Vec<(FunctionName, Function)> { vec![__0] } #[allow(unused_variables)] fn __action81< 'input, >( text: &'input str, (_, v, _): (usize, ::std::vec::Vec<(FunctionName, Function)>, usize), (_, e, _): (usize, (FunctionName, Function), usize), ) -> ::std::vec::Vec<(FunctionName, Function)> { { let mut v = v; v.push(e); v } } #[allow(unused_variables)] fn __action82< 'input, >( text: &'input str, (_, __0, _): (usize, FunctionName, usize), (_, _, _): (usize, Tok<'input>, usize), (_, __1, _): (usize, Function, usize), ) -> (FunctionName, Function) { (__0, __1) } #[allow(unused_variables)] fn __action83< 'input, >( text: &'input str, (_, i, _): (usize, Atom, usize), ) -> Annotated { Annotated(i, vec![]) } #[allow(unused_variables)] fn __action84< 'input, >( text: &'input str, (_, _, _): (usize, Tok<'input>, usize), (_, i, _): (usize, Atom, usize), (_, _, _): (usize, (), usize), (_, _, _): (usize, Tok<'input>, usize), ) -> Annotated { Annotated(i, vec![]) } #[allow(unused_variables)] fn __action85< 'input, >( text: &'input str, __lookbehind: &usize, __lookahead: &usize, ) -> ::std::vec::Vec> { vec![] } #[allow(unused_variables)] fn __action86< 'input, >( text: &'input str, (_, v, _): (usize, ::std::vec::Vec>, usize), ) -> ::std::vec::Vec> { v } #[allow(unused_variables)] fn __action87< 'input, >( text: &'input str, (_, i, _): (usize, CaseClause, usize), ) -> Annotated { Annotated(i, vec![]) } #[allow(unused_variables)] fn __action88< 'input, >( text: &'input str, (_, _, _): (usize, Tok<'input>, usize), (_, i, _): (usize, CaseClause, usize), (_, _, _): (usize, (), usize), (_, _, _): (usize, Tok<'input>, usize), ) -> Annotated { Annotated(i, vec![]) } #[allow(unused_variables)] fn __action89< 'input, >( text: &'input str, (_, rules, _): (usize, ::std::vec::Vec>, usize), (_, last, _): (usize, ::std::option::Option>, usize), ) -> Vec> { { let mut rules = rules; rules.extend(last); rules } } #[allow(unused_variables)] fn __action90< 'input, >( text: &'input str, (_, i, _): (usize, (Expression, MapExactAssoc, Expression), usize), ) -> Annotated<(Expression, MapExactAssoc, Expression)> { Annotated(i, vec![]) } #[allow(unused_variables)] fn __action91< 'input, >( text: &'input str, (_, _, _): (usize, Tok<'input>, usize), (_, i, _): (usize, (Expression, MapExactAssoc, Expression), usize), (_, _, _): (usize, (), usize), (_, _, _): (usize, Tok<'input>, usize), ) -> Annotated<(Expression, MapExactAssoc, Expression)> { Annotated(i, vec![]) } #[allow(unused_variables)] fn __action92< 'input, >( text: &'input str, (_, __0, _): (usize, Expression, usize), (_, __1, _): (usize, MapExactAssoc, usize), (_, __2, _): (usize, Expression, usize), ) -> (Expression, MapExactAssoc, Expression) { (__0, __1, __2) } #[allow(unused_variables)] fn __action93< 'input, >( text: &'input str, (_, __0, _): (usize, Expression, usize), ) -> ::std::option::Option { Some(__0) } #[allow(unused_variables)] fn __action94< 'input, >( text: &'input str, __lookbehind: &usize, __lookahead: &usize, ) -> ::std::option::Option { None } #[allow(unused_variables)] fn __action95< 'input, >( text: &'input str, (_, _, _): (usize, Tok<'input>, usize), (_, __0, _): (usize, Expression, usize), ) -> Expression { (__0) } #[allow(unused_variables)] fn __action96< 'input, >( text: &'input str, (_, rules, _): (usize, ::std::vec::Vec, usize), (_, last, _): (usize, ::std::option::Option, usize), ) -> Vec { { let mut rules = rules; rules.extend(last); rules } } #[allow(unused_variables)] fn __action97< 'input, >( text: &'input str, (_, rules, _): (usize, ::std::vec::Vec>, usize), (_, last, _): (usize, ::std::option::Option>, usize), ) -> Vec> { { let mut rules = rules; rules.extend(last); rules } } #[allow(unused_variables)] fn __action98< 'input, >( text: &'input str, (_, i, _): (usize, SingleExpression, usize), ) -> Annotated { Annotated(i, vec![]) } #[allow(unused_variables)] fn __action99< 'input, >( text: &'input str, (_, _, _): (usize, Tok<'input>, usize), (_, i, _): (usize, SingleExpression, usize), (_, _, _): (usize, (), usize), (_, _, _): (usize, Tok<'input>, usize), ) -> Annotated { Annotated(i, vec![]) } #[allow(unused_variables)] fn __action100< 'input, >( text: &'input str, (_, i, _): (usize, Vec>, usize), ) -> Annotated>> { Annotated(i, vec![]) } #[allow(unused_variables)] fn __action101< 'input, >( text: &'input str, (_, _, _): (usize, Tok<'input>, usize), (_, i, _): (usize, Vec>, usize), (_, _, _): (usize, (), usize), (_, _, _): (usize, Tok<'input>, usize), ) -> Annotated>> { Annotated(i, vec![]) } #[allow(unused_variables)] fn __action102< 'input, >( text: &'input str, (_, rules, _): (usize, ::std::vec::Vec>, usize), (_, last, _): (usize, ::std::option::Option>, usize), ) -> Vec> { { let mut rules = rules; rules.extend(last); rules } } #[allow(unused_variables)] fn __action103< 'input, >( text: &'input str, (_, i, _): (usize, Atom, usize), ) -> Annotated { Annotated(i, vec![]) } #[allow(unused_variables)] fn __action104< 'input, >( text: &'input str, (_, _, _): (usize, Tok<'input>, usize), (_, i, _): (usize, Atom, usize), (_, _, _): (usize, (), usize), (_, _, _): (usize, Tok<'input>, usize), ) -> Annotated { Annotated(i, vec![]) } #[allow(unused_variables)] fn __action105< 'input, >( text: &'input str, (_, i, _): (usize, Function, usize), ) -> Annotated { Annotated(i, vec![]) } #[allow(unused_variables)] fn __action106< 'input, >( text: &'input str, (_, _, _): (usize, Tok<'input>, usize), (_, i, _): (usize, Function, usize), (_, _, _): (usize, (), usize), (_, _, _): (usize, Tok<'input>, usize), ) -> Annotated { Annotated(i, vec![]) } #[allow(unused_variables)] fn __action107< 'input, >( text: &'input str, (_, i, _): (usize, FunctionName, usize), ) -> Annotated { Annotated(i, vec![]) } #[allow(unused_variables)] fn __action108< 'input, >( text: &'input str, (_, _, _): (usize, Tok<'input>, usize), (_, i, _): (usize, FunctionName, usize), (_, _, _): (usize, (), usize), (_, _, _): (usize, Tok<'input>, usize), ) -> Annotated { Annotated(i, vec![]) } #[allow(unused_variables)] fn __action109< 'input, >( text: &'input str, (_, rules, _): (usize, ::std::vec::Vec<(Atom, Constant)>, usize), (_, last, _): (usize, ::std::option::Option<(Atom, Constant)>, usize), ) -> Vec<(Atom, Constant)> { { let mut rules = rules; rules.extend(last); rules } } #[allow(unused_variables)] fn __action110< 'input, >( text: &'input str, (_, __0, _): (usize, Atom, usize), (_, _, _): (usize, Tok<'input>, usize), (_, __1, _): (usize, Constant, usize), ) -> (Atom, Constant) { (__0, __1) } #[allow(unused_variables)] fn __action111< 'input, >( text: &'input str, (_, rules, _): (usize, ::std::vec::Vec, usize), (_, last, _): (usize, ::std::option::Option, usize), ) -> Vec { { let mut rules = rules; rules.extend(last); rules } } #[allow(unused_variables)] fn __action112< 'input, >( text: &'input str, __lookbehind: &usize, __lookahead: &usize, ) -> ::std::vec::Vec { vec![] } #[allow(unused_variables)] fn __action113< 'input, >( text: &'input str, (_, v, _): (usize, ::std::vec::Vec, usize), ) -> ::std::vec::Vec { v } #[allow(unused_variables)] fn __action114< 'input, >( text: &'input str, (_, i, _): (usize, Module, usize), ) -> Annotated { Annotated(i, vec![]) } #[allow(unused_variables)] fn __action115< 'input, >( text: &'input str, (_, _, _): (usize, Tok<'input>, usize), (_, i, _): (usize, Module, usize), (_, _, _): (usize, (), usize), (_, _, _): (usize, Tok<'input>, usize), ) -> Annotated { Annotated(i, vec![]) } #[allow(unused_variables)] fn __action116< 'input, >( text: &'input str, (_, __0, _): (usize, FunctionDefinition, usize), ) -> ::std::vec::Vec { vec![__0] } #[allow(unused_variables)] fn __action117< 'input, >( text: &'input str, (_, v, _): (usize, ::std::vec::Vec, usize), (_, e, _): (usize, FunctionDefinition, usize), ) -> ::std::vec::Vec { { let mut v = v; v.push(e); v } } #[allow(unused_variables)] fn __action118< 'input, >( text: &'input str, (_, __0, _): (usize, FunctionName, usize), ) -> ::std::option::Option { Some(__0) } #[allow(unused_variables)] fn __action119< 'input, >( text: &'input str, __lookbehind: &usize, __lookahead: &usize, ) -> ::std::option::Option { None } #[allow(unused_variables)] fn __action120< 'input, >( text: &'input str, __lookbehind: &usize, __lookahead: &usize, ) -> ::std::vec::Vec { vec![] } #[allow(unused_variables)] fn __action121< 'input, >( text: &'input str, (_, v, _): (usize, ::std::vec::Vec, usize), ) -> ::std::vec::Vec { v } #[allow(unused_variables)] fn __action122< 'input, >( text: &'input str, (_, __0, _): (usize, FunctionName, usize), (_, _, _): (usize, Tok<'input>, usize), ) -> FunctionName { (__0) } #[allow(unused_variables)] fn __action123< 'input, >( text: &'input str, (_, __0, _): (usize, (Atom, Constant), usize), ) -> ::std::option::Option<(Atom, Constant)> { Some(__0) } #[allow(unused_variables)] fn __action124< 'input, >( text: &'input str, __lookbehind: &usize, __lookahead: &usize, ) -> ::std::option::Option<(Atom, Constant)> { None } #[allow(unused_variables)] fn __action125< 'input, >( text: &'input str, __lookbehind: &usize, __lookahead: &usize, ) -> ::std::vec::Vec<(Atom, Constant)> { vec![] } #[allow(unused_variables)] fn __action126< 'input, >( text: &'input str, (_, v, _): (usize, ::std::vec::Vec<(Atom, Constant)>, usize), ) -> ::std::vec::Vec<(Atom, Constant)> { v } #[allow(unused_variables)] fn __action127< 'input, >( text: &'input str, (_, __0, _): (usize, (Atom, Constant), usize), (_, _, _): (usize, Tok<'input>, usize), ) -> (Atom, Constant) { (__0) } #[allow(unused_variables)] fn __action128< 'input, >( text: &'input str, (_, __0, _): (usize, Annotated, usize), ) -> ::std::option::Option> { Some(__0) } #[allow(unused_variables)] fn __action129< 'input, >( text: &'input str, __lookbehind: &usize, __lookahead: &usize, ) -> ::std::option::Option> { None } #[allow(unused_variables)] fn __action130< 'input, >( text: &'input str, __lookbehind: &usize, __lookahead: &usize, ) -> ::std::vec::Vec> { vec![] } #[allow(unused_variables)] fn __action131< 'input, >( text: &'input str, (_, v, _): (usize, ::std::vec::Vec>, usize), ) -> ::std::vec::Vec> { v } #[allow(unused_variables)] fn __action132< 'input, >( text: &'input str, (_, __0, _): (usize, Annotated, usize), (_, _, _): (usize, Tok<'input>, usize), ) -> Annotated { (__0) } #[allow(unused_variables)] fn __action133< 'input, >( text: &'input str, (_, __0, _): (usize, Annotated, usize), ) -> ::std::option::Option> { Some(__0) } #[allow(unused_variables)] fn __action134< 'input, >( text: &'input str, __lookbehind: &usize, __lookahead: &usize, ) -> ::std::option::Option> { None } #[allow(unused_variables)] fn __action135< 'input, >( text: &'input str, __lookbehind: &usize, __lookahead: &usize, ) -> ::std::vec::Vec> { vec![] } #[allow(unused_variables)] fn __action136< 'input, >( text: &'input str, (_, v, _): (usize, ::std::vec::Vec>, usize), ) -> ::std::vec::Vec> { v } #[allow(unused_variables)] fn __action137< 'input, >( text: &'input str, (_, __0, _): (usize, Annotated, usize), (_, _, _): (usize, Tok<'input>, usize), ) -> Annotated { (__0) } #[allow(unused_variables)] fn __action138< 'input, >( text: &'input str, (_, __0, _): (usize, Expression, usize), ) -> ::std::option::Option { Some(__0) } #[allow(unused_variables)] fn __action139< 'input, >( text: &'input str, __lookbehind: &usize, __lookahead: &usize, ) -> ::std::option::Option { None } #[allow(unused_variables)] fn __action140< 'input, >( text: &'input str, __lookbehind: &usize, __lookahead: &usize, ) -> ::std::vec::Vec { vec![] } #[allow(unused_variables)] fn __action141< 'input, >( text: &'input str, (_, v, _): (usize, ::std::vec::Vec, usize), ) -> ::std::vec::Vec { v } #[allow(unused_variables)] fn __action142< 'input, >( text: &'input str, (_, __0, _): (usize, Expression, usize), (_, _, _): (usize, Tok<'input>, usize), ) -> Expression { (__0) } #[allow(unused_variables)] fn __action143< 'input, >( text: &'input str, (_, __0, _): (usize, Annotated<(Expression, MapExactAssoc, Expression)>, usize), ) -> ::std::option::Option> { Some(__0) } #[allow(unused_variables)] fn __action144< 'input, >( text: &'input str, __lookbehind: &usize, __lookahead: &usize, ) -> ::std::option::Option> { None } #[allow(unused_variables)] fn __action145< 'input, >( text: &'input str, __lookbehind: &usize, __lookahead: &usize, ) -> ::std::vec::Vec> { vec![] } #[allow(unused_variables)] fn __action146< 'input, >( text: &'input str, (_, v, _): (usize, ::std::vec::Vec>, usize), ) -> ::std::vec::Vec> { v } #[allow(unused_variables)] fn __action147< 'input, >( text: &'input str, (_, __0, _): (usize, Annotated<(Expression, MapExactAssoc, Expression)>, usize), (_, _, _): (usize, Tok<'input>, usize), ) -> Annotated<(Expression, MapExactAssoc, Expression)> { (__0) } #[allow(unused_variables)] fn __action148< 'input, >( text: &'input str, (_, __0, _): (usize, Annotated, usize), ) -> ::std::vec::Vec> { vec![__0] } #[allow(unused_variables)] fn __action149< 'input, >( text: &'input str, (_, v, _): (usize, ::std::vec::Vec>, usize), (_, e, _): (usize, Annotated, usize), ) -> ::std::vec::Vec> { { let mut v = v; v.push(e); v } } #[allow(unused_variables)] fn __action150< 'input, >( text: &'input str, (_, __0, _): (usize, Annotated, usize), ) -> ::std::option::Option> { Some(__0) } #[allow(unused_variables)] fn __action151< 'input, >( text: &'input str, __lookbehind: &usize, __lookahead: &usize, ) -> ::std::option::Option> { None } #[allow(unused_variables)] fn __action152< 'input, >( text: &'input str, __lookbehind: &usize, __lookahead: &usize, ) -> ::std::vec::Vec> { vec![] } #[allow(unused_variables)] fn __action153< 'input, >( text: &'input str, (_, v, _): (usize, ::std::vec::Vec>, usize), ) -> ::std::vec::Vec> { v } #[allow(unused_variables)] fn __action154< 'input, >( text: &'input str, (_, __0, _): (usize, Annotated, usize), (_, _, _): (usize, Tok<'input>, usize), ) -> Annotated { (__0) } #[allow(unused_variables)] fn __action155< 'input, >( text: &'input str, (_, __0, _): (usize, Annotated<(Annotated, Annotated)>, usize), ) -> ::std::option::Option, Annotated)>> { Some(__0) } #[allow(unused_variables)] fn __action156< 'input, >( text: &'input str, __lookbehind: &usize, __lookahead: &usize, ) -> ::std::option::Option, Annotated)>> { None } #[allow(unused_variables)] fn __action157< 'input, >( text: &'input str, __lookbehind: &usize, __lookahead: &usize, ) -> ::std::vec::Vec, Annotated)>> { vec![] } #[allow(unused_variables)] fn __action158< 'input, >( text: &'input str, (_, v, _): (usize, ::std::vec::Vec, Annotated)>>, usize), ) -> ::std::vec::Vec, Annotated)>> { v } #[allow(unused_variables)] fn __action159< 'input, >( text: &'input str, (_, __0, _): (usize, Annotated<(Annotated, Annotated)>, usize), (_, _, _): (usize, Tok<'input>, usize), ) -> Annotated<(Annotated, Annotated)> { (__0) } #[allow(unused_variables)] fn __action160< 'input, >( text: &'input str, (_, __0, _): (usize, (Annotated, Vec>), usize), ) -> ::std::option::Option<(Annotated, Vec>)> { Some(__0) } #[allow(unused_variables)] fn __action161< 'input, >( text: &'input str, __lookbehind: &usize, __lookahead: &usize, ) -> ::std::option::Option<(Annotated, Vec>)> { None } #[allow(unused_variables)] fn __action162< 'input, >( text: &'input str, __lookbehind: &usize, __lookahead: &usize, ) -> ::std::vec::Vec<(Annotated, Vec>)> { vec![] } #[allow(unused_variables)] fn __action163< 'input, >( text: &'input str, (_, v, _): (usize, ::std::vec::Vec<(Annotated, Vec>)>, usize), ) -> ::std::vec::Vec<(Annotated, Vec>)> { v } #[allow(unused_variables)] fn __action164< 'input, >( text: &'input str, (_, __0, _): (usize, (Annotated, Vec>), usize), (_, _, _): (usize, Tok<'input>, usize), ) -> (Annotated, Vec>) { (__0) } #[allow(unused_variables)] fn __action165< 'input, >( text: &'input str, (_, __0, _): (usize, (Expression, Vec), usize), ) -> ::std::option::Option<(Expression, Vec)> { Some(__0) } #[allow(unused_variables)] fn __action166< 'input, >( text: &'input str, __lookbehind: &usize, __lookahead: &usize, ) -> ::std::option::Option<(Expression, Vec)> { None } #[allow(unused_variables)] fn __action167< 'input, >( text: &'input str, __lookbehind: &usize, __lookahead: &usize, ) -> ::std::vec::Vec<(Expression, Vec)> { vec![] } #[allow(unused_variables)] fn __action168< 'input, >( text: &'input str, (_, v, _): (usize, ::std::vec::Vec<(Expression, Vec)>, usize), ) -> ::std::vec::Vec<(Expression, Vec)> { v } #[allow(unused_variables)] fn __action169< 'input, >( text: &'input str, (_, __0, _): (usize, (Expression, Vec), usize), (_, _, _): (usize, Tok<'input>, usize), ) -> (Expression, Vec) { (__0) } #[allow(unused_variables)] fn __action170< 'input, >( text: &'input str, (_, __0, _): (usize, Constant, usize), ) -> ::std::option::Option { Some(__0) } #[allow(unused_variables)] fn __action171< 'input, >( text: &'input str, __lookbehind: &usize, __lookahead: &usize, ) -> ::std::option::Option { None } #[allow(unused_variables)] fn __action172< 'input, >( text: &'input str, __lookbehind: &usize, __lookahead: &usize, ) -> ::std::vec::Vec { vec![] } #[allow(unused_variables)] fn __action173< 'input, >( text: &'input str, (_, v, _): (usize, ::std::vec::Vec, usize), ) -> ::std::vec::Vec { v } #[allow(unused_variables)] fn __action174< 'input, >( text: &'input str, (_, __0, _): (usize, Constant, usize), (_, _, _): (usize, Tok<'input>, usize), ) -> Constant { (__0) } #[allow(unused_variables)] fn __action175< 'input, >( text: &'input str, (_, __0, _): (usize, Constant, usize), ) -> ::std::vec::Vec { vec![__0] } #[allow(unused_variables)] fn __action176< 'input, >( text: &'input str, (_, v, _): (usize, ::std::vec::Vec, usize), (_, e, _): (usize, Constant, usize), ) -> ::std::vec::Vec { { let mut v = v; v.push(e); v } } #[allow(unused_variables)] fn __action177< 'input, >( text: &'input str, (_, __0, _): (usize, (Expression, Vec), usize), ) -> ::std::vec::Vec<(Expression, Vec)> { vec![__0] } #[allow(unused_variables)] fn __action178< 'input, >( text: &'input str, (_, v, _): (usize, ::std::vec::Vec<(Expression, Vec)>, usize), (_, e, _): (usize, (Expression, Vec), usize), ) -> ::std::vec::Vec<(Expression, Vec)> { { let mut v = v; v.push(e); v } } #[allow(unused_variables)] fn __action179< 'input, >( text: &'input str, (_, __0, _): (usize, (Annotated, Vec>), usize), ) -> ::std::vec::Vec<(Annotated, Vec>)> { vec![__0] } #[allow(unused_variables)] fn __action180< 'input, >( text: &'input str, (_, v, _): (usize, ::std::vec::Vec<(Annotated, Vec>)>, usize), (_, e, _): (usize, (Annotated, Vec>), usize), ) -> ::std::vec::Vec<(Annotated, Vec>)> { { let mut v = v; v.push(e); v } } #[allow(unused_variables)] fn __action181< 'input, >( text: &'input str, (_, __0, _): (usize, Annotated<(Annotated, Annotated)>, usize), ) -> ::std::vec::Vec, Annotated)>> { vec![__0] } #[allow(unused_variables)] fn __action182< 'input, >( text: &'input str, (_, v, _): (usize, ::std::vec::Vec, Annotated)>>, usize), (_, e, _): (usize, Annotated<(Annotated, Annotated)>, usize), ) -> ::std::vec::Vec, Annotated)>> { { let mut v = v; v.push(e); v } } #[allow(unused_variables)] fn __action183< 'input, >( text: &'input str, (_, __0, _): (usize, Annotated, usize), ) -> ::std::vec::Vec> { vec![__0] } #[allow(unused_variables)] fn __action184< 'input, >( text: &'input str, (_, v, _): (usize, ::std::vec::Vec>, usize), (_, e, _): (usize, Annotated, usize), ) -> ::std::vec::Vec> { { let mut v = v; v.push(e); v } } #[allow(unused_variables)] fn __action185< 'input, >( text: &'input str, (_, __0, _): (usize, Annotated<(Expression, MapExactAssoc, Expression)>, usize), ) -> ::std::vec::Vec> { vec![__0] } #[allow(unused_variables)] fn __action186< 'input, >( text: &'input str, (_, v, _): (usize, ::std::vec::Vec>, usize), (_, e, _): (usize, Annotated<(Expression, MapExactAssoc, Expression)>, usize), ) -> ::std::vec::Vec> { { let mut v = v; v.push(e); v } } #[allow(unused_variables)] fn __action187< 'input, >( text: &'input str, (_, __0, _): (usize, Expression, usize), ) -> ::std::vec::Vec { vec![__0] } #[allow(unused_variables)] fn __action188< 'input, >( text: &'input str, (_, v, _): (usize, ::std::vec::Vec, usize), (_, e, _): (usize, Expression, usize), ) -> ::std::vec::Vec { { let mut v = v; v.push(e); v } } #[allow(unused_variables)] fn __action189< 'input, >( text: &'input str, (_, __0, _): (usize, Annotated, usize), ) -> ::std::vec::Vec> { vec![__0] } #[allow(unused_variables)] fn __action190< 'input, >( text: &'input str, (_, v, _): (usize, ::std::vec::Vec>, usize), (_, e, _): (usize, Annotated, usize), ) -> ::std::vec::Vec> { { let mut v = v; v.push(e); v } } #[allow(unused_variables)] fn __action191< 'input, >( text: &'input str, (_, __0, _): (usize, Annotated, usize), ) -> ::std::vec::Vec> { vec![__0] } #[allow(unused_variables)] fn __action192< 'input, >( text: &'input str, (_, v, _): (usize, ::std::vec::Vec>, usize), (_, e, _): (usize, Annotated, usize), ) -> ::std::vec::Vec> { { let mut v = v; v.push(e); v } } #[allow(unused_variables)] fn __action193< 'input, >( text: &'input str, (_, __0, _): (usize, (Atom, Constant), usize), ) -> ::std::vec::Vec<(Atom, Constant)> { vec![__0] } #[allow(unused_variables)] fn __action194< 'input, >( text: &'input str, (_, v, _): (usize, ::std::vec::Vec<(Atom, Constant)>, usize), (_, e, _): (usize, (Atom, Constant), usize), ) -> ::std::vec::Vec<(Atom, Constant)> { { let mut v = v; v.push(e); v } } #[allow(unused_variables)] fn __action195< 'input, >( text: &'input str, (_, __0, _): (usize, FunctionName, usize), ) -> ::std::vec::Vec { vec![__0] } #[allow(unused_variables)] fn __action196< 'input, >( text: &'input str, (_, v, _): (usize, ::std::vec::Vec, usize), (_, e, _): (usize, FunctionName, usize), ) -> ::std::vec::Vec { { let mut v = v; v.push(e); v } } #[allow(unused_variables)] fn __action197< 'input, >( text: &'input str, __0: (usize, Tok<'input>, usize), __1: (usize, Annotated, usize), ) -> ::std::option::Option> { let __start0 = __0.0.clone(); let __end0 = __1.2.clone(); let __temp0 = __action73( text, __0, __1, ); let __temp0 = (__start0, __temp0, __end0); __action71( text, __temp0, ) } #[allow(unused_variables)] fn __action198< 'input, >( text: &'input str, __0: (usize, Tok<'input>, usize), __1: (usize, Vec>, usize), __2: (usize, Tok<'input>, usize), __3: (usize, Annotated, usize), __4: (usize, Tok<'input>, usize), ) -> Pattern { let __start0 = __2.0.clone(); let __end0 = __3.2.clone(); let __temp0 = __action197( text, __2, __3, ); let __temp0 = (__start0, __temp0, __end0); __action50( text, __0, __1, __temp0, __4, ) } #[allow(unused_variables)] fn __action199< 'input, >( text: &'input str, __0: (usize, Tok<'input>, usize), __1: (usize, Vec>, usize), __2: (usize, Tok<'input>, usize), ) -> Pattern { let __start0 = __1.2.clone(); let __end0 = __2.0.clone(); let __temp0 = __action72( text, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); __action50( text, __0, __1, __temp0, __2, ) } #[allow(unused_variables)] fn __action200< 'input, >( text: &'input str, __0: (usize, Tok<'input>, usize), __1: (usize, Expression, usize), ) -> ::std::option::Option { let __start0 = __0.0.clone(); let __end0 = __1.2.clone(); let __temp0 = __action95( text, __0, __1, ); let __temp0 = (__start0, __temp0, __end0); __action93( text, __temp0, ) } #[allow(unused_variables)] fn __action201< 'input, >( text: &'input str, __0: (usize, Tok<'input>, usize), __1: (usize, Vec, usize), __2: (usize, Tok<'input>, usize), __3: (usize, Expression, usize), __4: (usize, Tok<'input>, usize), ) -> SingleExpression { let __start0 = __2.0.clone(); let __end0 = __3.2.clone(); let __temp0 = __action200( text, __2, __3, ); let __temp0 = (__start0, __temp0, __end0); __action16( text, __0, __1, __temp0, __4, ) } #[allow(unused_variables)] fn __action202< 'input, >( text: &'input str, __0: (usize, Tok<'input>, usize), __1: (usize, Vec, usize), __2: (usize, Tok<'input>, usize), ) -> SingleExpression { let __start0 = __1.2.clone(); let __end0 = __2.0.clone(); let __temp0 = __action94( text, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); __action16( text, __0, __1, __temp0, __2, ) } #[allow(unused_variables)] fn __action203< 'input, >( text: &'input str, __0: (usize, Tok<'input>, usize), __1: (usize, Vec>, usize), __2: (usize, Tok<'input>, usize), __3: (usize, Expression, usize), __4: (usize, Tok<'input>, usize), ) -> SingleExpression { let __start0 = __2.0.clone(); let __end0 = __3.2.clone(); let __temp0 = __action200( text, __2, __3, ); let __temp0 = (__start0, __temp0, __end0); __action23( text, __0, __1, __temp0, __4, ) } #[allow(unused_variables)] fn __action204< 'input, >( text: &'input str, __0: (usize, Tok<'input>, usize), __1: (usize, Vec>, usize), __2: (usize, Tok<'input>, usize), ) -> SingleExpression { let __start0 = __1.2.clone(); let __end0 = __2.0.clone(); let __temp0 = __action94( text, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); __action23( text, __0, __1, __temp0, __2, ) } #[allow(unused_variables)] fn __action205< 'input, >( text: &'input str, __0: (usize, Tok<'input>, usize), __1: (usize, Constant, usize), ) -> ::std::option::Option<(Tok<'input>, Constant)> { let __start0 = __0.0.clone(); let __end0 = __1.2.clone(); let __temp0 = __action67( text, __0, __1, ); let __temp0 = (__start0, __temp0, __end0); __action65( text, __temp0, ) } #[allow(unused_variables)] fn __action206< 'input, >( text: &'input str, __0: (usize, Tok<'input>, usize), __1: (usize, Vec, usize), __2: (usize, Tok<'input>, usize), __3: (usize, Constant, usize), __4: (usize, Tok<'input>, usize), ) -> Constant { let __start0 = __2.0.clone(); let __end0 = __3.2.clone(); let __temp0 = __action205( text, __2, __3, ); let __temp0 = (__start0, __temp0, __end0); __action56( text, __0, __1, __temp0, __4, ) } #[allow(unused_variables)] fn __action207< 'input, >( text: &'input str, __0: (usize, Tok<'input>, usize), __1: (usize, Vec, usize), __2: (usize, Tok<'input>, usize), ) -> Constant { let __start0 = __1.2.clone(); let __end0 = __2.0.clone(); let __temp0 = __action66( text, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); __action56( text, __0, __1, __temp0, __2, ) } #[allow(unused_variables)] fn __action208< 'input, >( text: &'input str, __0: (usize, Tok<'input>, usize), __1: (usize, Vec, usize), __2: (usize, Tok<'input>, usize), __3: (usize, Constant, usize), __4: (usize, Tok<'input>, usize), ) -> () { let __start0 = __2.0.clone(); let __end0 = __3.2.clone(); let __temp0 = __action205( text, __2, __3, ); let __temp0 = (__start0, __temp0, __end0); __action63( text, __0, __1, __temp0, __4, ) } #[allow(unused_variables)] fn __action209< 'input, >( text: &'input str, __0: (usize, Tok<'input>, usize), __1: (usize, Vec, usize), __2: (usize, Tok<'input>, usize), ) -> () { let __start0 = __1.2.clone(); let __end0 = __2.0.clone(); let __temp0 = __action66( text, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); __action63( text, __0, __1, __temp0, __2, ) } #[allow(unused_variables)] fn __action210< 'input, >( text: &'input str, __0: (usize, Atom, usize), __1: (usize, Tok<'input>, usize), __2: (usize, Constant, usize), __3: (usize, Tok<'input>, usize), ) -> (Atom, Constant) { let __start0 = __0.0.clone(); let __end0 = __2.2.clone(); let __temp0 = __action110( text, __0, __1, __2, ); let __temp0 = (__start0, __temp0, __end0); __action127( text, __temp0, __3, ) } #[allow(unused_variables)] fn __action211< 'input, >( text: &'input str, __0: (usize, Atom, usize), __1: (usize, Tok<'input>, usize), __2: (usize, Constant, usize), ) -> ::std::option::Option<(Atom, Constant)> { let __start0 = __0.0.clone(); let __end0 = __2.2.clone(); let __temp0 = __action110( text, __0, __1, __2, ); let __temp0 = (__start0, __temp0, __end0); __action123( text, __temp0, ) } #[allow(unused_variables)] fn __action212< 'input, >( text: &'input str, __0: (usize, Atom, usize), __1: (usize, Tok<'input>, usize), __2: (usize, Constant, usize), __3: (usize, Tok<'input>, usize), ) -> ::std::vec::Vec<(Atom, Constant)> { let __start0 = __0.0.clone(); let __end0 = __3.2.clone(); let __temp0 = __action210( text, __0, __1, __2, __3, ); let __temp0 = (__start0, __temp0, __end0); __action193( text, __temp0, ) } #[allow(unused_variables)] fn __action213< 'input, >( text: &'input str, __0: (usize, ::std::vec::Vec<(Atom, Constant)>, usize), __1: (usize, Atom, usize), __2: (usize, Tok<'input>, usize), __3: (usize, Constant, usize), __4: (usize, Tok<'input>, usize), ) -> ::std::vec::Vec<(Atom, Constant)> { let __start0 = __1.0.clone(); let __end0 = __4.2.clone(); let __temp0 = __action210( text, __1, __2, __3, __4, ); let __temp0 = (__start0, __temp0, __end0); __action194( text, __0, __temp0, ) } #[allow(unused_variables)] fn __action214< 'input, >( text: &'input str, __0: (usize, ::std::option::Option<(Atom, Constant)>, usize), ) -> Vec<(Atom, Constant)> { let __start0 = __0.0.clone(); let __end0 = __0.0.clone(); let __temp0 = __action125( text, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); __action109( text, __temp0, __0, ) } #[allow(unused_variables)] fn __action215< 'input, >( text: &'input str, __0: (usize, ::std::vec::Vec<(Atom, Constant)>, usize), __1: (usize, ::std::option::Option<(Atom, Constant)>, usize), ) -> Vec<(Atom, Constant)> { let __start0 = __0.0.clone(); let __end0 = __0.2.clone(); let __temp0 = __action126( text, __0, ); let __temp0 = (__start0, __temp0, __end0); __action109( text, __temp0, __1, ) } #[allow(unused_variables)] fn __action216< 'input, >( text: &'input str, __0: (usize, Annotated<(Expression, MapExactAssoc, Expression)>, usize), __1: (usize, Tok<'input>, usize), ) -> ::std::vec::Vec> { let __start0 = __0.0.clone(); let __end0 = __1.2.clone(); let __temp0 = __action147( text, __0, __1, ); let __temp0 = (__start0, __temp0, __end0); __action185( text, __temp0, ) } #[allow(unused_variables)] fn __action217< 'input, >( text: &'input str, __0: (usize, ::std::vec::Vec>, usize), __1: (usize, Annotated<(Expression, MapExactAssoc, Expression)>, usize), __2: (usize, Tok<'input>, usize), ) -> ::std::vec::Vec> { let __start0 = __1.0.clone(); let __end0 = __2.2.clone(); let __temp0 = __action147( text, __1, __2, ); let __temp0 = (__start0, __temp0, __end0); __action186( text, __0, __temp0, ) } #[allow(unused_variables)] fn __action218< 'input, >( text: &'input str, __0: (usize, ::std::option::Option>, usize), ) -> Vec> { let __start0 = __0.0.clone(); let __end0 = __0.0.clone(); let __temp0 = __action145( text, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); __action89( text, __temp0, __0, ) } #[allow(unused_variables)] fn __action219< 'input, >( text: &'input str, __0: (usize, ::std::vec::Vec>, usize), __1: (usize, ::std::option::Option>, usize), ) -> Vec> { let __start0 = __0.0.clone(); let __end0 = __0.2.clone(); let __temp0 = __action146( text, __0, ); let __temp0 = (__start0, __temp0, __end0); __action89( text, __temp0, __1, ) } #[allow(unused_variables)] fn __action220< 'input, >( text: &'input str, __0: (usize, Annotated, usize), __1: (usize, Tok<'input>, usize), ) -> ::std::vec::Vec> { let __start0 = __0.0.clone(); let __end0 = __1.2.clone(); let __temp0 = __action137( text, __0, __1, ); let __temp0 = (__start0, __temp0, __end0); __action189( text, __temp0, ) } #[allow(unused_variables)] fn __action221< 'input, >( text: &'input str, __0: (usize, ::std::vec::Vec>, usize), __1: (usize, Annotated, usize), __2: (usize, Tok<'input>, usize), ) -> ::std::vec::Vec> { let __start0 = __1.0.clone(); let __end0 = __2.2.clone(); let __temp0 = __action137( text, __1, __2, ); let __temp0 = (__start0, __temp0, __end0); __action190( text, __0, __temp0, ) } #[allow(unused_variables)] fn __action222< 'input, >( text: &'input str, __0: (usize, ::std::option::Option>, usize), ) -> Vec> { let __start0 = __0.0.clone(); let __end0 = __0.0.clone(); let __temp0 = __action135( text, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); __action97( text, __temp0, __0, ) } #[allow(unused_variables)] fn __action223< 'input, >( text: &'input str, __0: (usize, ::std::vec::Vec>, usize), __1: (usize, ::std::option::Option>, usize), ) -> Vec> { let __start0 = __0.0.clone(); let __end0 = __0.2.clone(); let __temp0 = __action136( text, __0, ); let __temp0 = (__start0, __temp0, __end0); __action97( text, __temp0, __1, ) } #[allow(unused_variables)] fn __action224< 'input, >( text: &'input str, __0: (usize, Annotated, usize), __1: (usize, Tok<'input>, usize), ) -> ::std::vec::Vec> { let __start0 = __0.0.clone(); let __end0 = __1.2.clone(); let __temp0 = __action132( text, __0, __1, ); let __temp0 = (__start0, __temp0, __end0); __action191( text, __temp0, ) } #[allow(unused_variables)] fn __action225< 'input, >( text: &'input str, __0: (usize, ::std::vec::Vec>, usize), __1: (usize, Annotated, usize), __2: (usize, Tok<'input>, usize), ) -> ::std::vec::Vec> { let __start0 = __1.0.clone(); let __end0 = __2.2.clone(); let __temp0 = __action132( text, __1, __2, ); let __temp0 = (__start0, __temp0, __end0); __action192( text, __0, __temp0, ) } #[allow(unused_variables)] fn __action226< 'input, >( text: &'input str, __0: (usize, ::std::option::Option>, usize), ) -> Vec> { let __start0 = __0.0.clone(); let __end0 = __0.0.clone(); let __temp0 = __action130( text, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); __action102( text, __temp0, __0, ) } #[allow(unused_variables)] fn __action227< 'input, >( text: &'input str, __0: (usize, ::std::vec::Vec>, usize), __1: (usize, ::std::option::Option>, usize), ) -> Vec> { let __start0 = __0.0.clone(); let __end0 = __0.2.clone(); let __temp0 = __action131( text, __0, ); let __temp0 = (__start0, __temp0, __end0); __action102( text, __temp0, __1, ) } #[allow(unused_variables)] fn __action228< 'input, >( text: &'input str, __0: (usize, Annotated, usize), __1: (usize, Tok<'input>, usize), ) -> ::std::vec::Vec> { let __start0 = __0.0.clone(); let __end0 = __1.2.clone(); let __temp0 = __action154( text, __0, __1, ); let __temp0 = (__start0, __temp0, __end0); __action183( text, __temp0, ) } #[allow(unused_variables)] fn __action229< 'input, >( text: &'input str, __0: (usize, ::std::vec::Vec>, usize), __1: (usize, Annotated, usize), __2: (usize, Tok<'input>, usize), ) -> ::std::vec::Vec> { let __start0 = __1.0.clone(); let __end0 = __2.2.clone(); let __temp0 = __action154( text, __1, __2, ); let __temp0 = (__start0, __temp0, __end0); __action184( text, __0, __temp0, ) } #[allow(unused_variables)] fn __action230< 'input, >( text: &'input str, __0: (usize, ::std::option::Option>, usize), ) -> Vec> { let __start0 = __0.0.clone(); let __end0 = __0.0.clone(); let __temp0 = __action152( text, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); __action79( text, __temp0, __0, ) } #[allow(unused_variables)] fn __action231< 'input, >( text: &'input str, __0: (usize, ::std::vec::Vec>, usize), __1: (usize, ::std::option::Option>, usize), ) -> Vec> { let __start0 = __0.0.clone(); let __end0 = __0.2.clone(); let __temp0 = __action153( text, __0, ); let __temp0 = (__start0, __temp0, __end0); __action79( text, __temp0, __1, ) } #[allow(unused_variables)] fn __action232< 'input, >( text: &'input str, __0: (usize, Annotated<(Annotated, Annotated)>, usize), __1: (usize, Tok<'input>, usize), ) -> ::std::vec::Vec, Annotated)>> { let __start0 = __0.0.clone(); let __end0 = __1.2.clone(); let __temp0 = __action159( text, __0, __1, ); let __temp0 = (__start0, __temp0, __end0); __action181( text, __temp0, ) } #[allow(unused_variables)] fn __action233< 'input, >( text: &'input str, __0: (usize, ::std::vec::Vec, Annotated)>>, usize), __1: (usize, Annotated<(Annotated, Annotated)>, usize), __2: (usize, Tok<'input>, usize), ) -> ::std::vec::Vec, Annotated)>> { let __start0 = __1.0.clone(); let __end0 = __2.2.clone(); let __temp0 = __action159( text, __1, __2, ); let __temp0 = (__start0, __temp0, __end0); __action182( text, __0, __temp0, ) } #[allow(unused_variables)] fn __action234< 'input, >( text: &'input str, __0: (usize, ::std::option::Option, Annotated)>>, usize), ) -> Vec, Annotated)>> { let __start0 = __0.0.clone(); let __end0 = __0.0.clone(); let __temp0 = __action157( text, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); __action74( text, __temp0, __0, ) } #[allow(unused_variables)] fn __action235< 'input, >( text: &'input str, __0: (usize, ::std::vec::Vec, Annotated)>>, usize), __1: (usize, ::std::option::Option, Annotated)>>, usize), ) -> Vec, Annotated)>> { let __start0 = __0.0.clone(); let __end0 = __0.2.clone(); let __temp0 = __action158( text, __0, ); let __temp0 = (__start0, __temp0, __end0); __action74( text, __temp0, __1, ) } #[allow(unused_variables)] fn __action236< 'input, >( text: &'input str, __0: (usize, Atom, usize), __1: (usize, Tok<'input>, usize), __2: (usize, Constant, usize), ) -> Vec<(Atom, Constant)> { let __start0 = __0.0.clone(); let __end0 = __2.2.clone(); let __temp0 = __action211( text, __0, __1, __2, ); let __temp0 = (__start0, __temp0, __end0); __action214( text, __temp0, ) } #[allow(unused_variables)] fn __action237< 'input, >( text: &'input str, __lookbehind: &usize, __lookahead: &usize, ) -> Vec<(Atom, Constant)> { let __start0 = __lookbehind.clone(); let __end0 = __lookahead.clone(); let __temp0 = __action124( text, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); __action214( text, __temp0, ) } #[allow(unused_variables)] fn __action238< 'input, >( text: &'input str, __0: (usize, ::std::vec::Vec<(Atom, Constant)>, usize), __1: (usize, Atom, usize), __2: (usize, Tok<'input>, usize), __3: (usize, Constant, usize), ) -> Vec<(Atom, Constant)> { let __start0 = __1.0.clone(); let __end0 = __3.2.clone(); let __temp0 = __action211( text, __1, __2, __3, ); let __temp0 = (__start0, __temp0, __end0); __action215( text, __0, __temp0, ) } #[allow(unused_variables)] fn __action239< 'input, >( text: &'input str, __0: (usize, ::std::vec::Vec<(Atom, Constant)>, usize), ) -> Vec<(Atom, Constant)> { let __start0 = __0.2.clone(); let __end0 = __0.2.clone(); let __temp0 = __action124( text, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); __action215( text, __0, __temp0, ) } #[allow(unused_variables)] fn __action240< 'input, >( text: &'input str, __0: (usize, (Expression, Vec), usize), __1: (usize, Tok<'input>, usize), ) -> ::std::vec::Vec<(Expression, Vec)> { let __start0 = __0.0.clone(); let __end0 = __1.2.clone(); let __temp0 = __action169( text, __0, __1, ); let __temp0 = (__start0, __temp0, __end0); __action177( text, __temp0, ) } #[allow(unused_variables)] fn __action241< 'input, >( text: &'input str, __0: (usize, ::std::vec::Vec<(Expression, Vec)>, usize), __1: (usize, (Expression, Vec), usize), __2: (usize, Tok<'input>, usize), ) -> ::std::vec::Vec<(Expression, Vec)> { let __start0 = __1.0.clone(); let __end0 = __2.2.clone(); let __temp0 = __action169( text, __1, __2, ); let __temp0 = (__start0, __temp0, __end0); __action178( text, __0, __temp0, ) } #[allow(unused_variables)] fn __action242< 'input, >( text: &'input str, __0: (usize, ::std::option::Option<(Expression, Vec)>, usize), ) -> Vec<(Expression, Vec)> { let __start0 = __0.0.clone(); let __end0 = __0.0.clone(); let __temp0 = __action167( text, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); __action69( text, __temp0, __0, ) } #[allow(unused_variables)] fn __action243< 'input, >( text: &'input str, __0: (usize, ::std::vec::Vec<(Expression, Vec)>, usize), __1: (usize, ::std::option::Option<(Expression, Vec)>, usize), ) -> Vec<(Expression, Vec)> { let __start0 = __0.0.clone(); let __end0 = __0.2.clone(); let __temp0 = __action168( text, __0, ); let __temp0 = (__start0, __temp0, __end0); __action69( text, __temp0, __1, ) } #[allow(unused_variables)] fn __action244< 'input, >( text: &'input str, __0: (usize, Constant, usize), __1: (usize, Tok<'input>, usize), ) -> ::std::vec::Vec { let __start0 = __0.0.clone(); let __end0 = __1.2.clone(); let __temp0 = __action174( text, __0, __1, ); let __temp0 = (__start0, __temp0, __end0); __action175( text, __temp0, ) } #[allow(unused_variables)] fn __action245< 'input, >( text: &'input str, __0: (usize, ::std::vec::Vec, usize), __1: (usize, Constant, usize), __2: (usize, Tok<'input>, usize), ) -> ::std::vec::Vec { let __start0 = __1.0.clone(); let __end0 = __2.2.clone(); let __temp0 = __action174( text, __1, __2, ); let __temp0 = (__start0, __temp0, __end0); __action176( text, __0, __temp0, ) } #[allow(unused_variables)] fn __action246< 'input, >( text: &'input str, __0: (usize, ::std::option::Option, usize), ) -> Vec { let __start0 = __0.0.clone(); let __end0 = __0.0.clone(); let __temp0 = __action172( text, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); __action68( text, __temp0, __0, ) } #[allow(unused_variables)] fn __action247< 'input, >( text: &'input str, __0: (usize, ::std::vec::Vec, usize), __1: (usize, ::std::option::Option, usize), ) -> Vec { let __start0 = __0.0.clone(); let __end0 = __0.2.clone(); let __temp0 = __action173( text, __0, ); let __temp0 = (__start0, __temp0, __end0); __action68( text, __temp0, __1, ) } #[allow(unused_variables)] fn __action248< 'input, >( text: &'input str, __0: (usize, Expression, usize), __1: (usize, Tok<'input>, usize), ) -> ::std::vec::Vec { let __start0 = __0.0.clone(); let __end0 = __1.2.clone(); let __temp0 = __action142( text, __0, __1, ); let __temp0 = (__start0, __temp0, __end0); __action187( text, __temp0, ) } #[allow(unused_variables)] fn __action249< 'input, >( text: &'input str, __0: (usize, ::std::vec::Vec, usize), __1: (usize, Expression, usize), __2: (usize, Tok<'input>, usize), ) -> ::std::vec::Vec { let __start0 = __1.0.clone(); let __end0 = __2.2.clone(); let __temp0 = __action142( text, __1, __2, ); let __temp0 = (__start0, __temp0, __end0); __action188( text, __0, __temp0, ) } #[allow(unused_variables)] fn __action250< 'input, >( text: &'input str, __0: (usize, ::std::option::Option, usize), ) -> Vec { let __start0 = __0.0.clone(); let __end0 = __0.0.clone(); let __temp0 = __action140( text, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); __action96( text, __temp0, __0, ) } #[allow(unused_variables)] fn __action251< 'input, >( text: &'input str, __0: (usize, ::std::vec::Vec, usize), __1: (usize, ::std::option::Option, usize), ) -> Vec { let __start0 = __0.0.clone(); let __end0 = __0.2.clone(); let __temp0 = __action141( text, __0, ); let __temp0 = (__start0, __temp0, __end0); __action96( text, __temp0, __1, ) } #[allow(unused_variables)] fn __action252< 'input, >( text: &'input str, __0: (usize, Expression, usize), __1: (usize, MapExactAssoc, usize), __2: (usize, Expression, usize), ) -> Annotated<(Expression, MapExactAssoc, Expression)> { let __start0 = __0.0.clone(); let __end0 = __2.2.clone(); let __temp0 = __action92( text, __0, __1, __2, ); let __temp0 = (__start0, __temp0, __end0); __action90( text, __temp0, ) } #[allow(unused_variables)] fn __action253< 'input, >( text: &'input str, __0: (usize, Tok<'input>, usize), __1: (usize, Expression, usize), __2: (usize, MapExactAssoc, usize), __3: (usize, Expression, usize), __4: (usize, (), usize), __5: (usize, Tok<'input>, usize), ) -> Annotated<(Expression, MapExactAssoc, Expression)> { let __start0 = __1.0.clone(); let __end0 = __3.2.clone(); let __temp0 = __action92( text, __1, __2, __3, ); let __temp0 = (__start0, __temp0, __end0); __action91( text, __0, __temp0, __4, __5, ) } #[allow(unused_variables)] fn __action254< 'input, >( text: &'input str, __0: (usize, FunctionName, usize), __1: (usize, Tok<'input>, usize), ) -> ::std::vec::Vec { let __start0 = __0.0.clone(); let __end0 = __1.2.clone(); let __temp0 = __action122( text, __0, __1, ); let __temp0 = (__start0, __temp0, __end0); __action195( text, __temp0, ) } #[allow(unused_variables)] fn __action255< 'input, >( text: &'input str, __0: (usize, ::std::vec::Vec, usize), __1: (usize, FunctionName, usize), __2: (usize, Tok<'input>, usize), ) -> ::std::vec::Vec { let __start0 = __1.0.clone(); let __end0 = __2.2.clone(); let __temp0 = __action122( text, __1, __2, ); let __temp0 = (__start0, __temp0, __end0); __action196( text, __0, __temp0, ) } #[allow(unused_variables)] fn __action256< 'input, >( text: &'input str, __0: (usize, ::std::option::Option, usize), ) -> Vec { let __start0 = __0.0.clone(); let __end0 = __0.0.clone(); let __temp0 = __action120( text, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); __action111( text, __temp0, __0, ) } #[allow(unused_variables)] fn __action257< 'input, >( text: &'input str, __0: (usize, ::std::vec::Vec, usize), __1: (usize, ::std::option::Option, usize), ) -> Vec { let __start0 = __0.0.clone(); let __end0 = __0.2.clone(); let __temp0 = __action121( text, __0, ); let __temp0 = (__start0, __temp0, __end0); __action111( text, __temp0, __1, ) } #[allow(unused_variables)] fn __action258< 'input, >( text: &'input str, __0: (usize, FunctionName, usize), __1: (usize, Tok<'input>, usize), __2: (usize, Function, usize), ) -> ::std::vec::Vec<(FunctionName, Function)> { let __start0 = __0.0.clone(); let __end0 = __2.2.clone(); let __temp0 = __action82( text, __0, __1, __2, ); let __temp0 = (__start0, __temp0, __end0); __action80( text, __temp0, ) } #[allow(unused_variables)] fn __action259< 'input, >( text: &'input str, __0: (usize, ::std::vec::Vec<(FunctionName, Function)>, usize), __1: (usize, FunctionName, usize), __2: (usize, Tok<'input>, usize), __3: (usize, Function, usize), ) -> ::std::vec::Vec<(FunctionName, Function)> { let __start0 = __1.0.clone(); let __end0 = __3.2.clone(); let __temp0 = __action82( text, __1, __2, __3, ); let __temp0 = (__start0, __temp0, __end0); __action81( text, __0, __temp0, ) } #[allow(unused_variables)] fn __action260< 'input, >( text: &'input str, __0: (usize, (Annotated, Vec>), usize), __1: (usize, Tok<'input>, usize), ) -> ::std::vec::Vec<(Annotated, Vec>)> { let __start0 = __0.0.clone(); let __end0 = __1.2.clone(); let __temp0 = __action164( text, __0, __1, ); let __temp0 = (__start0, __temp0, __end0); __action179( text, __temp0, ) } #[allow(unused_variables)] fn __action261< 'input, >( text: &'input str, __0: (usize, ::std::vec::Vec<(Annotated, Vec>)>, usize), __1: (usize, (Annotated, Vec>), usize), __2: (usize, Tok<'input>, usize), ) -> ::std::vec::Vec<(Annotated, Vec>)> { let __start0 = __1.0.clone(); let __end0 = __2.2.clone(); let __temp0 = __action164( text, __1, __2, ); let __temp0 = (__start0, __temp0, __end0); __action180( text, __0, __temp0, ) } #[allow(unused_variables)] fn __action262< 'input, >( text: &'input str, __0: (usize, ::std::option::Option<(Annotated, Vec>)>, usize), ) -> Vec<(Annotated, Vec>)> { let __start0 = __0.0.clone(); let __end0 = __0.0.clone(); let __temp0 = __action162( text, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); __action70( text, __temp0, __0, ) } #[allow(unused_variables)] fn __action263< 'input, >( text: &'input str, __0: (usize, ::std::vec::Vec<(Annotated, Vec>)>, usize), __1: (usize, ::std::option::Option<(Annotated, Vec>)>, usize), ) -> Vec<(Annotated, Vec>)> { let __start0 = __0.0.clone(); let __end0 = __0.2.clone(); let __temp0 = __action163( text, __0, ); let __temp0 = (__start0, __temp0, __end0); __action70( text, __temp0, __1, ) } #[allow(unused_variables)] fn __action264< 'input, >( text: &'input str, __0: (usize, Annotated<(Expression, MapExactAssoc, Expression)>, usize), ) -> Vec> { let __start0 = __0.0.clone(); let __end0 = __0.2.clone(); let __temp0 = __action143( text, __0, ); let __temp0 = (__start0, __temp0, __end0); __action218( text, __temp0, ) } #[allow(unused_variables)] fn __action265< 'input, >( text: &'input str, __lookbehind: &usize, __lookahead: &usize, ) -> Vec> { let __start0 = __lookbehind.clone(); let __end0 = __lookahead.clone(); let __temp0 = __action144( text, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); __action218( text, __temp0, ) } #[allow(unused_variables)] fn __action266< 'input, >( text: &'input str, __0: (usize, ::std::vec::Vec>, usize), __1: (usize, Annotated<(Expression, MapExactAssoc, Expression)>, usize), ) -> Vec> { let __start0 = __1.0.clone(); let __end0 = __1.2.clone(); let __temp0 = __action143( text, __1, ); let __temp0 = (__start0, __temp0, __end0); __action219( text, __0, __temp0, ) } #[allow(unused_variables)] fn __action267< 'input, >( text: &'input str, __0: (usize, ::std::vec::Vec>, usize), ) -> Vec> { let __start0 = __0.2.clone(); let __end0 = __0.2.clone(); let __temp0 = __action144( text, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); __action219( text, __0, __temp0, ) } #[allow(unused_variables)] fn __action268< 'input, >( text: &'input str, __0: (usize, Tok<'input>, usize), __1: (usize, Expression, usize), __2: (usize, Tok<'input>, usize), __3: (usize, Tok<'input>, usize), ) -> SingleExpression { let __start0 = __2.2.clone(); let __end0 = __3.0.clone(); let __temp0 = __action85( text, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); __action27( text, __0, __1, __2, __temp0, __3, ) } #[allow(unused_variables)] fn __action269< 'input, >( text: &'input str, __0: (usize, Tok<'input>, usize), __1: (usize, Expression, usize), __2: (usize, Tok<'input>, usize), __3: (usize, ::std::vec::Vec>, usize), __4: (usize, Tok<'input>, usize), ) -> SingleExpression { let __start0 = __3.0.clone(); let __end0 = __3.2.clone(); let __temp0 = __action86( text, __3, ); let __temp0 = (__start0, __temp0, __end0); __action27( text, __0, __1, __2, __temp0, __4, ) } #[allow(unused_variables)] fn __action270< 'input, >( text: &'input str, __0: (usize, Tok<'input>, usize), __1: (usize, Tok<'input>, usize), __2: (usize, Expression, usize), __3: (usize, Tok<'input>, usize), __4: (usize, Expression, usize), ) -> SingleExpression { let __start0 = __0.2.clone(); let __end0 = __1.0.clone(); let __temp0 = __action85( text, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); __action32( text, __0, __temp0, __1, __2, __3, __4, ) } #[allow(unused_variables)] fn __action271< 'input, >( text: &'input str, __0: (usize, Tok<'input>, usize), __1: (usize, ::std::vec::Vec>, usize), __2: (usize, Tok<'input>, usize), __3: (usize, Expression, usize), __4: (usize, Tok<'input>, usize), __5: (usize, Expression, usize), ) -> SingleExpression { let __start0 = __1.0.clone(); let __end0 = __1.2.clone(); let __temp0 = __action86( text, __1, ); let __temp0 = (__start0, __temp0, __end0); __action32( text, __0, __temp0, __2, __3, __4, __5, ) } #[allow(unused_variables)] fn __action272< 'input, >( text: &'input str, __0: (usize, Annotated, usize), ) -> Vec> { let __start0 = __0.0.clone(); let __end0 = __0.2.clone(); let __temp0 = __action133( text, __0, ); let __temp0 = (__start0, __temp0, __end0); __action222( text, __temp0, ) } #[allow(unused_variables)] fn __action273< 'input, >( text: &'input str, __lookbehind: &usize, __lookahead: &usize, ) -> Vec> { let __start0 = __lookbehind.clone(); let __end0 = __lookahead.clone(); let __temp0 = __action134( text, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); __action222( text, __temp0, ) } #[allow(unused_variables)] fn __action274< 'input, >( text: &'input str, __0: (usize, ::std::vec::Vec>, usize), __1: (usize, Annotated, usize), ) -> Vec> { let __start0 = __1.0.clone(); let __end0 = __1.2.clone(); let __temp0 = __action133( text, __1, ); let __temp0 = (__start0, __temp0, __end0); __action223( text, __0, __temp0, ) } #[allow(unused_variables)] fn __action275< 'input, >( text: &'input str, __0: (usize, ::std::vec::Vec>, usize), ) -> Vec> { let __start0 = __0.2.clone(); let __end0 = __0.2.clone(); let __temp0 = __action134( text, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); __action223( text, __0, __temp0, ) } #[allow(unused_variables)] fn __action276< 'input, >( text: &'input str, __0: (usize, Annotated, usize), ) -> Vec> { let __start0 = __0.0.clone(); let __end0 = __0.2.clone(); let __temp0 = __action128( text, __0, ); let __temp0 = (__start0, __temp0, __end0); __action226( text, __temp0, ) } #[allow(unused_variables)] fn __action277< 'input, >( text: &'input str, __lookbehind: &usize, __lookahead: &usize, ) -> Vec> { let __start0 = __lookbehind.clone(); let __end0 = __lookahead.clone(); let __temp0 = __action129( text, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); __action226( text, __temp0, ) } #[allow(unused_variables)] fn __action278< 'input, >( text: &'input str, __0: (usize, ::std::vec::Vec>, usize), __1: (usize, Annotated, usize), ) -> Vec> { let __start0 = __1.0.clone(); let __end0 = __1.2.clone(); let __temp0 = __action128( text, __1, ); let __temp0 = (__start0, __temp0, __end0); __action227( text, __0, __temp0, ) } #[allow(unused_variables)] fn __action279< 'input, >( text: &'input str, __0: (usize, ::std::vec::Vec>, usize), ) -> Vec> { let __start0 = __0.2.clone(); let __end0 = __0.2.clone(); let __temp0 = __action129( text, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); __action227( text, __0, __temp0, ) } #[allow(unused_variables)] fn __action280< 'input, >( text: &'input str, __0: (usize, Annotated, usize), ) -> Vec> { let __start0 = __0.0.clone(); let __end0 = __0.2.clone(); let __temp0 = __action150( text, __0, ); let __temp0 = (__start0, __temp0, __end0); __action230( text, __temp0, ) } #[allow(unused_variables)] fn __action281< 'input, >( text: &'input str, __lookbehind: &usize, __lookahead: &usize, ) -> Vec> { let __start0 = __lookbehind.clone(); let __end0 = __lookahead.clone(); let __temp0 = __action151( text, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); __action230( text, __temp0, ) } #[allow(unused_variables)] fn __action282< 'input, >( text: &'input str, __0: (usize, ::std::vec::Vec>, usize), __1: (usize, Annotated, usize), ) -> Vec> { let __start0 = __1.0.clone(); let __end0 = __1.2.clone(); let __temp0 = __action150( text, __1, ); let __temp0 = (__start0, __temp0, __end0); __action231( text, __0, __temp0, ) } #[allow(unused_variables)] fn __action283< 'input, >( text: &'input str, __0: (usize, ::std::vec::Vec>, usize), ) -> Vec> { let __start0 = __0.2.clone(); let __end0 = __0.2.clone(); let __temp0 = __action151( text, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); __action231( text, __0, __temp0, ) } #[allow(unused_variables)] fn __action284< 'input, >( text: &'input str, __0: (usize, Annotated<(Annotated, Annotated)>, usize), ) -> Vec, Annotated)>> { let __start0 = __0.0.clone(); let __end0 = __0.2.clone(); let __temp0 = __action155( text, __0, ); let __temp0 = (__start0, __temp0, __end0); __action234( text, __temp0, ) } #[allow(unused_variables)] fn __action285< 'input, >( text: &'input str, __lookbehind: &usize, __lookahead: &usize, ) -> Vec, Annotated)>> { let __start0 = __lookbehind.clone(); let __end0 = __lookahead.clone(); let __temp0 = __action156( text, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); __action234( text, __temp0, ) } #[allow(unused_variables)] fn __action286< 'input, >( text: &'input str, __0: (usize, ::std::vec::Vec, Annotated)>>, usize), __1: (usize, Annotated<(Annotated, Annotated)>, usize), ) -> Vec, Annotated)>> { let __start0 = __1.0.clone(); let __end0 = __1.2.clone(); let __temp0 = __action155( text, __1, ); let __temp0 = (__start0, __temp0, __end0); __action235( text, __0, __temp0, ) } #[allow(unused_variables)] fn __action287< 'input, >( text: &'input str, __0: (usize, ::std::vec::Vec, Annotated)>>, usize), ) -> Vec, Annotated)>> { let __start0 = __0.2.clone(); let __end0 = __0.2.clone(); let __temp0 = __action156( text, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); __action235( text, __0, __temp0, ) } #[allow(unused_variables)] fn __action288< 'input, >( text: &'input str, __0: (usize, (Expression, Vec), usize), ) -> Vec<(Expression, Vec)> { let __start0 = __0.0.clone(); let __end0 = __0.2.clone(); let __temp0 = __action165( text, __0, ); let __temp0 = (__start0, __temp0, __end0); __action242( text, __temp0, ) } #[allow(unused_variables)] fn __action289< 'input, >( text: &'input str, __lookbehind: &usize, __lookahead: &usize, ) -> Vec<(Expression, Vec)> { let __start0 = __lookbehind.clone(); let __end0 = __lookahead.clone(); let __temp0 = __action166( text, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); __action242( text, __temp0, ) } #[allow(unused_variables)] fn __action290< 'input, >( text: &'input str, __0: (usize, ::std::vec::Vec<(Expression, Vec)>, usize), __1: (usize, (Expression, Vec), usize), ) -> Vec<(Expression, Vec)> { let __start0 = __1.0.clone(); let __end0 = __1.2.clone(); let __temp0 = __action165( text, __1, ); let __temp0 = (__start0, __temp0, __end0); __action243( text, __0, __temp0, ) } #[allow(unused_variables)] fn __action291< 'input, >( text: &'input str, __0: (usize, ::std::vec::Vec<(Expression, Vec)>, usize), ) -> Vec<(Expression, Vec)> { let __start0 = __0.2.clone(); let __end0 = __0.2.clone(); let __temp0 = __action166( text, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); __action243( text, __0, __temp0, ) } #[allow(unused_variables)] fn __action292< 'input, >( text: &'input str, __0: (usize, Constant, usize), ) -> Vec { let __start0 = __0.0.clone(); let __end0 = __0.2.clone(); let __temp0 = __action170( text, __0, ); let __temp0 = (__start0, __temp0, __end0); __action246( text, __temp0, ) } #[allow(unused_variables)] fn __action293< 'input, >( text: &'input str, __lookbehind: &usize, __lookahead: &usize, ) -> Vec { let __start0 = __lookbehind.clone(); let __end0 = __lookahead.clone(); let __temp0 = __action171( text, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); __action246( text, __temp0, ) } #[allow(unused_variables)] fn __action294< 'input, >( text: &'input str, __0: (usize, ::std::vec::Vec, usize), __1: (usize, Constant, usize), ) -> Vec { let __start0 = __1.0.clone(); let __end0 = __1.2.clone(); let __temp0 = __action170( text, __1, ); let __temp0 = (__start0, __temp0, __end0); __action247( text, __0, __temp0, ) } #[allow(unused_variables)] fn __action295< 'input, >( text: &'input str, __0: (usize, ::std::vec::Vec, usize), ) -> Vec { let __start0 = __0.2.clone(); let __end0 = __0.2.clone(); let __temp0 = __action171( text, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); __action247( text, __0, __temp0, ) } #[allow(unused_variables)] fn __action296< 'input, >( text: &'input str, __0: (usize, Expression, usize), ) -> Vec { let __start0 = __0.0.clone(); let __end0 = __0.2.clone(); let __temp0 = __action138( text, __0, ); let __temp0 = (__start0, __temp0, __end0); __action250( text, __temp0, ) } #[allow(unused_variables)] fn __action297< 'input, >( text: &'input str, __lookbehind: &usize, __lookahead: &usize, ) -> Vec { let __start0 = __lookbehind.clone(); let __end0 = __lookahead.clone(); let __temp0 = __action139( text, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); __action250( text, __temp0, ) } #[allow(unused_variables)] fn __action298< 'input, >( text: &'input str, __0: (usize, ::std::vec::Vec, usize), __1: (usize, Expression, usize), ) -> Vec { let __start0 = __1.0.clone(); let __end0 = __1.2.clone(); let __temp0 = __action138( text, __1, ); let __temp0 = (__start0, __temp0, __end0); __action251( text, __0, __temp0, ) } #[allow(unused_variables)] fn __action299< 'input, >( text: &'input str, __0: (usize, ::std::vec::Vec, usize), ) -> Vec { let __start0 = __0.2.clone(); let __end0 = __0.2.clone(); let __temp0 = __action139( text, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); __action251( text, __0, __temp0, ) } #[allow(unused_variables)] fn __action300< 'input, >( text: &'input str, __0: (usize, Tok<'input>, usize), __1: (usize, Atom, usize), __2: (usize, Vec, usize), __3: (usize, Tok<'input>, usize), __4: (usize, Vec<(Atom, Constant)>, usize), __5: (usize, Tok<'input>, usize), ) -> Module { let __start0 = __4.2.clone(); let __end0 = __5.0.clone(); let __temp0 = __action112( text, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); __action5( text, __0, __1, __2, __3, __4, __temp0, __5, ) } #[allow(unused_variables)] fn __action301< 'input, >( text: &'input str, __0: (usize, Tok<'input>, usize), __1: (usize, Atom, usize), __2: (usize, Vec, usize), __3: (usize, Tok<'input>, usize), __4: (usize, Vec<(Atom, Constant)>, usize), __5: (usize, ::std::vec::Vec, usize), __6: (usize, Tok<'input>, usize), ) -> Module { let __start0 = __5.0.clone(); let __end0 = __5.2.clone(); let __temp0 = __action113( text, __5, ); let __temp0 = (__start0, __temp0, __end0); __action5( text, __0, __1, __2, __3, __4, __temp0, __6, ) } #[allow(unused_variables)] fn __action302< 'input, >( text: &'input str, __0: (usize, FunctionName, usize), ) -> Vec { let __start0 = __0.0.clone(); let __end0 = __0.2.clone(); let __temp0 = __action118( text, __0, ); let __temp0 = (__start0, __temp0, __end0); __action256( text, __temp0, ) } #[allow(unused_variables)] fn __action303< 'input, >( text: &'input str, __lookbehind: &usize, __lookahead: &usize, ) -> Vec { let __start0 = __lookbehind.clone(); let __end0 = __lookahead.clone(); let __temp0 = __action119( text, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); __action256( text, __temp0, ) } #[allow(unused_variables)] fn __action304< 'input, >( text: &'input str, __0: (usize, ::std::vec::Vec, usize), __1: (usize, FunctionName, usize), ) -> Vec { let __start0 = __1.0.clone(); let __end0 = __1.2.clone(); let __temp0 = __action118( text, __1, ); let __temp0 = (__start0, __temp0, __end0); __action257( text, __0, __temp0, ) } #[allow(unused_variables)] fn __action305< 'input, >( text: &'input str, __0: (usize, ::std::vec::Vec, usize), ) -> Vec { let __start0 = __0.2.clone(); let __end0 = __0.2.clone(); let __temp0 = __action119( text, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); __action257( text, __0, __temp0, ) } #[allow(unused_variables)] fn __action306< 'input, >( text: &'input str, __0: (usize, Annotated, usize), __1: (usize, Tok<'input>, usize), __2: (usize, Annotated, usize), ) -> Annotated { let __start0 = __0.0.clone(); let __end0 = __2.2.clone(); let __temp0 = __action44( text, __0, __1, __2, ); let __temp0 = (__start0, __temp0, __end0); __action77( text, __temp0, ) } #[allow(unused_variables)] fn __action307< 'input, >( text: &'input str, __0: (usize, Atom, usize), ) -> Annotated { let __start0 = __0.0.clone(); let __end0 = __0.2.clone(); let __temp0 = __action45( text, __0, ); let __temp0 = (__start0, __temp0, __end0); __action77( text, __temp0, ) } #[allow(unused_variables)] fn __action308< 'input, >( text: &'input str, __0: (usize, AtomicTerm, usize), ) -> Annotated { let __start0 = __0.0.clone(); let __end0 = __0.2.clone(); let __temp0 = __action46( text, __0, ); let __temp0 = (__start0, __temp0, __end0); __action77( text, __temp0, ) } #[allow(unused_variables)] fn __action309< 'input, >( text: &'input str, __0: (usize, Vec<(Annotated, Vec>)>, usize), ) -> Annotated { let __start0 = __0.0.clone(); let __end0 = __0.2.clone(); let __temp0 = __action47( text, __0, ); let __temp0 = (__start0, __temp0, __end0); __action77( text, __temp0, ) } #[allow(unused_variables)] fn __action310< 'input, >( text: &'input str, __0: (usize, Tok<'input>, usize), __1: (usize, Vec>, usize), __2: (usize, Tok<'input>, usize), ) -> Annotated { let __start0 = __0.0.clone(); let __end0 = __2.2.clone(); let __temp0 = __action48( text, __0, __1, __2, ); let __temp0 = (__start0, __temp0, __end0); __action77( text, __temp0, ) } #[allow(unused_variables)] fn __action311< 'input, >( text: &'input str, __0: (usize, Tok<'input>, usize), __1: (usize, Vec, Annotated)>>, usize), __2: (usize, Tok<'input>, usize), ) -> Annotated { let __start0 = __0.0.clone(); let __end0 = __2.2.clone(); let __temp0 = __action49( text, __0, __1, __2, ); let __temp0 = (__start0, __temp0, __end0); __action77( text, __temp0, ) } #[allow(unused_variables)] fn __action312< 'input, >( text: &'input str, __0: (usize, Tok<'input>, usize), __1: (usize, Vec>, usize), __2: (usize, Tok<'input>, usize), __3: (usize, Annotated, usize), __4: (usize, Tok<'input>, usize), ) -> Annotated { let __start0 = __0.0.clone(); let __end0 = __4.2.clone(); let __temp0 = __action198( text, __0, __1, __2, __3, __4, ); let __temp0 = (__start0, __temp0, __end0); __action77( text, __temp0, ) } #[allow(unused_variables)] fn __action313< 'input, >( text: &'input str, __0: (usize, Tok<'input>, usize), __1: (usize, Vec>, usize), __2: (usize, Tok<'input>, usize), ) -> Annotated { let __start0 = __0.0.clone(); let __end0 = __2.2.clone(); let __temp0 = __action199( text, __0, __1, __2, ); let __temp0 = (__start0, __temp0, __end0); __action77( text, __temp0, ) } #[allow(unused_variables)] fn __action314< 'input, >( text: &'input str, __0: (usize, Tok<'input>, usize), __1: (usize, Annotated, usize), __2: (usize, Tok<'input>, usize), __3: (usize, Annotated, usize), __4: (usize, (), usize), __5: (usize, Tok<'input>, usize), ) -> Annotated { let __start0 = __1.0.clone(); let __end0 = __3.2.clone(); let __temp0 = __action44( text, __1, __2, __3, ); let __temp0 = (__start0, __temp0, __end0); __action78( text, __0, __temp0, __4, __5, ) } #[allow(unused_variables)] fn __action315< 'input, >( text: &'input str, __0: (usize, Tok<'input>, usize), __1: (usize, Atom, usize), __2: (usize, (), usize), __3: (usize, Tok<'input>, usize), ) -> Annotated { let __start0 = __1.0.clone(); let __end0 = __1.2.clone(); let __temp0 = __action45( text, __1, ); let __temp0 = (__start0, __temp0, __end0); __action78( text, __0, __temp0, __2, __3, ) } #[allow(unused_variables)] fn __action316< 'input, >( text: &'input str, __0: (usize, Tok<'input>, usize), __1: (usize, AtomicTerm, usize), __2: (usize, (), usize), __3: (usize, Tok<'input>, usize), ) -> Annotated { let __start0 = __1.0.clone(); let __end0 = __1.2.clone(); let __temp0 = __action46( text, __1, ); let __temp0 = (__start0, __temp0, __end0); __action78( text, __0, __temp0, __2, __3, ) } #[allow(unused_variables)] fn __action317< 'input, >( text: &'input str, __0: (usize, Tok<'input>, usize), __1: (usize, Vec<(Annotated, Vec>)>, usize), __2: (usize, (), usize), __3: (usize, Tok<'input>, usize), ) -> Annotated { let __start0 = __1.0.clone(); let __end0 = __1.2.clone(); let __temp0 = __action47( text, __1, ); let __temp0 = (__start0, __temp0, __end0); __action78( text, __0, __temp0, __2, __3, ) } #[allow(unused_variables)] fn __action318< 'input, >( text: &'input str, __0: (usize, Tok<'input>, usize), __1: (usize, Tok<'input>, usize), __2: (usize, Vec>, usize), __3: (usize, Tok<'input>, usize), __4: (usize, (), usize), __5: (usize, Tok<'input>, usize), ) -> Annotated { let __start0 = __1.0.clone(); let __end0 = __3.2.clone(); let __temp0 = __action48( text, __1, __2, __3, ); let __temp0 = (__start0, __temp0, __end0); __action78( text, __0, __temp0, __4, __5, ) } #[allow(unused_variables)] fn __action319< 'input, >( text: &'input str, __0: (usize, Tok<'input>, usize), __1: (usize, Tok<'input>, usize), __2: (usize, Vec, Annotated)>>, usize), __3: (usize, Tok<'input>, usize), __4: (usize, (), usize), __5: (usize, Tok<'input>, usize), ) -> Annotated { let __start0 = __1.0.clone(); let __end0 = __3.2.clone(); let __temp0 = __action49( text, __1, __2, __3, ); let __temp0 = (__start0, __temp0, __end0); __action78( text, __0, __temp0, __4, __5, ) } #[allow(unused_variables)] fn __action320< 'input, >( text: &'input str, __0: (usize, Tok<'input>, usize), __1: (usize, Tok<'input>, usize), __2: (usize, Vec>, usize), __3: (usize, Tok<'input>, usize), __4: (usize, Annotated, usize), __5: (usize, Tok<'input>, usize), __6: (usize, (), usize), __7: (usize, Tok<'input>, usize), ) -> Annotated { let __start0 = __1.0.clone(); let __end0 = __5.2.clone(); let __temp0 = __action198( text, __1, __2, __3, __4, __5, ); let __temp0 = (__start0, __temp0, __end0); __action78( text, __0, __temp0, __6, __7, ) } #[allow(unused_variables)] fn __action321< 'input, >( text: &'input str, __0: (usize, Tok<'input>, usize), __1: (usize, Tok<'input>, usize), __2: (usize, Vec>, usize), __3: (usize, Tok<'input>, usize), __4: (usize, (), usize), __5: (usize, Tok<'input>, usize), ) -> Annotated { let __start0 = __1.0.clone(); let __end0 = __3.2.clone(); let __temp0 = __action199( text, __1, __2, __3, ); let __temp0 = (__start0, __temp0, __end0); __action78( text, __0, __temp0, __4, __5, ) } #[allow(unused_variables)] fn __action322< 'input, >( text: &'input str, __0: (usize, (Annotated, Vec>), usize), ) -> Vec<(Annotated, Vec>)> { let __start0 = __0.0.clone(); let __end0 = __0.2.clone(); let __temp0 = __action160( text, __0, ); let __temp0 = (__start0, __temp0, __end0); __action262( text, __temp0, ) } #[allow(unused_variables)] fn __action323< 'input, >( text: &'input str, __lookbehind: &usize, __lookahead: &usize, ) -> Vec<(Annotated, Vec>)> { let __start0 = __lookbehind.clone(); let __end0 = __lookahead.clone(); let __temp0 = __action161( text, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); __action262( text, __temp0, ) } #[allow(unused_variables)] fn __action324< 'input, >( text: &'input str, __0: (usize, ::std::vec::Vec<(Annotated, Vec>)>, usize), __1: (usize, (Annotated, Vec>), usize), ) -> Vec<(Annotated, Vec>)> { let __start0 = __1.0.clone(); let __end0 = __1.2.clone(); let __temp0 = __action160( text, __1, ); let __temp0 = (__start0, __temp0, __end0); __action263( text, __0, __temp0, ) } #[allow(unused_variables)] fn __action325< 'input, >( text: &'input str, __0: (usize, ::std::vec::Vec<(Annotated, Vec>)>, usize), ) -> Vec<(Annotated, Vec>)> { let __start0 = __0.2.clone(); let __end0 = __0.2.clone(); let __temp0 = __action161( text, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); __action263( text, __0, __temp0, ) } pub trait __ToTriple<'input, > { fn to_triple(value: Self) -> Result<(usize,Tok<'input>,usize), __lalrpop_util::ParseError, ()>>; } impl<'input, > __ToTriple<'input, > for (usize, Tok<'input>, usize) { fn to_triple(value: Self) -> Result<(usize,Tok<'input>,usize), __lalrpop_util::ParseError, ()>> { Ok(value) } } impl<'input, > __ToTriple<'input, > for Result<(usize, Tok<'input>, usize), ()> { fn to_triple(value: Self) -> Result<(usize,Tok<'input>,usize), __lalrpop_util::ParseError, ()>> { match value { Ok(v) => Ok(v), Err(error) => Err(__lalrpop_util::ParseError::User { error }), } } } ================================================ FILE: libeir_syntax_core/src/parser/mod.rs ================================================ use crate::ast::{ Annotated, Module }; use crate::lexer::{ Tokenizer, Tok }; mod grammar; pub fn parse<'input>(text: &'input str) -> Result, ::lalrpop_util::ParseError, ()>> { let tokenizer = Tokenizer::new(text); let parser = grammar::AnnotatedModuleParser::new(); parser.parse(text, tokenizer) } ================================================ FILE: libeir_syntax_erl/.gitignore ================================================ /target **/*.rs.bk Cargo.lock ================================================ FILE: libeir_syntax_erl/Cargo.toml ================================================ [package] name = "libeir_syntax_erl" version = "0.1.0" authors = ["Paul Schoenfelder ", "Luke Imhoff "] readme = "README.md" publish = false edition = "2018" license = "MIT OR Apache-2.0" build = "build.rs" [dependencies] libeir_diagnostics = { path = "../libeir_diagnostics" } libeir_ir = { path = "../libeir_ir" } libeir_intern = { path = "../libeir_intern" } libeir_util_datastructures = { path = "../util/libeir_util_datastructures" } libeir_util_number = { path = "../util/libeir_util_number" } libeir_util_binary = { path = "../util/libeir_util_binary" } libeir_util_parse = { path = "../util/libeir_util_parse" } libeir_util_parse_listing = { path = "../util/libeir_util_parse_listing" } codespan-reporting = "0.9" cranelift-entity = "0.56.0" rustc-hash = "1.0" lalrpop-util = "0.17" glob = "0.2" termcolor = "0.3" snafu = "0.5" itertools = "0.8" lazy_static = "1.2" either = "1.5" bumpalo = { git = "https://github.com/hansihe/bumpalo", features = ["nightly"] } # [dependencies.rug] # version = "1.2" # default-features = false # features = ["integer", "float", "rand"] [dev-dependencies] pretty_assertions = "0.5" [build-dependencies] lalrpop = "0.17" ================================================ FILE: libeir_syntax_erl/build.rs ================================================ extern crate lalrpop; fn main() { lalrpop::Configuration::new() .use_cargo_dir_conventions() .process_file("src/parser/grammar.lalrpop") .unwrap(); println!("cargo:rerun-if-changed=src/parser/grammar.lalrpop"); } ================================================ FILE: libeir_syntax_erl/src/abstr/lower.rs ================================================ use libeir_diagnostics::SourceSpan; use libeir_intern::Ident; use libeir_ir::ToPrimitive; use libeir_ir::binary::BinaryEntrySpecifier; use libeir_util_number::Float; use libeir_util_parse::MessageIgnore; use std::convert::TryInto; use crate::ast::Name; use crate::parser::ast; use libeir_util_parse_listing::ast as aast; fn to_list_expr( id_gen: &mut ast::NodeIdGenerator, span: SourceSpan, mut list: Vec, ) -> ast::Expr { let mut acc = ast::Expr::Nil(ast::Nil(span, id_gen.next())); for elem in list.drain(..).rev() { acc = ast::Expr::Cons(ast::Cons { id: id_gen.next(), span, head: Box::new(elem), tail: Box::new(acc), }); } acc } pub fn lower(root: &aast::Root) -> ast::Module { let mut toplevel: Vec = Vec::new(); let mut id_gen = ast::NodeIdGenerator::new(); let module_span = root.span(); let mut module_name = None; let mut eof = false; for item in root.items.iter() { let tuple = item.tuple().unwrap(); let name_ident = tuple.entries[0].atom().unwrap(); let name = name_ident.as_str(); let _line = tuple.entries[1].integer().unwrap(); assert!(!eof); match &*name { "attribute" => { let attr_ident = tuple.entries[2].atom().unwrap(); let attr = attr_ident.as_str(); match &*attr { "file" => (), "module" => { module_name = Some(tuple.entries[3].atom().unwrap()); } "export" => { let exports = tuple.entries[3] .list_iter() .unwrap() .map(|item| { let item_tup = item.tuple().unwrap(); let name = item_tup.entries[0].atom().unwrap(); let arity = item_tup.entries[1].integer().unwrap(); ast::PartiallyResolvedFunctionName { span: item_tup.span, id: id_gen.next(), function: name, arity: arity.integer.to_usize().unwrap(), } }) .collect(); toplevel.push(ast::TopLevel::Attribute(ast::Attribute::Export( tuple.span, exports, ))); } "compile" => { let opts = tuple.entries[3] .list_iter() .unwrap() .map(|item| match item { aast::Item::Atom(ident) => { ast::Expr::Literal(ast::Literal::Atom(id_gen.next(), *ident)) } _ => unimplemented!("{:?}", item), }) .collect(); toplevel.push(ast::TopLevel::Attribute(ast::Attribute::Compile( tuple.span, to_list_expr(&mut id_gen, tuple.span, opts), ))) } "spec" => { continue; } "dialyzer" => { continue; } "export_type" => { continue; } "type" => { continue; } "opaque" => { continue; //let inner_tup = tuple.entries[3].tuple().unwrap(); //let def = ast::TypeDef { // span, // opaque: true, // name: inner_tup.entries[0].atom().unwrap(), //}; //toplevel.push(ast::TopLevel::Attribute( // ast::Attribute::Type(def))); } "record" => { let rec_tup = tuple.entries[3].tuple().unwrap(); let name = rec_tup.entries[0].atom().unwrap(); let fields = rec_tup.entries[1] .list_iter() .unwrap() .map(|v| lower_record_field(&mut id_gen, v)) .collect(); let record = ast::Record { span: rec_tup.span, id: id_gen.next(), name, fields, }; toplevel.push(ast::TopLevel::Record(record)); } "behaviour" => toplevel.push(ast::TopLevel::Attribute( ast::Attribute::Behaviour(tuple.span, tuple.entries[3].atom().unwrap()), )), n => unimplemented!("attribute {} {:?}", n, tuple), } } "function" => { let fun_name = tuple.entries[2].atom().unwrap(); let fun_arity = tuple.entries[3] .integer() .unwrap() .integer .to_usize() .unwrap(); let clauses = tuple.entries[4] .list_iter() .unwrap() .map(|clause| lower_function_clause(&mut id_gen, clause)) .collect(); toplevel.push(ast::TopLevel::Function(ast::NamedFunction { span: tuple.span, id: id_gen.next(), name: Name::Atom(fun_name), arity: fun_arity, clauses, spec: None, })); } "eof" => { eof = true; } n => unimplemented!("{}", n), } } let mut errors = MessageIgnore::new(); let module = ast::Module::new( &mut errors, module_span, &mut id_gen, module_name.unwrap(), toplevel, ); assert!(!errors.failed()); module } fn lower_record_field(gen: &mut ast::NodeIdGenerator, tup_item: &aast::Item) -> ast::RecordField { let tup = tup_item.tuple().unwrap(); assert!(&*tup.entries[0].atom().unwrap().as_str() == "record_field"); assert!(tup.entries.len() == 3 || tup.entries.len() == 4); let name = atom(&tup.entries[2]); let value = tup.entries.get(3).map(|v| lower_expr(gen, v)); ast::RecordField { span: tup.span, id: gen.next(), name, value, ty: None, } } fn lower_function_clause( gen: &mut ast::NodeIdGenerator, clause: &aast::Item, ) -> ast::FunctionClause { let tup = clause.tuple().unwrap(); assert!(tup.entries[0].atom().unwrap().as_str() == "clause"); let _line = tup.entries[1].integer().unwrap(); let params = &tup.entries[2]; let guard = &tup.entries[3]; let body = &tup.entries[4]; let params_n: Vec<_> = params .list_iter() .unwrap() .map(|param| lower_expr(gen, param)) .collect(); let guard_n = lower_guards(gen, guard); let body_n = lower_body(gen, body); ast::FunctionClause { span: clause.span(), name: None, params: params_n, guard: guard_n, body: body_n, } } fn lower_clause(gen: &mut ast::NodeIdGenerator, clause: &aast::Item) -> ast::Clause { let tup = clause.tuple().unwrap(); assert!(tup.entries[0].atom().unwrap().as_str() == "clause"); let _line = tup.entries[1].integer().unwrap(); let pattern = &tup.entries[2]; let guard = &tup.entries[3]; let body = &tup.entries[4]; let mut patterns = pattern.list_iter().unwrap(); let pattern_n = lower_expr(gen, patterns.next().unwrap()); assert!(patterns.next().is_none()); let guard_n = lower_guards(gen, guard); let body_n = lower_body(gen, body); ast::Clause { span: clause.span(), id: gen.next(), pattern: pattern_n, guard: guard_n, body: body_n, } } fn lower_if_clause(gen: &mut ast::NodeIdGenerator, clause: &aast::Item) -> ast::IfClause { let tup = clause.tuple().unwrap(); assert!(tup.entries[0].atom().unwrap().as_str() == "clause"); let _line = tup.entries[1].integer().unwrap(); assert!(tup.entries[2].list_iter().unwrap().count() == 0); let guard = &tup.entries[3]; let body = &tup.entries[4]; let guard_n = lower_guards(gen, guard); let body_n = lower_body(gen, body); ast::IfClause { span: clause.span(), id: gen.next(), guards: guard_n.unwrap(), body: body_n, } } fn lower_try_clause(gen: &mut ast::NodeIdGenerator, clause: &aast::Item) -> ast::TryClause { let tup = clause.tuple().unwrap(); assert!(tup.entries[0].atom().unwrap().as_str() == "clause"); let _line = tup.entries[1].integer().unwrap(); let pattern = &tup.entries[2]; let guard = &tup.entries[3]; let body = &tup.entries[4]; let mut patterns = pattern.list_iter().unwrap(); let pattern = patterns.next().unwrap(); assert!(patterns.next().is_none()); let patterns_tup_cont = pattern.tuple().unwrap(); assert!(patterns_tup_cont.entries.len() == 3); assert!(patterns_tup_cont.entries[0].atom().unwrap().as_str() == "tuple"); let mut patterns_tup = patterns_tup_cont.entries[2].list_iter().unwrap(); let err_kind = patterns_tup.next().unwrap(); let err_error = patterns_tup.next().unwrap(); let err_trace = patterns_tup.next().unwrap(); assert!(patterns_tup.next().is_none()); let err_kind_tup = err_kind.tuple().unwrap(); let err_kind_name = match &*err_kind_tup.entries[0].atom().unwrap().as_str() { "var" => ast::Name::Var(err_kind_tup.entries[2].atom().unwrap()), "atom" => ast::Name::Atom(err_kind_tup.entries[2].atom().unwrap()), _ => panic!(), }; let err_trace_tup = err_trace.tuple().unwrap(); assert!(&*err_trace_tup.entries[0].atom().unwrap().as_str() == "var"); let err_trace_ident = err_trace_tup.entries[2].atom().unwrap(); let guard_n = lower_guards(gen, guard); let body_n = lower_body(gen, body); ast::TryClause { span: clause.span(), id: gen.next(), kind: err_kind_name, error: lower_expr(gen, err_error), trace: err_trace_ident, guard: guard_n, body: body_n, } } fn lower_guards(gen: &mut ast::NodeIdGenerator, guard: &aast::Item) -> Option> { let guard_n: Vec<_> = guard .list_iter() .unwrap() .map(|guard| ast::Guard { span: guard.span(), conditions: guard .list_iter() .unwrap() .map(|v| lower_expr(gen, v)) .collect(), }) .collect(); if guard_n.len() == 0 { None } else { Some(guard_n) } } fn lower_body(gen: &mut ast::NodeIdGenerator, body: &aast::Item) -> Vec { let body_n: Vec<_> = body .list_iter() .unwrap() .map(|expr| lower_expr(gen, expr)) .collect(); body_n } fn lower_expr(gen: &mut ast::NodeIdGenerator, expr: &aast::Item) -> ast::Expr { let tup = expr.tuple().unwrap(); let name = tup.entries[0].atom().unwrap().as_str(); let _line = tup.entries[1].integer().unwrap(); let span = tup.span; match &*name { "var" => ast::Expr::Var(ast::Var(gen.next(), tup.entries[2].atom().unwrap())), "op" => { let tup_len = tup.entries.len(); let op = tup.entries[2].atom().unwrap().as_str(); enum ExprKind { Unary(ast::UnaryOp), Binary(ast::BinaryOp), } let expr_kind = match (&*op, tup_len) { ("+", 5) => ExprKind::Binary(ast::BinaryOp::Add), ("-", 5) => ExprKind::Binary(ast::BinaryOp::Sub), ("*", 5) => ExprKind::Binary(ast::BinaryOp::Multiply), ("==", 5) => ExprKind::Binary(ast::BinaryOp::Equal), ("=:=", 5) => ExprKind::Binary(ast::BinaryOp::StrictEqual), ("=/=", 5) => ExprKind::Binary(ast::BinaryOp::StrictNotEqual), ("andalso", 5) => ExprKind::Binary(ast::BinaryOp::AndAlso), ("++", 5) => ExprKind::Binary(ast::BinaryOp::Append), (">", 5) => ExprKind::Binary(ast::BinaryOp::Gt), ("<", 5) => ExprKind::Binary(ast::BinaryOp::Lt), ("rem", 5) => ExprKind::Binary(ast::BinaryOp::Rem), ("+", 4) => ExprKind::Unary(ast::UnaryOp::Plus), ("-", 4) => ExprKind::Unary(ast::UnaryOp::Minus), ("bnot", 4) => ExprKind::Unary(ast::UnaryOp::Bnot), ("not", 4) => ExprKind::Unary(ast::UnaryOp::Not), (n, a) => unimplemented!("{} {}", n, a), }; match expr_kind { ExprKind::Unary(op) => ast::Expr::UnaryExpr(ast::UnaryExpr { span, id: gen.next(), op: op, operand: Box::new(lower_expr(gen, &tup.entries[3])), }), ExprKind::Binary(op) => ast::Expr::BinaryExpr(ast::BinaryExpr { span, id: gen.next(), op: op, lhs: Box::new(lower_expr(gen, &tup.entries[3])), rhs: Box::new(lower_expr(gen, &tup.entries[4])), }), } } "integer" => { let int = tup.entries[2].integer().unwrap(); let lit = ast::Literal::Integer(span, gen.next(), int.integer.clone()); ast::Expr::Literal(lit) } "string" => { if let Some(string) = tup.entries[2].string() { ast::Expr::Literal(ast::Literal::String(gen.next(), string)) } else { let elems: Vec<_> = tup.entries[2].list_iter().unwrap().collect(); let mut acc = ast::Expr::Nil(ast::Nil(tup.span, gen.next())); for elem in elems.iter().rev() { acc = ast::Expr::Cons(ast::Cons { span: elem.span(), id: gen.next(), head: Box::new(lower_expr(gen, elem)), tail: Box::new(acc), }); } acc } } "atom" => { let atom = tup.entries[2].atom().unwrap(); ast::Expr::Literal(ast::Literal::Atom(gen.next(), atom)) } "nil" => ast::Expr::Nil(ast::Nil(span, gen.next())), "tuple" => ast::Expr::Tuple(ast::Tuple { span, id: gen.next(), elements: tup.entries[2] .list_iter() .unwrap() .map(|e| lower_expr(gen, e)) .collect(), }), "cons" => { let head = lower_expr(gen, &tup.entries[2]); let tail = lower_expr(gen, &tup.entries[3]); ast::Expr::Cons(ast::Cons { span, id: gen.next(), head: Box::new(head), tail: Box::new(tail), }) } "map" => { let tup_len = tup.entries.len(); let fields = tup.entries[tup_len - 1] .list_iter() .unwrap() .map(|field| { let field_tup = field.tuple().unwrap(); let span = field_tup.span; let op_name = field_tup.entries[0].atom().unwrap().as_str(); let key = lower_expr(gen, &field_tup.entries[2]); let value = lower_expr(gen, &field_tup.entries[3]); match &*op_name { "map_field_exact" => ast::MapField::Exact { span, id: gen.next(), key, value, }, "map_field_assoc" => ast::MapField::Assoc { span, id: gen.next(), key, value, }, r => panic!("{}", r), } }) .collect(); match tup_len { 3 => ast::Expr::Map(ast::Map { span, id: gen.next(), fields, }), 4 => ast::Expr::MapUpdate(ast::MapUpdate { span, id: gen.next(), map: Box::new(lower_expr(gen, &tup.entries[2])), updates: fields, }), _ => panic!(), } } "case" => { let expr = lower_expr(gen, &tup.entries[2]); let clauses = tup.entries[3] .list_iter() .unwrap() .map(|c| lower_clause(gen, c)) .collect(); ast::Expr::Case(ast::Case { span, id: gen.next(), expr: Box::new(expr), clauses, }) } "call" => { let target = lower_expr(gen, &tup.entries[2]); let args = tup.entries[3] .list_iter() .unwrap() .map(|v| lower_expr(gen, v)) .collect(); ast::Expr::Apply(ast::Apply { span, id: gen.next(), callee: Box::new(target), args, }) } "remote" => ast::Expr::Remote(ast::Remote { span, id: gen.next(), module: Box::new(lower_expr(gen, &tup.entries[2])), function: Box::new(lower_expr(gen, &tup.entries[3])), }), "bin" => { let elements = tup.entries[2] .list_iter() .unwrap() .map(|elem| { let tup = elem.tuple().unwrap(); assert!(tup.entries[0].atom().unwrap().as_str() == "bin_element"); let bit_expr = lower_expr(gen, &tup.entries[2]); let bit_size_v = &tup.entries[3]; let bit_size = if let Some(atom) = bit_size_v.atom() { assert!(&*atom.as_str() == "default"); None } else { Some(lower_expr(gen, bit_size_v)) }; let bit_type_v = &tup.entries[4]; let specifier = if let Some(atom) = bit_type_v.atom() { assert!(&*atom.as_str() == "default"); None } else { let list: Vec<_> = bit_type_v .list_iter() .unwrap() .map(|item| { if let Some(atom) = item.atom() { ast::BitType::Name(span, gen.next(), atom) } else { unimplemented!() } }) .collect(); Some(crate::parser::binary::specifier_from_parsed(&list, bit_size.is_some()).unwrap()) }; ast::BinaryElement { span: elem.span(), id: gen.next(), bit_expr, bit_size, specifier, } }) .collect(); ast::Expr::Binary(ast::Binary { span, id: gen.next(), elements, }) } "fun" => { // We expect either a M:F/A or a function definition. let inner = tup.entries[2].tuple().unwrap(); let inner_name = inner.entries[0].atom().unwrap(); match &*inner_name.as_str() { "function" => { let module = atom(&inner.entries[1]); let function = atom(&inner.entries[2]); let arity = integer(&inner.entries[3]); ast::Expr::FunctionName(ast::FunctionName::Resolved( ast::ResolvedFunctionName { span: inner.span, id: gen.next(), module, function, arity: arity.integer.to_usize().unwrap(), }, )) } "clauses" => { let clauses: Vec<_> = inner.entries[1] .list_iter() .unwrap() .map(|v| lower_function_clause(gen, v)) .collect(); let arity = clauses[0].params.len(); for clause in clauses.iter() { assert!(clause.params.len() == arity); } ast::Expr::Fun(ast::Function::Unnamed(ast::Lambda { span: inner.span, id: gen.next(), arity: arity, clauses, })) } v => unimplemented!("{}", v), } } "match" => { let pattern = lower_expr(gen, &tup.entries[2]); let expr = lower_expr(gen, &tup.entries[3]); ast::Expr::Match(ast::Match { span, id: gen.next(), pattern: Box::new(pattern), expr: Box::new(expr), }) } "char" => { let int = tup.entries[2].integer().unwrap(); ast::Expr::Literal(ast::Literal::Char( span, gen.next(), int.integer.to_u32().unwrap().try_into().unwrap(), )) } "float" => { let float = tup.entries[2].float().unwrap(); ast::Expr::Literal(ast::Literal::Float( span, gen.next(), Float::new(float.float).unwrap(), )) } "catch" => ast::Expr::Catch(ast::Catch { span, id: gen.next(), expr: Box::new(lower_expr(gen, &tup.entries[2])), }), "generate" => ast::Expr::Generator(ast::Generator { span, id: gen.next(), pattern: Box::new(lower_expr(gen, &tup.entries[2])), expr: Box::new(lower_expr(gen, &tup.entries[3])), }), "lc" => ast::Expr::ListComprehension(ast::ListComprehension { span, id: gen.next(), body: Box::new(lower_expr(gen, &tup.entries[2])), qualifiers: tup.entries[3] .list_iter() .unwrap() .map(|v| lower_expr(gen, v)) .collect(), }), "receive" => { let mut clauses = Vec::new(); let after = None; for clause in tup.entries[2].list_iter().unwrap() { let clause_tup = clause.tuple().unwrap(); match &*clause_tup.entries[0].atom().unwrap().as_str() { "clause" => { let mut arg_iter = clause_tup.entries[2].list_iter().unwrap(); let arg = arg_iter.next().unwrap(); assert!(arg_iter.next().is_none()); let pattern = lower_expr(gen, arg); let guard = lower_guards(gen, &clause_tup.entries[3]); let body = lower_body(gen, &clause_tup.entries[4]); clauses.push(ast::Clause { span: clause_tup.span, id: gen.next(), pattern, guard: guard, body, }); } _ => unimplemented!(), } } ast::Expr::Receive(ast::Receive { span, id: gen.next(), clauses: if clauses.len() == 0 { None } else { Some(clauses) }, after: after, }) } "block" => { let body = lower_body(gen, &tup.entries[2]); ast::Expr::Begin(ast::Begin { span, id: gen.next(), body, }) } "if" => { let clauses = tup.entries[2] .list_iter() .unwrap() .map(|v| lower_if_clause(gen, v)) .collect(); ast::Expr::If(ast::If { span, id: gen.next(), clauses, }) } "record" => match tup.entries.len() { 4 => { let name = tup.entries[2].atom().unwrap(); let fields = tup.entries[3] .list_iter() .unwrap() .map(|v| lower_record_field(gen, v)) .collect(); ast::Expr::Record(ast::Record { span, id: gen.next(), name, fields, }) } 5 => { let old = lower_expr(gen, &tup.entries[2]); let name = tup.entries[3].atom().unwrap(); let fields = tup.entries[4] .list_iter() .unwrap() .map(|v| lower_record_field(gen, v)) .collect(); ast::Expr::RecordUpdate(ast::RecordUpdate { span, id: gen.next(), record: Box::new(old), name, updates: fields, }) } _ => unimplemented!(), }, "try" => { let exprs = lower_body(gen, &tup.entries[2]); let clauses: Vec<_> = tup.entries[3] .list_iter() .unwrap() .map(|v| lower_clause(gen, v)) .collect(); let catch_clauses: Vec<_> = tup.entries[4] .list_iter() .unwrap() .map(|v| lower_try_clause(gen, v)) .collect(); let after = lower_body(gen, &tup.entries[5]); ast::Expr::Try(ast::Try { span, id: gen.next(), exprs, clauses: if clauses.len() == 0 { None } else { Some(clauses) }, catch_clauses: if catch_clauses.len() == 0 { None } else { Some(catch_clauses) }, after: if after.len() == 0 { None } else { Some(after) }, }) } v => unimplemented!("{}", v), } } fn atom(item: &aast::Item) -> Ident { let tup = item.tuple().unwrap(); assert!(&*tup.entries[0].atom().unwrap().as_str() == "atom"); tup.entries[2].atom().unwrap() } fn integer(item: &aast::Item) -> &aast::Int { let tup = item.tuple().unwrap(); assert!(&*tup.entries[0].atom().unwrap().as_str() == "integer"); tup.entries[2].integer().unwrap() } #[cfg(test)] mod test { use libeir_diagnostics::{CodeMap, Diagnostic, ToDiagnostic}; use libeir_util_parse::{error_tee, Errors, Parse, Parser}; use libeir_util_parse_listing::ast::Root; use libeir_util_parse_listing::parser::ParseError; use std::path::Path; use std::sync::Arc; use crate::LowerError; enum ParseOrLowerError { Parse(ParseError), Lower(LowerError), } impl ToDiagnostic for ParseOrLowerError { fn to_diagnostic(&self) -> Diagnostic { match self { ParseOrLowerError::Parse(err) => err.to_diagnostic(), ParseOrLowerError::Lower(err) => err.to_diagnostic(), } } } impl From for ParseOrLowerError { fn from(e: ParseError) -> Self { Self::Parse(e) } } impl From for ParseOrLowerError { fn from(e: LowerError) -> Self { Self::Lower(e) } } fn parse(input: S) -> T where T: Parse, S: AsRef, { let parser = Parser::new((), Arc::new(CodeMap::new())); let mut errors = Errors::new(); match parser.parse_string::(&mut errors, input) { Ok(ast) => return ast, Err(()) => { errors.print(&parser.codemap); panic!() } }; } fn parse_file(path: S) -> T where T: Parse, S: AsRef, { let parser = Parser::new((), Arc::new(CodeMap::new())); let mut errors = Errors::new(); match parser.parse_file::(&mut errors, path) { Ok(ast) => return ast, Err(()) => { errors.print(&parser.codemap); panic!() } }; } #[test] fn basic_ast() { let root: Root = parse( " {attribute,1,file,{\"woo.erl\",1}}. {attribute,1,module,woo}. {attribute,3,export,[{foo,2},{bar,1},{barr,1}]}. {function,5,foo,2, [{clause,5, [{var,5,'A'},{var,5,'B'}], [], [{op,5,'+',{var,5,'A'},{var,5,'B'}}]}]}. {function,7,bar,1, [{clause,7,[{integer,7,1}],[],[{integer,7,2}]}, {clause,8,[{integer,8,2}],[],[{integer,8,4}]}, {clause,9,[{var,9,'N'}],[],[{var,9,'N'}]}]}. {function,11,barr,1, [{clause,11,[{integer,11,1}],[],[{integer,11,2}]}, {clause,12,[{integer,12,2}],[],[{integer,12,4}]}]}. {function,14,binary,0, [{clause,14,[],[], [{bin,14,[{bin_element,14,{string,14,\"woo\"},default,default}]}]}]}. {function,16,string,0,[{clause,16,[],[],[{string,16,\"woo\"}]}]}. {eof,17}. ", ); super::lower(&root); } #[test] fn maps() { let root: Root = parse_file("../test_data/maps.abstr"); super::lower(&root); } #[test] fn match_suite() { let parser = Parser::new((), Arc::new(CodeMap::new())); let mut errors: Errors = Errors::new(); let res = error_tee(&mut errors, |mut errors| { match parser.parse_file::( &mut errors.make_into_adapter(), "../test_data/match_SUITE.abstr", ) { Ok(ast) => { let module = super::lower(&ast); crate::lower_module( &mut errors.make_into_adapter(), parser.codemap.clone(), &module, ) } Err(()) => Err(()), } }); match res { Ok(_res) => (), Err(()) => { errors.print(&parser.codemap); panic!(); } } } } ================================================ FILE: libeir_syntax_erl/src/abstr/mod.rs ================================================ mod lower; pub use lower::lower; #[cfg(test)] mod test {} ================================================ FILE: libeir_syntax_erl/src/evaluator.rs ================================================ use std::cmp::Ordering; use std::collections::BTreeMap; use std::hash::{Hash, Hasher}; use snafu::{ResultExt, Snafu}; use crate::lexer::symbols; use crate::parser::ast::{BinaryOp, Expr, Literal, UnaryOp}; use libeir_diagnostics::{Diagnostic, Label, SourceSpan, ToDiagnostic}; use libeir_intern::{Ident, Symbol}; use libeir_ir::ToPrimitive; use libeir_util_number::{Float, Integer, Number}; #[derive(Debug, Snafu)] pub enum EvalError { #[snafu(display("invalid const expression"))] InvalidConstExpression { span: SourceSpan }, #[snafu(display("floating point error"))] FloatError { source: libeir_util_number::FloatError, span: SourceSpan, }, #[snafu(display("integer division requires both operands to be integers"))] InvalidDivOperand { span: SourceSpan }, #[snafu(display("expression evaluated to division by zero"))] DivisionByZero { span: SourceSpan }, #[snafu(display("bitwise operators requires all operands to be integers"))] InvalidBitwiseOperand { span: SourceSpan }, #[snafu(display("attempted too large bitshift"))] TooLargeShift { span: SourceSpan }, #[snafu(display("no record with name"))] NoRecord { span: SourceSpan }, #[snafu(display("field doesn't exist in record"))] NoRecordField { span: SourceSpan }, } impl ToDiagnostic for EvalError { fn to_diagnostic(&self) -> Diagnostic { let msg = self.to_string(); match self { EvalError::InvalidConstExpression { span } => Diagnostic::error() .with_message(msg) .with_labels(vec![Label::primary(span.source_id(), *span) .with_message("expression not evaluable to constant")]), EvalError::FloatError { span, .. } => Diagnostic::error() .with_message(msg) .with_labels(vec![Label::primary(span.source_id(), *span)]), EvalError::InvalidDivOperand { span } => Diagnostic::error() .with_message(msg) .with_labels(vec![Label::primary(span.source_id(), *span)]), EvalError::DivisionByZero { span } => Diagnostic::error() .with_message(msg) .with_labels(vec![Label::primary(span.source_id(), *span)]), EvalError::InvalidBitwiseOperand { span } => Diagnostic::error() .with_message(msg) .with_labels(vec![Label::primary(span.source_id(), *span)]), EvalError::TooLargeShift { span } => Diagnostic::error() .with_message(msg) .with_labels(vec![Label::primary(span.source_id(), *span)]), EvalError::NoRecord { span } => Diagnostic::error() .with_message(msg) .with_labels(vec![Label::primary(span.source_id(), *span)]), EvalError::NoRecordField { span } => Diagnostic::error() .with_message(msg) .with_labels(vec![Label::primary(span.source_id(), *span)]), } } } #[derive(Clone, Hash)] pub enum Term { Cons(Box, Box), Nil, Map(BTreeMap), Tuple(Vec), Atom(Symbol), Number(Number), } impl PartialEq for Term { fn eq(&self, other: &Term) -> bool { self.equals(other, false) } } impl Eq for Term {} impl Ord for Term { // number < atom < reference < fun < port < pid < tuple < map < nil < list < bit string fn cmp(&self, other: &Term) -> Ordering { match (self, other) { (Term::Number(l), Term::Number(r)) => l.cmp(r), (Term::Number(_), _) => Ordering::Less, (Term::Atom(_), Term::Number(_)) => Ordering::Greater, (Term::Atom(l), Term::Atom(r)) => l.cmp(r), (Term::Atom(_), _) => Ordering::Less, (Term::Tuple(_), Term::Number(_) | Term::Atom(_)) => Ordering::Greater, (Term::Tuple(l), Term::Tuple(r)) => l.cmp(r), (Term::Tuple(_), _) => Ordering::Less, (Term::Map(_), Term::Number(_) | Term::Atom(_) | Term::Tuple(_)) => Ordering::Greater, (Term::Map(l), Term::Map(r)) => l.cmp(r), (Term::Map(_), _) => Ordering::Less, (Term::Nil, Term::Number(_) | Term::Atom(_) | Term::Tuple(_) | Term::Map(_)) => { Ordering::Greater } (Term::Nil, Term::Nil) => Ordering::Equal, (Term::Nil, _) => Ordering::Less, ( Term::Cons(_, _), Term::Number(_) | Term::Atom(_) | Term::Tuple(_) | Term::Map(_) | Term::Nil, ) => Ordering::Greater, (Term::Cons(lh, lt), Term::Cons(rh, rt)) => (lh, lt).cmp(&(rh, rt)), (Term::Cons(_, _), _) => Ordering::Less, } } } impl PartialOrd for Term { fn partial_cmp(&self, other: &Term) -> Option { Some(self.cmp(other)) } } impl From for Term { fn from(num: Number) -> Term { Term::Number(num) } } impl From for Term { fn from(cond: bool) -> Term { if cond { Term::Atom(symbols::True) } else { Term::Atom(symbols::False) } } } impl Term { pub fn equals(&self, rhs: &Term, exact: bool) -> bool { match (self, rhs) { (Term::Atom(l), Term::Atom(r)) => l == r, (Term::Number(l), Term::Number(r)) => l.equals(r, exact), (Term::Tuple(l), Term::Tuple(r)) => l == r, (Term::Map(l), Term::Map(r)) => l == r, (Term::Nil, Term::Nil) => true, (Term::Cons(lh, lt), Term::Cons(rh, rt)) => lh == rh && lt == rt, _ => false, } } } pub enum ResolveRecordIndexError { NoRecord, NoField, } pub fn eval_expr( expr: &Expr, resolve_record_index: Option<&dyn Fn(Ident, Ident) -> Result>, ) -> Result { let span = expr.span(); let invalid_expr = InvalidConstExpression { span }; let float_err = FloatError { span }; let res = match expr { Expr::Literal(lit) => match lit { Literal::Integer(_span, _id, int) => Term::Number(int.clone().into()), Literal::Float(_span, _id, float) => Term::Number((*float).into()), Literal::Atom(_id, atom) => Term::Atom(atom.name), lit => return Err(EvalError::InvalidConstExpression { span: lit.span() }), }, Expr::Nil(_) => Term::Nil, Expr::Cons(cons) => { let head = eval_expr(&cons.head, resolve_record_index)?; let tail = eval_expr(&cons.tail, resolve_record_index)?; Term::Cons(Box::new(head), Box::new(tail)) } Expr::Tuple(tup) => Term::Tuple( tup.elements .iter() .map(|e| eval_expr(e, resolve_record_index)) .collect::, _>>()?, ), Expr::Map(_) => unimplemented!(), Expr::Binary(_) => unimplemented!(), Expr::Record(_) => unimplemented!(), Expr::RecordIndex(rec_idx) if resolve_record_index.is_some() => { match resolve_record_index.unwrap()(rec_idx.name, rec_idx.field) { Ok(index) => Term::Number(index.into()), Err(ResolveRecordIndexError::NoRecord) => { Err(EvalError::NoRecord { span: rec_idx.span })? } Err(ResolveRecordIndexError::NoField) => { Err(EvalError::NoRecordField { span: rec_idx.span })? } } } Expr::BinaryExpr(bin_expr) => { use BinaryOp as B; let lhs = eval_expr(&bin_expr.lhs, resolve_record_index)?; let rhs = eval_expr(&bin_expr.rhs, resolve_record_index)?; match (bin_expr.op, lhs, rhs) { (B::Add, Term::Number(l), Term::Number(r)) => (&l + &r).context(float_err)?.into(), (B::Sub, Term::Number(l), Term::Number(r)) => (&l - &r).context(float_err)?.into(), (B::Multiply, Term::Number(l), Term::Number(r)) => { (&l * &r).context(float_err)?.into() } (B::Divide, Term::Number(l), Term::Number(r)) => { if r.is_zero() { Err(EvalError::DivisionByZero { span })? } (&l / &r).context(float_err)?.into() } (B::Div, Term::Number(Number::Integer(l)), Term::Number(Number::Integer(r))) => { if r.is_zero() { Err(EvalError::DivisionByZero { span })? } Number::Integer((l / &r).unwrap()).into() } (B::Div, _, _) => Err(EvalError::InvalidDivOperand { span })?, (B::Bor, Term::Number(Number::Integer(l)), Term::Number(Number::Integer(r))) => { Number::Integer(l | &r).into() } (B::Band, Term::Number(Number::Integer(l)), Term::Number(Number::Integer(r))) => { Number::Integer(l & &r).into() } (B::Bxor, Term::Number(Number::Integer(l)), Term::Number(Number::Integer(r))) => { Number::Integer(l ^ &r).into() } (B::Bsl, Term::Number(Number::Integer(l)), Term::Number(Number::Integer(r))) => { let shift = r.to_u32().ok_or(EvalError::TooLargeShift { span })?; Number::Integer(l << shift).into() } (B::Bsr, Term::Number(Number::Integer(l)), Term::Number(Number::Integer(r))) => { let shift = r.to_u32().ok_or(EvalError::TooLargeShift { span })?; Number::Integer(l >> shift).into() } (B::Bor | B::Band | B::Bxor | B::Bsl | B::Bsr, _, _) => { Err(EvalError::InvalidBitwiseOperand { span })? } (B::Lt, l, r) => (l < r).into(), (B::Lte, l, r) => (l <= r).into(), (B::Gt, l, r) => (l > r).into(), (B::Gte, l, r) => (l >= r).into(), (B::Equal, l, r) => l.equals(&r, false).into(), (B::NotEqual, l, r) => (!l.equals(&r, false)).into(), (B::StrictEqual, l, r) => l.equals(&r, true).into(), (B::StrictNotEqual, l, r) => (!l.equals(&r, true)).into(), (B::Append, _, _) => unimplemented!(), (B::Remove, _, _) => unimplemented!(), _ => Err(EvalError::InvalidConstExpression { span })?, } } Expr::UnaryExpr(un_expr) => { use UnaryOp as U; let operand = eval_expr(&un_expr.operand, resolve_record_index)?; match (un_expr.op, operand) { (UnaryOp::Plus, Term::Number(o)) => o.plus().into(), (UnaryOp::Minus, Term::Number(o)) => (-o).into(), (UnaryOp::Bnot, Term::Number(Number::Integer(i))) => Number::Integer(!&i).into(), (UnaryOp::Bnot, _) => Err(EvalError::InvalidBitwiseOperand { span })?, (UnaryOp::Not, Term::Atom(sym)) if sym == symbols::True => false.into(), (UnaryOp::Not, Term::Atom(sym)) if sym == symbols::False => true.into(), //(UnaryOp::Not, Term::Atom) _ => Err(EvalError::InvalidConstExpression { span })?, } } _ => Err(EvalError::InvalidConstExpression { span })?, }; Ok(res) } ================================================ FILE: libeir_syntax_erl/src/lexer/errors.rs ================================================ use std::hash::{Hash, Hasher}; use snafu::Snafu; use libeir_diagnostics::{Diagnostic, Label, SourceIndex, SourceSpan, ToDiagnostic}; use super::token::{Token, TokenType}; use crate::util::escape_stm::EscapeStmError; /// An enum of possible errors that can occur during lexing. #[derive(Clone, Debug, PartialEq, Snafu)] pub enum LexicalError { #[snafu(display("{}", reason))] InvalidFloat { span: SourceSpan, reason: String }, #[snafu(display("{}", reason))] InvalidRadix { span: SourceSpan, reason: String }, /// Occurs when a string literal is not closed (e.g. `"this is an unclosed string`) /// It is also implicit that hitting this error means we've reached EOF, as we'll scan the /// entire input looking for the closing quote #[snafu(display("Unclosed string literal"))] UnclosedString { span: SourceSpan }, /// Like UnclosedStringLiteral, but for quoted atoms #[snafu(display("Unclosed atom literal"))] UnclosedAtom { span: SourceSpan }, #[snafu(display("{}", source))] EscapeError { source: EscapeStmError }, /// Occurs when we encounter an unexpected character #[snafu(display("Encountered unexpected character '{}'", found))] UnexpectedCharacter { start: SourceIndex, found: char }, } impl Hash for LexicalError { fn hash(&self, state: &mut H) { let id = match *self { LexicalError::InvalidFloat { .. } => 0, LexicalError::InvalidRadix { .. } => 1, LexicalError::UnclosedString { .. } => 2, LexicalError::UnclosedAtom { .. } => 3, LexicalError::EscapeError { .. } => 4, LexicalError::UnexpectedCharacter { .. } => 5, }; id.hash(state); } } impl ToDiagnostic for LexicalError { fn to_diagnostic(&self) -> Diagnostic { let span = self.span(); let msg = self.to_string(); match self { LexicalError::InvalidFloat { .. } => Diagnostic::error() .with_message("invalid float literal") .with_labels(vec![ Label::primary(span.source_id(), span).with_message(msg) ]), LexicalError::InvalidRadix { .. } => Diagnostic::error() .with_message("invalid radix value for integer literal") .with_labels(vec![ Label::primary(span.source_id(), span).with_message(msg) ]), LexicalError::EscapeError { source } => source.to_diagnostic(), LexicalError::UnexpectedCharacter { .. } => Diagnostic::error() .with_message("unexpected character") .with_labels(vec![ Label::primary(span.source_id(), span).with_message(msg) ]), _ => Diagnostic::error() .with_message(msg) .with_labels(vec![Label::primary(span.source_id(), span)]), } } } impl LexicalError { /// Return the source span for this error pub fn span(&self) -> SourceSpan { match self { LexicalError::InvalidFloat { span, .. } => *span, LexicalError::InvalidRadix { span, .. } => *span, LexicalError::UnclosedString { span, .. } => *span, LexicalError::UnclosedAtom { span, .. } => *span, LexicalError::EscapeError { source } => source.span(), LexicalError::UnexpectedCharacter { start, .. } => SourceSpan::new(*start, *start), } } } // Produced when converting from LexicalToken to {Atom,Ident,String,Symbol}Token #[derive(Debug, Clone)] pub struct TokenConvertError { pub span: SourceSpan, pub token: Token, pub expected: TokenType, } ================================================ FILE: libeir_syntax_erl/src/lexer/lexer.rs ================================================ use std::ops::Range; use std::str::FromStr; use libeir_diagnostics::{ByteOffset, SourceIndex, SourceSpan}; use libeir_util_number::{Float, FloatError, Integer, ToPrimitive}; use libeir_util_parse::{Scanner, Source}; use crate::util::escape_stm::{EscapeStm, EscapeStmAction}; use super::errors::LexicalError; use super::token::*; use super::{Lexed, Symbol}; macro_rules! pop { ($lex:ident) => {{ $lex.skip(); }}; ($lex:ident, $code:expr) => {{ $lex.skip(); $code }}; } macro_rules! pop2 { ($lex:ident) => {{ $lex.skip(); $lex.skip(); }}; ($lex:ident, $code:expr) => {{ $lex.skip(); $lex.skip(); $code }}; } macro_rules! pop3 { ($lex:ident) => {{ $lex.skip(); $lex.skip(); $lex.skip() }}; ($lex:ident, $code:expr) => {{ $lex.skip(); $lex.skip(); $lex.skip(); $code }}; } /// The lexer that is used to perform lexical analysis on the Erlang grammar. The lexer implements /// the `Iterator` trait, so in order to retrieve the tokens, you simply have to iterate over it. /// /// # Errors /// /// Because the lexer is implemented as an iterator over tokens, this means that you can continue /// to get tokens even if a lexical error occurs. The lexer will attempt to recover from an error /// by injecting tokens it expects. /// /// If an error is unrecoverable, the lexer will continue to produce tokens, but there is no /// guarantee that parsing them will produce meaningful results, it is primarily to assist in /// gathering as many errors as possible. pub struct Lexer { /// The scanner produces a sequence of chars + location, and can be controlled /// The location produces is a SourceIndex scanner: Scanner, /// Escape sequence state machine. escape: EscapeStm, /// The most recent token to be lexed. /// At the start and end, this should be Token::EOF token: Token, /// The position in the input where the current token starts /// At the start this will be the byte index of the beginning of the input token_start: SourceIndex, /// The position in the input where the current token ends /// At the start this will be the byte index of the beginning of the input token_end: SourceIndex, /// When we have reached true EOF, this gets set to true, and the only token /// produced after that point is Token::EOF, or None, depending on how you are /// consuming the lexer eof: bool, } impl Lexer where S: Source, { /// Produces an instance of the lexer with the lexical analysis to be performed on the `input` /// string. Note that no lexical analysis occurs until the lexer has been iterated over. pub fn new(scanner: Scanner) -> Self { let start = scanner.start(); let mut lexer = Lexer { scanner, escape: EscapeStm::new(), token: Token::EOF, token_start: start + ByteOffset(0), token_end: start + ByteOffset(0), eof: false, }; lexer.advance(); lexer } pub fn lex(&mut self) -> Option<::Item> { if self.eof && self.token == Token::EOF { return None; } let token = std::mem::replace(&mut self.token, Token::EOF); let result = if let Token::Error(err) = token { Some(Err(err)) } else { Some(Ok(LexicalToken( self.token_start.clone(), token, self.token_end.clone(), ))) }; self.advance(); result } fn advance(&mut self) { self.advance_start(); self.token = self.tokenize(); } #[inline] fn advance_start(&mut self) { let mut position: SourceIndex; loop { let (pos, c) = self.scanner.read(); position = pos; if c == '\0' { self.eof = true; return; } if c.is_whitespace() { self.scanner.advance(); continue; } break; } self.token_start = position; } #[inline] fn pop(&mut self) -> char { let (pos, c) = self.scanner.pop(); self.token_end = pos + ByteOffset::from_char_len(c); c } #[inline] fn peek(&mut self) -> char { let (_, c) = self.scanner.peek(); c } #[inline] fn peek_next(&mut self) -> char { let (_, c) = self.scanner.peek_next(); c } #[inline] fn read(&mut self) -> char { let (_, c) = self.scanner.read(); c } #[inline] fn index(&mut self) -> SourceIndex { self.scanner.read().0 } #[inline] fn skip(&mut self) { self.pop(); } /// Get the span for the current token in `Source`. #[inline] pub fn span(&self) -> SourceSpan { SourceSpan::new(self.token_start, self.token_end) } /// Get a string slice of the current token. #[inline] fn slice(&self) -> &str { self.scanner.slice(self.span()) } #[inline] fn slice_span(&self, span: impl Into>) -> &str { self.scanner.slice(span) } #[inline] fn skip_whitespace(&mut self) { let mut c: char; loop { c = self.read(); if !c.is_whitespace() { break; } self.skip(); } } fn tokenize(&mut self) -> Token { let c = self.read(); if c == '%' { self.skip(); return self.lex_comment(); } if c == '\0' { self.eof = true; return Token::EOF; } if c.is_whitespace() { self.skip_whitespace(); } match self.read() { ',' => pop!(self, Token::Comma), ';' => pop!(self, Token::Semicolon), '_' => self.lex_identifier(), '0'..='9' => self.lex_number(), 'a'..='z' => self.lex_bare_atom(), 'A'..='Z' => self.lex_identifier(), '#' => pop!(self, Token::Pound), '*' => pop!(self, Token::Star), '!' => pop!(self, Token::Bang), '[' => pop!(self, Token::LBracket), ']' => pop!(self, Token::RBracket), '(' => pop!(self, Token::LParen), ')' => pop!(self, Token::RParen), '{' => pop!(self, Token::LBrace), '}' => pop!(self, Token::RBrace), '?' => match self.peek() { '?' => pop2!(self, Token::DoubleQuestion), _ => pop!(self, Token::Question), }, '-' => match self.peek() { '-' => pop2!(self, Token::MinusMinus), '>' => pop2!(self, Token::RightStab), _ => pop!(self, Token::Minus), }, '$' => { self.skip(); if self.read() == '\\' { return match self.lex_escape_sequence() { Ok(num) => match std::char::from_u32(num as u32) { Some(c) => Token::Char(c), None => Token::Integer((num as i64).into()), }, Err(err) => Token::Error(err), }; } Token::Char(self.pop()) } '"' => self.lex_string(), '\'' => match self.lex_string() { Token::String(s) => Token::Atom(s), other => other, }, ':' => match self.peek() { '=' => pop2!(self, Token::ColonEqual), ':' => pop2!(self, Token::ColonColon), _ => pop!(self, Token::Colon), }, '+' => { if self.peek() == '+' { pop2!(self, Token::PlusPlus) } else { pop!(self, Token::Plus) } } '/' => { if self.peek() == '=' { pop2!(self, Token::IsNotEqual) } else { pop!(self, Token::Slash) } } '=' => match self.peek() { '=' => pop2!(self, Token::IsEqual), '>' => pop2!(self, Token::RightArrow), '<' => pop2!(self, Token::IsLessThanOrEqual), ':' => { if self.peek_next() == '=' { pop3!(self, Token::IsExactlyEqual) } else { Token::Error(LexicalError::UnexpectedCharacter { start: self.span().start(), found: self.peek_next(), }) } } '/' => { if self.peek_next() == '=' { pop3!(self, Token::IsExactlyNotEqual) } else { Token::Error(LexicalError::UnexpectedCharacter { start: self.span().start(), found: self.peek_next(), }) } } _ => pop!(self, Token::Equals), }, '<' => match self.peek() { '<' => pop2!(self, Token::BinaryStart), '-' => pop2!(self, Token::LeftStab), '=' => pop2!(self, Token::LeftArrow), _ => pop!(self, Token::IsLessThan), }, '>' => match self.peek() { '>' => pop2!(self, Token::BinaryEnd), '=' => pop2!(self, Token::IsGreaterThanOrEqual), _ => pop!(self, Token::IsGreaterThan), }, '|' => { if self.peek() == '|' { pop2!(self, Token::BarBar) } else { pop!(self, Token::Bar) } } '.' => { if self.peek() == '.' { if self.peek_next() == '.' { pop3!(self, Token::DotDotDot) } else { pop2!(self, Token::DotDot) } } else { pop!(self, Token::Dot) } } '\\' => { // Allow escaping newlines let c = self.peek(); if c == '\n' { pop2!(self); return self.tokenize(); } return match self.lex_escape_sequence() { Ok(t) => Token::Integer((t as i64).into()), Err(e) => Token::Error(e), }; } c => Token::Error(LexicalError::UnexpectedCharacter { start: self.span().start(), found: c, }), } } fn lex_comment(&mut self) -> Token { let mut c = self.read(); // If there is another '%', then this is a regular comment line if c == '%' { self.skip(); loop { c = self.read(); if c == '\n' { break; } if c == '\0' { self.eof = true; break; } self.skip(); } return Token::Comment; } // If no '%', then we should check for an Edoc tag, first skip all whitespace and advance // the token start self.skip_whitespace(); // See if this is an Edoc tag c = self.read(); if c == '@' { if self.peek().is_ascii_alphabetic() { self.skip(); // Get the tag identifier self.lex_identifier(); // Skip any leading whitespace in the value self.skip_whitespace(); // Get value loop { c = self.read(); if c == '\n' { break; } if c == '\0' { self.eof = true; break; } self.skip(); } return Token::Edoc; } } // If we reach here, its a normal comment loop { if c == '\n' { break; } if c == '\0' { self.eof = true; break; } self.skip(); c = self.read(); } return Token::Comment; } #[inline] fn lex_escape_sequence(&mut self) -> Result { let start_idx = self.index(); let mut c = self.read(); debug_assert_eq!(c, '\\'); self.escape.reset(); let mut byte_idx = 0; loop { let c = self.read(); let idx = start_idx + byte_idx; let c = if c == '\0' { None } else { Some(c) }; let res = self.escape.transition(c, idx); match res { Ok((action, result)) => { if let EscapeStmAction::Next = action { byte_idx += c.map(|c| c.len_utf8()).unwrap_or(0); self.pop(); } if let Some(result) = result { return Ok(result.cp); } } Err(err) => Err(LexicalError::EscapeError { source: err })?, } } } #[inline] fn lex_string(&mut self) -> Token { let quote = self.pop(); debug_assert!(quote == '"' || quote == '\''); let mut buf = None; loop { match self.read() { '\\' => match self.lex_escape_sequence() { Ok(_c) => (), Err(err) => return Token::Error(err), }, '\0' if quote == '"' => { return Token::Error(LexicalError::UnclosedString { span: self.span() }); } '\0' if quote == '\'' => { return Token::Error(LexicalError::UnclosedAtom { span: self.span() }); } c if c == quote => { let span = self.span().shrink_front(ByteOffset(1)); self.skip(); self.advance_start(); if self.read() == quote { self.skip(); buf = Some(self.slice_span(span).to_string()); continue; } let symbol = if let Some(mut buf) = buf { buf.push_str(self.slice_span(span)); Symbol::intern(&buf) } else { Symbol::intern(self.slice_span(span)) }; let token = Token::String(symbol); return token; } _ => { self.skip(); continue; } } } } #[inline] fn lex_identifier(&mut self) -> Token { let c = self.pop(); debug_assert!(c == '_' || c.is_ascii_alphabetic()); loop { match self.read() { '_' => self.skip(), '@' => self.skip(), '0'..='9' => self.skip(), c if c.is_alphabetic() => self.skip(), _ => break, } } Token::Ident(Symbol::intern(self.slice())) } #[inline] fn lex_bare_atom(&mut self) -> Token { let c = self.pop(); debug_assert!(c.is_ascii_lowercase()); loop { match self.read() { '_' => self.skip(), '@' => self.skip(), '0'..='9' => self.skip(), c if c.is_alphabetic() => self.skip(), _ => break, } } Token::from_bare_atom(self.slice()) } #[inline] fn lex_digits( &mut self, radix: u32, allow_leading_underscore: bool, num: &mut String, ) -> Result<(), LexicalError> { let mut last_underscore = !allow_leading_underscore; let mut c = self.read(); loop { match c { c if c.is_digit(radix) => { last_underscore = false; num.push(self.pop()); } '_' if last_underscore => { return Err(LexicalError::UnexpectedCharacter { start: self.span().start(), found: c, }); } '_' if self.peek().is_digit(radix) => { last_underscore = true; self.pop(); } _ => break, } c = self.read(); } Ok(()) } #[inline] fn lex_number(&mut self) -> Token { let mut num = String::new(); let mut c; // Expect the first character to be either a sign on digit c = self.read(); debug_assert!(c == '-' || c == '+' || c.is_digit(10), "got {}", c); // If sign, consume it // // -10 // ^ // let negative = c == '-'; if c == '-' || c == '+' { num.push(self.pop()); } // Consume leading digits // // -10.0 // ^^ // // 10e10 // ^^ // if let Err(err) = self.lex_digits(10, false, &mut num) { return Token::Error(err); } // If we have a dot with a trailing number, we lex a float. // Otherwise we return consumed digits as an integer token. // // 10.0 // ^ lex_float() // // fn() -> 10 + 10. // ^ return integer token // c = self.read(); if c == '.' { if self.peek().is_digit(10) { // Pushes . num.push(self.pop()); return self.lex_float(num, false); } return to_integer_literal(&num, 10); } // Consume exponent marker // // 10e10 // ^ lex_float() // // 10e-10 // ^^ lex_float() if c == 'e' || c == 'E' { let c2 = self.peek(); if c2 == '-' || c2 == '+' { num.push(self.pop()); num.push(self.pop()); return self.lex_float(num, true); } else if c2.is_digit(10) { num.push(self.pop()); return self.lex_float(num, true); } } // If followed by '#', the leading digits were the radix // // 10#16 // ^ interpret leading as radix if c == '#' { self.skip(); // Parse in the given radix let radix = match num[..].parse::() { Ok(r) => r, Err(e) => { return Token::Error(LexicalError::InvalidRadix { span: self.span(), reason: e.to_string(), }); } }; if radix >= 2 && radix <= 32 { let mut num = String::new(); // If we have a sign, push that to the new integer string c = self.read(); if c.is_digit(radix) { if negative { num.push('-'); } } // Lex the digits themselves if let Err(err) = self.lex_digits(radix, false, &mut num) { return Token::Error(err); } return to_integer_literal(&num, radix); } else { Token::Error(LexicalError::InvalidRadix { span: self.span(), reason: "invalid radix (must be in 2..32)".to_string(), }) } } else { to_integer_literal(&num, 10) } } // Called after consuming a number up to and including the '.' #[inline] fn lex_float(&mut self, num: String, seen_e: bool) -> Token { let mut num = num; let mut c = self.pop(); debug_assert!(c.is_digit(10), "got {}", c); num.push(c); if let Err(err) = self.lex_digits(10, true, &mut num) { return Token::Error(err); } c = self.read(); // If we've already seen e|E, then we're done if seen_e { return self.to_float_literal(num); } if c == 'E' || c == 'e' { num.push(self.pop()); c = self.read(); if c == '-' || c == '+' { num.push(self.pop()); c = self.read(); } if !c.is_digit(10) { return Token::Error(LexicalError::InvalidFloat { span: self.span(), reason: "expected digits after scientific notation".to_string(), }); } if let Err(err) = self.lex_digits(10, false, &mut num) { return Token::Error(err); } } self.to_float_literal(num) } fn to_float_literal(&self, num: String) -> Token { let reason = match f64::from_str(&num) { Ok(f) => match Float::new(f) { Ok(f) => return Token::Float(f), Err(FloatError::Nan) => "float cannot be NaN".to_string(), Err(FloatError::Infinite) => "float cannot be -Inf or Inf".to_string(), }, Err(e) => e.to_string(), }; Token::Error(LexicalError::InvalidFloat { span: self.span(), reason, }) } } impl Iterator for Lexer where S: Source, { type Item = Lexed; fn next(&mut self) -> Option { let mut res = self.lex(); loop { match res { Some(Ok(LexicalToken(_, Token::Comment, _))) => { res = self.lex(); } _ => break, } } res } } // Converts the string literal into either a `i64` or arbitrary precision integer, preferring `i64`. // // This function panics if the literal is unparseable due to being invalid for the given radix, // or containing non-ASCII digits. fn to_integer_literal(literal: &str, radix: u32) -> Token { let int = Integer::from_string_radix(literal, radix).unwrap(); Token::Integer(int) } #[cfg(test)] mod test { use libeir_diagnostics::{ByteIndex, CodeMap, SourceId, SourceIndex, SourceSpan}; use libeir_util_number::Float; use libeir_util_parse::{FileMapSource, Scanner, Source}; use pretty_assertions::assert_eq; use crate::lexer::*; macro_rules! symbol { ($sym:expr) => { Symbol::intern($sym) }; } macro_rules! assert_lex( ($input:expr, $expected:expr) => ({ let codemap = CodeMap::new(); let id = codemap.add("nofile", $input.to_string()); let file = codemap.get(id).unwrap(); let source = FileMapSource::new(file); let scanner = Scanner::new(source); let lexer = Lexer::new(scanner); let results = lexer.map(|result| { match result { Ok(LexicalToken(_start, token, _end)) => { Ok(token) } Err(err) => { Err(err) } } }).collect::>(); assert_eq!(results, $expected(id)); }) ); #[test] fn lex_symbols() { assert_lex!(":", |_| vec![Ok(Token::Colon)]); assert_lex!(",", |_| vec![Ok(Token::Comma)]); assert_lex!("=", |_| vec![Ok(Token::Equals)]); } #[test] fn lex_comment() { assert_lex!("% this is a comment", |_| vec![]); assert_lex!("% @author Paul", |_| vec![Ok(Token::Edoc)]); } macro_rules! f { ($float:expr) => { Token::Float(Float::new($float).unwrap()) }; } #[test] fn lex_float_literal() { // With leading 0 assert_lex!("0.0", |_| vec![Ok(f!(0.0))]); assert_lex!("000051.0", |_| vec![Ok(f!(51.0))]); assert_lex!("05162.0", |_| vec![Ok(f!(5162.0))]); assert_lex!("099.0", |_| vec![Ok(f!(99.0))]); assert_lex!("04624.51235", |_| vec![Ok(f!(4624.51235))]); assert_lex!("0.987", |_| vec![Ok(f!(0.987))]); assert_lex!("0.55e10", |_| vec![Ok(f!(0.55e10))]); assert_lex!("612.0e61", |_| vec![Ok(f!(612e61))]); assert_lex!("0.0e-1", |_| vec![Ok(f!(0e-1))]); assert_lex!("41.0e+9", |_| vec![Ok(f!(41e+9))]); // Without leading 0 assert_lex!("5162.0", |_| vec![Ok(f!(5162.0))]); assert_lex!("99.0", |_| vec![Ok(f!(99.0))]); assert_lex!("4624.51235", |_| vec![Ok(f!(4624.51235))]); assert_lex!("612.0e61", |_| vec![Ok(f!(612e61))]); assert_lex!("41.0e+9", |_| vec![Ok(f!(41e+9))]); // With leading negative sign assert_lex!("-700.5", |_| vec![Ok(Token::Minus), Ok(f!(700.5))]); assert_lex!("-9.0e2", |_| vec![Ok(Token::Minus), Ok(f!(9.0e2))]); assert_lex!("-0.5e1", |_| vec![Ok(Token::Minus), Ok(f!(0.5e1))]); assert_lex!("-0.0", |_| vec![Ok(Token::Minus), Ok(f!(0.0))]); // Underscores assert_lex!("12_3.45_6", |_| vec![Ok(f!(123.456))]); assert_lex!("1e1_0", |_| vec![Ok(f!(1e10))]); assert_lex!("123_.456", |_| vec![ Ok(Token::Integer(123.into())), Ok(Token::Ident(symbol!("_"))), Ok(Token::Dot), Ok(Token::Integer(456.into())), ]); } #[test] fn lex_identifier_or_atom() { assert_lex!("_identifier", |_| vec![Ok(Token::Ident(symbol!( "_identifier" )))]); assert_lex!("_Identifier", |_| vec![Ok(Token::Ident(symbol!( "_Identifier" )))]); assert_lex!("identifier", |_| vec![Ok(Token::Atom(symbol!( "identifier" )))]); assert_lex!("Identifier", |_| vec![Ok(Token::Ident(symbol!( "Identifier" )))]); assert_lex!("z0123", |_| vec![Ok(Token::Atom(symbol!("z0123")))]); assert_lex!("i_d@e_t0123", |_| vec![Ok(Token::Atom(symbol!( "i_d@e_t0123" )))]); } #[test] fn lex_integer_literal() { // Decimal assert_lex!("1", |_| vec![Ok(Token::Integer(1.into()))]); assert_lex!("9624", |_| vec![Ok(Token::Integer(9624.into()))]); assert_lex!("-1", |_| vec![ Ok(Token::Minus), Ok(Token::Integer(1.into())) ]); assert_lex!("-9624", |_| vec![ Ok(Token::Minus), Ok(Token::Integer(9624.into())) ]); // Hexadecimal assert_lex!(r#"\x00"#, |_| vec![Ok(Token::Integer(0x0.into()))]); assert_lex!(r#"\x{1234FF}"#, |_| vec![Ok(Token::Integer( 0x1234FF.into() ))]); assert_lex!("-16#0", |_| vec![ Ok(Token::Minus), Ok(Token::Integer(0x0.into())) ]); assert_lex!("-16#1234FF", |_| vec![ Ok(Token::Minus), Ok(Token::Integer(0x1234FF.into())) ]); // Octal assert_lex!(r#"\0"#, |_| vec![Ok(Token::Integer(0.into()))]); assert_lex!(r#"\624"#, |_| vec![Ok(Token::Integer(0o624.into()))]); assert_lex!(r#"\6244"#, |_| vec![ Ok(Token::Integer(0o624.into())), Ok(Token::Integer(4.into())) ]); // Octal integer literal followed by non-octal digits. assert_lex!(r#"\008"#, |_| vec![ Ok(Token::Integer(0.into())), Ok(Token::Integer(8.into())) ]); assert_lex!(r#"\1238"#, |_| vec![ Ok(Token::Integer(0o123.into())), Ok(Token::Integer(8.into())) ]); // Underscores assert_lex!("123_456", |_| vec![Ok(Token::Integer(123456.into()))]); assert_lex!("123_456_789", |_| vec![Ok(Token::Integer( 123456789.into() ))]); assert_lex!("1_2", |_| vec![Ok(Token::Integer(12.into()))]); assert_lex!("16#123_abc", |_| vec![Ok(Token::Integer(0x123abc.into()))]); assert_lex!("10#123_abc", |_| vec![ Ok(Token::Integer(123.into())), Ok(Token::Ident(Symbol::intern("_abc"))) ]); assert_lex!("1_6#abc", |_| vec![Ok(Token::Integer(0xabc.into()))]); assert_lex!("1__0", |_| vec![ Ok(Token::Integer(1.into())), Ok(Token::Ident(Symbol::intern("__0"))) ]); assert_lex!("123_", |_| vec![ Ok(Token::Integer(123.into())), Ok(Token::Ident(Symbol::intern("_"))), ]); assert_lex!("123__", |_| vec![ Ok(Token::Integer(123.into())), Ok(Token::Ident(Symbol::intern("__"))), ]); } #[test] fn lex_string() { assert_lex!(r#""this is a string""#, |_| vec![Ok(Token::String( symbol!("this is a string") ))]); assert_lex!(r#""this is a string"#, |source_id| vec![Err( LexicalError::UnclosedString { span: SourceSpan::new( SourceIndex::new(source_id, ByteIndex(0)), SourceIndex::new(source_id, ByteIndex(17)) ) } )]); } #[test] fn lex_whitespace() { assert_lex!(" \n \t", |_| vec![]); assert_lex!("\r\n", |_| vec![]); } } ================================================ FILE: libeir_syntax_erl/src/lexer/mod.rs ================================================ //! A fairly basic lexer for Erlang pub use libeir_intern::symbol::{symbols, SYMBOL_TABLE}; pub use libeir_intern::symbol::{Ident, InternedString, LocalInternedString, Symbol}; mod errors; mod lexer; mod token; pub use self::errors::{LexicalError, TokenConvertError}; pub use self::lexer::Lexer; pub use self::token::{AtomToken, IdentToken, IntegerToken, StringToken, SymbolToken, TokenType}; pub use self::token::{DelayedSubstitution, LexicalToken, Token}; /// The type that serves as an `Item` for the lexer iterator. pub type Lexed = Result; /// The result type produced by TryFrom pub type TokenConvertResult = Result; ================================================ FILE: libeir_syntax_erl/src/lexer/token.rs ================================================ use std::convert::TryFrom; use std::fmt; use std::hash::{Hash, Hasher}; use std::mem; use libeir_diagnostics::{SourceIndex, SourceSpan}; use libeir_util_number::{Float, Integer, ToPrimitive}; use super::{LexicalError, Symbol, TokenConvertError, TokenConvertResult}; #[derive(Debug, Clone, PartialEq, Eq)] pub struct LexicalToken(pub SourceIndex, pub Token, pub SourceIndex); impl LexicalToken { #[inline] pub fn token(&self) -> Token { self.1.clone() } #[inline] pub fn span(&self) -> SourceSpan { SourceSpan::new(self.0, self.2) } } impl fmt::Display for LexicalToken { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{}", self.token()) } } impl std::convert::Into<(SourceIndex, Token, SourceIndex)> for LexicalToken { fn into(self) -> (SourceIndex, Token, SourceIndex) { (self.0, self.1, self.2) } } impl std::convert::From<(SourceIndex, Token, SourceIndex)> for LexicalToken { fn from(triple: (SourceIndex, Token, SourceIndex)) -> LexicalToken { LexicalToken(triple.0, triple.1, triple.2) } } /// Used to identify the type of token expected in a TokenConvertError #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub enum TokenType { Atom, Ident, String, Integer, Symbol, } impl fmt::Display for TokenType { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { TokenType::Atom => write!(f, "ATOM"), TokenType::Ident => write!(f, "IDENT"), TokenType::String => write!(f, "STRING"), TokenType::Integer => write!(f, "INTEGER"), TokenType::Symbol => write!(f, "SYMBOL"), } } } #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct AtomToken(pub SourceIndex, pub Token, pub SourceIndex); impl AtomToken { pub fn token(&self) -> Token { self.1.clone() } pub fn span(&self) -> SourceSpan { SourceSpan::new(self.0, self.2) } pub fn symbol(&self) -> Symbol { match self.token() { Token::Atom(a) => a, _ => unreachable!(), } } } impl TryFrom for AtomToken { type Error = TokenConvertError; fn try_from(t: LexicalToken) -> TokenConvertResult { use libeir_intern::symbol::symbols; match t { LexicalToken(start, tok @ Token::Atom(_), end) => { return Ok(AtomToken(start, tok, end)) } LexicalToken(start, Token::If, end) => { return Ok(AtomToken(start, Token::Atom(symbols::If), end)); } t => Err(TokenConvertError { span: t.span(), token: t.token(), expected: TokenType::Atom, }), } } } impl Into for AtomToken { fn into(self) -> LexicalToken { LexicalToken(self.0, self.1, self.2) } } impl fmt::Display for AtomToken { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { self.1.fmt(f) } } #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct IdentToken(pub SourceIndex, pub Token, pub SourceIndex); impl IdentToken { pub fn token(&self) -> Token { self.1.clone() } pub fn span(&self) -> SourceSpan { SourceSpan::new(self.0, self.2) } pub fn symbol(&self) -> Symbol { match self.token() { Token::Ident(a) => a, _ => unreachable!(), } } } impl TryFrom for IdentToken { type Error = TokenConvertError; fn try_from(t: LexicalToken) -> TokenConvertResult { if let LexicalToken(start, tok @ Token::Ident(_), end) = t { return Ok(IdentToken(start, tok, end)); } Err(TokenConvertError { span: t.span(), token: t.token(), expected: TokenType::Ident, }) } } impl Into for IdentToken { fn into(self) -> LexicalToken { LexicalToken(self.0, self.1, self.2) } } impl fmt::Display for IdentToken { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { self.1.fmt(f) } } #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct StringToken(pub SourceIndex, pub Token, pub SourceIndex); impl StringToken { pub fn token(&self) -> Token { self.1.clone() } pub fn span(&self) -> SourceSpan { SourceSpan::new(self.0, self.2) } pub fn symbol(&self) -> Symbol { match self.token() { Token::String(a) => a, _ => unreachable!(), } } } impl TryFrom for StringToken { type Error = TokenConvertError; fn try_from(t: LexicalToken) -> TokenConvertResult { if let LexicalToken(start, tok @ Token::String(_), end) = t { return Ok(StringToken(start, tok, end)); } Err(TokenConvertError { span: t.span(), token: t.token(), expected: TokenType::String, }) } } impl Into for StringToken { fn into(self) -> LexicalToken { LexicalToken(self.0, self.1, self.2) } } impl fmt::Display for StringToken { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { self.1.fmt(f) } } #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct IntegerToken(pub SourceIndex, pub Token, pub SourceIndex); impl IntegerToken { pub fn token(&self) -> Token { self.1.clone() } pub fn span(&self) -> SourceSpan { SourceSpan::new(self.0, self.2) } pub fn small_integer(&self) -> Option { match self.token() { Token::Integer(a) => a.to_i64(), _ => unreachable!(), } } } impl TryFrom for IntegerToken { type Error = TokenConvertError; fn try_from(t: LexicalToken) -> TokenConvertResult { if let LexicalToken(start, tok @ Token::Integer(_), end) = t { return Ok(IntegerToken(start, tok, end)); } Err(TokenConvertError { span: t.span(), token: t.token(), expected: TokenType::Integer, }) } } impl Into for IntegerToken { fn into(self) -> LexicalToken { LexicalToken(self.0, self.1, self.2) } } impl fmt::Display for IntegerToken { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { self.1.fmt(f) } } #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct SymbolToken(pub SourceIndex, pub Token, pub SourceIndex); impl SymbolToken { pub fn token(&self) -> Token { self.1.clone() } pub fn span(&self) -> SourceSpan { SourceSpan::new(self.0, self.2) } } impl TryFrom for SymbolToken { type Error = TokenConvertError; fn try_from(t: LexicalToken) -> TokenConvertResult { match t { LexicalToken(_, Token::Atom(_), _) => (), LexicalToken(_, Token::Ident(_), _) => (), LexicalToken(_, Token::String(_), _) => (), LexicalToken(start, token, end) => return Ok(SymbolToken(start, token, end)), } Err(TokenConvertError { span: t.span(), token: t.token(), expected: TokenType::Symbol, }) } } impl Into for SymbolToken { fn into(self) -> LexicalToken { LexicalToken(self.0, self.1, self.2) } } impl fmt::Display for SymbolToken { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { self.1.fmt(f) } } #[derive(Debug, Copy, Clone, PartialEq, Eq)] pub enum DelayedSubstitution { FunctionName, FunctionArity, } /// This enum contains tokens produced by the lexer #[derive(Debug, Clone)] pub enum Token { // Signifies end of input EOF, // A tokenization error which may be recovered from Error(LexicalError), DelayedSubstitution(DelayedSubstitution), // Docs Comment, Edoc, // Literals Char(char), Integer(Integer), Float(Float), Atom(Symbol), String(Symbol), Ident(Symbol), // Keywords and Symbols LParen, RParen, Comma, RightStab, LBrace, RBrace, LBracket, RBracket, Bar, BarBar, LeftStab, Semicolon, Colon, Pound, Dot, // Keywords After, Begin, Case, Try, Catch, End, Fun, If, Of, Receive, When, // Attributes Record, Spec, Callback, OptionalCallback, Import, Export, ExportType, Removed, Module, Compile, Vsn, Author, OnLoad, Behaviour, Deprecated, Type, Opaque, File, // Operators AndAlso, OrElse, Bnot, Not, Star, Slash, Div, Rem, Band, And, Plus, Minus, Bor, Bxor, Bsl, Bsr, Or, Xor, PlusPlus, MinusMinus, // == IsEqual, // /= IsNotEqual, // =< IsLessThanOrEqual, // < IsLessThan, // >= IsGreaterThanOrEqual, // > IsGreaterThan, // =:= IsExactlyEqual, // =/= IsExactlyNotEqual, // <= LeftArrow, // => RightArrow, // := ColonEqual, // << BinaryStart, // >> BinaryEnd, Bang, // = Equals, ColonColon, DotDot, DotDotDot, Question, DoubleQuestion, } impl PartialEq for Token { fn eq(&self, other: &Token) -> bool { match self { Token::Char(c) => { if let Token::Char(c2) = other { return *c == *c2; } } Token::Integer(i) => { if let Token::Integer(i2) = other { return *i == *i2; } } Token::Float(n) => { if let Token::Float(n2) = other { return *n == *n2; } } Token::Error(_) => { if let Token::Error(_) = other { return true; } } Token::Atom(ref a) => { if let Token::Atom(a2) = other { return *a == *a2; } } Token::Ident(ref i) => { if let Token::Ident(i2) = other { return *i == *i2; } } Token::String(ref s) => { if let Token::String(s2) = other { return *s == *s2; } } _ => return mem::discriminant(self) == mem::discriminant(other), } return false; } } impl Eq for Token {} impl Hash for Token { fn hash(&self, state: &mut H) { match *self { Token::Float(n) => n.raw().hash(state), Token::Error(ref e) => e.hash(state), Token::Atom(ref a) => a.hash(state), Token::Ident(ref i) => i.hash(state), Token::String(ref s) => s.hash(state), Token::Char(c) => c.hash(state), ref token => token.to_string().hash(state), } } } impl Token { pub fn from_bare_atom<'input>(atom: &'input str) -> Self { match atom.as_ref() { // Reserved words "after" => Token::After, "begin" => Token::Begin, "case" => Token::Case, "try" => Token::Try, "catch" => Token::Catch, "end" => Token::End, "fun" => Token::Fun, "if" => Token::If, "of" => Token::Of, "receive" => Token::Receive, "when" => Token::When, "andalso" => Token::AndAlso, "orelse" => Token::OrElse, "bnot" => Token::Bnot, "not" => Token::Not, "div" => Token::Div, "rem" => Token::Rem, "band" => Token::Band, "and" => Token::And, "bor" => Token::Bor, "bxor" => Token::Bxor, "bsl" => Token::Bsl, "bsr" => Token::Bsr, "or" => Token::Or, "xor" => Token::Xor, _ => Token::Atom(Symbol::intern(atom)), } } /// For opening tokens like `(` and `[`, get the corresponding /// closing token. pub fn get_closing_token(&self) -> Self { match self { Token::LParen => Token::RParen, Token::LBrace => Token::RBrace, Token::LBracket => Token::RBracket, Token::BinaryStart => Token::BinaryEnd, _ => panic!("{} has no closing token", self), } } } impl fmt::Display for Token { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { Token::EOF => write!(f, "EOF"), Token::Error(_) => write!(f, "ERROR"), Token::Comment => write!(f, "COMMENT"), Token::Edoc => write!(f, "EDOC"), Token::DelayedSubstitution(DelayedSubstitution::FunctionName) => write!(f, "STRING"), Token::DelayedSubstitution(DelayedSubstitution::FunctionArity) => write!(f, "INTEGER"), // Literals Token::Char(ref c) => write!(f, "{}", c), Token::Integer(ref i) => write!(f, "{}", i), Token::Float(ref n) => write!(f, "{}", n), Token::Atom(ref s) => write!(f, "'{}'", s), Token::String(ref s) => write!(f, "\"{}\"", s), Token::Ident(ref s) => write!(f, "{}", s), Token::LParen => write!(f, "("), Token::RParen => write!(f, ")"), Token::Comma => write!(f, ","), Token::RightStab => write!(f, "->"), Token::LBrace => write!(f, "{{"), Token::RBrace => write!(f, "}}"), Token::LBracket => write!(f, "["), Token::RBracket => write!(f, "]"), Token::Bar => write!(f, "|"), Token::BarBar => write!(f, "||"), Token::LeftStab => write!(f, "<-"), Token::Semicolon => write!(f, ";"), Token::Colon => write!(f, ":"), Token::Pound => write!(f, "#"), Token::Dot => write!(f, "."), Token::After => write!(f, "after"), Token::Begin => write!(f, "begin"), Token::Case => write!(f, "case"), Token::Try => write!(f, "try"), Token::Catch => write!(f, "catch"), Token::End => write!(f, "end"), Token::Fun => write!(f, "fun"), Token::If => write!(f, "if"), Token::Of => write!(f, "of"), Token::Receive => write!(f, "receive"), Token::When => write!(f, "when"), Token::Record => write!(f, "record"), Token::Spec => write!(f, "spec"), Token::Callback => write!(f, "callback"), Token::OptionalCallback => write!(f, "optional_callback"), Token::Import => write!(f, "import"), Token::Export => write!(f, "export"), Token::ExportType => write!(f, "export_type"), Token::Removed => write!(f, "removed"), Token::Module => write!(f, "module"), Token::Compile => write!(f, "compile"), Token::Vsn => write!(f, "vsn"), Token::Author => write!(f, "author"), Token::OnLoad => write!(f, "on_load"), Token::Behaviour => write!(f, "behaviour"), Token::Deprecated => write!(f, "deprecated"), Token::Type => write!(f, "type"), Token::Opaque => write!(f, "opaque"), Token::File => write!(f, "file"), Token::AndAlso => write!(f, "andalso"), Token::OrElse => write!(f, "orelse"), Token::Bnot => write!(f, "bnot"), Token::Not => write!(f, "not"), Token::Star => write!(f, "*"), Token::Slash => write!(f, "/"), Token::Div => write!(f, "div"), Token::Rem => write!(f, "rem"), Token::Band => write!(f, "band"), Token::And => write!(f, "and"), Token::Plus => write!(f, "+"), Token::Minus => write!(f, "-"), Token::Bor => write!(f, "bor"), Token::Bxor => write!(f, "bxor"), Token::Bsl => write!(f, "bsl"), Token::Bsr => write!(f, "bsr"), Token::Or => write!(f, "or"), Token::Xor => write!(f, "xor"), Token::PlusPlus => write!(f, "++"), Token::MinusMinus => write!(f, "--"), Token::IsEqual => write!(f, "=="), Token::IsNotEqual => write!(f, "/="), Token::IsLessThanOrEqual => write!(f, "=<"), Token::IsLessThan => write!(f, "<"), Token::IsGreaterThanOrEqual => write!(f, ">="), Token::IsGreaterThan => write!(f, ">"), Token::IsExactlyEqual => write!(f, "=:="), Token::IsExactlyNotEqual => write!(f, "=/="), Token::LeftArrow => write!(f, "<="), Token::RightArrow => write!(f, "=>"), Token::ColonEqual => write!(f, ":="), Token::BinaryStart => write!(f, "<<"), Token::BinaryEnd => write!(f, ">>"), Token::Bang => write!(f, "!"), Token::Equals => write!(f, "="), Token::ColonColon => write!(f, "::"), Token::DotDot => write!(f, ".."), Token::DotDotDot => write!(f, "..."), Token::Question => write!(f, "?"), Token::DoubleQuestion => write!(f, "??"), } } } ================================================ FILE: libeir_syntax_erl/src/lib.rs ================================================ //#![deny(warnings)] #![feature(trait_alias, or_patterns, never_type)] mod abstr; mod evaluator; mod lexer; mod lower; mod parser; mod preprocessor; mod util; pub use self::abstr::lower as lower_abstr; pub use self::lexer::*; pub use self::lower::{lower_module, LowerError}; pub use self::parser::*; pub use self::preprocessor::*; pub enum ErlangError { Parser(ParserError), Lower(LowerError), } impl From for ErlangError { fn from(e: ParserError) -> Self { ErlangError::Parser(e) } } impl From for ErlangError { fn from(e: LowerError) -> Self { ErlangError::Lower(e) } } impl libeir_diagnostics::ToDiagnostic for ErlangError { fn to_diagnostic(&self) -> libeir_diagnostics::Diagnostic { match self { ErlangError::Parser(err) => err.to_diagnostic(), ErlangError::Lower(err) => err.to_diagnostic(), } } } ================================================ FILE: libeir_syntax_erl/src/lower/errors.rs ================================================ use libeir_diagnostics::{Diagnostic, Label, SourceIndex, SourceSpan, ToDiagnostic}; use crate::parser::binary::TypeName as BinaryTypeName; use crate::util::encoding::StringError; use snafu::Snafu; #[derive(Debug, Snafu)] #[snafu(visibility = "pub(crate)")] pub enum LowerError { #[snafu(display("illegal expression"))] IllegalExpression { span: SourceSpan, }, /// An invalid expression occurred in a pattern #[snafu(display("an invalid expression occurred in a pattern"))] NotAllowedInPattern { span: SourceSpan, }, /// Equality in a pattern caused two nodes to be merged. /// It has been shown to be unmatchable. #[snafu(display("patterns are fully disjoint and can never be matched"))] DisjointPatternUnionWarning { left: Option, right: Option, }, /// Pattern is constrained by two different constant /// values, or is matched against an unmatchable value #[snafu(display("pattern can never be matched"))] UnmatchablePatternWarning { pat: Option, reason: Option, }, /// Equality in a pattern caused two nodes to be merged, /// but merging these two nodes is not supported. /// Happens when trying to merge two binary patterns. #[snafu(display("patterns cannot be merged"))] UnsupportedPatternUnion { left: Option, right: SourceSpan, }, #[snafu(display("invalid const expression in pattern"))] PatternConst { source: crate::evaluator::EvalError, span: SourceSpan, }, StringTokenizeError { source: crate::util::string_tokenizer::StringTokenizeError, }, /// Unable to resolve a variable in scope. #[snafu(display("could not resolve variable"))] UnresolvedVariable { span: SourceSpan, }, /// Unable to bind a variable in a scope, it is already bound. #[snafu(display("variable was already bound in scope"))] AlreadyBound { new: SourceSpan, old: SourceSpan, }, /// Variable binding shadowed other binding #[snafu(display("binding shadowed previously bound variable"))] ShadowingBind { new: SourceSpan, old: SourceSpan, }, // Binary specifier parsing #[snafu(display("{} does not support size in binary entry", typ))] BinaryInvalidSize { span: SourceSpan, typ: BinaryTypeName, }, #[snafu(display("binary construction can never succeed"))] BinaryConstructEntryTypeWarning { span: SourceSpan, }, String { source: StringError, }, // Records #[snafu(display("record field specified more than once"))] DuplicateRecordField { new: SourceSpan, old: SourceSpan, }, #[snafu(display("record is not defined"))] UndefinedRecord { span: SourceSpan, }, // Maps #[snafu(display("only map put (=>) allowed in map construction"))] MapUpdateInConstruction { map: SourceSpan, field: SourceSpan, }, #[snafu(display("map update performed on a non map"))] MapUpdateOnNonMap { map: SourceSpan, }, } impl From for LowerError { fn from(err: crate::util::string_tokenizer::StringTokenizeError) -> Self { LowerError::StringTokenizeError { source: err } } } impl From for LowerError { fn from(err: StringError) -> LowerError { LowerError::String { source: err } } } impl ToDiagnostic for LowerError { fn to_diagnostic(&self) -> Diagnostic { let msg = self.to_string(); match self { LowerError::IllegalExpression { span } => Diagnostic::error() .with_message(msg) .with_labels(vec![ Label::primary(span.source_id(), *span).with_message("illegal expression") ]), LowerError::NotAllowedInPattern { span } => Diagnostic::error() .with_message(msg) .with_labels(vec![Label::primary(span.source_id(), *span) .with_message("disallowed expression in pattern")]), LowerError::DisjointPatternUnionWarning { left, right } => { let dig = Diagnostic::warning().with_message(msg); let mut labels = vec![]; if let Some(left) = left { labels .push(Label::primary(left.source_id(), *left).with_message("left pattern")); } if let Some(right) = right { labels.push( Label::primary(right.source_id(), *right).with_message("right pattern"), ); } dig.with_labels(labels) } LowerError::UnmatchablePatternWarning { pat, reason } => { let dig = Diagnostic::warning().with_message(msg); let mut labels = vec![]; if let Some(pat) = pat { labels.push( Label::primary(pat.source_id(), *pat) .with_message("pattern can never be matched"), ); } if let Some(reason) = reason { labels.push( Label::primary(reason.source_id(), *reason) .with_message("matched against this"), ); } dig.with_labels(labels) } LowerError::UnsupportedPatternUnion { left, right } => { let dig = Diagnostic::warning().with_message(msg); let mut labels = vec![]; if let Some(left) = left { labels .push(Label::primary(left.source_id(), *left).with_message("left pattern")); } labels .push(Label::primary(right.source_id(), *right).with_message("right pattern")); dig.with_labels(labels) } LowerError::PatternConst { source, .. } => source.to_diagnostic(), LowerError::StringTokenizeError { source } => source.to_diagnostic(), LowerError::UnresolvedVariable { span } => Diagnostic::error() .with_message(msg) .with_labels(vec![ Label::primary(span.source_id(), *span).with_message("not bound in scope") ]), LowerError::AlreadyBound { new, old } => { Diagnostic::error().with_message(msg).with_labels(vec![ Label::primary(new.source_id(), *new) .with_message("variable was already bound in scope"), Label::secondary(old.source_id(), *old).with_message("previously bound here"), ]) } LowerError::ShadowingBind { new, old } => { Diagnostic::warning().with_message(msg).with_labels(vec![ Label::primary(new.source_id(), *new) .with_message("variable was already bound in scope"), Label::secondary(old.source_id(), *old).with_message("previously bound here"), ]) } LowerError::BinaryInvalidSize { span, typ } => Diagnostic::error() .with_message(msg) .with_labels(vec![Label::primary(span.source_id(), *span).with_message( format!("size specifier not valid for {} binary entries", typ), )]), LowerError::BinaryConstructEntryTypeWarning { span } => Diagnostic::warning() .with_message(msg) .with_labels(vec![ Label::primary(span.source_id(), *span).with_message("can never succeed") ]), LowerError::String { source } => source.to_diagnostic(), LowerError::DuplicateRecordField { new, old } => { Diagnostic::error().with_message(msg).with_labels(vec![ Label::primary(new.source_id(), *old) .with_message("duplicate field definition in record"), Label::secondary(old.source_id(), *old).with_message("previously defined here"), ]) } LowerError::UndefinedRecord { span } => Diagnostic::error() .with_message(msg) .with_labels(vec![Label::primary(span.source_id(), *span)]), LowerError::MapUpdateInConstruction { map, field } => { Diagnostic::error().with_message(msg).with_labels(vec![ Label::primary(field.source_id(), *field) .with_message("map update (:=) attempted"), Label::secondary(map.source_id(), *map) .with_message("expression is map construction"), ]) } LowerError::MapUpdateOnNonMap { map } => Diagnostic::warning() .with_message(msg) .with_labels(vec![Label::primary(map.source_id(), *map).with_message( "updated value is not a map, this will fail at runtime", )]), } } } ================================================ FILE: libeir_syntax_erl/src/lower/exception_handler_stack.rs ================================================ use libeir_diagnostics::SourceSpan; use libeir_ir::{Block, FunctionBuilder, Value}; pub struct ExceptionHandlerStack { stack: Vec<(Value, bool)>, } impl ExceptionHandlerStack { pub fn new() -> Self { ExceptionHandlerStack { stack: vec![] } } pub fn push_handler(&mut self, handler: Value) { self.stack.push((handler, true)); } pub fn pop_handler(&mut self) { self.stack.pop(); } pub fn make_error_jump_trace( &self, b: &mut FunctionBuilder, block: Block, typ: Value, error: Value, trace: Value, ) { let (handler, has_arg) = self.stack.last().unwrap(); if *has_arg { b.op_call_flow(block, *handler, &[typ, error, trace]) } else { b.op_call_flow(block, *handler, &[]) } } pub fn make_error_jump( &self, b: &mut FunctionBuilder, span: SourceSpan, block: Block, typ: Value, error: Value, ) { let loc = b.fun().block_location(block); let cont = b.op_trace_capture_raw(span, block); b.block_set_location(cont, loc); let trace = b.block_args(cont)[0]; self.make_error_jump_trace(b, cont, typ, error, trace); } pub fn finish(&self) { assert!(self.stack.len() == 0); } pub fn len(&self) -> usize { self.stack.len() } } ================================================ FILE: libeir_syntax_erl/src/lower/expr/binary.rs ================================================ pub use libeir_ir::binary::{BinaryEntrySpecifier, Endianness}; use libeir_ir::{ operation::binary_construct::{ BinaryConstructFinish, BinaryConstructPush, BinaryConstructStart, }, Block as IrBlock, FunctionBuilder, Value as IrValue, }; use libeir_util_binary::BitVec; use crate::parser::binary::{TypeName, specifier_to_typename, specifier_can_have_size, default_specifier}; use crate::parser::ast::{Binary, BinaryElement, Expr, Literal}; use crate::lower::{LowerCtx, LowerError}; use crate::lower::expr::lower_single_same_scope; use crate::util::string_tokenizer::StringTokenizer; fn make_size( ctx: &mut LowerCtx, b: &mut FunctionBuilder, block: &mut IrBlock, bit_size: &Option, spec: BinaryEntrySpecifier, ) -> Option { let spec_typ = specifier_to_typename(&spec); if let Some(size_expr) = bit_size { if !specifier_can_have_size(&spec) { ctx.error(LowerError::BinaryInvalidSize { span: size_expr.span(), typ: spec_typ, }); None } else { Some(map_block!( *block, lower_single_same_scope(ctx, b, *block, size_expr) )) } } else { match spec_typ { TypeName::Integer => Some(b.value(8)), TypeName::Float => Some(b.value(64)), _ => None, } } } /// Lowers a single entry of a binary construction element. /// /// A couple of gotchas with the syntax: /// - `<<"abc">>.`: obviously valid, creates a binary of the ascii characters /// - `<<"™">>.`: also valid, encodes each CODEPOINT in the string as a byte, /// truncated. This evaluates to `<<34>>`. /// - `<<[97, 98, 99]>>.` not valid, while a string binary element is handled /// as a special case, this does not apply to char lists. /// - `<<"abc":10/integer>>` valid! a string literal is desugared to a list of /// individual integers in the binary entry, each with the specifier on it. pub(crate) fn lower_binary_elem( ctx: &mut LowerCtx, b: &mut FunctionBuilder, mut block: IrBlock, bin_ref: &mut IrValue, elem: &BinaryElement, ) -> IrBlock { let spec = elem.specifier.unwrap_or(default_specifier()); let size_val = make_size(ctx, b, &mut block, &elem.bit_size, spec); let elem_val = match &elem.bit_expr { Expr::Literal(Literal::String(_id, string)) if !spec.is_native_endian() => { let tokenizer = StringTokenizer::new(*string); for elem in tokenizer { match elem { Ok((cp, span)) => { let elem_val = b.value(cp); let (ok_cont, err_cont) = BinaryConstructPush::build( b, block, *bin_ref, elem_val, spec, size_val, ); *bin_ref = b.block_args(ok_cont)[0]; block = ok_cont; // TODO: Proper error b.op_unreachable(span, err_cont); }, Err(err) => { ctx.error(err.into()); }, } } None } _ => Some(map_block!( block, lower_single_same_scope(ctx, b, block, &elem.bit_expr) )), }; if let Some(elem_val) = elem_val { let (ok_cont, err_cont) = BinaryConstructPush::build(b, block, *bin_ref, elem_val, spec, size_val); *bin_ref = b.block_args(ok_cont)[0]; block = ok_cont; // TODO: Proper error b.op_unreachable(elem.span, err_cont); } block } pub(super) fn lower_binary_expr( ctx: &mut LowerCtx, b: &mut FunctionBuilder, mut block: IrBlock, bin: Option, binary: &Binary, ) -> (IrBlock, IrValue) { block = BinaryConstructStart::build(b, block); let mut bin_ref = b.block_args(block)[0]; if let Some(bin) = bin { let spec = BinaryEntrySpecifier::Bytes { unit: 1 }; let (ok_cont, err_cont) = BinaryConstructPush::build(b, block, bin_ref, bin, spec, None); block = ok_cont; b.op_unreachable(binary.span, err_cont); bin_ref = b.block_args(ok_cont)[0]; } let mut bitvec = BitVec::new(); for elem in binary.elements.iter() { let resolve_rec_idx = |name, field| ctx.resolve_rec_idx(name, field); match crate::util::binary::append_static_binary_element(elem, &mut bitvec, Some(&resolve_rec_idx)) { // This means the binary element was fully static, and the data has // been appended to the BitVec. Ok(()) => (), // Element was dynamic, we need to generate binary construction // operations. Err(_) => { // If we have static data before this dynamic element, we // need to append that first. if !bitvec.empty() { let bin = b.value(bitvec); let spec = BinaryEntrySpecifier::Bits { unit: 1 }; let (ok_cont, err_cont) = BinaryConstructPush::build(b, block, bin_ref, bin, spec, None); bin_ref = b.block_args(ok_cont)[0]; block = ok_cont; // We know the value we appended is a BitVec, this can never // fail. b.op_unreachable(binary.span, err_cont); bitvec = BitVec::new(); } block = lower_binary_elem(ctx, b, block, &mut bin_ref, elem); }, } } if !bitvec.empty() { let bin = b.value(bitvec); let spec = BinaryEntrySpecifier::Bits { unit: 1 }; let (ok_cont, err_cont) = BinaryConstructPush::build(b, block, bin_ref, bin, spec, None); bin_ref = b.block_args(ok_cont)[0]; block = ok_cont; // We know the value we appended is a BitVec, this can never // fail. b.op_unreachable(binary.span, err_cont); } block = BinaryConstructFinish::build(b, block, bin_ref); let res_arg = b.block_args(block)[0]; (block, res_arg) } ================================================ FILE: libeir_syntax_erl/src/lower/expr/binary_expr.rs ================================================ use libeir_ir::{Block as IrBlock, FunctionBuilder, Value as IrValue}; use libeir_intern::{Ident, Symbol}; use crate::parser::ast::BinaryExpr; use crate::parser::ast::BinaryOp; use crate::lower::expr::{lower_single, lower_single_same_scope}; use crate::lower::LowerCtx; pub(super) fn lower_binary_expr( ctx: &mut LowerCtx, b: &mut FunctionBuilder, mut block: IrBlock, expr: &BinaryExpr, ) -> (IrBlock, IrValue) { let BinaryExpr { lhs, rhs, op, id: _, span, } = expr; let span = *span; match op { BinaryOp::AndAlso => { let loc = ctx.current_location(b, span); let (l1_block, lhs_val) = lower_single(ctx, b, block, lhs); let ret_block = b.block_insert(); let ret_val = b.block_arg_insert(ret_block); let (true1_block, false1_block, non1_block) = b.op_if_bool(span, l1_block, lhs_val); // True branch let (l2_block, rhs_val) = lower_single(ctx, b, true1_block, rhs); b.op_call_flow(l2_block, ret_block, &[rhs_val]); // False branch let false_val = b.value(false); b.op_call_flow(false1_block, ret_block, &[false_val]); // Nonbool branch { let block = non1_block; let typ_val = b.value(Symbol::intern("error")); let err_atom = b.value(Symbol::intern("badarg")); let err_val = b.prim_tuple(span, &[err_atom, lhs_val]); b.block_set_location(block, loc); ctx.exc_stack .make_error_jump(b, span, block, typ_val, err_val); } (ret_block, ret_val) } BinaryOp::OrElse => { let loc = ctx.current_location(b, span); let (l1_block, lhs_val) = lower_single(ctx, b, block, lhs); let ret_block = b.block_insert(); let ret_val = b.block_arg_insert(ret_block); let (true1_block, false1_block, non1_block) = b.op_if_bool(span, l1_block, lhs_val); // True branch let true_val = b.value(true); b.op_call_flow(true1_block, ret_block, &[true_val]); // False branch let (l2_block, rhs_val) = lower_single(ctx, b, false1_block, rhs); b.op_call_flow(l2_block, ret_block, &[rhs_val]); // Nonbool branch { let block = non1_block; let typ_val = b.value(Symbol::intern("error")); let err_atom = b.value(Symbol::intern("badarg")); let err_val = b.prim_tuple(span, &[err_atom, lhs_val]); b.block_set_location(block, loc); ctx.exc_stack .make_error_jump(b, span, block, typ_val, err_val); } (ret_block, ret_val) } _ => { let lhs_val = map_block!(block, lower_single_same_scope(ctx, b, block, lhs)); let rhs_val = map_block!(block, lower_single_same_scope(ctx, b, block, rhs)); let (m, f) = match op { BinaryOp::Lt => (Ident::from_str("erlang"), Ident::from_str("<")), BinaryOp::Lte => (Ident::from_str("erlang"), Ident::from_str("=<")), BinaryOp::Gt => (Ident::from_str("erlang"), Ident::from_str(">")), BinaryOp::Gte => (Ident::from_str("erlang"), Ident::from_str(">=")), BinaryOp::Sub => (Ident::from_str("erlang"), Ident::from_str("-")), BinaryOp::Add => (Ident::from_str("erlang"), Ident::from_str("+")), BinaryOp::Append => (Ident::from_str("erlang"), Ident::from_str("++")), BinaryOp::Remove => (Ident::from_str("erlang"), Ident::from_str("--")), BinaryOp::Multiply => (Ident::from_str("erlang"), Ident::from_str("*")), BinaryOp::Divide => (Ident::from_str("erlang"), Ident::from_str("/")), BinaryOp::Rem => (Ident::from_str("erlang"), Ident::from_str("rem")), BinaryOp::Div => (Ident::from_str("erlang"), Ident::from_str("div")), BinaryOp::Equal => (Ident::from_str("erlang"), Ident::from_str("==")), BinaryOp::NotEqual => (Ident::from_str("erlang"), Ident::from_str("/=")), BinaryOp::StrictEqual => (Ident::from_str("erlang"), Ident::from_str("=:=")), BinaryOp::StrictNotEqual => (Ident::from_str("erlang"), Ident::from_str("=/=")), BinaryOp::Band => (Ident::from_str("erlang"), Ident::from_str("band")), BinaryOp::Bor => (Ident::from_str("erlang"), Ident::from_str("bor")), BinaryOp::Bxor => (Ident::from_str("erlang"), Ident::from_str("bxor")), BinaryOp::Bsl => (Ident::from_str("erlang"), Ident::from_str("bsl")), BinaryOp::Bsr => (Ident::from_str("erlang"), Ident::from_str("bsr")), BinaryOp::Or => (Ident::from_str("erlang"), Ident::from_str("or")), BinaryOp::Xor => (Ident::from_str("erlang"), Ident::from_str("xor")), BinaryOp::And => (Ident::from_str("erlang"), Ident::from_str("and")), BinaryOp::Send => (Ident::from_str("erlang"), Ident::from_str("!")), BinaryOp::AndAlso => unreachable!(), BinaryOp::OrElse => unreachable!(), }; ctx.call_function(b, block, span, m, f, &[lhs_val, rhs_val]) } } } ================================================ FILE: libeir_syntax_erl/src/lower/expr/case.rs ================================================ use libeir_ir::operation::case::Case as CaseOp; use libeir_ir::{Block as IrBlock, FunctionBuilder, Value as IrValue}; use libeir_intern::Symbol; use crate::parser::ast::{Case, If}; use crate::lower::expr::{lower_block, lower_block_same_scope, lower_single_same_scope}; use crate::lower::pattern::lower_clause; use crate::lower::scope::ScopeMerge; use crate::lower::LowerCtx; pub(super) fn lower_case_expr( ctx: &mut LowerCtx, b: &mut FunctionBuilder, mut block: IrBlock, case: &Case, ) -> (IrBlock, IrValue) { let span = case.span; let case_loc = ctx.current_location(b, span); let match_val = map_block!(block, lower_single_same_scope(ctx, b, block, &case.expr)); let no_match = b.block_insert(); b.block_set_location(no_match, case_loc); { let typ_val = b.value(Symbol::intern("error")); let case_clause_val = b.value(Symbol::intern("case_clause")); let err_val = b.prim_tuple(span, &[case_clause_val, match_val]); ctx.exc_stack .make_error_jump(b, span, no_match, typ_val, err_val); } let mut case_b = CaseOp::builder(); case_b.set_span(span); case_b.match_on = Some(match_val); case_b.no_match = Some(b.value(no_match)); let entry_exc_height = ctx.exc_stack.len(); let mut scope_merge = ScopeMerge::new(); for clause in case.clauses.iter() { match lower_clause( ctx, &mut case_b.container, b, &mut block, false, clause.span, [&clause.pattern].iter().map(|i| *i), clause.guard.as_ref(), ) { Ok(lowered) => { let (scope_token, body) = lowered.make_body(ctx, b); // Add to case let body_val = b.value(body); case_b.push_clause(lowered.clause, lowered.guard, body_val, b); for value in lowered.values.iter() { case_b.push_value(*value, b); } let (body_ret_block, body_ret) = lower_block_same_scope(ctx, b, body, &clause.body); let binds = ctx.scope.pop_take(scope_token); scope_merge.branch(body_ret_block, body_ret, binds); } Err(lowered) => { let (scope_tok, dummy_body) = lowered.make_body(ctx, b); let (body_ret_block, body_ret) = lower_block_same_scope(ctx, b, dummy_body, &clause.body); let binds = ctx.scope.pop_take(scope_tok); scope_merge.branch(body_ret_block, body_ret, binds); } } assert!(ctx.exc_stack.len() == entry_exc_height) } case_b.finish(block, b); scope_merge.finish(ctx, b) } pub(super) fn lower_if_expr( ctx: &mut LowerCtx, b: &mut FunctionBuilder, mut block: IrBlock, if_expr: &If, ) -> (IrBlock, IrValue) { let span = if_expr.span; let loc = ctx.current_location(b, span); let match_val = b.prim_value_list(&[]); let no_match = b.block_insert(); { let block = no_match; b.block_set_location(block, loc); let typ_val = b.value(Symbol::intern("error")); let badmatch_val = b.value(Symbol::intern("badmatch")); let err_val = b.prim_tuple(span, &[badmatch_val, match_val]); ctx.exc_stack .make_error_jump(b, span, block, typ_val, err_val); } let mut case_b = CaseOp::builder(); case_b.set_span(span); case_b.match_on = Some(match_val); case_b.no_match = Some(b.value(no_match)); let entry_exc_height = ctx.exc_stack.len(); let mut scope_merge = ScopeMerge::new(); for clause in if_expr.clauses.iter() { match lower_clause( ctx, &mut case_b.container, b, &mut block, false, span, [].iter(), Some(&clause.guards), ) { Ok(lowered) => { let (scope_token, body) = lowered.make_body(ctx, b); // Add to case let body_val = b.value(body); case_b.push_clause(lowered.clause, lowered.guard, body_val, b); for value in lowered.values.iter() { case_b.push_value(*value, b); } let (body_ret_block, body_ret) = lower_block(ctx, b, body, &clause.body); // Pop scope pushed in lower_clause let binds = ctx.scope.pop_take(scope_token); scope_merge.branch(body_ret_block, body_ret, binds); } Err(lowered) => { let (scope_token, body) = lowered.make_body(ctx, b); let (body_ret_block, body_ret) = lower_block(ctx, b, body, &clause.body); let binds = ctx.scope.pop_take(scope_token); scope_merge.branch(body_ret_block, body_ret, binds); } } assert!(ctx.exc_stack.len() == entry_exc_height) } case_b.finish(block, b); scope_merge.finish(ctx, b) } ================================================ FILE: libeir_syntax_erl/src/lower/expr/catch.rs ================================================ use libeir_ir::operation::case::{Case, CaseBuilder}; use libeir_ir::{Block as IrBlock, FunctionBuilder, Value as IrValue}; use libeir_intern::Symbol; use crate::parser::ast::Name; use crate::parser::ast::NodeId; use crate::parser::ast::{Catch, Try}; use crate::parser::ast::{Expr, Literal, Var}; use crate::lower::expr::{lower_block, lower_single}; use crate::lower::pattern::lower_clause; use crate::lower::LowerCtx; pub(super) fn lower_try_expr( ctx: &mut LowerCtx, b: &mut FunctionBuilder, mut block: IrBlock, try_expr: &Try, ) -> (IrBlock, IrValue) { let span = try_expr.span; let exc_block = b.block_insert(); let exc_type = b.block_arg_insert(exc_block); let exc_error = b.block_arg_insert(exc_block); let exc_trace = b.block_arg_insert(exc_block); // Lower exprs while catching exceptions ctx.exc_stack.push_handler(b.value(exc_block)); let body_ret = map_block!(block, lower_block(ctx, b, block, &try_expr.exprs)); ctx.exc_stack.pop_handler(); let entry_exc_height = ctx.exc_stack.len(); let join_block = b.block_insert(); let join_val = b.block_arg_insert(join_block); // Clauses if let Some(clauses) = try_expr.clauses.as_ref() { let no_match = b.block_insert(); { let block = no_match; let typ_val = b.value(Symbol::intern("error")); let try_clause_val = b.value(Symbol::intern("try_clause")); let err_val = b.prim_tuple(span, &[try_clause_val, body_ret]); ctx.exc_stack .make_error_jump(b, span, block, typ_val, err_val); } let mut case_b = Case::builder(); case_b.set_span(span); case_b.match_on = Some(body_ret); case_b.no_match = Some(b.value(no_match)); for clause in clauses { match lower_clause( ctx, &mut case_b.container, b, &mut block, false, clause.span, [&clause.pattern].iter().map(|i| *i), clause.guard.as_ref(), ) { Ok(lowered) => { let (scope_token, body) = lowered.make_body(ctx, b); // Add to case let body_val = b.value(body); case_b.push_clause(lowered.clause, lowered.guard, body_val, b); for value in lowered.values.iter() { case_b.push_value(*value, b); } let (body_ret_block, body_ret) = lower_block(ctx, b, body, &clause.body); // Call to join block b.op_call_flow(body_ret_block, join_block, &[body_ret]); // Pop scope pushed in lower_clause ctx.scope.pop(scope_token); } Err(_lowered) => {} } assert!(ctx.exc_stack.len() == entry_exc_height) } case_b.finish(block, b); } else { b.op_call_flow(block, join_block, &[body_ret]); } let catch_no_match_block = b.block_insert(); // Catch if let Some(catch_clauses) = try_expr.catch_clauses.as_ref() { let mut block = exc_block; let match_val = b.prim_value_list(&[exc_type, exc_error]); let mut case_b = Case::builder(); case_b.set_span(span); case_b.match_on = Some(match_val); case_b.no_match = Some(b.value(catch_no_match_block)); let entry_exc_height = ctx.exc_stack.len(); for clause in catch_clauses { // Convert the kind expression into a pattern expression so // that we can use existing pattern matching infrastructure. let kind_expr = match clause.kind { Name::Atom(atom) => Expr::Literal(Literal::Atom(NodeId(0), atom)), Name::Var(var) => Expr::Var(Var(NodeId(0), var)), }; match lower_clause( ctx, &mut case_b.container, b, &mut block, false, clause.span, [&kind_expr, &clause.error].iter().map(|i| *i), clause.guard.as_ref(), ) { Ok(lowered) => { let (scope_token, body) = lowered.make_body(ctx, b); // Add to case let body_val = b.value(body); case_b.push_clause(lowered.clause, lowered.guard, body_val, b); for value in lowered.values.iter() { case_b.push_value(*value, b); } // Bind stack trace in scope ctx.bind(clause.trace, exc_trace); let (body_ret_block, body_ret) = lower_block(ctx, b, body, &clause.body); // Call to join block b.op_call_flow(body_ret_block, join_block, &[body_ret]); // Pop scope pushed in lower_clause ctx.scope.pop(scope_token); } Err(_lowered) => {} } assert!(ctx.exc_stack.len() == entry_exc_height) } case_b.finish(block, b); } else { b.op_call_flow(exc_block, catch_no_match_block, &[]); } // After if let Some(after) = try_expr.after.as_ref() { // Make after lambda let after_lambda = b.block_insert(); let cont = b.block_arg_insert(after_lambda); let (after_block_cont, _after_val) = lower_block(ctx, b, after_lambda, &*after); b.op_call_flow(after_block_cont, cont, &[]); let ret_block = b.block_insert(); let ret_val = b.block_arg_insert(ret_block); // Exception let ret_exc_block = b.block_insert(); let ret_exc_block_val = b.value(ret_exc_block); b.op_call_flow(catch_no_match_block, after_lambda, &[ret_exc_block_val]); ctx.exc_stack .make_error_jump_trace(b, ret_exc_block, exc_type, exc_error, exc_trace); // Return regular let ret_regular_block = b.block_insert(); let ret_regular_block_val = b.value(ret_regular_block); b.op_call_flow(join_block, after_lambda, &[ret_regular_block_val]); b.op_call_flow(ret_regular_block, ret_block, &[join_val]); (ret_block, ret_val) } else { ctx.exc_stack.make_error_jump_trace( b, catch_no_match_block, exc_type, exc_error, exc_trace, ); (join_block, join_val) } } pub(super) fn lower_catch_expr( ctx: &mut LowerCtx, b: &mut FunctionBuilder, mut block: IrBlock, catch_expr: &Catch, ) -> (IrBlock, IrValue) { let span = catch_expr.span; let exc_block = b.block_insert(); let exc_type = b.block_arg_insert(exc_block); let exc_error = b.block_arg_insert(exc_block); let exc_trace = b.block_arg_insert(exc_block); let mut case_b = Case::builder(); case_b.set_span(span); // Atoms let big_exit_atom = b.value(Symbol::intern("EXIT")); let make_value_clause = |b: &mut FunctionBuilder, case_b: &mut CaseBuilder, val: IrValue| { let clause = case_b.container.clause_start(span); // Value case_b.push_value(val, b); let pat_val = case_b.container.clause_value(clause); let pat = case_b.container.node_empty(Some(span)); case_b.container.value(pat, pat_val); case_b.container.clause_node_push(clause, pat); case_b.container.clause_finish(clause); clause }; let error_atom = b.value(Symbol::intern("error")); let error_clause = make_value_clause(b, &mut case_b, error_atom); let exit_atom = b.value(Symbol::intern("exit")); let exit_clause = make_value_clause(b, &mut case_b, exit_atom); let throw_atom = b.value(Symbol::intern("throw")); let throw_clause = make_value_clause(b, &mut case_b, throw_atom); // Join block let join_block = b.block_insert(); let join_arg = b.block_arg_insert(join_block); // Lower exprs while catching exceptions ctx.exc_stack.push_handler(b.value(exc_block)); let body_ret = map_block!(block, lower_single(ctx, b, block, &catch_expr.expr)); ctx.exc_stack.pop_handler(); b.op_call_flow(block, join_block, &[body_ret]); // no_match is unreachable let no_match = b.block_insert(); b.op_unreachable(span, no_match); // Guard lambda returning true let guard = b.block_insert(); let guard_val = b.value(guard); let guard_cont = b.block_arg_insert(guard); let _guard_throw_cont = b.block_arg_insert(guard); let true_val = b.value(true); b.op_call_flow(guard, guard_cont, &[true_val]); // Actual case case_b.match_on = Some(exc_type); case_b.no_match = Some(b.value(no_match)); // Error branch { let error_block = b.block_insert(); let error_block_val = b.value(error_block); case_b.push_clause(error_clause, guard_val, error_block_val, b); let inner_tup = b.prim_tuple(span, &[exc_error, exc_trace]); let ret_tup = b.prim_tuple(span, &[big_exit_atom, inner_tup]); b.op_call_flow(error_block, join_block, &[ret_tup]); } // Exit branch { let exit_block = b.block_insert(); let exit_block_val = b.value(exit_block); case_b.push_clause(exit_clause, guard_val, exit_block_val, b); let ret_tup = b.prim_tuple(span, &[big_exit_atom, exc_error]); b.op_call_flow(exit_block, join_block, &[ret_tup]); } // Throw branch { let throw_block = b.block_insert(); let throw_block_val = b.value(throw_block); case_b.push_clause(throw_clause, guard_val, throw_block_val, b); b.op_call_flow(throw_block, join_block, &[exc_error]); } case_b.finish(exc_block, b); (join_block, join_arg) } ================================================ FILE: libeir_syntax_erl/src/lower/expr/comprehension.rs ================================================ use snafu::Snafu; use libeir_ir::binary::BinaryEntrySpecifier; use libeir_ir::constant::NilTerm; use libeir_ir::operation::binary_construct::{ BinaryConstructFinish, BinaryConstructPush, BinaryConstructStart, }; use libeir_ir::operation::case::Case; use libeir_ir::BinOp; use libeir_ir::{Block as IrBlock, FunctionBuilder, Value as IrValue}; use libeir_ir::pattern::{PatternContainer, PatternClause}; use libeir_intern::{Ident, Symbol}; use libeir_diagnostics::SourceSpan; use crate::parser::ast::{BinaryComprehension, Binary, BinaryElement, Expr, ListComprehension, NodeId, Var}; use crate::lower::expr::binary::lower_binary_expr; use crate::lower::expr::{lower_single, lower_single_same_scope}; use crate::lower::pattern::lower_clause; use crate::lower::LowerCtx; #[derive(Debug, Snafu)] pub enum ComprehensionError { InvalidUnsizedBinaryElement { span: SourceSpan, }, } /// Makes a pattern that matches on a single iteration of a binary generator. fn make_head_pattern( ctx: &mut LowerCtx, b: &mut FunctionBuilder, expr: &Expr, ) -> Result<(Expr, Ident), ComprehensionError> { match expr { Expr::Binary(binary) => { let mut elements = binary.elements.clone(); let tail = Ident::from_str(&format!("$generatortail{}", ctx.make_unique())); // Validate that all elements in binary pattern are actually sized for elem in elements.iter() { match elem.specifier { Some(BinaryEntrySpecifier::Bytes { .. }) if elem.bit_size.is_none() => { return Err(ComprehensionError::InvalidUnsizedBinaryElement { span: elem.span, }); }, Some(BinaryEntrySpecifier::Bits { .. }) if elem.bit_size.is_none() => { return Err(ComprehensionError::InvalidUnsizedBinaryElement { span: elem.span, }); }, _ => (), } } elements.push(BinaryElement { span: binary.span, id: NodeId(0), bit_expr: Expr::Var(Var(NodeId(0), tail)), bit_size: None, specifier: Some(BinaryEntrySpecifier::Bytes { unit: 1 }), }); let pattern = Expr::Binary(Binary { span: binary.span, id: NodeId(0), elements, }); Ok((pattern, tail)) }, _ => unreachable!(), } } fn make_structural_bin_pattern( pat: &mut PatternContainer, expr: &Expr, ) -> PatternClause { match expr { Expr::Binary(bin) => { unimplemented!() } _ => unimplemented!(), } } fn lower_qual( ctx: &mut LowerCtx, b: &mut FunctionBuilder, inner: &F, quals: &[Expr], mut block: IrBlock, acc: IrValue, ) -> (IrBlock, IrValue) where F: Fn(&mut LowerCtx, &mut FunctionBuilder, IrBlock, IrValue) -> (IrBlock, IrValue), { if quals.len() == 0 { inner(ctx, b, block, acc) } else { match &quals[0] { Expr::Generator(gen) => { let gen_span = gen.span; // loop_block(list_val, acc) // loop_block(loop_list_arg, loop_acc_arg): // binop equal(is_nil_block, non_nil_block, loop_list_arg, []) // is_nil_block: // ret(loop_acc_arg) // non_nil_block: // unpack_list_cell(unpack_ok_block, unpack_fail_block, loop_list_arg) // unpack_fail_block: // throw non proper list // unpack_ok_block(head_val, tail_val): // do match on head_val // loop_block(tail_val, acc) let list_val = map_block!(block, lower_single(ctx, b, block, &gen.expr)); // Loop entry block let loop_block = b.block_insert(); let loop_list_arg = b.block_arg_insert(loop_block); let loop_acc_arg = b.block_arg_insert(loop_block); // Initial list cell unpack call b.op_call_flow(block, loop_block, &[list_val, acc]); // Return block let ret_block; let ret_val; // Check for nil and unpack list let nil = b.value(NilTerm); let comp_res = b.prim_binop(gen_span, BinOp::Equal, loop_list_arg, nil); let (is_nil_block, non_nil_block) = b.op_if_bool_strict(gen_span, loop_block, comp_res); ret_block = is_nil_block; ret_val = loop_acc_arg; let mut match_builder = b.op_match_build(gen_span); let unpack_ok_block = match_builder.push_list_cell(b); let unpack_fail_block = match_builder.push_wildcard(gen_span, b); match_builder.finish(non_nil_block, loop_list_arg, b); let head_val = b.block_args(unpack_ok_block)[0]; let tail_val = b.block_args(unpack_ok_block)[1]; { let typ = b.value(Symbol::intern("error")); let error = b.value(Symbol::intern("function_clause")); ctx.exc_stack .make_error_jump(b, gen_span, unpack_fail_block, typ, error); } // When there is no match, continue iterating let no_match = b.block_insert(); b.op_call_flow(no_match, loop_block, &[tail_val, acc]); block = unpack_ok_block; let pattern_span = gen.pattern.span(); let mut case_b = Case::builder(); case_b.set_span(pattern_span); case_b.match_on = Some(head_val); case_b.no_match = Some(b.value(no_match)); match lower_clause( ctx, &mut case_b.container, b, &mut block, false, pattern_span, [&*gen.pattern].iter().map(|i| *i), None, ) { Ok(lowered) => { let (scope_token, body) = lowered.make_body(ctx, b); // Add to case let body_val = b.value(body); case_b.push_clause(lowered.clause, lowered.guard, body_val, b); for value in lowered.values.iter() { case_b.push_value(*value, b); } let (cont, cont_val) = lower_qual(ctx, b, inner, &quals[1..], body, loop_acc_arg); b.op_call_flow(cont, loop_block, &[tail_val, cont_val]); // Pop scope pushed in lower_clause ctx.scope.pop(scope_token); case_b.finish(block, b); (ret_block, ret_val) } Err(_) => unimplemented!(), // TODO warn/error unreachable pattern } } Expr::BinaryGenerator(gen) => { let gen_span = gen.span; // loop_block(bin_val, acc) // loop_block(loop_bin_arg, loop_acc_arg): // do match on loop_bin_arg // 1. full pattern, append acc and continue // 2. structural pattern, continue // 3. wildcard, break let nil = b.value(NilTerm); let bin_val = map_block!(block, lower_single(ctx, b, block, &gen.expr)); let break_block = b.block_insert(); let break_arg = b.block_arg_insert(break_block); // Loop entry block let loop_block = b.block_insert(); let mut loop_block_head = loop_block; let loop_bin_arg = b.block_arg_insert(loop_block); let loop_acc_arg = b.block_arg_insert(loop_block); let pattern_span = gen.pattern.span(); b.op_call_flow(block, loop_block, &[bin_val, acc]); // No match block, break let no_match = b.block_insert(); b.op_call_flow(no_match, break_block, &[nil]); let mut case_b = Case::builder(); case_b.set_span(pattern_span); case_b.match_on = Some(loop_bin_arg); case_b.no_match = Some(b.value(no_match)); let (head_pattern, tail_ident) = make_head_pattern(ctx, b, &gen.pattern).unwrap(); match lower_clause( ctx, &mut case_b.container, b, &mut loop_block_head, false, pattern_span, [&head_pattern].iter().map(|v| *v), None, ) { Ok(lowered) => { // Main body { let (scope_token, body) = lowered.make_body(ctx, b); // Add to case let body_val = b.value(body); case_b.push_clause(lowered.clause, lowered.guard, body_val, b); for value in lowered.values.iter() { case_b.push_value(*value, b); } let tail_val = ctx.resolve(tail_ident); let (cont, cont_val) = lower_qual(ctx, b, inner, &quals[1..], body, loop_acc_arg); b.op_call_flow(cont, loop_block, &[tail_val, cont_val]); // Pop scope pushed in lower_clause ctx.scope.pop(scope_token); } // Structural body { let (scope_token, body) = lowered.make_body(ctx, b); // Make an always succeeding dummy guard let dummy_guard = { let dummy_guard = b.block_insert(); let guard_ret_cont = b.block_arg_insert(dummy_guard); let _guard_throw_cont = b.block_arg_insert(dummy_guard); for _bind in lowered.binds.iter() { b.block_arg_insert(dummy_guard); } let true_val = b.value(true); b.op_call_flow(dummy_guard, guard_ret_cont, &[true_val]); dummy_guard }; let dummy_guard_val = b.value(dummy_guard); let structural_clause = case_b.container.make_structural(lowered.clause); // Add to case let body_val = b.value(body); case_b.push_clause(structural_clause, dummy_guard_val, body_val, b); for value in lowered.values.iter() { case_b.push_value(*value, b); } let tail_val = ctx.resolve(tail_ident); // Match on structural means full match failed. // We consume the matched binary chunk and proceed // to the next iteration. b.op_call_flow(body, loop_block, &[tail_val, loop_acc_arg]); // Pop scope pushed in lower_clause ctx.scope.pop(scope_token); } }, Err(_) => unimplemented!(), } case_b.finish(loop_block_head, b); //let structual_pattern = make_structural_bin_pattern(&mut case_b.container, &gen.expr); (break_block, break_arg) }, expr => { let bool_val = map_block!(block, lower_single_same_scope(ctx, b, block, expr)); let span = expr.span(); let (true_block, false_block, else_block) = b.op_if_bool(span, block, bool_val); let join_block = b.block_insert(); let join_arg = b.block_arg_insert(join_block); let (cont, cont_val) = lower_qual(ctx, b, inner, &quals[1..], true_block, acc); b.op_call_flow(cont, join_block, &[cont_val]); b.op_call_flow(false_block, join_block, &[acc]); b.op_call_flow(else_block, join_block, &[acc]); (join_block, join_arg) } } } } pub(super) fn lower_list_comprehension_expr( ctx: &mut LowerCtx, b: &mut FunctionBuilder, mut block: IrBlock, compr: &ListComprehension, ) -> (IrBlock, IrValue) { let inner = |ctx: &mut LowerCtx, b: &mut FunctionBuilder, mut block: IrBlock, acc: IrValue| { let span = compr.body.span(); let val = map_block!(block, lower_single(ctx, b, block, &compr.body)); let cell = b.prim_list_cell(span, val, acc); (block, cell) }; let nil = b.value(NilTerm); let val = map_block!( block, lower_qual(ctx, b, &inner, &compr.qualifiers, block, nil) ); ctx.call_function( b, block, compr.span, Ident::from_str("lists"), Ident::from_str("reverse"), &[val], ) } pub(super) fn lower_binary_comprehension_expr( ctx: &mut LowerCtx, b: &mut FunctionBuilder, mut block: IrBlock, compr: &BinaryComprehension, ) -> (IrBlock, IrValue) { let inner = |ctx: &mut LowerCtx, b: &mut FunctionBuilder, mut block: IrBlock, bin_ref: IrValue| { let val = map_block!(block, lower_single(ctx, b, block, &compr.body)); let spec = BinaryEntrySpecifier::Bytes { unit: 1 }; let (ok_cont, err_cont) = BinaryConstructPush::build(b, block, bin_ref, val, spec, None); b.op_unreachable(compr.span, err_cont); let bin_ref = b.block_args(ok_cont)[0]; (ok_cont, bin_ref) }; block = BinaryConstructStart::build(b, block); let mut bin_ref = b.block_args(block)[0]; bin_ref = map_block!( block, lower_qual(ctx, b, &inner, &compr.qualifiers, block, bin_ref) ); block = BinaryConstructFinish::build(b, block, bin_ref); let res = b.block_args(block)[0]; (block, res) } ================================================ FILE: libeir_syntax_erl/src/lower/expr/literal.rs ================================================ use libeir_ir::constant::{AtomTerm, BinaryTerm, Const, ConstantContainer, NilTerm}; use libeir_ir::{Block as IrBlock, FunctionBuilder, Value as IrValue}; use libeir_diagnostics::{SourceIndex, SourceSpan}; use libeir_intern::Ident; use crate::util::string_tokenizer::StringTokenizer; use crate::lower::{LowerCtx, LowerError}; use crate::parser::ast::Literal; pub(super) fn lower_literal( ctx: &mut LowerCtx, b: &mut FunctionBuilder, block: IrBlock, literal: &Literal, ) -> (IrBlock, IrValue) { let value = match literal { Literal::Atom(_id, ident) => b.value(AtomTerm(ident.name)), Literal::Integer(_id, _span, int) => b.value(int.clone()), Literal::Float(_id, _span, flt) => b.value(*flt), Literal::String(_id, ident) => match intern_string_const(*ident, b.cons_mut()) { Ok(cons) => b.value(cons), Err(err) => { ctx.error(err); ctx.sentinel() } }, Literal::Char(_id, _span, c) => b.value(*c), }; (block, value) } pub fn intern_string_const(ident: Ident, c: &mut ConstantContainer) -> Result { let mut chars = Vec::new(); let tokenizer = StringTokenizer::new(ident); for elem in tokenizer { let (cp, _span) = elem?; chars.push(cp); } let mut cons = c.from(NilTerm); for elem in chars.iter().rev() { let val = c.from(*elem); cons = c.list_cell(val, cons); } Ok(c.from(cons)) } ================================================ FILE: libeir_syntax_erl/src/lower/expr/map.rs ================================================ use libeir_ir::{ constant::EmptyMap, Block as IrBlock, FunctionBuilder, MapPutUpdate, Value as IrValue, }; use libeir_diagnostics::SourceSpan; use libeir_intern::Symbol; use crate::lower::{lower_single, LowerCtx, LowerError}; use crate::parser::ast::{Map, MapField, MapUpdate}; pub(super) fn lower_map_update_expr( ctx: &mut LowerCtx, b: &mut FunctionBuilder, mut block: IrBlock, map: &MapUpdate, ) -> (IrBlock, IrValue) { let entry_map_val = map_block!(block, lower_single(ctx, b, block, &map.map)); if let Some(cons) = b.fun().value_const(entry_map_val) { if b.cons().const_kind(cons).is_map() { // TODO: More warnings } else { ctx.warn(LowerError::MapUpdateOnNonMap { map: map.span }); } } lower(ctx, b, block, entry_map_val, map.span, &map.updates) } pub(super) fn lower_map_expr( ctx: &mut LowerCtx, b: &mut FunctionBuilder, block: IrBlock, map: &Map, ) -> (IrBlock, IrValue) { for field in map.fields.iter() { match field { MapField::Exact { .. } => { ctx.error(LowerError::MapUpdateInConstruction { map: map.span, field: field.span(), }); // No need to generate more than one error here, // the user will probably have gotten the point. break; } _ => (), } } let empty_map = b.value(EmptyMap); lower(ctx, b, block, empty_map, map.span, &map.fields) } fn lower( ctx: &mut LowerCtx, b: &mut FunctionBuilder, mut block: IrBlock, old_map: IrValue, span: SourceSpan, fields: &[MapField], ) -> (IrBlock, IrValue) { let mut map_builder = b.op_map_put_build(span, old_map); for field in fields.iter() { let (key, value, action) = match field { MapField::Assoc { key, value, .. } => (key, value, MapPutUpdate::Put), MapField::Exact { key, value, .. } => (key, value, MapPutUpdate::Update), }; let key_val = map_block!(block, lower_single(ctx, b, block, key)); let value_val = map_block!(block, lower_single(ctx, b, block, value)); map_builder.push_kv(key_val, value_val, action, b); } let loc = ctx.current_location(b, span); b.block_set_location(block, loc); let (ok, fail) = map_builder.finish(block, b); b.block_set_location(fail, loc); let typ_val = b.value(Symbol::intern("error")); let badmatch_val = b.value(Symbol::intern("badkey")); let failed_key = b.block_args(fail)[0]; let err_val = b.prim_tuple(span, &[badmatch_val, failed_key]); ctx.exc_stack .make_error_jump(b, span, fail, typ_val, err_val); (ok, b.block_args(ok)[0]) } ================================================ FILE: libeir_syntax_erl/src/lower/expr/mod.rs ================================================ use libeir_ir::constant::NilTerm; use libeir_ir::operation::case::Case; use libeir_ir::{Block as IrBlock, FunctionBuilder, Value as IrValue}; use libeir_intern::{Ident, Symbol}; use super::lower_function; use super::pattern::lower_clause; use super::{LowerCtx, LowerError}; use crate::parser::ast::UnaryOp; use crate::parser::ast::{Apply, Remote, UnaryExpr}; use crate::parser::ast::{Arity, Name}; use crate::parser::ast::{Expr, Literal, Var}; use crate::{ parser::ast::{FunctionName, LocalFunctionName}, DelayedSubstitution, }; pub mod literal; use literal::lower_literal; pub mod binary; mod binary_expr; mod case; mod catch; mod comprehension; mod record; mod map; mod receive; pub(super) fn lower_block<'a, T>( ctx: &mut LowerCtx, b: &mut FunctionBuilder, block: IrBlock, exprs: T, ) -> (IrBlock, IrValue) where T: IntoIterator, { let scope_tok = ctx.scope.push(); let mut block = block; let mut value = None; let mut loc = None; for expr in exprs { assert!(b.fun().block_kind(block).is_none()); let (new_block, val) = lower_expr(ctx, b, block, expr); loc = Some(b.fun().block_location(block)); assert!(b.fun().block_kind(new_block).is_none()); block = new_block; value = Some(val); } // This will pop all the scopes that has been pushed by // the expressions in the block. ctx.scope.pop(scope_tok); // In the case that this is the last block in a function, we want the // location of the return block to be the last expression. if let Some(loc) = loc { b.block_set_location(block, loc); } (block, value.unwrap()) } pub(super) fn lower_block_same_scope<'a, T>( ctx: &mut LowerCtx, b: &mut FunctionBuilder, block: IrBlock, exprs: T, ) -> (IrBlock, IrValue) where T: IntoIterator, { let mut block = block; let mut value = None; for expr in exprs { assert!(b.fun().block_kind(block).is_none()); let (new_block, val) = lower_expr(ctx, b, block, expr); assert!(b.fun().block_kind(new_block).is_none()); block = new_block; value = Some(val); } (block, value.unwrap()) } pub(super) fn lower_single( ctx: &mut LowerCtx, b: &mut FunctionBuilder, block: IrBlock, expr: &Expr, ) -> (IrBlock, IrValue) { let scope_tok = ctx.scope.push(); assert!(b.fun().block_kind(block).is_none()); let (new_block, val) = lower_expr(ctx, b, block, expr); assert!(b.fun().block_kind(new_block).is_none()); ctx.scope.pop(scope_tok); (new_block, val) } pub(super) fn lower_single_same_scope( ctx: &mut LowerCtx, b: &mut FunctionBuilder, block: IrBlock, expr: &Expr, ) -> (IrBlock, IrValue) { assert!(b.fun().block_kind(block).is_none()); let (new_block, val) = lower_expr(ctx, b, block, expr); assert!(b.fun().block_kind(new_block).is_none()); (new_block, val) } fn lower_expr( ctx: &mut LowerCtx, b: &mut FunctionBuilder, block: IrBlock, expr: &Expr, ) -> (IrBlock, IrValue) { let mut block = block; let loc = ctx.current_location(b, expr.span()); b.block_set_location(block, loc); match expr { Expr::Apply(Apply { span, callee, args, .. }) => { let span = *span; let mut arg_vals = vec![]; let arity_val = b.value(args.len()); let callee_val = match &**callee { Expr::Remote(Remote { module, function, .. }) => { let mod_val = map_block!(block, lower_single(ctx, b, block, module)); let fun_val = map_block!(block, lower_single(ctx, b, block, function)); b.prim_capture_function(span, mod_val, fun_val, arity_val) } Expr::Literal(Literal::Atom(_id, name)) => { let local = LocalFunctionName { span: callee.span(), function: *name, arity: args.len(), }; let (module, function) = if ctx.module.functions.contains_key(&local) { (ctx.module.name, *name) } else { if let Some(resolved) = ctx.module.imports.get(&local) { assert!(resolved.arity == args.len()); (resolved.module, resolved.function) } else { (ctx.module.name, *name) } }; let mod_val = b.value(module); let fun_val = b.value(function); b.prim_capture_function(span, mod_val, fun_val, arity_val) } expr => map_block!(block, lower_single_same_scope(ctx, b, block, expr)), }; for arg in args { let (new_block, arg_val) = lower_single_same_scope(ctx, b, block, arg); block = new_block; arg_vals.push(arg_val); } let (ok_block, fail_block) = b.op_call_function(span, block, callee_val, &arg_vals); b.block_set_location(fail_block, loc); let fail_type = b.block_args(fail_block)[0]; let fail_error = b.block_args(fail_block)[1]; let fail_trace = b.block_args(fail_block)[2]; ctx.exc_stack .make_error_jump_trace(b, fail_block, fail_type, fail_error, fail_trace); let ok_res = b.block_args(ok_block)[0]; (ok_block, ok_res) } Expr::Var(Var(_id, var)) => (block, ctx.resolve(*var)), Expr::UnaryExpr(UnaryExpr { op, operand, span, .. }) => { let operand_val = map_block!(block, lower_single(ctx, b, block, operand)); let (block, val) = match op { UnaryOp::Not => ctx.call_function( b, block, *span, Symbol::intern("erlang"), Symbol::intern("not"), &[operand_val], ), UnaryOp::Minus => ctx.call_function( b, block, *span, Symbol::intern("erlang"), Symbol::intern("-"), &[operand_val], ), UnaryOp::Plus => ctx.call_function( b, block, *span, Symbol::intern("erlang"), Symbol::intern("+"), &[operand_val], ), UnaryOp::Bnot => ctx.call_function( b, block, *span, Symbol::intern("erlang"), Symbol::intern("bnot"), &[operand_val], ), }; (block, val) } Expr::Match(mat) => { let match_val = map_block!(block, lower_single_same_scope(ctx, b, block, &mat.expr)); if let Expr::Var(Var(_id, var)) = *mat.pattern { // This branch is not required, since the normal pattern match // compilation path will cover it just fine. // However, since this is a really really common path, we can save // ourself a lot of work by just handling variable binding in a // simpler way. if ctx.scope.resolve(var).is_err() { ctx.bind(var, match_val); return (block, match_val); } } let no_match = b.block_insert(); b.block_set_location(no_match, loc); { let typ_val = b.value(Symbol::intern("error")); let badmatch_val = b.value(Symbol::intern("badmatch")); let err_val = b.prim_tuple(mat.span, &[badmatch_val, match_val]); ctx.exc_stack .make_error_jump(b, mat.span, no_match, typ_val, err_val); } let mut match_case = Case::builder(); match_case.set_span(mat.span); match lower_clause( ctx, &mut match_case.container, b, &mut block, false, mat.span, [&mat.pattern].iter().map(|i| &***i), None, ) { Ok(lowered) => { let (_scope_token, body) = lowered.make_body(ctx, b); match_case.match_on = Some(match_val); match_case.no_match = Some(b.value(no_match)); // Add clause to match let body_val = b.value(body); match_case.push_clause(lowered.clause, lowered.guard, body_val, b); for value in lowered.values.iter() { match_case.push_value(*value, b); } match_case.finish(block, b); // The scope pushed in lower_case will be popped by the // calling `lower_block`. (body, match_val) } Err(lowered) => { b.op_call_flow(block, no_match, &[]); let (_scope_token, body) = lowered.make_body(ctx, b); (body, match_val) } } } Expr::Cons(cons) => { let head = map_block!(block, lower_single(ctx, b, block, &cons.head)); let tail = map_block!(block, lower_single(ctx, b, block, &cons.tail)); let list = b.prim_list_cell(cons.span, head, tail); (block, list) } Expr::Nil(_nil) => { let nil_val = b.value(NilTerm); (block, nil_val) } Expr::Tuple(tup) => { let mut vals = Vec::new(); for elem in tup.elements.iter() { let val = map_block!(block, lower_single_same_scope(ctx, b, block, elem)); vals.push(val); } let tuple = b.prim_tuple(tup.span, &vals); (block, tuple) } Expr::Fun(fun) => { let fun = lower_function(ctx, b, fun); (block, b.value(fun)) } Expr::FunctionName(name) => match name { FunctionName::Resolved(resolved) => { let module = b.value(resolved.module); let function = b.value(resolved.function); let arity = b.value(resolved.arity); let fun_val = b.prim_capture_function(resolved.span, module, function, arity); (block, fun_val) } FunctionName::PartiallyResolved(partial) => { let local = ctx.module.imports.get(&partial.to_local()); let resolved = if let Some(fun) = local { fun.clone() } else { partial.resolve(ctx.module.name) }; let module = b.value(resolved.module); let function = b.value(resolved.function); let arity = b.value(resolved.arity); let fun_val = b.prim_capture_function(partial.span, module, function, arity); (block, fun_val) } FunctionName::Unresolved(unresolved) => { let module = match unresolved.module { None => b.value(ctx.module.name), Some(Name::Atom(atom)) => b.value(atom), Some(Name::Var(var)) => ctx.resolve(var), }; let function = match unresolved.function { Name::Atom(atom) => b.value(atom), Name::Var(var) => ctx.resolve(var), }; let arity = match unresolved.arity { Arity::Int(int) => b.value(int), Arity::Var(var) => b.value(var), }; let fun_val = b.prim_capture_function(unresolved.span, module, function, arity); (block, fun_val) } }, Expr::Receive(recv) => receive::lower_receive(ctx, b, block, recv), Expr::Map(map) => map::lower_map_expr(ctx, b, block, map), Expr::MapUpdate(map) => map::lower_map_update_expr(ctx, b, block, map), Expr::Begin(begin) => lower_block_same_scope(ctx, b, block, &begin.body), Expr::Case(case) => case::lower_case_expr(ctx, b, block, case), Expr::If(if_expr) => case::lower_if_expr(ctx, b, block, if_expr), Expr::Try(try_expr) => catch::lower_try_expr(ctx, b, block, try_expr), Expr::Catch(catch_expr) => catch::lower_catch_expr(ctx, b, block, catch_expr), Expr::BinaryExpr(binary_expr) => binary_expr::lower_binary_expr(ctx, b, block, binary_expr), Expr::Literal(lit) => lower_literal(ctx, b, block, lit), Expr::Record(rec) => record::lower_record_expr(ctx, b, block, rec), Expr::RecordAccess(rec) => record::lower_record_access_expr(ctx, b, block, rec), Expr::RecordUpdate(rec) => record::lower_record_update_expr(ctx, b, block, rec), Expr::RecordIndex(rec) => record::lower_record_index(ctx, b, block, rec), Expr::ListComprehension(compr) => { comprehension::lower_list_comprehension_expr(ctx, b, block, compr) } Expr::BinaryComprehension(compr) => { comprehension::lower_binary_comprehension_expr(ctx, b, block, compr) } Expr::Binary(bin) => binary::lower_binary_expr(ctx, b, block, None, bin), Expr::DelayedSubstitution(_, id, DelayedSubstitution::FunctionName) => { lower_literal(ctx, b, block, &Literal::Atom(*id, b.fun().ident().name)) } Expr::DelayedSubstitution(span, id, DelayedSubstitution::FunctionArity) => lower_literal( ctx, b, block, &Literal::Integer(*span, *id, b.fun().ident().arity.into()), ), Expr::Remote(rem) => { ctx.error(LowerError::IllegalExpression { span: rem.span }); (block, ctx.sentinel()) } Expr::MapProjection(_) => unreachable!(), Expr::BinaryGenerator(_) => unreachable!(), Expr::Generator(_) => unreachable!(), //_ => { // unimplemented!("{:?}", expr); //} } } ================================================ FILE: libeir_syntax_erl/src/lower/expr/receive.rs ================================================ use libeir_intern::Ident; use libeir_ir::{ operation::case::Case, operation::receive::{ReceiveDone, ReceiveStart, ReceiveWait}, Block as IrBlock, FunctionBuilder, Value as IrValue, }; use crate::{ lower::{lower_block, lower_single, pattern::lower_clause, LowerCtx}, parser::ast::Receive, }; pub(super) fn lower_receive( ctx: &mut LowerCtx, b: &mut FunctionBuilder, mut block: IrBlock, recv: &Receive, ) -> (IrBlock, IrValue) { let loc = ctx.current_location(b, recv.span); let join_block = b.block_insert(); b.block_set_location(join_block, loc); let join_arg = b.block_arg_insert(join_block); // The timeout time let after_timeout_val = if let Some(after) = &recv.after { map_block!(block, lower_single(ctx, b, block, &after.timeout)) } else { b.value(Ident::from_str("infinity")) }; // Receive start let recv_wait_block = ReceiveStart::build(b, block, after_timeout_val); b.block_set_location(recv_wait_block, loc); let recv_ref_val = b.block_args(recv_wait_block)[0]; // Receive wait let (after_block, mut body_block) = ReceiveWait::build(b, recv_wait_block, recv_ref_val); b.block_set_location(body_block, loc); let body_message_arg = b.block_args(body_block)[0]; // If there is a timeout block, the after code if let Some(after) = &recv.after { let (after_ret_block, after_ret) = lower_block(ctx, b, after_block, &after.body); b.op_call_flow(after_ret_block, join_block, &[after_ret]); } else { b.block_set_location(after_block, loc); b.op_unreachable(recv.span, after_block); }; if let Some(clauses) = &recv.clauses { let no_match = b.block_insert(); b.block_set_location(no_match, loc); b.op_call_flow(no_match, recv_wait_block, &[recv_ref_val]); let mut case_b = Case::builder(); case_b.set_span(recv.span); case_b.match_on = Some(body_message_arg); case_b.no_match = Some(b.value(no_match)); let entry_exc_height = ctx.exc_stack.len(); for clause in clauses.iter() { match lower_clause( ctx, &mut case_b.container, b, &mut body_block, false, clause.span, [&clause.pattern].iter().map(|i| *i), clause.guard.as_ref(), ) { Ok(lowered) => { let scope_token = ctx.scope.push(); let body = b.block_insert(); let body_loc = ctx.current_location(b, clause.span); b.block_set_location(body, body_loc); // Map all matched values through receive_done. // This enables us to do things like copy from // a heap fragment to the main process heap. let values: Vec<_> = lowered .binds .iter() .map(|_bind| b.block_arg_insert(body)) .collect(); let body_mapped = ReceiveDone::build(b, body, recv_ref_val, &values); for (idx, bind) in lowered.binds.iter().enumerate() { if let Some(name) = bind { let mapped_val = b.block_args(body_mapped)[idx]; ctx.bind(*name, mapped_val); } } // Add to case let body_val = b.value(body); case_b.push_clause(lowered.clause, lowered.guard, body_val, b); for value in lowered.values.iter() { case_b.push_value(*value, b); } let (body_ret_block, body_ret) = lower_block(ctx, b, body_mapped, &clause.body); // Call to join block b.op_call_flow(body_ret_block, join_block, &[body_ret]); // Pop scope pushed in lower_clause ctx.scope.pop(scope_token); } Err(_lowered) => {} } assert!(ctx.exc_stack.len() == entry_exc_height) } case_b.finish(body_block, b); } else { b.op_call_flow(body_block, join_block, &[body_message_arg]); } (join_block, join_arg) } ================================================ FILE: libeir_syntax_erl/src/lower/expr/record.rs ================================================ use libeir_diagnostics::SourceSpan; use libeir_ir::{BinOp as IrBinOp, Block as IrBlock, FunctionBuilder, Value as IrValue}; use libeir_intern::Symbol; use crate::parser::ast::{Record, RecordAccess, RecordIndex, RecordUpdate}; use crate::lower::expr::lower_single; use crate::lower::{LowerCtx, LowerError}; fn make_rec_fail( ctx: &mut LowerCtx, b: &mut FunctionBuilder, span: SourceSpan, recname_val: IrValue, ) -> IrBlock { let fail_block = b.block_insert(); let block = fail_block; let fail_type = b.value(Symbol::intern("error")); // TODO double check correct type let badrecord_val = b.value(Symbol::intern("badrecord")); let fail_error = b.prim_tuple(span, &[badrecord_val, recname_val]); ctx.exc_stack .make_error_jump(b, span, block, fail_type, fail_error); fail_block } pub(super) fn lower_record_access_expr( ctx: &mut LowerCtx, b: &mut FunctionBuilder, mut block: IrBlock, rec: &RecordAccess, ) -> (IrBlock, IrValue) { let span = rec.span; let rec_def = &ctx.module.records[&rec.name.name]; let recname_val = b.value(rec.name); let idx = rec_def.field_idx_map[&rec.field]; let fail_block = make_rec_fail(ctx, b, span, recname_val); let record_val = map_block!(block, lower_single(ctx, b, block, &rec.record)); let mut match_builder = b.op_match_build(span); let unpack_ok_block = match_builder.push_tuple(rec_def.record.fields.len() + 1, b); let unpack_fail_block = match_builder.push_wildcard(span, b); match_builder.finish(block, record_val, b); block = unpack_ok_block; b.op_call_flow(unpack_fail_block, fail_block, &[]); let recname_test_val = b.block_args(block)[0]; let rec_field_val = b.block_args(block)[idx + 1]; let eq_cond = b.prim_binop(span, IrBinOp::Equal, recname_test_val, recname_val); let eq_fail_block = map_block!(block, b.op_if_bool_strict(span, block, eq_cond)); b.op_call_flow(eq_fail_block, fail_block, &[]); (block, rec_field_val) } pub(super) fn lower_record_update_expr( ctx: &mut LowerCtx, b: &mut FunctionBuilder, mut block: IrBlock, rec: &RecordUpdate, ) -> (IrBlock, IrValue) { let span = rec.span; // TODO Warn/error when updates overlap? let rec_def = &ctx.module.records[&rec.name.name]; let recname_val = b.value(rec.name); let num_fields = rec_def.record.fields.len(); let fail_block = make_rec_fail(ctx, b, span, recname_val); // Unpack tuple let record_val = map_block!(block, lower_single(ctx, b, block, &rec.record)); let mut match_builder = b.op_match_build(span); let unpack_ok_block = match_builder.push_tuple(num_fields + 1, b); let unpack_fail_block = match_builder.push_wildcard(span, b); match_builder.finish(block, record_val, b); block = unpack_ok_block; b.op_call_flow(unpack_fail_block, fail_block, &[]); // Make a vector with all the values in the unpacked tuple let mut elems = Vec::with_capacity(num_fields); for idx in 0..num_fields { elems.push(b.block_args(block)[idx + 1]); } // Check first tuple element let recname_test_val = b.block_args(block)[0]; let eq_cond = b.prim_binop(span, IrBinOp::Equal, recname_test_val, recname_val); let eq_fail_block = map_block!(block, b.op_if_bool_strict(span, block, eq_cond)); b.op_call_flow(eq_fail_block, fail_block, &[]); // Update fields for update in rec.updates.iter() { let idx = rec_def.field_idx_map[&update.name]; let new_val = map_block!( block, lower_single(ctx, b, block, update.value.as_ref().unwrap()) ); elems[idx] = new_val; } // Create new tuple let mut tup_values = Vec::new(); tup_values.push(recname_val); tup_values.extend(elems.iter().cloned()); let tup = b.prim_tuple(span, &tup_values); (block, tup) } pub(super) fn lower_record_expr( ctx: &mut LowerCtx, b: &mut FunctionBuilder, mut block: IrBlock, rec: &Record, ) -> (IrBlock, IrValue) { let span = rec.span; let rec_def = &ctx.module.records[&rec.name.name]; let recname_val = b.value(rec.name); let num_fields = rec_def.record.fields.len(); let mut elems = vec![None; num_fields]; // Populate values from expression for field in rec.fields.iter() { let idx = rec_def.field_idx_map[&field.name]; if elems[idx].is_some() { ctx.error(LowerError::DuplicateRecordField { new: field.name.span, old: rec .fields .iter() .find(|f| f.name == field.name) .unwrap() .name .span, }); } let new_val = map_block!( block, lower_single(ctx, b, block, field.value.as_ref().unwrap()) ); elems[idx] = Some(new_val); } // Fill with defaults for (idx, field) in rec_def.record.fields.iter().enumerate() { if elems[idx].is_none() { let new_val = if let Some(const_expr) = field.value.as_ref() { // TODO: Allow only constants. This should be a separate lowering method! map_block!(block, lower_single(ctx, b, block, const_expr)) } else { b.value(Symbol::intern("undefined")) }; elems[idx] = Some(new_val); } } let mut tup_values = Vec::new(); tup_values.push(recname_val); tup_values.extend(elems.iter().map(|e| e.unwrap())); let tup = b.prim_tuple(span, &tup_values); (block, tup) } pub(super) fn lower_record_index( ctx: &mut LowerCtx, b: &mut FunctionBuilder, block: IrBlock, rec: &RecordIndex, ) -> (IrBlock, IrValue) { let rec_def = &ctx.module.records[&rec.name.name]; let index = rec_def.field_idx_map[&rec.field]; let val = b.value(index); (block, val) } ================================================ FILE: libeir_syntax_erl/src/lower/mod.rs ================================================ use std::sync::Arc; use libeir_ir::operation::case::Case; use libeir_ir::{ Block as IrBlock, FunctionBuilder, IntoValue, Location, Module as IrModule, Value as IrValue, }; use libeir_diagnostics::{CodeMap, SourceSpan}; use libeir_intern::{Ident, Symbol}; use libeir_util_parse::ErrorReceiver; use crate::parser::ast::{Function, FunctionClause, Module, NamedFunction}; use crate::evaluator::ResolveRecordIndexError; macro_rules! map_block { ($block:expr, $call:expr) => {{ let (block, val) = $call; $block = block; val }}; } mod pattern; use pattern::lower_clause; mod expr; use expr::{lower_block, lower_single}; mod errors; pub use errors::LowerError; mod exception_handler_stack; use exception_handler_stack::ExceptionHandlerStack; mod scope; use scope::ScopeToken; #[cfg(test)] mod tests; pub(crate) struct LowerCtx<'a> { codemap: Arc, module: &'a Module, scope: scope::ScopeTracker, exc_stack: ExceptionHandlerStack, sentinel_value: Option, errors: &'a mut (dyn ErrorReceiver + 'a), val_buf: Vec, fun_num: usize, /// Top is current function name. /// Used to generate debug info. functions: Vec, unique: usize, } impl<'a> LowerCtx<'a> { /// Since we want to catch as many errors as possible in a single /// compiler invocation, we frequently purposefully generate invalid /// IR so that the lowering process can continue. /// In a case where, say, we have an unresolved variable, we need /// a dummy value that we can use. /// If this value is used in the resulting IR, it is REQUIRED that /// `error` be called at least once, which sets the error receiver /// to the failed state. pub fn sentinel(&self) -> IrValue { self.sentinel_value.unwrap() } pub fn error(&mut self, err: LowerError) { self.errors.error(err); } pub fn warn(&mut self, err: LowerError) { self.errors.warning(err); } pub fn failed(&self) -> bool { self.errors.is_failed() } pub fn make_unique(&mut self) -> usize { self.unique += 1; self.unique } /// Resolves the index of a field in a record. pub fn resolve_rec_idx(&self, name: Ident, field: Ident) -> Result { let rec = self .module .records .get(&name.name) .ok_or(ResolveRecordIndexError::NoRecord)?; let idx = rec .field_idx_map .get(&field) .ok_or(ResolveRecordIndexError::NoField)?; Ok(*idx) } pub fn resolve(&mut self, ident: Ident) -> IrValue { match self.scope.resolve(ident) { Ok(val) => val, Err(err) => { self.error(err); self.sentinel() } } } pub fn bind_shadow(&mut self, ident: Ident, val: IrValue) { match self.scope.bind_shadow(ident, val) { Ok(()) => (), Err(err) => { self.warn(err); } } } pub fn bind(&mut self, ident: Ident, val: IrValue) { match self.scope.bind(ident, val) { Ok(()) => (), Err(err) => { self.error(err); } } } pub fn function_name(&self) -> String { self.functions[self.functions.len() - 1].clone() } pub fn current_location(&self, b: &mut FunctionBuilder, span: SourceSpan) -> Location { b.fun_mut().locations.from_bytespan( &self.codemap, span, Some(self.module.name.as_str().to_string()), Some(self.function_name()), ) } pub fn call_function( &mut self, b: &mut FunctionBuilder, block: IrBlock, span: SourceSpan, m: M, f: F, args: &[IrValue], ) -> (IrBlock, IrValue) where M: IntoValue, F: IntoValue, { let fun_val = b.prim_capture_function(span, m, f, args.len()); self.val_buf.clear(); for arg in args.iter() { self.val_buf.push(*arg); } let loc = self.current_location(b, span); b.block_set_location(block, loc); let (ok_block, fail_block) = b.op_call_function(span, block, fun_val, args); b.block_set_location(fail_block, loc); let fail_type = b.block_args(fail_block)[0]; let fail_error = b.block_args(fail_block)[1]; let fail_trace = b.block_args(fail_block)[2]; self.exc_stack .make_error_jump_trace(b, fail_block, fail_type, fail_error, fail_trace); let ok_res = b.block_args(ok_block)[0]; (ok_block, ok_res) } } pub fn lower_module<'a>( errors: &'a mut (dyn ErrorReceiver + 'a), codemap: Arc, module: &Module, ) -> Result { // TODO sort functions for more deterministic compilation let mut ir_module = IrModule::new_with_span(module.name, module.span); let mut ctx = LowerCtx { codemap, module, scope: scope::ScopeTracker::new(), exc_stack: ExceptionHandlerStack::new(), sentinel_value: None, errors, val_buf: Vec::new(), fun_num: 0, functions: Vec::new(), unique: 0, }; for (ident, function) in module.functions.iter() { assert!(ctx.scope.height() == 0); ctx.fun_num = 0; let fun_def = ir_module.add_function(function.span, ident.function, function.arity); let mut fun = fun_def.function_mut(); let mut builder = FunctionBuilder::new(&mut fun); // We do not want the sentinel value to be a constant, // since that would interfere with potential constant // comparisons while lowering. Insert an orphaned block // with an argument that we use. // This has the added benefit of generating actually // invalid IR when used. let sentinel_block = builder.block_insert(); let sentinel_value = builder.block_arg_insert(sentinel_block); ctx.sentinel_value = Some(sentinel_value); lower_top_function(&mut ctx, &mut builder, function); } ctx.exc_stack.finish(); if ctx.failed() { Err(()) } else { Ok(ir_module) } } fn lower_function(ctx: &mut LowerCtx, b: &mut FunctionBuilder, fun: &Function) -> IrBlock { let entry = b.block_insert_with_span(Some(fun.span())); ctx.fun_num += 1; let base_fun = &ctx.functions[0]; let new_fun = format!("{}-fun-{}", base_fun, ctx.fun_num); ctx.functions.push(new_fun); match fun { Function::Named(named) => { let entry_val = b.value(entry); ctx.bind(named.name.var(), entry_val); lower_function_base(ctx, b, entry, named.span, named.arity, &named.clauses); } Function::Unnamed(lambda) => { lower_function_base(ctx, b, entry, lambda.span, lambda.arity, &lambda.clauses); } } ctx.functions.pop().unwrap(); entry } fn lower_function_base( ctx: &mut LowerCtx, b: &mut FunctionBuilder, // The block the function should be lowered into entry: IrBlock, span: SourceSpan, arity: usize, clauses: &[FunctionClause], ) { let match_loc = ctx.current_location(b, span); let mut block = entry; // Ok and Fail continuations let ok_cont = b.block_arg_insert(entry); let err_cont = b.block_arg_insert(entry); ctx.exc_stack.push_handler(err_cont); // Add arguments and pack them into a value list let mut args_val = Vec::new(); for _ in 0..arity { let arg = b.block_arg_insert(entry); args_val.push(arg); } let args_list = b.prim_value_list(&args_val); // Join block after case let join_block = b.block_insert(); b.block_set_location(join_block, match_loc); let join_arg = b.block_arg_insert(join_block); b.op_call_flow(join_block, ok_cont, &[join_arg]); // Match fail block let match_fail_block = b.block_insert(); b.block_set_location(match_fail_block, match_loc); { let typ_val = b.value(Symbol::intern("error")); let err_val = b.value(Symbol::intern("function_clause")); ctx.exc_stack .make_error_jump(b, span, match_fail_block, typ_val, err_val); } let entry_exc_height = ctx.exc_stack.len(); // Top level function case expression { // TODO: Fuse locations of function heads //let mut func_case = b.op_case_build(span); let mut func_case = Case::builder(); func_case.set_span(span); func_case.match_on = Some(args_list); func_case.no_match = Some(b.value(match_fail_block)); for clause in clauses.iter() { match lower_clause( ctx, &mut func_case.container, b, &mut block, true, clause.span, clause.params.iter(), clause.guard.as_ref(), ) { Ok(lowered) => { let (scope_token, body) = lowered.make_body(ctx, b); // Add to case let body_val = b.value(body); func_case.push_clause(lowered.clause, lowered.guard, body_val, b); for value in lowered.values.iter() { func_case.push_value(*value, b); } let (body_ret_block, body_ret) = lower_block(ctx, b, body, &clause.body); // Call to join block b.op_call_flow(body_ret_block, join_block, &[body_ret]); // Pop scope pushed in lower_clause ctx.scope.pop(scope_token); } // When the pattern of the clause is unmatchable, we don't add it to // the case. Err(_lowered) => {} } assert!(ctx.exc_stack.len() == entry_exc_height) } func_case.finish(block, b); } ctx.exc_stack.pop_handler(); } fn lower_top_function(ctx: &mut LowerCtx, b: &mut FunctionBuilder, function: &NamedFunction) { let entry = b.block_insert(); b.block_set_entry(entry); let fun_name = format!("{}/{}", function.name.atom(), function.arity); assert!(ctx.functions.len() == 0); ctx.functions.push(fun_name); let loc = ctx.current_location(b, function.span); b.block_set_location(entry, loc); lower_function_base( ctx, b, entry, function.span, function.arity, &function.clauses, ); ctx.functions.pop().unwrap(); assert!(ctx.functions.len() == 0); } ================================================ FILE: libeir_syntax_erl/src/lower/pattern/mod.rs ================================================ use std::collections::HashMap; use libeir_diagnostics::SourceSpan; use libeir_ir::pattern::{PatternClause, PatternContainer, PatternValue}; use libeir_ir::{Block as IrBlock, FunctionBuilder, Location, LogicOp, Value as IrValue}; use crate::parser::ast::{Expr, Guard}; use super::{lower_block, LowerCtx, ScopeToken}; use libeir_intern::Ident; mod tree; use tree::Tree; //use prewalk::{ prewalk_pattern, PrewalkFail }; //use lower::{ lower_pattern, to_node, PatternRes, LowerFail }; enum EqGuard { EqValue(usize, IrValue), EqBind(usize, usize), } struct ClauseLowerCtx { span: SourceSpan, loc: Location, // The clause we are constructing pat_clause: PatternClause, /// Patterns can contain a (limited) amount of expressions. /// We construct these values before the case structure starts. /// This contains the current last block in the control flow /// chain of constructed values. pre_case: IrBlock, /// When values are bound when lowering patterns, they are added /// here in the same order as they are referenced in the pattern. binds: Vec>, /// Corresponds to PatternValues in the clause values: Vec, // Auxillary equality guards // The first value represents the position in the bind list eq_guards: Vec, value_dedup: HashMap, } impl ClauseLowerCtx { pub fn clause_value(&mut self, pat: &mut PatternContainer, val: IrValue) -> PatternValue { if let Some(pat_val) = self.value_dedup.get(&val) { *pat_val } else { self.values.push(val); pat.clause_value(self.pat_clause) } } } pub(crate) struct LoweredClause { pub clause: PatternClause, pub guard: IrValue, pub values: Vec, pub shadow: bool, pub binds: Vec>, } impl LoweredClause { pub fn make_body(&self, ctx: &mut LowerCtx, b: &mut FunctionBuilder) -> (ScopeToken, IrBlock) { let scope_token = ctx.scope.push(); let body_block = b.block_insert(); for bind in self.binds.iter() { let val = b.block_arg_insert(body_block); if let Some(name) = bind { if self.shadow { ctx.bind_shadow(*name, val); } else { ctx.bind(*name, val); } } } (scope_token, body_block) } } pub(crate) struct UnreachableClause { pub shadow: bool, pub binds: Vec, } impl UnreachableClause { pub fn make_body(&self, ctx: &mut LowerCtx, b: &mut FunctionBuilder) -> (ScopeToken, IrBlock) { let scope_token = ctx.scope.push(); let body_block = b.block_insert(); let sentinel = ctx.sentinel(); for bind in self.binds.iter() { if self.shadow { ctx.bind_shadow(*bind, sentinel); } else { ctx.bind(*bind, sentinel); } } (scope_token, body_block) } } /// When this returns Some: /// * A scope will be pushed with the bound variables in the body block /// * The body is empty pub(super) fn lower_clause<'a, P>( ctx: &mut LowerCtx, pat: &mut PatternContainer, b: &mut FunctionBuilder, // Once all clauses have been lowered, this is the block where the case // operation itself will be lowered into. The lowering logic for a clause // can use this to prepend anything it needs done before the pattern // starts, like creating needed values. // This block should always be empty. pre_case: &mut IrBlock, shadow: bool, span: SourceSpan, patterns: P, guard: Option<&Vec>, ) -> Result where P: Iterator, { assert!(b.fun().block_kind(*pre_case).is_none()); let loc = ctx.current_location(b, span); let pat_clause = pat.clause_start(span); let mut clause_ctx = ClauseLowerCtx { span, loc, pat_clause, pre_case: *pre_case, binds: Vec::new(), values: Vec::new(), eq_guards: Vec::new(), value_dedup: HashMap::new(), }; let mut tree = Tree::new(); for pattern in patterns { tree.add_root(ctx, b, &mut clause_ctx.pre_case, pattern); } tree.process(ctx, b, shadow); if tree.unmatchable { return Err(UnreachableClause { shadow, binds: tree.pseudo_binds(), }); } tree.lower(b, pat, &mut clause_ctx); // Construct guard lambda let guard_lambda_block = clause_ctx.lower_guard(ctx, b, shadow, guard); *pre_case = clause_ctx.pre_case; // Construct body //let scope_token = ctx.scope.push(); // Binds //let body_block = b.block_insert(); //for bind in clause_ctx.binds.iter() { // let val = b.block_arg_insert(body_block); // if let Some(name) = bind { // ctx.bind(*name, val); // } //} Ok(LoweredClause { clause: pat_clause, guard: b.value(guard_lambda_block), values: clause_ctx.values, shadow, binds: clause_ctx.binds, }) } impl ClauseLowerCtx { fn lower_guard( &self, ctx: &mut LowerCtx, b: &mut FunctionBuilder, shadow: bool, guard: Option<&Vec>, ) -> IrBlock { let guard_lambda_block = b.block_insert(); b.block_set_location(guard_lambda_block, self.loc); let ret_cont = b.block_arg_insert(guard_lambda_block); let _throw_cont = b.block_arg_insert(guard_lambda_block); let scope_tok = ctx.scope.push(); { let fail_handler_block = b.block_insert(); b.block_set_location(fail_handler_block, self.loc); b.block_arg_insert(fail_handler_block); b.block_arg_insert(fail_handler_block); b.block_arg_insert(fail_handler_block); let false_val = b.value(false); b.op_call_flow(fail_handler_block, ret_cont, &[false_val]); ctx.exc_stack.push_handler(b.value(fail_handler_block)); } // Binds for bind in self.binds.iter() { let val = b.block_arg_insert(guard_lambda_block); if let Some(name) = bind { if shadow { let _ = ctx.scope.bind_shadow(*name, val); } else { ctx.bind(*name, val); } } } // Body let mut block = guard_lambda_block; let mut top_and = Vec::new(); let erlang_atom = b.value(Ident::from_str("erlang")); let exact_eq_atom = b.value(Ident::from_str("=:=")); let two_atom = b.value(2); // Aux guards for eq_guard in self.eq_guards.iter() { let (lhs, rhs) = match eq_guard { EqGuard::EqValue(lhs_idx, rhs) => { let lhs = b.block_args(guard_lambda_block)[lhs_idx + 2]; (lhs, *rhs) } EqGuard::EqBind(lhs_idx, rhs_idx) => { let lhs = b.block_args(guard_lambda_block)[lhs_idx + 2]; let rhs = b.block_args(guard_lambda_block)[rhs_idx + 2]; (lhs, rhs) } }; let fun_val = b.prim_capture_function(self.span, erlang_atom, exact_eq_atom, two_atom); let (ok_block, err_block) = b.op_call_function(self.span, block, fun_val, &[lhs, rhs]); b.block_set_location(block, self.loc); let res_val = b.block_args(ok_block)[0]; block = ok_block; b.op_unreachable(self.span, err_block); b.block_set_location(err_block, self.loc); top_and.push(res_val); } let mut or = Vec::new(); let mut and = Vec::new(); // Clause guards if let Some(guard_seq) = guard { for guard in guard_seq { for condition in guard.conditions.iter() { let (block_new, val) = lower_block(ctx, b, block, [condition].iter().map(|v| *v)); and.push(val); block = block_new; } let val = b.prim_logic_op(guard.span, LogicOp::And, &and); and.clear(); or.push(val); } let val = b.prim_logic_op(self.span, LogicOp::Or, &or); or.clear(); top_and.push(val); } let result_bool = b.prim_logic_op(self.span, LogicOp::And, &top_and); b.op_call_flow(block, ret_cont, &[result_bool]); b.block_set_location(block, self.loc); ctx.exc_stack.pop_handler(); ctx.scope.pop(scope_tok); guard_lambda_block } } ================================================ FILE: libeir_syntax_erl/src/lower/pattern/tree/from_expr.rs ================================================ use either::Either; use std::convert::TryInto; use cranelift_entity::EntityList; use libeir_ir::{ AtomicTerm, BigIntTerm, BinaryTerm, Block, FloatTerm, FunctionBuilder, IntTerm, NilTerm, }; use libeir_diagnostics::SourceSpan; use libeir_intern::Ident; use libeir_util_number::bigint::BigInt; use snafu::ResultExt; use crate::evaluator::{eval_expr, ResolveRecordIndexError, Term}; use crate::lower::{lower_single, LowerCtx, LowerError}; use crate::util::string_tokenizer::StringTokenizer; use crate::parser::ast::{Binary, BinaryExpr, BinaryOp, Expr, Literal, UnaryExpr, UnaryOp, Var}; use super::{Tree, TreeNode, TreeNodeKind}; fn pattern_to_tree_node_append_tail( ctx: &mut LowerCtx, b: &mut FunctionBuilder, pre_block: &mut Block, t: &mut Tree, expr: &Expr, tail: TreeNode, span: SourceSpan, ) -> TreeNode { match expr { Expr::Literal(Literal::String(_id, ident)) => { let mut tokens = Vec::new(); let tokenizer = StringTokenizer::new(*ident); for elem in tokenizer { match elem { Ok((cp, _span)) => { tokens.push(cp); }, Err(err) => { ctx.error(err.into()); return t.nodes.push(TreeNodeKind::Wildcard(span)); }, } } let mut node = tail; for c in tokens.iter().rev() { let head = t .nodes .push(TreeNodeKind::Atomic(span, b.cons_mut().from(*c))); node = t.nodes.push(TreeNodeKind::Cons { span, head, tail: node, }); } node } Expr::Nil(_) => tail, Expr::Cons(cons) => { let tail = pattern_to_tree_node_append_tail(ctx, b, pre_block, t, &cons.tail, tail, span); let head = pattern_to_tree_node(ctx, b, pre_block, t, &cons.head); t.nodes.push(TreeNodeKind::Cons { span, head, tail, }) } _ => unimplemented!("{:?}", expr), } } impl Tree { pub(crate) fn add_root( &mut self, ctx: &mut LowerCtx, b: &mut FunctionBuilder, pre_block: &mut Block, expr: &Expr, ) { let root = pattern_to_tree_node(ctx, b, pre_block, self, expr); self.roots.push(root); } } fn pattern_to_tree_node( ctx: &mut LowerCtx, b: &mut FunctionBuilder, pre_block: &mut Block, t: &mut Tree, expr: &Expr, ) -> TreeNode { match expr { Expr::Nil(nil) => { let cons = b.cons_mut().from(NilTerm); t.nodes.push(TreeNodeKind::Atomic(nil.0, cons)) } Expr::Literal(lit) => { let cons = match lit { Literal::Atom(_id, ident) => b.cons_mut().from(*ident).into(), Literal::Char(_span, _id, c) => b.cons_mut().from(*c).into(), Literal::Integer(_span, _id, num) => b.cons_mut().from(num.clone()).into(), Literal::Float(_span, _id, num) => b.cons_mut().from(*num).into(), Literal::String(_id, ident) => { let mut chars = Vec::new(); let tokenizer = StringTokenizer::new(*ident); for elem in tokenizer { match elem { Ok((cp, _span)) => { chars.push(cp); }, Err(err) => { ctx.error(err.into()); return t.nodes.push(TreeNodeKind::Wildcard(ident.span)); }, } } let nil_const = b.cons_mut().from(NilTerm); let mut node = t.nodes.push(TreeNodeKind::Atomic(ident.span, nil_const)); for c in chars.iter().rev() { let char_const = b.cons_mut().from(*c); let head = t.nodes.push(TreeNodeKind::Atomic(ident.span, char_const)); node = t.nodes.push(TreeNodeKind::Cons { span: ident.span, head, tail: node, }); } return node; } }; t.nodes.push(TreeNodeKind::Atomic(lit.span(), cons)) } Expr::Match(match_expr) => { let left = pattern_to_tree_node(ctx, b, pre_block, t, &match_expr.pattern); let right = pattern_to_tree_node(ctx, b, pre_block, t, &match_expr.expr); t.nodes.push(TreeNodeKind::And { left, right }) } Expr::Var(Var(_id, var)) => { let node = t.nodes.push(TreeNodeKind::Wildcard(expr.span())); if !crate::lower::scope::is_wildcard(*var) { t.binds[node].push(*var); } node } Expr::Tuple(tup) => { let mut elems = EntityList::new(); for elem in tup.elements.iter() { let node = pattern_to_tree_node(ctx, b, pre_block, t, elem); elems.push(node, &mut t.node_pool); } t.nodes.push(TreeNodeKind::Tuple { span: tup.span, elems, }) } Expr::Cons(cons) => { let head = pattern_to_tree_node(ctx, b, pre_block, t, &cons.head); let tail = pattern_to_tree_node(ctx, b, pre_block, t, &cons.tail); t.nodes.push(TreeNodeKind::Cons { span: cons.span, head, tail, }) } Expr::Record(rec) => { let span = expr.span(); if !ctx.module.records.contains_key(&rec.name.name) { ctx.error(LowerError::UndefinedRecord { span: rec.name.span, }); return t.nodes.push(TreeNodeKind::Wildcard(span)); } let rec_def = &ctx.module.records[&rec.name.name]; let name = b.cons_mut().from(rec.name); let name_node = t.nodes.push(TreeNodeKind::Atomic(rec.name.span, name)); let mut pat_fields = vec![]; for _ in 0..rec_def.record.fields.len() { pat_fields.push(t.nodes.push(TreeNodeKind::Wildcard(span))); } for field in rec.fields.iter() { let idx = rec_def.field_idx_map[&field.name]; let node = pattern_to_tree_node(ctx, b, pre_block, t, &field.value.as_ref().unwrap()); let prev = pat_fields[idx]; pat_fields[idx] = t.nodes.push(TreeNodeKind::And { left: prev, right: node, }); } let mut elems = EntityList::new(); elems.push(name_node, &mut t.node_pool); for field in pat_fields { elems.push(field, &mut t.node_pool); } t.nodes.push(TreeNodeKind::Tuple { span: rec.span, elems, }) } Expr::BinaryExpr(BinaryExpr { op: BinaryOp::Append, lhs, rhs, span, .. }) => { let tail = pattern_to_tree_node(ctx, b, pre_block, t, rhs); pattern_to_tree_node_append_tail(ctx, b, pre_block, t, lhs, tail, *span) } Expr::Binary(Binary { span, elements, .. }) => { use crate::parser::binary::{default_specifier, specifier_can_have_size, specifier_to_typename, TypeName}; // Desugar <<"binary string">> if elements.len() == 1 { let elem = &elements[0]; if elem.bit_size.is_none() && elem.specifier.is_none() { if let Expr::Literal(Literal::String(_id, string)) = &elem.bit_expr { let mut chars = Vec::new(); let tokenizer = StringTokenizer::new(*string); for elem in tokenizer { match elem { Ok((cp, _span)) => { chars.push(cp); }, Err(err) => { ctx.error(err.into()); return t.nodes.push(TreeNodeKind::Wildcard(string.span)); }, } } let bin = chars.iter().map(|ch| (ch & 0xff) as u8).collect::>(); let cons = b.cons_mut().from(bin); return t.nodes.push(TreeNodeKind::Atomic(*span, cons)); } } } let mut bin_node = None; //let mut bin_node = t.nodes.push(TreeNodeKind::Atomic( // span.clone(), // b.cons_mut().from(Vec::::new()), //)); for (_idx, elem) in elements.iter().enumerate().rev() { let spec = elem .specifier .unwrap_or(default_specifier()); let spec_typ = specifier_to_typename(&spec); let bit_val = pattern_to_tree_node(ctx, b, pre_block, t, &elem.bit_expr); let size_val = if let Some(size_expr) = &elem.bit_size { if !specifier_can_have_size(&spec) { ctx.error(LowerError::BinaryInvalidSize { span: size_expr.span(), typ: spec_typ, }); None } else { let ret = match size_expr { Expr::Var(Var(_id, var)) => Either::Left(*var), _ => { let (block, val) = lower_single(ctx, b, *pre_block, size_expr); *pre_block = block; Either::Right(val) } }; Some(ret) } } else { match spec_typ { TypeName::Integer => Some(b.value(8)), TypeName::Float => Some(b.value(64)), _ => None, } .map(Either::Right) }; bin_node = Some(t.nodes.push(TreeNodeKind::Binary { span: *span, specifier: spec, size: size_val, size_resolved: None, value: bit_val, tail: bin_node, })); } bin_node.unwrap_or_else(|| { t.nodes.push(TreeNodeKind::Atomic( span.clone(), b.cons_mut().from(Vec::::new()), )) }) } Expr::Map(map) => { let mut entries = Vec::new(); for field in map.fields.iter() { let (block, key) = lower_single(ctx, b, *pre_block, &field.key()); *pre_block = block; let val = pattern_to_tree_node(ctx, b, pre_block, t, &field.value()); entries.push((key, val)); } t.nodes.push(TreeNodeKind::Map { span: map.span, entries, }) } expr => { let resolve_rec_idx = |name: Ident, field: Ident| { ctx.resolve_rec_idx(name, field) }; match eval_expr(expr, Some(&resolve_rec_idx)) { Ok(term) => { let constant = match term { Term::Number(num) => b.cons_mut().from(num), _ => unreachable!(), }; t.nodes.push(TreeNodeKind::Atomic(expr.span(), constant)) } Err(error) => { ctx.error(LowerError::PatternConst { source: error, span: expr.span(), }); // In this path compilation has failed. // Add a wildcard to don't affect other parts of the compilation. t.nodes.push(TreeNodeKind::Wildcard(expr.span())) } } } } } ================================================ FILE: libeir_syntax_erl/src/lower/pattern/tree/lower.rs ================================================ use std::collections::{BTreeMap, HashMap}; use either::Either; use libeir_intern::Ident; use libeir_ir::pattern::PatternContainer; use libeir_ir::{FunctionBuilder, PatternNode}; use super::super::{ClauseLowerCtx, EqGuard}; use super::{ConstraintKind, Tree, TreeNode, TreeNodeKind}; impl Tree { pub(in super::super) fn lower( &self, b: &mut FunctionBuilder, pat: &mut PatternContainer, cl_ctx: &mut ClauseLowerCtx, ) { let mut node_map = BTreeMap::new(); for root in self.roots.iter() { create_nodes(b, pat, self, &mut node_map, *root); } for root in self.roots.iter() { let lowered = lower_tree_node(b, pat, cl_ctx, &node_map, self, *root); pat.clause_node_push(cl_ctx.pat_clause, lowered); } let mut node_binds_map = HashMap::new(); for (ident, node) in self.resolved_binds.as_ref().unwrap() { let new_bind_idx = cl_ctx.binds.len(); node_binds_map.insert(*node, new_bind_idx); cl_ctx.binds.push(Some(*ident)); let pat_node = node_map[node]; pat.clause_bind_push(cl_ctx.pat_clause, pat_node); } for (node, constraints) in self.constraints.iter() { if constraints.len() == 0 { continue; } let pat_node = node_map[&node]; let new_bind_idx = cl_ctx.binds.len(); cl_ctx.binds.push(None); pat.clause_bind_push(cl_ctx.pat_clause, pat_node); for constraint in constraints.iter() { match constraint { ConstraintKind::Value(val) => { cl_ctx.eq_guards.push(EqGuard::EqValue(new_bind_idx, *val)); } ConstraintKind::Const(cons) => { let val = b.value(*cons); cl_ctx.eq_guards.push(EqGuard::EqValue(new_bind_idx, val)); } ConstraintKind::PrimOp(prim) => { let val = b.value(*prim); cl_ctx.eq_guards.push(EqGuard::EqValue(new_bind_idx, val)); } ConstraintKind::Node(node) => { let bind_idx = node_binds_map[node]; cl_ctx .eq_guards .push(EqGuard::EqBind(new_bind_idx, bind_idx)); } } } } } pub fn pseudo_binds(&self) -> Vec { self.resolved_binds .as_ref() .unwrap() .keys() .cloned() .collect() } } fn create_nodes( b: &mut FunctionBuilder, pat: &mut PatternContainer, t: &Tree, map: &mut BTreeMap, node: TreeNode, ) { assert!(!map.contains_key(&node)); let span = t.node_span(node); let p_node = pat.node_empty(Some(span)); map.insert(node, p_node); match &t.nodes[node] { TreeNodeKind::Atomic(_, _) => (), TreeNodeKind::Value(_, _) => (), TreeNodeKind::Wildcard(_) => (), TreeNodeKind::Tuple { elems, .. } => { for elem in elems.as_slice(&t.node_pool) { create_nodes(b, pat, t, map, *elem); } } TreeNodeKind::Cons { head, tail, .. } => { create_nodes(b, pat, t, map, *head); create_nodes(b, pat, t, map, *tail); } TreeNodeKind::Binary { value, tail, .. } => { create_nodes(b, pat, t, map, *value); if let Some(tail_node) = tail { create_nodes(b, pat, t, map, *tail_node); } } TreeNodeKind::Map { entries, .. } => { for (_, v) in entries { create_nodes(b, pat, t, map, *v); } } _ => unreachable!(), } } fn lower_tree_node( b: &mut FunctionBuilder, pat: &mut PatternContainer, cl_ctx: &mut ClauseLowerCtx, map: &BTreeMap, t: &Tree, node: TreeNode, ) -> PatternNode { let p_node = map[&node]; match &t.nodes[node] { TreeNodeKind::Atomic(span, cons) => { pat.constant(p_node, *cons); pat.node_set_span(p_node, *span); } TreeNodeKind::Value(span, Either::Left(val)) => { let cl_val = cl_ctx.clause_value(pat, *val); pat.value(p_node, cl_val); pat.node_set_span(p_node, *span); } TreeNodeKind::Value(_, Either::Right(_node)) => unimplemented!(), TreeNodeKind::Wildcard(_) => { pat.wildcard(p_node); } TreeNodeKind::Tuple { span, elems } => { pat.tuple(p_node); for elem in elems.as_slice(&t.node_pool) { let child = lower_tree_node(b, pat, cl_ctx, map, t, *elem); pat.tuple_elem_push(p_node, child); } pat.node_finish(p_node); pat.node_set_span(p_node, *span); } TreeNodeKind::Cons { span, head, tail } => { let head_n = lower_tree_node(b, pat, cl_ctx, map, t, *head); let tail_n = lower_tree_node(b, pat, cl_ctx, map, t, *tail); pat.list(p_node, head_n, tail_n); pat.node_set_span(p_node, *span); } TreeNodeKind::Binary { span, specifier, size_resolved, value, tail, .. } => { let size = size_resolved.map(|s| match s { Either::Left(node) => { let pat_node = map[&node]; pat.clause_node_value(cl_ctx.pat_clause, pat_node) } Either::Right(val) => cl_ctx.clause_value(pat, val), }); let value_n = lower_tree_node(b, pat, cl_ctx, map, t, *value); let tail_n = tail.map(|n| lower_tree_node(b, pat, cl_ctx, map, t, n)); pat.binary(p_node, *specifier, value_n, size, tail_n); pat.node_set_span(p_node, *span); } TreeNodeKind::Map { span, entries } => { pat.map(p_node); for (k, v) in entries { let key = cl_ctx.clause_value(pat, *k); let val = lower_tree_node(b, pat, cl_ctx, map, t, *v); pat.map_push(p_node, key, val); } pat.node_set_span(p_node, *span); } _ => unreachable!(), } p_node } ================================================ FILE: libeir_syntax_erl/src/lower/pattern/tree/merge.rs ================================================ //! Merges And nodes in the pattern tree use std::collections::{BTreeMap, BTreeSet}; use libeir_ir::FunctionBuilder; use cranelift_entity::EntityList; use super::{Tree, TreeNode, TreeNodeKind}; use crate::lower::{LowerCtx, LowerError}; pub(crate) fn merge_tree_nodes(ctx: &mut LowerCtx, b: &mut FunctionBuilder, t: &mut Tree) { let num_root = t.roots.len(); for n in 0..num_root { let root = t.roots[n]; let new = map_node(ctx, b, t, root); t.roots[n] = new; } } fn map_node(ctx: &mut LowerCtx, b: &mut FunctionBuilder, t: &mut Tree, node: TreeNode) -> TreeNode { let new = match t.nodes[node].clone() { TreeNodeKind::Atomic(_, _) => node, TreeNodeKind::Wildcard(_) => node, TreeNodeKind::Tuple { span, elems } => { let mut new_elems = EntityList::new(); for idx in 0..elems.len(&t.node_pool) { let node = elems.get(idx, &t.node_pool).unwrap(); let new = map_node(ctx, b, t, node); new_elems.push(new, &mut t.node_pool); } t.nodes.push(TreeNodeKind::Tuple { span, elems: new_elems, }) } TreeNodeKind::Cons { span, head, tail } => { let new_head = map_node(ctx, b, t, head); let new_tail = map_node(ctx, b, t, tail); t.nodes.push(TreeNodeKind::Cons { span, head: new_head, tail: new_tail, }) } TreeNodeKind::Binary { span, specifier, size, size_resolved, value, tail, } => { let n_value = map_node(ctx, b, t, value); let n_tail = tail.map(|n| map_node(ctx, b, t, n)); t.nodes.push(TreeNodeKind::Binary { span, specifier, size, size_resolved, value: n_value, tail: n_tail, }) } TreeNodeKind::Map { span, entries } => { let mut dedup = BTreeMap::new(); for (k, v) in entries.iter() { if let Some(old) = dedup.get(k) { let new = t.nodes.push(TreeNodeKind::And { left: *old, right: *v, }); dedup.insert(*k, new); } else { dedup.insert(*k, *v); } } let new_entries: Vec<_> = dedup .iter() .map(|(k, v)| (*k, map_node(ctx, b, t, *v))) .collect(); t.nodes.push(TreeNodeKind::Map { span, entries: new_entries, }) } TreeNodeKind::And { left, right } => merge_nodes(ctx, b, t, left, right), _ => unreachable!(), }; t.rename(node, new); new } fn merge_nodes( ctx: &mut LowerCtx, b: &mut FunctionBuilder, t: &mut Tree, left: TreeNode, right: TreeNode, ) -> TreeNode { let left = map_node(ctx, b, t, left); let l_kind = t.nodes[left].clone(); let right = map_node(ctx, b, t, right); let r_kind = t.nodes[right].clone(); let new = match (l_kind, r_kind) { (TreeNodeKind::Wildcard(_), _) => right, (_, TreeNodeKind::Wildcard(_)) => left, (TreeNodeKind::Atomic(s1, c1), TreeNodeKind::Atomic(s2, c2)) => { if c1 == c2 { t.nodes.push(TreeNodeKind::Atomic(s1, c1)) } else { ctx.warn(LowerError::DisjointPatternUnionWarning { left: Some(s1), right: Some(s2), }); t.unmatchable = true; t.nodes.push(TreeNodeKind::Wildcard(s1)) } } ( TreeNodeKind::Tuple { span: s1, elems: e1, }, TreeNodeKind::Tuple { span: s2, elems: e2, }, ) => { let len1 = e1.len(&t.node_pool); if len1 != e2.len(&t.node_pool) { ctx.warn(LowerError::DisjointPatternUnionWarning { left: Some(s1), right: Some(s2), }); t.unmatchable = true; t.nodes.push(TreeNodeKind::Wildcard(s1)) } else { let mut elems = EntityList::new(); for idx in 0..len1 { let l = e1.get(idx, &t.node_pool).unwrap(); let r = e2.get(idx, &t.node_pool).unwrap(); let merged = merge_nodes(ctx, b, t, l, r); elems.push(merged, &mut t.node_pool); } t.nodes.push(TreeNodeKind::Tuple { span: s1, elems }) } } ( TreeNodeKind::Cons { span: s1, head: h1, tail: t1, }, TreeNodeKind::Cons { span: _s2, head: h2, tail: t2, }, ) => { let h_m = merge_nodes(ctx, b, t, h1, h2); let t_m = merge_nodes(ctx, b, t, t1, t2); t.nodes.push(TreeNodeKind::Cons { span: s1, head: h_m, tail: t_m, }) } (TreeNodeKind::Binary { .. }, TreeNodeKind::Binary { .. }) => unimplemented!(), (TreeNodeKind::Map { entries: e_l, span }, TreeNodeKind::Map { entries: e_r, .. }) => { // Entries vectors should already be sorted debug_assert!(e_l.windows(2).all(|w| w[0].0 < w[1].0)); debug_assert!(e_r.windows(2).all(|w| w[0].0 < w[1].0)); let left: BTreeSet<_> = e_l.iter().map(|(k, _v)| *k).collect(); let right: BTreeSet<_> = e_r.iter().map(|(k, _v)| *k).collect(); let mut new = Vec::new(); // Merge the intersection of the two maps let mut l_iter = e_l.iter(); let mut r_iter = e_r.iter(); for key in left.intersection(&right) { let l_n = l_iter.find(|(k, _v)| k == key).map(|(_k, v)| *v).unwrap(); let r_n = r_iter.find(|(k, _v)| k == key).map(|(_k, v)| *v).unwrap(); let merged = merge_nodes(ctx, b, t, l_n, r_n); new.push((*key, merged)); } // Map over the left and right differences let mut l_iter = e_l.iter(); for key in left.difference(&right) { let l_n = l_iter.find(|(k, _v)| k == key).map(|(_k, v)| *v).unwrap(); let node = map_node(ctx, b, t, l_n); new.push((*key, node)); } let mut r_iter = e_r.iter(); for key in right.difference(&left) { let r_n = r_iter.find(|(k, _v)| k == key).map(|(_k, v)| *v).unwrap(); let node = map_node(ctx, b, t, r_n); new.push((*key, node)); } new.sort_by(|(k1, _), (k2, _)| k1.cmp(k2)); t.nodes.push(TreeNodeKind::Map { span, entries: new }) } (TreeNodeKind::And { .. }, TreeNodeKind::And { .. }) => unreachable!(), _ => { ctx.warn(LowerError::DisjointPatternUnionWarning { left: Some(t.node_span(left)), right: Some(t.node_span(right)), }); t.unmatchable = true; t.nodes.push(TreeNodeKind::And { left, right }) } }; t.rename(left, new); t.rename(right, new); new } ================================================ FILE: libeir_syntax_erl/src/lower/pattern/tree/mod.rs ================================================ //! Small IR used to do linting and transformations on patterns //! before they are lowered to Eir. use std::collections::{BTreeSet, HashMap}; use either::Either; use cranelift_entity::{entity_impl, EntityList, ListPool, PrimaryMap, SecondaryMap}; use libeir_ir::{BinaryEntrySpecifier, Const, FunctionBuilder, PrimOp, Value as IrValue}; use libeir_diagnostics::SourceSpan; use libeir_intern::Ident; use crate::lower::LowerCtx; mod from_expr; mod merge; use self::merge::merge_tree_nodes; mod promote_values; use self::promote_values::promote_values; mod lower; #[derive(Debug)] pub(crate) struct Tree { roots: Vec, pub unmatchable: bool, nodes: PrimaryMap, node_pool: ListPool, binds: SecondaryMap>, constraints: SecondaryMap>, resolved_binds: Option>, } impl Tree { pub fn new() -> Self { Tree { roots: Vec::new(), unmatchable: false, nodes: PrimaryMap::new(), node_pool: ListPool::new(), binds: SecondaryMap::new(), constraints: SecondaryMap::new(), resolved_binds: None, } } pub fn process(&mut self, ctx: &mut LowerCtx, b: &mut FunctionBuilder, shadow: bool) { merge_tree_nodes(ctx, b, self); promote_values(ctx, b, self, shadow); } pub fn node_span(&self, node: TreeNode) -> SourceSpan { match &self.nodes[node] { TreeNodeKind::Atomic(span, _) => *span, TreeNodeKind::Value(span, _) => *span, TreeNodeKind::Wildcard(span) => *span, TreeNodeKind::Tuple { span, .. } => *span, TreeNodeKind::Cons { span, .. } => *span, TreeNodeKind::Binary { span, .. } => *span, TreeNodeKind::Map { span, .. } => *span, TreeNodeKind::And { left, .. } => self.node_span(*left), } } fn rename(&mut self, from: TreeNode, to: TreeNode) { if from == to { return; } let len = self.binds[from].len(); for n in 0..len { let ident = self.binds[from][n]; self.binds[to].push(ident); } } } #[derive(Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] pub(crate) struct TreeNode(u32); entity_impl!(TreeNode, "tree_node"); #[derive(Debug, Clone)] pub(crate) enum TreeNodeKind { /// This must be an atomic value. /// Compound types are not allowed. Atomic(SourceSpan, Const), // Promoted to in a late pass. Value(SourceSpan, Either), Wildcard(SourceSpan), Tuple { span: SourceSpan, elems: EntityList, }, Cons { span: SourceSpan, head: TreeNode, tail: TreeNode, }, Binary { span: SourceSpan, specifier: BinaryEntrySpecifier, size: Option>, size_resolved: Option>, value: TreeNode, tail: Option, }, Map { span: SourceSpan, entries: Vec<(IrValue, TreeNode)>, }, And { left: TreeNode, right: TreeNode, }, } #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] pub(crate) enum ConstraintKind { Value(IrValue), Const(Const), PrimOp(PrimOp), Node(TreeNode), } impl ConstraintKind { fn constant(&self) -> Option { if let ConstraintKind::Const(cons) = self { Some(*cons) } else { None } } fn primop(&self) -> Option { if let ConstraintKind::PrimOp(prim) = self { Some(*prim) } else { None } } fn value(&self) -> Option { if let ConstraintKind::Value(val) = self { Some(*val) } else { None } } } ================================================ FILE: libeir_syntax_erl/src/lower/pattern/tree/promote_values.rs ================================================ //! Resolves values, promotes nodes to values, applies constraints use either::Either; use std::collections::{BTreeSet, HashMap}; use libeir_ir::{FunctionBuilder, Value as IrValue, ValueKind}; use libeir_intern::Ident; use libeir_util_datastructures::hashmap_stack::HashMapStack; use super::{ConstraintKind, Tree, TreeNode, TreeNodeKind}; use crate::lower::{LowerCtx, LowerError}; struct PromoteCtx<'a, 'b> { ctx: &'a mut LowerCtx<'b>, binds: HashMap, binds_scope: HashMapStack, shadow: bool, } impl<'a, 'b> PromoteCtx<'a, 'b> { fn resolve_or_bind( &mut self, hier: bool, ident: Ident, node: TreeNode, ) -> Option> { if hier { self.binds_scope.insert(ident, node); } if self.shadow { if let Some(bound_node) = self.binds.get(&ident) { Some(Either::Left(*bound_node)) } else { self.bind(ident, node); None } } else { if let Ok(prev_bound) = self.ctx.scope.resolve(ident) { Some(Either::Right(prev_bound)) } else { if let Some(bound_node) = self.binds.get(&ident) { Some(Either::Left(*bound_node)) } else { self.bind(ident, node); None } } } } fn resolve_only(&self, ident: Ident) -> Option> { if let Some(bound_node) = self.binds_scope.get(&ident) { Some(Either::Left(*bound_node)) } else { if let Ok(prev_bound) = self.ctx.scope.resolve(ident) { Some(Either::Right(prev_bound)) } else { None } } } fn bind(&mut self, ident: Ident, node: TreeNode) -> Option { let res = if let Some(prev) = self.binds.get(&ident) { if *prev == node { None } else { Some(*prev) } } else { self.binds.insert(ident, node); None }; res } } pub(crate) fn promote_values( ctx: &mut LowerCtx, b: &mut FunctionBuilder, t: &mut Tree, shadow: bool, ) { let mut prom = PromoteCtx { ctx, binds: HashMap::new(), binds_scope: HashMapStack::new(), shadow, }; prom.binds_scope.push(); let num_root = t.roots.len(); for n in 0..num_root { let root = t.roots[n]; process_constants_node(b, &mut prom, t, root, false); promote_values_node(b, &mut prom, t, root); } prom.binds_scope.push(); t.resolved_binds = Some(prom.binds); } fn process_constants_node( b: &mut FunctionBuilder, prom: &mut PromoteCtx, t: &mut Tree, node: TreeNode, hier_bind: bool, ) { let constraints: BTreeSet<_> = t.binds[node] .iter() .flat_map(|ident| prom.resolve_or_bind(hier_bind, *ident, node)) .map(|v| match v { Either::Left(node) => ConstraintKind::Node(node), Either::Right(val) => match b.fun().value_kind(val) { ValueKind::Const(cons) => ConstraintKind::Const(cons), ValueKind::PrimOp(prim) => ConstraintKind::PrimOp(prim), _ => ConstraintKind::Value(val), }, }) .collect(); t.constraints[node] = constraints; } fn promote_values_node( b: &mut FunctionBuilder, prom: &mut PromoteCtx, t: &mut Tree, node: TreeNode, ) { let kind = t.nodes[node].clone(); let constraints = &t.constraints[node]; let mut const_iter = constraints.iter().flat_map(|v| v.constant()); // Get first constant constraint let const_constraint = const_iter.next(); // If we have multiple different constant constraints, // the pattern can never be matched. if let Some(first) = const_constraint { for other in const_iter { if first != other { prom.ctx.warn(LowerError::UnmatchablePatternWarning { pat: Some(t.node_span(node)), reason: None, }); t.unmatchable = true; return; } } } // If we have multiple different PrimOp constraints, // the pattern can never be matched // TODO implement this warning when eir typing utilities // are more complete. // TODO: Check compatibility with TreeNode constraints. match kind { TreeNodeKind::Atomic(span, c) => { // If we have another constant constraint, and they are not // equal, we can never match the pattern. if let Some(nc) = const_constraint { if c != nc { prom.ctx.warn(LowerError::UnmatchablePatternWarning { pat: Some(span), reason: None, }); t.unmatchable = true; return; } } } TreeNodeKind::Wildcard(span) => { // Prefer to promote to constants, here we have // the most information. if let Some(cons) = const_constraint { t.nodes[node] = TreeNodeKind::Atomic(span, cons); return; } // Second choice is PrimOps. Here we have a certain // amount of information. if let Some(prim) = constraints.iter().flat_map(|c| c.primop()).nth(0) { let val = b.value(prim); t.nodes[node] = TreeNodeKind::Value(span, Either::Left(val)); return; } // Third choice is any other value if let Some(val) = constraints.iter().flat_map(|c| c.value()).nth(0) { t.nodes[node] = TreeNodeKind::Value(span, Either::Left(val)); return; } } TreeNodeKind::Tuple { elems, .. } => { for idx in 0..elems.len(&t.node_pool) { let child = elems.get(idx, &t.node_pool).unwrap(); process_constants_node(b, prom, t, child, false); } for idx in 0..elems.len(&t.node_pool) { let child = elems.get(idx, &t.node_pool).unwrap(); promote_values_node(b, prom, t, child); } } TreeNodeKind::Cons { head, tail, .. } => { process_constants_node(b, prom, t, head, false); process_constants_node(b, prom, t, tail, false); promote_values_node(b, prom, t, head); promote_values_node(b, prom, t, tail); } TreeNodeKind::Binary { value, tail, size, .. } => { let size_res = size.map(|v| match v { // The size references another node Either::Left(ident) => { // We try to resolve it in the current pattern match prom.resolve_only(ident) { // We found a node in the pattern Some(inner) => inner, // No value found, error and return sentinel None => { prom.ctx .error(LowerError::UnresolvedVariable { span: ident.span }); Either::Right(prom.ctx.sentinel()) } } } Either::Right(val) => Either::Right(val), }); if let TreeNodeKind::Binary { size_resolved, .. } = &mut t.nodes[node] { *size_resolved = size_res; } else { unreachable!(); } prom.binds_scope.push(); process_constants_node(b, prom, t, value, true); if let Some(tail_node) = tail { process_constants_node(b, prom, t, tail_node, false); } promote_values_node(b, prom, t, value); if let Some(tail_node) = tail { promote_values_node(b, prom, t, tail_node); } prom.binds_scope.pop(); } TreeNodeKind::Map { entries, .. } => { for (_k, v) in entries.iter() { process_constants_node(b, prom, t, *v, false); } for (_k, v) in entries.iter() { promote_values_node(b, prom, t, *v); } } // While this cannot occur in a matchable pattern, we still // need to resolve scoping, so we handle it. TreeNodeKind::And { left, right } => { assert!(t.unmatchable); process_constants_node(b, prom, t, left, false); process_constants_node(b, prom, t, right, false); promote_values_node(b, prom, t, left); promote_values_node(b, prom, t, right); } TreeNodeKind::Value(_, _) => unreachable!(), } } ================================================ FILE: libeir_syntax_erl/src/lower/scope.rs ================================================ use std::collections::{HashMap, HashSet}; use libeir_util_datastructures::hashmap_stack::HashMapStack; use libeir_ir::{Block as IrBlock, FunctionBuilder, Value as IrValue}; use libeir_intern::Ident; use super::{LowerCtx, LowerError}; pub fn is_wildcard(ident: Ident) -> bool { ident.name.as_str() == "_" } pub struct ScopeToken { /// The position in the stack of the referenced scope. height: usize, } #[derive(Debug)] pub struct ScopeTracker { // FIXME: Annoying that we have to store the key in the value. // Fix when get_key_value makes it into stable. stack: HashMapStack, } impl ScopeTracker { pub fn new() -> Self { ScopeTracker { stack: HashMapStack::new(), } } /// This will push a new scope, returning a token which is required /// when later popping the token off the stack. pub fn push(&mut self) -> ScopeToken { self.stack.push(); ScopeToken { height: self.stack.height(), } } /// This will pop all scopes above and including the provided token. /// Popping a token after one of its predecessors has been popped /// is illegal. pub fn pop(&mut self, token: ScopeToken) { assert!(self.stack.height() >= token.height); while self.stack.height() >= token.height { self.stack.pop(); } } pub fn pop_take(&mut self, token: ScopeToken) -> HashMap { assert!(self.stack.height() >= token.height); let mut ret = HashMap::new(); for layer_n in (token.height - 1)..self.stack.height() { let layer = self.stack.layer(layer_n); for (key, value) in layer.iter() { ret.insert(*key, value.1); } } self.pop(token); ret } pub fn resolve(&self, ident: Ident) -> Result { if let Some(val) = self.stack.get(&ident) { Ok(val.1) } else { Err(LowerError::UnresolvedVariable { span: ident.span }) } } pub fn bind(&mut self, ident: Ident, val: IrValue) -> Result<(), LowerError> { if is_wildcard(ident) { Ok(()) } else { if let Some(prev_val) = self.stack.get(&ident) { Err(LowerError::AlreadyBound { new: ident.span, old: prev_val.0.span, }) } else { self.stack.insert(ident, (ident, val)); Ok(()) } } } pub fn bind_shadow(&mut self, ident: Ident, val: IrValue) -> Result<(), LowerError> { if is_wildcard(ident) { Ok(()) } else { let ret = if let Some(prev_val) = self.stack.get(&ident) { Err(LowerError::ShadowingBind { new: ident.span, old: prev_val.0.span, }) } else { Ok(()) }; self.stack.insert(ident, (ident, val)); ret } } pub fn height(&self) -> usize { self.stack.height() } } #[derive(Debug)] struct Branch { cont_block: IrBlock, ret: IrValue, binds: HashMap, } /// Utility for performing a scope merge, as is /// needed for case, if and receive branches. /// This will insert variable binding in the top /// scope if the binding is found to be present in /// every branch. pub(super) struct ScopeMerge { branches: Vec, } impl ScopeMerge { pub fn new() -> Self { ScopeMerge { branches: Vec::new(), } } pub fn branch(&mut self, cont: IrBlock, ret: IrValue, binds: HashMap) { self.branches.push(Branch { cont_block: cont, ret, binds, }); } pub fn finish(&mut self, ctx: &mut LowerCtx, b: &mut FunctionBuilder) -> (IrBlock, IrValue) { // Find all bindings that are common to all branches let common_vars = if self.branches.len() > 0 { let mut common_set: HashSet<_> = self.branches[0].binds.keys().cloned().collect(); common_set.retain(|ident| { self.branches .iter() .all(|res| res.binds.contains_key(ident)) }); common_set.drain().collect() } else { Vec::new() }; // Insert the join block and the return argument let join_block = b.block_insert(); let ret = b.block_arg_insert(join_block); // Insert common bindings on join block for var in common_vars.iter() { let val = b.block_arg_insert(join_block); ctx.bind(*var, val); } // Create calls from all branches to join block let mut val_buf = Vec::new(); for result in self.branches.iter() { val_buf.clear(); val_buf.push(result.ret); for var in common_vars.iter() { val_buf.push(result.binds[var]); } b.op_call_flow(result.cont_block, join_block, &val_buf); } (join_block, ret) } } ================================================ FILE: libeir_syntax_erl/src/lower/tests.rs ================================================ use std::sync::Arc; use crate::ast::*; use crate::*; use crate::lower::lower_module; use crate::parser::ParseConfig; use libeir_diagnostics::CodeMap; use libeir_ir::{Module as IrModule, StandardFormatConfig}; use libeir_util_parse::Errors; fn parse(input: S, config: ParseConfig, codemap: Arc) -> T where T: Parse, S: AsRef, { let parser = Parser::new(config, codemap); let mut errors = Errors::new(); match parser.parse_string::(&mut errors, input) { Ok(ast) => return ast, Err(()) => (), }; errors.print(&parser.codemap); panic!("parse failed"); } fn lower(input: &str, config: ParseConfig) -> Result { let codemap = Arc::new(CodeMap::new()); let parsed: Module = parse(input, config, codemap.clone()); let mut errors = Errors::new(); let res = lower_module(&mut errors, codemap.clone(), &parsed); errors.print(&codemap); res } #[test] fn fib_lower() { let _result = lower( "-module(fib). fib(X) when X < 2 -> 1; fib(X) -> fib(X - 1) + fib(X-2). ", ParseConfig::default(), ) .unwrap(); } #[test] fn pat_1_lower() { let fun = lower( "-module(pat). pat(A, A) -> 1. ", ParseConfig::default(), ) .unwrap(); println!("{}", fun.to_text(&mut StandardFormatConfig::default())); } #[test] fn spec_named_return_type() { let _result = lower( " -module(test). -spec uniform() -> X :: float(). uniform() -> 1.0. ", ParseConfig::default(), ) .unwrap(); } #[test] fn delayed_substitution_macros() { let _result = lower( " -module(test). function_name() -> ?FUNCTION_NAME. function_arity() -> ?FUNCTION_ARITY. ", ParseConfig::default(), ) .unwrap(); } //#[test] //fn compiler_lower() { // let mut config = ParseConfig::default(); // // config.include_paths.push_front(PathBuf::from("../otp/lib/compiler/src/")); // config.include_paths.push_front(PathBuf::from("../otp/bootstrap/lib/stdlib/include/")); // // let ir = lower_file("../otp/lib/compiler/src/compile.erl", config).unwrap(); // // let ident = FunctionIdent { // module: Ident::from_str("compile"), // name: Ident::from_str("iofile"), // arity: 1, // }; // // let mut errors = Vec::new(); // for fun in ir.functions.values() { // //if fun.ident() == &ident { // println!("{:?}", fun.ident()); // fun.validate(&mut errors); // //} // } // println!("{:#?}", errors); // // let fun = &ir.functions[&ident]; // // print!("{}", fun.to_text()); // // let mut dot = Vec::::new(); // libeir_ir::text::dot_printer::function_to_dot(fun, &mut dot).unwrap(); // let dot_text = std::str::from_utf8(&dot).unwrap(); // print!("{}", dot_text); // //} ================================================ FILE: libeir_syntax_erl/src/parser/ast/attributes.rs ================================================ use std::fmt; use std::hash::{Hash, Hasher}; use libeir_diagnostics::SourceSpan; use super::{Expr, Ident, Name, PartiallyResolvedFunctionName, Type}; /// Type definitions /// /// ## Examples /// /// ```text /// %% Simple types /// -type foo() :: bar. /// -opaque foo() :: bar. /// /// %% Generic/parameterized types /// -type foo(T) :: [T]. /// -opaque foo(T) :: [T]. /// ``` #[derive(Debug, Clone)] pub struct TypeDef { pub span: SourceSpan, pub opaque: bool, pub name: Ident, pub params: Vec, pub ty: Type, } impl PartialEq for TypeDef { fn eq(&self, other: &Self) -> bool { if self.opaque != other.opaque { return false; } if self.name != other.name { return false; } if self.params != other.params { return false; } if self.ty != other.ty { return false; } return true; } } /// Function type specifications, used for both function specs and callback specs /// /// ## Example /// /// ```text /// %% Monomorphic function /// -spec foo(A :: map(), Opts :: list({atom(), term()})) -> {ok, map()} | {error, term()}. /// /// %% Polymorphic function /// -spec foo(A, Opts :: list({atom, term()})) -> {ok, A} | {error, term()}. /// /// %% Multiple dispatch function /// -spec foo(map(), Opts) -> {ok, map()} | {error, term()}; /// foo(list(), Opts) -> {ok, list()} | {error, term()}. /// /// %% Using `when` to express subtype constraints /// -spec foo(map(), Opts) -> {ok, map()} | {error, term()} /// when Opts :: list({atom, term}); /// ``` #[derive(Debug, Clone)] pub struct TypeSpec { pub span: SourceSpan, pub module: Option, pub function: Ident, pub sigs: Vec, } impl PartialEq for TypeSpec { fn eq(&self, other: &Self) -> bool { self.module == other.module && self.function == other.function && self.sigs == other.sigs } } /// A callback declaration, which is functionally identical to `TypeSpec` in /// its syntax, but is used to both define a callback function for a behaviour, /// as well as provide an expected type specification for that function. #[derive(Debug, Clone)] pub struct Callback { pub span: SourceSpan, pub optional: bool, pub module: Option, pub function: Ident, pub sigs: Vec, } impl PartialEq for Callback { fn eq(&self, other: &Self) -> bool { self.optional == other.optional && self.module == other.module && self.function == other.function && self.sigs == other.sigs } } /// Contains type information for a single clause of a function type specification #[derive(Debug, Clone, PartialEq)] pub struct TypeSig { pub span: SourceSpan, pub params: Vec, pub ret: Box, pub guards: Option>, } /// Contains a single subtype constraint to be applied to a type specification #[derive(Debug, Clone)] pub struct TypeGuard { pub span: SourceSpan, pub var: Name, pub ty: Type, } impl PartialEq for TypeGuard { fn eq(&self, other: &TypeGuard) -> bool { self.var == other.var && self.ty == other.ty } } /// Represents a user-defined custom attribute. /// /// ## Example /// /// ```text /// -my_attribute([foo, bar]). /// ``` #[derive(Debug, Clone)] pub struct UserAttribute { pub span: SourceSpan, pub name: Ident, pub value: Expr, } impl PartialEq for UserAttribute { fn eq(&self, other: &Self) -> bool { self.name == other.name && self.value == other.value } } /// Represents a deprecated function or module #[derive(Debug, Clone)] pub enum Deprecation { Module { span: SourceSpan, flag: DeprecatedFlag, }, Function { span: SourceSpan, function: PartiallyResolvedFunctionName, flag: DeprecatedFlag, }, } impl Deprecation { pub fn span(&self) -> SourceSpan { match self { &Deprecation::Module { ref span, .. } => span.clone(), &Deprecation::Function { ref span, .. } => span.clone(), } } } impl PartialEq for Deprecation { fn eq(&self, other: &Self) -> bool { match (self, other) { (&Deprecation::Module { .. }, &Deprecation::Module { .. }) => true, // We ignore the flag because it used only for display, // the function/arity determines equality ( &Deprecation::Function { function: ref x1, .. }, &Deprecation::Function { function: ref y1, .. }, ) => x1 == y1, _ => false, } } } impl Eq for Deprecation {} impl Hash for Deprecation { fn hash(&self, state: &mut H) { let discriminant = std::mem::discriminant(self); discriminant.hash(state); match self { &Deprecation::Module { .. } => (), &Deprecation::Function { ref function, .. } => function.hash(state), } } } #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum DeprecatedFlag { Eventually, NextVersion, NextMajorRelease, Description(Ident), } impl fmt::Display for DeprecatedFlag { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { &DeprecatedFlag::Eventually => write!(f, "eventually"), &DeprecatedFlag::NextVersion => write!(f, "in the next version"), &DeprecatedFlag::NextMajorRelease => write!(f, "in the next major release"), &DeprecatedFlag::Description(descr) => write!(f, "{}", descr.name), } } } /// Represents the set of allowed attributes in the body of a module #[derive(Debug, Clone)] pub enum Attribute { Type(TypeDef), Spec(TypeSpec), Callback(Callback), Custom(UserAttribute), ExportType(SourceSpan, Vec), Export(SourceSpan, Vec), Import(SourceSpan, Ident, Vec), Removed(SourceSpan, Vec<(PartiallyResolvedFunctionName, Ident)>), Compile(SourceSpan, Expr), Vsn(SourceSpan, Expr), Author(SourceSpan, Expr), OnLoad(SourceSpan, PartiallyResolvedFunctionName), Behaviour(SourceSpan, Ident), Deprecation(Vec), } impl PartialEq for Attribute { fn eq(&self, other: &Attribute) -> bool { let left = std::mem::discriminant(self); let right = std::mem::discriminant(other); if left != right { return false; } match (self, other) { (&Attribute::Type(ref x), &Attribute::Type(ref y)) => x == y, (&Attribute::Spec(ref x), &Attribute::Spec(ref y)) => x == y, (&Attribute::Callback(ref x), &Attribute::Callback(ref y)) => x == y, (&Attribute::Custom(ref x), &Attribute::Custom(ref y)) => x == y, (&Attribute::ExportType(_, ref x), &Attribute::ExportType(_, ref y)) => x == y, (&Attribute::Export(_, ref x), &Attribute::Export(_, ref y)) => x == y, (&Attribute::Import(_, ref x1, ref x2), &Attribute::Import(_, ref y1, ref y2)) => { (x1 == y1) && (x2 == y2) } (&Attribute::Removed(_, ref x), &Attribute::Removed(_, ref y)) => x == y, (&Attribute::Compile(_, ref x), &Attribute::Compile(_, ref y)) => x == y, (&Attribute::Vsn(_, ref x), &Attribute::Vsn(_, ref y)) => x == y, (&Attribute::Author(_, ref x), &Attribute::Author(_, ref y)) => x == y, (&Attribute::OnLoad(_, ref x), &Attribute::OnLoad(_, ref y)) => x == y, (&Attribute::Behaviour(_, ref x), &Attribute::Behaviour(_, ref y)) => x == y, _ => false, } } } ================================================ FILE: libeir_syntax_erl/src/parser/ast/expr.rs ================================================ use std::cmp::Ordering; use libeir_diagnostics::SourceSpan; use libeir_util_number::{Float, Integer, Number}; use libeir_ir::binary::BinaryEntrySpecifier; use super::NodeId; use super::{BinaryOp, Ident, UnaryOp}; use super::{Function, FunctionName, Guard, Name, Type}; use crate::lexer::DelayedSubstitution; /// The set of all possible expressions #[derive(Debug, Clone, PartialEq)] pub enum Expr { // An identifier/variable/function reference Var(Var), Literal(Literal), FunctionName(FunctionName), // Delayed substitution of macro DelayedSubstitution(SourceSpan, NodeId, DelayedSubstitution), // The various list forms Nil(Nil), Cons(Cons), // Other data structures Tuple(Tuple), Map(Map), MapUpdate(MapUpdate), MapProjection(MapProjection), Binary(Binary), Record(Record), RecordAccess(RecordAccess), RecordIndex(RecordIndex), RecordUpdate(RecordUpdate), // Comprehensions ListComprehension(ListComprehension), BinaryComprehension(BinaryComprehension), Generator(Generator), BinaryGenerator(BinaryGenerator), // Complex expressions Begin(Begin), Apply(Apply), Remote(Remote), BinaryExpr(BinaryExpr), UnaryExpr(UnaryExpr), Match(Match), If(If), Catch(Catch), Case(Case), Receive(Receive), Try(Try), Fun(Function), } impl Expr { pub fn span(&self) -> SourceSpan { match self { &Expr::Var(Var(_, Ident { ref span, .. })) => span.clone(), &Expr::Literal(ref lit) => lit.span(), &Expr::FunctionName(ref name) => name.span(), &Expr::DelayedSubstitution(ref span, _, _) => *span, &Expr::Nil(Nil(ref span, _)) => span.clone(), &Expr::Cons(Cons { ref span, .. }) => span.clone(), &Expr::Tuple(Tuple { ref span, .. }) => span.clone(), &Expr::Map(Map { ref span, .. }) => span.clone(), &Expr::MapUpdate(MapUpdate { ref span, .. }) => span.clone(), &Expr::MapProjection(MapProjection { ref span, .. }) => span.clone(), &Expr::Binary(Binary { ref span, .. }) => span.clone(), &Expr::Record(Record { ref span, .. }) => span.clone(), &Expr::RecordAccess(RecordAccess { ref span, .. }) => span.clone(), &Expr::RecordIndex(RecordIndex { ref span, .. }) => span.clone(), &Expr::RecordUpdate(RecordUpdate { ref span, .. }) => span.clone(), &Expr::ListComprehension(ListComprehension { ref span, .. }) => span.clone(), &Expr::BinaryComprehension(BinaryComprehension { ref span, .. }) => span.clone(), &Expr::Generator(Generator { ref span, .. }) => span.clone(), &Expr::BinaryGenerator(BinaryGenerator { ref span, .. }) => span.clone(), &Expr::Begin(Begin { ref span, .. }) => span.clone(), &Expr::Apply(Apply { ref span, .. }) => span.clone(), &Expr::Remote(Remote { ref span, .. }) => span.clone(), &Expr::BinaryExpr(BinaryExpr { ref span, .. }) => span.clone(), &Expr::UnaryExpr(UnaryExpr { ref span, .. }) => span.clone(), &Expr::Match(Match { ref span, .. }) => span.clone(), &Expr::If(If { ref span, .. }) => span.clone(), &Expr::Catch(Catch { ref span, .. }) => span.clone(), &Expr::Case(Case { ref span, .. }) => span.clone(), &Expr::Receive(Receive { ref span, .. }) => span.clone(), &Expr::Try(Try { ref span, .. }) => span.clone(), &Expr::Fun(ref fun) => fun.span(), } } pub fn id(&self) -> NodeId { match self { Expr::Var(Var(id, _)) => *id, Expr::Literal(lit) => lit.id(), Expr::FunctionName(name) => name.id(), Expr::DelayedSubstitution(_, id, _) => *id, Expr::Nil(Nil(_, id)) => *id, Expr::Cons(cons) => cons.id, Expr::Tuple(tuple) => tuple.id, Expr::Map(map) => map.id, Expr::MapUpdate(map) => map.id, Expr::MapProjection(map) => map.id, Expr::Binary(bin) => bin.id, Expr::Record(rec) => rec.id, Expr::RecordAccess(rec) => rec.id, Expr::RecordIndex(rec) => rec.id, Expr::RecordUpdate(rec) => rec.id, Expr::ListComprehension(compr) => compr.id, Expr::BinaryComprehension(compr) => compr.id, Expr::Generator(gen) => gen.id, Expr::BinaryGenerator(gen) => gen.id, Expr::Begin(begin) => begin.id, Expr::Apply(apply) => apply.id, Expr::Remote(rem) => rem.id, Expr::BinaryExpr(bin) => bin.id, Expr::UnaryExpr(un) => un.id, Expr::Match(mat) => mat.id, Expr::If(expr) => expr.id, Expr::Catch(catch) => catch.id, Expr::Case(case) => case.id, Expr::Receive(rec) => rec.id, Expr::Try(tr) => tr.id, Expr::Fun(fun) => fun.id(), } } } #[derive(Debug, Clone)] pub struct Var(pub NodeId, pub Ident); impl PartialEq for Var { fn eq(&self, other: &Self) -> bool { self.1 == other.1 } } impl Eq for Var {} #[derive(Debug, Clone)] pub struct Nil(pub SourceSpan, pub NodeId); impl PartialEq for Nil { fn eq(&self, _: &Self) -> bool { return true; } } impl Eq for Nil {} #[derive(Debug, Clone)] pub struct Cons { pub span: SourceSpan, pub id: NodeId, pub head: Box, pub tail: Box, } impl PartialEq for Cons { fn eq(&self, other: &Self) -> bool { self.head == other.head && self.tail == other.tail } } //impl PartialOrd for Cons { // fn partial_cmp(&self, other: &Self) -> Option { // match self.head.partial_cmp(&other.head) { // None => self.tail.partial_cmp(&other.tail), // Some(order) => Some(order), // } // } //} #[derive(Debug, Clone)] pub struct Tuple { pub span: SourceSpan, pub id: NodeId, pub elements: Vec, } impl PartialEq for Tuple { fn eq(&self, other: &Self) -> bool { self.elements == other.elements } } //impl PartialOrd for Tuple { // fn partial_cmp(&self, other: &Self) -> Option { // self.elements.partial_cmp(&other.elements) // } //} #[derive(Debug, Clone)] pub struct Map { pub span: SourceSpan, pub id: NodeId, pub fields: Vec, } impl PartialEq for Map { fn eq(&self, other: &Self) -> bool { self.fields == other.fields } } //impl PartialOrd for Map { // fn partial_cmp(&self, other: &Self) -> Option { // self.fields.partial_cmp(&other.fields) // } //} // Updating fields on an existing map, e.g. `Map#{field1 = value1}.` #[derive(Debug, Clone)] pub struct MapUpdate { pub span: SourceSpan, pub id: NodeId, pub map: Box, pub updates: Vec, } impl PartialEq for MapUpdate { fn eq(&self, other: &Self) -> bool { self.map == other.map && self.updates == other.updates } } // Pattern matching a map expression #[derive(Debug, Clone)] pub struct MapProjection { pub span: SourceSpan, pub id: NodeId, pub map: Box, pub fields: Vec, } impl PartialEq for MapProjection { fn eq(&self, other: &Self) -> bool { self.map == other.map && self.fields == other.fields } } /// The set of literal values /// /// This does not include tuples, lists, and maps, /// even though those can be constructed at compile-time, /// as some places that allow literals do not permit those /// types #[derive(Debug, Clone)] pub enum Literal { Atom(NodeId, Ident), String(NodeId, Ident), Char(SourceSpan, NodeId, char), Integer(SourceSpan, NodeId, Integer), Float(SourceSpan, NodeId, Float), } impl Literal { pub fn span(&self) -> SourceSpan { match self { &Literal::Atom(_, Ident { ref span, .. }) => span.clone(), &Literal::String(_, Ident { ref span, .. }) => span.clone(), &Literal::Char(span, _, _) => span.clone(), &Literal::Integer(span, _, _) => span.clone(), &Literal::Float(span, _, _) => span.clone(), } } pub fn id(&self) -> NodeId { match self { Literal::Atom(id, _) => *id, Literal::String(id, _) => *id, Literal::Char(_, id, _) => *id, Literal::Integer(_, id, _) => *id, Literal::Float(_, id, _) => *id, } } } impl PartialEq for Literal { fn eq(&self, other: &Literal) -> bool { match (self, other) { (&Literal::Atom(_, ref lhs), &Literal::Atom(_, ref rhs)) => lhs == rhs, (&Literal::Atom(_, _), _) => false, (_, &Literal::Atom(_, _)) => false, (&Literal::String(_, ref lhs), &Literal::String(_, ref rhs)) => lhs == rhs, (&Literal::String(_, _), _) => false, (_, &Literal::String(_, _)) => false, (x, y) => x.partial_cmp(y) == Some(Ordering::Equal), } } } impl PartialOrd for Literal { // number < atom < reference < fun < port < pid < tuple < map < nil < list < bit string fn partial_cmp(&self, other: &Literal) -> Option { match (self, other) { (Literal::String(_, ref lhs), Literal::String(_, ref rhs)) => lhs.partial_cmp(rhs), (Literal::String(_, _), _) => Some(Ordering::Greater), (_, Literal::String(_, _)) => Some(Ordering::Less), (Literal::Atom(_, ref lhs), Literal::Atom(_, ref rhs)) => lhs.partial_cmp(rhs), (Literal::Atom(_, _), _) => Some(Ordering::Greater), (_, Literal::Atom(_, _)) => Some(Ordering::Less), ( l @ (Literal::Integer(_, _, _) | Literal::Float(_, _, _) | Literal::Char(_, _, _)), r @ (Literal::Integer(_, _, _) | Literal::Float(_, _, _) | Literal::Char(_, _, _)), ) => { let to_num = |lit: &Literal| match lit { Literal::Integer(_, _, x) => x.clone().into(), Literal::Float(_, _, x) => x.clone().into(), Literal::Char(_, _, x) => { let int: Integer = (*x).into(); int.into() } _ => unreachable!(), }; let ln: Number = to_num(l); let rn: Number = to_num(r); ln.partial_cmp(&rn) } _ => unimplemented!(), } } } /// Maps can have two different types of field assignment: /// /// * assoc - inserts or updates the given key with the given value /// * exact - updates the given key with the given value, or produces an error #[derive(Debug, Clone)] pub enum MapField { Assoc { span: SourceSpan, id: NodeId, key: Expr, value: Expr, }, Exact { span: SourceSpan, id: NodeId, key: Expr, value: Expr, }, } impl MapField { pub fn key(&self) -> Expr { match self { &MapField::Assoc { ref key, .. } => key.clone(), &MapField::Exact { ref key, .. } => key.clone(), } } pub fn value(&self) -> Expr { match self { &MapField::Assoc { ref value, .. } => value.clone(), &MapField::Exact { ref value, .. } => value.clone(), } } pub fn span(&self) -> SourceSpan { match self { MapField::Assoc { span, .. } => *span, MapField::Exact { span, .. } => *span, } } } impl PartialEq for MapField { fn eq(&self, other: &Self) -> bool { (self.key() == other.key()) && (self.value() == other.value()) } } //impl PartialOrd for MapField { // fn partial_cmp(&self, other: &Self) -> Option { // match self.key().partial_cmp(&other.key()) { // None => None, // Some(Ordering::Equal) => self.value().partial_cmp(&other.value()), // Some(order) => Some(order), // } // } //} #[derive(Debug, Clone)] pub struct Record { pub span: SourceSpan, pub id: NodeId, pub name: Ident, pub fields: Vec, } impl PartialEq for Record { fn eq(&self, other: &Self) -> bool { self.name == other.name && self.fields == other.fields } } // Accessing a record field value, e.g. Expr#myrec.field1 #[derive(Debug, Clone)] pub struct RecordAccess { pub span: SourceSpan, pub id: NodeId, pub record: Box, pub name: Ident, pub field: Ident, } impl PartialEq for RecordAccess { fn eq(&self, other: &Self) -> bool { self.name == other.name && self.field == other.field && self.record == other.record } } // Referencing a record fields index, e.g. #myrec.field1 #[derive(Debug, Clone)] pub struct RecordIndex { pub span: SourceSpan, pub id: NodeId, pub name: Ident, pub field: Ident, } impl PartialEq for RecordIndex { fn eq(&self, other: &Self) -> bool { self.name == other.name && self.field == other.field } } // Update a record field value, e.g. Expr#myrec.field1 #[derive(Debug, Clone)] pub struct RecordUpdate { pub span: SourceSpan, pub id: NodeId, pub record: Box, pub name: Ident, pub updates: Vec, } impl PartialEq for RecordUpdate { fn eq(&self, other: &Self) -> bool { self.name == other.name && self.record == other.record && self.updates == other.updates } } /// Record fields always have a name, but both default value and type /// are optional in a record definition. When instantiating a record, /// if no value is given for a field, and no default is given, /// then `undefined` is the default. #[derive(Debug, Clone)] pub struct RecordField { pub span: SourceSpan, pub id: NodeId, pub name: Ident, pub value: Option, pub ty: Option, } impl PartialEq for RecordField { fn eq(&self, other: &Self) -> bool { (self.name == other.name) && (self.value == other.value) && (self.ty == other.ty) } } #[derive(Debug, Clone)] pub struct Binary { pub span: SourceSpan, pub id: NodeId, pub elements: Vec, } impl PartialEq for Binary { fn eq(&self, other: &Self) -> bool { self.elements == other.elements } } /// Used to represent a specific segment in a binary constructor, to /// produce a binary, all segments must be evaluated, and then assembled #[derive(Debug, Clone)] pub struct BinaryElement { pub span: SourceSpan, pub id: NodeId, pub bit_expr: Expr, pub bit_size: Option, pub specifier: Option, } impl PartialEq for BinaryElement { fn eq(&self, other: &Self) -> bool { (self.bit_expr == other.bit_expr) && (self.bit_size == other.bit_size) && (self.specifier == other.specifier) } } /// A bit type can come in the form `Type` or `Type:Size` #[derive(Debug, Clone)] pub enum BitType { Name(SourceSpan, NodeId, Ident), Sized(SourceSpan, NodeId, Ident, i64), } impl BitType { pub fn span(&self) -> SourceSpan { match self { BitType::Name(span, _, _) => *span, BitType::Sized(span, _, _, _) => *span, } } } impl PartialEq for BitType { fn eq(&self, other: &Self) -> bool { match (self, other) { (&BitType::Name(_, _, ref x1), &BitType::Name(_, _, ref y1)) => x1 == y1, (&BitType::Sized(_, _, ref x1, ref x2), &BitType::Sized(_, _, ref y1, ref y2)) => { (x1 == y1) && (x2 == y2) } _ => false, } } } #[derive(Debug, Clone)] pub struct ListComprehension { pub span: SourceSpan, pub id: NodeId, pub body: Box, pub qualifiers: Vec, } impl PartialEq for ListComprehension { fn eq(&self, other: &Self) -> bool { self.body == other.body && self.qualifiers == other.qualifiers } } #[derive(Debug, Clone)] pub struct BinaryComprehension { pub span: SourceSpan, pub id: NodeId, pub body: Box, pub qualifiers: Vec, } impl PartialEq for BinaryComprehension { fn eq(&self, other: &Self) -> bool { self.body == other.body && self.qualifiers == other.qualifiers } } // A generator of the form `LHS <- RHS` #[derive(Debug, Clone)] pub struct Generator { pub span: SourceSpan, pub id: NodeId, pub pattern: Box, pub expr: Box, } impl PartialEq for Generator { fn eq(&self, other: &Self) -> bool { self.pattern == other.pattern && self.expr == other.expr } } // A generator of the form `LHS <= RHS` #[derive(Debug, Clone)] pub struct BinaryGenerator { pub span: SourceSpan, pub id: NodeId, pub pattern: Box, pub expr: Box, } impl PartialEq for BinaryGenerator { fn eq(&self, other: &Self) -> bool { self.pattern == other.pattern && self.expr == other.expr } } // A sequence of expressions, e.g. begin expr1, .., exprN end #[derive(Debug, Clone)] pub struct Begin { pub span: SourceSpan, pub id: NodeId, pub body: Vec, } impl PartialEq for Begin { fn eq(&self, other: &Self) -> bool { self.body == other.body } } // Function application, e.g. foo(expr1, .., exprN) #[derive(Debug, Clone)] pub struct Apply { pub span: SourceSpan, pub id: NodeId, pub callee: Box, pub args: Vec, } impl PartialEq for Apply { fn eq(&self, other: &Self) -> bool { self.callee == other.callee && self.args == other.args } } // Remote, e.g. Foo:Bar #[derive(Debug, Clone)] pub struct Remote { pub span: SourceSpan, pub id: NodeId, pub module: Box, pub function: Box, } impl PartialEq for Remote { fn eq(&self, other: &Self) -> bool { self.module == other.module && self.function == other.function } } #[derive(Debug, Clone)] pub struct BinaryExpr { pub span: SourceSpan, pub id: NodeId, pub lhs: Box, pub op: BinaryOp, pub rhs: Box, } impl PartialEq for BinaryExpr { fn eq(&self, other: &Self) -> bool { self.op == other.op && self.lhs == other.lhs && self.rhs == other.rhs } } #[derive(Debug, Clone)] pub struct UnaryExpr { pub span: SourceSpan, pub id: NodeId, pub op: UnaryOp, pub operand: Box, } impl PartialEq for UnaryExpr { fn eq(&self, other: &Self) -> bool { self.op == other.op && self.operand == other.operand } } #[derive(Debug, Clone)] pub struct Match { pub span: SourceSpan, pub id: NodeId, pub pattern: Box, pub expr: Box, } impl PartialEq for Match { fn eq(&self, other: &Self) -> bool { self.pattern == other.pattern && self.expr == other.expr } } #[derive(Debug, Clone)] pub struct If { pub span: SourceSpan, pub id: NodeId, pub clauses: Vec, } impl PartialEq for If { fn eq(&self, other: &Self) -> bool { self.clauses == other.clauses } } /// Represents a single clause in an `if` expression #[derive(Debug, Clone)] pub struct IfClause { pub span: SourceSpan, pub id: NodeId, pub guards: Vec, pub body: Vec, } impl PartialEq for IfClause { fn eq(&self, other: &Self) -> bool { self.guards == other.guards && self.body == other.body } } #[derive(Debug, Clone)] pub struct Catch { pub span: SourceSpan, pub id: NodeId, pub expr: Box, } impl PartialEq for Catch { fn eq(&self, other: &Self) -> bool { self.expr == other.expr } } #[derive(Debug, Clone)] pub struct Case { pub span: SourceSpan, pub id: NodeId, pub expr: Box, pub clauses: Vec, } impl PartialEq for Case { fn eq(&self, other: &Self) -> bool { self.expr == other.expr && self.clauses == other.clauses } } #[derive(Debug, Clone)] pub struct Receive { pub span: SourceSpan, pub id: NodeId, pub clauses: Option>, pub after: Option, } impl PartialEq for Receive { fn eq(&self, other: &Self) -> bool { self.clauses == other.clauses && self.after == other.after } } #[derive(Debug, Clone)] pub struct Try { pub span: SourceSpan, pub id: NodeId, pub exprs: Vec, pub clauses: Option>, pub catch_clauses: Option>, pub after: Option>, } impl PartialEq for Try { fn eq(&self, other: &Self) -> bool { self.exprs == other.exprs && self.clauses == other.clauses && self.catch_clauses == other.catch_clauses && self.after == other.after } } /// Represents a single `catch` clause in a `try` expression #[derive(Debug, Clone)] pub struct TryClause { pub span: SourceSpan, pub id: NodeId, pub kind: Name, pub error: Expr, pub guard: Option>, pub trace: Ident, pub body: Vec, } impl PartialEq for TryClause { fn eq(&self, other: &Self) -> bool { self.kind == other.kind && self.error == other.error && self.guard == other.guard && self.trace == other.trace && self.body == other.body } } /// Represents the `after` clause of a `receive` expression #[derive(Debug, Clone)] pub struct After { pub span: SourceSpan, pub id: NodeId, pub timeout: Box, pub body: Vec, } impl PartialEq for After { fn eq(&self, other: &Self) -> bool { self.timeout == other.timeout && self.body == other.body } } /// Represents a single match clause in a `case`, `try`, or `receive` expression #[derive(Debug, Clone)] pub struct Clause { pub span: SourceSpan, pub id: NodeId, pub pattern: Expr, pub guard: Option>, pub body: Vec, } impl PartialEq for Clause { fn eq(&self, other: &Self) -> bool { self.pattern == other.pattern && self.guard == other.guard && self.body == other.body } } ================================================ FILE: libeir_syntax_erl/src/parser/ast/functions.rs ================================================ use std::cmp::Ordering; use std::fmt; use std::hash::{Hash, Hasher}; use libeir_diagnostics::{Diagnostic, Label, SourceSpan}; use libeir_util_parse::ErrorReceiver; use crate::preprocessor::PreprocessorError; use super::ParserError; use super::{Arity, Expr, Ident, Name, NodeId, NodeIdGenerator, TypeSpec}; #[derive(Debug, Copy, Clone)] pub struct LocalFunctionName { pub span: SourceSpan, pub function: Ident, pub arity: usize, } impl PartialEq for LocalFunctionName { fn eq(&self, other: &Self) -> bool { self.function == other.function && self.arity == other.arity } } impl Eq for LocalFunctionName {} impl Hash for LocalFunctionName { fn hash(&self, state: &mut H) { self.function.hash(state); self.arity.hash(state); } } impl PartialOrd for LocalFunctionName { fn partial_cmp(&self, other: &Self) -> Option { let (xf, xa) = (self.function, self.arity); let (yf, ya) = (other.function, other.arity); match xf.partial_cmp(&yf) { None | Some(Ordering::Equal) => xa.partial_cmp(&ya), Some(order) => Some(order), } } } impl Ord for LocalFunctionName { fn cmp(&self, other: &Self) -> Ordering { self.partial_cmp(other).unwrap() } } /// Represents a fully-resolved function name, with module/function/arity explicit #[derive(Debug, Clone)] pub struct ResolvedFunctionName { pub span: SourceSpan, pub id: NodeId, pub module: Ident, pub function: Ident, pub arity: usize, } impl PartialEq for ResolvedFunctionName { fn eq(&self, other: &Self) -> bool { self.module == other.module && self.function == other.function && self.arity == other.arity } } impl Eq for ResolvedFunctionName {} impl Hash for ResolvedFunctionName { fn hash(&self, state: &mut H) { self.module.hash(state); self.function.hash(state); self.arity.hash(state); } } impl PartialOrd for ResolvedFunctionName { fn partial_cmp(&self, other: &Self) -> Option { let (xm, xf, xa) = (self.module, self.function, self.arity); let (ym, yf, ya) = (other.module, other.function, other.arity); match xm.partial_cmp(&ym) { None | Some(Ordering::Equal) => match xf.partial_cmp(&yf) { None | Some(Ordering::Equal) => xa.partial_cmp(&ya), Some(order) => Some(order), }, Some(order) => Some(order), } } } impl Ord for ResolvedFunctionName { fn cmp(&self, other: &Self) -> Ordering { self.partial_cmp(other).unwrap() } } impl ResolvedFunctionName { pub fn to_local(&self) -> LocalFunctionName { LocalFunctionName { span: self.span, function: self.function, arity: self.arity, } } } /// Represents a partially-resolved function name, not yet associated with a module /// This is typically used to express local captures, e.g. `fun do_stuff/0` #[derive(Debug, Clone)] pub struct PartiallyResolvedFunctionName { pub span: SourceSpan, pub id: NodeId, pub function: Ident, pub arity: usize, } impl PartiallyResolvedFunctionName { pub fn resolve(&self, module: Ident) -> ResolvedFunctionName { ResolvedFunctionName { span: self.span.clone(), id: self.id, module, function: self.function.clone(), arity: self.arity, } } } impl PartialEq for PartiallyResolvedFunctionName { fn eq(&self, other: &Self) -> bool { self.function == other.function && self.arity == other.arity } } impl Eq for PartiallyResolvedFunctionName {} impl Hash for PartiallyResolvedFunctionName { fn hash(&self, state: &mut H) { self.function.hash(state); self.arity.hash(state); } } impl PartialOrd for PartiallyResolvedFunctionName { fn partial_cmp(&self, other: &Self) -> Option { let (xf, xa) = (self.function, self.arity); let (yf, ya) = (other.function, other.arity); match xf.partial_cmp(&yf) { None | Some(Ordering::Equal) => xa.partial_cmp(&ya), Some(order) => Some(order), } } } impl PartiallyResolvedFunctionName { pub fn to_local(&self) -> LocalFunctionName { LocalFunctionName { span: self.span, function: self.function, arity: self.arity, } } } /// Represents a function name which contains parts which are not yet concrete, /// i.e. they are expressions which need to be evaluated to know precisely which /// module or function is referenced #[derive(Debug, Clone)] pub struct UnresolvedFunctionName { pub span: SourceSpan, pub id: NodeId, pub module: Option, pub function: Name, pub arity: Arity, } impl PartialEq for UnresolvedFunctionName { fn eq(&self, other: &Self) -> bool { self.module == other.module && self.function == other.function && self.arity == other.arity } } impl Eq for UnresolvedFunctionName {} impl Hash for UnresolvedFunctionName { fn hash(&self, state: &mut H) { self.module.hash(state); self.function.hash(state); self.arity.hash(state); } } impl PartialOrd for UnresolvedFunctionName { fn partial_cmp(&self, other: &Self) -> Option { match self.module.partial_cmp(&other.module) { None | Some(Ordering::Equal) => match self.function.partial_cmp(&other.function) { None | Some(Ordering::Equal) => self.arity.partial_cmp(&other.arity), Some(order) => Some(order), }, Some(order) => Some(order), } } } #[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Hash)] pub enum FunctionName { Resolved(ResolvedFunctionName), PartiallyResolved(PartiallyResolvedFunctionName), Unresolved(UnresolvedFunctionName), } impl FunctionName { pub fn span(&self) -> SourceSpan { match self { &FunctionName::Resolved(ResolvedFunctionName { ref span, .. }) => span.clone(), &FunctionName::PartiallyResolved(PartiallyResolvedFunctionName { ref span, .. }) => span.clone(), &FunctionName::Unresolved(UnresolvedFunctionName { ref span, .. }) => span.clone(), } } pub fn id(&self) -> NodeId { match self { FunctionName::Resolved(fun) => fun.id, FunctionName::PartiallyResolved(fun) => fun.id, FunctionName::Unresolved(fun) => fun.id, } } pub fn detect( span: SourceSpan, nid: &mut NodeIdGenerator, module: Option, function: Name, arity: Arity, ) -> Self { if module.is_none() { return match (function, arity) { (Name::Atom(f), Arity::Int(a)) => { FunctionName::PartiallyResolved(PartiallyResolvedFunctionName { span, id: nid.next(), function: f, arity: a, }) } _ => FunctionName::Unresolved(UnresolvedFunctionName { span, id: nid.next(), module: None, function, arity, }), }; } if let (Some(Name::Atom(m)), Name::Atom(f), Arity::Int(a)) = (module, function, arity) { return FunctionName::Resolved(ResolvedFunctionName { span, id: nid.next(), module: m, function: f, arity: a, }); } FunctionName::Unresolved(UnresolvedFunctionName { span, id: nid.next(), module, function, arity, }) } pub fn from_clause(nid: &mut NodeIdGenerator, clause: &FunctionClause) -> FunctionName { match clause { &FunctionClause { name: Some(ref name), ref span, ref params, .. } => FunctionName::PartiallyResolved(PartiallyResolvedFunctionName { span: span.clone(), id: nid.next(), function: name.atom(), arity: params.len(), }), _ => panic!("cannot create a FunctionName from an anonymous FunctionClause!"), } } } impl fmt::Display for FunctionName { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { FunctionName::Resolved(ResolvedFunctionName { ref module, ref function, arity, .. }) => write!(f, "{}:{}/{}", module, function, arity), FunctionName::PartiallyResolved(PartiallyResolvedFunctionName { ref function, arity, .. }) => write!(f, "{}/{}", function, arity), FunctionName::Unresolved(UnresolvedFunctionName { module: Some(ref module), ref function, arity, .. }) => write!(f, "{:?}:{:?}/{:?}", module, function, arity), FunctionName::Unresolved(UnresolvedFunctionName { ref function, arity, .. }) => write!(f, "{:?}/{:?}", function, arity), } } } #[derive(Debug, Clone)] pub struct NamedFunction { pub span: SourceSpan, pub id: NodeId, pub name: Name, pub arity: usize, pub clauses: Vec, pub spec: Option, } impl PartialEq for NamedFunction { fn eq(&self, other: &Self) -> bool { self.name == other.name && self.arity == other.arity && self.clauses == other.clauses && self.spec == other.spec } } impl NamedFunction { pub fn new( errs: &mut dyn ErrorReceiver, span: SourceSpan, nid: &mut NodeIdGenerator, clauses: Vec, ) -> Result { debug_assert!(clauses.len() > 0); let (head, rest) = clauses.split_first().unwrap(); if head.name.is_none() { errs.error( PreprocessorError::ShowDiagnostic { diagnostic: Diagnostic::error() .with_message("expected named function") .with_labels(vec![Label::primary(head.span.source_id(), head.span) .with_message( "this clause has no name, but a name is required here", )]), } .into(), ); return Err(()); } let head_span = &head.span; let name = head.name.clone().unwrap(); let params = &head.params; let arity = params.len(); // Check clauses let mut last_clause = head_span.clone(); for clause in rest.iter() { if clause.name.is_none() { errs.error( PreprocessorError::ShowDiagnostic { diagnostic: Diagnostic::error() .with_message("expected named function clause") .with_labels(vec![ Label::primary(clause.span.source_id(), clause.span).with_message( "this clause has no name, but a name is required here", ), Label::secondary(last_clause.source_id(), last_clause) .with_message( "expected a clause with the same name as this clause", ), ]), } .into(), ); return Err(()); } let clause_span = &clause.span; let clause_name = clause.name.clone().unwrap(); let clause_params = &clause.params; let clause_arity = clause_params.len(); if clause_name != name { errs.error(ParserError::ShowDiagnostic { diagnostic: Diagnostic::error() .with_message("unterminated function clause") .with_labels(vec![ Label::primary(last_clause.source_id(), last_clause.clone()) .with_message( "this clause ends with ';', indicating that another clause follows", ), Label::secondary(clause_span.source_id(), clause_span.clone()) .with_message("but this clause has a different name"), ]), }); continue; } if clause_arity != arity { errs.error(ParserError::ShowDiagnostic { diagnostic: Diagnostic::error() .with_message("unterminated function clause") .with_labels(vec![ Label::primary(last_clause.source_id(), last_clause.clone()) .with_message( "this clause ends with ';', indicating that another clause follows", ), Label::secondary(clause_span.source_id(), clause_span.clone()) .with_message("but this clause has a different arity"), ]), }); continue; } last_clause = clause_span.clone(); } Ok(NamedFunction { span, id: nid.next(), name: name.clone(), arity, clauses, spec: None, }) } } #[derive(Debug, Clone)] pub struct Lambda { pub span: SourceSpan, pub id: NodeId, pub arity: usize, pub clauses: Vec, } impl PartialEq for Lambda { fn eq(&self, other: &Self) -> bool { self.arity == other.arity && self.clauses == other.clauses } } impl Lambda { pub fn new( errs: &mut dyn ErrorReceiver, span: SourceSpan, nid: &mut NodeIdGenerator, clauses: Vec, ) -> Result { debug_assert!(clauses.len() > 0); let (head, rest) = clauses.split_first().unwrap(); let head_span = &head.span; let params = &head.params; let arity = params.len(); // Check clauses let mut last_clause = head_span.clone(); for clause in rest.iter() { let clause_span = &clause.span; let clause_name = &clause.name; let clause_params = &clause.params; let clause_arity = clause_params.len(); if clause_name.is_some() { errs.error(ParserError::ShowDiagnostic { diagnostic: Diagnostic::error() .with_message("mismatched function clause") .with_labels(vec![ Label::primary(clause_span.source_id(), clause_span.clone()) .with_message("this clause is named"), Label::secondary(last_clause.source_id(), last_clause.clone()) .with_message( "but this clause is unnamed, all clauses must share the same name", ), ]), }); return Err(()); } if clause_arity != arity { errs.error(ParserError::ShowDiagnostic { diagnostic: Diagnostic::error() .with_message("mismatched function clause") .with_labels(vec![ Label::primary(clause_span.source_id(), clause_span.clone()) .with_message( "the arity of this clause does not match the previous clause", ), Label::secondary(last_clause.source_id(), last_clause.clone()) .with_message("this is the previous clause"), ]), }); continue; } last_clause = clause_span.clone(); } Ok(Lambda { span, id: nid.next(), arity, clauses, }) } } #[derive(Debug, Clone, PartialEq)] pub enum Function { Named(NamedFunction), Unnamed(Lambda), } impl Function { pub fn span(&self) -> SourceSpan { match self { &Function::Named(NamedFunction { ref span, .. }) => span.clone(), &Function::Unnamed(Lambda { ref span, .. }) => span.clone(), } } pub fn id(&self) -> NodeId { match self { Function::Named(fun) => fun.id, Function::Unnamed(fun) => fun.id, } } pub fn new( errs: &mut dyn ErrorReceiver, span: SourceSpan, nid: &mut NodeIdGenerator, clauses: Vec, ) -> Result { debug_assert!(clauses.len() > 0); if clauses[0].name.is_some() { Ok(Function::Named(NamedFunction::new( errs, span, nid, clauses, )?)) } else { Ok(Function::Unnamed(Lambda::new(errs, span, nid, clauses)?)) } } } #[derive(Debug, Clone)] pub struct FunctionClause { pub span: SourceSpan, pub name: Option, pub params: Vec, pub guard: Option>, pub body: Vec, } impl PartialEq for FunctionClause { fn eq(&self, other: &FunctionClause) -> bool { self.name == other.name && self.params == other.params && self.guard == other.guard && self.body == other.body } } impl FunctionClause { pub fn new( span: SourceSpan, name: Option, params: Vec, guard: Option>, body: Vec, ) -> Self { FunctionClause { span, name, params, guard, body, } } } #[derive(Debug, Clone)] pub struct Guard { pub span: SourceSpan, pub conditions: Vec, } impl PartialEq for Guard { fn eq(&self, other: &Guard) -> bool { self.conditions == other.conditions } } ================================================ FILE: libeir_syntax_erl/src/parser/ast/mod.rs ================================================ mod attributes; mod expr; mod functions; mod module; mod types; use libeir_diagnostics::{SourceIndex, SourceSpan}; pub use self::attributes::*; pub use self::expr::*; pub use self::functions::*; pub use self::module::*; pub use self::types::*; pub use super::{ParseError, ParserError}; pub use crate::lexer::{Ident, Symbol}; use crate::lexer::Token; use crate::preprocessor::PreprocessorError; /// Used for AST functions which need to raise an error to the parser directly pub type TryParseResult = Result>; /// Represents either a concrete name (an atom) or a variable name (an identifier). /// This is used in constructs where either are permitted. #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] pub enum Name { Atom(Ident), Var(Ident), } impl Name { pub fn symbol(&self) -> Symbol { match self { Name::Atom(Ident { ref name, .. }) => name.clone(), Name::Var(Ident { ref name, .. }) => name.clone(), } } pub fn span(&self) -> SourceSpan { match self { Name::Atom(Ident { ref span, .. }) => span.clone(), Name::Var(Ident { ref span, .. }) => span.clone(), } } pub fn atom(&self) -> Ident { match self { Name::Atom(ident) => *ident, _ => panic!(), } } pub fn var(&self) -> Ident { match self { Name::Var(ident) => *ident, _ => panic!(), } } } impl PartialOrd for Name { fn partial_cmp(&self, other: &Name) -> Option { self.symbol().partial_cmp(&other.symbol()) } } #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, PartialOrd)] pub enum Arity { Int(usize), Var(Ident), } #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, PartialOrd)] pub struct NodeId(pub usize); #[derive(Debug, Clone)] pub struct NodeIdGenerator(usize); impl NodeIdGenerator { pub fn new() -> Self { NodeIdGenerator(0) } pub fn next(&mut self) -> NodeId { self.0 += 1; NodeId(self.0) } } /// The set of all binary operators which may be used in expressions #[derive(Debug, Copy, Clone, PartialEq)] pub enum BinaryOp { // 100 !, right associative Send, // 150 orelse OrElse, // 160 andalso AndAlso, // 200 Equal, // right associative NotEqual, Lte, Lt, Gte, Gt, StrictEqual, StrictNotEqual, // 300 , right associative Append, Remove, // 400 , left associative Add, Sub, Bor, Bxor, Bsl, Bsr, Or, Xor, // 500 , left associative Divide, Multiply, Div, Rem, Band, And, } /// The set of all unary (prefix) operators which may be used in expressions #[derive(Debug, Copy, Clone, PartialEq)] pub enum UnaryOp { // 600 Plus, Minus, Bnot, Not, } ================================================ FILE: libeir_syntax_erl/src/parser/ast/module.rs ================================================ use std::collections::btree_map::Entry; use std::collections::BTreeMap; use std::collections::{HashMap, HashSet}; use libeir_diagnostics::{Diagnostic, Label, SourceSpan}; use libeir_util_number::ToPrimitive; use libeir_util_parse::ErrorReceiver; use super::Name; use super::NodeIdGenerator; use super::ParserError; use super::{Apply, Cons, Nil, Remote, Tuple, Var}; use super::{Attribute, Deprecation, UserAttribute}; use super::{Callback, Record, TypeDef, TypeSig, TypeSpec}; use super::{Expr, Ident, Literal, Symbol}; use super::{ FunctionClause, FunctionName, LocalFunctionName, NamedFunction, PartiallyResolvedFunctionName, ResolvedFunctionName, }; /// Represents expressions valid at the top level of a module body #[derive(Debug, Clone, PartialEq)] pub enum TopLevel { Attribute(Attribute), Record(Record), Function(NamedFunction), } #[derive(Debug, Clone)] pub struct DefinedRecord { pub record: Record, pub field_idx_map: HashMap, } impl PartialEq for DefinedRecord { fn eq(&self, other: &Self) -> bool { self.record == other.record } } /// Represents a complete module, broken down into its constituent parts /// /// Creating a module via `Module::new` ensures that each field is correctly /// populated, that sanity checking of the top-level constructs is performed, /// and that a module is ready for semantic analysis and lowering to IR /// /// A key step performed by `Module::new` is decorating `ResolvedFunctionName` /// structs with the current module where appropriate (as this is currently not /// done during parsing, as the module is constructed last). This means that once /// constructed, one can use `ResolvedFunctionName` equality in sets/maps, which /// allows us to easily check definitions, usages, and more. #[derive(Debug, Clone)] pub struct Module { pub span: SourceSpan, pub name: Ident, pub vsn: Option, pub author: Option, pub compile: Option, pub on_load: Option, pub imports: HashMap, pub exports: HashSet, pub removed: HashMap, pub types: HashMap, pub exported_types: HashSet, pub behaviours: HashSet, pub callbacks: HashMap, pub records: HashMap, pub attributes: HashMap, pub functions: BTreeMap, // Used for module-level deprecation pub deprecation: Option, // Used for function-level deprecation pub deprecations: HashSet, } impl Module { /// Called by the parser to create the module once all of the top-level expressions have been /// parsed, in other words this is the last function called when parsing a module. /// /// As a result, this function performs some initial linting of the module: /// /// * If configured to do so, warns if functions are missing type specs /// * Warns about type specs for undefined functions /// * Warns about redefined attributes /// * Errors on invalid syntax in built-in attributes (e.g. -import(..)) /// * Errors on mismatched function clauses (name/arity) /// * Errors on unterminated function clauses /// * Errors on redefined functions /// /// And a few other similar lints pub fn new( errs: &mut dyn ErrorReceiver, span: SourceSpan, nid: &mut NodeIdGenerator, name: Ident, mut body: Vec, ) -> Self { let mut module = Module { span, name, vsn: None, author: None, on_load: None, compile: None, imports: HashMap::new(), exports: HashSet::new(), removed: HashMap::new(), types: HashMap::new(), exported_types: HashSet::new(), behaviours: HashSet::new(), callbacks: HashMap::new(), records: HashMap::new(), attributes: HashMap::new(), functions: BTreeMap::new(), deprecation: None, deprecations: HashSet::new(), }; // Functions will be decorated with their type specs as they are added // to the module. To accomplish this, we keep track of seen type specs // as they are defined, then later look up the spec for a function when // a definition is encountered let mut specs: HashMap = HashMap::new(); // Walk every top-level expression and extend our initial module definition accordingly for item in body.drain(..) { match item { TopLevel::Attribute(Attribute::Vsn(aspan, vsn)) => { if module.vsn.is_none() { module.vsn = Some(vsn); continue; } let module_vsn_span = module.vsn.as_ref().map(|v| v.span()).unwrap(); let module_vsn_source_id = module_vsn_span.source_id(); errs.error(ParserError::ShowDiagnostic { diagnostic: Diagnostic::error() .with_message("attribute is already defined") .with_labels(vec![ Label::primary(aspan.source_id(), aspan) .with_message("redefinition occurs here"), Label::secondary(module_vsn_source_id, module_vsn_span) .with_message("first defined here"), ]), }); } TopLevel::Attribute(Attribute::Author(aspan, author)) => { if module.author.is_none() { module.author = Some(author); continue; } let module_author_span = module.author.as_ref().map(|v| v.span()).unwrap(); let module_author_source_id = module_author_span.source_id(); errs.error(ParserError::ShowDiagnostic { diagnostic: Diagnostic::error() .with_message("attribute is already defined") .with_labels(vec![ Label::primary(aspan.source_id(), aspan) .with_message("redefinition occurs here"), Label::secondary(module_author_source_id, module_author_span) .with_message("first defined here"), ]), }); } TopLevel::Attribute(Attribute::OnLoad(aspan, fname)) => { if module.on_load.is_none() { module.on_load = Some(fname.to_local()); continue; } let module_onload_span = module.on_load.as_ref().map(|v| v.span).unwrap(); let module_onload_source_id = module_onload_span.source_id(); errs.error(ParserError::ShowDiagnostic { diagnostic: Diagnostic::error() .with_message("on_load can only be defined once") .with_labels(vec![ Label::primary(aspan.source_id(), aspan) .with_message("redefinition occurs here"), Label::secondary(module_onload_source_id, module_onload_span) .with_message("first defined here"), ]), }); } TopLevel::Attribute(Attribute::Import(aspan, from_module, mut imports)) => { for import in imports.drain(..) { let import = import.resolve(from_module.clone()); match module.imports.get(&import.to_local()) { None => { module.imports.insert(import.to_local(), import); } Some(ResolvedFunctionName { span: ref prev_span, .. }) => { errs.error(ParserError::ShowDiagnostic { diagnostic: Diagnostic::warning() .with_message("unused import") .with_labels(vec![ Label::primary(aspan.source_id(), aspan).with_message( "this import is a duplicate of a previous import", ), Label::secondary( prev_span.source_id(), prev_span.clone(), ) .with_message("function was first imported here"), ]), }); } } } } TopLevel::Attribute(Attribute::Export(aspan, mut exports)) => { for export in exports.drain(..) { match module.exports.get(&export.to_local()) { None => { module.exports.insert(export.to_local()); } Some(LocalFunctionName { span: ref prev_span, .. }) => { errs.error(ParserError::ShowDiagnostic { diagnostic: Diagnostic::warning() .with_message("already exported") .with_labels(vec![ Label::primary(aspan.source_id(), aspan) .with_message("duplicate export occurs here"), Label::secondary( prev_span.source_id(), prev_span.clone(), ) .with_message("function was first exported here"), ]), }); } } } } TopLevel::Attribute(Attribute::Removed(span, mut removed)) => { for (name, description) in removed.drain(..) { if let Some((prev_span, _)) = module.removed.get(&name.to_local()) { errs.error(ParserError::ShowDiagnostic { diagnostic: Diagnostic::warning() .with_message("already marked as removed") .with_labels(vec![ Label::primary(span.source_id(), span) .with_message("duplicate entry occurs here"), Label::secondary(prev_span.source_id(), prev_span.clone()) .with_message("function was marked here"), ]), }); } else { module.removed.insert(name.to_local(), (span, description)); } } } TopLevel::Attribute(Attribute::Type(ty)) => { let arity = ty.params.len(); let type_name = ResolvedFunctionName { span: ty.name.span.clone(), id: nid.next(), module: module.name.clone(), function: ty.name.clone(), arity, }; match module.types.get(&type_name.to_local()) { None => { module.types.insert(type_name.to_local(), ty); } Some(TypeDef { span: ref prev_span, .. }) => { errs.error(ParserError::ShowDiagnostic { diagnostic: Diagnostic::warning() .with_message("type is already defined") .with_labels(vec![ Label::primary(ty.span.source_id(), ty.span) .with_message("redefinition occurs here"), Label::secondary(prev_span.source_id(), prev_span.clone()) .with_message("type was first defined here"), ]), }); } } } TopLevel::Attribute(Attribute::ExportType(aspan, mut exports)) => { for export in exports.drain(..) { match module.exported_types.get(&export.to_local()) { None => { module.exported_types.insert(export.to_local()); } Some(LocalFunctionName { span: ref prev_span, .. }) => { errs.error(ParserError::ShowDiagnostic { diagnostic: Diagnostic::warning() .with_message("type already exported") .with_labels(vec![ Label::primary(aspan.source_id(), aspan) .with_message("duplicate export occurs here"), Label::secondary( prev_span.source_id(), prev_span.clone(), ) .with_message("type was first exported here"), ]), }); } } } } TopLevel::Attribute(Attribute::Behaviour(aspan, b_module)) => { match module.behaviours.get(&b_module) { None => { module.behaviours.insert(b_module); } Some(Ident { span: ref prev_span, .. }) => { errs.error(ParserError::ShowDiagnostic { diagnostic: Diagnostic::warning() .with_message("duplicate behaviour declaration") .with_labels(vec![ Label::primary(aspan.source_id(), aspan) .with_message("duplicate declaration occurs here"), Label::secondary(prev_span.source_id(), prev_span.clone()) .with_message("first declaration occurs here"), ]), }); } } } TopLevel::Attribute(Attribute::Callback(callback)) => { let first_sig = callback.sigs.first().unwrap(); let arity = first_sig.params.len(); // Verify that all clauses match if callback.sigs.len() > 1 { for TypeSig { span: ref sigspan, ref params, .. } in &callback.sigs[1..] { if params.len() != arity { errs.error(ParserError::ShowDiagnostic { diagnostic: Diagnostic::error() .with_message("mismatched arity") .with_labels(vec![ Label::primary(sigspan.source_id(), sigspan.clone()) .with_message(format!( "expected arity of {}", arity )), Label::secondary( first_sig.span.source_id(), first_sig.span.clone(), ) .with_message( "expected arity was derived from this clause", ), ]), }); } } } // Check for redefinition let cb_name = ResolvedFunctionName { span: callback.span.clone(), id: nid.next(), module: module.name.clone(), function: callback.function.clone(), arity, }; match module.callbacks.get(&cb_name.to_local()) { None => { module.callbacks.insert(cb_name.to_local(), callback); continue; } Some(ref a @ Callback { //span: ref prev_span, .. }) => { errs.error(ParserError::ShowDiagnostic { diagnostic: Diagnostic::error() .with_message("cannot redefine callback") .with_labels(vec![ Label::primary(callback.span.source_id(), callback.span) .with_message("redefinition occurs here"), Label::secondary(a.span.source_id(), a.span.clone()) .with_message("callback first defined here") ]), }); } } } TopLevel::Attribute(Attribute::Spec(typespec)) => { let first_sig = typespec.sigs.first().unwrap(); let arity = first_sig.params.len(); // Verify that all clauses match if typespec.sigs.len() > 1 { for TypeSig { span: ref sigspan, ref params, .. } in &typespec.sigs[1..] { if params.len() != arity { errs.error(ParserError::ShowDiagnostic { diagnostic: Diagnostic::error() .with_message("mismatched arity") .with_labels(vec![ Label::primary(sigspan.source_id(), sigspan.clone()) .with_message(format!( "expected arity of {}", arity )), Label::secondary( first_sig.span.source_id(), first_sig.span.clone(), ) .with_message( "expected arity was derived from this clause", ), ]), }); } } } // Check for redefinition let spec_name = ResolvedFunctionName { span: typespec.span.clone(), id: nid.next(), module: module.name.clone(), function: typespec.function.clone(), arity, }; match specs.get(&spec_name) { None => { specs.insert(spec_name.clone(), typespec); } Some(TypeSpec { span: ref prev_span, .. }) => { errs.error(ParserError::ShowDiagnostic { diagnostic: Diagnostic::error() .with_message("spec already defined") .with_labels(vec![ Label::primary(typespec.span.source_id(), typespec.span) .with_message("redefinition occurs here"), Label::secondary(prev_span.source_id(), prev_span.clone()) .with_message("spec first defined here"), ]), }); } } } TopLevel::Attribute(Attribute::Compile(_, compile)) => match module.compile { None => { let (opts, mut validation_errs) = CompileOptions::from_expr(&module.name, &compile); module.compile = Some(opts); for diagnostic in validation_errs.drain(..) { errs.error(ParserError::ShowDiagnostic { diagnostic }); } continue; } Some(ref mut opts) => { if let Err(mut validation_errs) = opts.merge_from_expr(&module.name, &compile) { for diagnostic in validation_errs.drain(..) { errs.error(ParserError::ShowDiagnostic { diagnostic }); } } } }, TopLevel::Attribute(Attribute::Deprecation(mut deprecations)) => { for deprecation in deprecations.drain(..) { match deprecation { Deprecation::Module { span: ref dspan, .. } => match module.deprecation { None => { module.deprecation = Some(deprecation); } Some(Deprecation::Module { span: ref orig_span, .. }) => { errs.error(ParserError::ShowDiagnostic { diagnostic: Diagnostic::warning() .with_message("redundant deprecation") .with_labels(vec![ Label::primary(dspan.source_id(), dspan.clone()) .with_message("this module is already deprecated by a previous declaration"), Label::secondary(orig_span.source_id(), orig_span.clone()) .with_message("deprecation first declared here") ]), }); } Some(Deprecation::Function { .. }) => unreachable!(), }, Deprecation::Function { span: ref fspan, .. } => { if let Some(Deprecation::Module { span: ref mspan, .. }) = module.deprecation { errs.error(ParserError::ShowDiagnostic { diagnostic: Diagnostic::warning() .with_message("redundant deprecation") .with_labels(vec![ Label::primary(fspan.source_id(), *fspan) .with_message("module is deprecated, so deprecating functions is redundant"), Label::secondary(mspan.source_id(), mspan.clone()) .with_message("module deprecation occurs here") ]), }); continue; } match module.deprecations.get(&deprecation) { None => { module.deprecations.insert(deprecation); } Some(Deprecation::Function { span: ref prev_span, .. }) => { errs.error(ParserError::ShowDiagnostic { diagnostic: Diagnostic::warning() .with_message("redundant deprecation") .with_labels(vec![ Label::primary(fspan.source_id(), *fspan) .with_message("this function is already deprecated by a previous declaration"), Label::secondary(prev_span.source_id(), prev_span.clone()) .with_message("deprecation first declared here") ]) }); } Some(Deprecation::Module { .. }) => unreachable!(), } } } } } TopLevel::Attribute(Attribute::Custom(attr)) => { match attr.name.name.as_str().get() { "module" => { errs.error(ParserError::ShowDiagnostic { diagnostic: Diagnostic::error() .with_message("multiple module declarations") .with_labels(vec![ Label::primary(attr.span.source_id(), attr.span.clone()) .with_message("invalid declaration occurs here"), Label::secondary( module.name.span.source_id(), module.name.span.clone(), ) .with_message("module first declared here"), ]), }); continue; } "optional_callbacks" => { //if let Some(callback) = module.callbacks.get_mut() continue; } "dialyzer" => { // Drop dialyzer attributes as they are unused continue; } _ => (), } match module.attributes.get(&attr.name) { None => { module.attributes.insert(attr.name.clone(), attr); } Some(UserAttribute { span: ref prev_span, .. }) => { errs.error(ParserError::ShowDiagnostic { diagnostic: Diagnostic::warning() .with_message("redefined attribute") .with_labels(vec![ Label::primary(attr.span.source_id(), attr.span.clone()) .with_message("redefinition occurs here"), Label::secondary(prev_span.source_id(), prev_span.clone()) .with_message("previously defined here"), ]), }); module.attributes.insert(attr.name.clone(), attr); } } } TopLevel::Record(mut record) => { let name = record.name.name.clone(); match module.records.get(&name) { None => { // FIXME: Remove the set when hashmap gets api // for getting keys. let mut fields = HashSet::::new(); let mut field_idx_map = HashMap::::new(); for (idx, field) in record.fields.iter_mut().enumerate() { if field.value.is_none() { field.value = Some(atom!(nid, undefined)); } if let Some(prev) = fields.get(&field.name) { errs.error(ParserError::ShowDiagnostic { diagnostic: Diagnostic::error() .with_message("duplicate field in record") .with_labels(vec![ Label::primary( field.name.span.source_id(), field.name.span, ) .with_message("duplicate field occurs here"), Label::secondary(prev.span.source_id(), prev.span) .with_message("previous field"), ]), }); } fields.insert(field.name); field_idx_map.insert(field.name, idx); } module.records.insert( name, DefinedRecord { record, field_idx_map, }, ); } Some(prev) => { errs.error(ParserError::ShowDiagnostic { diagnostic: Diagnostic::error() .with_message("record already defined") .with_labels(vec![ Label::primary(record.span.source_id(), record.span) .with_message("duplicate definition occurs here"), Label::secondary( prev.record.span.source_id(), prev.record.span, ) .with_message("previously defined here"), ]), }); } } } TopLevel::Function(mut function @ NamedFunction { .. }) => { let name = &function.name; let resolved_name = ResolvedFunctionName { span: name.span(), id: nid.next(), module: module.name.clone(), function: name.atom(), arity: function.arity, }; let warn_missing_specs = module .compile .as_ref() .map(|c| c.warn_missing_spec) .unwrap_or(false); function.spec = match specs.get(&resolved_name) { None if warn_missing_specs => { errs.error(ParserError::ShowDiagnostic { diagnostic: Diagnostic::warning() .with_message("missing function spec") .with_labels(vec![Label::primary( function.span.source_id(), function.span.clone(), ) .with_message("expected type spec for this function")]), }); None } None => None, Some(spec) => Some(spec.clone()), }; match module.functions.entry(resolved_name.to_local()) { Entry::Vacant(f) => { f.insert(function); } Entry::Occupied(initial_def) => { let def = initial_def.into_mut(); errs.error(ParserError::ShowDiagnostic { diagnostic: Diagnostic::error() .with_message( "clauses from the same function should be grouped together", ) .with_labels(vec![ Label::primary( function.span.source_id(), function.span.clone(), ) .with_message("found more clauses here"), Label::secondary(def.span.source_id(), def.span.clone()) .with_message("function is first defined here"), ]), }); def.clauses.append(&mut function.clauses); } } } } } // Ensure internal pseudo-locals are defined module.define_pseudolocals(nid); // Auto imports module.add_auto_imports(nid); // Verify on_load function exists if let Some(ref on_load_name) = module.on_load { if !module.functions.contains_key(on_load_name) { errs.error(ParserError::ShowDiagnostic { diagnostic: Diagnostic::error() .with_message("invalid on_load function") .with_labels(vec![Label::primary( on_load_name.span.source_id(), on_load_name.span.clone(), ) .with_message("this function is not defined in this module")]), }); } } // Check for orphaned type specs for (spec_name, spec) in &specs { if !module.functions.contains_key(&spec_name.to_local()) { errs.warning(ParserError::ShowDiagnostic { diagnostic: Diagnostic::warning() .with_message("type spec for undefined function") .with_labels(vec![Label::primary( spec.span.source_id(), spec.span.clone(), ) .with_message("this type spec has no corresponding function definition")]), }); } } module } fn add_auto_imports(&mut self, nid: &mut NodeIdGenerator) { macro_rules! auto_imports { ($($m:ident : $f:ident / $a:expr),*) => { [ $( ResolvedFunctionName { span: self.name.span, id: nid.next(), module: Ident::from_str(stringify!($m)), function: Ident::from_str(stringify!($f)), arity: $a, }, )* ] } } let autos = auto_imports! { erlang:abs/1, erlang:apply/2, erlang:apply/3, erlang:atom_to_binary/2, erlang:atom_to_list/1, erlang:binary_part/2, erlang:binary_part/3, erlang:binary_to_atom/2, erlang:binary_to_existing_atom/2, erlang:binary_to_float/1, erlang:binary_to_integer/1, erlang:binary_to_integer/2, erlang:binary_to_list/1, erlang:binary_to_list/3, erlang:binary_to_term/1, erlang:binary_to_term/2, erlang:bit_size/1, erlang:bitstring_to_list/1, erlang:byte_size/1, erlang:ceil/1, erlang:check_old_code/1, erlang:check_process_code/2, erlang:check_process_code/3, erlang:date/0, erlang:delete_module/1, erlang:demonitor/1, erlang:demonitor/2, erlang:disconnect_node/1, erlang:element/2, erlang:erase/0, erlang:erase/1, erlang:error/1, erlang:error/2, erlang:exit/1, erlang:exit/2, erlang:float/1, erlang:float_to_binary/1, erlang:float_to_binary/2, erlang:float_to_list/1, erlang:float_to_list/2, erlang:floor/1, erlang:garbage_collect/0, erlang:garbage_collect/1, erlang:garbage_collect/2, erlang:get/0, erlang:get/1, erlang:get_keys/0, erlang:get_keys/1, erlang:group_leader/0, erlang:group_leader/2, erlang:halt/0, erlang:halt/1, erlang:halt/2, erlang:hd/1, erlang:integer_to_binary/1, erlang:integer_to_binary/2, erlang:integer_to_list/1, erlang:integer_to_list/2, erlang:iolist_size/1, erlang:iolist_to_binary/1, erlang:iolist_to_iovec/1, erlang:is_alive/0, erlang:is_atom/1, erlang:is_binary/1, erlang:is_bitstring/1, erlang:is_boolean/1, erlang:is_float/1, erlang:is_function/1, erlang:is_function/2, erlang:is_integer/1, erlang:is_list/1, erlang:is_map/1, erlang:is_map_key/2, erlang:is_number/1, erlang:is_pid/1, erlang:is_port/1, erlang:is_process_alive/1, erlang:is_record/2, erlang:is_record/3, erlang:is_reference/1, erlang:is_tuple/1, erlang:length/1, erlang:link/1, erlang:list_to_atom/1, erlang:list_to_binary/1, erlang:list_to_bitstring/1, erlang:list_to_existing_atom/1, erlang:list_to_float/1, erlang:list_to_integer/1, erlang:list_to_integer/2, erlang:list_to_pid/1, erlang:list_to_port/1, erlang:list_to_ref/1, erlang:list_to_tuple/1, erlang:load_module/2, erlang:make_ref/0, erlang:map_get/2, erlang:map_size/1, erlang:max/2, erlang:min/2, erlang:module_loaded/1, erlang:monitor/2, erlang:monitor_node/2, erlang:node/0, erlang:node/1, erlang:nodes/0, erlang:nodes/1, erlang:now/0, erlang:open_port/2, erlang:pid_to_list/1, erlang:port_close/1, erlang:port_command/2, erlang:port_command/3, erlang:port_connect/2, erlang:port_control/3, erlang:port_to_list/1, erlang:pre_loaded/0, erlang:process_flag/2, erlang:process_flag/3, erlang:process_info/1, erlang:process_info/2, erlang:processes/0, erlang:purge_module/1, erlang:put/2, erlang:ref_to_list/1, erlang:register/2, erlang:registered/0, erlang:round/1, erlang:setelement/3, erlang:self/0, erlang:size/1, erlang:spawn/1, erlang:spawn/2, erlang:spawn/3, erlang:spawn/4, erlang:spawn_link/1, erlang:spawn_link/2, erlang:spawn_link/3, erlang:spawn_link/4, erlang:spawn_monitor/1, erlang:spawn_monitor/3, erlang:spawn_opt/2, erlang:spawn_opt/3, erlang:spawn_opt/4, erlang:spawn_opt/5, erlang:split_binary/2, erlang:statistics/1, erlang:term_to_binary/1, erlang:term_to_binary/2, erlang:throw/1, erlang:time/0, erlang:tl/1, erlang:trunc/1, erlang:tuple_size/1, erlang:tuple_to_list/1, erlang:unlink/1, erlang:unregister/1, erlang:whereis/1 }; if let Some(compile) = self.compile.as_ref() { if compile.no_auto_import { return; } for fun in autos.iter() { if !compile.no_auto_imports.contains(fun) { self.imports.insert(fun.to_local(), fun.clone()); } } } else { for fun in autos.iter() { self.imports.insert(fun.to_local(), fun.clone()); } } } // Every module in Erlang has some functions implicitly defined for internal use: // // * `module_info/0` (exported) // * `module_info/1` (exported) // * `record_info/2` // * `behaviour_info/1` (optional) fn define_pseudolocals(&mut self, nid: &mut NodeIdGenerator) { let mod_info_0 = fun!(nid, module_info () -> apply!(nid, remote!(nid, erlang, get_module_info), Expr::Literal(Literal::Atom(nid.next(), self.name.clone()))) ); let mod_info_1 = fun!(nid, module_info (Key) -> apply!(nid, remote!(nid, erlang, get_module_info), Expr::Literal(Literal::Atom(nid.next(), self.name.clone())), var!(nid, Key)) ); self.define_function(mod_info_0); self.define_function(mod_info_1); if self.callbacks.len() > 0 { let callbacks = self.callbacks.iter().fold(nil!(nid), |acc, (cbname, cb)| { if cb.optional { acc } else { cons!( nid, tuple!( nid, atom_from_sym!(nid, cbname.function.name.clone()), int!(nid, (cbname.arity as i64).into()) ), acc ) } }); let opt_callbacks = self.callbacks.iter().fold(nil!(nid), |acc, (cbname, cb)| { if cb.optional { cons!( nid, tuple!( nid, atom_from_sym!(nid, cbname.function.name.clone()), int!(nid, (cbname.arity as i64).into()) ), acc ) } else { acc } }); let behaviour_info_1 = fun!(nid, behaviour_info (atom!(nid, callbacks)) -> callbacks; (atom!(nid, optional_callbacks)) -> opt_callbacks); self.define_function(behaviour_info_1); } } fn define_function(&mut self, f: NamedFunction) { let name = ResolvedFunctionName { span: f.span.clone(), id: f.id, module: self.name.clone(), function: f.name.atom(), arity: f.arity, }; self.functions.insert(name.to_local(), f); } } impl PartialEq for Module { fn eq(&self, other: &Module) -> bool { if self.name != other.name { return false; } if self.vsn != other.vsn { return false; } if self.on_load != other.on_load { return false; } if self.imports != other.imports { return false; } if self.exports != other.exports { return false; } if self.types != other.types { return false; } if self.exported_types != other.exported_types { return false; } if self.behaviours != other.behaviours { return false; } if self.callbacks != other.callbacks { return false; } if self.records != other.records { return false; } if self.attributes != other.attributes { return false; } if self.functions != other.functions { return false; } true } } /// This structure holds all module-specific compiler options /// and configuration; it is passed through all phases of /// compilation and is a superset of options in CompilerSettings /// where applicable #[derive(Debug, Clone)] pub struct CompileOptions { // Same as erlc, prints informational warnings about // binary matching optimizations pub compile_info: HashMap, // Used to override the filename used in errors/warnings pub file: Option, pub verbose: bool, pub report_errors: bool, pub report_warnings: bool, // Treats all warnings as errors pub warnings_as_errors: bool, // Disables warnings pub no_warn: bool, // Exports all functions pub export_all: bool, // Prevents auto importing any functions pub no_auto_import: bool, // Prevents auto importing the specified functions pub no_auto_imports: HashSet, // Warns if export_all is used pub warn_export_all: bool, // Warns when exported variables are used pub warn_export_vars: bool, // Warns when variables are shadowed pub warn_shadow_vars: bool, // Warns when a function is unused pub warn_unused_function: bool, // Disables the unused function warning for the specified functions pub no_warn_unused_functions: HashSet, // Warns about unused imports pub warn_unused_import: bool, // Warns about unused variables pub warn_unused_var: bool, // Warns about unused records pub warn_unused_record: bool, pub warn_untyped_record: bool, pub warn_unused_type: bool, pub warn_removed: bool, pub warn_nif_inline: bool, pub warn_bif_clash: bool, // Warns about missing type specs pub warn_missing_spec: bool, pub warn_missing_spec_all: bool, pub warn_deprecated_function: bool, pub warn_deprecated_type: bool, pub warn_obsolete_guard: bool, pub inline: bool, // Inlines the given functions pub inline_functions: HashSet, } impl Default for CompileOptions { fn default() -> Self { CompileOptions { compile_info: HashMap::new(), file: None, verbose: true, report_errors: true, report_warnings: true, warnings_as_errors: false, no_warn: false, export_all: false, no_auto_import: false, no_auto_imports: HashSet::new(), inline: false, inline_functions: HashSet::new(), // Warning toggles warn_export_all: true, warn_export_vars: true, warn_shadow_vars: true, warn_unused_function: true, no_warn_unused_functions: HashSet::new(), warn_unused_import: true, warn_unused_var: true, warn_unused_record: true, warn_untyped_record: false, warn_unused_type: true, warn_removed: true, warn_nif_inline: true, warn_bif_clash: true, warn_missing_spec: false, warn_missing_spec_all: false, warn_deprecated_function: true, warn_deprecated_type: true, warn_obsolete_guard: true, } } } impl CompileOptions { pub fn from_expr(module: &Ident, expr: &Expr) -> (Self, Vec) { let mut opts = CompileOptions::default(); match opts.merge_from_expr(module, expr) { Ok(_) => (opts, Vec::new()), Err(errs) => (opts, errs), } } pub fn merge_from_expr(&mut self, module: &Ident, expr: &Expr) -> Result<(), Vec> { self.set_option(module, expr) } fn set_option(&mut self, module: &Ident, expr: &Expr) -> Result<(), Vec> { let mut diagnostics = Vec::new(); match expr { // e.g. -compile(export_all). &Expr::Literal(Literal::Atom(id, ref option_name)) => { match option_name.as_str().get() { "no_native" => (), // Disables hipe compilation, not relevant for us "inline" => self.inline = true, "export_all" => self.export_all = true, "no_auto_import" => self.no_auto_import = true, "report_errors" => self.report_errors = true, "report_warnings" => self.report_errors = true, "verbose" => self.verbose = true, "inline_list_funcs" => { let funs = [ ("lists", "all", 2), ("lists", "any", 2), ("lists", "foreach", 2), ("lists", "map", 2), ("lists", "flatmap", 2), ("lists", "filter", 2), ("lists", "foldl", 3), ("lists", "foldr", 3), ("lists", "mapfoldl", 3), ("lists", "mapfoldr", 3), ]; for (m, f, a) in funs.iter() { self.inline_functions.insert(ResolvedFunctionName { span: option_name.span, id: id, module: Ident::from_str(m), function: Ident::from_str(f), arity: *a, }); } } // Warning toggles "warn_export_all" => self.warn_export_all = true, "nowarn_export_all" => self.warn_export_all = false, "warn_shadow_vars" => self.warn_shadow_vars = true, "nowarn_shadow_vars" => self.warn_shadow_vars = false, "warn_unused_function" => self.warn_unused_function = true, "nowarn_unused_function" => self.warn_unused_function = false, "warn_unused_import" => self.warn_unused_import = true, "nowarn_unused_import" => self.warn_unused_import = false, "warn_unused_type" => self.warn_unused_type = true, "nowarn_unused_type" => self.warn_unused_type = false, "warn_export_vars" => self.warn_export_vars = true, "nowarn_export_vars" => self.warn_export_vars = false, "warn_unused_vars" => self.warn_unused_var = true, "nowarn_unused_vars" => self.warn_unused_var = false, "warn_bif_clash" => self.warn_bif_clash = true, "nowarn_bif_clash" => self.warn_bif_clash = false, "warn_unused_record" => self.warn_unused_record = true, "nowarn_unused_record" => self.warn_unused_record = false, "warn_deprecated_function" => self.warn_deprecated_function = true, "nowarn_deprecated_function" => self.warn_deprecated_function = false, "warn_deprecated_type" => self.warn_deprecated_type = true, "nowarn_deprecated_type" => self.warn_deprecated_type = false, "warn_obsolete_guard" => self.warn_obsolete_guard = true, "nowarn_obsolete_guard" => self.warn_obsolete_guard = false, "warn_untyped_record" => self.warn_untyped_record = true, "nowarn_untyped_record" => self.warn_untyped_record = false, "warn_missing_spec" => self.warn_missing_spec = true, "nowarn_missing_spec" => self.warn_missing_spec = false, "warn_missing_spec_all" => self.warn_missing_spec_all = true, "nowarn_missing_spec_all" => self.warn_missing_spec_all = false, "warn_removed" => self.warn_removed = true, "nowarn_removed" => self.warn_removed = false, "warn_nif_inline" => self.warn_nif_inline = true, "nowarn_nif_inline" => self.warn_nif_inline = false, _name => { diagnostics.push( Diagnostic::warning() .with_message("invalid compile option") .with_labels(vec![Label::primary( option_name.span.source_id(), option_name.span, ) .with_message( "this option is either unsupported or unrecognized", )]), ); } } } // e.g. -compile([export_all, nowarn_unused_function]). &Expr::Cons(Cons { ref head, ref tail, .. }) => self.compiler_opts_from_list(&mut diagnostics, module, to_list(head, tail)), // e.g. -compile({nowarn_unused_function, [some_fun/0]}). &Expr::Tuple(Tuple { ref elements, .. }) if elements.len() == 2 => { //if let Some((head, tail)) = elements.split_first() { if let &Expr::Literal(Literal::Atom(_id, ref option_name)) = &elements[0] { let list = to_list_simple(&elements[1]); match option_name.as_str().get() { "no_auto_import" => { self.no_auto_imports(&mut diagnostics, module, &list); } "nowarn_unused_function" => { self.no_warn_unused_functions(&mut diagnostics, module, &list); } "inline" => { self.inline_functions(&mut diagnostics, module, &list); } "hipe" => { // Should we warn about this? I'm inclined to think // not, since we want to ignore warning spam. } _name => { diagnostics.push( Diagnostic::warning() .with_message("invalid compile option") .with_labels(vec![Label::primary( option_name.span.source_id(), option_name.span, ) .with_message( "this option is either unsupported or unrecognized", )]), ); } } } //} } term => { let term_span = term.span(); diagnostics.push( Diagnostic::warning() .with_message("invalid compile option") .with_labels(vec![Label::primary(term_span.source_id(), term_span) .with_message( "unexpected expression: expected atom, list, or tuple", )]), ); } } if diagnostics.len() > 0 { return Err(diagnostics); } Ok(()) } fn compiler_opts_from_list( &mut self, diagnostics: &mut Vec, module: &Ident, options: Vec, ) { for option in options { match self.set_option(module, &option) { Ok(_) => continue, Err(mut diags) => diagnostics.append(&mut diags), } } } fn no_auto_imports( &mut self, diagnostics: &mut Vec, module: &Ident, imports: &[Expr], ) { for import in imports { match import { Expr::FunctionName(FunctionName::PartiallyResolved(name)) => { self.no_auto_imports.insert(name.resolve(module.clone())); } Expr::Tuple(tup) if tup.elements.len() == 2 => { match (&tup.elements[0], &tup.elements[1]) { ( Expr::Literal(Literal::Atom(_, name)), Expr::Literal(Literal::Integer(_, _, arity)), ) => { let local = PartiallyResolvedFunctionName { span: tup.span, id: tup.id, function: *name, arity: (*arity).to_usize().unwrap(), }; self.no_auto_imports.insert(local.resolve(*module)); continue; } _ => (), } } other => { let other_span = other.span(); diagnostics.push( Diagnostic::warning() .with_message("invalid compile option") .with_labels(vec![Label::primary(other_span.source_id(), other_span) .with_message( "expected function name/arity term for no_auto_imports", )]), ); } } } } fn no_warn_unused_functions( &mut self, diagnostics: &mut Vec, _module: &Ident, funs: &[Expr], ) { for fun in funs { match fun { Expr::FunctionName(FunctionName::PartiallyResolved(name)) => { self.no_warn_unused_functions.insert(name.to_local()); } other => { let other_span = other.span(); diagnostics.push( Diagnostic::warning() .with_message("invalid compile option") .with_labels(vec![Label::primary(other_span.source_id(), other_span) .with_message( "expected function name/arity term for no_warn_unused_functions", )]), ); } } } } fn inline_functions( &mut self, diagnostics: &mut Vec, module: &Ident, funs: &[Expr], ) { for fun in funs { match fun { Expr::FunctionName(FunctionName::PartiallyResolved(name)) => { self.inline_functions.insert(name.resolve(*module)); continue; } Expr::Tuple(tup) if tup.elements.len() == 2 => { match (&tup.elements[0], &tup.elements[1]) { ( Expr::Literal(Literal::Atom(_, name)), Expr::Literal(Literal::Integer(_, _, arity)), ) => { let local = PartiallyResolvedFunctionName { span: tup.span, id: tup.id, function: *name, arity: (*arity).to_usize().unwrap(), }; self.inline_functions.insert(local.resolve(*module)); continue; } _ => (), } } _ => (), } let fun_span = fun.span(); diagnostics.push( Diagnostic::warning() .with_message("invalid compile option") .with_labels(vec![Label::primary(fun_span.source_id(), fun_span) .with_message("expected function name/arity term for inline")]), ); } } } fn to_list_simple(mut expr: &Expr) -> Vec { let mut list = Vec::new(); loop { match expr { Expr::Cons(cons) => { list.push((*cons.head).clone()); expr = &cons.tail; } Expr::Nil(_) => { return list; } _ => { list.push(expr.clone()); return list; } } } } fn to_list(head: &Expr, tail: &Expr) -> Vec { let mut list = Vec::new(); match head { &Expr::Cons(Cons { head: ref head2, tail: ref tail2, .. }) => { let mut h = to_list(head2, tail2); list.append(&mut h); } expr => list.push(expr.clone()), } match tail { &Expr::Cons(Cons { head: ref head2, tail: ref tail2, .. }) => { let mut t = to_list(head2, tail2); list.append(&mut t); } &Expr::Nil(_) => (), expr => list.push(expr.clone()), } list } ================================================ FILE: libeir_syntax_erl/src/parser/ast/types.rs ================================================ use std::collections::HashSet; use lazy_static::lazy_static; use libeir_diagnostics::SourceSpan; use libeir_util_number::Integer; use super::{BinaryOp, UnaryOp}; use super::{Ident, Name, Symbol}; lazy_static! { pub static ref BUILTIN_TYPES: HashSet<(Symbol, usize)> = { let mut bts = HashSet::new(); bts.insert((Symbol::intern("any"), 0)); bts.insert((Symbol::intern("arity"), 0)); bts.insert((Symbol::intern("atom"), 0)); bts.insert((Symbol::intern("binary"), 0)); bts.insert((Symbol::intern("bitstring"), 0)); bts.insert((Symbol::intern("bool"), 0)); bts.insert((Symbol::intern("boolean"), 0)); bts.insert((Symbol::intern("byte"), 0)); bts.insert((Symbol::intern("char"), 0)); bts.insert((Symbol::intern("float"), 0)); bts.insert((Symbol::intern("function"), 0)); bts.insert((Symbol::intern("identifier"), 0)); bts.insert((Symbol::intern("integer"), 0)); bts.insert((Symbol::intern("iodata"), 0)); bts.insert((Symbol::intern("iolist"), 0)); bts.insert((Symbol::intern("list"), 0)); bts.insert((Symbol::intern("list"), 1)); bts.insert((Symbol::intern("map"), 0)); bts.insert((Symbol::intern("maybe_improper_list"), 0)); bts.insert((Symbol::intern("maybe_improper_list"), 2)); bts.insert((Symbol::intern("mfa"), 0)); bts.insert((Symbol::intern("module"), 0)); bts.insert((Symbol::intern("neg_integer"), 0)); bts.insert((Symbol::intern("nil"), 0)); bts.insert((Symbol::intern("no_return"), 0)); bts.insert((Symbol::intern("node"), 0)); bts.insert((Symbol::intern("non_neg_integer"), 0)); bts.insert((Symbol::intern("none"), 0)); bts.insert((Symbol::intern("nonempty_improper_list"), 2)); bts.insert((Symbol::intern("nonempty_list"), 0)); bts.insert((Symbol::intern("nonempty_list"), 1)); bts.insert((Symbol::intern("nonempty_maybe_improper_list"), 0)); bts.insert((Symbol::intern("nonempty_maybe_improper_list"), 2)); bts.insert((Symbol::intern("nonempty_string"), 0)); bts.insert((Symbol::intern("number"), 0)); bts.insert((Symbol::intern("pid"), 0)); bts.insert((Symbol::intern("port"), 0)); bts.insert((Symbol::intern("pos_integer"), 0)); bts.insert((Symbol::intern("reference"), 0)); bts.insert((Symbol::intern("string"), 0)); bts.insert((Symbol::intern("term"), 0)); bts.insert((Symbol::intern("timeout"), 0)); bts.insert((Symbol::intern("tuple"), 0)); bts }; } #[derive(Debug, Clone)] pub enum Type { Name(Name), Annotated { span: SourceSpan, name: Name, ty: Box, }, Union { span: SourceSpan, types: Vec, }, Range { span: SourceSpan, start: Box, end: Box, }, BinaryOp { span: SourceSpan, lhs: Box, op: BinaryOp, rhs: Box, }, UnaryOp { span: SourceSpan, op: UnaryOp, rhs: Box, }, Generic { span: SourceSpan, fun: Ident, params: Vec, }, Remote { span: SourceSpan, module: Ident, fun: Ident, args: Vec, }, Nil(SourceSpan), List(SourceSpan, Box), NonEmptyList(SourceSpan, Box), Map(SourceSpan, Vec), Tuple(SourceSpan, Vec), Record(SourceSpan, Ident, Vec), Binary(SourceSpan, Box, Box), Integer(SourceSpan, Integer), Char(SourceSpan, char), AnyFun { span: SourceSpan, ret: Option>, }, Fun { span: SourceSpan, params: Vec, ret: Box, }, KeyValuePair(SourceSpan, Box, Box), Field(SourceSpan, Ident, Box), } impl Type { pub fn union(span: SourceSpan, lhs: Type, rhs: Type) -> Self { let mut types = match lhs { Type::Union { types, .. } => types, ty => vec![ty], }; let mut rest = match rhs { Type::Union { types, .. } => types, ty => vec![ty], }; types.append(&mut rest); Type::Union { span, types } } pub fn is_builtin_type(&self) -> bool { match self { &Type::Name(Name::Atom(Ident { ref name, .. })) => BUILTIN_TYPES.contains(&(*name, 0)), &Type::Annotated { ref name, .. } => match name { Name::Atom(v) => BUILTIN_TYPES.contains(&(v.name, 0)), Name::Var(v) => BUILTIN_TYPES.contains(&(v.name, 0)), }, &Type::Generic { ref fun, ref params, .. } => BUILTIN_TYPES.contains(&(fun.name, params.len())), &Type::Nil(_) => true, &Type::List(_, _) => true, &Type::NonEmptyList(_, _) => true, &Type::Map(_, _) => true, &Type::Tuple(_, _) => true, &Type::Record(_, _, _) => true, &Type::Binary(_, _, _) => true, &Type::Integer(_, _) => true, &Type::Char(_, _) => true, &Type::AnyFun { .. } => true, &Type::Fun { .. } => true, &Type::KeyValuePair(_, _, _) => true, &Type::Field(_, _, _) => true, _ => false, } } } impl PartialEq for Type { fn eq(&self, other: &Type) -> bool { let left = std::mem::discriminant(self); let right = std::mem::discriminant(other); if left != right { return false; } match (self, other) { ( Type::Annotated { name: ref x1, ty: ref x2, .. }, Type::Annotated { name: ref y1, ty: ref y2, .. }, ) => (x1 == y1) && (x2 == y2), ( Type::Union { types: ref types1, .. }, Type::Union { types: ref types2, .. }, ) => types1 == types2, ( Type::Range { start: ref x1, end: ref x2, .. }, Type::Range { start: ref y1, end: ref y2, .. }, ) => (x1 == y1) && (x2 == y2), ( Type::BinaryOp { lhs: ref x1, op: ref x2, rhs: ref x3, .. }, Type::BinaryOp { lhs: ref y1, op: ref y2, rhs: ref y3, .. }, ) => (x1 == y1) && (x2 == y2) && (x3 == y3), ( Type::UnaryOp { op: ref x1, rhs: ref x2, .. }, Type::UnaryOp { op: ref y1, rhs: ref y2, .. }, ) => (x1 == y1) && (x2 == y2), ( Type::Generic { fun: ref x1, params: ref x2, .. }, Type::Generic { fun: ref y1, params: ref y2, .. }, ) => (x1 == y1) && (x2 == y2), ( Type::Remote { module: ref x1, fun: ref x2, args: ref x3, .. }, Type::Remote { module: ref y1, fun: ref y2, args: ref y3, .. }, ) => (x1 == y1) && (x2 == y2) && (x3 == y3), (Type::Nil(_), Type::Nil(_)) => true, (Type::List(_, ref x), Type::List(_, ref y)) => x == y, (Type::NonEmptyList(_, ref x), Type::List(_, ref y)) => x == y, (Type::Map(_, ref x), Type::Map(_, ref y)) => x == y, (Type::Tuple(_, ref x), Type::Tuple(_, ref y)) => x == y, (Type::Record(_, ref x1, ref x2), Type::Record(_, ref y1, ref y2)) => { (x1 == y1) && (x2 == y2) } (Type::Binary(_, ref m1, ref n1), Type::Binary(_, ref m2, ref n2)) => { (m1 == m2) && (n1 == n2) } (Type::Integer(_, x), Type::Integer(_, y)) => x == y, (Type::Char(_, x), Type::Char(_, y)) => x == y, (Type::AnyFun { ret: x, .. }, Type::AnyFun { ret: y, .. }) => x == y, ( Type::Fun { params: ref x1, ret: ref x2, .. }, Type::Fun { params: ref y1, ret: ref y2, .. }, ) => (x1 == y1) && (x2 == y2), (Type::KeyValuePair(_, ref x1, ref x2), Type::KeyValuePair(_, ref y1, ref y2)) => { (x1 == y1) && (x2 == y2) } (Type::Field(_, ref x1, ref x2), Type::Field(_, ref y1, ref y2)) => { (x1 == y1) && (x2 == y2) } _ => false, } } } ================================================ FILE: libeir_syntax_erl/src/parser/binary.rs ================================================ use snafu::Snafu; pub use libeir_ir::binary::{BinaryEntrySpecifier, Endianness}; use libeir_diagnostics::{SourceSpan, ToDiagnostic, Diagnostic, Label}; use super::ast::{BitType, BinaryElement, Expr, Literal}; use crate::lower::LowerError; #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] pub enum TypeName { Integer, Float, Bytes, Bits, Utf8, Utf16, Utf32, } impl std::fmt::Display for TypeName { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { match self { TypeName::Integer => write!(f, "integer"), TypeName::Float => write!(f, "float"), TypeName::Bytes => write!(f, "binary"), TypeName::Bits => write!(f, "bitstring"), TypeName::Utf8 => write!(f, "utf8"), TypeName::Utf16 => write!(f, "utf16"), TypeName::Utf32 => write!(f, "utf32"), } } } pub fn default_specifier() -> BinaryEntrySpecifier { BinaryEntrySpecifier::Integer { signed: false, endianness: Endianness::Big, unit: 1, } } #[derive(Debug, Snafu)] pub enum SpecifierError { #[snafu(display("unknown specifier in binary entry"))] BinaryUnknownSpecifier { span: SourceSpan, }, #[snafu(display("conflicting specifiers in binary entry"))] BinaryConflictingSpecifier { new: SourceSpan, old: SourceSpan, }, #[snafu(display("invalid specifier for {} in binary entry", typ))] BinaryInvalidSpecifier { span: SourceSpan, typ: TypeName, }, #[snafu(display("size is not allowed for {}", typ))] BinarySizeNotAllowed { span: SourceSpan, typ: TypeName, }, } impl ToDiagnostic for SpecifierError { fn to_diagnostic(&self) -> Diagnostic { let msg = self.to_string(); match self { SpecifierError::BinaryUnknownSpecifier { span } => Diagnostic::error() .with_message(msg) .with_labels(vec![ Label::primary(span.source_id(), *span).with_message("specifier is not known") ]), SpecifierError::BinaryConflictingSpecifier { new, old } => { Diagnostic::error().with_message(msg).with_labels(vec![ Label::primary(new.source_id(), *new).with_message("specifier 1"), Label::primary(old.source_id(), *old).with_message("specifier 2"), ]) } SpecifierError::BinaryInvalidSpecifier { span, typ } => Diagnostic::error() .with_message(msg) .with_labels(vec![Label::primary(span.source_id(), *span) .with_message(format!("specifier is not valid for {} entries", typ))]), SpecifierError::BinarySizeNotAllowed { span, typ } => Diagnostic::error() .with_message(msg) .with_labels(vec![Label::primary(span.source_id(), *span) .with_message(format!("size is not allowed for {} entries", typ))]), } } } macro_rules! try_specifier { ($field:expr, $entry:expr, $spec:expr) => {{ let spec = $spec; match $field { Some((f, _)) if f == spec => (), Some((_, old)) => { return Err(SpecifierError::BinaryConflictingSpecifier { old, new: $entry.span(), }); } None => $field = Some((spec, $entry.span())), } }}; } macro_rules! test_none { ($field:expr, $typ:expr) => {{ if let Some((_, span)) = $field { return Err(SpecifierError::BinaryInvalidSpecifier { span: span, typ: $typ, }); } }}; } pub fn specifier_from_parsed(parsed: &[BitType], has_size: bool) -> Result { let mut raw_typ = None; let mut signed = None; let mut endianness = None; let mut unit = None; for entry in parsed { match entry { // Types BitType::Name(_id, _span, ident) if ident.as_str() == "integer" => { try_specifier!(raw_typ, entry, TypeName::Integer) } BitType::Name(_id, _span, ident) if ident.as_str() == "float" => { try_specifier!(raw_typ, entry, TypeName::Float) } BitType::Name(_id, _span, ident) if ident.as_str() == "binary" => { try_specifier!(raw_typ, entry, TypeName::Bytes) } BitType::Name(_id, _span, ident) if ident.as_str() == "bytes" => { try_specifier!(raw_typ, entry, TypeName::Bytes) } BitType::Name(_id, _span, ident) if ident.as_str() == "bitstring" => { try_specifier!(raw_typ, entry, TypeName::Bits) } BitType::Name(_id, _span, ident) if ident.as_str() == "bits" => { try_specifier!(raw_typ, entry, TypeName::Bits) } BitType::Name(_id, _span, ident) if ident.as_str() == "utf8" => { try_specifier!(raw_typ, entry, TypeName::Utf8) } BitType::Name(_id, _span, ident) if ident.as_str() == "utf16" => { try_specifier!(raw_typ, entry, TypeName::Utf16) } BitType::Name(_id, _span, ident) if ident.as_str() == "utf32" => { try_specifier!(raw_typ, entry, TypeName::Utf32) } // Signed BitType::Name(_id, _span, ident) if ident.as_str() == "signed" => { try_specifier!(signed, entry, true) } BitType::Name(_id, _span, ident) if ident.as_str() == "unsigned" => { try_specifier!(signed, entry, false) } // Endianness BitType::Name(_id, _span, ident) if ident.as_str() == "big" => { try_specifier!(endianness, entry, Endianness::Big) } BitType::Name(_id, _span, ident) if ident.as_str() == "little" => { try_specifier!(endianness, entry, Endianness::Little) } BitType::Name(_id, _span, ident) if ident.as_str() == "native" => { try_specifier!(endianness, entry, Endianness::Native) } // Unit BitType::Sized(_id, _span, ident, num) if ident.as_str() == "unit" => { try_specifier!(unit, entry, *num) } entry => { return Err(SpecifierError::BinaryUnknownSpecifier { span: entry.span() }); } } } let typ = raw_typ.map(|(t, _)| t).unwrap_or(TypeName::Integer); let size_not_allowed_err = || Err(SpecifierError::BinarySizeNotAllowed { typ, span: raw_typ.unwrap().1, }); let spec = match typ { TypeName::Integer => { // Default is signed-big-unit:1 let signed = signed.map(|(t, _)| t).unwrap_or(false); let endianness = endianness.map(|(t, _)| t).unwrap_or(Endianness::Big); let unit = unit.map(|(t, _)| t).unwrap_or(1); BinaryEntrySpecifier::Integer { signed, endianness, unit, } } TypeName::Float => { // Default is big-unit:1 test_none!(signed, typ); let endianness = endianness.map(|(t, _)| t).unwrap_or(Endianness::Big); let unit = unit.map(|(t, _)| t).unwrap_or(1); BinaryEntrySpecifier::Float { endianness, unit } } TypeName::Bytes => { // Default is unit:8 test_none!(signed, typ); test_none!(endianness, typ); let unit = unit.map(|(t, _)| t).unwrap_or(8); BinaryEntrySpecifier::Bytes { unit } } TypeName::Bits => { // Default is unit:1 test_none!(signed, typ); test_none!(endianness, typ); let unit = unit.map(|(t, _)| t).unwrap_or(1); BinaryEntrySpecifier::Bits { unit } } TypeName::Utf8 => { test_none!(signed, typ); test_none!(endianness, typ); test_none!(unit, typ); if has_size { return size_not_allowed_err(); } BinaryEntrySpecifier::Utf8 } TypeName::Utf16 => { test_none!(signed, typ); let endianness = endianness.map(|(t, _)| t).unwrap_or(Endianness::Big); test_none!(unit, typ); if has_size { return size_not_allowed_err(); } BinaryEntrySpecifier::Utf16 { endianness } } TypeName::Utf32 => { test_none!(signed, typ); let endianness = endianness.map(|(t, _)| t).unwrap_or(Endianness::Big); test_none!(unit, typ); if has_size { return size_not_allowed_err(); } BinaryEntrySpecifier::Utf32 { endianness } } }; Ok(spec) } pub fn specifier_to_typename(specifier: &BinaryEntrySpecifier) -> TypeName { match specifier { BinaryEntrySpecifier::Integer { .. } => TypeName::Integer, BinaryEntrySpecifier::Float { .. } => TypeName::Float, BinaryEntrySpecifier::Bytes { .. } => TypeName::Bytes, BinaryEntrySpecifier::Bits { .. } => TypeName::Bits, BinaryEntrySpecifier::Utf8 => TypeName::Utf8, BinaryEntrySpecifier::Utf16 { .. } => TypeName::Utf16, BinaryEntrySpecifier::Utf32 { .. } => TypeName::Utf32, } } pub fn specifier_can_have_size(specifier: &BinaryEntrySpecifier) -> bool { match specifier { BinaryEntrySpecifier::Utf8 => false, BinaryEntrySpecifier::Utf16 { .. } => false, BinaryEntrySpecifier::Utf32 { .. } => false, _ => true, } } ================================================ FILE: libeir_syntax_erl/src/parser/errors.rs ================================================ use std::convert::From; use libeir_diagnostics::*; use libeir_util_parse::SourceError; use snafu::Snafu; use crate::lexer::Token; use crate::preprocessor::PreprocessorError; pub type ParseError = lalrpop_util::ParseError; #[derive(Debug, Snafu)] pub enum ParserError { #[snafu(display("{} occurred while reading {:?}", source, path))] RootFile { source: std::io::Error, path: std::path::PathBuf, }, #[snafu(visibility(pub), display("{}", source))] Preprocessor { source: PreprocessorError }, #[snafu(display("{}", source))] Source { source: SourceError }, #[snafu(display("{}", diagnostic.message))] ShowDiagnostic { diagnostic: Diagnostic }, #[snafu(display("invalid token"))] InvalidToken { location: SourceIndex }, #[snafu(display("unrecognized token"))] UnrecognizedToken { span: SourceSpan, expected: Vec, }, #[snafu(display("extra token"))] ExtraToken { span: SourceSpan }, #[snafu(display("unexpected eof"))] UnexpectedEOF { location: SourceIndex, expected: Vec, }, } impl From for ParserError { fn from(err: Diagnostic) -> Self { ParserError::ShowDiagnostic { diagnostic: err, } } } impl From for ParserError { fn from(err: ParseError) -> Self { use lalrpop_util::ParseError::*; match err { InvalidToken { location } => Self::InvalidToken { location }, UnrecognizedEOF { location, expected } => Self::UnexpectedEOF { location, expected }, UnrecognizedToken { token: (l, _, r), expected, } => Self::UnrecognizedToken { span: SourceSpan::new(l, r), expected, }, ExtraToken { token: (l, _, r) } => Self::ExtraToken { span: SourceSpan::new(l, r), }, User { .. } => panic!(), } } } impl ToDiagnostic for ParserError { fn to_diagnostic(&self) -> Diagnostic { match self { Self::RootFile { .. } => Diagnostic::error().with_message(self.to_string()), Self::ShowDiagnostic { diagnostic } => diagnostic.clone(), Self::Preprocessor { source } => source.to_diagnostic(), Self::Source { source } => source.to_diagnostic(), Self::UnrecognizedToken { ref span, ref expected, } => Diagnostic::error() .with_message("unrecognized token") .with_labels(vec![Label::primary(span.source_id(), *span) .with_message(format!("expected: {}", expected.join(", ")))]), Self::InvalidToken { location } => { let index = *location; Diagnostic::error() .with_message("unexpected token") .with_labels(vec![Label::primary( index.source_id(), SourceSpan::new(index, index), ) .with_message("did not expect this token")]) } Self::UnexpectedEOF { location, ref expected, } => { let index = *location; Diagnostic::error() .with_message("unexpected end of file") .with_labels(vec![Label::primary( index.source_id(), SourceSpan::new(index, index), ) .with_message(format!("expected: {}", expected.join(", ")))]) } Self::ExtraToken { span } => Diagnostic::error() .with_message("unexpected token") .with_labels(vec![Label::primary(span.source_id(), *span) .with_message("did not expect this token")]), } } } impl From for ParserError { fn from(source: SourceError) -> Self { Self::Source { source } } } impl From for ParserError { fn from(source: PreprocessorError) -> Self { Self::Preprocessor { source } } } ================================================ FILE: libeir_syntax_erl/src/parser/grammar.lalrpop ================================================ //-*- mode: rust -*- use libeir_diagnostics::*; use libeir_util_number::{Integer, ToPrimitive, Float}; use libeir_ir::binary::BinaryEntrySpecifier; use crate::parser::binary::specifier_from_parsed; use crate::lexer::{Token, DelayedSubstitution, Symbol, Ident}; use crate::preprocessor::PreprocessorError; use super::{ParserError, ParserErrorReceiver}; use super::ast::*; grammar<'a>( errs: &'a mut ParserErrorReceiver<'a>, nid: &mut NodeIdGenerator, ); // The following are _not_ non-terminals, but macros // which can be identified by the generic type parameter, // // Currently all of the macros expect the name of the corresponding // non-terminal to have a type of the same name, a macro can // be written to handle differing non-terminal/type combinations by // adding a second type parameter used only in the type signature // Semicolon-delimited with at least one element Semi: Vec = { ";")*> => { let mut v = v; v.push(e); v } }; // Comma-delimited with at least one element Comma: Vec = { ",")*> => { let mut v = v; v.push(e); v } }; // Comma-delimited with zero or more elements CommaOpt: Vec = { ",")*> => { let mut vals = vals; vals.extend(last); vals }, }; // Dash-delimited with at least one element Dash: Vec = { "-")*> => { let mut v = v; v.push(e); v } }; pub Module: Module = { "COMMENT"* "-" "module" "(" ")" "." "COMMENT"* => { let body = match body { None => Vec::new(), Some(body) => body, }; Module::new(errs, span!(l, r), nid, name, body) } }; ModuleBody: Vec = TopLevel+; TopLevel: TopLevel = { => TopLevel::Function(<>), => TopLevel::Record(<>), => TopLevel::Attribute(<>), }; // Top-level Functions FunctionDefinition: NamedFunction = { > "." =>? match NamedFunction::new(errs, span!(l, r), nid, clauses) { Ok(inner) => Ok(inner), Err(()) => Err(to_lalrpop_err!(())), }, }; FunctionHead: FunctionClause = { "(" > ")" "->" > => { FunctionClause::new(span!(l, r), Some(Name::Atom(a)), params, g, body) } }; FunctionClause: FunctionClause = { "(" > ")" "->" > => { FunctionClause::new(span!(l, r), a.map(Name::Var), params, g, body) } }; Guards: Vec = "when" ; BaseGuards: Vec = >; Guard: Guard = > => Guard { span: span!(l, r), conditions }; FunctionName: PartiallyResolvedFunctionName = { "/" => { PartiallyResolvedFunctionName { span: span!(l, r), id: nid.next(), function, arity, } } }; // Attributes AttributeDefinition: Attribute = { "-" "vsn" "(" ")" "." => Attribute::Vsn(span!(l, r), vsn), "-" "author" "(" ")" "." => Attribute::Author(span!(l, r), author), "-" "compile" "(" ")" "." => Attribute::Compile(span!(l, r), opts), "-" "import" "(" "," "[" > "]" ")" "." => Attribute::Import(span!(l, r), module, imports), "-" "export" "(" "[" > "]" ")" "." => Attribute::Export(span!(l, r), exports), "-" "export_type" "(" "[" > "]" ")" "." => Attribute::ExportType(span!(l, r), exports), "-" "behaviour" "(" ")" "." => Attribute::Behaviour(span!(l, r), module), "-" "on_load" "(" ")" "." => Attribute::OnLoad(span!(l, r), fun), TypeAttribute, TypeSpecAttribute, CallbackAttribute, DeprecatedAttribute, RemovedAttribute, UserAttribute, }; RecordDeclaration: Record = { "-" "record" "(" "," ")" "." => Record { span: span!(l, r), id: nid.next(), name, fields }, }; RemovedAttribute: Attribute = { "-" "removed" "(" "[" > "]" ")" "." => Attribute::Removed(span!(l, r), rs), }; Removed: (PartiallyResolvedFunctionName, Ident) = { "{" "," "," "}" => { let span = span!(l, r); let f = PartiallyResolvedFunctionName { span: span.clone(), id: nid.next(), function, arity, }; (f, descr) }, }; TypeAttribute: Attribute = { "-" "type" => { let mut def = def; def.span = span!(l, r); Attribute::Type(def) }, "-" "opaque" => { let mut def = def; def.span = span!(l, r); def.opaque = true; Attribute::Type(def) }, }; TypeSpecAttribute: Attribute = { "-" "spec" => { let mut spec = spec; spec.span = span!(l, r); Attribute::Spec(spec) } }; CallbackAttribute: Attribute = { "-" "callback" => { let callback = Callback { span: span!(l, r), optional: false, module: spec.module, function: spec.function, sigs: spec.sigs, }; Attribute::Callback(callback) }, "-" "optional_callback" => { let callback = Callback { span: span!(l, r), optional: true, module: spec.module, function: spec.function, sigs: spec.sigs, }; Attribute::Callback(callback) } }; DeprecatedAttribute: Attribute = { "-" "deprecated" "(" )?> ")" "." =>? { match a.as_str().get() { "module" => { Ok(Attribute::Deprecation(vec![ Deprecation::Module { span: span!(l, r), flag: flag.unwrap_or(DeprecatedFlag::Eventually), } ])) } other => { let span = span!(l, r); errs.error(PreprocessorError::ShowDiagnostic { diagnostic: Diagnostic::warning() .with_message("invalid deprecated attribute") .with_labels(vec![ Label::primary(span.source_id(), span) .with_message("expected 'module', '{module, Flag}', 'Function/Arity', or '{Function/Arity, Flag}'") ]) }.into()); Err(to_lalrpop_err!(())) } } }, "-" "deprecated" "(" ")" "." => Attribute::Deprecation(vec![d]), "-" "deprecated" "(" "[" > "]" ")" "." => Attribute::Deprecation(ds), }; Deprecation: Deprecation = { => Deprecation::Function { span: span!(l, r), function, flag: DeprecatedFlag::Eventually }, "{" "," "}" => Deprecation::Function { span: span!(l, r), function, flag }, "{" "," "," "}" => { let span = span!(l, r); let f = PartiallyResolvedFunctionName { span: span.clone(), id: nid.next(), function, arity, }; Deprecation::Function { span, function: f, flag } } }; DeprecatedFlag: DeprecatedFlag = { => DeprecatedFlag::Description(s), => { match flag.as_str().get() { "eventually" => DeprecatedFlag::Eventually, "next_version" => DeprecatedFlag::NextVersion, "next_major_release" => DeprecatedFlag::NextMajorRelease, other => { let span = span!(l, r); errs.warning(ParserError::ShowDiagnostic { diagnostic: Diagnostic::warning() .with_message("invalid deprecation flag") .with_labels(vec![ Label::primary(span.source_id(), span) .with_message(format!("expected one of 'eventually', 'next_version', or 'next_major_release', got '{}'", other)) ]), }); DeprecatedFlag::Eventually } } }, }; UserAttribute: Attribute = { "-" "(" ")" "." => Attribute::Custom(UserAttribute { span: span!(l, r), name, value }), }; TypedRecordFields: Vec = { "{" > "}" }; TypedRecordField: RecordField = { )?> )?> => RecordField { span: span!(l, r), id: nid.next(), name: name, value, ty }, }; // Type Specifications TypeDef: TypeDef = { "(" ")" => (<>), TypeDef100, }; TypeDef100: TypeDef = { "(" > ")" "::" "." => TypeDef { span: span!(l, r), name, params, ty, opaque: false }, }; TypeSpec: TypeSpec = { "(" ":")?> > ")" "." => TypeSpec { span: span!(l, r), module, function, sigs }, ":")?> > "." => TypeSpec { span: span!(l, r), module, function, sigs }, }; TypeSig: TypeSig = { "(" > ")" "->" >)?> => TypeSig { span: span!(l, r), params, ret: Box::new(ret), guards }, }; TypeGuard: TypeGuard = { // is_subtype is not supported >OTP 19, but is allowed for backwards compatibility "(" "," ")" =>? { match name.name.as_str().get() { "is_subtype" => Ok(TypeGuard { span: span!(l, r), var, ty }), name => { let span = span!(l, r); errs.error(PreprocessorError::ShowDiagnostic { diagnostic: Diagnostic::error() .with_message("invalid type constraint") .with_labels(vec![ Label::primary(span.source_id(), span) .with_message("expected constraint in the form `Name :: Type`") ]), }.into()); Err(to_lalrpop_err!(())) } } }, "::" => TypeGuard { span: span!(l, r), var, ty }, }; TopType: Type = { "|" => Type::union(span!(l, r), lhs, rhs), Type100, }; Type100: Type = { "::" => Type::Annotated { span: span!(l, r), name, ty: Box::new(ty) }, Type200, }; Type200: Type = { ".." => Type::Range { span: span!(l, r), start: Box::new(lhs), end: Box::new(rhs) }, Type300, }; Type300: Type = { => Type::BinaryOp { span: span!(l, r), lhs: Box::new(lhs), op, rhs: Box::new(rhs) }, Type400, }; Type400: Type = { => Type::BinaryOp { span: span!(l, r), lhs: Box::new(lhs), op, rhs: Box::new(rhs) }, Type500, }; Type500: Type = { => Type::UnaryOp { span: span!(l, r), op, rhs: Box::new(rhs) }, Type600, }; Type600: Type = { "(" > ")" => Type::Generic { span: span!(l, r), fun, params }, ":" "(" > ")" => Type::Remote { span: span!(l, r), module, fun, args }, TypeMax, }; TypeMax: Type = { "(" ")" => ty, "[" "]" => Type::Nil(span!(l, r)), "[" "]" => Type::List(span!(l, r), Box::new(lt)), "[" "," "..." "]" => Type::NonEmptyList(span!(l, r), Box::new(lt)), "{" > "}" => Type::Tuple(span!(l, r), et), "#" "{" > "}" => Type::Map(span!(l, r), ft), "#" "{" > "}" => Type::Record(span!(l, r), record, ft), BinaryType, => Type::Name(name), => Type::Integer(span!(l, r), i), => Type::Char(span!(l, r), c), FunType, }; TypeName: Name = { => name, // While this is stupid, generated code by elixir // uses 'fun' as a variable a lot in in typespecs. // Hack to make this work. "fun" => Name::Var(Ident::new(Symbol::intern("fun"), span!(l, r))), }; BinaryType: Type = { "<<" ">>" => Type::Binary(span!(l, r), Box::new(Type::Integer(span!(l, r), 0.into())), Box::new(Type::Integer(span!(l, r), 0.into()))), "<<" ident ":" ">>" => Type::Binary(span!(l, r), Box::new(m), Box::new(Type::Integer(span!(l, r), 0.into()))), "<<" ident ":" "," ident ":" ">>" => Type::Binary(span!(l, r), Box::new(m), Box::new(n)), }; FunType: Type = { "fun" "(" ")" => Type::AnyFun { span: span!(l, r), ret: None }, "fun" "(" "(" "..." ")" "->" ")" => Type::AnyFun { span: span!(l, r), ret: Some(Box::new(ret)) }, "fun" "(" "(" > ")" "->" ")" => Type::Fun { span: span!(l, r), params, ret: Box::new(ret) }, }; MapFieldType: Type = { "=>" => Type::KeyValuePair(span!(l, r), Box::new(key), Box::new(val)), ":=" => Type::KeyValuePair(span!(l, r), Box::new(key), Box::new(val)), }; RecordFieldType: Type = { "::" => Type::Field(span!(l, r), key, Box::new(val)), }; // Pattern Matching Pattern: Expr = { "=" => Expr::Match(Match { span: span!(l, r), id: nid.next(), pattern: Box::new(lhs), expr: Box::new(rhs) }), Pattern200 }; Pattern200: Expr = { => Expr::BinaryExpr(BinaryExpr { span: span!(l, r), id: nid.next(), lhs: Box::new(lhs), op, rhs: Box::new(rhs) }), Pattern300 }; Pattern300: Expr = { => Expr::BinaryExpr(BinaryExpr { span: span!(l, r), id: nid.next(), lhs: Box::new(lhs), op, rhs: Box::new(rhs) }), Pattern400 }; Pattern400: Expr = { => Expr::BinaryExpr(BinaryExpr { span: span!(l, r), id: nid.next(), lhs: Box::new(lhs), op, rhs: Box::new(rhs) }), Pattern500 }; Pattern500: Expr = { => Expr::BinaryExpr(BinaryExpr { span: span!(l, r), id: nid.next(), lhs: Box::new(lhs), op, rhs: Box::new(rhs) }), Pattern600 }; Pattern600: Expr = { => Expr::UnaryExpr(UnaryExpr { span: span!(l, r), id: nid.next(), op, operand: Box::new(rhs) }), MapPattern, Pattern700 }; Pattern700: Expr = { RecordPattern, PatternMax }; PatternMax: Expr = { => Expr::Var(Var(nid.next(), i)), Atomic, ListPattern, Binary, Tuple, "(" ")" }; ListPattern: Expr = { "[" "]" => Expr::Nil(Nil(span!(l, r), nid.next())), "[" => Expr::Cons(Cons { span: span!(l, r), id: nid.next(), head: Box::new(head), tail: Box::new(tail) }) }; TailPattern: Expr = { "]" => Expr::Nil(Nil(span!(l, r), nid.next())), "|" "]", "," => Expr::Cons(Cons { span: span!(l, r), id: nid.next(), head: Box::new(head), tail: Box::new(tail) }) }; MapPattern: Expr = { "#" => Expr::Map(Map { span: span!(l, r), id: nid.next(), fields }), "#" => Expr::MapProjection(MapProjection { span: span!(l, r), id: nid.next(), map: Box::new(lhs), fields }), "#" => Expr::MapProjection(MapProjection { span: span!(l, r), id: nid.next(), map: Box::new(lhs), fields }), }; MapTuplePattern: Vec = { "{" > "}" }; MapFieldPattern: MapField = { "=>" => MapField::Assoc { span: span!(l, r), id: nid.next(), key, value }, ":=" => MapField::Exact { span: span!(l, r), id: nid.next(), key, value }, }; RecordPattern: Expr = { "#" "." => Expr::RecordIndex(RecordIndex { span: span!(l, r), id: nid.next(), name, field }), "#" => Expr::Record(Record { span: span!(l, r), id: nid.next(), name, fields }), }; RecordTuplePattern: Vec = { "{" > "}" }; RecordFieldPattern: RecordField = { "=" => RecordField { span: span!(l, r), id: nid.next(), name, value: Some(value), ty: None }, }; // Expressions pub Expr: Expr = { "catch" => Expr::Catch(Catch { span: span!(l, r), id: nid.next(), expr: Box::new(e) }), Expr100, }; Expr100: Expr = { // We would like to use Pattern200 here, but this leads to an ambiguity conflict // between non-terminals which are same in structure but different type, e.g. Tuple/TuplePattern, // so we just need to be aware that Expr::Match is really a pattern expression "=" => Expr::Match(Match { span: span!(l, r), id: nid.next(), pattern: Box::new(lhs), expr: Box::new(rhs) }), Expr140, }; Expr140: Expr = { "!" => Expr::BinaryExpr(BinaryExpr { span: span!(l, r), id: nid.next(), lhs: Box::new(lhs), op: BinaryOp::Send, rhs: Box::new(rhs) }), Expr150 }; Expr150: Expr = { "orelse" => Expr::BinaryExpr(BinaryExpr { span: span!(l, r), id: nid.next(), lhs: Box::new(lhs), op: BinaryOp::OrElse, rhs: Box::new(rhs) }), Expr160 }; Expr160: Expr = { "andalso" => Expr::BinaryExpr(BinaryExpr { span: span!(l, r), id: nid.next(), lhs: Box::new(lhs), op: BinaryOp::AndAlso, rhs: Box::new(rhs) }), Expr200 }; Expr200: Expr = { => Expr::BinaryExpr(BinaryExpr { span: span!(l, r), id: nid.next(), lhs: Box::new(lhs), op, rhs: Box::new(rhs) }), Expr300 }; Expr300: Expr = { => Expr::BinaryExpr(BinaryExpr { span: span!(l, r), id: nid.next(), lhs: Box::new(lhs), op, rhs: Box::new(rhs) }), Expr400 }; Expr400: Expr = { => Expr::BinaryExpr(BinaryExpr { span: span!(l, r), id: nid.next(), lhs: Box::new(lhs), op, rhs: Box::new(rhs) }), Expr500 }; Expr500: Expr = { => Expr::BinaryExpr(BinaryExpr { span: span!(l, r), id: nid.next(), lhs: Box::new(lhs), op, rhs: Box::new(rhs) }), Expr600 }; Expr600: Expr = { => Expr::UnaryExpr(UnaryExpr { span: span!(l, r), id: nid.next(), op, operand: Box::new(rhs) }), MapExpr, Expr700 }; Expr700: Expr = { Apply, RecordExpr, Expr800 }; Expr800: Expr = { ":" => Expr::Remote(Remote { span: span!(l, r), id: nid.next(), module: Box::new(lhs), function: Box::new(rhs) }), ExprMax }; ExprMax: Expr = { => Expr::Var(Var(nid.next(), i)), Atomic, Tuple, List, Binary, ListComprehension, BinaryComprehension, "(" ")", "begin" > "end" => Expr::Begin(Begin { span: span!(l, r), id: nid.next(), body }), If, Case, Receive, Try, Fun, DelayedSubstitution, }; Fun: Expr = { "fun" => Expr::FunctionName(FunctionName::PartiallyResolved(fun)), "fun" ":" "/" => Expr::FunctionName(FunctionName::detect(span!(l, r), nid, Some(module), function, arity)), "fun" > "end" =>? { match Function::new(errs, span!(l, r), nid, clauses) { Ok(fun) => Ok(Expr::Fun(fun)), Err(()) => Err(to_lalrpop_err!(())), } }, }; If: Expr = { "if" > "end" => Expr::If(If { span: span!(l, r), id: nid.next(), clauses }) }; IfClause: IfClause = { "->" > => IfClause { span: span!(l, r), id: nid.next(), guards, body } }; Case: Expr = { "case" "of" > "end" => Expr::Case(Case { span: span!(l, r), id: nid.next(), expr: Box::new(input), clauses }) }; Receive: Expr = { "receive" "end" => Expr::Receive(Receive { span: span!(l, r), id: nid.next(), clauses: None, after: Some(after) }), "receive" > "end" => Expr::Receive(Receive { span: span!(l, r), id: nid.next(), clauses: Some(clauses), after }) }; After: After = { "after" "->" > => After { span: span!(l, r), id: nid.next(), timeout: Box::new(timeout), body } }; Try: Expr = { "try" > "of" > => Expr::Try(Try { span: span!(l, catch.2), id: nid.next(), exprs, clauses: Some(clauses), catch_clauses: catch.0, after: catch.1 }), "try" > => Expr::Try(Try { span: span!(l, catch.2), id: nid.next(), exprs, clauses: None, catch_clauses: catch.0, after: catch.1 }) }; TryCatch: (Option>, Option>, SourceIndex) = { "catch" > "end" => (Some(clauses), None, r), "catch" > "after" > "end" => (Some(clauses), Some(body), r), "after" > "end" => (None, Some(body), r) }; TryClause: TryClause = { "->" > => TryClause { span: span!(l, r), id: nid.next(), kind: Name::Atom(Ident::from_str("throw")), error, guard, trace: Ident::from_str("_"), body }, ":" "->" > => TryClause { span: span!(l, r), id: nid.next(), kind, error, guard, trace: Ident::from_str("_"), body }, ":" ":" "->" > => TryClause { span: span!(l, r), id: nid.next(), kind, error, guard, trace, body }, }; Clause: Clause = { "->" > => Clause { span: span!(l, r), id: nid.next(), pattern, guard, body } }; Apply: Expr = { "(" > ")" => Expr::Apply(Apply { span: span!(l, r), id: nid.next(), callee: Box::new(lhs), args }) }; ListComprehension: Expr = { "[" "||" > "]" => Expr::ListComprehension(ListComprehension { span: span!(l, r), id: nid.next(), body: Box::new(body), qualifiers }), }; BinaryComprehension: Expr = { "<<" "||" > ">>" => Expr::BinaryComprehension(BinaryComprehension { span: span!(l, r), id: nid.next(), body: Box::new(body), qualifiers }), }; ComprehensionExpr: Expr = { "<=" => Expr::BinaryGenerator(BinaryGenerator { span: span!(l, r), id: nid.next(), pattern: Box::new(lhs), expr: Box::new(rhs) }), "<-" => Expr::Generator(Generator { span: span!(l, r), id: nid.next(), pattern: Box::new(lhs), expr: Box::new(rhs) }), Expr, }; Binary: Expr = { "<<" > ">>" => Expr::Binary(Binary { span: span!(l, r), id: nid.next(), elements }), }; BinaryElement: BinaryElement = { => { let spec = bts.as_ref().map(|b| match specifier_from_parsed(b, bs.is_some()) { Ok(specifier) => specifier, Err(error) => { // TODO errs.error(error.to_diagnostic().into()); BinaryEntrySpecifier::default() }, }); BinaryElement { span: span!(l, r), id: nid.next(), bit_expr: be, bit_size: bs, specifier: spec } } }; BitExpr: Expr = { => Expr::UnaryExpr(UnaryExpr { span: span!(l, r), id: nid.next(), op, operand: Box::new(rhs) }), ExprMax, }; BitSize: Expr = { ":" , }; BitTypeList: Vec = { "/" > => bts, }; BitType: BitType = { ":" => BitType::Sized(span!(l, r), nid.next(), ty, i.to_i64().unwrap()), => BitType::Name(span!(l, r), nid.next(), ty) }; Tuple: Expr = { "{" > "}" => Expr::Tuple(Tuple { span: span!(l, r), id: nid.next(), elements }) }; List: Expr = { "[" "]" => Expr::Nil(Nil(span!(l, r), nid.next())), "[" => Expr::Cons(Cons { span: span!(l, r), id: nid.next(), head: Box::new(head), tail: Box::new(tail) }) }; Tail: Expr = { "]" => Expr::Nil(Nil(span!(l, r), nid.next())), "|" "]", "," => Expr::Cons(Cons { span: span!(l, r), id: nid.next(), head: Box::new(head), tail: Box::new(tail) }) }; MapExpr: Expr = { "#" => Expr::Map(Map { span: span!(l, r), id: nid.next(), fields }), "#" => Expr::MapUpdate(MapUpdate { span: span!(l, r), id: nid.next(), map: Box::new(map), updates }), "#" => Expr::MapUpdate(MapUpdate { span: span!(l, r), id: nid.next(), map: Box::new(map), updates }), }; MapTuple: Vec = { "{" > "}" }; MapField: MapField = { MapFieldAssoc, MapFieldExact }; MapFieldAssoc: MapField = { "=>" => MapField::Assoc { span: span!(l, r), id: nid.next(), key, value } }; MapFieldExact: MapField = { ":=" => MapField::Exact { span: span!(l, r), id: nid.next(), key, value } }; MapKey: Expr = Expr; RecordExpr: Expr = { "#" "." => Expr::RecordIndex(RecordIndex { span: span!(l, r), id: nid.next(), name, field }), "#" => Expr::Record(Record { span: span!(l, r), id: nid.next(), name, fields }), "#" "." => Expr::RecordAccess(RecordAccess { span: span!(l, r), id: nid.next(), record: Box::new(lhs), name, field }), "#" => Expr::RecordUpdate(RecordUpdate { span: span!(l, r), id: nid.next(), record: Box::new(lhs), name, updates }), "#" "." => Expr::RecordAccess(RecordAccess { span: span!(l, r), id: nid.next(), record: Box::new(lhs), name, field }), "#" => Expr::RecordUpdate(RecordUpdate { span: span!(l, r), id: nid.next(), record: Box::new(lhs), name, updates }), }; RecordTuple: Vec = { "{" > "}" }; RecordField: RecordField = { "=" => RecordField { span: span!(l, r), id: nid.next(), name, value: Some(value), ty: None }, }; Constant: Expr = { ConstantTuple, ConstantList, ConstantMapExpr, => Expr::FunctionName(FunctionName::PartiallyResolved(<>)), Atomic, }; ConstantTuple: Expr = { "{" > "}" => Expr::Tuple(Tuple { span: span!(l, r), id: nid.next(), elements }) }; ConstantList: Expr = { "[" "]" => Expr::Nil(Nil(span!(l, r), nid.next())), "[" => Expr::Cons(Cons { span: span!(l, r), id: nid.next(), head: Box::new(head), tail: Box::new(tail) }) }; ConstantTail: Expr = { "]" => Expr::Nil(Nil(span!(l, r), nid.next())), "|" "]", "," => Expr::Cons(Cons { span: span!(l, r), id: nid.next(), head: Box::new(head), tail: Box::new(tail) }) }; ConstantMapExpr: Expr = { "#" => Expr::Map(Map { span: span!(l, r), id: nid.next(), fields }), }; ConstantMapTuple: Vec = { "{" > "}" }; ConstantMapField: MapField = { "=>" => MapField::Assoc { span: span!(l, r), id: nid.next(), key, value } }; ConstantMapKey: Expr = Constant; Atomic: Expr = { => Expr::Literal(Literal::Char(span!(l, r), nid.next(), c)), => Expr::Literal(<>), => Expr::Literal(Literal::Float(span!(l, r), nid.next(), f)), => Expr::Literal(Literal::Atom(nid.next(), <>)), => Expr::Literal(Literal::String(nid.next(), s)), }; StringLiteral: Ident = => { let span = span!(l, r); if s.len() == 1 { Ident::new(s[0], span) } else { let mut buf = String::new(); for frag in s.iter() { buf.push_str(&frag.as_str()); } let symbol = Symbol::intern(&buf); Ident::new(symbol, span) } }; DelayedSubstitution: Expr = { => Expr::DelayedSubstitution(span!(l, r), nid.next(), subs), }; #[inline] atom_or_var: Name = { => Name::Atom(a), => Name::Var(i), }; #[inline] atom: Ident = => Ident::new(a, span!(l, r)); #[inline] Ident: Ident = => Ident::new(i, span!(l, r)); #[inline] Integer: Literal = { => Literal::Integer(span!(l, r), nid.next(), i), }; #[inline] arity_or_var: Arity = { => Arity::Int(i.to_usize().unwrap()), => Arity::Var(i), }; #[inline] arity: usize = => i.to_usize().unwrap(); #[inline] ident_or_integer: Expr = { => Expr::Var(Var(nid.next(), i)), => Expr::Literal(i) } PrefixOp: UnaryOp = { "+" => UnaryOp::Plus, "-" => UnaryOp::Minus, "bnot" => UnaryOp::Bnot, "not" => UnaryOp::Not, }; MultOp: BinaryOp = { "/" => BinaryOp::Divide, "*" => BinaryOp::Multiply, "div" => BinaryOp::Div, "rem" => BinaryOp::Rem, "band" => BinaryOp::Band, "and" => BinaryOp::And, }; AddOp: BinaryOp = { "+" => BinaryOp::Add, "-" => BinaryOp::Sub, "bor" => BinaryOp::Bor, "bxor" => BinaryOp::Bxor, "bsl" => BinaryOp::Bsl, "bsr" => BinaryOp::Bsr, "or" => BinaryOp::Or, "xor" => BinaryOp::Xor, }; TypeMultOp: BinaryOp = { "*" => BinaryOp::Multiply, "div" => BinaryOp::Div, "rem" => BinaryOp::Rem, "band" => BinaryOp::Band, }; TypeAddOp: BinaryOp = { "+" => BinaryOp::Add, "-" => BinaryOp::Sub, "bor" => BinaryOp::Bor, "bxor" => BinaryOp::Bxor, "bsl" => BinaryOp::Bsl, "bsr" => BinaryOp::Bsr, }; TypeUnaryOp: UnaryOp = { "+" => UnaryOp::Plus, "-" => UnaryOp::Minus, "bnot" => UnaryOp::Bnot, }; ListOp: BinaryOp = { "++" => BinaryOp::Append, "--" => BinaryOp::Remove, }; CompOp: BinaryOp = { "==" => BinaryOp::Equal, "/=" => BinaryOp::NotEqual, "=<" => BinaryOp::Lte, "<" => BinaryOp::Lt, ">=" => BinaryOp::Gte, ">" => BinaryOp::Gt, "=:=" => BinaryOp::StrictEqual, "=/=" => BinaryOp::StrictNotEqual }; BaseInt: Integer = { "-" => -i, => i, }; Float: Float = { "-" => -i, => i, }; extern { type Location = SourceIndex; type Error = (); enum Token { // Docs "COMMENT" => Token::Comment, // Literals char => Token::Char(), int => Token::Integer(), float => Token::Float(), "atom" => Token::Atom(), string => Token::String(), ident => Token::Ident(), delayed_substitution => Token::DelayedSubstitution(), // Keywords and Symbols "(" => Token::LParen, ")" => Token::RParen, "," => Token::Comma, "->" => Token::RightStab, "{" => Token::LBrace, "}" => Token::RBrace, "[" => Token::LBracket, "]" => Token::RBracket, "|" => Token::Bar, "||" => Token::BarBar, "<-" => Token::LeftStab, ";" => Token::Semicolon, ":" => Token::Colon, "#" => Token::Pound, "." => Token::Dot, "after" => Token::After, "begin" => Token::Begin, "case" => Token::Case, "try" => Token::Try, "catch" => Token::Catch, "end" => Token::End, "fun" => Token::Fun, "if" => Token::If, "of" => Token::Of, "receive" => Token::Receive, "when" => Token::When, "record" => Token::Record, "spec" => Token::Spec, "callback" => Token::Callback, "optional_callback" => Token::OptionalCallback, "import" => Token::Import, "export" => Token::Export, "removed" => Token::Removed, "export_type" => Token::ExportType, "module" => Token::Module, "compile" => Token::Compile, "vsn" => Token::Vsn, "author" => Token::Author, "on_load" => Token::OnLoad, "behaviour" => Token::Behaviour, "deprecated" => Token::Deprecated, "type" => Token::Type, "opaque" => Token::Opaque, "file" => Token::File, "andalso" => Token::AndAlso, "orelse" => Token::OrElse, "bnot" => Token::Bnot, "not" => Token::Not, "*" => Token::Star, "/" => Token::Slash, "div" => Token::Div, "rem" => Token::Rem, "band" => Token::Band, "and" => Token::And, "+" => Token::Plus, "-" => Token::Minus, "bor" => Token::Bor, "bxor" => Token::Bxor, "bsl" => Token::Bsl, "bsr" => Token::Bsr, "or" => Token::Or, "xor" => Token::Xor, "++" => Token::PlusPlus, "--" => Token::MinusMinus, "==" => Token::IsEqual, "/=" => Token::IsNotEqual, "=<" => Token::IsLessThanOrEqual, "<" => Token::IsLessThan, ">=" => Token::IsGreaterThanOrEqual, ">" => Token::IsGreaterThan, "=:=" => Token::IsExactlyEqual, "=/=" => Token::IsExactlyNotEqual, "<=" => Token::LeftArrow, "=>" => Token::RightArrow, ":=" => Token::ColonEqual, "<<" => Token::BinaryStart, ">>" => Token::BinaryEnd, "!" => Token::Bang, "=" => Token::Equals, "::" => Token::ColonColon, ".." => Token::DotDot, "..." => Token::DotDotDot, "?" => Token::Question, } } ================================================ FILE: libeir_syntax_erl/src/parser/macros.rs ================================================ /// Construct a keyword list AST from a list of expressions, e.g.: /// /// kwlist!(tuple!(atom!(key), var!(Value))) /// /// It is required that elements are two-tuples, but no checking is done /// to make sure that the first element in each tuple is an atom #[allow(unused_macros)] macro_rules! kwlist { ($nid:expr, $($element:expr),*) => { let mut elements = vec![$($element),*]; elements.reverse(); elements.fold(nil!($nid), |acc, (key, val)| { cons!($nid, Expr::Tuple(Tuple { span: SourceSpan::UNKNOWN, id: $nid.next(), elements: vec![key, val] }), acc) }) } } /// Like `kwlist!`, but produces a list of elements produced by any arbitrary expression /// /// list!(atom!(foo), tuple!(atom!(bar), atom!(baz))) /// /// Like `kwlist!`, this produces a proper list #[allow(unused_macros)] macro_rules! list { ($nid:expr, $($element:expr),*) => { { let mut elements = vec![$($element),*]; elements.reverse(); elements.iter().fold(nil!($nid), |acc, el| { cons!($nid, *el, acc) }) } } } /// A lower-level primitive for constructing lists, via cons cells. /// Given the following: /// /// cons!(atom!(a), cons!(atom!(b), nil!())) /// /// This is equivalent to `[a | [b | []]]`, which is in turn equivalent /// to `[a, b]`. You are better off using `list!` unless you explicitly /// need to construct an improper list #[allow(unused_macros)] macro_rules! cons { ($nid:expr, $head:expr, $tail:expr) => { Expr::Cons(Cons { span: SourceSpan::UNKNOWN, id: $nid.next(), head: Box::new($head), tail: Box::new($tail), }) }; } macro_rules! nil { ($nid:expr) => { Expr::Nil(Nil(SourceSpan::UNKNOWN, $nid.next())) }; } /// Produces a tuple expression with the given elements macro_rules! tuple { ($nid:expr, $($element:expr),*) => { Expr::Tuple(Tuple{ span: SourceSpan::UNKNOWN, id: $nid.next(), elements: vec![$($element),*], }) } } /// Produces an integer literal expression macro_rules! int { ($nid:expr, $i:expr) => { Expr::Literal(Literal::Integer(SourceSpan::UNKNOWN, $nid.next(), $i)) }; } /// Produces a literal expression which evaluates to an atom macro_rules! atom { ($nid:expr, $sym:ident) => { Expr::Literal(Literal::Atom( $nid.next(), Ident::with_empty_span(Symbol::intern(stringify!($sym))), )) }; ($nid:expr, $sym:expr) => { Expr::Literal(Literal::Atom( $nid.next(), Ident::with_empty_span(Symbol::intern($sym)), )) }; } macro_rules! atom_from_sym { ($nid:expr, $sym:expr) => { Expr::Literal(Literal::Atom($nid.next(), Ident::with_empty_span($sym))) }; } /// Produces an Ident from an expression, meant to be used to simplify generating /// identifiers in the AST from strings or symbols macro_rules! ident { ($sym:ident) => { Ident::with_empty_span(Symbol::intern(stringify!($sym))) }; ($sym:expr) => { Ident::with_empty_span(Symbol::intern($sym)) }; (_) => { Ident::with_empty_span(Symbol::intern("_")) }; } /// Produces an Option from an expression, meant to be used to simplify generating /// identifiers in the AST from strings or symbols #[allow(unused_macros)] macro_rules! ident_opt { ($sym:ident) => { Some(Ident::with_empty_span(Symbol::intern(stringify!($sym)))) }; ($sym:expr) => { Some(Ident::with_empty_span(Symbol::intern($sym))) }; (_) => { Ident::with_empty_span(Symbol::intern("_")) }; } /// Produces a variable expression macro_rules! var { ($nid:expr, $name:ident) => { Expr::Var(Var($nid.next(), ident!(stringify!($name)))) }; ($nid:expr, _) => { Expr::Var(Var($nid.next(), ident!(_))) }; } /// Produces a remote expression, e.g. `erlang:get_module_info` /// /// Expects the module/function to be identifier symbols macro_rules! remote { ($nid: expr, $module:ident, $function:ident) => { Expr::Remote(Remote { span: SourceSpan::UNKNOWN, id: $nid.next(), module: Box::new(atom!($nid, $module)), function: Box::new(atom!($nid, $function)), }) }; ($nid:expr, $module:expr, $function:expr) => { Expr::Remote(Remote { span: SourceSpan::UNKNOWN, id: $nid.next(), module: Box::new($module), function: Box::new($function), }) }; } /// Produces a function application expression macro_rules! apply { ($nid:expr, $callee:expr, $($args:expr),*) => { Expr::Apply(Apply { span: SourceSpan::UNKNOWN, id: $nid.next(), callee: Box::new($callee), args: vec![$($args),*] }) } } /// Produces a function definition macro_rules! fun { ($nid:expr, $name:ident ($($params:ident),*) -> $body:expr) => { { let params = vec![$(var!($nid, $params)),*]; let arity = params.len(); NamedFunction { span: SourceSpan::UNKNOWN, id: $nid.next(), name: Name::Atom(ident!($name)), arity, clauses: vec![ FunctionClause{ span: SourceSpan::UNKNOWN, name: Some(Name::Atom(ident!($name))), params, guard: None, body: vec![$body], } ], spec: None, } } }; ($nid:expr, $name:ident $(($($params:expr),*) -> $body:expr);*) => { { let mut clauses = Vec::new(); $( clauses.push(FunctionClause { span: SourceSpan::UNKNOWN, name: Some(Name::Atom(ident!($name))), params: vec![$($params),*], guard: None, body: vec![$body], }); )* let arity = clauses.first().as_ref().unwrap().params.len(); NamedFunction { span: SourceSpan::UNKNOWN, id: $nid.next(), name: Name::Atom(ident!($name)), arity, clauses, spec: None, } } } } ================================================ FILE: libeir_syntax_erl/src/parser/mod.rs ================================================ /// Used in the grammar for easy span creation macro_rules! span { ($l:expr, $r:expr) => { SourceSpan::new($l, $r) }; ($i:expr) => { SourceSpan::new($i, $i) }; } /// Convenience function for building parser errors macro_rules! to_lalrpop_err ( ($error:expr) => (lalrpop_util::ParseError::User { error: $error }) ); type ParserErrorReceiver<'a> = dyn ErrorReceiver + 'a; #[cfg_attr(rustfmt, rustfmt_skip)] #[allow(unknown_lints)] #[allow(clippy)] #[allow(unused_parens)] pub(crate) mod grammar { // During the build step, `build.rs` will output the generated parser to `OUT_DIR` to avoid // adding it to the source directory, so we just directly include the generated parser here. // // Even with `.gitignore` and the `exclude` in the `Cargo.toml`, the generated parser can still // end up in the source directory. This could happen when `cargo build` builds the file out of // the Cargo cache (`$HOME/.cargo/registrysrc`), and the build script would then put its output // in that cached source directory because of https://github.com/lalrpop/lalrpop/issues/280. // Later runs of `cargo vendor` then copy the source from that directory, including the // generated file. include!(concat!(env!("OUT_DIR"), "/parser/grammar.rs")); } #[macro_use] mod macros; pub mod ast; mod errors; pub mod binary; use std::collections::VecDeque; use std::path::PathBuf; use libeir_util_parse::{error_tee, ErrorReceiver, Scanner, Source, SourceError}; use libeir_util_parse::{Parse as GParse, Parser as GParser}; pub type Parser = GParser; pub trait Parse = GParse; use crate::lexer::Lexer; use crate::preprocessor::{MacroContainer, Preprocessed, Preprocessor}; pub use self::ast::{NodeId, NodeIdGenerator}; pub use self::errors::*; /// The type of result returned from parsing functions pub type ParseResult = Result>; #[derive(Debug, Clone, PartialEq, Eq)] pub struct ParseConfig { pub warnings_as_errors: bool, pub no_warn: bool, pub include_paths: VecDeque, pub code_paths: VecDeque, pub macros: Option, } impl ParseConfig { pub fn new() -> Self { ParseConfig::default() } } impl Default for ParseConfig { fn default() -> Self { ParseConfig { warnings_as_errors: false, no_warn: false, include_paths: VecDeque::new(), code_paths: VecDeque::new(), macros: None, } } } impl GParse for ast::Module { type Parser = grammar::ModuleParser; type Error = ParserError; type Config = ParseConfig; type Token = Preprocessed; fn root_file_error(source: std::io::Error, path: std::path::PathBuf) -> Self::Error { ParserError::RootFile { source, path } } fn parse<'a, S>( parser: &Parser, err: &'a mut ParserErrorReceiver<'a>, source: S, ) -> Result where S: Source, { error_tee(err, |mut errors| { let scanner = Scanner::new(source); let lexer = Lexer::new(scanner); error_tee(&mut errors.clone().make_into_adapter(), |preproc_errors| { let tokens = Preprocessor::new(parser, lexer, preproc_errors); Self::parse_tokens(&mut errors, tokens) }) }) } fn parse_tokens<'a, S: IntoIterator>( err: &'a mut ParserErrorReceiver<'a>, tokens: S, ) -> Result { let mut nid = NodeIdGenerator::new(); let result = Self::Parser::new().parse(err, &mut nid, tokens); to_parse_result(err, result) } } impl GParse for ast::Expr { type Parser = grammar::ExprParser; type Error = ParserError; type Config = ParseConfig; type Token = Preprocessed; fn root_file_error(source: std::io::Error, path: std::path::PathBuf) -> Self::Error { ParserError::RootFile { source, path } } fn parse(parser: &Parser, err: &mut ParserErrorReceiver, source: S) -> Result where S: Source, { error_tee(err, |mut errors| { let scanner = Scanner::new(source); let lexer = Lexer::new(scanner); error_tee(&mut errors.clone().make_into_adapter(), |preproc_errors| { let tokens = Preprocessor::new(parser, lexer, preproc_errors); Self::parse_tokens(&mut errors, tokens) }) }) } fn parse_tokens>( err: &mut ParserErrorReceiver, tokens: S, ) -> Result { let mut nid = NodeIdGenerator::new(); let result = Self::Parser::new().parse(err, &mut nid, tokens); to_parse_result(err, result) } } fn to_parse_result( errs: &mut ParserErrorReceiver, result: Result, ) -> Result { match result { Ok(ast) => { if (*errs).is_failed() { return Err(()); } Ok(ast) } Err(lalrpop_util::ParseError::User { .. }) => Err(()), Err(err) => { errs.error(err.into()); Err(()) } } } #[cfg(test)] mod test { use std::sync::Arc; use pretty_assertions::assert_eq; use super::ast::*; use super::*; use libeir_diagnostics::*; use libeir_util_parse::{ErrorOrWarning, Errors}; use crate::lexer::{Ident, Symbol}; use crate::preprocessor::PreprocessorError; fn fail_with(errors: &Errors, codemap: &CodeMap, message: &'static str) -> ! where E: ToDiagnostic, W: ToDiagnostic, { use term::termcolor::{ColorChoice, StandardStream}; let config = term::Config::default(); let mut out = StandardStream::stderr(ColorChoice::Always); for diagnostic in errors.iter_diagnostics() { term::emit(&mut out, &config, codemap, &diagnostic).unwrap(); } panic!(message); } fn parse(config: ParseConfig, codemap: Arc, input: S) -> T where T: Parse, S: AsRef, { let mut errors = Errors::new(); let parser = Parser::new(config, codemap); match parser.parse_string::(&mut errors, input) { Ok(ast) => return ast, Err(_errs) => fail_with(&errors, &parser.codemap, "parse failed"), } } fn parse_fail( config: ParseConfig, codemap: Arc, input: S, ) -> Errors where T: Parse, S: AsRef, { let mut errors = Errors::new(); let parser = Parser::new(config, codemap); match parser.parse_string::(&mut errors, input) { Err(()) => errors, _ => panic!("expected parse to fail, but it succeeded!"), } } macro_rules! module { ($codemap:expr, $nid:expr, $name:expr, $body:expr) => {{ let mut errs = Errors::new(); let module = Module::new(&mut errs, SourceSpan::UNKNOWN, $nid, $name, $body); if errs.is_failed() { fail_with(&errs, $codemap, "failed to create expected module!"); } module }}; } #[test] fn parse_empty_module() { let codemap = Arc::new(CodeMap::new()); let config = ParseConfig::default(); let result: Module = parse(config, codemap.clone(), "-module(foo)."); let mut nid = NodeIdGenerator::new(); let expected = module!(&codemap, &mut nid, ident!("foo"), vec![]); assert_eq!(result, expected); } #[test] fn parse_module_with_multi_clause_function() { let codemap = Arc::new(CodeMap::new()); let config = ParseConfig::default(); let result: Module = parse( config, codemap.clone(), "-module(foo). foo([], Acc) -> Acc; foo([H|T], Acc) -> foo(T, [H|Acc]). ", ); let mut id_gen = NodeIdGenerator::new(); let nid = &mut id_gen; let mut clauses = Vec::new(); clauses.push(FunctionClause { span: SourceSpan::UNKNOWN, name: ident_opt!(foo).map(Name::Atom), params: vec![nil!(nid), var!(nid, Acc)], guard: None, body: vec![var!(nid, Acc)], }); clauses.push(FunctionClause { span: SourceSpan::UNKNOWN, name: ident_opt!(foo).map(Name::Atom), params: vec![cons!(nid, var!(nid, H), var!(nid, T)), var!(nid, Acc)], guard: None, body: vec![apply!( nid, atom!(nid, foo), var!(nid, T), cons!(nid, var!(nid, H), var!(nid, Acc)) )], }); let mut body = Vec::new(); body.push(TopLevel::Function(NamedFunction { span: SourceSpan::UNKNOWN, id: nid.next(), name: Name::Atom(ident!("foo")), arity: 2, clauses, spec: None, })); let expected = module!(&codemap, nid, ident!(foo), body); assert_eq!(result, expected); } #[test] fn parse_if_expressions() { let codemap = Arc::new(CodeMap::new()); let config = ParseConfig::default(); let result: Module = parse( config, codemap.clone(), "-module(foo). unless(false) -> true; unless(true) -> false; unless(Value) -> if Value == 0 -> true; Value -> false; else -> true end. ", ); let mut id_gen = NodeIdGenerator::new(); let nid = &mut id_gen; let mut clauses = Vec::new(); clauses.push(FunctionClause { span: SourceSpan::UNKNOWN, name: ident_opt!(unless).map(Name::Atom), params: vec![atom!(nid, false)], guard: None, body: vec![atom!(nid, true)], }); clauses.push(FunctionClause { span: SourceSpan::UNKNOWN, name: ident_opt!(unless).map(Name::Atom), params: vec![atom!(nid, true)], guard: None, body: vec![atom!(nid, false)], }); clauses.push(FunctionClause { span: SourceSpan::UNKNOWN, name: ident_opt!(unless).map(Name::Atom), params: vec![var!(nid, Value)], guard: None, body: vec![Expr::If(If { span: SourceSpan::UNKNOWN, id: nid.next(), clauses: vec![ IfClause { span: SourceSpan::UNKNOWN, id: nid.next(), guards: vec![Guard { span: SourceSpan::UNKNOWN, conditions: vec![Expr::BinaryExpr(BinaryExpr { span: SourceSpan::UNKNOWN, id: nid.next(), lhs: Box::new(var!(nid, Value)), op: BinaryOp::Equal, rhs: Box::new(int!(nid, 0.into())), })], }], body: vec![atom!(nid, true)], }, IfClause { span: SourceSpan::UNKNOWN, id: nid.next(), guards: vec![Guard { span: SourceSpan::UNKNOWN, conditions: vec![var!(nid, Value)], }], body: vec![atom!(nid, false)], }, IfClause { span: SourceSpan::UNKNOWN, id: nid.next(), guards: vec![Guard { span: SourceSpan::UNKNOWN, conditions: vec![atom!(nid, else)], }], body: vec![atom!(nid, true)], }, ], })], }); let mut body = Vec::new(); body.push(TopLevel::Function(NamedFunction { span: SourceSpan::UNKNOWN, id: nid.next(), name: Name::Atom(ident!(unless)), arity: 1, clauses, spec: None, })); let expected = module!(&codemap, nid, ident!(foo), body); assert_eq!(result, expected); } #[test] fn parse_case_expressions() { let codemap = Arc::new(CodeMap::new()); let config = ParseConfig::default(); let result: Module = parse( config, codemap.clone(), "-module(foo). typeof(Value) -> case Value of [] -> nil; [_|_] -> list; N when is_number(N) -> N; _ -> other end. ", ); let mut id_gen = NodeIdGenerator::new(); let nid = &mut id_gen; let mut clauses = Vec::new(); clauses.push(FunctionClause { span: SourceSpan::UNKNOWN, name: ident_opt!(typeof).map(Name::Atom), params: vec![var!(nid, Value)], guard: None, body: vec![Expr::Case(Case { span: SourceSpan::UNKNOWN, id: nid.next(), expr: Box::new(var!(nid, Value)), clauses: vec![ Clause { span: SourceSpan::UNKNOWN, id: nid.next(), pattern: nil!(nid), guard: None, body: vec![atom!(nid, nil)], }, Clause { span: SourceSpan::UNKNOWN, id: nid.next(), pattern: cons!(nid, var!(nid, _), var!(nid, _)), guard: None, body: vec![atom!(nid, list)], }, Clause { span: SourceSpan::UNKNOWN, id: nid.next(), pattern: var!(nid, N), guard: Some(vec![Guard { span: SourceSpan::UNKNOWN, conditions: vec![apply!(nid, atom!(nid, is_number), var!(nid, N))], }]), body: vec![var!(nid, N)], }, Clause { span: SourceSpan::UNKNOWN, id: nid.next(), pattern: var!(nid, _), guard: None, body: vec![atom!(nid, other)], }, ], })], }); let mut body = Vec::new(); body.push(TopLevel::Function(NamedFunction { span: SourceSpan::UNKNOWN, id: nid.next(), name: Name::Atom(ident!(typeof)), arity: 1, clauses, spec: None, })); let expected = module!(&codemap, nid, ident!(foo), body); assert_eq!(result, expected); } #[test] fn parse_receive_expressions() { let codemap = Arc::new(CodeMap::new()); let config = ParseConfig::default(); let result: Module = parse( config, codemap.clone(), "-module(foo). loop(State, Timeout) -> receive {From, {Ref, Msg}} -> From ! {Ref, ok}, handle_info(Msg, State); _ -> exit(io_lib:format(\"unexpected message: ~p~n\", [Msg])) after Timeout -> timeout end. ", ); let mut id_gen = NodeIdGenerator::new(); let nid = &mut id_gen; let mut clauses = Vec::new(); clauses.push(FunctionClause { span: SourceSpan::UNKNOWN, name: ident_opt!(loop).map(Name::Atom), params: vec![var!(nid, State), var!(nid, Timeout)], guard: None, body: vec![Expr::Receive(Receive { span: SourceSpan::UNKNOWN, id: nid.next(), clauses: Some(vec![ Clause { span: SourceSpan::UNKNOWN, id: nid.next(), pattern: tuple!( nid, var!(nid, From), tuple!(nid, var!(nid, Ref), var!(nid, Msg)) ), guard: None, body: vec![ Expr::BinaryExpr(BinaryExpr { span: SourceSpan::UNKNOWN, id: nid.next(), lhs: Box::new(var!(nid, From)), op: BinaryOp::Send, rhs: Box::new(tuple!(nid, var!(nid, Ref), atom!(nid, ok))), }), apply!( nid, atom!(nid, handle_info), var!(nid, Msg), var!(nid, State) ), ], }, Clause { span: SourceSpan::UNKNOWN, id: nid.next(), pattern: var!(nid, _), guard: None, body: vec![apply!( nid, atom!(nid, exit), apply!( nid, remote!(nid, io_lib, format), Expr::Literal(Literal::String( nid.next(), ident!("unexpected message: ~p~n") )), cons!(nid, var!(nid, Msg), nil!(nid)) ) )], }, ]), after: Some(After { span: SourceSpan::UNKNOWN, id: nid.next(), timeout: Box::new(var!(nid, Timeout)), body: vec![atom!(nid, timeout)], }), })], }); let mut body = Vec::new(); body.push(TopLevel::Function(NamedFunction { span: SourceSpan::UNKNOWN, id: nid.next(), name: Name::Atom(ident!(loop)), arity: 2, clauses, spec: None, })); let expected = module!(&codemap, nid, ident!(foo), body); assert_eq!(result, expected); } #[test] fn parse_preprocessor_if() { let codemap = Arc::new(CodeMap::new()); let config = ParseConfig::default(); let result: Module = parse( config, codemap.clone(), "-module(foo). -define(TEST, true). -define(OTP_VERSION, 21). -ifdef(TEST). env() -> test. -else. env() -> release. -endif. -if(?OTP_VERSION > 21). system_version() -> future. -elif(?OTP_VERSION == 21). system_version() -> ?OTP_VERSION. -else. system_version() -> old. -endif. ", ); let mut id_gen = NodeIdGenerator::new(); let nid = &mut id_gen; let mut body = Vec::new(); let mut clauses = Vec::new(); clauses.push(FunctionClause { span: SourceSpan::UNKNOWN, name: ident_opt!(env).map(Name::Atom), params: vec![], guard: None, body: vec![atom!(nid, test)], }); let env_fun = NamedFunction { span: SourceSpan::UNKNOWN, id: nid.next(), name: Name::Atom(ident!(env)), arity: 0, clauses, spec: None, }; body.push(TopLevel::Function(env_fun)); let mut clauses = Vec::new(); clauses.push(FunctionClause { span: SourceSpan::UNKNOWN, name: ident_opt!(system_version).map(Name::Atom), params: vec![], guard: None, body: vec![int!(nid, 21.into())], }); let system_version_fun = NamedFunction { span: SourceSpan::UNKNOWN, id: nid.next(), name: Name::Atom(ident!(system_version)), arity: 0, clauses, spec: None, }; body.push(TopLevel::Function(system_version_fun)); let expected = module!(&codemap, nid, ident!(foo), body); assert_eq!(result, expected); } #[test] fn parse_preprocessor_warning_error() { // NOTE: Warnings are not printed with cfg(test), as we // cannot control where they end up without refactoring to pass // a writer everywhere. You can change this for testing by // going to the Preprocessor and finding the line where we handle // the warning directive and toggle the config flag let codemap = Arc::new(CodeMap::default()); let config = ParseConfig::default(); let mut errs = parse_fail::( config, codemap.clone(), "-module(foo). -warning(\"this is a compiler warning\"). -error(\"this is a compiler error\"). ", ); match errs.errors.pop() { Some(ErrorOrWarning::Error(ParserError::Preprocessor { source: PreprocessorError::CompilerError { .. }, })) => (), Some(err) => panic!( "expected compiler error, but got a different error instead: {:?}", err ), None => panic!("expected compiler error, but didn't get any errors!"), } match errs.errors.pop() { Some(ErrorOrWarning::Warning(ParserError::Preprocessor { source: PreprocessorError::WarningDirective { .. }, })) => (), Some(err) => panic!( "expected warning directive, but got a different error instead: {:?}", err ), None => panic!("expected compiler error, but didn't get any errors!"), } } #[test] fn parse_try() { let codemap = Arc::new(CodeMap::default()); let config = ParseConfig::default(); let result: Module = parse( config, codemap.clone(), "-module(foo). example(File) -> try read(File) of {ok, Contents} -> {ok, Contents} catch error:{Mod, Code} -> {error, Mod:format_error(Code)}; Reason -> {error, Reason} after close(File) end. ", ); let mut id_gen = NodeIdGenerator::new(); let nid = &mut id_gen; let mut clauses = Vec::new(); clauses.push(FunctionClause { span: SourceSpan::UNKNOWN, name: ident_opt!(example).map(Name::Atom), params: vec![var!(nid, File)], guard: None, body: vec![Expr::Try(Try { span: SourceSpan::UNKNOWN, id: nid.next(), exprs: vec![apply!(nid, atom!(nid, read), var!(nid, File))], clauses: Some(vec![Clause { span: SourceSpan::UNKNOWN, id: nid.next(), pattern: tuple!(nid, atom!(nid, ok), var!(nid, Contents)), guard: None, body: vec![tuple!(nid, atom!(nid, ok), var!(nid, Contents))], }]), catch_clauses: Some(vec![ TryClause { span: SourceSpan::UNKNOWN, id: nid.next(), kind: Name::Atom(ident!(error)), error: tuple!(nid, var!(nid, Mod), var!(nid, Code)), trace: ident!(_), guard: None, body: vec![tuple!( nid, atom!(nid, error), apply!( nid, remote!(nid, var!(nid, Mod), atom!(nid, format_error)), var!(nid, Code) ) )], }, TryClause { span: SourceSpan::UNKNOWN, id: nid.next(), kind: Name::Atom(ident!(throw)), error: var!(nid, Reason), trace: ident!(_), guard: None, body: vec![tuple!(nid, atom!(nid, error), var!(nid, Reason))], }, ]), after: Some(vec![apply!(nid, atom!(nid, close), var!(nid, File))]), })], }); let mut body = Vec::new(); body.push(TopLevel::Function(NamedFunction { span: SourceSpan::UNKNOWN, id: nid.next(), name: Name::Atom(ident!(example)), arity: 1, clauses, spec: None, })); let expected = module!(&codemap, nid, ident!(foo), body); assert_eq!(result, expected); } #[test] fn parse_try2() { let codemap = Arc::new(CodeMap::default()); let config = ParseConfig::default(); let _result: Module = parse( config, codemap.clone(), "-module(foo). example(File < 2) -> try read(File) of {ok, Contents} -> {ok, Contents} catch error:{Mod, Code} -> {error, Mod:format_error(Code)}; Reason -> {error, Reason} after close(File) end. exw(File) -> case File of File < 2 -> ok end. ", ); } #[test] fn parse_numbers() { let _result: Module = parse( ParseConfig::default(), Arc::new(CodeMap::new()), "-module(foo). foo(F) -> F-1+1/1*1. bar() -> - 2. ", ); } #[test] fn parse_spec() { let _result: Module = parse( ParseConfig::default(), Arc::new(CodeMap::new()), "-module(foo). -spec bar() -> number. bar() -> 2. ", ); } #[test] fn parse_binary_spec_constant() { let _result: Module = parse( ParseConfig::default(), Arc::new(CodeMap::new()), "-module(foo). -type txs_hash() :: <<_:(32 * 8)>>. -type a() :: <<_:A * (12 * 8)>>. ", ); } #[test] fn parse_multi_line_string() { let _result: Module = parse( ParseConfig::default(), Arc::new(CodeMap::new()), r#"-module(foo). -deprecated([{woo, 0, "testing testing" "testing testing"}]). woo() -> 2. "#, ); } #[test] fn parse_multi_line_record() { let _result: Module = parse( ParseConfig::default(), Arc::new(CodeMap::new()), r#"-module(foo). -record(some_record, { woohoo }). "#, ); } #[test] fn parse_removed_attribute() { let _result: Module = parse( ParseConfig::default(), Arc::new(CodeMap::new()), r#"-module(foo). -removed([{foo, 0, "we don't support this anymore!"}]). "#, ); } #[test] fn parse_on_load() { let _result: Module = parse( ParseConfig::default(), Arc::new(CodeMap::new()), r#"-module(foo). -on_load(bar/0). bar() -> yay. "#, ); } #[test] fn parse_elixir_enum_erl() { use std::io::Read; let file = std::fs::File::open("../test_data/Elixir.Enum.erl"); let mut string = String::new(); file.unwrap().read_to_string(&mut string).unwrap(); let codemap = Arc::new(CodeMap::new()); let _result: Module = parse(ParseConfig::default(), codemap, &string); } } ================================================ FILE: libeir_syntax_erl/src/preprocessor/directive.rs ================================================ use std::fmt; use libeir_diagnostics::SourceSpan; use crate::lexer::{AtomToken, LexicalToken, SymbolToken, Token}; use super::Result; use super::directives; use super::token_reader::{ReadFrom, TokenReader}; /// Macro directive #[derive(Debug, Clone)] pub enum Directive { Module(directives::Module), Include(directives::Include), IncludeLib(directives::IncludeLib), Define(directives::Define), Undef(directives::Undef), Ifdef(directives::Ifdef), Ifndef(directives::Ifndef), If(directives::If), Else(directives::Else), Elif(directives::Elif), Endif(directives::Endif), Error(directives::Error), Warning(directives::Warning), File(directives::File), } impl Directive { pub fn span(&self) -> SourceSpan { match *self { Directive::Module(ref t) => t.span(), Directive::Include(ref t) => t.span(), Directive::IncludeLib(ref t) => t.span(), Directive::Define(ref t) => t.span(), Directive::Undef(ref t) => t.span(), Directive::Ifdef(ref t) => t.span(), Directive::Ifndef(ref t) => t.span(), Directive::If(ref t) => t.span(), Directive::Else(ref t) => t.span(), Directive::Elif(ref t) => t.span(), Directive::Endif(ref t) => t.span(), Directive::Error(ref t) => t.span(), Directive::Warning(ref t) => t.span(), Directive::File(ref t) => t.span(), } } } impl fmt::Display for Directive { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { Directive::Module(ref t) => t.fmt(f), Directive::Include(ref t) => t.fmt(f), Directive::IncludeLib(ref t) => t.fmt(f), Directive::Define(ref t) => t.fmt(f), Directive::Undef(ref t) => t.fmt(f), Directive::Ifdef(ref t) => t.fmt(f), Directive::Ifndef(ref t) => t.fmt(f), Directive::If(ref t) => t.fmt(f), Directive::Else(ref t) => t.fmt(f), Directive::Elif(ref t) => t.fmt(f), Directive::Endif(ref t) => t.fmt(f), Directive::Error(ref t) => t.fmt(f), Directive::Warning(ref t) => t.fmt(f), Directive::File(ref t) => t.fmt(f), } } } impl ReadFrom for Directive { fn try_read_from(reader: &mut R) -> Result> where R: TokenReader, { macro_rules! unread_token { ($reader:expr, $hyphen:expr, $source:expr, $tok:expr) => {{ $reader.unread_token(LexicalToken($source.0, $tok, $source.2)); $reader.unread_token($hyphen); return Ok(None); }}; } let _hyphen: SymbolToken = if let Some(_hyphen) = reader.try_read_expected(&Token::Minus)? { _hyphen } else { return Ok(None); }; let name: AtomToken = if let Some(name) = reader.try_read()? { name } else { reader.unread_token(_hyphen.into()); return Ok(None); }; let name_sym = name.symbol().as_str().get(); // Replace atoms with more concrete tokens for special attributes, // but otherwise do nothing else with them match name_sym { "compile" => unread_token!(reader, _hyphen.into(), name, Token::Compile), "record" => unread_token!(reader, _hyphen.into(), name, Token::Record), "spec" => unread_token!(reader, _hyphen.into(), name, Token::Spec), "callback" => unread_token!(reader, _hyphen.into(), name, Token::Callback), "optional_callback" => { unread_token!(reader, _hyphen.into(), name, Token::OptionalCallback) } "import" => unread_token!(reader, _hyphen.into(), name, Token::Import), "export" => unread_token!(reader, _hyphen.into(), name, Token::Export), "export_type" => unread_token!(reader, _hyphen.into(), name, Token::ExportType), "removed" => unread_token!(reader, _hyphen.into(), name, Token::Removed), "vsn" => unread_token!(reader, _hyphen.into(), name, Token::Vsn), "author" => unread_token!(reader, _hyphen.into(), name, Token::Author), "on_load" => unread_token!(reader, _hyphen.into(), name, Token::OnLoad), "behaviour" => unread_token!(reader, _hyphen.into(), name, Token::Behaviour), "deprecated" => unread_token!(reader, _hyphen.into(), name, Token::Deprecated), "type" => unread_token!(reader, _hyphen.into(), name, Token::Type), "opaque" => unread_token!(reader, _hyphen.into(), name, Token::Opaque), _ => { reader.unread_token(name.clone().into()); reader.unread_token(_hyphen.into()); } } match name.symbol().as_str().get() { // -module(name) is treated as equivalent to -define(?MODULE, name) "module" => reader.read().map(Directive::Module).map(Some), // Actual preprocessor directives "include" => reader.read().map(Directive::Include).map(Some), "include_lib" => reader.read().map(Directive::IncludeLib).map(Some), "define" => reader.read().map(Directive::Define).map(Some), "undef" => reader.read().map(Directive::Undef).map(Some), "ifdef" => reader.read().map(Directive::Ifdef).map(Some), "ifndef" => reader.read().map(Directive::Ifndef).map(Some), "if" => reader.read().map(Directive::If).map(Some), "else" => reader.read().map(Directive::Else).map(Some), "elif" => reader.read().map(Directive::Elif).map(Some), "endif" => reader.read().map(Directive::Endif).map(Some), "error" => reader.read().map(Directive::Error).map(Some), "warning" => reader.read().map(Directive::Warning).map(Some), "file" => reader.read().map(Directive::File).map(Some), _ => Ok(None), } } } ================================================ FILE: libeir_syntax_erl/src/preprocessor/directives.rs ================================================ use std::collections::VecDeque; use std::fmt; use std::path::{Component, PathBuf}; use snafu::{ResultExt, Snafu}; use libeir_diagnostics::{Diagnostic, Label, SourceSpan}; use libeir_util_parse::substitute_path_variables; use libeir_util_parse::PathVariableSubstituteError; use crate::lexer::{symbols, Lexed, LexicalToken, Symbol, Token}; use crate::lexer::{AtomToken, IntegerToken, StringToken, SymbolToken}; use super::token_reader::{ReadFrom, TokenReader}; use super::types::{MacroName, MacroVariables}; use super::{PreprocessorError, Result}; #[derive(Debug)] pub enum IncludeLibErrorVariant { NoAppNameComponent, NotFound { searched: Vec, }, } #[derive(Debug, Snafu)] pub enum DirectiveError { #[snafu(display("{}", source))] PathSubstitute { span: SourceSpan, source: PathVariableSubstituteError, }, #[snafu(display("could not find file"))] FileNotFound { span: SourceSpan, searched: Vec, }, #[snafu(display("include_lib could not find file"))] IncludeLibError { span: SourceSpan, first_searched: Vec, second: IncludeLibErrorVariant, }, } impl DirectiveError { pub fn to_diagnostic(&self) -> Diagnostic { match self { DirectiveError::PathSubstitute { span, source } => Diagnostic::error() .with_message(source.to_string()) .with_labels(vec![Label::primary(span.source_id(), *span) .with_message("in expansion of this path")]), DirectiveError::FileNotFound { span, searched } => { let aux_msg = if searched.is_empty() { format!("attempted searching include paths, but none were specified\n") } else { let mut msg = format!("attempted searching search paths:\n"); for path in searched.iter() { msg.push_str(path); msg.push('\n'); } msg }; Diagnostic::error() .with_message("could not find file") .with_labels(vec![ Label::primary(span.source_id(), *span).with_message("failed to find file") ]) .with_notes(vec![aux_msg]) } DirectiveError::IncludeLibError { span, first_searched, second } => { let aux_msg_1 = if first_searched.is_empty() { format!("first, attempted searching include paths, but none were specified\n") } else { let mut msg = format!("first, attempted searching include paths:\n"); for path in first_searched.iter() { msg.push_str(" - "); msg.push_str(path); msg.push('\n'); } msg }; let aux_msg_2 = match second { IncludeLibErrorVariant::NoAppNameComponent => { format!("then, attempted searching codepath, but first path component wasn't an application directory!") }, IncludeLibErrorVariant::NotFound { searched } if searched.is_empty() => { format!("then, attempted searching codepath, but none were specified\n") }, IncludeLibErrorVariant::NotFound { searched } => { let mut msg = format!("then, attempted include from codepath:\n"); if searched.is_empty() { msg.push_str("[]\n"); } for path in searched.iter() { msg.push_str(" - "); msg.push_str(path); msg.push('\n'); } msg }, }; Diagnostic::error() .with_message("could not find file") .with_labels(vec![ Label::primary(span.source_id(), *span).with_message("failed to find file") ]) .with_notes(vec![aux_msg_1, aux_msg_2]) } } } } type DirectiveResult = std::result::Result; /// `module` directive. /// /// Not really a directive, but we need it for the ?MODULE macro #[derive(Debug, Clone)] pub struct Module { pub _hyphen: SymbolToken, pub _module: AtomToken, pub _open_paren: SymbolToken, pub name: AtomToken, pub _close_paren: SymbolToken, pub _dot: SymbolToken, } impl Module { pub fn span(&self) -> SourceSpan { let start = self._hyphen.0; let end = self._dot.2; SourceSpan::new(start, end) } pub fn expand(&self) -> VecDeque { let mod_span = self._module.span(); vec![ self._hyphen.clone().into(), LexicalToken(mod_span.start(), Token::Module, mod_span.end()), self._open_paren.clone().into(), self.name.clone().into(), self._close_paren.clone().into(), self._dot.clone().into(), ] .into() } } impl Eq for Module {} impl PartialEq for Module { fn eq(&self, other: &Self) -> bool { self.name.symbol() == other.name.symbol() } } impl fmt::Display for Module { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "-module({}).", self.name.symbol()) } } impl ReadFrom for Module { fn read_from(reader: &mut R) -> Result where R: TokenReader, { Ok(Module { _hyphen: reader.read_expected(&Token::Minus)?, _module: reader.read_expected(&symbols::Module)?, _open_paren: reader.read_expected(&Token::LParen)?, name: reader.read()?, _close_paren: reader.read_expected(&Token::RParen)?, _dot: reader.read_expected(&Token::Dot)?, }) } } fn do_include(subs_path: &PathBuf, include_paths: &VecDeque) -> std::result::Result> { let mut tmp_path = PathBuf::new(); for include_path in include_paths.iter() { tmp_path.push(include_path); tmp_path.push(subs_path); if tmp_path.exists() { return Ok(tmp_path); } tmp_path.clear(); } let searched: Vec = include_paths .iter() .map(|path| { path.to_str() .map(|v| v.to_owned()) .unwrap_or_else(|| path.to_string_lossy().chars().collect()) }) .collect(); Err(searched) } /// `include` directive. /// /// See [9.1 File Inclusion](http://erlang.org/doc/reference_manual/macros.html#id85412) /// for detailed information. #[derive(Debug, Clone)] pub struct Include { pub _hyphen: SymbolToken, pub _include: AtomToken, pub _open_paren: SymbolToken, pub path: StringToken, pub _close_paren: SymbolToken, pub _dot: SymbolToken, } impl Include { /// Executes file inclusion. pub fn include(&self, include_paths: &VecDeque) -> DirectiveResult { let path = substitute_path_variables(self.path.symbol().as_str().get()).context( PathSubstitute { span: self.path.span(), }, )?; match do_include(&path, include_paths) { Ok(path) => Ok(path), Err(searched) => Err(DirectiveError::FileNotFound { span: self.span(), searched, }), } } pub fn span(&self) -> SourceSpan { let start = self._hyphen.0; let end = self._dot.2; SourceSpan::new(start, end) } } impl Eq for Include {} impl PartialEq for Include { fn eq(&self, other: &Self) -> bool { self.path.symbol() == other.path.symbol() } } impl fmt::Display for Include { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "-include({}).", self.path.symbol()) } } impl ReadFrom for Include { fn read_from(reader: &mut R) -> Result where R: TokenReader, { Ok(Include { _hyphen: reader.read_expected(&Token::Minus)?, _include: reader.read_expected(&symbols::Include)?, _open_paren: reader.read_expected(&Token::LParen)?, path: reader.read()?, _close_paren: reader.read_expected(&Token::RParen)?, _dot: reader.read_expected(&Token::Dot)?, }) } } /// `include_lib` directive. /// /// See [9.1 File Inclusion](http://erlang.org/doc/reference_manual/macros.html#id85412) /// for detailed information. #[derive(Debug, Clone)] #[allow(missing_docs)] pub struct IncludeLib { pub _hyphen: SymbolToken, pub _include_lib: AtomToken, pub _open_paren: SymbolToken, pub path: StringToken, pub _close_paren: SymbolToken, pub _dot: SymbolToken, } impl IncludeLib { /// Executes file inclusion. pub fn include_lib(&self, include_paths: &VecDeque, code_paths: &VecDeque) -> DirectiveResult { let path = substitute_path_variables(self.path.symbol().as_str().get()).context( PathSubstitute { span: self.path.span(), }, )?; let first_searched = match do_include(&path, include_paths) { Ok(path) => return Ok(path), Err(searched) => searched, }; let mut second_searched = Vec::new(); let components: Vec<_> = path.components().collect(); if let Component::Normal(_app_name) = &components[0] { for root in code_paths.iter() { let full_path = root.join(&path); if full_path.exists() { return Ok(full_path); } let string = full_path.to_str() .map(|v| v.to_owned()) .unwrap_or_else(|| path.to_string_lossy().chars().collect()); second_searched.push(string); } Err(DirectiveError::IncludeLibError { span: self.span(), first_searched, second: IncludeLibErrorVariant::NotFound { searched: second_searched, }, }) } else { Err(DirectiveError::IncludeLibError { span: self.span(), first_searched, second: IncludeLibErrorVariant::NoAppNameComponent, }) } } pub fn span(&self) -> SourceSpan { let start = self._hyphen.0; let end = self._dot.2; SourceSpan::new(start, end) } } impl Eq for IncludeLib {} impl PartialEq for IncludeLib { fn eq(&self, other: &Self) -> bool { self.path.symbol() == other.path.symbol() } } impl fmt::Display for IncludeLib { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "-include_lib({}).", self.path.symbol()) } } impl ReadFrom for IncludeLib { fn read_from(reader: &mut R) -> Result where R: TokenReader, { Ok(IncludeLib { _hyphen: reader.read_expected(&Token::Minus)?, _include_lib: reader.read_expected(&symbols::IncludeLib)?, _open_paren: reader.read_expected(&Token::LParen)?, path: reader.read()?, _close_paren: reader.read_expected(&Token::RParen)?, _dot: reader.read_expected(&Token::Dot)?, }) } } /// `error` directive. /// /// See [9.6 -error() and -warning() directives][error_and_warning] /// for detailed information. /// /// [error_and_warning]: http://erlang.org/doc/reference_manual/macros.html#id85997 #[derive(Debug, Clone)] pub struct Error { pub _hyphen: SymbolToken, pub _error: AtomToken, pub _open_paren: SymbolToken, pub message: StringToken, pub _close_paren: SymbolToken, pub _dot: SymbolToken, } impl Error { pub fn span(&self) -> SourceSpan { let start = self._hyphen.0; let end = self._dot.2; SourceSpan::new(start, end) } } impl Eq for Error {} impl PartialEq for Error { fn eq(&self, other: &Self) -> bool { self.message.symbol() == other.message.symbol() } } impl fmt::Display for Error { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "-error({}).", self.message.symbol()) } } impl ReadFrom for Error { fn read_from(reader: &mut R) -> Result where R: TokenReader, { Ok(Error { _hyphen: reader.read_expected(&Token::Minus)?, _error: reader.read_expected(&symbols::Error)?, _open_paren: reader.read_expected(&Token::LParen)?, message: reader.read()?, _close_paren: reader.read_expected(&Token::RParen)?, _dot: reader.read_expected(&Token::Dot)?, }) } } /// `warning` directive. /// /// See [9.6 -error() and -warning() directives][error_and_warning] /// for detailed information. /// /// [error_and_warning]: http://erlang.org/doc/reference_manual/macros.html#id85997 #[derive(Debug, Clone)] pub struct Warning { pub _hyphen: SymbolToken, pub _warning: AtomToken, pub _open_paren: SymbolToken, pub message: StringToken, pub _close_paren: SymbolToken, pub _dot: SymbolToken, } impl Warning { pub fn span(&self) -> SourceSpan { let start = self._hyphen.0; let end = self._dot.2; SourceSpan::new(start, end) } } impl Eq for Warning {} impl PartialEq for Warning { fn eq(&self, other: &Self) -> bool { self.message.symbol() == other.message.symbol() } } impl fmt::Display for Warning { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "-warning({}).", self.message.symbol()) } } impl ReadFrom for Warning { fn read_from(reader: &mut R) -> Result where R: TokenReader, { Ok(Warning { _hyphen: reader.read_expected(&Token::Minus)?, _warning: reader.read_expected(&symbols::Warning)?, _open_paren: reader.read_expected(&Token::LParen)?, message: reader.read()?, _close_paren: reader.read_expected(&Token::RParen)?, _dot: reader.read_expected(&Token::Dot)?, }) } } /// `endif` directive. /// /// See [9.5 Flow Control in Macros][flow_control] for detailed information. /// /// [flow_control]: http://erlang.org/doc/reference_manual/macros.html#id85859 #[derive(Debug, Clone)] pub struct Endif { pub _hyphen: SymbolToken, pub _endif: AtomToken, pub _dot: SymbolToken, } impl Endif { pub fn span(&self) -> SourceSpan { let start = self._hyphen.0; let end = self._dot.2; SourceSpan::new(start, end) } } impl Eq for Endif {} impl PartialEq for Endif { fn eq(&self, _other: &Self) -> bool { true } } impl fmt::Display for Endif { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "-endif.") } } impl ReadFrom for Endif { fn read_from(reader: &mut R) -> Result where R: TokenReader, { Ok(Endif { _hyphen: reader.read_expected(&Token::Minus)?, _endif: reader.read_expected(&symbols::Endif)?, _dot: reader.read_expected(&Token::Dot)?, }) } } /// `else` directive. /// /// See [9.5 Flow Control in Macros][flow_control] for detailed information. /// /// [flow_control]: http://erlang.org/doc/reference_manual/macros.html#id85859 #[derive(Debug, Clone)] pub struct Else { pub _hyphen: SymbolToken, pub _else: AtomToken, pub _dot: SymbolToken, } impl Else { pub fn span(&self) -> SourceSpan { let start = self._hyphen.0; let end = self._dot.2; SourceSpan::new(start, end) } } impl Eq for Else {} impl PartialEq for Else { fn eq(&self, _other: &Self) -> bool { true } } impl fmt::Display for Else { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "-else.") } } impl ReadFrom for Else { fn read_from(reader: &mut R) -> Result where R: TokenReader, { Ok(Else { _hyphen: reader.read_expected(&Token::Minus)?, _else: reader.read_expected(&symbols::Else)?, _dot: reader.read_expected(&Token::Dot)?, }) } } /// `undef` directive. /// /// See [9.5 Flow Control in Macros][flow_control] for detailed information. /// /// [flow_control]: http://erlang.org/doc/reference_manual/macros.html#id85859 #[derive(Debug, Clone)] pub struct Undef { pub _hyphen: SymbolToken, pub _undef: AtomToken, pub _open_paren: SymbolToken, pub name: MacroName, pub _close_paren: SymbolToken, pub _dot: SymbolToken, } impl Undef { pub fn span(&self) -> SourceSpan { let start = self._hyphen.0; let end = self._dot.2; SourceSpan::new(start, end) } pub fn name(&self) -> Symbol { self.name.symbol() } } impl Eq for Undef {} impl PartialEq for Undef { fn eq(&self, other: &Self) -> bool { self.name == other.name } } impl fmt::Display for Undef { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "-undef({}).", self.name.symbol()) } } impl ReadFrom for Undef { fn read_from(reader: &mut R) -> Result where R: TokenReader, { Ok(Undef { _hyphen: reader.read_expected(&Token::Minus)?, _undef: reader.read_expected(&symbols::Undef)?, _open_paren: reader.read_expected(&Token::LParen)?, name: reader.read()?, _close_paren: reader.read_expected(&Token::RParen)?, _dot: reader.read_expected(&Token::Dot)?, }) } } /// `if` directive. /// /// See [9.5 Flow Control in Macros][flow_control] for detailed information. /// /// [flow_control]: http://erlang.org/doc/reference_manual/macros.html#id85859 #[derive(Debug, Clone)] pub struct If { pub _hyphen: SymbolToken, pub _if: AtomToken, pub _open_paren: SymbolToken, pub condition: VecDeque, pub _close_paren: SymbolToken, pub _dot: SymbolToken, } impl If { pub fn span(&self) -> SourceSpan { let start = self._hyphen.0; let end = self._dot.2; SourceSpan::new(start, end) } } impl Eq for If {} impl PartialEq for If { fn eq(&self, other: &Self) -> bool { self.condition == other.condition } } impl fmt::Display for If { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "-if({:?}).", self.condition) } } impl ReadFrom for If { fn read_from(reader: &mut R) -> Result where R: TokenReader, { Ok(If { _hyphen: reader.read_expected(&Token::Minus)?, _if: reader.read_expected(&symbols::If)?, _open_paren: reader.read_expected(&Token::LParen)?, condition: read_condition(reader)?, _close_paren: reader.read_expected(&Token::RParen)?, _dot: reader.read_expected(&Token::Dot)?, }) } } /// `elif` directive. /// /// See [9.5 Flow Control in Macros][flow_control] for detailed information. /// /// [flow_control]: http://erlang.org/doc/reference_manual/macros.html#id85859 #[derive(Debug, Clone)] pub struct Elif { pub _hyphen: SymbolToken, pub _elif: AtomToken, pub _open_paren: SymbolToken, pub condition: VecDeque, pub _close_paren: SymbolToken, pub _dot: SymbolToken, } impl Elif { pub fn span(&self) -> SourceSpan { let start = self._hyphen.0; let end = self._dot.2; SourceSpan::new(start, end) } } impl Eq for Elif {} impl PartialEq for Elif { fn eq(&self, other: &Self) -> bool { self.condition == other.condition } } impl fmt::Display for Elif { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "-elif({:?}).", self.condition) } } impl ReadFrom for Elif { fn read_from(reader: &mut R) -> Result where R: TokenReader, { Ok(Elif { _hyphen: reader.read_expected(&Token::Minus)?, _elif: reader.read_expected(&symbols::Elif)?, _open_paren: reader.read_expected(&Token::LParen)?, condition: read_condition(reader)?, _close_paren: reader.read_expected(&Token::RParen)?, _dot: reader.read_expected(&Token::Dot)?, }) } } fn read_condition(reader: &mut R) -> Result> where R: TokenReader, { let mut open = 0; let mut condition = VecDeque::new(); loop { match reader.try_read_token()? { None => return Err(PreprocessorError::UnexpectedEOF), Some(token) => match token { LexicalToken(_, Token::LParen, _) => { open = open + 1; condition.push_back(Ok(token)); } LexicalToken(_, Token::RParen, _) if open == 0 => { reader.unread_token(token); break; } LexicalToken(_, Token::RParen, _) => { open = open - 1; condition.push_back(Ok(token)); } _ => { condition.push_back(Ok(token)); } }, } } Ok(condition) } /// `ifdef` directive. /// /// See [9.5 Flow Control in Macros][flow_control] for detailed information. /// /// [flow_control]: http://erlang.org/doc/reference_manual/macros.html#id85859 #[derive(Debug, Clone)] pub struct Ifdef { pub _hyphen: SymbolToken, pub _ifdef: AtomToken, pub _open_paren: SymbolToken, pub name: MacroName, pub _close_paren: SymbolToken, pub _dot: SymbolToken, } impl Ifdef { pub fn span(&self) -> SourceSpan { let start = self._hyphen.0; let end = self._dot.2; SourceSpan::new(start, end) } pub fn name(&self) -> Symbol { self.name.symbol() } } impl Eq for Ifdef {} impl PartialEq for Ifdef { fn eq(&self, other: &Self) -> bool { self.name == other.name } } impl fmt::Display for Ifdef { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "-ifdef({}).", self.name.symbol()) } } impl ReadFrom for Ifdef { fn read_from(reader: &mut R) -> Result where R: TokenReader, { Ok(Ifdef { _hyphen: reader.read_expected(&Token::Minus)?, _ifdef: reader.read_expected(&symbols::Ifdef)?, _open_paren: reader.read_expected(&Token::LParen)?, name: reader.read()?, _close_paren: reader.read_expected(&Token::RParen)?, _dot: reader.read_expected(&Token::Dot)?, }) } } /// `ifndef` directive. /// /// See [9.5 Flow Control in Macros][flow_control] for detailed information. /// /// [flow_control]: http://erlang.org/doc/reference_manual/macros.html#id85859 #[derive(Debug, Clone)] pub struct Ifndef { pub _hyphen: SymbolToken, pub _ifndef: AtomToken, pub _open_paren: SymbolToken, pub name: MacroName, pub _close_paren: SymbolToken, pub _dot: SymbolToken, } impl Ifndef { pub fn span(&self) -> SourceSpan { let start = self._hyphen.0; let end = self._dot.2; SourceSpan::new(start, end) } pub fn name(&self) -> Symbol { self.name.symbol() } } impl Eq for Ifndef {} impl PartialEq for Ifndef { fn eq(&self, other: &Self) -> bool { self.name == other.name } } impl fmt::Display for Ifndef { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "-ifndef({}).", self.name.symbol()) } } impl ReadFrom for Ifndef { fn read_from(reader: &mut R) -> Result where R: TokenReader, { Ok(Ifndef { _hyphen: reader.read_expected(&Token::Minus)?, _ifndef: reader.read_expected(&symbols::Ifndef)?, _open_paren: reader.read_expected(&Token::LParen)?, name: reader.read()?, _close_paren: reader.read_expected(&Token::RParen)?, _dot: reader.read_expected(&Token::Dot)?, }) } } /// `define` directive. /// /// See [9.2 Defining and Using Macros][define_and_use] for detailed information. /// /// [define_and_use]: http://erlang.org/doc/reference_manual/macros.html#id85572 #[derive(Debug, Clone)] pub struct Define { pub _hyphen: SymbolToken, pub _define: AtomToken, pub _open_paren: SymbolToken, pub name: MacroName, pub variables: Option, pub _comma: SymbolToken, pub replacement: Vec, pub _close_paren: SymbolToken, pub _dot: SymbolToken, } impl Define { pub fn span(&self) -> SourceSpan { let start = self._hyphen.0; let end = self._dot.0; SourceSpan::new(start, end) } } impl Eq for Define {} impl PartialEq for Define { fn eq(&self, other: &Self) -> bool { self.name == other.name && self.variables == other.variables && self.replacement == other.replacement } } impl fmt::Display for Define { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!( f, "-define({}{}, {}).", self.name, self.variables .as_ref() .map_or("".to_string(), |v| v.to_string(),), self.replacement .iter() .map(|t| t.to_string()) .collect::() ) } } impl ReadFrom for Define { fn read_from(reader: &mut R) -> Result where R: TokenReader, { let _hyphen = reader.read_expected(&Token::Minus)?; let _define = reader.read_expected(&symbols::Define)?; let _open_paren = reader.read_expected(&Token::LParen)?; let name = reader.read()?; let variables = if let Some(token) = reader.try_read_expected::(&Token::LParen)? { reader.unread_token(token.into()); Some(reader.read()?) } else { None }; let _comma = reader.read_expected(&Token::Comma)?; let mut replacement = Vec::new(); loop { if let Some(_close_paren) = reader.try_read_expected(&Token::RParen)? { if let Some(_dot) = reader.try_read_expected(&Token::Dot)? { return Ok(Define { _hyphen, _define, _open_paren, name, variables, _comma, replacement, _close_paren, _dot, }); } replacement.push(_close_paren.into()); } else { replacement.push(reader.read_token()?); //match reader.read_token()? { // token @ LexicalToken(_, Token::Dot, _) => { // println!("yay {:?}", token); // return Err(PreprocessorError::UnexpectedToken(token, Vec::new())); // } // token => replacement.push(token), //} } } } } #[derive(Debug, Clone)] pub struct File { pub _hyphen: SymbolToken, pub _file: AtomToken, pub _open_paren: SymbolToken, pub path: StringToken, pub _comma: SymbolToken, pub line: IntegerToken, pub _close_paren: SymbolToken, pub _dot: SymbolToken, } impl File { pub fn span(&self) -> SourceSpan { let start = self._hyphen.0; let end = self._dot.0; SourceSpan::new(start, end) } } impl Eq for File {} impl PartialEq for File { fn eq(&self, other: &Self) -> bool { self.path.symbol() == other.path.symbol() && self.line == other.line } } impl fmt::Display for File { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "-file({}, {}).", self.path, self.line,) } } impl ReadFrom for File { fn read_from(reader: &mut R) -> Result where R: TokenReader, { Ok(File { _hyphen: reader.read_expected(&Token::Minus)?, _file: reader.read_expected(&symbols::File)?, _open_paren: reader.read_expected(&Token::LParen)?, path: reader.read()?, _comma: reader.read_expected(&Token::Comma)?, line: reader.read()?, _close_paren: reader.read_expected(&Token::RParen)?, _dot: reader.read_expected(&Token::Dot)?, }) } } ================================================ FILE: libeir_syntax_erl/src/preprocessor/errors.rs ================================================ use std; use std::path::PathBuf; use itertools::Itertools; use snafu::Snafu; use libeir_diagnostics::*; use libeir_intern::Symbol; use libeir_util_number::FloatError; use libeir_util_parse::SourceError; use crate::lexer::{LexicalError, LexicalToken, TokenConvertError}; use crate::parser::ParserError; use super::directive::Directive; use super::directives::DirectiveError; use super::macros::{MacroCall, MacroDef, Stringify}; #[derive(Debug, Snafu)] pub enum PreprocessorError { #[snafu(visibility(pub), display("{}", source))] Lexical { source: LexicalError }, #[snafu(visibility(pub), display("{}", source))] Source { source: SourceError }, #[snafu( visibility(pub), display("{} occurred while including {:?}", source, path) )] IncludeError { source: std::io::Error, path: PathBuf, span: SourceSpan, }, #[snafu(display("unable to parse constant expression"))] ParseError { span: SourceSpan, inner: Box, }, #[snafu(display("{}", reason))] CompilerError { span: Option, reason: String, }, #[snafu(display("invalid constant expression found in preprocessor directive"))] InvalidConstExpression { span: SourceSpan }, #[snafu(display("constant evaluation error"))] EvalError { source: crate::evaluator::EvalError }, #[snafu(visibility(pub))] BadDirective { source: DirectiveError }, #[snafu(display("invalid conditional expression"))] InvalidConditional { span: SourceSpan }, #[snafu(visibility(pub), display("call to builtin function failed"))] BuiltinFailed { span: SourceSpan, source: Box, }, #[snafu(display("found orphaned '-end.' directive"))] OrphanedEnd { directive: Directive }, #[snafu(display("found orphaned '-else.' directive"))] OrphanedElse { directive: Directive }, #[snafu(display("undefined macro"))] UndefinedStringifyMacro { call: Stringify }, #[snafu(display("undefined macro"))] UndefinedMacro { call: MacroCall }, #[snafu(display("invalid macro invocation"))] BadMacroCall { call: MacroCall, def: MacroDef, reason: String, }, #[snafu(display("{}", diagnostic.message))] ShowDiagnostic { diagnostic: Diagnostic }, #[snafu(display("unexpected token"))] InvalidTokenType { token: LexicalToken, expected: String, }, #[snafu(display("unexpected token"))] UnexpectedToken { token: LexicalToken, expected: Vec, }, #[snafu(display("unexpected eof"))] UnexpectedEOF, #[snafu(display("warning directive: {}", message))] WarningDirective { span: SourceSpan, message: Symbol, as_error: bool, }, } impl PreprocessorError { pub fn to_diagnostic(&self) -> Diagnostic { //let span = self.span(); //let msg = self.to_string(); match self { PreprocessorError::Lexical { source } => source.to_diagnostic(), PreprocessorError::Source { source } => source.to_diagnostic(), PreprocessorError::IncludeError { span, .. } => { Diagnostic::error() .with_message(self.to_string()) .with_labels(vec![ Label::primary(span.source_id(), *span) .with_message("while processing include directive"), ]) }, PreprocessorError::ParseError { span, inner } => { let err = inner.to_diagnostic(); let mut labels = vec![ Label::primary(span.source_id(), *span) .with_message("invalid constant expression") ]; for label in err.labels { labels.push(label); } Diagnostic::error() .with_message(self.to_string()) .with_labels(labels) } PreprocessorError::CompilerError { span: Some(span), reason } => Diagnostic::error() .with_message("found error directive") .with_labels(vec![ Label::primary(span.source_id(), *span) .with_message(reason) ]), PreprocessorError::CompilerError { span: None, reason } => Diagnostic::error().with_message(reason), PreprocessorError::InvalidConstExpression { span, .. } => Diagnostic::error() .with_message(self.to_string()) .with_labels(vec![ Label::primary(span.source_id(), *span) .with_message("expected valid constant expression (example: `?OTP_VERSION >= 21`)") ]), PreprocessorError::EvalError { source } => source.to_diagnostic(), PreprocessorError::BadDirective { source } => source.to_diagnostic(), PreprocessorError::InvalidConditional { span, .. } => Diagnostic::error() .with_message(self.to_string()) .with_labels(vec![ Label::primary(span.source_id(), *span) .with_message("expected 'true', 'false', or an expression which can be evaluated to 'true' or 'false'") ]), PreprocessorError::BuiltinFailed { span, source } => Diagnostic::error() .with_message(self.to_string()) .with_labels(vec![ Label::primary(span.source_id(), *span) .with_message(source.to_string()) ]), PreprocessorError::OrphanedEnd { directive } => { let span = directive.span(); Diagnostic::error() .with_message(self.to_string()) .with_labels(vec![ Label::primary(span.source_id(), span) ]) } PreprocessorError::OrphanedElse { directive } => { let span = directive.span(); Diagnostic::error() .with_message(self.to_string()) .with_labels(vec![ Label::primary(span.source_id(), span) ]) } PreprocessorError::UndefinedStringifyMacro { call } => { let span = call.span(); Diagnostic::error() .with_message(self.to_string()) .with_labels(vec![ Label::primary(span.source_id(), span) ]) } PreprocessorError::UndefinedMacro { call } => { let span = call.span(); Diagnostic::error() .with_message(self.to_string()) .with_labels(vec![ Label::primary(span.source_id(), span) ]) } PreprocessorError::BadMacroCall { call, def: MacroDef::String(_), reason, .. } => { let span = call.span(); Diagnostic::error() .with_message(self.to_string()) .with_labels(vec![ Label::primary(span.source_id(), span) .with_message(reason.to_owned()) ]) } PreprocessorError::BadMacroCall { call, def, reason, .. } => { let secondary_span = match def { MacroDef::Static(ref define) => define.span(), MacroDef::Dynamic(ref tokens) => { assert!(tokens.len() > 0); SourceSpan::new( tokens[0].span().start(), tokens.last().unwrap().span().end() ) }, _ => unreachable!() }; let call_span = call.span(); Diagnostic::error() .with_message(self.to_string()) .with_labels(vec![ Label::primary(call_span.source_id(), call_span) .with_message("this macro call does not match its definition"), Label::secondary(secondary_span.source_id(), secondary_span) .with_message(reason.to_owned()) ]) } PreprocessorError::ShowDiagnostic { diagnostic } => diagnostic.clone(), PreprocessorError::InvalidTokenType { token, expected } => { let token_span = token.span(); Diagnostic::error() .with_message(self.to_string()) .with_labels(vec![ Label::primary(token_span.source_id(), token_span) .with_message(format!("expected \"{}\"", expected)) ]) } PreprocessorError::UnexpectedToken { token, expected } => { let token_span = token.span(); if expected.len() > 0 { let expected = expected.iter() .map(|t| format!("\"{}\"", t)) .join(", "); Diagnostic::error() .with_message(self.to_string()) .with_labels(vec![ Label::primary(token_span.source_id(), token_span) .with_message(format!("expected one of {}", expected)) ]) } else { Diagnostic::error() .with_message(self.to_string()) .with_labels(vec![ Label::primary(token_span.source_id(), token_span) ]) } } PreprocessorError::UnexpectedEOF => Diagnostic::error().with_message(self.to_string()), PreprocessorError::WarningDirective { span, message, as_error } => { let message_str = message.as_str().get(); if *as_error { Diagnostic::error() } else { Diagnostic::warning() } .with_message("found warning directive") .with_labels(vec![ Label::primary(span.source_id(), *span).with_message(message_str), ]) } } } } impl From for PreprocessorError { fn from(source: LexicalError) -> PreprocessorError { PreprocessorError::Lexical { source } } } impl From for PreprocessorError { fn from(source: SourceError) -> PreprocessorError { PreprocessorError::Source { source } } } impl From for PreprocessorError { fn from(err: TokenConvertError) -> PreprocessorError { let span = err.span; let token = LexicalToken(span.start(), err.token, span.end()); PreprocessorError::InvalidTokenType { token, expected: err.expected.to_string(), } } } impl From for PreprocessorError { fn from(diagnostic: Diagnostic) -> Self { PreprocessorError::ShowDiagnostic { diagnostic } } } impl From for PreprocessorError { fn from(source: crate::evaluator::EvalError) -> Self { PreprocessorError::EvalError { source } } } ================================================ FILE: libeir_syntax_erl/src/preprocessor/macros.rs ================================================ use std::collections::HashMap; use std::fmt; use libeir_diagnostics::SourceSpan; use crate::lexer::{DelayedSubstitution, LexicalToken, Symbol, Token}; use crate::lexer::{IdentToken, SymbolToken}; use super::directives::Define; use super::token_reader::{ReadFrom, TokenReader}; use super::types::{MacroArgs, MacroName}; use super::Result; pub enum MacroIdent { Const(Symbol), Func(Symbol, usize), } impl MacroIdent { pub fn ident(&self) -> Symbol { match self { MacroIdent::Const(sym) => *sym, MacroIdent::Func(sym, _) => *sym, } } pub fn arity(&self) -> Option { match self { MacroIdent::Const(_) => None, MacroIdent::Func(_, arity) => Some(*arity), } } } impl From<&MacroCall> for MacroIdent { fn from(call: &MacroCall) -> MacroIdent { let ident = match &call.name { MacroName::Atom(tok) => tok.symbol(), MacroName::Variable(tok) => tok.symbol(), }; if let Some(args) = &call.args { MacroIdent::Func(ident, args.len()) } else { MacroIdent::Const(ident) } } } impl From<&super::directives::Define> for MacroIdent { fn from(def: &super::directives::Define) -> MacroIdent { let ident = match &def.name { MacroName::Atom(tok) => tok.symbol(), MacroName::Variable(tok) => tok.symbol(), }; if let Some(args) = &def.variables { MacroIdent::Func(ident, args.len()) } else { MacroIdent::Const(ident) } } } #[derive(Debug, Clone, PartialEq, Eq)] pub struct MacroContainer { func_defines: HashMap>, const_defines: HashMap, } impl MacroContainer { pub fn new() -> Self { MacroContainer { func_defines: HashMap::new(), const_defines: HashMap::new(), } } pub fn insert(&mut self, key: T, def: MacroDef) -> bool where T: Into, { let key: MacroIdent = key.into(); match key { MacroIdent::Const(name) => self.const_defines.insert(name, def).is_some(), MacroIdent::Func(name, arity) => { if !self.func_defines.contains_key(&name) { self.func_defines.insert(name, HashMap::new()); } let container = self.func_defines.get_mut(&name).unwrap(); container.insert(arity, def).is_some() } } } pub fn get<'a, T>(&'a self, key: T) -> Option<&'a MacroDef> where T: Into, { let key: MacroIdent = key.into(); match key { MacroIdent::Const(name) => self.const_defines.get(&name), MacroIdent::Func(name, arity) => { self.func_defines.get(&name).and_then(|c| c.get(&arity)) } } } pub fn undef(&mut self, symbol: &Symbol) -> bool { let mut res = false; res |= self.const_defines.remove(symbol).is_some(); res |= self.func_defines.remove(symbol).is_some(); res } pub fn defined(&self, symbol: &Symbol) -> bool { self.defined_const(symbol) || self.defined_func(symbol) } pub fn defined_const(&self, symbol: &Symbol) -> bool { self.const_defines.contains_key(symbol) } pub fn defined_func(&self, symbol: &Symbol) -> bool { self.func_defines.contains_key(symbol) } } /// Macro Definition. #[derive(Debug, Clone, PartialEq, Eq)] pub enum MacroDef { Boolean(bool), String(Symbol), Static(Define), Dynamic(Vec), DelayedSubstitution(DelayedSubstitution), } impl MacroDef { /// Returns `true` if this macro has variables, otherwise `false`. pub fn has_variables(&self) -> bool { match *self { MacroDef::Static(ref d) => d.variables.is_some(), MacroDef::Dynamic(_) => false, MacroDef::String(_) => false, MacroDef::Boolean(_) => false, MacroDef::DelayedSubstitution(_) => false, } } } /// Macro call. #[derive(Debug, Clone)] pub struct MacroCall { pub _question: SymbolToken, pub name: MacroName, pub args: Option, } impl MacroCall { pub fn span(&self) -> SourceSpan { let start = self._question.0; let end = self .args .as_ref() .map(|a| a.span().end()) .unwrap_or_else(|| self.name.span().end()); SourceSpan::new(start, end) } pub fn name(&self) -> Symbol { self.name.symbol() } } impl fmt::Display for MacroCall { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!( f, "?{}{}", self.name.symbol(), self.args.as_ref().map_or("".to_string(), |a| a.to_string()) ) } } impl ReadFrom for MacroCall { fn read_from(reader: &mut R) -> Result where R: TokenReader, { Ok(MacroCall { _question: reader.read_expected(&Token::Question)?, name: reader.read()?, args: reader.try_read()?, }) } } #[derive(Debug, Clone)] pub struct NoArgsMacroCall { pub _question: SymbolToken, pub name: MacroName, } impl NoArgsMacroCall { pub fn span(&self) -> SourceSpan { SourceSpan::new(self._question.span().start(), self.name.span().end()) } } impl ReadFrom for NoArgsMacroCall { fn read_from(reader: &mut R) -> Result where R: TokenReader, { Ok(NoArgsMacroCall { _question: reader.read_expected(&Token::Question)?, name: reader.read()?, }) } } #[derive(Debug, Clone)] pub struct Stringify { pub _double_question: SymbolToken, pub name: IdentToken, } impl Stringify { pub fn span(&self) -> SourceSpan { let start = self._double_question.0; let end = self.name.2; SourceSpan::new(start, end) } } impl fmt::Display for Stringify { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "??{}", self.name) } } impl ReadFrom for Stringify { fn read_from(reader: &mut R) -> Result where R: TokenReader, { Ok(Stringify { _double_question: reader.read_expected(&Token::DoubleQuestion)?, name: reader.read()?, }) } } ================================================ FILE: libeir_syntax_erl/src/preprocessor/mod.rs ================================================ mod directive; mod errors; //mod evaluator; mod macros; mod preprocessor; mod token_reader; mod token_stream; pub mod directives; pub mod types; pub use self::directive::Directive; pub use self::errors::PreprocessorError; pub use self::macros::{MacroCall, MacroContainer, MacroDef, MacroIdent}; pub use self::preprocessor::Preprocessor; use libeir_diagnostics::SourceIndex; use crate::lexer::Token; /// The result produced by the preprocessor pub type Preprocessed = std::result::Result<(SourceIndex, Token, SourceIndex), ()>; type Result = std::result::Result; ================================================ FILE: libeir_syntax_erl/src/preprocessor/preprocessor.rs ================================================ use std::collections::{BTreeMap, HashMap, VecDeque}; use std::convert::TryFrom; use std::path::PathBuf; use std::sync::Arc; use snafu::ResultExt; use libeir_diagnostics::*; use libeir_util_parse::{ErrorReceiver, ErrorReceiverTee, Source}; use crate::evaluator; use crate::lexer::Lexer; use crate::lexer::{symbols, DelayedSubstitution, IdentToken, Lexed, LexicalToken, Symbol, Token}; use crate::parser::Parser; use super::errors; use super::macros::Stringify; use super::token_reader::{TokenBufferReader, TokenReader, TokenStreamReader}; use super::{Directive, MacroCall, MacroContainer, MacroDef, MacroIdent}; use super::{Preprocessed, PreprocessorError, Result as PResult}; type Errors<'a> = ErrorReceiverTee<'a, PreprocessorError, PreprocessorError>; macro_rules! error_into { ($errors:expr, $result:expr) => { match $result { Ok(inner) => Ok(inner), Err(error) => { $errors.error(error.into()); Err(()) } } }; } pub struct Preprocessor<'a, Reader: TokenReader> { errors: Errors<'a>, codemap: Arc, reader: Reader, can_directive_start: bool, directives: BTreeMap, code_paths: VecDeque, include_paths: VecDeque, branches: Vec, macros: MacroContainer, macro_calls: BTreeMap, expanded_tokens: VecDeque, warnings_as_errors: bool, no_warn: bool, } impl<'a, S> Preprocessor<'a, TokenStreamReader> where S: Source, { pub fn new(parser: &Parser, tokens: Lexer, errors: Errors<'a>) -> Self { let reader = TokenStreamReader::new(parser.codemap.clone(), tokens); let code_paths = parser.config.code_paths.clone(); let include_paths = parser.config.include_paths.clone(); let mut macros = match parser.config.macros { None => MacroContainer::new(), Some(ref macros) => macros.clone(), }; macros.insert( MacroIdent::Const(Symbol::intern("FUNCTION_NAME")), MacroDef::DelayedSubstitution(DelayedSubstitution::FunctionName), ); macros.insert( MacroIdent::Const(Symbol::intern("FUNCTION_ARITY")), MacroDef::DelayedSubstitution(DelayedSubstitution::FunctionArity), ); Preprocessor { errors, codemap: parser.codemap.clone(), reader, can_directive_start: true, directives: BTreeMap::new(), code_paths, include_paths, branches: Vec::new(), macros, macro_calls: BTreeMap::new(), expanded_tokens: VecDeque::new(), warnings_as_errors: parser.config.warnings_as_errors, no_warn: parser.config.no_warn, } } } impl<'a, R, S> Preprocessor<'a, R> where R: TokenReader, { fn clone_with(&self, tokens: VecDeque) -> Preprocessor { let codemap = self.codemap.clone(); let reader = TokenBufferReader::new(codemap.clone(), tokens); Preprocessor { errors: self.errors.clone(), codemap, reader, can_directive_start: false, directives: BTreeMap::new(), code_paths: self.code_paths.clone(), include_paths: self.include_paths.clone(), branches: Vec::new(), macros: self.macros.clone(), macro_calls: BTreeMap::new(), expanded_tokens: VecDeque::new(), warnings_as_errors: self.warnings_as_errors, no_warn: self.no_warn, } } fn ignore(&self) -> bool { self.branches.iter().any(|b| !b.entered) } fn next_token(&mut self) -> Result, ()> { loop { if let Some(token) = self.expanded_tokens.pop_front() { return Ok(Some(token)); } if self.can_directive_start { match self.try_read_directive()? { Some(Directive::Module(d)) => { // We need to expand this directive back to a token stream for the parser self.expanded_tokens = d.expand(); // Otherwise treat it like other directives self.directives .insert(d.span().start(), Directive::Module(d)); continue; } Some(d) => { self.directives.insert(d.span().start(), d); continue; } None => (), } } if !self.ignore() { if let Some(m) = error_into!(self.errors, self.reader.try_read_macro_call(&self.macros))? { self.macro_calls.insert(m.span().start(), m.clone()); self.expanded_tokens = error_into!(self.errors, self.expand_macro(m))?; continue; } } if let Some(token) = error_into!(self.errors, self.reader.try_read_token())? { if self.ignore() { continue; } if let LexicalToken(_, Token::Dot, _) = token { self.can_directive_start = true; } else { self.can_directive_start = false; } return Ok(Some(token)); } else { break; } } Ok(None) } fn expand_macro(&self, call: MacroCall) -> PResult> { if let Some(expanded) = self.try_expand_predefined_macro(&call)? { Ok(vec![expanded].into()) } else { self.expand_userdefined_macro(call) } } fn try_expand_predefined_macro(&self, call: &MacroCall) -> PResult> { let expanded = match call.name().as_str().get() { "FILE" => { let span = call.span(); let source_id = span.source_id(); let current = span.start(); let file = self.codemap.get(source_id).unwrap(); let filename = file.name().to_string(); LexicalToken( current, Token::String(Symbol::intern(&filename)), span.end(), ) } "LINE" => { let span = call.span(); let source_id = span.source_id(); let current = span.start(); let file = self.codemap.get(source_id).unwrap(); let line = file.line_index(current.index()).to_usize() as i64; LexicalToken(current, Token::Integer(line.into()), span.end()) } "MACHINE" => { let span = call.span(); let current = span.start(); LexicalToken(current, Token::Atom(Symbol::intern("Lumen")), span.end()) } _ => return Ok(None), }; Ok(Some(expanded)) } fn expand_userdefined_macro(&self, call: MacroCall) -> PResult> { let span = call.span(); let definition = match self.macros.get(&call) { None => return Err(PreprocessorError::UndefinedMacro { call }), Some(def) => def, }; match definition { MacroDef::Dynamic(replacement) => { let mut replacement = replacement.clone(); for token in replacement.iter_mut() { token.0 = span.start(); token.2 = span.end(); } Ok(replacement.into()) }, MacroDef::String(s) => Ok(vec![LexicalToken( span.start(), Token::String(s.clone()), span.end(), )] .into()), MacroDef::Boolean(true) => Ok(vec![LexicalToken( span.start(), Token::Atom(symbols::True), span.end(), )] .into()), MacroDef::Boolean(false) => Ok(VecDeque::new()), MacroDef::Static(def) => { let arity = def.variables.as_ref().map(|v| v.len()).unwrap_or(0); let argc = call.args.as_ref().map(|a| a.len()).unwrap_or(0); if arity != argc { let err = format!( "expected {} arguments at call site, but given {}", arity, argc ); return Err(PreprocessorError::BadMacroCall { call, def: definition.clone(), reason: err, }); } let bindings = def .variables .as_ref() .iter() .flat_map(|i| i.iter().map(|v| v.symbol())) .zip( call.args .iter() .flat_map(|i| i.iter().map(|a| &a.tokens[..])), ) .collect::>(); let mut expanded = self.expand_replacement(bindings, &def.replacement)?; for token in expanded.iter_mut() { token.0 = span.start(); token.2 = span.end(); } Ok(expanded) } MacroDef::DelayedSubstitution(subst) => Ok(vec![LexicalToken( span.start(), Token::DelayedSubstitution(*subst), span.end(), )] .into()), } } fn expand_replacement( &self, bindings: HashMap, replacement: &[LexicalToken], ) -> PResult> { let mut expanded = VecDeque::new(); let replacement_tokens: VecDeque<_> = replacement.iter().map(|t| Ok(t.clone())).collect(); let mut reader = TokenBufferReader::new(self.codemap.clone(), replacement_tokens); loop { if let Some(call) = reader.try_read_macro_call(&self.macros)? { let nested = self.expand_macro(call)?; for token in nested.into_iter().rev() { reader.unread_token(token); } } else if let Some(stringify) = reader.try_read::()? { let tokens = match bindings.get(&stringify.name.symbol()) { None => { return Err(PreprocessorError::UndefinedStringifyMacro { call: stringify }) } Some(tokens) => tokens, }; let string = tokens.iter().map(|t| t.to_string()).collect::(); let span = tokens[0].span(); let start = span.start(); let end = span.end(); let token = (start, Token::String(Symbol::intern(&string)), end); expanded.push_back(token.into()); } else if let Some(token) = reader.try_read_token()? { match IdentToken::try_from(token.clone()) { Ok(ident) => match bindings.get(&ident.symbol()) { Some(value) => { let nested = self.expand_replacement(HashMap::new(), value)?; expanded.extend(nested); continue; } None => (), }, Err(_) => (), } expanded.push_back(token); } else { break; } } Ok(expanded) } fn try_read_directive(&mut self) -> Result, ()> { let directive: Directive = if let Some(directive) = error_into!(self.errors, self.reader.try_read())? { directive } else { return Ok(None); }; let ignore = self.ignore(); match directive { Directive::Module(ref d) => { self.macros.insert( MacroIdent::Const(symbols::ModuleCapital), MacroDef::String(d.name.symbol()), ); self.macros.insert( MacroIdent::Const(symbols::ModuleStringCapital), MacroDef::String(d.name.symbol()), ); } Directive::Include(ref d) if !ignore => { let path = error_into!( self.errors, d.include(&self.include_paths).context(errors::BadDirective) )?; error_into!(self.errors, self.reader.inject_include(path, d.span()))?; } Directive::IncludeLib(ref d) if !ignore => { let path = error_into!( self.errors, d.include_lib(&self.include_paths, &self.code_paths) .context(errors::BadDirective) )?; error_into!(self.errors, self.reader.inject_include(path, d.span()))?; } Directive::Define(ref d) if !ignore => { self.macros.insert(d, MacroDef::Static(d.clone())); } Directive::Undef(ref d) if !ignore => { self.macros.undef(&d.name()); } Directive::Ifdef(ref d) => { let entered = self.macros.defined(&d.name()); self.branches.push(Branch::new(entered)); } Directive::If(ref d) => { let entered = self.eval_conditional(d.span(), d.condition.clone())?; self.branches.push(Branch::new(entered)); } Directive::Ifndef(ref d) => { let entered = !self.macros.defined(&d.name()); self.branches.push(Branch::new(entered)); } Directive::Else(_) => match self.branches.last_mut() { None => { return error_into!( self.errors, Err(PreprocessorError::OrphanedElse { directive }) ) } Some(branch) => { match branch.switch_to_else_branch() { Err(_) => { return error_into!( self.errors, Err(PreprocessorError::OrphanedElse { directive }) ) } Ok(_) => (), }; } }, Directive::Elif(ref d) => { // Treat this like -endif followed by -if(Cond) match self.branches.pop() { None => { return error_into!( self.errors, Err(PreprocessorError::OrphanedElse { directive }) ) } Some(_) => { let entered = self.eval_conditional(d.span(), d.condition.clone())?; self.branches.push(Branch::new(entered)); } } } Directive::Endif(_) => match self.branches.pop() { None => { return error_into!( self.errors, Err(PreprocessorError::OrphanedEnd { directive }) ) } Some(_) => (), }, Directive::Error(ref d) if !ignore => { let span = d.span(); let err = d.message.symbol().as_str().get().to_string(); return error_into!( self.errors, Err(PreprocessorError::CompilerError { span: Some(span), reason: err }) ); } Directive::Warning(ref d) if !ignore => { if self.no_warn { return Ok(Some(directive)); } if self.warnings_as_errors { let err = PreprocessorError::WarningDirective { span: d.span(), message: d.message.symbol(), as_error: true, }; return error_into!(self.errors, Err(err)); } else { let err = PreprocessorError::WarningDirective { span: d.span(), message: d.message.symbol(), as_error: false, }; self.errors.warning(err); } } Directive::File(ref f) if !ignore => { // TODO println!("TODO file directive {}", f); } _ => {} } Ok(Some(directive)) } fn eval_conditional( &mut self, span: SourceSpan, condition: VecDeque, ) -> Result { use crate::lexer::Ident; use crate::parser::ast::{Expr, Literal}; use crate::parser::Parse; let result = { let mut adapter = self.errors.make_adapter( move |v| PreprocessorError::ParseError { span, inner: Box::new(v), }, move |v| PreprocessorError::ParseError { span, inner: Box::new(v), }, ); let pp = self.clone_with(condition); // TODO add adapter which adds PreprocessorError between //let adapter = ErrorReceiverAdapter::new( // &mut self.errors, //); Expr::parse_tokens(&mut adapter, pp) }; match evaluator::eval_expr(&result?, None) { Ok(evaluator::Term::Atom(atom)) if atom == symbols::True => Ok(true), Ok(evaluator::Term::Atom(atom)) if atom == symbols::False => Ok(false), Err(err) => { self.errors.error(err.into()); return Err(()); } _other => { self.errors .error(PreprocessorError::InvalidConditional { span }.into()); return Err(()); } } } } impl<'a, R, S> Iterator for Preprocessor<'a, R> where R: TokenReader, { type Item = Preprocessed; fn next(&mut self) -> Option { match self.next_token() { Err(()) => Some(Err(())), Ok(None) => None, Ok(Some(token)) => Some(Ok(token.into())), } } } #[derive(Debug)] struct Branch { pub then_branch: bool, pub entered: bool, } impl Branch { pub fn new(entered: bool) -> Self { Branch { then_branch: true, entered, } } pub fn switch_to_else_branch(&mut self) -> Result<(), ()> { if !self.then_branch { return Err(()); } self.then_branch = false; self.entered = !self.entered; Ok(()) } } ================================================ FILE: libeir_syntax_erl/src/preprocessor/token_reader.rs ================================================ use std::collections::VecDeque; use std::convert::TryFrom; use std::fmt::Display; use std::fs; use std::path::Path; use std::sync::Arc; use snafu::ResultExt; use libeir_diagnostics::{CodeMap, SourceSpan}; use libeir_util_parse::{FileMapSource, Scanner, Source}; use crate::lexer::{AtomToken, SymbolToken, TokenConvertError}; use crate::lexer::{Lexed, Lexer, LexicalToken, Symbol, Token}; use super::errors; use super::macros::NoArgsMacroCall; use super::token_stream::TokenStream; use super::{MacroCall, MacroContainer, PreprocessorError, Result}; pub trait TokenReader: Sized { type Source; fn new(codemap: Arc, tokens: Self::Source) -> Self; fn inject_include

(&mut self, path: P, directive: SourceSpan) -> Result<()> where P: AsRef; fn read(&mut self) -> Result { V::read_from(self) } fn try_read(&mut self) -> Result> { V::try_read_from(self) } fn try_read_macro_call(&mut self, macros: &MacroContainer) -> Result> { if let Some(call) = self.try_read::()? { let span = call.span(); let start = span.start(); let mut call = MacroCall { _question: SymbolToken(start, Token::Question, start), name: call.name, args: None, }; // The logic for macro resolve/execution is as follows, in order: // 1. If there is only a constant macro of the given name and not // a function macro, apply the const without looking ahead. // 2. If there exists a function macro with the given name, and // there is a paren open following the macro identifier, then // try to resolve and execute the macro. If there is not a // function macro of the correct arity defined, error. // 3. If there is a constant macro, apply that. // 4. Error. // If there is a function macro defined with the name... if macros.defined_func(&call.name()) { let paren_ahead = if let Some(lex_tok) = self.try_read_token()? { let res = if let LexicalToken(_, Token::LParen, _) = lex_tok { true } else { false }; self.unread_token(lex_tok); res } else { false }; // If there is a following LParen, read arguments if paren_ahead { call.args = Some(self.read()?); } } Ok(Some(call)) } else { Ok(None) } } fn read_expected(&mut self, expected: &V::Value) -> Result where V: ReadFrom + Expect + Into, { V::read_expected(self, expected) } fn try_read_expected(&mut self, expected: &V::Value) -> Result> where V: ReadFrom + Expect + Into, { V::try_read_expected(self, expected) } fn try_read_token(&mut self) -> Result>; fn read_token(&mut self) -> Result; fn unread_token(&mut self, token: LexicalToken); } /// Reads tokens from an in-memory buffer (VecDeque) pub struct TokenBufferReader { codemap: Arc, tokens: VecDeque, unread: VecDeque, } impl TokenReader for TokenBufferReader { type Source = VecDeque; fn new(codemap: Arc, tokens: Self::Source) -> Self { TokenBufferReader { codemap: codemap.clone(), tokens, unread: VecDeque::new(), } } // Adds tokens from the provided path fn inject_include

(&mut self, path: P, directive: SourceSpan) -> Result<()> where P: AsRef, { let path = path.as_ref(); let content = std::fs::read_to_string(path).context(errors::IncludeError { path: path.to_owned(), span: directive, })?; let id = self.codemap.add(path, content); let file = self.codemap.get(id).unwrap(); let source = FileMapSource::new(file); let scanner = Scanner::new(source); let lexer = Lexer::new(scanner); let mut tokens: VecDeque = lexer.collect(); tokens.append(&mut self.tokens); self.tokens = tokens; Ok(()) } fn try_read_token(&mut self) -> Result> { if let Some(token) = self.unread.pop_front() { return Ok(Some(token)); } self.tokens.pop_front().transpose().context(errors::Lexical) } fn read_token(&mut self) -> Result { if let Some(token) = self.try_read_token()? { Ok(token) } else { Err(PreprocessorError::UnexpectedEOF) } } fn unread_token(&mut self, token: LexicalToken) { self.unread.push_front(token); } } /// Reads tokens from a TokenStream (backed by a Lexer) pub struct TokenStreamReader { codemap: Arc, tokens: TokenStream, unread: VecDeque, } impl TokenReader for TokenStreamReader where S: Source, { type Source = Lexer; fn new(codemap: Arc, tokens: Self::Source) -> Self { TokenStreamReader { codemap: codemap.clone(), tokens: TokenStream::new(tokens), unread: VecDeque::new(), } } // Adds tokens from the provided path fn inject_include

(&mut self, path: P, directive: SourceSpan) -> Result<()> where P: AsRef, { let path = path.as_ref(); let content = fs::read_to_string(path).context(errors::IncludeError { path: path.to_owned(), span: directive, })?; let id = self.codemap.add_child(path, content, directive); let file = self.codemap.get(id).unwrap(); let source = Source::new(file); let scanner = Scanner::new(source); let lexer = Lexer::new(scanner); self.tokens.include(lexer); Ok(()) } fn try_read_token(&mut self) -> Result> { if let Some(token) = self.unread.pop_front() { return Ok(Some(token)); } self.tokens.next().transpose().context(errors::Lexical) } fn read_token(&mut self) -> Result { if let Some(token) = self.try_read_token()? { Ok(token) } else { Err(PreprocessorError::UnexpectedEOF) } } fn unread_token(&mut self, token: LexicalToken) { self.unread.push_front(token); } } pub trait ReadFrom: Sized { fn read_from(reader: &mut R) -> Result where R: TokenReader, { let directive = Self::try_read_from(reader)?; Ok(directive.unwrap()) } fn try_read_from(reader: &mut R) -> Result> where R: TokenReader, { Self::read_from(reader).map(Some).or_else(|e| match e { PreprocessorError::UnexpectedToken { token, .. } => { reader.unread_token(token.clone()); return Ok(None); } PreprocessorError::InvalidTokenType { token, .. } => { reader.unread_token(token.clone()); return Ok(None); } PreprocessorError::UnexpectedEOF => { return Ok(None); } _ => Err(e), }) } fn read_expected(reader: &mut R, expected: &Self::Value) -> Result where R: TokenReader, Self: Expect + Into, { Self::read_from(reader) .map_err(|err| match err { PreprocessorError::UnexpectedToken { token, .. } => { PreprocessorError::UnexpectedToken { token, expected: vec![expected.to_string()], } } PreprocessorError::InvalidTokenType { token, .. } => { PreprocessorError::InvalidTokenType { token, expected: expected.to_string(), } } _ => err, }) .and_then(|token| { if token.expect(expected) { Ok(token) } else { Err(PreprocessorError::UnexpectedToken { token: token.into(), expected: vec![expected.to_string()], }) } }) } fn try_read_expected(reader: &mut R, expected: &Self::Value) -> Result> where R: TokenReader, Self: Expect + Into, { Self::try_read_from(reader).map(|token| { token.and_then(|token| { if token.expect(expected) { Some(token) } else { reader.unread_token(token.into()); None } }) }) } } /// Default implementation for all TryFrom supporting types impl ReadFrom for T where T: TryFrom, { fn read_from(reader: &mut R) -> Result where R: TokenReader, { let token = reader.read_token()?; Self::try_from(token).map_err(PreprocessorError::from) } } pub trait Expect { type Value: PartialEq + Display + ?Sized; fn expect(&self, expected: &Self::Value) -> bool; } impl Expect for AtomToken { type Value = Symbol; fn expect(&self, expected: &Self::Value) -> bool { self.symbol() == *expected } } impl Expect for SymbolToken { type Value = Token; fn expect(&self, expected: &Self::Value) -> bool { expected.eq(&self.token()) } } ================================================ FILE: libeir_syntax_erl/src/preprocessor/token_stream.rs ================================================ use std::collections::VecDeque; use crate::lexer::{Lexed, Lexer}; use libeir_util_parse::Source; pub struct TokenStream { eof: bool, current: Lexer, streams: VecDeque>, } impl TokenStream where S: Source, { pub fn new(current: Lexer) -> Self { TokenStream { eof: false, current, streams: VecDeque::new(), } } pub fn include(&mut self, next: Lexer) { if self.eof { self.eof = false; } let previous = std::mem::replace::>(&mut self.current, next); self.streams.push_front(previous); } } impl Iterator for TokenStream where S: Source, { type Item = Lexed; fn next(&mut self) -> Option { if self.eof == true { return None; } if let Some(next) = self.current.next() { return Some(next); } match self.streams.pop_front() { None => { self.eof = true; return None; } Some(next) => { self.current = next; return self.next(); } } } } ================================================ FILE: libeir_syntax_erl/src/preprocessor/types.rs ================================================ use std::fmt; use std::hash::{Hash, Hasher}; use std::mem; use libeir_diagnostics::SourceSpan; use crate::lexer::{AtomToken, IdentToken, SymbolToken}; use crate::lexer::{LexicalToken, Symbol, Token}; use super::token_reader::{ReadFrom, TokenReader}; use super::{PreprocessorError, Result}; /// The list of tokens that can be used as a macro name. #[derive(Debug, Clone)] pub enum MacroName { Atom(AtomToken), Variable(IdentToken), } impl MacroName { /// Returns the value of this token. pub fn value(&self) -> Token { match *self { MacroName::Atom(ref token) => token.token(), MacroName::Variable(ref token) => token.token(), } } /// Returns the original textual representation of this token. pub fn symbol(&self) -> Symbol { match *self { MacroName::Atom(ref token) => token.symbol(), MacroName::Variable(ref token) => token.symbol(), } } pub fn span(&self) -> SourceSpan { match *self { MacroName::Atom(ref token) => token.span(), MacroName::Variable(ref token) => token.span(), } } } impl Eq for MacroName {} impl PartialEq for MacroName { fn eq(&self, other: &Self) -> bool { self.value() == other.value() } } impl Hash for MacroName { fn hash(&self, hasher: &mut H) { self.value().hash(hasher); } } impl fmt::Display for MacroName { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{}", self.symbol()) } } impl ReadFrom for MacroName { fn read_from(reader: &mut R) -> Result where R: TokenReader, { if let Some(token) = reader.try_read()? { Ok(MacroName::Atom(token)) } else { let token = reader.read()?; Ok(MacroName::Variable(token)) } } } #[derive(Debug, Clone)] pub struct MacroVariables { pub _open_paren: SymbolToken, pub list: List, pub _close_paren: SymbolToken, } impl MacroVariables { /// Returns an iterator which iterates over this variables. pub fn iter(&self) -> ListIter { self.list.iter() } /// Returns the number of this variables. pub fn len(&self) -> usize { self.list.iter().count() } /// Returns `true` if there are no variables. pub fn is_empty(&self) -> bool { self.len() == 0 } pub fn span(&self) -> SourceSpan { SourceSpan::new(self._open_paren.0, self._close_paren.2) } } impl Eq for MacroVariables {} impl PartialEq for MacroVariables { fn eq(&self, other: &Self) -> bool { self.list.eq(&other.list) } } impl fmt::Display for MacroVariables { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "({})", self.list) } } impl ReadFrom for MacroVariables { fn read_from(reader: &mut R) -> Result where R: TokenReader, { Ok(MacroVariables { _open_paren: reader.read_expected(&Token::LParen)?, list: reader.read()?, _close_paren: reader.read_expected(&Token::RParen)?, }) } } /// Macro arguments. #[derive(Debug, Clone)] pub struct MacroArgs { pub _open_paren: SymbolToken, pub list: List, pub _close_paren: SymbolToken, } impl MacroArgs { /// Returns an iterator which iterates over this arguments. pub fn iter(&self) -> ListIter { self.list.iter() } /// Returns the number of this arguments. pub fn len(&self) -> usize { self.list.iter().count() } /// Returns `true` if there are no arguments. pub fn is_empty(&self) -> bool { self.len() == 0 } pub fn span(&self) -> SourceSpan { SourceSpan::new(self._open_paren.0, self._close_paren.2) } } impl Eq for MacroArgs {} impl PartialEq for MacroArgs { fn eq(&self, other: &Self) -> bool { self.list.eq(&other.list) } } impl fmt::Display for MacroArgs { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "({})", self.list) } } impl ReadFrom for MacroArgs { fn read_from(reader: &mut R) -> Result where R: TokenReader, { Ok(MacroArgs { _open_paren: reader.read_expected(&Token::LParen)?, list: reader.read()?, _close_paren: reader.read_expected(&Token::RParen)?, }) } } /// Macro argument. #[derive(Debug, Clone, PartialEq, Eq)] pub struct MacroArg { /// Tokens which represent a macro argument. /// /// Note that this must not be empty. pub tokens: Vec, } impl MacroArg { pub fn span(&self) -> SourceSpan { let start = self.tokens.first().unwrap().span().start(); let end = self.tokens.last().unwrap().span().end(); SourceSpan::new(start, end) } } impl fmt::Display for MacroArg { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { for t in &self.tokens { write!(f, "{}", t)?; } Ok(()) } } impl ReadFrom for MacroArg { fn try_read_from(reader: &mut R) -> Result> where R: TokenReader, { let mut stack = Vec::new(); let mut arg = Vec::new(); while let Some(ref token @ LexicalToken(_, _, _)) = reader.try_read_token()? { match token.1 { Token::RParen if stack.is_empty() => { reader.unread_token(token.clone().into()); return if arg.is_empty() { Ok(None) } else { Ok(Some(MacroArg { tokens: arg })) }; } Token::RBrace | Token::RBracket | Token::BinaryEnd if stack.is_empty() => { return Err(PreprocessorError::UnexpectedToken { token: token.clone(), expected: vec![Token::RParen.to_string()], }); } Token::Comma if stack.is_empty() => { if arg.len() == 0 { return Err(PreprocessorError::UnexpectedToken { token: token.clone(), expected: vec![], }); } reader.unread_token(token.clone().into()); return Ok(Some(MacroArg { tokens: arg })); } Token::LParen | Token::LBrace | Token::LBracket | Token::BinaryStart => { stack.push(token.clone()); } Token::RParen | Token::RBrace | Token::RBracket | Token::BinaryEnd => { match stack.pop() { None => unreachable!(), Some(LexicalToken(_, t2, _)) => { let closing = t2.get_closing_token(); if token.1 != closing { return Err(PreprocessorError::UnexpectedToken { token: token.clone(), expected: vec![closing.to_string()], }); } } } } _ => (), } arg.push(token.clone()); } Err(PreprocessorError::UnexpectedEOF) } } /// Tail part of a linked list (cons cell). #[derive(Debug, Clone)] pub enum Tail { Nil, Cons { _comma: SymbolToken, head: T, tail: Box>, }, } impl Eq for Tail {} impl PartialEq for Tail { fn eq(&self, other: &Self) -> bool { match (self, other) { (Self::Nil, Self::Nil) => true, ( Self::Cons { head: lh, tail: lt, .. }, Self::Cons { head: rh, tail: rt, .. }, ) => lh == rh && lt == rt, _ => false, } } } impl fmt::Display for Tail { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { Tail::Nil => Ok(()), Tail::Cons { ref head, ref tail, .. } => write!(f, ",{}{}", head, tail), } } } impl ReadFrom for Tail { fn read_from(reader: &mut R) -> Result where R: TokenReader, { if let Some(_comma) = reader.try_read_expected(&Token::Comma)? { let head = reader.read()?; let tail = Box::new(reader.read()?); Ok(Tail::Cons { _comma, head, tail }) } else { Ok(Tail::Nil) } } } /// Linked list (cons cell). #[derive(Debug, Clone)] #[allow(missing_docs)] pub enum List { Nil, Cons { head: T, tail: Tail }, } impl List { /// Returns an iterator which iterates over the elements in this list. pub fn iter(&self) -> ListIter { ListIter(ListIterInner::List(self)) } } impl Eq for List {} impl PartialEq for List { fn eq(&self, other: &Self) -> bool { match (self, other) { (Self::Nil, Self::Nil) => true, (Self::Cons { head: lh, tail: lt }, Self::Cons { head: rh, tail: rt }) => { lh == rh && lt == rt } _ => false, } } } impl fmt::Display for List { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { List::Nil => Ok(()), List::Cons { ref head, ref tail } => write!(f, "{}{}", head, tail), } } } impl ReadFrom for List { fn read_from(reader: &mut R) -> Result where R: TokenReader, { if let Some(head) = reader.try_read()? { let tail = reader.read()?; Ok(List::Cons { head, tail }) } else { Ok(List::Nil) } } } /// An iterator which iterates over the elements in a `List`. #[derive(Debug)] pub struct ListIter<'a, T: 'a>(ListIterInner<'a, T>); impl<'a, T: 'a> Iterator for ListIter<'a, T> { type Item = &'a T; fn next(&mut self) -> Option { self.0.next() } } #[derive(Debug)] enum ListIterInner<'a, T: 'a> { List(&'a List), Tail(&'a Tail), End, } impl<'a, T: 'a> Iterator for ListIterInner<'a, T> { type Item = &'a T; fn next(&mut self) -> Option { match mem::replace(self, ListIterInner::End) { ListIterInner::List(&List::Cons { ref head, ref tail }) => { *self = ListIterInner::Tail(tail); Some(head) } ListIterInner::Tail(&Tail::Cons { ref head, ref tail, .. }) => { *self = ListIterInner::Tail(tail); Some(head) } ListIterInner::List(&List::Nil) | ListIterInner::Tail(&Tail::Nil) | ListIterInner::End => None, } } } ================================================ FILE: libeir_syntax_erl/src/util/binary/mod.rs ================================================ mod r#static; pub use r#static::*; ================================================ FILE: libeir_syntax_erl/src/util/binary/static.rs ================================================ use std::convert::TryInto; use snafu::{ResultExt, Snafu}; use libeir_ir::{BinaryEntrySpecifier, Endianness}; use libeir_util_number::{Number, Integer}; use libeir_util_binary::{BitVec, Endian}; use libeir_intern::Ident; use libeir_diagnostics::SourceSpan; use crate::evaluator::{Term, EvalError as SrcEvalError, eval_expr, ResolveRecordIndexError}; use crate::parser::ast::{BinaryElement, Expr, Literal}; use crate::util::encoding; use crate::util::string_tokenizer::StringTokenizer; #[derive(Debug, Snafu)] pub enum StaticBinaryElementError { EvalError { source: SrcEvalError }, #[snafu(display("size expression evaluated to invalid type, must be integer"))] InvalidSizeType { span: SourceSpan }, #[snafu(display("size expression evaluated to outside of valid range"))] InvalidSizeValue { span: SourceSpan }, #[snafu(display("native endianness not allowed in static binary expressions"))] NativeEndianNotAllowed { span: SourceSpan }, #[snafu(display("specifier was invalid for given value"))] InvalidSpecifier { span: SourceSpan }, #[snafu(display("provided value not compatible with binary element specifier"))] IncompatibleValue { span: SourceSpan }, #[snafu(display("only total sizes 32 and 64 are permitted for floats, got {}", size))] InvalidFloatSize { span: SourceSpan, size: usize }, } fn map_endian(endianness: Endianness) -> Endian { match endianness { Endianness::Big => Endian::Big, Endianness::Little => Endian::Little, Endianness::Native => unreachable!(), } } fn append_number( num: &Number, span: SourceSpan, size: Option, specifier: BinaryEntrySpecifier, out: &mut BitVec, ) -> Result<(), StaticBinaryElementError> { use BinaryEntrySpecifier as BES; match specifier { BES::Integer { endianness, unit, .. } => { let endian = map_endian(endianness); let size = size.unwrap_or(8); let unit: usize = unit.try_into().unwrap(); let total_size = size * unit; if let Number::Integer(integer) = num { let bitslice = integer.encode_bitstring(total_size, endian); out.push(&bitslice); Ok(()) } else { Err(StaticBinaryElementError::IncompatibleValue { span, }) } }, BES::Float { endianness, unit } => { let endian = map_endian(endianness); let size = size.unwrap_or(64); let unit: usize = unit.try_into().unwrap(); let total_size = size * unit; let float = num.to_efloat().unwrap().inner(); match total_size { 32 => { let float = float as f32; todo!() }, 64 => { todo!() }, _ => { Err(StaticBinaryElementError::InvalidFloatSize { span, size: total_size, }) }, } }, BES::Utf8 => { if let Number::Integer(integer) = num { let cp = integer.to_u64().unwrap(); let encoded = encoding::encode_utf8(cp, span).unwrap(); out.push(encoded); Ok(()) } else { Err(StaticBinaryElementError::IncompatibleValue { span, }) } }, BES::Utf16 { endianness } => { if let Number::Integer(integer) = num { let cp = integer.to_u64().unwrap(); let mut encoded = encoding::encode_utf16(cp, span).unwrap(); if endianness == Endianness::Little { encoded = encoded.swap(); } out.push(encoded); Ok(()) } else { Err(StaticBinaryElementError::IncompatibleValue { span, }) } }, BES::Utf32 { endianness } => { let endian = map_endian(endianness); if let Number::Integer(integer) = num { let cp = integer.to_u64().unwrap(); let mut encoded = encoding::encode_utf32(cp, span).unwrap(); if endianness == Endianness::Little { encoded = encoded.swap(); } out.push(encoded); Ok(()) } else { Err(StaticBinaryElementError::IncompatibleValue { span, }) } }, BES::Bytes { .. } => { unreachable!() }, BES::Bits { .. } => { unreachable!() }, } } pub fn append_static_binary_element( elem: &BinaryElement, out: &mut BitVec, resolve_record_index: Option<&dyn Fn(Ident, Ident) -> Result>, ) -> Result<(), StaticBinaryElementError> { let specifier = elem.specifier.unwrap_or_else(BinaryEntrySpecifier::default); if specifier.is_native_endian() { return Err(StaticBinaryElementError::NativeEndianNotAllowed { span: elem.bit_expr.span(), }) } // Evaluate bit size let size: Option = if let Some(size_expr) = &elem.bit_size { let result = eval_expr(size_expr, resolve_record_index) .context(EvalError)?; match result { Term::Number(Number::Integer(num)) => { if let Some(integer) = num.to_usize() { Some(integer) } else { return Err(StaticBinaryElementError::InvalidSizeValue { span: size_expr.span(), }); } }, _ => { return Err(StaticBinaryElementError::InvalidSizeType { span: size_expr.span(), }); }, } } else { None }; // TODO switch to evaluator? match &elem.bit_expr { Expr::Literal(Literal::String(_id, string)) => { let tokenizer = StringTokenizer::new(*string); for result in tokenizer { // TODO error let (cp, span) = result.unwrap(); let cp_int: Integer = cp.into(); append_number(&cp_int.into(), span, size, specifier, out)?; } Ok(()) }, _ => { let evaluated = crate::evaluator::eval_expr(&elem.bit_expr, resolve_record_index) .context(EvalError)?; match evaluated { Term::Number(number) => { append_number(&number, elem.bit_expr.span(), size, specifier, out)?; Ok(()) }, _ => { Err(StaticBinaryElementError::IncompatibleValue { span: elem.bit_expr.span(), }) }, } }, } } #[cfg(test)] mod tests { use libeir_ir::binary::{BinaryEntrySpecifier, Endianness}; use libeir_diagnostics::SourceSpan; use libeir_util_binary::BitVec; use crate::parser::ast; use super::*; #[test] fn simple_integer() { let expr = ast::Expr::Literal(Literal::Integer(SourceSpan::UNKNOWN, ast::NodeId(0), 21.into())); let elem = ast::BinaryElement { span: SourceSpan::UNKNOWN, id: ast::NodeId(1), bit_expr: expr, bit_size: None, specifier: None, }; let mut bits = BitVec::new(); append_static_binary_element(&elem, &mut bits, None).unwrap(); assert_eq!(bits.as_ref(), &[21]); } #[test] fn simple_integer_with_size() { let expr = ast::Expr::Literal(Literal::Integer(SourceSpan::UNKNOWN, ast::NodeId(0), 21.into())); let size_expr = ast::Expr::Literal(Literal::Integer(SourceSpan::UNKNOWN, ast::NodeId(2), 12.into())); let elem = ast::BinaryElement { span: SourceSpan::UNKNOWN, id: ast::NodeId(1), bit_expr: expr, bit_size: Some(size_expr), specifier: None, }; let mut bits = BitVec::new(); append_static_binary_element(&elem, &mut bits, None).unwrap(); assert_eq!(bits.as_ref(), &[21 >> 4, 21 << 4]); } #[test] fn simple_integer_little_endian_with_size() { let expr = ast::Expr::Literal(Literal::Integer(SourceSpan::UNKNOWN, ast::NodeId(0), 21.into())); let size_expr = ast::Expr::Literal(Literal::Integer(SourceSpan::UNKNOWN, ast::NodeId(2), 12.into())); let elem = ast::BinaryElement { span: SourceSpan::UNKNOWN, id: ast::NodeId(1), bit_expr: expr, bit_size: Some(size_expr), specifier: Some(BinaryEntrySpecifier::Integer { signed: true, unit: 1, endianness: Endianness::Little, }), }; let mut bits = BitVec::new(); append_static_binary_element(&elem, &mut bits, None).unwrap(); assert_eq!(bits.as_ref(), &[21, 0]); } } ================================================ FILE: libeir_syntax_erl/src/util/encoding.rs ================================================ use std::fmt::{Display, Formatter}; use std::convert::TryFrom; use snafu::Snafu; use libeir_diagnostics::{Diagnostic, Label, SourceIndex, SourceSpan, ToDiagnostic}; #[derive(Debug, Snafu)] pub enum StringError { #[snafu(display("unicode codepoint #{} is not encodable in {}", codepoint, encoding))] CodepointEncoding { span: SourceSpan, codepoint: u64, encoding: Encoding, }, } impl ToDiagnostic for StringError { fn to_diagnostic(&self) -> Diagnostic { let msg = self.to_string(); match self { StringError::CodepointEncoding { span, codepoint, encoding, } => Diagnostic::error() .with_message(msg) .with_labels(vec![Label::primary(span.source_id(), *span) .with_message("encoding failed at codepoint")]), } } } #[derive(Debug, Copy, Clone)] pub enum Encoding { /// The default encoding for binary string literals. /// In practice this is the unicode codepoint modulo 2^8 (truncated to 8 bits). Latin1, Utf8, Utf16, Utf32, } impl Display for Encoding { fn fmt(&self, f: &mut Formatter) -> std::fmt::Result { match self { Encoding::Latin1 => write!(f, "latin1"), Encoding::Utf8 => write!(f, "utf8"), Encoding::Utf16 => write!(f, "utf16"), Encoding::Utf32 => write!(f, "utf32"), } } } impl Encoding { pub fn encode(&self, cp: u64, span: SourceSpan) -> Result { match self { Encoding::Latin1 => encode_latin1(cp, span), Encoding::Utf8 => encode_utf8(cp, span), Encoding::Utf16 => encode_utf16(cp, span), Encoding::Utf32 => encode_utf32(cp, span), } } } #[derive(Debug, Copy, Clone)] pub enum Endianness { Big, Little, } use libeir_ir::binary::Endianness as EirEndianness; impl TryFrom for Endianness { type Error = (); fn try_from(end: EirEndianness) -> Result { match end { EirEndianness::Big => Ok(Endianness::Big), EirEndianness::Little => Ok(Endianness::Little), EirEndianness::Native => Err(()), } } } #[derive(Copy, Clone)] pub enum Encoded { N1(u8), N2(u8, u8), N3(u8, u8, u8), N4(u8, u8, u8, u8), } impl Encoded { pub fn swap(self) -> Self { match self { Encoded::N1(a) => Encoded::N1(a), Encoded::N2(a, b) => Encoded::N2(b, a), Encoded::N3(a, b, c) => Encoded::N3(c, b, a), Encoded::N4(a, b, c, d) => Encoded::N4(d, c, b, a), } } pub fn write(self, endianness: Endianness, out: &mut Vec) { match endianness { Endianness::Big => self.write_be(out), Endianness::Little => self.write_le(out), } } pub fn write_le(self, out: &mut Vec) { match self { Encoded::N1(a) => out.push(a), Encoded::N2(a, b) => { out.push(b); out.push(a); } Encoded::N3(a, b, c) => { out.push(c); out.push(b); out.push(a); } Encoded::N4(a, b, c, d) => { out.push(d); out.push(c); out.push(b); out.push(a); } } } pub fn write_be(self, out: &mut Vec) { match self { Encoded::N1(a) => out.push(a), Encoded::N2(a, b) => { out.push(a); out.push(b); } Encoded::N3(a, b, c) => { out.push(a); out.push(b); out.push(c); } Encoded::N4(a, b, c, d) => { out.push(a); out.push(b); out.push(c); out.push(d); } } } } impl libeir_util_binary::BitCarrier for Encoded { type T = u8; fn bit_len(&self) -> usize { match self { Self::N1(_) => 8, Self::N2(_, _) => 16, Self::N3(_, _, _) => 24, Self::N4(_, _, _, _) => 32, } } } impl libeir_util_binary::BitRead for Encoded { fn read_word(&self, n: usize) -> u8 { match (self, n) { (Self::N1(val), 0) => *val, (Self::N2(val, _), 0) => *val, (Self::N2(_, val), 1) => *val, (Self::N3(val, _, _), 0) => *val, (Self::N3(_, val, _), 1) => *val, (Self::N3(_, _, val), 2) => *val, (Self::N4(val, _, _, _), 0) => *val, (Self::N4(_, val, _, _), 1) => *val, (Self::N4(_, _, val, _), 2) => *val, (Self::N4(_, _, _, val), 3) => *val, _ => unreachable!(), } } } pub fn encode_utf8(cp: u64, span: SourceSpan) -> Result { match cp { 0x00..=0x7f => Ok(Encoded::N1(cp as u8)), 0x80..=0x7ff => Ok(Encoded::N2( 0b110_00000 | (cp >> 6 & 0b000_11111) as u8, 0b10_000000 | (cp >> 0 & 0b00_111111) as u8, )), 0x800..=0xffff => Ok(Encoded::N3( 0b1110_0000 | (cp >> 12 & 0b0000_1111) as u8, 0b10_000000 | (cp >> 6 & 0b00_111111) as u8, 0b10_000000 | (cp >> 0 & 0b00_111111) as u8, )), 0x10000..=0x1fffff => Ok(Encoded::N4( 0b11110_000 | (cp >> 18 & 0b00000_111) as u8, 0b10_000000 | (cp >> 12 & 0b00_111111) as u8, 0b10_000000 | (cp >> 6 & 0b00_111111) as u8, 0b10_000000 | (cp >> 0 & 0b00_111111) as u8, )), _ => Err(StringError::CodepointEncoding { span, codepoint: cp, encoding: Encoding::Utf8, }), } } pub fn encode_utf16(cp: u64, span: SourceSpan) -> Result { match cp { 0x0000..=0xd7ff => Ok(Encoded::N2((cp >> 8) as u8, (cp >> 0) as u8)), 0xd800..=0xdfff => Err(StringError::CodepointEncoding { span, codepoint: cp, encoding: Encoding::Utf16, }), 0xd800..=0xffff => Ok(Encoded::N2((cp >> 8) as u8, (cp >> 0) as u8)), 0x10000..=0x10ffff => { let val = cp - 0x10000; Ok(Encoded::N4( 0b110110_00 | (cp >> 18 & 0b000000_11) as u8, (cp >> 10) as u8, 0b110111_00 | (cp >> 8 & 0b000000_11) as u8, (cp >> 0) as u8, )) } _ => Err(StringError::CodepointEncoding { span, codepoint: cp, encoding: Encoding::Utf16, }), } } pub fn encode_utf32(cp: u64, span: SourceSpan) -> Result { if cp > std::u32::MAX as u64 { Err(StringError::CodepointEncoding { span, codepoint: cp, encoding: Encoding::Utf32, }) } else { Ok(Encoded::N4( (cp >> 24) as u8, (cp >> 16) as u8, (cp >> 8) as u8, (cp >> 0) as u8, )) } } fn encode_latin1(cp: u64, _span: SourceSpan) -> Result { Ok(Encoded::N1(cp as u8)) } ================================================ FILE: libeir_syntax_erl/src/util/escape_stm.rs ================================================ use libeir_diagnostics::{Diagnostic, Label, SourceIndex, SourceSpan, ToDiagnostic}; use snafu::Snafu; #[derive(Snafu, Debug, Clone, PartialEq, Eq)] pub enum EscapeStmError { /// Unknown escape character #[snafu(display("unknown escape character '{}'", escape_char))] UnknownEscape { range: (D, D), escape_char: char }, /// Expected a base-n digit or alt #[snafu(display("expected base{} digit or '{}', found '{}'", base, alt, found))] InvalidBaseNDigitOrAlt { range: (D, D), found: char, base: usize, alt: char, }, /// Expected a base-n digit #[snafu(display("expected base{} digit, found '{}'", base, found))] InvalidBaseNDigit { range: (D, D), found: char, base: usize, }, /// Expected control character symbol #[snafu(display("expected control character symbol (a-z), found '{}'", found))] InvalidControl { range: (D, D), found: char }, #[snafu(display("unexpected EOF"))] UnexpectedEof { range: (D, D) }, } impl EscapeStmError { pub fn range(&self) -> &(D, D) { match self { Self::UnknownEscape { range, .. } => range, Self::InvalidBaseNDigitOrAlt { range, .. } => range, Self::InvalidBaseNDigit { range, .. } => range, Self::InvalidControl { range, .. } => range, Self::UnexpectedEof { range } => range, } } } impl EscapeStmError { pub fn span(&self) -> SourceSpan { let (start, end) = self.range(); SourceSpan::new(*start, *end) } } impl ToDiagnostic for EscapeStmError { fn to_diagnostic(&self) -> Diagnostic { let msg = self.to_string(); let span = self.span(); Diagnostic::error() .with_message("invalid string escape") .with_labels(vec![ Label::primary(span.source_id(), span).with_message(msg) ]) } } /// Erlang string escape state machine. #[derive(Clone, Debug)] pub struct EscapeStm { buf: String, curr_start: Option, state: EscapeStmState, } #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub enum EscapeStmState { Norm, Escape, Oct, HexStart, HexN, Hex2, Control, } #[derive(Debug)] pub enum EscapeStmAction { Next, Again, } #[derive(Debug)] pub struct EscapeStmOut { pub range: (D, D), pub cp: u64, } impl EscapeStm { pub fn new() -> Self { EscapeStm { buf: String::new(), curr_start: None, state: EscapeStmState::Norm, } } pub fn reset(&mut self) { self.buf.clear(); self.curr_start = None; self.state = EscapeStmState::Norm; } pub fn is_norm(&self) -> bool { self.state == EscapeStmState::Norm } pub fn transition( &mut self, c: Option, pos: D, ) -> Result<(EscapeStmAction, Option>), EscapeStmError> { use EscapeStmAction as A; use EscapeStmState as S; let mut range = (self.curr_start.unwrap_or(pos), pos); let mut out = None; let action = match self.state { S::Norm => match c { Some('\\') => { self.state = S::Escape; self.curr_start = Some(pos); A::Next } Some(c) => { self.state = S::Norm; range = (pos, pos); out = Some(c as u64); A::Next } None => A::Next, }, S::Escape => { match c { Some('b') => { // Backspace self.state = S::Norm; out = Some('\x08' as u64); } Some('d') => { // Delete self.state = S::Norm; out = Some('\x7f' as u64); } Some('e') => { // Escape self.state = S::Norm; out = Some('\x1b' as u64); } Some('f') => { // Form feed self.state = S::Norm; out = Some('\x0c' as u64); } Some('n') => { // Line feed self.state = S::Norm; out = Some('\n' as u64); } Some('r') => { // Carriage return self.state = S::Norm; out = Some('\r' as u64); } Some('s') => { // Space self.state = S::Norm; out = Some(' ' as u64); } Some('t') => { // Tab self.state = S::Norm; out = Some('\t' as u64); } Some('v') => { // Vertical tab self.state = S::Norm; out = Some('\x0b' as u64); } Some(n) if n >= '0' && n <= '7' => { self.buf.clear(); self.buf.push(n); self.state = S::Oct; } Some('x') => { self.state = S::HexStart; } Some('^') => { self.state = S::Control; } Some(c) => { self.state = S::Norm; out = Some(c as u64); } None => return Err(EscapeStmError::UnexpectedEof { range }), } A::Next } S::Oct => match c { Some(c) if c >= '0' && c <= '7' => { self.buf.push(c); if self.buf.len() == 3 { let parsed = u64::from_str_radix(&self.buf, 8).unwrap(); self.state = S::Norm; out = Some(parsed); } else { self.state = S::Oct; } A::Next } _ => { let parsed = u64::from_str_radix(&self.buf, 8).unwrap(); self.state = S::Norm; out = Some(parsed); A::Again } }, S::HexStart => match c { Some('{') => { self.state = S::HexN; A::Next } Some(n) if n.is_digit(16) => { self.buf.clear(); self.buf.push(n); self.state = S::Hex2; A::Next } Some(c) => { return Err(EscapeStmError::InvalidBaseNDigitOrAlt { range, found: c, base: 16, alt: '{', }); } None => return Err(EscapeStmError::UnexpectedEof { range }), }, S::Hex2 => match c { Some(n) if n.is_digit(16) => { self.buf.push(n); self.state = S::Norm; let parsed = u64::from_str_radix(&self.buf, 16).unwrap(); out = Some(parsed); A::Next } Some(c) => { return Err(EscapeStmError::InvalidBaseNDigit { range, found: c, base: 16, }); } None => return Err(EscapeStmError::UnexpectedEof { range }), }, S::HexN => match c { Some('}') => { let parsed = u64::from_str_radix(&self.buf, 16).unwrap(); self.state = S::Norm; out = Some(parsed); A::Next } Some(n) if n.is_digit(16) => { self.buf.push(n); self.state = S::HexN; A::Next } Some(c) => { return Err(EscapeStmError::InvalidBaseNDigitOrAlt { range, found: c, base: 16, alt: '}', }); } None => return Err(EscapeStmError::UnexpectedEof { range }), }, S::Control => { match c { Some(c) => { let num = (c as u64) % 32; self.state = S::Norm; out = Some(num); if c < '@' || c > '~' { // TODO: Warn? // return Err(EscapeStmError::InvalidControl { range, found: c }) } A::Next } None => return Err(EscapeStmError::UnexpectedEof { range }), } } }; Ok((action, out.map(|c| EscapeStmOut { cp: c, range }))) } } ================================================ FILE: libeir_syntax_erl/src/util/mod.rs ================================================ pub mod encoding; pub mod escape_stm; pub mod string_tokenizer; pub mod string; pub mod binary; ================================================ FILE: libeir_syntax_erl/src/util/string.rs ================================================ use libeir_intern::Ident; use crate::lower::LowerError; use super::string_tokenizer::{StringTokenizer, StringTokenizeError}; use super::encoding::{Encoding, Endianness}; pub fn string_to_codepoints(string: Ident) -> Result, StringTokenizeError> { StringTokenizer::new(string).map(|v| v.map(|(cp, _span)| cp)).collect() } pub fn string_to_binary( ident: Ident, encoding: Encoding, endianness: Endianness, ) -> Result, LowerError> { let mut out = Vec::new(); let tokenizer = StringTokenizer::new(ident); for tok in tokenizer { let (cp, span) = tok?; let encoded = encoding.encode(cp, span)?; encoded.write(endianness, &mut out); } Ok(out) } #[cfg(test)] mod tests { use libeir_intern::Ident; use super::{string_to_binary, string_to_codepoints, Encoding, Endianness}; #[test] fn string_literal_parse() { assert!( string_to_codepoints(Ident::from_str("abc")).unwrap() == vec!['a' as u64, 'b' as u64, 'c' as u64] ); assert!( string_to_codepoints(Ident::from_str("a\\bc")).unwrap() == vec!['a' as u64, 8, 'c' as u64] ); assert!( string_to_codepoints(Ident::from_str("a\\b\\d\\e\\f\\n\\r\\s\\t\\vc")).unwrap() == vec!['a' as u64, 8, 127, 27, 12, 10, 13, ' ' as u64, 9, 11, 'c' as u64] ); assert!( string_to_codepoints(Ident::from_str("a\\'\\\"\\\\c")).unwrap() == vec!['a' as u64, '\'' as u64, '"' as u64, '\\' as u64, 'c' as u64] ); assert!( string_to_codepoints(Ident::from_str("a\\1\\12\\123c")).unwrap() == vec!['a' as u64, 0o1, 0o12, 0o123, 'c' as u64] ); assert!(string_to_codepoints(Ident::from_str("\\123")).unwrap() == vec![0o123]); assert!(string_to_codepoints(Ident::from_str("\\12")).unwrap() == vec![0o12]); assert!(string_to_codepoints(Ident::from_str("\\1")).unwrap() == vec![0o1]); assert!( string_to_codepoints(Ident::from_str("a\\xffc")).unwrap() == vec!['a' as u64, 0xff, 'c' as u64] ); assert!(string_to_codepoints(Ident::from_str("\\xff")).unwrap() == vec![0xff]); assert!(string_to_codepoints(Ident::from_str("\\x{ff}")).unwrap() == vec![0xff]); assert!(string_to_codepoints(Ident::from_str("\\x{ffff}")).unwrap() == vec![0xffff]); assert!(string_to_codepoints(Ident::from_str("\\^a\\^z")).unwrap() == vec![1, 26]); } #[test] fn test_string_to_binary() { assert!( string_to_binary(Ident::from_str("abcå"), Encoding::Utf8, Endianness::Big).unwrap() == vec![0x61, 0x62, 0x63, 0xc3, 0xa5] ) } } ================================================ FILE: libeir_syntax_erl/src/util/string_tokenizer.rs ================================================ use snafu::Snafu; use libeir_diagnostics::{Diagnostic, SourceIndex, SourceSpan, ToDiagnostic}; use libeir_intern::Ident; use super::escape_stm as escape; #[derive(Debug, Snafu)] pub enum StringTokenizeError { InvalidStringEscape { span: SourceSpan, source: escape::EscapeStmError, }, } impl ToDiagnostic for StringTokenizeError { fn to_diagnostic(&self) -> Diagnostic { match self { StringTokenizeError::InvalidStringEscape { source, .. } => source.to_diagnostic(), } } } pub struct StringTokenizer { ident: Ident, chars: std::str::Chars<'static>, byte_idx: usize, stm: escape::EscapeStm, again: Option<(Option, SourceIndex)>, finished: bool, } impl StringTokenizer { pub fn new(string: Ident) -> Self { StringTokenizer { ident: string, chars: string.name.as_str().get().chars(), byte_idx: 0, stm: escape::EscapeStm::new(), again: None, finished: false, } } } impl Iterator for StringTokenizer { type Item = Result<(u64, SourceSpan), StringTokenizeError>; fn next(&mut self) -> Option { use escape::EscapeStmAction; if self.finished { return None; } loop { if let Some((again_chr, idx)) = self.again.take() { let res = self.stm.transition(again_chr, idx); let out = match res { Ok((EscapeStmAction::Next, out)) => { match again_chr { Some(c) => self.byte_idx += c.len_utf8(), // If this is None, it means we have reached the // end of the string. None => self.finished = true, } out }, Ok((EscapeStmAction::Again, out)) => { self.again = Some((again_chr, idx)); out }, Err(err) => { self.finished = true; return Some(Err(StringTokenizeError::InvalidStringEscape { span: err.span(), source: err, })); }, }; if let Some(result) = out { // If we have a result, we return that let span = SourceSpan::new(result.range.0, result.range.1); return Some(Ok((result.cp, span))); } else if self.finished { // If there is no result, and the iterator has been marked // as finished, we return nothing. return None; } else { // Otherwise, the state machine needs more data. continue; } } let idx = self.ident.span.start() + self.byte_idx; let chr = self.chars.next(); self.again = Some((chr, idx)); } } } #[cfg(test)] mod tests { use libeir_intern::Ident; use libeir_diagnostics::SourceSpan; use super::*; #[test] fn tokenize_plaintext() { let mut tokenizer = StringTokenizer::new(Ident::from_str("abc")); assert_eq!(tokenizer.next().unwrap().unwrap(), ('a' as u64, SourceSpan::UNKNOWN)); assert_eq!(tokenizer.next().unwrap().unwrap(), ('b' as u64, SourceSpan::UNKNOWN)); assert_eq!(tokenizer.next().unwrap().unwrap(), ('c' as u64, SourceSpan::UNKNOWN)); assert!(tokenizer.next().is_none()); } #[test] fn tokenize_unicode_codepoint() { let mut tokenizer = StringTokenizer::new(Ident::from_str("\\x{afaf}")); assert_eq!(tokenizer.next().unwrap().unwrap(), (0xafaf, SourceSpan::UNKNOWN)); assert!(tokenizer.next().is_none()); } } ================================================ FILE: libeir_tests/Cargo.toml ================================================ [package] name = "libeir_tests" version = "0.1.0" authors = ["Hans Elias B. Josephsen "] edition = "2018" license = "MIT OR Apache-2.0" [dependencies] libeir_ir = { path = "../libeir_ir" } libeir_passes = { path = "../libeir_passes" } libeir_syntax_erl = { path = "../libeir_syntax_erl" } libeir_diagnostics = { path = "../libeir_diagnostics" } libeir_intern = { path = "../libeir_intern" } libeir_interpreter = { path = "../libeir_interpreter" } libeir_lowerutils = { path = "../libeir_lowerutils" } libeir_util_parse = { path = "../util/libeir_util_parse" } libeir_util_dot_graph = { path = "../util/libeir_util_dot_graph" } [dev-dependencies] env_logger = "0.7" ================================================ FILE: libeir_tests/shadowing.erl ================================================ -module(shadowing). -export([run/0]). run() -> 1 = case_matching({1}, 1), {_, _} = (catch case_matching({1}, 2)), 1 = fun_shadowing({1}, 1), 2 = fun_shadowing({1}, 2). case_matching(A, B) -> case A of {B} -> B end. fun_shadowing(A, B) -> C = fun({B}) -> B end, C(A). ================================================ FILE: libeir_tests/src/control_flow/accumulate_list.rs ================================================ use crate::lower; use libeir_intern::Ident; use libeir_ir::FunctionIdent; use libeir_passes::PassManager; use libeir_syntax_erl::ParseConfig; use libeir_interpreter::{Term, VMState}; use std::rc::Rc; #[test] fn test_list_acc() { let _ = env_logger::try_init(); let mut eir_mod = lower( "-module(woo). woo([], Acc) -> Acc; woo([H | T], Acc) -> woo(T, H + Acc). woo(V) -> woo(V, 0). ", ParseConfig::default(), ) .unwrap(); let mut pass_manager = PassManager::default(); pass_manager.run(&mut eir_mod); let mut vm = VMState::new(); vm.add_builtin_modules(); vm.add_erlang_module(eir_mod); let fun = FunctionIdent { module: Ident::from_str("woo"), name: Ident::from_str("woo"), arity: 1, }; { let arg = Term::slice_to_list( &[ Term::Integer(1.into()).into(), Term::Integer(2.into()).into(), Term::Integer(4.into()).into(), ], Term::Nil.into(), ); assert!( vm.call(&fun, &[Rc::try_unwrap(arg).unwrap()]) .unwrap() .as_i64() == Some(7) ); } } ================================================ FILE: libeir_tests/src/control_flow/fib.rs ================================================ use crate::lower; use libeir_intern::Ident; use libeir_ir::FunctionIdent; use libeir_passes::PassManager; use libeir_syntax_erl::ParseConfig; use libeir_interpreter::{Term, VMState}; #[test] fn test_fib() { let _ = env_logger::try_init(); let mut eir_mod = lower( "-module(fib). fib(X) when X < 2 -> 1; fib(X) -> fib(X - 1) + fib(X-2). ", ParseConfig::default(), ) .unwrap(); let mut pass_manager = PassManager::default(); pass_manager.run(&mut eir_mod); let mut vm = VMState::new(); vm.add_builtin_modules(); vm.add_erlang_module(eir_mod); let fun = FunctionIdent { module: Ident::from_str("fib"), name: Ident::from_str("fib"), arity: 1, }; let mut call_fib = |n: i64| { let num = Term::Integer(n.into()); vm.call(&fun, &[num.into()]) }; fn rust_fib(x: i64) -> i64 { if x < 2 { 1 } else { rust_fib(x - 1) + rust_fib(x - 2) } } assert!(call_fib(1).unwrap().as_i64().unwrap() == rust_fib(1)); assert!(call_fib(2).unwrap().as_i64().unwrap() == rust_fib(2)); assert!(call_fib(3).unwrap().as_i64().unwrap() == rust_fib(3)); assert!(call_fib(4).unwrap().as_i64().unwrap() == rust_fib(4)); assert!(call_fib(5).unwrap().as_i64().unwrap() == rust_fib(5)); assert!(call_fib(6).unwrap().as_i64().unwrap() == rust_fib(6)); assert!(call_fib(7).unwrap().as_i64().unwrap() == rust_fib(7)); assert!(call_fib(8).unwrap().as_i64().unwrap() == rust_fib(8)); } ================================================ FILE: libeir_tests/src/control_flow/get_values.rs ================================================ use crate::lower; use libeir_passes::PassManager; use libeir_syntax_erl::ParseConfig; //-module('Elixir.Keyword'). // //get_values(_keywords@1, _key@1) // when // is_list(_keywords@1) // andalso // is_atom(_key@1) -> // _fun@1 = // fun({_key@2,_val@1}) when _key@1 =:= _key@2 -> // {true,_val@1}; // ({_,_}) -> // false // end, // lists:filtermap(_fun@1, _keywords@1). #[test] fn get_values() { let _ = env_logger::try_init(); let mut eir_mod = lower( "-module('Elixir.Keyword'). get_values(_key@1) -> A = fun(_key@2) -> _key@1 =:= _key@2 end, A. ", ParseConfig::default(), ) .unwrap(); let mut pass_manager = PassManager::default(); pass_manager.run(&mut eir_mod); for fun in eir_mod.function_iter() { let _ = fun.function().live_values(); } } ================================================ FILE: libeir_tests/src/control_flow/mod.rs ================================================ mod fib; //mod nth_root; mod accumulate_list; mod get_values; mod shadowing; ================================================ FILE: libeir_tests/src/control_flow/nth_root.rs ================================================ use std::rc::Rc; use crate::{lower, write_dot}; use libeir_intern::{Ident, Symbol}; use libeir_ir::FunctionIdent; use libeir_passes::PassManager; use libeir_syntax_erl::ParseConfig; use libeir_interpreter::{ErlEq, Term, VMState}; #[test] fn test_nth_root() { let _ = env_logger::try_init(); let mut eir_mod = lower( " -module(woo). fixed_point(F, Guess, Tolerance) -> fixed_point(F, Guess, Tolerance, F(Guess)). fixed_point(_, Guess, Tolerance, Next) when erlang:abs(Guess - Next) < Tolerance -> Next; fixed_point(F, _, Tolerance, Next) -> fixed_point(F, Next, Tolerance, F(Next)). nth_root(N, X) -> nth_root(N, X, 1.0e-5). nth_root(N, X, Precision) -> F = fun(Prev) -> ((N - 1) * Prev + X / math:pow(Prev, (N-1))) / N end, fixed_point(F, X, Precision). ", ParseConfig::default(), ) .unwrap(); let mut pass_manager = PassManager::default(); pass_manager.run(&mut eir_mod); let fun = FunctionIdent { module: Ident::from_str("woo"), name: Ident::from_str("nth_root"), arity: 2, }; let mut vm = VMState::new(); vm.add_builtin_modules(); vm.add_erlang_module(eir_mod); assert!(vm.call(&fun, &[2.into(), 2.into()]).unwrap().as_boolean() == Some(true)); } ================================================ FILE: libeir_tests/src/control_flow/shadowing.rs ================================================ use crate::lower; use libeir_intern::Ident; use libeir_ir::FunctionIdent; use libeir_passes::PassManager; use libeir_syntax_erl::ParseConfig; use libeir_interpreter::VMState; #[test] fn pattern_variable_shadowing() { let _ = env_logger::try_init(); let mut eir_mod = lower( "-module(shadowing). run() -> 1 = case_matching({1}, 1), {_, _} = (catch case_matching({1}, 2)), 1 = fun_shadowing({1}, 1), 2 = fun_shadowing({2}, 1). case_matching(A, B) -> case A of {B} -> B end. fun_shadowing(A, B) -> C = fun({B}) -> B end, C(A). ", ParseConfig::default(), ) .unwrap(); let mut pass_manager = PassManager::default(); pass_manager.run(&mut eir_mod); let mut vm = VMState::new(); vm.add_builtin_modules(); vm.add_erlang_module(eir_mod); let run_fun = FunctionIdent { module: Ident::from_str("shadowing"), name: Ident::from_str("run"), arity: 0, }; assert!(vm.call(&run_fun, &[]).is_ok()); } #[test] fn pattern_variable_shadowing_a() { let _ = env_logger::try_init(); let mut eir_mod = lower( "-module(shadowinga). fun_shadowing(A) -> C = fun(B) -> B end, C(A). ", ParseConfig::default(), ) .unwrap(); let mut pass_manager = PassManager::default(); pass_manager.run(&mut eir_mod); for fun_def in eir_mod.function_iter() { let fun = fun_def.function(); fun.live_values(); } } ================================================ FILE: libeir_tests/src/ct_runner.rs ================================================ use std::collections::HashMap; use libeir_intern::{Ident, Symbol}; use libeir_ir::FunctionIdent; use libeir_interpreter::{Term, VMState}; #[derive(Debug, Clone)] struct SuiteSpec { entries: Vec, } #[derive(Debug, Clone)] enum SuiteEntrySpec { Test(Symbol), Group { name: Symbol, tests: Vec }, } fn get_suite_spec(vm: &mut VMState, module: Ident) -> SuiteSpec { let groups = { let fun = FunctionIdent { module, name: Ident::from_str("groups"), arity: 0, }; let ret = vm.call(&fun, &[]).unwrap(); let mut groups = HashMap::new(); for elem in Term::as_list(&ret).unwrap() { let tup = elem.as_tuple().unwrap(); assert!(tup.len() == 3); let name = tup[0].as_atom().unwrap(); let tests = Term::as_list(&tup[2]) .unwrap() .iter() .map(|v| v.as_atom().unwrap()) .collect(); let group = SuiteEntrySpec::Group { name, tests }; groups.insert(name, group); } groups }; let all = { let fun = FunctionIdent { module, name: Ident::from_str("all"), arity: 0, }; let ret = vm.call(&fun, &[]).unwrap(); let mut entries = Vec::new(); for elem in Term::as_list(&ret).unwrap() { if let Some(name) = elem.as_atom() { entries.push(SuiteEntrySpec::Test(name)); } else if let Some(tup) = elem.as_tuple() { match &tup { &[group_atom, group] if group_atom.as_atom() == Some(Symbol::intern("group")) => { let group_name = group.as_atom().unwrap(); entries.push(groups[&group_name].clone()); } _ => panic!(), } } else { panic!() } } entries }; SuiteSpec { entries: all } } pub fn run_ct_suite(vm: &mut VMState, module: Ident) { let spec = get_suite_spec(vm, module); let config = Term::Nil; for entry in spec.entries.iter() { match entry { SuiteEntrySpec::Group { tests, .. } => { for test in tests { let fun = FunctionIdent { module, name: Ident::with_empty_span(*test), arity: 1, }; let res = vm.call(&fun, &[config.clone()]); res.unwrap(); } } SuiteEntrySpec::Test(sym) => { let fun = FunctionIdent { module, name: Ident::with_empty_span(*sym), arity: 1, }; let res = vm.call(&fun, &[config.clone()]); res.unwrap(); } } } } ================================================ FILE: libeir_tests/src/errors.rs ================================================ use super::lower; use libeir_intern::{Ident, Symbol}; use libeir_ir::FunctionIdent; use libeir_passes::PassManager; use libeir_syntax_erl::ParseConfig; use libeir_interpreter::{Term, VMState}; #[test] fn test_basic_catch() { let _ = env_logger::try_init(); let mut eir_mod = lower( " -module(woo). foo(foo) -> false. woo(A) -> try foo(A) catch error:function_clause -> true end. ", ParseConfig::default(), ) .unwrap(); let mut pass_manager = PassManager::default(); pass_manager.run(&mut eir_mod); let fun = FunctionIdent { module: Ident::from_str("woo"), name: Ident::from_str("woo"), arity: 1, }; let mut vm = VMState::new(); vm.add_builtin_modules(); vm.add_erlang_module(eir_mod); assert!(vm.call(&fun, &[1.into()]).unwrap().as_boolean() == Some(true)); assert!( vm.call(&fun, &[Term::Atom(Symbol::intern("foo")).into()]) .unwrap() .as_boolean() == Some(false) ); } #[test] fn test_basic_catch_miss() { let _ = env_logger::try_init(); let mut eir_mod = lower( " -module(woo). foo(foo) -> false. woo(A) -> try foo(A) catch error:function_clause_not -> true end. ", ParseConfig::default(), ) .unwrap(); let mut pass_manager = PassManager::default(); pass_manager.run(&mut eir_mod); let fun = FunctionIdent { module: Ident::from_str("woo"), name: Ident::from_str("woo"), arity: 1, }; let mut vm = VMState::new(); vm.add_builtin_modules(); vm.add_erlang_module(eir_mod); assert!( vm.call(&fun, &[Term::Atom(Symbol::intern("foo")).into()]) .unwrap() .as_boolean() == Some(false) ); assert!(vm.call(&fun, &[1.into()]).is_err()); } ================================================ FILE: libeir_tests/src/lib.rs ================================================ //#![deny(warnings)] #![cfg(test)] use std::path::Path; use std::sync::Arc; use libeir_diagnostics::*; use libeir_ir::{FunctionIdent, Module}; use libeir_syntax_erl::lower_module; use libeir_syntax_erl::{ErlangError, Parse, ParseConfig, Parser, ParserError}; use libeir_util_parse::{error_tee, Errors}; use libeir_util_dot_graph::GraphPrinter; mod control_flow; mod ct_runner; mod errors; mod list_comprehensions; mod otp; mod patterns; mod records; fn lower_file(path: S, config: ParseConfig) -> Result where S: AsRef, { let mut errors: Errors = Errors::new(); let codemap = Arc::new(CodeMap::new()); let eir_res = error_tee(&mut errors, |mut errors| { let parser = Parser::new(config, codemap.clone()); let ast = parser.parse_file(&mut errors.make_into_adapter(), path)?; let eir = lower_module(&mut errors.make_into_adapter(), codemap.clone(), &ast)?; Ok(eir) }); errors.print(&codemap); eir_res } pub fn lower(input: S, config: ParseConfig) -> Result where S: AsRef, { let mut errors: Errors = Errors::new(); let codemap = Arc::new(CodeMap::new()); let eir_res = error_tee(&mut errors, |mut errors| { let parser = Parser::new(config, codemap.clone()); let ast = parser.parse_string(&mut errors.make_into_adapter(), input)?; let eir = lower_module(&mut errors.make_into_adapter(), codemap.clone(), &ast)?; Ok(eir) }); errors.print(&codemap); eir_res } pub fn write_dot(module: &Module, ident: Option) { if let Some(ident) = ident { let idx = module.ident_index(&ident).unwrap(); let fun_def = &module[idx]; let fun = fun_def.function(); let dot = libeir_ir::text::dot_printer::function_to_dot(fun); print!("{}", dot); } else { unimplemented!() } } #[test] fn rand_error() { let _ = env_logger::try_init(); let mut eir_mod = lower( r#" -module(rand). uniform_s(#{a:=_}, _) -> 0; uniform_s(#{b:=B}, N) -> N(), B. "#, ParseConfig::default(), ) .unwrap(); for fun_def in eir_mod.function_iter() { let fun = fun_def.function(); let mut out = Vec::new(); fun.validate(&mut out); assert!(out.len() == 0); } let mut pass_manager = libeir_passes::PassManager::default(); pass_manager.run(&mut eir_mod); } ================================================ FILE: libeir_tests/src/list_comprehensions.rs ================================================ use std::rc::Rc; use crate::lower; use libeir_intern::Ident; use libeir_ir::FunctionIdent; use libeir_passes::PassManager; use libeir_syntax_erl::ParseConfig; use libeir_interpreter::{ErlEq, Term, VMState}; #[test] fn test_list_comprehension_single_filter() { let _ = env_logger::try_init(); let mut eir_mod = lower( " -module(woo). woo(N) -> [1 || erlang:is_integer(N)]. ", ParseConfig::default(), ) .unwrap(); for fun_def in eir_mod.function_iter() { let fun = fun_def.function(); let mut out = Vec::new(); fun.validate(&mut out); assert!(out.len() == 0); } let mut pass_manager = PassManager::default(); pass_manager.run(&mut eir_mod); for fun_def in eir_mod.function_iter() { let fun = fun_def.function(); let mut out = Vec::new(); fun.validate(&mut out); assert!(out.len() == 0); } let fun = FunctionIdent { module: Ident::from_str("woo"), name: Ident::from_str("woo"), arity: 1, }; println!("{}", eir_mod.to_text_standard()); let mut vm = VMState::new(); vm.add_builtin_modules(); vm.add_erlang_module(eir_mod); assert!(vm.call(&fun, &[Term::Nil]).unwrap().erl_eq(&Term::Nil)); { let out = Term::slice_to_list(&[Term::Integer(1.into()).into()], Term::Nil.into()); assert!(vm .call(&fun, &[Term::Integer(1.into())]) .unwrap() .erl_eq(&*out)); } } #[test] fn test_list_comprehension_single_list_generator() { let _ = env_logger::try_init(); let mut eir_mod = lower( " -module(woo). woo(L) -> [X*2 || X <- L]. ", ParseConfig::default(), ) .unwrap(); for fun_def in eir_mod.function_iter() { let fun = fun_def.function(); let mut out = Vec::new(); fun.validate(&mut out); assert!(out.len() == 0); } let mut pass_manager = PassManager::default(); pass_manager.run(&mut eir_mod); for fun_def in eir_mod.function_iter() { let fun = fun_def.function(); let mut out = Vec::new(); fun.validate(&mut out); assert!(out.len() == 0); } let fun = FunctionIdent { module: Ident::from_str("woo"), name: Ident::from_str("woo"), arity: 1, }; println!("{}", eir_mod.to_text_standard()); let mut vm = VMState::new(); vm.add_builtin_modules(); vm.add_erlang_module(eir_mod); assert!(vm.call(&fun, &[Term::Nil]).unwrap().erl_eq(&Term::Nil)); { let in_list = Term::slice_to_list(&[Term::Integer(1.into()).into()], Term::Nil.into()); let out_list = Term::slice_to_list(&[Term::Integer(2.into()).into()], Term::Nil.into()); assert!(vm .call(&fun, &[Rc::try_unwrap(in_list).unwrap()]) .unwrap() .erl_eq(&*out_list)); } { let in_list = Term::slice_to_list( &[ Term::Integer(1.into()).into(), Term::Integer(2.into()).into(), Term::Integer(3.into()).into(), ], Term::Nil.into(), ); let out_list = Term::slice_to_list( &[ Term::Integer(2.into()).into(), Term::Integer(4.into()).into(), Term::Integer(6.into()).into(), ], Term::Nil.into(), ); assert!(vm .call(&fun, &[Rc::try_unwrap(in_list).unwrap()]) .unwrap() .erl_eq(&*out_list)); } } #[test] fn test_list_comprehension_combinations() { let _ = env_logger::try_init(); let mut eir_mod = lower( " -module(woo). comb([]) -> [[]]; comb(L) -> [[A, B] || A <- L, B <- L]. ", ParseConfig::default(), ) .unwrap(); for fun_def in eir_mod.function_iter() { let fun = fun_def.function(); let mut out = Vec::new(); fun.validate(&mut out); assert!(out.len() == 0); } let mut pass_manager = PassManager::default(); pass_manager.run(&mut eir_mod); for fun_def in eir_mod.function_iter() { let fun = fun_def.function(); let mut out = Vec::new(); fun.validate(&mut out); println!("{:?}", out); assert!(out.len() == 0); } let fun = FunctionIdent { module: Ident::from_str("woo"), name: Ident::from_str("comb"), arity: 1, }; let mut vm = VMState::new(); vm.add_builtin_modules(); vm.add_erlang_module(eir_mod); { let arg = Term::slice_to_list( &[Term::new_atom("b").into(), Term::new_atom("u").into()], Term::Nil.into(), ); let out = Term::slice_to_list( &[ Term::slice_to_list( &[Term::new_atom("b").into(), Term::new_atom("b").into()], Term::Nil.into(), ), Term::slice_to_list( &[Term::new_atom("b").into(), Term::new_atom("u").into()], Term::Nil.into(), ), Term::slice_to_list( &[Term::new_atom("u").into(), Term::new_atom("b").into()], Term::Nil.into(), ), Term::slice_to_list( &[Term::new_atom("u").into(), Term::new_atom("u").into()], Term::Nil.into(), ), ], Term::Nil.into(), ); let res = vm.call(&fun, &[Rc::try_unwrap(arg).unwrap()]).unwrap(); assert!(res.erl_eq(&out)); } } #[test] fn test_basic_comprehension() { let _ = env_logger::try_init(); let mut eir_mod = lower( " -module(woo). perms(L) -> [H || H <- L]. ", ParseConfig::default(), ) .unwrap(); for fun_def in eir_mod.function_iter() { let fun = fun_def.function(); let mut out = Vec::new(); fun.validate(&mut out); assert!(out.len() == 0); } let mut pass_manager = PassManager::default(); pass_manager.run(&mut eir_mod); for fun_def in eir_mod.function_iter() { let fun = fun_def.function(); let mut out = Vec::new(); fun.validate(&mut out); println!("{:?}", out); assert!(out.len() == 0); println!("{}", fun.to_text_standard()); libeir_lowerutils::analyze(fun); } println!("{}", eir_mod.to_text_standard()); } #[test] fn test_list_comprehension_permutations() { let _ = env_logger::try_init(); let mut eir_mod = lower( " -module(woo). perms([]) -> [[]]; perms(L) -> [[H|T] || H <- L, T <- perms(L--[H])]. ", ParseConfig::default(), ) .unwrap(); for fun_def in eir_mod.function_iter() { let fun = fun_def.function(); let mut out = Vec::new(); fun.validate(&mut out); assert!(out.len() == 0); } let mut pass_manager = PassManager::default(); pass_manager.run(&mut eir_mod); for fun_def in eir_mod.function_iter() { let fun = fun_def.function(); let mut out = Vec::new(); fun.validate(&mut out); assert!(out.len() == 0); let analysis = libeir_lowerutils::analyze(fun); dbg!(analysis); } println!("{}", eir_mod.to_text_standard()); let fun = FunctionIdent { module: Ident::from_str("woo"), name: Ident::from_str("perms"), arity: 1, }; let mut vm = VMState::new(); vm.add_builtin_modules(); vm.add_erlang_module(eir_mod); { let b: Rc = Term::new_atom("b").into(); let u: Rc = Term::new_atom("u").into(); let g: Rc = Term::new_atom("g").into(); let arg = Term::slice_to_list(&[b.clone(), u.clone(), g.clone()], Term::Nil.into()); let out = Term::slice_to_list( &[ Term::slice_to_list(&[b.clone(), u.clone(), g.clone()], Term::Nil.into()), Term::slice_to_list(&[b.clone(), g.clone(), u.clone()], Term::Nil.into()), Term::slice_to_list(&[u.clone(), b.clone(), g.clone()], Term::Nil.into()), Term::slice_to_list(&[u.clone(), g.clone(), b.clone()], Term::Nil.into()), Term::slice_to_list(&[g.clone(), b.clone(), u.clone()], Term::Nil.into()), Term::slice_to_list(&[g.clone(), u.clone(), b.clone()], Term::Nil.into()), ], Term::Nil.into(), ); let res = vm.call(&fun, &[Rc::try_unwrap(arg).unwrap()]).unwrap(); println!("{:?}", res); println!("{:?}", out); assert!(res.erl_eq(&out)); } } #[ignore] #[test] fn test_binary_comprehension() { let _ = env_logger::try_init(); let mut eir_mod = lower( " -module(woo). woo(N) -> [X || <> <= <<1, 2, 3>>]. ", ParseConfig::default(), ) .unwrap(); for fun_def in eir_mod.function_iter() { let fun = fun_def.function(); let mut out = Vec::new(); fun.validate(&mut out); assert!(out.len() == 0); } let mut pass_manager = PassManager::default(); pass_manager.run(&mut eir_mod); for fun_def in eir_mod.function_iter() { let fun = fun_def.function(); let mut out = Vec::new(); fun.validate(&mut out); assert!(out.len() == 0); } let fun = FunctionIdent { module: Ident::from_str("woo"), name: Ident::from_str("woo"), arity: 1, }; println!("{}", eir_mod.to_text_standard()); let mut vm = VMState::new(); vm.add_builtin_modules(); vm.add_erlang_module(eir_mod); assert!(vm.call(&fun, &[Term::Nil]).unwrap().erl_eq(&Term::Nil)); { let out = Term::slice_to_list(&[Term::Integer(1.into()).into()], Term::Nil.into()); assert!(vm .call(&fun, &[Term::Integer(1.into())]) .unwrap() .erl_eq(&*out)); } } ================================================ FILE: libeir_tests/src/otp/mod.rs ================================================ use std::path::PathBuf; use crate::ct_runner::run_ct_suite; use crate::{lower, lower_file, ParseConfig}; use libeir_intern::Ident; use libeir_passes::PassManager; use libeir_interpreter::VMState; use libeir_lowerutils::analyze; #[ignore] #[test] fn compiler() { let _ = env_logger::try_init(); let mut config = ParseConfig::default(); config .include_paths .push_front(PathBuf::from("../otp/lib/compiler/src/")); config .include_paths .push_front(PathBuf::from("../otp/bootstrap/lib/stdlib/include/")); let mut eir_mod = lower_file("../otp/lib/compiler/src/compile.erl", config).unwrap(); for fun_def in eir_mod.function_iter() { let fun = fun_def.function(); fun.graph_validate_global(); } let mut pass_manager = PassManager::default(); pass_manager.run(&mut eir_mod); } #[ignore] #[test] fn beam_disasm() { let _ = env_logger::try_init(); let mut config = ParseConfig::default(); config .include_paths .push_front(PathBuf::from("../otp/lib/compiler/src/")); config .include_paths .push_front(PathBuf::from("../otp/bootstrap/lib/stdlib/include/")); let mut eir_mod = lower_file("../otp/lib/compiler/src/beam_disasm.erl", config).unwrap(); for fun_def in eir_mod.function_iter() { let fun = fun_def.function(); fun.graph_validate_global(); } let mut pass_manager = PassManager::default(); pass_manager.run(&mut eir_mod); } #[ignore] #[test] fn core_parse() { let _ = env_logger::try_init(); let mut config = ParseConfig::default(); config .include_paths .push_front(PathBuf::from("../otp/lib/compiler/src/")); config .include_paths .push_front(PathBuf::from("../otp/bootstrap/lib/stdlib/include/")); let mut eir_mod = lower_file("../otp/lib/compiler/src/core_parse.erl", config).unwrap(); for fun_def in eir_mod.function_iter() { let fun = fun_def.function(); fun.graph_validate_global(); } let mut pass_manager = PassManager::default(); pass_manager.run(&mut eir_mod); } #[ignore] #[test] fn maps() { let _ = env_logger::try_init(); let config = ParseConfig::default(); let mut eir_mod = lower_file("../otp/lib/stdlib/src/maps.erl", config).unwrap(); for fun_def in eir_mod.function_iter() { let fun = fun_def.function(); fun.graph_validate_global(); } let mut pass_manager = PassManager::default(); pass_manager.run(&mut eir_mod); } #[ignore] #[test] fn match_suite() { let _ = env_logger::try_init(); let mut config = ParseConfig::default(); config.code_paths.push_front(PathBuf::from("../otp/lib/")); let mut eir_mod = lower_file("../otp/lib/compiler/test/match_SUITE.erl", config).unwrap(); for fun_def in eir_mod.function_iter() { let fun = fun_def.function(); println!("{}", fun.ident()); fun.graph_validate_global(); fun.live_values(); } let mut pass_manager = PassManager::default(); pass_manager.run(&mut eir_mod); for fun_def in eir_mod.function_iter() { let fun = fun_def.function(); println!("{}", fun.ident()); println!("{}", fun.to_text_standard()); fun.graph_validate_global(); fun.live_values(); } let mut vm = VMState::new(); vm.add_builtin_modules(); vm.add_erlang_module(eir_mod); run_ct_suite(&mut vm, Ident::from_str("match_SUITE")); } #[ignore] #[test] fn bs_match_suite() { let _ = env_logger::try_init(); let mut config = ParseConfig::default(); config.code_paths.push_front(PathBuf::from("../otp/lib/")); let mut eir_mod = lower_file("../otp_build/bs_match_SUITE_patched.erl", config).unwrap(); for fun_def in eir_mod.function_iter() { let fun = fun_def.function(); fun.graph_validate_global(); } let mut pass_manager = PassManager::default(); pass_manager.run(&mut eir_mod); let mut vm = VMState::new(); vm.add_builtin_modules(); vm.add_erlang_module(eir_mod); run_ct_suite(&mut vm, Ident::from_str("bs_match_SUITE")); } #[ignore] #[test] fn maps_suite() { let _ = env_logger::try_init(); let config = ParseConfig::default(); let mut maps_eir_mod = lower_file("../otp/lib/stdlib/src/maps.erl", config).unwrap(); let config = ParseConfig::default(); let mut eir_mod = lower_file("../otp/lib/compiler/test/map_SUITE.erl", config).unwrap(); for fun_def in maps_eir_mod.function_iter() { let fun = fun_def.function(); fun.graph_validate_global(); } for fun_def in eir_mod.function_iter() { let fun = fun_def.function(); fun.graph_validate_global(); } let mut pass_manager = PassManager::default(); pass_manager.run(&mut maps_eir_mod); pass_manager.run(&mut eir_mod); let mut vm = VMState::new(); vm.add_builtin_modules(); vm.add_erlang_module(eir_mod); vm.add_erlang_module(maps_eir_mod); run_ct_suite(&mut vm, Ident::from_str("map_SUITE")); } #[ignore] #[test] fn xmerl_scan() { let _ = env_logger::try_init(); let mut config = ParseConfig::default(); config.code_paths.push_front(PathBuf::from("../otp/lib/")); config .include_paths .push_front(PathBuf::from("../otp/lib/xmerl/src/")); config .include_paths .push_front(PathBuf::from("../otp/lib/xmerl/include/")); let mut eir_mod = lower_file("../otp/lib/xmerl/src/xmerl_scan.erl", config).unwrap(); for fun_def in eir_mod.function_iter() { let fun = fun_def.function(); fun.graph_validate_global(); } let mut pass_manager = PassManager::default(); pass_manager.run(&mut eir_mod); } #[ignore] #[test] fn xmerl_sax_parser_utf8() { let _ = env_logger::try_init(); let mut config = ParseConfig::default(); config.code_paths.push_front(PathBuf::from("../otp/lib/")); config .include_paths .push_front(PathBuf::from("../otp/lib/xmerl/src/")); config .include_paths .push_front(PathBuf::from("../otp/lib/xmerl/include/")); let mut eir_mod = lower_file("../otp/lib/xmerl/src/xmerl_sax_parser_latin1.erl", config).unwrap(); for fun_def in eir_mod.function_iter() { let fun = fun_def.function(); fun.graph_validate_global(); } let mut pass_manager = PassManager::default(); pass_manager.run(&mut eir_mod); } #[ignore] #[test] fn foo() { let _ = env_logger::try_init(); let config = ParseConfig::default(); let mut eir_mod = lower_file("foo.erl", config).unwrap(); for fun_def in eir_mod.function_iter() { let fun = fun_def.function(); fun.graph_validate_global(); } let mut pass_manager = PassManager::default(); pass_manager.run(&mut eir_mod); panic!("{:?}"); } #[test] fn aa() { let _ = env_logger::try_init(); let text = " -module(foo). do_map_vars_used(X, Y, Map) -> case {X,Y} of T -> %% core_lib:is_var_used/2 would not consider T used. #{T:=42,v:=Val} = Map, Val end. "; let config = ParseConfig::default(); let mut eir_mod = lower(text, config).unwrap(); for fun_def in eir_mod.function_iter() { let fun = fun_def.function(); fun.graph_validate_global(); } let mut pass_manager = PassManager::default(); pass_manager.run(&mut eir_mod); for fun_def in eir_mod.function_iter() { let fun = fun_def.function(); fun.live_values(); } } #[test] fn unary_op_1() { let _ = env_logger::try_init(); let text = " -module(foo). unary_op_1(Vop@1) -> %% If all optimizations are working as they should, there should %% be no stack frame and all '=:=' tests should be coalesced into %% a single select_val instruction. case Vop@1 =:= '&' of true -> {non_associative,30}; false -> case case Vop@1 =:= '^' of true -> true; false -> case Vop@1 =:= 'not' of true -> true; false -> case Vop@1 =:= '+' of true -> true; false -> case Vop@1 =:= '-' of true -> true; false -> case Vop@1 =:= '~~~' of true -> true; false -> Vop@1 =:= '!' end end end end end of true -> {non_associative,300}; false -> case Vop@1 =:= '@' of true -> {non_associative,320}; false -> error end end end. "; let config = ParseConfig::default(); let mut eir_mod = lower(text, config).unwrap(); for fun_def in eir_mod.function_iter() { let fun = fun_def.function(); fun.graph_validate_global(); } let mut pass_manager = PassManager::default(); pass_manager.run(&mut eir_mod); for fun_def in eir_mod.function_iter() { let fun = fun_def.function(); fun.live_values(); } } #[test] fn unary_op_1_a() { let _ = env_logger::try_init(); let text = " -module(foobarrr). unary_op_1(Vop@1) -> case case Vop@1 =:= '^' of true -> a; false -> b end of true -> c end. "; let config = ParseConfig::default(); let mut eir_mod = lower(text, config).unwrap(); for fun_def in eir_mod.function_iter() { let fun = fun_def.function(); fun.graph_validate_global(); } let mut pass_manager = PassManager::default(); pass_manager.run(&mut eir_mod); for fun_def in eir_mod.function_iter() { let fun = fun_def.function(); fun.live_values(); } } ================================================ FILE: libeir_tests/src/patterns.rs ================================================ use std::rc::Rc; use super::lower; use libeir_intern::{Ident, Symbol}; use libeir_ir::FunctionIdent; use libeir_passes::PassManager; use libeir_syntax_erl::ParseConfig; use libeir_interpreter::{ErlEq, Term, VMState}; #[test] fn test_pattern_equality() { let _ = env_logger::try_init(); let mut eir_mod = lower( " -module(woo). basic_pat(A, A) -> true; basic_pat(_, _) -> false. ", ParseConfig::default(), ) .unwrap(); let mut pass_manager = PassManager::default(); pass_manager.run(&mut eir_mod); let fun = FunctionIdent { module: Ident::from_str("woo"), name: Ident::from_str("basic_pat"), arity: 2, }; let mut vm = VMState::new(); vm.add_builtin_modules(); vm.add_erlang_module(eir_mod); assert!(vm.call(&fun, &[1.into(), 1.into()]).unwrap().as_boolean() == Some(true)); assert!(vm.call(&fun, &[1.into(), 2.into()]).unwrap().as_boolean() == Some(false)); } #[test] fn test_tuple_pattern() { let _ = env_logger::try_init(); let mut eir_mod = lower( " -module(woo). woo({1, 2}) -> 1; woo({1, 2, 3}) -> 2; woo(_) -> 3. ", ParseConfig::default(), ) .unwrap(); let mut pass_manager = PassManager::default(); pass_manager.run(&mut eir_mod); let fun = FunctionIdent { module: Ident::from_str("woo"), name: Ident::from_str("woo"), arity: 1, }; let mut vm = VMState::new(); vm.add_builtin_modules(); vm.add_erlang_module(eir_mod); assert!(vm.call(&fun, &[1.into()]).unwrap().as_i64() == Some(3)); { let arg = Term::Tuple(vec![ Term::Integer(1.into()).into(), Term::Integer(2.into()).into(), ]); assert!(vm.call(&fun, &[arg.into()]).unwrap().as_i64() == Some(1)); } { let arg = Term::Tuple(vec![ Term::Integer(2.into()).into(), Term::Integer(2.into()).into(), ]); assert!(vm.call(&fun, &[arg.into()]).unwrap().as_i64() == Some(3)); } { let arg = Term::Tuple(vec![ Term::Integer(1.into()).into(), Term::Integer(2.into()).into(), Term::Integer(3.into()).into(), ]); assert!(vm.call(&fun, &[arg.into()]).unwrap().as_i64() == Some(2)); } { let arg = Term::Tuple(vec![ Term::Integer(1.into()).into(), Term::Integer(2.into()).into(), Term::Integer(2.into()).into(), ]); assert!(vm.call(&fun, &[arg.into()]).unwrap().as_i64() == Some(3)); } } #[test] fn test_list_pattern() { let _ = env_logger::try_init(); let mut eir_mod = lower( " -module(woo). woo([6 | 7]) -> 1; woo([1, 2]) -> 2; woo([]) -> 3; woo(_) -> 4. ", ParseConfig::default(), ) .unwrap(); let mut pass_manager = PassManager::default(); pass_manager.run(&mut eir_mod); let fun = FunctionIdent { module: Ident::from_str("woo"), name: Ident::from_str("woo"), arity: 1, }; let mut vm = VMState::new(); vm.add_builtin_modules(); vm.add_erlang_module(eir_mod); assert!(vm.call(&fun, &[1.into()]).unwrap().as_i64() == Some(4)); { let arg = Term::slice_to_list( &[ Term::Integer(1.into()).into(), Term::Integer(2.into()).into(), ], Term::Nil.into(), ); assert!( vm.call(&fun, &[Rc::try_unwrap(arg).unwrap()]) .unwrap() .as_i64() == Some(2) ); } } #[test] fn test_fun_atom_pattern() { let _ = env_logger::try_init(); let mut eir_mod = lower( " -module(woo). woo(abc) -> 1; woo(def) -> 2. ", ParseConfig::default(), ) .unwrap(); let mut pass_manager = PassManager::default(); pass_manager.run(&mut eir_mod); let fun = FunctionIdent { module: Ident::from_str("woo"), name: Ident::from_str("woo"), arity: 1, }; let mut vm = VMState::new(); vm.add_builtin_modules(); vm.add_erlang_module(eir_mod); assert!( vm.call(&fun, &[Term::Atom(Symbol::intern("abc")).into()]) .unwrap() .as_i64() == Some(1) ); assert!( vm.call(&fun, &[Term::Atom(Symbol::intern("def")).into()]) .unwrap() .as_i64() == Some(2) ); { let res = vm.call(&fun, &[Term::Nil.into()]).err().unwrap(); assert!(res.0.erl_eq(&Term::Atom(Symbol::intern("error")).into())); assert!(res .1 .erl_eq(&Term::Atom(Symbol::intern("function_clause")).into())); } } #[test] fn test_case_atom_pattern() { let _ = env_logger::try_init(); let mut eir_mod = lower( " -module(woo). woo(A) -> case A of abc -> 1; def -> 2 end. ", ParseConfig::default(), ) .unwrap(); let mut pass_manager = PassManager::default(); pass_manager.run(&mut eir_mod); let fun = FunctionIdent { module: Ident::from_str("woo"), name: Ident::from_str("woo"), arity: 1, }; let mut vm = VMState::new(); vm.add_builtin_modules(); vm.add_erlang_module(eir_mod); assert!( vm.call(&fun, &[Term::Atom(Symbol::intern("abc")).into()]) .unwrap() .as_i64() == Some(1) ); assert!( vm.call(&fun, &[Term::Atom(Symbol::intern("def")).into()]) .unwrap() .as_i64() == Some(2) ); { let res = vm .call(&fun, &[Term::Atom(Symbol::intern("aaa")).into()]) .err() .unwrap(); assert!(res.0.erl_eq(&Term::Atom(Symbol::intern("error")).into())); assert!(res.1.erl_eq(&Term::Tuple(vec![ Term::Atom(Symbol::intern("case_clause")).into(), Term::Atom(Symbol::intern("aaa")).into(), ]))); } } ================================================ FILE: libeir_tests/src/records.rs ================================================ use super::{lower, write_dot}; use libeir_intern::{Ident, Symbol}; use libeir_ir::FunctionIdent; use libeir_passes::PassManager; use libeir_syntax_erl::ParseConfig; use libeir_interpreter::{ErlEq, Term, VMState}; #[test] fn record_creation() { let _ = env_logger::try_init(); let mut eir_mod = lower( " -module(woo). -record(person, {name, phone, address}). -record(alien, {name, planet = zorgon}). create_1(A) -> #person{name=A}. create_2(A) -> #person{address=A}. create_3(A) -> #person{address=A, phone=12}. create_4(A) -> #alien{name=A}. create_5(A, B) -> #alien{name=A, planet=B}. ", ParseConfig::default(), ) .unwrap(); let mut pass_manager = PassManager::default(); pass_manager.run(&mut eir_mod); let fun = FunctionIdent { module: Ident::from_str("woo"), name: Ident::from_str("create_1"), arity: 1, }; write_dot(&eir_mod, Some(fun.clone())); let mut vm = VMState::new(); vm.add_builtin_modules(); vm.add_erlang_module(eir_mod); { let fun = FunctionIdent { module: Ident::from_str("woo"), name: Ident::from_str("create_1"), arity: 1, }; let out = Term::Tuple(vec![ Term::Atom(Symbol::intern("person")).into(), Term::Integer(1.into()).into(), Term::Atom(Symbol::intern("undefined")).into(), Term::Atom(Symbol::intern("undefined")).into(), ]); assert!(vm.call(&fun, &[1.into()]).unwrap().erl_eq(&out)); } { let fun = FunctionIdent { module: Ident::from_str("woo"), name: Ident::from_str("create_2"), arity: 1, }; let out = Term::Tuple(vec![ Term::Atom(Symbol::intern("person")).into(), Term::Atom(Symbol::intern("undefined")).into(), Term::Atom(Symbol::intern("undefined")).into(), Term::Integer(1.into()).into(), ]); assert!(vm.call(&fun, &[1.into()]).unwrap().erl_eq(&out)); } { let fun = FunctionIdent { module: Ident::from_str("woo"), name: Ident::from_str("create_3"), arity: 1, }; let out = Term::Tuple(vec![ Term::Atom(Symbol::intern("person")).into(), Term::Atom(Symbol::intern("undefined")).into(), Term::Integer(12.into()).into(), Term::Integer(2.into()).into(), ]); assert!(vm.call(&fun, &[2.into()]).unwrap().erl_eq(&out)); } { let fun = FunctionIdent { module: Ident::from_str("woo"), name: Ident::from_str("create_4"), arity: 1, }; let out = Term::Tuple(vec![ Term::Atom(Symbol::intern("alien")).into(), Term::Atom(Symbol::intern("zsf")).into(), Term::Atom(Symbol::intern("zorgon")).into(), ]); assert!(vm .call(&fun, &[Term::Atom(Symbol::intern("zsf")).into()]) .unwrap() .erl_eq(&out)); } { let fun = FunctionIdent { module: Ident::from_str("woo"), name: Ident::from_str("create_5"), arity: 2, }; let out = Term::Tuple(vec![ Term::Atom(Symbol::intern("alien")).into(), Term::Atom(Symbol::intern("zsf")).into(), Term::Atom(Symbol::intern("xon")).into(), ]); assert!(vm .call( &fun, &[ Term::Atom(Symbol::intern("zsf")).into(), Term::Atom(Symbol::intern("xon")).into(), ] ) .unwrap() .erl_eq(&out)); } } #[test] fn record_creation_a() { let _ = env_logger::try_init(); let mut eir_mod = lower( " -module(woohoo). -record(person, {name, phone, address}). create_1(A) -> #person{name=A}. ", ParseConfig::default(), ) .unwrap(); let mut pass_manager = PassManager::default(); pass_manager.run(&mut eir_mod); let fun = FunctionIdent { module: Ident::from_str("woo"), name: Ident::from_str("create_1"), arity: 1, }; let mut vm = VMState::new(); vm.add_builtin_modules(); vm.add_erlang_module(eir_mod); } ================================================ FILE: otp_build/bs_match_SUITE.erl ================================================ %% %% %CopyrightBegin% %% %% Copyright Ericsson AB 2005-2018. All Rights Reserved. %% %% 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. %% %% %CopyrightEnd% %% -module(bs_match_SUITE). -compile(nowarn_shadow_vars). -export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1, init_per_group/2,end_per_group/2, init_per_testcase/2,end_per_testcase/2, size_shadow/1,int_float/1,otp_5269/1,null_fields/1,wiger/1, bin_tail/1,save_restore/1, partitioned_bs_match/1,function_clause/1, unit/1,shared_sub_bins/1,bin_and_float/1, dec_subidentifiers/1,skip_optional_tag/1,decode_integer/1, wfbm/1,degenerated_match/1,bs_sum/1,coverage/1, multiple_uses/1,zero_label/1,followed_by_catch/1, matching_meets_construction/1,simon/1,matching_and_andalso/1, otp_7188/1,otp_7233/1,otp_7240/1,otp_7498/1, match_string/1,zero_width/1,bad_size/1,haystack/1, cover_beam_bool/1,matched_out_size/1,follow_fail_branch/1, no_partition/1,calling_a_binary/1,binary_in_map/1, match_string_opt/1,select_on_integer/1, map_and_binary/1,unsafe_branch_caching/1, bad_literals/1,good_literals/1,constant_propagation/1, parse_xml/1,get_payload/1,escape/1,num_slots_different/1, beam_bsm/1,guard/1,is_ascii/1,non_opt_eq/1,erl_689/1, bs_start_match2_defs/1]). -export([coverage_id/1,coverage_external_ignore/2]). -include_lib("common_test/include/ct.hrl"). %-include_lib("syntax_tools/include/merl.hrl"). suite() -> [{ct_hooks,[ts_install_cth]}, {timetrap,{minutes,1}}]. all() -> [{group,p}]. groups() -> [{p,[parallel], [size_shadow,int_float,otp_5269,null_fields,wiger, bin_tail,save_restore, partitioned_bs_match,function_clause,unit, shared_sub_bins,bin_and_float,dec_subidentifiers, skip_optional_tag,decode_integer,wfbm,degenerated_match,bs_sum, coverage,multiple_uses,zero_label,followed_by_catch, matching_meets_construction,simon, matching_and_andalso,otp_7188,otp_7233,otp_7240, otp_7498,match_string,zero_width,bad_size,haystack, cover_beam_bool,matched_out_size,follow_fail_branch, no_partition,calling_a_binary,binary_in_map, match_string_opt,select_on_integer, map_and_binary,unsafe_branch_caching, % bad_literals,good_literals,constant_propagation,parse_xml, good_literals,constant_propagation,parse_xml, get_payload,escape,num_slots_different, beam_bsm,guard,is_ascii,non_opt_eq,erl_689, bs_start_match2_defs]}]. init_per_suite(Config) -> test_lib:recompile(?MODULE), Config. end_per_suite(_Config) -> ok. init_per_group(_GroupName, Config) -> Config. end_per_group(_GroupName, Config) -> Config. init_per_testcase(Case, Config) when is_atom(Case), is_list(Config) -> Config. end_per_testcase(Case, Config) when is_atom(Case), is_list(Config) -> ok. size_shadow(Config) when is_list(Config) -> %% Originally OTP-5270. 7 = size_shadow_1(), 7 = size_shadow_2(8), 7 = size_shadow_3(), no = size_shadow_4(8), Any = {any,term,goes}, {2577,Any,-175,whatever} = (size_shadow_5(Any, 12))(<<2577:12>>, -175, whatever), {7777,Any,42,whatever} = (size_shadow_6(Any, 13))(42, <<7777:13>>, whatever), {<<45>>,<<>>} = size_shadow_7({int,1}, <<1:16,45>>), {'EXIT',{function_clause,_}} = (catch size_shadow_7({int,42}, <<1:16,45>>)), ok. size_shadow_1() -> L = 8, F = fun(<>) -> B end, F(<<16:8, 7:16>>). size_shadow_2(L) -> F = fun(<>) -> B end, F(<<16:8, 7:16>>). size_shadow_3() -> L = 8, F = fun(<>) -> B end, F(<<16:8, 7:16,16:16>>). size_shadow_4(L) -> F = fun(<>) -> B; (_) -> no end, F(<<16:8, 7:16,15:16>>). size_shadow_5(X, Y) -> fun (<< A:Y >>, Y, B) -> fum(A, X, Y, B) end. size_shadow_6(X, Y) -> fun (Y, << A:Y >>, B) -> fum(A, X, Y, B) end. fum(A, B, C, D) -> {A,B,C,D}. size_shadow_7({int,N}, <>) -> {B,T}. int_float(Config) when is_list(Config) -> %% OTP-5323 <<103133.0:64/float>> = <<103133:64/float>>, <<103133:64/float>> = <<103133:64/float>>, %% Coverage of error cases in sys_pre_expand:coerce_to_float/2. case id(default) of <<(1 bsl 1024):64/float>> -> ct:fail(should_not_match); default -> ok end. %% Stolen from erl_eval_SUITE and modified. %% OTP-5269. Bugs in the bit syntax. otp_5269(Config) when is_list(Config) -> check(fun() -> L = 8, F = fun(<>) -> B end, F(<<16:8, 7:16>>) end, 7), check(fun() -> L = 8, <> = <<16:8, 7:16>>, B end, 7), check(fun() -> U = 8, (fun(<>) -> U end)(<<32:8>>) end, 32), check(fun() -> U = 8, [U || <> <- [<<32:8>>]] end, [32]), check(fun() -> [X || <> <- [<<16:8,19:16>>], <> <- [<>]] end, [19]), check(fun() -> A = 4, B = 28, bit_size(<<13:(A+(X=B))>>), X end, 28), check(fun() -> <> = <<2,"AB","CD">>, {Size,B,Rest} end, {2,<<"AB">>,<<"CD">>}), check(fun() -> X = 32, [X || <> <- [<<1:32>>,<<2:32>>,<<3:8>>]] end, %% "binsize variable" ^ [1,2]), check(fun() -> (fun (<>) -> case A of B -> wrong; _ -> ok end end)(<<1,2,3,4>>) end, ok), ok. null_fields(Config) when is_list(Config) -> check(fun() -> W = id(0), F = fun(<<_:W>>) -> tail; (<<>>) -> empty end, F(<<>>) end, tail), check(fun() -> F = fun(<<_/binary>>) -> tail; (<<>>) -> empty end, F(<<>>) end, tail), ok. wiger(Config) when is_list(Config) -> ok1 = wcheck(<<3>>), ok2 = wcheck(<<1,2,3>>), ok3 = wcheck(<<4>>), {error,<<1,2,3,4>>} = wcheck(<<1,2,3,4>>), {error,<<>>} = wcheck(<<>>), ok. wcheck(<>) when A==3-> ok1; wcheck(<<_,_:2/binary>>) -> ok2; wcheck(<<_>>) -> ok3; wcheck(Other) -> {error,Other}. bin_tail(Config) when is_list(Config) -> S = <<"abcde">>, $a = bin_tail_c(S, 0), $c = bin_tail_c(S, 2), $e = bin_tail_c(S, 4), {'EXIT',_} = (catch bin_tail_c(S, 5)), {'EXIT',_} = (catch bin_tail_c_var(S, 5)), $a = bin_tail_d(S, 0), $b = bin_tail_d(S, 8), $d = bin_tail_d(S, 3*8), {'EXIT',_} = (catch bin_tail_d_dead(S, 1)), {'EXIT',_} = (catch bin_tail_d_dead(S, 9)), {'EXIT',_} = (catch bin_tail_d_dead(S, 5*8)), {'EXIT',_} = (catch bin_tail_d_var(S, 1)), ok = bin_tail_e(<<2:2,0:1,1:5>>), ok = bin_tail_e(<<2:2,1:1,1:5,42:64>>), error = bin_tail_e(<<3:2,1:1,1:5,42:64>>), error = bin_tail_e(<<>>), ok. bin_tail_c(Bin, Offset) -> Res = bin_tail_c_dead(Bin, Offset), <<_:Offset/binary,_,Tail/binary>> = Bin, {Res,Tail} = bin_tail_c_var(Bin, Offset), Res. bin_tail_c_dead(Bin, Offset) -> <<_:Offset/binary,C,_/binary>> = Bin, C. bin_tail_c_var(Bin, Offset) -> <<_:Offset/binary,C,Tail/binary>> = Bin, {C,Tail}. bin_tail_d(Bin, BitOffset) -> Res = bin_tail_d_dead(Bin, BitOffset), <<_:BitOffset,_:8,Tail/binary>> = Bin, {Res,Tail} = bin_tail_d_var(Bin, BitOffset), Res. bin_tail_d_dead(Bin, BitOffset) -> <<_:BitOffset,C,_/binary>> = Bin, C. bin_tail_d_var(Bin, BitOffset) -> <<_:BitOffset,C,Tail/binary>> = Bin, {C,Tail}. bin_tail_e(Bin) -> case bin_tail_e_dead(Bin) of ok -> <<_,Tail/binary>> = Bin, Tail = bin_tail_e_var(Bin), ok; error -> bin_tail_e_var(Bin) end. bin_tail_e_dead(Bin) -> case Bin of %% The binary is aligned at the end; neither the bs_skip_bits2 nor %% bs_test_tail2 instructions are needed. <<2:2,_:1,1:5,_/binary>> -> ok; _ -> error end. bin_tail_e_var(Bin) -> case Bin of %% The binary is aligned at the end; neither the bs_skip_bits2 nor %% bs_test_tail2 instructions are needed. <<2:2,_:1,1:5,Tail/binary>> -> Tail; _ -> error end. save_restore(Config) when is_list(Config) -> 0 = save_restore_1(<<0:2,42:6>>), {1,3456} = save_restore_1(<<1:2,3456:14>>), {2,7981234} = save_restore_1(<<2:2,7981234:30>>), {3,763967493838} = save_restore_1(<<0:2,763967493838:62>>), A = <<" x">>, B = <<".x">>, C = <<"-x">>, {" ",<<"x">>} = lll(A), {" ",<<"x">>} = mmm(A), {" ",<<"x">>} = nnn(A), {" ",<<"x">>} = ooo(A), {".",<<"x">>} = lll(B), {".",<<"x">>} = mmm(B), {".",<<"x">>} = nnn(B), {".",<<"x">>} = ooo(B), {"-",<<"x">>} = lll(C), {"-",<<"x">>} = mmm(C), {"-",<<"x">>} = nnn(C), {"-",<<"x">>} = ooo(C), a = multiple_matches(<<777:16>>, <<777:16>>), b = multiple_matches(<<777:16>>, <<999:16>>), c = multiple_matches(<<777:16>>, <<57:8>>), d = multiple_matches(<<17:8>>, <<1111:16>>), Bin = <<-1:64>>, case bad_float_unpack_match(Bin) of -1 -> ok; _Other -> ct:fail(bad_return_value_probably_NaN) end. save_restore_1(Bin) -> case Bin of <<0:2,_:6>> -> 0; <<1:2,A:14>> -> {1,A}; <<2:2,A:30>> -> {2,A}; <> -> {3,A} end. lll(<>) -> {[Char],Tail}. mmm(<<$.,$.,$., Tail/binary>>) -> Tail; mmm(<<$\s,$-,$\s, Tail/binary>>) -> Tail; mmm(<>) -> {[Char],Tail}. %% Buggy Tail! nnn(<<"...", Tail/binary>>) -> Tail; nnn(<<" - ", Tail/binary>>) -> Tail; nnn(<>) -> {[Char],Tail}. %% Buggy Tail! ooo(<<" - ", Tail/binary>>) -> Tail; ooo(<>) -> {[Char],Tail}. multiple_matches(<>, <>) -> a; multiple_matches(<<_:16>>, <<_:16>>) -> b; multiple_matches(<<_:16>>, <<_:8>>) -> c; multiple_matches(<<_:8>>, <<_:16>>) -> d. bad_float_unpack_match(<>) -> F; bad_float_unpack_match(<>) -> I. partitioned_bs_match(Config) when is_list(Config) -> <<1,2,3>> = partitioned_bs_match(blurf, <<42,1,2,3>>), error = partitioned_bs_match(10, <<7,8,15,13>>), error = partitioned_bs_match(100, {a,tuple,is,'not',a,binary}), ok = partitioned_bs_match(0, <<>>), fc(partitioned_bs_match, [-1,blurf], catch partitioned_bs_match(-1, blurf)), fc(partitioned_bs_match, [-1,<<1,2,3>>], catch partitioned_bs_match(-1, <<1,2,3>>)), {17,<<1,2,3>>} = partitioned_bs_match_2(1, <<17,1,2,3>>), {7,<<1,2,3>>} = partitioned_bs_match_2(7, <<17,1,2,3>>), fc(partitioned_bs_match_2, [4,<<0:17>>], catch partitioned_bs_match_2(4, <<0:17>>)), anything = partitioned_bs_match_3(anything, <<42>>), ok = partitioned_bs_match_3(1, 2), ok. partitioned_bs_match(_, <<42:8,T/binary>>) -> T; partitioned_bs_match(N, _) when N > 0 -> error; partitioned_bs_match(_, <<>>) -> ok. partitioned_bs_match_2(1, <>) -> {B,T}; partitioned_bs_match_2(Len, <<_:8,T/binary>>) -> {Len,T}. partitioned_bs_match_3(Var, <<_>>) -> Var; partitioned_bs_match_3(1, 2) -> ok. function_clause(Config) when is_list(Config) -> ok = function_clause_1(<<0,7,0,7,42>>), fc(function_clause_1, [<<0,1,2,3>>], catch function_clause_1(<<0,1,2,3>>)), fc(function_clause_1, [<<0,1,2,3>>], catch function_clause_1(<<0,7,0,1,2,3>>)), ok = function_clause_2(<<0,7,0,7,42>>), ok = function_clause_2(<<255>>), ok = function_clause_2(<<13:4>>), fc(function_clause_2, [<<0,1,2,3>>], catch function_clause_2(<<0,1,2,3>>)), fc(function_clause_2, [<<0,1,2,3>>], catch function_clause_2(<<0,7,0,1,2,3>>)), ok. function_clause_1(<<0:8,7:8,T/binary>>) -> function_clause_1(T); function_clause_1(<<_:8>>) -> ok. function_clause_2(<<0:8,7:8,T/binary>>) -> function_clause_2(T); function_clause_2(<<_:8>>) -> ok; function_clause_2(<<_:4>>) -> ok. unit(Config) when is_list(Config) -> 42 = peek1(<<42>>), 43 = peek1(<<43,1,2>>), 43 = peek1(<<43,1,2,(-1):1>>), 43 = peek1(<<43,1,2,(-1):2>>), 43 = peek1(<<43,1,2,(-1):7>>), 99 = peek8(<<99>>), 100 = peek8(<<100,101>>), fc(peek8, [<<100,101,0:1>>], catch peek8(<<100,101,0:1>>)), 37484 = peek16(<<37484:16>>), 37489 = peek16(<<37489:16,5566:16>>), fc(peek16, [<<8>>], catch peek16(<<8>>)), fc(peek16, [<<42:15>>], catch peek16(<<42:15>>)), fc(peek16, [<<1,2,3,4,5>>], catch peek16(<<1,2,3,4,5>>)), 127 = peek7(<<127:7>>), 100 = peek7(<<100:7,19:7>>), fc(peek7, [<<1,2>>], catch peek7(<<1,2>>)), ok. peek1(<>) -> B. peek7(<>) -> B. peek8(<>) -> B. peek16(<>) -> B. shared_sub_bins(Config) when is_list(Config) -> {15,[<<>>,<<5>>,<<4,5>>,<<3,4,5>>,<<2,3,4,5>>]} = sum(<<1,2,3,4,5>>, [], 0), ok. sum(<>, Acc, Sum) -> sum(T, [T|Acc], Sum+B); sum(<<>>, Last, Sum) -> {Sum,Last}. bin_and_float(Config) when is_list(Config) -> 14.0 = bin_and_float(<<1.0/float,2.0/float,3.0/float>>, 0.0), ok. bin_and_float(<>, Sum) when is_float(X), is_float(Y), is_float(Z) -> bin_and_float(T, Sum+X*X+Y*Y+Z*Z); bin_and_float(<<>>, Sum) -> Sum. dec_subidentifiers(Config) when is_list(Config) -> {[],<<1,2,3>>} = do_dec_subidentifiers(<<1:1,42:7,1:1,99:7,1,2,3>>, 0, [], 2), {[5389],<<1,2,3>>} = do_dec_subidentifiers(<<1:1,42:7,0:1,13:7,1,2,3>>, 0, [], 2), {[3,2,1],not_a_binary} = dec_subidentifiers(not_a_binary, any, [1,2,3], 0), ok. do_dec_subidentifiers(Buffer, Av, Al, Len) -> Res = dec_subidentifiers(Buffer, Av, Al, Len), Res = dec_subidentifiers2(Buffer, Av, Al, Len), Res = dec_subidentifiers4(Buffer, Av, Al, Len), Res = dec_subidentifiers3(Buffer, Av, Al, Len). dec_subidentifiers(Buffer, _Av, Al, 0) -> {lists:reverse(Al),Buffer}; dec_subidentifiers(<<1:1,H:7,T/binary>>, Av, Al, Len) -> dec_subidentifiers(T, (Av bsl 7) bor H, Al, Len-1); dec_subidentifiers(<>, Av, Al, Len) -> dec_subidentifiers(T, 0, [((Av bsl 7) bor H)|Al], Len-1). dec_subidentifiers2(<>, _Av, Al, 0) -> {lists:reverse(Al),Buffer}; dec_subidentifiers2(<<1:1,H:7,T/binary>>, Av, Al, Len) -> dec_subidentifiers2(T, (Av bsl 7) bor H, Al, Len-1); dec_subidentifiers2(<>, Av, Al, Len) -> dec_subidentifiers2(T, 0, [((Av bsl 7) bor H)|Al], Len-1). dec_subidentifiers3(Buffer, _Av, Al, 0) when is_binary(Buffer) -> {lists:reverse(Al),Buffer}; dec_subidentifiers3(<<1:1,H:7,T/binary>>, Av, Al, Len) -> dec_subidentifiers3(T, (Av bsl 7) bor H, Al, Len-1); dec_subidentifiers3(<>, Av, Al, Len) -> dec_subidentifiers3(T, 0, [((Av bsl 7) bor H)|Al], Len-1). dec_subidentifiers4(<<1:1,H:7,T/binary>>, Av, Al, Len) when Len =/= 0 -> dec_subidentifiers4(T, (Av bsl 7) bor H, Al, Len-1); dec_subidentifiers4(<>, Av, Al, Len) when Len =/= 0 -> dec_subidentifiers4(T, 0, [((Av bsl 7) bor H)|Al], Len-1); dec_subidentifiers4(Buffer, _Av, Al, 0) -> {lists:reverse(Al),Buffer}. skip_optional_tag(Config) when is_list(Config) -> {ok,<<>>} = skip_optional_tag(<<42>>, <<42>>), {ok,<<>>} = skip_optional_tag(<<42,1>>, <<42,1>>), {ok,<<1,2,3>>} = skip_optional_tag(<<42>>, <<42,1,2,3>>), missing = skip_optional_tag(<<2:3>>, blurf), ok. skip_optional_tag(<<>>, Binary) -> {ok,Binary}; skip_optional_tag(<>, <>) -> skip_optional_tag(RestTag, Rest); skip_optional_tag(_, _) -> missing. decode_integer(_Config) -> {10795,<<43>>,whatever} = decode_integer(1, <<42,43>>, whatever), {-28909,<<19>>,whatever} = decode_integer(1, <<143,19>>, whatever), ok. decode_integer(Len, <>, RemovedBytes) when B1 == 0 -> Bin = <<_Skip:Len/unit:8, Buffer2/binary>> = <>, Size = byte_size(Bin), <> = Bin, {Int,Buffer2,RemovedBytes}; decode_integer(Len, <>, RemovedBytes) -> Bin = <<_Skip:Len/unit:8,Buffer2/binary>> = <>, Size = byte_size(Bin), <> = <>, Int = N - (1 bsl (8 * size(Bin) -1)), {Int,Buffer2,RemovedBytes}. -define(DATELEN, 16). wfbm(Config) when is_list(Config) -> %% check_for_dot_or_space and get_tail is from wfbm4 by Steve Vinoski, %% with modifications. {nomatch,0} = check_for_dot_or_space(<<" ">>), {nomatch,0} = check_for_dot_or_space(<<" abc">>), {ok,<<"abcde">>} = check_for_dot_or_space(<<"abcde 34555">>), {nomatch,0} = check_for_dot_or_space(<<".gurka">>), {nomatch,1} = check_for_dot_or_space(<<"g.urka">>), nomatch = get_tail(<<>>), {ok,<<"2007/10/23/blurf">>} = get_tail(<<"200x/2007/10/23/blurf ">>), {skip,?DATELEN+5} = get_tail(<<"200x/2007/10/23/blurf.">>), nomatch = get_tail(<<"200y.2007.10.23.blurf ">>), {'EXIT',_} = (catch get_tail({no,binary,at,all})), {'EXIT',_} = (catch get_tail(no_binary)), ok. check_for_dot_or_space(Bin) -> check_for_dot_or_space(Bin, 0). check_for_dot_or_space(<<$\s, _/binary>>, 0) -> {nomatch,0}; check_for_dot_or_space(Bin, Len) -> case Bin of <> -> {ok,Front}; <<_:Len/binary, $., _/binary>> -> {nomatch,Len}; _ -> check_for_dot_or_space(Bin, Len+1) end. get_tail(<<>>) -> nomatch; get_tail(Bin) -> <> = Bin, case Front of <<_:3/binary,"x/",Y:4/binary,$/,M:2/binary,$/,D:2/binary,$/>> -> case check_for_dot_or_space(Tail) of {ok,Match} -> {ok,<>}; {nomatch,Skip} -> {skip,?DATELEN + Skip} end; _ -> nomatch end. degenerated_match(Config) when is_list(Config) -> error = degenerated_match_1(<<>>), 1 = degenerated_match_1(<<1:1>>), 2 = degenerated_match_1(<<42,43>>), error = degenerated_match_2(<<>>), no_split = degenerated_match_2(<<1,2>>), {<<1,2,3,4>>,<<5>>} = degenerated_match_2(<<1,2,3,4,5>>), ok. degenerated_match_1(<<>>) -> error; degenerated_match_1(Bin) -> byte_size(Bin). degenerated_match_2(<<>>) -> error; degenerated_match_2(Bin) -> case byte_size(Bin) > 4 of true -> split_binary(Bin, 4); false -> no_split end. bs_sum(Config) when is_list(Config) -> 0 = bs_sum_1([]), 0 = bs_sum_1(<<>>), 42 = bs_sum_1([42]), 1 = bs_sum_1(<<1>>), 10 = bs_sum_1([1,2,3,4]), 15 = bs_sum_1(<<1,2,3,4,5>>), 21 = bs_sum_1([1,2,3|<<4,5,6>>]), 15 = bs_sum_1([1,2,3|{4,5}]), 6 = bs_sum_1([1,2,3|zero]), 6 = bs_sum_1([1,2,3|0]), 7 = bs_sum_1([1,2,3|one]), fc(catch bs_sum_1({too,big,tuple})), fc(catch bs_sum_1([1,2,3|{too,big,tuple}])), [] = sneaky_alias(<<>>), [559,387655] = sneaky_alias(id(<<559:32,387655:32>>)), fc(sneaky_alias, [<<1>>], catch sneaky_alias(id(<<1>>))), fc(sneaky_alias, [[1,2,3,4]], catch sneaky_alias(lists:seq(1, 4))), ok. bs_sum_1(<>) -> H+bs_sum_1(T); bs_sum_1([H|T]) -> H+bs_sum_1(T); bs_sum_1({A,B}=_Tuple=_AliasForNoGoodReason) -> A+B; bs_sum_1(0) -> 0; bs_sum_1(zero=_Zero) -> 0; bs_sum_1(one) -> 1; bs_sum_1([]) -> 0; bs_sum_1(<<>>) -> 0. sneaky_alias(<<>>=L) -> binary_to_list(L); sneaky_alias(<>) -> [From|sneaky_alias(L)]. coverage(Config) when is_list(Config) -> 0 = coverage_fold(fun(B, A) -> A+B end, 0, <<>>), 6 = coverage_fold(fun(B, A) -> A+B end, 0, <<1,2,3>>), fc(catch coverage_fold(fun(B, A) -> A+B end, 0, [a,b,c])), {<<42.0:64/float>>,float} = coverage_build(<<>>, <<42>>, float), {<<>>,not_a_tuple} = coverage_build(<<>>, <<>>, not_a_tuple), {<<16#76,"abc",16#A9,"abc">>,{x,42,43}} = coverage_build(<<>>, <<16#7,16#A>>, {x,y,z}), [<<2>>,<<1>>] = coverage_bc(<<1,2>>, []), {x,<<"abc">>,z} = coverage_setelement(<<2,"abc">>, {x,y,z}), [42] = coverage_apply(<<42>>, [coverage_id]), 42 = coverage_external(<<42>>), do_coverage_bin_to_term_list([]), do_coverage_bin_to_term_list([lists:seq(0, 10),{a,b,c},<<23:42>>]), fc(coverage_bin_to_term_list, [<<0,0,0,7>>], catch do_coverage_bin_to_term_list_1(<<7:32>>)), <<>> = coverage_per_key(<<4:32>>), <<$a,$b,$c>> = coverage_per_key(<<7:32,"abc">>), binary = coverage_bitstring(<<>>), binary = coverage_bitstring(<<7>>), bitstring = coverage_bitstring(<<7:4>>), other = coverage_bitstring([a]), ok. coverage_fold(Fun, Acc, <>) -> IdFun = fun id/1, coverage_fold(Fun, Fun(IdFun(H), IdFun(Acc)), T); coverage_fold(Fun, Acc, <<>>) when is_function(Fun, 2) -> Acc. coverage_build(Acc0, <>, float) -> Float = id(<>), Acc = <>, coverage_build(Acc, T, float); coverage_build(Acc0, <>, Tuple0) -> Str = id(<>), Acc = id(<>), Tuple = setelement(2, setelement(3, Tuple0, 43), 42), if byte_size(Acc) > 0 -> coverage_build(Acc, T, Tuple) end; coverage_build(Acc, <<>>, Tuple) -> {Acc,Tuple}. coverage_bc(<>, Acc) -> B = << <> || C <- [H] >>, coverage_bc(T, [B|Acc]); coverage_bc(<<>>, Acc) -> Acc. coverage_setelement(<>, Tuple) when element(1, Tuple) =:= x -> setelement(H, Tuple, T1). coverage_apply(<>, [F|Fs]) -> [?MODULE:F(H)|coverage_apply(T, Fs)]; coverage_apply(<<>>, []) -> []. coverage_external(<>) -> ?MODULE:coverage_external_ignore(T, T), H. coverage_external_ignore(_, _) -> ok. coverage_id(I) -> id(I). do_coverage_bin_to_term_list(L) -> Bin = << <<(begin BinTerm = term_to_binary(Term), <<(byte_size(BinTerm)):32,BinTerm/binary>> end)/binary>> || Term <- L >>, L = do_coverage_bin_to_term_list_1(Bin), L = do_coverage_bin_to_term_list_1(<>), L = do_coverage_bin_to_term_list_1(<<7:32,"garbage",Bin/binary>>). do_coverage_bin_to_term_list_1(Bin) -> Res = coverage_bin_to_term_list(Bin), Res = coverage_bin_to_term_list(Bin, []), Res = coverage_bin_to_term_list_catch(Bin), Res = coverage_bin_to_term_list_catch(Bin, []). coverage_bin_to_term_list(<>) -> try binary_to_term(BinTerm) of Term -> [Term|coverage_bin_to_term_list(T)] catch error:badarg -> coverage_bin_to_term_list(T) end; coverage_bin_to_term_list(<<>>) -> []. coverage_bin_to_term_list(<>, Acc) -> try binary_to_term(BinTerm) of Term -> coverage_bin_to_term_list(T, [Term|Acc]) catch error:badarg -> coverage_bin_to_term_list(T, Acc) end; coverage_bin_to_term_list(<<>>, Acc) -> lists:reverse(Acc). coverage_bin_to_term_list_catch(<>) -> case catch binary_to_term(BinTerm) of {'EXIT',_} -> coverage_bin_to_term_list_catch(T); Term -> [Term|coverage_bin_to_term_list_catch(T)] end; coverage_bin_to_term_list_catch(<<>>) -> []. coverage_bin_to_term_list_catch(<>, Acc) -> case catch binary_to_term(BinTerm) of {'EXIT',_} -> coverage_bin_to_term_list_catch(T, Acc); Term -> coverage_bin_to_term_list_catch(T, [Term|Acc]) end; coverage_bin_to_term_list_catch(<<>>, Acc) -> lists:reverse(Acc). coverage_per_key(<> = B) -> true = (byte_size(B) =:= BinSize), Bin. coverage_bitstring(Bin) when is_binary(Bin) -> binary; coverage_bitstring(<<_/bitstring>>) -> bitstring; coverage_bitstring(_) -> other. multiple_uses(Config) when is_list(Config) -> {344,62879,345,<<245,159,1,89>>} = multiple_uses_1(<<1,88,245,159,1,89>>), true = multiple_uses_2(<<0,0,197,18>>), <<42,43>> = multiple_uses_3(<<0,0,42,43>>, fun id/1), ok = first_after(<<>>, 42), <<1>> = first_after(<<1,2,3>>, 0), <<2>> = first_after(<<1,2,3>>, 1), ok. multiple_uses_1(<>) -> %% NOT OPTIMIZED: sub binary is matched or used in more than one place {Y,Z} = multiple_uses_match(Tail), {X,Y,Z,Tail}. multiple_uses_2(<<_:16,Tail/binary>>) -> %% NOT OPTIMIZED: sub binary is matched or used in more than one place multiple_uses_cmp(Tail, Tail). multiple_uses_3(<<_:16,Tail/binary>>, Fun) -> %% NOT OPTIMIZED: sub binary is used or returned Fun(Tail). multiple_uses_match(<>) -> {Y,Z}. multiple_uses_cmp(<>, <>) -> true; multiple_uses_cmp(<<_:16>>, <<_:16>>) -> false. first_after(Data, Offset) -> case byte_size(Data) > Offset of false -> {_First, _Rest} = {ok, ok}, ok; true -> <<_:Offset/binary, Rest/binary>> = Data, %% 'Rest' saved in y(0) before the call. {First, _} = match_first(Data, Rest), %% When beam_bsm sees the code, the following line %% which uses y(0) has been optimized away. {First, Rest} = {First, Rest}, First end. match_first(_, <>) -> {First, Rest}. zero_label(Config) when is_list(Config) -> <<"nosemouth">> = read_pols(<<"FACE","nose","mouth">>), <<"CE">> = read_pols(<<"noFACE">>), ok. read_pols(Data) -> <> = Data, %% Intentional warning. (PolygonType == <<"FACE">>) or (PolygonType == <<"PTCH">>), Rest. followed_by_catch(Config) when is_list(Config) -> ok = handle(<<0,1,2,3,4,5>>). -record(rec,{field}). handle(<<>>) -> ok; handle(Msg) -> <<_DataLen:16, Rest/binary>> = Msg, case catch fooX:func() of [X] -> X#rec.field; _ -> ok end, handle(Rest). matching_meets_construction(Config) when is_list(Config) -> Bin = id(<<"abc">>), Len = id(2), Tail0 = id(<<1,2,3,4,5>>), <<_:Len/binary,Tail/binary>> = Tail0, Res = <>, <<3,4,5,"abc">> = Res, {'EXIT',{badarg,_}} = (catch matching_meets_construction_1(<<"Abc">>)), {'EXIT',{badarg,_}} = (catch matching_meets_construction_2(<<"Abc">>)), <<"Bbc">> = matching_meets_construction_3(<<"Abc">>), <<1,2>> = encode_octet_string(<<1,2,3>>, 2), ok. matching_meets_construction_1(<<"A",H/binary>>) -> <<"B",H>>. matching_meets_construction_2(<<"A",H/binary>>) -> <<"B",H/float>>. matching_meets_construction_3(<<"A",H/binary>>) -> <<"B",H/binary>>. encode_octet_string(<>, Len) -> <>. simon(Config) when is_list(Config) -> one = simon(blurf, <<>>), two = simon(0, <<42>>), fc(simon, [17,<<1>>], catch simon(17, <<1>>)), fc(simon, [0,<<1,2,3>>], catch simon(0, <<1,2,3>>)), one = simon2(blurf, <<9>>), two = simon2(0, <<9,1>>), fc(simon2, [0,<<9,10,11>>], catch simon2(0, <<9,10,11>>)), ok. simon(_, <<>>) -> one; simon(0, <<_>>) -> two. simon2(_, <<9>>) -> one; simon2(0, <<_:16>>) -> two. %% OTP-7113: Crash in v3_codegen. matching_and_andalso(Config) when is_list(Config) -> ok = matching_and_andalso_1(<<1,2,3>>, 3), {'EXIT',{function_clause,_}} = (catch matching_and_andalso_1(<<1,2,3>>, -8)), {'EXIT',{function_clause,_}} = (catch matching_and_andalso_1(<<1,2,3>>, blurf)), {'EXIT',{function_clause,_}} = (catch matching_and_andalso_1(<<1,2,3>>, 19)), {"abc",<<"xyz">>} = matching_and_andalso_23("abc", <<"-xyz">>), {"abc",<<"">>} = matching_and_andalso_23("abc", <<($a-1)>>), {"abc",<<"">>} = matching_and_andalso_23("abc", <<($z+1)>>), {"abc",<<"">>} = matching_and_andalso_23("abc", <<($A-1)>>), {"abc",<<"">>} = matching_and_andalso_23("abc", <<($Z+1)>>), error = matching_and_andalso_23([], <<>>), error = matching_and_andalso_23([], <<$A>>), error = matching_and_andalso_23([], <<$Z>>), error = matching_and_andalso_23([], <<$a>>), error = matching_and_andalso_23([], <<$z>>), ok. matching_and_andalso_1(<>, K) when is_integer(K) andalso size(Bitmap) >= K andalso 0 < K -> ok. matching_and_andalso_23(Datetime, Bin) -> Res = matching_and_andalso_2(Datetime, Bin), Res = matching_and_andalso_3(Datetime, Bin), Res. matching_and_andalso_2(Datetime, <>) when not ((H >= $a) andalso (H =< $z)) andalso not ((H >= $A) andalso (H =< $Z)) -> {Datetime,T}; matching_and_andalso_2(_, _) -> error. %% Contrived example to ensure we cover the handling of 'call' instructions %% in v3_codegen:bsm_rename_ctx/4. matching_and_andalso_3(Datetime, <>) when not ((abs(H) >= $a) andalso (abs(H) =< $z)) andalso not ((abs(H) >= $A) andalso (abs(H) =< $Z)) -> {Datetime,T}; matching_and_andalso_3(_, _) -> error. %% Thanks to Tomas Stejskal. otp_7188(Config) when is_list(Config) -> MP3 = <<84,65,71,68,117,154,105,232,107,121,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,68,97,110,105,101,108,32,76, 97,110,100,97,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66, 101,115,116,32,79,102,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,50,48,48,48,50,48,48,48,32,45,32,66,101,115, 116,32,79,102,32,32,32,32,32,32,32,32,32,32,32,32,32,32, 32,32,12>>, {ok,{"ID3v1", [{title,<<68,117,154,105,232,107,121>>}, {artist,<<"Daniel Landa">>}, {album,<<"Best Of">>}]}} = parse_v1_or_v11_tag(MP3). parse_v1_or_v11_tag(<<"TAG", Title:30/binary, Artist:30/binary, Album:30/binary, _Year:4/binary, _Comment:28/binary, 0:8, Track:8, _Genre:8>>) -> {ok, {"ID3v1.1", [{track, Track}, {title, trim(Title)}, {artist, trim(Artist)}, {album, trim(Album)}]}}; parse_v1_or_v11_tag(<<"TAG", Title:30/binary, Artist:30/binary, Album:30/binary, _Year:4/binary, _Comment:30/binary, _Genre:8>>) -> {ok, {"ID3v1", [{title, trim(Title)}, {artist, trim(Artist)}, {album, trim(Album)}]}}; parse_v1_or_v11_tag(_) -> error. trim(Bin) -> list_to_binary(trim_blanks(binary_to_list(Bin))). trim_blanks(L) -> lists:reverse(skip_blanks_and_zero(lists:reverse(L))). skip_blanks_and_zero([$\s|T]) -> skip_blanks_and_zero(T); skip_blanks_and_zero([0|T]) -> skip_blanks_and_zero(T); skip_blanks_and_zero(L) -> L. %% OTP-7233. Record and binary matching optimizations clashed. %% Thanks to Vladimir Klebansky. -record(rec_otp_7233, {key, val}). otp_7233(Config) when is_list(Config) -> otp_7233_1(#rec_otp_7233{key = <<"XXabcde">>,val=[{"xxxxxxxx",42}]}), [<<"XXabcde">>,{"xxxxxxxx",42}] = get(io_format), erase(io_format), otp_7233_1(#rec_otp_7233{key = <<"XXabcde">>,val=[]}), undefined = get(io_format), ok. otp_7233_1(Rec) -> <> = Rec#rec_otp_7233.key, case K of <<"XX">> -> Value = Rec#rec_otp_7233.val, case lists:keyfind("xxxxxxxx", 1, Value) of false -> ok; T -> put(io_format, [Rec#rec_otp_7233.key,T]) end; _ -> ok end. otp_7240(Config) when is_list(Config) -> a = otp_7240_a(0, <<>>), b = otp_7240_a(1, 2), a = otp_7240_b(anything, <<>>), b = otp_7240_b(1, {x,y}), a = otp_7240_c(anything, <<>>), b = otp_7240_c(1, <<2>>), a = otp_7240_d(anything, <<>>), b = otp_7240_d(again, <<2>>), a = otp_7240_e(anything, <<>>), b = otp_7240_e(1, 41), a = otp_7240_f(anything, <<>>), b = otp_7240_f(1, {}), ok. otp_7240_a(_, <<>>) -> a; otp_7240_a(1, 2) -> b. otp_7240_b(_, <<>>) -> a; otp_7240_b(1, {_,_}) -> b. otp_7240_c(_, <<>>) -> a; otp_7240_c(1, <<2>>) -> b. otp_7240_d(_, <<>>) -> a; otp_7240_d(_, <<2>>) -> b. otp_7240_e(_, <<>>) -> a; otp_7240_e(1, B) when B < 42 -> b. otp_7240_f(_, <<>>) -> a; otp_7240_f(1, B) when is_tuple(B) -> b. otp_7498(Config) when is_list(Config) -> <<1,2,3>> = otp_7498_foo(<<1,2,3>>, 0), <<2,3>> = otp_7498_foo(<<1,2,3>>, 1), <<1,2,3>> = otp_7498_foo(<<1,2,3>>, 2), <<1,2,3>> = otp_7498_bar(<<1,2,3>>, 0), <<2,3>> = otp_7498_bar(<<1,2,3>>, 1), <<1,2,3>> = otp_7498_bar(<<1,2,3>>, 2), <<>> = otp_7498_bar(<<>>, 2), <<1,2,3>> = otp_7498_bar(<<1,2,3>>, 3), ok. otp_7498_foo(Bin, 0) -> otp_7498_foo(Bin, 42); otp_7498_foo(<<_A, Rest/bitstring>>, 1) -> otp_7498_foo(Rest, 43); otp_7498_foo(Bin, _I) -> Bin. otp_7498_bar(Bin, 0) -> otp_7498_bar(Bin, 42); otp_7498_bar(<<_A, Rest/bitstring>>, 1) -> otp_7498_bar(Rest, 43); otp_7498_bar(<<>>, 2) -> otp_7498_bar(<<>>, 44); otp_7498_bar(Bin, _I) -> Bin. match_string(Config) when is_list(Config) -> %% To make sure that native endian really is handled correctly %% (i.e. that the compiler does not attempt to use bs_match_string/4 %% instructions for native segments), running this test is not enough. %% Either examine the generated for do_match_string_native/1 or %% check the coverage for the v3_kernel module. case erlang:system_info(endian) of little -> do_match_string_native(<<$a,0,$b,0>>); big -> do_match_string_native(<<0,$a,0,$b>>) end, do_match_string_big(<<0,$a,0,$b>>), do_match_string_little(<<$a,0,$b,0>>), do_match_string_big_signed(<<255,255>>), do_match_string_little_signed(<<255,255>>), plain = no_match_string_opt(<<"abc">>), strange = no_match_string_opt(<<$a:9,$b:9,$c:9>>), ok. do_match_string_native(<<$a:16/native,$b:16/native>>) -> ok. do_match_string_big(<<$a:16/big,$b:16/big>>) -> ok. do_match_string_little(<<$a:16/little,$b:16/little>>) -> ok. do_match_string_big_signed(<<(-1):16/signed>>) -> ok. do_match_string_little_signed(<<(-1):16/little-signed>>) -> ok. no_match_string_opt(<<"abc">>) -> plain; no_match_string_opt(<<$a:9,$b:9,$c:9>>) -> strange. %% OTP-7591: A zero-width segment in matching would crash the compiler. zero_width(Config) when is_list(Config) -> <> = <<2, 0, $h, $i, 0:0>>, 2 = Len, Str = <<"hi">>, %% Match sure that values that cannot fit in a segment will not match. case id(<<0:8>>) of <<256:8>> -> ct:fail(should_not_match); _ -> ok end, ok. %% OTP_7650: A invalid size for binary segments could crash the compiler. bad_size(Config) when is_list(Config) -> Tuple = {a,b,c}, {'EXIT',{{badmatch,<<>>},_}} = (catch <<32:Tuple>> = id(<<>>)), Binary = <<1,2,3>>, {'EXIT',{{badmatch,<<>>},_}} = (catch <<32:Binary>> = id(<<>>)), ok. haystack(Config) when is_list(Config) -> <<0:10/unit:8>> = haystack_1(<<0:10/unit:8>>), [<<0:10/unit:8>>, <<0:20/unit:8>>] = haystack_2(<<1:8192>>), ok. %% Used to crash the compiler. haystack_1(Haystack) -> Subs = [10], [begin <> = Haystack, B end || Y <- Subs], Haystack. %% There would be an incorrect badmatch exception. haystack_2(Haystack) -> Subs = [{687,10},{369,20}], [begin <<_:X/binary,B:Y/binary,_/binary>> = Haystack, B end || {X,Y} <- Subs ]. fc({'EXIT',{function_clause,_}}) -> ok; fc({'EXIT',{{case_clause,_},_}}) when ?MODULE =:= bs_match_inline_SUITE -> ok. fc(Name, Args, {'EXIT',{function_clause,[{?MODULE,Name,Args,_}|_]}}) -> ok; fc(Name, Args, {'EXIT',{function_clause,[{?MODULE,Name,Arity,_}|_]}}) when length(Args) =:= Arity -> true = test_server:is_native(?MODULE); fc(_, Args, {'EXIT',{{case_clause,ActualArgs},_}}) when ?MODULE =:= bs_match_inline_SUITE -> Args = tuple_to_list(ActualArgs). %% Cover the clause handling bs_context to binary in %% beam_block:initialized_regs/2. cover_beam_bool(Config) when is_list(Config) -> ok = do_cover_beam_bool(<<>>, 3), <<19>> = do_cover_beam_bool(<<19>>, 2), <<42>> = do_cover_beam_bool(<<42>>, 1), <<17>> = do_cover_beam_bool(<<13,17>>, 0), ok. do_cover_beam_bool(Bin, X) when X > 0 -> if X =:= 1; X =:= 2 -> Bin; true -> ok end; do_cover_beam_bool(<<_,Bin/binary>>, X) -> do_cover_beam_bool(Bin, X+1). matched_out_size(Config) when is_list(Config) -> {253,16#DEADBEEF} = mos_int(<<8,253,16#DEADBEEF:32>>), {6,16#BEEFDEAD} = mos_int(<<3,6:3,16#BEEFDEAD:32>>), {53,16#CAFEDEADBEEFCAFE} = mos_int(<<16,53:16,16#CAFEDEADBEEFCAFE:64>>), {23,16#CAFEDEADBEEFCAFE} = mos_int(<<5,23:5,16#CAFEDEADBEEFCAFE:64>>), {<<1,2,3>>,4} = mos_bin(<<3,1,2,3,4,3>>), {<<1,2,3,7>>,19,42} = mos_bin(<<4,1,2,3,7,19,4,42>>), <<1,2,3,7>> = mos_bin(<<4,1,2,3,7,"abcdefghij">>), ok. mos_int(<>) -> {I,X}; mos_int(<>) -> {I,X}. mos_bin(<>) -> L = byte_size(Bin), {Bin,X}; mos_bin(<>) -> L = byte_size(Bin), {Bin,X,Y}; mos_bin(<>) -> L = byte_size(Bin), Bin. follow_fail_branch(_) -> 42 = ffb_1(<<0,1>>, <<0>>), 8 = ffb_1(<<0,1>>, [a]), 42 = ffb_2(<<0,1>>, <<0>>, 17), 8 = ffb_2(<<0,1>>, [a], 0), ok. ffb_1(<<_,T/bitstring>>, List) -> case List of <<_>> -> 42; [_|_] -> %% The fail branch of the bs_start_match2 instruction %% pointing to here would be ignored, making the compiler %% incorrectly assume that the delayed sub-binary %% optimization was safe. bit_size(T) end. ffb_2(<<_,T/bitstring>>, List, A) -> case List of <<_>> when A =:= 17 -> 42; [_|_] -> bit_size(T) end. no_partition(_) -> one = no_partition_1(<<"string">>, a1), {two,<<"string">>} = no_partition_1(<<"string">>, a2), {two,<<>>} = no_partition_1(<<>>, a2), {two,a} = no_partition_1(a, a2), three = no_partition_1(undefined, a3), {four,a,[]} = no_partition_1([a], a4), {five,a,b} = no_partition_1({a,b}, a5), one = no_partition_2(<<"string">>, a1), two = no_partition_2(<<"string">>, a2), two = no_partition_2(<<>>, a2), two = no_partition_2(a, a2), three = no_partition_2(undefined, a3), four = no_partition_2(42, a4), five = no_partition_2([], a5), six = no_partition_2(42.0, a6), ok. no_partition_1(<<"string">>, a1) -> one; no_partition_1(V, a2) -> {two,V}; no_partition_1(undefined, a3) -> three; no_partition_1([H|T], a4) -> {four,H,T}; no_partition_1({A,B}, a5) -> {five,A,B}. no_partition_2(<<"string">>, a1) -> one; no_partition_2(_, a2) -> two; no_partition_2(undefined, a3) -> three; no_partition_2(42, a4) -> four; no_partition_2([], a5) -> five; no_partition_2(42.0, a6) -> six. calling_a_binary(Config) when is_list(Config) -> [] = call_binary(<<>>, []), {'EXIT',{badarg,_}} = (catch call_binary(<<1>>, [])), {'EXIT',{badarg,_}} = (catch call_binary(<<1,2,3>>, [])), ok. call_binary(<<>>, Acc) -> Acc; call_binary(<>, Acc) -> T(<>). binary_in_map(Config) when is_list(Config) -> ok = match_binary_in_map(#{key => <<42:8>>}), {'EXIT',{{badmatch,#{key := 1}},_}} = (catch match_binary_in_map(#{key => 1})), {'EXIT',{{badmatch,#{key := <<1023:16>>}},_}} = (catch match_binary_in_map(#{key => <<1023:16>>})), {'EXIT',{{badmatch,#{key := <<1:8>>}},_}} = (catch match_binary_in_map(#{key => <<1:8>>})), {'EXIT',{{badmatch,not_a_map},_}} = (catch match_binary_in_map(not_a_map)), ok. match_binary_in_map(Map) -> case 8 of N -> #{key := <<42:N>>} = Map, ok end. match_string_opt(Config) when is_list(Config) -> {x,<<1,2,3>>,{<<1>>,{v,<<1,2,3>>}}} = do_match_string_opt({<<1>>,{v,<<1,2,3>>}}), ok. do_match_string_opt({<<1>>,{v,V}}=T) -> {x,V,T}. select_on_integer(Config) when is_list(Config) -> 42 = do_select_on_integer(<<42>>), <<"abc">> = do_select_on_integer(<<128,"abc">>), {'EXIT',_} = (catch do_select_on_integer(<<0:1>>)), {'EXIT',_} = (catch do_select_on_integer(<<1:1>>)), {'EXIT',_} = (catch do_select_on_integer(<<0:1,0:15>>)), ok. %% The ASN.1 compiler frequently generates code like this. do_select_on_integer(<<0:1,I:7>>) -> I; do_select_on_integer(<<1:1,_:7,Bin/binary>>) -> Bin. %% If 'bin_opt_info' was given the warning would lack filename %% and line number. map_and_binary(_Config) -> {<<"10">>,<<"37">>,<<"am">>} = do_map_and_binary(<<"10:37am">>), Map1 = #{time => "noon"}, {ok,Map1} = do_map_and_binary(Map1), Map2 = #{hour => 8, min => 42}, {8,42,Map2} = do_map_and_binary(Map2), ok. do_map_and_binary(<>) -> {Hour, Min, Rest}; do_map_and_binary(#{time := _} = T) -> {ok, T}; do_map_and_binary(#{hour := Hour, min := Min} = T) -> {Hour, Min, T}. %% Unsafe caching of branch outcomes in beam_bsm would cause the %% delayed creation of sub-binaries optimization to be applied even %% when it was unsafe. unsafe_branch_caching(_Config) -> <<>> = do_unsafe_branch_caching(<<42,1>>), <<>> = do_unsafe_branch_caching(<<42,2>>), <<>> = do_unsafe_branch_caching(<<42,3>>), <<17,18>> = do_unsafe_branch_caching(<<42,3,17,18>>), <<>> = do_unsafe_branch_caching(<<1,3,42,2>>), ok. do_unsafe_branch_caching(<>) -> <> = Bin, case C1 of X when X =:= 1 orelse X =:= 2 -> Bin2 = <<>>; _ -> Bin2 = B1 end, case Code of 1 -> do_unsafe_branch_caching(Bin2); _ -> Bin2 end. bad_literals(_Config) -> % Mod = list_to_atom(?MODULE_STRING ++ "_" ++ % atom_to_list(?FUNCTION_NAME)), % S = [signed_lit_match(V, Sz) || V <- lists:seq(-8, 8), % Sz <- [0,1,2,3]] ++ % [unsigned_lit_match(V, Sz) || V <- lists:seq(-2, 8), % Sz <- [0,1,2]] ++ % [unicode_match(V) || % V <- [-100,-1,0,1,2|lists:seq(16#10FFFC, 16#110004)]], % Code = ?Q(["-module('@Mod@').\n" % "-export([f/0]).\n" % "f() ->\n" % "_@S,\n" % "ok.\n"]), % merl:print(Code), % Opts = test_lib:opt_opts(?MODULE), % {ok,_} = merl:compile_and_load(Code, Opts), % Mod:f(), {'EXIT',<<42>>} = (catch bad_literals_1()), Sz = id(8), {'EXIT',{{badmatch,_},_}} = (catch <<-1:Sz>> = <<-1>>), ok. bad_literals_1() -> BadSz = bad, case case <<42>> of <<42:BadSz>> -> ok; Val -> exit(Val) end of ok -> ok; error -> error end. %signed_lit_match(V, Sz) -> % case <> of % <> -> % ?Q("<<_@V@:_@Sz@/signed>> = <<_@V@:_@Sz@>>"); % _ -> % ?Q(["case <<_@V@:_@Sz@>> of\n", % " <<_@V@:_@Sz@/signed>> ->\n", % " ct:fail(should_not_match);\n", % " _ ->\n", % " ok\n", % "end\n"]) % end. %unsigned_lit_match(V, Sz) -> % case <> of % <> -> % ?Q("<<_@V@:_@Sz@>> = <<_@V@:_@Sz@>>"); % _ -> % ?Q(["case <<_@V@:_@Sz@>> of\n", % " <<_@V@:_@Sz@/unsigned>> ->\n", % " ct:fail(should_not_match);\n", % " _ ->\n", % " ok\n", % "end\n"]) % end. %unicode_match(V) -> % try <> of % <> -> % ?Q(["<<_@V@/utf8>> = <<_@V@/utf8>>,\n", % "<<_@V@/utf16>> = <<_@V@/utf16>>,\n", % "<<_@V@/utf32>> = <<_@V@/utf32>>\n"]) % catch % error:badarg -> % ?Q(["case <<_@V@:32>> of\n", % " <<_@V@/utf32>> ->\n", % " ct:fail(should_not_match);\n", % " _ ->\n", % " ok\n", % "end\n"]) % end. %% Test a few legal but rare cases. good_literals(_Config) -> Sz = id(64), %% Variable size. <<42:Sz>> = id(<<42:Sz>>), <<42.0:Sz/float>> = id(<<42:Sz/float>>), %% unit > 1 <<16#cafebeef:4/unit:8>> = id(<<16#cafebeef:32>>), ok. constant_propagation(_Config) -> <<5>> = constant_propagation_a(a, <<5>>), {'EXIT',{{case_clause,b},_}} = (catch constant_propagation_a(b, <<5>>)), 258 = constant_propagation_b(<<1,2>>), F = constant_propagation_c(), 259 = F(<<1,3>>), ok. constant_propagation_a(X, Y) -> case X of a -> Y2 = 8 end, <<5:Y2>> = Y. constant_propagation_b(B) -> Sz = 16, <> = B, X. constant_propagation_c() -> Size = 16, fun(Bin) -> <> = Bin, X end. parse_xml(_Config) -> <<"> = do_parse_xml(<<">), <<" ">> = do_parse_xml(<<">), ok. do_parse_xml(<<"> = Bytes) -> %% Delayed sub-binary creation is not safe. A buggy (development) %% version of check_liveness_everywhere() in beam_utils would turn %% on the optimization. Rest1 = case is_next_char_whitespace(Rest) of false -> Bytes; true -> id(Rest) end, id(Rest1). is_next_char_whitespace(<>) -> C =:= $\s. -record(ext_header, {this_hdr = 17, ext_hdr_opts}). get_payload(_Config) -> <<3445:48>> = do_get_payload(#ext_header{ext_hdr_opts = <<3445:48>>}), {'EXIT',_} = (catch do_get_payload(#ext_header{})), ok. do_get_payload(ExtHdr) -> _ = ExtHdr#ext_header.this_hdr, ExtHdrOptions = ExtHdr#ext_header.ext_hdr_opts, <<_:13,_:35>> = ExtHdr#ext_header.ext_hdr_opts, ExtHdrOptions. escape(_Config) -> 0 = escape(<<>>, 0), 1 = escape(<<128>>, 0), 2 = escape(<<128,255>>, 0), 42 = escape(<<42>>, 0), 50 = escape(<<42,8>>, 0), ok. escape(<>, Pos) when Byte >= 127 -> escape(Rest, Pos + 1); escape(<>, Pos) -> escape(Rest, Pos + Byte); escape(<<_Rest/bits>>, Pos) -> Pos. %% ERL-490 num_slots_different(_Config) -> Ts = [{<<"de">>, <<"default">>, <<"Remove">>, <<"a">>}, {<<"de">>, <<"default">>, <<"Remove from list">>, <<"a">>}, {<<"de">>, <<"default">>, <<"Remove from the list">>, <<"a">>}, {<<"de">>, <<"default">>, <<"Results">>, <<"Ergebnisse">>}, {<<"de">>, <<"default">>, <<"Reservatio">>, <<"a">>}, {<<"de">>, <<"navigation">>, <<"Results">>, <<"Ergebnisse">>}, {<<"de">>, <<"navigation">>, <<"Resources">>, <<"Ressourcen">>}], _ = [{ok,Res} = lgettext(A, B, C) || {A,B,C,Res} <- Ts], {'EXIT',_} = (catch lgettext(<<"d">>, <<"default">>, <<"Remove">>)), {'EXIT',_} = (catch lgettext("", <<"default">>, <<"Remove">>)), {'EXIT',_} = (catch lgettext(<<"de">>, <<"def">>, <<"Remove">>)), {'EXIT',_} = (catch lgettext(<<"de">>, <<"default">>, <<"Res">>)), ok. lgettext(<<"de">>, <<"default">>, <<"Remove">>) -> {ok, <<"a">>}; lgettext(<<"de">>, <<"default">>, <<"Remove from list">>) -> {ok, <<"a">>}; lgettext(<<"de">>, <<"default">>, <<"Remove from the list">>) -> {ok, <<"a">>}; lgettext(<<"de">>, <<"default">>, <<"Results">>) -> {ok, <<"Ergebnisse">>}; lgettext(<<"de">>, <<"default">>, <<"Reservatio">>) -> {ok, <<"a">>}; lgettext(<<"de">>, <<"navigation">>, <<"Results">>) -> {ok, <<"Ergebnisse">>}; lgettext(<<"de">>, <<"navigation">>, <<"Resources">>) -> {ok, <<"Ressourcen">>}. %% Test more code in beam_bsm. beam_bsm(_Config) -> true = check_bitstring_list(<<1:1,0:1,1:1,1:1>>, [1,0,1,1]), false = check_bitstring_list(<<1:1,0:1,1:1,1:1>>, [0]), true = bsm_validate_scheme(<<>>), true = bsm_validate_scheme(<<5,10>>), false = bsm_validate_scheme(<<5,10,11,12>>), true = bsm_validate_scheme([]), true = bsm_validate_scheme([5,10]), false = bsm_validate_scheme([5,6,7]), <<1,2,3>> = bsm_must_save_and_not_save(<<1,2,3>>, []), D = fun(N) -> 2*N end, [2,4|<<3>>] = bsm_must_save_and_not_save(<<1,2,3>>, [D,D]), ok. check_bitstring_list(<>, [H|T2]) -> check_bitstring_list(T1, T2); check_bitstring_list(<<>>, []) -> true; check_bitstring_list(_, _) -> false. bsm_validate_scheme([]) -> true; bsm_validate_scheme([H|T]) -> case bsm_is_scheme(H) of true -> bsm_validate_scheme(T); false -> false end; bsm_validate_scheme(<<>>) -> true; bsm_validate_scheme(<>) -> case bsm_is_scheme(H) of true -> bsm_validate_scheme(Rest); false -> false end. bsm_is_scheme(Int) -> Int rem 5 =:= 0. %% NOT OPTIMIZED: different control paths use different positions in the binary bsm_must_save_and_not_save(Bin, []) -> Bin; bsm_must_save_and_not_save(<>, [F|Fs]) -> [F(H)|bsm_must_save_and_not_save(T, Fs)]; bsm_must_save_and_not_save(<<>>, []) -> []. guard(_Config) -> _Tuple = id({a,b}), ok = guard_1(<<1,2,3>>, {1,2,3}), ok = guard_2(<<42>>, #{}), ok. %% Cover handling of #k_put{} in v3_codegen:bsm_rename_ctx/4. guard_1(<>, Tuple) when Tuple =:= {A,B,C} -> ok. %% Cover handling of #k_call{} in v3_codegen:bsm_rename_ctx/4. guard_2(<<_>>, Healing) when Healing#{[] => Healing} =:= #{[] => #{}} -> ok. is_ascii(_Config) -> true = do_is_ascii(<<>>), true = do_is_ascii(<<"string">>), false = do_is_ascii(<<1024/utf8>>), {'EXIT',{function_clause,_}} = (catch do_is_ascii(<<$A,0:3>>)), {'EXIT',{function_clause,_}} = (catch do_is_ascii(<<16#80,0:3>>)), ok. do_is_ascii(<<>>) -> true; do_is_ascii(<>) when C >= 16#80 -> %% This clause must fail to match if the size of the argument in %% bits is not divisible by 8. Beware of unsafe optimizations. false; do_is_ascii(<<_, T/binary>>) -> do_is_ascii(T). non_opt_eq(_Config) -> true = non_opt_eq([], <<>>), true = non_opt_eq([$a], <<$a>>), false = non_opt_eq([$a], <<$b>>), ok. %% An example from the Efficiency Guide. It used to be not optimized, %% but now it can be optimized. non_opt_eq([H|T1], <>) -> non_opt_eq(T1, T2); non_opt_eq([_|_], <<_,_/binary>>) -> false; non_opt_eq([], <<>>) -> true. %% ERL-689 erl_689(_Config) -> {{0, 0, 0}, <<>>} = do_erl_689_1(<<0>>, ?MODULE), {{2018, 8, 7}, <<>>} = do_erl_689_1(<<4,2018:16/little,8,7>>, ?MODULE), {{0, 0, 0}, <<>>} = do_erl_689_2(?MODULE, <<0>>), {{2018, 8, 7}, <<>>} = do_erl_689_2(?MODULE, <<4,2018:16/little,8,7>>), ok. do_erl_689_1(Arg1, Arg2) -> Res = do_erl_689_1a(Arg1, Arg2), Res = do_erl_689_1b(Arg1, Arg2). do_erl_689_2(Arg1, Arg2) -> Res = do_erl_689_2a(Arg1, Arg2), Res = do_erl_689_2b(Arg1, Arg2). do_erl_689_1a(<>, _) -> case {Data, Length} of {_, 0} -> %% bs_context_to_binary would incorrectly set Data to the original %% binary (before matching in the function head). {{0, 0, 0}, Data}; {<>, 4} -> {{Y, M, D}, Rest} end. do_erl_689_1b(<>, _) -> case {Data, Length} of {_, 0} -> %% bs_context_to_binary would incorrectly set Data to the original %% binary (before matching in the function head). id(0), {{0, 0, 0}, Data}; {<>, 4} -> id(1), {{Y, M, D}, Rest} end. do_erl_689_2a(_, <>) -> case {Length, Data} of {0, _} -> %% bs_context_to_binary would incorrectly set Data to the original %% binary (before matching in the function head). {{0, 0, 0}, Data}; {4, <>} -> {{Y, M, D}, Rest} end. do_erl_689_2b(_, <>) -> case {Length, Data} of {0, _} -> %% bs_context_to_binary would incorrectly set Data to the original %% binary (before matching in the function head). id(0), {{0, 0, 0}, Data}; {4, <>} -> id(1), {{Y, M, D}, Rest} end. %% ERL-753 bs_start_match2_defs(_Config) -> {<<"http://127.0.0.1:1234/vsaas/hello">>} = api_url(<<"hello">>, dummy), {"https://127.0.0.1:4321/vsaas/hello"} = api_url({https, "hello"}, dummy). api_url(URL, Auth) -> Header = [], case URL of <<_/binary>> -> {<<"http://127.0.0.1:1234/vsaas/",URL/binary>>}; {https, [_|_] = URL1} -> {"https://127.0.0.1:4321/vsaas/"++URL1} end. check(F, R) -> R = F(). id(I) -> I. ================================================ FILE: otp_build/bs_match_SUITE.erl.patch ================================================ 49c49 < -include_lib("syntax_tools/include/merl.hrl"). --- > %-include_lib("syntax_tools/include/merl.hrl"). 74c74,75 < bad_literals,good_literals,constant_propagation,parse_xml, --- > % bad_literals,good_literals,constant_propagation,parse_xml, > good_literals,constant_propagation,parse_xml, 1399,1415c1400,1416 < Mod = list_to_atom(?MODULE_STRING ++ "_" ++ < atom_to_list(?FUNCTION_NAME)), < S = [signed_lit_match(V, Sz) || V <- lists:seq(-8, 8), < Sz <- [0,1,2,3]] ++ < [unsigned_lit_match(V, Sz) || V <- lists:seq(-2, 8), < Sz <- [0,1,2]] ++ < [unicode_match(V) || < V <- [-100,-1,0,1,2|lists:seq(16#10FFFC, 16#110004)]], < Code = ?Q(["-module('@Mod@').\n" < "-export([f/0]).\n" < "f() ->\n" < "_@S,\n" < "ok.\n"]), < merl:print(Code), < Opts = test_lib:opt_opts(?MODULE), < {ok,_} = merl:compile_and_load(Code, Opts), < Mod:f(), --- > % Mod = list_to_atom(?MODULE_STRING ++ "_" ++ > % atom_to_list(?FUNCTION_NAME)), > % S = [signed_lit_match(V, Sz) || V <- lists:seq(-8, 8), > % Sz <- [0,1,2,3]] ++ > % [unsigned_lit_match(V, Sz) || V <- lists:seq(-2, 8), > % Sz <- [0,1,2]] ++ > % [unicode_match(V) || > % V <- [-100,-1,0,1,2|lists:seq(16#10FFFC, 16#110004)]], > % Code = ?Q(["-module('@Mod@').\n" > % "-export([f/0]).\n" > % "f() ->\n" > % "_@S,\n" > % "ok.\n"]), > % merl:print(Code), > % Opts = test_lib:opt_opts(?MODULE), > % {ok,_} = merl:compile_and_load(Code, Opts), > % Mod:f(), 1433,1473c1434,1474 < signed_lit_match(V, Sz) -> < case <> of < <> -> < ?Q("<<_@V@:_@Sz@/signed>> = <<_@V@:_@Sz@>>"); < _ -> < ?Q(["case <<_@V@:_@Sz@>> of\n", < " <<_@V@:_@Sz@/signed>> ->\n", < " ct:fail(should_not_match);\n", < " _ ->\n", < " ok\n", < "end\n"]) < end. < < unsigned_lit_match(V, Sz) -> < case <> of < <> -> < ?Q("<<_@V@:_@Sz@>> = <<_@V@:_@Sz@>>"); < _ -> < ?Q(["case <<_@V@:_@Sz@>> of\n", < " <<_@V@:_@Sz@/unsigned>> ->\n", < " ct:fail(should_not_match);\n", < " _ ->\n", < " ok\n", < "end\n"]) < end. < < unicode_match(V) -> < try <> of < <> -> < ?Q(["<<_@V@/utf8>> = <<_@V@/utf8>>,\n", < "<<_@V@/utf16>> = <<_@V@/utf16>>,\n", < "<<_@V@/utf32>> = <<_@V@/utf32>>\n"]) < catch < error:badarg -> < ?Q(["case <<_@V@:32>> of\n", < " <<_@V@/utf32>> ->\n", < " ct:fail(should_not_match);\n", < " _ ->\n", < " ok\n", < "end\n"]) < end. --- > %signed_lit_match(V, Sz) -> > % case <> of > % <> -> > % ?Q("<<_@V@:_@Sz@/signed>> = <<_@V@:_@Sz@>>"); > % _ -> > % ?Q(["case <<_@V@:_@Sz@>> of\n", > % " <<_@V@:_@Sz@/signed>> ->\n", > % " ct:fail(should_not_match);\n", > % " _ ->\n", > % " ok\n", > % "end\n"]) > % end. > > %unsigned_lit_match(V, Sz) -> > % case <> of > % <> -> > % ?Q("<<_@V@:_@Sz@>> = <<_@V@:_@Sz@>>"); > % _ -> > % ?Q(["case <<_@V@:_@Sz@>> of\n", > % " <<_@V@:_@Sz@/unsigned>> ->\n", > % " ct:fail(should_not_match);\n", > % " _ ->\n", > % " ok\n", > % "end\n"]) > % end. > > %unicode_match(V) -> > % try <> of > % <> -> > % ?Q(["<<_@V@/utf8>> = <<_@V@/utf8>>,\n", > % "<<_@V@/utf16>> = <<_@V@/utf16>>,\n", > % "<<_@V@/utf32>> = <<_@V@/utf32>>\n"]) > % catch > % error:badarg -> > % ?Q(["case <<_@V@:32>> of\n", > % " <<_@V@/utf32>> ->\n", > % " ct:fail(should_not_match);\n", > % " _ ->\n", > % " ok\n", > % "end\n"]) > % end. ================================================ FILE: otp_build/bs_match_SUITE_patched.erl ================================================ %% %% %CopyrightBegin% %% %% Copyright Ericsson AB 2005-2018. All Rights Reserved. %% %% 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. %% %% %CopyrightEnd% %% -module(bs_match_SUITE). -compile(nowarn_shadow_vars). -export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1, init_per_group/2,end_per_group/2, init_per_testcase/2,end_per_testcase/2, size_shadow/1,int_float/1,otp_5269/1,null_fields/1,wiger/1, bin_tail/1,save_restore/1, partitioned_bs_match/1,function_clause/1, unit/1,shared_sub_bins/1,bin_and_float/1, dec_subidentifiers/1,skip_optional_tag/1,decode_integer/1, wfbm/1,degenerated_match/1,bs_sum/1,coverage/1, multiple_uses/1,zero_label/1,followed_by_catch/1, matching_meets_construction/1,simon/1,matching_and_andalso/1, otp_7188/1,otp_7233/1,otp_7240/1,otp_7498/1, match_string/1,zero_width/1,bad_size/1,haystack/1, cover_beam_bool/1,matched_out_size/1,follow_fail_branch/1, no_partition/1,calling_a_binary/1,binary_in_map/1, match_string_opt/1,select_on_integer/1, map_and_binary/1,unsafe_branch_caching/1, bad_literals/1,good_literals/1,constant_propagation/1, parse_xml/1,get_payload/1,escape/1,num_slots_different/1, beam_bsm/1,guard/1,is_ascii/1,non_opt_eq/1,erl_689/1, bs_start_match2_defs/1]). -export([coverage_id/1,coverage_external_ignore/2]). -include_lib("common_test/include/ct.hrl"). %-include_lib("syntax_tools/include/merl.hrl"). suite() -> [{ct_hooks,[ts_install_cth]}, {timetrap,{minutes,1}}]. all() -> [{group,p}]. groups() -> [{p,[parallel], [size_shadow,int_float,otp_5269,null_fields,wiger, bin_tail,save_restore, partitioned_bs_match,function_clause,unit, shared_sub_bins,bin_and_float,dec_subidentifiers, skip_optional_tag,decode_integer,wfbm,degenerated_match,bs_sum, coverage,multiple_uses,zero_label,followed_by_catch, matching_meets_construction,simon, matching_and_andalso,otp_7188,otp_7233,otp_7240, otp_7498,match_string,zero_width,bad_size,haystack, cover_beam_bool,matched_out_size,follow_fail_branch, no_partition,calling_a_binary,binary_in_map, match_string_opt,select_on_integer, map_and_binary,unsafe_branch_caching, % bad_literals,good_literals,constant_propagation,parse_xml, good_literals,constant_propagation,parse_xml, get_payload,escape,num_slots_different, beam_bsm,guard,is_ascii,non_opt_eq,erl_689, bs_start_match2_defs]}]. init_per_suite(Config) -> test_lib:recompile(?MODULE), Config. end_per_suite(_Config) -> ok. init_per_group(_GroupName, Config) -> Config. end_per_group(_GroupName, Config) -> Config. init_per_testcase(Case, Config) when is_atom(Case), is_list(Config) -> Config. end_per_testcase(Case, Config) when is_atom(Case), is_list(Config) -> ok. size_shadow(Config) when is_list(Config) -> %% Originally OTP-5270. 7 = size_shadow_1(), 7 = size_shadow_2(8), 7 = size_shadow_3(), no = size_shadow_4(8), Any = {any,term,goes}, {2577,Any,-175,whatever} = (size_shadow_5(Any, 12))(<<2577:12>>, -175, whatever), {7777,Any,42,whatever} = (size_shadow_6(Any, 13))(42, <<7777:13>>, whatever), {<<45>>,<<>>} = size_shadow_7({int,1}, <<1:16,45>>), {'EXIT',{function_clause,_}} = (catch size_shadow_7({int,42}, <<1:16,45>>)), ok. size_shadow_1() -> L = 8, F = fun(<>) -> B end, F(<<16:8, 7:16>>). size_shadow_2(L) -> F = fun(<>) -> B end, F(<<16:8, 7:16>>). size_shadow_3() -> L = 8, F = fun(<>) -> B end, F(<<16:8, 7:16,16:16>>). size_shadow_4(L) -> F = fun(<>) -> B; (_) -> no end, F(<<16:8, 7:16,15:16>>). size_shadow_5(X, Y) -> fun (<< A:Y >>, Y, B) -> fum(A, X, Y, B) end. size_shadow_6(X, Y) -> fun (Y, << A:Y >>, B) -> fum(A, X, Y, B) end. fum(A, B, C, D) -> {A,B,C,D}. size_shadow_7({int,N}, <>) -> {B,T}. int_float(Config) when is_list(Config) -> %% OTP-5323 <<103133.0:64/float>> = <<103133:64/float>>, <<103133:64/float>> = <<103133:64/float>>, %% Coverage of error cases in sys_pre_expand:coerce_to_float/2. case id(default) of <<(1 bsl 1024):64/float>> -> ct:fail(should_not_match); default -> ok end. %% Stolen from erl_eval_SUITE and modified. %% OTP-5269. Bugs in the bit syntax. otp_5269(Config) when is_list(Config) -> check(fun() -> L = 8, F = fun(<>) -> B end, F(<<16:8, 7:16>>) end, 7), check(fun() -> L = 8, <> = <<16:8, 7:16>>, B end, 7), check(fun() -> U = 8, (fun(<>) -> U end)(<<32:8>>) end, 32), check(fun() -> U = 8, [U || <> <- [<<32:8>>]] end, [32]), check(fun() -> [X || <> <- [<<16:8,19:16>>], <> <- [<>]] end, [19]), check(fun() -> A = 4, B = 28, bit_size(<<13:(A+(X=B))>>), X end, 28), check(fun() -> <> = <<2,"AB","CD">>, {Size,B,Rest} end, {2,<<"AB">>,<<"CD">>}), check(fun() -> X = 32, [X || <> <- [<<1:32>>,<<2:32>>,<<3:8>>]] end, %% "binsize variable" ^ [1,2]), check(fun() -> (fun (<>) -> case A of B -> wrong; _ -> ok end end)(<<1,2,3,4>>) end, ok), ok. null_fields(Config) when is_list(Config) -> check(fun() -> W = id(0), F = fun(<<_:W>>) -> tail; (<<>>) -> empty end, F(<<>>) end, tail), check(fun() -> F = fun(<<_/binary>>) -> tail; (<<>>) -> empty end, F(<<>>) end, tail), ok. wiger(Config) when is_list(Config) -> ok1 = wcheck(<<3>>), ok2 = wcheck(<<1,2,3>>), ok3 = wcheck(<<4>>), {error,<<1,2,3,4>>} = wcheck(<<1,2,3,4>>), {error,<<>>} = wcheck(<<>>), ok. wcheck(<>) when A==3-> ok1; wcheck(<<_,_:2/binary>>) -> ok2; wcheck(<<_>>) -> ok3; wcheck(Other) -> {error,Other}. bin_tail(Config) when is_list(Config) -> S = <<"abcde">>, $a = bin_tail_c(S, 0), $c = bin_tail_c(S, 2), $e = bin_tail_c(S, 4), {'EXIT',_} = (catch bin_tail_c(S, 5)), {'EXIT',_} = (catch bin_tail_c_var(S, 5)), $a = bin_tail_d(S, 0), $b = bin_tail_d(S, 8), $d = bin_tail_d(S, 3*8), {'EXIT',_} = (catch bin_tail_d_dead(S, 1)), {'EXIT',_} = (catch bin_tail_d_dead(S, 9)), {'EXIT',_} = (catch bin_tail_d_dead(S, 5*8)), {'EXIT',_} = (catch bin_tail_d_var(S, 1)), ok = bin_tail_e(<<2:2,0:1,1:5>>), ok = bin_tail_e(<<2:2,1:1,1:5,42:64>>), error = bin_tail_e(<<3:2,1:1,1:5,42:64>>), error = bin_tail_e(<<>>), ok. bin_tail_c(Bin, Offset) -> Res = bin_tail_c_dead(Bin, Offset), <<_:Offset/binary,_,Tail/binary>> = Bin, {Res,Tail} = bin_tail_c_var(Bin, Offset), Res. bin_tail_c_dead(Bin, Offset) -> <<_:Offset/binary,C,_/binary>> = Bin, C. bin_tail_c_var(Bin, Offset) -> <<_:Offset/binary,C,Tail/binary>> = Bin, {C,Tail}. bin_tail_d(Bin, BitOffset) -> Res = bin_tail_d_dead(Bin, BitOffset), <<_:BitOffset,_:8,Tail/binary>> = Bin, {Res,Tail} = bin_tail_d_var(Bin, BitOffset), Res. bin_tail_d_dead(Bin, BitOffset) -> <<_:BitOffset,C,_/binary>> = Bin, C. bin_tail_d_var(Bin, BitOffset) -> <<_:BitOffset,C,Tail/binary>> = Bin, {C,Tail}. bin_tail_e(Bin) -> case bin_tail_e_dead(Bin) of ok -> <<_,Tail/binary>> = Bin, Tail = bin_tail_e_var(Bin), ok; error -> bin_tail_e_var(Bin) end. bin_tail_e_dead(Bin) -> case Bin of %% The binary is aligned at the end; neither the bs_skip_bits2 nor %% bs_test_tail2 instructions are needed. <<2:2,_:1,1:5,_/binary>> -> ok; _ -> error end. bin_tail_e_var(Bin) -> case Bin of %% The binary is aligned at the end; neither the bs_skip_bits2 nor %% bs_test_tail2 instructions are needed. <<2:2,_:1,1:5,Tail/binary>> -> Tail; _ -> error end. save_restore(Config) when is_list(Config) -> 0 = save_restore_1(<<0:2,42:6>>), {1,3456} = save_restore_1(<<1:2,3456:14>>), {2,7981234} = save_restore_1(<<2:2,7981234:30>>), {3,763967493838} = save_restore_1(<<0:2,763967493838:62>>), A = <<" x">>, B = <<".x">>, C = <<"-x">>, {" ",<<"x">>} = lll(A), {" ",<<"x">>} = mmm(A), {" ",<<"x">>} = nnn(A), {" ",<<"x">>} = ooo(A), {".",<<"x">>} = lll(B), {".",<<"x">>} = mmm(B), {".",<<"x">>} = nnn(B), {".",<<"x">>} = ooo(B), {"-",<<"x">>} = lll(C), {"-",<<"x">>} = mmm(C), {"-",<<"x">>} = nnn(C), {"-",<<"x">>} = ooo(C), a = multiple_matches(<<777:16>>, <<777:16>>), b = multiple_matches(<<777:16>>, <<999:16>>), c = multiple_matches(<<777:16>>, <<57:8>>), d = multiple_matches(<<17:8>>, <<1111:16>>), Bin = <<-1:64>>, case bad_float_unpack_match(Bin) of -1 -> ok; _Other -> ct:fail(bad_return_value_probably_NaN) end. save_restore_1(Bin) -> case Bin of <<0:2,_:6>> -> 0; <<1:2,A:14>> -> {1,A}; <<2:2,A:30>> -> {2,A}; <> -> {3,A} end. lll(<>) -> {[Char],Tail}. mmm(<<$.,$.,$., Tail/binary>>) -> Tail; mmm(<<$\s,$-,$\s, Tail/binary>>) -> Tail; mmm(<>) -> {[Char],Tail}. %% Buggy Tail! nnn(<<"...", Tail/binary>>) -> Tail; nnn(<<" - ", Tail/binary>>) -> Tail; nnn(<>) -> {[Char],Tail}. %% Buggy Tail! ooo(<<" - ", Tail/binary>>) -> Tail; ooo(<>) -> {[Char],Tail}. multiple_matches(<>, <>) -> a; multiple_matches(<<_:16>>, <<_:16>>) -> b; multiple_matches(<<_:16>>, <<_:8>>) -> c; multiple_matches(<<_:8>>, <<_:16>>) -> d. bad_float_unpack_match(<>) -> F; bad_float_unpack_match(<>) -> I. partitioned_bs_match(Config) when is_list(Config) -> <<1,2,3>> = partitioned_bs_match(blurf, <<42,1,2,3>>), error = partitioned_bs_match(10, <<7,8,15,13>>), error = partitioned_bs_match(100, {a,tuple,is,'not',a,binary}), ok = partitioned_bs_match(0, <<>>), fc(partitioned_bs_match, [-1,blurf], catch partitioned_bs_match(-1, blurf)), fc(partitioned_bs_match, [-1,<<1,2,3>>], catch partitioned_bs_match(-1, <<1,2,3>>)), {17,<<1,2,3>>} = partitioned_bs_match_2(1, <<17,1,2,3>>), {7,<<1,2,3>>} = partitioned_bs_match_2(7, <<17,1,2,3>>), fc(partitioned_bs_match_2, [4,<<0:17>>], catch partitioned_bs_match_2(4, <<0:17>>)), anything = partitioned_bs_match_3(anything, <<42>>), ok = partitioned_bs_match_3(1, 2), ok. partitioned_bs_match(_, <<42:8,T/binary>>) -> T; partitioned_bs_match(N, _) when N > 0 -> error; partitioned_bs_match(_, <<>>) -> ok. partitioned_bs_match_2(1, <>) -> {B,T}; partitioned_bs_match_2(Len, <<_:8,T/binary>>) -> {Len,T}. partitioned_bs_match_3(Var, <<_>>) -> Var; partitioned_bs_match_3(1, 2) -> ok. function_clause(Config) when is_list(Config) -> ok = function_clause_1(<<0,7,0,7,42>>), fc(function_clause_1, [<<0,1,2,3>>], catch function_clause_1(<<0,1,2,3>>)), fc(function_clause_1, [<<0,1,2,3>>], catch function_clause_1(<<0,7,0,1,2,3>>)), ok = function_clause_2(<<0,7,0,7,42>>), ok = function_clause_2(<<255>>), ok = function_clause_2(<<13:4>>), fc(function_clause_2, [<<0,1,2,3>>], catch function_clause_2(<<0,1,2,3>>)), fc(function_clause_2, [<<0,1,2,3>>], catch function_clause_2(<<0,7,0,1,2,3>>)), ok. function_clause_1(<<0:8,7:8,T/binary>>) -> function_clause_1(T); function_clause_1(<<_:8>>) -> ok. function_clause_2(<<0:8,7:8,T/binary>>) -> function_clause_2(T); function_clause_2(<<_:8>>) -> ok; function_clause_2(<<_:4>>) -> ok. unit(Config) when is_list(Config) -> 42 = peek1(<<42>>), 43 = peek1(<<43,1,2>>), 43 = peek1(<<43,1,2,(-1):1>>), 43 = peek1(<<43,1,2,(-1):2>>), 43 = peek1(<<43,1,2,(-1):7>>), 99 = peek8(<<99>>), 100 = peek8(<<100,101>>), fc(peek8, [<<100,101,0:1>>], catch peek8(<<100,101,0:1>>)), 37484 = peek16(<<37484:16>>), 37489 = peek16(<<37489:16,5566:16>>), fc(peek16, [<<8>>], catch peek16(<<8>>)), fc(peek16, [<<42:15>>], catch peek16(<<42:15>>)), fc(peek16, [<<1,2,3,4,5>>], catch peek16(<<1,2,3,4,5>>)), 127 = peek7(<<127:7>>), 100 = peek7(<<100:7,19:7>>), fc(peek7, [<<1,2>>], catch peek7(<<1,2>>)), ok. peek1(<>) -> B. peek7(<>) -> B. peek8(<>) -> B. peek16(<>) -> B. shared_sub_bins(Config) when is_list(Config) -> {15,[<<>>,<<5>>,<<4,5>>,<<3,4,5>>,<<2,3,4,5>>]} = sum(<<1,2,3,4,5>>, [], 0), ok. sum(<>, Acc, Sum) -> sum(T, [T|Acc], Sum+B); sum(<<>>, Last, Sum) -> {Sum,Last}. bin_and_float(Config) when is_list(Config) -> 14.0 = bin_and_float(<<1.0/float,2.0/float,3.0/float>>, 0.0), ok. bin_and_float(<>, Sum) when is_float(X), is_float(Y), is_float(Z) -> bin_and_float(T, Sum+X*X+Y*Y+Z*Z); bin_and_float(<<>>, Sum) -> Sum. dec_subidentifiers(Config) when is_list(Config) -> {[],<<1,2,3>>} = do_dec_subidentifiers(<<1:1,42:7,1:1,99:7,1,2,3>>, 0, [], 2), {[5389],<<1,2,3>>} = do_dec_subidentifiers(<<1:1,42:7,0:1,13:7,1,2,3>>, 0, [], 2), {[3,2,1],not_a_binary} = dec_subidentifiers(not_a_binary, any, [1,2,3], 0), ok. do_dec_subidentifiers(Buffer, Av, Al, Len) -> Res = dec_subidentifiers(Buffer, Av, Al, Len), Res = dec_subidentifiers2(Buffer, Av, Al, Len), Res = dec_subidentifiers4(Buffer, Av, Al, Len), Res = dec_subidentifiers3(Buffer, Av, Al, Len). dec_subidentifiers(Buffer, _Av, Al, 0) -> {lists:reverse(Al),Buffer}; dec_subidentifiers(<<1:1,H:7,T/binary>>, Av, Al, Len) -> dec_subidentifiers(T, (Av bsl 7) bor H, Al, Len-1); dec_subidentifiers(<>, Av, Al, Len) -> dec_subidentifiers(T, 0, [((Av bsl 7) bor H)|Al], Len-1). dec_subidentifiers2(<>, _Av, Al, 0) -> {lists:reverse(Al),Buffer}; dec_subidentifiers2(<<1:1,H:7,T/binary>>, Av, Al, Len) -> dec_subidentifiers2(T, (Av bsl 7) bor H, Al, Len-1); dec_subidentifiers2(<>, Av, Al, Len) -> dec_subidentifiers2(T, 0, [((Av bsl 7) bor H)|Al], Len-1). dec_subidentifiers3(Buffer, _Av, Al, 0) when is_binary(Buffer) -> {lists:reverse(Al),Buffer}; dec_subidentifiers3(<<1:1,H:7,T/binary>>, Av, Al, Len) -> dec_subidentifiers3(T, (Av bsl 7) bor H, Al, Len-1); dec_subidentifiers3(<>, Av, Al, Len) -> dec_subidentifiers3(T, 0, [((Av bsl 7) bor H)|Al], Len-1). dec_subidentifiers4(<<1:1,H:7,T/binary>>, Av, Al, Len) when Len =/= 0 -> dec_subidentifiers4(T, (Av bsl 7) bor H, Al, Len-1); dec_subidentifiers4(<>, Av, Al, Len) when Len =/= 0 -> dec_subidentifiers4(T, 0, [((Av bsl 7) bor H)|Al], Len-1); dec_subidentifiers4(Buffer, _Av, Al, 0) -> {lists:reverse(Al),Buffer}. skip_optional_tag(Config) when is_list(Config) -> {ok,<<>>} = skip_optional_tag(<<42>>, <<42>>), {ok,<<>>} = skip_optional_tag(<<42,1>>, <<42,1>>), {ok,<<1,2,3>>} = skip_optional_tag(<<42>>, <<42,1,2,3>>), missing = skip_optional_tag(<<2:3>>, blurf), ok. skip_optional_tag(<<>>, Binary) -> {ok,Binary}; skip_optional_tag(<>, <>) -> skip_optional_tag(RestTag, Rest); skip_optional_tag(_, _) -> missing. decode_integer(_Config) -> {10795,<<43>>,whatever} = decode_integer(1, <<42,43>>, whatever), {-28909,<<19>>,whatever} = decode_integer(1, <<143,19>>, whatever), ok. decode_integer(Len, <>, RemovedBytes) when B1 == 0 -> Bin = <<_Skip:Len/unit:8, Buffer2/binary>> = <>, Size = byte_size(Bin), <> = Bin, {Int,Buffer2,RemovedBytes}; decode_integer(Len, <>, RemovedBytes) -> Bin = <<_Skip:Len/unit:8,Buffer2/binary>> = <>, Size = byte_size(Bin), <> = <>, Int = N - (1 bsl (8 * size(Bin) -1)), {Int,Buffer2,RemovedBytes}. -define(DATELEN, 16). wfbm(Config) when is_list(Config) -> %% check_for_dot_or_space and get_tail is from wfbm4 by Steve Vinoski, %% with modifications. {nomatch,0} = check_for_dot_or_space(<<" ">>), {nomatch,0} = check_for_dot_or_space(<<" abc">>), {ok,<<"abcde">>} = check_for_dot_or_space(<<"abcde 34555">>), {nomatch,0} = check_for_dot_or_space(<<".gurka">>), {nomatch,1} = check_for_dot_or_space(<<"g.urka">>), nomatch = get_tail(<<>>), {ok,<<"2007/10/23/blurf">>} = get_tail(<<"200x/2007/10/23/blurf ">>), {skip,?DATELEN+5} = get_tail(<<"200x/2007/10/23/blurf.">>), nomatch = get_tail(<<"200y.2007.10.23.blurf ">>), {'EXIT',_} = (catch get_tail({no,binary,at,all})), {'EXIT',_} = (catch get_tail(no_binary)), ok. check_for_dot_or_space(Bin) -> check_for_dot_or_space(Bin, 0). check_for_dot_or_space(<<$\s, _/binary>>, 0) -> {nomatch,0}; check_for_dot_or_space(Bin, Len) -> case Bin of <> -> {ok,Front}; <<_:Len/binary, $., _/binary>> -> {nomatch,Len}; _ -> check_for_dot_or_space(Bin, Len+1) end. get_tail(<<>>) -> nomatch; get_tail(Bin) -> <> = Bin, case Front of <<_:3/binary,"x/",Y:4/binary,$/,M:2/binary,$/,D:2/binary,$/>> -> case check_for_dot_or_space(Tail) of {ok,Match} -> {ok,<>}; {nomatch,Skip} -> {skip,?DATELEN + Skip} end; _ -> nomatch end. degenerated_match(Config) when is_list(Config) -> error = degenerated_match_1(<<>>), 1 = degenerated_match_1(<<1:1>>), 2 = degenerated_match_1(<<42,43>>), error = degenerated_match_2(<<>>), no_split = degenerated_match_2(<<1,2>>), {<<1,2,3,4>>,<<5>>} = degenerated_match_2(<<1,2,3,4,5>>), ok. degenerated_match_1(<<>>) -> error; degenerated_match_1(Bin) -> byte_size(Bin). degenerated_match_2(<<>>) -> error; degenerated_match_2(Bin) -> case byte_size(Bin) > 4 of true -> split_binary(Bin, 4); false -> no_split end. bs_sum(Config) when is_list(Config) -> 0 = bs_sum_1([]), 0 = bs_sum_1(<<>>), 42 = bs_sum_1([42]), 1 = bs_sum_1(<<1>>), 10 = bs_sum_1([1,2,3,4]), 15 = bs_sum_1(<<1,2,3,4,5>>), 21 = bs_sum_1([1,2,3|<<4,5,6>>]), 15 = bs_sum_1([1,2,3|{4,5}]), 6 = bs_sum_1([1,2,3|zero]), 6 = bs_sum_1([1,2,3|0]), 7 = bs_sum_1([1,2,3|one]), fc(catch bs_sum_1({too,big,tuple})), fc(catch bs_sum_1([1,2,3|{too,big,tuple}])), [] = sneaky_alias(<<>>), [559,387655] = sneaky_alias(id(<<559:32,387655:32>>)), fc(sneaky_alias, [<<1>>], catch sneaky_alias(id(<<1>>))), fc(sneaky_alias, [[1,2,3,4]], catch sneaky_alias(lists:seq(1, 4))), ok. bs_sum_1(<>) -> H+bs_sum_1(T); bs_sum_1([H|T]) -> H+bs_sum_1(T); bs_sum_1({A,B}=_Tuple=_AliasForNoGoodReason) -> A+B; bs_sum_1(0) -> 0; bs_sum_1(zero=_Zero) -> 0; bs_sum_1(one) -> 1; bs_sum_1([]) -> 0; bs_sum_1(<<>>) -> 0. sneaky_alias(<<>>=L) -> binary_to_list(L); sneaky_alias(<>) -> [From|sneaky_alias(L)]. coverage(Config) when is_list(Config) -> 0 = coverage_fold(fun(B, A) -> A+B end, 0, <<>>), 6 = coverage_fold(fun(B, A) -> A+B end, 0, <<1,2,3>>), fc(catch coverage_fold(fun(B, A) -> A+B end, 0, [a,b,c])), {<<42.0:64/float>>,float} = coverage_build(<<>>, <<42>>, float), {<<>>,not_a_tuple} = coverage_build(<<>>, <<>>, not_a_tuple), {<<16#76,"abc",16#A9,"abc">>,{x,42,43}} = coverage_build(<<>>, <<16#7,16#A>>, {x,y,z}), [<<2>>,<<1>>] = coverage_bc(<<1,2>>, []), {x,<<"abc">>,z} = coverage_setelement(<<2,"abc">>, {x,y,z}), [42] = coverage_apply(<<42>>, [coverage_id]), 42 = coverage_external(<<42>>), do_coverage_bin_to_term_list([]), do_coverage_bin_to_term_list([lists:seq(0, 10),{a,b,c},<<23:42>>]), fc(coverage_bin_to_term_list, [<<0,0,0,7>>], catch do_coverage_bin_to_term_list_1(<<7:32>>)), <<>> = coverage_per_key(<<4:32>>), <<$a,$b,$c>> = coverage_per_key(<<7:32,"abc">>), binary = coverage_bitstring(<<>>), binary = coverage_bitstring(<<7>>), bitstring = coverage_bitstring(<<7:4>>), other = coverage_bitstring([a]), ok. coverage_fold(Fun, Acc, <>) -> IdFun = fun id/1, coverage_fold(Fun, Fun(IdFun(H), IdFun(Acc)), T); coverage_fold(Fun, Acc, <<>>) when is_function(Fun, 2) -> Acc. coverage_build(Acc0, <>, float) -> Float = id(<>), Acc = <>, coverage_build(Acc, T, float); coverage_build(Acc0, <>, Tuple0) -> Str = id(<>), Acc = id(<>), Tuple = setelement(2, setelement(3, Tuple0, 43), 42), if byte_size(Acc) > 0 -> coverage_build(Acc, T, Tuple) end; coverage_build(Acc, <<>>, Tuple) -> {Acc,Tuple}. coverage_bc(<>, Acc) -> B = << <> || C <- [H] >>, coverage_bc(T, [B|Acc]); coverage_bc(<<>>, Acc) -> Acc. coverage_setelement(<>, Tuple) when element(1, Tuple) =:= x -> setelement(H, Tuple, T1). coverage_apply(<>, [F|Fs]) -> [?MODULE:F(H)|coverage_apply(T, Fs)]; coverage_apply(<<>>, []) -> []. coverage_external(<>) -> ?MODULE:coverage_external_ignore(T, T), H. coverage_external_ignore(_, _) -> ok. coverage_id(I) -> id(I). do_coverage_bin_to_term_list(L) -> Bin = << <<(begin BinTerm = term_to_binary(Term), <<(byte_size(BinTerm)):32,BinTerm/binary>> end)/binary>> || Term <- L >>, L = do_coverage_bin_to_term_list_1(Bin), L = do_coverage_bin_to_term_list_1(<>), L = do_coverage_bin_to_term_list_1(<<7:32,"garbage",Bin/binary>>). do_coverage_bin_to_term_list_1(Bin) -> Res = coverage_bin_to_term_list(Bin), Res = coverage_bin_to_term_list(Bin, []), Res = coverage_bin_to_term_list_catch(Bin), Res = coverage_bin_to_term_list_catch(Bin, []). coverage_bin_to_term_list(<>) -> try binary_to_term(BinTerm) of Term -> [Term|coverage_bin_to_term_list(T)] catch error:badarg -> coverage_bin_to_term_list(T) end; coverage_bin_to_term_list(<<>>) -> []. coverage_bin_to_term_list(<>, Acc) -> try binary_to_term(BinTerm) of Term -> coverage_bin_to_term_list(T, [Term|Acc]) catch error:badarg -> coverage_bin_to_term_list(T, Acc) end; coverage_bin_to_term_list(<<>>, Acc) -> lists:reverse(Acc). coverage_bin_to_term_list_catch(<>) -> case catch binary_to_term(BinTerm) of {'EXIT',_} -> coverage_bin_to_term_list_catch(T); Term -> [Term|coverage_bin_to_term_list_catch(T)] end; coverage_bin_to_term_list_catch(<<>>) -> []. coverage_bin_to_term_list_catch(<>, Acc) -> case catch binary_to_term(BinTerm) of {'EXIT',_} -> coverage_bin_to_term_list_catch(T, Acc); Term -> coverage_bin_to_term_list_catch(T, [Term|Acc]) end; coverage_bin_to_term_list_catch(<<>>, Acc) -> lists:reverse(Acc). coverage_per_key(<> = B) -> true = (byte_size(B) =:= BinSize), Bin. coverage_bitstring(Bin) when is_binary(Bin) -> binary; coverage_bitstring(<<_/bitstring>>) -> bitstring; coverage_bitstring(_) -> other. multiple_uses(Config) when is_list(Config) -> {344,62879,345,<<245,159,1,89>>} = multiple_uses_1(<<1,88,245,159,1,89>>), true = multiple_uses_2(<<0,0,197,18>>), <<42,43>> = multiple_uses_3(<<0,0,42,43>>, fun id/1), ok = first_after(<<>>, 42), <<1>> = first_after(<<1,2,3>>, 0), <<2>> = first_after(<<1,2,3>>, 1), ok. multiple_uses_1(<>) -> %% NOT OPTIMIZED: sub binary is matched or used in more than one place {Y,Z} = multiple_uses_match(Tail), {X,Y,Z,Tail}. multiple_uses_2(<<_:16,Tail/binary>>) -> %% NOT OPTIMIZED: sub binary is matched or used in more than one place multiple_uses_cmp(Tail, Tail). multiple_uses_3(<<_:16,Tail/binary>>, Fun) -> %% NOT OPTIMIZED: sub binary is used or returned Fun(Tail). multiple_uses_match(<>) -> {Y,Z}. multiple_uses_cmp(<>, <>) -> true; multiple_uses_cmp(<<_:16>>, <<_:16>>) -> false. first_after(Data, Offset) -> case byte_size(Data) > Offset of false -> {_First, _Rest} = {ok, ok}, ok; true -> <<_:Offset/binary, Rest/binary>> = Data, %% 'Rest' saved in y(0) before the call. {First, _} = match_first(Data, Rest), %% When beam_bsm sees the code, the following line %% which uses y(0) has been optimized away. {First, Rest} = {First, Rest}, First end. match_first(_, <>) -> {First, Rest}. zero_label(Config) when is_list(Config) -> <<"nosemouth">> = read_pols(<<"FACE","nose","mouth">>), <<"CE">> = read_pols(<<"noFACE">>), ok. read_pols(Data) -> <> = Data, %% Intentional warning. (PolygonType == <<"FACE">>) or (PolygonType == <<"PTCH">>), Rest. followed_by_catch(Config) when is_list(Config) -> ok = handle(<<0,1,2,3,4,5>>). -record(rec,{field}). handle(<<>>) -> ok; handle(Msg) -> <<_DataLen:16, Rest/binary>> = Msg, case catch fooX:func() of [X] -> X#rec.field; _ -> ok end, handle(Rest). matching_meets_construction(Config) when is_list(Config) -> Bin = id(<<"abc">>), Len = id(2), Tail0 = id(<<1,2,3,4,5>>), <<_:Len/binary,Tail/binary>> = Tail0, Res = <>, <<3,4,5,"abc">> = Res, {'EXIT',{badarg,_}} = (catch matching_meets_construction_1(<<"Abc">>)), {'EXIT',{badarg,_}} = (catch matching_meets_construction_2(<<"Abc">>)), <<"Bbc">> = matching_meets_construction_3(<<"Abc">>), <<1,2>> = encode_octet_string(<<1,2,3>>, 2), ok. matching_meets_construction_1(<<"A",H/binary>>) -> <<"B",H>>. matching_meets_construction_2(<<"A",H/binary>>) -> <<"B",H/float>>. matching_meets_construction_3(<<"A",H/binary>>) -> <<"B",H/binary>>. encode_octet_string(<>, Len) -> <>. simon(Config) when is_list(Config) -> one = simon(blurf, <<>>), two = simon(0, <<42>>), fc(simon, [17,<<1>>], catch simon(17, <<1>>)), fc(simon, [0,<<1,2,3>>], catch simon(0, <<1,2,3>>)), one = simon2(blurf, <<9>>), two = simon2(0, <<9,1>>), fc(simon2, [0,<<9,10,11>>], catch simon2(0, <<9,10,11>>)), ok. simon(_, <<>>) -> one; simon(0, <<_>>) -> two. simon2(_, <<9>>) -> one; simon2(0, <<_:16>>) -> two. %% OTP-7113: Crash in v3_codegen. matching_and_andalso(Config) when is_list(Config) -> ok = matching_and_andalso_1(<<1,2,3>>, 3), {'EXIT',{function_clause,_}} = (catch matching_and_andalso_1(<<1,2,3>>, -8)), {'EXIT',{function_clause,_}} = (catch matching_and_andalso_1(<<1,2,3>>, blurf)), {'EXIT',{function_clause,_}} = (catch matching_and_andalso_1(<<1,2,3>>, 19)), {"abc",<<"xyz">>} = matching_and_andalso_23("abc", <<"-xyz">>), {"abc",<<"">>} = matching_and_andalso_23("abc", <<($a-1)>>), {"abc",<<"">>} = matching_and_andalso_23("abc", <<($z+1)>>), {"abc",<<"">>} = matching_and_andalso_23("abc", <<($A-1)>>), {"abc",<<"">>} = matching_and_andalso_23("abc", <<($Z+1)>>), error = matching_and_andalso_23([], <<>>), error = matching_and_andalso_23([], <<$A>>), error = matching_and_andalso_23([], <<$Z>>), error = matching_and_andalso_23([], <<$a>>), error = matching_and_andalso_23([], <<$z>>), ok. matching_and_andalso_1(<>, K) when is_integer(K) andalso size(Bitmap) >= K andalso 0 < K -> ok. matching_and_andalso_23(Datetime, Bin) -> Res = matching_and_andalso_2(Datetime, Bin), Res = matching_and_andalso_3(Datetime, Bin), Res. matching_and_andalso_2(Datetime, <>) when not ((H >= $a) andalso (H =< $z)) andalso not ((H >= $A) andalso (H =< $Z)) -> {Datetime,T}; matching_and_andalso_2(_, _) -> error. %% Contrived example to ensure we cover the handling of 'call' instructions %% in v3_codegen:bsm_rename_ctx/4. matching_and_andalso_3(Datetime, <>) when not ((abs(H) >= $a) andalso (abs(H) =< $z)) andalso not ((abs(H) >= $A) andalso (abs(H) =< $Z)) -> {Datetime,T}; matching_and_andalso_3(_, _) -> error. %% Thanks to Tomas Stejskal. otp_7188(Config) when is_list(Config) -> MP3 = <<84,65,71,68,117,154,105,232,107,121,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,68,97,110,105,101,108,32,76, 97,110,100,97,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66, 101,115,116,32,79,102,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,50,48,48,48,50,48,48,48,32,45,32,66,101,115, 116,32,79,102,32,32,32,32,32,32,32,32,32,32,32,32,32,32, 32,32,12>>, {ok,{"ID3v1", [{title,<<68,117,154,105,232,107,121>>}, {artist,<<"Daniel Landa">>}, {album,<<"Best Of">>}]}} = parse_v1_or_v11_tag(MP3). parse_v1_or_v11_tag(<<"TAG", Title:30/binary, Artist:30/binary, Album:30/binary, _Year:4/binary, _Comment:28/binary, 0:8, Track:8, _Genre:8>>) -> {ok, {"ID3v1.1", [{track, Track}, {title, trim(Title)}, {artist, trim(Artist)}, {album, trim(Album)}]}}; parse_v1_or_v11_tag(<<"TAG", Title:30/binary, Artist:30/binary, Album:30/binary, _Year:4/binary, _Comment:30/binary, _Genre:8>>) -> {ok, {"ID3v1", [{title, trim(Title)}, {artist, trim(Artist)}, {album, trim(Album)}]}}; parse_v1_or_v11_tag(_) -> error. trim(Bin) -> list_to_binary(trim_blanks(binary_to_list(Bin))). trim_blanks(L) -> lists:reverse(skip_blanks_and_zero(lists:reverse(L))). skip_blanks_and_zero([$\s|T]) -> skip_blanks_and_zero(T); skip_blanks_and_zero([0|T]) -> skip_blanks_and_zero(T); skip_blanks_and_zero(L) -> L. %% OTP-7233. Record and binary matching optimizations clashed. %% Thanks to Vladimir Klebansky. -record(rec_otp_7233, {key, val}). otp_7233(Config) when is_list(Config) -> otp_7233_1(#rec_otp_7233{key = <<"XXabcde">>,val=[{"xxxxxxxx",42}]}), [<<"XXabcde">>,{"xxxxxxxx",42}] = get(io_format), erase(io_format), otp_7233_1(#rec_otp_7233{key = <<"XXabcde">>,val=[]}), undefined = get(io_format), ok. otp_7233_1(Rec) -> <> = Rec#rec_otp_7233.key, case K of <<"XX">> -> Value = Rec#rec_otp_7233.val, case lists:keyfind("xxxxxxxx", 1, Value) of false -> ok; T -> put(io_format, [Rec#rec_otp_7233.key,T]) end; _ -> ok end. otp_7240(Config) when is_list(Config) -> a = otp_7240_a(0, <<>>), b = otp_7240_a(1, 2), a = otp_7240_b(anything, <<>>), b = otp_7240_b(1, {x,y}), a = otp_7240_c(anything, <<>>), b = otp_7240_c(1, <<2>>), a = otp_7240_d(anything, <<>>), b = otp_7240_d(again, <<2>>), a = otp_7240_e(anything, <<>>), b = otp_7240_e(1, 41), a = otp_7240_f(anything, <<>>), b = otp_7240_f(1, {}), ok. otp_7240_a(_, <<>>) -> a; otp_7240_a(1, 2) -> b. otp_7240_b(_, <<>>) -> a; otp_7240_b(1, {_,_}) -> b. otp_7240_c(_, <<>>) -> a; otp_7240_c(1, <<2>>) -> b. otp_7240_d(_, <<>>) -> a; otp_7240_d(_, <<2>>) -> b. otp_7240_e(_, <<>>) -> a; otp_7240_e(1, B) when B < 42 -> b. otp_7240_f(_, <<>>) -> a; otp_7240_f(1, B) when is_tuple(B) -> b. otp_7498(Config) when is_list(Config) -> <<1,2,3>> = otp_7498_foo(<<1,2,3>>, 0), <<2,3>> = otp_7498_foo(<<1,2,3>>, 1), <<1,2,3>> = otp_7498_foo(<<1,2,3>>, 2), <<1,2,3>> = otp_7498_bar(<<1,2,3>>, 0), <<2,3>> = otp_7498_bar(<<1,2,3>>, 1), <<1,2,3>> = otp_7498_bar(<<1,2,3>>, 2), <<>> = otp_7498_bar(<<>>, 2), <<1,2,3>> = otp_7498_bar(<<1,2,3>>, 3), ok. otp_7498_foo(Bin, 0) -> otp_7498_foo(Bin, 42); otp_7498_foo(<<_A, Rest/bitstring>>, 1) -> otp_7498_foo(Rest, 43); otp_7498_foo(Bin, _I) -> Bin. otp_7498_bar(Bin, 0) -> otp_7498_bar(Bin, 42); otp_7498_bar(<<_A, Rest/bitstring>>, 1) -> otp_7498_bar(Rest, 43); otp_7498_bar(<<>>, 2) -> otp_7498_bar(<<>>, 44); otp_7498_bar(Bin, _I) -> Bin. match_string(Config) when is_list(Config) -> %% To make sure that native endian really is handled correctly %% (i.e. that the compiler does not attempt to use bs_match_string/4 %% instructions for native segments), running this test is not enough. %% Either examine the generated for do_match_string_native/1 or %% check the coverage for the v3_kernel module. case erlang:system_info(endian) of little -> do_match_string_native(<<$a,0,$b,0>>); big -> do_match_string_native(<<0,$a,0,$b>>) end, do_match_string_big(<<0,$a,0,$b>>), do_match_string_little(<<$a,0,$b,0>>), do_match_string_big_signed(<<255,255>>), do_match_string_little_signed(<<255,255>>), plain = no_match_string_opt(<<"abc">>), strange = no_match_string_opt(<<$a:9,$b:9,$c:9>>), ok. do_match_string_native(<<$a:16/native,$b:16/native>>) -> ok. do_match_string_big(<<$a:16/big,$b:16/big>>) -> ok. do_match_string_little(<<$a:16/little,$b:16/little>>) -> ok. do_match_string_big_signed(<<(-1):16/signed>>) -> ok. do_match_string_little_signed(<<(-1):16/little-signed>>) -> ok. no_match_string_opt(<<"abc">>) -> plain; no_match_string_opt(<<$a:9,$b:9,$c:9>>) -> strange. %% OTP-7591: A zero-width segment in matching would crash the compiler. zero_width(Config) when is_list(Config) -> <> = <<2, 0, $h, $i, 0:0>>, 2 = Len, Str = <<"hi">>, %% Match sure that values that cannot fit in a segment will not match. case id(<<0:8>>) of <<256:8>> -> ct:fail(should_not_match); _ -> ok end, ok. %% OTP_7650: A invalid size for binary segments could crash the compiler. bad_size(Config) when is_list(Config) -> Tuple = {a,b,c}, {'EXIT',{{badmatch,<<>>},_}} = (catch <<32:Tuple>> = id(<<>>)), Binary = <<1,2,3>>, {'EXIT',{{badmatch,<<>>},_}} = (catch <<32:Binary>> = id(<<>>)), ok. haystack(Config) when is_list(Config) -> <<0:10/unit:8>> = haystack_1(<<0:10/unit:8>>), [<<0:10/unit:8>>, <<0:20/unit:8>>] = haystack_2(<<1:8192>>), ok. %% Used to crash the compiler. haystack_1(Haystack) -> Subs = [10], [begin <> = Haystack, B end || Y <- Subs], Haystack. %% There would be an incorrect badmatch exception. haystack_2(Haystack) -> Subs = [{687,10},{369,20}], [begin <<_:X/binary,B:Y/binary,_/binary>> = Haystack, B end || {X,Y} <- Subs ]. fc({'EXIT',{function_clause,_}}) -> ok; fc({'EXIT',{{case_clause,_},_}}) when ?MODULE =:= bs_match_inline_SUITE -> ok. fc(Name, Args, {'EXIT',{function_clause,[{?MODULE,Name,Args,_}|_]}}) -> ok; fc(Name, Args, {'EXIT',{function_clause,[{?MODULE,Name,Arity,_}|_]}}) when length(Args) =:= Arity -> true = test_server:is_native(?MODULE); fc(_, Args, {'EXIT',{{case_clause,ActualArgs},_}}) when ?MODULE =:= bs_match_inline_SUITE -> Args = tuple_to_list(ActualArgs). %% Cover the clause handling bs_context to binary in %% beam_block:initialized_regs/2. cover_beam_bool(Config) when is_list(Config) -> ok = do_cover_beam_bool(<<>>, 3), <<19>> = do_cover_beam_bool(<<19>>, 2), <<42>> = do_cover_beam_bool(<<42>>, 1), <<17>> = do_cover_beam_bool(<<13,17>>, 0), ok. do_cover_beam_bool(Bin, X) when X > 0 -> if X =:= 1; X =:= 2 -> Bin; true -> ok end; do_cover_beam_bool(<<_,Bin/binary>>, X) -> do_cover_beam_bool(Bin, X+1). matched_out_size(Config) when is_list(Config) -> {253,16#DEADBEEF} = mos_int(<<8,253,16#DEADBEEF:32>>), {6,16#BEEFDEAD} = mos_int(<<3,6:3,16#BEEFDEAD:32>>), {53,16#CAFEDEADBEEFCAFE} = mos_int(<<16,53:16,16#CAFEDEADBEEFCAFE:64>>), {23,16#CAFEDEADBEEFCAFE} = mos_int(<<5,23:5,16#CAFEDEADBEEFCAFE:64>>), {<<1,2,3>>,4} = mos_bin(<<3,1,2,3,4,3>>), {<<1,2,3,7>>,19,42} = mos_bin(<<4,1,2,3,7,19,4,42>>), <<1,2,3,7>> = mos_bin(<<4,1,2,3,7,"abcdefghij">>), ok. mos_int(<>) -> {I,X}; mos_int(<>) -> {I,X}. mos_bin(<>) -> L = byte_size(Bin), {Bin,X}; mos_bin(<>) -> L = byte_size(Bin), {Bin,X,Y}; mos_bin(<>) -> L = byte_size(Bin), Bin. follow_fail_branch(_) -> 42 = ffb_1(<<0,1>>, <<0>>), 8 = ffb_1(<<0,1>>, [a]), 42 = ffb_2(<<0,1>>, <<0>>, 17), 8 = ffb_2(<<0,1>>, [a], 0), ok. ffb_1(<<_,T/bitstring>>, List) -> case List of <<_>> -> 42; [_|_] -> %% The fail branch of the bs_start_match2 instruction %% pointing to here would be ignored, making the compiler %% incorrectly assume that the delayed sub-binary %% optimization was safe. bit_size(T) end. ffb_2(<<_,T/bitstring>>, List, A) -> case List of <<_>> when A =:= 17 -> 42; [_|_] -> bit_size(T) end. no_partition(_) -> one = no_partition_1(<<"string">>, a1), {two,<<"string">>} = no_partition_1(<<"string">>, a2), {two,<<>>} = no_partition_1(<<>>, a2), {two,a} = no_partition_1(a, a2), three = no_partition_1(undefined, a3), {four,a,[]} = no_partition_1([a], a4), {five,a,b} = no_partition_1({a,b}, a5), one = no_partition_2(<<"string">>, a1), two = no_partition_2(<<"string">>, a2), two = no_partition_2(<<>>, a2), two = no_partition_2(a, a2), three = no_partition_2(undefined, a3), four = no_partition_2(42, a4), five = no_partition_2([], a5), six = no_partition_2(42.0, a6), ok. no_partition_1(<<"string">>, a1) -> one; no_partition_1(V, a2) -> {two,V}; no_partition_1(undefined, a3) -> three; no_partition_1([H|T], a4) -> {four,H,T}; no_partition_1({A,B}, a5) -> {five,A,B}. no_partition_2(<<"string">>, a1) -> one; no_partition_2(_, a2) -> two; no_partition_2(undefined, a3) -> three; no_partition_2(42, a4) -> four; no_partition_2([], a5) -> five; no_partition_2(42.0, a6) -> six. calling_a_binary(Config) when is_list(Config) -> [] = call_binary(<<>>, []), {'EXIT',{badarg,_}} = (catch call_binary(<<1>>, [])), {'EXIT',{badarg,_}} = (catch call_binary(<<1,2,3>>, [])), ok. call_binary(<<>>, Acc) -> Acc; call_binary(<>, Acc) -> T(<>). binary_in_map(Config) when is_list(Config) -> ok = match_binary_in_map(#{key => <<42:8>>}), {'EXIT',{{badmatch,#{key := 1}},_}} = (catch match_binary_in_map(#{key => 1})), {'EXIT',{{badmatch,#{key := <<1023:16>>}},_}} = (catch match_binary_in_map(#{key => <<1023:16>>})), {'EXIT',{{badmatch,#{key := <<1:8>>}},_}} = (catch match_binary_in_map(#{key => <<1:8>>})), {'EXIT',{{badmatch,not_a_map},_}} = (catch match_binary_in_map(not_a_map)), ok. match_binary_in_map(Map) -> case 8 of N -> #{key := <<42:N>>} = Map, ok end. match_string_opt(Config) when is_list(Config) -> {x,<<1,2,3>>,{<<1>>,{v,<<1,2,3>>}}} = do_match_string_opt({<<1>>,{v,<<1,2,3>>}}), ok. do_match_string_opt({<<1>>,{v,V}}=T) -> {x,V,T}. select_on_integer(Config) when is_list(Config) -> 42 = do_select_on_integer(<<42>>), <<"abc">> = do_select_on_integer(<<128,"abc">>), {'EXIT',_} = (catch do_select_on_integer(<<0:1>>)), {'EXIT',_} = (catch do_select_on_integer(<<1:1>>)), {'EXIT',_} = (catch do_select_on_integer(<<0:1,0:15>>)), ok. %% The ASN.1 compiler frequently generates code like this. do_select_on_integer(<<0:1,I:7>>) -> I; do_select_on_integer(<<1:1,_:7,Bin/binary>>) -> Bin. %% If 'bin_opt_info' was given the warning would lack filename %% and line number. map_and_binary(_Config) -> {<<"10">>,<<"37">>,<<"am">>} = do_map_and_binary(<<"10:37am">>), Map1 = #{time => "noon"}, {ok,Map1} = do_map_and_binary(Map1), Map2 = #{hour => 8, min => 42}, {8,42,Map2} = do_map_and_binary(Map2), ok. do_map_and_binary(<>) -> {Hour, Min, Rest}; do_map_and_binary(#{time := _} = T) -> {ok, T}; do_map_and_binary(#{hour := Hour, min := Min} = T) -> {Hour, Min, T}. %% Unsafe caching of branch outcomes in beam_bsm would cause the %% delayed creation of sub-binaries optimization to be applied even %% when it was unsafe. unsafe_branch_caching(_Config) -> <<>> = do_unsafe_branch_caching(<<42,1>>), <<>> = do_unsafe_branch_caching(<<42,2>>), <<>> = do_unsafe_branch_caching(<<42,3>>), <<17,18>> = do_unsafe_branch_caching(<<42,3,17,18>>), <<>> = do_unsafe_branch_caching(<<1,3,42,2>>), ok. do_unsafe_branch_caching(<>) -> <> = Bin, case C1 of X when X =:= 1 orelse X =:= 2 -> Bin2 = <<>>; _ -> Bin2 = B1 end, case Code of 1 -> do_unsafe_branch_caching(Bin2); _ -> Bin2 end. bad_literals(_Config) -> % Mod = list_to_atom(?MODULE_STRING ++ "_" ++ % atom_to_list(?FUNCTION_NAME)), % S = [signed_lit_match(V, Sz) || V <- lists:seq(-8, 8), % Sz <- [0,1,2,3]] ++ % [unsigned_lit_match(V, Sz) || V <- lists:seq(-2, 8), % Sz <- [0,1,2]] ++ % [unicode_match(V) || % V <- [-100,-1,0,1,2|lists:seq(16#10FFFC, 16#110004)]], % Code = ?Q(["-module('@Mod@').\n" % "-export([f/0]).\n" % "f() ->\n" % "_@S,\n" % "ok.\n"]), % merl:print(Code), % Opts = test_lib:opt_opts(?MODULE), % {ok,_} = merl:compile_and_load(Code, Opts), % Mod:f(), {'EXIT',<<42>>} = (catch bad_literals_1()), Sz = id(8), {'EXIT',{{badmatch,_},_}} = (catch <<-1:Sz>> = <<-1>>), ok. bad_literals_1() -> BadSz = bad, case case <<42>> of <<42:BadSz>> -> ok; Val -> exit(Val) end of ok -> ok; error -> error end. %signed_lit_match(V, Sz) -> % case <> of % <> -> % ?Q("<<_@V@:_@Sz@/signed>> = <<_@V@:_@Sz@>>"); % _ -> % ?Q(["case <<_@V@:_@Sz@>> of\n", % " <<_@V@:_@Sz@/signed>> ->\n", % " ct:fail(should_not_match);\n", % " _ ->\n", % " ok\n", % "end\n"]) % end. %unsigned_lit_match(V, Sz) -> % case <> of % <> -> % ?Q("<<_@V@:_@Sz@>> = <<_@V@:_@Sz@>>"); % _ -> % ?Q(["case <<_@V@:_@Sz@>> of\n", % " <<_@V@:_@Sz@/unsigned>> ->\n", % " ct:fail(should_not_match);\n", % " _ ->\n", % " ok\n", % "end\n"]) % end. %unicode_match(V) -> % try <> of % <> -> % ?Q(["<<_@V@/utf8>> = <<_@V@/utf8>>,\n", % "<<_@V@/utf16>> = <<_@V@/utf16>>,\n", % "<<_@V@/utf32>> = <<_@V@/utf32>>\n"]) % catch % error:badarg -> % ?Q(["case <<_@V@:32>> of\n", % " <<_@V@/utf32>> ->\n", % " ct:fail(should_not_match);\n", % " _ ->\n", % " ok\n", % "end\n"]) % end. %% Test a few legal but rare cases. good_literals(_Config) -> Sz = id(64), %% Variable size. <<42:Sz>> = id(<<42:Sz>>), <<42.0:Sz/float>> = id(<<42:Sz/float>>), %% unit > 1 <<16#cafebeef:4/unit:8>> = id(<<16#cafebeef:32>>), ok. constant_propagation(_Config) -> <<5>> = constant_propagation_a(a, <<5>>), {'EXIT',{{case_clause,b},_}} = (catch constant_propagation_a(b, <<5>>)), 258 = constant_propagation_b(<<1,2>>), F = constant_propagation_c(), 259 = F(<<1,3>>), ok. constant_propagation_a(X, Y) -> case X of a -> Y2 = 8 end, <<5:Y2>> = Y. constant_propagation_b(B) -> Sz = 16, <> = B, X. constant_propagation_c() -> Size = 16, fun(Bin) -> <> = Bin, X end. parse_xml(_Config) -> <<"> = do_parse_xml(<<">), <<" ">> = do_parse_xml(<<">), ok. do_parse_xml(<<"> = Bytes) -> %% Delayed sub-binary creation is not safe. A buggy (development) %% version of check_liveness_everywhere() in beam_utils would turn %% on the optimization. Rest1 = case is_next_char_whitespace(Rest) of false -> Bytes; true -> id(Rest) end, id(Rest1). is_next_char_whitespace(<>) -> C =:= $\s. -record(ext_header, {this_hdr = 17, ext_hdr_opts}). get_payload(_Config) -> <<3445:48>> = do_get_payload(#ext_header{ext_hdr_opts = <<3445:48>>}), {'EXIT',_} = (catch do_get_payload(#ext_header{})), ok. do_get_payload(ExtHdr) -> _ = ExtHdr#ext_header.this_hdr, ExtHdrOptions = ExtHdr#ext_header.ext_hdr_opts, <<_:13,_:35>> = ExtHdr#ext_header.ext_hdr_opts, ExtHdrOptions. escape(_Config) -> 0 = escape(<<>>, 0), 1 = escape(<<128>>, 0), 2 = escape(<<128,255>>, 0), 42 = escape(<<42>>, 0), 50 = escape(<<42,8>>, 0), ok. escape(<>, Pos) when Byte >= 127 -> escape(Rest, Pos + 1); escape(<>, Pos) -> escape(Rest, Pos + Byte); escape(<<_Rest/bits>>, Pos) -> Pos. %% ERL-490 num_slots_different(_Config) -> Ts = [{<<"de">>, <<"default">>, <<"Remove">>, <<"a">>}, {<<"de">>, <<"default">>, <<"Remove from list">>, <<"a">>}, {<<"de">>, <<"default">>, <<"Remove from the list">>, <<"a">>}, {<<"de">>, <<"default">>, <<"Results">>, <<"Ergebnisse">>}, {<<"de">>, <<"default">>, <<"Reservatio">>, <<"a">>}, {<<"de">>, <<"navigation">>, <<"Results">>, <<"Ergebnisse">>}, {<<"de">>, <<"navigation">>, <<"Resources">>, <<"Ressourcen">>}], _ = [{ok,Res} = lgettext(A, B, C) || {A,B,C,Res} <- Ts], {'EXIT',_} = (catch lgettext(<<"d">>, <<"default">>, <<"Remove">>)), {'EXIT',_} = (catch lgettext("", <<"default">>, <<"Remove">>)), {'EXIT',_} = (catch lgettext(<<"de">>, <<"def">>, <<"Remove">>)), {'EXIT',_} = (catch lgettext(<<"de">>, <<"default">>, <<"Res">>)), ok. lgettext(<<"de">>, <<"default">>, <<"Remove">>) -> {ok, <<"a">>}; lgettext(<<"de">>, <<"default">>, <<"Remove from list">>) -> {ok, <<"a">>}; lgettext(<<"de">>, <<"default">>, <<"Remove from the list">>) -> {ok, <<"a">>}; lgettext(<<"de">>, <<"default">>, <<"Results">>) -> {ok, <<"Ergebnisse">>}; lgettext(<<"de">>, <<"default">>, <<"Reservatio">>) -> {ok, <<"a">>}; lgettext(<<"de">>, <<"navigation">>, <<"Results">>) -> {ok, <<"Ergebnisse">>}; lgettext(<<"de">>, <<"navigation">>, <<"Resources">>) -> {ok, <<"Ressourcen">>}. %% Test more code in beam_bsm. beam_bsm(_Config) -> true = check_bitstring_list(<<1:1,0:1,1:1,1:1>>, [1,0,1,1]), false = check_bitstring_list(<<1:1,0:1,1:1,1:1>>, [0]), true = bsm_validate_scheme(<<>>), true = bsm_validate_scheme(<<5,10>>), false = bsm_validate_scheme(<<5,10,11,12>>), true = bsm_validate_scheme([]), true = bsm_validate_scheme([5,10]), false = bsm_validate_scheme([5,6,7]), <<1,2,3>> = bsm_must_save_and_not_save(<<1,2,3>>, []), D = fun(N) -> 2*N end, [2,4|<<3>>] = bsm_must_save_and_not_save(<<1,2,3>>, [D,D]), ok. check_bitstring_list(<>, [H|T2]) -> check_bitstring_list(T1, T2); check_bitstring_list(<<>>, []) -> true; check_bitstring_list(_, _) -> false. bsm_validate_scheme([]) -> true; bsm_validate_scheme([H|T]) -> case bsm_is_scheme(H) of true -> bsm_validate_scheme(T); false -> false end; bsm_validate_scheme(<<>>) -> true; bsm_validate_scheme(<>) -> case bsm_is_scheme(H) of true -> bsm_validate_scheme(Rest); false -> false end. bsm_is_scheme(Int) -> Int rem 5 =:= 0. %% NOT OPTIMIZED: different control paths use different positions in the binary bsm_must_save_and_not_save(Bin, []) -> Bin; bsm_must_save_and_not_save(<>, [F|Fs]) -> [F(H)|bsm_must_save_and_not_save(T, Fs)]; bsm_must_save_and_not_save(<<>>, []) -> []. guard(_Config) -> _Tuple = id({a,b}), ok = guard_1(<<1,2,3>>, {1,2,3}), ok = guard_2(<<42>>, #{}), ok. %% Cover handling of #k_put{} in v3_codegen:bsm_rename_ctx/4. guard_1(<>, Tuple) when Tuple =:= {A,B,C} -> ok. %% Cover handling of #k_call{} in v3_codegen:bsm_rename_ctx/4. guard_2(<<_>>, Healing) when Healing#{[] => Healing} =:= #{[] => #{}} -> ok. is_ascii(_Config) -> true = do_is_ascii(<<>>), true = do_is_ascii(<<"string">>), false = do_is_ascii(<<1024/utf8>>), {'EXIT',{function_clause,_}} = (catch do_is_ascii(<<$A,0:3>>)), {'EXIT',{function_clause,_}} = (catch do_is_ascii(<<16#80,0:3>>)), ok. do_is_ascii(<<>>) -> true; do_is_ascii(<>) when C >= 16#80 -> %% This clause must fail to match if the size of the argument in %% bits is not divisible by 8. Beware of unsafe optimizations. false; do_is_ascii(<<_, T/binary>>) -> do_is_ascii(T). non_opt_eq(_Config) -> true = non_opt_eq([], <<>>), true = non_opt_eq([$a], <<$a>>), false = non_opt_eq([$a], <<$b>>), ok. %% An example from the Efficiency Guide. It used to be not optimized, %% but now it can be optimized. non_opt_eq([H|T1], <>) -> non_opt_eq(T1, T2); non_opt_eq([_|_], <<_,_/binary>>) -> false; non_opt_eq([], <<>>) -> true. %% ERL-689 erl_689(_Config) -> {{0, 0, 0}, <<>>} = do_erl_689_1(<<0>>, ?MODULE), {{2018, 8, 7}, <<>>} = do_erl_689_1(<<4,2018:16/little,8,7>>, ?MODULE), {{0, 0, 0}, <<>>} = do_erl_689_2(?MODULE, <<0>>), {{2018, 8, 7}, <<>>} = do_erl_689_2(?MODULE, <<4,2018:16/little,8,7>>), ok. do_erl_689_1(Arg1, Arg2) -> Res = do_erl_689_1a(Arg1, Arg2), Res = do_erl_689_1b(Arg1, Arg2). do_erl_689_2(Arg1, Arg2) -> Res = do_erl_689_2a(Arg1, Arg2), Res = do_erl_689_2b(Arg1, Arg2). do_erl_689_1a(<>, _) -> case {Data, Length} of {_, 0} -> %% bs_context_to_binary would incorrectly set Data to the original %% binary (before matching in the function head). {{0, 0, 0}, Data}; {<>, 4} -> {{Y, M, D}, Rest} end. do_erl_689_1b(<>, _) -> case {Data, Length} of {_, 0} -> %% bs_context_to_binary would incorrectly set Data to the original %% binary (before matching in the function head). id(0), {{0, 0, 0}, Data}; {<>, 4} -> id(1), {{Y, M, D}, Rest} end. do_erl_689_2a(_, <>) -> case {Length, Data} of {0, _} -> %% bs_context_to_binary would incorrectly set Data to the original %% binary (before matching in the function head). {{0, 0, 0}, Data}; {4, <>} -> {{Y, M, D}, Rest} end. do_erl_689_2b(_, <>) -> case {Length, Data} of {0, _} -> %% bs_context_to_binary would incorrectly set Data to the original %% binary (before matching in the function head). id(0), {{0, 0, 0}, Data}; {4, <>} -> id(1), {{Y, M, D}, Rest} end. %% ERL-753 bs_start_match2_defs(_Config) -> {<<"http://127.0.0.1:1234/vsaas/hello">>} = api_url(<<"hello">>, dummy), {"https://127.0.0.1:4321/vsaas/hello"} = api_url({https, "hello"}, dummy). api_url(URL, Auth) -> Header = [], case URL of <<_/binary>> -> {<<"http://127.0.0.1:1234/vsaas/",URL/binary>>}; {https, [_|_] = URL1} -> {"https://127.0.0.1:4321/vsaas/"++URL1} end. check(F, R) -> R = F(). id(I) -> I. ================================================ FILE: otp_build/otp_build_core.patch ================================================ diff --git a/make/otp.mk.in b/make/otp.mk.in index df29d26833..b74fb14a71 100644 --- a/make/otp.mk.in +++ b/make/otp.mk.in @@ -126,9 +126,11 @@ endif $(EBIN)/%.beam: $(EGEN)/%.erl $(V_ERLC) $(ERL_COMPILE_FLAGS) -o$(EBIN) $< + $(V_ERLC) $(ERL_COMPILE_FLAGS) +to_core -o$(EBIN) $< $(EBIN)/%.beam: $(ESRC)/%.erl $(V_ERLC) $(ERL_COMPILE_FLAGS) -o$(EBIN) $< + $(V_ERLC) $(ERL_COMPILE_FLAGS) +to_core -o$(EBIN) $< ifeq ($(NATIVE_LIBS_ENABLED),yes) # Special rule for the HIPE bootstrap w/ native libs ================================================ FILE: otp_build/patch_build_otp.sh ================================================ #!/bin/bash set -e pushd ../otp git reset --hard git apply ../otp_build/otp_build_core.patch ./otp_build autoconf ./configure # TODO: This will fail on the `tools` app. Will fix when needed make preloaded libs #APPS="kernel stdlib compiler common_test" #for app_name in $APPS; do # make -C lib/$app_name opt #done popd ================================================ FILE: otp_build/patch_tests.sh ================================================ #!/bin/bash set -e cp ../otp/lib/compiler/test/bs_match_SUITE.erl . patch -l --normal --verbose bs_match_SUITE.erl bs_match_SUITE.erl.patch ================================================ FILE: test_data/Elixir.Enum.erl ================================================ -file("/home/build/elixir/lib/elixir/lib/enum.ex", 196). -module('Elixir.Enum'). -compile([no_auto_import, inline_list_funcs, {inline, [{reduce_enumerable,3}, {reduce_by,3}, {reduce,3}, {entry_to_string,1}, {aggregate,3}]}]). -spec reverse(t(), t()) -> list(). -spec slice(t(), index(), non_neg_integer()) -> list(). -spec 'empty?'(t()) -> boolean(). -spec drop(t(), integer()) -> list(). -spec unzip(t()) -> {[element()], [element()]}. -spec zip([t()]) -> t(); (t()) -> t(). -spec split(t(), integer()) -> {list(), list()}. -spec flat_map(t(), fun((element()) -> t())) -> list(). -spec chunk_every(t(), pos_integer(), pos_integer(), t() | discard) -> [list()]. -spec min_max_by(t(), fun((element()) -> any()), fun(() -> empty_result)) -> {element(), element()} | empty_result when empty_result :: any(). -spec reduce(t(), fun((element(), any()) -> any())) -> any(). -spec flat_map_reduce(t(), acc, fun) -> {[any()], any()} when fun :: fun((element(), acc) -> {t(), acc} | {halt, acc}), acc :: any(). -spec at(t(), index(), default()) -> element() | default(). -spec drop_while(t(), fun((element()) -> elixir:as_boolean(term()))) -> list(). -spec find_value(t(), any(), fun((element()) -> any())) -> any() | nil. -spec into('Elixir.Enumerable':t(), 'Elixir.Collectable':t()) -> 'Elixir.Collectable':t(). -spec reverse_slice(t(), non_neg_integer(), non_neg_integer()) -> list(). -spec into('Elixir.Enumerable':t(), 'Elixir.Collectable':t(), fun((term()) -> term())) -> 'Elixir.Collectable':t(). -spec take_while(t(), fun((element()) -> elixir:as_boolean(term()))) -> list(). -spec min(t(), fun(() -> empty_result)) -> element() | empty_result when empty_result :: any(). -spec sum(t()) -> number(). -spec map_reduce(t(), any(), fun((element(), any()) -> {any(), any()})) -> {any(), any()}. -spec dedup(t()) -> list(). -spec scan(t(), any(), fun((element(), any()) -> any())) -> list(). -spec each(t(), fun((element()) -> any())) -> ok. -spec random(t()) -> element(). -spec 'any?'(t(), fun((element()) -> elixir:as_boolean(term()))) -> boolean(). -spec count(t()) -> non_neg_integer(). -spec fetch(t(), index()) -> {ok, element()} | error. -spec intersperse(t(), element()) -> list(). -spec map_every(t(), non_neg_integer(), fun((element()) -> any())) -> list(). -spec sort(t(), fun((element(), element()) -> boolean())) -> list(). -spec chunk_while(t(), acc(), fun((element(), acc()) -> {cont, chunk, acc()} | {cont, acc()} | {halt, acc()}), fun((acc()) -> {cont, chunk, acc()} | {cont, acc()})) -> 'Elixir.Enumerable':t() when chunk :: any(). -spec map_join(t(), 'Elixir.String':t(), fun((element()) -> 'Elixir.String.Chars':t())) -> 'Elixir.String':t(). -spec take(t(), integer()) -> list(). -spec drop_every(t(), non_neg_integer()) -> list(). -spec uniq(t()) -> list(). -spec 'member?'(t(), element()) -> boolean(). -spec count(t(), fun((element()) -> elixir:as_boolean(term()))) -> non_neg_integer(). -spec min_by(t(), fun((element()) -> any()), fun(() -> empty_result)) -> element() | empty_result when empty_result :: any(). -spec uniq_by(t(), fun((element()) -> term())) -> list(). -spec min_max(t(), fun(() -> empty_result)) -> {element(), element()} | empty_result when empty_result :: any(). -spec sort_by(t(), fun((element()) -> mapped_element), fun((mapped_element, mapped_element) -> boolean())) -> list() when mapped_element :: element(). -spec reduce_while(t(), any(), fun((element(), any()) -> {cont, any()} | {halt, any()})) -> any(). -spec map(t(), fun((element()) -> any())) -> list(). -spec 'all?'(t(), fun((element()) -> elixir:as_boolean(term()))) -> boolean(). -spec chunk_by(t(), fun((element()) -> any())) -> [list()]. -spec max_by(t(), fun((element()) -> any()), fun(() -> empty_result)) -> element() | empty_result when empty_result :: any(). -spec split_while(t(), fun((element()) -> elixir:as_boolean(term()))) -> {list(), list()}. -spec take_every(t(), non_neg_integer()) -> list(). -spec sort(t()) -> list(). -spec join(t(), 'Elixir.String':t()) -> 'Elixir.String':t(). -spec split_with(t(), fun((element()) -> any())) -> {list(), list()}. -spec scan(t(), fun((element(), any()) -> any())) -> list(). -spec reverse(t()) -> list(). -spec take_random(t(), non_neg_integer()) -> list(). -spec group_by(t(), fun((element()) -> any()), fun((element()) -> any())) -> map(). -spec find_index(t(), fun((element()) -> any())) -> non_neg_integer() | nil. -spec concat(t()) -> t(). -spec zip(t(), t()) -> [{any(), any()}]. -spec slice(t(), 'Elixir.Range':t()) -> list(). -spec with_index(t(), integer()) -> [{element(), index()}]. -spec concat(t(), t()) -> t(). -spec max(t(), fun(() -> empty_result)) -> element() | empty_result when empty_result :: any(). -spec 'fetch!'(t(), index()) -> element(). -spec filter(t(), fun((element()) -> elixir:as_boolean(term()))) -> list(). -spec reject(t(), fun((element()) -> elixir:as_boolean(term()))) -> list(). -spec reduce(t(), any(), fun((element(), any()) -> any())) -> any(). -spec find(t(), default(), fun((element()) -> any())) -> element() | default(). -spec shuffle(t()) -> list(). -spec to_list(t()) -> [element()]. -spec dedup_by(t(), fun((element()) -> term())) -> list(). -spec chunk_every(t(), pos_integer()) -> [list()]. -export_type([default/0]). -type default() :: any(). -export_type([index/0]). -type index() :: integer(). -export_type([element/0]). -type element() :: any(). -export_type([acc/0]). -type acc() :: any(). -export_type([t/0]). -type t() :: 'Elixir.Enumerable':t(). -export(['__info__'/1, 'all?'/1, 'all?'/2, 'any?'/1, 'any?'/2, at/2, at/3, chunk/2, chunk/3, chunk/4, chunk_by/2, chunk_every/2, chunk_every/3, chunk_every/4, chunk_while/4, concat/1, concat/2, count/1, count/2, dedup/1, dedup_by/2, drop/2, drop_every/2, drop_while/2, each/2, 'empty?'/1, fetch/2, 'fetch!'/2, filter/2, filter_map/3, find/2, find/3, find_index/2, find_value/2, find_value/3, flat_map/2, flat_map_reduce/3, group_by/2, group_by/3, intersperse/2, into/2, into/3, join/1, join/2, map/2, map_every/3, map_join/2, map_join/3, map_reduce/3, max/1, max/2, max_by/2, max_by/3, 'member?'/2, min/1, min/2, min_by/2, min_by/3, min_max/1, min_max/2, min_max_by/2, min_max_by/3, partition/2, random/1, reduce/2, reduce/3, reduce_while/3, reject/2, reverse/1, reverse/2, reverse_slice/3, scan/2, scan/3, shuffle/1, slice/2, slice/3, sort/1, sort/2, sort_by/2, sort_by/3, split/2, split_while/2, split_with/2, sum/1, take/2, take_every/2, take_random/2, take_while/2, to_list/1, uniq/1, uniq/2, uniq_by/2, unzip/1, with_index/1, with_index/2, zip/1, zip/2]). -spec '__info__'(attributes | compile | functions | macros | md5 | module | deprecated) -> any(). '__info__'(module) -> 'Elixir.Enum'; '__info__'(functions) -> [{'all?',1}, {'all?',2}, {'any?',1}, {'any?',2}, {at,2}, {at,3}, {chunk,2}, {chunk,3}, {chunk,4}, {chunk_by,2}, {chunk_every,2}, {chunk_every,3}, {chunk_every,4}, {chunk_while,4}, {concat,1}, {concat,2}, {count,1}, {count,2}, {dedup,1}, {dedup_by,2}, {drop,2}, {drop_every,2}, {drop_while,2}, {each,2}, {'empty?',1}, {fetch,2}, {'fetch!',2}, {filter,2}, {filter_map,3}, {find,2}, {find,3}, {find_index,2}, {find_value,2}, {find_value,3}, {flat_map,2}, {flat_map_reduce,3}, {group_by,2}, {group_by,3}, {intersperse,2}, {into,2}, {into,3}, {join,1}, {join,2}, {map,2}, {map_every,3}, {map_join,2}, {map_join,3}, {map_reduce,3}, {max,1}, {max,2}, {max_by,2}, {max_by,3}, {'member?',2}, {min,1}, {min,2}, {min_by,2}, {min_by,3}, {min_max,1}, {min_max,2}, {min_max_by,2}, {min_max_by,3}, {partition,2}, {random,1}, {reduce,2}, {reduce,3}, {reduce_while,3}, {reject,2}, {reverse,1}, {reverse,2}, {reverse_slice,3}, {scan,2}, {scan,3}, {shuffle,1}, {slice,2}, {slice,3}, {sort,1}, {sort,2}, {sort_by,2}, {sort_by,3}, {split,2}, {split_while,2}, {split_with,2}, {sum,1}, {take,2}, {take_every,2}, {take_random,2}, {take_while,2}, {to_list,1}, {uniq,1}, {uniq,2}, {uniq_by,2}, {unzip,1}, {with_index,1}, {with_index,2}, {zip,1}, {zip,2}]; '__info__'(macros) -> []; '__info__'(Key = attributes) -> erlang:get_module_info('Elixir.Enum', Key); '__info__'(Key = compile) -> erlang:get_module_info('Elixir.Enum', Key); '__info__'(Key = md5) -> erlang:get_module_info('Elixir.Enum', Key); '__info__'(deprecated) -> [{{chunk,2},<<"Use Enum.chunk_every/2 instead">>}, {{chunk,3},<<"Use Enum.chunk_every/3 instead">>}, {{chunk,4},<<"Use Enum.chunk_every/4 instead">>}, {{filter_map,3}, <<"Use Enum.filter/2 + Enum.map/2 or for comprehensions instead">>}, {{partition,2},<<"Use Enum.split_with/2 instead">>}, {{uniq,2},<<"Use Enum.uniq_by/2 instead">>}]. aggregate([_head@1|_tail@1], _fun@1, __empty@1) -> lists:foldl(_fun@1, _head@1, _tail@1); aggregate([], __fun@1, _empty@1) -> _empty@1(); aggregate(#{'__struct__' := 'Elixir.Range', first := _first@1, last := _last@1}, _fun@1, __empty@1) -> _fun@1(_first@1, _last@1); aggregate(_enumerable@1, _fun@1, _empty@1) -> _ref@1 = make_ref(), case reduce(_enumerable@1, _ref@1, fun(_element@1, _ref@2) when _ref@1 =:= _ref@2 -> _element@1; (_element@2, _acc@1) -> _fun@1(_element@2, _acc@1) end) of _ref@1 -> _empty@1(); _result@1 -> _result@1 end. 'all?'(__@1) -> 'all?'(__@1, fun(_x@1) -> _x@1 end). 'all?'(_enumerable@1, _fun@1) when is_list(_enumerable@1) -> all_list(_enumerable@1, _fun@1); 'all?'(_enumerable@1, _fun@1) -> element(2, 'Elixir.Enumerable':reduce(_enumerable@1, {cont,true}, fun(_entry@1, _) -> case _fun@1(_entry@1) of __@1 when __@1 =:= nil orelse __@1 =:= false -> {halt,false}; _ -> {cont,true} end end)). all_list([_h@1|_t@1], _fun@1) -> case _fun@1(_h@1) of __@1 when __@1 =:= nil orelse __@1 =:= false -> false; _ -> all_list(_t@1, _fun@1) end; all_list([], _) -> true. 'any?'(__@1) -> 'any?'(__@1, fun(_x@1) -> _x@1 end). 'any?'(_enumerable@1, _fun@1) when is_list(_enumerable@1) -> any_list(_enumerable@1, _fun@1); 'any?'(_enumerable@1, _fun@1) -> element(2, 'Elixir.Enumerable':reduce(_enumerable@1, {cont,false}, fun(_entry@1, _) -> case _fun@1(_entry@1) of __@1 when __@1 =:= nil orelse __@1 =:= false -> {cont,false}; _ -> {halt,true} end end)). any_list([_h@1|_t@1], _fun@1) -> case _fun@1(_h@1) of __@1 when __@1 =:= nil orelse __@1 =:= false -> any_list(_t@1, _fun@1); _ -> true end; any_list([], _) -> false. at(__@1, __@2) -> at(__@1, __@2, nil). at(_enumerable@1, _index@1, _default@1) -> case slice_any(_enumerable@1, _index@1, 1) of [_value@1] -> _value@1; [] -> _default@1 end. backwards_compatible_slice(_args@1) -> try 'Elixir.Enumerable':slice(_args@1) catch error:undef:___STACKTRACE__@1 -> case ___STACKTRACE__@1 of [{_module@1,slice,[_args@1],_}|_] -> {error,_module@1}; _stack@1 -> erlang:raise(error, undef, _stack@1) end end. chunk(_enumerable@1, _count@1) -> chunk(_enumerable@1, _count@1, _count@1, nil). chunk(_enum@1, _n@1, _step@1) -> chunk_every(_enum@1, _n@1, _step@1, nil). chunk(_enumerable@1, _count@1, _step@1, _leftover@1) -> chunk_every(_enumerable@1, _count@1, _step@1, case _leftover@1 of __@1 when __@1 =:= nil orelse __@1 =:= false -> discard; __@2 -> __@2 end). chunk_by(_enumerable@1, _fun@1) -> 'Elixir.Stream.Reducers':chunk_by(fun chunk_while/4, _enumerable@1, _fun@1). chunk_every(_enumerable@1, _count@1) -> chunk_every(_enumerable@1, _count@1, _count@1, []). chunk_every(__@1, __@2, __@3) -> chunk_every(__@1, __@2, __@3, []). chunk_every(_enumerable@1, _count@1, _step@1, _leftover@1) when ((is_integer(_count@1) andalso _count@1 > 0) andalso is_integer(_step@1)) andalso _step@1 > 0 -> 'Elixir.Stream.Reducers':chunk_every(fun chunk_while/4, _enumerable@1, _count@1, _step@1, _leftover@1). chunk_while(_enumerable@1, _acc@1, _chunk_fun@1, _after_fun@1) -> {_,{_res@1,_acc@6}} = 'Elixir.Enumerable':reduce(_enumerable@1, {cont,{[],_acc@1}}, fun(_entry@1, {_buffer@1,_acc@2}) -> case _chunk_fun@1(_entry@1, _acc@2) of {cont,_emit@1,_acc@3} -> {cont, {[_emit@1|_buffer@1], _acc@3}}; {cont,_acc@4} -> {cont, {_buffer@1,_acc@4}}; {halt,_acc@5} -> {halt, {_buffer@1,_acc@5}} end end), case _after_fun@1(_acc@6) of {cont,__acc@1} -> lists:reverse(_res@1); {cont,_elem@1,__acc@2} -> lists:reverse([_elem@1|_res@1]) end. concat(_enumerables@1) -> _fun@1 = fun(__@1, __@2) -> [__@1|__@2] end, lists:reverse(reduce(_enumerables@1, [], fun(__@3, __@4) -> reduce(__@3, __@4, _fun@1) end)). concat(_left@1, _right@1) when is_list(_left@1) andalso is_list(_right@1) -> _left@1 ++ _right@1; concat(_left@1, _right@1) -> concat([_left@1,_right@1]). count(_enumerable@1) when is_list(_enumerable@1) -> length(_enumerable@1); count(_enumerable@1) -> case 'Elixir.Enumerable':count(_enumerable@1) of {ok,_value@1} when is_integer(_value@1) -> _value@1; {error,_module@1} -> element(2, _module@1:reduce(_enumerable@1, {cont,0}, fun(_, _acc@1) -> {cont,_acc@1 + 1} end)) end. count(_enumerable@1, _fun@1) -> reduce(_enumerable@1, 0, fun(_entry@1, _acc@1) -> case _fun@1(_entry@1) of __@1 when __@1 =:= nil orelse __@1 =:= false -> _acc@1; _ -> _acc@1 + 1 end end). dedup(_enumerable@1) -> dedup_by(_enumerable@1, fun(_x@1) -> _x@1 end). dedup_by(_enumerable@1, _fun@1) -> {_list@1,_} = reduce(_enumerable@1, {[],[]}, fun(__@1, {__@3,__@4} = __@2) -> __@5 = _fun@1(__@1), case __@4 of {value,__@5} -> __@2; _ -> {[__@1|__@3],{value,__@5}} end end), lists:reverse(_list@1). drop(_enumerable@1, _amount@1) when (is_list(_enumerable@1) andalso is_integer(_amount@1)) andalso _amount@1 >= 0 -> drop_list(_enumerable@1, _amount@1); drop(_enumerable@1, _amount@1) when is_integer(_amount@1) andalso _amount@1 >= 0 -> {_result@1,_} = reduce(_enumerable@1, {[],_amount@1}, fun(__@1, {__@2,__@3}) when __@3 > 0 -> {__@2,__@3 - 1}; (__@4, {__@5,__@6}) -> {[__@4|__@5],__@6} end), case is_list(_result@1) of false -> []; true -> lists:reverse(_result@1) end; drop(_enumerable@1, _amount@1) when is_integer(_amount@1) andalso _amount@1 < 0 -> {_count@1,_fun@1} = slice_count_and_fun(_enumerable@1), _amount@2 = min(_amount@1 + _count@1, _count@1), case _amount@2 > 0 of false -> []; true -> _fun@1(0, _amount@2) end. drop_every(__enumerable@1, 1) -> []; drop_every(_enumerable@1, 0) -> to_list(_enumerable@1); drop_every([], _nth@1) when is_integer(_nth@1) -> []; drop_every(_enumerable@1, _nth@1) when is_integer(_nth@1) andalso _nth@1 > 1 -> {_res@1,_} = reduce(_enumerable@1, {[],first}, fun(__@1, {__@2,__@3}) when __@3 =:= first orelse __@3 =:= _nth@1 -> {__@2,1}; (__@4, {__@5,__@6}) -> {[__@4|__@5],__@6 + 1} end), lists:reverse(_res@1). drop_list(_list@1, 0) -> _list@1; drop_list([_|_tail@1], _counter@1) -> drop_list(_tail@1, _counter@1 - 1); drop_list([], _) -> []. drop_while(_enumerable@1, _fun@1) when is_list(_enumerable@1) -> drop_while_list(_enumerable@1, _fun@1); drop_while(_enumerable@1, _fun@1) -> {_res@1,_} = reduce(_enumerable@1, {[],true}, fun(__@1, {__@3,__@4} = __@2) -> case case __@4 of false -> false; true -> _fun@1(__@1); __@5 -> error({badbool,'and',__@5}) end of __@6 when __@6 =:= nil orelse __@6 =:= false -> {[__@1|__@3],false}; _ -> __@2 end end), lists:reverse(_res@1). drop_while_list([_head@1|_tail@1], _fun@1) -> case _fun@1(_head@1) of __@1 when __@1 =:= nil orelse __@1 =:= false -> [_head@1|_tail@1]; _ -> drop_while_list(_tail@1, _fun@1) end; drop_while_list([], _) -> []. each(_enumerable@1, _fun@1) when is_list(_enumerable@1) -> lists:foreach(_fun@1, _enumerable@1), ok; each(_enumerable@1, _fun@1) -> reduce(_enumerable@1, nil, fun(_entry@1, _) -> _fun@1(_entry@1), nil end), ok. 'empty?'(_enumerable@1) when is_list(_enumerable@1) -> _enumerable@1 == []; 'empty?'(_enumerable@1) -> case backwards_compatible_slice(_enumerable@1) of {ok,_value@1,_} -> _value@1 == 0; {error,_module@1} -> element(2, _module@1:reduce(_enumerable@1, {cont,true}, fun(_, _) -> {halt,false} end)) end. entry_to_string(_entry@1) when is_binary(_entry@1) -> _entry@1; entry_to_string(_entry@1) -> case _entry@1 of _rewrite@1 when is_binary(_rewrite@1) -> _rewrite@1; _rewrite@1 -> 'Elixir.String.Chars':to_string(_rewrite@1) end. fetch(_enumerable@1, _index@1) -> case slice_any(_enumerable@1, _index@1, 1) of [_value@1] -> {ok,_value@1}; [] -> error end. 'fetch!'(_enumerable@1, _index@1) -> case slice_any(_enumerable@1, _index@1, 1) of [_value@1] -> _value@1; [] -> error('Elixir.Enum.OutOfBoundsError':exception([])) end. filter(_enumerable@1, _fun@1) when is_list(_enumerable@1) -> filter_list(_enumerable@1, _fun@1); filter(_enumerable@1, _fun@1) -> lists:reverse(reduce(_enumerable@1, [], fun(__@1, __@2) -> case _fun@1(__@1) of __@3 when __@3 =:= nil orelse __@3 =:= false -> __@2; _ -> [__@1|__@2] end end)). filter_list([_head@1|_tail@1], _fun@1) -> case _fun@1(_head@1) of __@1 when __@1 =:= nil orelse __@1 =:= false -> filter_list(_tail@1, _fun@1); _ -> [_head@1|filter_list(_tail@1, _fun@1)] end; filter_list([], __fun@1) -> []. filter_map(_enumerable@1, _filter@1, _mapper@1) when is_list(_enumerable@1) -> lists:reverse('Elixir.Enum':reduce(_enumerable@1, [], fun(_item@1, __@2) -> case _filter@1(_item@1) of __@1 when __@1 == false; __@1 == nil -> __@2; _ -> [_mapper@1(_item@1)| __@2] end end)); filter_map(_enumerable@1, _filter@1, _mapper@1) -> lists:reverse(reduce(_enumerable@1, [], fun(__@1, __@2) -> case _filter@1(__@1) of __@3 when __@3 =:= nil orelse __@3 =:= false -> __@2; _ -> [_mapper@1(__@1)|__@2] end end)). find(__@1, __@2) -> find(__@1, nil, __@2). find(_enumerable@1, _default@1, _fun@1) when is_list(_enumerable@1) -> find_list(_enumerable@1, _default@1, _fun@1); find(_enumerable@1, _default@1, _fun@1) -> element(2, 'Elixir.Enumerable':reduce(_enumerable@1, {cont,_default@1}, fun(_entry@1, _default@2) -> case _fun@1(_entry@1) of __@1 when __@1 =:= nil orelse __@1 =:= false -> {cont,_default@2}; _ -> {halt,_entry@1} end end)). find_index(_enumerable@1, _fun@1) when is_list(_enumerable@1) -> find_index_list(_enumerable@1, 0, _fun@1); find_index(_enumerable@1, _fun@1) -> _result@1 = 'Elixir.Enumerable':reduce(_enumerable@1, {cont,{not_found,0}}, fun(_entry@1, {_,_index@1}) -> case _fun@1(_entry@1) of __@1 when __@1 =:= nil orelse __@1 =:= false -> {cont, {not_found, _index@1 + 1}}; _ -> {halt, {found,_index@1}} end end), case element(2, _result@1) of {found,_index@2} -> _index@2; {not_found,_} -> nil end. find_index_list([_head@1|_tail@1], _counter@1, _fun@1) -> case _fun@1(_head@1) of __@1 when __@1 =:= nil orelse __@1 =:= false -> find_index_list(_tail@1, _counter@1 + 1, _fun@1); _ -> _counter@1 end; find_index_list([], _, _) -> nil. find_list([_head@1|_tail@1], _default@1, _fun@1) -> case _fun@1(_head@1) of __@1 when __@1 =:= nil orelse __@1 =:= false -> find_list(_tail@1, _default@1, _fun@1); _ -> _head@1 end; find_list([], _default@1, _) -> _default@1. find_value(__@1, __@2) -> find_value(__@1, nil, __@2). find_value(_enumerable@1, _default@1, _fun@1) when is_list(_enumerable@1) -> find_value_list(_enumerable@1, _default@1, _fun@1); find_value(_enumerable@1, _default@1, _fun@1) -> element(2, 'Elixir.Enumerable':reduce(_enumerable@1, {cont,_default@1}, fun(_entry@1, _default@2) -> _fun_entry@1 = _fun@1(_entry@1), case _fun_entry@1 of __@1 when __@1 =:= nil orelse __@1 =:= false -> {cont,_default@2}; _ -> {halt, _fun_entry@1} end end)). find_value_list([_head@1|_tail@1], _default@1, _fun@1) -> case _fun@1(_head@1) of __@1 when __@1 =:= nil orelse __@1 =:= false -> find_value_list(_tail@1, _default@1, _fun@1); __@2 -> __@2 end; find_value_list([], _default@1, _) -> _default@1. flat_map(_enumerable@1, _fun@1) when is_list(_enumerable@1) -> flat_map_list(_enumerable@1, _fun@1); flat_map(_enumerable@1, _fun@1) -> lists:reverse(reduce(_enumerable@1, [], fun(_entry@1, _acc@1) -> case _fun@1(_entry@1) of _list@1 when is_list(_list@1) -> lists:reverse(_list@1, _acc@1); _other@1 -> reduce(_other@1, _acc@1, fun(__@1, __@2) -> [__@1|__@2] end) end end)). flat_map_list([_head@1|_tail@1], _fun@1) -> case _fun@1(_head@1) of _list@1 when is_list(_list@1) -> _list@1 ++ flat_map_list(_tail@1, _fun@1); _other@1 -> to_list(_other@1) ++ flat_map_list(_tail@1, _fun@1) end; flat_map_list([], __fun@1) -> []. flat_map_reduce(_enumerable@1, _acc@1, _fun@1) -> {_,{_list@2,_acc@7}} = 'Elixir.Enumerable':reduce(_enumerable@1, {cont,{[],_acc@1}}, fun(_entry@1, {_list@1,_acc@2}) -> case _fun@1(_entry@1, _acc@2) of {halt,_acc@3} -> {halt, {_list@1,_acc@3}}; {[],_acc@4} -> {cont, {_list@1,_acc@4}}; {[_entry@2],_acc@5} -> {cont, {[_entry@2|_list@1], _acc@5}}; {_entries@1,_acc@6} -> {cont, {reduce(_entries@1, _list@1, fun(__@1, __@2) -> [__@1| __@2] end), _acc@6}} end end), {lists:reverse(_list@2),_acc@7}. group_by(__@1, __@2) -> group_by(__@1, __@2, fun(_x@1) -> _x@1 end). group_by(_enumerable@1, _key_fun@1, _value_fun@1) when is_function(_key_fun@1) -> reduce(reverse(_enumerable@1), #{}, fun(_entry@1, _acc@1) -> _key@1 = _key_fun@1(_entry@1), _value@1 = _value_fun@1(_entry@1), case _acc@1 of #{_key@1 := _existing@1} -> _acc@1#{_key@1 => [_value@1|_existing@1]}; #{} -> _acc@1#{_key@1 => [_value@1]} end end); group_by(_enumerable@1, _dict@1, _fun@1) -> 'Elixir.IO':warn(<<"Enum.group_by/3 with a map/dictionary as second" " element is deprecated. ", "A map is used by default and it is no longer re" "quired to pass one to this function">>), _dict_module@1 = 'Elixir.Dict', reduce(reverse(_enumerable@1), _dict@1, fun(_entry@1, _categories@1) -> _dict_module@1:update(_categories@1, _fun@1(_entry@1), [_entry@1], fun(__@1) -> [_entry@1|__@1] end) end). head_slice(_rest@1, 0, _acc@1) -> {_acc@1,_rest@1}; head_slice([_elem@1|_rest@1], _count@1, _acc@1) -> head_slice(_rest@1, _count@1 - 1, [_elem@1|_acc@1]). intersperse(_enumerable@1, _element@1) -> _list@1 = lists:reverse(reduce(_enumerable@1, [], fun(_x@1, _acc@1) -> [_x@1,_element@1|_acc@1] end)), case _list@1 of [] -> []; [_|_t@1] -> _t@1 end. into(_enumerable@1, []) -> to_list(_enumerable@1); into(#{'__struct__' := __@1 = _} = _enumerable@1, _collectable@1) when is_atom(__@1) -> into_protocol(_enumerable@1, _collectable@1); into(_enumerable@1, #{'__struct__' := __@1 = _} = _collectable@1) when is_atom(__@1) -> into_protocol(_enumerable@1, _collectable@1); into(#{} = _enumerable@1, #{} = _collectable@1) -> maps:merge(_collectable@1, _enumerable@1); into(_enumerable@1, #{} = _collectable@1) when is_list(_enumerable@1) -> maps:merge(_collectable@1, maps:from_list(_enumerable@1)); into(_enumerable@1, #{} = _collectable@1) -> reduce(_enumerable@1, _collectable@1, fun({_key@1,_val@1}, _acc@1) -> _acc@1#{_key@1 => _val@1} end); into(_enumerable@1, _collectable@1) -> into_protocol(_enumerable@1, _collectable@1). into(_enumerable@1, _collectable@1, _transform@1) when is_list(_collectable@1) -> _collectable@1 ++ map(_enumerable@1, _transform@1); into(_enumerable@1, _collectable@1, _transform@1) -> {_initial@1,_fun@1} = 'Elixir.Collectable':into(_collectable@1), into(_enumerable@1, _initial@1, _fun@1, fun(_entry@1, _acc@1) -> _fun@1(_acc@1, {cont,_transform@1(_entry@1)}) end). into(_enumerable@1, _initial@1, _fun@1, _callback@1) -> try reduce(_enumerable@1, _initial@1, _callback@1) of _acc@1 -> _fun@1(_acc@1, done) catch _kind@1:_reason@1:___STACKTRACE__@1 -> _fun@1(_initial@1, halt), erlang:raise(_kind@1, _reason@1, ___STACKTRACE__@1) end. into_protocol(_enumerable@1, _collectable@1) -> {_initial@1,_fun@1} = 'Elixir.Collectable':into(_collectable@1), into(_enumerable@1, _initial@1, _fun@1, fun(_entry@1, _acc@1) -> _fun@1(_acc@1, {cont,_entry@1}) end). join(__@1) -> join(__@1, <<>>). join(_enumerable@1, _joiner@1) when is_binary(_joiner@1) -> _reduced@1 = reduce(_enumerable@1, first, fun(_entry@1, first) -> entry_to_string(_entry@1); (_entry@2, _acc@1) -> [_acc@1,_joiner@1|entry_to_string(_entry@2)] end), case _reduced@1 == first of false -> iolist_to_binary(_reduced@1); true -> <<>> end. map(_enumerable@1, _fun@1) when is_list(_enumerable@1) -> lists:map(_fun@1, _enumerable@1); map(_enumerable@1, _fun@1) -> lists:reverse(reduce(_enumerable@1, [], fun(__@1, __@2) -> [_fun@1(__@1)|__@2] end)). map_every(_enumerable@1, 1, _fun@1) -> map(_enumerable@1, _fun@1); map_every(_enumerable@1, 0, __fun@1) -> to_list(_enumerable@1); map_every([], _nth@1, __fun@1) when is_integer(_nth@1) andalso _nth@1 > 1 -> []; map_every(_enumerable@1, _nth@1, _fun@1) when is_integer(_nth@1) andalso _nth@1 > 1 -> {_res@1,_} = reduce(_enumerable@1, {[],first}, fun(__@1, {__@2,__@3}) when __@3 =:= first orelse __@3 =:= _nth@1 -> {[_fun@1(__@1)|__@2],1}; (__@4, {__@5,__@6}) -> {[__@4|__@5],__@6 + 1} end), lists:reverse(_res@1). map_join(__@1, __@2) -> map_join(__@1, <<>>, __@2). map_join(_enumerable@1, _joiner@1, _mapper@1) when is_binary(_joiner@1) -> _reduced@1 = reduce(_enumerable@1, first, fun(_entry@1, first) -> entry_to_string(_mapper@1(_entry@1)); (_entry@2, _acc@1) -> [_acc@1, _joiner@1| entry_to_string(_mapper@1(_entry@2))] end), case _reduced@1 == first of false -> iolist_to_binary(_reduced@1); true -> <<>> end. map_reduce(_enumerable@1, _acc@1, _fun@1) when is_list(_enumerable@1) -> lists:mapfoldl(_fun@1, _acc@1, _enumerable@1); map_reduce(_enumerable@1, _acc@1, _fun@1) -> {_list@2,_acc@4} = reduce(_enumerable@1, {[],_acc@1}, fun(_entry@1, {_list@1,_acc@2}) -> {_new_entry@1,_acc@3} = _fun@1(_entry@1, _acc@2), {[_new_entry@1|_list@1],_acc@3} end), {lists:reverse(_list@2),_acc@4}. max(__@1) -> max(__@1, fun() -> error('Elixir.Enum.EmptyError':exception([])) end). max(_enumerable@1, _empty_fallback@1) when is_function(_empty_fallback@1, 0) -> aggregate(_enumerable@1, fun erlang:max/2, _empty_fallback@1). max_by(__@1, __@2) -> max_by(__@1, __@2, fun() -> error('Elixir.Enum.EmptyError':exception([])) end). max_by(_enumerable@1, _fun@1, _empty_fallback@1) when is_function(_fun@1, 1) andalso is_function(_empty_fallback@1, 0) -> _first_fun@1 = fun(__@1) -> {__@1,_fun@1(__@1)} end, _reduce_fun@1 = fun(_entry@1, {_,_fun_max@1} = _old@1) -> _fun_entry@1 = _fun@1(_entry@1), case _fun_entry@1 > _fun_max@1 of false -> _old@1; true -> {_entry@1,_fun_entry@1} end end, case reduce_by(_enumerable@1, _first_fun@1, _reduce_fun@1) of empty -> _empty_fallback@1(); {_entry@2,_} -> _entry@2 end. 'member?'(_enumerable@1, _element@1) when is_list(_enumerable@1) -> lists:member(_element@1, _enumerable@1); 'member?'(_enumerable@1, _element@1) -> case 'Elixir.Enumerable':'member?'(_enumerable@1, _element@1) of {ok,_element@2} when is_boolean(_element@2) -> _element@2; {error,_module@1} -> element(2, _module@1:reduce(_enumerable@1, {cont,false}, fun(_v@1, _) when _v@1 =:= _element@1 -> {halt,true}; (_, _) -> {cont,false} end)) end. min(__@1) -> min(__@1, fun() -> error('Elixir.Enum.EmptyError':exception([])) end). min(_enumerable@1, _empty_fallback@1) when is_function(_empty_fallback@1, 0) -> aggregate(_enumerable@1, fun erlang:min/2, _empty_fallback@1). min_by(__@1, __@2) -> min_by(__@1, __@2, fun() -> error('Elixir.Enum.EmptyError':exception([])) end). min_by(_enumerable@1, _fun@1, _empty_fallback@1) when is_function(_fun@1, 1) andalso is_function(_empty_fallback@1, 0) -> _first_fun@1 = fun(__@1) -> {__@1,_fun@1(__@1)} end, _reduce_fun@1 = fun(_entry@1, {_,_fun_min@1} = _old@1) -> _fun_entry@1 = _fun@1(_entry@1), case _fun_entry@1 < _fun_min@1 of false -> _old@1; true -> {_entry@1,_fun_entry@1} end end, case reduce_by(_enumerable@1, _first_fun@1, _reduce_fun@1) of empty -> _empty_fallback@1(); {_entry@2,_} -> _entry@2 end. min_max(__@1) -> min_max(__@1, fun() -> error('Elixir.Enum.EmptyError':exception([])) end). min_max(#{'__struct__' := 'Elixir.Range', first := _first@1, last := _last@1}, _empty_fallback@1) when is_function(_empty_fallback@1, 0) -> {min(_first@1, _last@1),max(_first@1, _last@1)}; min_max(_enumerable@1, _empty_fallback@1) when is_function(_empty_fallback@1, 0) -> _first_fun@1 = fun(__@1) -> {__@1,__@1} end, _reduce_fun@1 = fun(_entry@1, {_min@1,_max@1}) -> {min(_entry@1, _min@1),max(_entry@1, _max@1)} end, case reduce_by(_enumerable@1, _first_fun@1, _reduce_fun@1) of empty -> _empty_fallback@1(); _entry@2 -> _entry@2 end. min_max_by(__@1, __@2) -> min_max_by(__@1, __@2, fun() -> error('Elixir.Enum.EmptyError':exception([])) end). min_max_by(_enumerable@1, _fun@1, _empty_fallback@1) when is_function(_fun@1, 1) andalso is_function(_empty_fallback@1, 0) -> _first_fun@1 = fun(_entry@1) -> _fun_entry@1 = _fun@1(_entry@1), {{_entry@1,_entry@1},{_fun_entry@1,_fun_entry@1}} end, _reduce_fun@1 = fun(_entry@2, {{_prev_min@1,_prev_max@1},{_fun_min@1,_fun_max@1}} = _acc@1) -> _fun_entry@2 = _fun@1(_entry@2), case _fun_entry@2 < _fun_min@1 of true -> {{_entry@2,_prev_max@1}, {_fun_entry@2,_fun_max@1}}; false -> case _fun_entry@2 > _fun_max@1 of true -> {{_prev_min@1,_entry@2}, {_fun_min@1,_fun_entry@2}}; false -> case true of true -> _acc@1; false -> error(cond_clause) end end end end, case reduce_by(_enumerable@1, _first_fun@1, _reduce_fun@1) of empty -> _empty_fallback@1(); {_entry@3,_} -> _entry@3 end. partition(_enumerable@1, _fun@1) -> split_with(_enumerable@1, _fun@1). random(_enumerable@1) when is_list(_enumerable@1) -> case take_random(_enumerable@1, 1) of [] -> error('Elixir.Enum.EmptyError':exception([])); [_elem@1] -> _elem@1 end; random(_enumerable@1) -> _result@1 = case backwards_compatible_slice(_enumerable@1) of {ok,0,_} -> []; {ok,_count@1,_fun@1} when is_function(_fun@1) -> _fun@1(random_integer(0, _count@1 - 1), 1); {error,_} -> take_random(_enumerable@1, 1) end, case _result@1 of [] -> error('Elixir.Enum.EmptyError':exception([])); [_elem@1] -> _elem@1 end. random_integer(_limit@1, _limit@1) when is_integer(_limit@1) -> _limit@1; random_integer(_lower_limit@1, _upper_limit@1) when _upper_limit@1 < _lower_limit@1 -> random_integer(_upper_limit@1, _lower_limit@1); random_integer(_lower_limit@1, _upper_limit@1) -> _lower_limit@1 + rand:uniform(_upper_limit@1 - _lower_limit@1 + 1) - 1. reduce([_h@1|_t@1], _fun@1) -> reduce(_t@1, _h@1, _fun@1); reduce([], __fun@1) -> error('Elixir.Enum.EmptyError':exception([])); reduce(_enumerable@1, _fun@1) -> _result@1 = element(2, 'Elixir.Enumerable':reduce(_enumerable@1, {cont,first}, fun(_x@1, first) -> {cont,{acc,_x@1}}; (_x@2, {acc,_acc@1}) -> {cont, {acc, _fun@1(_x@2, _acc@1)}} end)), case _result@1 of first -> error('Elixir.Enum.EmptyError':exception([])); {acc,_acc@2} -> _acc@2 end. reduce(_enumerable@1, _acc@1, _fun@1) when is_list(_enumerable@1) -> lists:foldl(_fun@1, _acc@1, _enumerable@1); reduce(#{'__struct__' := 'Elixir.Range', first := _first@1, last := _last@1}, _acc@1, _fun@1) -> case _first@1 =< _last@1 of false -> reduce_range_dec(_first@1, _last@1, _acc@1, _fun@1); true -> reduce_range_inc(_first@1, _last@1, _acc@1, _fun@1) end; reduce(#{'__struct__' := __@1 = _} = _enumerable@1, _acc@1, _fun@1) when is_atom(__@1) -> reduce_enumerable(_enumerable@1, _acc@1, _fun@1); reduce(#{} = _enumerable@1, _acc@1, _fun@1) -> maps:fold(fun(_k@1, _v@1, _acc@2) -> _fun@1({_k@1,_v@1}, _acc@2) end, _acc@1, _enumerable@1); reduce(_enumerable@1, _acc@1, _fun@1) -> reduce_enumerable(_enumerable@1, _acc@1, _fun@1). reduce_by([_head@1|_tail@1], _first@1, _fun@1) -> lists:foldl(_fun@1, _first@1(_head@1), _tail@1); reduce_by([], __first@1, __fun@1) -> empty; reduce_by(_enumerable@1, _first@1, _fun@1) -> reduce(_enumerable@1, empty, fun(_element@1, {_,_} = _acc@1) -> _fun@1(_element@1, _acc@1); (_element@2, empty) -> _first@1(_element@2) end). reduce_enumerable(_enumerable@1, _acc@1, _fun@1) -> element(2, 'Elixir.Enumerable':reduce(_enumerable@1, {cont,_acc@1}, fun(_x@1, _acc@2) -> {cont, _fun@1(_x@1, _acc@2)} end)). reduce_range_dec(_first@1, _first@1, _acc@1, _fun@1) -> _fun@1(_first@1, _acc@1); reduce_range_dec(_first@1, _last@1, _acc@1, _fun@1) -> reduce_range_dec(_first@1 - 1, _last@1, _fun@1(_first@1, _acc@1), _fun@1). reduce_range_inc(_first@1, _first@1, _acc@1, _fun@1) -> _fun@1(_first@1, _acc@1); reduce_range_inc(_first@1, _last@1, _acc@1, _fun@1) -> reduce_range_inc(_first@1 + 1, _last@1, _fun@1(_first@1, _acc@1), _fun@1). reduce_while(_enumerable@1, _acc@1, _fun@1) -> element(2, 'Elixir.Enumerable':reduce(_enumerable@1, {cont,_acc@1}, _fun@1)). reject(_enumerable@1, _fun@1) when is_list(_enumerable@1) -> reject_list(_enumerable@1, _fun@1); reject(_enumerable@1, _fun@1) -> lists:reverse(reduce(_enumerable@1, [], fun(__@1, __@2) -> case _fun@1(__@1) of __@3 when __@3 =:= nil orelse __@3 =:= false -> [__@1|__@2]; _ -> __@2 end end)). reject_list([_head@1|_tail@1], _fun@1) -> case _fun@1(_head@1) of __@1 when __@1 =:= nil orelse __@1 =:= false -> [_head@1|reject_list(_tail@1, _fun@1)]; _ -> reject_list(_tail@1, _fun@1) end; reject_list([], __fun@1) -> []. reverse([]) -> []; reverse([_] = _list@1) -> _list@1; reverse([_item1@1,_item2@1]) -> [_item2@1,_item1@1]; reverse([_item1@1,_item2@1|_rest@1]) -> lists:reverse(_rest@1, [_item2@1,_item1@1]); reverse(_enumerable@1) -> reduce(_enumerable@1, [], fun(__@1, __@2) -> [__@1|__@2] end). reverse(_enumerable@1, _tail@1) when is_list(_enumerable@1) -> lists:reverse(_enumerable@1, to_list(_tail@1)); reverse(_enumerable@1, _tail@1) -> reduce(_enumerable@1, to_list(_tail@1), fun(_entry@1, _acc@1) -> [_entry@1|_acc@1] end). reverse_slice(_enumerable@1, _start_index@1, _count@1) when ((is_integer(_start_index@1) andalso _start_index@1 >= 0) andalso is_integer(_count@1)) andalso _count@1 >= 0 -> _list@1 = reverse(_enumerable@1), _length@1 = length(_list@1), _count@2 = min(_count@1, _length@1 - _start_index@1), case _count@2 > 0 of false -> lists:reverse(_list@1); true -> reverse_slice(_list@1, _length@1, _start_index@1 + _count@2, _count@2, []) end. reverse_slice(_rest@1, _idx@1, _idx@1, _count@1, _acc@1) -> {_slice@1,_rest@2} = head_slice(_rest@1, _count@1, []), lists:reverse(_rest@2, lists:reverse(_slice@1, _acc@1)); reverse_slice([_elem@1|_rest@1], _idx@1, _start@1, _count@1, _acc@1) -> reverse_slice(_rest@1, _idx@1 - 1, _start@1, _count@1, [_elem@1|_acc@1]). reverse_sort_merge([[_h2@1|_t2@1],_t1@1|_l@1], _acc@1, _fun@1, true) -> reverse_sort_merge(_l@1, [sort_merge1(_t1@1, _h2@1, _t2@1, [], _fun@1, true)| _acc@1], _fun@1, true); reverse_sort_merge([_t1@1,[_h2@1|_t2@1]|_l@1], _acc@1, _fun@1, false) -> reverse_sort_merge(_l@1, [sort_merge1(_t1@1, _h2@1, _t2@1, [], _fun@1, true)| _acc@1], _fun@1, false); reverse_sort_merge([_l@1], _acc@1, _fun@1, _bool@1) -> sort_merge([lists:reverse(_l@1, [])|_acc@1], [], _fun@1, _bool@1); reverse_sort_merge([], _acc@1, _fun@1, _bool@1) -> sort_merge(_acc@1, [], _fun@1, _bool@1). scan(_enumerable@1, _fun@1) -> {_res@1,_} = reduce(_enumerable@1, {[],first}, fun(__@1, {__@2,first}) -> {[__@1|__@2],{ok,__@1}}; (__@3, {__@4,{ok,__@5}}) -> __@6 = _fun@1(__@3, __@5), {[__@6|__@4],{ok,__@6}} end), lists:reverse(_res@1). scan(_enumerable@1, _acc@1, _fun@1) -> {_res@1,_} = reduce(_enumerable@1, {[],_acc@1}, fun(__@1, {__@2,__@3}) -> __@4 = _fun@1(__@1, __@3), {[__@4|__@2],__@4} end), lists:reverse(_res@1). shuffle(_enumerable@1) -> _randomized@1 = reduce(_enumerable@1, [], fun(_x@1, _acc@1) -> [{rand:uniform(),_x@1}|_acc@1] end), shuffle_unwrap(lists:keysort(1, _randomized@1), []). shuffle_unwrap([{_,_h@1}|_enumerable@1], _t@1) -> shuffle_unwrap(_enumerable@1, [_h@1|_t@1]); shuffle_unwrap([], _t@1) -> _t@1. slice(_enumerable@1, #{'__struct__' := 'Elixir.Range', first := _first@1, last := _last@1}) -> {_count@1,_fun@1} = slice_count_and_fun(_enumerable@1), _corr_first@1 = case _first@1 >= 0 of false -> _first@1 + _count@1; true -> _first@1 end, _corr_last@1 = case _last@1 >= 0 of false -> _last@1 + _count@1; true -> _last@1 end, _amount@1 = _corr_last@1 - _corr_first@1 + 1, case case case _corr_first@1 >= 0 of false -> false; true -> _corr_first@1 < _count@1 end of false -> false; true -> _amount@1 > 0 end of false -> []; true -> _fun@1(_corr_first@1, min(_amount@1, _count@1 - _corr_first@1)) end. slice(__enumerable@1, _start_index@1, 0) when is_integer(_start_index@1) -> []; slice(_enumerable@1, _start_index@1, _amount@1) when (is_integer(_start_index@1) andalso is_integer(_amount@1)) andalso _amount@1 >= 0 -> slice_any(_enumerable@1, _start_index@1, _amount@1). slice_any(_enumerable@1, _start@1, _amount@1) when _start@1 < 0 -> {_count@1,_fun@1} = slice_count_and_fun(_enumerable@1), _start@2 = _count@1 + _start@1, case _start@2 >= 0 of false -> []; true -> _fun@1(_start@2, min(_amount@1, _count@1 - _start@2)) end; slice_any(_list@1, _start@1, _amount@1) when is_list(_list@1) -> 'Elixir.Enumerable.List':slice(_list@1, _start@1, _amount@1); slice_any(_enumerable@1, _start@1, _amount@1) -> case backwards_compatible_slice(_enumerable@1) of {ok,_count@1,_} when _start@1 >= _count@1 -> []; {ok,_count@2,_fun@1} when is_function(_fun@1) -> _fun@1(_start@1, min(_amount@1, _count@2 - _start@1)); {error,_module@1} -> slice_enum(_enumerable@1, _module@1, _start@1, _amount@1) end. slice_count_and_fun(_enumerable@1) when is_list(_enumerable@1) -> {length(_enumerable@1), fun(__@1, __@2) -> 'Elixir.Enumerable.List':slice(_enumerable@1, __@1, __@2) end}; slice_count_and_fun(_enumerable@1) -> case backwards_compatible_slice(_enumerable@1) of {ok,_count@1,_fun@1} when is_function(_fun@1) -> {_count@1,_fun@1}; {error,_module@1} -> {_,{_list@1,_count@3}} = _module@1:reduce(_enumerable@1, {cont,{[],0}}, fun(_elem@1, {_acc@1,_count@2}) -> {cont, {[_elem@1|_acc@1],_count@2 + 1}} end), {_count@3, fun(__@1, __@2) -> 'Elixir.Enumerable.List':slice(lists:reverse(_list@1), __@1, __@2) end} end. slice_enum(_enumerable@1, _module@1, _start@1, _amount@1) -> {_,{_,_,_slice@1}} = _module@1:reduce(_enumerable@1, {cont,{_start@1,_amount@1,[]}}, fun(__entry@1, {_start@2,_amount@2,__list@1}) when _start@2 > 0 -> {cont,{_start@2 - 1,_amount@2,[]}}; (_entry@1, {_start@3,_amount@3,_list@1}) when _amount@3 > 1 -> {cont, {_start@3, _amount@3 - 1, [_entry@1|_list@1]}}; (_entry@2, {_start@4,_amount@4,_list@2}) -> {halt, {_start@4,_amount@4,[_entry@2|_list@2]}} end), lists:reverse(_slice@1). sort(_enumerable@1) when is_list(_enumerable@1) -> lists:sort(_enumerable@1); sort(_enumerable@1) -> sort(_enumerable@1, fun erlang:'=<'/2). sort(_enumerable@1, _fun@1) when is_list(_enumerable@1) -> lists:sort(_fun@1, _enumerable@1); sort(_enumerable@1, _fun@1) -> sort_terminator(reduce(_enumerable@1, [], fun(__@1, __@2) -> sort_reducer(__@1, __@2, _fun@1) end), _fun@1). sort_by(__@1, __@2) -> sort_by(__@1, __@2, fun erlang:'=<'/2). sort_by(_enumerable@1, _mapper@1, _sorter@1) -> map(sort(map(_enumerable@1, fun(__@1) -> {__@1,_mapper@1(__@1)} end), fun(__@2, __@3) -> _sorter@1(element(2, __@2), element(2, __@3)) end), fun(__@4) -> element(1, __@4) end). sort_merge(_list@1, _fun@1, true) -> reverse_sort_merge(_list@1, [], _fun@1, true); sort_merge(_list@1, _fun@1, false) -> sort_merge(_list@1, [], _fun@1, false). sort_merge([_t1@1,[_h2@1|_t2@1]|_l@1], _acc@1, _fun@1, true) -> sort_merge(_l@1, [sort_merge1(_t1@1, _h2@1, _t2@1, [], _fun@1, false)| _acc@1], _fun@1, true); sort_merge([[_h2@1|_t2@1],_t1@1|_l@1], _acc@1, _fun@1, false) -> sort_merge(_l@1, [sort_merge1(_t1@1, _h2@1, _t2@1, [], _fun@1, false)| _acc@1], _fun@1, false); sort_merge([_l@1], [], __fun@1, __bool@1) -> _l@1; sort_merge([_l@1], _acc@1, _fun@1, _bool@1) -> reverse_sort_merge([lists:reverse(_l@1, [])|_acc@1], [], _fun@1, _bool@1); sort_merge([], _acc@1, _fun@1, _bool@1) -> reverse_sort_merge(_acc@1, [], _fun@1, _bool@1). sort_merge1([_h1@1|_t1@1], _h2@1, _t2@1, _m@1, _fun@1, _bool@1) -> case _fun@1(_h1@1, _h2@1) == _bool@1 of false -> sort_merge1(_t1@1, _h2@1, _t2@1, [_h1@1|_m@1], _fun@1, _bool@1); true -> sort_merge2(_h1@1, _t1@1, _t2@1, [_h2@1|_m@1], _fun@1, _bool@1) end; sort_merge1([], _h2@1, _t2@1, _m@1, __fun@1, __bool@1) -> lists:reverse(_t2@1, [_h2@1|_m@1]). sort_merge2(_h1@1, _t1@1, [_h2@1|_t2@1], _m@1, _fun@1, _bool@1) -> case _fun@1(_h1@1, _h2@1) == _bool@1 of false -> sort_merge1(_t1@1, _h2@1, _t2@1, [_h1@1|_m@1], _fun@1, _bool@1); true -> sort_merge2(_h1@1, _t1@1, _t2@1, [_h2@1|_m@1], _fun@1, _bool@1) end; sort_merge2(_h1@1, _t1@1, [], _m@1, __fun@1, __bool@1) -> lists:reverse(_t1@1, [_h1@1|_m@1]). sort_reducer(_entry@1, {split,_y@1,_x@1,_r@1,_rs@1,_bool@1}, _fun@1) -> case _fun@1(_y@1, _entry@1) == _bool@1 of true -> {split,_entry@1,_y@1,[_x@1|_r@1],_rs@1,_bool@1}; false -> case _fun@1(_x@1, _entry@1) == _bool@1 of true -> {split,_y@1,_entry@1,[_x@1|_r@1],_rs@1,_bool@1}; false -> case _r@1 == [] of true -> {split,_y@1,_x@1,[_entry@1],_rs@1,_bool@1}; false -> case true of true -> {pivot, _y@1, _x@1, _r@1, _rs@1, _entry@1, _bool@1}; false -> error(cond_clause) end end end end; sort_reducer(_entry@1, {pivot,_y@1,_x@1,_r@1,_rs@1,_s@1,_bool@1}, _fun@1) -> case _fun@1(_y@1, _entry@1) == _bool@1 of true -> {pivot,_entry@1,_y@1,[_x@1|_r@1],_rs@1,_s@1,_bool@1}; false -> case _fun@1(_x@1, _entry@1) == _bool@1 of true -> {pivot,_y@1,_entry@1,[_x@1|_r@1],_rs@1,_s@1,_bool@1}; false -> case _fun@1(_s@1, _entry@1) == _bool@1 of true -> {split, _entry@1, _s@1, [], [[_y@1,_x@1|_r@1]|_rs@1], _bool@1}; false -> case true of true -> {split, _s@1, _entry@1, [], [[_y@1,_x@1|_r@1]|_rs@1], _bool@1}; false -> error(cond_clause) end end end end; sort_reducer(_entry@1, [_x@1], _fun@1) -> {split,_entry@1,_x@1,[],[],_fun@1(_x@1, _entry@1)}; sort_reducer(_entry@1, _acc@1, __fun@1) -> [_entry@1|_acc@1]. sort_terminator({split,_y@1,_x@1,_r@1,_rs@1,_bool@1}, _fun@1) -> sort_merge([[_y@1,_x@1|_r@1]|_rs@1], _fun@1, _bool@1); sort_terminator({pivot,_y@1,_x@1,_r@1,_rs@1,_s@1,_bool@1}, _fun@1) -> sort_merge([[_s@1],[_y@1,_x@1|_r@1]|_rs@1], _fun@1, _bool@1); sort_terminator(_acc@1, __fun@1) -> _acc@1. split(_enumerable@1, _count@1) when is_list(_enumerable@1) andalso _count@1 >= 0 -> split_list(_enumerable@1, _count@1, []); split(_enumerable@1, _count@1) when _count@1 >= 0 -> {_,_list1@1,_list2@1} = reduce(_enumerable@1, {_count@1,[],[]}, fun(_entry@1, {_counter@1,_acc1@1,_acc2@1}) -> case _counter@1 > 0 of false -> {_counter@1,_acc1@1,[_entry@1|_acc2@1]}; true -> {_counter@1 - 1, [_entry@1|_acc1@1], _acc2@1} end end), {lists:reverse(_list1@1),lists:reverse(_list2@1)}; split(_enumerable@1, _count@1) when _count@1 < 0 -> split_reverse_list(reverse(_enumerable@1), - _count@1, []). split_list([_head@1|_tail@1], _counter@1, _acc@1) when _counter@1 > 0 -> split_list(_tail@1, _counter@1 - 1, [_head@1|_acc@1]); split_list(_list@1, 0, _acc@1) -> {lists:reverse(_acc@1),_list@1}; split_list([], _, _acc@1) -> {lists:reverse(_acc@1),[]}. split_reverse_list([_head@1|_tail@1], _counter@1, _acc@1) when _counter@1 > 0 -> split_reverse_list(_tail@1, _counter@1 - 1, [_head@1|_acc@1]); split_reverse_list(_list@1, 0, _acc@1) -> {lists:reverse(_list@1),_acc@1}; split_reverse_list([], _, _acc@1) -> {[],_acc@1}. split_while(_enumerable@1, _fun@1) when is_list(_enumerable@1) -> split_while_list(_enumerable@1, _fun@1, []); split_while(_enumerable@1, _fun@1) -> {_list1@1,_list2@1} = reduce(_enumerable@1, {[],[]}, fun(_entry@1, {_acc1@1,[]}) -> case _fun@1(_entry@1) of __@1 when __@1 =:= nil orelse __@1 =:= false -> {_acc1@1,[_entry@1]}; _ -> {[_entry@1|_acc1@1],[]} end; (_entry@2, {_acc1@2,_acc2@1}) -> {_acc1@2,[_entry@2|_acc2@1]} end), {lists:reverse(_list1@1),lists:reverse(_list2@1)}. split_while_list([_head@1|_tail@1], _fun@1, _acc@1) -> case _fun@1(_head@1) of __@1 when __@1 =:= nil orelse __@1 =:= false -> {lists:reverse(_acc@1),[_head@1|_tail@1]}; _ -> split_while_list(_tail@1, _fun@1, [_head@1|_acc@1]) end; split_while_list([], _, _acc@1) -> {lists:reverse(_acc@1),[]}. split_with(_enumerable@1, _fun@1) -> {_acc1@2,_acc2@2} = reduce(_enumerable@1, {[],[]}, fun(_entry@1, {_acc1@1,_acc2@1}) -> case _fun@1(_entry@1) of __@1 when __@1 =:= nil orelse __@1 =:= false -> {_acc1@1,[_entry@1|_acc2@1]}; _ -> {[_entry@1|_acc1@1],_acc2@1} end end), {lists:reverse(_acc1@2),lists:reverse(_acc2@2)}. sum(#{'__struct__' := 'Elixir.Range',first := _first@1,last := _last@1}) -> (_last@1 + _first@1) * (abs(_last@1 - _first@1) + 1) div 2; sum(_enumerable@1) -> reduce(_enumerable@1, 0, fun erlang:'+'/2). take(__enumerable@1, 0) -> []; take(_enumerable@1, _amount@1) when (is_list(_enumerable@1) andalso is_integer(_amount@1)) andalso _amount@1 > 0 -> take_list(_enumerable@1, _amount@1); take(_enumerable@1, _amount@1) when is_integer(_amount@1) andalso _amount@1 > 0 -> {_,{_res@1,_}} = 'Elixir.Enumerable':reduce(_enumerable@1, {cont,{[],_amount@1}}, fun(_entry@1, {_list@1,_n@1}) -> case _n@1 of 1 -> {halt, {[_entry@1|_list@1], _n@1 - 1}}; _ -> {cont, {[_entry@1|_list@1], _n@1 - 1}} end end), lists:reverse(_res@1); take(_enumerable@1, _amount@1) when is_integer(_amount@1) andalso _amount@1 < 0 -> {_count@1,_fun@1} = slice_count_and_fun(_enumerable@1), _first@1 = max(_amount@1 + _count@1, 0), _fun@1(_first@1, _count@1 - _first@1). take_every(_enumerable@1, 1) -> to_list(_enumerable@1); take_every(__enumerable@1, 0) -> []; take_every([], _nth@1) when is_integer(_nth@1) andalso _nth@1 > 1 -> []; take_every(_enumerable@1, _nth@1) when is_integer(_nth@1) andalso _nth@1 > 1 -> {_res@1,_} = reduce(_enumerable@1, {[],first}, fun(__@1, {__@2,__@3}) when __@3 =:= first orelse __@3 =:= _nth@1 -> {[__@1|__@2],1}; (__@4, {__@5,__@6}) -> {__@5,__@6 + 1} end), lists:reverse(_res@1). take_list([_head@1|_], 1) -> [_head@1]; take_list([_head@1|_tail@1], _counter@1) -> [_head@1|take_list(_tail@1, _counter@1 - 1)]; take_list([], __counter@1) -> []. take_random(__enumerable@1, 0) -> []; take_random(_enumerable@1, _count@1) when is_integer(_count@1) andalso _count@1 > 128 -> _reducer@1 = fun(_elem@1, {_idx@1,_sample@1}) -> _jdx@1 = random_integer(0, _idx@1), case _idx@1 < _count@1 of true -> _value@1 = 'Elixir.Map':get(_sample@1, _jdx@1), {_idx@1 + 1, _sample@1#{_idx@1 => _value@1,_jdx@1 => _elem@1}}; false -> case _jdx@1 < _count@1 of true -> {_idx@1 + 1, _sample@1#{_jdx@1 => _elem@1}}; false -> case true of true -> {_idx@1 + 1,_sample@1}; false -> error(cond_clause) end end end end, {_size@1,_sample@2} = reduce(_enumerable@1, {0,#{}}, _reducer@1), take_random(_sample@2, min(_count@1, _size@1), []); take_random(_enumerable@1, _count@1) when is_integer(_count@1) andalso _count@1 > 0 -> _sample@1 = erlang:make_tuple(_count@1, nil), _reducer@1 = fun(_elem@1, {_idx@1,_sample@2}) -> _jdx@1 = random_integer(0, _idx@1), case _idx@1 < _count@1 of true -> _value@1 = element(_jdx@1 + 1, _sample@2), {_idx@1 + 1, setelement(_jdx@1 + 1, setelement(_idx@1 + 1, _sample@2, _value@1), _elem@1)}; false -> case _jdx@1 < _count@1 of true -> {_idx@1 + 1, setelement(_jdx@1 + 1, _sample@2, _elem@1)}; false -> case true of true -> {_idx@1 + 1,_sample@2}; false -> error(cond_clause) end end end end, {_size@1,_sample@3} = reduce(_enumerable@1, {0,_sample@1}, _reducer@1), take(tuple_to_list(_sample@3), min(_count@1, _size@1)). take_random(__sample@1, 0, _acc@1) -> _acc@1; take_random(_sample@1, _position@1, _acc@1) -> _position@2 = _position@1 - 1, take_random(_sample@1, _position@2, ['Elixir.Map':get(_sample@1, _position@2)|_acc@1]). take_while(_enumerable@1, _fun@1) when is_list(_enumerable@1) -> take_while_list(_enumerable@1, _fun@1); take_while(_enumerable@1, _fun@1) -> {_,_res@1} = 'Elixir.Enumerable':reduce(_enumerable@1, {cont,[]}, fun(_entry@1, _acc@1) -> case _fun@1(_entry@1) of __@1 when __@1 =:= nil orelse __@1 =:= false -> {halt,_acc@1}; _ -> {cont, [_entry@1|_acc@1]} end end), lists:reverse(_res@1). take_while_list([_head@1|_tail@1], _fun@1) -> case _fun@1(_head@1) of __@1 when __@1 =:= nil orelse __@1 =:= false -> []; _ -> [_head@1|take_while_list(_tail@1, _fun@1)] end; take_while_list([], _) -> []. to_list(_enumerable@1) when is_list(_enumerable@1) -> _enumerable@1; to_list(#{'__struct__' := __@1 = _} = _enumerable@1) when is_atom(__@1) -> lists:reverse(reverse(_enumerable@1)); to_list(#{} = _enumerable@1) -> maps:to_list(_enumerable@1); to_list(_enumerable@1) -> lists:reverse(reverse(_enumerable@1)). uniq(_enumerable@1) -> uniq_by(_enumerable@1, fun(_x@1) -> _x@1 end). uniq(_enumerable@1, _fun@1) -> uniq_by(_enumerable@1, _fun@1). uniq_by(_enumerable@1, _fun@1) when is_list(_enumerable@1) -> uniq_list(_enumerable@1, #{}, _fun@1); uniq_by(_enumerable@1, _fun@1) -> {_list@1,_} = reduce(_enumerable@1, {[],#{}}, fun(__@1, {__@3,__@4} = __@2) -> __@5 = _fun@1(__@1), case maps:is_key(__@5, __@4) of __@6 when __@6 =:= nil orelse __@6 =:= false -> {[__@1|__@3],__@4#{__@5 => true}}; _ -> __@2 end end), lists:reverse(_list@1). uniq_list([_head@1|_tail@1], _set@1, _fun@1) -> _value@1 = _fun@1(_head@1), case _set@1 of #{_value@1 := true} -> uniq_list(_tail@1, _set@1, _fun@1); #{} -> [_head@1| uniq_list(_tail@1, _set@1#{_value@1 => true}, _fun@1)] end; uniq_list([], __set@1, __fun@1) -> []. unzip(_enumerable@1) -> {_list1@2,_list2@2} = reduce(_enumerable@1, {[],[]}, fun({_el1@1,_el2@1}, {_list1@1,_list2@1}) -> {[_el1@1|_list1@1],[_el2@1|_list2@1]} end), {lists:reverse(_list1@2),lists:reverse(_list2@2)}. with_index(__@1) -> with_index(__@1, 0). with_index(_enumerable@1, _offset@1) -> element(1, map_reduce(_enumerable@1, _offset@1, fun(_x@1, _acc@1) -> {{_x@1,_acc@1},_acc@1 + 1} end)). zip([]) -> []; zip(_enumerables@1) -> lists:reverse(element(2, ('Elixir.Stream':zip(_enumerables@1))({cont, []}, fun(__@1, __@2) -> {cont, [__@1| __@2]} end))). zip(_enumerable1@1, _enumerable2@1) when is_list(_enumerable1@1) andalso is_list(_enumerable2@1) -> zip_list(_enumerable1@1, _enumerable2@1); zip(_enumerable1@1, _enumerable2@1) -> zip([_enumerable1@1,_enumerable2@1]). zip_list([_h1@1|_next1@1], [_h2@1|_next2@1]) -> [{_h1@1,_h2@1}|zip_list(_next1@1, _next2@1)]; zip_list(_, []) -> []; zip_list([], _) -> []. ================================================ FILE: test_data/README.md ================================================ * basic_regress - Large amount of tiny snippets, checked for panics or errors, not valid output ================================================ FILE: test_data/application_controller.core ================================================ module 'application_controller' ['change_application_data'/2, 'code_change'/3, 'config_change'/1, 'control_application'/1, 'do_config_diff'/2, 'get_all_env'/1, 'get_all_key'/1, 'get_application'/1, 'get_application_module'/1, 'get_env'/2, 'get_key'/2, 'get_loaded'/1, 'get_master'/1, 'get_pid_all_env'/1, 'get_pid_all_key'/1, 'get_pid_env'/2, 'get_pid_key'/2, 'handle_call'/3, 'handle_cast'/2, 'handle_info'/2, 'info'/0, 'init_starter'/4, 'load_application'/1, 'loaded_applications'/0, 'module_info'/0, 'module_info'/1, 'permit_application'/2, 'prep_config_change'/0, 'set_env'/3, 'set_env'/4, 'start'/1, 'start_application'/2, 'start_boot_application'/2, 'start_type'/1, 'stop_application'/1, 'terminate'/2, 'test_change_apps'/2, 'unload_application'/1, 'unset_env'/2, 'unset_env'/3, 'which_applications'/0, 'which_applications'/1] attributes [%% Line 1 'file' = %% Line 1 [{[97|[112|[112|[108|[105|[99|[97|[116|[105|[111|[110|[95|[99|[111|[110|[116|[114|[111|[108|[108|[101|[114|[46|[101|[114|[108]]]]]]]]]]]]]]]]]]]]]]]]]],1}], %% Line 1 'file' = %% Line 1 [{[97|[112|[112|[108|[105|[99|[97|[116|[105|[111|[110|[95|[109|[97|[115|[116|[101|[114|[46|[104|[114|[108]]]]]]]]]]]]]]]]]]]]]],1}], %% Line 20 'record' = %% Line 20 [{'appl_data',[{'record_field',20,{'atom',20,'name'}}|[{'record_field',20,{'atom',20,'regs'},{'nil',20}}|[{'record_field',20,{'atom',20,'phases'}}|[{'record_field',20,{'atom',20,'mod'}}|[{'record_field',20,{'atom',20,'mods'},{'nil',20}}|[{'record_field',21,{'atom',21,'inc_apps'}}|[{'record_field',21,{'atom',21,'maxP'},{'atom',21,'infinity'}}|[{'record_field',21,{'atom',21,'maxT'},{'atom',21,'infinity'}}]]]]]]]]}], %% Line 47 'file' = %% Line 47 [{[97|[112|[112|[108|[105|[99|[97|[116|[105|[111|[110|[95|[99|[111|[110|[116|[114|[111|[108|[108|[101|[114|[46|[101|[114|[108]]]]]]]]]]]]]]]]]]]]]]]]]],47}], %% Line 1 'file' = %% Line 1 [{[47|[104|[111|[109|[101|[47|[104|[97|[110|[115|[105|[104|[101|[47|[103|[105|[116|[47|[99|[111|[114|[101|[95|[101|[114|[108|[97|[110|[103|[47|[111|[116|[112|[47|[108|[105|[98|[47|[107|[101|[114|[110|[101|[108|[47|[115|[114|[99|[47|[46|[46|[47|[105|[110|[99|[108|[117|[100|[101|[47|[108|[111|[103|[103|[101|[114|[46|[104|[114|[108]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]],1}], %% Line 48 'file' = %% Line 48 [{[97|[112|[112|[108|[105|[99|[97|[116|[105|[111|[110|[95|[99|[111|[110|[116|[114|[111|[108|[108|[101|[114|[46|[101|[114|[108]]]]]]]]]]]]]]]]]]]]]]]]]],48}], %% Line 134 'type' = %% Line 134 [{'appname',{'type',134,'atom',[]},[]}], %% Line 136 'record' = %% Line 136 [{'state',[{'record_field',136,{'atom',136,'loading'},{'nil',136}}|[{'record_field',136,{'atom',136,'starting'},{'nil',136}}|[{'record_field',136,{'atom',136,'start_p_false'},{'nil',136}}|[{'record_field',136,{'atom',136,'running'},{'nil',136}}|[{'record_field',137,{'atom',137,'control'},{'nil',137}}|[{'record_field',137,{'atom',137,'started'},{'nil',137}}|[{'record_field',137,{'atom',137,'start_req'},{'nil',137}}|[{'record_field',137,{'atom',137,'conf_data'}}]]]]]]]]}], %% Line 138 'type' = %% Line 138 [{'state',{'type',138,'record',[{'atom',138,'state'}]},[]}], %% Line 158 'record' = %% Line 158 [{'appl',[{'record_field',158,{'atom',158,'name'}}|[{'record_field',158,{'atom',158,'appl_data'}}|[{'record_field',158,{'atom',158,'descr'}}|[{'record_field',158,{'atom',158,'id'}}|[{'record_field',158,{'atom',158,'vsn'}}|[{'record_field',158,{'atom',158,'restart_type'}}|[{'record_field',158,{'atom',158,'inc_apps'}}|[{'record_field',158,{'atom',158,'apps'}}]]]]]]]]}], %% Line 610 'type' = %% Line 610 [{'calls',{'type',610,'union',[{'atom',610,'info'}|[{'atom',610,'prep_config_change'}|[{'atom',610,'which_applications'}|[{'type',611,'tuple',[{'type',611,'union',[{'atom',611,'config_change'}|[{'atom',611,'control_application'}|[{'atom',612,'load_application'}|[{'atom',612,'start_type'}|[{'atom',612,'stop_application'}|[{'atom',613,'unload_application'}]]]]]]}|[{'type',613,'term',[]}]]}|[{'type',614,'tuple',[{'atom',614,'change_application_data'}|[{'var',614,'_'}|[{'var',614,'_'}]]]}|[{'type',615,'tuple',[{'atom',615,'permit_application'}|[{'type',615,'union',[{'type',615,'atom',[]}|[{'type',615,'tuple',[{'atom',615,'application'}|[{'type',615,'atom',[]}|[{'var',615,'_'}]]]}]]}|[{'var',615,'_'}]]]}|[{'type',616,'tuple',[{'atom',616,'start_application'}|[{'var',616,'_'}|[{'var',616,'_'}]]]}|[{'type',617,'tuple',[{'atom',617,'unset_env'}|[{'var',617,'_'}|[{'var',617,'_'}|[{'var',617,'_'}]]]]}|[{'type',618,'tuple',[{'atom',618,'set_env'}|[{'var',618,'_'}|[{'var',618,'_'}|[{'var',618,'_'}|[{'var',618,'_'}]]]]]}]]]]]]]]]},[]}], %% Line 620 'spec' = %% Line 620 [{{'handle_call',3},[{'type',620,'fun',[{'type',620,'product',[{'user_type',620,'calls',[]}|[{'type',620,'tuple',[{'type',620,'pid',[]}|[{'type',620,'term',[]}]]}|[{'user_type',620,'state',[]}]]]}|[{'type',621,'union',[{'type',621,'tuple',[{'atom',621,'noreply'}|[{'user_type',621,'state',[]}]]}|[{'type',621,'tuple',[{'atom',621,'reply'}|[{'type',621,'term',[]}|[{'user_type',621,'state',[]}]]]}]]}]]}]}], %% Line 915 'spec' = %% Line 915 [{{'handle_cast',2},[{'type',915,'fun',[{'type',915,'product',[{'type',915,'tuple',[{'atom',915,'application_started'}|[{'user_type',915,'appname',[]}|[{'var',915,'_'}]]]}|[{'user_type',915,'state',[]}]]}|[{'type',916,'union',[{'type',916,'tuple',[{'atom',916,'noreply'}|[{'user_type',916,'state',[]}]]}|[{'type',916,'tuple',[{'atom',916,'stop'}|[{'type',916,'string',[]}|[{'user_type',916,'state',[]}]]]}]]}]]}]}], %% Line 1005 'spec' = %% Line 1005 [{{'handle_info',2},[{'type',1005,'fun',[{'type',1005,'product',[{'type',1005,'term',[]}|[{'user_type',1005,'state',[]}]]}|[{'type',1006,'union',[{'type',1006,'tuple',[{'atom',1006,'noreply'}|[{'user_type',1006,'state',[]}]]}|[{'type',1006,'tuple',[{'atom',1006,'stop'}|[{'type',1006,'string',[]}|[{'user_type',1006,'state',[]}]]]}]]}]]}]}], %% Line 1182 'spec' = %% Line 1182 [{{'terminate',2},[{'type',1182,'fun',[{'type',1182,'product',[{'type',1182,'term',[]}|[{'user_type',1182,'state',[]}]]}|[{'atom',1182,'ok'}]]}]}], %% Line 1219 'spec' = %% Line 1219 [{{'code_change',3},[{'type',1219,'fun',[{'type',1219,'product',[{'type',1219,'term',[]}|[{'user_type',1219,'state',[]}|[{'type',1219,'term',[]}]]]}|[{'type',1219,'tuple',[{'atom',1219,'ok'}|[{'user_type',1219,'state',[]}]]}]]}]}], %% Line 2021 'spec' = %% Line 2021 [{{'to_string',1},[{'type',2021,'fun',[{'type',2021,'product',[{'type',2021,'term',[]}]}|[{'type',2021,'string',[]}]]}]}]] 'start'/1 = %% Line 186 fun (_0) -> let = call %% Line 189 'erlang':%% Line 189 'self' () in let <_2> = fun () -> %% Line 190 apply 'init'/2 (Init, _0) in let = call %% Line 190 'erlang':%% Line 190 'spawn_link' (_2) in %% Line 191 receive %% Line 192 <{'ack',_5,'ok'}> when call 'erlang':'=:=' (_5, AC) -> %% Line 193 {'ok',AC} %% Line 194 <{'ack',_6,{'error',Reason}}> when call 'erlang':'=:=' (_6, AC) -> %% Line 195 apply 'to_string'/1 (Reason) %% Line 196 <{'EXIT',_X_Pid,Reason}> when 'true' -> %% Line 197 apply 'to_string'/1 (Reason) after 'infinity' -> 'true' 'load_application'/1 = %% Line 207 fun (_0) -> %% Line 208 call 'gen_server':'call' ('application_controller', {'load_application',_0}, 'infinity') 'unload_application'/1 = %% Line 210 fun (_0) -> %% Line 211 call 'gen_server':'call' ('application_controller', {'unload_application',_0}, 'infinity') 'start_application'/2 = %% Line 234 fun (_1,_0) -> %% Line 235 call 'gen_server':'call' ('application_controller', {'start_application',_1,_0}, 'infinity') 'start_boot_application'/2 = %% Line 244 fun (_1,_0) -> let <_2> = call %% Line 245 'application':%% Line 245 'load' (_1) in %% Line 245 case <_2,_0> of %% Line 246 <( 'ok' -| ['compiler_generated'] ),_10> when 'true' -> let = apply %% Line 247 'get_appl_name'/1 (_1) in %% Line 248 call 'gen_server':'call' ('application_controller', {'start_application',AppName,_0}, 'infinity') %% Line 249 <( {( 'error' -| ['compiler_generated'] ),( {( 'already_loaded' -| ['compiler_generated'] ),AppName} -| ['compiler_generated'] )} -| ['compiler_generated'] ),_11> when 'true' -> %% Line 250 call 'gen_server':'call' ('application_controller', {'start_application',AppName,_0}, 'infinity') %% Line 251 <( {( 'error' -| ['compiler_generated'] ),( {( 'bad_environment_value' -| ['compiler_generated'] ),Env} -| ['compiler_generated'] )} -| ['compiler_generated'] ),( 'permanent' -| ['compiler_generated'] )> when 'true' -> let = call %% Line 252 'io_lib':%% Line 252 'format' (%% Line 252 [66|[97|[100|[32|[101|[110|[118|[105|[114|[111|[110|[109|[101|[110|[116|[32|[118|[97|[114|[105|[97|[98|[108|[101|[58|[32|[126|[116|[112|[32|[32|[65|[112|[112|[108|[105|[99|[97|[116|[105|[111|[110|[58|[32|[126|[112]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]], %% Line 253 [Env|[_1|[]]]) in let <_5> = call %% Line 254 'lists':%% Line 254 'flatten' (%% Line 254 Txt) in let <_6> = call %% Line 254 'erlang':%% Line 254 'list_to_atom' (_5) in %% Line 254 call 'erlang':'exit' ({'error',_6}) %% Line 255 when 'true' -> %% Line 256 Error end 'stop_application'/1 = %% Line 259 fun (_0) -> %% Line 260 call 'gen_server':'call' ('application_controller', {'stop_application',_0}, 'infinity') 'which_applications'/0 = %% Line 265 fun () -> %% Line 266 call 'gen_server':'call' ('application_controller', 'which_applications') 'which_applications'/1 = %% Line 267 fun (_0) -> %% Line 268 call 'gen_server':'call' ('application_controller', 'which_applications', _0) 'loaded_applications'/0 = %% Line 270 fun () -> let <_2> = fun (_0) -> %% Line 272 case _0 of <[{{'loaded',AppName},{'appl',_3,_4,Descr,_5,Vsn,_6,_7,_8}}|[]]> when 'true' -> %% Line 273 {'true',{AppName,Descr,Vsn}} %% Line 274 <_9> when 'true' -> %% Line 275 'false' end in %% Line 271 call 'ets':'filter' ('ac_tab', _2, %% Line 277 []) 'info'/0 = %% Line 280 fun () -> %% Line 281 call 'gen_server':'call' ('application_controller', 'info') 'control_application'/1 = %% Line 283 fun (_0) -> %% Line 284 call 'gen_server':'call' ('application_controller', {'control_application',_0}, 'infinity') 'change_application_data'/2 = %% Line 308 fun (_1,_0) -> %% Line 309 call 'gen_server':'call' ('application_controller', %% Line 310 {'change_application_data',_1,_0}, %% Line 311 'infinity') 'prep_config_change'/0 = %% Line 313 fun () -> %% Line 314 call 'gen_server':'call' ('application_controller', %% Line 315 'prep_config_change', %% Line 316 'infinity') 'config_change'/1 = %% Line 319 fun (_0) -> %% Line 320 call 'gen_server':'call' ('application_controller', %% Line 321 {'config_change',_0}, %% Line 322 'infinity') 'get_pid_env'/2 = %% Line 326 fun (_1,_0) -> %% Line 327 case call 'ets':'match' ('ac_tab', {{'application_master','$1'},_1}) of %% Line 328 <[[AppName|[]]|[]]> when 'true' -> apply 'get_env'/2 (AppName, _0) %% Line 329 <_5> when 'true' -> 'undefined' end 'get_env'/2 = %% Line 332 fun (_1,_0) -> %% Line 333 case call 'ets':'lookup' ('ac_tab', {'env',_1,_0}) of %% Line 334 <[{_5,Val}|[]]> when 'true' -> {'ok',Val} %% Line 335 <_6> when 'true' -> 'undefined' end 'get_pid_all_env'/1 = %% Line 338 fun (_0) -> %% Line 339 case call 'ets':'match' ('ac_tab', {{'application_master','$1'},_0}) of %% Line 340 <[[AppName|[]]|[]]> when 'true' -> apply 'get_all_env'/1 (AppName) %% Line 341 <_3> when 'true' -> [] end 'get_all_env'/1 = %% Line 344 fun (_0) -> let <_4> = fun (_2) -> %% Line 345 case _2 of <[Key|[Val|[]]]> when 'true' -> {Key,Val} ( <_3> when 'true' -> ( primop 'match_fail' ({'function_clause',_3}) -| [{'function_name',{'-get_all_env/1-fun-0-',1}}] ) -| ['compiler_generated'] ) end in let <_1> = call %% Line 346 'ets':%% Line 346 'match' (%% Line 346 'ac_tab', %% Line 346 {{'env',_0,'$1'},'$2'}) in %% Line 345 call 'lists':'map' (_4, _1) 'get_pid_key'/2 = %% Line 351 fun (_1,_0) -> %% Line 352 case call 'ets':'match' ('ac_tab', {{'application_master','$1'},_1}) of %% Line 353 <[[AppName|[]]|[]]> when 'true' -> apply 'get_key'/2 (AppName, _0) %% Line 354 <_5> when 'true' -> 'undefined' end 'get_key'/2 = %% Line 357 fun (_1,_0) -> %% Line 358 case call 'ets':'lookup' ('ac_tab', {'loaded',_1}) of %% Line 359 <[{_41,Appl}|[]]> when 'true' -> %% Line 360 case _0 of %% Line 361 <'description'> when 'true' -> %% Line 362 ( case Appl of ( <( {'appl',_42,_43,_rec0,_44,_45,_46,_47,_48} -| ['compiler_generated'] )> when 'true' -> {'ok',_rec0} -| ['compiler_generated'] ) ( <_49> when 'true' -> ( call ( 'erlang' -| ['compiler_generated'] ):( 'error' -| ['compiler_generated'] ) (( {'badrecord','appl'} -| ['compiler_generated'] )) -| ['compiler_generated'] ) -| ['compiler_generated'] ) end -| ['compiler_generated'] ) %% Line 363 <'id'> when 'true' -> %% Line 364 ( case Appl of ( <( {'appl',_50,_51,_52,_rec1,_53,_54,_55,_56} -| ['compiler_generated'] )> when 'true' -> {'ok',_rec1} -| ['compiler_generated'] ) ( <_57> when 'true' -> ( call ( 'erlang' -| ['compiler_generated'] ):( 'error' -| ['compiler_generated'] ) (( {'badrecord','appl'} -| ['compiler_generated'] )) -| ['compiler_generated'] ) -| ['compiler_generated'] ) end -| ['compiler_generated'] ) %% Line 365 <'vsn'> when 'true' -> %% Line 366 ( case Appl of ( <( {'appl',_58,_59,_60,_61,_rec2,_62,_63,_64} -| ['compiler_generated'] )> when 'true' -> {'ok',_rec2} -| ['compiler_generated'] ) ( <_65> when 'true' -> ( call ( 'erlang' -| ['compiler_generated'] ):( 'error' -| ['compiler_generated'] ) (( {'badrecord','appl'} -| ['compiler_generated'] )) -| ['compiler_generated'] ) -| ['compiler_generated'] ) end -| ['compiler_generated'] ) %% Line 367 <'modules'> when 'true' -> %% Line 368 ( case Appl of ( <( {'appl',_66,_rec4,_67,_68,_69,_70,_71,_72} -| ['compiler_generated'] )> when 'true' -> ( case _rec4 of ( <( {'appl_data',_74,_75,_76,_77,_rec3,_78,_79,_80} -| ['compiler_generated'] )> when 'true' -> {'ok',_rec3} -| ['compiler_generated'] ) ( <_81> when 'true' -> ( call ( 'erlang' -| ['compiler_generated'] ):( 'error' -| ['compiler_generated'] ) (( {'badrecord','appl_data'} -| ['compiler_generated'] )) -| ['compiler_generated'] ) -| ['compiler_generated'] ) end -| ['compiler_generated'] ) -| ['compiler_generated'] ) ( <_73> when 'true' -> ( call ( 'erlang' -| ['compiler_generated'] ):( 'error' -| ['compiler_generated'] ) (( {'badrecord','appl'} -| ['compiler_generated'] )) -| ['compiler_generated'] ) -| ['compiler_generated'] ) end -| ['compiler_generated'] ) %% Line 369 <'maxP'> when 'true' -> %% Line 370 ( case Appl of ( <( {'appl',_82,_rec6,_83,_84,_85,_86,_87,_88} -| ['compiler_generated'] )> when 'true' -> ( case _rec6 of ( <( {'appl_data',_90,_91,_92,_93,_94,_95,_rec5,_96} -| ['compiler_generated'] )> when 'true' -> {'ok',_rec5} -| ['compiler_generated'] ) ( <_97> when 'true' -> ( call ( 'erlang' -| ['compiler_generated'] ):( 'error' -| ['compiler_generated'] ) (( {'badrecord','appl_data'} -| ['compiler_generated'] )) -| ['compiler_generated'] ) -| ['compiler_generated'] ) end -| ['compiler_generated'] ) -| ['compiler_generated'] ) ( <_89> when 'true' -> ( call ( 'erlang' -| ['compiler_generated'] ):( 'error' -| ['compiler_generated'] ) (( {'badrecord','appl'} -| ['compiler_generated'] )) -| ['compiler_generated'] ) -| ['compiler_generated'] ) end -| ['compiler_generated'] ) %% Line 371 <'maxT'> when 'true' -> %% Line 372 ( case Appl of ( <( {'appl',_98,_rec8,_99,_100,_101,_102,_103,_104} -| ['compiler_generated'] )> when 'true' -> ( case _rec8 of ( <( {'appl_data',_106,_107,_108,_109,_110,_111,_112,_rec7} -| ['compiler_generated'] )> when 'true' -> {'ok',_rec7} -| ['compiler_generated'] ) ( <_113> when 'true' -> ( call ( 'erlang' -| ['compiler_generated'] ):( 'error' -| ['compiler_generated'] ) (( {'badrecord','appl_data'} -| ['compiler_generated'] )) -| ['compiler_generated'] ) -| ['compiler_generated'] ) end -| ['compiler_generated'] ) -| ['compiler_generated'] ) ( <_105> when 'true' -> ( call ( 'erlang' -| ['compiler_generated'] ):( 'error' -| ['compiler_generated'] ) (( {'badrecord','appl'} -| ['compiler_generated'] )) -| ['compiler_generated'] ) -| ['compiler_generated'] ) end -| ['compiler_generated'] ) %% Line 373 <'registered'> when 'true' -> %% Line 374 ( case Appl of ( <( {'appl',_114,_rec10,_115,_116,_117,_118,_119,_120} -| ['compiler_generated'] )> when 'true' -> ( case _rec10 of ( <( {'appl_data',_122,_rec9,_123,_124,_125,_126,_127,_128} -| ['compiler_generated'] )> when 'true' -> {'ok',_rec9} -| ['compiler_generated'] ) ( <_129> when 'true' -> ( call ( 'erlang' -| ['compiler_generated'] ):( 'error' -| ['compiler_generated'] ) (( {'badrecord','appl_data'} -| ['compiler_generated'] )) -| ['compiler_generated'] ) -| ['compiler_generated'] ) end -| ['compiler_generated'] ) -| ['compiler_generated'] ) ( <_121> when 'true' -> ( call ( 'erlang' -| ['compiler_generated'] ):( 'error' -| ['compiler_generated'] ) (( {'badrecord','appl'} -| ['compiler_generated'] )) -| ['compiler_generated'] ) -| ['compiler_generated'] ) end -| ['compiler_generated'] ) %% Line 375 <'included_applications'> when 'true' -> %% Line 376 ( case Appl of ( <( {'appl',_130,_131,_132,_133,_134,_135,_rec11,_136} -| ['compiler_generated'] )> when 'true' -> {'ok',_rec11} -| ['compiler_generated'] ) ( <_137> when 'true' -> ( call ( 'erlang' -| ['compiler_generated'] ):( 'error' -| ['compiler_generated'] ) (( {'badrecord','appl'} -| ['compiler_generated'] )) -| ['compiler_generated'] ) -| ['compiler_generated'] ) end -| ['compiler_generated'] ) %% Line 377 <'applications'> when 'true' -> %% Line 378 ( case Appl of ( <( {'appl',_138,_139,_140,_141,_142,_143,_144,_rec12} -| ['compiler_generated'] )> when 'true' -> {'ok',_rec12} -| ['compiler_generated'] ) ( <_145> when 'true' -> ( call ( 'erlang' -| ['compiler_generated'] ):( 'error' -| ['compiler_generated'] ) (( {'badrecord','appl'} -| ['compiler_generated'] )) -| ['compiler_generated'] ) -| ['compiler_generated'] ) end -| ['compiler_generated'] ) %% Line 379 <'env'> when 'true' -> let <_28> = apply %% Line 380 'get_all_env'/1 (_1) in %% Line 380 {'ok',_28} %% Line 381 <'mod'> when 'true' -> %% Line 382 ( case Appl of ( <( {'appl',_146,_rec14,_147,_148,_149,_150,_151,_152} -| ['compiler_generated'] )> when 'true' -> ( case _rec14 of ( <( {'appl_data',_154,_155,_156,_rec13,_157,_158,_159,_160} -| ['compiler_generated'] )> when 'true' -> {'ok',_rec13} -| ['compiler_generated'] ) ( <_161> when 'true' -> ( call ( 'erlang' -| ['compiler_generated'] ):( 'error' -| ['compiler_generated'] ) (( {'badrecord','appl_data'} -| ['compiler_generated'] )) -| ['compiler_generated'] ) -| ['compiler_generated'] ) end -| ['compiler_generated'] ) -| ['compiler_generated'] ) ( <_153> when 'true' -> ( call ( 'erlang' -| ['compiler_generated'] ):( 'error' -| ['compiler_generated'] ) (( {'badrecord','appl'} -| ['compiler_generated'] )) -| ['compiler_generated'] ) -| ['compiler_generated'] ) end -| ['compiler_generated'] ) %% Line 383 <'start_phases'> when 'true' -> %% Line 384 ( case Appl of ( <( {'appl',_162,_rec16,_163,_164,_165,_166,_167,_168} -| ['compiler_generated'] )> when 'true' -> ( case _rec16 of ( <( {'appl_data',_170,_171,_rec15,_172,_173,_174,_175,_176} -| ['compiler_generated'] )> when 'true' -> {'ok',_rec15} -| ['compiler_generated'] ) ( <_177> when 'true' -> ( call ( 'erlang' -| ['compiler_generated'] ):( 'error' -| ['compiler_generated'] ) (( {'badrecord','appl_data'} -| ['compiler_generated'] )) -| ['compiler_generated'] ) -| ['compiler_generated'] ) end -| ['compiler_generated'] ) -| ['compiler_generated'] ) ( <_169> when 'true' -> ( call ( 'erlang' -| ['compiler_generated'] ):( 'error' -| ['compiler_generated'] ) (( {'badrecord','appl'} -| ['compiler_generated'] )) -| ['compiler_generated'] ) -| ['compiler_generated'] ) end -| ['compiler_generated'] ) %% Line 385 <_178> when 'true' -> 'undefined' end %% Line 387 <_179> when 'true' -> %% Line 388 'undefined' end 'get_pid_all_key'/1 = %% Line 391 fun (_0) -> %% Line 392 case call 'ets':'match' ('ac_tab', {{'application_master','$1'},_0}) of %% Line 393 <[[AppName|[]]|[]]> when 'true' -> apply 'get_all_key'/1 (AppName) %% Line 394 <_3> when 'true' -> [] end 'get_all_key'/1 = %% Line 397 fun (_0) -> %% Line 398 case call 'ets':'lookup' ('ac_tab', {'loaded',_0}) of %% Line 399 <[{_38,Appl}|[]]> when 'true' -> %% Line 400 ( case Appl of ( <( {'appl',_39,_40,_rec17,_41,_42,_43,_44,_45} -| ['compiler_generated'] )> when 'true' -> %% Line 403 ( case _40 of ( <( {'appl_data',_71,_72,_73,_74,_rec20,_75,_76,_77} -| ['compiler_generated'] )> when 'true' -> let <_27> = apply %% Line 409 'get_all_env'/1 (_0) in {'ok',[{'description',_rec17}|[{'id',_41}|[{'vsn',_42}|[{'modules',_rec20}|%% Line 404 [{'maxP',_76}|%% Line 405 [{'maxT',_77}|%% Line 406 [{'registered',_72}|%% Line 407 [{'included_applications',_44}|%% Line 408 [{'applications',_45}|%% Line 409 [{'env',_27}|%% Line 410 [{'mod',_74}|%% Line 411 [{'start_phases',_73}|%% Line 412 []]]]]]]]]]]]]} -| ['compiler_generated'] ) ( <_78> when 'true' -> ( call ( 'erlang' -| ['compiler_generated'] ):( 'error' -| ['compiler_generated'] ) (( {'badrecord','appl_data'} -| ['compiler_generated'] )) -| ['compiler_generated'] ) -| ['compiler_generated'] ) end -| ['compiler_generated'] ) -| ['compiler_generated'] ) ( <_46> when 'true' -> ( call ( 'erlang' -| ['compiler_generated'] ):( 'error' -| ['compiler_generated'] ) (( {'badrecord','appl'} -| ['compiler_generated'] )) -| ['compiler_generated'] ) -| ['compiler_generated'] ) end -| ['compiler_generated'] ) %% Line 413 <_175> when 'true' -> %% Line 414 'undefined' end 'start_type'/1 = %% Line 418 fun (_0) -> %% Line 419 case call 'ets':'match' ('ac_tab', {{'application_master','$1'},_0}) of %% Line 420 <[[AppName|[]]|[]]> when 'true' -> %% Line 421 call 'gen_server':'call' ('application_controller', {'start_type',AppName}, 'infinity') %% Line 422 <_X_X> when 'true' -> %% Line 423 'undefined' end 'get_master'/1 = %% Line 431 fun (_0) -> %% Line 432 case call 'ets':'lookup' ('ac_tab', {'application_master',_0}) of %% Line 433 <[{_3,Pid}|[]]> when 'true' -> Pid %% Line 434 <_4> when 'true' -> 'undefined' end 'get_application'/1 = %% Line 437 fun (_0) -> %% Line 438 case call 'ets':'match' ('ac_tab', {{'application_master','$1'},_0}) of %% Line 439 <[[AppName|[]]|[]]> when 'true' -> {'ok',AppName} %% Line 440 <_3> when 'true' -> 'undefined' end 'get_application_module'/1 = %% Line 443 fun (_0) -> let = call %% Line 446 'ets':%% Line 446 'match' (%% Line 446 'ac_tab', %% Line 446 {{'loaded','$1'},{'appl','_',{'appl_data','_','_','_','_','$2','_','_','_'},'_','_','_','_','_','_'}}) in %% Line 447 apply 'get_application_module'/2 (_0, AppModules) 'get_application_module'/2 = %% Line 449 fun (_1,_0) -> case <_1,_0> of when 'true' -> %% Line 450 case call 'lists':'member' (Module, Modules) of %% Line 451 <'true'> when 'true' -> %% Line 452 {'ok',AppName} %% Line 453 <'false'> when 'true' -> %% Line 454 apply 'get_application_module'/2 (Module, AppModules) ( <_2> when 'true' -> primop 'match_fail' ({'case_clause',_2}) -| ['compiler_generated'] ) end %% Line 456 <_X_Module,[]> when 'true' -> %% Line 457 'undefined' ( <_4,_3> when 'true' -> ( primop 'match_fail' ({'function_clause',_4,_3}) -| [{'function_name',{'get_application_module',2}}] ) -| ['compiler_generated'] ) end 'permit_application'/2 = %% Line 459 fun (_1,_0) -> %% Line 460 call 'gen_server':'call' ('application_controller', %% Line 461 {'permit_application',_1,_0}, %% Line 462 'infinity') 'set_env'/3 = %% Line 465 fun (_2,_1,_0) -> %% Line 466 call 'gen_server':'call' ('application_controller', {'set_env',_2,_1,_0,[]}) 'set_env'/4 = %% Line 467 fun (_3,_2,_1,_0) -> let = call %% Line 468 'proplists':%% Line 468 'get_value' (%% Line 468 'timeout', _0, %% Line 468 5000) in %% Line 469 call 'gen_server':'call' ('application_controller', {'set_env',_3,_2,_1,_0}, Timeout) 'unset_env'/2 = %% Line 471 fun (_1,_0) -> %% Line 472 call 'gen_server':'call' ('application_controller', {'unset_env',_1,_0,[]}) 'unset_env'/3 = %% Line 473 fun (_2,_1,_0) -> let = call %% Line 474 'proplists':%% Line 474 'get_value' (%% Line 474 'timeout', _0, %% Line 474 5000) in %% Line 475 call 'gen_server':'call' ('application_controller', {'unset_env',_2,_1,_0}, Timeout) 'init'/2 = %% Line 480 fun (_1,_0) -> let <_2> = call %% Line 481 'erlang':%% Line 481 'self' () in do %% Line 481 call 'erlang':'register' ('application_controller', _2) do %% Line 482 call 'erlang':'process_flag' ('trap_exit', 'true') do %% Line 483 call 'erlang':'put' ('$ancestors', [_1|[]]) do %% Line 484 call 'erlang':'put' ('$initial_call', {'application_controller','start',1}) let <_3> = catch %% Line 486 apply 'check_conf'/0 () in %% Line 486 case _3 of %% Line 487 <{'ok',ConfData}> when 'true' -> %% Line 493 case apply 'check_conf_data'/1 (ConfData) of %% Line 494 <'ok'> when 'true' -> do %% Line 495 ( call ( 'ets' -| ['result_not_wanted'] ):( 'new' -| ['result_not_wanted'] ) (( 'ac_tab' -| ['result_not_wanted'] ), ( ['set'|['public'|['named_table'|[{'read_concurrency','true'}]]]] -| ['result_not_wanted'] )) -| ['result_not_wanted'] ) let = {%% Line 497 'state',[],[],[],[],[],[],[],%% Line 497 ConfData} in %% Line 498 case apply 'make_appl'/1 (_0) of <{'ok',KAppl}> when 'true' -> let <_7> = catch %% Line 499 apply 'load'/2 (S, KAppl) in %% Line 499 case _7 of %% Line 500 <{'EXIT',LoadError}> when 'true' -> let = {%% Line 501 'load error',%% Line 501 LoadError} in let <_10> = call %% Line 502 'erlang':%% Line 502 'self' () in let <_9> = apply %% Line 502 'to_string'/1 (%% Line 502 Reason) in %% Line 502 call 'erlang':'!' (_1, {'ack',_10,{'error',_9}}) %% Line 503 <{'error',Error}> when 'true' -> let <_12> = call %% Line 504 'erlang':%% Line 504 'self' () in let <_11> = apply %% Line 504 'to_string'/1 (%% Line 504 Error) in %% Line 504 call 'erlang':'!' (_1, {'ack',_12,{'error',_11}}) %% Line 505 <{'ok',NewS}> when 'true' -> let <_13> = call %% Line 506 'erlang':%% Line 506 'self' () in do %% Line 506 call 'erlang':'!' (_1, {'ack',_13,'ok'}) %% Line 507 call 'gen_server':'enter_loop' ('application_controller', [], NewS, %% Line 508 {'local','application_controller'}) ( <_14> when 'true' -> primop 'match_fail' ({'case_clause',_14}) -| ['compiler_generated'] ) end ( <_6> when 'true' -> primop 'match_fail' ({'badmatch',_6}) -| ['compiler_generated'] ) end %% Line 510 <{'error',ErrorStr}> when 'true' -> let <_15> = call %% Line 511 'io_lib':%% Line 511 'format' (%% Line 511 [105|[110|[118|[97|[108|[105|[100|[32|[99|[111|[110|[102|[105|[103|[32|[100|[97|[116|[97|[58|[32|[126|[116|[115]]]]]]]]]]]]]]]]]]]]]]]], %% Line 511 [ErrorStr|[]]) in let = call %% Line 511 'lists':%% Line 511 'flatten' (_15) in let <_18> = call %% Line 512 'erlang':%% Line 512 'self' () in let <_17> = apply %% Line 512 'to_string'/1 (%% Line 512 Str) in %% Line 512 call 'erlang':'!' (_1, {'ack',_18,{'error',_17}}) ( <_19> when 'true' -> primop 'match_fail' ({'case_clause',_19}) -| ['compiler_generated'] ) end %% Line 514 <{'error',{File,Line,Str}}> when 'true' -> let <_20> = call %% Line 516 'io_lib':%% Line 516 'format' (%% Line 516 [101|[114|[114|[111|[114|[32|[105|[110|[32|[99|[111|[110|[102|[105|[103|[32|[102|[105|[108|[101|[32|[126|[116|[112|[32|[40|[126|[119|[41|[58|[32|[126|[116|[115]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]], %% Line 518 [File|[Line|[Str|[]]]]) in let = call %% Line 516 'lists':%% Line 516 'flatten' (_20) in let <_23> = call %% Line 519 'erlang':%% Line 519 'self' () in let <_22> = apply %% Line 519 'to_string'/1 (%% Line 519 ReasonStr) in %% Line 519 call 'erlang':'!' (_1, {'ack',_23,{'error',_22}}) ( <_24> when 'true' -> primop 'match_fail' ({'case_clause',_24}) -| ['compiler_generated'] ) end 'check_conf_data'/1 = %% Line 526 fun (_0) -> case _0 of <[]> when 'true' -> %% Line 527 'ok' %% Line 528 when call 'erlang':'is_list' (_0) -> %% Line 529 case ConfData of <[Application|ConfDataRem]> when 'true' -> %% Line 530 case Application of %% Line 531 <{'kernel',List}> when call 'erlang':'is_list' (List) -> %% Line 532 case apply 'check_para_kernel'/1 (List) of %% Line 533 <'ok'> when 'true' -> %% Line 534 apply 'check_conf_data'/1 (ConfDataRem) %% Line 535 when 'true' -> %% Line 536 Error1 end %% Line 538 <{AppName,List}> when let <_3> = call 'erlang':'is_atom' (AppName) in let <_4> = call 'erlang':'is_list' (List) in call 'erlang':'and' (_3, _4) -> let <_5> = call %% Line 539 'erlang':%% Line 539 'atom_to_list' (%% Line 539 AppName) in %% Line 539 case apply 'check_para'/2 (List, _5) of %% Line 540 <'ok'> when 'true' -> %% Line 541 apply 'check_conf_data'/1 (ConfDataRem) %% Line 542 when 'true' -> %% Line 543 Error2 end %% Line 545 <{AppName,List}> when call 'erlang':'is_list' (List) -> let <_7> = call %% Line 547 'io_lib':%% Line 547 'format' (%% Line 547 [126|[116|[112]]], %% Line 547 [AppName|[]]) in let <_8> = call %% Line 547 'lists':%% Line 547 'flatten' (_7) in let <_9> = call %% Line 548 'erlang':%% Line 548 '++' (_8, %% Line 548 [59|[32|[97|[112|[112|[108|[105|[99|[97|[116|[105|[111|[110|[32|[110|[97|[109|[101|[32|[109|[117|[115|[116|[32|[98|[101|[32|[97|[110|[32|[97|[116|[111|[109]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]) in let = call %% Line 547 'erlang':%% Line 547 '++' (%% Line 546 [97|[112|[112|[108|[105|[99|[97|[116|[105|[111|[110|[58|[32]]]]]]]]]]]]], _9) in %% Line 549 {'error',ErrMsg} %% Line 550 <{AppName,_X_List}> when 'true' -> let <_11> = call %% Line 552 'io_lib':%% Line 552 'format' (%% Line 552 [126|[116|[112]]], %% Line 552 [AppName|[]]) in let <_12> = call %% Line 552 'lists':%% Line 552 'flatten' (_11) in let <_13> = call %% Line 553 'erlang':%% Line 553 '++' (_12, %% Line 553 [59|[32|[112|[97|[114|[97|[109|[101|[116|[101|[114|[115|[32|[109|[117|[115|[116|[32|[98|[101|[32|[97|[32|[108|[105|[115|[116]]]]]]]]]]]]]]]]]]]]]]]]]]]) in let = call %% Line 552 'erlang':%% Line 552 '++' (%% Line 551 [97|[112|[112|[108|[105|[99|[97|[116|[105|[111|[110|[58|[32]]]]]]]]]]]]], _13) in %% Line 554 {'error',ErrMsg} %% Line 555 when 'true' -> let <_15> = call %% Line 557 'io_lib':%% Line 557 'format' (%% Line 557 [32|[126|[116|[112]]]], %% Line 557 [Else|[]]) in let <_16> = call %% Line 557 'lists':%% Line 557 'flatten' (_15) in let = call %% Line 556 'erlang':%% Line 556 '++' (%% Line 556 [105|[110|[118|[97|[108|[105|[100|[32|[97|[112|[112|[108|[105|[99|[97|[116|[105|[111|[110|[32|[110|[97|[109|[101|[58|[32]]]]]]]]]]]]]]]]]]]]]]]]]], _16) in %% Line 558 {'error',ErrMsg} end ( <_1> when 'true' -> primop 'match_fail' ({'badmatch',_1}) -| ['compiler_generated'] ) end %% Line 560 <_X_ConfData> when 'true' -> %% Line 561 {'error','configuration must be a list ended by '} end 'check_para_kernel'/1 = %% Line 565 fun (_0) -> case _0 of <[]> when 'true' -> %% Line 566 'ok' %% Line 567 <[{'distributed',Apps}|ParaList]> when call 'erlang':'is_list' (Apps) -> %% Line 568 case apply 'check_distributed'/1 (Apps) of %% Line 569 when 'true' -> %% Line 570 Error %% Line 571 <_9> when 'true' -> %% Line 572 apply 'check_para_kernel'/1 (ParaList) end %% Line 574 <[{'distributed',_X_Apps}|_X_ParaList]> when 'true' -> %% Line 575 {'error',[97|[112|[112|[108|[105|[99|[97|[116|[105|[111|[110|[58|[32|[107|[101|[114|[110|[101|[108|[59|[32|[101|[114|[114|[111|[110|[101|[111|[117|[115|[32|[112|[97|[114|[97|[109|[101|[116|[101|[114|[58|[32|[100|[105|[115|[116|[114|[105|[98|[117|[116|[101|[100]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]} %% Line 576 <[{Para,_X_Val}|ParaList]> when call 'erlang':'is_atom' (Para) -> %% Line 577 apply 'check_para_kernel'/1 (ParaList) %% Line 578 <[{Para,_X_Val}|_X_ParaList]> when 'true' -> let <_2> = call %% Line 580 'io_lib':%% Line 580 'format' (%% Line 580 [126|[116|[112]]], %% Line 580 [Para|[]]) in let <_3> = call %% Line 580 'lists':%% Line 580 'flatten' (_2) in let <_4> = call %% Line 579 'erlang':%% Line 579 '++' (%% Line 579 [97|[112|[112|[108|[105|[99|[97|[116|[105|[111|[110|[58|[32|[107|[101|[114|[110|[101|[108|[59|[32|[105|[110|[118|[97|[108|[105|[100|[32|[112|[97|[114|[97|[109|[101|[116|[101|[114|[58|[32]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]], _3) in %% Line 579 {'error',_4} %% Line 581 when 'true' -> let <_5> = call %% Line 583 'io_lib':%% Line 583 'format' (%% Line 583 [126|[116|[112]]], %% Line 583 [Else|[]]) in let <_6> = call %% Line 583 'lists':%% Line 583 'flatten' (_5) in let <_7> = call %% Line 582 'erlang':%% Line 582 '++' (%% Line 582 [97|[112|[112|[108|[105|[99|[97|[116|[105|[111|[110|[58|[32|[107|[101|[114|[110|[101|[108|[59|[32|[105|[110|[118|[97|[108|[105|[100|[32|[112|[97|[114|[97|[109|[101|[116|[101|[114|[32|[108|[105|[115|[116|[58|[32]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]], _6) in %% Line 582 {'error',_7} end 'check_distributed'/1 = %% Line 586 fun (_0) -> case _0 of <[]> when 'true' -> %% Line 587 'ok' %% Line 588 <[{App,List}|Apps]> when let <_1> = call 'erlang':'is_atom' (App) in let <_2> = call 'erlang':'is_list' (List) in call 'erlang':'and' (_1, _2) -> %% Line 589 apply 'check_distributed'/1 (Apps) %% Line 590 <[{App,'infinity',List}|Apps]> when let <_3> = call 'erlang':'is_atom' (App) in let <_4> = call 'erlang':'is_list' (List) in call 'erlang':'and' (_3, _4) -> %% Line 591 apply 'check_distributed'/1 (Apps) %% Line 592 <[{App,Time,List}|Apps]> when try let <_5> = call 'erlang':'is_atom' (App) in let <_6> = call 'erlang':'is_integer' (Time) in let <_7> = call 'erlang':'is_list' (List) in let <_8> = call 'erlang':'and' (_6, _7) in call 'erlang':'and' (_5, _8) of -> Try catch -> 'false' -> %% Line 593 apply 'check_distributed'/1 (Apps) %% Line 594 <_X_Else> when 'true' -> %% Line 595 {'error',[97|[112|[112|[108|[105|[99|[97|[116|[105|[111|[110|[58|[32|[107|[101|[114|[110|[101|[108|[59|[32|[101|[114|[114|[111|[110|[101|[111|[117|[115|[32|[112|[97|[114|[97|[109|[101|[116|[101|[114|[58|[32|[100|[105|[115|[116|[114|[105|[98|[117|[116|[101|[100]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]} end 'check_para'/2 = %% Line 598 fun (_1,_0) -> case <_1,_0> of <[],_X_AppName> when 'true' -> %% Line 599 'ok' %% Line 600 <[{Para,_X_Val}|ParaList],AppName> when call 'erlang':'is_atom' (Para) -> %% Line 601 apply 'check_para'/2 (ParaList, AppName) %% Line 602 <[{Para,_X_Val}|_X_ParaList],AppName> when 'true' -> let <_2> = call %% Line 604 'io_lib':%% Line 604 'format' (%% Line 604 [126|[116|[112]]], %% Line 604 [Para|[]]) in let <_3> = call %% Line 604 'lists':%% Line 604 'flatten' (_2) in let <_4> = call %% Line 603 'erlang':%% Line 603 '++' (%% Line 603 [59|[32|[105|[110|[118|[97|[108|[105|[100|[32|[112|[97|[114|[97|[109|[101|[116|[101|[114|[58|[32]]]]]]]]]]]]]]]]]]]]], _3) in let <_5> = call %% Line 603 'erlang':%% Line 603 '++' (%% Line 603 AppName, _4) in let <_6> = call %% Line 603 'erlang':%% Line 603 '++' (%% Line 603 [97|[112|[112|[108|[105|[99|[97|[116|[105|[111|[110|[58|[32]]]]]]]]]]]]], _5) in %% Line 603 {'error',_6} %% Line 605 <[Else|_X_ParaList],AppName> when 'true' -> let <_7> = call %% Line 607 'io_lib':%% Line 607 'format' (%% Line 607 [126|[116|[112]]], %% Line 607 [Else|[]]) in let <_8> = call %% Line 607 'lists':%% Line 607 'flatten' (_7) in let <_9> = call %% Line 606 'erlang':%% Line 606 '++' (%% Line 606 [59|[32|[105|[110|[118|[97|[108|[105|[100|[32|[112|[97|[114|[97|[109|[101|[116|[101|[114|[58|[32]]]]]]]]]]]]]]]]]]]]], _8) in let <_10> = call %% Line 606 'erlang':%% Line 606 '++' (%% Line 606 AppName, _9) in let <_11> = call %% Line 606 'erlang':%% Line 606 '++' (%% Line 606 [97|[112|[112|[108|[105|[99|[97|[116|[105|[111|[110|[58|[32]]]]]]]]]]]]], _10) in %% Line 606 {'error',_11} ( <_13,_12> when 'true' -> ( primop 'match_fail' ({'function_clause',_13,_12}) -| [{'function_name',{'check_para',2}}] ) -| ['compiler_generated'] ) end 'handle_call'/3 = %% Line 623 fun (_2,_1,_0) -> case <_2,_1,_0> of <{'load_application',Application},From,S> when 'true' -> let <_3> = catch %% Line 624 apply 'do_load_application'/2 (Application, S) in %% Line 624 case _3 of %% Line 625 <{'ok',NewS}> when 'true' -> let = apply %% Line 626 'get_appl_name'/1 (%% Line 626 Application) in %% Line 627 case apply 'cntrl'/3 (AppName, S, {'ac_load_application_req',AppName}) of %% Line 628 <'true'> when 'true' -> %% Line 630 ( case S of ( <( {'state',_rec36,_203,_204,_205,_206,_207,_208,_209} -| ['compiler_generated'] )> when 'true' -> let <_rec34> = [{AppName,From}|_rec36] in let <_10> = call 'erlang':'setelement' (2, S, _rec34) in {'noreply',_10} -| ['compiler_generated'] ) ( <_210> when 'true' -> ( call ( 'erlang' -| ['compiler_generated'] ):( 'error' -| ['compiler_generated'] ) (( {'badrecord','state'} -| ['compiler_generated'] )) -| ['compiler_generated'] ) -| ['compiler_generated'] ) end -| ['compiler_generated'] ) %% Line 631 <'false'> when 'true' -> %% Line 632 {'reply','ok',NewS} ( <_11> when 'true' -> primop 'match_fail' ({'case_clause',_11}) -| ['compiler_generated'] ) end %% Line 634 when 'true' -> %% Line 635 {'reply',Error,S} %% Line 636 <{'EXIT',R}> when 'true' -> %% Line 637 {'reply',{'error',R},S} ( <_12> when 'true' -> primop 'match_fail' ({'case_clause',_12}) -| ['compiler_generated'] ) end %% Line 640 <{'unload_application',AppName},_X_From,S> when 'true' -> %% Line 641 ( case S of ( <( {'state',_221,_222,_223,_rec37,_224,_225,_226,_227} -| ['compiler_generated'] )> when 'true' -> case call 'lists':'keymember' (AppName, 1, _rec37) of %% Line 642 <'true'> when 'true' -> {'reply',{'error',{'running',AppName}},S} %% Line 643 <'false'> when 'true' -> %% Line 644 case apply 'get_loaded'/1 (AppName) of %% Line 645 <{'true',_229}> when 'true' -> let = apply %% Line 646 'unload'/2 (%% Line 646 AppName, %% Line 646 S) in do %% Line 647 apply 'cntrl'/3 (AppName, S, {'ac_application_unloaded',AppName}) %% Line 648 {'reply','ok',NewS} %% Line 649 <'false'> when 'true' -> %% Line 650 {'reply',{'error',{'not_loaded',AppName}},S} ( <_16> when 'true' -> primop 'match_fail' ({'case_clause',_16}) -| ['compiler_generated'] ) end ( <_17> when 'true' -> primop 'match_fail' ({'case_clause',_17}) -| ['compiler_generated'] ) end -| ['compiler_generated'] ) ( <_228> when 'true' -> ( call ( 'erlang' -| ['compiler_generated'] ):( 'error' -| ['compiler_generated'] ) (( {'badrecord','state'} -| ['compiler_generated'] )) -| ['compiler_generated'] ) -| ['compiler_generated'] ) end -| ['compiler_generated'] ) %% Line 654 <{'start_application',AppName,RestartType},From,S> when 'true' -> %% Line 656 case S of <{'state',_230,Starting,SPF,Running,_231,Started,Start_req,_232}> when 'true' -> %% Line 661 case call 'lists':'keyfind' (AppName, 1, Start_req) of %% Line 662 <'false'> when 'true' -> let <_19> = catch %% Line 663 apply 'check_start_cond'/4 (AppName, RestartType, Started, Running) in %% Line 663 case _19 of %% Line 664 <{'ok',Appl}> when 'true' -> let = apply %% Line 665 'cntrl'/3 (%% Line 665 AppName, %% Line 665 S, %% Line 665 {'ac_start_application_req',AppName}) in let = call %% Line 666 'application':%% Line 666 'get_env' (%% Line 666 'kernel', %% Line 666 'permissions') in %% Line 667 case of %% Line 668 <( 'true' -| ['compiler_generated'] ),_233> when 'true' -> let <_rec38> = [%% Line 669 {AppName,RestartType,'normal',From}|%% Line 670 Starting] in let <_rec39> = [%% Line 671 {AppName,From}|%% Line 671 Start_req] in let <_25> = call %% Line 671 'erlang':%% Line 671 'setelement' (%% Line 671 8, %% Line 669 S, %% Line 671 _rec39) in let <_27> = call %% Line 669 'erlang':%% Line 669 'setelement' (%% Line 669 3, _25, %% Line 669 _rec38) in %% Line 669 {'noreply',_27} %% Line 672 <'false','undefined'> when 'true' -> do %% Line 673 apply 'spawn_starter'/4 (From, Appl, S, 'normal') let <_rec41> = [%% Line 674 {AppName,RestartType,'normal',From}|%% Line 675 Starting] in let <_rec42> = [%% Line 676 {AppName,From}|%% Line 676 Start_req] in let <_31> = call %% Line 676 'erlang':%% Line 676 'setelement' (%% Line 676 8, %% Line 674 S, %% Line 676 _rec42) in let <_33> = call %% Line 674 'erlang':%% Line 674 'setelement' (%% Line 674 3, _31, %% Line 674 _rec41) in %% Line 674 {'noreply',_33} %% Line 677 <( 'false' -| ['compiler_generated'] ),( {( 'ok' -| ['compiler_generated'] ),Perms} -| ['compiler_generated'] )> when 'true' -> %% Line 678 case call 'lists':'member' ({AppName,'false'}, Perms) of %% Line 679 <'false'> when 'true' -> do %% Line 680 apply 'spawn_starter'/4 (From, Appl, S, 'normal') let <_rec44> = [%% Line 681 {AppName,RestartType,'normal',From}|%% Line 682 Starting] in let <_rec45> = [%% Line 683 {AppName,From}|%% Line 683 Start_req] in let <_37> = call %% Line 683 'erlang':%% Line 683 'setelement' (%% Line 683 8, %% Line 681 S, %% Line 683 _rec45) in let <_39> = call %% Line 681 'erlang':%% Line 681 'setelement' (%% Line 681 3, _37, %% Line 681 _rec44) in %% Line 681 {'noreply',_39} %% Line 684 <'true'> when 'true' -> let <_rec47> = [%% Line 685 {AppName,RestartType,'normal',From}|%% Line 686 SPF] in let <_43> = call %% Line 685 'erlang':%% Line 685 'setelement' (%% Line 685 4, %% Line 685 S, %% Line 685 _rec47) in %% Line 687 {'reply','ok',_43} ( <_45> when 'true' -> primop 'match_fail' ({'case_clause',_45}) -| ['compiler_generated'] ) end ( <( _561 -| ['compiler_generated'] ),( _562 -| ['compiler_generated'] )> when 'true' -> let <_46> = {( _561 -| ['compiler_generated'] ),( _562 -| ['compiler_generated'] )} in primop 'match_fail' ({'case_clause',_46}) -| ['compiler_generated'] ) end %% Line 690 when 'true' -> %% Line 691 {'reply',Error,S} ( <_47> when 'true' -> primop 'match_fail' ({'case_clause',_47}) -| ['compiler_generated'] ) end %% Line 693 <{_270,_X_FromX}> when call 'erlang':'=:=' (_270, AppName) -> let <_rec49> = [%% Line 694 {AppName,From}|%% Line 694 Start_req] in let <_51> = call %% Line 694 'erlang':%% Line 694 'setelement' (%% Line 694 8, %% Line 694 S, %% Line 694 _rec49) in %% Line 695 {'noreply',_51} ( <_53> when 'true' -> primop 'match_fail' ({'case_clause',_53}) -| ['compiler_generated'] ) end ( <_18> when 'true' -> primop 'match_fail' ({'badmatch',_18}) -| ['compiler_generated'] ) end %% Line 698 <{'permit_application',AppName,Bool},From,S> when 'true' -> %% Line 699 ( case S of ( <( {'state',_280,_281,_282,_283,_rec51,_284,_285,_286} -| ['compiler_generated'] )> when 'true' -> let = apply %% Line 705 'get_loaded'/1 (%% Line 705 AppName) in let = call %% Line 706 'lists':%% Line 706 'keysearch' (%% Line 706 AppName, %% Line 706 1, _281) in let = call %% Line 707 'lists':%% Line 707 'keysearch' (%% Line 707 AppName, %% Line 707 1, _282) in let = call %% Line 708 'lists':%% Line 708 'keysearch' (%% Line 708 AppName, %% Line 708 1, _284) in let = call %% Line 709 'lists':%% Line 709 'keysearch' (%% Line 709 AppName, %% Line 709 1, _283) in %% Line 711 case call 'lists':'keymember' (AppName, 1, _rec51) of %% Line 715 <'true'> when 'true' -> %% Line 716 case of %% Line 718 <( 'false' -| ['compiler_generated'] ),_328,_329> when 'true' -> %% Line 719 {'reply',{'error',{'not_loaded',AppName}},S} %% Line 721 <( {( 'true' -| ['compiler_generated'] ),_X_Appl} -| ['compiler_generated'] ),( 'false' -| ['compiler_generated'] ),( 'false' -| ['compiler_generated'] )> when 'true' -> do %% Line 722 apply 'update_permissions'/2 (AppName, Bool) %% Line 723 {'reply',{'distributed_application','only_loaded'},S} %% Line 724 <( _563 -| ['compiler_generated'] ),( _564 -| ['compiler_generated'] ),( _565 -| ['compiler_generated'] )> when 'true' -> do %% Line 725 apply 'update_permissions'/2 (AppName, Bool) %% Line 726 {'reply','distributed_application',S} end %% Line 731 <'false'> when 'true' -> %% Line 732 case of %% Line 737 <( 'true' -| ['compiler_generated'] ),_331,_332,_333,_334,( {( 'value' -| ['compiler_generated'] ),_X_Tuple} -| ['compiler_generated'] )> when 'true' -> %% Line 738 {'reply','ok',S} %% Line 740 <( 'true' -| ['compiler_generated'] ),( 'false' -| ['compiler_generated'] ),_335,_336,_337,_338> when 'true' -> %% Line 741 {'reply',{'error',{'not_loaded',AppName}},S} %% Line 743 <( 'true' -| ['compiler_generated'] ),( {( 'true' -| ['compiler_generated'] ),_X_Appl} -| ['compiler_generated'] ),( 'false' -| ['compiler_generated'] ),( 'false' -| ['compiler_generated'] ),( 'false' -| ['compiler_generated'] ),( 'false' -| ['compiler_generated'] )> when 'true' -> do %% Line 744 apply 'update_permissions'/2 (AppName, Bool) %% Line 745 {'reply','ok',S} %% Line 747 <( 'true' -| ['compiler_generated'] ),( {( 'true' -| ['compiler_generated'] ),_X_Appl} -| ['compiler_generated'] ),( {( 'value' -| ['compiler_generated'] ),_X_Tuple} -| ['compiler_generated'] ),( 'false' -| ['compiler_generated'] ),( 'false' -| ['compiler_generated'] ),( 'false' -| ['compiler_generated'] )> when 'true' -> do %% Line 748 apply 'update_permissions'/2 (AppName, Bool) %% Line 749 {'reply','ok',S} %% Line 751 <( 'true' -| ['compiler_generated'] ),( {( 'true' -| ['compiler_generated'] ),Appl} -| ['compiler_generated'] ),( 'false' -| ['compiler_generated'] ),( {( 'value' -| ['compiler_generated'] ),Tuple} -| ['compiler_generated'] ),( 'false' -| ['compiler_generated'] ),( 'false' -| ['compiler_generated'] )> when 'true' -> do %% Line 752 apply 'update_permissions'/2 (AppName, Bool) %% Line 753 case Tuple of <{_X_AppName2,RestartType,'normal',_X_From}> when 'true' -> do %% Line 754 apply 'spawn_starter'/4 (From, Appl, S, 'normal') let <_rec57> = [%% Line 755 {AppName,RestartType,'normal',From}|_281] in let <_rec58> = call %% Line 756 'lists':%% Line 756 'keydelete' (%% Line 756 AppName, %% Line 756 1, _282) in let <_rec59> = [%% Line 757 {AppName,From}|_285] in let <_83> = call %% Line 757 'erlang':%% Line 757 'setelement' (%% Line 757 8, %% Line 755 S, %% Line 757 _rec59) in let <_84> = call %% Line 756 'erlang':%% Line 756 'setelement' (%% Line 756 4, _83, %% Line 756 _rec58) in let <_86> = call %% Line 755 'erlang':%% Line 755 'setelement' (%% Line 755 3, _84, %% Line 755 _rec57) in %% Line 758 {'noreply',_86} ( <_78> when 'true' -> primop 'match_fail' ({'badmatch',_78}) -| ['compiler_generated'] ) end %% Line 760 <( 'true' -| ['compiler_generated'] ),( {( 'true' -| ['compiler_generated'] ),Appl} -| ['compiler_generated'] ),_348,_349,( {( 'value' -| ['compiler_generated'] ),( {_350,RestartType} -| ['compiler_generated'] )} -| ['compiler_generated'] ),( 'false' -| ['compiler_generated'] )> when call 'erlang':'=:=' (_350, AppName) -> do %% Line 761 apply 'update_permissions'/2 (AppName, Bool) do %% Line 762 apply 'spawn_starter'/4 (From, Appl, S, 'normal') let <_rec61> = [%% Line 763 {AppName,RestartType,'normal',From}|_281] in let <_rec62> = call %% Line 764 'lists':%% Line 764 'keydelete' (%% Line 764 AppName, %% Line 764 1, _284) in let <_rec63> = [%% Line 765 {AppName,From}|_285] in let <_92> = call %% Line 765 'erlang':%% Line 765 'setelement' (%% Line 765 8, %% Line 763 S, %% Line 765 _rec63) in let <_93> = call %% Line 764 'erlang':%% Line 764 'setelement' (%% Line 764 7, _92, %% Line 764 _rec62) in let <_95> = call %% Line 763 'erlang':%% Line 763 'setelement' (%% Line 763 3, _93, %% Line 763 _rec61) in %% Line 766 {'noreply',_95} %% Line 772 <( 'false' -| ['compiler_generated'] ),_360,_361,_362,_363,( {( 'value' -| ['compiler_generated'] ),( {_X_AppName,Id} -| ['compiler_generated'] )} -| ['compiler_generated'] )> when 'true' -> %% Line 773 case call 'lists':'keyfind' (AppName, 1, _284) of <{_X_AppName2,Type}> when 'true' -> do %% Line 774 apply 'stop_appl'/3 (AppName, Id, Type) let = call %% Line 775 'lists':%% Line 775 'keydelete' (%% Line 775 AppName, %% Line 775 1, _283) in let <_101> = call %% Line 776 'erlang':%% Line 776 'setelement' (%% Line 776 5, %% Line 776 S, %% Line 776 NRunning) in %% Line 776 {'reply','ok',_101} ( <_97> when 'true' -> primop 'match_fail' ({'badmatch',_97}) -| ['compiler_generated'] ) end %% Line 778 <( 'false' -| ['compiler_generated'] ),( 'false' -| ['compiler_generated'] ),_373,_374,_375,_376> when 'true' -> %% Line 779 {'reply',{'error',{'not_loaded',AppName}},S} %% Line 781 <( 'false' -| ['compiler_generated'] ),( {( 'true' -| ['compiler_generated'] ),_X_Appl} -| ['compiler_generated'] ),( 'false' -| ['compiler_generated'] ),( 'false' -| ['compiler_generated'] ),( 'false' -| ['compiler_generated'] ),( 'false' -| ['compiler_generated'] )> when 'true' -> do %% Line 782 apply 'update_permissions'/2 (AppName, Bool) %% Line 783 {'reply','ok',S} %% Line 785 <( 'false' -| ['compiler_generated'] ),( {( 'true' -| ['compiler_generated'] ),_X_Appl} -| ['compiler_generated'] ),( {( 'value' -| ['compiler_generated'] ),_X_Tuple} -| ['compiler_generated'] ),( 'false' -| ['compiler_generated'] ),( 'false' -| ['compiler_generated'] ),( 'false' -| ['compiler_generated'] )> when 'true' -> do %% Line 786 apply 'update_permissions'/2 (AppName, Bool) %% Line 787 {'reply','ok',S} %% Line 789 <( 'false' -| ['compiler_generated'] ),( {( 'true' -| ['compiler_generated'] ),_X_Appl} -| ['compiler_generated'] ),( 'false' -| ['compiler_generated'] ),( {( 'value' -| ['compiler_generated'] ),_X_Tuple} -| ['compiler_generated'] ),( 'false' -| ['compiler_generated'] ),( 'false' -| ['compiler_generated'] )> when 'true' -> do %% Line 790 apply 'update_permissions'/2 (AppName, Bool) let <_rec66> = call %% Line 791 'lists':%% Line 791 'keydelete' (%% Line 791 AppName, %% Line 791 1, _282) in let <_105> = call %% Line 791 'erlang':%% Line 791 'setelement' (%% Line 791 4, %% Line 791 S, %% Line 791 _rec66) in %% Line 792 {'reply','ok',_105} %% Line 794 <( 'false' -| ['compiler_generated'] ),( {( 'true' -| ['compiler_generated'] ),_X_Appl} -| ['compiler_generated'] ),_386,_387,( {( 'value' -| ['compiler_generated'] ),_X_Tuple} -| ['compiler_generated'] ),( 'false' -| ['compiler_generated'] )> when 'true' -> do %% Line 795 apply 'update_permissions'/2 (AppName, Bool) %% Line 796 {'reply','ok',S} ( <( _569 -| ['compiler_generated'] ),( _570 -| ['compiler_generated'] ),( _571 -| ['compiler_generated'] ),( _572 -| ['compiler_generated'] ),( _573 -| ['compiler_generated'] ),( _574 -| ['compiler_generated'] )> when 'true' -> let <_107> = {( _569 -| ['compiler_generated'] ),( _570 -| ['compiler_generated'] ),( _571 -| ['compiler_generated'] ),( _572 -| ['compiler_generated'] ),( _573 -| ['compiler_generated'] ),( _574 -| ['compiler_generated'] )} in primop 'match_fail' ({'case_clause',_107}) -| ['compiler_generated'] ) end ( <_108> when 'true' -> primop 'match_fail' ({'case_clause',_108}) -| ['compiler_generated'] ) end -| ['compiler_generated'] ) ( <_287> when 'true' -> ( call ( 'erlang' -| ['compiler_generated'] ):( 'error' -| ['compiler_generated'] ) (( {'badrecord','state'} -| ['compiler_generated'] )) -| ['compiler_generated'] ) -| ['compiler_generated'] ) end -| ['compiler_generated'] ) %% Line 801 <{'stop_application',AppName},_X_From,S> when 'true' -> %% Line 802 case S of <{'state',_388,_389,_390,Running,_391,Started,_392,_393}> when 'true' -> %% Line 803 case call 'lists':'keyfind' (AppName, 1, Running) of %% Line 804 <{_X_AppName,Id}> when 'true' -> %% Line 805 case call 'lists':'keyfind' (AppName, 1, Started) of <{_X_AppName2,Type}> when 'true' -> do %% Line 806 apply 'stop_appl'/3 (AppName, Id, Type) let = call %% Line 807 'lists':%% Line 807 'keydelete' (%% Line 807 AppName, %% Line 807 1, %% Line 807 Running) in let = call %% Line 808 'lists':%% Line 808 'keydelete' (%% Line 808 AppName, %% Line 808 1, %% Line 808 Started) in do %% Line 809 apply 'cntrl'/3 (AppName, S, {'ac_application_stopped',AppName}) let <_114> = call %% Line 810 'erlang':%% Line 810 'setelement' (%% Line 810 7, %% Line 810 S, %% Line 810 NStarted) in let <_116> = call %% Line 810 'erlang':%% Line 810 'setelement' (%% Line 810 5, _114, %% Line 810 NRunning) in %% Line 810 {'reply','ok',_116} ( <_110> when 'true' -> primop 'match_fail' ({'badmatch',_110}) -| ['compiler_generated'] ) end %% Line 811 <'false'> when 'true' -> %% Line 812 case call 'lists':'keymember' (AppName, 1, Started) of %% Line 813 <'true'> when 'true' -> let = call %% Line 814 'lists':%% Line 814 'keydelete' (%% Line 814 AppName, %% Line 814 1, %% Line 814 Started) in do %% Line 815 apply 'cntrl'/3 (AppName, S, {'ac_application_stopped',AppName}) let <_120> = call %% Line 816 'erlang':%% Line 816 'setelement' (%% Line 816 7, %% Line 816 S, %% Line 816 NStarted) in %% Line 816 {'reply','ok',_120} %% Line 817 <'false'> when 'true' -> %% Line 818 {'reply',{'error',{'not_started',AppName}},S} ( <_121> when 'true' -> primop 'match_fail' ({'case_clause',_121}) -| ['compiler_generated'] ) end ( <_122> when 'true' -> primop 'match_fail' ({'case_clause',_122}) -| ['compiler_generated'] ) end ( <_109> when 'true' -> primop 'match_fail' ({'badmatch',_109}) -| ['compiler_generated'] ) end %% Line 822 <{'change_application_data',Applications,Config},_X_From,S> when 'true' -> let <_125> = fun (_123) -> %% Line 824 case _123 of <[{{'loaded',_X_AppName},Appl}|[]]> when 'true' -> %% Line 825 {'true',Appl} %% Line 826 <_412> when 'true' -> %% Line 827 'false' end in let = call %% Line 823 'ets':%% Line 823 'filter' (%% Line 823 'ac_tab', _125, %% Line 829 []) in let <_127> = catch %% Line 830 apply 'do_change_apps'/3 (Applications, Config, OldAppls) in %% Line 830 case _127 of %% Line 831 when 'true' -> %% Line 832 {'reply',Error,S} %% Line 833 <{'EXIT',R}> when 'true' -> %% Line 834 {'reply',{'error',R},S} %% Line 835 <{NewAppls,NewConfig}> when 'true' -> let <_132> = fun (_130) -> %% Line 837 ( case _130 of ( <( {'appl',_rec70,_414,_415,_416,_417,_418,_419,_420} -| ['compiler_generated'] )> when 'true' -> call 'ets':'insert' ('ac_tab', {{'loaded',_rec70},_130}) -| ['compiler_generated'] ) ( <_421> when 'true' -> ( call ( 'erlang' -| ['compiler_generated'] ):( 'error' -| ['compiler_generated'] ) (( {'badrecord','appl'} -| ['compiler_generated'] )) -| ['compiler_generated'] ) -| ['compiler_generated'] ) end -| ['compiler_generated'] ) in do %% Line 836 call 'lists':'foreach' (_132, %% Line 839 NewAppls) %% Line 840 case S of <{'state',_422,_423,_424,_425,_426,_427,_428,_429}> when 'true' -> let <_135> = call 'erlang':'setelement' (9, S, NewConfig) in {'reply','ok',_135} ( <_430> when 'true' -> ( call ( 'erlang' -| ['compiler_generated'] ):( 'error' -| ['compiler_generated'] ) (( {'badrecord','state'} -| ['compiler_generated'] )) -| ['compiler_generated'] ) -| ['compiler_generated'] ) end ( <_136> when 'true' -> primop 'match_fail' ({'case_clause',_136}) -| ['compiler_generated'] ) end %% Line 843 <'prep_config_change',_X_From,S> when 'true' -> %% Line 844 ( case S of ( <( {'state',_431,_432,_433,_rec72,_434,_435,_436,_437} -| ['compiler_generated'] )> when 'true' -> let <_140> = apply %% Line 845 'do_prep_config_change'/1 (_rec72) in let = call %% Line 845 'lists':%% Line 845 'reverse' (_140) in %% Line 846 {'reply',EnvBefore,S} -| ['compiler_generated'] ) ( <_438> when 'true' -> ( call ( 'erlang' -| ['compiler_generated'] ):( 'error' -| ['compiler_generated'] ) (( {'badrecord','state'} -| ['compiler_generated'] )) -| ['compiler_generated'] ) -| ['compiler_generated'] ) end -| ['compiler_generated'] ) %% Line 848 <{'config_change',EnvBefore},_X_From,S> when 'true' -> %% Line 849 ( case S of ( <( {'state',_439,_440,_441,_rec73,_442,_443,_444,_445} -| ['compiler_generated'] )> when 'true' -> let = apply %% Line 850 'do_config_change'/2 (_rec73, %% Line 850 EnvBefore) in %% Line 851 {'reply',R,S} -| ['compiler_generated'] ) ( <_446> when 'true' -> ( call ( 'erlang' -| ['compiler_generated'] ):( 'error' -| ['compiler_generated'] ) (( {'badrecord','state'} -| ['compiler_generated'] )) -| ['compiler_generated'] ) -| ['compiler_generated'] ) end -| ['compiler_generated'] ) %% Line 853 <'which_applications',_X_From,S> when 'true' -> let <_152> = fun (_150) -> %% Line 854 case _150 of <{Name,Id}> when 'true' -> %% Line 855 case Id of %% Line 856 <{'distributed',_X_Node}> when 'true' -> %% Line 857 'false' %% Line 858 <_447> when 'true' -> %% Line 859 case %% Line 860 apply 'get_loaded'/1 (Name) of <{'true',{'appl',_448,_449,Descr,_450,Vsn,_451,_452,_453}}> when 'true' -> %% Line 861 {'true',{Name,Descr,Vsn}} ( <_148> when 'true' -> primop 'match_fail' ({'badmatch',_148}) -| ['compiler_generated'] ) end end ( <_151> when 'true' -> ( primop 'match_fail' ({'function_clause',_151}) -| [{'function_name',{'-handle_call/3-fun-2-',1}}] ) -| ['compiler_generated'] ) end in %% Line 863 ( case S of ( <( {'state',_454,_455,_456,_rec74,_457,_458,_459,_460} -| ['compiler_generated'] )> when 'true' -> let = call 'lists':'zf' (_152, _rec74) in %% Line 864 {'reply',Reply,S} -| ['compiler_generated'] ) ( <_461> when 'true' -> ( call ( 'erlang' -| ['compiler_generated'] ):( 'error' -| ['compiler_generated'] ) (( {'badrecord','state'} -| ['compiler_generated'] )) -| ['compiler_generated'] ) -| ['compiler_generated'] ) end -| ['compiler_generated'] ) %% Line 866 <{'set_env',AppName,Key,Val,Opts},_X_From,S> when 'true' -> do %% Line 867 call 'ets':'insert' ('ac_tab', {{'env',AppName,Key},Val}) %% Line 868 case call 'proplists':'get_value' ('persistent', Opts, 'false') of %% Line 869 <'true'> when 'true' -> let = fun (_154) -> %% Line 870 call 'lists':'keystore' (Key, 1, _154, {Key,Val}) in %% Line 871 ( case S of ( <( {'state',_462,_463,_464,_465,_466,_467,_468,_rec77} -| ['compiler_generated'] )> when 'true' -> let <_rec75> = apply 'change_app_env'/3 (_rec77, AppName, Fun) in let <_162> = call 'erlang':'setelement' (9, S, _rec75) in {'reply','ok',_162} -| ['compiler_generated'] ) ( <_469> when 'true' -> ( call ( 'erlang' -| ['compiler_generated'] ):( 'error' -| ['compiler_generated'] ) (( {'badrecord','state'} -| ['compiler_generated'] )) -| ['compiler_generated'] ) -| ['compiler_generated'] ) end -| ['compiler_generated'] ) %% Line 872 <'false'> when 'true' -> %% Line 873 {'reply','ok',S} ( <_163> when 'true' -> primop 'match_fail' ({'case_clause',_163}) -| ['compiler_generated'] ) end %% Line 876 <{'unset_env',AppName,Key,Opts},_X_From,S> when 'true' -> do %% Line 877 call 'ets':'delete' ('ac_tab', {'env',AppName,Key}) %% Line 878 case call 'proplists':'get_value' ('persistent', Opts, 'false') of %% Line 879 <'true'> when 'true' -> let = fun (_164) -> %% Line 880 call 'lists':'keydelete' (Key, 1, _164) in %% Line 881 ( case S of ( <( {'state',_479,_480,_481,_482,_483,_484,_485,_rec80} -| ['compiler_generated'] )> when 'true' -> let <_rec78> = apply 'change_app_env'/3 (_rec80, AppName, Fun) in let <_172> = call 'erlang':'setelement' (9, S, _rec78) in {'reply','ok',_172} -| ['compiler_generated'] ) ( <_486> when 'true' -> ( call ( 'erlang' -| ['compiler_generated'] ):( 'error' -| ['compiler_generated'] ) (( {'badrecord','state'} -| ['compiler_generated'] )) -| ['compiler_generated'] ) -| ['compiler_generated'] ) end -| ['compiler_generated'] ) %% Line 882 <'false'> when 'true' -> %% Line 883 {'reply','ok',S} ( <_173> when 'true' -> primop 'match_fail' ({'case_clause',_173}) -| ['compiler_generated'] ) end %% Line 886 <{'control_application',AppName},{Pid,_X_Tag},S> when 'true' -> %% Line 887 ( case S of ( <( {'state',_496,_497,_498,_499,_rec81,_500,_501,_502} -| ['compiler_generated'] )> when 'true' -> %% Line 888 case call 'lists':'keymember' (AppName, 1, _rec81) of %% Line 889 <'false'> when 'true' -> do %% Line 890 call 'erlang':'link' (Pid) let <_rec82> = [%% Line 891 {AppName,Pid}|_rec81] in let <_180> = call %% Line 891 'erlang':%% Line 891 'setelement' (%% Line 891 6, %% Line 891 S, %% Line 891 _rec82) in %% Line 891 {'reply','true',_180} %% Line 892 <'true'> when 'true' -> %% Line 893 {'reply','false',S} ( <_181> when 'true' -> primop 'match_fail' ({'case_clause',_181}) -| ['compiler_generated'] ) end -| ['compiler_generated'] ) ( <_503> when 'true' -> ( call ( 'erlang' -| ['compiler_generated'] ):( 'error' -| ['compiler_generated'] ) (( {'badrecord','state'} -| ['compiler_generated'] )) -| ['compiler_generated'] ) -| ['compiler_generated'] ) end -| ['compiler_generated'] ) %% Line 896 <{'start_type',AppName},_X_From,S> when 'true' -> %% Line 897 ( case S of ( <( {'state',_513,_rec84,_514,_515,_516,_517,_518,_519} -| ['compiler_generated'] )> when 'true' -> let <_186> = case %% Line 898 call 'lists':'keyfind' (AppName, 1, _rec84) of %% Line 899 <'false'> when 'true' -> %% Line 900 'local' %% Line 901 <{_X_AppName,_X_RestartType,Type,_X_F}> when 'true' -> %% Line 902 Type ( <_185> when 'true' -> %% Line 898 primop 'match_fail' ({'case_clause',_185}) -| ['compiler_generated'] ) end in %% Line 904 {'reply',_186,S} -| ['compiler_generated'] ) ( <_520> when 'true' -> ( call ( 'erlang' -| ['compiler_generated'] ):( 'error' -| ['compiler_generated'] ) (( {'badrecord','state'} -| ['compiler_generated'] )) -| ['compiler_generated'] ) -| ['compiler_generated'] ) end -| ['compiler_generated'] ) %% Line 906 <'info',_X_From,S> when 'true' -> let <_188> = apply %% Line 907 'loaded_applications'/0 () in %% Line 908 ( case S of ( <( {'state',_rec85,_521,_522,_523,_524,_525,_526,_527} -| ['compiler_generated'] )> when 'true' -> let = [{'loaded',_188}|[{'loading',_rec85}|%% Line 909 [{'started',_525}|%% Line 910 [{'start_p_false',_522}|%% Line 911 [{'running',_523}|%% Line 912 [{'starting',_521}|[]]]]]]] in %% Line 913 {'reply',Reply,S} -| ['compiler_generated'] ) ( <_528> when 'true' -> ( call ( 'erlang' -| ['compiler_generated'] ):( 'error' -| ['compiler_generated'] ) (( {'badrecord','state'} -| ['compiler_generated'] )) -| ['compiler_generated'] ) -| ['compiler_generated'] ) end -| ['compiler_generated'] ) ( <_202,_201,_200> when 'true' -> ( primop 'match_fail' ({'function_clause',_202,_201,_200}) -| [{'function_name',{'handle_call',3}}] ) -| ['compiler_generated'] ) end 'handle_cast'/2 = %% Line 918 fun (_1,_0) -> case <_1,_0> of <{'application_started',AppName,Res},S> when 'true' -> %% Line 919 apply 'handle_application_started'/3 (AppName, Res, S) ( <_3,_2> when 'true' -> ( primop 'match_fail' ({'function_clause',_3,_2}) -| [{'function_name',{'handle_cast',2}}] ) -| ['compiler_generated'] ) end 'handle_application_started'/3 = %% Line 921 fun (_2,_1,_0) -> %% Line 923 case _0 of <{'state',_63,Starting,_64,Running,_65,Started,Start_req,_66}> when 'true' -> let = apply %% Line 924 'reply_to_requester'/3 (_2, %% Line 924 Start_req, _1) in %% Line 925 case call 'lists':'keyfind' (_2, 1, Starting) of <{_X_AppName,RestartType,_X_Type,_X_From}> when 'true' -> %% Line 926 case _1 of %% Line 927 <{'ok',Id}> when 'true' -> do %% Line 928 case _2 of %% Line 929 <'kernel'> when 'true' -> apply 'check_user'/0 () %% Line 930 <_67> when 'true' -> 'ok' end let <_7> = apply %% Line 932 'nd'/1 (%% Line 932 Id) in do %% Line 932 apply 'info_started'/2 (_2, _7) do %% Line 933 apply 'notify_cntrl_started'/4 (_2, Id, _0, 'ok') let = apply %% Line 934 'keyreplaceadd'/4 (_2, %% Line 934 1, %% Line 934 Running, %% Line 934 {_2,Id}) in let = apply %% Line 935 'keyreplaceadd'/4 (_2, %% Line 935 1, %% Line 935 Started, %% Line 935 {_2,RestartType}) in let <_rec90> = call %% Line 936 'lists':%% Line 936 'keydelete' (_2, %% Line 936 1, %% Line 936 Starting) in let <_12> = call %% Line 939 'erlang':%% Line 939 'setelement' (%% Line 939 8, _0, %% Line 939 Start_reqN) in let <_13> = call %% Line 938 'erlang':%% Line 938 'setelement' (%% Line 938 7, _12, %% Line 938 NStarted) in let <_14> = call %% Line 937 'erlang':%% Line 937 'setelement' (%% Line 937 5, _13, %% Line 937 NRunning) in let <_16> = call %% Line 936 'erlang':%% Line 936 'setelement' (%% Line 936 3, _14, %% Line 936 _rec90) in let = call %% Line 941 'application':%% Line 941 'get_env' (%% Line 941 'kernel', %% Line 941 'permissions') in %% Line 942 case of %% Line 943 <( 'undefined' -| ['compiler_generated'] ),_77> when 'true' -> %% Line 944 {'noreply',_16} %% Line 946 <( {( 'ok' -| ['compiler_generated'] ),Perms} -| ['compiler_generated'] ),( {( 'distributed' -| ['compiler_generated'] ),StartNode} -| ['compiler_generated'] )> when try let <_19> = call 'erlang':'node' () in call 'erlang':'=:=' (StartNode, _19) of -> Try catch -> 'false' -> %% Line 947 case call 'lists':'member' ({_2,'false'}, Perms) of %% Line 948 <'true'> when 'true' -> %% Line 949 case _16 of <{'state',_78,_79,_80,StopRunning,_81,StopStarted,_82,_83}> when 'true' -> %% Line 950 case call 'lists':'keyfind' (_2, 1, StopRunning) of %% Line 951 <{_84,_85}> when let <_86> = call 'erlang':'=:=' (_84, _X_AppName) in let <_87> = call 'erlang':'=:=' (_85, Id) in call 'erlang':'and' (_86, _87) -> %% Line 952 case %% Line 953 call 'lists':'keyfind' (_2, 1, StopStarted) of <{_X_AppName2,Type}> when 'true' -> do %% Line 954 apply 'stop_appl'/3 (_2, Id, Type) let = call %% Line 955 'lists':%% Line 955 'keydelete' (_2, %% Line 955 1, %% Line 955 StopRunning) in do %% Line 956 apply 'cntrl'/3 (_2, _16, {'ac_application_stopped',_2}) let <_24> = call %% Line 958 'erlang':%% Line 958 'setelement' (%% Line 958 7, _16, %% Line 958 StopStarted) in let <_26> = call %% Line 957 'erlang':%% Line 957 'setelement' (%% Line 957 5, _24, %% Line 957 NStopRunning) in %% Line 957 {'noreply',_26} ( <_21> when 'true' -> primop 'match_fail' ({'badmatch',_21}) -| ['compiler_generated'] ) end %% Line 959 <'false'> when 'true' -> %% Line 960 {'noreply',_16} ( <_27> when 'true' -> primop 'match_fail' ({'case_clause',_27}) -| ['compiler_generated'] ) end ( <_20> when 'true' -> primop 'match_fail' ({'badmatch',_20}) -| ['compiler_generated'] ) end %% Line 962 <'false'> when 'true' -> %% Line 963 {'noreply',_16} ( <_28> when 'true' -> primop 'match_fail' ({'case_clause',_28}) -| ['compiler_generated'] ) end %% Line 965 <( _126 -| ['compiler_generated'] ),( _127 -| ['compiler_generated'] )> when 'true' -> %% Line 966 {'noreply',_16} end %% Line 968 when call 'erlang':'=:=' (RestartType, 'temporary') -> do %% Line 969 apply 'notify_cntrl_started'/4 (_2, 'undefined', _0, Error) do %% Line 970 apply 'info_exited'/3 (_2, R, RestartType) let <_rec93> = call %% Line 971 'lists':%% Line 971 'keydelete' (_2, %% Line 971 1, %% Line 971 Starting) in let <_32> = call %% Line 972 'erlang':%% Line 972 'setelement' (%% Line 972 8, _0, %% Line 972 Start_reqN) in let <_34> = call %% Line 971 'erlang':%% Line 971 'setelement' (%% Line 971 3, _32, %% Line 971 _rec93) in %% Line 971 {'noreply',_34} %% Line 973 <{'info',R}> when call 'erlang':'=:=' (RestartType, 'temporary') -> do %% Line 974 apply 'notify_cntrl_started'/4 (_2, 'undefined', _0, {'error',R}) let <_rec95> = call %% Line 975 'lists':%% Line 975 'keydelete' (_2, %% Line 975 1, %% Line 975 Starting) in let <_37> = call %% Line 976 'erlang':%% Line 976 'setelement' (%% Line 976 8, _0, %% Line 976 Start_reqN) in let <_39> = call %% Line 975 'erlang':%% Line 975 'setelement' (%% Line 975 3, _37, %% Line 975 _rec95) in %% Line 975 {'noreply',_39} %% Line 977 <{ErrInf,R}> when let <_40> = call 'erlang':'=:=' (RestartType, 'transient') in let <_41> = call 'erlang':'=:=' (ErrInf, 'error') in let <_42> = call 'erlang':'and' (_40, _41) in let <_43> = call %% Line 978 'erlang':%% Line 978 '=:=' (%% Line 978 RestartType, %% Line 978 'transient') in let <_44> = call %% Line 978 'erlang':%% Line 978 '=:=' (%% Line 978 ErrInf, %% Line 978 'info') in let <_45> = call %% Line 978 'erlang':%% Line 978 'and' (_43, _44) in call 'erlang':'or' (_42, _45) -> do %% Line 979 apply 'notify_cntrl_started'/4 (_2, 'undefined', _0, {'error',R}) do %% Line 980 case ErrInf of %% Line 981 <'error'> when 'true' -> %% Line 982 apply 'info_exited'/3 (_2, R, RestartType) %% Line 983 <'info'> when 'true' -> 'ok' ( <_46> when 'true' -> primop 'match_fail' ({'case_clause',_46}) -| ['compiler_generated'] ) end %% Line 986 case R of %% Line 987 <{{'EXIT','normal'},_X_Call}> when 'true' -> let <_rec97> = call %% Line 988 'lists':%% Line 988 'keydelete' (_2, %% Line 988 1, %% Line 988 Starting) in let <_49> = call %% Line 989 'erlang':%% Line 989 'setelement' (%% Line 989 8, _0, %% Line 989 Start_reqN) in let <_51> = call %% Line 988 'erlang':%% Line 988 'setelement' (%% Line 988 3, _49, %% Line 988 _rec97) in %% Line 988 {'noreply',_51} %% Line 990 <_125> when 'true' -> let = {%% Line 991 'application_start_failure',_2,%% Line 991 R} in let <_53> = apply %% Line 992 'to_string'/1 (%% Line 992 Reason) in %% Line 992 {'stop',_53,_0} end %% Line 994 when 'true' -> do %% Line 995 apply 'notify_cntrl_started'/4 (_2, 'undefined', _0, Error) do %% Line 996 apply 'info_exited'/3 (_2, R, RestartType) let = {%% Line 997 'application_start_failure',_2,%% Line 997 R} in let <_56> = apply %% Line 998 'to_string'/1 (%% Line 998 Reason) in %% Line 998 {'stop',_56,_0} %% Line 999 <{'info',R}> when 'true' -> do %% Line 1000 apply 'notify_cntrl_started'/4 (_2, 'undefined', _0, {'error',R}) let = {%% Line 1001 'application_start_failure',_2,%% Line 1001 R} in let <_58> = apply %% Line 1002 'to_string'/1 (%% Line 1002 Reason) in %% Line 1002 {'stop',_58,_0} ( <_59> when 'true' -> primop 'match_fail' ({'case_clause',_59}) -| ['compiler_generated'] ) end ( <_5> when 'true' -> primop 'match_fail' ({'badmatch',_5}) -| ['compiler_generated'] ) end ( <_3> when 'true' -> primop 'match_fail' ({'badmatch',_3}) -| ['compiler_generated'] ) end 'handle_info'/2 = %% Line 1008 fun (_1,_0) -> case <_1,_0> of <{'ac_load_application_reply',AppName,Res},S> when 'true' -> %% Line 1009 ( case S of ( <( {'state',_rec99,_122,_123,_124,_125,_126,_127,_128} -| ['compiler_generated'] )> when 'true' -> case apply 'keysearchdelete'/3 (AppName, 1, _rec99) of %% Line 1010 <{'value',{_X_AppName,From},Loading}> when 'true' -> do %% Line 1011 call 'gen_server':'reply' (From, Res) %% Line 1012 case Res of %% Line 1013 <'ok'> when 'true' -> let <_6> = call %% Line 1014 'erlang':%% Line 1014 'setelement' (%% Line 1014 2, %% Line 1014 S, %% Line 1014 Loading) in %% Line 1014 {'noreply',_6} %% Line 1015 <{'error',_X_R}> when 'true' -> let = apply %% Line 1016 'unload'/2 (%% Line 1016 AppName, %% Line 1016 S) in %% Line 1017 case NewS of <{'state',_139,_140,_141,_142,_143,_144,_145,_146}> when 'true' -> let <_10> = call 'erlang':'setelement' (2, NewS, Loading) in {'noreply',_10} ( <_147> when 'true' -> ( call ( 'erlang' -| ['compiler_generated'] ):( 'error' -| ['compiler_generated'] ) (( {'badrecord','state'} -| ['compiler_generated'] )) -| ['compiler_generated'] ) -| ['compiler_generated'] ) end ( <_11> when 'true' -> primop 'match_fail' ({'case_clause',_11}) -| ['compiler_generated'] ) end %% Line 1019 <'false'> when 'true' -> %% Line 1020 {'noreply',S} ( <_12> when 'true' -> primop 'match_fail' ({'case_clause',_12}) -| ['compiler_generated'] ) end -| ['compiler_generated'] ) ( <_129> when 'true' -> ( call ( 'erlang' -| ['compiler_generated'] ):( 'error' -| ['compiler_generated'] ) (( {'badrecord','state'} -| ['compiler_generated'] )) -| ['compiler_generated'] ) -| ['compiler_generated'] ) end -| ['compiler_generated'] ) %% Line 1023 <{'ac_start_application_reply',AppName,Res},S> when 'true' -> %% Line 1024 ( case S of ( <( {'state',_148,_149,_150,_151,_152,_153,_rec102,_154} -| ['compiler_generated'] )> when 'true' -> %% Line 1025 case call 'lists':'keyfind' (AppName, 1, _149) of %% Line 1026 <{_X_AppName,RestartType,Type,From}> when 'true' -> %% Line 1027 case Res of %% Line 1028 <'start_it'> when 'true' -> %% Line 1029 case apply 'get_loaded'/1 (AppName) of <{'true',Appl}> when 'true' -> do %% Line 1030 apply 'spawn_starter'/4 (From, Appl, S, Type) %% Line 1031 {'noreply',S} ( <_19> when 'true' -> primop 'match_fail' ({'badmatch',_19}) -| ['compiler_generated'] ) end %% Line 1032 <{'started',Node}> when 'true' -> %% Line 1033 apply 'handle_application_started'/3 (AppName, %% Line 1034 {'ok',{'distributed',Node}}, %% Line 1035 S) %% Line 1036 <'not_started'> when 'true' -> let = apply %% Line 1039 'reply_to_requester'/3 (%% Line 1039 AppName, _rec102, %% Line 1039 'ok') in let <_rec105> = call %% Line 1041 'lists':%% Line 1041 'keydelete' (%% Line 1041 AppName, %% Line 1041 1, _149) in let <_rec106> = [%% Line 1042 {AppName,RestartType}|_153] in let <_27> = call %% Line 1043 'erlang':%% Line 1043 'setelement' (%% Line 1043 8, %% Line 1041 S, %% Line 1043 Start_reqN) in let <_28> = call %% Line 1042 'erlang':%% Line 1042 'setelement' (%% Line 1042 7, _27, %% Line 1042 _rec106) in let <_30> = call %% Line 1041 'erlang':%% Line 1041 'setelement' (%% Line 1041 3, _28, %% Line 1041 _rec105) in %% Line 1040 {'noreply',_30} %% Line 1044 when 'true' -> %% Line 1045 case apply 'get_loaded'/1 (AppName) of <{'true',Appl}> when 'true' -> do %% Line 1046 apply 'spawn_starter'/4 (From, Appl, S, Takeover) let = call %% Line 1047 'lists':%% Line 1047 'keydelete' (%% Line 1047 AppName, %% Line 1047 1, _149) in let = [%% Line 1048 {AppName,RestartType,Takeover,From}|%% Line 1048 NewStarting1] in let <_36> = call %% Line 1049 'erlang':%% Line 1049 'setelement' (%% Line 1049 3, %% Line 1049 S, %% Line 1049 NewStarting) in %% Line 1049 {'noreply',_36} ( <_31> when 'true' -> primop 'match_fail' ({'badmatch',_31}) -| ['compiler_generated'] ) end %% Line 1050 when call 'erlang':'=:=' (RestartType, 'permanent') -> let = apply %% Line 1051 'reply_to_requester'/3 (%% Line 1051 AppName, _rec102, %% Line 1051 Error) in let <_41> = apply %% Line 1052 'to_string'/1 (%% Line 1052 Reason) in let <_40> = call %% Line 1052 'erlang':%% Line 1052 'setelement' (%% Line 1052 8, %% Line 1052 S, %% Line 1052 Start_reqN) in %% Line 1052 {'stop',_41,_40} %% Line 1053 when 'true' -> let = apply %% Line 1054 'reply_to_requester'/3 (%% Line 1054 AppName, _rec102, %% Line 1054 Error) in let <_rec110> = call %% Line 1056 'lists':%% Line 1056 'keydelete' (%% Line 1056 AppName, %% Line 1056 1, _149) in let <_45> = call %% Line 1057 'erlang':%% Line 1057 'setelement' (%% Line 1057 8, %% Line 1055 S, %% Line 1057 Start_reqN) in let <_47> = call %% Line 1055 'erlang':%% Line 1055 'setelement' (%% Line 1055 3, _45, %% Line 1055 _rec110) in %% Line 1055 {'noreply',_47} ( <_48> when 'true' -> primop 'match_fail' ({'case_clause',_48}) -| ['compiler_generated'] ) end %% Line 1059 <'false'> when 'true' -> %% Line 1060 {'noreply',S} ( <_49> when 'true' -> primop 'match_fail' ({'case_clause',_49}) -| ['compiler_generated'] ) end -| ['compiler_generated'] ) ( <_155> when 'true' -> ( call ( 'erlang' -| ['compiler_generated'] ):( 'error' -| ['compiler_generated'] ) (( {'badrecord','state'} -| ['compiler_generated'] )) -| ['compiler_generated'] ) -| ['compiler_generated'] ) end -| ['compiler_generated'] ) %% Line 1063 <{'ac_change_application_req',AppName,Msg},S> when 'true' -> %% Line 1064 ( case S of ( <( {'state',_208,_209,_210,_rec112,_211,_212,_213,_214} -| ['compiler_generated'] )> when 'true' -> let <_60> = call %% Line 1067 'lists':%% Line 1067 'keyfind' (%% Line 1067 AppName, %% Line 1067 1, _rec112) in let <_59> = call %% Line 1067 'lists':%% Line 1067 'keyfind' (%% Line 1067 AppName, %% Line 1067 1, _212) in %% Line 1067 case <_60,_59> of %% Line 1068 <( {_232,Id} -| ['compiler_generated'] ),( {_X_AppName2,Type} -| ['compiler_generated'] )> when call 'erlang':'=:=' (_232, AppName) -> %% Line 1069 case Msg of %% Line 1070 <{'started',Node}> when 'true' -> do %% Line 1071 apply 'stop_appl'/3 (AppName, Id, Type) let <_61> = call %% Line 1073 'lists':%% Line 1073 'keydelete' (%% Line 1073 AppName, %% Line 1073 1, _rec112) in let = [%% Line 1072 {AppName,{'distributed',Node}}|_61] in let <_65> = call %% Line 1074 'erlang':%% Line 1074 'setelement' (%% Line 1074 5, %% Line 1074 S, %% Line 1074 NRunning) in %% Line 1074 {'noreply',_65} %% Line 1075 <{'takeover',_X_Node,_X_RT}> when call 'erlang':'is_pid' (Id) -> do %% Line 1076 apply 'notify_cntrl_started'/4 (AppName, Id, S, 'ok') %% Line 1077 {'noreply',S} %% Line 1078 <{'takeover',Node,RT}> when 'true' -> let = apply %% Line 1079 'do_start'/5 (%% Line 1079 AppName, %% Line 1079 RT, %% Line 1079 {'takeover',Node}, %% Line 1079 'undefined', %% Line 1079 S) in %% Line 1080 {'noreply',NewS} %% Line 1081 <{'failover',_X_Node,_X_RT}> when call 'erlang':'is_pid' (Id) -> do %% Line 1082 apply 'notify_cntrl_started'/4 (AppName, Id, S, 'ok') %% Line 1083 {'noreply',S} %% Line 1084 <{'failover',Node,RT}> when 'true' -> %% Line 1085 case call 'application':'get_key' (AppName, 'start_phases') of %% Line 1086 <{'ok','undefined'}> when 'true' -> let = apply %% Line 1090 'do_start'/5 (%% Line 1090 AppName, %% Line 1090 RT, %% Line 1090 'normal', %% Line 1090 'undefined', %% Line 1090 S) in %% Line 1091 {'noreply',NewS} %% Line 1092 <{'ok',_X_StartPhases}> when 'true' -> let = apply %% Line 1093 'do_start'/5 (%% Line 1093 AppName, %% Line 1093 RT, %% Line 1093 {'failover',Node}, %% Line 1093 'undefined', %% Line 1093 S) in %% Line 1094 {'noreply',NewS} ( <_69> when 'true' -> primop 'match_fail' ({'case_clause',_69}) -| ['compiler_generated'] ) end %% Line 1096 <'stop_it'> when 'true' -> do %% Line 1097 apply 'stop_appl'/3 (AppName, Id, Type) do %% Line 1098 apply 'cntrl'/3 (AppName, S, {'ac_application_not_run',AppName}) let = call %% Line 1099 'lists':%% Line 1099 'keyreplace' (%% Line 1099 AppName, %% Line 1099 1, _rec112, %% Line 1100 {AppName,{'distributed',[]}}) in let <_73> = call %% Line 1101 'erlang':%% Line 1101 'setelement' (%% Line 1101 5, %% Line 1101 S, %% Line 1101 NRunning) in %% Line 1101 {'noreply',_73} %% Line 1103 <'start_it'> when call 'erlang':'is_pid' (Id) -> do %% Line 1104 apply 'notify_cntrl_started'/4 (AppName, Id, S, 'ok') %% Line 1105 {'noreply',S} %% Line 1106 <'start_it'> when 'true' -> let = apply %% Line 1107 'do_start'/5 (%% Line 1107 AppName, %% Line 1107 'undefined', %% Line 1107 'normal', %% Line 1107 'undefined', %% Line 1107 S) in %% Line 1108 {'noreply',NewS} %% Line 1109 <'not_running'> when 'true' -> let = call %% Line 1110 'lists':%% Line 1110 'keydelete' (%% Line 1110 AppName, %% Line 1110 1, _rec112) in let <_78> = call %% Line 1111 'erlang':%% Line 1111 'setelement' (%% Line 1111 5, %% Line 1111 S, %% Line 1111 NRunning) in %% Line 1111 {'noreply',_78} %% Line 1112 <_260> when 'true' -> %% Line 1113 {'noreply',S} end %% Line 1115 <( _340 -| ['compiler_generated'] ),( _341 -| ['compiler_generated'] )> when 'true' -> let = apply %% Line 1116 'get_loaded'/1 (%% Line 1116 AppName) in let = call %% Line 1117 'lists':%% Line 1117 'keysearch' (%% Line 1117 AppName, %% Line 1117 1, _209) in let = call %% Line 1118 'lists':%% Line 1118 'keysearch' (%% Line 1118 AppName, %% Line 1118 1, _212) in let = call %% Line 1119 'lists':%% Line 1119 'keysearch' (%% Line 1119 AppName, %% Line 1119 1, _rec112) in %% Line 1121 case Msg of %% Line 1122 <'start_it'> when 'true' -> %% Line 1123 case of %% Line 1125 <_262,_263,_264,( {( 'value' -| ['compiler_generated'] ),_X_Tuple} -| ['compiler_generated'] )> when 'true' -> %% Line 1126 {'noreply',S} %% Line 1128 <( 'false' -| ['compiler_generated'] ),_265,_266,_267> when 'true' -> %% Line 1129 {'noreply',S} %% Line 1131 <( {( 'true' -| ['compiler_generated'] ),_X_Appl} -| ['compiler_generated'] ),( 'false' -| ['compiler_generated'] ),( 'false' -| ['compiler_generated'] ),( 'false' -| ['compiler_generated'] )> when 'true' -> %% Line 1132 {'noreply',S} %% Line 1134 <( {( 'true' -| ['compiler_generated'] ),_X_Appl} -| ['compiler_generated'] ),( {( 'value' -| ['compiler_generated'] ),Tuple} -| ['compiler_generated'] ),( 'false' -| ['compiler_generated'] ),( 'false' -| ['compiler_generated'] )> when 'true' -> %% Line 1135 case Tuple of <{_X_AppName,_X_RStype,_X_Type,From}> when 'true' -> let = apply %% Line 1136 'do_start'/5 (%% Line 1136 AppName, %% Line 1136 'undefined', %% Line 1136 'normal', %% Line 1136 From, %% Line 1136 S) in %% Line 1137 {'noreply',NewS} ( <_84> when 'true' -> primop 'match_fail' ({'badmatch',_84}) -| ['compiler_generated'] ) end %% Line 1139 <( {( 'true' -| ['compiler_generated'] ),_X_Appl} -| ['compiler_generated'] ),_268,( {( 'value' -| ['compiler_generated'] ),( {_269,_X_RestartType} -| ['compiler_generated'] )} -| ['compiler_generated'] ),( 'false' -| ['compiler_generated'] )> when call 'erlang':'=:=' (_269, AppName) -> let = apply %% Line 1140 'do_start'/5 (%% Line 1140 AppName, %% Line 1140 'undefined', %% Line 1140 'normal', %% Line 1140 'undefined', %% Line 1140 S) in let <_rec118> = call %% Line 1141 'lists':%% Line 1141 'keydelete' (%% Line 1141 AppName, %% Line 1141 1, _212) in %% Line 1141 case NewS of <{'state',_270,_271,_272,_273,_274,_275,_276,_277}> when 'true' -> let <_90> = call 'erlang':'setelement' (7, NewS, _rec118) in %% Line 1142 {'noreply',_90} ( <_278> when 'true' -> ( call ( 'erlang' -| ['compiler_generated'] ):( 'error' -| ['compiler_generated'] ) (( {'badrecord','state'} -| ['compiler_generated'] )) -| ['compiler_generated'] ) -| ['compiler_generated'] ) end ( <( _344 -| ['compiler_generated'] ),( _345 -| ['compiler_generated'] ),( _346 -| ['compiler_generated'] ),( _347 -| ['compiler_generated'] )> when 'true' -> let <_92> = {( _344 -| ['compiler_generated'] ),( _345 -| ['compiler_generated'] ),( _346 -| ['compiler_generated'] ),( _347 -| ['compiler_generated'] )} in primop 'match_fail' ({'case_clause',_92}) -| ['compiler_generated'] ) end %% Line 1144 <{'started',Node}> when 'true' -> let <_93> = call %% Line 1146 'lists':%% Line 1146 'keydelete' (%% Line 1146 AppName, %% Line 1146 1, _rec112) in let = [%% Line 1145 {AppName,{'distributed',Node}}|_93] in let <_97> = call %% Line 1147 'erlang':%% Line 1147 'setelement' (%% Line 1147 5, %% Line 1147 S, %% Line 1147 NRunning) in %% Line 1147 {'noreply',_97} %% Line 1148 <_288> when 'true' -> %% Line 1149 {'noreply',S} end end -| ['compiler_generated'] ) ( <_215> when 'true' -> ( call ( 'erlang' -| ['compiler_generated'] ):( 'error' -| ['compiler_generated'] ) (( {'badrecord','state'} -| ['compiler_generated'] )) -| ['compiler_generated'] ) -| ['compiler_generated'] ) end -| ['compiler_generated'] ) %% Line 1157 <{'EXIT',Pid,Reason},S> when 'true' -> do %% Line 1158 call 'ets':'match_delete' ('ac_tab', {{'application_master','_'},Pid}) %% Line 1159 ( case S of ( <( {'state',_289,_290,_291,_rec121,_292,_293,_294,_295} -| ['compiler_generated'] )> when 'true' -> let = call 'lists':'keydelete' (Pid, 2, _rec121) in let <_105> = call %% Line 1160 'erlang':%% Line 1160 'setelement' (%% Line 1160 5, %% Line 1160 S, %% Line 1160 NRunning) in %% Line 1161 case call 'lists':'keyfind' (Pid, 2, _rec121) of %% Line 1162 <{AppName,_X_AmPid}> when 'true' -> do %% Line 1163 apply 'cntrl'/3 (AppName, S, {'ac_application_stopped',AppName}) %% Line 1164 case call 'lists':'keyfind' (AppName, 1, _293) of %% Line 1165 <{_X_AppName,'temporary'}> when 'true' -> do %% Line 1166 apply 'info_exited'/3 (AppName, Reason, 'temporary') %% Line 1167 {'noreply',_105} %% Line 1168 <{_X_AppName,'transient'}> when call 'erlang':'=:=' (Reason, 'normal') -> do %% Line 1169 apply 'info_exited'/3 (AppName, Reason, 'transient') %% Line 1170 {'noreply',_105} %% Line 1171 <{_X_AppName,Type}> when 'true' -> do %% Line 1172 apply 'info_exited'/3 (AppName, Reason, Type) let <_111> = apply %% Line 1173 'to_string'/1 (%% Line 1173 {'application_terminated',AppName,Reason}) in %% Line 1173 {'stop',_111,_105} ( <_112> when 'true' -> primop 'match_fail' ({'case_clause',_112}) -| ['compiler_generated'] ) end %% Line 1175 <'false'> when 'true' -> let <_rec125> = apply %% Line 1176 'del_cntrl'/2 (_292, %% Line 1176 Pid) in let <_118> = call %% Line 1176 'erlang':%% Line 1176 'setelement' (%% Line 1176 6, %% Line 1176 S, %% Line 1176 _rec125) in %% Line 1176 {'noreply',_118} ( <_119> when 'true' -> primop 'match_fail' ({'case_clause',_119}) -| ['compiler_generated'] ) end -| ['compiler_generated'] ) ( <_296> when 'true' -> ( call ( 'erlang' -| ['compiler_generated'] ):( 'error' -| ['compiler_generated'] ) (( {'badrecord','state'} -| ['compiler_generated'] )) -| ['compiler_generated'] ) -| ['compiler_generated'] ) end -| ['compiler_generated'] ) %% Line 1179 <_339,S> when 'true' -> %% Line 1180 {'noreply',S} end 'terminate'/2 = %% Line 1184 fun (_1,_0) -> do %% Line 1185 case call 'application':'get_env' ('kernel', 'shutdown_func') of %% Line 1186 <{'ok',{M,F}}> when 'true' -> try %% Line 1187 call M:F (_1) of <_catch_value> -> _catch_value catch -> 'ok' %% Line 1188 <_15> when 'true' -> 'ok' end let <_4> = case %% Line 1192 call 'application':'get_env' ('kernel', 'shutdown_timeout') of %% Line 1193 <'undefined'> when 'true' -> 'infinity' %% Line 1194 <{'ok',T}> when 'true' -> T ( <_3> when 'true' -> %% Line 1192 primop 'match_fail' ({'case_clause',_3}) -| ['compiler_generated'] ) end in let <_11> = fun (_9) -> %% Line 1196 case _9 of <{_X_AppName,Id}> when call 'erlang':'is_pid' (Id) -> let = call %% Line 1197 'erlang':%% Line 1197 'monitor' (%% Line 1197 'process', %% Line 1197 Id) in do %% Line 1198 call 'erlang':'unlink' (Id) do %% Line 1199 call 'erlang':'exit' (Id, 'shutdown') %% Line 1200 receive %% Line 1202 <{'EXIT',_16,_17}> when call 'erlang':'=:=' (_16, Id) -> 'ok' after %% Line 1203 0 -> %% Line 1204 receive %% Line 1205 <{'DOWN',_18,'process',_19,_20}> when let <_21> = call 'erlang':'=:=' (_18, Ref) in let <_22> = call 'erlang':'=:=' (_19, Id) in call 'erlang':'and' (_21, _22) -> 'ok' after _4 -> do %% Line 1207 call 'erlang':'exit' (Id, 'kill') %% Line 1208 receive %% Line 1209 <{'DOWN',_23,'process',_24,_25}> when let <_26> = call 'erlang':'=:=' (_23, Ref) in let <_27> = call 'erlang':'=:=' (_24, Id) in call 'erlang':'and' (_26, _27) -> 'ok' after 'infinity' -> 'true' %% Line 1213 <_28> when 'true' -> 'ok' end in %% Line 1215 ( case _0 of ( <( {'state',_29,_30,_31,_rec128,_32,_33,_34,_35} -| ['compiler_generated'] )> when 'true' -> do call 'lists':'foreach' (_11, _rec128) %% Line 1216 case call 'ets':'delete' ('ac_tab') of <'true'> when 'true' -> %% Line 1217 'ok' ( <_12> when 'true' -> primop 'match_fail' ({'badmatch',_12}) -| ['compiler_generated'] ) end -| ['compiler_generated'] ) ( <_36> when 'true' -> ( call ( 'erlang' -| ['compiler_generated'] ):( 'error' -| ['compiler_generated'] ) (( {'badrecord','state'} -| ['compiler_generated'] )) -| ['compiler_generated'] ) -| ['compiler_generated'] ) end -| ['compiler_generated'] ) 'code_change'/3 = %% Line 1221 fun (_2,_1,_0) -> %% Line 1222 {'ok',_1} 'cntrl'/3 = %% Line 1228 fun (_2,_1,_0) -> case <_2,_1,_0> of when 'true' -> %% Line 1229 case call 'lists':'keyfind' (AppName, 1, Control) of %% Line 1230 <{_X_AppName,Pid}> when 'true' -> do %% Line 1231 call 'erlang':'!' (Pid, Msg) %% Line 1232 'true' %% Line 1233 <'false'> when 'true' -> %% Line 1234 'false' ( <_3> when 'true' -> primop 'match_fail' ({'case_clause',_3}) -| ['compiler_generated'] ) end ( <_6,_5,_4> when 'true' -> ( primop 'match_fail' ({'function_clause',_6,_5,_4}) -| [{'function_name',{'cntrl',3}}] ) -| ['compiler_generated'] ) end 'notify_cntrl_started'/4 = %% Line 1237 fun (_3,_2,_1,_0) -> case <_3,_2,_1,_0> of <_X_AppName,{'distributed',_X_Node},_X_S,_X_Res> when 'true' -> %% Line 1238 'ok' %% Line 1239 when 'true' -> %% Line 1240 apply 'cntrl'/3 (AppName, S, {'ac_application_run',AppName,Res}) end 'del_cntrl'/2 = %% Line 1242 fun (_1,_0) -> case <_1,_0> of <[{_5,Pid}|T],_6> when call 'erlang':'=:=' (_6, Pid) -> %% Line 1243 apply 'del_cntrl'/2 (T, Pid) %% Line 1244 <[H|T],Pid> when 'true' -> let <_2> = apply %% Line 1245 'del_cntrl'/2 (%% Line 1245 T, %% Line 1245 Pid) in %% Line 1245 [H|_2] %% Line 1246 <[],_X_Pid> when 'true' -> %% Line 1247 [] ( <_4,_3> when 'true' -> ( primop 'match_fail' ({'function_clause',_4,_3}) -| [{'function_name',{'del_cntrl',2}}] ) -| ['compiler_generated'] ) end 'get_loaded'/1 = %% Line 1249 fun (_0) -> let = apply %% Line 1250 'get_appl_name'/1 (_0) in %% Line 1251 case call 'ets':'lookup' ('ac_tab', {'loaded',AppName}) of %% Line 1252 <[{_X_Key,Appl}|[]]> when 'true' -> {'true',Appl} %% Line 1253 <_4> when 'true' -> 'false' end 'do_load_application'/2 = %% Line 1256 fun (_1,_0) -> %% Line 1257 case apply 'get_loaded'/1 (_1) of %% Line 1258 <{'true',_6}> when 'true' -> %% Line 1259 call 'erlang':'throw' ({'error',{'already_loaded',_1}}) %% Line 1260 <'false'> when 'true' -> %% Line 1261 case apply 'make_appl'/1 (_1) of %% Line 1262 <{'ok',Appl}> when 'true' -> apply 'load'/2 (_0, Appl) %% Line 1263 when 'true' -> Error end ( <_3> when 'true' -> primop 'match_fail' ({'case_clause',_3}) -| ['compiler_generated'] ) end 'load'/2 = %% Line 1269 fun (_1,_0) -> case <_1,_0> of when 'true' -> %% Line 1270 ( case ApplData of ( <( {'appl_data',_rec129,_20,_21,_22,_23,_24,_25,_26} -| ['compiler_generated'] )> when 'true' -> let = apply %% Line 1271 'get_env_i'/2 (_rec129, %% Line 1271 S) in let = apply %% Line 1272 'merge_app_env'/2 (%% Line 1272 ApplEnv, %% Line 1272 ConfEnv) in let = apply %% Line 1273 'get_cmd_env'/1 (_rec129) in let = apply %% Line 1274 'merge_app_env'/2 (%% Line 1274 NewEnv, %% Line 1274 CmdLineEnv) in do %% Line 1275 apply 'add_env'/2 (_rec129, NewEnv2) let = {%% Line 1276 'appl',_rec129,%% Line 1277 ApplData,%% Line 1276 Descr,%% Line 1276 Id,%% Line 1276 Vsn,'undefined',%% Line 1277 IncApps,%% Line 1277 Apps} in do %% Line 1278 call 'ets':'insert' ('ac_tab', {{'loaded',_rec129},Appl}) let <_16> = fun (_13,_12) -> %% Line 1281 case apply 'get_loaded'/1 (_13) of %% Line 1282 <{'true',_28}> when 'true' -> _12 %% Line 1283 <'false'> when 'true' -> %% Line 1284 case apply 'do_load_application'/2 (_13, _12) of %% Line 1285 <{'ok',S2}> when 'true' -> S2 %% Line 1286 when 'true' -> call 'erlang':'throw' (Error) end ( <_11> when 'true' -> primop 'match_fail' ({'case_clause',_11}) -| ['compiler_generated'] ) end in let = call %% Line 1280 'lists':%% Line 1280 'foldl' (_16, %% Line 1289 S, %% Line 1289 IncApps) in %% Line 1290 {'ok',NewS} -| ['compiler_generated'] ) ( <_27> when 'true' -> ( call ( 'erlang' -| ['compiler_generated'] ):( 'error' -| ['compiler_generated'] ) (( {'badrecord','appl_data'} -| ['compiler_generated'] )) -| ['compiler_generated'] ) -| ['compiler_generated'] ) end -| ['compiler_generated'] ) ( <_19,_18> when 'true' -> ( primop 'match_fail' ({'function_clause',_19,_18}) -| [{'function_name',{'load',2}}] ) -| ['compiler_generated'] ) end 'unload'/2 = %% Line 1292 fun (_1,_0) -> %% Line 1293 case apply 'get_key'/2 (_1, 'included_applications') of <{'ok',IncApps}> when 'true' -> do %% Line 1294 apply 'del_env'/1 (_1) do %% Line 1295 call 'ets':'delete' ('ac_tab', {'loaded',_1}) let <_8> = fun (_5,_4) -> %% Line 1297 case apply 'get_loaded'/1 (_5) of %% Line 1298 <'false'> when 'true' -> _4 %% Line 1299 <{'true',_11}> when 'true' -> apply 'unload'/2 (_5, _4) ( <_3> when 'true' -> primop 'match_fail' ({'case_clause',_3}) -| ['compiler_generated'] ) end in %% Line 1296 call 'lists':'foldl' (_8, _0, %% Line 1301 IncApps) ( <_2> when 'true' -> primop 'match_fail' ({'badmatch',_2}) -| ['compiler_generated'] ) end 'check_start_cond'/4 = %% Line 1303 fun (_3,_2,_1,_0) -> do %% Line 1304 apply 'validRestartType'/1 (_2) %% Line 1305 case apply 'get_loaded'/1 (_3) of %% Line 1306 <{'true',Appl}> when 'true' -> %% Line 1309 case call 'lists':'keymember' (_3, 1, _0) of %% Line 1310 <'true'> when 'true' -> %% Line 1311 {'error',{'already_started',_3}} %% Line 1312 <'false'> when 'true' -> let <_9> = fun (_7) -> %% Line 1315 case call 'lists':'keymember' (_7, 1, _1) of %% Line 1316 <'true'> when 'true' -> 'ok' %% Line 1317 <'false'> when 'true' -> %% Line 1318 call 'erlang':'throw' ({'error',{'not_started',_7}}) ( <_6> when 'true' -> primop 'match_fail' ({'case_clause',_6}) -| ['compiler_generated'] ) end in %% Line 1320 ( case Appl of ( <( {'appl',_16,_17,_18,_19,_20,_21,_22,_rec130} -| ['compiler_generated'] )> when 'true' -> do call 'lists':'foreach' (_9, _rec130) %% Line 1321 {'ok',Appl} -| ['compiler_generated'] ) ( <_23> when 'true' -> ( call ( 'erlang' -| ['compiler_generated'] ):( 'error' -| ['compiler_generated'] ) (( {'badrecord','appl'} -| ['compiler_generated'] )) -| ['compiler_generated'] ) -| ['compiler_generated'] ) end -| ['compiler_generated'] ) ( <_10> when 'true' -> primop 'match_fail' ({'case_clause',_10}) -| ['compiler_generated'] ) end %% Line 1323 <'false'> when 'true' -> %% Line 1324 {'error',{'not_loaded',_3}} ( <_11> when 'true' -> primop 'match_fail' ({'case_clause',_11}) -| ['compiler_generated'] ) end 'do_start'/5 = %% Line 1327 fun (_4,_3,_2,_1,_0) -> %% Line 1328 ( case _0 of ( <( {'state',_34,_35,_36,_37,_38,_rec131,_39,_40} -| ['compiler_generated'] )> when 'true' -> let <_8> = case call 'lists':'keyfind' (_4, 1, _rec131) of %% Line 1329 <{_X_AppName2,OldRT}> when 'true' -> %% Line 1330 apply 'get_restart_type'/2 (_3, OldRT) %% Line 1331 <'false'> when 'true' -> _3 ( <_7> when 'true' -> primop 'match_fail' ({'case_clause',_7}) -| ['compiler_generated'] ) end in %% Line 1336 case call 'lists':'keymember' (_4, 1, _39) of %% Line 1337 <'false'> when 'true' -> %% Line 1338 case apply 'get_loaded'/1 (_4) of <{'true',Appl}> when 'true' -> do %% Line 1340 apply 'spawn_starter'/4 ('undefined', Appl, _0, _2) let <_22> = case %% Line 1341 call 'lists':'keymember' (_4, 1, _35) of %% Line 1342 <'false'> when 'true' -> %% Line 1344 [{_4,_8,_2,_1}|_35] %% Line 1346 <'true'> when 'true' -> _35 ( <_21> when 'true' -> %% Line 1341 primop 'match_fail' ({'case_clause',_21}) -| ['compiler_generated'] ) end in let <_rec137> = [%% Line 1350 {_4,_1}|_39] in let <_26> = call %% Line 1350 'erlang':%% Line 1350 'setelement' (%% Line 1350 8, _0, %% Line 1350 _rec137) in %% Line 1349 call 'erlang':'setelement' (3, _26, _22) ( <_12> when 'true' -> primop 'match_fail' ({'badmatch',_12}) -| ['compiler_generated'] ) end %% Line 1351 <'true'> when 'true' -> _0 ( <_28> when 'true' -> primop 'match_fail' ({'case_clause',_28}) -| ['compiler_generated'] ) end -| ['compiler_generated'] ) ( <_41> when 'true' -> ( call ( 'erlang' -| ['compiler_generated'] ):( 'error' -| ['compiler_generated'] ) (( {'badrecord','state'} -| ['compiler_generated'] )) -| ['compiler_generated'] ) -| ['compiler_generated'] ) end -| ['compiler_generated'] ) 'spawn_starter'/4 = %% Line 1355 fun (_3,_2,_1,_0) -> %% Line 1356 call 'erlang':'spawn_link' ('application_controller', 'init_starter', [_3|[_2|[_1|[_0|[]]]]]) 'init_starter'/4 = %% Line 1358 fun (_3,_2,_1,_0) -> do %% Line 1359 call 'erlang':'process_flag' ('trap_exit', 'true') %% Line 1360 ( case _2 of ( <( {'appl',_rec139,_12,_13,_14,_15,_16,_17,_18} -| ['compiler_generated'] )> when 'true' -> let <_7> = catch %% Line 1362 apply 'start_appl'/3 (_2, _1, _0) in %% Line 1361 call 'gen_server':'cast' ('application_controller', {'application_started',_rec139,_7}) -| ['compiler_generated'] ) ( <_19> when 'true' -> ( call ( 'erlang' -| ['compiler_generated'] ):( 'error' -| ['compiler_generated'] ) (( {'badrecord','appl'} -| ['compiler_generated'] )) -| ['compiler_generated'] ) -| ['compiler_generated'] ) end -| ['compiler_generated'] ) 'reply'/2 = %% Line 1364 fun (_1,_0) -> case <_1,_0> of <'undefined',_X_Reply> when 'true' -> %% Line 1365 'ok' %% Line 1366 when 'true' -> call 'gen_server':'reply' (From, Reply) end 'start_appl'/3 = %% Line 1368 fun (_2,_1,_0) -> %% Line 1369 ( case _2 of ( <( {'appl',_22,_rec140,_23,_24,_25,_26,_27,_28} -| ['compiler_generated'] )> when 'true' -> %% Line 1370 ( case _rec140 of ( <( {'appl_data',_30,_31,_32,_rec141,_33,_34,_35,_36} -| ['compiler_generated'] )> when 'true' -> case _rec141 of %% Line 1371 <[]> when 'true' -> %% Line 1372 {'ok','undefined'} %% Line 1373 <_38> when 'true' -> %% Line 1375 ( case _1 of ( <( {'state',_39,_40,_41,_rec142,_42,_43,_44,_45} -| ['compiler_generated'] )> when 'true' -> let <_16> = fun (_14) -> %% Line 1378 case call 'lists':'keymember' (_14, 1, _rec142) of %% Line 1379 <'true'> when 'true' -> %% Line 1380 'ok' %% Line 1381 <'false'> when 'true' -> %% Line 1382 call 'erlang':'throw' ({'info',{'not_running',_14}}) ( <_13> when 'true' -> primop 'match_fail' ({'case_clause',_13}) -| ['compiler_generated'] ) end in do %% Line 1376 call 'lists':'foreach' (_16, _28) %% Line 1385 case call 'application_master':'start_link' (_rec140, _0) of %% Line 1386 when 'true' -> %% Line 1387 Ok %% Line 1388 when 'true' -> %% Line 1389 call 'erlang':'throw' (Error) ( <_17> when 'true' -> primop 'match_fail' ({'case_clause',_17}) -| ['compiler_generated'] ) end -| ['compiler_generated'] ) ( <_46> when 'true' -> ( call ( 'erlang' -| ['compiler_generated'] ):( 'error' -| ['compiler_generated'] ) (( {'badrecord','state'} -| ['compiler_generated'] )) -| ['compiler_generated'] ) -| ['compiler_generated'] ) end -| ['compiler_generated'] ) end -| ['compiler_generated'] ) ( <_37> when 'true' -> ( call ( 'erlang' -| ['compiler_generated'] ):( 'error' -| ['compiler_generated'] ) (( {'badrecord','appl_data'} -| ['compiler_generated'] )) -| ['compiler_generated'] ) -| ['compiler_generated'] ) end -| ['compiler_generated'] ) -| ['compiler_generated'] ) ( <_29> when 'true' -> ( call ( 'erlang' -| ['compiler_generated'] ):( 'error' -| ['compiler_generated'] ) (( {'badrecord','appl'} -| ['compiler_generated'] )) -| ['compiler_generated'] ) -| ['compiler_generated'] ) end -| ['compiler_generated'] ) 'stop_appl'/3 = %% Line 1397 fun (_2,_1,_0) -> case <_2,_1,_0> of when call 'erlang':'is_pid' (Id) -> do %% Line 1398 call 'erlang':'unlink' (Id) do %% Line 1399 call 'application_master':'stop' (Id) do %% Line 1400 apply 'info_exited'/3 (AppName, 'stopped', Type) %% Line 1401 call 'ets':'delete' ('ac_tab', {'application_master',AppName}) %% Line 1402 when 'true' -> %% Line 1404 apply 'info_exited'/3 (AppName, 'stopped', Type) %% Line 1405 <_X_AppName,_X_Id,_X_Type> when 'true' -> %% Line 1407 'ok' end 'keysearchdelete'/3 = %% Line 1409 fun (_2,_1,_0) -> %% Line 1410 apply 'ksd'/4 (_2, _1, _0, []) 'ksd'/4 = %% Line 1412 fun (_3,_2,_1,_0) -> case <_3,_2,_1,_0> of when try let <_4> = call 'erlang':'element' (Pos, H) in call 'erlang':'=:=' (_4, Key) of -> Try catch -> 'false' -> let <_5> = call %% Line 1413 'erlang':%% Line 1413 '++' (%% Line 1413 Rest, %% Line 1413 T) in %% Line 1413 {'value',H,_5} %% Line 1414 when 'true' -> %% Line 1415 apply 'ksd'/4 (Key, Pos, T, [H|Rest]) %% Line 1416 <_X_Key,_X_Pos,[],_X_Rest> when 'true' -> %% Line 1417 'false' ( <_9,_8,_7,_6> when 'true' -> ( primop 'match_fail' ({'function_clause',_9,_8,_7,_6}) -| [{'function_name',{'ksd',4}}] ) -| ['compiler_generated'] ) end 'keyreplaceadd'/4 = %% Line 1419 fun (_3,_2,_1,_0) -> %% Line 1421 case call 'lists':'keymember' (_3, _2, _1) of %% Line 1422 <'true'> when 'true' -> call 'lists':'keyreplace' (_3, _2, _1, _0) %% Line 1423 <'false'> when 'true' -> [_0|_1] ( <_4> when 'true' -> primop 'match_fail' ({'case_clause',_4}) -| ['compiler_generated'] ) end 'validRestartType'/1 = %% Line 1426 fun (_0) -> case _0 of <'permanent'> when 'true' -> 'true' %% Line 1427 <'temporary'> when 'true' -> 'true' %% Line 1428 <'transient'> when 'true' -> 'true' %% Line 1429 when 'true' -> %% Line 1430 call 'erlang':'throw' ({'error',{'invalid_restart_type',RestartType}}) end 'nd'/1 = %% Line 1432 fun (_0) -> case _0 of <{'distributed',Node}> when 'true' -> Node %% Line 1433 <_2> when 'true' -> call 'erlang':'node' () end 'get_restart_type'/2 = %% Line 1435 fun (_1,_0) -> case <_1,_0> of <'undefined',OldRT> when 'true' -> %% Line 1436 OldRT %% Line 1437 when 'true' -> %% Line 1438 RT end 'get_appl_name'/1 = %% Line 1440 fun (_0) -> case _0 of when call 'erlang':'is_atom' (_0) -> Name %% Line 1441 <{'application',Name,_2}> when call 'erlang':'is_atom' (Name) -> Name %% Line 1442 when 'true' -> call 'erlang':'throw' ({'error',{'bad_application',Appl}}) end 'make_appl'/1 = %% Line 1444 fun (_0) -> case _0 of when call 'erlang':'is_atom' (_0) -> let <_1> = call %% Line 1445 'erlang':%% Line 1445 'atom_to_list' (%% Line 1445 Name) in let = call %% Line 1445 'erlang':%% Line 1445 '++' (_1, %% Line 1445 [46|[97|[112|[112]]]]) in %% Line 1446 case call 'code':'where_is_file' (FName) of %% Line 1447 <'non_existing'> when 'true' -> let <_3> = call %% Line 1448 'file':%% Line 1448 'format_error' (%% Line 1448 'enoent') in %% Line 1448 {'error',{_3,FName}} %% Line 1449 when 'true' -> %% Line 1450 case apply 'prim_consult'/1 (FullName) of %% Line 1451 <{'ok',[Application|[]]}> when 'true' -> let <_4> = apply %% Line 1452 'make_appl_i'/1 (%% Line 1452 Application) in %% Line 1452 {'ok',_4} %% Line 1453 <{'error',Reason}> when 'true' -> let <_5> = call %% Line 1454 'file':%% Line 1454 'format_error' (%% Line 1454 Reason) in %% Line 1454 {'error',{_5,FName}} %% Line 1455 <'error'> when 'true' -> %% Line 1456 {'error',[98|[97|[100|[32|[101|[110|[99|[111|[100|[105|[110|[103]]]]]]]]]]]]} ( <_6> when 'true' -> primop 'match_fail' ({'case_clause',_6}) -| ['compiler_generated'] ) end end %% Line 1459 when 'true' -> let <_8> = apply %% Line 1460 'make_appl_i'/1 (%% Line 1460 Application) in %% Line 1460 {'ok',_8} end 'prim_consult'/1 = %% Line 1462 fun (_0) -> %% Line 1463 case call 'erl_prim_loader':'get_file' (_0) of %% Line 1464 <{'ok',Bin,_5}> when 'true' -> %% Line 1465 case apply 'file_binary_to_list'/1 (Bin) of %% Line 1466 <{'ok',String}> when 'true' -> %% Line 1467 case call 'erl_scan':'string' (String) of %% Line 1468 <{'ok',Tokens,_X_EndLine}> when 'true' -> %% Line 1469 apply 'prim_parse'/2 (Tokens, []) %% Line 1470 <{'error',Reason,_X_EndLine}> when 'true' -> %% Line 1471 {'error',Reason} ( <_1> when 'true' -> primop 'match_fail' ({'case_clause',_1}) -| ['compiler_generated'] ) end %% Line 1473 <'error'> when 'true' -> %% Line 1474 'error' ( <_2> when 'true' -> primop 'match_fail' ({'case_clause',_2}) -| ['compiler_generated'] ) end %% Line 1476 <'error'> when 'true' -> %% Line 1477 {'error','enoent'} ( <_3> when 'true' -> primop 'match_fail' ({'case_clause',_3}) -| ['compiler_generated'] ) end 'prim_parse'/2 = %% Line 1480 fun (_1,_0) -> let <_5> = fun (_3) -> let <_2> = call %% Line 1481 'erlang':%% Line 1481 'element' (%% Line 1481 1, %% Line 1481 _3) in %% Line 1481 call 'erlang':'=/=' (_2, 'dot') in %% Line 1481 case call 'lists':'splitwith' (_5, _1) of %% Line 1482 <{[],[]}> when 'true' -> let <_6> = call %% Line 1483 'lists':%% Line 1483 'reverse' (_0) in %% Line 1483 {'ok',_6} %% Line 1484 <{Tokens2,[Dot = {'dot',_14}|Rest]}> when 'true' -> let <_7> = call %% Line 1485 'erlang':%% Line 1485 '++' (%% Line 1485 Tokens2, %% Line 1485 [Dot|[]]) in %% Line 1485 case call 'erl_parse':'parse_term' (_7) of %% Line 1486 <{'ok',Term}> when 'true' -> %% Line 1487 apply 'prim_parse'/2 (Rest, [Term|_0]) %% Line 1488 when 'true' -> %% Line 1489 Error ( <_8> when 'true' -> primop 'match_fail' ({'case_clause',_8}) -| ['compiler_generated'] ) end %% Line 1491 <{Tokens2,[]}> when 'true' -> %% Line 1492 case call 'erl_parse':'parse_term' (Tokens2) of %% Line 1493 <{'ok',Term}> when 'true' -> let <_9> = call %% Line 1494 'lists':%% Line 1494 'reverse' (%% Line 1494 [Term|_0]) in %% Line 1494 {'ok',_9} %% Line 1495 when 'true' -> %% Line 1496 Error ( <_10> when 'true' -> primop 'match_fail' ({'case_clause',_10}) -| ['compiler_generated'] ) end ( <_11> when 'true' -> primop 'match_fail' ({'case_clause',_11}) -| ['compiler_generated'] ) end 'make_appl_i'/1 = %% Line 1500 fun (_0) -> case _0 of <{'application',Name,Opts}> when let <_1> = call 'erlang':'is_atom' (Name) in let <_2> = call 'erlang':'is_list' (Opts) in call 'erlang':'and' (_1, _2) -> let = apply %% Line 1501 'get_opt'/3 (%% Line 1501 'description', %% Line 1501 Opts, %% Line 1501 []) in let = apply %% Line 1502 'get_opt'/3 (%% Line 1502 'id', %% Line 1502 Opts, %% Line 1502 []) in let = apply %% Line 1503 'get_opt'/3 (%% Line 1503 'vsn', %% Line 1503 Opts, %% Line 1503 []) in let = apply %% Line 1504 'get_opt'/3 (%% Line 1504 'modules', %% Line 1504 Opts, %% Line 1504 []) in let = apply %% Line 1505 'get_opt'/3 (%% Line 1505 'registered', %% Line 1505 Opts, %% Line 1505 []) in let = apply %% Line 1506 'get_opt'/3 (%% Line 1506 'applications', %% Line 1506 Opts, %% Line 1506 []) in let <_10> = case %% Line 1508 apply 'get_opt'/3 ('mod', Opts, []) of %% Line 1509 when call 'erlang':'is_atom' (M) -> MA %% Line 1510 <[]> when 'true' -> [] %% Line 1511 when 'true' -> call 'erlang':'throw' ({'error',{'badstartspec',Other}}) end in let = apply %% Line 1513 'get_opt'/3 (%% Line 1513 'start_phases', %% Line 1513 Opts, %% Line 1513 'undefined') in let = apply %% Line 1514 'get_opt'/3 (%% Line 1514 'env', %% Line 1514 Opts, %% Line 1514 []) in let = apply %% Line 1515 'get_opt'/3 (%% Line 1515 'maxP', %% Line 1515 Opts, %% Line 1515 'infinity') in let = apply %% Line 1516 'get_opt'/3 (%% Line 1516 'maxT', %% Line 1516 Opts, %% Line 1516 'infinity') in let = apply %% Line 1517 'get_opt'/3 (%% Line 1517 'included_applications', %% Line 1517 Opts, %% Line 1517 []) in %% Line 1518 {{'appl_data',Name,Regs,Phases,_10,%% Line 1519 Mods,%% Line 1519 IncApps,%% Line 1519 MaxP,%% Line 1519 MaxT},%% Line 1520 Env,%% Line 1520 IncApps,%% Line 1520 Descr,%% Line 1520 Id,%% Line 1520 Vsn,%% Line 1520 Apps} %% Line 1521 <{'application',Name,Opts}> when call 'erlang':'is_list' (Opts) -> %% Line 1522 call 'erlang':'throw' ({'error',{'invalid_name',Name}}) %% Line 1523 <{'application',_X_Name,Opts}> when 'true' -> %% Line 1524 call 'erlang':'throw' ({'error',{'invalid_options',Opts}}) %% Line 1525 when 'true' -> call 'erlang':'throw' ({'error',{'bad_application',Appl}}) end 'do_change_apps'/3 = %% Line 1536 fun (_2,_1,_0) -> %% Line 1543 case apply 'check_conf_sys'/1 (_1) of <{'ok',SysConfig,Errors}> when 'true' -> let <_7> = fun (_5) -> %% Line 1547 case _5 of <{'error',{SysFName,Line,Str}}> when 'true' -> %% Line 1548 case call 'logger':'allow' ('error', 'application_controller') of <'true'> when 'true' -> call 'logger':'macro_log' (~{'file'=>[97|[112|[112|[108|[105|[99|[97|[116|[105|[111|[110|[95|[99|[111|[110|[116|[114|[111|[108|[108|[101|[114|[46|[101|[114|[108]]]]]]]]]]]]]]]]]]]]]]]]]],'line'=>1548,'mfa'=>{'application_controller','do_change_apps',3}}~, 'error', [126|[116|[112|[58|[32|[126|[119|[58|[32|[126|[116|[115|[126|[110]]]]]]]]]]]]]], [SysFName|[Line|[Str|[]]]], ~{'error_logger'=>~{'tag'=>'error'}~}~) %% Line 1549 <'false'> when 'true' -> 'ok' ( <_4> when 'true' -> primop 'match_fail' ({'case_clause',_4}) -| ['compiler_generated'] ) end ( <_6> when 'true' -> ( primop 'match_fail' ({'function_clause',_6}) -| [{'function_name',{'-do_change_apps/3-fun-0-',1}}] ) -| ['compiler_generated'] ) end in do %% Line 1547 call 'lists':'foreach' (_7, %% Line 1551 Errors) let <_15> = fun (_13) -> %% Line 1554 ( case _13 of ( <( {'appl',_rec144,_20,_21,_22,_23,_24,_25,_26} -| ['compiler_generated'] )> when 'true' -> %% Line 1555 case apply 'is_loaded_app'/2 (_rec144, _2) of %% Line 1556 <{'true',Application}> when 'true' -> let <_11> = apply %% Line 1557 'make_appl'/1 (%% Line 1557 Application) in %% Line 1557 apply 'do_change_appl'/3 (_11, _13, %% Line 1558 SysConfig) %% Line 1561 <'false'> when 'true' -> _13 ( <_12> when 'true' -> primop 'match_fail' ({'case_clause',_12}) -| ['compiler_generated'] ) end -| ['compiler_generated'] ) ( <_27> when 'true' -> ( call ( 'erlang' -| ['compiler_generated'] ):( 'error' -| ['compiler_generated'] ) (( {'badrecord','appl'} -| ['compiler_generated'] )) -| ['compiler_generated'] ) -| ['compiler_generated'] ) end -| ['compiler_generated'] ) in let <_16> = call %% Line 1553 'lists':%% Line 1553 'map' (_15, _0) in %% Line 1553 {_16,%% Line 1565 SysConfig} ( <_3> when 'true' -> primop 'match_fail' ({'badmatch',_3}) -| ['compiler_generated'] ) end 'is_loaded_app'/2 = %% Line 1567 fun (_1,_0) -> case <_1,_0> of when call 'erlang':'=:=' (_4, AppName) -> %% Line 1568 {'true',{'application',AppName,App}} %% Line 1569 when 'true' -> apply 'is_loaded_app'/2 (AppName, T) %% Line 1570 <_X_AppName,[]> when 'true' -> 'false' ( <_3,_2> when 'true' -> ( primop 'match_fail' ({'function_clause',_3,_2}) -| [{'function_name',{'is_loaded_app',2}}] ) -| ['compiler_generated'] ) end 'do_change_appl'/3 = %% Line 1572 fun (_2,_1,_0) -> case <_2,_1,_0> of <{'ok',{ApplData,Env,IncApps,Descr,Id,Vsn,Apps}},%% Line 1573 OldAppl,%% Line 1573 Config> when 'true' -> %% Line 1574 ( case OldAppl of ( <( {'appl',_rec145,_15,_16,_17,_18,_19,_20,_21} -| ['compiler_generated'] )> when 'true' -> let = apply %% Line 1577 'get_opt'/3 (_rec145, %% Line 1577 Config, %% Line 1577 []) in let = apply %% Line 1578 'merge_app_env'/2 (%% Line 1578 Env, %% Line 1578 ConfEnv) in let = apply %% Line 1581 'get_cmd_env'/1 (_rec145) in let = apply %% Line 1582 'merge_app_env'/2 (%% Line 1582 NewEnv1, %% Line 1582 CmdLineEnv) in do %% Line 1585 apply 'del_env'/1 (_rec145) do %% Line 1586 apply 'add_env'/2 (_rec145, NewEnv2) %% Line 1593 {'appl',_rec145,ApplData,Descr,Id,Vsn,_19,IncApps,Apps} -| ['compiler_generated'] ) ( <_22> when 'true' -> ( call ( 'erlang' -| ['compiler_generated'] ):( 'error' -| ['compiler_generated'] ) (( {'badrecord','appl'} -| ['compiler_generated'] )) -| ['compiler_generated'] ) -| ['compiler_generated'] ) end -| ['compiler_generated'] ) %% Line 1594 when 'true' -> %% Line 1595 call 'erlang':'throw' (Error) ( <_14,_13,_12> when 'true' -> ( primop 'match_fail' ({'function_clause',_14,_13,_12}) -| [{'function_name',{'do_change_appl',3}}] ) -| ['compiler_generated'] ) end 'get_opt'/3 = %% Line 1597 fun (_2,_1,_0) -> %% Line 1598 case call 'lists':'keyfind' (_2, 1, _1) of %% Line 1599 <{_X_Key,Val}> when 'true' -> Val %% Line 1600 <_7> when 'true' -> _0 end 'get_cmd_env'/1 = %% Line 1603 fun (_0) -> %% Line 1604 case call 'init':'get_argument' (_0) of %% Line 1605 <{'ok',Args}> when 'true' -> let <_6> = fun (_3,_2) -> let <_1> = apply %% Line 1606 'conv'/1 (_3) in %% Line 1606 call 'erlang':'++' (_1, _2) in %% Line 1606 call 'lists':'foldl' (_6, [], Args) %% Line 1607 <_9> when 'true' -> [] end 'conv'/1 = %% Line 1610 fun (_0) -> case _0 of <[Key|[Val|T]]> when 'true' -> let <_2> = apply %% Line 1611 'make_term'/1 (%% Line 1611 Key) in let <_1> = apply %% Line 1611 'make_term'/1 (%% Line 1611 Val) in let <_3> = apply %% Line 1611 'conv'/1 (%% Line 1611 T) in %% Line 1611 [{_2,_1}|_3] %% Line 1612 <_5> when 'true' -> [] end 'make_term'/1 = %% Line 1614 fun (_0) -> %% Line 1615 case call 'erl_scan':'string' (_0) of %% Line 1616 <{'ok',Tokens,_6}> when 'true' -> let <_1> = call %% Line 1617 'erl_anno':%% Line 1617 'new' (%% Line 1617 1) in let <_2> = call %% Line 1617 'erlang':%% Line 1617 '++' (%% Line 1617 Tokens, %% Line 1617 [{'dot',_1}|[]]) in %% Line 1617 case call 'erl_parse':'parse_term' (_2) of %% Line 1618 <{'ok',Term}> when 'true' -> %% Line 1619 Term %% Line 1620 <{'error',{_7,M,Reason}}> when 'true' -> %% Line 1621 apply 'handle_make_term_error'/3 (M, Reason, _0) ( <_3> when 'true' -> primop 'match_fail' ({'case_clause',_3}) -| ['compiler_generated'] ) end %% Line 1623 <{'error',{_8,M,Reason},_9}> when 'true' -> %% Line 1624 apply 'handle_make_term_error'/3 (M, Reason, _0) ( <_4> when 'true' -> primop 'match_fail' ({'case_clause',_4}) -| ['compiler_generated'] ) end 'handle_make_term_error'/3 = %% Line 1627 fun (_2,_1,_0) -> do %% Line 1628 case call 'logger':'allow' ('error', 'application_controller') of <'true'> when 'true' -> let <_3> = call _2:%% Line 1629 'format_error' (_1) in call 'logger':'macro_log' (~{'file'=>[97|[112|[112|[108|[105|[99|[97|[116|[105|[111|[110|[95|[99|[111|[110|[116|[114|[111|[108|[108|[101|[114|[46|[101|[114|[108]]]]]]]]]]]]]]]]]]]]]]]]]],'line'=>1628,'mfa'=>{'application_controller','handle_make_term_error',3}}~, 'error', [97|[112|[112|[108|[105|[99|[97|[116|[105|[111|[110|[95|[99|[111|[110|[116|[114|[111|[108|[108|[101|[114|[58|[32|[126|[116|[115|[58|[32|[126|[116|[115|[126|[110]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]], %% Line 1629 [_3|[_0|[]]], ~{'error_logger'=>~{'tag'=>'error'}~}~) %% Line 1630 <'false'> when 'true' -> 'ok' ( <_4> when 'true' -> primop 'match_fail' ({'case_clause',_4}) -| ['compiler_generated'] ) end %% Line 1631 call 'erlang':'throw' ({'error',{'bad_environment_value',_0}}) 'get_env_i'/2 = %% Line 1633 fun (_1,_0) -> case <_1,_0> of when call 'erlang':'is_list' (ConfData) -> %% Line 1634 case call 'lists':'keyfind' (Name, 1, ConfData) of %% Line 1635 <{_X_Name,Env}> when 'true' -> Env %% Line 1636 <_12> when 'true' -> [] end %% Line 1638 <_X_Name,_13> when 'true' -> [] end 'merge_env'/2 = %% Line 1641 fun (_1,_0) -> %% Line 1642 apply 'merge_env'/3 (_1, _0, []) 'merge_env'/3 = %% Line 1644 fun (_2,_1,_0) -> case <_2,_1,_0> of <[_@r0 = {App,AppEnv1}|T],Env2,Res> when 'true' -> %% Line 1645 case apply 'get_env_key'/2 (App, Env2) of %% Line 1646 <{'value',AppEnv2,RestEnv2}> when 'true' -> let = apply %% Line 1647 'merge_app_env'/2 (%% Line 1647 AppEnv1, %% Line 1647 AppEnv2) in %% Line 1648 apply 'merge_env'/3 (T, RestEnv2, [{App,NewAppEnv}|Res]) %% Line 1649 <_8> when 'true' -> %% Line 1650 apply 'merge_env'/3 (T, Env2, [_@r0|Res]) end %% Line 1652 <[],Env2,Res> when 'true' -> %% Line 1653 call 'erlang':'++' (Env2, Res) ( <_7,_6,_5> when 'true' -> ( primop 'match_fail' ({'function_clause',_7,_6,_5}) -| [{'function_name',{'merge_env',3}}] ) -| ['compiler_generated'] ) end 'change_app_env'/3 = %% Line 1657 fun (_2,_1,_0) -> %% Line 1658 case apply 'get_env_key'/2 (_1, _2) of %% Line 1659 <{'value',AppEnv,RestEnv}> when 'true' -> let <_3> = apply _0 (%% Line 1660 AppEnv) in %% Line 1660 [{_1,_3}|RestEnv] %% Line 1661 <_9> when 'true' -> let <_4> = apply _0 (%% Line 1662 []) in %% Line 1662 [{_1,_4}|_2] end 'merge_app_env'/2 = %% Line 1666 fun (_1,_0) -> %% Line 1667 apply 'merge_app_env'/3 (_1, _0, []) 'merge_app_env'/3 = %% Line 1669 fun (_2,_1,_0) -> case <_2,_1,_0> of <[_@r0 = {Key,Val}|T],Env2,Res> when 'true' -> %% Line 1670 case apply 'get_env_key'/2 (Key, Env2) of %% Line 1671 <{'value',NewVal,RestEnv}> when 'true' -> %% Line 1672 apply 'merge_app_env'/3 (T, RestEnv, [{Key,NewVal}|Res]) %% Line 1673 <_7> when 'true' -> %% Line 1674 apply 'merge_app_env'/3 (T, Env2, [_@r0|Res]) end %% Line 1676 <[],Env2,Res> when 'true' -> %% Line 1677 call 'erlang':'++' (Env2, Res) ( <_6,_5,_4> when 'true' -> ( primop 'match_fail' ({'function_clause',_6,_5,_4}) -| [{'function_name',{'merge_app_env',3}}] ) -| ['compiler_generated'] ) end 'get_env_key'/2 = %% Line 1679 fun (_1,_0) -> apply 'get_env_key'/3 (_0, _1, []) 'get_env_key'/3 = %% Line 1680 fun (_2,_1,_0) -> case <_2,_1,_0> of <[{Key,Val}|T],_7,Res> when call 'erlang':'=:=' (_7, Key) -> let <_3> = call %% Line 1681 'erlang':%% Line 1681 '++' (%% Line 1681 T, %% Line 1681 Res) in %% Line 1681 {'value',Val,_3} %% Line 1682 <[H|T],Key,Res> when 'true' -> %% Line 1683 apply 'get_env_key'/3 (T, Key, [H|Res]) %% Line 1684 <[],_X_Key,Res> when 'true' -> Res ( <_6,_5,_4> when 'true' -> ( primop 'match_fail' ({'function_clause',_6,_5,_4}) -| [{'function_name',{'get_env_key',3}}] ) -| ['compiler_generated'] ) end 'add_env'/2 = %% Line 1686 fun (_1,_0) -> let <_4> = fun (_2) -> %% Line 1687 case _2 of <{Key,Value}> when 'true' -> %% Line 1688 call 'ets':'insert' ('ac_tab', {{'env',_1,Key},Value}) ( <_3> when 'true' -> ( primop 'match_fail' ({'function_clause',_3}) -| [{'function_name',{'-add_env/2-fun-0-',1}}] ) -| ['compiler_generated'] ) end in %% Line 1687 call 'lists':'foreach' (_4, _0) 'del_env'/1 = %% Line 1692 fun (_0) -> %% Line 1693 call 'ets':'match_delete' ('ac_tab', {{'env',_0,'_'},'_'}) 'check_user'/0 = %% Line 1695 fun () -> %% Line 1696 case call 'erlang':'whereis' ('user') of %% Line 1697 when call 'erlang':'is_pid' (User) -> let <_0> = call 'erlang':'self' () in call 'erlang':'group_leader' (User, _0) %% Line 1698 <_2> when 'true' -> 'ok' end 'do_prep_config_change'/1 = %% Line 1705 fun (_0) -> %% Line 1706 apply 'do_prep_config_change'/2 (_0, []) 'do_prep_config_change'/2 = %% Line 1708 fun (_1,_0) -> case <_1,_0> of <[],EnvBefore> when 'true' -> %% Line 1709 EnvBefore %% Line 1710 <[{App,_X_Id}|Apps],EnvBefore> when 'true' -> let = call %% Line 1711 'application':%% Line 1711 'get_all_env' (%% Line 1711 App) in %% Line 1712 apply 'do_prep_config_change'/2 (Apps, [{App,Env}|EnvBefore]) ( <_4,_3> when 'true' -> ( primop 'match_fail' ({'function_clause',_4,_3}) -| [{'function_name',{'do_prep_config_change',2}}] ) -| ['compiler_generated'] ) end 'do_config_change'/2 = %% Line 1719 fun (_1,_0) -> %% Line 1720 apply 'do_config_change'/3 (_1, _0, []) 'do_config_change'/3 = %% Line 1722 fun (_2,_1,_0) -> case <_2,_1,_0> of <[],_X_EnvBefore,[]> when 'true' -> %% Line 1723 'ok' %% Line 1724 <[],_X_EnvBefore,Errors> when 'true' -> %% Line 1725 {'error',Errors} %% Line 1726 <[{App,_X_Id}|Apps],EnvBefore,Errors> when 'true' -> let <_3> = call %% Line 1727 'application':%% Line 1727 'get_all_env' (%% Line 1727 App) in let = call %% Line 1727 'lists':%% Line 1727 'sort' (_3) in let <_6> = case %% Line 1728 call 'lists':'keyfind' (App, 1, EnvBefore) of %% Line 1729 <'false'> when 'true' -> %% Line 1730 [] %% Line 1731 <{_19,AppEnvBeforeT}> when call 'erlang':'=:=' (_19, App) -> %% Line 1732 call 'lists':'sort' (AppEnvBeforeT) ( <_5> when 'true' -> %% Line 1728 primop 'match_fail' ({'case_clause',_5}) -| ['compiler_generated'] ) end in let <_13> = case %% Line 1735 AppEnvNow of %% Line 1736 <_20> when call 'erlang':'=:=' (AppEnvNow, _6) -> %% Line 1737 'ok' %% Line 1738 <_21> when 'true' -> %% Line 1739 case apply 'do_config_diff'/2 (AppEnvNow, _6) of %% Line 1740 <{[],[],[]}> when 'true' -> %% Line 1741 'ok' %% Line 1742 <{Changed,New,Removed}> when 'true' -> %% Line 1743 case call 'application':'get_key' (App, 'mod') of %% Line 1744 <{'ok',{Mod,_X_Para}}> when 'true' -> let <_8> = catch %% Line 1745 call Mod:'config_change' (Changed, New, %% Line 1746 Removed) in %% Line 1745 case _8 of %% Line 1747 <'ok'> when 'true' -> %% Line 1748 'ok' %% Line 1751 <{'EXIT',{'undef',_22}}> when 'true' -> %% Line 1752 'ok' %% Line 1753 when 'true' -> %% Line 1754 Error %% Line 1755 when 'true' -> %% Line 1756 {'error',Else} end %% Line 1758 <{'ok',[]}> when 'true' -> %% Line 1759 {'error',{'module_not_defined',App}} %% Line 1760 <'undefined'> when 'true' -> %% Line 1761 {'error',{'application_not_found',App}} ( <_10> when 'true' -> primop 'match_fail' ({'case_clause',_10}) -| ['compiler_generated'] ) end ( <_11> when 'true' -> primop 'match_fail' ({'case_clause',_11}) -| ['compiler_generated'] ) end end in %% Line 1766 case _13 of %% Line 1767 <'ok'> when 'true' -> %% Line 1768 apply 'do_config_change'/3 (Apps, EnvBefore, Errors) %% Line 1769 <{'error',NewError}> when 'true' -> %% Line 1770 apply 'do_config_change'/3 (Apps, EnvBefore, [NewError|Errors]) ( <_15> when 'true' -> primop 'match_fail' ({'case_clause',_15}) -| ['compiler_generated'] ) end ( <_18,_17,_16> when 'true' -> ( primop 'match_fail' ({'function_clause',_18,_17,_16}) -| [{'function_name',{'do_config_change',3}}] ) -| ['compiler_generated'] ) end 'do_config_diff'/2 = %% Line 1777 fun (_1,_0) -> %% Line 1778 apply 'do_config_diff'/3 (_1, _0, {[],[]}) 'do_config_diff'/3 = %% Line 1780 fun (_2,_1,_0) -> case <_2,_1,_0> of <[],AppEnvBefore,{Changed,New}> when 'true' -> let <_7> = fun (_4,_3) -> %% Line 1781 case <_4,_3> of <{Env,_X_Value},Acc> when 'true' -> [Env|Acc] ( <_6,_5> when 'true' -> ( primop 'match_fail' ({'function_clause',_6,_5}) -| [{'function_name',{'-do_config_diff/3-fun-0-',2}}] ) -| ['compiler_generated'] ) end in let = call %% Line 1781 'lists':%% Line 1781 'foldl' (_7, %% Line 1781 [], %% Line 1781 AppEnvBefore) in %% Line 1782 {Changed,New,Removed} %% Line 1783 when 'true' -> let <_9> = call %% Line 1784 'erlang':%% Line 1784 '++' (%% Line 1784 AppEnvNow, %% Line 1784 New) in %% Line 1784 {Changed,_9,[]} %% Line 1785 <[_@r1 = {Env,Value}|AppEnvNow],AppEnvBefore,_@r0 = {Changed,New}> when 'true' -> %% Line 1786 case call 'lists':'keyfind' (Env, 1, AppEnvBefore) of %% Line 1787 <{_16,_17}> when let <_18> = call 'erlang':'=:=' (_16, Env) in let <_19> = call 'erlang':'=:=' (_17, Value) in call 'erlang':'and' (_18, _19) -> let <_10> = call %% Line 1788 'lists':%% Line 1788 'keydelete' (%% Line 1788 Env, %% Line 1788 1, %% Line 1788 AppEnvBefore) in %% Line 1788 apply 'do_config_diff'/3 (AppEnvNow, _10, _@r0) %% Line 1789 <{_20,_X_OtherValue}> when call 'erlang':'=:=' (_20, Env) -> let <_11> = call %% Line 1790 'lists':%% Line 1790 'keydelete' (%% Line 1790 Env, %% Line 1790 1, %% Line 1790 AppEnvBefore) in %% Line 1790 apply 'do_config_diff'/3 (AppEnvNow, _11, %% Line 1791 {[_@r1|Changed],New}) %% Line 1792 <'false'> when 'true' -> %% Line 1793 apply 'do_config_diff'/3 (AppEnvNow, AppEnvBefore, {Changed,[_@r1|New]}) ( <_12> when 'true' -> primop 'match_fail' ({'case_clause',_12}) -| ['compiler_generated'] ) end ( <_15,_14,_13> when 'true' -> ( primop 'match_fail' ({'function_clause',_15,_14,_13}) -| [{'function_name',{'do_config_diff',3}}] ) -| ['compiler_generated'] ) end 'check_conf'/0 = %% Line 1800 fun () -> %% Line 1801 case call 'init':'get_argument' ('config') of %% Line 1802 <{'ok',Files}> when 'true' -> let <_12> = fun (_9,_8) -> %% Line 1804 case <_9,_8> of <[File|[]],Env> when 'true' -> let = call %% Line 1805 'filename':%% Line 1805 'basename' (%% Line 1805 File, %% Line 1805 [46|[99|[111|[110|[102|[105|[103]]]]]]]) in let <_2> = call %% Line 1806 'filename':%% Line 1806 'dirname' (%% Line 1806 File) in let <_1> = call %% Line 1807 'erlang':%% Line 1807 '++' (%% Line 1807 BFName, %% Line 1807 [46|[99|[111|[110|[102|[105|[103]]]]]]]) in let = call %% Line 1806 'filename':%% Line 1806 'join' (_2, _1) in %% Line 1808 case apply 'load_file'/1 (FName) of %% Line 1809 <{'ok',NewEnv}> when 'true' -> %% Line 1815 case <> of %% Line 1816 <> when call 'erlang':'=:=' (BFName, [115|[121|[115]]]) -> let = call %% Line 1817 'filename':%% Line 1817 'dirname' (%% Line 1817 FName) in %% Line 1818 case %% Line 1819 apply 'check_conf_sys'/4 (NewEnv, [], [], DName) of <{'ok',SysEnv,Errors}> when 'true' -> %% Line 1824 case Errors of %% Line 1825 <[]> when 'true' -> %% Line 1826 apply 'merge_env'/2 (Env, SysEnv) %% Line 1827 <[_@r0 = {'error',{SysFName,Line,Str}}|_15]> when 'true' -> %% Line 1828 call 'erlang':'throw' (_@r0) ( <_6> when 'true' -> primop 'match_fail' ({'case_clause',_6}) -| ['compiler_generated'] ) end ( <_5> when 'true' -> primop 'match_fail' ({'badmatch',_5}) -| ['compiler_generated'] ) end %% Line 1830 <> when 'true' -> %% Line 1831 apply 'merge_env'/2 (Env, NewEnv) end %% Line 1833 <{'error',{Line,_X_Mod,Str}}> when 'true' -> %% Line 1834 call 'erlang':'throw' ({'error',{FName,Line,Str}}) ( <_7> when 'true' -> primop 'match_fail' ({'case_clause',_7}) -| ['compiler_generated'] ) end ( <_11,_10> when 'true' -> ( primop 'match_fail' ({'function_clause',_11,_10}) -| [{'function_name',{'-check_conf/0-fun-0-',2}}] ) -| ['compiler_generated'] ) end in let <_13> = call %% Line 1803 'lists':%% Line 1803 'foldl' (_12, %% Line 1836 [], %% Line 1836 Files) in %% Line 1803 {'ok',_13} %% Line 1837 <_16> when 'true' -> {'ok',[]} end 'check_conf_sys'/1 = %% Line 1840 fun (_0) -> %% Line 1841 apply 'check_conf_sys'/4 (_0, [], [], []) 'check_conf_sys'/4 = %% Line 1843 fun (_3,_2,_1,_0) -> case <_3,_2,_1,_0> of <[File|T],SysEnv,Errors,DName> when let <_4> = call 'erlang':'is_list' (File) in let <_5> = call 'erlang':'is_list' (DName) in call 'erlang':'and' (_4, _5) -> let = call %% Line 1844 'filename':%% Line 1844 'basename' (%% Line 1844 File, %% Line 1844 [46|[99|[111|[110|[102|[105|[103]]]]]]]) in let <_8> = call %% Line 1845 'filename':%% Line 1845 'dirname' (%% Line 1845 File) in let <_7> = call %% Line 1845 'erlang':%% Line 1845 '++' (%% Line 1845 BFName, %% Line 1845 [46|[99|[111|[110|[102|[105|[103]]]]]]]) in let = call %% Line 1845 'filename':%% Line 1845 'join' (_8, _7) in let <_13> = case %% Line 1846 call 'filename':'pathtype' (FName) of %% Line 1847 <'relative'> when call 'erlang':'=/=' (DName, []) -> let = call %% Line 1850 'filename':%% Line 1850 'join' (%% Line 1850 DName, %% Line 1850 FName) in %% Line 1851 case call 'erl_prim_loader':'read_file_info' (RName) of %% Line 1852 <{'ok',_23}> when 'true' -> RName %% Line 1853 <'error'> when 'true' -> FName ( <_11> when 'true' -> primop 'match_fail' ({'case_clause',_11}) -| ['compiler_generated'] ) end %% Line 1855 <_24> when 'true' -> FName end in %% Line 1857 case apply 'load_file'/1 (_13) of %% Line 1858 <{'ok',NewEnv}> when 'true' -> let <_15> = apply %% Line 1859 'merge_env'/2 (%% Line 1859 SysEnv, %% Line 1859 NewEnv) in %% Line 1859 apply 'check_conf_sys'/4 (T, _15, Errors, DName) %% Line 1860 <{'error',{Line,_X_Mod,Str}}> when 'true' -> %% Line 1861 apply 'check_conf_sys'/4 (T, SysEnv, [{'error',{_13,Line,Str}}|Errors], DName) ( <_16> when 'true' -> primop 'match_fail' ({'case_clause',_16}) -| ['compiler_generated'] ) end %% Line 1863 <[Tuple|T],SysEnv,Errors,DName> when 'true' -> let <_17> = apply %% Line 1864 'merge_env'/2 (%% Line 1864 SysEnv, %% Line 1864 [Tuple|[]]) in %% Line 1864 apply 'check_conf_sys'/4 (T, _17, Errors, DName) %% Line 1865 <[],SysEnv,Errors,_25> when 'true' -> let <_18> = call %% Line 1866 'lists':%% Line 1866 'reverse' (%% Line 1866 Errors) in %% Line 1866 {'ok',SysEnv,_18} ( <_22,_21,_20,_19> when 'true' -> ( primop 'match_fail' ({'function_clause',_22,_21,_20,_19}) -| [{'function_name',{'check_conf_sys',4}}] ) -| ['compiler_generated'] ) end 'load_file'/1 = %% Line 1868 fun (_0) -> %% Line 1870 case call 'erl_prim_loader':'get_file' (_0) of %% Line 1871 <{'ok',Bin,_X_FileName}> when 'true' -> %% Line 1874 case apply 'file_binary_to_list'/1 (Bin) of %% Line 1875 <{'ok',String}> when 'true' -> let <_1> = call %% Line 1876 'erlang':%% Line 1876 '++' (%% Line 1876 String, %% Line 1876 [32]) in %% Line 1876 apply 'scan_file'/1 (_1) %% Line 1877 <'error'> when 'true' -> %% Line 1878 {'error',{'none','scan_file',[98|[97|[100|[32|[101|[110|[99|[111|[100|[105|[110|[103]]]]]]]]]]]]}} ( <_2> when 'true' -> primop 'match_fail' ({'case_clause',_2}) -| ['compiler_generated'] ) end %% Line 1880 <'error'> when 'true' -> %% Line 1881 {'error',{'none','open_file',[99|[111|[110|[102|[105|[103|[117|[114|[97|[116|[105|[111|[110|[32|[102|[105|[108|[101|[32|[110|[111|[116|[32|[102|[111|[117|[110|[100]]]]]]]]]]]]]]]]]]]]]]]]]]]]}} ( <_3> when 'true' -> primop 'match_fail' ({'case_clause',_3}) -| ['compiler_generated'] ) end 'scan_file'/1 = %% Line 1884 fun (_0) -> %% Line 1885 case call 'erl_scan':'tokens' ([], _0, 1) of %% Line 1886 <{'done',{'ok',Tokens,_6},Left}> when 'true' -> %% Line 1887 case call 'erl_parse':'parse_term' (Tokens) of %% Line 1888 when call 'erlang':'is_list' (L) -> %% Line 1889 case apply 'only_ws'/1 (Left) of %% Line 1890 <'true'> when 'true' -> %% Line 1891 Res %% Line 1892 <'false'> when 'true' -> %% Line 1894 apply 'config_error'/0 () ( <_1> when 'true' -> primop 'match_fail' ({'case_clause',_1}) -| ['compiler_generated'] ) end %% Line 1896 <{'ok',_7}> when 'true' -> %% Line 1898 apply 'config_error'/0 () %% Line 1899 when 'true' -> %% Line 1900 Error end %% Line 1902 <{'done',Result,_8}> when 'true' -> let <_3> = call %% Line 1903 'erlang':%% Line 1903 'tuple_to_list' (%% Line 1903 Result) in %% Line 1903 {'error',{'none','parse_file',_3}} %% Line 1904 <{'more',_9}> when 'true' -> %% Line 1905 {'error',{'none','load_file',[110|[111|[32|[101|[110|[100|[105|[110|[103|[32|[60|[100|[111|[116|[62|[32|[102|[111|[117|[110|[100]]]]]]]]]]]]]]]]]]]]]}} ( <_4> when 'true' -> primop 'match_fail' ({'case_clause',_4}) -| ['compiler_generated'] ) end 'only_ws'/1 = %% Line 1908 fun (_0) -> case _0 of <[C|Cs]> when call 'erlang':'=<' (C, 32) -> apply 'only_ws'/1 (Cs) %% Line 1909 <[37|Cs]> when 'true' -> let <_1> = apply 'strip_comment'/1 (Cs) in apply 'only_ws'/1 (_1) %% Line 1910 <[_3|_4]> when 'true' -> 'false' %% Line 1911 <[]> when 'true' -> 'true' ( <_2> when 'true' -> ( primop 'match_fail' ({'function_clause',_2}) -| [{'function_name',{'only_ws',1}}] ) -| ['compiler_generated'] ) end 'strip_comment'/1 = %% Line 1913 fun (_0) -> case _0 of <[10|Cs]> when 'true' -> Cs %% Line 1914 <[_2|Cs]> when 'true' -> apply 'strip_comment'/1 (Cs) %% Line 1915 <[]> when 'true' -> [] ( <_1> when 'true' -> ( primop 'match_fail' ({'function_clause',_1}) -| [{'function_name',{'strip_comment',1}}] ) -| ['compiler_generated'] ) end 'config_error'/0 = %% Line 1917 fun () -> %% Line 1918 {'error',{'none','load_file',[99|[111|[110|[102|[105|[103|[117|[114|[97|[116|[105|[111|[110|[32|[102|[105|[108|[101|[32|[109|[117|[115|[116|[32|[99|[111|[110|[116|[97|[105|[110|[32|[79|[78|[69|[32|[108|[105|[115|[116|[32|[101|[110|[100|[101|[100|[32|[98|[121|[32|[60|[100|[111|[116|[62]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]}} 'info_started'/2 = %% Line 1925 fun (_1,_0) -> %% Line 1926 case call 'logger':'allow' ('info', 'application_controller') of <'true'> when 'true' -> let <_2> = ~{%% Line 1927 'report'=>[{'application',_1}|%% Line 1928 [{'started_at',_0}|[]]]|~{'label'=>{'application_controller','progress'}}~}~ in call 'logger':'macro_log' (~{'file'=>[97|[112|[112|[108|[105|[99|[97|[116|[105|[111|[110|[95|[99|[111|[110|[116|[114|[111|[108|[108|[101|[114|[46|[101|[114|[108]]]]]]]]]]]]]]]]]]]]]]]]]],'line'=>1926,'mfa'=>{'application_controller','info_started',2}}~, 'info', _2, ~{'domain'=>['otp'|['sasl']],'error_logger'=>~{'tag'=>'info_report','type'=>'progress'}~,'logger_formatter'=>~{'title'=>[80|[82|[79|[71|[82|[69|[83|[83|[32|[82|[69|[80|[79|[82|[84]]]]]]]]]]]]]]]}~,'report_cb'=>fun 'logger':'format_otp_report'/1}~) %% Line 1932 <'false'> when 'true' -> 'ok' ( <_5> when 'true' -> primop 'match_fail' ({'case_clause',_5}) -| ['compiler_generated'] ) end 'info_exited'/3 = %% Line 1934 fun (_2,_1,_0) -> %% Line 1935 case call 'logger':'allow' ('notice', 'application_controller') of <'true'> when 'true' -> let <_3> = ~{%% Line 1936 'report'=>[{'application',_2}|%% Line 1937 [{'exited',_1}|%% Line 1938 [{'type',_0}|[]]]]|~{'label'=>{'application_controller','exit'}}~}~ in call 'logger':'macro_log' (~{'file'=>[97|[112|[112|[108|[105|[99|[97|[116|[105|[111|[110|[95|[99|[111|[110|[116|[114|[111|[108|[108|[101|[114|[46|[101|[114|[108]]]]]]]]]]]]]]]]]]]]]]]]]],'line'=>1935,'mfa'=>{'application_controller','info_exited',3}}~, 'notice', _3, ~{'domain'=>['otp'],'error_logger'=>~{'tag'=>'info_report','type'=>'std_info'}~,'report_cb'=>fun 'logger':'format_otp_report'/1}~) %% Line 1941 <'false'> when 'true' -> 'ok' ( <_6> when 'true' -> primop 'match_fail' ({'case_clause',_6}) -| ['compiler_generated'] ) end 'reply_to_requester'/3 = %% Line 1946 fun (_2,_1,_0) -> let <_4> = case _0 of %% Line 1948 <{'ok',_X_Id}> when 'true' -> %% Line 1949 'ok' %% Line 1950 <{'info',Reason}> when 'true' -> %% Line 1951 {'error',Reason} %% Line 1952 when 'true' -> %% Line 1953 Error end in let <_11> = fun (_8,_7) -> %% Line 1957 case _8 of %% Line 1958 <{_15,From}> when call 'erlang':'=:=' (_15, _2) -> do %% Line 1959 apply 'reply'/2 (From, _4) _7 %% Line 1961 <_16> when 'true' -> %% Line 1962 [_8|_7] end in %% Line 1956 call 'lists':'foldl' (_11, %% Line 1965 [], _1) 'update_permissions'/2 = %% Line 1972 fun (_1,_0) -> %% Line 1974 case call 'ets':'lookup' ('ac_tab', {'env','kernel','permissions'}) of %% Line 1975 <[]> when 'true' -> %% Line 1976 call 'ets':'insert' ('ac_tab', {{'env','kernel','permissions'},[{_1,_0}|[]]}) %% Line 1977 <[{_7,Perm}|[]]> when 'true' -> let = call %% Line 1978 'lists':%% Line 1978 'keydelete' (_1, %% Line 1978 1, %% Line 1978 Perm) in %% Line 1979 call 'ets':'insert' ('ac_tab', {{'env','kernel','permissions'},[{_1,_0}|Perm2]}) ( <_4> when 'true' -> primop 'match_fail' ({'case_clause',_4}) -| ['compiler_generated'] ) end 'test_change_apps'/2 = %% Line 1985 fun (_1,_0) -> let = apply %% Line 1986 'test_make_apps'/2 (_1, %% Line 1986 []) in %% Line 1987 apply 'test_do_change_appl'/3 (_1, _0, Res) 'test_do_change_appl'/3 = %% Line 1989 fun (_2,_1,_0) -> case <_2,_1,_0> of <[],_8,_9> when 'true' -> %% Line 1990 'ok' %% Line 1991 <[A|Apps],[],[R|Res]> when 'true' -> do %% Line 1992 apply 'do_change_appl'/3 (R, ( {( 'appl' -| ['result_not_wanted'] ),A,( 'undefined' -| ['result_not_wanted'] ),( 'undefined' -| ['result_not_wanted'] ),( 'undefined' -| ['result_not_wanted'] ),( 'undefined' -| ['result_not_wanted'] ),( 'undefined' -| ['result_not_wanted'] ),( 'undefined' -| ['result_not_wanted'] ),( 'undefined' -| ['result_not_wanted'] )} -| ['result_not_wanted'] ), ( [] -| ['result_not_wanted'] )) %% Line 1993 apply 'test_do_change_appl'/3 (Apps, [], Res) %% Line 1994 <[A|Apps],[C|Conf],[R|Res]> when 'true' -> do %% Line 1995 apply 'do_change_appl'/3 (R, ( {( 'appl' -| ['result_not_wanted'] ),A,( 'undefined' -| ['result_not_wanted'] ),( 'undefined' -| ['result_not_wanted'] ),( 'undefined' -| ['result_not_wanted'] ),( 'undefined' -| ['result_not_wanted'] ),( 'undefined' -| ['result_not_wanted'] ),( 'undefined' -| ['result_not_wanted'] ),( 'undefined' -| ['result_not_wanted'] )} -| ['result_not_wanted'] ), C) %% Line 1996 apply 'test_do_change_appl'/3 (Apps, Conf, Res) ( <_7,_6,_5> when 'true' -> ( primop 'match_fail' ({'function_clause',_7,_6,_5}) -| [{'function_name',{'test_do_change_appl',3}}] ) -| ['compiler_generated'] ) end 'test_make_apps'/2 = %% Line 1998 fun (_1,_0) -> case <_1,_0> of <[],Res> when 'true' -> %% Line 1999 call 'lists':'reverse' (Res) %% Line 2000 <[A|Apps],Res> when 'true' -> let <_2> = apply %% Line 2001 'make_appl'/1 (%% Line 2001 A) in %% Line 2001 apply 'test_make_apps'/2 (Apps, [_2|Res]) ( <_4,_3> when 'true' -> ( primop 'match_fail' ({'function_clause',_4,_3}) -| [{'function_name',{'test_make_apps',2}}] ) -| ['compiler_generated'] ) end 'file_binary_to_list'/1 = %% Line 2003 fun (_0) -> let <_2> = case %% Line 2004 call 'epp':'read_encoding_from_binary' (_0) of %% Line 2005 <'none'> when 'true' -> call 'epp':'default_encoding' () %% Line 2006 when 'true' -> Encoding end in let <_4> = catch %% Line 2008 call 'unicode':'characters_to_list' (_0, _2) in %% Line 2008 case _4 of %% Line 2009 when call 'erlang':'is_list' (_4) -> %% Line 2010 {'ok',String} %% Line 2011 <_7> when 'true' -> %% Line 2012 'error' end 'to_string'/1 = %% Line 2023 fun (_0) -> %% Line 2024 case call 'io_lib':'printable_list' (_0) of %% Line 2025 <'true'> when 'true' -> _0 %% Line 2027 <'false'> when 'true' -> let <_1> = call %% Line 2028 'io_lib':%% Line 2028 'format' (%% Line 2028 [126|[48|[112]]], %% Line 2028 [_0|[]]) in %% Line 2028 call 'lists':'flatten' (_1) ( <_2> when 'true' -> primop 'match_fail' ({'case_clause',_2}) -| ['compiler_generated'] ) end 'module_info'/0 = fun () -> call 'erlang':'get_module_info' ('application_controller') 'module_info'/1 = fun (_0) -> call 'erlang':'get_module_info' ('application_controller', _0) end ================================================ FILE: test_data/basic_module.core ================================================ module 'basic_module' ['woo'/1, 'hoo'/2] attributes [ 'file' = {1, 2, 3}, 'file' = {1, 2, 3}] 'start_application'/2 = %% what fun (_1,_0) -> 'woo' 'woo'/1 = fun (_0) -> _0 'woo'/1 = fun (_0) -> _0 end ================================================ FILE: test_data/basic_module.erl ================================================ -module(basic_module). -export([woo/1]). woo(A) -> A. ================================================ FILE: test_data/basic_regress/enum_aggregate.core ================================================ module 'Elixir.Enum' ['aggregate'/3] attributes [] 'aggregate'/3 = %% Line 2815 fun (_2,_1,_0) -> case <_2,_1,_0> of <[_X_head@1|_X_tail@1],_X_fun@1,_X__empty@1> when 'true' -> letrec 'lists^foldl'/2 = fun (Xs,_15) -> case Xs of <[X|_16]> when 'true' -> %% Line 2816 apply 'lists^foldl'/2 (_16, apply _X_fun@1 (X, _15)) <[]> when call 'erlang':'is_function' (%% Line 2816 _X_fun@1, 2) -> _15 <_17> when 'true' -> %% Line 2816 ( primop 'match_fail' ({'function_clause',_X_fun@1,_15,_17}) -| [{'function_name',{'lists^foldl',2}}] ) end in %% Line 2816 apply 'lists^foldl'/2 (_X_tail@1, _X_head@1) %% Line 2819 <[],_X__fun@1,_X_empty@1> when 'true' -> %% Line 2820 apply _X_empty@1 () %% Line 2823 <~{'last':=_X_last@1,'first':=_X_first@1,'__struct__':='Elixir.Range'}~,_X_fun@1,_X__empty@1> when 'true' -> %% Line 2824 apply _X_fun@1 (_X_first@1, _X_last@1) %% Line 2827 <_X_enumerable@1,_X_fun@1,_X_empty@1> when 'true' -> let <_X_ref@1> = call 'erlang':%% Line 2828 'make_ref' () in let <_8> = fun (_5,_4) -> %% Line 2831 case <_5,_4> of %% Line 2832 <_X_element@1,_X_ref@2> when ( call ( 'erlang' -| ['compiler_generated'] ):( '=:=' -| ['compiler_generated'] ) (( _X_ref@1 -| ['compiler_generated'] ), _X_ref@2) -| ['compiler_generated'] ) -> _X_element@1 %% Line 2833 <_X_element@2,_X_acc@1> when 'true' -> apply _X_fun@1 (_X_element@2, _X_acc@1) end in %% Line 2835 case ( case ( <( _X_enumerable@1 -| ['compiler_generated'] ),( _X_ref@1 -| ['compiler_generated'] ),( _8 -| ['compiler_generated'] )> -| ['compiler_generated'] ) of ( <_21,( _X_acc@1 -| ['compiler_generated'] ),_22> when ( call ( 'erlang' -| ['compiler_generated'] ):( 'is_list' -| ['compiler_generated'] ) (_21) -| ['compiler_generated'] ) -> letrec 'lists^foldl'/2 = fun (Xs,_23) -> case Xs of <[X|_24]> when 'true' -> ( apply 'lists^foldl'/2 (_24, ( apply _22 (X, _23) -| ['compiler_generated'] )) -| ['compiler_generated'] ) <[]> when call 'erlang':'is_function' (_22, 2) -> _23 <_25> when 'true' -> ( primop 'match_fail' ({'function_clause',_22,_23,_25}) -| [{'function_name',{'lists^foldl',2}},'compiler_generated'] ) end in ( apply 'lists^foldl'/2 (_21, ( _X_acc@1 -| ['compiler_generated'] )) -| ['compiler_generated'] ) -| ['compiler_generated'] ) ( <( ~{( ( 'last' -| ['compiler_generated'] ):=( _X_last@1 -| ['compiler_generated'] ) -| ['compiler_generated'] ),( ( 'first' -| ['compiler_generated'] ):=( _X_first@1 -| ['compiler_generated'] ) -| ['compiler_generated'] ),( ( '__struct__' -| ['compiler_generated'] ):=( 'Elixir.Range' -| ['compiler_generated'] ) -| ['compiler_generated'] )}~ -| ['compiler_generated'] ),( _X_acc@1 -| ['compiler_generated'] ),_26> when ( 'true' -| ['compiler_generated'] ) -> ( case <> of ( <> when ( call ( 'erlang' -| ['compiler_generated'] ):( '=<' -| ['compiler_generated'] ) (( _X_first@1 -| ['compiler_generated'] ), ( _X_last@1 -| ['compiler_generated'] )) -| ['compiler_generated'] ) -> ( apply ( 'reduce_range_inc'/4 -| ['compiler_generated'] ) (( _X_first@1 -| ['compiler_generated'] ), ( _X_last@1 -| ['compiler_generated'] ), ( _X_acc@1 -| ['compiler_generated'] ), _26) -| ['compiler_generated'] ) -| ['compiler_generated'] ) ( <> when ( 'true' -| ['compiler_generated'] ) -> ( apply ( 'reduce_range_dec'/4 -| ['compiler_generated'] ) (( _X_first@1 -| ['compiler_generated'] ), ( _X_last@1 -| ['compiler_generated'] ), ( _X_acc@1 -| ['compiler_generated'] ), _26) -| ['compiler_generated'] ) -| ['compiler_generated'] ) end -| ['compiler_generated'] ) -| ['compiler_generated'] ) ( <( _27 = ( ~{( ( '__struct__' -| ['compiler_generated'] ):=( ( _X__@1 -| ['compiler_generated'] ) = ( _14 -| ['compiler_generated'] ) -| ['compiler_generated'] ) -| ['compiler_generated'] )}~ -| ['compiler_generated'] ) -| ['compiler_generated'] ),( _X_acc@1 -| ['compiler_generated'] ),_28> when ( call ( 'erlang' -| ['compiler_generated'] ):( 'is_atom' -| ['compiler_generated'] ) (( _X__@1 -| ['compiler_generated'] )) -| ['compiler_generated'] ) -> ( let <_37> = fun (( _5 -| ['compiler_generated'] ),( _4 -| ['compiler_generated'] )) -> ( let <_3> = apply _28 (( _5 -| ['compiler_generated'] ), ( _4 -| ['compiler_generated'] )) in ( {( 'cont' -| ['compiler_generated'] ),( _3 -| ['compiler_generated'] )} -| ['compiler_generated'] ) -| ['compiler_generated'] ) in ( let <_9> = call ( 'Elixir.Enumerable' -| ['compiler_generated'] ):%% Line 3015 ( 'reduce' -| ['compiler_generated'] ) (_27, ( {( 'cont' -| ['compiler_generated'] ),( _X_acc@1 -| ['compiler_generated'] )} -| ['compiler_generated'] ), _37) in %% Line 3015 ( call ( 'erlang' -| ['compiler_generated'] ):( 'element' -| ['compiler_generated'] ) (( 2 -| ['compiler_generated'] ), ( _9 -| ['compiler_generated'] )) -| ['compiler_generated'] ) -| ['compiler_generated'] ) -| ['compiler_generated'] ) -| ['compiler_generated'] ) ( <( _41 = ( ~{}~ -| ['compiler_generated'] ) -| ['compiler_generated'] ),( _X_acc@1 -| ['compiler_generated'] ),_42> when ( 'true' -| ['compiler_generated'] ) -> ( let <_10> = fun (( _6 -| ['compiler_generated'] ),( _5 -| ['compiler_generated'] ),( _4 -| ['compiler_generated'] )) -> ( apply _42 (( {( _6 -| ['compiler_generated'] ),( _5 -| ['compiler_generated'] )} -| ['compiler_generated'] ), ( _4 -| ['compiler_generated'] )) -| ['compiler_generated'] ) in ( call ( 'maps' -| ['compiler_generated'] ):( 'fold' -| ['compiler_generated'] ) (( _10 -| ['compiler_generated'] ), ( _X_acc@1 -| ['compiler_generated'] ), _41) -| ['compiler_generated'] ) -| ['compiler_generated'] ) -| ['compiler_generated'] ) ( <_46,( _X_acc@1 -| ['compiler_generated'] ),_47> when ( 'true' -| ['compiler_generated'] ) -> ( let <_56> = fun (( _5 -| ['compiler_generated'] ),( _4 -| ['compiler_generated'] )) -> ( let <_3> = apply _47 (( _5 -| ['compiler_generated'] ), ( _4 -| ['compiler_generated'] )) in ( {( 'cont' -| ['compiler_generated'] ),( _3 -| ['compiler_generated'] )} -| ['compiler_generated'] ) -| ['compiler_generated'] ) in ( let <_9> = call ( 'Elixir.Enumerable' -| ['compiler_generated'] ):%% Line 3015 ( 'reduce' -| ['compiler_generated'] ) (_46, ( {( 'cont' -| ['compiler_generated'] ),( _X_acc@1 -| ['compiler_generated'] )} -| ['compiler_generated'] ), _56) in %% Line 3015 ( call ( 'erlang' -| ['compiler_generated'] ):( 'element' -| ['compiler_generated'] ) (( 2 -| ['compiler_generated'] ), ( _9 -| ['compiler_generated'] )) -| ['compiler_generated'] ) -| ['compiler_generated'] ) -| ['compiler_generated'] ) -| ['compiler_generated'] ) end -| ['compiler_generated'] ) of %% Line 2836 <_13> when ( call 'erlang':'=:=' (_13, ( _X_ref@1 -| ['compiler_generated'] )) -| ['compiler_generated'] ) -> apply _X_empty@1 () %% Line 2837 <_X_result@1> when 'true' -> _X_result@1 end end end ================================================ FILE: test_data/basic_regress/function_capture_1.core ================================================ module 'test' ['test'/0] attributes [] 'test'/0 = fun () -> fun 'logger':'format_otp_report'/1 end ================================================ FILE: test_data/basic_regress/line_annotation_fail_1.core ================================================ module 'test' ['test'/3] attributes [] 'test'/3 = fun (_2,_1,_0) -> case <_2,_1,_0> of <{'ok',{ApplData,Env,IncApps,Descr,Id,Vsn,Apps}},%% Line 1573 OldAppl,%% Line 1573 Config> when 'true' -> 'false' <_w,_t,_f> when 'true' -> 'true' end end ================================================ FILE: test_data/basic_regress/type_construction_fail_1.core ================================================ module 'test' ['test1'/3,'test2'/3,'test3'/3] attributes [] 'test3'/3 = fun (_2,_1,_0) -> ~{'a'=>[]|[]}~ 'test2'/3 = fun (_2,_1,_0) -> ~{%% Line 1927 'report'=>[{'application',_1} |%% Line 1928 [{'started_at',_0}| [] ] ]| ~{'label'=>{'application_controller','progress'}}~}~ 'test1'/3 = fun (_2,_1,_0) -> ~{%% Line 1927 'report'=>[{'application',_1}|%% Line 1928 [{'started_at',_0}|[]]]|~{'label'=>{'application_controller','progress'}}~}~ end ================================================ FILE: test_data/compile.core ================================================ module 'compile' ['compile'/3, 'compile_asm'/3, 'compile_beam'/3, 'compile_core'/3, 'env_compiler_options'/0, 'file'/1, 'file'/2, 'format_error'/1, 'forms'/1, 'forms'/2, 'iofile'/1, 'module_info'/0, 'module_info'/1, 'noenv_file'/2, 'noenv_forms'/2, 'noenv_output_generated'/1, 'options'/0, 'output_generated'/1] attributes [%% Line 1 'file' = %% Line 1 [{[115|[114|[99|[47|[99|[111|[109|[112|[105|[108|[101|[46|[101|[114|[108]]]]]]]]]]]]]]],1}], %% Line 34 'export_type' = %% Line 34 [{'option',0}], %% Line 1 'file' = %% Line 1 [{[47|[104|[111|[109|[101|[47|[104|[97|[110|[115|[105|[104|[101|[47|[112|[114|[111|[106|[47|[114|[117|[115|[116|[47|[99|[111|[114|[101|[95|[101|[114|[108|[97|[110|[103|[47|[111|[116|[112|[47|[108|[105|[98|[47|[99|[111|[109|[112|[105|[108|[101|[114|[47|[46|[46|[47|[115|[116|[100|[108|[105|[98|[47|[105|[110|[99|[108|[117|[100|[101|[47|[101|[114|[108|[95|[99|[111|[109|[112|[105|[108|[101|[46|[104|[114|[108]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]],1}], %% Line 23 'record' = %% Line 23 [{'options',[{'typed_record_field',{'record_field',24,{'atom',24,'includes'},{'nil',24}},{'type',24,'list',[{'remote_type',24,[{'atom',24,'file'}|[{'atom',24,'filename'}|[[]]]]}]}}|[{'typed_record_field',{'record_field',26,{'atom',26,'outdir'},{'string',26,[46]}},{'remote_type',26,[{'atom',26,'file'}|[{'atom',26,'filename'}|[[]]]]}}|[{'typed_record_field',{'record_field',28,{'atom',28,'output_type'},{'atom',28,'undefined'}},{'type',28,'atom',[]}}|[{'typed_record_field',{'record_field',29,{'atom',29,'defines'},{'nil',29}},{'type',29,'list',[{'type',29,'union',[{'type',29,'atom',[]}|[{'type',29,'tuple',[{'type',29,'atom',[]}|[{'var',29,'_'}]]}]]}]}}|[{'typed_record_field',{'record_field',33,{'atom',33,'warning'},{'integer',33,1}},{'type',33,'non_neg_integer',[]}}|[{'typed_record_field',{'record_field',36,{'atom',36,'verbose'},{'atom',36,'false'}},{'type',36,'boolean',[]}}|[{'record_field',37,{'atom',37,'optimize'},{'integer',37,999}}|[{'typed_record_field',{'record_field',38,{'atom',38,'specific'},{'nil',38}},{'type',38,'list',[{'var',38,'_'}]}}|[{'typed_record_field',{'record_field',39,{'atom',39,'outfile'},{'string',39,[]}},{'remote_type',39,[{'atom',39,'file'}|[{'atom',39,'filename'}|[[]]]]}}|[{'typed_record_field',{'record_field',41,{'atom',41,'cwd'}},{'remote_type',41,[{'atom',41,'file'}|[{'atom',41,'filename'}|[[]]]]}}]]]]]]]]]]}], %% Line 37 'file' = %% Line 37 [{[115|[114|[99|[47|[99|[111|[109|[112|[105|[108|[101|[46|[101|[114|[108]]]]]]]]]]]]]]],37}], %% Line 1 'file' = %% Line 1 [{[115|[114|[99|[47|[99|[111|[114|[101|[95|[112|[97|[114|[115|[101|[46|[104|[114|[108]]]]]]]]]]]]]]]]]],1}], %% Line 32 'record' = %% Line 32 [{'c_alias',[{'record_field',32,{'atom',32,'anno'},{'nil',32}}|[{'record_field',32,{'atom',32,'var'}}|[{'record_field',33,{'atom',33,'pat'}}]]]}], %% Line 35 'record' = %% Line 35 [{'c_apply',[{'record_field',35,{'atom',35,'anno'},{'nil',35}}|[{'record_field',35,{'atom',35,'op'}}|[{'record_field',36,{'atom',36,'args'}}]]]}], %% Line 38 'record' = %% Line 38 [{'c_binary',[{'record_field',38,{'atom',38,'anno'},{'nil',38}}|[{'typed_record_field',{'record_field',38,{'atom',38,'segments'}},{'type',38,'list',[{'remote_type',38,[{'atom',38,'cerl'}|[{'atom',38,'c_bitstr'}|[[]]]]}]}}]]}], %% Line 40 'record' = %% Line 40 [{'c_bitstr',[{'record_field',40,{'atom',40,'anno'},{'nil',40}}|[{'record_field',40,{'atom',40,'val'}}|[{'record_field',41,{'atom',41,'size'}}|[{'record_field',42,{'atom',42,'unit'}}|[{'record_field',43,{'atom',43,'type'}}|[{'record_field',44,{'atom',44,'flags'}}]]]]]]}], %% Line 46 'record' = %% Line 46 [{'c_call',[{'record_field',46,{'atom',46,'anno'},{'nil',46}}|[{'record_field',46,{'atom',46,'module'}}|[{'record_field',47,{'atom',47,'name'}}|[{'record_field',48,{'atom',48,'args'}}]]]]}], %% Line 50 'record' = %% Line 50 [{'c_case',[{'record_field',50,{'atom',50,'anno'},{'nil',50}}|[{'record_field',50,{'atom',50,'arg'}}|[{'record_field',51,{'atom',51,'clauses'}}]]]}], %% Line 53 'record' = %% Line 53 [{'c_catch',[{'record_field',53,{'atom',53,'anno'},{'nil',53}}|[{'record_field',53,{'atom',53,'body'}}]]}], %% Line 55 'record' = %% Line 55 [{'c_clause',[{'record_field',55,{'atom',55,'anno'},{'nil',55}}|[{'record_field',55,{'atom',55,'pats'}}|[{'record_field',56,{'atom',56,'guard'}}|[{'record_field',57,{'atom',57,'body'}}]]]]}], %% Line 59 'record' = %% Line 59 [{'c_cons',[{'record_field',59,{'atom',59,'anno'},{'nil',59}}|[{'record_field',59,{'atom',59,'hd'}}|[{'record_field',60,{'atom',60,'tl'}}]]]}], %% Line 62 'record' = %% Line 62 [{'c_fun',[{'record_field',62,{'atom',62,'anno'},{'nil',62}}|[{'record_field',62,{'atom',62,'vars'}}|[{'record_field',63,{'atom',63,'body'}}]]]}], %% Line 65 'record' = %% Line 65 [{'c_let',[{'record_field',65,{'atom',65,'anno'},{'nil',65}}|[{'record_field',65,{'atom',65,'vars'}}|[{'record_field',66,{'atom',66,'arg'}}|[{'record_field',67,{'atom',67,'body'}}]]]]}], %% Line 69 'record' = %% Line 69 [{'c_letrec',[{'record_field',69,{'atom',69,'anno'},{'nil',69}}|[{'record_field',69,{'atom',69,'defs'}}|[{'record_field',70,{'atom',70,'body'}}]]]}], %% Line 72 'record' = %% Line 72 [{'c_literal',[{'record_field',72,{'atom',72,'anno'},{'nil',72}}|[{'record_field',72,{'atom',72,'val'}}]]}], %% Line 74 'record' = %% Line 74 [{'c_map',[{'record_field',74,{'atom',74,'anno'},{'nil',74}}|[{'typed_record_field',{'record_field',75,{'atom',75,'arg'},{'record',75,'c_literal',[{'record_field',75,{'atom',75,'val'},{'map',75,[]}}]}},{'type',75,'union',[{'remote_type',75,[{'atom',75,'cerl'}|[{'atom',75,'c_var'}|[[]]]]}|[{'remote_type',75,[{'atom',75,'cerl'}|[{'atom',75,'c_literal'}|[[]]]]}]]}}|[{'typed_record_field',{'record_field',76,{'atom',76,'es'}},{'type',76,'list',[{'remote_type',76,[{'atom',76,'cerl'}|[{'atom',76,'c_map_pair'}|[[]]]]}]}}|[{'typed_record_field',{'record_field',77,{'atom',77,'is_pat'},{'atom',77,'false'}},{'type',77,'boolean',[]}}]]]]}], %% Line 79 'record' = %% Line 79 [{'c_map_pair',[{'record_field',79,{'atom',79,'anno'},{'nil',79}}|[{'typed_record_field',{'record_field',80,{'atom',80,'op'}},{'type',80,'union',[{'type',80,'record',[{'atom',80,'c_literal'}|[{'type',80,'field_type',[{'atom',80,'val'}|[{'atom',80,'assoc'}]]}]]}|[{'type',80,'record',[{'atom',80,'c_literal'}|[{'type',80,'field_type',[{'atom',80,'val'}|[{'atom',80,'exact'}]]}]]}]]}}|[{'record_field',81,{'atom',81,'key'}}|[{'record_field',82,{'atom',82,'val'}}]]]]}], %% Line 84 'record' = %% Line 84 [{'c_module',[{'record_field',84,{'atom',84,'anno'},{'nil',84}}|[{'record_field',84,{'atom',84,'name'}}|[{'record_field',85,{'atom',85,'exports'}}|[{'record_field',86,{'atom',86,'attrs'}}|[{'record_field',87,{'atom',87,'defs'}}]]]]]}], %% Line 89 'record' = %% Line 89 [{'c_primop',[{'record_field',89,{'atom',89,'anno'},{'nil',89}}|[{'record_field',89,{'atom',89,'name'}}|[{'record_field',90,{'atom',90,'args'}}]]]}], %% Line 92 'record' = %% Line 92 [{'c_receive',[{'record_field',92,{'atom',92,'anno'},{'nil',92}}|[{'record_field',92,{'atom',92,'clauses'}}|[{'record_field',93,{'atom',93,'timeout'}}|[{'record_field',94,{'atom',94,'action'}}]]]]}], %% Line 96 'record' = %% Line 96 [{'c_seq',[{'record_field',96,{'atom',96,'anno'},{'nil',96}}|[{'record_field',96,{'atom',96,'arg'}}|[{'record_field',97,{'atom',97,'body'}}]]]}], %% Line 99 'record' = %% Line 99 [{'c_try',[{'record_field',99,{'atom',99,'anno'},{'nil',99}}|[{'record_field',99,{'atom',99,'arg'}}|[{'record_field',100,{'atom',100,'vars'}}|[{'record_field',101,{'atom',101,'body'}}|[{'record_field',102,{'atom',102,'evars'}}|[{'record_field',103,{'atom',103,'handler'}}]]]]]]}], %% Line 105 'record' = %% Line 105 [{'c_tuple',[{'record_field',105,{'atom',105,'anno'},{'nil',105}}|[{'record_field',105,{'atom',105,'es'}}]]}], %% Line 107 'record' = %% Line 107 [{'c_values',[{'record_field',107,{'atom',107,'anno'},{'nil',107}}|[{'record_field',107,{'atom',107,'es'}}]]}], %% Line 109 'record' = %% Line 109 [{'c_var',[{'record_field',109,{'atom',109,'anno'},{'nil',109}}|[{'typed_record_field',{'record_field',109,{'atom',109,'name'}},{'remote_type',109,[{'atom',109,'cerl'}|[{'atom',109,'var_name'}|[[]]]]}}]]}], %% Line 38 'file' = %% Line 38 [{[115|[114|[99|[47|[99|[111|[109|[112|[105|[108|[101|[46|[101|[114|[108]]]]]]]]]]]]]]],38}], %% Line 44 'type' = %% Line 44 [{'abstract_code',{'type',44,'list',[{'remote_type',44,[{'atom',44,'erl_parse'}|[{'atom',44,'abstract_form'}|[[]]]]}]},[]}], %% Line 48 'type' = %% Line 48 [{'forms',{'type',48,'union',[{'user_type',48,'abstract_code',[]}|[{'remote_type',48,[{'atom',48,'cerl'}|[{'atom',48,'c_module'}|[[]]]]}]]},[]}], %% Line 50 'type' = %% Line 50 [{'option',{'type',50,'union',[{'type',50,'atom',[]}|[{'type',50,'tuple',[{'type',50,'atom',[]}|[{'type',50,'term',[]}]]}|[{'type',50,'tuple',[{'atom',50,'d'}|[{'type',50,'atom',[]}|[{'type',50,'term',[]}]]]}]]]},[]}], %% Line 52 'type' = %% Line 52 [{'err_info',{'type',52,'tuple',[{'type',52,'union',[{'remote_type',52,[{'atom',52,'erl_anno'}|[{'atom',52,'line'}|[[]]]]}|[{'atom',52,'none'}]]}|[{'type',53,'module',[]}|[{'type',53,'term',[]}]]]},[]}], %% Line 54 'type' = %% Line 54 [{'errors',{'type',54,'list',[{'type',54,'tuple',[{'remote_type',54,[{'atom',54,'file'}|[{'atom',54,'filename'}|[[]]]]}|[{'type',54,'list',[{'user_type',54,'err_info',[]}]}]]}]},[]}], %% Line 55 'type' = %% Line 55 [{'warnings',{'type',55,'list',[{'type',55,'tuple',[{'remote_type',55,[{'atom',55,'file'}|[{'atom',55,'filename'}|[[]]]]}|[{'type',55,'list',[{'user_type',55,'err_info',[]}]}]]}]},[]}], %% Line 56 'type' = %% Line 56 [{'mod_ret',{'type',56,'union',[{'type',56,'tuple',[{'atom',56,'ok'}|[{'type',56,'module',[]}]]}|[{'type',57,'tuple',[{'atom',57,'ok'}|[{'type',57,'module',[]}|[{'remote_type',57,[{'atom',57,'cerl'}|[{'atom',57,'c_module'}|[[]]]]}]]]}|[{'type',58,'tuple',[{'atom',58,'ok'}|[{'type',59,'union',[{'type',59,'module',[]}|[{'type',59,'nil',[]}]]}|[{'user_type',60,'abstract_code',[]}]]]}|[{'type',61,'tuple',[{'atom',61,'ok'}|[{'type',61,'module',[]}|[{'user_type',61,'warnings',[]}]]]}]]]]},[]}], %% Line 62 'type' = %% Line 62 [{'bin_ret',{'type',62,'union',[{'type',62,'tuple',[{'atom',62,'ok'}|[{'type',62,'module',[]}|[{'type',62,'binary',[]}]]]}|[{'type',63,'tuple',[{'atom',63,'ok'}|[{'type',63,'module',[]}|[{'type',63,'binary',[]}|[{'user_type',63,'warnings',[]}]]]]}]]},[]}], %% Line 64 'type' = %% Line 64 [{'err_ret',{'type',64,'union',[{'atom',64,'error'}|[{'type',64,'tuple',[{'atom',64,'error'}|[{'user_type',64,'errors',[]}|[{'user_type',64,'warnings',[]}]]]}]]},[]}], %% Line 65 'type' = %% Line 65 [{'comp_ret',{'type',65,'union',[{'user_type',65,'mod_ret',[]}|[{'user_type',65,'bin_ret',[]}|[{'user_type',65,'err_ret',[]}]]]},[]}], %% Line 80 'spec' = %% Line 80 [{{'file',1},[{'type',80,'fun',[{'type',80,'product',[{'type',80,'union',[{'type',80,'module',[]}|[{'remote_type',80,[{'atom',80,'file'}|[{'atom',80,'filename'}|[[]]]]}]]}]}|[{'user_type',80,'comp_ret',[]}]]}]}], %% Line 84 'spec' = %% Line 84 [{{'file',2},[{'type',84,'fun',[{'type',84,'product',[{'type',84,'union',[{'type',84,'module',[]}|[{'remote_type',84,[{'atom',84,'file'}|[{'atom',84,'filename'}|[[]]]]}]]}|[{'type',84,'union',[{'type',84,'list',[{'user_type',84,'option',[]}]}|[{'user_type',84,'option',[]}]]}]]}|[{'user_type',84,'comp_ret',[]}]]}]}], %% Line 91 'spec' = %% Line 91 [{{'forms',1},[{'type',91,'fun',[{'type',91,'product',[{'user_type',91,'abstract_code',[]}]}|[{'user_type',91,'comp_ret',[]}]]}]}], %% Line 95 'spec' = %% Line 95 [{{'forms',2},[{'type',95,'fun',[{'type',95,'product',[{'user_type',95,'forms',[]}|[{'type',95,'union',[{'type',95,'list',[{'user_type',95,'option',[]}]}|[{'user_type',95,'option',[]}]]}]]}|[{'user_type',95,'comp_ret',[]}]]}]}], %% Line 106 'spec' = %% Line 106 [{{'output_generated',1},[{'type',106,'fun',[{'type',106,'product',[{'type',106,'list',[{'user_type',106,'option',[]}]}]}|[{'type',106,'boolean',[]}]]}]}], %% Line 116 'spec' = %% Line 116 [{{'noenv_file',2},[{'type',116,'fun',[{'type',116,'product',[{'type',116,'union',[{'type',116,'module',[]}|[{'remote_type',116,[{'atom',116,'file'}|[{'atom',116,'filename'}|[[]]]]}]]}|[{'type',116,'union',[{'type',116,'list',[{'user_type',116,'option',[]}]}|[{'user_type',116,'option',[]}]]}]]}|[{'user_type',116,'comp_ret',[]}]]}]}], %% Line 123 'spec' = %% Line 123 [{{'noenv_forms',2},[{'type',123,'fun',[{'type',123,'product',[{'user_type',123,'forms',[]}|[{'type',123,'union',[{'type',123,'list',[{'user_type',123,'option',[]}]}|[{'user_type',123,'option',[]}]]}]]}|[{'user_type',123,'comp_ret',[]}]]}]}], %% Line 130 'spec' = %% Line 130 [{{'noenv_output_generated',1},[{'type',130,'fun',[{'type',130,'product',[{'type',130,'list',[{'user_type',130,'option',[]}]}]}|[{'type',130,'boolean',[]}]]}]}], %% Line 142 'spec' = %% Line 142 [{{'env_compiler_options',0},[{'type',142,'fun',[{'type',142,'product',[]}|[{'type',142,'list',[{'type',142,'term',[]}]}]]}]}], %% Line 240 'spec' = %% Line 240 [{{'format_error',1},[{'type',240,'fun',[{'type',240,'product',[{'type',240,'term',[]}]}|[{'type',240,'iolist',[]}]]}]}], %% Line 302 'type' = %% Line 302 [{'err_warn_info',{'type',302,'tuple','any'},[]}], %% Line 305 'record' = %% Line 305 [{'compile',[{'typed_record_field',{'record_field',305,{'atom',305,'filename'},{'string',305,[]}},{'remote_type',305,[{'atom',305,'file'}|[{'atom',305,'filename'}|[[]]]]}}|[{'typed_record_field',{'record_field',306,{'atom',306,'dir'},{'string',306,[]}},{'remote_type',306,[{'atom',306,'file'}|[{'atom',306,'filename'}|[[]]]]}}|[{'typed_record_field',{'record_field',307,{'atom',307,'base'},{'string',307,[]}},{'remote_type',307,[{'atom',307,'file'}|[{'atom',307,'filename'}|[[]]]]}}|[{'typed_record_field',{'record_field',308,{'atom',308,'ifile'},{'string',308,[]}},{'remote_type',308,[{'atom',308,'file'}|[{'atom',308,'filename'}|[[]]]]}}|[{'typed_record_field',{'record_field',309,{'atom',309,'ofile'},{'string',309,[]}},{'remote_type',309,[{'atom',309,'file'}|[{'atom',309,'filename'}|[[]]]]}}|[{'typed_record_field',{'record_field',310,{'atom',310,'module'},{'nil',310}},{'type',310,'union',[{'type',310,'module',[]}|[{'type',310,'nil',[]}]]}}|[{'typed_record_field',{'record_field',311,{'atom',311,'core_code'},{'nil',311}},{'type',311,'union',[{'remote_type',311,[{'atom',311,'cerl'}|[{'atom',311,'c_module'}|[[]]]]}|[{'type',311,'nil',[]}]]}}|[{'typed_record_field',{'record_field',312,{'atom',312,'abstract_code'},{'nil',312}},{'user_type',312,'abstract_code',[]}}|[{'typed_record_field',{'record_field',313,{'atom',313,'options'},{'nil',313}},{'type',313,'list',[{'user_type',313,'option',[]}]}}|[{'typed_record_field',{'record_field',314,{'atom',314,'mod_options'},{'nil',314}},{'type',314,'list',[{'user_type',314,'option',[]}]}}|[{'typed_record_field',{'record_field',315,{'atom',315,'encoding'},{'atom',315,'none'}},{'type',315,'union',[{'atom',315,'none'}|[{'remote_type',315,[{'atom',315,'epp'}|[{'atom',315,'source_encoding'}|[[]]]]}]]}}|[{'typed_record_field',{'record_field',316,{'atom',316,'errors'},{'nil',316}},{'type',316,'list',[{'user_type',316,'err_warn_info',[]}]}}|[{'typed_record_field',{'record_field',317,{'atom',317,'warnings'},{'nil',317}},{'type',317,'list',[{'user_type',317,'err_warn_info',[]}]}}|[{'typed_record_field',{'record_field',318,{'atom',318,'extra_chunks'},{'nil',318}},{'type',318,'list',[{'type',318,'tuple',[{'type',318,'binary',[]}|[{'type',318,'binary',[]}]]}]}}]]]]]]]]]]]]]]}], %% Line 814 'record' = %% Line 814 [{'asm_module',[{'record_field',814,{'atom',814,'module'}}|[{'record_field',815,{'atom',815,'exports'}}|[{'record_field',816,{'atom',816,'labels'}}|[{'record_field',817,{'atom',817,'functions'},{'nil',817}}|[{'record_field',818,{'atom',818,'cfun'}}|[{'record_field',819,{'atom',819,'code'}}|[{'record_field',820,{'atom',820,'attributes'},{'nil',820}}]]]]]]]}], %% Line 1721 'spec' = %% Line 1721 [{{'iofile',1},[{'type',1721,'fun',[{'type',1721,'product',[{'type',1721,'union',[{'type',1721,'atom',[]}|[{'remote_type',1721,[{'atom',1721,'file'}|[{'atom',1721,'filename_all'}|[[]]]]}]]}]}|[{'type',1722,'tuple',[{'remote_type',1722,[{'atom',1722,'file'}|[{'atom',1722,'name_all'}|[[]]]]}|[{'remote_type',1722,[{'atom',1722,'file'}|[{'atom',1722,'name_all'}|[[]]]]}]]}]]}]}], %% Line 1833 'spec' = %% Line 1833 [{{'options',0},[{'type',1833,'fun',[{'type',1833,'product',[]}|[{'atom',1833,'ok'}]]}]}], %% Line 1873 'spec' = %% Line 1873 [{{'compile',3},[{'type',1873,'fun',[{'type',1873,'product',[{'remote_type',1873,[{'atom',1873,'file'}|[{'atom',1873,'filename'}|[[]]]]}|[{'var',1873,'_'}|[{'type',1873,'record',[{'atom',1873,'options'}]}]]]}|[{'type',1873,'union',[{'atom',1873,'ok'}|[{'atom',1873,'error'}]]}]]}]}], %% Line 1883 'spec' = %% Line 1883 [{{'compile_beam',3},[{'type',1883,'fun',[{'type',1883,'product',[{'remote_type',1883,[{'atom',1883,'file'}|[{'atom',1883,'filename'}|[[]]]]}|[{'var',1883,'_'}|[{'type',1883,'record',[{'atom',1883,'options'}]}]]]}|[{'type',1883,'union',[{'atom',1883,'ok'}|[{'atom',1883,'error'}]]}]]}]}], %% Line 1892 'spec' = %% Line 1892 [{{'compile_asm',3},[{'type',1892,'fun',[{'type',1892,'product',[{'remote_type',1892,[{'atom',1892,'file'}|[{'atom',1892,'filename'}|[[]]]]}|[{'var',1892,'_'}|[{'type',1892,'record',[{'atom',1892,'options'}]}]]]}|[{'type',1892,'union',[{'atom',1892,'ok'}|[{'atom',1892,'error'}]]}]]}]}], %% Line 1901 'spec' = %% Line 1901 [{{'compile_core',3},[{'type',1901,'fun',[{'type',1901,'product',[{'remote_type',1901,[{'atom',1901,'file'}|[{'atom',1901,'filename'}|[[]]]]}|[{'var',1901,'_'}|[{'type',1901,'record',[{'atom',1901,'options'}]}]]]}|[{'type',1901,'union',[{'atom',1901,'ok'}|[{'atom',1901,'error'}]]}]]}]}]] 'file'/1 = %% Line 82 fun (_0) -> apply 'file'/2 (_0, ['verbose'|['report_errors'|['report_warnings']]]) 'file'/2 = %% Line 86 fun (_1,_0) -> case <_1,_0> of when call 'erlang':'is_list' (Opts) -> let <_2> = apply %% Line 87 'env_default_opts'/0 () in let <_3> = call %% Line 87 'erlang':%% Line 87 '++' (%% Line 87 Opts, _2) in %% Line 87 apply 'do_compile'/2 ({'file',File}, _3) %% Line 88 when 'true' -> %% Line 89 apply 'file'/2 (File, [Opt|['verbose'|['report_errors'|['report_warnings']]]]) end 'forms'/1 = %% Line 93 fun (_0) -> apply 'forms'/2 (_0, ['verbose'|['report_errors'|['report_warnings']]]) 'forms'/2 = %% Line 97 fun (_1,_0) -> case <_1,_0> of when call 'erlang':'is_list' (Opts) -> let <_2> = apply %% Line 98 'env_default_opts'/0 () in let <_3> = call %% Line 98 'erlang':%% Line 98 '++' (%% Line 98 Opts, _2) in %% Line 98 apply 'do_compile'/2 ({'forms',Forms}, ['binary'|_3]) %% Line 99 when call 'erlang':'is_atom' (Opt) -> %% Line 100 apply 'forms'/2 (Forms, [Opt|['verbose'|['report_errors'|['report_warnings']]]]) ( <_5,_4> when 'true' -> ( primop 'match_fail' ({'function_clause',_5,_4}) -| [{'function_name',{'forms',2}}] ) -| ['compiler_generated'] ) end 'output_generated'/1 = %% Line 108 fun (_0) -> let <_1> = apply %% Line 109 'env_default_opts'/0 () in let <_2> = call %% Line 109 'erlang':%% Line 109 '++' (_0, _1) in %% Line 109 apply 'noenv_output_generated'/1 (_2) 'noenv_file'/2 = %% Line 118 fun (_1,_0) -> case <_1,_0> of when call 'erlang':'is_list' (Opts) -> %% Line 119 apply 'do_compile'/2 ({'file',File}, Opts) %% Line 120 when 'true' -> %% Line 121 apply 'noenv_file'/2 (File, [Opt|['verbose'|['report_errors'|['report_warnings']]]]) end 'noenv_forms'/2 = %% Line 125 fun (_1,_0) -> case <_1,_0> of when call 'erlang':'is_list' (Opts) -> %% Line 126 apply 'do_compile'/2 ({'forms',Forms}, ['binary'|Opts]) %% Line 127 when call 'erlang':'is_atom' (Opt) -> %% Line 128 apply 'noenv_forms'/2 (Forms, [Opt|['verbose'|['report_errors'|['report_warnings']]]]) ( <_3,_2> when 'true' -> ( primop 'match_fail' ({'function_clause',_3,_2}) -| [{'function_name',{'noenv_forms',2}}] ) -| ['compiler_generated'] ) end 'noenv_output_generated'/1 = %% Line 132 fun (_0) -> let <_1> = apply %% Line 133 'expand_opts'/1 (_0) in %% Line 133 case apply 'passes'/2 ('file', _1) of <{_7,Passes}> when 'true' -> let <_5> = fun (_3) -> %% Line 134 case _3 of <{'save_binary',_X_T,_X_F}> when 'true' -> 'true' %% Line 135 <_X_Other> when 'true' -> 'false' end in %% Line 134 call 'lists':'any' (_5, %% Line 136 Passes) ( <_2> when 'true' -> primop 'match_fail' ({'badmatch',_2}) -| ['compiler_generated'] ) end 'env_compiler_options'/0 = %% Line 144 fun () -> apply 'env_default_opts'/0 () 'env_default_opts'/0 = %% Line 153 fun () -> %% Line 155 case call 'os':'getenv' ([69|[82|[76|[95|[67|[79|[77|[80|[73|[76|[69|[82|[95|[79|[80|[84|[73|[79|[78|[83]]]]]]]]]]]]]]]]]]]]) of %% Line 156 <'false'> when 'true' -> [] %% Line 157 when call 'erlang':'is_list' (Str) -> %% Line 158 case call 'erl_scan':'string' (Str) of %% Line 159 <{'ok',Tokens,_7}> when 'true' -> let <_1> = call %% Line 160 'erl_anno':%% Line 160 'new' (%% Line 160 1) in let = {%% Line 160 'dot',_1} in let <_3> = call %% Line 161 'erlang':%% Line 161 '++' (%% Line 161 Tokens, %% Line 161 [Dot|[]]) in %% Line 161 case call 'erl_parse':'parse_term' (_3) of %% Line 162 <{'ok',List}> when call 'erlang':'is_list' (List) -> List %% Line 163 <{'ok',Term}> when 'true' -> [Term|[]] %% Line 164 <{'error',_X_Reason}> when 'true' -> do %% Line 165 call 'io':'format' ([73|[103|[110|[111|[114|[105|[110|[103|[32|[98|[97|[100|[32|[116|[101|[114|[109|[32|[105|[110|[32|[126|[115|[10]]]]]]]]]]]]]]]]]]]]]]]], [[69|[82|[76|[95|[67|[79|[77|[80|[73|[76|[69|[82|[95|[79|[80|[84|[73|[79|[78|[83]]]]]]]]]]]]]]]]]]]]]) %% Line 166 [] ( <_4> when 'true' -> primop 'match_fail' ({'case_clause',_4}) -| ['compiler_generated'] ) end %% Line 168 <{'error',{_8,_9,_X_Reason},_10}> when 'true' -> do %% Line 169 call 'io':'format' ([73|[103|[110|[111|[114|[105|[110|[103|[32|[98|[97|[100|[32|[116|[101|[114|[109|[32|[105|[110|[32|[126|[115|[10]]]]]]]]]]]]]]]]]]]]]]]], [[69|[82|[76|[95|[67|[79|[77|[80|[73|[76|[69|[82|[95|[79|[80|[84|[73|[79|[78|[83]]]]]]]]]]]]]]]]]]]]]) %% Line 170 [] ( <_5> when 'true' -> primop 'match_fail' ({'case_clause',_5}) -| ['compiler_generated'] ) end ( <_6> when 'true' -> primop 'match_fail' ({'case_clause',_6}) -| ['compiler_generated'] ) end 'do_compile'/2 = %% Line 174 fun (_1,_0) -> let = apply %% Line 175 'expand_opts'/1 (_0) in let = fun () -> %% Line 176 try %% Line 177 apply 'internal'/2 (_1, Opts) of <_3> -> _3 catch <_6,_5,_4> -> %% Line 179 case <_6,_5,_4> of <( 'error' -| ['compiler_generated'] ),Reason,_14> when 'true' -> %% Line 180 {'error',Reason} ( <_19,_20,_21> when 'true' -> primop 'raise' (_21, _20) -| ['compiler_generated'] ) end in %% Line 184 case call 'lists':'member' ('dialyzer', Opts) of %% Line 185 <'true'> when 'true' -> %% Line 186 apply IntFun () %% Line 187 <'false'> when 'true' -> let <_9> = fun () -> let <_8> = apply %% Line 190 IntFun () in %% Line 190 call 'erlang':'exit' (_8) in %% Line 188 case %% Line 189 call 'erlang':'spawn_monitor' (_9) of <{Pid,Ref}> when 'true' -> %% Line 192 receive %% Line 193 <{'DOWN',_15,'process',_16,Rep}> when let <_17> = call 'erlang':'=:=' (_15, Ref) in let <_18> = call 'erlang':'=:=' (_16, Pid) in call 'erlang':'and' (_17, _18) -> Rep after 'infinity' -> 'true' ( <_10> when 'true' -> primop 'match_fail' ({'badmatch',_10}) -| ['compiler_generated'] ) end ( <_11> when 'true' -> primop 'match_fail' ({'case_clause',_11}) -| ['compiler_generated'] ) end 'expand_opts'/1 = %% Line 197 fun (_0) -> let <_3> = call %% Line 199 'proplists':%% Line 199 'get_value' (%% Line 199 'debug_info_key', _0) in let <_2> = call %% Line 200 'proplists':%% Line 200 'get_value' (%% Line 200 'encrypt_debug_info', _0) in let <_1> = call %% Line 201 'proplists':%% Line 201 'get_value' (%% Line 201 'debug_info', _0) in let <_5> = case <_3,_2,_1> of %% Line 202 <( 'undefined' -| ['compiler_generated'] ),( 'undefined' -| ['compiler_generated'] ),_11> when 'true' -> _0 %% Line 203 <_12,_13,( 'undefined' -| ['compiler_generated'] )> when 'true' -> ['debug_info'|_0] %% Line 204 <_14,_15,_16> when 'true' -> _0 end in let <_8> = case %% Line 207 call 'proplists':'is_defined' ('makedep_side_effect', _5) of %% Line 208 <'true'> when 'true' -> call 'proplists':'delete' ('makedep', _5) %% Line 209 <'false'> when 'true' -> _5 ( <_7> when 'true' -> %% Line 207 primop 'match_fail' ({'case_clause',_7}) -| ['compiler_generated'] ) end in %% Line 211 call 'lists':'foldr' (( 'expand_opt'/2 -| [{'id',{0,0,'-expand_opts/1-fun-0-'}}] ), [], _8) 'expand_opt'/2 = %% Line 213 fun (_1,_0) -> case <_1,_0> of <'basic_validation',Os> when 'true' -> %% Line 214 ['no_code_generation'|['to_pp'|['binary'|Os]]] %% Line 215 <'strong_validation',Os> when 'true' -> %% Line 216 ['no_code_generation'|['to_kernel'|['binary'|Os]]] %% Line 217 <'report',Os> when 'true' -> %% Line 218 ['report_errors'|['report_warnings'|Os]] %% Line 219 <'return',Os> when 'true' -> %% Line 220 ['return_errors'|['return_warnings'|Os]] %% Line 221 <'r16',Os> when 'true' -> %% Line 222 ['no_get_hd_tl'|['no_record_opt'|['no_utf8_atoms'|Os]]] %% Line 223 <'r17',Os> when 'true' -> %% Line 224 ['no_get_hd_tl'|['no_record_opt'|['no_utf8_atoms'|Os]]] %% Line 225 <'r18',Os> when 'true' -> %% Line 226 ['no_get_hd_tl'|['no_record_opt'|['no_utf8_atoms'|Os]]] %% Line 227 <'r19',Os> when 'true' -> %% Line 228 ['no_get_hd_tl'|['no_record_opt'|['no_utf8_atoms'|Os]]] %% Line 229 <'r20',Os> when 'true' -> %% Line 230 ['no_get_hd_tl'|['no_record_opt'|['no_utf8_atoms'|Os]]] %% Line 231 when 'true' -> %% Line 232 ['encrypt_debug_info'|[O|Os]] %% Line 233 <'no_float_opt',Os> when 'true' -> %% Line 235 ['no_topt'|Os] %% Line 236 when 'true' -> [O|Os] end 'format_error'/1 = %% Line 242 fun (_0) -> case _0 of <'no_native_support'> when 'true' -> %% Line 243 [116|[104|[105|[115|[32|[115|[121|[115|[116|[101|[109|[32|[105|[115|[32|[110|[111|[116|[32|[99|[111|[110|[102|[105|[103|[117|[114|[101|[100|[32|[102|[111|[114|[32|[110|[97|[116|[105|[118|[101|[45|[99|[111|[100|[101|[32|[99|[111|[109|[112|[105|[108|[97|[116|[105|[111|[110|[46]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]] %% Line 244 <'no_crypto'> when 'true' -> %% Line 245 [116|[104|[105|[115|[32|[115|[121|[115|[116|[101|[109|[32|[105|[115|[32|[110|[111|[116|[32|[99|[111|[110|[102|[105|[103|[117|[114|[101|[100|[32|[119|[105|[116|[104|[32|[99|[114|[121|[112|[116|[111|[32|[115|[117|[112|[112|[111|[114|[116|[46]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]] %% Line 246 <'bad_crypto_key'> when 'true' -> %% Line 247 [105|[110|[118|[97|[108|[105|[100|[32|[99|[114|[121|[112|[116|[111|[32|[107|[101|[121|[46]]]]]]]]]]]]]]]]]]] %% Line 248 <'no_crypto_key'> when 'true' -> %% Line 249 [110|[111|[32|[99|[114|[121|[112|[116|[111|[32|[107|[101|[121|[32|[115|[117|[112|[112|[108|[105|[101|[100|[46]]]]]]]]]]]]]]]]]]]]]]] %% Line 250 <{'native',E}> when 'true' -> %% Line 251 call 'io_lib':'fwrite' ([110|[97|[116|[105|[118|[101|[45|[99|[111|[100|[101|[32|[99|[111|[109|[112|[105|[108|[97|[116|[105|[111|[110|[32|[102|[97|[105|[108|[101|[100|[32|[119|[105|[116|[104|[32|[114|[101|[97|[115|[111|[110|[58|[32|[126|[116|[80|[46]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]], %% Line 252 [E|[25]]) %% Line 253 <{'native_crash',E,Stk}> when 'true' -> %% Line 254 call 'io_lib':'fwrite' ([110|[97|[116|[105|[118|[101|[45|[99|[111|[100|[101|[32|[99|[111|[109|[112|[105|[108|[97|[116|[105|[111|[110|[32|[99|[114|[97|[115|[104|[101|[100|[32|[119|[105|[116|[104|[32|[114|[101|[97|[115|[111|[110|[58|[32|[126|[116|[80|[46|[10|[126|[116|[80|[10]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]], %% Line 255 [E|[25|[Stk|[25]]]]) %% Line 256 <{'open',E}> when 'true' -> let <_1> = call %% Line 257 'file':%% Line 257 'format_error' (%% Line 257 E) in %% Line 257 call 'io_lib':'format' ([111|[112|[101|[110|[32|[101|[114|[114|[111|[114|[32|[39|[126|[116|[115|[39]]]]]]]]]]]]]]]], [_1|[]]) %% Line 258 <{'epp',E}> when 'true' -> %% Line 259 call 'epp':'format_error' (E) %% Line 260 <'write_error'> when 'true' -> %% Line 261 [101|[114|[114|[111|[114|[32|[119|[114|[105|[116|[105|[110|[103|[32|[102|[105|[108|[101]]]]]]]]]]]]]]]]]] %% Line 262 <{'write_error',Error}> when 'true' -> let <_2> = call %% Line 263 'file':%% Line 263 'format_error' (%% Line 263 Error) in %% Line 263 call 'io_lib':'format' ([101|[114|[114|[111|[114|[32|[119|[114|[105|[116|[105|[110|[103|[32|[102|[105|[108|[101|[58|[32|[126|[116|[115]]]]]]]]]]]]]]]]]]]]]]], [_2|[]]) %% Line 264 <{'rename',From,To,Error}> when 'true' -> let <_3> = call %% Line 266 'file':%% Line 266 'format_error' (%% Line 266 Error) in %% Line 265 call 'io_lib':'format' ([102|[97|[105|[108|[101|[100|[32|[116|[111|[32|[114|[101|[110|[97|[109|[101|[32|[126|[116|[115|[32|[116|[111|[32|[126|[116|[115|[58|[32|[126|[116|[115]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]], %% Line 266 [From|[To|[_3|[]]]]) %% Line 267 <{'delete',File,Error}> when 'true' -> let <_4> = call %% Line 269 'file':%% Line 269 'format_error' (%% Line 269 Error) in %% Line 268 call 'io_lib':'format' ([102|[97|[105|[108|[101|[100|[32|[116|[111|[32|[100|[101|[108|[101|[116|[101|[32|[102|[105|[108|[101|[32|[126|[116|[115|[58|[32|[126|[116|[115]]]]]]]]]]]]]]]]]]]]]]]]]]]]]], %% Line 269 [File|[_4|[]]]) %% Line 270 <{'delete_temp',File,Error}> when 'true' -> let <_5> = call %% Line 272 'file':%% Line 272 'format_error' (%% Line 272 Error) in %% Line 271 call 'io_lib':'format' ([102|[97|[105|[108|[101|[100|[32|[116|[111|[32|[100|[101|[108|[101|[116|[101|[32|[116|[101|[109|[112|[111|[114|[97|[114|[121|[32|[102|[105|[108|[101|[32|[126|[116|[115|[58|[32|[126|[116|[115]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]], %% Line 272 [File|[_5|[]]]) %% Line 273 <{'parse_transform',M,R}> when 'true' -> %% Line 274 call 'io_lib':'format' ([101|[114|[114|[111|[114|[32|[105|[110|[32|[112|[97|[114|[115|[101|[32|[116|[114|[97|[110|[115|[102|[111|[114|[109|[32|[39|[126|[116|[115|[39|[58|[32|[126|[116|[112]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]], [M|[R|[]]]) %% Line 275 <{'undef_parse_transform',M}> when 'true' -> %% Line 276 call 'io_lib':'format' ([117|[110|[100|[101|[102|[105|[110|[101|[100|[32|[112|[97|[114|[115|[101|[32|[116|[114|[97|[110|[115|[102|[111|[114|[109|[32|[39|[126|[116|[115|[39]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]], [M|[]]) %% Line 277 <{'core_transform',M,R}> when 'true' -> %% Line 278 call 'io_lib':'format' ([101|[114|[114|[111|[114|[32|[105|[110|[32|[99|[111|[114|[101|[32|[116|[114|[97|[110|[115|[102|[111|[114|[109|[32|[39|[126|[115|[39|[58|[32|[126|[116|[112]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]], [M|[R|[]]]) %% Line 279 <{'crash',Pass,Reason}> when 'true' -> let <_6> = apply %% Line 280 'format_error_reason'/1 (%% Line 280 Reason) in %% Line 280 call 'io_lib':'format' ([105|[110|[116|[101|[114|[110|[97|[108|[32|[101|[114|[114|[111|[114|[32|[105|[110|[32|[126|[112|[59|[10|[99|[114|[97|[115|[104|[32|[114|[101|[97|[115|[111|[110|[58|[32|[126|[116|[115]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]], [Pass|[_6|[]]]) %% Line 281 <{'bad_return',Pass,Reason}> when 'true' -> let <_7> = apply %% Line 282 'format_error_reason'/1 (%% Line 282 Reason) in %% Line 282 call 'io_lib':'format' ([105|[110|[116|[101|[114|[110|[97|[108|[32|[101|[114|[114|[111|[114|[32|[105|[110|[32|[126|[112|[59|[10|[98|[97|[100|[32|[114|[101|[116|[117|[114|[110|[32|[118|[97|[108|[117|[101|[58|[32|[126|[116|[115]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]], [Pass|[_7|[]]]) %% Line 283 <{'module_name',Mod,Filename}> when 'true' -> %% Line 284 call 'io_lib':'format' ([77|[111|[100|[117|[108|[101|[32|[110|[97|[109|[101|[32|[39|[126|[115|[39|[32|[100|[111|[101|[115|[32|[110|[111|[116|[32|[109|[97|[116|[99|[104|[32|[102|[105|[108|[101|[32|[110|[97|[109|[101|[32|[39|[126|[116|[115|[39]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]], [Mod|[Filename|[]]]) %% Line 285 <'reparsing_invalid_unicode'> when 'true' -> %% Line 286 [78|[111|[110|[45|[85|[84|[70|[45|[56|[32|[99|[104|[97|[114|[97|[99|[116|[101|[114|[40|[115|[41|[32|[100|[101|[116|[101|[99|[116|[101|[100|[44|[32|[98|[117|[116|[32|[110|[111|[32|[101|[110|[99|[111|[100|[105|[110|[103|[32|[100|[101|[99|[108|[97|[114|[101|[100|[46|[32|[69|[110|[99|[111|[100|[101|[32|[116|[104|[101|[32|[102|[105|[108|[101|[32|[105|[110|[32|[85|[84|[70|[45|[56|[32|[111|[114|[32|[97|[100|[100|[32|[34|[37|[37|[32|[99|[111|[100|[105|[110|[103|[58|[32|[108|[97|[116|[105|[110|[45|[49|[34|[32|[97|[116|[32|[116|[104|[101|[32|[98|[101|[103|[105|[110|[110|[105|[110|[103|[32|[111|[102|[32|[116|[104|[101|[32|[102|[105|[108|[101|[46|[32|[82|[101|[116|[114|[121|[105|[110|[103|[32|[119|[105|[116|[104|[32|[108|[97|[116|[105|[110|[45|[49|[32|[101|[110|[99|[111|[100|[105|[110|[103|[46]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]] ( <_8> when 'true' -> ( primop 'match_fail' ({'function_clause',_8}) -| [{'function_name',{'format_error',1}}] ) -| ['compiler_generated'] ) end 'format_error_reason'/1 = %% Line 288 fun (_0) -> case _0 of <{Reason,Stack}> when call 'erlang':'is_list' (Stack) -> let = fun (_3,_2,_1) -> %% Line 289 case <_3,_2,_1> of %% Line 290 <'escript','run',2> when 'true' -> 'true' %% Line 291 <'escript','start',1> when 'true' -> 'true' %% Line 292 <'init','start_it',1> when 'true' -> 'true' %% Line 293 <'init','start_em',1> when 'true' -> 'true' %% Line 294 <_X_Mod,_X_Fun,_X_Arity> when 'true' -> 'false' end in let = fun (_9,_8) -> %% Line 296 call 'io_lib':'format' ([126|[116|[112]]], [_9|[]]) in let <_13> = call %% Line 297 'io_lib':%% Line 297 'format' (%% Line 297 [126|[116|[112]]], %% Line 297 [Reason|[]]) in let <_14> = call %% Line 298 'erl_error':%% Line 298 'format_stacktrace' (%% Line 298 1, %% Line 298 Stack, %% Line 298 StackFun, %% Line 298 FormatFun) in %% Line 297 [_13|[[10|[10]]|%% Line 298 [_14|[]]]] %% Line 299 when 'true' -> %% Line 300 call 'io_lib':'format' ([126|[116|[112]]], [Reason|[]]) end 'internal'/2 = %% Line 320 fun (_1,_0) -> case <_1,_0> of <{'forms',Forms},Opts0> when 'true' -> %% Line 321 case apply 'passes'/2 ('forms', Opts0) of <{_10,Ps}> when 'true' -> let = call %% Line 322 'proplists':%% Line 322 'get_value' (%% Line 322 'source', %% Line 322 Opts0, %% Line 322 []) in let = call %% Line 323 'proplists':%% Line 323 'delete' (%% Line 323 'source', %% Line 323 Opts0) in let = apply %% Line 324 'build_compile'/1 (%% Line 324 Opts1) in %% Line 325 apply 'internal_comp'/5 (Ps, Forms, Source, [], Compile) ( <_2> when 'true' -> primop 'match_fail' ({'badmatch',_2}) -| ['compiler_generated'] ) end %% Line 326 <{'file',File},Opts> when 'true' -> %% Line 327 case apply 'passes'/2 ('file', Opts) of <{Ext,Ps}> when 'true' -> let = apply %% Line 328 'build_compile'/1 (%% Line 328 Opts) in %% Line 329 apply 'internal_comp'/5 (Ps, 'none', File, Ext, Compile) ( <_6> when 'true' -> primop 'match_fail' ({'badmatch',_6}) -| ['compiler_generated'] ) end ( <_9,_8> when 'true' -> ( primop 'match_fail' ({'function_clause',_9,_8}) -| [{'function_name',{'internal',2}}] ) -| ['compiler_generated'] ) end 'build_compile'/1 = %% Line 331 fun (_0) -> let = call %% Line 332 'proplists':%% Line 332 'get_value' (%% Line 332 'extra_chunks', _0, %% Line 332 []) in let = call %% Line 333 'proplists':%% Line 333 'delete' (%% Line 333 'extra_chunks', _0) in %% Line 334 {'compile',[],[],[],[],[],[],[],[],Opts1,Opts1,'none',[],[],ExtraChunks} 'internal_comp'/5 = %% Line 336 fun (_4,_3,_2,_1,_0) -> let

= call %% Line 337 'filename':%% Line 337 'dirname' (_2) in let = call %% Line 338 'filename':%% Line 338 'basename' (_2, _1) in let <_rec0> = apply %% Line 340 'erlfile'/3 (%% Line 340 Dir, %% Line 340 Base, _1) in let <_rec1> = apply %% Line 341 'objfile'/2 (%% Line 341 Base, _0) in %% Line 339 case _0 of <{'compile',_44,_45,_46,_47,_48,_49,_50,_51,_52,_53,_54,_55,_56,_57}> when 'true' -> let <_10> = call %% Line 341 'erlang':%% Line 341 'setelement' (%% Line 341 6, _0, %% Line 341 _rec1) in let <_11> = call %% Line 340 'erlang':%% Line 340 'setelement' (%% Line 340 5, _10, %% Line 340 _rec0) in let <_12> = call 'erlang':'setelement' (4, _11, Base) in let <_13> = call 'erlang':'setelement' (3, _12, Dir) in let <_15> = call 'erlang':'setelement' (2, _13, _2) in %% Line 342 ( case _15 of ( <( {'compile',_59,_60,_61,_62,_63,_64,_65,_66,_rec3,_67,_68,_69,_70,_71} -| ['compiler_generated'] )> when 'true' -> let <_27> = case %% Line 343 call 'lists':'member' ('time', _rec3) of %% Line 344 <'true'> when 'true' -> do %% Line 345 call 'io':'format' ([67|[111|[109|[112|[105|[108|[105|[110|[103|[32|[126|[116|[112|[10]]]]]]]]]]]]]], [_2|[]]) %% Line 346 ( 'run_tc'/3 -| [{'id',{0,0,'-internal_comp/5-fun-0-'}}] ) %% Line 347 <'false'> when 'true' -> %% Line 348 ( fun (_22,_21,_20) -> case <_22,_21,_20> of <{_X_Name,Fun},Code,St> when 'true' -> catch %% Line 349 apply Fun (Code, St) ( <_25,_24,_23> when 'true' -> ( primop 'match_fail' ({'function_clause',_25,_24,_23}) -| [{'function_name',{'-internal_comp/5-fun-1-',3}}] ) -| ['compiler_generated'] ) end -| [{'id',{0,0,'-internal_comp/5-fun-1-'}}] ) ( <_26> when 'true' -> %% Line 343 primop 'match_fail' ({'case_clause',_26}) -| ['compiler_generated'] ) end in let <_36> = case %% Line 352 call 'lists':'keyfind' ('eprof', 1, _rec3) of %% Line 353 <{'eprof',EprofPass}> when 'true' -> %% Line 354 ( fun (_31,_30,_29) -> %% Line 355 apply 'run_eprof'/4 (_31, _30, EprofPass, _29) -| [{'id',{0,0,'-internal_comp/5-fun-2-'}}] ) %% Line 357 <'false'> when 'true' -> _27 ( <_35> when 'true' -> %% Line 352 primop 'match_fail' ({'case_clause',_35}) -| ['compiler_generated'] ) end in %% Line 360 case apply 'fold_comp'/4 (_4, _36, _3, _15) of %% Line 361 <{'ok',Code,St2}> when 'true' -> apply 'comp_ret_ok'/2 (Code, St2) %% Line 362 <{'error',St2}> when 'true' -> apply 'comp_ret_err'/1 (St2) ( <_38> when 'true' -> primop 'match_fail' ({'case_clause',_38}) -| ['compiler_generated'] ) end -| ['compiler_generated'] ) ( <_72> when 'true' -> ( call ( 'erlang' -| ['compiler_generated'] ):( 'error' -| ['compiler_generated'] ) (( {'badrecord','compile'} -| ['compiler_generated'] )) -| ['compiler_generated'] ) -| ['compiler_generated'] ) end -| ['compiler_generated'] ) ( <_58> when 'true' -> ( call ( 'erlang' -| ['compiler_generated'] ):( 'error' -| ['compiler_generated'] ) (( {'badrecord','compile'} -| ['compiler_generated'] )) -| ['compiler_generated'] ) -| ['compiler_generated'] ) end 'fold_comp'/4 = %% Line 365 fun (_3,_2,_1,_0) -> case <_3,_2,_1,_0> of <[{'delay',Ps0}|Passes],Run,Code,St = {'compile',_30,_31,_32,_33,_34,_35,_36,_37,Opts,_38,_39,_40,_41,_42}> when 'true' -> let <_4> = apply %% Line 366 'select_passes'/2 (%% Line 366 Ps0, %% Line 366 Opts) in let = call %% Line 366 'erlang':%% Line 366 '++' (_4, %% Line 366 Passes) in %% Line 367 apply 'fold_comp'/4 (Ps, Run, Code, St) %% Line 368 <[{Name,Test,Pass}|Ps],Run,Code,St> when 'true' -> %% Line 369 case apply Test (St) of %% Line 370 <'false'> when 'true' -> %% Line 371 apply 'fold_comp'/4 (Ps, Run, Code, St) %% Line 372 <'true'> when 'true' -> %% Line 373 apply 'fold_comp'/4 ([{Name,Pass}|Ps], Run, Code, St) ( <_6> when 'true' -> primop 'match_fail' ({'case_clause',_6}) -| ['compiler_generated'] ) end %% Line 375 <[_@r0 = {Name,Pass}|Ps],Run,Code0,St0> when 'true' -> %% Line 376 case apply Run (_@r0, Code0, St0) of %% Line 377 <{'ok',Code,St1}> when 'true' -> %% Line 378 apply 'fold_comp'/4 (Ps, Run, Code, St1) %% Line 379 when 'true' -> %% Line 380 Error %% Line 381 <{'EXIT',Reason}> when 'true' -> %% Line 382 ( case St0 of ( <( {'compile',_43,_44,_45,_rec4,_46,_47,_48,_49,_50,_51,_52,_53,_54,_55} -| ['compiler_generated'] )> when 'true' -> let = [{_rec4,[{'none','compile',{'crash',Name,Reason}}|[]]}|[]] in let <_rec5> = call %% Line 383 'erlang':%% Line 383 '++' (_53, %% Line 383 Es) in let <_15> = call %% Line 383 'erlang':%% Line 383 'setelement' (%% Line 383 13, %% Line 383 St0, %% Line 383 _rec5) in %% Line 383 {'error',_15} -| ['compiler_generated'] ) ( <_56> when 'true' -> ( call ( 'erlang' -| ['compiler_generated'] ):( 'error' -| ['compiler_generated'] ) (( {'badrecord','compile'} -| ['compiler_generated'] )) -| ['compiler_generated'] ) -| ['compiler_generated'] ) end -| ['compiler_generated'] ) %% Line 384 when 'true' -> %% Line 385 ( case St0 of ( <( {'compile',_86,_87,_88,_rec8,_89,_90,_91,_92,_93,_94,_95,_96,_97,_98} -| ['compiler_generated'] )> when 'true' -> let = [{_rec8,[{'none','compile',{'bad_return',Name,Other}}|[]]}|[]] in let <_rec9> = call %% Line 386 'erlang':%% Line 386 '++' (_96, %% Line 386 Es) in let <_24> = call %% Line 386 'erlang':%% Line 386 'setelement' (%% Line 386 13, %% Line 386 St0, %% Line 386 _rec9) in %% Line 386 {'error',_24} -| ['compiler_generated'] ) ( <_99> when 'true' -> ( call ( 'erlang' -| ['compiler_generated'] ):( 'error' -| ['compiler_generated'] ) (( {'badrecord','compile'} -| ['compiler_generated'] )) -| ['compiler_generated'] ) -| ['compiler_generated'] ) end -| ['compiler_generated'] ) end %% Line 388 <[],_X_Run,Code,St> when 'true' -> {'ok',Code,St} ( <_29,_28,_27,_26> when 'true' -> ( primop 'match_fail' ({'function_clause',_29,_28,_27,_26}) -| [{'function_name',{'fold_comp',4}}] ) -| ['compiler_generated'] ) end 'run_tc'/3 = %% Line 390 fun (_2,_1,_0) -> case <_2,_1,_0> of <{Name,Fun},Code,St> when 'true' -> let = call %% Line 391 'erlang':%% Line 391 'monotonic_time' () in let <_4> = catch %% Line 392 apply Fun (Code, St) in let = call %% Line 393 'erlang':%% Line 393 'monotonic_time' () in let <_7> = call %% Line 394 'erlang':%% Line 394 '-' (%% Line 394 T2, %% Line 394 T1) in let = call %% Line 394 'erlang':%% Line 394 'convert_time_unit' (_7, %% Line 394 'native', %% Line 394 'millisecond') in let <_10> = call %% Line 395 'erts_debug':%% Line 395 'flat_size' (_4) in let <_9> = call %% Line 395 'erlang':%% Line 395 'system_info' (%% Line 395 'wordsize') in let = call %% Line 395 'erlang':%% Line 395 '*' (_10, _9) in let <_12> = call %% Line 396 'erlang':%% Line 396 '/' (%% Line 396 Mem0, %% Line 396 1024) in let <_13> = call %% Line 396 'io_lib':%% Line 396 'format' (%% Line 396 [126|[46|[49|[102|[32|[107|[66]]]]]]], %% Line 396 [_12|[]]) in let = call %% Line 396 'lists':%% Line 396 'flatten' (_13) in let <_15> = call %% Line 398 'erlang':%% Line 398 '/' (%% Line 398 Elapsed, %% Line 398 1000) in do %% Line 397 call 'io':'format' ([32|[126|[45|[51|[48|[115|[58|[32|[126|[49|[48|[46|[51|[102|[32|[115|[32|[126|[49|[50|[115|[10]]]]]]]]]]]]]]]]]]]]]], %% Line 398 [Name|[_15|[Mem|[]]]]) _4 ( <_18,_17,_16> when 'true' -> ( primop 'match_fail' ({'function_clause',_18,_17,_16}) -| [{'function_name',{'run_tc',3}}] ) -| ['compiler_generated'] ) end 'run_eprof'/4 = %% Line 401 fun (_3,_2,_1,_0) -> case <_3,_2,_1,_0> of <{Name,Fun},Code,_11,St> when call 'erlang':'=:=' (_11, Name) -> do %% Line 402 call 'io':'format' ([126|[112|[58|[32|[82|[117|[110|[110|[105|[110|[103|[32|[101|[112|[114|[111|[102|[10]]]]]]]]]]]]]]]]]], [Name|[]]) let <_4> = call %% Line 403 'erlang':%% Line 403 'self' () in do %% Line 403 call 'c':'appcall' ('tools', 'eprof', 'start_profiling', [[_4|[]]|[]]) let <_5> = catch %% Line 404 apply Fun (Code, St) in do %% Line 405 call 'c':'appcall' ('tools', 'eprof', 'stop_profiling', []) do %% Line 406 call 'c':'appcall' ('tools', 'eprof', 'analyze', []) _5 %% Line 408 <{_12,Fun},Code,_13,St> when 'true' -> catch %% Line 409 apply Fun (Code, St) ( <_10,_9,_8,_7> when 'true' -> ( primop 'match_fail' ({'function_clause',_10,_9,_8,_7}) -| [{'function_name',{'run_eprof',4}}] ) -| ['compiler_generated'] ) end 'comp_ret_ok'/2 = %% Line 411 fun (_1,_0) -> case <_1,_0> of when 'true' -> %% Line 412 case apply 'werror'/1 (St) of %% Line 413 <'true'> when 'true' -> do %% Line 414 case call 'lists':'member' ('report_warnings', Opts) of %% Line 415 <'true'> when 'true' -> %% Line 416 call 'io':'format' ([126|[112|[58|[32|[119|[97|[114|[110|[105|[110|[103|[115|[32|[98|[101|[105|[110|[103|[32|[116|[114|[101|[97|[116|[101|[100|[32|[97|[115|[32|[101|[114|[114|[111|[114|[115|[10]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]], %% Line 417 ['compile']) %% Line 418 <'false'> when 'true' -> 'ok' ( <_2> when 'true' -> primop 'match_fail' ({'case_clause',_2}) -| ['compiler_generated'] ) end %% Line 421 apply 'comp_ret_err'/1 (St) %% Line 422 <'false'> when 'true' -> let = apply %% Line 423 'messages_per_file'/1 (%% Line 423 Warn0) in let <_6> = call %% Line 424 'erlang':%% Line 424 'setelement' (%% Line 424 14, %% Line 424 St, %% Line 424 Warn) in do %% Line 424 apply 'report_warnings'/1 (_6) let <_10> = case %% Line 425 call 'lists':'member' ('binary', Opts) of %% Line 425 ( <( 'true' -| ['compiler_generated'] )> when 'true' -> let <_8> = call %% Line 426 'lists':%% Line 426 'member' (%% Line 426 'no_code_generation', %% Line 426 Opts) in %% Line 426 call 'erlang':'not' (_8) -| ['compiler_generated'] ) %% Line 425 ( <( 'false' -| ['compiler_generated'] )> when 'true' -> 'false' -| ['compiler_generated'] ) %% Line 425 ( <_7> when 'true' -> ( call ( 'erlang' -| ['compiler_generated'] ):( 'error' -| ['compiler_generated'] ) (( {( 'badarg' -| ['compiler_generated'] ),_7} -| ['compiler_generated'] )) -| ['compiler_generated'] ) -| ['compiler_generated'] ) end in let <_12> = case _10 of %% Line 427 <'true'> when 'true' -> [Code|[]] %% Line 428 <'false'> when 'true' -> [] ( <_11> when 'true' -> %% Line 425 primop 'match_fail' ({'case_clause',_11}) -| ['compiler_generated'] ) end in let <_15> = case %% Line 430 call 'lists':'member' ('return_warnings', Opts) of %% Line 431 <'true'> when 'true' -> call 'erlang':'++' (_12, [Warn|[]]) %% Line 432 <'false'> when 'true' -> _12 ( <_14> when 'true' -> %% Line 430 primop 'match_fail' ({'case_clause',_14}) -| ['compiler_generated'] ) end in %% Line 434 call 'erlang':'list_to_tuple' (['ok'|[Mod|_15]]) ( <_17> when 'true' -> primop 'match_fail' ({'case_clause',_17}) -| ['compiler_generated'] ) end ( <_19,_18> when 'true' -> ( primop 'match_fail' ({'function_clause',_19,_18}) -| [{'function_name',{'comp_ret_ok',2}}] ) -| ['compiler_generated'] ) end 'comp_ret_err'/1 = %% Line 437 fun (_0) -> case _0 of when 'true' -> let = apply %% Line 438 'messages_per_file'/1 (%% Line 438 Warn0) in let = apply %% Line 439 'messages_per_file'/1 (%% Line 439 Err0) in let <_5> = call %% Line 440 'erlang':%% Line 440 'setelement' (%% Line 440 13, %% Line 440 St, %% Line 440 Err) in do %% Line 440 apply 'report_errors'/1 (_5) let <_8> = call %% Line 441 'erlang':%% Line 441 'setelement' (%% Line 441 14, %% Line 441 St, %% Line 441 Warn) in do %% Line 441 apply 'report_warnings'/1 (_8) %% Line 442 case call 'lists':'member' ('return_errors', Opts) of %% Line 443 <'true'> when 'true' -> {'error',Err,Warn} %% Line 444 <'false'> when 'true' -> 'error' ( <_9> when 'true' -> primop 'match_fail' ({'case_clause',_9}) -| ['compiler_generated'] ) end ( <_10> when 'true' -> ( primop 'match_fail' ({'function_clause',_10}) -| [{'function_name',{'comp_ret_err',1}}] ) -| ['compiler_generated'] ) end 'not_werror'/1 = %% Line 447 fun (_0) -> let <_1> = apply 'werror'/1 (_0) in call 'erlang':'not' (_1) 'werror'/1 = %% Line 449 fun (_0) -> case _0 of <{'compile',_4,_5,_6,_7,_8,_9,_10,_11,Opts,_12,_13,_14,Ws,_15}> when 'true' -> %% Line 450 ( case <> of ( <> when call 'erlang':'=/=' (Ws, []) -> call 'lists':'member' ('warnings_as_errors', Opts) -| ['compiler_generated'] ) ( <> when 'true' -> 'false' -| ['compiler_generated'] ) end -| ['compiler_generated'] ) ( <_3> when 'true' -> ( primop 'match_fail' ({'function_clause',_3}) -| [{'function_name',{'werror',1}}] ) -| ['compiler_generated'] ) end 'messages_per_file'/1 = %% Line 453 fun (_0) -> let <_8> = letrec 'lc$^0'/1 = %% Line 454 fun (_5) -> case _5 of <[{File,Messages}|_2]> when 'true' -> ( letrec 'lc$^1'/1 = fun (_6) -> case _6 of <[M|_4]> when 'true' -> let <_7> = apply 'lc$^1'/1 (_4) in ( [{File,M}|_7] -| ['compiler_generated'] ) <[]> when 'true' -> apply 'lc$^0'/1 (_2) ( <_38> when 'true' -> ( primop 'match_fail' ({'function_clause',_38}) -| [{'function_name',{'lc$^1',1}}] ) -| ['compiler_generated'] ) end in apply 'lc$^1'/1 (Messages) -| ['list_comprehension'] ) ( <[_1|_2]> when 'true' -> apply 'lc$^0'/1 (_2) -| ['compiler_generated'] ) <[]> when 'true' -> [] ( <_39> when 'true' -> ( primop 'match_fail' ({'function_clause',_39}) -| [{'function_name',{'lc$^0',1}}] ) -| ['compiler_generated'] ) end in %% Line 454 apply 'lc$^0'/1 (_0) in let = call %% Line 454 'lists':%% Line 454 'sort' (_8) in let <_18> = fun (_15,_14) -> let <_13> = fun (_11) -> %% Line 458 case _11 of <{_28,{_29,Mod,_30}}> when 'true' -> call 'erlang':'=:=' (Mod, _15) %% Line 459 <_31> when 'true' -> 'false' end in %% Line 458 call 'lists':'partition' (_13, _14) in %% Line 456 case %% Line 457 call 'lists':'mapfoldl' (_18, %% Line 461 T, ['erl_scan'|['epp'|['erl_parse']]]) of <{Prio0,Rest}> when 'true' -> let <_25> = fun (_22,_21) -> %% Line 462 case <_22,_21> of <{_32,{L1,_33,_34}},{_35,{L2,_36,_37}}> when 'true' -> call 'erlang':'=<' (L1, L2) ( <_24,_23> when 'true' -> ( primop 'match_fail' ({'function_clause',_24,_23}) -| [{'function_name',{'-messages_per_file/1-fun-4-',2}}] ) -| ['compiler_generated'] ) end in let <_20> = call %% Line 463 'lists':%% Line 463 'append' (%% Line 463 Prio0) in let = call %% Line 462 'lists':%% Line 462 'sort' (_25, _20) in %% Line 464 call 'lists':'flatmap' (( 'mpf'/1 -| [{'id',{0,0,'-messages_per_file/1-fun-5-'}}] ), [Prio|[Rest|[]]]) ( <_19> when 'true' -> primop 'match_fail' ({'badmatch',_19}) -| ['compiler_generated'] ) end 'mpf'/1 = %% Line 466 fun (_0) -> %% Line 468 ( letrec 'lc$^1'/1 = fun (_9) -> case _9 of <[File|_2]> when 'true' -> let <_14> = letrec 'lc$^2'/1 = fun (_12) -> case _12 of <[{F,M}|_11]> when call 'erlang':'=:=' (F, File) -> let <_13> = apply 'lc$^2'/1 (_11) in ( [M|_13] -| ['compiler_generated'] ) ( <[_10|_11]> when 'true' -> apply 'lc$^2'/1 (_11) -| ['compiler_generated'] ) <[]> when 'true' -> [] ( <_18> when 'true' -> ( primop 'match_fail' ({'function_clause',_18}) -| [{'function_name',{'lc$^2',1}}] ) -| ['compiler_generated'] ) end in apply 'lc$^2'/1 (_0) in let <_15> = apply 'lc$^1'/1 (_2) in ( [{File,_14}|_15] -| ['compiler_generated'] ) <[]> when 'true' -> [] ( <_19> when 'true' -> ( primop 'match_fail' ({'function_clause',_19}) -| [{'function_name',{'lc$^1',1}}] ) -| ['compiler_generated'] ) end in let <_7> = letrec 'lc$^0'/1 = fun (_5) -> case _5 of <[{F,_17}|_4]> when 'true' -> let <_6> = apply 'lc$^0'/1 (_4) in ( [F|_6] -| ['compiler_generated'] ) ( <[_3|_4]> when 'true' -> apply 'lc$^0'/1 (_4) -| ['compiler_generated'] ) <[]> when 'true' -> [] ( <_20> when 'true' -> ( primop 'match_fail' ({'function_clause',_20}) -| [{'function_name',{'lc$^0',1}}] ) -| ['compiler_generated'] ) end in apply 'lc$^0'/1 (_0) in let <_8> = call 'lists':'usort' (_7) in apply 'lc$^1'/1 (_8) -| ['list_comprehension'] ) 'passes'/2 = %% Line 474 fun (_1,_0) -> %% Line 475 case apply 'passes_1'/1 (_0) of <{Ext,Passes0}> when 'true' -> let <_4> = case _1 of %% Line 477 <'file'> when 'true' -> %% Line 478 Passes0 %% Line 479 <'forms'> when 'true' -> %% Line 480 apply 'fix_first_pass'/1 (Passes0) ( <_3> when 'true' -> %% Line 476 primop 'match_fail' ({'case_clause',_3}) -| ['compiler_generated'] ) end in let = apply %% Line 482 'select_passes'/2 (_4, _0) in let <_9> = case %% Line 487 call 'lists':'last' (Passes) of %% Line 488 <{'save_binary',_X_TestFun,_X_Fun}> when 'true' -> %% Line 489 case Passes of %% Line 490 <[{'read_beam_file',_12}|_13]> when 'true' -> %% Line 493 Passes %% Line 494 <_14> when 'true' -> %% Line 495 [{'remove_file',( 'remove_file'/2 -| [{'id',{0,0,'-passes/2-fun-0-'}}] )}|Passes] end %% Line 497 <_15> when 'true' -> %% Line 498 Passes end in %% Line 487 {Ext,_9} ( <_2> when 'true' -> primop 'match_fail' ({'badmatch',_2}) -| ['compiler_generated'] ) end 'passes_1'/1 = %% Line 501 fun (_0) -> case _0 of <[Opt|Opts]> when 'true' -> %% Line 502 case apply 'pass'/1 (Opt) of %% Line 503 when 'true' -> Res %% Line 504 <'none'> when 'true' -> apply 'passes_1'/1 (Opts) ( <_1> when 'true' -> primop 'match_fail' ({'case_clause',_1}) -| ['compiler_generated'] ) end %% Line 506 <[]> when 'true' -> let <_2> = apply %% Line 507 'standard_passes'/0 () in %% Line 507 {[46|[101|[114|[108]]]],[{'parse_module',( 'parse_module'/2 -| [{'id',{0,0,'-passes_1/1-fun-0-'}}] )}|_2]} ( <_3> when 'true' -> ( primop 'match_fail' ({'function_clause',_3}) -| [{'function_name',{'passes_1',1}}] ) -| ['compiler_generated'] ) end 'pass'/1 = %% Line 509 fun (_0) -> case _0 of <'from_core'> when 'true' -> let <_1> = apply %% Line 510 'core_passes'/0 () in %% Line 510 {[46|[99|[111|[114|[101]]]]],[{'parse_core',( 'parse_core'/2 -| [{'id',{0,0,'-pass/1-fun-0-'}}] )}|_1]} %% Line 511 <'from_asm'> when 'true' -> let <_2> = apply %% Line 512 'asm_passes'/0 () in %% Line 512 {[46|[83]],[{'beam_consult_asm',( 'beam_consult_asm'/2 -| [{'id',{0,0,'-pass/1-fun-1-'}}] )}|_2]} %% Line 513 <'from_beam'> when 'true' -> let <_3> = apply %% Line 514 'binary_passes'/0 () in %% Line 514 {[46|[98|[101|[97|[109]]]]],[{'read_beam_file',( 'read_beam_file'/2 -| [{'id',{0,0,'-pass/1-fun-2-'}}] )}|_3]} %% Line 515 <_5> when 'true' -> 'none' end 'fix_first_pass'/1 = %% Line 521 fun (_0) -> case _0 of <[{'parse_core',_2}|Passes]> when 'true' -> %% Line 522 [{'get_module_name_from_core',( 'get_module_name_from_core'/2 -| [{'id',{0,0,'-fix_first_pass/1-fun-0-'}}] )}|Passes] %% Line 523 <[{'beam_consult_asm',_3}|Passes]> when 'true' -> %% Line 524 [{'get_module_name_from_asm',( 'get_module_name_from_asm'/2 -| [{'id',{0,0,'-fix_first_pass/1-fun-1-'}}] )}|Passes] %% Line 525 <[{'read_beam_file',_4}|Passes]> when 'true' -> %% Line 526 [{'get_module_name_from_beam',( 'get_module_name_from_beam'/2 -| [{'id',{0,0,'-fix_first_pass/1-fun-2-'}}] )}|Passes] %% Line 527 <[_5|Passes]> when 'true' -> %% Line 530 Passes ( <_1> when 'true' -> ( primop 'match_fail' ({'function_clause',_1}) -| [{'function_name',{'fix_first_pass',1}}] ) -| ['compiler_generated'] ) end 'select_passes'/2 = %% Line 583 fun (_1,_0) -> case <_1,_0> of <[{'pass',Mod}|Ps],Opts> when 'true' -> let = fun (_19,_18) -> let <_4> = catch %% Line 585 ( case _18 of ( <( {'compile',_45,_46,_47,_48,_49,_50,_51,_52,_rec15,_53,_54,_55,_56,_57} -| ['compiler_generated'] )> when 'true' -> call Mod:'module' (_19, _rec15) -| ['compiler_generated'] ) ( <_58> when 'true' -> ( call ( 'erlang' -| ['compiler_generated'] ):( 'error' -| ['compiler_generated'] ) (( {'badrecord','compile'} -| ['compiler_generated'] )) -| ['compiler_generated'] ) -| ['compiler_generated'] ) end -| ['compiler_generated'] ) in %% Line 585 case _4 of %% Line 586 <{'ok',Code}> when 'true' -> %% Line 587 {'ok',Code,_18} %% Line 588 <{'ok',Code,Ws}> when 'true' -> %% Line 589 ( case _18 of ( <( {'compile',_59,_60,_61,_62,_63,_64,_65,_66,_67,_68,_69,_70,_rec18,_71} -| ['compiler_generated'] )> when 'true' -> let <_rec16> = call 'erlang':'++' (_rec18, Ws) in let <_10> = call 'erlang':'setelement' (14, _18, _rec16) in {'ok',Code,_10} -| ['compiler_generated'] ) ( <_72> when 'true' -> ( call ( 'erlang' -| ['compiler_generated'] ):( 'error' -| ['compiler_generated'] ) (( {'badrecord','compile'} -| ['compiler_generated'] )) -| ['compiler_generated'] ) -| ['compiler_generated'] ) end -| ['compiler_generated'] ) %% Line 590 <{'error',Es}> when 'true' -> %% Line 591 ( case _18 of ( <( {'compile',_88,_89,_90,_91,_92,_93,_94,_95,_96,_97,_98,_rec21,_99,_100} -| ['compiler_generated'] )> when 'true' -> let <_rec19> = call 'erlang':'++' (_rec21, Es) in let <_16> = call 'erlang':'setelement' (13, _18, _rec19) in {'error',_16} -| ['compiler_generated'] ) ( <_101> when 'true' -> ( call ( 'erlang' -| ['compiler_generated'] ):( 'error' -| ['compiler_generated'] ) (( {'badrecord','compile'} -| ['compiler_generated'] )) -| ['compiler_generated'] ) -| ['compiler_generated'] ) end -| ['compiler_generated'] ) ( <_17> when 'true' -> primop 'match_fail' ({'case_clause',_17}) -| ['compiler_generated'] ) end in let <_23> = apply %% Line 594 'select_passes'/2 (%% Line 594 Ps, %% Line 594 Opts) in %% Line 594 [{Mod,F}|_23] %% Line 595 <[{'src_listing',Ext}|_117],_X_Opts> when 'true' -> let <_28> = fun (_25,_24) -> %% Line 596 apply 'src_listing'/3 (Ext, _25, _24) in %% Line 596 [{'listing',_28}|[]] %% Line 597 <[{'listing',Ext}|_118],_X_Opts> when 'true' -> let <_33> = fun (_30,_29) -> %% Line 598 apply 'listing'/3 (Ext, _30, _29) in %% Line 598 [{'listing',_33}|[]] %% Line 599 <['done'|_119],_X_Opts> when 'true' -> %% Line 600 [] %% Line 601 <[{'done',Ext}|_120],Opts> when 'true' -> %% Line 602 apply 'select_passes'/2 ([{'unless','binary',{'listing',Ext}}|[]], Opts) %% Line 603 <[{'iff',Flag,Pass}|Ps],Opts> when 'true' -> %% Line 604 apply 'select_cond'/5 (Flag, 'true', Pass, Ps, Opts) %% Line 605 <[{'unless',Flag,Pass}|Ps],Opts> when 'true' -> %% Line 606 apply 'select_cond'/5 (Flag, 'false', Pass, Ps, Opts) %% Line 607 <[P = {_121,Fun}|Ps],Opts> when call 'erlang':'is_function' (Fun) -> let <_34> = apply %% Line 608 'select_passes'/2 (%% Line 608 Ps, %% Line 608 Opts) in %% Line 608 [P|_34] %% Line 609 <[{'delay',Passes0}|Ps],Opts> when call 'erlang':'is_list' (Passes0) -> %% Line 614 case apply 'select_list_passes'/2 (Passes0, Opts) of %% Line 615 <{'done',Passes}> when 'true' -> %% Line 616 [{'delay',Passes}|[]] %% Line 617 <{'not_done',Passes}> when 'true' -> let <_35> = apply %% Line 618 'select_passes'/2 (%% Line 618 Ps, %% Line 618 Opts) in %% Line 618 [{'delay',Passes}|_35] ( <_36> when 'true' -> primop 'match_fail' ({'case_clause',_36}) -| ['compiler_generated'] ) end %% Line 620 <[P = {_122,Test,Fun}|Ps],Opts> when try let <_37> = call 'erlang':'is_function' (Test) in let <_38> = call %% Line 621 'erlang':%% Line 621 'is_function' (%% Line 621 Fun) in call 'erlang':'and' (_37, _38) of -> Try catch -> 'false' -> let <_39> = apply %% Line 622 'select_passes'/2 (%% Line 622 Ps, %% Line 622 Opts) in %% Line 622 [P|_39] %% Line 623 <[],_X_Opts> when 'true' -> %% Line 624 [] %% Line 625 <[List|Ps],Opts> when call 'erlang':'is_list' (List) -> %% Line 626 case apply 'select_passes'/2 (List, Opts) of %% Line 627 <[]> when 'true' -> apply 'select_passes'/2 (Ps, Opts) %% Line 628 when 'true' -> %% Line 629 case call 'lists':'last' (Nested) of %% Line 630 <{'listing',_X_Fun}> when 'true' -> Nested %% Line 631 <_X_Other> when 'true' -> let <_40> = apply 'select_passes'/2 (Ps, Opts) in call 'erlang':'++' (Nested, _40) end end ( <_44,_43> when 'true' -> ( primop 'match_fail' ({'function_clause',_44,_43}) -| [{'function_name',{'select_passes',2}}] ) -| ['compiler_generated'] ) end 'select_cond'/5 = %% Line 635 fun (_4,_3,_2,_1,_0) -> let = call %% Line 636 'erlang':%% Line 636 'not' (_3) in %% Line 637 case call 'lists':'member' (_4, _0) of %% Line 638 <_12> when call 'erlang':'=:=' (_12, _3) -> apply 'select_passes'/2 ([_2|_1], _0) %% Line 639 <_13> when call 'erlang':'=:=' (_13, ShouldNotBe) -> apply 'select_passes'/2 (_1, _0) ( <_6> when 'true' -> primop 'match_fail' ({'case_clause',_6}) -| ['compiler_generated'] ) end 'select_list_passes'/2 = %% Line 646 fun (_1,_0) -> %% Line 647 apply 'select_list_passes_1'/3 (_1, _0, []) 'select_list_passes_1'/3 = %% Line 649 fun (_2,_1,_0) -> case <_2,_1,_0> of <[{'iff',Flag,Listing = {'listing',_18}}|Ps],Opts,Acc> when 'true' -> %% Line 650 case call 'lists':'member' (Flag, Opts) of %% Line 651 <'true'> when 'true' -> let <_3> = call 'lists':'reverse' (Acc, [Listing|[]]) in {'done',_3} %% Line 652 <'false'> when 'true' -> apply 'select_list_passes_1'/3 (Ps, Opts, Acc) ( <_4> when 'true' -> primop 'match_fail' ({'case_clause',_4}) -| ['compiler_generated'] ) end %% Line 654 <[{'iff',Flag,{'done',Ext}}|Ps],Opts,Acc> when 'true' -> %% Line 655 case call 'lists':'member' (Flag, Opts) of %% Line 656 <'false'> when 'true' -> %% Line 657 apply 'select_list_passes_1'/3 (Ps, Opts, Acc) %% Line 658 <'true'> when 'true' -> let <_6> = case %% Line 659 call 'lists':'member' ('binary', Opts) of %% Line 660 <'false'> when 'true' -> call 'lists':'reverse' (Acc, [{'listing',Ext}|[]]) %% Line 661 <'true'> when 'true' -> call 'lists':'reverse' (Acc) ( <_5> when 'true' -> %% Line 659 primop 'match_fail' ({'case_clause',_5}) -| ['compiler_generated'] ) end in %% Line 659 {'done',_6} ( <_7> when 'true' -> primop 'match_fail' ({'case_clause',_7}) -| ['compiler_generated'] ) end %% Line 664 <[{Op = 'iff',Flag,List0}|Ps],Opts,Acc> when call 'erlang':'is_list' (List0) -> %% Line 665 case apply 'select_list_passes'/2 (List0, Opts) of %% Line 666 <{'done',List}> when 'true' -> let <_8> = call 'lists':'reverse' (Acc) in let <_9> = call 'erlang':'++' (_8, List) in {'done',_9} %% Line 667 <{'not_done',List}> when 'true' -> apply 'select_list_passes_1'/3 (Ps, Opts, [{Op,Flag,List}|Acc]) ( <_10> when 'true' -> primop 'match_fail' ({'case_clause',_10}) -| ['compiler_generated'] ) end %% Line 669 <[{Op = 'unless',Flag,List0}|Ps],Opts,Acc> when call 'erlang':'is_list' (List0) -> %% Line 670 case apply 'select_list_passes'/2 (List0, Opts) of %% Line 671 <{'done',List}> when 'true' -> let <_11> = call 'lists':'reverse' (Acc) in let <_12> = call 'erlang':'++' (_11, List) in {'done',_12} %% Line 672 <{'not_done',List}> when 'true' -> apply 'select_list_passes_1'/3 (Ps, Opts, [{Op,Flag,List}|Acc]) ( <_13> when 'true' -> primop 'match_fail' ({'case_clause',_13}) -| ['compiler_generated'] ) end %% Line 674 <[P|Ps],Opts,Acc> when 'true' -> %% Line 675 apply 'select_list_passes_1'/3 (Ps, Opts, [P|Acc]) %% Line 676 <[],_19,Acc> when 'true' -> let <_14> = call %% Line 677 'lists':%% Line 677 'reverse' (%% Line 677 Acc) in %% Line 677 {'not_done',_14} ( <_17,_16,_15> when 'true' -> ( primop 'match_fail' ({'function_clause',_17,_16,_15}) -| [{'function_name',{'select_list_passes_1',3}}] ) -| ['compiler_generated'] ) end 'standard_passes'/0 = %% Line 681 fun () -> let <_0> = apply %% Line 708 'core_passes'/0 () in %% Line 682 [{'transform_module',( 'transform_module'/2 -| [{'id',{0,0,'-standard_passes/0-fun-0-'}}] )}|%% Line 684 [{'iff','makedep_side_effect',{'makedep_and_output',( 'makedep_and_output'/2 -| [{'id',{0,0,'-standard_passes/0-fun-1-'}}] )}}|%% Line 685 [{'iff','makedep',[%% Line 686 {'makedep',( 'makedep'/2 -| [{'id',{0,0,'-standard_passes/0-fun-2-'}}] )}|%% Line 687 [{'unless','binary',{'makedep_output',( 'makedep_output'/2 -| [{'id',{0,0,'-standard_passes/0-fun-3-'}}] )}}|%% Line 688 []]]}|%% Line 689 [{'iff','makedep','done'}|%% Line 691 [{'iff','dpp',{'listing',[112|[112]]}}|%% Line 692 [{'lint_module',( 'lint_module'/2 -| [{'id',{0,0,'-standard_passes/0-fun-4-'}}] )}|%% Line 693 [{'iff','P',{'src_listing',[80]}}|%% Line 694 [{'iff','to_pp',{'done',[80]}}|%% Line 696 [{'iff','dabstr',{'listing',[97|[98|[115|[116|[114]]]]]}}|%% Line 697 [{'iff','debug_info',{'save_abstract_code',( 'save_abstract_code'/2 -| [{'id',{0,0,'-standard_passes/0-fun-5-'}}] )}}|%% Line 699 [{'expand_records',( 'expand_records'/2 -| [{'id',{0,0,'-standard_passes/0-fun-6-'}}] )}|%% Line 700 [{'iff','dexp',{'listing',[101|[120|[112|[97|[110|[100]]]]]]}}|%% Line 701 [{'iff','E',{'src_listing',[69]}}|%% Line 702 [{'iff','to_exp',{'done',[69]}}|%% Line 705 [{'core',( 'core'/2 -| [{'id',{0,0,'-standard_passes/0-fun-7-'}}] )}|%% Line 706 [{'iff','dcore',{'listing',[99|[111|[114|[101]]]]}}|%% Line 707 [{'iff','to_core0',{'done',[99|[111|[114|[101]]]]}}|_0]]]]]]]]]]]]]]]]] 'core_passes'/0 = %% Line 710 fun () -> let <_0> = apply %% Line 728 'kernel_passes'/0 () in %% Line 712 [{'iff','clint0',{'core_lint_module',( 'core_lint_module'/2 -| [{'id',{0,0,'-core_passes/0-fun-0-'}}] )}}|%% Line 713 [{'delay',%% Line 714 [{'unless','no_copt',%% Line 715 [{'core_old_inliner',( 'test_old_inliner'/1 -| [{'id',{0,0,'-core_passes/0-fun-2-'}}] ),( 'core_old_inliner'/2 -| [{'id',{0,0,'-core_passes/0-fun-1-'}}] )}|%% Line 716 [{'iff','doldinline',{'listing',[111|[108|[100|[105|[110|[108|[105|[110|[101]]]]]]]]]}}|%% Line 717 [{'unless','no_fold',{'pass','sys_core_fold'}}|%% Line 718 [{'iff','dcorefold',{'listing',[99|[111|[114|[101|[102|[111|[108|[100]]]]]]]]}}|%% Line 719 [{'core_inline_module',( 'test_core_inliner'/1 -| [{'id',{0,0,'-core_passes/0-fun-4-'}}] ),( 'core_inline_module'/2 -| [{'id',{0,0,'-core_passes/0-fun-3-'}}] )}|%% Line 720 [{'iff','dinline',{'listing',[105|[110|[108|[105|[110|[101]]]]]]}}|%% Line 721 [{'core_fold_after_inlining',( 'test_any_inliner'/1 -| [{'id',{0,0,'-core_passes/0-fun-6-'}}] ),%% Line 722 ( 'core_fold_module_after_inlining'/2 -| [{'id',{0,0,'-core_passes/0-fun-5-'}}] )}|%% Line 723 [{'iff','dcopt',{'listing',[99|[111|[112|[116]]]]}}|%% Line 724 [{'unless','no_alias',{'pass','sys_core_alias'}}|%% Line 725 [{'iff','dalias',{'listing',[99|[111|[114|[101|[95|[97|[108|[105|[97|[115]]]]]]]]]]}}|%% Line 726 [{'core_transforms',( 'core_transforms'/2 -| [{'id',{0,0,'-core_passes/0-fun-7-'}}] )}|[]]]]]]]]]]]]}|%% Line 727 [{'iff','to_core',{'done',[99|[111|[114|[101]]]]}}]]}|_0]] 'kernel_passes'/0 = %% Line 730 fun () -> let <_0> = apply %% Line 746 'asm_passes'/0 () in %% Line 732 [{'pass','sys_core_bsm'}|%% Line 733 [{'iff','dcbsm',{'listing',[99|[111|[114|[101|[95|[98|[115|[109]]]]]]]]}}|%% Line 734 [{'pass','sys_core_dsetel'}|%% Line 735 [{'iff','dsetel',{'listing',[100|[115|[101|[116|[101|[108]]]]]]}}|%% Line 737 [{'iff','clint',{'core_lint_module',( 'core_lint_module'/2 -| [{'id',{0,0,'-kernel_passes/0-fun-0-'}}] )}}|%% Line 738 [{'iff','core',{'save_core_code',( 'save_core_code'/2 -| [{'id',{0,0,'-kernel_passes/0-fun-1-'}}] )}}|%% Line 741 [{'v3_kernel',( 'v3_kernel'/2 -| [{'id',{0,0,'-kernel_passes/0-fun-2-'}}] )}|%% Line 742 [{'iff','dkern',{'listing',[107|[101|[114|[110|[101|[108]]]]]]}}|%% Line 743 [{'iff','to_kernel',{'done',[107|[101|[114|[110|[101|[108]]]]]]}}|%% Line 744 [{'pass','v3_codegen'}|%% Line 745 [{'iff','dcg',{'listing',[99|[111|[100|[101|[103|[101|[110]]]]]]]}}|_0]]]]]]]]]]] 'asm_passes'/0 = %% Line 748 fun () -> let <_0> = apply %% Line 797 'binary_passes'/0 () in %% Line 750 [{'delay',%% Line 751 [{'pass','beam_a'}|%% Line 752 [{'iff','da',{'listing',[97]}}|%% Line 753 [{'unless','no_postopt',%% Line 754 [{'unless','no_reorder',{'pass','beam_reorder'}}|%% Line 755 [{'iff','dre',{'listing',[114|[101|[111|[114|[100|[101|[114]]]]]]]}}|%% Line 756 [{'pass','beam_block'}|%% Line 757 [{'iff','dblk',{'listing',[98|[108|[111|[99|[107]]]]]}}|%% Line 758 [{'unless','no_except',{'pass','beam_except'}}|%% Line 759 [{'iff','dexcept',{'listing',[101|[120|[99|[101|[112|[116]]]]]]}}|%% Line 760 [{'unless','no_bs_opt',{'pass','beam_bs'}}|%% Line 761 [{'iff','dbs',{'listing',[98|[115]]}}|%% Line 762 [{'unless','no_topt',{'pass','beam_type'}}|%% Line 763 [{'iff','dtype',{'listing',[116|[121|[112|[101]]]]}}|%% Line 764 [{'pass','beam_split'}|%% Line 765 [{'iff','dsplit',{'listing',[115|[112|[108|[105|[116]]]]]}}|%% Line 766 [{'unless','no_dead',{'pass','beam_dead'}}|%% Line 767 [{'iff','ddead',{'listing',[100|[101|[97|[100]]]]}}|%% Line 768 [{'unless','no_jopt',{'pass','beam_jump'}}|%% Line 769 [{'iff','djmp',{'listing',[106|[117|[109|[112]]]]}}|%% Line 770 [{'unless','no_peep_opt',{'pass','beam_peep'}}|%% Line 771 [{'iff','dpeep',{'listing',[112|[101|[101|[112]]]]}}|%% Line 772 [{'pass','beam_clean'}|%% Line 773 [{'iff','dclean',{'listing',[99|[108|[101|[97|[110]]]]]}}|%% Line 774 [{'unless','no_bsm_opt',{'pass','beam_bsm'}}|%% Line 775 [{'iff','dbsm',{'listing',[98|[115|[109]]]}}|%% Line 776 [{'unless','no_recv_opt',{'pass','beam_receive'}}|%% Line 777 [{'iff','drecv',{'listing',[114|[101|[99|[118]]]]}}|%% Line 778 [{'unless','no_record_opt',{'pass','beam_record'}}|%% Line 779 [{'iff','drecord',{'listing',[114|[101|[99|[111|[114|[100]]]]]]}}|%% Line 780 [{'unless','no_blk2',{'block2',( 'block2'/2 -| [{'id',{0,0,'-asm_passes/0-fun-0-'}}] )}}|%% Line 781 [{'iff','dblk2',{'listing',[98|[108|[111|[99|[107|[50]]]]]]}}|[{'unless','no_stack_trimming',{'pass','beam_trim'}}|[{'iff','dtrim',{'listing',[116|[114|[105|[109]]]]}}|[{'pass','beam_flatten'}]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]}|%% Line 788 [{'iff','no_postopt',[{'pass','beam_clean'}]}|[{'pass','beam_z'}|[{'iff','dz',{'listing',[122]}}|[{'iff','dopt',{'listing',[111|[112|[116|[105|[109|[105|[122|[101]]]]]]]]}}|[{'iff','S',{'listing',[83]}}|[{'iff','to_asm',{'done',[83]}}]]]]]]]]]}|%% Line 795 [{'pass','beam_validator'}|%% Line 796 [{'beam_asm',( 'beam_asm'/2 -| [{'id',{0,0,'-asm_passes/0-fun-1-'}}] )}|_0]]] 'binary_passes'/0 = %% Line 799 fun () -> %% Line 800 [{'iff','to_dis',{'to_dis',( 'to_dis'/2 -| [{'id',{0,0,'-binary_passes/0-fun-0-'}}] )}}|%% Line 801 [{'native_compile',( 'test_native'/1 -| [{'id',{0,0,'-binary_passes/0-fun-2-'}}] ),( 'native_compile'/2 -| [{'id',{0,0,'-binary_passes/0-fun-1-'}}] )}|%% Line 802 [{'unless','binary',{'save_binary',( 'not_werror'/1 -| [{'id',{0,0,'-binary_passes/0-fun-4-'}}] ),( 'save_binary'/2 -| [{'id',{0,0,'-binary_passes/0-fun-3-'}}] )}}|%% Line 803 []]]] 'remove_file'/2 = %% Line 810 fun (_1,_0) -> %% Line 811 ( case _0 of ( <( {'compile',_7,_8,_9,_10,_rec22,_11,_12,_13,_14,_15,_16,_17,_18,_19} -| ['result_not_wanted','compiler_generated'] )> when 'true' -> do ( call ( 'file' -| ['result_not_wanted'] ):( 'delete' -| ['result_not_wanted'] ) (_rec22) -| ['result_not_wanted'] ) %% Line 812 {'ok',_1,_0} -| ['compiler_generated'] ) ( <_20> when 'true' -> ( call ( 'erlang' -| ['result_not_wanted','compiler_generated'] ):( 'error' -| ['result_not_wanted','compiler_generated'] ) (( {'badrecord','compile'} -| ['result_not_wanted','compiler_generated'] )) -| ['result_not_wanted','compiler_generated'] ) -| ['compiler_generated'] ) end -| ['compiler_generated'] ) 'preprocess_asm_forms'/1 = %% Line 822 fun (_0) -> %% Line 825 ( case apply 'collect_asm'/2 (_0, {'asm_module','undefined','undefined','undefined',[],'undefined','undefined',[]}) of ( <( {'asm_module',_rec23,_16,_17,_18,_19,_20,_21} -| ['compiler_generated'] )> when 'true' -> {_rec23,%% Line 826 {_rec23,_16,_21,_18,_17}} -| ['compiler_generated'] ) ( <_22> when 'true' -> ( call ( 'erlang' -| ['compiler_generated'] ):( 'error' -| ['compiler_generated'] ) (( {'badrecord','asm_module'} -| ['compiler_generated'] )) -| ['compiler_generated'] ) -| ['compiler_generated'] ) end -| ['compiler_generated'] ) 'collect_asm'/2 = %% Line 832 fun (_1,_0) -> case <_1,_0> of <[],R> when 'true' -> %% Line 833 ( case R of ( <( {'asm_module',_49,_50,_51,_52,_rec29,_53,_54} -| ['compiler_generated'] )> when 'true' -> case _rec29 of %% Line 834 <'undefined'> when 'true' -> %% Line 835 R %% Line 836 <{A,B,C}> when 'true' -> let <_rec30> = call %% Line 837 'erlang':%% Line 837 '++' (_52, %% Line 838 [{'function',A,B,C,_53}|[]]) in %% Line 837 call 'erlang':'setelement' (5, R, _rec30) ( <_11> when 'true' -> primop 'match_fail' ({'case_clause',_11}) -| ['compiler_generated'] ) end -| ['compiler_generated'] ) ( <_55> when 'true' -> ( call ( 'erlang' -| ['compiler_generated'] ):( 'error' -| ['compiler_generated'] ) (( {'badrecord','asm_module'} -| ['compiler_generated'] )) -| ['compiler_generated'] ) -| ['compiler_generated'] ) end -| ['compiler_generated'] ) %% Line 840 <[{'module',M}|Rest],R> when 'true' -> %% Line 841 case R of <{'asm_module',_78,_79,_80,_81,_82,_83,_84}> when 'true' -> let <_14> = call 'erlang':'setelement' (2, R, M) in apply 'collect_asm'/2 (Rest, _14) ( <_85> when 'true' -> ( call ( 'erlang' -| ['compiler_generated'] ):( 'error' -| ['compiler_generated'] ) (( {'badrecord','asm_module'} -| ['compiler_generated'] )) -| ['compiler_generated'] ) -| ['compiler_generated'] ) end %% Line 842 <[{'exports',M}|Rest],R> when 'true' -> %% Line 843 case R of <{'asm_module',_86,_87,_88,_89,_90,_91,_92}> when 'true' -> let <_17> = call 'erlang':'setelement' (3, R, M) in apply 'collect_asm'/2 (Rest, _17) ( <_93> when 'true' -> ( call ( 'erlang' -| ['compiler_generated'] ):( 'error' -| ['compiler_generated'] ) (( {'badrecord','asm_module'} -| ['compiler_generated'] )) -| ['compiler_generated'] ) -| ['compiler_generated'] ) end %% Line 844 <[{'labels',M}|Rest],R> when 'true' -> %% Line 845 case R of <{'asm_module',_94,_95,_96,_97,_98,_99,_100}> when 'true' -> let <_20> = call 'erlang':'setelement' (4, R, M) in apply 'collect_asm'/2 (Rest, _20) ( <_101> when 'true' -> ( call ( 'erlang' -| ['compiler_generated'] ):( 'error' -| ['compiler_generated'] ) (( {'badrecord','asm_module'} -| ['compiler_generated'] )) -| ['compiler_generated'] ) -| ['compiler_generated'] ) end %% Line 846 <[{'function',A,B,C}|Rest],R> when 'true' -> %% Line 847 ( case R of ( <( {'asm_module',_102,_103,_104,_105,_rec37,_106,_107} -| ['compiler_generated'] )> when 'true' -> let <_31> = case _rec37 of %% Line 848 <'undefined'> when 'true' -> %% Line 849 R %% Line 850 <{A0,B0,C0}> when 'true' -> let <_rec38> = call %% Line 851 'erlang':%% Line 851 '++' (_105, %% Line 852 [{'function',A0,B0,C0,_106}|[]]) in %% Line 851 call 'erlang':'setelement' (5, R, _rec38) ( <_30> when 'true' -> primop 'match_fail' ({'case_clause',_30}) -| ['compiler_generated'] ) end in let <_rec42> = {%% Line 854 A,%% Line 854 B,%% Line 854 C} in %% Line 854 case _31 of <{'asm_module',_131,_132,_133,_134,_135,_136,_137}> when 'true' -> let <_35> = call 'erlang':'setelement' (7, _31, []) in let <_37> = call 'erlang':'setelement' (6, _35, _rec42) in apply 'collect_asm'/2 (Rest, _37) ( <_138> when 'true' -> ( call ( 'erlang' -| ['compiler_generated'] ):( 'error' -| ['compiler_generated'] ) (( {'badrecord','asm_module'} -| ['compiler_generated'] )) -| ['compiler_generated'] ) -| ['compiler_generated'] ) end -| ['compiler_generated'] ) ( <_108> when 'true' -> ( call ( 'erlang' -| ['compiler_generated'] ):( 'error' -| ['compiler_generated'] ) (( {'badrecord','asm_module'} -| ['compiler_generated'] )) -| ['compiler_generated'] ) -| ['compiler_generated'] ) end -| ['compiler_generated'] ) %% Line 855 <[{'attributes',Attr}|Rest],R> when 'true' -> %% Line 856 case R of <{'asm_module',_139,_140,_141,_142,_143,_144,_145}> when 'true' -> let <_40> = call 'erlang':'setelement' (8, R, Attr) in apply 'collect_asm'/2 (Rest, _40) ( <_146> when 'true' -> ( call ( 'erlang' -| ['compiler_generated'] ):( 'error' -| ['compiler_generated'] ) (( {'badrecord','asm_module'} -| ['compiler_generated'] )) -| ['compiler_generated'] ) -| ['compiler_generated'] ) end %% Line 857 <[X|Rest],R> when 'true' -> %% Line 858 ( case R of ( <( {'asm_module',_147,_148,_149,_150,_151,_rec47,_152} -| ['compiler_generated'] )> when 'true' -> let <_rec45> = call 'erlang':'++' (_rec47, [X|[]]) in let <_46> = call 'erlang':'setelement' (7, R, _rec45) in apply 'collect_asm'/2 (Rest, _46) -| ['compiler_generated'] ) ( <_153> when 'true' -> ( call ( 'erlang' -| ['compiler_generated'] ):( 'error' -| ['compiler_generated'] ) (( {'badrecord','asm_module'} -| ['compiler_generated'] )) -| ['compiler_generated'] ) -| ['compiler_generated'] ) end -| ['compiler_generated'] ) ( <_48,_47> when 'true' -> ( primop 'match_fail' ({'function_clause',_48,_47}) -| [{'function_name',{'collect_asm',2}}] ) -| ['compiler_generated'] ) end 'beam_consult_asm'/2 = %% Line 860 fun (_1,_0) -> %% Line 861 ( case _0 of ( <( {'compile',_24,_25,_26,_rec48,_27,_28,_29,_30,_31,_32,_33,_34,_35,_36} -| ['compiler_generated'] )> when 'true' -> case call 'file':'consult' (_rec48) of %% Line 862 <{'ok',Forms0}> when 'true' -> let = call %% Line 863 'epp':%% Line 863 'read_encoding' (_rec48) in %% Line 864 case apply 'preprocess_asm_forms'/1 (Forms0) of <{Module,Forms}> when 'true' -> let <_9> = call %% Line 865 'erlang':%% Line 865 'setelement' (%% Line 865 12, _0, %% Line 865 Encoding) in let <_11> = call %% Line 865 'erlang':%% Line 865 'setelement' (%% Line 865 7, _9, %% Line 865 Module) in %% Line 865 {'ok',Forms,_11} ( <_7> when 'true' -> primop 'match_fail' ({'badmatch',_7}) -| ['compiler_generated'] ) end %% Line 866 <{'error',E}> when 'true' -> let = [%% Line 867 {_rec48,[{'none','compile',{'open',E}}|[]]}|%% Line 867 []] in let <_rec52> = call %% Line 868 'erlang':%% Line 868 '++' (_34, %% Line 868 Es) in let <_20> = call %% Line 868 'erlang':%% Line 868 'setelement' (%% Line 868 13, _0, %% Line 868 _rec52) in %% Line 868 {'error',_20} ( <_21> when 'true' -> primop 'match_fail' ({'case_clause',_21}) -| ['compiler_generated'] ) end -| ['compiler_generated'] ) ( <_37> when 'true' -> ( call ( 'erlang' -| ['compiler_generated'] ):( 'error' -| ['compiler_generated'] ) (( {'badrecord','compile'} -| ['compiler_generated'] )) -| ['compiler_generated'] ) -| ['compiler_generated'] ) end -| ['compiler_generated'] ) 'get_module_name_from_asm'/2 = %% Line 871 fun (_1,_0) -> case <_1,_0> of when 'true' -> %% Line 872 case St of <{'compile',_11,_12,_13,_14,_15,_16,_17,_18,_19,_20,_21,_22,_23,_24}> when 'true' -> let <_4> = call 'erlang':'setelement' (7, St, Mod) in {'ok',Asm,_4} ( <_25> when 'true' -> ( call ( 'erlang' -| ['compiler_generated'] ):( 'error' -| ['compiler_generated'] ) (( {'badrecord','compile'} -| ['compiler_generated'] )) -| ['compiler_generated'] ) -| ['compiler_generated'] ) end %% Line 873 when 'true' -> %% Line 875 {'ok',Asm,St} end 'read_beam_file'/2 = %% Line 877 fun (_1,_0) -> %% Line 878 ( case _0 of ( <( {'compile',_30,_31,_32,_rec56,_33,_34,_35,_36,_37,_38,_39,_40,_41,_42} -| ['compiler_generated'] )> when 'true' -> case call 'file':'read_file' (_rec56) of %% Line 879 <{'ok',Beam}> when 'true' -> %% Line 881 case apply 'no_native_compilation'/2 (_rec56, _0) of %% Line 882 <'true'> when 'true' -> let <_9> = call %% Line 883 'erlang':%% Line 883 'setelement' (%% Line 883 7, _0, %% Line 883 'none') in %% Line 883 {'ok','none',_9} %% Line 884 <'false'> when 'true' -> let <_10> = call %% Line 885 'filename':%% Line 885 'basename' (_rec56) in let = call %% Line 885 'filename':%% Line 885 'rootname' (_10) in let = call %% Line 886 'erlang':%% Line 886 'list_to_atom' (%% Line 886 Mod0) in let <_14> = call %% Line 887 'erlang':%% Line 887 'setelement' (%% Line 887 7, _0, %% Line 887 Mod) in let <_16> = call %% Line 887 'erlang':%% Line 887 'setelement' (%% Line 887 6, _14, _rec56) in %% Line 887 {'ok',Beam,_16} ( <_17> when 'true' -> primop 'match_fail' ({'case_clause',_17}) -| ['compiler_generated'] ) end %% Line 889 <{'error',E}> when 'true' -> let = [%% Line 890 {_rec56,[{'none','compile',{'open',E}}|[]]}|%% Line 890 []] in let <_rec61> = call %% Line 891 'erlang':%% Line 891 '++' (_40, %% Line 891 Es) in let <_26> = call %% Line 891 'erlang':%% Line 891 'setelement' (%% Line 891 13, _0, %% Line 891 _rec61) in %% Line 891 {'error',_26} ( <_27> when 'true' -> primop 'match_fail' ({'case_clause',_27}) -| ['compiler_generated'] ) end -| ['compiler_generated'] ) ( <_43> when 'true' -> ( call ( 'erlang' -| ['compiler_generated'] ):( 'error' -| ['compiler_generated'] ) (( {'badrecord','compile'} -| ['compiler_generated'] )) -| ['compiler_generated'] ) -| ['compiler_generated'] ) end -| ['compiler_generated'] ) 'get_module_name_from_beam'/2 = %% Line 894 fun (_1,_0) -> %% Line 895 case call 'beam_lib':'info' (_1) of %% Line 896 <{'error','beam_lib',Error}> when 'true' -> let = [%% Line 897 {[40|[40|[102|[111|[114|[109|[115|[41|[41]]]]]]]]],[{'none','beam_lib',Error}|[]]}|%% Line 897 []] in %% Line 898 ( case _0 of ( <( {'compile',_16,_17,_18,_19,_20,_21,_22,_23,_24,_25,_26,_rec66,_27,_28} -| ['compiler_generated'] )> when 'true' -> let <_rec64> = call 'erlang':'++' (_rec66, Es) in let <_8> = call 'erlang':'setelement' (13, _0, _rec64) in {'error',_8} -| ['compiler_generated'] ) ( <_29> when 'true' -> ( call ( 'erlang' -| ['compiler_generated'] ):( 'error' -| ['compiler_generated'] ) (( {'badrecord','compile'} -| ['compiler_generated'] )) -| ['compiler_generated'] ) -| ['compiler_generated'] ) end -| ['compiler_generated'] ) %% Line 899 when 'true' -> %% Line 900 case call 'lists':'keyfind' ('module', 1, Info) of <{'module',Mod}> when 'true' -> %% Line 901 case _0 of <{'compile',_45,_46,_47,_48,_49,_50,_51,_52,_53,_54,_55,_56,_57,_58}> when 'true' -> let <_12> = call 'erlang':'setelement' (7, _0, Mod) in {'ok',_1,_12} ( <_59> when 'true' -> ( call ( 'erlang' -| ['compiler_generated'] ):( 'error' -| ['compiler_generated'] ) (( {'badrecord','compile'} -| ['compiler_generated'] )) -| ['compiler_generated'] ) -| ['compiler_generated'] ) end ( <_9> when 'true' -> primop 'match_fail' ({'badmatch',_9}) -| ['compiler_generated'] ) end end 'no_native_compilation'/2 = %% Line 904 fun (_1,_0) -> case <_1,_0> of when 'true' -> %% Line 905 case call 'beam_lib':'chunks' (BeamFile, [[67|[73|[110|[102]]]]]) of %% Line 906 <{'ok',{_24,[{[67|[73|[110|[102]]]],Term0}|[]]}}> when 'true' -> let = call %% Line 907 'erlang':%% Line 907 'binary_to_term' (%% Line 907 Term0) in let <_3> = call %% Line 911 'proplists':%% Line 911 'get_value' (%% Line 911 'options', %% Line 911 Term, %% Line 911 []) in let = call %% Line 911 'erlang':%% Line 911 '++' (_3, %% Line 911 Opts0) in %% Line 912 ( case call 'lists':'member' ('no_new_funs', Opts) of ( <( 'true' -| ['compiler_generated'] )> when 'true' -> 'true' -| ['compiler_generated'] ) ( <( 'false' -| ['compiler_generated'] )> when 'true' -> let <_6> = apply 'is_native_enabled'/1 (Opts) in call 'erlang':'not' (_6) -| ['compiler_generated'] ) ( <_5> when 'true' -> ( call ( 'erlang' -| ['compiler_generated'] ):( 'error' -| ['compiler_generated'] ) (( {( 'badarg' -| ['compiler_generated'] ),_5} -| ['compiler_generated'] )) -| ['compiler_generated'] ) -| ['compiler_generated'] ) end -| ['compiler_generated'] ) %% Line 913 <_25> when 'true' -> 'false' end ( <_10,_9> when 'true' -> ( primop 'match_fail' ({'function_clause',_10,_9}) -| [{'function_name',{'no_native_compilation',2}}] ) -| ['compiler_generated'] ) end 'parse_module'/2 = %% Line 916 fun (_1,_0) -> %% Line 917 case apply 'do_parse_module'/2 ('utf8', _0) of %% Line 918 when 'true' -> %% Line 919 Ret %% Line 920 when 'true' -> %% Line 921 Ret %% Line 922 <{'invalid_unicode',File,Line}> when 'true' -> %% Line 923 case apply 'do_parse_module'/2 ('latin1', _0) of %% Line 924 <{'ok',Code,St}> when 'true' -> let = [%% Line 925 {File,[{Line,'compile','reparsing_invalid_unicode'}|[]]}|%% Line 925 []] in %% Line 926 ( case St of ( <( {'compile',_23,_24,_25,_26,_27,_28,_29,_30,_31,_32,_33,_34,_rec70,_35} -| ['compiler_generated'] )> when 'true' -> let <_rec68> = call 'erlang':'++' (Es, _rec70) in let <_8> = call 'erlang':'setelement' (14, St, _rec68) in {'ok',Code,_8} -| ['compiler_generated'] ) ( <_36> when 'true' -> ( call ( 'erlang' -| ['compiler_generated'] ):( 'error' -| ['compiler_generated'] ) (( {'badrecord','compile'} -| ['compiler_generated'] )) -| ['compiler_generated'] ) -| ['compiler_generated'] ) end -| ['compiler_generated'] ) %% Line 927 <{'error',St}> when 'true' -> let = [%% Line 928 {File,[{Line,'compile','reparsing_invalid_unicode'}|[]]}|%% Line 928 []] in %% Line 929 ( case St of ( <( {'compile',_52,_53,_54,_55,_56,_57,_58,_59,_60,_61,_62,_rec73,_63,_64} -| ['compiler_generated'] )> when 'true' -> let <_rec71> = call 'erlang':'++' (Es, _rec73) in let <_15> = call 'erlang':'setelement' (13, St, _rec71) in {'error',_15} -| ['compiler_generated'] ) ( <_65> when 'true' -> ( call ( 'erlang' -| ['compiler_generated'] ):( 'error' -| ['compiler_generated'] ) (( {'badrecord','compile'} -| ['compiler_generated'] )) -| ['compiler_generated'] ) -| ['compiler_generated'] ) end -| ['compiler_generated'] ) ( <_16> when 'true' -> primop 'match_fail' ({'case_clause',_16}) -| ['compiler_generated'] ) end ( <_17> when 'true' -> primop 'match_fail' ({'case_clause',_17}) -| ['compiler_generated'] ) end 'do_parse_module'/2 = %% Line 933 fun (_1,_0) -> case <_1,_0> of when 'true' -> let <_2> = apply %% Line 935 'inc_paths'/1 (%% Line 935 Opts) in let <_3> = apply %% Line 936 'pre_defs'/1 (%% Line 936 Opts) in %% Line 939 case call 'epp':'parse_file' (File, [{'includes',[[46]|[Dir|_2]]}|[{'macros',_3}|[{'default_encoding',DefEncoding}|['extra']]]]) of %% Line 940 <{'ok',Forms,Extra}> when 'true' -> let = call %% Line 941 'proplists':%% Line 941 'get_value' (%% Line 941 'encoding', %% Line 941 Extra) in %% Line 942 case apply 'find_invalid_unicode'/2 (Forms, File) of %% Line 943 <'none'> when 'true' -> let <_8> = call %% Line 944 'erlang':%% Line 944 'setelement' (%% Line 944 12, %% Line 944 St, %% Line 944 Encoding) in %% Line 944 {'ok',Forms,_8} %% Line 945 when 'true' -> %% Line 946 case Encoding of %% Line 947 <'none'> when 'true' -> %% Line 948 Ret %% Line 949 <_54> when 'true' -> let <_11> = call %% Line 950 'erlang':%% Line 950 'setelement' (%% Line 950 12, %% Line 950 St, %% Line 950 Encoding) in %% Line 950 {'ok',Forms,_11} end ( <_13> when 'true' -> primop 'match_fail' ({'case_clause',_13}) -| ['compiler_generated'] ) end %% Line 953 <{'error',E}> when 'true' -> let = [%% Line 954 {File,[{'none','compile',{'epp',E}}|[]]}|%% Line 954 []] in let <_rec77> = call %% Line 955 'erlang':%% Line 955 '++' (_34, %% Line 955 Es) in let <_22> = call %% Line 955 'erlang':%% Line 955 'setelement' (%% Line 955 13, %% Line 955 St, %% Line 955 _rec77) in %% Line 955 {'error',_22} ( <_23> when 'true' -> primop 'match_fail' ({'case_clause',_23}) -| ['compiler_generated'] ) end ( <_25,_24> when 'true' -> ( primop 'match_fail' ({'function_clause',_25,_24}) -| [{'function_name',{'do_parse_module',2}}] ) -| ['compiler_generated'] ) end 'find_invalid_unicode'/2 = %% Line 958 fun (_1,_0) -> case <_1,_0> of <[H|T],File0> when 'true' -> %% Line 959 case H of %% Line 960 <{'attribute',_5,'file',{File,_6}}> when 'true' -> %% Line 961 apply 'find_invalid_unicode'/2 (T, File) %% Line 962 <{'error',{Line,'file_io_server','invalid_unicode'}}> when 'true' -> %% Line 963 {'invalid_unicode',File0,Line} %% Line 964 <_X_Other> when 'true' -> %% Line 965 apply 'find_invalid_unicode'/2 (T, File0) end %% Line 967 <[],_7> when 'true' -> 'none' ( <_4,_3> when 'true' -> ( primop 'match_fail' ({'function_clause',_4,_3}) -| [{'function_name',{'find_invalid_unicode',2}}] ) -| ['compiler_generated'] ) end 'parse_core'/2 = %% Line 969 fun (_1,_0) -> %% Line 970 ( case _0 of ( <( {'compile',_45,_46,_47,_rec80,_48,_49,_50,_51,_52,_53,_54,_55,_56,_57} -| ['compiler_generated'] )> when 'true' -> case call 'file':'read_file' (_rec80) of %% Line 971 <{'ok',Bin}> when 'true' -> let <_4> = call %% Line 972 'erlang':%% Line 972 'binary_to_list' (%% Line 972 Bin) in %% Line 972 case call 'core_scan':'string' (_4) of %% Line 973 <{'ok',Toks,_59}> when 'true' -> %% Line 974 case call 'core_parse':'parse' (Toks) of %% Line 975 <{'ok',Mod}> when 'true' -> %% Line 976 ( case Mod of ( <( {'c_module',_60,_rec82,_61,_62,_63} -| ['compiler_generated'] )> when 'true' -> ( case _rec82 of ( <( {'c_literal',_65,_rec81} -| ['compiler_generated'] )> when 'true' -> let <_12> = call %% Line 977 'erlang':%% Line 977 'setelement' (%% Line 977 7, _0, _rec81) in %% Line 977 {'ok',Mod,_12} -| ['compiler_generated'] ) ( <_66> when 'true' -> ( call ( 'erlang' -| ['compiler_generated'] ):( 'error' -| ['compiler_generated'] ) (( {'badrecord','c_literal'} -| ['compiler_generated'] )) -| ['compiler_generated'] ) -| ['compiler_generated'] ) end -| ['compiler_generated'] ) -| ['compiler_generated'] ) ( <_64> when 'true' -> ( call ( 'erlang' -| ['compiler_generated'] ):( 'error' -| ['compiler_generated'] ) (( {'badrecord','c_module'} -| ['compiler_generated'] )) -| ['compiler_generated'] ) -| ['compiler_generated'] ) end -| ['compiler_generated'] ) %% Line 978 <{'error',E}> when 'true' -> let = [%% Line 979 {_rec80,[E|[]]}|%% Line 979 []] in let <_rec85> = call %% Line 980 'erlang':%% Line 980 '++' (_55, %% Line 980 Es) in let <_21> = call %% Line 980 'erlang':%% Line 980 'setelement' (%% Line 980 13, _0, %% Line 980 _rec85) in %% Line 980 {'error',_21} ( <_22> when 'true' -> primop 'match_fail' ({'case_clause',_22}) -| ['compiler_generated'] ) end %% Line 982 <{'error',E,_125}> when 'true' -> let = [%% Line 983 {_rec80,[E|[]]}|%% Line 983 []] in let <_rec89> = call %% Line 984 'erlang':%% Line 984 '++' (_55, %% Line 984 Es) in let <_31> = call %% Line 984 'erlang':%% Line 984 'setelement' (%% Line 984 13, _0, %% Line 984 _rec89) in %% Line 984 {'error',_31} ( <_32> when 'true' -> primop 'match_fail' ({'case_clause',_32}) -| ['compiler_generated'] ) end %% Line 986 <{'error',E}> when 'true' -> let = [%% Line 987 {_rec80,[{'none','compile',{'open',E}}|[]]}|%% Line 987 []] in let <_rec93> = call %% Line 988 'erlang':%% Line 988 '++' (_55, %% Line 988 Es) in let <_41> = call %% Line 988 'erlang':%% Line 988 'setelement' (%% Line 988 13, _0, %% Line 988 _rec93) in %% Line 988 {'error',_41} ( <_42> when 'true' -> primop 'match_fail' ({'case_clause',_42}) -| ['compiler_generated'] ) end -| ['compiler_generated'] ) ( <_58> when 'true' -> ( call ( 'erlang' -| ['compiler_generated'] ):( 'error' -| ['compiler_generated'] ) (( {'badrecord','compile'} -| ['compiler_generated'] )) -| ['compiler_generated'] ) -| ['compiler_generated'] ) end -| ['compiler_generated'] ) 'get_module_name_from_core'/2 = %% Line 991 fun (_1,_0) -> %% Line 992 try let <_2> = call %% Line 993 'cerl':%% Line 993 'module_name' (_1) in let = call %% Line 993 'cerl':%% Line 993 'concrete' (_2) in %% Line 994 case _0 of <{'compile',_13,_14,_15,_16,_17,_18,_19,_20,_21,_22,_23,_24,_25,_26}> when 'true' -> let <_6> = call 'erlang':'setelement' (7, _0, Mod) in {'ok',_1,_6} ( <_27> when 'true' -> ( call ( 'erlang' -| ['compiler_generated'] ):( 'error' -| ['compiler_generated'] ) (( {'badrecord','compile'} -| ['compiler_generated'] )) -| ['compiler_generated'] ) -| ['compiler_generated'] ) end of <_7> -> _7 catch <_10,_9,_8> -> %% Line 998 {'ok',_1,_0} 'compile_options'/1 = %% Line 1001 fun (_0) -> case _0 of <[{'attribute',_X_L,'compile',C}|Fs]> when call 'erlang':'is_list' (C) -> let <_1> = apply %% Line 1002 'compile_options'/1 (%% Line 1002 Fs) in %% Line 1002 call 'erlang':'++' (C, _1) %% Line 1003 <[{'attribute',_X_L,'compile',C}|Fs]> when 'true' -> let <_2> = apply %% Line 1004 'compile_options'/1 (%% Line 1004 Fs) in %% Line 1004 [C|_2] %% Line 1005 <[_X_F|Fs]> when 'true' -> apply 'compile_options'/1 (Fs) %% Line 1006 <[]> when 'true' -> [] ( <_3> when 'true' -> ( primop 'match_fail' ({'function_clause',_3}) -| [{'function_name',{'compile_options',1}}] ) -| ['compiler_generated'] ) end 'clean_parse_transforms'/1 = %% Line 1008 fun (_0) -> %% Line 1009 apply 'clean_parse_transforms_1'/2 (_0, []) 'clean_parse_transforms_1'/2 = %% Line 1011 fun (_1,_0) -> case <_1,_0> of <[{'attribute',L,'compile',C0}|Fs],Acc> when call 'erlang':'is_list' (C0) -> let <_4> = fun (_2) -> %% Line 1012 case _2 of <{'parse_transform',_8}> when 'true' -> 'false' %% Line 1013 <_9> when 'true' -> 'true' end in let = call %% Line 1012 'lists':%% Line 1012 'filter' (_4, %% Line 1014 C0) in %% Line 1015 apply 'clean_parse_transforms_1'/2 (Fs, [{'attribute',L,'compile',C}|Acc]) %% Line 1016 <[{'attribute',_10,'compile',{'parse_transform',_11}}|Fs],Acc> when 'true' -> %% Line 1017 apply 'clean_parse_transforms_1'/2 (Fs, Acc) %% Line 1018 <[F|Fs],Acc> when 'true' -> %% Line 1019 apply 'clean_parse_transforms_1'/2 (Fs, [F|Acc]) %% Line 1020 <[],Acc> when 'true' -> call 'lists':'reverse' (Acc) ( <_7,_6> when 'true' -> ( primop 'match_fail' ({'function_clause',_7,_6}) -| [{'function_name',{'clean_parse_transforms_1',2}}] ) -| ['compiler_generated'] ) end 'transforms'/1 = %% Line 1022 fun (_0) -> ( letrec 'lc$^0'/1 = fun (_3) -> case _3 of <[{'parse_transform',M}|_2]> when 'true' -> let <_4> = apply 'lc$^0'/1 (_2) in ( [M|_4] -| ['compiler_generated'] ) ( <[_1|_2]> when 'true' -> apply 'lc$^0'/1 (_2) -| ['compiler_generated'] ) <[]> when 'true' -> [] ( <_6> when 'true' -> ( primop 'match_fail' ({'function_clause',_6}) -| [{'function_name',{'lc$^0',1}}] ) -| ['compiler_generated'] ) end in apply 'lc$^0'/1 (_0) -| ['list_comprehension'] ) 'transform_module'/2 = %% Line 1024 fun (_1,_0) -> case <_1,_0> of when 'true' -> let <_2> = apply %% Line 1026 'compile_options'/1 (%% Line 1026 Code0) in let <_3> = call %% Line 1026 'erlang':%% Line 1026 '++' (%% Line 1026 Opt, _2) in %% Line 1026 case apply 'transforms'/1 (_3) of %% Line 1027 <[]> when 'true' -> %% Line 1029 {'ok',Code0,St} %% Line 1030 when 'true' -> let = apply %% Line 1033 'clean_parse_transforms'/1 (%% Line 1033 Code0) in %% Line 1034 apply 'foldl_transform'/3 (Ts, Code, St) end ( <_7,_6> when 'true' -> ( primop 'match_fail' ({'function_clause',_7,_6}) -| [{'function_name',{'transform_module',2}}] ) -| ['compiler_generated'] ) end 'foldl_transform'/3 = %% Line 1037 fun (_2,_1,_0) -> case <_2,_1,_0> of <[T|Ts],Code0,St> when 'true' -> let <_3> = call %% Line 1038 'erlang':%% Line 1038 'atom_to_list' (%% Line 1038 T) in let = call %% Line 1038 'erlang':%% Line 1038 '++' (%% Line 1038 [116|[114|[97|[110|[115|[102|[111|[114|[109|[32]]]]]]]]]], _3) in let <_6> = call %% Line 1039 'code':%% Line 1039 'ensure_loaded' (%% Line 1039 T) in let <_8> = case <> of %% Line 1039 ( <> when call 'erlang':'=:=' (_6, {'module',T}) -> %% Line 1040 call 'erlang':'function_exported' (T, 'parse_transform', 2) -| ['compiler_generated'] ) %% Line 1039 ( <> when 'true' -> 'false' -| ['compiler_generated'] ) end in %% Line 1039 case _8 of %% Line 1041 <'true'> when 'true' -> let = fun (_12,_11) -> %% Line 1043 ( case _11 of ( <( {'compile',_66,_67,_68,_69,_70,_71,_72,_73,_rec97,_74,_75,_76,_77,_78} -| ['compiler_generated'] )> when 'true' -> call T:'parse_transform' (_12, _rec97) -| ['compiler_generated'] ) ( <_79> when 'true' -> ( call ( 'erlang' -| ['compiler_generated'] ):( 'error' -| ['compiler_generated'] ) (( {'badrecord','compile'} -| ['compiler_generated'] )) -| ['compiler_generated'] ) -| ['compiler_generated'] ) end -| ['compiler_generated'] ) in %% Line 1045 ( case St of ( <( {'compile',_80,_81,_82,_83,_84,_85,_86,_87,_rec98,_88,_89,_90,_91,_92} -| ['compiler_generated'] )> when 'true' -> let <_25> = case call 'lists':'member' ('time', _rec98) of %% Line 1046 <'true'> when 'true' -> %% Line 1047 ( 'run_tc'/3 -| [{'id',{0,0,'-foldl_transform/3-fun-1-'}}] ) %% Line 1048 <'false'> when 'true' -> %% Line 1049 ( fun (_20,_19,_18) -> case <_20,_19,_18> of <{_X_Name,F},Code,S> when 'true' -> catch %% Line 1050 apply F (Code, S) ( <_23,_22,_21> when 'true' -> ( primop 'match_fail' ({'function_clause',_23,_22,_21}) -| [{'function_name',{'-foldl_transform/3-fun-2-',3}}] ) -| ['compiler_generated'] ) end -| [{'id',{0,0,'-foldl_transform/3-fun-2-'}}] ) ( <_24> when 'true' -> primop 'match_fail' ({'case_clause',_24}) -| ['compiler_generated'] ) end in %% Line 1053 case apply _25 ({Name,Fun}, Code0, St) of %% Line 1054 <{'error',Es,Ws}> when 'true' -> let <_rec99> = call %% Line 1055 'erlang':%% Line 1055 '++' (_91, %% Line 1055 Ws) in let <_rec100> = call %% Line 1056 'erlang':%% Line 1056 '++' (_90, %% Line 1056 Es) in let <_34> = call %% Line 1055 'erlang':%% Line 1055 'setelement' (%% Line 1055 14, %% Line 1055 St, %% Line 1055 _rec99) in let <_36> = call %% Line 1056 'erlang':%% Line 1056 'setelement' (%% Line 1056 13, _34, %% Line 1056 _rec100) in %% Line 1055 {'error',_36} %% Line 1057 <{'EXIT',R}> when 'true' -> let = [%% Line 1058 {_83,[{'none','compile',%% Line 1059 {'parse_transform',T,R}}|%% Line 1059 []]}|%% Line 1059 []] in let <_rec105> = call %% Line 1060 'erlang':%% Line 1060 '++' (_90, %% Line 1060 Es) in let <_45> = call %% Line 1060 'erlang':%% Line 1060 'setelement' (%% Line 1060 13, %% Line 1060 St, %% Line 1060 _rec105) in %% Line 1060 {'error',_45} %% Line 1061 <{'warning',Forms,Ws}> when 'true' -> let <_rec108> = call %% Line 1063 'erlang':%% Line 1063 '++' (_91, %% Line 1063 Ws) in let <_51> = call %% Line 1063 'erlang':%% Line 1063 'setelement' (%% Line 1063 14, %% Line 1063 St, %% Line 1063 _rec108) in %% Line 1062 apply 'foldl_transform'/3 (Ts, Forms, _51) %% Line 1064 when 'true' -> %% Line 1065 apply 'foldl_transform'/3 (Ts, Forms, St) end -| ['compiler_generated'] ) ( <_93> when 'true' -> ( call ( 'erlang' -| ['compiler_generated'] ):( 'error' -| ['compiler_generated'] ) (( {'badrecord','compile'} -| ['compiler_generated'] )) -| ['compiler_generated'] ) -| ['compiler_generated'] ) end -| ['compiler_generated'] ) %% Line 1067 <'false'> when 'true' -> %% Line 1068 ( case St of ( <( {'compile',_209,_210,_211,_rec111,_212,_213,_214,_215,_216,_217,_218,_219,_220,_221} -| ['compiler_generated'] )> when 'true' -> let = [{_rec111,[{'none','compile',%% Line 1069 {'undef_parse_transform',T}}|%% Line 1069 []]}|%% Line 1069 []] in let <_rec112> = call %% Line 1070 'erlang':%% Line 1070 '++' (_219, %% Line 1070 Es) in let <_61> = call %% Line 1070 'erlang':%% Line 1070 'setelement' (%% Line 1070 13, %% Line 1070 St, %% Line 1070 _rec112) in %% Line 1070 {'error',_61} -| ['compiler_generated'] ) ( <_222> when 'true' -> ( call ( 'erlang' -| ['compiler_generated'] ):( 'error' -| ['compiler_generated'] ) (( {'badrecord','compile'} -| ['compiler_generated'] )) -| ['compiler_generated'] ) -| ['compiler_generated'] ) end -| ['compiler_generated'] ) ( <_62> when 'true' -> primop 'match_fail' ({'case_clause',_62}) -| ['compiler_generated'] ) end %% Line 1072 <[],Code,St> when 'true' -> {'ok',Code,St} ( <_65,_64,_63> when 'true' -> ( primop 'match_fail' ({'function_clause',_65,_64,_63}) -| [{'function_name',{'foldl_transform',3}}] ) -| ['compiler_generated'] ) end 'get_core_transforms'/1 = %% Line 1074 fun (_0) -> ( letrec 'lc$^0'/1 = fun (_3) -> case _3 of <[{'core_transform',M}|_2]> when 'true' -> let <_4> = apply 'lc$^0'/1 (_2) in ( [M|_4] -| ['compiler_generated'] ) ( <[_1|_2]> when 'true' -> apply 'lc$^0'/1 (_2) -| ['compiler_generated'] ) <[]> when 'true' -> [] ( <_6> when 'true' -> ( primop 'match_fail' ({'function_clause',_6}) -| [{'function_name',{'lc$^0',1}}] ) -| ['compiler_generated'] ) end in apply 'lc$^0'/1 (_0) -| ['list_comprehension'] ) 'core_transforms'/2 = %% Line 1076 fun (_1,_0) -> %% Line 1078 ( case _0 of ( <( {'compile',_7,_8,_9,_10,_11,_12,_13,_14,_rec115,_15,_16,_17,_18,_19} -| ['compiler_generated'] )> when 'true' -> let = apply 'get_core_transforms'/1 (_rec115) in %% Line 1079 apply 'foldl_core_transforms'/3 (Ts, _1, _0) -| ['compiler_generated'] ) ( <_20> when 'true' -> ( call ( 'erlang' -| ['compiler_generated'] ):( 'error' -| ['compiler_generated'] ) (( {'badrecord','compile'} -| ['compiler_generated'] )) -| ['compiler_generated'] ) -| ['compiler_generated'] ) end -| ['compiler_generated'] ) 'foldl_core_transforms'/3 = %% Line 1081 fun (_2,_1,_0) -> case <_2,_1,_0> of <[T|Ts],Code0,St> when 'true' -> let <_3> = call %% Line 1082 'erlang':%% Line 1082 'atom_to_list' (%% Line 1082 T) in let = call %% Line 1082 'erlang':%% Line 1082 '++' (%% Line 1082 [99|[111|[114|[101|[32|[116|[114|[97|[110|[115|[102|[111|[114|[109|[32]]]]]]]]]]]]]]], _3) in let = fun (_8,_7) -> %% Line 1083 ( case _7 of ( <( {'compile',_36,_37,_38,_39,_40,_41,_42,_43,_rec116,_44,_45,_46,_47,_48} -| ['compiler_generated'] )> when 'true' -> call T:'core_transform' (_8, _rec116) -| ['compiler_generated'] ) ( <_49> when 'true' -> ( call ( 'erlang' -| ['compiler_generated'] ):( 'error' -| ['compiler_generated'] ) (( {'badrecord','compile'} -| ['compiler_generated'] )) -| ['compiler_generated'] ) -| ['compiler_generated'] ) end -| ['compiler_generated'] ) in %% Line 1084 ( case St of ( <( {'compile',_50,_51,_52,_53,_54,_55,_56,_57,_rec117,_58,_59,_60,_61,_62} -| ['compiler_generated'] )> when 'true' -> let <_21> = case call 'lists':'member' ('time', _rec117) of %% Line 1085 <'true'> when 'true' -> %% Line 1086 ( 'run_tc'/3 -| [{'id',{0,0,'-foldl_core_transforms/3-fun-1-'}}] ) %% Line 1087 <'false'> when 'true' -> %% Line 1088 ( fun (_16,_15,_14) -> case <_16,_15,_14> of <{_X_Name,F},Code,S> when 'true' -> catch %% Line 1089 apply F (Code, S) ( <_19,_18,_17> when 'true' -> ( primop 'match_fail' ({'function_clause',_19,_18,_17}) -| [{'function_name',{'-foldl_core_transforms/3-fun-2-',3}}] ) -| ['compiler_generated'] ) end -| [{'id',{0,0,'-foldl_core_transforms/3-fun-2-'}}] ) ( <_20> when 'true' -> primop 'match_fail' ({'case_clause',_20}) -| ['compiler_generated'] ) end in %% Line 1092 case apply _21 ({Name,Fun}, Code0, St) of %% Line 1093 <{'EXIT',R}> when 'true' -> let = [%% Line 1094 {_53,[{'none','compile',{'core_transform',T,R}}|[]]}|%% Line 1094 []] in let <_rec119> = call %% Line 1095 'erlang':%% Line 1095 '++' (_60, %% Line 1095 Es) in let <_31> = call %% Line 1095 'erlang':%% Line 1095 'setelement' (%% Line 1095 13, %% Line 1095 St, %% Line 1095 _rec119) in %% Line 1095 {'error',_31} %% Line 1096 when 'true' -> %% Line 1097 apply 'foldl_core_transforms'/3 (Ts, Forms, St) end -| ['compiler_generated'] ) ( <_63> when 'true' -> ( call ( 'erlang' -| ['compiler_generated'] ):( 'error' -| ['compiler_generated'] ) (( {'badrecord','compile'} -| ['compiler_generated'] )) -| ['compiler_generated'] ) -| ['compiler_generated'] ) end -| ['compiler_generated'] ) %% Line 1099 <[],Code,St> when 'true' -> {'ok',Code,St} ( <_35,_34,_33> when 'true' -> ( primop 'match_fail' ({'function_clause',_35,_34,_33}) -| [{'function_name',{'foldl_core_transforms',3}}] ) -| ['compiler_generated'] ) end 'get_module'/1 = %% Line 1103 fun (_0) -> case _0 of <[{'attribute',_2,'module',M}|_3]> when 'true' -> M %% Line 1104 <[_4|Rest]> when 'true' -> %% Line 1105 apply 'get_module'/1 (Rest) ( <_1> when 'true' -> ( primop 'match_fail' ({'function_clause',_1}) -| [{'function_name',{'get_module',1}}] ) -| ['compiler_generated'] ) end 'add_default_base'/2 = %% Line 1110 fun (_1,_0) -> %% Line 1111 ( case _1 of ( <( {'compile',_rec122,_12,_13,_14,_15,_16,_17,_18,_19,_20,_21,_22,_23,_24} -| ['compiler_generated'] )> when 'true' -> %% Line 1112 case _rec122 of %% Line 1113 <[]> when 'true' -> let = apply %% Line 1114 'get_module'/1 (_0) in let <_rec123> = call %% Line 1115 'erlang':%% Line 1115 'atom_to_list' (%% Line 1115 M) in %% Line 1115 call 'erlang':'setelement' (4, _1, _rec123) %% Line 1116 <_41> when 'true' -> _1 end -| ['compiler_generated'] ) ( <_25> when 'true' -> ( call ( 'erlang' -| ['compiler_generated'] ):( 'error' -| ['compiler_generated'] ) (( {'badrecord','compile'} -| ['compiler_generated'] )) -| ['compiler_generated'] ) -| ['compiler_generated'] ) end -| ['compiler_generated'] ) 'lint_module'/2 = %% Line 1120 fun (_1,_0) -> %% Line 1121 ( case _0 of ( <( {'compile',_26,_27,_28,_rec125,_29,_30,_31,_32,_33,_34,_35,_36,_37,_38} -| ['compiler_generated'] )> when 'true' -> case call 'erl_lint':'module' (_1, _rec125, _33) of %% Line 1122 <{'ok',Ws}> when 'true' -> let = apply %% Line 1125 'add_default_base'/2 (_0, _1) in %% Line 1126 ( case St1 of ( <( {'compile',_54,_55,_56,_57,_58,_59,_60,_61,_62,_63,_64,_65,_rec129,_66} -| ['compiler_generated'] )> when 'true' -> let <_rec127> = call 'erlang':'++' (_rec129, Ws) in let <_12> = call 'erlang':'setelement' (14, St1, _rec127) in {'ok',_1,_12} -| ['compiler_generated'] ) ( <_67> when 'true' -> ( call ( 'erlang' -| ['compiler_generated'] ):( 'error' -| ['compiler_generated'] ) (( {'badrecord','compile'} -| ['compiler_generated'] )) -| ['compiler_generated'] ) -| ['compiler_generated'] ) end -| ['compiler_generated'] ) %% Line 1127 <{'error',Es,Ws}> when 'true' -> let <_rec130> = call %% Line 1128 'erlang':%% Line 1128 '++' (_37, %% Line 1128 Ws) in let <_rec131> = call %% Line 1129 'erlang':%% Line 1129 '++' (_36, %% Line 1129 Es) in let <_20> = call %% Line 1128 'erlang':%% Line 1128 'setelement' (%% Line 1128 14, _0, %% Line 1128 _rec130) in let <_22> = call %% Line 1129 'erlang':%% Line 1129 'setelement' (%% Line 1129 13, _20, %% Line 1129 _rec131) in %% Line 1128 {'error',_22} ( <_23> when 'true' -> primop 'match_fail' ({'case_clause',_23}) -| ['compiler_generated'] ) end -| ['compiler_generated'] ) ( <_39> when 'true' -> ( call ( 'erlang' -| ['compiler_generated'] ):( 'error' -| ['compiler_generated'] ) (( {'badrecord','compile'} -| ['compiler_generated'] )) -| ['compiler_generated'] ) -| ['compiler_generated'] ) end -| ['compiler_generated'] ) 'core_lint_module'/2 = %% Line 1132 fun (_1,_0) -> %% Line 1133 ( case _0 of ( <( {'compile',_23,_24,_25,_26,_27,_28,_29,_30,_rec135,_31,_32,_33,_34,_35} -| ['compiler_generated'] )> when 'true' -> case call 'core_lint':'module' (_1, _rec135) of %% Line 1134 <{'ok',Ws}> when 'true' -> let <_rec136> = call %% Line 1135 'erlang':%% Line 1135 '++' (_34, %% Line 1135 Ws) in let <_9> = call %% Line 1135 'erlang':%% Line 1135 'setelement' (%% Line 1135 14, _0, %% Line 1135 _rec136) in %% Line 1135 {'ok',_1,_9} %% Line 1136 <{'error',Es,Ws}> when 'true' -> let <_rec139> = call %% Line 1137 'erlang':%% Line 1137 '++' (_34, %% Line 1137 Ws) in let <_rec140> = call %% Line 1138 'erlang':%% Line 1138 '++' (_33, %% Line 1138 Es) in let <_17> = call %% Line 1137 'erlang':%% Line 1137 'setelement' (%% Line 1137 14, _0, %% Line 1137 _rec139) in let <_19> = call %% Line 1138 'erlang':%% Line 1138 'setelement' (%% Line 1138 13, _17, %% Line 1138 _rec140) in %% Line 1137 {'error',_19} ( <_20> when 'true' -> primop 'match_fail' ({'case_clause',_20}) -| ['compiler_generated'] ) end -| ['compiler_generated'] ) ( <_36> when 'true' -> ( call ( 'erlang' -| ['compiler_generated'] ):( 'error' -| ['compiler_generated'] ) (( {'badrecord','compile'} -| ['compiler_generated'] )) -| ['compiler_generated'] ) -| ['compiler_generated'] ) end -| ['compiler_generated'] ) 'makedep_and_output'/2 = %% Line 1142 fun (_1,_0) -> %% Line 1143 case apply 'makedep'/2 (_1, _0) of <{'ok',DepCode,St1}> when 'true' -> %% Line 1144 case apply 'makedep_output'/2 (DepCode, St1) of %% Line 1145 <{'ok',_X_IgnoreCode,St2}> when 'true' -> %% Line 1146 {'ok',_1,St2} %% Line 1147 <_@r0 = {'error',St2}> when 'true' -> %% Line 1148 _@r0 ( <_3> when 'true' -> primop 'match_fail' ({'case_clause',_3}) -| ['compiler_generated'] ) end ( <_2> when 'true' -> primop 'match_fail' ({'badmatch',_2}) -| ['compiler_generated'] ) end 'makedep'/2 = %% Line 1151 fun (_1,_0) -> case <_1,_0> of when 'true' -> let <_3> = case %% Line 1155 call 'proplists':'get_value' ('makedep_target', Opts) of %% Line 1156 <'undefined'> when 'true' -> %% Line 1160 apply 'shorten_filename'/1 (Ofile) %% Line 1161 when 'true' -> %% Line 1163 T end in let <_9> = case %% Line 1167 call 'proplists':'get_value' ('makedep_quote_target', Opts) of %% Line 1168 <'true'> when 'true' -> let = fun (_5) -> %% Line 1170 case _5 of %% Line 1171 <36> when 'true' -> [36|[36]] %% Line 1172 when 'true' -> C end in %% Line 1174 call 'lists':'map' (Fun, _3) %% Line 1175 <_31> when 'true' -> _3 end in let = call %% Line 1178 'erlang':%% Line 1178 '++' (_9, %% Line 1178 [58]) in let <_12> = call %% Line 1185 'erlang':%% Line 1185 'length' (%% Line 1185 Target) in %% Line 1181 case apply 'makedep_add_headers'/7 (%% Line 1182 Ifile, %% Line 1183 Code0, %% Line 1184 [], _12, %% Line 1186 Target, %% Line 1187 [], %% Line 1188 Opts) of <{MainRule,PhonyRules}> when 'true' -> let <_15> = case %% Line 1199 call 'proplists':'get_value' ('makedep_phony', Opts) of %% Line 1200 <'true'> when 'true' -> call 'erlang':'++' (MainRule, PhonyRules) %% Line 1201 <_32> when 'true' -> MainRule end in let = call %% Line 1203 'erlang':%% Line 1203 'iolist_to_binary' (%% Line 1203 [_15|[[10]]]) in %% Line 1204 {'ok',Code,St} ( <_13> when 'true' -> primop 'match_fail' ({'badmatch',_13}) -| ['compiler_generated'] ) end ( <_19,_18> when 'true' -> ( primop 'match_fail' ({'function_clause',_19,_18}) -| [{'function_name',{'makedep',2}}] ) -| ['compiler_generated'] ) end 'makedep_add_headers'/7 = %% Line 1206 fun (_6,_5,_4,_3,_2,_1,_0) -> case <_6,_5,_4,_3,_2,_1,_0> of when 'true' -> %% Line 1209 case %% Line 1210 apply 'makedep_add_header'/6 (Ifile, Included, LineLen, MainTarget, Phony, File) of <{Included1,LineLen1,MainTarget1,Phony1}> when 'true' -> %% Line 1211 apply 'makedep_add_headers'/7 (Ifile, Rest, Included1, LineLen1, %% Line 1212 MainTarget1, %% Line 1212 Phony1, %% Line 1212 Opts) ( <_7> when 'true' -> primop 'match_fail' ({'badmatch',_7}) -| ['compiler_generated'] ) end %% Line 1213 when 'true' -> %% Line 1216 case call 'proplists':'get_value' ('makedep_add_missing', Opts) of %% Line 1217 <'true'> when 'true' -> %% Line 1218 case %% Line 1219 apply 'makedep_add_header'/6 (Ifile, Included, LineLen, MainTarget, %% Line 1220 Phony, %% Line 1220 File) of <{Included1,LineLen1,MainTarget1,Phony1}> when 'true' -> %% Line 1221 apply 'makedep_add_headers'/7 (Ifile, Rest, Included1, LineLen1, %% Line 1222 MainTarget1, %% Line 1222 Phony1, %% Line 1222 Opts) ( <_8> when 'true' -> primop 'match_fail' ({'badmatch',_8}) -| ['compiler_generated'] ) end %% Line 1223 <_20> when 'true' -> %% Line 1224 apply 'makedep_add_headers'/7 (Ifile, Rest, Included, LineLen, %% Line 1225 MainTarget, %% Line 1225 Phony, %% Line 1225 Opts) end %% Line 1227 when 'true' -> %% Line 1229 apply 'makedep_add_headers'/7 (Ifile, Rest, Included, %% Line 1230 LineLen, %% Line 1230 MainTarget, %% Line 1230 Phony, %% Line 1230 Opts) %% Line 1231 <_X_Ifile,[],_X_Included,_X_LineLen,%% Line 1232 MainTarget,%% Line 1232 Phony,%% Line 1232 _X_Opts> when 'true' -> %% Line 1233 {MainTarget,Phony} ( <_16,_15,_14,_13,_12,_11,_10> when 'true' -> ( primop 'match_fail' ({'function_clause',_16,_15,_14,_13,_12,_11,_10}) -| [{'function_name',{'makedep_add_headers',7}}] ) -| ['compiler_generated'] ) end 'makedep_add_header'/6 = %% Line 1235 fun (_5,_4,_3,_2,_1,_0) -> %% Line 1236 case call 'lists':'member' (_0, _4) of %% Line 1237 <'true'> when 'true' -> %% Line 1239 {_4,_3,_2,_1} %% Line 1240 <'false'> when 'true' -> let = [_0|_4] in let <_8> = case _0 of %% Line 1245 <[46|[47|File0]]> when 'true' -> File0 %% Line 1246 <_34> when 'true' -> _0 end in let <_13> = case _0 of %% Line 1251 <_35> when call 'erlang':'=:=' (_0, _5) -> _1 %% Line 1252 <_36> when 'true' -> let <_10> = call 'erlang':'++' (_8, [58]) in let <_11> = [10|[10|_10]] in call 'erlang':'++' (_1, _11) end in %% Line 1257 case <> of %% Line 1258 <> when try let <_16> = call 'erlang':'+' (_3, 1) in let <_15> = call 'erlang':'length' (_8) in let <_17> = call 'erlang':'+' (_16, _15) in call 'erlang':'>' (_17, 76) of -> Try catch -> 'false' -> let <_18> = call %% Line 1259 'erlang':%% Line 1259 'length' (_8) in let = call %% Line 1259 'erlang':%% Line 1259 '+' (%% Line 1259 2, _18) in let <_20> = call %% Line 1260 'erlang':%% Line 1260 '++' (%% Line 1260 [32|[92|[10|[32|[32]]]]], _8) in let = call %% Line 1260 'erlang':%% Line 1260 '++' (_2, _20) in %% Line 1261 {Included1,LineLen1,MainTarget1,_13} %% Line 1262 <> when 'true' -> let <_23> = call %% Line 1263 'erlang':%% Line 1263 '+' (_3, %% Line 1263 1) in let <_22> = call %% Line 1263 'erlang':%% Line 1263 'length' (_8) in let = call %% Line 1263 'erlang':%% Line 1263 '+' (_23, _22) in let <_25> = [32|_8] in let = call %% Line 1264 'erlang':%% Line 1264 '++' (_2, _25) in %% Line 1265 {Included1,LineLen1,MainTarget1,_13} end ( <_27> when 'true' -> primop 'match_fail' ({'case_clause',_27}) -| ['compiler_generated'] ) end 'makedep_output'/2 = %% Line 1269 fun (_1,_0) -> case <_1,_0> of when 'true' -> let <_4> = case %% Line 1273 call 'proplists':'get_value' ('makedep_output', Opts) of %% Line 1274 <'undefined'> when 'true' -> let <_2> = call %% Line 1276 'filename':%% Line 1276 'basename' (%% Line 1276 Ofile, %% Line 1276 [46|[98|[101|[97|[109]]]]]) in %% Line 1276 apply 'outfile'/3 (_2, [80|[98|[101|[97|[109]]]]], Opts) %% Line 1277 when 'true' -> %% Line 1278 O end in let <_197,_198,_199> = case _4 of %% Line 1285 <_60> when call 'erlang':'is_list' (_4) -> %% Line 1286 case call 'file':'delete' (_4) of %% Line 1287 when let <_6> = call 'erlang':'=:=' (Ret2, 'ok') in let <_7> = call 'erlang':'=:=' (Ret2, {'error','enoent'}) in call 'erlang':'or' (_6, _7) -> %% Line 1288 case call 'file':'open' (_4, ['write']) of %% Line 1289 <{'ok',IODev}> when 'true' -> %% Line 1290 <'ok',IODev,'true'> %% Line 1291 <{'error',Reason2}> when 'true' -> %% Line 1292 <'error','open',Reason2> ( <_8> when 'true' -> primop 'match_fail' ({'case_clause',_8}) -| ['compiler_generated'] ) end %% Line 1294 <{'error',Reason1}> when 'true' -> %% Line 1295 <'error','delete',Reason1> ( <_9> when 'true' -> primop 'match_fail' ({'case_clause',_9}) -| ['compiler_generated'] ) end %% Line 1297 <_61> when 'true' -> %% Line 1298 <'ok',_4,'false'> end in %% Line 1301 case ( <( _197 -| ['compiler_generated'] ),( _198 -| ['compiler_generated'] ),( _199 -| ['compiler_generated'] )> -| ['compiler_generated'] ) of %% Line 1302 <( 'ok' -| ['compiler_generated'] ),Output1,CloseOutput> when 'true' -> %% Line 1303 try do %% Line 1305 call 'io':'fwrite' (Output1, [126|[116|[115]]], [Code|[]]) do %% Line 1307 case <> of %% Line 1308 <> when ( call 'erlang':'=:=' (CloseOutput, 'true') -| ['compiler_generated'] ) -> case call 'file':'close' (Output1) of <'ok'> when 'true' -> 'ok' ( <_13> when 'true' -> primop 'match_fail' ({'badmatch',_13}) -| ['compiler_generated'] ) end %% Line 1309 <> when 'true' -> 'ok' end %% Line 1311 {'ok',Code,St} of <_14> -> _14 catch <_17,_16,_15> -> %% Line 1313 case <_17,_16,_15> of <( 'error' -| ['compiler_generated'] ),_63,_64> when 'true' -> let = {_51,%% Line 1315 [{'none','compile','write_error'}]} in let <_rec145> = call %% Line 1316 'erlang':%% Line 1316 '++' (_57, %% Line 1316 [Err|[]]) in let <_26> = call %% Line 1316 'erlang':%% Line 1316 'setelement' (%% Line 1316 13, %% Line 1316 St, %% Line 1316 _rec145) in %% Line 1316 {'error',_26} ( <_194,_195,_196> when 'true' -> primop 'raise' (_196, _195) -| ['compiler_generated'] ) end %% Line 1318 <( 'error' -| ['compiler_generated'] ),( 'open' -| ['compiler_generated'] ),Reason> when 'true' -> let = {_51,%% Line 1320 [{'none','compile',{'open',Reason}}|[]]} in let <_rec149> = call %% Line 1321 'erlang':%% Line 1321 '++' (_57, %% Line 1321 [Err|[]]) in let <_35> = call %% Line 1321 'erlang':%% Line 1321 'setelement' (%% Line 1321 13, %% Line 1321 St, %% Line 1321 _rec149) in %% Line 1321 {'error',_35} %% Line 1322 <( 'error' -| ['compiler_generated'] ),( 'delete' -| ['compiler_generated'] ),Reason> when 'true' -> let = {_51,%% Line 1324 [{'none','compile',{'delete',_4,Reason}}|[]]} in let <_rec153> = call %% Line 1325 'erlang':%% Line 1325 '++' (_57, %% Line 1325 [Err|[]]) in let <_44> = call %% Line 1325 'erlang':%% Line 1325 'setelement' (%% Line 1325 13, %% Line 1325 St, %% Line 1325 _rec153) in %% Line 1325 {'error',_44} ( <( _200 -| ['compiler_generated'] ),( _201 -| ['compiler_generated'] ),( _202 -| ['compiler_generated'] )> when 'true' -> let <_45> = {( _200 -| ['compiler_generated'] ),( _201 -| ['compiler_generated'] ),( _202 -| ['compiler_generated'] )} in primop 'match_fail' ({'case_clause',_45}) -| ['compiler_generated'] ) end ( <_47,_46> when 'true' -> ( primop 'match_fail' ({'function_clause',_47,_46}) -| [{'function_name',{'makedep_output',2}}] ) -| ['compiler_generated'] ) end 'expand_records'/2 = %% Line 1328 fun (_1,_0) -> case <_1,_0> of when 'true' -> let = call %% Line 1329 'erl_expand_records':%% Line 1329 'module' (%% Line 1329 Code0, %% Line 1329 Opts) in %% Line 1330 {'ok',Code,St} ( <_4,_3> when 'true' -> ( primop 'match_fail' ({'function_clause',_4,_3}) -| [{'function_name',{'expand_records',2}}] ) -| ['compiler_generated'] ) end 'core'/2 = %% Line 1332 fun (_1,_0) -> case <_1,_0> of when 'true' -> let <_6> = letrec 'lc$^0'/1 = %% Line 1333 fun (_4) -> case _4 of <[{'attribute',_35,'compile',C}|_3]> when 'true' -> let <_5> = apply 'lc$^0'/1 (_3) in ( [C|_5] -| ['compiler_generated'] ) ( <[_2|_3]> when 'true' -> apply 'lc$^0'/1 (_3) -| ['compiler_generated'] ) <[]> when 'true' -> Opts0 ( <_65> when 'true' -> ( primop 'match_fail' ({'function_clause',_65}) -| [{'function_name',{'lc$^0',1}}] ) -| ['compiler_generated'] ) end in %% Line 1333 apply 'lc$^0'/1 (Forms) in let = call %% Line 1333 'lists':%% Line 1333 'flatten' (_6) in let = apply %% Line 1334 'expand_opts'/1 (%% Line 1334 Opts1) in %% Line 1335 case call 'v3_core':'module' (Forms, Opts) of <{'ok',Core,Ws}> when 'true' -> let <_10> = call %% Line 1336 'cerl':%% Line 1336 'module_name' (%% Line 1336 Core) in let = call %% Line 1336 'cerl':%% Line 1336 'concrete' (_10) in let <_rec156> = call %% Line 1338 'erlang':%% Line 1338 '++' (_33, %% Line 1338 Ws) in let <_16> = call %% Line 1338 'erlang':%% Line 1338 'setelement' (%% Line 1338 14, %% Line 1337 St, %% Line 1338 _rec156) in let <_17> = call %% Line 1337 'erlang':%% Line 1337 'setelement' (%% Line 1337 10, _16, %% Line 1337 Opts) in let <_19> = call %% Line 1337 'erlang':%% Line 1337 'setelement' (%% Line 1337 7, _17, %% Line 1337 Mod) in %% Line 1337 {'ok',Core,_19} ( <_9> when 'true' -> primop 'match_fail' ({'badmatch',_9}) -| ['compiler_generated'] ) end ( <_21,_20> when 'true' -> ( primop 'match_fail' ({'function_clause',_21,_20}) -| [{'function_name',{'core',2}}] ) -| ['compiler_generated'] ) end 'core_fold_module_after_inlining'/2 = %% Line 1340 fun (_1,_0) -> case <_1,_0> of when 'true' -> %% Line 1343 case call 'sys_core_fold':'module' (Code0, Opts) of <{'ok',Code,_X_Ws}> when 'true' -> %% Line 1344 {'ok',Code,St} ( <_2> when 'true' -> primop 'match_fail' ({'badmatch',_2}) -| ['compiler_generated'] ) end ( <_4,_3> when 'true' -> ( primop 'match_fail' ({'function_clause',_4,_3}) -| [{'function_name',{'core_fold_module_after_inlining',2}}] ) -| ['compiler_generated'] ) end 'v3_kernel'/2 = %% Line 1346 fun (_1,_0) -> case <_1,_0> of when 'true' -> %% Line 1347 case call 'v3_kernel':'module' (Code0, Opts) of <{'ok',Code,Ws}> when 'true' -> let <_5> = case <> of %% Line 1348 ( <> when call 'erlang':'=:=' (Ws, []) -> 'true' -| ['compiler_generated'] ) %% Line 1348 ( <> when 'true' -> apply 'test_core_inliner'/1 (St) -| ['compiler_generated'] ) end in %% Line 1348 case _5 of %% Line 1349 <'false'> when 'true' -> let <_rec159> = call %% Line 1350 'erlang':%% Line 1350 '++' (%% Line 1350 Ws0, %% Line 1350 Ws) in let <_9> = call %% Line 1350 'erlang':%% Line 1350 'setelement' (%% Line 1350 14, %% Line 1350 St, %% Line 1350 _rec159) in %% Line 1350 {'ok',Code,_9} %% Line 1351 <'true'> when 'true' -> %% Line 1354 {'ok',Code,St} ( <_10> when 'true' -> primop 'match_fail' ({'case_clause',_10}) -| ['compiler_generated'] ) end ( <_2> when 'true' -> primop 'match_fail' ({'badmatch',_2}) -| ['compiler_generated'] ) end ( <_12,_11> when 'true' -> ( primop 'match_fail' ({'function_clause',_12,_11}) -| [{'function_name',{'v3_kernel',2}}] ) -| ['compiler_generated'] ) end 'block2'/2 = %% Line 1357 fun (_1,_0) -> case <_1,_0> of when 'true' -> %% Line 1358 case call 'beam_block':'module' (Code0, ['no_blockify'|Opts]) of <{'ok',Code}> when 'true' -> %% Line 1359 {'ok',Code,St} ( <_2> when 'true' -> primop 'match_fail' ({'badmatch',_2}) -| ['compiler_generated'] ) end ( <_4,_3> when 'true' -> ( primop 'match_fail' ({'function_clause',_4,_3}) -| [{'function_name',{'block2',2}}] ) -| ['compiler_generated'] ) end 'test_old_inliner'/1 = %% Line 1361 fun (_0) -> case _0 of <{'compile',_5,_6,_7,_8,_9,_10,_11,_12,Opts,_13,_14,_15,_16,_17}> when 'true' -> let <_3> = fun (_1) -> %% Line 1364 case _1 of <{'inline',_18}> when 'true' -> 'true' %% Line 1365 <_19> when 'true' -> 'false' end in %% Line 1364 call 'lists':'any' (_3, %% Line 1366 Opts) ( <_4> when 'true' -> ( primop 'match_fail' ({'function_clause',_4}) -| [{'function_name',{'test_old_inliner',1}}] ) -| ['compiler_generated'] ) end 'test_core_inliner'/1 = %% Line 1368 fun (_0) -> case _0 of <{'compile',_9,_10,_11,_12,_13,_14,_15,_16,Opts,_17,_18,_19,_20,_21}> when 'true' -> let <_3> = fun (_1) -> %% Line 1369 case _1 of <'no_inline'> when 'true' -> 'true' %% Line 1370 <_22> when 'true' -> 'false' end in %% Line 1369 case call 'lists':'any' (_3, %% Line 1371 Opts) of %% Line 1372 <'true'> when 'true' -> 'false' %% Line 1373 <'false'> when 'true' -> let <_6> = fun (_4) -> %% Line 1374 case _4 of <'inline'> when 'true' -> 'true' %% Line 1375 <_23> when 'true' -> 'false' end in %% Line 1374 call 'lists':'any' (_6, %% Line 1376 Opts) ( <_7> when 'true' -> primop 'match_fail' ({'case_clause',_7}) -| ['compiler_generated'] ) end ( <_8> when 'true' -> ( primop 'match_fail' ({'function_clause',_8}) -| [{'function_name',{'test_core_inliner',1}}] ) -| ['compiler_generated'] ) end 'test_any_inliner'/1 = %% Line 1379 fun (_0) -> %% Line 1380 ( case apply 'test_old_inliner'/1 (_0) of ( <( 'true' -| ['compiler_generated'] )> when 'true' -> 'true' -| ['compiler_generated'] ) ( <( 'false' -| ['compiler_generated'] )> when 'true' -> apply 'test_core_inliner'/1 (_0) -| ['compiler_generated'] ) ( <_1> when 'true' -> ( call ( 'erlang' -| ['compiler_generated'] ):( 'error' -| ['compiler_generated'] ) (( {( 'badarg' -| ['compiler_generated'] ),_1} -| ['compiler_generated'] )) -| ['compiler_generated'] ) -| ['compiler_generated'] ) end -| ['compiler_generated'] ) 'core_old_inliner'/2 = %% Line 1382 fun (_1,_0) -> case <_1,_0> of when 'true' -> %% Line 1383 case call 'sys_core_inline':'module' (Code0, Opts) of <{'ok',Code}> when 'true' -> %% Line 1384 {'ok',Code,St} ( <_2> when 'true' -> primop 'match_fail' ({'badmatch',_2}) -| ['compiler_generated'] ) end ( <_4,_3> when 'true' -> ( primop 'match_fail' ({'function_clause',_4,_3}) -| [{'function_name',{'core_old_inliner',2}}] ) -| ['compiler_generated'] ) end 'core_inline_module'/2 = %% Line 1386 fun (_1,_0) -> case <_1,_0> of when 'true' -> let = call %% Line 1387 'cerl_inline':%% Line 1387 'core_transform' (%% Line 1387 Code0, %% Line 1387 Opts) in %% Line 1388 {'ok',Code,St} ( <_4,_3> when 'true' -> ( primop 'match_fail' ({'function_clause',_4,_3}) -| [{'function_name',{'core_inline_module',2}}] ) -| ['compiler_generated'] ) end 'save_abstract_code'/2 = %% Line 1390 fun (_1,_0) -> let <_rec161> = call %% Line 1391 'erl_parse':%% Line 1391 'anno_to_term' (_1) in %% Line 1391 case _0 of <{'compile',_8,_9,_10,_11,_12,_13,_14,_15,_16,_17,_18,_19,_20,_21}> when 'true' -> let <_5> = call 'erlang':'setelement' (9, _0, _rec161) in {'ok',_1,_5} ( <_22> when 'true' -> ( call ( 'erlang' -| ['compiler_generated'] ):( 'error' -| ['compiler_generated'] ) (( {'badrecord','compile'} -| ['compiler_generated'] )) -| ['compiler_generated'] ) -| ['compiler_generated'] ) end 'debug_info'/1 = %% Line 1393 fun (_0) -> case _0 of <{'compile',_12,_13,_14,_15,OFile,Module,_16,Abst,_17,Opts0,_18,_19,_20,_21}> when 'true' -> let = apply %% Line 1394 'cleanup_compile_options'/1 (%% Line 1394 Opts0) in let = call %% Line 1395 'proplists':%% Line 1395 'delete' (%% Line 1395 'debug_info', %% Line 1395 Opts0) in let <_23,_24,_25> = case %% Line 1397 call 'proplists':'get_value' ('debug_info', Opts0, 'false') of %% Line 1398 <{OptBackend,OptMetadata}> when call 'erlang':'is_atom' (OptBackend) -> %% Line 1399 <'false'> when 'true' -> <'erl_abstract_code',{'none',AbstOpts},Opts1> %% Line 1400 <'true'> when 'true' -> <'erl_abstract_code',{Abst,AbstOpts},['debug_info'|Opts1]> ( <_3> when 'true' -> %% Line 1397 primop 'match_fail' ({'case_clause',_3}) -| ['compiler_generated'] ) end in let = call %% Line 1402 'erlang':%% Line 1402 'term_to_binary' (%% Line 1402 {'debug_info_v1',( _23 -| ['compiler_generated'] ),( _24 -| ['compiler_generated'] )}, %% Line 1402 ['compressed']) in %% Line 1404 case call 'lists':'member' ('encrypt_debug_info', ( _25 -| ['compiler_generated'] )) of %% Line 1405 <'true'> when 'true' -> %% Line 1406 case call 'lists':'keytake' ('debug_info_key', 1, ( _25 -| ['compiler_generated'] )) of %% Line 1407 <{'value',{_22,Key},Opts3}> when 'true' -> %% Line 1408 apply 'encrypt_debug_info'/3 (DebugInfo, Key, [{'debug_info_key','********'}|Opts3]) %% Line 1409 <'false'> when 'true' -> let = call %% Line 1410 'proplists':%% Line 1410 'get_value' (%% Line 1410 'crypto_mode', ( _25 -| ['compiler_generated'] ), %% Line 1410 'des3_cbc') in %% Line 1411 case call 'beam_lib':'get_crypto_key' ({'debug_info',Mode,Module,OFile}) of %% Line 1412 <'error'> when 'true' -> %% Line 1413 {'error',[{'none','compile','no_crypto_key'}]} %% Line 1414 when 'true' -> %% Line 1415 apply 'encrypt_debug_info'/3 (DebugInfo, {Mode,Key}, ( _25 -| ['compiler_generated'] )) end ( <_9> when 'true' -> primop 'match_fail' ({'case_clause',_9}) -| ['compiler_generated'] ) end %% Line 1418 <'false'> when 'true' -> %% Line 1419 {'ok',DebugInfo,( _25 -| ['compiler_generated'] )} ( <_10> when 'true' -> primop 'match_fail' ({'case_clause',_10}) -| ['compiler_generated'] ) end ( <_11> when 'true' -> ( primop 'match_fail' ({'function_clause',_11}) -| [{'function_name',{'debug_info',1}}] ) -| ['compiler_generated'] ) end 'encrypt_debug_info'/3 = %% Line 1422 fun (_2,_1,_0) -> %% Line 1423 try let = apply %% Line 1424 'generate_key'/1 (_1) in %% Line 1425 case apply 'start_crypto'/0 () of %% Line 1426 <'ok'> when 'true' -> let <_4> = apply 'encrypt'/2 (RealKey, _2) in {'ok',_4,_0} %% Line 1427 when 'true' -> E ( <_5> when 'true' -> primop 'match_fail' ({'case_clause',_5}) -| ['compiler_generated'] ) end of <_6> -> _6 catch <_9,_8,_7> -> %% Line 1430 case <_9,_8,_7> of <( 'error' -| ['compiler_generated'] ),_14,_15> when 'true' -> %% Line 1431 {'error',[{'none','compile','bad_crypto_key'}]} ( <_16,_17,_18> when 'true' -> primop 'raise' (_18, _17) -| ['compiler_generated'] ) end 'cleanup_compile_options'/1 = %% Line 1434 fun (_0) -> %% Line 1435 call 'lists':'filter' (( 'keep_compile_option'/1 -| [{'id',{0,0,'-cleanup_compile_options/1-fun-0-'}}] ), _0) 'keep_compile_option'/1 = %% Line 1438 fun (_0) -> case _0 of <'from_asm'> when 'true' -> 'false' %% Line 1439 <'from_core'> when 'true' -> 'false' %% Line 1441 <{'parse_transform',_2}> when 'true' -> 'false' %% Line 1442 <{'d',_3,_4}> when 'true' -> 'false' %% Line 1444
= call %% Line 916 'gen':%% Line 916 'format_status_header' (%% Line 916 [83|[116|[97|[116|[117|[115|[32|[102|[111|[114|[32|[103|[101|[110|[101|[114|[105|[99|[32|[115|[101|[114|[118|[101|[114]]]]]]]]]]]]]]]]]]]]]]]]], %% Line 916 Name) in let = call %% Line 917 'sys':%% Line 917 'get_debug' (%% Line 917 'log', %% Line 917 Debug, %% Line 917 []) in let <_@c6> = case %% Line 918 apply 'format_status'/4 (_@c1, Mod, PDict, State) of %% Line 919 when call 'erlang':'is_list' (S) -> S %% Line 920 when 'true' -> [S|[]] end in %% Line 922 [{'header',Header}|%% Line 923 [{'data',[{[83|[116|[97|[116|[117|[115]]]]]],SysState}|%% Line 924 [{[80|[97|[114|[101|[110|[116]]]]]],Parent}|%% Line 925 [{[76|[111|[103|[103|[101|[100|[32|[101|[118|[101|[110|[116|[115]]]]]]]]]]]]],Log}|[]]]]}|_@c6]] ( <_@c2> when 'true' -> primop 'match_fail' ({'badmatch',_@c2}) -| ['compiler_generated'] ) end 'format_status'/4 = %% Line 928 fun (_@c3,_@c2,_@c1,_@c0) -> let <_@c5> = case _@c3 of %% Line 930 <'terminate'> when 'true' -> _@c0 %% Line 931 <_@c14> when 'true' -> [{'data',[{[83|[116|[97|[116|[101]]]]],_@c0}|[]]}|[]] end in %% Line 933 case call 'erlang':'function_exported' (_@c2, 'format_status', 2) of %% Line 934 <'true'> when 'true' -> let <_@c7> = catch %% Line 935 call _@c2:'format_status' (_@c3, [_@c1|[_@c0|[]]]) in %% Line 935 case _@c7 of %% Line 936 <{'EXIT',_@c15}> when 'true' -> _@c5 %% Line 937 when 'true' -> Else end %% Line 939 <_@c16> when 'true' -> _@c5 end 'behaviour_info'/1 = fun (_@c0) -> case _@c0 of <'callbacks'> when 'true' -> [{'init',1}|[{'handle_call',3}|[{'handle_cast',2}|[{'handle_info',2}|[{'terminate',2}|[{'code_change',3}|[{'format_status',2}]]]]]]] <'optional_callbacks'> when 'true' -> [{'handle_info',2}|[{'terminate',2}|[{'code_change',3}|[{'format_status',2}]]]] ( <_@c1> when 'true' -> ( primop 'match_fail' ({'function_clause',_@c1}) -| [{'function_name',{'behaviour_info',1}}] ) -| ['compiler_generated'] ) end 'module_info'/0 = fun () -> call 'erlang':'get_module_info' ('gen_server') 'module_info'/1 = fun (_@c0) -> call 'erlang':'get_module_info' ('gen_server', _@c0) end ================================================ FILE: test_data/language_test.core ================================================ module 'language_test' ['module_info'/0, 'module_info'/1] attributes [%% Line 1 'file' = %% Line 1 [{[108|[97|[110|[103|[117|[97|[103|[101|[95|[116|[101|[115|[116|[46|[101|[114|[108]]]]]]]]]]]]]]]]],1}]] 'module_function_capture'/0 = %% Line 5 fun () -> %% Line 6 fun 'woohoo':'hoo'/2 'do_throw'/0 = %% Line 8 fun () -> %% Line 9 call 'erlang':'throw' ('something') 'do_error'/0 = %% Line 10 fun () -> %% Line 11 call 'erlang':'error' ('something') 'do_exit'/0 = %% Line 12 fun () -> %% Line 13 call 'erlang':'exit' ('something') 'try_catch'/1 = %% Line 15 fun (_0) -> %% Line 16 try apply _0 () of <_1> -> %% Line 17 'woo' catch <_5,_4,_3> -> %% Line 19 case <_5,_4,_3> of <( 'throw' -| ['compiler_generated'] ),( 'hoo' -| ['compiler_generated'] ),_8> when 'true' -> 'a_throw' ( <_10,_11,_12> when 'true' -> primop 'raise' (_12, _11) -| ['compiler_generated'] ) end 'try_catch_finally'/1 = %% Line 22 fun (_0) -> %% Line 23 letrec 'after$^0'/0 = fun () -> %% Line 28 'some_after_clause' in try try apply _0 () of <_1> -> %% Line 24 'woo' catch <_5,_4,_3> -> %% Line 26 case <_5,_4,_3> of <( 'throw' -| ['compiler_generated'] ),( 'hoo' -| ['compiler_generated'] ),_12> when 'true' -> 'a_throw' ( <_14,_15,_16> when 'true' -> primop 'raise' (_16, _15) -| ['compiler_generated'] ) end of <_6> -> do ( apply 'after$^0'/0 () -| ['compiler_generated'] ) _6 catch <_9,_8,_7> -> do ( apply 'after$^0'/0 () -| ['compiler_generated'] ) primop 'raise' (_7, _8) 'self_tail_call'/1 = %% Line 31 fun (_0) -> %% Line 32 case _0 of %% Line 33 <0> when 'true' -> %% Line 34 'reached_end' %% Line 35 <_4> when 'true' -> let <_1> = call %% Line 36 'erlang':%% Line 36 '-' (_0, %% Line 36 1) in %% Line 36 apply 'self_tail_call'/1 (_1) end 'binary_construct_1'/1 = %% Line 39 fun (_0) -> %% Line 40 #{#<_0>(8,1,'integer',['unsigned'|['big']])}# 'binary_pattern_match_1'/1 = %% Line 42 fun (_0) -> case _0 of <#{#<_X_A>(4,8,'integer',['signed'|['little']]), #<_X_B>('all',8,'binary',['unsigned'|['big']])}#> when 'true' -> %% Line 43 'matched' ( <_1> when 'true' -> ( primop 'match_fail' ({'function_clause',_1}) -| [{'function_name',{'binary_pattern_match_1',1}}] ) -| ['compiler_generated'] ) end 'binary_pattern_match_2'/1 = %% Line 44 fun (_0) -> case _0 of <#{#<_X_A>(4,8,'integer',['signed'|['little']]), #<_X_B>(8,1,'integer',['unsigned'|['big']])}#> when 'true' -> %% Line 45 'matched' ( <_1> when 'true' -> ( primop 'match_fail' ({'function_clause',_1}) -| [{'function_name',{'binary_pattern_match_2',1}}] ) -| ['compiler_generated'] ) end 'binary_pattern_match_3'/1 = %% Line 46 fun (_0) -> case _0 of <#{#<_X_A>(2,2,'integer',['signed'|['little']]), #<_X_B>('all',8,'binary',['unsigned'|['big']])}#> when 'true' -> %% Line 47 'matched' ( <_1> when 'true' -> ( primop 'match_fail' ({'function_clause',_1}) -| [{'function_name',{'binary_pattern_match_3',1}}] ) -| ['compiler_generated'] ) end 'binary_pattern_match_4'/1 = %% Line 48 fun (_0) -> case _0 of <#{#<_X_A>(4,8,'float',['unsigned'|['big']]), #<_X_B>('all',8,'binary',['unsigned'|['big']])}#> when 'true' -> %% Line 49 'matched' ( <_1> when 'true' -> ( primop 'match_fail' ({'function_clause',_1}) -| [{'function_name',{'binary_pattern_match_4',1}}] ) -| ['compiler_generated'] ) end 'module_info'/0 = fun () -> call 'erlang':'get_module_info' ('language_test') 'module_info'/1 = fun (_0) -> call 'erlang':'get_module_info' ('language_test', _0) end ================================================ FILE: test_data/language_test.erl ================================================ -module(language_test). -export([]). module_function_capture() -> fun woohoo:hoo/2. do_throw() -> throw(something). do_error() -> erlang:error(something). do_exit() -> erlang:exit(something). try_catch(A) -> try A() of _ -> woo catch throw:hoo -> a_throw end. try_catch_finally(A) -> try A() of _ -> woo catch throw:hoo -> a_throw after some_after_clause end. self_tail_call(A) -> case A of 0 -> reached_end; _ -> self_tail_call(A - 1) end. binary_construct_1(A) -> <>. binary_pattern_match_1(<<_A:4/integer-signed-little-unit:8, _B/binary>>) -> matched. binary_pattern_match_2(<<_A:4/integer-signed-little-unit:8, _B/integer>>) -> matched. binary_pattern_match_3(<<_A:2/integer-signed-little-unit:2, _B/binary>>) -> matched. binary_pattern_match_4(<<_A:4/float-unit:8, _B/binary>>) -> matched. ================================================ FILE: test_data/long_strings.core ================================================ module 'long_strings' ['format_error'/1] attributes [] 'format_error'/1 = %% Line 242 fun (_0) -> case _0 of <'no_native_support'> when 'true' -> %% Line 243 [116|[104|[105|[115|[32|[115|[121|[115|[116|[101|[109|[32|[105|[115|[32|[110|[111|[116|[32|[99|[111|[110|[102|[105|[103|[117|[114|[101|[100|[32|[102|[111|[114|[32|[110|[97|[116|[105|[118|[101|[45|[99|[111|[100|[101|[32|[99|[111|[109|[112|[105|[108|[97|[116|[105|[111|[110|[46]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]] %% Line 244 <'no_crypto'> when 'true' -> %% Line 245 [116|[104|[105|[115|[32|[115|[121|[115|[116|[101|[109|[32|[105|[115|[32|[110|[111|[116|[32|[99|[111|[110|[102|[105|[103|[117|[114|[101|[100|[32|[119|[105|[116|[104|[32|[99|[114|[121|[112|[116|[111|[32|[115|[117|[112|[112|[111|[114|[116|[46]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]] %% Line 246 <'bad_crypto_key'> when 'true' -> %% Line 247 [105|[110|[118|[97|[108|[105|[100|[32|[99|[114|[121|[112|[116|[111|[32|[107|[101|[121|[46]]]]]]]]]]]]]]]]]]] %% Line 248 <'no_crypto_key'> when 'true' -> %% Line 249 [110|[111|[32|[99|[114|[121|[112|[116|[111|[32|[107|[101|[121|[32|[115|[117|[112|[112|[108|[105|[101|[100|[46]]]]]]]]]]]]]]]]]]]]]]] %% Line 250 <{'native',E}> when 'true' -> %% Line 251 call 'io_lib':'fwrite' ([110|[97|[116|[105|[118|[101|[45|[99|[111|[100|[101|[32|[99|[111|[109|[112|[105|[108|[97|[116|[105|[111|[110|[32|[102|[97|[105|[108|[101|[100|[32|[119|[105|[116|[104|[32|[114|[101|[97|[115|[111|[110|[58|[32|[126|[116|[80|[46]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]], %% Line 252 [E|[25]]) %% Line 253 <{'native_crash',E,Stk}> when 'true' -> %% Line 254 call 'io_lib':'fwrite' ([110|[97|[116|[105|[118|[101|[45|[99|[111|[100|[101|[32|[99|[111|[109|[112|[105|[108|[97|[116|[105|[111|[110|[32|[99|[114|[97|[115|[104|[101|[100|[32|[119|[105|[116|[104|[32|[114|[101|[97|[115|[111|[110|[58|[32|[126|[116|[80|[46|[10|[126|[116|[80|[10]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]], %% Line 255 [E|[25|[Stk|[25]]]]) %% Line 256 <{'open',E}> when 'true' -> let <_1> = call %% Line 257 'file':%% Line 257 'format_error' (%% Line 257 E) in %% Line 257 call 'io_lib':'format' ([111|[112|[101|[110|[32|[101|[114|[114|[111|[114|[32|[39|[126|[116|[115|[39]]]]]]]]]]]]]]]], [_1|[]]) %% Line 258 <{'epp',E}> when 'true' -> %% Line 259 call 'epp':'format_error' (E) %% Line 260 <'write_error'> when 'true' -> %% Line 261 [101|[114|[114|[111|[114|[32|[119|[114|[105|[116|[105|[110|[103|[32|[102|[105|[108|[101]]]]]]]]]]]]]]]]]] %% Line 262 <{'write_error',Error}> when 'true' -> let <_2> = call %% Line 263 'file':%% Line 263 'format_error' (%% Line 263 Error) in %% Line 263 call 'io_lib':'format' ([101|[114|[114|[111|[114|[32|[119|[114|[105|[116|[105|[110|[103|[32|[102|[105|[108|[101|[58|[32|[126|[116|[115]]]]]]]]]]]]]]]]]]]]]]], [_2|[]]) %% Line 264 <{'rename',From,To,Error}> when 'true' -> let <_3> = call %% Line 266 'file':%% Line 266 'format_error' (%% Line 266 Error) in %% Line 265 call 'io_lib':'format' ([102|[97|[105|[108|[101|[100|[32|[116|[111|[32|[114|[101|[110|[97|[109|[101|[32|[126|[116|[115|[32|[116|[111|[32|[126|[116|[115|[58|[32|[126|[116|[115]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]], %% Line 266 [From|[To|[_3|[]]]]) %% Line 267 <{'delete',File,Error}> when 'true' -> let <_4> = call %% Line 269 'file':%% Line 269 'format_error' (%% Line 269 Error) in %% Line 268 call 'io_lib':'format' ([102|[97|[105|[108|[101|[100|[32|[116|[111|[32|[100|[101|[108|[101|[116|[101|[32|[102|[105|[108|[101|[32|[126|[116|[115|[58|[32|[126|[116|[115]]]]]]]]]]]]]]]]]]]]]]]]]]]]]], %% Line 269 [File|[_4|[]]]) %% Line 270 <{'delete_temp',File,Error}> when 'true' -> let <_5> = call %% Line 272 'file':%% Line 272 'format_error' (%% Line 272 Error) in %% Line 271 call 'io_lib':'format' ([102|[97|[105|[108|[101|[100|[32|[116|[111|[32|[100|[101|[108|[101|[116|[101|[32|[116|[101|[109|[112|[111|[114|[97|[114|[121|[32|[102|[105|[108|[101|[32|[126|[116|[115|[58|[32|[126|[116|[115]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]], %% Line 272 [File|[_5|[]]]) %% Line 273 <{'parse_transform',M,R}> when 'true' -> %% Line 274 call 'io_lib':'format' ([101|[114|[114|[111|[114|[32|[105|[110|[32|[112|[97|[114|[115|[101|[32|[116|[114|[97|[110|[115|[102|[111|[114|[109|[32|[39|[126|[116|[115|[39|[58|[32|[126|[116|[112]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]], [M|[R|[]]]) %% Line 275 <{'undef_parse_transform',M}> when 'true' -> %% Line 276 call 'io_lib':'format' ([117|[110|[100|[101|[102|[105|[110|[101|[100|[32|[112|[97|[114|[115|[101|[32|[116|[114|[97|[110|[115|[102|[111|[114|[109|[32|[39|[126|[116|[115|[39]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]], [M|[]]) %% Line 277 <{'core_transform',M,R}> when 'true' -> %% Line 278 call 'io_lib':'format' ([101|[114|[114|[111|[114|[32|[105|[110|[32|[99|[111|[114|[101|[32|[116|[114|[97|[110|[115|[102|[111|[114|[109|[32|[39|[126|[115|[39|[58|[32|[126|[116|[112]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]], [M|[R|[]]]) %% Line 279 <{'crash',Pass,Reason}> when 'true' -> let <_6> = apply %% Line 280 'format_error_reason'/1 (%% Line 280 Reason) in %% Line 280 call 'io_lib':'format' ([105|[110|[116|[101|[114|[110|[97|[108|[32|[101|[114|[114|[111|[114|[32|[105|[110|[32|[126|[112|[59|[10|[99|[114|[97|[115|[104|[32|[114|[101|[97|[115|[111|[110|[58|[32|[126|[116|[115]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]], [Pass|[_6|[]]]) %% Line 281 <{'bad_return',Pass,Reason}> when 'true' -> let <_7> = apply %% Line 282 'format_error_reason'/1 (%% Line 282 Reason) in %% Line 282 call 'io_lib':'format' ([105|[110|[116|[101|[114|[110|[97|[108|[32|[101|[114|[114|[111|[114|[32|[105|[110|[32|[126|[112|[59|[10|[98|[97|[100|[32|[114|[101|[116|[117|[114|[110|[32|[118|[97|[108|[117|[101|[58|[32|[126|[116|[115]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]], [Pass|[_7|[]]]) %% Line 283 <{'module_name',Mod,Filename}> when 'true' -> %% Line 284 call 'io_lib':'format' ([77|[111|[100|[117|[108|[101|[32|[110|[97|[109|[101|[32|[39|[126|[115|[39|[32|[100|[111|[101|[115|[32|[110|[111|[116|[32|[109|[97|[116|[99|[104|[32|[102|[105|[108|[101|[32|[110|[97|[109|[101|[32|[39|[126|[116|[115|[39]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]], [Mod|[Filename|[]]]) ( <_8> when 'true' -> ( primop 'match_fail' ({'function_clause',_8}) -| [{'function_name',{'format_error',1}}] ) -| ['compiler_generated'] ) end end ================================================ FILE: test_data/long_strings.core.bak ================================================ module 'long_strings' ['format_error'/1] attributes [] 'format_error'/1 = %% Line 242 fun (_0) -> case _0 of <'no_native_support'> when 'true' -> %% Line 243 [116|[104|[105|[115|[32|[115|[121|[115|[116|[101|[109|[32|[105|[115|[32|[110|[111|[116|[32|[99|[111|[110|[102|[105|[103|[117|[114|[101|[100|[32|[102|[111|[114|[32|[110|[97|[116|[105|[118|[101|[45|[99|[111|[100|[101|[32|[99|[111|[109|[112|[105|[108|[97|[116|[105|[111|[110|[46]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]] %% Line 244 <'no_crypto'> when 'true' -> %% Line 245 [116|[104|[105|[115|[32|[115|[121|[115|[116|[101|[109|[32|[105|[115|[32|[110|[111|[116|[32|[99|[111|[110|[102|[105|[103|[117|[114|[101|[100|[32|[119|[105|[116|[104|[32|[99|[114|[121|[112|[116|[111|[32|[115|[117|[112|[112|[111|[114|[116|[46]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]] %% Line 246 <'bad_crypto_key'> when 'true' -> %% Line 247 [105|[110|[118|[97|[108|[105|[100|[32|[99|[114|[121|[112|[116|[111|[32|[107|[101|[121|[46]]]]]]]]]]]]]]]]]]] %% Line 248 <'no_crypto_key'> when 'true' -> %% Line 249 [110|[111|[32|[99|[114|[121|[112|[116|[111|[32|[107|[101|[121|[32|[115|[117|[112|[112|[108|[105|[101|[100|[46]]]]]]]]]]]]]]]]]]]]]]] %% Line 250 <{'native',E}> when 'true' -> %% Line 251 call 'io_lib':'fwrite' ([110|[97|[116|[105|[118|[101|[45|[99|[111|[100|[101|[32|[99|[111|[109|[112|[105|[108|[97|[116|[105|[111|[110|[32|[102|[97|[105|[108|[101|[100|[32|[119|[105|[116|[104|[32|[114|[101|[97|[115|[111|[110|[58|[32|[126|[116|[80|[46]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]], %% Line 252 [E|[25]]) %% Line 253 <{'native_crash',E,Stk}> when 'true' -> %% Line 254 call 'io_lib':'fwrite' ([110|[97|[116|[105|[118|[101|[45|[99|[111|[100|[101|[32|[99|[111|[109|[112|[105|[108|[97|[116|[105|[111|[110|[32|[99|[114|[97|[115|[104|[101|[100|[32|[119|[105|[116|[104|[32|[114|[101|[97|[115|[111|[110|[58|[32|[126|[116|[80|[46|[10|[126|[116|[80|[10]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]], %% Line 255 [E|[25|[Stk|[25]]]]) %% Line 256 <{'open',E}> when 'true' -> let <_1> = call %% Line 257 'file':%% Line 257 'format_error' (%% Line 257 E) in %% Line 257 call 'io_lib':'format' ([111|[112|[101|[110|[32|[101|[114|[114|[111|[114|[32|[39|[126|[116|[115|[39]]]]]]]]]]]]]]]], [_1|[]]) %% Line 258 <{'epp',E}> when 'true' -> %% Line 259 call 'epp':'format_error' (E) %% Line 260 <'write_error'> when 'true' -> %% Line 261 [101|[114|[114|[111|[114|[32|[119|[114|[105|[116|[105|[110|[103|[32|[102|[105|[108|[101]]]]]]]]]]]]]]]]]] %% Line 262 <{'write_error',Error}> when 'true' -> let <_2> = call %% Line 263 'file':%% Line 263 'format_error' (%% Line 263 Error) in %% Line 263 call 'io_lib':'format' ([101|[114|[114|[111|[114|[32|[119|[114|[105|[116|[105|[110|[103|[32|[102|[105|[108|[101|[58|[32|[126|[116|[115]]]]]]]]]]]]]]]]]]]]]]], [_2|[]]) %% Line 264 <{'rename',From,To,Error}> when 'true' -> let <_3> = call %% Line 266 'file':%% Line 266 'format_error' (%% Line 266 Error) in %% Line 265 call 'io_lib':'format' ([102|[97|[105|[108|[101|[100|[32|[116|[111|[32|[114|[101|[110|[97|[109|[101|[32|[126|[116|[115|[32|[116|[111|[32|[126|[116|[115|[58|[32|[126|[116|[115]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]], %% Line 266 [From|[To|[_3|[]]]]) %% Line 267 <{'delete',File,Error}> when 'true' -> let <_4> = call %% Line 269 'file':%% Line 269 'format_error' (%% Line 269 Error) in %% Line 268 call 'io_lib':'format' ([102|[97|[105|[108|[101|[100|[32|[116|[111|[32|[100|[101|[108|[101|[116|[101|[32|[102|[105|[108|[101|[32|[126|[116|[115|[58|[32|[126|[116|[115]]]]]]]]]]]]]]]]]]]]]]]]]]]]]], %% Line 269 [File|[_4|[]]]) %% Line 270 <{'delete_temp',File,Error}> when 'true' -> let <_5> = call %% Line 272 'file':%% Line 272 'format_error' (%% Line 272 Error) in %% Line 271 call 'io_lib':'format' ([102|[97|[105|[108|[101|[100|[32|[116|[111|[32|[100|[101|[108|[101|[116|[101|[32|[116|[101|[109|[112|[111|[114|[97|[114|[121|[32|[102|[105|[108|[101|[32|[126|[116|[115|[58|[32|[126|[116|[115]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]], %% Line 272 [File|[_5|[]]]) %% Line 273 <{'parse_transform',M,R}> when 'true' -> %% Line 274 call 'io_lib':'format' ([101|[114|[114|[111|[114|[32|[105|[110|[32|[112|[97|[114|[115|[101|[32|[116|[114|[97|[110|[115|[102|[111|[114|[109|[32|[39|[126|[116|[115|[39|[58|[32|[126|[116|[112]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]], [M|[R|[]]]) %% Line 275 <{'undef_parse_transform',M}> when 'true' -> %% Line 276 call 'io_lib':'format' ([117|[110|[100|[101|[102|[105|[110|[101|[100|[32|[112|[97|[114|[115|[101|[32|[116|[114|[97|[110|[115|[102|[111|[114|[109|[32|[39|[126|[116|[115|[39]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]], [M|[]]) %% Line 277 <{'core_transform',M,R}> when 'true' -> %% Line 278 call 'io_lib':'format' ([101|[114|[114|[111|[114|[32|[105|[110|[32|[99|[111|[114|[101|[32|[116|[114|[97|[110|[115|[102|[111|[114|[109|[32|[39|[126|[115|[39|[58|[32|[126|[116|[112]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]], [M|[R|[]]]) %% Line 279 <{'crash',Pass,Reason}> when 'true' -> let <_6> = apply %% Line 280 'format_error_reason'/1 (%% Line 280 Reason) in %% Line 280 call 'io_lib':'format' ([105|[110|[116|[101|[114|[110|[97|[108|[32|[101|[114|[114|[111|[114|[32|[105|[110|[32|[126|[112|[59|[10|[99|[114|[97|[115|[104|[32|[114|[101|[97|[115|[111|[110|[58|[32|[126|[116|[115]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]], [Pass|[_6|[]]]) %% Line 281 <{'bad_return',Pass,Reason}> when 'true' -> let <_7> = apply %% Line 282 'format_error_reason'/1 (%% Line 282 Reason) in %% Line 282 call 'io_lib':'format' ([105|[110|[116|[101|[114|[110|[97|[108|[32|[101|[114|[114|[111|[114|[32|[105|[110|[32|[126|[112|[59|[10|[98|[97|[100|[32|[114|[101|[116|[117|[114|[110|[32|[118|[97|[108|[117|[101|[58|[32|[126|[116|[115]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]], [Pass|[_7|[]]]) %% Line 283 <{'module_name',Mod,Filename}> when 'true' -> %% Line 284 call 'io_lib':'format' ([77|[111|[100|[117|[108|[101|[32|[110|[97|[109|[101|[32|[39|[126|[115|[39|[32|[100|[111|[101|[115|[32|[110|[111|[116|[32|[109|[97|[116|[99|[104|[32|[102|[105|[108|[101|[32|[110|[97|[109|[101|[32|[39|[126|[116|[115|[39]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]], [Mod|[Filename|[]]]) %% Line 285 <'reparsing_invalid_unicode'> when 'true' -> %% Line 286 [78|[111|[110|[45|[85|[84|[70|[45|[56|[32|[99|[104|[97|[114|[97|[99|[116|[101|[114|[40|[115|[41|[32|[100|[101|[116|[101|[99|[116|[101|[100|[44|[32|[98|[117|[116|[32|[110|[111|[32|[101|[110|[99|[111|[100|[105|[110|[103|[32|[100|[101|[99|[108|[97|[114|[101|[100|[46|[32|[69|[110|[99|[111|[100|[101|[32|[116|[104|[101|[32|[102|[105|[108|[101|[32|[105|[110|[32|[85|[84|[70|[45|[56|[32|[111|[114|[32|[97|[100|[100|[32|[34|[37|[37|[32|[99|[111|[100|[105|[110|[103|[58|[32|[108|[97|[116|[105|[110|[45|[49|[34|[32|[97|[116|[32|[116|[104|[101|[32|[98|[101|[103|[105|[110|[110|[105|[110|[103|[32|[111|[102|[32|[116|[104|[101|[32|[102|[105|[108|[101|[46|[32|[82|[101|[116|[114|[121|[105|[110|[103|[32|[119|[105|[116|[104|[32|[108|[97|[116|[105|[110|[45|[49|[32|[101|[110|[99|[111|[100|[105|[110|[103|[46]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]] ( <_8> when 'true' -> ( primop 'match_fail' ({'function_clause',_8}) -| [{'function_name',{'format_error',1}}] ) -| ['compiler_generated'] ) end end ================================================ FILE: test_data/map_test.core ================================================ module 'maptest' ['module_info'/0, 'module_info'/1, 'test'/0, 'test6'/1, 'test7'/1] attributes [%% Line 1 'file' = %% Line 1 [{[109|[97|[112|[95|[116|[101|[115|[116|[46|[101|[114|[108]]]]]]]]]]]],1}]] 'test'/0 = %% Line 5 fun () -> %% Line 6 ~{'foo'=>'bar','woo'=>[104|[111|[111]]]}~ 'test6'/1 = %% Line 8 fun (_0) -> %% Line 9 case _0 of %% Line 10 <~{{'hoo'}:='true','foo':='bar'}~> when 'true' -> 'lsdlla' %% Line 11 <_3> when 'true' -> 'false' end 'test7'/2 = %% Line 14 fun (_0, _1) -> %% Line 15 case <_0, _1> of %% Line 16 <~{~{'foo'=>'bar'}~:='true'}~, _something> when 'true' -> 'lpsdlas' %% Line 17 <_3, _somethingelse> when 'true' -> apply 'test7'/1 (_0) end 'foo'/0 = %% Line 20 fun () -> 12 'module_info'/0 = fun () -> call 'erlang':'get_module_info' ('maptest') 'module_info'/1 = fun (_0) -> call 'erlang':'get_module_info' ('maptest', _0) end ================================================ FILE: test_data/map_test.erl ================================================ -module(maptest). -export([test/0, test6/1, test7/1]). %-export([test/0, test2/2, test3/2, test4/2]). test() -> #{woo => "hoo", foo => bar}. test6(Woo) -> case Woo of #{ {hoo} := true, foo := bar } -> lsdlla; _ -> false end. test7(Woo, Hoo) -> case of <#{ #{ foo => bar } := true }, _> -> lpsdlas; <_, _> -> test7(Woo, Hoo) end. foo() -> 12. % test2(Woo, Hoo) -> % case Woo of % #{Hoo := true} -> true; % _ -> false % end. % % test3(Woo, Hoo) -> % case Woo of % { Hoo } -> true; % _ -> false % end. % % test4(Woo, Hoo) -> % case Woo of % { Hoo, Foo, Foo } -> true; % _ -> false % end. % % test5(Woo, Hoo) -> % T = {Hoo}, % case Woo of % #{T := true} -> true; % _ -> false % end. ================================================ FILE: test_data/maps.abstr ================================================ {attribute,1,file,{"maps.erl",1}}. {attribute,21,module,maps}. {attribute,23,export, [{get,3}, {filter,2}, {fold,3}, {map,2}, {size,1}, {new,0}, {update_with,3}, {update_with,4}, {without,2}, {with,2}, {iterator,1}, {next,1}]}. {attribute,30,export, [{get,2}, {find,2}, {from_list,1}, {is_key,2}, {keys,1}, {merge,2}, {put,3}, {remove,2}, {take,2}, {to_list,1}, {update,3}, {values,1}]}. {attribute,35,opaque, {iterator, {type,35,union, [{type,35,tuple, [{var,35,'Key'}, {var,35,'Value'}, {user_type,35,iterator,[{var,35,'Key'},{var,35,'Value'}]}]}, {atom,35,none}, {type,36,nonempty_improper_list, [{type,36,integer,[]}, {type,36,map, [{type,36,map_field_assoc, [{var,36,'Key'},{var,36,'Value'}]}]}]}]}, [{var,35,'Key'},{var,35,'Value'}]}}. {attribute,38,type, {iterator,{user_type,38,iterator, [{type,38,term,[]},{type,38,term,[]}]}, []}}. {attribute,40,export_type,[{iterator,2},{iterator,0}]}. {attribute,42,dialyzer,{no_improper_lists,{iterator,1}}}. {attribute,47,spec, {{get,2}, [{type,47,bounded_fun, [{type,47,'fun', [{type,47,product,[{var,47,'Key'},{var,47,'Map'}]}, {var,47,'Value'}]}, [{type,48,constraint, [{atom,48,is_subtype}, [{var,48,'Key'},{type,48,term,[]}]]}, {type,49,constraint, [{atom,49,is_subtype}, [{var,49,'Map'},{type,49,map,any}]]}, {type,50,constraint, [{atom,50,is_subtype}, [{var,50,'Value'},{type,50,term,[]}]]}]]}]}}. {function,52,get,2, [{clause,52, [{var,52,'_'},{var,52,'_'}], [], [{call,52, {remote,52,{atom,52,erlang},{atom,52,nif_error}}, [{atom,52,undef}]}]}]}. {attribute,54,spec, {{find,2}, [{type,54,bounded_fun, [{type,54,'fun', [{type,54,product,[{var,54,'Key'},{var,54,'Map'}]}, {type,54,union, [{type,54,tuple,[{atom,54,ok},{var,54,'Value'}]}, {atom,54,error}]}]}, [{type,55,constraint, [{atom,55,is_subtype}, [{var,55,'Map'}, {type,55,map, [{type,55,map_field_assoc, [{var,55,'Key'},{var,55,'Value'}]}, {type,55,map_field_assoc, [{var,55,'_'},{var,55,'_'}]}]}]]}]]}]}}. {function,57,find,2, [{clause,57, [{var,57,'_'},{var,57,'_'}], [], [{call,57, {remote,57,{atom,57,erlang},{atom,57,nif_error}}, [{atom,57,undef}]}]}]}. {attribute,60,spec, {{from_list,1}, [{type,60,bounded_fun, [{type,60,'fun', [{type,60,product,[{var,60,'List'}]},{var,60,'Map'}]}, [{type,61,constraint, [{atom,61,is_subtype}, [{var,61,'List'}, {type,61,list, [{type,61,tuple,[{var,61,'Key'},{var,61,'Value'}]}]}]]}, {type,62,constraint, [{atom,62,is_subtype},[{var,62,'Key'},{type,62,term,[]}]]}, {type,63,constraint, [{atom,63,is_subtype},[{var,63,'Value'},{type,63,term,[]}]]}, {type,64,constraint, [{atom,64,is_subtype}, [{var,64,'Map'},{type,64,map,any}]]}]]}]}}. {function,66,from_list,1, [{clause,66, [{var,66,'_'}], [], [{call,66, {remote,66,{atom,66,erlang},{atom,66,nif_error}}, [{atom,66,undef}]}]}]}. {attribute,70,spec, {{is_key,2}, [{type,70,bounded_fun, [{type,70,'fun', [{type,70,product,[{var,70,'Key'},{var,70,'Map'}]}, {type,70,boolean,[]}]}, [{type,71,constraint, [{atom,71,is_subtype}, [{var,71,'Key'},{type,71,term,[]}]]}, {type,72,constraint, [{atom,72,is_subtype}, [{var,72,'Map'},{type,72,map,any}]]}]]}]}}. {function,74,is_key,2, [{clause,74, [{var,74,'_'},{var,74,'_'}], [], [{call,74, {remote,74,{atom,74,erlang},{atom,74,nif_error}}, [{atom,74,undef}]}]}]}. {attribute,77,spec, {{keys,1}, [{type,77,bounded_fun, [{type,77,'fun', [{type,77,product,[{var,77,'Map'}]},{var,77,'Keys'}]}, [{type,78,constraint, [{atom,78,is_subtype}, [{var,78,'Map'}, {type,78,map, [{type,78,map_field_assoc, [{var,78,'Key'},{var,78,'_'}]}]}]]}, {type,79,constraint, [{atom,79,is_subtype}, [{var,79,'Keys'},{type,79,list,[{var,79,'Key'}]}]]}]]}]}}. {function,81,keys,1, [{clause,81, [{var,81,'_'}], [], [{call,81, {remote,81,{atom,81,erlang},{atom,81,nif_error}}, [{atom,81,undef}]}]}]}. {attribute,85,spec, {{merge,2}, [{type,85,bounded_fun, [{type,85,'fun', [{type,85,product,[{var,85,'Map1'},{var,85,'Map2'}]}, {var,85,'Map3'}]}, [{type,86,constraint, [{atom,86,is_subtype}, [{var,86,'Map1'},{type,86,map,any}]]}, {type,87,constraint, [{atom,87,is_subtype}, [{var,87,'Map2'},{type,87,map,any}]]}, {type,88,constraint, [{atom,88,is_subtype}, [{var,88,'Map3'},{type,88,map,any}]]}]]}]}}. {function,90,merge,2, [{clause,90, [{var,90,'_'},{var,90,'_'}], [], [{call,90, {remote,90,{atom,90,erlang},{atom,90,nif_error}}, [{atom,90,undef}]}]}]}. {attribute,94,spec, {{put,3}, [{type,94,bounded_fun, [{type,94,'fun', [{type,94,product, [{var,94,'Key'}, {var,94,'Value'}, {var,94,'Map1'}]}, {var,94,'Map2'}]}, [{type,95,constraint, [{atom,95,is_subtype}, [{var,95,'Key'},{type,95,term,[]}]]}, {type,96,constraint, [{atom,96,is_subtype}, [{var,96,'Value'},{type,96,term,[]}]]}, {type,97,constraint, [{atom,97,is_subtype}, [{var,97,'Map1'},{type,97,map,any}]]}, {type,98,constraint, [{atom,98,is_subtype}, [{var,98,'Map2'},{type,98,map,any}]]}]]}]}}. {function,100,put,3, [{clause,100, [{var,100,'_'},{var,100,'_'},{var,100,'_'}], [], [{call,100, {remote,100,{atom,100,erlang},{atom,100,nif_error}}, [{atom,100,undef}]}]}]}. {attribute,104,spec, {{remove,2}, [{type,104,bounded_fun, [{type,104,'fun', [{type,104,product, [{var,104,'Key'},{var,104,'Map1'}]}, {var,104,'Map2'}]}, [{type,105,constraint, [{atom,105,is_subtype}, [{var,105,'Key'},{type,105,term,[]}]]}, {type,106,constraint, [{atom,106,is_subtype}, [{var,106,'Map1'},{type,106,map,any}]]}, {type,107,constraint, [{atom,107,is_subtype}, [{var,107,'Map2'},{type,107,map,any}]]}]]}]}}. {function,109,remove,2, [{clause,109, [{var,109,'_'},{var,109,'_'}], [], [{call,109, {remote,109,{atom,109,erlang},{atom,109,nif_error}}, [{atom,109,undef}]}]}]}. {attribute,111,spec, {{take,2}, [{type,111,bounded_fun, [{type,111,'fun', [{type,111,product,[{var,111,'Key'},{var,111,'Map1'}]}, {type,111,union, [{type,111,tuple,[{var,111,'Value'},{var,111,'Map2'}]}, {atom,111,error}]}]}, [{type,112,constraint, [{atom,112,is_subtype}, [{var,112,'Map1'}, {type,112,map, [{type,112,map_field_assoc, [{var,112,'Key'},{var,112,'Value'}]}, {type,112,map_field_assoc, [{var,112,'_'},{var,112,'_'}]}]}]]}, {type,113,constraint, [{atom,113,is_subtype}, [{var,113,'Map2'}, {type,113,map, [{type,113,map_field_assoc, [{var,113,'_'},{var,113,'_'}]}]}]]}]]}]}}. {function,115,take,2, [{clause,115, [{var,115,'_'},{var,115,'_'}], [], [{call,115, {remote,115,{atom,115,erlang},{atom,115,nif_error}}, [{atom,115,undef}]}]}]}. {attribute,117,spec, {{to_list,1}, [{type,117,bounded_fun, [{type,117,'fun', [{type,117,product,[{var,117,'Map'}]}, {type,117,list, [{type,117,tuple,[{var,117,'Key'},{var,117,'Value'}]}]}]}, [{type,118,constraint, [{atom,118,is_subtype}, [{var,118,'Map'}, {type,118,map, [{type,118,map_field_assoc, [{var,118,'Key'},{var,118,'Value'}]}]}]]}]]}]}}. {function,120,to_list,1, [{clause,120, [{var,120,'Map'}], [[{call,120,{atom,120,is_map},[{var,120,'Map'}]}]], [{call,121, {atom,121,to_list_internal}, [{call,121, {remote,121,{atom,121,erts_internal},{atom,121,map_next}}, [{integer,121,0},{var,121,'Map'},{nil,121}]}]}]}, {clause,122, [{var,122,'Map'}], [], [{call,123, {remote,123,{atom,123,erlang},{atom,123,error}}, [{tuple,123,[{atom,123,badmap},{var,123,'Map'}]}, {cons,123,{var,123,'Map'},{nil,123}}]}]}]}. {function,125,to_list_internal,1, [{clause,125, [{cons,125, {var,125,'Iter'}, {cons,125,{var,125,'Map'},{var,125,'Acc'}}}], [[{call,125,{atom,125,is_integer},[{var,125,'Iter'}]}]], [{call,126, {atom,126,to_list_internal}, [{call,126, {remote,126,{atom,126,erts_internal},{atom,126,map_next}}, [{var,126,'Iter'},{var,126,'Map'},{var,126,'Acc'}]}]}]}, {clause,127,[{var,127,'Acc'}],[],[{var,128,'Acc'}]}]}. {attribute,131,spec, {{update,3}, [{type,131,bounded_fun, [{type,131,'fun', [{type,131,product, [{var,131,'Key'},{var,131,'Value'},{var,131,'Map1'}]}, {var,131,'Map2'}]}, [{type,132,constraint, [{atom,132,is_subtype}, [{var,132,'Map1'}, {type,132,map, [{type,132,map_field_exact, [{var,132,'Key'},{var,132,'_'}]}, {type,132,map_field_assoc, [{var,132,'_'},{var,132,'_'}]}]}]]}, {type,133,constraint, [{atom,133,is_subtype}, [{var,133,'Map2'}, {type,133,map, [{type,133,map_field_exact, [{var,133,'Key'},{var,133,'Value'}]}, {type,133,map_field_assoc, [{var,133,'_'},{var,133,'_'}]}]}]]}]]}]}}. {function,135,update,3, [{clause,135, [{var,135,'_'},{var,135,'_'},{var,135,'_'}], [], [{call,135, {remote,135,{atom,135,erlang},{atom,135,nif_error}}, [{atom,135,undef}]}]}]}. {attribute,138,spec, {{values,1}, [{type,138,bounded_fun, [{type,138,'fun', [{type,138,product,[{var,138,'Map'}]},{var,138,'Values'}]}, [{type,139,constraint, [{atom,139,is_subtype}, [{var,139,'Map'}, {type,139,map, [{type,139,map_field_assoc, [{var,139,'_'},{var,139,'Value'}]}]}]]}, {type,140,constraint, [{atom,140,is_subtype}, [{var,140,'Values'}, {type,140,list,[{var,140,'Value'}]}]]}]]}]}}. {function,142,values,1, [{clause,142, [{var,142,'_'}], [], [{call,142, {remote,142,{atom,142,erlang},{atom,142,nif_error}}, [{atom,142,undef}]}]}]}. {attribute,146,spec, {{new,0}, [{type,146,bounded_fun, [{type,146,'fun',[{type,146,product,[]},{var,146,'Map'}]}, [{type,147,constraint, [{atom,147,is_subtype}, [{var,147,'Map'},{type,147,map,[]}]]}]]}]}}. {function,149,new,0,[{clause,149,[],[],[{map,149,[]}]}]}. {attribute,151,spec, {{update_with,3}, [{type,151,bounded_fun, [{type,151,'fun', [{type,151,product, [{var,151,'Key'},{var,151,'Fun'},{var,151,'Map1'}]}, {var,151,'Map2'}]}, [{type,152,constraint, [{atom,152,is_subtype}, [{var,152,'Map1'}, {type,152,map, [{type,152,map_field_exact, [{var,152,'Key'},{var,152,'Value1'}]}, {type,152,map_field_assoc, [{var,152,'_'},{var,152,'_'}]}]}]]}, {type,153,constraint, [{atom,153,is_subtype}, [{var,153,'Map2'}, {type,153,map, [{type,153,map_field_exact, [{var,153,'Key'},{var,153,'Value2'}]}, {type,153,map_field_assoc, [{var,153,'_'},{var,153,'_'}]}]}]]}, {type,154,constraint, [{atom,154,is_subtype}, [{var,154,'Fun'}, {type,154,'fun', [{type,154,product,[{var,154,'Value1'}]}, {var,154,'Value2'}]}]]}]]}]}}. {function,156,update_with,3, [{clause,156, [{var,156,'Key'},{var,156,'Fun'},{var,156,'Map'}], [[{call,156,{atom,156,is_function},[{var,156,'Fun'},{integer,156,1}]}, {call,156,{atom,156,is_map},[{var,156,'Map'}]}]], [{'case',157, {var,157,'Map'}, [{clause,158, [{map,158, [{map_field_exact,158, {var,158,'Key'}, {var,158,'Value'}}]}], [], [{map,158, {var,158,'Map'}, [{map_field_exact,158, {var,158,'Key'}, {call,158, {var,158,'Fun'}, [{var,158,'Value'}]}}]}]}, {clause,159, [{map,159,[]}], [], [{call,159, {remote,159,{atom,159,erlang},{atom,159,error}}, [{tuple,159,[{atom,159,badkey},{var,159,'Key'}]}, {cons,159, {var,159,'Key'}, {cons,159, {var,159,'Fun'}, {cons,159, {var,159,'Map'}, {nil,159}}}}]}]}]}]}, {clause,161, [{var,161,'Key'},{var,161,'Fun'},{var,161,'Map'}], [], [{call,162, {remote,162,{atom,162,erlang},{atom,162,error}}, [{call,162,{atom,162,error_type},[{var,162,'Map'}]}, {cons,162, {var,162,'Key'}, {cons,162, {var,162,'Fun'}, {cons,162,{var,162,'Map'},{nil,162}}}}]}]}]}. {attribute,165,spec, {{update_with,4}, [{type,165,bounded_fun, [{type,165,'fun', [{type,165,product, [{var,165,'Key'}, {var,165,'Fun'}, {var,165,'Init'}, {var,165,'Map1'}]}, {var,165,'Map2'}]}, [{type,166,constraint, [{atom,166,is_subtype}, [{var,166,'Map1'}, {type,166,map, [{type,166,map_field_assoc, [{var,166,'Key'},{var,166,'Value1'}]}, {type,166,map_field_assoc, [{var,166,'_'},{var,166,'_'}]}]}]]}, {type,167,constraint, [{atom,167,is_subtype}, [{var,167,'Map2'}, {type,167,map, [{type,167,map_field_exact, [{var,167,'Key'}, {type,167,union, [{var,167,'Value2'},{var,167,'Init'}]}]}, {type,167,map_field_assoc, [{var,167,'_'},{var,167,'_'}]}]}]]}, {type,168,constraint, [{atom,168,is_subtype}, [{var,168,'Fun'}, {type,168,'fun', [{type,168,product,[{var,168,'Value1'}]}, {var,168,'Value2'}]}]]}]]}]}}. {function,170,update_with,4, [{clause,170, [{var,170,'Key'},{var,170,'Fun'},{var,170,'Init'},{var,170,'Map'}], [[{call,170,{atom,170,is_function},[{var,170,'Fun'},{integer,170,1}]}, {call,170,{atom,170,is_map},[{var,170,'Map'}]}]], [{'case',171, {var,171,'Map'}, [{clause,172, [{map,172, [{map_field_exact,172, {var,172,'Key'}, {var,172,'Value'}}]}], [], [{map,172, {var,172,'Map'}, [{map_field_exact,172, {var,172,'Key'}, {call,172, {var,172,'Fun'}, [{var,172,'Value'}]}}]}]}, {clause,173, [{map,173,[]}], [], [{map,173, {var,173,'Map'}, [{map_field_assoc,173, {var,173,'Key'}, {var,173,'Init'}}]}]}]}]}, {clause,175, [{var,175,'Key'},{var,175,'Fun'},{var,175,'Init'},{var,175,'Map'}], [], [{call,176, {remote,176,{atom,176,erlang},{atom,176,error}}, [{call,176,{atom,176,error_type},[{var,176,'Map'}]}, {cons,176, {var,176,'Key'}, {cons,176, {var,176,'Fun'}, {cons,176, {var,176,'Init'}, {cons,176,{var,176,'Map'},{nil,176}}}}}]}]}]}. {attribute,179,spec, {{get,3}, [{type,179,bounded_fun, [{type,179,'fun', [{type,179,product, [{var,179,'Key'},{var,179,'Map'},{var,179,'Default'}]}, {type,179,union,[{var,179,'Value'},{var,179,'Default'}]}]}, [{type,180,constraint, [{atom,180,is_subtype}, [{var,180,'Map'}, {type,180,map, [{type,180,map_field_assoc, [{var,180,'Key'},{var,180,'Value'}]}, {type,180,map_field_assoc, [{var,180,'_'},{var,180,'_'}]}]}]]}]]}]}}. {function,182,get,3, [{clause,182, [{var,182,'Key'},{var,182,'Map'},{var,182,'Default'}], [[{call,182,{atom,182,is_map},[{var,182,'Map'}]}]], [{'case',183, {var,183,'Map'}, [{clause,184, [{map,184, [{map_field_exact,184, {var,184,'Key'}, {var,184,'Value'}}]}], [], [{var,184,'Value'}]}, {clause,185,[{map,185,[]}],[],[{var,185,'Default'}]}]}]}, {clause,187, [{var,187,'Key'},{var,187,'Map'},{var,187,'Default'}], [], [{call,188, {remote,188,{atom,188,erlang},{atom,188,error}}, [{tuple,188,[{atom,188,badmap},{var,188,'Map'}]}, {cons,188, {var,188,'Key'}, {cons,188, {var,188,'Map'}, {cons,188,{var,188,'Default'},{nil,188}}}}]}]}]}. {attribute,191,spec, {{filter,2}, [{type,191,bounded_fun, [{type,191,'fun', [{type,191,product,[{var,191,'Pred'},{var,191,'MapOrIter'}]}, {var,191,'Map'}]}, [{type,192,constraint, [{atom,192,is_subtype}, [{var,192,'Pred'}, {type,192,'fun', [{type,192,product,[{var,192,'Key'},{var,192,'Value'}]}, {type,192,boolean,[]}]}]]}, {type,193,constraint, [{atom,193,is_subtype}, [{var,193,'MapOrIter'}, {type,193,union, [{type,193,map, [{type,193,map_field_assoc, [{var,193,'Key'},{var,193,'Value'}]}]}, {user_type,193,iterator, [{var,193,'Key'},{var,193,'Value'}]}]}]]}, {type,194,constraint, [{atom,194,is_subtype}, [{var,194,'Map'}, {type,194,map, [{type,194,map_field_assoc, [{var,194,'Key'},{var,194,'Value'}]}]}]]}]]}]}}. {function,196,filter,2, [{clause,196, [{var,196,'Pred'},{var,196,'Map'}], [[{call,196, {atom,196,is_function}, [{var,196,'Pred'},{integer,196,2}]}, {call,196,{atom,196,is_map},[{var,196,'Map'}]}]], [{call,197, {remote,197,{atom,197,maps},{atom,197,from_list}}, [{call,197, {atom,197,filter_1}, [{var,197,'Pred'}, {call,197,{atom,197,iterator},[{var,197,'Map'}]}]}]}]}, {clause,198, [{var,198,'Pred'},{var,198,'Iterator'}], [[{call,198, {atom,198,is_function}, [{var,198,'Pred'},{integer,198,2}]}, {op,198,'andalso', {call,198,{atom,198,is_tuple},[{var,198,'Iterator'}]}, {op,198,'==', {call,198,{atom,198,tuple_size},[{var,198,'Iterator'}]}, {integer,198,3}}}], [{op,198,'==',{var,198,'Iterator'},{atom,198,none}}], [{op,198,'andalso', {call,198, {atom,198,is_integer}, [{call,198,{atom,198,hd},[{var,198,'Iterator'}]}]}, {call,198, {atom,198,is_map}, [{call,198,{atom,198,tl},[{var,198,'Iterator'}]}]}}]], [{call,199, {remote,199,{atom,199,maps},{atom,199,from_list}}, [{call,199, {atom,199,filter_1}, [{var,199,'Pred'},{var,199,'Iterator'}]}]}]}, {clause,200, [{var,200,'Pred'},{var,200,'Map'}], [], [{call,201, {remote,201,{atom,201,erlang},{atom,201,error}}, [{call,201,{atom,201,error_type},[{var,201,'Map'}]}, {cons,201, {var,201,'Pred'}, {cons,201,{var,201,'Map'},{nil,201}}}]}]}]}. {function,203,filter_1,2, [{clause,203, [{var,203,'Pred'},{var,203,'Iter'}], [], [{'case',204, {call,204,{atom,204,next},[{var,204,'Iter'}]}, [{clause,205, [{tuple,205, [{var,205,'K'},{var,205,'V'},{var,205,'NextIter'}]}], [], [{'case',206, {call,206, {var,206,'Pred'}, [{var,206,'K'},{var,206,'V'}]}, [{clause,207, [{atom,207,true}], [], [{cons,208, {tuple,208,[{var,208,'K'},{var,208,'V'}]}, {call,208, {atom,208,filter_1}, [{var,208,'Pred'}, {var,208,'NextIter'}]}}]}, {clause,209, [{atom,209,false}], [], [{call,210, {atom,210,filter_1}, [{var,210,'Pred'}, {var,210,'NextIter'}]}]}]}]}, {clause,212,[{atom,212,none}],[],[{nil,213}]}]}]}]}. {attribute,216,spec, {{fold,3}, [{type,216,bounded_fun, [{type,216,'fun', [{type,216,product, [{var,216,'Fun'},{var,216,'Init'},{var,216,'MapOrIter'}]}, {var,216,'Acc'}]}, [{type,217,constraint, [{atom,217,is_subtype}, [{var,217,'Fun'}, {type,217,'fun', [{type,217,product, [{var,217,'Key'}, {var,217,'Value'}, {var,217,'AccIn'}]}, {var,217,'AccOut'}]}]]}, {type,218,constraint, [{atom,218,is_subtype},[{var,218,'Init'},{type,218,term,[]}]]}, {type,219,constraint, [{atom,219,is_subtype},[{var,219,'Acc'},{var,219,'AccOut'}]]}, {type,220,constraint, [{atom,220,is_subtype}, [{var,220,'AccIn'}, {type,220,union,[{var,220,'Init'},{var,220,'AccOut'}]}]]}, {type,221,constraint, [{atom,221,is_subtype}, [{var,221,'MapOrIter'}, {type,221,union, [{type,221,map, [{type,221,map_field_assoc, [{var,221,'Key'},{var,221,'Value'}]}]}, {user_type,221,iterator, [{var,221,'Key'},{var,221,'Value'}]}]}]]}]]}]}}. {function,223,fold,3, [{clause,223, [{var,223,'Fun'},{var,223,'Init'},{var,223,'Map'}], [[{call,223,{atom,223,is_function},[{var,223,'Fun'},{integer,223,3}]}, {call,223,{atom,223,is_map},[{var,223,'Map'}]}]], [{call,224, {atom,224,fold_1}, [{var,224,'Fun'}, {var,224,'Init'}, {call,224,{atom,224,iterator},[{var,224,'Map'}]}]}]}, {clause,225, [{var,225,'Fun'},{var,225,'Init'},{var,225,'Iterator'}], [[{call,225,{atom,225,is_function},[{var,225,'Fun'},{integer,225,3}]}, {op,225,'andalso', {call,225,{atom,225,is_tuple},[{var,225,'Iterator'}]}, {op,225,'==', {call,225,{atom,225,tuple_size},[{var,225,'Iterator'}]}, {integer,225,3}}}], [{op,225,'==',{var,225,'Iterator'},{atom,225,none}}], [{op,225,'andalso', {call,225, {atom,225,is_integer}, [{call,225,{atom,225,hd},[{var,225,'Iterator'}]}]}, {call,225, {atom,225,is_map}, [{call,225,{atom,225,tl},[{var,225,'Iterator'}]}]}}]], [{call,226, {atom,226,fold_1}, [{var,226,'Fun'},{var,226,'Init'},{var,226,'Iterator'}]}]}, {clause,227, [{var,227,'Fun'},{var,227,'Init'},{var,227,'Map'}], [], [{call,228, {remote,228,{atom,228,erlang},{atom,228,error}}, [{call,228,{atom,228,error_type_iter},[{var,228,'Map'}]}, {cons,228, {var,228,'Fun'}, {cons,228, {var,228,'Init'}, {cons,228,{var,228,'Map'},{nil,228}}}}]}]}]}. {function,230,fold_1,3, [{clause,230, [{var,230,'Fun'},{var,230,'Acc'},{var,230,'Iter'}], [], [{'case',231, {call,231,{atom,231,next},[{var,231,'Iter'}]}, [{clause,232, [{tuple,232, [{var,232,'K'},{var,232,'V'},{var,232,'NextIter'}]}], [], [{call,233, {atom,233,fold_1}, [{var,233,'Fun'}, {call,233, {var,233,'Fun'}, [{var,233,'K'},{var,233,'V'},{var,233,'Acc'}]}, {var,233,'NextIter'}]}]}, {clause,234,[{atom,234,none}],[],[{var,235,'Acc'}]}]}]}]}. {attribute,238,spec, {{map,2}, [{type,238,bounded_fun, [{type,238,'fun', [{type,238,product,[{var,238,'Fun'},{var,238,'MapOrIter'}]}, {var,238,'Map'}]}, [{type,239,constraint, [{atom,239,is_subtype}, [{var,239,'Fun'}, {type,239,'fun', [{type,239,product,[{var,239,'Key'},{var,239,'Value1'}]}, {var,239,'Value2'}]}]]}, {type,240,constraint, [{atom,240,is_subtype}, [{var,240,'MapOrIter'}, {type,240,union, [{type,240,map, [{type,240,map_field_assoc, [{var,240,'Key'},{var,240,'Value1'}]}]}, {user_type,240,iterator, [{var,240,'Key'},{var,240,'Value1'}]}]}]]}, {type,241,constraint, [{atom,241,is_subtype}, [{var,241,'Map'}, {type,241,map, [{type,241,map_field_assoc, [{var,241,'Key'},{var,241,'Value2'}]}]}]]}]]}]}}. {function,243,map,2, [{clause,243, [{var,243,'Fun'},{var,243,'Map'}], [[{call,243,{atom,243,is_function},[{var,243,'Fun'},{integer,243,2}]}, {call,243,{atom,243,is_map},[{var,243,'Map'}]}]], [{call,244, {remote,244,{atom,244,maps},{atom,244,from_list}}, [{call,244, {atom,244,map_1}, [{var,244,'Fun'}, {call,244,{atom,244,iterator},[{var,244,'Map'}]}]}]}]}, {clause,245, [{var,245,'Fun'},{var,245,'Iterator'}], [[{call,245,{atom,245,is_function},[{var,245,'Fun'},{integer,245,2}]}, {op,245,'andalso', {call,245,{atom,245,is_tuple},[{var,245,'Iterator'}]}, {op,245,'==', {call,245,{atom,245,tuple_size},[{var,245,'Iterator'}]}, {integer,245,3}}}], [{op,245,'==',{var,245,'Iterator'},{atom,245,none}}], [{op,245,'andalso', {call,245, {atom,245,is_integer}, [{call,245,{atom,245,hd},[{var,245,'Iterator'}]}]}, {call,245, {atom,245,is_map}, [{call,245,{atom,245,tl},[{var,245,'Iterator'}]}]}}]], [{call,246, {remote,246,{atom,246,maps},{atom,246,from_list}}, [{call,246, {atom,246,map_1}, [{var,246,'Fun'},{var,246,'Iterator'}]}]}]}, {clause,247, [{var,247,'Fun'},{var,247,'Map'}], [], [{call,248, {remote,248,{atom,248,erlang},{atom,248,error}}, [{call,248,{atom,248,error_type_iter},[{var,248,'Map'}]}, {cons,248, {var,248,'Fun'}, {cons,248,{var,248,'Map'},{nil,248}}}]}]}]}. {function,250,map_1,2, [{clause,250, [{var,250,'Fun'},{var,250,'Iter'}], [], [{'case',251, {call,251,{atom,251,next},[{var,251,'Iter'}]}, [{clause,252, [{tuple,252, [{var,252,'K'},{var,252,'V'},{var,252,'NextIter'}]}], [], [{cons,253, {tuple,253, [{var,253,'K'}, {call,253, {var,253,'Fun'}, [{var,253,'K'},{var,253,'V'}]}]}, {call,253, {atom,253,map_1}, [{var,253,'Fun'},{var,253,'NextIter'}]}}]}, {clause,254,[{atom,254,none}],[],[{nil,255}]}]}]}]}. {attribute,258,spec, {{size,1}, [{type,258,bounded_fun, [{type,258,'fun', [{type,258,product,[{var,258,'Map'}]}, {type,258,non_neg_integer,[]}]}, [{type,259,constraint, [{atom,259,is_subtype}, [{var,259,'Map'},{type,259,map,any}]]}]]}]}}. {function,261,size,1, [{clause,261, [{var,261,'Map'}], [[{call,261,{atom,261,is_map},[{var,261,'Map'}]}]], [{call,262, {remote,262,{atom,262,erlang},{atom,262,map_size}}, [{var,262,'Map'}]}]}, {clause,263, [{var,263,'Val'}], [], [{call,264, {remote,264,{atom,264,erlang},{atom,264,error}}, [{tuple,264,[{atom,264,badmap},{var,264,'Val'}]}, {cons,264,{var,264,'Val'},{nil,264}}]}]}]}. {attribute,266,spec, {{iterator,1}, [{type,266,bounded_fun, [{type,266,'fun', [{type,266,product,[{var,266,'Map'}]},{var,266,'Iterator'}]}, [{type,267,constraint, [{atom,267,is_subtype}, [{var,267,'Map'}, {type,267,map, [{type,267,map_field_assoc, [{var,267,'Key'},{var,267,'Value'}]}]}]]}, {type,268,constraint, [{atom,268,is_subtype}, [{var,268,'Iterator'}, {user_type,268,iterator, [{var,268,'Key'},{var,268,'Value'}]}]]}]]}]}}. {function,270,iterator,1, [{clause,270, [{var,270,'M'}], [[{call,270,{atom,270,is_map},[{var,270,'M'}]}]], [{cons,270,{integer,270,0},{var,270,'M'}}]}, {clause,271, [{var,271,'M'}], [], [{call,271, {remote,271,{atom,271,erlang},{atom,271,error}}, [{tuple,271,[{atom,271,badmap},{var,271,'M'}]}, {cons,271,{var,271,'M'},{nil,271}}]}]}]}. {attribute,273,spec, {{next,1}, [{type,273,bounded_fun, [{type,273,'fun', [{type,273,product,[{var,273,'Iterator'}]}, {type,273,union, [{type,273,tuple, [{var,273,'Key'}, {var,273,'Value'}, {var,273,'NextIterator'}]}, {atom,273,none}]}]}, [{type,274,constraint, [{atom,274,is_subtype}, [{var,274,'Iterator'}, {user_type,274,iterator, [{var,274,'Key'},{var,274,'Value'}]}]]}, {type,275,constraint, [{atom,275,is_subtype}, [{var,275,'NextIterator'}, {user_type,275,iterator, [{var,275,'Key'},{var,275,'Value'}]}]]}]]}]}}. {function,276,next,1, [{clause,276, [{tuple,276,[{var,276,'K'},{var,276,'V'},{var,276,'I'}]}], [], [{tuple,277,[{var,277,'K'},{var,277,'V'},{var,277,'I'}]}]}, {clause,278, [{cons,278,{var,278,'Path'},{var,278,'Map'}}], [[{call,278,{atom,278,is_integer},[{var,278,'Path'}]}, {call,278,{atom,278,is_map},[{var,278,'Map'}]}]], [{call,279, {remote,279, {atom,279,erts_internal}, {atom,279,map_next}}, [{var,279,'Path'}, {var,279,'Map'}, {atom,279,iterator}]}]}, {clause,280,[{atom,280,none}],[],[{atom,281,none}]}, {clause,282, [{var,282,'Iter'}], [], [{call,283, {remote,283,{atom,283,erlang},{atom,283,error}}, [{atom,283,badarg}, {cons,283,{var,283,'Iter'},{nil,283}}]}]}]}. {attribute,285,spec, {{without,2}, [{type,285,bounded_fun, [{type,285,'fun', [{type,285,product, [{var,285,'Ks'},{var,285,'Map1'}]}, {var,285,'Map2'}]}, [{type,286,constraint, [{atom,286,is_subtype}, [{var,286,'Ks'},{type,286,list,[{var,286,'K'}]}]]}, {type,287,constraint, [{atom,287,is_subtype}, [{var,287,'Map1'},{type,287,map,any}]]}, {type,288,constraint, [{atom,288,is_subtype}, [{var,288,'Map2'},{type,288,map,any}]]}, {type,289,constraint, [{atom,289,is_subtype}, [{var,289,'K'},{type,289,term,[]}]]}]]}]}}. {function,291,without,2, [{clause,291, [{var,291,'Ks'},{var,291,'M'}], [[{call,291,{atom,291,is_list},[{var,291,'Ks'}]}, {call,291,{atom,291,is_map},[{var,291,'M'}]}]], [{call,292, {remote,292,{atom,292,lists},{atom,292,foldl}}, [{'fun',292, {function, {atom,292,maps}, {atom,292,remove}, {integer,292,2}}}, {var,292,'M'}, {var,292,'Ks'}]}]}, {clause,293, [{var,293,'Ks'},{var,293,'M'}], [], [{call,294, {remote,294,{atom,294,erlang},{atom,294,error}}, [{call,294,{atom,294,error_type},[{var,294,'M'}]}, {cons,294, {var,294,'Ks'}, {cons,294,{var,294,'M'},{nil,294}}}]}]}]}. {attribute,296,spec, {{with,2}, [{type,296,bounded_fun, [{type,296,'fun', [{type,296,product,[{var,296,'Ks'},{var,296,'Map1'}]}, {var,296,'Map2'}]}, [{type,297,constraint, [{atom,297,is_subtype}, [{var,297,'Ks'},{type,297,list,[{var,297,'K'}]}]]}, {type,298,constraint, [{atom,298,is_subtype}, [{var,298,'Map1'}, {type,298,map, [{type,298,map_field_assoc, [{var,298,'K'},{var,298,'V'}]}, {type,298,map_field_assoc, [{var,298,'_'},{var,298,'_'}]}]}]]}, {type,299,constraint, [{atom,299,is_subtype}, [{var,299,'Map2'}, {type,299,map, [{type,299,map_field_assoc, [{var,299,'K'},{var,299,'V'}]}]}]]}]]}]}}. {function,301,with,2, [{clause,301, [{var,301,'Ks'},{var,301,'Map1'}], [[{call,301,{atom,301,is_list},[{var,301,'Ks'}]}, {call,301,{atom,301,is_map},[{var,301,'Map1'}]}]], [{call,302, {remote,302,{atom,302,maps},{atom,302,from_list}}, [{call,302, {atom,302,with_1}, [{var,302,'Ks'},{var,302,'Map1'}]}]}]}, {clause,303, [{var,303,'Ks'},{var,303,'M'}], [], [{call,304, {remote,304,{atom,304,erlang},{atom,304,error}}, [{call,304,{atom,304,error_type},[{var,304,'M'}]}, {cons,304, {var,304,'Ks'}, {cons,304,{var,304,'M'},{nil,304}}}]}]}]}. {function,306,with_1,2, [{clause,306, [{cons,306,{var,306,'K'},{var,306,'Ks'}},{var,306,'Map'}], [], [{'case',307, {var,307,'Map'}, [{clause,308, [{map,308, [{map_field_exact,308,{var,308,'K'},{var,308,'V'}}]}], [], [{cons,308, {tuple,308,[{var,308,'K'},{var,308,'V'}]}, {call,308, {atom,308,with_1}, [{var,308,'Ks'},{var,308,'Map'}]}}]}, {clause,309, [{map,309,[]}], [], [{call,309, {atom,309,with_1}, [{var,309,'Ks'},{var,309,'Map'}]}]}]}]}, {clause,311,[{nil,311},{var,311,'_Map'}],[],[{nil,311}]}]}. {function,313,error_type,1, [{clause,313, [{var,313,'M'}], [[{call,313,{atom,313,is_map},[{var,313,'M'}]}]], [{atom,313,badarg}]}, {clause,314, [{var,314,'V'}], [], [{tuple,314,[{atom,314,badmap},{var,314,'V'}]}]}]}. {function,316,error_type_iter,1, [{clause,316, [{var,316,'M'}], [[{call,316,{atom,316,is_map},[{var,316,'M'}]}], [{op,316,'andalso', {call,316,{atom,316,is_tuple},[{var,316,'M'}]}, {op,316,'==', {call,316,{atom,316,tuple_size},[{var,316,'M'}]}, {integer,316,3}}}], [{op,316,'==',{var,316,'M'},{atom,316,none}}], [{op,316,'andalso', {call,316, {atom,316,is_integer}, [{call,316,{atom,316,hd},[{var,316,'M'}]}]}, {call,316, {atom,316,is_map}, [{call,316,{atom,316,tl},[{var,316,'M'}]}]}}]], [{atom,316,badarg}]}, {clause,317, [{var,317,'V'}], [], [{tuple,317,[{atom,317,badmap},{var,317,'V'}]}]}]}. {eof,318}. ================================================ FILE: test_data/maps.erl ================================================ %% %% %CopyrightBegin% %% %% Copyright Ericsson AB 2013-2019. All Rights Reserved. %% %% 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. %% %% %CopyrightEnd% %% -module(maps). -export([get/3, filter/2,fold/3, map/2, size/1, new/0, update_with/3, update_with/4, without/2, with/2, iterator/1, next/1]). %% BIFs -export([get/2, find/2, from_list/1, is_key/2, keys/1, merge/2, put/3, remove/2, take/2, to_list/1, update/3, values/1]). -opaque iterator(Key, Value) :: {Key, Value, iterator(Key, Value)} | none | nonempty_improper_list(integer(), #{Key => Value}). -type iterator() :: iterator(term(), term()). -export_type([iterator/2, iterator/0]). -dialyzer({no_improper_lists, iterator/1}). -define(IS_ITERATOR(I), is_tuple(I) andalso tuple_size(I) == 3; I == none; is_integer(hd(I)) andalso is_map(tl(I))). %% Shadowed by erl_bif_types: maps:get/2 -spec get(Key,Map) -> Value when Key :: term(), Map :: map(), Value :: term(). get(_,_) -> erlang:nif_error(undef). -spec find(Key,Map) -> {ok, Value} | error when Map :: #{Key => Value, _ => _}. find(_,_) -> erlang:nif_error(undef). %% Shadowed by erl_bif_types: maps:from_list/1 -spec from_list(List) -> Map when List :: [{Key,Value}], Key :: term(), Value :: term(), Map :: map(). from_list(_) -> erlang:nif_error(undef). %% Shadowed by erl_bif_types: maps:is_key/2 -spec is_key(Key,Map) -> boolean() when Key :: term(), Map :: map(). is_key(_,_) -> erlang:nif_error(undef). -spec keys(Map) -> Keys when Map :: #{Key => _}, Keys :: [Key]. keys(_) -> erlang:nif_error(undef). %% Shadowed by erl_bif_types: maps:merge/2 -spec merge(Map1,Map2) -> Map3 when Map1 :: map(), Map2 :: map(), Map3 :: map(). merge(_,_) -> erlang:nif_error(undef). %% Shadowed by erl_bif_types: maps:put/3 -spec put(Key,Value,Map1) -> Map2 when Key :: term(), Value :: term(), Map1 :: map(), Map2 :: map(). put(_,_,_) -> erlang:nif_error(undef). %% Shadowed by erl_bif_types: maps:remove/2 -spec remove(Key,Map1) -> Map2 when Key :: term(), Map1 :: map(), Map2 :: map(). remove(_,_) -> erlang:nif_error(undef). -spec take(Key,Map1) -> {Value,Map2} | error when Map1 :: #{Key => Value, _ => _}, Map2 :: #{_ => _}. take(_,_) -> erlang:nif_error(undef). -spec to_list(Map) -> [{Key,Value}] when Map :: #{Key => Value}. to_list(Map) when is_map(Map) -> to_list_internal(erts_internal:map_next(0, Map, [])); to_list(Map) -> erlang:error({badmap,Map},[Map]). to_list_internal([Iter, Map | Acc]) when is_integer(Iter) -> to_list_internal(erts_internal:map_next(Iter, Map, Acc)); to_list_internal(Acc) -> Acc. %% Shadowed by erl_bif_types: maps:update/3 -spec update(Key,Value,Map1) -> Map2 when Map1 :: #{Key := _, _ => _}, Map2 :: #{Key := Value, _ => _}. update(_,_,_) -> erlang:nif_error(undef). -spec values(Map) -> Values when Map :: #{_ => Value}, Values :: [Value]. values(_) -> erlang:nif_error(undef). %% End of BIFs -spec new() -> Map when Map :: #{}. new() -> #{}. -spec update_with(Key,Fun,Map1) -> Map2 when Map1 :: #{Key := Value1, _ => _}, Map2 :: #{Key := Value2, _ => _}, Fun :: fun((Value1) -> Value2). update_with(Key,Fun,Map) when is_function(Fun,1), is_map(Map) -> case Map of #{Key := Value} -> Map#{Key := Fun(Value)}; #{} -> erlang:error({badkey,Key},[Key,Fun,Map]) end; update_with(Key,Fun,Map) -> erlang:error(error_type(Map),[Key,Fun,Map]). -spec update_with(Key,Fun,Init,Map1) -> Map2 when Map1 :: #{Key => Value1, _ => _}, Map2 :: #{Key := Value2 | Init, _ => _}, Fun :: fun((Value1) -> Value2). update_with(Key,Fun,Init,Map) when is_function(Fun,1), is_map(Map) -> case Map of #{Key := Value} -> Map#{Key := Fun(Value)}; #{} -> Map#{Key => Init} end; update_with(Key,Fun,Init,Map) -> erlang:error(error_type(Map),[Key,Fun,Init,Map]). -spec get(Key, Map, Default) -> Value | Default when Map :: #{Key => Value, _ => _}. get(Key,Map,Default) when is_map(Map) -> case Map of #{Key := Value} -> Value; #{} -> Default end; get(Key,Map,Default) -> erlang:error({badmap,Map},[Key,Map,Default]). -spec filter(Pred, MapOrIter) -> Map when Pred :: fun((Key, Value) -> boolean()), MapOrIter :: #{Key => Value} | iterator(Key, Value), Map :: #{Key => Value}. filter(Pred,Map) when is_function(Pred,2), is_map(Map) -> maps:from_list(filter_1(Pred, iterator(Map))); filter(Pred,Iterator) when is_function(Pred,2), ?IS_ITERATOR(Iterator) -> maps:from_list(filter_1(Pred, Iterator)); filter(Pred,Map) -> erlang:error(error_type(Map),[Pred,Map]). filter_1(Pred, Iter) -> case next(Iter) of {K, V, NextIter} -> case Pred(K,V) of true -> [{K,V} | filter_1(Pred, NextIter)]; false -> filter_1(Pred, NextIter) end; none -> [] end. -spec fold(Fun,Init,MapOrIter) -> Acc when Fun :: fun((Key, Value, AccIn) -> AccOut), Init :: term(), Acc :: AccOut, AccIn :: Init | AccOut, MapOrIter :: #{Key => Value} | iterator(Key, Value). fold(Fun,Init,Map) when is_function(Fun,3), is_map(Map) -> fold_1(Fun,Init,iterator(Map)); fold(Fun,Init,Iterator) when is_function(Fun,3), ?IS_ITERATOR(Iterator) -> fold_1(Fun,Init,Iterator); fold(Fun,Init,Map) -> erlang:error(error_type_iter(Map),[Fun,Init,Map]). fold_1(Fun, Acc, Iter) -> case next(Iter) of {K, V, NextIter} -> fold_1(Fun, Fun(K,V,Acc), NextIter); none -> Acc end. -spec map(Fun,MapOrIter) -> Map when Fun :: fun((Key, Value1) -> Value2), MapOrIter :: #{Key => Value1} | iterator(Key, Value1), Map :: #{Key => Value2}. map(Fun,Map) when is_function(Fun, 2), is_map(Map) -> maps:from_list(map_1(Fun, iterator(Map))); map(Fun,Iterator) when is_function(Fun, 2), ?IS_ITERATOR(Iterator) -> maps:from_list(map_1(Fun, Iterator)); map(Fun,Map) -> erlang:error(error_type_iter(Map),[Fun,Map]). map_1(Fun, Iter) -> case next(Iter) of {K, V, NextIter} -> [{K, Fun(K, V)} | map_1(Fun, NextIter)]; none -> [] end. -spec size(Map) -> non_neg_integer() when Map :: map(). size(Map) when is_map(Map) -> erlang:map_size(Map); size(Val) -> erlang:error({badmap,Val},[Val]). -spec iterator(Map) -> Iterator when Map :: #{Key => Value}, Iterator :: iterator(Key, Value). iterator(M) when is_map(M) -> [0 | M]; iterator(M) -> erlang:error({badmap, M}, [M]). -spec next(Iterator) -> {Key, Value, NextIterator} | 'none' when Iterator :: iterator(Key, Value), NextIterator :: iterator(Key, Value). next({K, V, I}) -> {K, V, I}; next([Path | Map]) when is_integer(Path), is_map(Map) -> erts_internal:map_next(Path, Map, iterator); next(none) -> none; next(Iter) -> erlang:error(badarg, [Iter]). -spec without(Ks,Map1) -> Map2 when Ks :: [K], Map1 :: map(), Map2 :: map(), K :: term(). without(Ks,M) when is_list(Ks), is_map(M) -> lists:foldl(fun maps:remove/2, M, Ks); without(Ks,M) -> erlang:error(error_type(M),[Ks,M]). -spec with(Ks, Map1) -> Map2 when Ks :: [K], Map1 :: #{K => V, _ => _}, Map2 :: #{K => V}. with(Ks,Map1) when is_list(Ks), is_map(Map1) -> maps:from_list(with_1(Ks, Map1)); with(Ks,M) -> erlang:error(error_type(M),[Ks,M]). with_1([K|Ks], Map) -> case Map of #{K := V} -> [{K,V}|with_1(Ks, Map)]; #{} -> with_1(Ks, Map) end; with_1([], _Map) -> []. error_type(M) when is_map(M) -> badarg; error_type(V) -> {badmap, V}. error_type_iter(M) when is_map(M); ?IS_ITERATOR(M) -> badarg; error_type_iter(V) -> {badmap, V}. ================================================ FILE: test_data/match.core ================================================ module 'match' ['hoo'/1, 'module_info'/0, 'module_info'/1, 'woo'/0] attributes [%% Line 1 'file' = %% Line 1 [{[109|[97|[116|[99|[104|[46|[101|[114|[108]]]]]]]]],1}]] 'woo'/0 = %% Line 4 fun () -> %% Line 5 receive %% Line 6 <{'send',Woo,_0 = {_X_Something,_X_Else}}> when call 'erlang':'=:=' (_0, Woo) -> %% Line 7 Woo %% Line 8 <{'woo',Hoo}> when 'true' -> %% Line 9 Hoo after 'infinity' -> 'true' 'hoo'/1 = %% Line 12 fun (_0) -> %% Line 13 receive %% Line 14 <{'send',_2}> when call 'erlang':'=:=' (_2, _0) -> _0 after 'infinity' -> 'true' 'module_info'/0 = fun () -> call 'erlang':'get_module_info' ('match') 'module_info'/1 = fun (_0) -> call 'erlang':'get_module_info' ('match', _0) end ================================================ FILE: test_data/match.erl ================================================ -module(match). -export([woo/0, hoo/1]). woo() -> receive {send, Woo, {_Something, _Else} = Woo} -> Woo; {woo, Hoo} -> Hoo end. hoo(Hoo) -> receive {send, Hoo} -> Hoo end. ================================================ FILE: test_data/match_SUITE.abstr ================================================ {attribute,1,file,{"match_SUITE.erl",1}}. {attribute,20,module,match_SUITE}. {attribute,22,export, [{all,0}, {suite,0}, {groups,0}, {init_per_suite,1}, {end_per_suite,1}, {init_per_group,2}, {end_per_group,2}, {pmatch,1}, {mixed,1}, {aliases,1}, {non_matching_aliases,1}, {match_in_call,1}, {untuplify,1}, {shortcut_boolean,1}, {letify_guard,1}, {selectify,1}, {deselectify,1}, {underscore,1}, {match_map,1}, {map_vars_used,1}, {coverage,1}, {grab_bag,1}, {literal_binary,1}, {unary_op,1}, {eq_types,1}, {match_after_return,1}, {match_right_tuple,1}, {tuple_size_in_try,1}, {match_boolean_list,1}]}. {attribute,1,file, {"/home/hansihe/.asdf/installs/erlang/21.2.4/lib/common_test-1.16.1/include/ct.hrl", 1}}. {attribute,32,file,{"match_SUITE.erl",32}}. {function,33,suite,0, [{clause,33,[],[], [{cons,33, {tuple,33, [{atom,33,ct_hooks}, {cons,33,{atom,33,ts_install_cth},{nil,33}}]}, {nil,33}}]}]}. {function,35,all,0, [{clause,35,[],[], [{cons,36, {tuple,36,[{atom,36,group},{atom,36,p}]}, {nil,36}}]}]}. {function,38,groups,0, [{clause,38,[],[], [{cons,39, {tuple,39, [{atom,39,p}, {cons,39,{atom,39,parallel},{nil,39}}, {cons,40, {atom,40,pmatch}, {cons,40, {atom,40,mixed}, {cons,40, {atom,40,aliases}, {cons,40, {atom,40,non_matching_aliases}, {cons,41, {atom,41,match_in_call}, {cons,41, {atom,41,untuplify}, {cons,42, {atom,42,shortcut_boolean}, {cons,42, {atom,42,letify_guard}, {cons,42, {atom,42,selectify}, {cons,42, {atom,42,deselectify}, {cons,43, {atom,43,underscore}, {cons,43, {atom,43,match_map}, {cons,43, {atom,43,map_vars_used}, {cons,43, {atom,43,coverage}, {cons,44, {atom,44,grab_bag}, {cons,44, {atom,44,literal_binary}, {cons,44, {atom,44,unary_op}, {cons,44, {atom,44,eq_types}, {cons,45, {atom,45,match_after_return}, {cons,45, {atom,45,match_right_tuple}, {cons,46, {atom,46,tuple_size_in_try}, {cons,46, {atom,46,match_boolean_list}, {nil,46}}}}}}}}}}}}}}}}}}}}}}}]}, {nil,46}}]}]}. {function,49,init_per_suite,1, [{clause,49, [{var,49,'Config'}], [], [{call,50, {remote,50,{atom,50,test_lib},{atom,50,recompile}}, [{atom,50,match_SUITE}]}, {var,51,'Config'}]}]}. {function,53,end_per_suite,1, [{clause,53,[{var,53,'_Config'}],[],[{atom,54,ok}]}]}. {function,56,init_per_group,2, [{clause,56, [{var,56,'_GroupName'},{var,56,'Config'}], [], [{var,57,'Config'}]}]}. {function,59,end_per_group,2, [{clause,59, [{var,59,'_GroupName'},{var,59,'Config'}], [], [{var,60,'Config'}]}]}. {function,63,pmatch,1, [{clause,63, [{var,63,'Config'}], [[{call,63,{atom,63,is_list},[{var,63,'Config'}]}]], [{match,64, {atom,64,ok}, {call,64,{atom,64,doit},[{integer,64,1}]}}, {match,65, {atom,65,ok}, {call,65,{atom,65,doit},[{integer,65,2}]}}, {match,66, {tuple,66,[{atom,66,error},{atom,66,baz}]}, {call,66,{atom,66,doit},[{integer,66,3}]}}, {match,67, {tuple,67,[{atom,67,error},{atom,67,foobar}]}, {call,67,{atom,67,doit},[{integer,67,4}]}}, {atom,68,ok}]}]}. {function,79,doit,1, [{clause,79, [{var,79,'X'}], [], [{'case',80, {'case',80, {var,80,'X'}, [{clause,80,[{integer,80,1}],[],[{atom,80,foo}]}, {clause,80,[{integer,80,2}],[],[{atom,80,bar}]}, {clause,80,[{integer,80,3}],[],[{atom,80,baz}]}, {clause,80,[{integer,80,4}],[],[{atom,80,foobar}]}]}, [{clause,81,[{atom,81,foo}],[],[{atom,81,ok}]}, {clause,82,[{atom,82,bar}],[],[{atom,82,ok}]}, {clause,83, [{var,83,'Other'}], [], [{tuple,83,[{atom,83,error},{var,83,'Other'}]}]}]}]}]}. {function,86,mixed,1, [{clause,86, [{var,86,'Config'}], [[{call,86,{atom,86,is_list},[{var,86,'Config'}]}]], [{match,87, {atom,87,glufs}, {call,87,{atom,87,mixit},[{integer,87,1}]}}, {match,88, {atom,88,klafs}, {call,88,{atom,88,mixit},[{integer,88,2}]}}, {match,89, {atom,89,fnurra}, {call,89,{atom,89,mixit},[{integer,89,3}]}}, {match,90,{atom,90,usch},{call,90,{atom,90,mixit},[{integer,90,4}]}}, {match,91, {tuple,91,[{atom,91,error},{atom,91,blurf}]}, {call,91,{atom,91,mixit},[{integer,91,5}]}}, {match,92, {tuple,92,[{atom,92,error},{integer,92,87987987}]}, {call,92,{atom,92,mixit},[{integer,92,6}]}}, {match,93, {tuple,93, [{atom,93,error}, {tuple,93,[{atom,93,a},{atom,93,b},{atom,93,c}]}]}, {call,93,{atom,93,mixit},[{integer,93,7}]}}, {atom,94,ok}]}]}. {function,96,mixit,1, [{clause,96, [{var,96,'X'}], [], [{'case',97, {'case',97, {var,97,'X'}, [{clause,98,[{integer,98,1}],[],[{atom,98,a}]}, {clause,99,[{integer,99,2}],[],[{atom,99,b}]}, {clause,100,[{integer,100,3}],[],[{integer,100,42}]}, {clause,101,[{integer,101,4}],[],[{integer,101,77}]}, {clause,102, [{op,102,'+',{integer,102,4},{integer,102,1}}], [], [{atom,102,blurf}]}, {clause,103, [{op,103,'+',{integer,103,5},{integer,103,1}}], [], [{integer,103,87987987}]}, {clause,104, [{op,104,'+',{integer,104,6},{integer,104,1}}], [], [{tuple,104, [{atom,104,a},{atom,104,b},{atom,104,c}]}]}]}, [{clause,106,[{atom,106,a}],[],[{atom,106,glufs}]}, {clause,107,[{atom,107,b}],[],[{atom,107,klafs}]}, {clause,108,[{integer,108,42}],[],[{atom,108,fnurra}]}, {clause,109,[{integer,109,77}],[],[{atom,109,usch}]}, {clause,110, [{var,110,'Other'}], [], [{tuple,110,[{atom,110,error},{var,110,'Other'}]}]}]}]}]}. {function,113,aliases,1, [{clause,113, [{var,113,'Config'}], [[{call,113,{atom,113,is_list},[{var,113,'Config'}]}]], [{match,115, {atom,115,ok}, {call,115,{atom,115,str_alias},[{string,115,"abc"}]}}, {match,116, {atom,116,ok}, {call,116,{atom,116,str_alias},[{string,116,"def"}]}}, {match,117, {atom,117,ok}, {call,117,{atom,117,str_alias},[{string,117,"ghi"}]}}, {match,118, {atom,118,ok}, {call,118,{atom,118,str_alias},[{string,118,"klm"}]}}, {match,119, {atom,119,ok}, {call,119,{atom,119,str_alias},[{string,119,"qrs"}]}}, {match,120, {atom,120,ok}, {call,120,{atom,120,str_alias},[{string,120,"xy"}]}}, {match,121, {atom,121,ok}, {call,121,{atom,121,str_alias},[{string,121,[]}]}}, {match,122, {atom,122,ok}, {call,122,{atom,122,str_alias},[{nil,122}]}}, {match,123, {atom,123,error}, {call,123,{atom,123,str_alias},[{string,123,"blurf"}]}}, {match,126, {atom,126,ok}, {call,126,{atom,126,char_alias},[{char,126,118}]}}, {match,127, {atom,127,ok}, {call,127,{atom,127,char_alias},[{integer,127,118}]}}, {match,128, {atom,128,ok}, {call,128,{atom,128,char_alias},[{char,128,119}]}}, {match,129, {atom,129,ok}, {call,129,{atom,129,char_alias},[{integer,129,119}]}}, {match,130, {atom,130,ok}, {call,130,{atom,130,char_alias},[{integer,130,42}]}}, {match,131, {atom,131,ok}, {call,131,{atom,131,char_alias},[{float,131,3.0}]}}, {match,132, {atom,132,error}, {call,132,{atom,132,char_alias},[{char,132,95}]}}, {match,133, {atom,133,error}, {call,133,{atom,133,char_alias},[{integer,133,0}]}}, {match,135, {tuple,135,[{integer,135,42},{integer,135,42},{integer,135,42}]}, {call,135,{atom,135,three},[{integer,135,42}]}}, {match,137, {tuple,137, [{integer,137,1}, {integer,137,42}, {integer,137,99}, {integer,137,1}, {integer,137,42}, {integer,137,99}]}, {call,137, {atom,137,tuple_alias}, [{tuple,137, [{integer,137,1},{integer,137,42},{integer,137,99}]}]}}, {match,138, {tuple,138, [{op,138,'-',{integer,138,10}}, {integer,138,20}, {op,138,'-',{integer,138,10}}, {integer,138,20}, {op,138,'-',{integer,138,10}}, {integer,138,20}]}, {call,138, {atom,138,tuple_alias}, [{tuple,138, [{op,138,'-',{integer,138,10}},{integer,138,20}]}]}}, {match,139, {integer,139,6}, {call,139, {atom,139,tup_lit_alias}, [{tuple,139, [{integer,139,1},{integer,139,2},{integer,139,3}]}]}}, {match,140, {integer,140,6}, {call,140, {atom,140,tup_lit_alias_rev}, [{tuple,140, [{integer,140,1},{integer,140,2},{integer,140,3}]}]}}, {match,142, {tuple,142, [{integer,142,42}, {integer,142,42}, {integer,142,42}, {integer,142,42}]}, {call,142,{atom,142,multiple_aliases_1},[{integer,142,42}]}}, {match,143, {tuple,143,[{integer,143,7},{integer,143,7},{integer,143,7}]}, {call,143,{atom,143,multiple_aliases_2},[{integer,143,7}]}}, {match,144, {tuple,144, [{tuple,144,[{atom,144,a},{atom,144,b}]}, {tuple,144,[{atom,144,a},{atom,144,b}]}, {tuple,144,[{atom,144,a},{atom,144,b}]}]}, {call,144, {atom,144,multiple_aliases_3}, [{tuple,144,[{atom,144,a},{atom,144,b}]}]}}, {match,147, {tuple,147,[{atom,147,a},{atom,147,b}]}, {call,147, {atom,147,list_alias1}, [{cons,147, {atom,147,a}, {cons,147,{atom,147,b},{nil,147}}}]}}, {match,148, {tuple,148,[{atom,148,a},{atom,148,b}]}, {call,148, {atom,148,list_alias2}, [{cons,148, {atom,148,a}, {cons,148,{atom,148,b},{nil,148}}}]}}, {match,149, {tuple,149,[{atom,149,a},{atom,149,b}]}, {call,149, {atom,149,list_alias3}, [{cons,149, {atom,149,a}, {cons,149,{atom,149,b},{nil,149}}}]}}, {atom,151,ok}]}]}. {function,153,str_alias,1, [{clause,153, [{var,153,'V'}], [], [{match,154, {var,154,'Res'}, {call,154,{atom,154,str_alias_1},[{var,154,'V'}]}}, {match,155, {var,155,'Res'}, {call,155, {atom,155,str_alias_2}, [{var,155,'V'}]}}]}]}. {function,157,str_alias_1,1, [{clause,157, [{match,157, {cons,157, {char,157,97}, {cons,157,{char,157,98},{cons,157,{char,157,99},{nil,157}}}}, {match,157, {string,157,"abc"}, {match,157, {op,157,'++', {string,157,"a"}, {cons,157, {char,157,98}, {cons,157,{char,157,99},{nil,157}}}}, {cons,157, {integer,157,97}, {cons,157, {integer,157,98}, {cons,157,{integer,157,99},{nil,157}}}}}}}], [], [{atom,157,ok}]}, {clause,158, [{match,158, {cons,158,{char,158,100},{string,158,"ef"}}, {string,158,"def"}}], [], [{atom,158,ok}]}, {clause,159, [{match,159, {cons,159,{char,159,103},{string,159,"hi"}}, {match,159, {op,159,'++',{string,159,"g"},{string,159,"hi"}}, {match,159, {op,159,'++',{string,159,"gh"},{string,159,"i"}}, {op,159,'++',{string,159,"ghi"},{string,159,[]}}}}}], [], [{atom,159,ok}]}, {clause,160, [{match,160, {op,160,'++',{string,160,"k"},{string,160,"lm"}}, {cons,160,{char,160,107},{string,160,"lm"}}}], [], [{atom,160,ok}]}, {clause,161, [{match,161, {cons,161, {integer,161,113}, {cons,161, {integer,161,114}, {cons,161,{integer,161,115},{nil,161}}}}, {match,161, {string,161,"qrs"}, {match,161, {cons,161, {char,161,113}, {cons,161, {char,161,114}, {cons,161,{char,161,115},{nil,161}}}}, {op,161,'++', {string,161,"q"}, {op,161,'++',{string,161,"r"},{string,161,"s"}}}}}}], [], [{atom,161,ok}]}, {clause,162, [{match,162, {cons,162,{char,162,120},{cons,162,{char,162,121},{nil,162}}}, {string,162,"xy"}}], [], [{atom,162,ok}]}, {clause,163,[{match,163,{string,163,[]},{nil,163}}],[],[{atom,163,ok}]}, {clause,164,[{var,164,'_'}],[],[{atom,164,error}]}]}. {function,168,str_alias_2,1, [{clause,168, [{match,168, {cons,168, {char,168,97}, {cons,168,{char,168,98},{cons,168,{char,168,99},{nil,168}}}}, {match,169, {string,169,"abc"}, {match,171, {op,170,'++', {string,170,"a"}, {cons,170, {char,170,98}, {cons,170,{char,170,99},{nil,171}}}}, {cons,172, {integer,172,97}, {cons,172, {integer,172,98}, {cons,172,{integer,172,99},{nil,173}}}}}}}], [], [{atom,173,ok}]}, {clause,174, [{match,174, {cons,174,{char,174,100},{string,174,"ef"}}, {string,175,"def"}}], [], [{atom,175,ok}]}, {clause,176, [{match,176, {cons,176,{char,176,103},{string,176,"hi"}}, {match,177, {op,177,'++',{string,177,"g"},{string,177,"hi"}}, {match,178, {op,178,'++',{string,178,"gh"},{string,178,"i"}}, {op,179,'++',{string,179,"ghi"},{string,179,[]}}}}}], [], [{atom,179,ok}]}, {clause,180, [{match,180, {op,180,'++',{string,180,"k"},{string,180,"lm"}}, {cons,181,{char,181,107},{string,181,"lm"}}}], [], [{atom,182,ok}]}, {clause,183, [{match,183, {cons,183, {integer,183,113}, {cons,183, {integer,183,114}, {cons,183,{integer,183,115},{nil,183}}}}, {match,184, {string,184,"qrs"}, {match,185, {cons,184, {char,184,113}, {cons,184, {char,184,114}, {cons,184,{char,184,115},{nil,185}}}}, {op,186,'++', {string,186,"q"}, {op,186,'++',{string,186,"r"},{string,186,"s"}}}}}}], [], [{atom,186,ok}]}, {clause,187, [{match,187, {cons,187,{char,187,120},{cons,187,{char,187,121},{nil,187}}}, {string,188,"xy"}}], [], [{atom,188,ok}]}, {clause,189,[{match,189,{string,189,[]},{nil,190}}],[],[{atom,190,ok}]}, {clause,191,[{var,191,'_'}],[],[{atom,191,error}]}]}. {function,193,char_alias,1, [{clause,193, [{var,193,'V'}], [], [{match,194, {var,194,'Res'}, {call,194,{atom,194,char_alias_1},[{var,194,'V'}]}}, {match,195, {var,195,'Res'}, {call,195, {atom,195,char_alias_2}, [{var,195,'V'}]}}]}]}. {function,197,char_alias_1,1, [{clause,197, [{match,197,{integer,197,118},{char,197,118}}], [], [{atom,197,ok}]}, {clause,198, [{match,198,{char,198,119},{integer,198,119}}], [], [{atom,198,ok}]}, {clause,199, [{match,199,{integer,199,42},{integer,199,42}}], [], [{atom,199,ok}]}, {clause,200, [{match,200,{float,200,3.0},{float,200,3.0}}], [], [{atom,200,ok}]}, {clause,201,[{var,201,'_'}],[],[{atom,201,error}]}]}. {function,203,char_alias_2,1, [{clause,203, [{match,203,{integer,203,118},{char,204,118}}], [], [{atom,204,ok}]}, {clause,205, [{match,205,{char,205,119},{integer,206,119}}], [], [{atom,206,ok}]}, {clause,207, [{match,207,{integer,207,42},{integer,208,42}}], [], [{atom,208,ok}]}, {clause,209, [{match,209,{float,209,3.0},{float,210,3.0}}], [], [{atom,210,ok}]}, {clause,211,[{var,211,'_'}],[],[{atom,211,error}]}]}. {function,213,three,1, [{clause,213, [{var,213,'V'}], [], [{match,214, {var,214,'Res'}, {call,214,{atom,214,three_1},[{var,214,'V'}]}}, {match,215, {var,215,'Res'}, {call,215,{atom,215,three_2},[{var,215,'V'}]}}]}]}. {function,217,three_1,1, [{clause,217, [{match,217, {var,217,'A'}, {match,217,{var,217,'B'},{var,217,'C'}}}], [], [{tuple,218, [{var,218,'A'},{var,218,'B'},{var,218,'C'}]}]}]}. {function,220,three_2,1, [{clause,220, [{match,220, {var,220,'A'}, {match,221,{var,221,'B'},{var,222,'C'}}}], [], [{tuple,223, [{var,223,'A'},{var,223,'B'},{var,223,'C'}]}]}]}. {function,225,tuple_alias,1, [{clause,225, [{match,225, {tuple,225, [{var,225,'A'},{var,225,'B'},{var,225,'C'}]}, {tuple,225, [{var,225,'X'}, {var,225,'Y'}, {var,225,'Z'}]}}], [], [{tuple,226, [{var,226,'A'}, {var,226,'B'}, {var,226,'C'}, {var,226,'X'}, {var,226,'Y'}, {var,226,'Z'}]}]}, {clause,227, [{match,227, {tuple,227,[{var,227,'A'},{var,227,'B'}]}, {match,227, {tuple,227,[{var,227,'C'},{var,227,'D'}]}, {tuple,227,[{var,227,'E'},{var,227,'F'}]}}}], [], [{tuple,228, [{var,228,'A'}, {var,228,'B'}, {var,228,'C'}, {var,228,'D'}, {var,228,'E'}, {var,228,'F'}]}]}]}. {function,230,tup_lit_alias,1, [{clause,230, [{match,230, {tuple,230, [{var,230,'A'},{var,230,'B'},{var,230,'C'}]}, {tuple,230, [{integer,230,1}, {integer,230,2}, {integer,230,3}]}}], [], [{op,231,'+', {op,231,'+',{var,231,'A'},{var,231,'B'}}, {var,231,'C'}}]}]}. {function,233,tup_lit_alias_rev,1, [{clause,233, [{match,233, {tuple,233, [{integer,233,1}, {integer,233,2}, {integer,233,3}]}, {tuple,233, [{var,233,'A'}, {var,233,'B'}, {var,233,'C'}]}}], [], [{op,234,'+', {op,234,'+',{var,234,'A'},{var,234,'B'}}, {var,234,'C'}}]}]}. {function,236,multiple_aliases_1,1, [{clause,236, [{match,236, {match,236,{var,236,'A'},{var,236,'B'}}, {match,236,{var,236,'C'},{var,236,'D'}}}], [], [{tuple,237, [{var,237,'A'}, {var,237,'B'}, {var,237,'C'}, {var,237,'D'}]}]}]}. {function,239,multiple_aliases_2,1, [{clause,239, [{match,239, {match,239,{var,239,'A'},{var,239,'B'}}, {match,239,{var,239,'A'},{var,239,'C'}}}], [], [{tuple,240, [{var,240,'A'},{var,240,'B'},{var,240,'C'}]}]}]}. {function,242,multiple_aliases_3,1, [{clause,242, [{match,242, {match,242, {var,242,'A'}, {match,242, {tuple,242,[{var,242,'_'},{var,242,'_'}]}, {var,242,'B'}}}, {match,242, {tuple,242,[{var,242,'_'},{var,242,'_'}]}, {var,242,'C'}}}], [], [{tuple,243,[{var,243,'A'},{var,243,'B'},{var,243,'C'}]}]}]}. {function,245,list_alias1,1, [{clause,245, [{match,245, {cons,245, {atom,245,a}, {cons,245,{atom,245,b},{nil,245}}}, {cons,245, {var,245,'X'}, {cons,245,{var,245,'Y'},{nil,245}}}}], [], [{tuple,246,[{var,246,'X'},{var,246,'Y'}]}]}]}. {function,248,list_alias2,1, [{clause,248, [{match,248, {cons,248, {var,248,'X'}, {cons,248,{var,248,'Y'},{nil,248}}}, {cons,248, {atom,248,a}, {cons,248,{atom,248,b},{nil,248}}}}], [], [{tuple,249,[{var,249,'X'},{var,249,'Y'}]}]}]}. {function,251,list_alias3,1, [{clause,251, [{match,251, {cons,251, {var,251,'X'}, {cons,251,{atom,251,b},{nil,251}}}, {cons,251, {atom,251,a}, {cons,251,{var,251,'Y'},{nil,251}}}}], [], [{tuple,252,[{var,252,'X'},{var,252,'Y'}]}]}]}. {function,254,non_matching_aliases,1, [{clause,254, [{var,254,'_Config'}], [], [{match,255, {atom,255,none}, {call,255, {atom,255,mixed_aliases}, [{bin,255, [{bin_element,255, {integer,255,42}, default,default}]}]}}, {match,256, {atom,256,none}, {call,256, {atom,256,mixed_aliases}, [{cons,256,{atom,256,b},{nil,256}}]}}, {match,257, {atom,257,none}, {call,257, {atom,257,mixed_aliases}, [{cons,257,{atom,257,d},{nil,257}}]}}, {match,258, {atom,258,none}, {call,258, {atom,258,mixed_aliases}, [{tuple,258,[{atom,258,a},{integer,258,42}]}]}}, {match,259, {atom,259,none}, {call,259,{atom,259,mixed_aliases},[{integer,259,42}]}}, {match,260, {atom,260,none}, {call,260, {atom,260,mixed_aliases}, [{bin,260, [{bin_element,260, {integer,260,6789}, {integer,260,16}, default}]}]}}, {match,261, {atom,261,none}, {call,261, {atom,261,mixed_aliases}, [{map,261, [{map_field_assoc,261, {atom,261,key}, {atom,261,value}}]}]}}, {match,263, {tuple,263, [{atom,263,'EXIT'}, {tuple,263, [{tuple,263,[{atom,263,badmatch},{integer,263,42}]}, {var,263,'_'}]}]}, {'catch',263, {call,263,{atom,263,nomatch_alias},[{integer,263,42}]}}}, {match,264, {tuple,264, [{atom,264,'EXIT'}, {tuple,264, [{tuple,264,[{atom,264,badmatch},{atom,264,job}]}, {var,264,'_'}]}]}, {'catch',264,{call,264,{atom,264,entirely},[]}}}, {match,265, {tuple,265, [{atom,265,'EXIT'}, {tuple,265, [{tuple,265, [{atom,265,badmatch},{atom,265,associates}]}, {var,265,'_'}]}]}, {'catch',265,{call,265,{atom,265,printer},[]}}}, {match,266, {tuple,266, [{atom,266,'EXIT'}, {tuple,266, [{tuple,266,[{atom,266,badmatch},{atom,266,borogoves}]}, {var,266,'_'}]}]}, {'catch',266,{call,266,{atom,266,tench},[]}}}, {call,268,{atom,268,put},[{atom,268,perch},{integer,268,0}]}, {match,269, {tuple,269, [{atom,269,'EXIT'}, {tuple,269, [{tuple,269, [{atom,269,badmatch}, {tuple,269,[{atom,269,spine},{integer,269,42}]}]}, {var,269,'_'}]}]}, {'catch',269,{call,269,{atom,269,perch},[{integer,269,42}]}}}, {match,270, {integer,270,1}, {call,270,{atom,270,erase},[{atom,270,perch}]}}, {call,272,{atom,272,put},[{atom,272,salmon},{integer,272,0}]}, {match,273, {tuple,273, [{atom,273,'EXIT'}, {tuple,273, [{tuple,273,[{atom,273,badmatch},{atom,273,mimsy}]}, {var,273,'_'}]}]}, {'catch',273,{call,273,{atom,273,salmon},[]}}}, {match,274, {integer,274,1}, {call,274,{atom,274,erase},[{atom,274,salmon}]}}, {call,276,{atom,276,put},[{atom,276,shark},{integer,276,0}]}, {match,277, {tuple,277, [{atom,277,'EXIT'}, {tuple,277, [{tuple,277,[{atom,277,badmatch},{var,277,'_'}]}, {var,277,'_'}]}]}, {'catch',277,{call,277,{atom,277,shark},[]}}}, {match,278, {integer,278,1}, {call,278,{atom,278,erase},[{atom,278,shark}]}}, {match,280, {tuple,280, [{atom,280,'EXIT'}, {tuple,280, [{tuple,280,[{atom,280,badmatch},{var,280,'_'}]}, {var,280,'_'}]}]}, {'catch',280,{call,280,{atom,280,radio},[{atom,280,research}]}}}, {atom,281,ok}]}]}. {function,283,mixed_aliases,1, [{clause,283, [{match,283, {bin,283, [{bin_element,283,{var,283,'X'},{integer,283,8},default}]}, {atom,283,x}}], [], [{tuple,283,[{atom,283,a},{var,283,'X'}]}]}, {clause,284, [{match,284, {cons,284,{atom,284,b},{nil,284}}, {bin,284, [{bin_element,284,{var,284,'X'},{integer,284,8},default}]}}], [], [{tuple,284,[{atom,284,b},{var,284,'X'}]}]}, {clause,285, [{match,285, {bin,285, [{bin_element,285,{var,285,'X'},{integer,285,8},default}]}, {tuple,285,[{atom,285,a},{var,285,'X'}]}}], [], [{tuple,285,[{atom,285,c},{var,285,'X'}]}]}, {clause,286, [{match,286, {cons,286,{var,286,'X'},{nil,286}}, {bin,286, [{bin_element,286,{var,286,'X'},{integer,286,8},default}]}}], [], [{tuple,286,[{atom,286,d},{var,286,'X'}]}]}, {clause,287, [{match,287, {bin,287, [{bin_element,287,{var,287,'X'},{integer,287,16},default}]}, {var,287,'X'}}], [], [{tuple,287,[{atom,287,e},{var,287,'X'}]}]}, {clause,288, [{match,288, {var,288,'X'}, {bin,288, [{bin_element,288, {var,288,'X'}, {integer,288,16}, default}]}}], [], [{tuple,288,[{atom,288,f},{var,288,'X'}]}]}, {clause,289, [{match,289, {bin,289, [{bin_element,289,{var,289,'X'},{integer,289,16},default}, {bin_element,289,{var,289,'_'},default,[binary]}]}, {var,289,'X'}}], [], [{tuple,289,[{atom,289,g},{var,289,'X'}]}]}, {clause,290, [{match,290, {var,290,'X'}, {bin,290, [{bin_element,290,{var,290,'X'},{integer,290,16},default}, {bin_element,290,{var,290,'_'},default,[binary]}]}}], [], [{tuple,290,[{atom,290,h},{var,290,'X'}]}]}, {clause,291, [{match,291, {var,291,'X'}, {map,291,[{map_field_exact,291,{atom,291,key},{var,291,'X'}}]}}], [], [{tuple,291,[{atom,291,i},{var,291,'X'}]}]}, {clause,292, [{match,292, {map,292,[{map_field_exact,292,{atom,292,key},{var,292,'X'}}]}, {var,292,'X'}}], [], [{tuple,292,[{atom,292,j},{var,292,'X'}]}]}, {clause,293, [{match,293, {cons,293,{var,293,'X'},{nil,293}}, {map,293,[{map_field_exact,293,{atom,293,key},{var,293,'X'}}]}}], [], [{tuple,293,[{atom,293,k},{var,293,'X'}]}]}, {clause,294, [{match,294, {map,294,[{map_field_exact,294,{atom,294,key},{var,294,'X'}}]}, {cons,294,{var,294,'X'},{nil,294}}}], [], [{tuple,294,[{atom,294,l},{var,294,'X'}]}]}, {clause,295, [{match,295, {tuple,295,[{atom,295,a},{var,295,'X'}]}, {map,295,[{map_field_exact,295,{atom,295,key},{var,295,'X'}}]}}], [], [{tuple,295,[{atom,295,m},{var,295,'X'}]}]}, {clause,296, [{match,296, {map,296,[{map_field_exact,296,{atom,296,key},{var,296,'X'}}]}, {tuple,296,[{atom,296,a},{var,296,'X'}]}}], [], [{tuple,296,[{atom,296,n},{var,296,'X'}]}]}, {clause,297,[{var,297,'_'}],[],[{atom,297,none}]}]}. {function,299,nomatch_alias,1, [{clause,299, [{var,299,'I'}], [], [{match,300, {tuple,300, [{match,300, {atom,300,ok}, {tuple,300,[{var,300,'A'},{var,300,'B'}]}}]}, {call,300,{atom,300,id},[{var,300,'I'}]}}, {tuple,301,[{var,301,'A'},{var,301,'B'}]}]}]}. {function,303,entirely,0, [{clause,303,[],[], [{call,304, {integer,304,0}, [{match,304, {match,304, {match,304,{var,304,'Voice'},{atom,304,true}}, {atom,304,cool}}, {atom,304,job}}]}, {lc,305, {'receive',305, [{clause,305,[{var,305,'_'}],[],[{var,305,'Voice'}]}]}, [{generate,305,{atom,305,banking},{atom,305,printer}}]}]}]}. {function,307,printer,0, [{clause,307,[],[], [{tuple,308, [{match,308, {cons,308,{var,308,'Indoor'},{nil,308}}, {match,308,{nil,308},{atom,308,associates}}}]}, {lc,309, {atom,309,ireland}, [{generate,309,{var,309,'Indoor'},{var,309,'Indoor'}}]}]}]}. {function,311,tench,0, [{clause,311,[],[], [{match,312, {var,312,'E'}, {block,312, [{match,313, {cons,313,{var,313,'A'},{nil,313}}, {match,313,{nil,313},{atom,313,borogoves}}}, {op,314,'+',{var,314,'A'},{integer,314,1}}]}}, {op,316,'+', {var,316,'E'}, {op,316,'*',{integer,316,7},{var,316,'A'}}}]}]}. {function,318,perch,1, [{clause,318, [{var,318,'X'}], [], [{block,319, [{call,320, {atom,320,put}, [{atom,320,perch}, {op,320,'+', {call,320,{atom,320,get},[{atom,320,perch}]}, {integer,320,1}}]}, {match,321, {cons,321,{var,321,'A'},{nil,321}}, {match,321, {nil,321}, {tuple,321,[{atom,321,spine},{var,321,'X'}]}}}]}]}]}. {function,324,salmon,0, [{clause,324,[],[], [{tuple,325, [{call,325, {atom,325,put}, [{atom,325,salmon}, {op,325,'+', {call,325,{atom,325,get},[{atom,325,salmon}]}, {integer,325,1}}]}, {match,325, {map,325, [{map_field_exact,325, {atom,325,key}, {match,325, {cons,325,{var,325,'A'},{nil,325}}, {nil,325}}}]}, {atom,325,mimsy}}, {call,325,{atom,325,exit},[{atom,325,fail}]}]}, {op,326,'+',{var,326,'A'},{integer,326,10}}]}]}. {function,328,shark,0, [{clause,328,[],[], [{match,329, {match,329,{atom,329,hello},{atom,329,there}}, {'catch',329, {call,329, {atom,329,shark}, [{call,329, {atom,329,put}, [{atom,329,shark}, {op,329,'+', {call,329,{atom,329,get},[{atom,329,shark}]}, {integer,329,1}}]}, {match,329,{atom,329,a},{atom,329,b}}]}}}]}]}. {function,331,shark,2, [{clause,331,[{var,331,'_'},{var,331,'_'}],[],[{atom,332,ok}]}]}. {function,334,radio,1, [{clause,334, [{atom,334,research}], [], [{match,335, {match,335,{atom,335,connection},{atom,335,proof}}, {'catch',336, {call,336, {remote,336,{atom,336,erlang},{atom,336,trace_pattern}}, [{'catch',336, {op,336,'+', {atom,336,mechanisms}, {atom,336,assist}}}, {match,337, {atom,337,summary}, {atom,337,mechanisms}}]}}}]}]}. {function,341,match_in_call,1, [{clause,341, [{var,341,'Config'}], [[{call,341,{atom,341,is_list},[{var,341,'Config'}]}]], [{call,342,{atom,342,mac_a},[{integer,342,0}]}, {call,343,{atom,343,mac_b},[{integer,343,1}]}, {call,344,{atom,344,mac_c},[{integer,344,42}]}, {call,345,{atom,345,mac_d},[{integer,345,42}]}, {call,346, {atom,346,mac_e}, [{tuple,346,[{atom,346,gurka},{integer,346,42}]}]}, {match,348, {cons,348, {tuple,348,[{integer,348,2},{integer,348,2}]}, {cons,348, {tuple,348,[{integer,348,2},{integer,348,2}]}, {nil,348}}}, {call,348, {atom,348,mac_lc}, [{cons,348, {tuple,348,[{integer,348,2},{atom,348,any}]}, {cons,348, {tuple,348,[{integer,348,2},{integer,348,2}]}, {nil,348}}}]}}, {match,349, {tuple,349,[{atom,349,'EXIT'},{var,349,'_'}]}, {'catch',349, {call,349, {atom,349,mac_lc}, [{cons,349, {tuple,349,[{integer,349,1},{integer,349,1}]}, {nil,349}}]}}}, {atom,351,ok}]}]}. {function,353,mac_a,1, [{clause,353, [{var,353,'X'}], [], [{call,354, {atom,354,id}, [{match,354, {var,354,'_Gurka'}, {tuple,354,[{atom,354,gurka},{var,354,'X'}]}}]}, {atom,355,ok}]}]}. {function,357,mac_b,1, [{clause,357, [{var,357,'X'}], [], [{call,358, {atom,358,id}, [{match,358, {var,358,'Gurka'}, {tuple,358,[{atom,358,gurka},{var,358,'X'}]}}]}, {call,359,{atom,359,gurka},[{var,359,'Gurka'},{var,359,'X'}]}, {atom,360,ok}]}]}. {function,362,mac_c,1, [{clause,362, [{var,362,'X'}], [], [{call,363, {atom,363,id}, [{match,363, {var,363,'Gurka'}, {match,363, {var,363,'Yxa'}, {tuple,363,[{atom,363,gurka},{var,363,'X'}]}}}]}, {call,364, {atom,364,id}, [{tuple,364,[{var,364,'Gurka'},{var,364,'Yxa'}]}]}, {atom,365,ok}]}]}. {function,367,mac_d,1, [{clause,367, [{var,367,'X'}], [], [{call,368, {atom,368,id}, [{match,368, {tuple,368,[{atom,368,gurka},{integer,368,42}]}, {tuple,368,[{atom,368,gurka},{var,368,'X'}]}}]}, {atom,369,ok}]}]}. {function,371,mac_e,1, [{clause,371, [{var,371,'X'}], [], [{call,372, {atom,372,id}, [{match,372, {tuple,372,[{atom,372,gurka},{integer,372,42}]}, {var,372,'X'}}]}, {atom,373,ok}]}]}. {function,375,mac_lc,1, [{clause,375, [{var,375,'E'}], [], [{match,376, {var,376,'Res'}, {call,376,{atom,376,mac_lc1},[{var,376,'E'}]}}, {match,377, {var,377,'Res'}, {call,377,{atom,377,mac_lc2},[{var,377,'E'}]}}]}]}. {function,379,mac_lc1,1, [{clause,379, [{var,379,'E'}], [], [{lc,380, {tuple,380,[{var,380,'X'},{var,380,'Y'}]}, [{generate,381, {tuple,381,[{var,381,'X'},{var,381,'_'}]}, {var,381,'E'}}, {op,382,'=:=', {match,382,{var,382,'Y'},{var,382,'X'}}, {match,382, {var,382,'Y'}, {op,382,'+',{integer,382,1},{integer,382,1}}}}]}]}]}. {function,384,mac_lc2,1, [{clause,384, [{var,384,'E'}], [], [{lc,385, {tuple,385,[{var,385,'X'},{var,385,'Y'}]}, [{generate,386, {tuple,386,[{var,386,'X'},{var,386,'_'}]}, {var,386,'E'}}, {op,387,'=:=', {match,387,{var,387,'Y'},{var,387,'X'}}, {match,387,{var,387,'Y'},{integer,387,2}}}]}]}]}. {function,389,gurka,2, [{clause,389, [{tuple,389,[{atom,389,gurka},{var,389,'X'}]}, {var,389,'X'}], [], [{atom,389,ok}]}]}. {function,392,untuplify,1, [{clause,392, [{var,392,'Config'}], [[{call,392,{atom,392,is_list},[{var,392,'Config'}]}]], [{match,394, {tuple,394, [{integer,394,1}, {integer,394,2}, {integer,394,3}, {integer,394,4}, {atom,394,alias}, {tuple,394, [{cons,394, {integer,394,1}, {cons,394,{integer,394,2},{nil,394}}}, {tuple,394,[{integer,394,3},{integer,394,4}]}, {atom,394,alias}]}]}, {call,394, {atom,394,untuplify_1}, [{cons,394, {integer,394,1}, {cons,394,{integer,394,2},{nil,394}}}, {tuple,394,[{integer,394,3},{integer,394,4}]}, {atom,394,alias}]}}, {match,395, {atom,395,error}, {call,395, {atom,395,untuplify_1}, [{cons,395, {integer,395,1}, {cons,395,{integer,395,2},{nil,395}}}, {tuple,395,[{integer,395,3},{integer,395,4}]}, {integer,395,42}]}}, {match,400, {cons,400, {integer,400,33}, {cons,400, {op,400,'-',{integer,400,1}}, {cons,400, {op,400,'-',{integer,400,33}}, {cons,400,{integer,400,1},{nil,400}}}}}, {call,400, {atom,400,untuplify_2}, [{integer,400,32},{integer,400,65}]}}, {match,401, {tuple,401, [{integer,401,33}, {integer,401,1}, {op,401,'-',{integer,401,33}}, {op,401,'-',{integer,401,1}}]}, {call,401, {atom,401,untuplify_2}, [{integer,401,65},{integer,401,32}]}}, {atom,403,ok}]}]}. {function,405,untuplify_1,3, [{clause,405, [{var,405,'A'},{var,405,'B'},{var,405,'C'}], [], [{'case',406, {tuple,406,[{var,406,'A'},{var,406,'B'},{var,406,'C'}]}, [{clause,407, [{match,407, {tuple,407, [{cons,407, {var,407,'X'}, {cons,407,{var,407,'Y'},{nil,407}}}, {tuple,407,[{var,407,'Z'},{var,407,'W'}]}, {match,407,{atom,407,alias},{var,407,'Alias'}}]}, {var,407,'Top'}}], [], [{tuple,408, [{var,408,'X'}, {var,408,'Y'}, {var,408,'Z'}, {var,408,'W'}, {var,408,'Alias'}, {var,408,'Top'}]}]}, {clause,409, [{match,409, {cons,409, {var,409,'_'}, {cons,409,{var,409,'_'},{nil,409}}}, {var,409,'CantMatch'}}], [], [{var,410,'CantMatch'}]}, {clause,411,[{var,411,'_'}],[],[{atom,412,error}]}]}]}]}. {function,415,untuplify_2,2, [{clause,415, [{var,415,'V1'},{var,415,'V2'}], [], [{match,416, {tuple,416, [{var,416,'D1'}, {var,416,'D2'}, {var,416,'D3'}, {var,416,'D4'}]}, {'if',417, [{clause,417,[], [[{op,417,'>',{var,417,'V1'},{var,417,'V2'}}]], [{tuple,419, [{op,419,'-',{var,419,'V1'},{var,419,'V2'}}, {integer,419,1}, {op,419,'-',{var,419,'V2'},{var,419,'V1'}}, {op,419,'-',{integer,419,1}}]}]}, {clause,420,[], [[{atom,420,true}]], [{tuple,421, [{op,421,'-',{var,421,'V2'},{var,421,'V1'}}, {op,421,'-',{integer,421,1}}, {op,421,'-',{var,421,'V1'},{var,421,'V2'}}, {integer,421,1}]}]}]}}, {'if',423, [{clause,424,[], [[{op,424,'>',{var,424,'D2'},{var,424,'D4'}}]], [{tuple,425, [{var,425,'D1'}, {var,425,'D2'}, {var,425,'D3'}, {var,425,'D4'}]}]}, {clause,426,[], [[{atom,426,true}]], [{cons,427, {var,427,'D1'}, {cons,427, {var,427,'D2'}, {cons,427, {var,427,'D3'}, {cons,427,{var,427,'D4'},{nil,427}}}}}]}]}]}]}. {function,431,shortcut_boolean,1, [{clause,431, [{var,431,'Config'}], [[{call,431,{atom,431,is_list},[{var,431,'Config'}]}]], [{match,432, {atom,432,false}, {call,432, {atom,432,shortcut_boolean_1}, [{cons,432,{integer,432,0},{nil,432}}]}}, {match,433, {atom,433,true}, {call,433, {atom,433,shortcut_boolean_1}, [{tuple,433,[{integer,433,42}]}]}}, {match,434, {atom,434,maybe}, {call,434, {atom,434,shortcut_boolean_1}, [{call,434,{atom,434,self},[]}]}}, {match,435, {tuple,435,[{atom,435,'EXIT'},{var,435,'_'}]}, {'catch',435, {call,435, {atom,435,shortcut_boolean_1}, [{cons,435, {atom,435,a}, {cons,435,{atom,435,b},{nil,435}}}]}}}, {match,436, {tuple,436,[{atom,436,'EXIT'},{var,436,'_'}]}, {'catch',436, {call,436, {atom,436,shortcut_boolean_1}, [{tuple,436,[{atom,436,a},{atom,436,b}]}]}}}, {atom,437,ok}]}]}. {function,439,shortcut_boolean_1,1, [{clause,439, [{var,439,'X'}], [], [{match,440, {var,440,'Outer'}, {'case',440, {op,440,'not',{call,440,{atom,440,is_pid},[{var,440,'X'}]}}, [{clause,441, [{atom,441,true}], [], [{match,442, {var,442,'V'}, {'case',442, {var,442,'X'}, [{clause,443, [{cons,443,{var,443,'_'},{nil,443}}], [], [{atom,443,true}]}, {clause,444, [{tuple,444,[{var,444,'_'}]}], [], [{atom,444,false}]}]}}, {op,446,'not',{var,446,'V'}}]}, {clause,447,[{atom,447,false}],[],[{atom,448,maybe}]}]}}, {call,450,{atom,450,id},[{var,450,'Outer'}]}]}]}. {function,454,letify_guard,1, [{clause,454, [{var,454,'Config'}], [[{call,454,{atom,454,is_list},[{var,454,'Config'}]}]], [{match,455, {tuple,455, [{op,455,'-',{integer,455,15}}, {atom,455,a}]}, {call,455, {atom,455,letify_guard}, [{op,455,'-',{integer,455,15}}, {atom,455,a}]}}, {match,456, {integer,456,5}, {call,456, {atom,456,letify_guard}, [{integer,456,2},{integer,456,3}]}}, {atom,457,ok}]}]}. {function,459,letify_guard,2, [{clause,459, [{var,459,'A'},{var,459,'B'}], [], [{'case',460, {tuple,460,[{var,460,'A'},{var,460,'B'}]}, [{clause,462, [{var,462,'Z'}], [[{op,462,'=:=', {call,462,{atom,462,tuple_size},[{var,462,'Z'}]}, {integer,462,2}}, {op,462,'<', {call,462, {atom,462,element}, [{integer,462,1},{var,462,'Z'}]}, {integer,462,0}}]], [{var,464,'Z'}]}, {clause,465, [{tuple,465,[{var,465,'X'},{var,465,'Y'}]}], [], [{op,465,'+',{var,465,'X'},{var,465,'Y'}}]}]}]}]}. {function,471,selectify,1, [{clause,471, [{var,471,'Config'}], [[{call,471,{atom,471,is_list},[{var,471,'Config'}]}]], [{match,472, {atom,472,integer}, {call,472, {atom,472,sel_different_types}, [{tuple,472,[{atom,472,r},{integer,472,42}]}]}}, {match,473, {atom,473,atom}, {call,473, {atom,473,sel_different_types}, [{tuple,473,[{atom,473,r},{atom,473,forty_two}]}]}}, {match,474, {atom,474,float}, {call,474, {atom,474,sel_different_types}, [{tuple,474,[{atom,474,r},{float,474,100.0}]}]}}, {match,475, {atom,475,none}, {call,475, {atom,475,sel_different_types}, [{tuple,475,[{atom,475,r},{integer,475,18}]}]}}, {match,476, {tuple,476,[{atom,476,'EXIT'},{var,476,'_'}]}, {'catch',476, {call,476, {atom,476,sel_different_types}, [{cons,476, {atom,476,a}, {cons,476, {atom,476,b}, {cons,476,{atom,476,c},{nil,476}}}}]}}}, {match,478, {atom,478,integer}, {call,478, {atom,478,sel_same_value}, [{tuple,478,[{atom,478,r},{integer,478,42}]}]}}, {match,479, {atom,479,error}, {call,479, {atom,479,sel_same_value}, [{tuple,479,[{atom,479,r},{integer,479,100}]}]}}, {match,480, {atom,480,error}, {call,480,{atom,480,sel_same_value},[{atom,480,a}]}}, {match,482, {atom,482,integer42}, {call,482,{atom,482,sel_same_value2},[{integer,482,42}]}}, {match,483, {atom,483,integer43}, {call,483,{atom,483,sel_same_value2},[{integer,483,43}]}}, {match,484, {atom,484,error}, {call,484,{atom,484,sel_same_value2},[{integer,484,44}]}}, {atom,486,ok}]}]}. {function,488,sel_different_types,1, [{clause,488, [{match,488, {tuple,488,[{atom,488,r},{var,488,'_'}]}, {var,488,'T'}}], [[{op,488,'=:=', {call,488, {atom,488,element}, [{integer,488,2},{var,488,'T'}]}, {atom,488,forty_two}}]], [{atom,489,atom}]}, {clause,490, [{match,490, {tuple,490,[{atom,490,r},{var,490,'_'}]}, {var,490,'T'}}], [[{op,490,'=:=', {call,490, {atom,490,element}, [{integer,490,2},{var,490,'T'}]}, {integer,490,42}}]], [{atom,491,integer}]}, {clause,492, [{match,492, {tuple,492,[{atom,492,r},{var,492,'_'}]}, {var,492,'T'}}], [[{op,492,'=:=', {call,492, {atom,492,element}, [{integer,492,2},{var,492,'T'}]}, {float,492,100.0}}]], [{atom,493,float}]}, {clause,494, [{tuple,494,[{atom,494,r},{var,494,'_'}]}], [], [{atom,495,none}]}]}. {function,497,sel_same_value,1, [{clause,497, [{tuple,497,[{atom,497,r},{var,497,'V'}]}], [[{op,497,'=:=',{var,497,'V'},{integer,497,42}}]], [{atom,498,integer}]}, {clause,499, [{tuple,499,[{atom,499,r},{var,499,'V'}]}], [[{op,499,'=:=',{var,499,'V'},{integer,499,42}}]], [{atom,500,integer42}]}, {clause,501,[{var,501,'_'}],[],[{atom,502,error}]}]}. {function,504,sel_same_value2,1, [{clause,504, [{var,504,'V'}], [[{op,504,'=:=',{var,504,'V'},{integer,504,42}}]], [{atom,505,integer42}]}, {clause,506, [{var,506,'V'}], [[{op,506,'=:=',{var,506,'V'},{integer,506,42}}], [{op,506,'=:=',{var,506,'V'},{integer,506,43}}]], [{atom,507,integer43}]}, {clause,508,[{var,508,'_'}],[],[{atom,509,error}]}]}. {function,514,deselectify,1, [{clause,514, [{var,514,'Config'}], [[{call,514,{atom,514,is_list},[{var,514,'Config'}]}]], [{match,515, {atom,515,one_or_other}, {call,515, {atom,515,desel_tuple_arity}, [{tuple,515,[{integer,515,1}]}]}}, {match,516, {atom,516,two}, {call,516, {atom,516,desel_tuple_arity}, [{tuple,516,[{integer,516,1},{integer,516,1}]}]}}, {match,517, {atom,517,one_or_other}, {call,517, {atom,517,desel_tuple_arity}, [{tuple,517, [{integer,517,1},{integer,517,1},{integer,517,1}]}]}}, {match,519, {atom,519,one_or_other}, {call,519,{atom,519,dsel_integer},[{integer,519,1}]}}, {match,520, {atom,520,two}, {call,520,{atom,520,dsel_integer},[{integer,520,2}]}}, {match,521, {atom,521,one_or_other}, {call,521,{atom,521,dsel_integer},[{integer,521,3}]}}, {match,523, {atom,523,one_or_other}, {call,523,{atom,523,dsel_integer_typecheck},[{integer,523,1}]}}, {match,524, {atom,524,two}, {call,524,{atom,524,dsel_integer_typecheck},[{integer,524,2}]}}, {match,525, {atom,525,one_or_other}, {call,525,{atom,525,dsel_integer_typecheck},[{integer,525,3}]}}, {match,527, {atom,527,one_or_other}, {call,527,{atom,527,dsel_atom},[{atom,527,one}]}}, {match,528, {atom,528,two}, {call,528,{atom,528,dsel_atom},[{atom,528,two}]}}, {match,529, {atom,529,one_or_other}, {call,529,{atom,529,dsel_atom},[{atom,529,three}]}}, {match,531, {atom,531,one_or_other}, {call,531,{atom,531,dsel_atom_typecheck},[{atom,531,one}]}}, {match,532, {atom,532,two}, {call,532,{atom,532,dsel_atom_typecheck},[{atom,532,two}]}}, {match,533, {atom,533,one_or_other}, {call,533,{atom,533,dsel_atom_typecheck},[{atom,533,three}]}}, {match,538, {atom,538,stop}, {call,538,{atom,538,dsel_peek_0},[{atom,538,stop}]}}, {match,539, {atom,539,ignore}, {call,539,{atom,539,dsel_peek_0},[{atom,539,ignore}]}}, {match,540, {var,540,'Config'}, {call,540,{atom,540,dsel_peek_0},[{var,540,'Config'}]}}, {match,542, {atom,542,stop}, {call,542, {atom,542,dsel_peek_1}, [{atom,542,stop},{atom,542,any}]}}, {match,543, {var,543,'Config'}, {call,543, {atom,543,dsel_peek_1}, [{atom,543,ignore},{var,543,'Config'}]}}, {match,544, {atom,544,other}, {call,544, {atom,544,dsel_peek_1}, [{atom,544,other},{atom,544,ignored}]}}, {match,546, {integer,546,0}, {call,546, {atom,546,dsel_peek_2}, [{integer,546,0},{atom,546,any}]}}, {match,547, {var,547,'Config'}, {call,547, {atom,547,dsel_peek_2}, [{integer,547,1},{var,547,'Config'}]}}, {match,548, {integer,548,2}, {call,548, {atom,548,dsel_peek_2}, [{integer,548,2},{atom,548,ignored}]}}, {match,550, {atom,550,true}, {call,550,{atom,550,dsel_peek_3},[{atom,550,true}]}}, {match,551, {atom,551,false}, {call,551,{atom,551,dsel_peek_3},[{atom,551,false}]}}, {match,552, {tuple,552,[{atom,552,error},{var,552,'Config'}]}, {call,552,{atom,552,dsel_peek_3},[{var,552,'Config'}]}}, {atom,554,ok}]}]}. {function,559,desel_tuple_arity,1, [{clause,559, [{var,559,'Tuple'}], [[{call,559,{atom,559,is_tuple},[{var,559,'Tuple'}]}]], [{'case',560, {var,560,'Tuple'}, [{clause,561, [{tuple,561,[{var,561,'_'}]}], [], [{atom,561,one_or_other}]}, {clause,562, [{tuple,562,[{var,562,'_'},{var,562,'_'}]}], [], [{atom,562,two}]}, {clause,563,[{var,563,'_'}],[],[{atom,563,one_or_other}]}]}]}]}. {function,566,dsel_integer,1, [{clause,566, [{var,566,'Val'}], [], [{'case',567, {var,567,'Val'}, [{clause,568, [{integer,568,1}], [], [{atom,568,one_or_other}]}, {clause,569, [{integer,569,2}], [], [{atom,569,two}]}, {clause,570, [{var,570,'_'}], [], [{atom,570,one_or_other}]}]}]}]}. {function,573,dsel_integer_typecheck,1, [{clause,573, [{var,573,'Val'}], [[{call,573,{atom,573,is_integer},[{var,573,'Val'}]}]], [{'case',574, {var,574,'Val'}, [{clause,575, [{integer,575,1}], [], [{atom,575,one_or_other}]}, {clause,576, [{integer,576,2}], [], [{atom,576,two}]}, {clause,577, [{var,577,'_'}], [], [{atom,577,one_or_other}]}]}]}]}. {function,580,dsel_atom,1, [{clause,580, [{var,580,'Val'}], [], [{'case',581, {var,581,'Val'}, [{clause,582, [{atom,582,one}], [], [{atom,582,one_or_other}]}, {clause,583,[{atom,583,two}],[],[{atom,583,two}]}, {clause,584, [{var,584,'_'}], [], [{atom,584,one_or_other}]}]}]}]}. {function,587,dsel_atom_typecheck,1, [{clause,587, [{var,587,'Val'}], [[{call,587,{atom,587,is_atom},[{var,587,'Val'}]}]], [{'case',588, {var,588,'Val'}, [{clause,589, [{atom,589,one}], [], [{atom,589,one_or_other}]}, {clause,590,[{atom,590,two}],[],[{atom,590,two}]}, {clause,591, [{var,591,'_'}], [], [{atom,591,one_or_other}]}]}]}]}. {function,599,dsel_peek_0,1, [{clause,599, [{var,599,'A0'}], [], [{'case',600, {call,600,{atom,600,id},[{var,600,'A0'}]}, [{clause,601, [{atom,601,stop}], [], [{atom,601,stop}]}, {clause,602, [{atom,602,ignore}], [], [{atom,602,ignore}]}, {clause,603, [{var,603,'A'}], [], [{var,603,'A'}]}]}]}]}. {function,606,dsel_peek_1,2, [{clause,606, [{var,606,'A0'},{var,606,'B'}], [], [{'case',607, {call,607,{atom,607,id},[{var,607,'A0'}]}, [{clause,608, [{atom,608,stop}], [], [{atom,608,stop}]}, {clause,609, [{atom,609,ignore}], [], [{var,609,'B'}]}, {clause,610, [{var,610,'A'}], [], [{var,610,'A'}]}]}]}]}. {function,613,dsel_peek_2,2, [{clause,613, [{var,613,'A0'},{var,613,'B'}], [], [{'case',614, {call,614,{atom,614,id},[{var,614,'A0'}]}, [{clause,615, [{integer,615,0}], [], [{integer,615,0}]}, {clause,616,[{integer,616,1}],[],[{var,616,'B'}]}, {clause,617, [{var,617,'A'}], [], [{var,617,'A'}]}]}]}]}. {function,620,dsel_peek_3,1, [{clause,620, [{var,620,'A0'}], [], [{'case',621, {call,621,{atom,621,id},[{var,621,'A0'}]}, [{clause,622,[{atom,622,true}],[],[{atom,622,true}]}, {clause,623,[{atom,623,false}],[],[{atom,623,false}]}, {clause,624, [{var,624,'Other'}], [], [{tuple,624,[{atom,624,error},{var,624,'Other'}]}]}]}]}]}. {function,627,underscore,1, [{clause,627, [{var,627,'Config'}], [[{call,627,{atom,627,is_list},[{var,627,'Config'}]}]], [{'case',628, {var,628,'Config'}, [{clause,629, [{nil,629}], [], [{match,631, {var,631,'_'}, {call,631,{atom,631,length},[{var,631,'Config'}]}}]}, {clause,632, [{cons,632,{var,632,'_'},{var,632,'_'}}], [], [{match,634, {var,634,'_'}, {call,634, {atom,634,list_to_tuple}, [{var,634,'Config'}]}}]}]}, {match,636, {var,636,'_'}, {call,636,{atom,636,is_list},[{var,636,'Config'}]}}, {atom,637,ok}]}]}. {attribute,639,record, {s,[{record_field,639,{atom,639,map}}, {record_field,639,{atom,639,t}}]}}. {function,641,match_map,1, [{clause,641, [{var,641,'Config'}], [[{call,641,{atom,641,is_list},[{var,641,'Config'}]}]], [{match,642, {var,642,'Map'}, {map,642, [{map_field_assoc,642, {atom,642,key}, {tuple,642,[{atom,642,x},{atom,642,y}]}}, {map_field_assoc,642, {atom,642,ignore}, {atom,642,anything}}]}}, {match,643, {record,643,s, [{record_field,643,{atom,643,map},{var,643,'Map'}}, {record_field,643, {atom,643,t}, {tuple,643,[{atom,643,x},{atom,643,y}]}}]}, {call,643, {atom,643,do_match_map}, [{record,643,s, [{record_field,643,{atom,643,map},{var,643,'Map'}}]}]}}, {match,644, {tuple,644, [{atom,644,a}, {map,644, [{map_field_exact,644, {atom,644,k}, {tuple,644, [{atom,644,a},{atom,644,b},{atom,644,c}]}}]}]}, {call,644, {atom,644,do_match_map_2}, [{map,644, [{map_field_assoc,644, {atom,644,k}, {tuple,644, [{atom,644,a}, {atom,644,b}, {atom,644,c}]}}]}]}}, {atom,645,ok}]}]}. {function,647,do_match_map,1, [{clause,647, [{match,647, {record,647,s, [{record_field,647, {atom,647,map}, {map,647, [{map_field_exact,647, {atom,647,key}, {var,647,'Val'}}]}}]}, {var,647,'S'}}], [], [{record,649, {var,649,'S'}, s, [{record_field,649,{atom,649,t},{var,649,'Val'}}]}]}]}. {function,651,do_match_map_2,1, [{clause,651, [{var,651,'Map'}], [], [{'case',652, {tuple,652,[{atom,652,a},{var,652,'Map'}]}, [{clause,653, [{match,653, {tuple,653, [{atom,653,a}, {map,653, [{map_field_exact,653, {atom,653,k}, {var,653,'_'}}]}]}, {var,653,'Tuple'}}], [], [{var,654,'Tuple'}]}]}]}]}. {function,657,map_vars_used,1, [{clause,657, [{var,657,'Config'}], [[{call,657,{atom,657,is_list},[{var,657,'Config'}]}]], [{match,658, {tuple,658,[{atom,658,some},{atom,658,value}]}, {call,658, {atom,658,do_map_vars_used}, [{atom,658,a}, {atom,658,b}, {map,658, [{map_field_assoc,658, {tuple,658,[{atom,658,a},{atom,658,b}]}, {integer,658,42}}, {map_field_assoc,658, {atom,658,v}, {tuple,658, [{atom,658,some},{atom,658,value}]}}]}]}}, {atom,659,ok}]}]}. {function,661,do_map_vars_used,3, [{clause,661, [{var,661,'X'},{var,661,'Y'},{var,661,'Map'}], [], [{'case',662, {tuple,662,[{var,662,'X'},{var,662,'Y'}]}, [{clause,663, [{var,663,'T'}], [], [{match,665, {map,665, [{map_field_exact,665, {var,665,'T'}, {integer,665,42}}, {map_field_exact,665, {atom,665,v}, {var,665,'Val'}}]}, {var,665,'Map'}}, {var,666,'Val'}]}]}]}]}. {attribute,669,record, {coverage_id,[{record_field,669,{atom,669,bool},{atom,669,false}}, {record_field,669,{atom,669,id}}]}}. {function,670,coverage,1, [{clause,670, [{var,670,'Config'}], [[{call,670,{atom,670,is_list},[{var,670,'Config'}]}]], [{match,672, {atom,672,ok}, {call,672,{atom,672,coverage_1},[{atom,672,x},{atom,672,a}]}}, {match,673, {atom,673,ok}, {call,673,{atom,673,coverage_1},[{atom,673,x},{atom,673,b}]}}, {match,676, {atom,676,ok}, {call,676,{atom,676,coverage_3},[{string,676,"abc"}]}}, {match,679, {tuple,679,[{atom,679,expr},{atom,679,key}]}, {call,679, {atom,679,coverage_4}, [{cons,679, {atom,679,literal}, {cons,679,{atom,679,get},{nil,679}}}, {cons,679, {cons,679, {atom,679,expr}, {cons,679,{atom,679,key},{nil,679}}}, {nil,679}}]}}, {match,680, {tuple,680,[{atom,680,expr},{atom,680,key}]}, {call,680, {atom,680,coverage_4}, [{cons,680, {atom,680,expr}, {cons,680,{atom,680,key},{nil,680}}}, {nil,680}]}}, {match,682, {atom,682,a}, {call,682, {atom,682,coverage_5}, [{cons,682, {integer,682,8}, {cons,682, {integer,682,8}, {cons,682,{integer,682,8},{nil,682}}}}, {record,682,coverage_id, [{record_field,682, {atom,682,bool}, {atom,682,true}}]}]}}, {match,683, {atom,683,b}, {call,683, {atom,683,coverage_5}, [{nil,683}, {record,683,coverage_id, [{record_field,683, {atom,683,bool}, {atom,683,true}}]}]}}, {match,686,{atom,686,ok},{call,686,{atom,686,coverage_6},[]}}, {atom,688,ok}]}]}. {function,690,coverage_1,2, [{clause,690, [{var,690,'B'},{var,690,'Tag'}], [], [{'case',691, {var,691,'Tag'}, [{clause,692, [{atom,692,a}], [], [{call,692, {atom,692,coverage_2}, [{integer,692,1},{atom,692,a},{var,692,'B'}]}]}, {clause,693, [{atom,693,b}], [], [{call,693, {atom,693,coverage_2}, [{integer,693,2},{atom,693,b},{var,693,'B'}]}]}]}]}]}. {function,696,coverage_2,3, [{clause,696, [{integer,696,1},{atom,696,a},{atom,696,x}], [], [{atom,696,ok}]}, {clause,697, [{integer,697,2},{atom,697,b},{atom,697,x}], [], [{atom,697,ok}]}]}. {function,699,coverage_3,1, [{clause,699, [{op,699,'++', {cons,699,{char,699,97},{nil,699}}, {op,699,'++',{nil,699},{string,699,"bc"}}}], [], [{atom,699,ok}]}]}. {function,702,coverage_4,2, [{clause,702, [{cons,702, {atom,702,literal}, {cons,702,{atom,702,get},{nil,702}}}, {cons,702,{var,702,'Expr'},{nil,702}}], [], [{call,703, {atom,703,coverage_4}, [{var,703,'Expr'},{nil,703}]}]}, {clause,704, [{cons,704, {var,704,'Expr'}, {cons,704,{var,704,'Key'},{nil,704}}}, {nil,704}], [], [{tuple,705,[{var,705,'Expr'},{var,705,'Key'}]}]}]}. {function,708,coverage_5,2, [{clause,708, [{var,708,'Config'},{var,708,'TermId'}], [[{op,709,'=:=', {var,709,'TermId'}, {record,709,coverage_id, [{record_field,709,{atom,709,bool},{atom,709,true}}]}}, {op,710,'=:=', {var,710,'Config'}, {cons,710, {integer,710,8}, {cons,710, {integer,710,8}, {cons,710,{integer,710,8},{nil,710}}}}}]], [{atom,711,a}]}, {clause,712, [{var,712,'_Config'}, {record,712,coverage_id, [{record_field,712,{atom,712,bool},{atom,712,true}}]}], [], [{atom,713,b}]}]}. {function,715,coverage_6,0, [{clause,715,[],[], [{match,716,{var,716,'X'},{integer,716,17}}, {'case',717, {'case',718, {op,718,'>', {call,718,{atom,718,id},[{integer,718,1}]}, {integer,718,0}}, [{clause,719,[{atom,719,true}],[],[{integer,720,17}]}, {clause,721,[{atom,721,false}],[],[{integer,722,42}]}]}, [{clause,725,[{var,725,'X'}],[],[{atom,726,ok}]}, {clause,727, [{var,727,'V'}], [], [{call,729, {atom,729,error}, [{cons,729, {atom,729,error}, {cons,729, {var,729,'X'}, {cons,729, {var,729,'V'}, {nil,729}}}}]}]}]}]}]}. {function,732,grab_bag,1, [{clause,732, [{var,732,'_Config'}], [], [{match,733, {cons,733,{var,733,'_'},{var,733,'T'}}, {call,733, {atom,733,id}, [{cons,733, {atom,733,a}, {cons,733,{atom,733,b},{cons,733,{atom,733,c},{nil,733}}}}]}}, {match,734, {cons,734,{atom,734,b},{cons,734,{atom,734,c},{nil,734}}}, {call,734,{atom,734,id},[{var,734,'T'}]}}, {match,736, {var,736,'T1'}, {'fun',736, {clauses, [{clause,736,[],[], [{match,737, {cons,737,{var,737,'_'},{var,737,'_'}}, {atom,737,x}}]}]}}}, {match,739, {tuple,739,[{atom,739,'EXIT'},{var,739,'_'}]}, {'catch',739,{call,739,{var,739,'T1'},[]}}}, {match,741, {var,741,'T2'}, {'fun',741, {clauses, [{clause,741, [{var,741,'A'},{var,741,'B'}], [], [{'case',742, {tuple,742, [{tuple,742, [{call,742,{atom,742,element},[{integer,742,1},{var,742,'A'}]}, {call,742,{atom,742,element},[{integer,742,2},{var,742,'B'}]}]}, {tuple,743, [{call,743,{atom,743,element},[{integer,743,2},{var,743,'A'}]}, {call,743, {atom,743,element}, [{integer,743,2},{var,743,'B'}]}]}]}, [{clause,744, [{tuple,744,[{var,744,'Same'},{var,744,'Same'}]}], [], [{atom,744,ok}]}, {clause,745, [{tuple,745, [{tuple,745,[{integer,745,0},{integer,745,1}]}, {tuple,745,[{atom,745,up},{var,745,'X'}]}]}], [], [{call,745,{atom,745,id},[{var,745,'X'}]}]}, {clause,746, [{tuple,746, [{var,746,'_'},{tuple,746,[{var,746,'X'},{var,746,'_'}]}]}], [], [{call,746,{atom,746,id},[{var,746,'X'}]}]}]}]}]}}}, {match,749, {atom,749,ok}, {call,749, {var,749,'T2'}, [{tuple,749,[{atom,749,a},{atom,749,a},{atom,749,z},{atom,749,z}]}, {tuple,749,[{atom,749,z},{atom,749,a},{atom,749,z}]}]}}, {match,750, {integer,750,1}, {call,750, {var,750,'T2'}, [{tuple,750,[{integer,750,0},{atom,750,up}]}, {tuple,750,[{atom,750,zzz},{integer,750,1}]}]}}, {match,751, {atom,751,y}, {call,751, {var,751,'T2'}, [{tuple,751,[{atom,751,x},{atom,751,y}]}, {tuple,751,[{atom,751,a},{atom,751,z},{atom,751,z}]}]}}, {match,754, {var,754,'L'}, {cons,754, {tuple,754,[{atom,754,stretch},{integer,754,0},{integer,754,0}]}, {cons,755, {tuple,755,[{atom,755,bad},{nil,755}]}, {cons,756, {tuple,756,[{atom,756,bad},{atom,756,atom}]}, {cons,757, {tuple,757,[{atom,757,bad},{integer,757,0}]}, {cons,758, {tuple,758, [{atom,758,bad}, {integer,758, 17140672472095896272447595651639067760236831933683123576548010}]}, {cons,759, {tuple,759, [{atom,759,bad}, {integer,759, 8570336236047948136223797825819533880118415966841561788274005}]}, {nil,759}}}}}}}}, {match,760, {atom,760,ok}, {call,760, {atom,760,grab_bag_remove_failure}, [{var,760,'L'},{atom,760,unit},{integer,760,0}]}}, {match,762, {tuple,762, [{integer,762,42}, {bin,762, [{bin_element,762,{integer,762,43},default,default}, {bin_element,762,{integer,762,44},default,default}]}]}, {call,762, {atom,762,grab_bag_single_valued}, [{bin,762, [{bin_element,762,{integer,762,42},default,default}, {bin_element,762,{integer,762,43},default,default}, {bin_element,762,{integer,762,44},default,default}]}]}}, {match,763, {atom,763,empty_list}, {call,763,{atom,763,grab_bag_single_valued},[{nil,763}]}}, {match,764, {atom,764,empty_tuple}, {call,764,{atom,764,grab_bag_single_valued},[{tuple,764,[]}]}}, {atom,766,ok}]}]}. {function,768,grab_bag_remove_failure,3, [{clause,768, [{nil,768},{var,768,'_Unit'},{var,768,'_MaxFailure'}], [], [{atom,769,ok}]}, {clause,770, [{cons,770, {tuple,770,[{atom,770,bad},{var,770,'Bad'}]}, {var,770,'_'}}, {var,770,'_Unit'}, {var,770,'_MaxFailure'}], [], [{var,771,'Bad'}]}, {clause,772, [{cons,772, {match,772, {tuple,772, [{atom,772,stretch},{var,772,'_'},{var,772,'Mi'}]}, {var,772,'Stretch'}}, {var,772,'Specs'}}, {var,772,'Unit'}, {var,772,'_MaxFailure'}], [], [{match,773, {tuple,773,[{var,773,'MinMax'},{var,773,'NewMaxFailure'}]}, {call,773, {atom,773,id}, [{tuple,773,[{atom,773,min},{integer,773,1}]}]}}, {'case',774, {tuple,774, [{var,774,'MinMax'}, {call,774, {atom,774,grab_bag_remove_failure}, [{var,774,'Specs'}, {var,774,'Unit'}, {var,774,'NewMaxFailure'}]}]}, [{clause,775, [{tuple,775, [{atom,775,min}, {tuple,775, [{var,775,'NewMaxFailure'},{var,775,'Rest'}]}]}], [], [{tuple,776, [{atom,776,done}, {cons,776, {tuple,776,[{atom,776,fixed},{var,776,'Mi'}]}, {var,776,'Rest'}}]}]}, {clause,777, [{tuple,777,[{atom,777,min},{var,777,'_'}]}], [[{op,777,'=/=',{var,777,'Specs'},{nil,777}}]], [{call,778, {atom,778,grab_bag_remove_failure}, [{cons,778, {var,778,'Stretch'}, {call,778,{atom,778,tl},[{var,778,'Specs'}]}}, {var,778,'Unit'}, {var,778,'NewMaxFailure'}]}]}, {clause,779, [{tuple,779,[{atom,779,min},{var,779,'_'}]}], [], [{atom,780,ok}]}]}]}]}. {function,784,grab_bag_single_valued,1, [{clause,784, [{bin,784, [{bin_element,784,{var,784,'H'},default,default}, {bin_element,784,{var,784,'T'},default,[bytes]}]}], [], [{tuple,784,[{var,784,'H'},{var,784,'T'}]}]}, {clause,785,[{nil,785}],[],[{atom,785,empty_list}]}, {clause,786,[{tuple,786,[]}],[],[{atom,786,empty_tuple}]}]}. {function,790,literal_binary,1, [{clause,790, [{var,790,'_Config'}], [], [{match,791, {integer,791,3}, {call,791, {atom,791,literal_binary_match}, [{atom,791,bar}, {bin,791, [{bin_element,791, {string,791,"y"}, default,default}]}]}}, {match,795, {integer,795,1}, {call,795, {atom,795,literal_binary_match}, [{atom,795,bar}, {bin,795, [{bin_element,795, {string,795,"x"}, default,default}]}]}}, {match,796, {integer,796,2}, {call,796, {atom,796,literal_binary_match}, [{atom,796,foo}, {bin,796, [{bin_element,796, {string,796,"x"}, default,default}]}]}}, {match,797, {integer,797,3}, {call,797, {atom,797,literal_binary_match}, [{atom,797,foo}, {bin,797, [{bin_element,797, {string,797,"y"}, default,default}]}]}}, {match,798, {atom,798,fail}, {call,798, {atom,798,literal_binary_match}, [{atom,798,bar}, {bin,798, [{bin_element,798, {string,798,"z"}, default,default}]}]}}, {match,799, {atom,799,fail}, {call,799, {atom,799,literal_binary_match}, [{atom,799,foo}, {bin,799, [{bin_element,799, {string,799,"z"}, default,default}]}]}}, {atom,800,ok}]}]}. {function,802,literal_binary_match,2, [{clause,802, [{atom,802,bar}, {bin,802,[{bin_element,802,{string,802,"x"},default,default}]}], [], [{integer,802,1}]}, {clause,803, [{var,803,'_'}, {bin,803,[{bin_element,803,{string,803,"x"},default,default}]}], [], [{integer,803,2}]}, {clause,804, [{var,804,'_'}, {bin,804,[{bin_element,804,{string,804,"y"},default,default}]}], [], [{integer,804,3}]}, {clause,805,[{var,805,'_'},{var,805,'_'}],[],[{atom,805,fail}]}]}. {function,807,unary_op,1, [{clause,807, [{var,807,'Config'}], [], [{match,812, {tuple,812, [{atom,812,non_associative}, {integer,812,30}]}, {call,812,{atom,812,unary_op_1},[{atom,812,'&'}]}}, {match,813, {tuple,813, [{atom,813,non_associative}, {integer,813,300}]}, {call,813,{atom,813,unary_op_1},[{atom,813,'^'}]}}, {match,814, {tuple,814, [{atom,814,non_associative}, {integer,814,300}]}, {call,814, {atom,814,unary_op_1}, [{atom,814,'not'}]}}, {match,815, {tuple,815, [{atom,815,non_associative}, {integer,815,300}]}, {call,815,{atom,815,unary_op_1},[{atom,815,'+'}]}}, {match,816, {tuple,816, [{atom,816,non_associative}, {integer,816,300}]}, {call,816,{atom,816,unary_op_1},[{atom,816,'-'}]}}, {match,817, {tuple,817, [{atom,817,non_associative}, {integer,817,300}]}, {call,817, {atom,817,unary_op_1}, [{atom,817,'~~~'}]}}, {match,818, {tuple,818, [{atom,818,non_associative}, {integer,818,300}]}, {call,818,{atom,818,unary_op_1},[{atom,818,'!'}]}}, {match,819, {tuple,819, [{atom,819,non_associative}, {integer,819,320}]}, {call,819,{atom,819,unary_op_1},[{atom,819,'@'}]}}, {match,821, {atom,821,error}, {call,821, {atom,821,unary_op_1}, [{var,821,'Config'}]}}, {match,822, {atom,822,error}, {call,822,{atom,822,unary_op_1},[{atom,822,abc}]}}, {match,823, {atom,823,error}, {call,823, {atom,823,unary_op_1}, [{integer,823,42}]}}, {atom,825,ok}]}]}. {function,827,unary_op_1,1, [{clause,827, [{var,827,'Vop@1'}], [], [{'case',832, {op,832,'=:=',{var,832,'Vop@1'},{atom,832,'&'}}, [{clause,833, [{atom,833,true}], [], [{tuple,834,[{atom,834,non_associative},{integer,834,30}]}]}, {clause,835, [{atom,835,false}], [], [{'case',836, {'case',837, {op,837,'=:=',{var,837,'Vop@1'},{atom,837,'^'}}, [{clause,838,[{atom,838,true}],[],[{atom,839,true}]}, {clause,840, [{atom,840,false}], [], [{'case',841, {op,841,'=:=',{var,841,'Vop@1'},{atom,841,'not'}}, [{clause,842,[{atom,842,true}],[],[{atom,843,true}]}, {clause,844, [{atom,844,false}], [], [{'case',845, {op,845,'=:=',{var,845,'Vop@1'},{atom,845,'+'}}, [{clause,846,[{atom,846,true}],[],[{atom,847,true}]}, {clause,848, [{atom,848,false}], [], [{'case',849, {op,849,'=:=',{var,849,'Vop@1'},{atom,849,'-'}}, [{clause,850,[{atom,850,true}],[],[{atom,851,true}]}, {clause,852, [{atom,852,false}], [], [{'case',853, {op,853,'=:=',{var,853,'Vop@1'},{atom,853,'~~~'}}, [{clause,854,[{atom,854,true}],[],[{atom,855,true}]}, {clause,856, [{atom,856,false}], [], [{op,857,'=:=', {var,857,'Vop@1'}, {atom,857,'!'}}]}]}]}]}]}]}]}]}]}]}, [{clause,864, [{atom,864,true}], [], [{tuple,865,[{atom,865,non_associative},{integer,865,300}]}]}, {clause,866, [{atom,866,false}], [], [{'case',867, {op,867,'=:=',{var,867,'Vop@1'},{atom,867,'@'}}, [{clause,868, [{atom,868,true}], [], [{tuple,869,[{atom,869,non_associative},{integer,869,320}]}]}, {clause,870, [{atom,870,false}], [], [{atom,871,error}]}]}]}]}]}]}]}]}. {function,876,eq_types,1, [{clause,876, [{var,876,'_Config'}], [], [{match,877, {var,877,'Ref'}, {call,877,{atom,877,make_ref},[]}}, {match,878, {var,878,'Ref'}, {call,878, {atom,878,eq_types}, [{var,878,'Ref'},{atom,878,any}]}}, {atom,879,ok}]}]}. {function,881,eq_types,2, [{clause,881, [{var,881,'A'},{var,881,'B'}], [], [{match,883, {var,883,'Term0'}, {tuple,883,[{var,883,'A'},{var,883,'B'}]}}, {match,884, {var,884,'Term'}, {call,884,{atom,884,id},[{var,884,'Term0'}]}}, {match,889,{var,889,'Term'},{var,889,'Term0'}}, {match,892, {tuple,892,[{var,892,'Ref22'},{var,892,'_'}]}, {var,892,'Term'}}, {var,894,'Ref22'}]}]}. {function,896,match_after_return,1, [{clause,896, [{var,896,'Config'}], [[{call,896,{atom,896,is_list},[{var,896,'Config'}]}]], [{match,900, {atom,900,ok}, {'case',900, {call,900, {atom,900,mar_test_tuple}, [{call,900, {remote,900, {atom,900,erlang}, {atom,900,unique_integer}}, []}]}, [{clause,901, [{tuple,901, [{atom,901,gurka}, {atom,901,never_matches}, {var,901,'A'}]}], [], [{tuple,901,[{atom,901,wont_happen},{var,901,'A'}]}]}, {clause,902,[{var,902,'_'}],[],[{atom,902,ok}]}]}}]}]}. {function,905,mar_test_tuple,1, [{clause,905, [{var,905,'I'}], [], [{tuple,905,[{atom,905,gurka},{var,905,'I'}]}]}]}. {function,907,match_right_tuple,1, [{clause,907, [{var,907,'Config'}], [[{call,907,{atom,907,is_list},[{var,907,'Config'}]}]], [{match,915, {var,915,'Inner'}, {tuple,915, [{call,915,{atom,915,id},[{atom,915,wrong_element}]}, {call,915,{atom,915,id},[{atom,915,ok}]}]}}, {match,916, {var,916,'Outer'}, {tuple,916, [{var,916,'Inner'}, {call,916,{atom,916,id},[{atom,916,wrong_tuple}]}]}}, {match,917, {atom,917,ok}, {call,917, {atom,917,match_right_tuple_1}, [{var,917,'Outer'}]}}]}]}. {function,919,match_right_tuple_1,1, [{clause,919, [{var,919,'T'}], [], [{match,920, {tuple,920,[{var,920,'A'},{var,920,'_'}]}, {var,920,'T'}}, {match,921, {tuple,921,[{var,921,'_'},{var,921,'B'}]}, {var,921,'A'}}, {call,923, {atom,923,id}, [{call,923, {atom,923,force_succ_regs}, [{var,923,'A'},{var,923,'B'}]}]}]}]}. {function,925,force_succ_regs,2, [{clause,925,[{var,925,'_A'},{var,925,'B'}],[],[{var,925,'B'}]}]}. {function,927,tuple_size_in_try,1, [{clause,927, [{var,927,'Config'}], [[{call,927,{atom,927,is_list},[{var,927,'Config'}]}]], [{match,930, {atom,930,ok}, {call,930,{atom,930,tsit},[{atom,930,gurka}]}}, {match,931, {atom,931,ok}, {call,931,{atom,931,tsit},[{atom,931,gaffel}]}}]}]}. {function,933,tsit,1, [{clause,933, [{var,933,'A'}], [], [{'try',934, [{call,935,{atom,935,id},[{atom,935,ignored}]}, {match,936, {integer,936,1}, {call,936,{atom,936,tuple_size},[{var,936,'A'}]}}, {atom,937,error}], [], [{clause,939, [{tuple,939,[{var,939,'_'},{var,939,'_'},{var,939,'_'}]}], [], [{atom,939,ok}]}], []}]}]}. {function,942,match_boolean_list,1, [{clause,942, [{var,942,'Config'}], [[{call,942,{atom,942,is_list},[{var,942,'Config'}]}]], [{match,943, {var,943,'BoolList'}, {lc,943, {op,943,'=:=', {op,943,'rem',{var,943,'N'},{integer,943,2}}, {integer,943,0}}, [{generate,943, {var,943,'N'}, {call,943, {remote,943,{atom,943,lists},{atom,943,seq}}, [{integer,943,1},{integer,943,8}]}}]}}, {match,950, {atom,950,ok}, {'case',950, {var,950,'BoolList'}, [{clause,951, [{cons,951,{atom,951,true},{var,951,'_'}}], [], [{atom,951,error}]}, {clause,952, [{cons,952,{atom,952,false},{var,952,'_'}}], [], [{atom,952,ok}]}]}}]}]}. {function,955,id,1,[{clause,955,[{var,955,'I'}],[],[{var,955,'I'}]}]}. {eof,956}. ================================================ FILE: test_data/match_SUITE.erl ================================================ %% %% %CopyrightBegin% %% %% Copyright Ericsson AB 2004-2019. All Rights Reserved. %% %% 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. %% %% %CopyrightEnd% %% -module(match_SUITE). -export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1, init_per_group/2,end_per_group/2, pmatch/1,mixed/1,aliases/1,non_matching_aliases/1, match_in_call/1,untuplify/1,shortcut_boolean/1,letify_guard/1, selectify/1,deselectify/1,underscore/1,match_map/1,map_vars_used/1, coverage/1,grab_bag/1,literal_binary/1, unary_op/1,eq_types/1,match_after_return/1,match_right_tuple/1, tuple_size_in_try/1,match_boolean_list/1]). -include_lib("common_test/include/ct.hrl"). suite() -> [{ct_hooks,[ts_install_cth]}]. all() -> [{group,p}]. groups() -> [{p,[parallel], [pmatch,mixed,aliases,non_matching_aliases, match_in_call,untuplify, shortcut_boolean,letify_guard,selectify,deselectify, underscore,match_map,map_vars_used,coverage, grab_bag,literal_binary,unary_op,eq_types, match_after_return,match_right_tuple, tuple_size_in_try,match_boolean_list]}]. init_per_suite(Config) -> test_lib:recompile(?MODULE), Config. end_per_suite(_Config) -> ok. init_per_group(_GroupName, Config) -> Config. end_per_group(_GroupName, Config) -> Config. pmatch(Config) when is_list(Config) -> ok = doit(1), ok = doit(2), {error,baz} = doit(3), {error,foobar} = doit(4), ok. %% Thanks to Tobias Lindahl (HiPE). -define(FOO(X), case X of 1 -> foo; 2 -> bar; 3 -> baz; 4 -> foobar end). doit(X) -> case ?FOO(X) of foo -> ok; bar -> ok; Other -> {error, Other} end. mixed(Config) when is_list(Config) -> glufs = mixit(1), klafs = mixit(2), fnurra = mixit(3), usch = mixit(4), {error,blurf} = mixit(5), {error,87987987} = mixit(6), {error,{a,b,c}} = mixit(7), ok. mixit(X) -> case case X of 1 -> a; 2 -> b; 3 -> 42; 4 -> 77; 4+1 -> blurf; 5+1 -> 87987987; 6+1 -> {a,b,c} end of a -> glufs; b -> klafs; 42 -> fnurra; 77 -> usch; Other -> {error,Other} end. aliases(Config) when is_list(Config) -> %% Lists/strings. ok = str_alias("abc"), ok = str_alias("def"), ok = str_alias("ghi"), ok = str_alias("klm"), ok = str_alias("qrs"), ok = str_alias("xy"), ok = str_alias(""), ok = str_alias([]), error = str_alias("blurf"), %% Characters/integers. ok = char_alias($v), ok = char_alias(118), ok = char_alias($w), ok = char_alias(119), ok = char_alias(42), ok = char_alias(3.0), error = char_alias($_), error = char_alias(0), {42,42,42} = three(42), {1,42,99,1,42,99} = tuple_alias({1,42,99}), {-10,20,-10,20,-10,20} = tuple_alias({-10,20}), 6 = tup_lit_alias({1,2,3}), 6 = tup_lit_alias_rev({1,2,3}), {42,42,42,42} = multiple_aliases_1(42), {7,7,7} = multiple_aliases_2(7), {{a,b},{a,b},{a,b}} = multiple_aliases_3({a,b}), %% Lists/literals. {a,b} = list_alias1([a,b]), {a,b} = list_alias2([a,b]), {a,b} = list_alias3([a,b]), ok. str_alias(V) -> Res = str_alias_1(V), Res = str_alias_2(V). str_alias_1([$a,$b,$c]="abc"="a"++[$b,$c]=[97,98,99]) -> ok; str_alias_1([$d|"ef"]="def") -> ok; str_alias_1([$g|"hi"]="g"++"hi"="gh"++"i"="ghi"++"") -> ok; str_alias_1("k"++"lm"=[$k|"lm"]) -> ok; str_alias_1([113,114,115]="qrs"=[$q,$r,$s]="q"++"r"++"s") -> ok; str_alias_1([$x,$y]="xy") -> ok; str_alias_1(""=[]) -> ok; str_alias_1(_) -> error. %% Make sure that different line numbers do not matter. str_alias_2([$a,$b,$c]= "abc"= "a"++[$b,$c ]= [97,98,99 ]) -> ok; str_alias_2([$d|"ef"]= "def") -> ok; str_alias_2([$g|"hi"]= "g"++"hi"= "gh"++"i"= "ghi"++"") -> ok; str_alias_2("k"++"lm"= [$k|"lm" ]) -> ok; str_alias_2([113,114,115]= "qrs"=[$q,$r,$s ]= "q"++"r"++"s") -> ok; str_alias_2([$x,$y]= "xy") -> ok; str_alias_2(""= []) -> ok; str_alias_2(_) -> error. char_alias(V) -> Res = char_alias_1(V), Res = char_alias_2(V). char_alias_1(118=$v) -> ok; char_alias_1($w=119) -> ok; char_alias_1(42=42) -> ok; char_alias_1(3.0=3.0) -> ok; char_alias_1(_) -> error. char_alias_2(118= $v) -> ok; char_alias_2($w= 119) -> ok; char_alias_2(42= 42) -> ok; char_alias_2(3.0= 3.0) -> ok; char_alias_2(_) -> error. three(V) -> Res = three_1(V), Res = three_2(V). three_1(A=B=C) -> {A,B,C}. three_2(A= B= C) -> {A,B,C}. tuple_alias({A,B,C}={X,Y,Z}) -> {A,B,C,X,Y,Z}; tuple_alias({A,B}={C,D}={E,F}) -> {A,B,C,D,E,F}. tup_lit_alias({A,B,C}={1,2,3}) -> A+B+C. tup_lit_alias_rev({1,2,3}={A,B,C}) -> A+B+C. multiple_aliases_1((A=B)=(C=D)) -> {A,B,C,D}. multiple_aliases_2((A=B)=(A=C)) -> {A,B,C}. multiple_aliases_3((A={_,_}=B)={_,_}=C) -> {A,B,C}. list_alias1([a,b]=[X,Y]) -> {X,Y}. list_alias2([X,Y]=[a,b]) -> {X,Y}. list_alias3([X,b]=[a,Y]) -> {X,Y}. non_matching_aliases(_Config) -> none = mixed_aliases(<<42>>), none = mixed_aliases([b]), none = mixed_aliases([d]), none = mixed_aliases({a,42}), none = mixed_aliases(42), none = mixed_aliases(<<6789:16>>), none = mixed_aliases(#{key=>value}), {'EXIT',{{badmatch,42},_}} = (catch nomatch_alias(42)), {'EXIT',{{badmatch,job},_}} = (catch entirely()), {'EXIT',{{badmatch,associates},_}} = (catch printer()), {'EXIT',{{badmatch,borogoves},_}} = (catch tench()), put(perch, 0), {'EXIT',{{badmatch,{spine,42}},_}} = (catch perch(42)), 1 = erase(perch), put(salmon, 0), {'EXIT',{{badmatch,mimsy},_}} = (catch salmon()), 1 = erase(salmon), put(shark, 0), {'EXIT',{{badmatch,_},_}} = (catch shark()), 1 = erase(shark), {'EXIT',{{badmatch,_},_}} = (catch radio(research)), ok. mixed_aliases(<> = x) -> {a,X}; mixed_aliases([b] = <>) -> {b,X}; mixed_aliases(<> = {a,X}) -> {c,X}; mixed_aliases([X] = <>) -> {d,X}; mixed_aliases(<> = X) -> {e,X}; mixed_aliases(X = <>) -> {f,X}; mixed_aliases(<> = X) -> {g,X}; mixed_aliases(X = <>) -> {h,X}; mixed_aliases(X = #{key:=X}) -> {i,X}; mixed_aliases(#{key:=X} = X) -> {j,X}; mixed_aliases([X] = #{key:=X}) -> {k,X}; mixed_aliases(#{key:=X} = [X]) -> {l,X}; mixed_aliases({a,X} = #{key:=X}) -> {m,X}; mixed_aliases(#{key:=X} = {a,X}) -> {n,X}; mixed_aliases(_) -> none. nomatch_alias(I) -> {ok={A,B}} = id(I), {A,B}. entirely() -> 0(((Voice = true) = cool) = job), [receive _ -> Voice end || banking <- printer]. printer() -> {[Indoor] = [] = associates}, [ireland || Indoor <- Indoor]. tench() -> E = begin [A] = [] = borogoves, A + 1 end, E + 7 * A. perch(X) -> begin put(perch, get(perch)+1), [A] = [] = {spine,X} end. salmon() -> {put(salmon, get(salmon)+1),#{key:=([A]=[])}=mimsy,exit(fail)}, A + 10. shark() -> (hello = there) = (catch shark(put(shark, get(shark)+1), a = b)). shark(_, _) -> ok. radio(research) -> (connection = proof) = (catch erlang:trace_pattern(catch mechanisms + assist, summary = mechanisms)). %% OTP-7018. match_in_call(Config) when is_list(Config) -> mac_a(0), mac_b(1), mac_c(42), mac_d(42), mac_e({gurka,42}), [{2,2},{2,2}] = mac_lc([{2,any},{2,2}]), {'EXIT',_} = (catch mac_lc([{1,1}])), ok. mac_a(X) -> id(_Gurka = {gurka,X}), ok. mac_b(X) -> id(Gurka = {gurka,X}), gurka(Gurka, X), ok. mac_c(X) -> id(Gurka = Yxa = {gurka,X}), id({Gurka,Yxa}), ok. mac_d(X) -> id({gurka,42} = {gurka,X}), ok. mac_e(X) -> id({gurka,42} = X), ok. mac_lc(E) -> Res = mac_lc1(E), Res = mac_lc2(E). mac_lc1(E) -> [{X,Y} || {X,_} <- E, (Y = X) =:= (Y = 1 + 1)]. mac_lc2(E) -> [{X,Y} || {X,_} <- E, (Y = X) =:= (Y = 2)]. gurka({gurka,X}, X) -> ok. untuplify(Config) when is_list(Config) -> %% We do this to cover sys_core_fold:unalias_pat/1. {1,2,3,4,alias,{[1,2],{3,4},alias}} = untuplify_1([1,2], {3,4}, alias), error = untuplify_1([1,2], {3,4}, 42), %% Test that a previous bug in v3_codegen is gone. (The sinking of %% stack frames into only the case arms that needed them was not always %% safe.) [33, -1, -33, 1] = untuplify_2(32, 65), {33, 1, -33, -1} = untuplify_2(65, 32), ok. untuplify_1(A, B, C) -> case {A,B,C} of {[X,Y],{Z,W},alias=Alias}=Top -> {X,Y,Z,W,Alias,Top}; [_,_]=CantMatch -> CantMatch; _ -> error end. untuplify_2(V1, V2) -> {D1,D2,D3,D4} = if V1 > V2 -> %% The 1 value was overwritten by the value of V2-V1. {V1-V2, 1, V2-V1, -1}; true -> {V2-V1, -1, V1-V2, 1} end, if D2 > D4 -> {D1, D2, D3, D4}; true -> [D1, D2, D3, D4] end. %% Coverage of beam_dead:shortcut_boolean_label/4. shortcut_boolean(Config) when is_list(Config) -> false = shortcut_boolean_1([0]), true = shortcut_boolean_1({42}), maybe = shortcut_boolean_1(self()), {'EXIT',_} = (catch shortcut_boolean_1([a,b])), {'EXIT',_} = (catch shortcut_boolean_1({a,b})), ok. shortcut_boolean_1(X) -> Outer = case not is_pid(X) of true -> V = case X of [_] -> true; {_} -> false end, not V; false -> maybe end, id(Outer). %% Test sys_core_fold:letify_guard/3. letify_guard(Config) when is_list(Config) -> {-15,a} = letify_guard(-15, a), 5 = letify_guard(2, 3), ok. letify_guard(A, B) -> case {A,B} of %% The tuple will be built in the guard... Z when tuple_size(Z) =:= 2, element(1, Z) < 0 -> %% ... and again here. Z; {X,Y} -> X+Y end. %% Test combining of is_eq_exact instructions to select_val %% instructions in beam_dead and beam_peep. selectify(Config) when is_list(Config) -> integer = sel_different_types({r,42}), atom = sel_different_types({r,forty_two}), float = sel_different_types({r,100.0}), none = sel_different_types({r,18}), {'EXIT',_} = (catch sel_different_types([a,b,c])), integer = sel_same_value({r,42}), error = sel_same_value({r,100}), error = sel_same_value(a), integer42 = sel_same_value2(42), integer43 = sel_same_value2(43), error = sel_same_value2(44), ok. sel_different_types({r,_}=T) when element(2, T) =:= forty_two -> atom; sel_different_types({r,_}=T) when element(2, T) =:= 42 -> integer; sel_different_types({r,_}=T) when element(2, T) =:= 100.0 -> float; sel_different_types({r,_}) -> none. sel_same_value({r,V}) when V =:= 42 -> integer; sel_same_value({r,V}) when V =:= 42 -> integer42; sel_same_value(_) -> error. sel_same_value2(V) when V =:= 42 -> integer42; sel_same_value2(V) when V =:= 42; V =:= 43 -> integer43; sel_same_value2(_) -> error. %% Test deconstruction of select_val instructions to regular tests %% with zero or one values left. deselectify(Config) when is_list(Config) -> one_or_other = desel_tuple_arity({1}), two = desel_tuple_arity({1,1}), one_or_other = desel_tuple_arity({1,1,1}), one_or_other = dsel_integer(1), two = dsel_integer(2), one_or_other = dsel_integer(3), one_or_other = dsel_integer_typecheck(1), two = dsel_integer_typecheck(2), one_or_other = dsel_integer_typecheck(3), one_or_other = dsel_atom(one), two = dsel_atom(two), one_or_other = dsel_atom(three), one_or_other = dsel_atom_typecheck(one), two = dsel_atom_typecheck(two), one_or_other = dsel_atom_typecheck(three), %% Cover deconstruction of select_val instructions in %% beam_peep. stop = dsel_peek_0(stop), ignore = dsel_peek_0(ignore), Config = dsel_peek_0(Config), stop = dsel_peek_1(stop, any), Config = dsel_peek_1(ignore, Config), other = dsel_peek_1(other, ignored), 0 = dsel_peek_2(0, any), Config = dsel_peek_2(1, Config), 2 = dsel_peek_2(2, ignored), true = dsel_peek_3(true), false = dsel_peek_3(false), {error,Config} = dsel_peek_3(Config), ok. %% The following will be optimized by the sharing optimizations %% in beam_ssa_opt. desel_tuple_arity(Tuple) when is_tuple(Tuple) -> case Tuple of {_} -> one_or_other; {_,_} -> two; _ -> one_or_other end. dsel_integer(Val) -> case Val of 1 -> one_or_other; 2 -> two; _ -> one_or_other end. dsel_integer_typecheck(Val) when is_integer(Val) -> case Val of 1 -> one_or_other; 2 -> two; _ -> one_or_other end. dsel_atom(Val) -> case Val of one -> one_or_other; two -> two; _ -> one_or_other end. dsel_atom_typecheck(Val) when is_atom(Val) -> case Val of one -> one_or_other; two -> two; _ -> one_or_other end. %% The following functions are carefully crafted so that the sharing %% optimizations in beam_ssa_opt can't be applied. After applying the %% beam_jump:eliminate_moves/1 optimization and beam_clean:clean_labels/1 %% has unified labels, beam_peep is able to optimize these functions. dsel_peek_0(A0) -> case id(A0) of stop -> stop; ignore -> ignore; A -> A end. dsel_peek_1(A0, B) -> case id(A0) of stop -> stop; ignore -> B; A -> A end. dsel_peek_2(A0, B) -> case id(A0) of 0 -> 0; 1 -> B; A -> A end. dsel_peek_3(A0) -> case id(A0) of true -> true; false -> false; Other -> {error,Other} end. underscore(Config) when is_list(Config) -> case Config of [] -> %% Assignment to _ at the end of a construct. _ = length(Config); [_|_] -> %% Assignment to _ at the end of a construct. _ = list_to_tuple(Config) end, _ = is_list(Config), ok. -record(s, {map,t}). match_map(Config) when is_list(Config) -> Map = #{key=>{x,y},ignore=>anything}, #s{map=Map,t={x,y}} = do_match_map(#s{map=Map}), {a,#{k:={a,b,c}}} = do_match_map_2(#{k=>{a,b,c}}), ok. do_match_map(#s{map=#{key:=Val}}=S) -> %% Would crash with a 'badarg' exception. S#s{t=Val}. do_match_map_2(Map) -> case {a,Map} of {a,#{k:=_}}=Tuple -> Tuple end. map_vars_used(Config) when is_list(Config) -> {some,value} = do_map_vars_used(a, b, #{{a,b}=>42,v=>{some,value}}), ok. do_map_vars_used(X, Y, Map) -> case {X,Y} of T -> %% core_lib:is_var_used/2 would not consider T used. #{T:=42,v:=Val} = Map, Val end. -record(coverage_id, {bool=false,id}). coverage(Config) when is_list(Config) -> %% Cover beam_dead. ok = coverage_1(x, a), ok = coverage_1(x, b), %% Cover sys_pre_expand. ok = coverage_3("abc"), %% Cover beam_ssa_dead. {expr,key} = coverage_4([literal,get], [[expr,key]]), {expr,key} = coverage_4([expr,key], []), a = coverage_5([8,8,8], #coverage_id{bool=true}), b = coverage_5([], #coverage_id{bool=true}), %% Cover beam_ssa_opt. ok = coverage_6(), ok. coverage_1(B, Tag) -> case Tag of a -> coverage_2(1, a, B); b -> coverage_2(2, b, B) end. coverage_2(1, a, x) -> ok; coverage_2(2, b, x) -> ok. coverage_3([$a]++[]++"bc") -> ok. %% Cover beam_ssa_dead:eval_type_test_1(is_nonempty_list, Arg). coverage_4([literal,get], [Expr]) -> coverage_4(Expr, []); coverage_4([Expr,Key], []) -> {Expr,Key}. %% Cover beam_ssa_dead:eval_type_test_1(is_tagged_tuple, Arg). coverage_5(Config, TermId) when TermId =:= #coverage_id{bool=true}, Config =:= [8,8,8] -> a; coverage_5(_Config, #coverage_id{bool=true}) -> b. coverage_6() -> X = 17, case case id(1) > 0 of true -> 17; false -> 42 end of X -> ok; V -> %% Cover beam_ssa_opt:make_literal/2. error([error,X,V]) end. grab_bag(_Config) -> [_|T] = id([a,b,c]), [b,c] = id(T), T1 = fun() -> [_|_] = x end, {'EXIT',_} = (catch T1()), T2 = fun(A, B) -> case {{element(1, A),element(2, B)}, {element(2, A),element(2, B)}} of {Same,Same} -> ok; {{0,1},{up,X}} -> id(X); {_,{X,_}} -> id(X) end end, ok = T2({a,a,z,z}, {z,a,z}), 1 = T2({0,up}, {zzz,1}), y = T2({x,y}, {a,z,z}), %% OTP-5244. L = [{stretch,0,0}, {bad,[]}, {bad,atom}, {bad,0}, {bad,16#AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA}, {bad,16#555555555555555555555555555555555555555555555555555}], ok = grab_bag_remove_failure(L, unit, 0), {42,<<43,44>>} = grab_bag_single_valued(<<42,43,44>>), empty_list = grab_bag_single_valued([]), empty_tuple = grab_bag_single_valued({}), ok. grab_bag_remove_failure([], _Unit, _MaxFailure) -> ok; grab_bag_remove_failure([{bad,Bad}|_], _Unit, _MaxFailure) -> Bad; grab_bag_remove_failure([{stretch,_,Mi}=Stretch | Specs], Unit, _MaxFailure) -> {MinMax,NewMaxFailure} = id({min,1}), case {MinMax,grab_bag_remove_failure(Specs, Unit, NewMaxFailure)} of {min,{NewMaxFailure,Rest}} -> {done,[{fixed,Mi} | Rest]}; {min,_} when Specs =/= [] -> grab_bag_remove_failure([Stretch|tl(Specs)], Unit, NewMaxFailure); {min,_} -> ok end. %% Cover a line v3_kernel that places binary matching first. grab_bag_single_valued(<>) -> {H,T}; grab_bag_single_valued([]) -> empty_list; grab_bag_single_valued({}) -> empty_tuple. %% Regression in 19.0, reported by Alexei Sholik literal_binary(_Config) -> 3 = literal_binary_match(bar, <<"y">>), %% While we are at it, also test the remaining code paths %% in literal_binary_match/2. 1 = literal_binary_match(bar, <<"x">>), 2 = literal_binary_match(foo, <<"x">>), 3 = literal_binary_match(foo, <<"y">>), fail = literal_binary_match(bar, <<"z">>), fail = literal_binary_match(foo, <<"z">>), ok. literal_binary_match(bar, <<"x">>) -> 1; literal_binary_match(_, <<"x">>) -> 2; literal_binary_match(_, <<"y">>) -> 3; literal_binary_match(_, _) -> fail. unary_op(Config) -> %% ERL-514. This test case only verifies that the code %% calculates the correct result, not that the generated %% code is optimial. {non_associative,30} = unary_op_1('&'), {non_associative,300} = unary_op_1('^'), {non_associative,300} = unary_op_1('not'), {non_associative,300} = unary_op_1('+'), {non_associative,300} = unary_op_1('-'), {non_associative,300} = unary_op_1('~~~'), {non_associative,300} = unary_op_1('!'), {non_associative,320} = unary_op_1('@'), error = unary_op_1(Config), error = unary_op_1(abc), error = unary_op_1(42), ok. unary_op_1(Vop@1) -> %% If all optimizations are working as they should, there should %% be no stack frame and all '=:=' tests should be coalesced into %% a single select_val instruction. case Vop@1 =:= '&' of true -> {non_associative,30}; false -> case case Vop@1 =:= '^' of true -> true; false -> case Vop@1 =:= 'not' of true -> true; false -> case Vop@1 =:= '+' of true -> true; false -> case Vop@1 =:= '-' of true -> true; false -> case Vop@1 =:= '~~~' of true -> true; false -> Vop@1 =:= '!' end end end end end of true -> {non_associative,300}; false -> case Vop@1 =:= '@' of true -> {non_associative,320}; false -> error end end end. eq_types(_Config) -> Ref = make_ref(), Ref = eq_types(Ref, any), ok. eq_types(A, B) -> %% {put_tuple2,{y,0},{list,[{x,0},{x,1}]}}. Term0 = {A, B}, Term = id(Term0), %% {test,is_eq_exact,{f,3},[{y,0},{x,0}]}. %% Here beam_validator must infer that {x,0} has the %% same type as {y,0}. Term = Term0, %% {get_tuple_element,{x,0},0,{x,0}}. {Ref22,_} = Term, Ref22. match_after_return(Config) when is_list(Config) -> %% The return type of the following call will never match the 'wont_happen' %% clauses below, and the beam_ssa_type was clever enough to see that but %% didn't remove the blocks, so it crashed when trying to extract A. ok = case mar_test_tuple(erlang:unique_integer()) of {gurka, never_matches, A} -> {wont_happen, A}; _ -> ok end. mar_test_tuple(I) -> {gurka, I}. match_right_tuple(Config) when is_list(Config) -> %% The loader wrongly coalesced certain get_tuple_element sequences, fusing %% the code below into a single i_get_tuple_element2 operating on {x,0} %% even though the first one overwrites it. %% %% {get_tuple_element,{x,0},0,{x,0}}. %% {get_tuple_element,{x,0},1,{x,1}}. Inner = {id(wrong_element), id(ok)}, Outer = {Inner, id(wrong_tuple)}, ok = match_right_tuple_1(Outer). match_right_tuple_1(T) -> {A, _} = T, {_, B} = A, %% The call ensures that A is in {x,0} and B is in {x,1} id(force_succ_regs(A, B)). force_succ_regs(_A, B) -> B. tuple_size_in_try(Config) when is_list(Config) -> %% The tuple_size optimization was applied outside of guards, causing %% either the emulator or compiler to crash. ok = tsit(gurka), ok = tsit(gaffel). tsit(A) -> try id(ignored), 1 = tuple_size(A), error catch _:_ -> ok end. match_boolean_list(Config) when is_list(Config) -> BoolList = [N rem 2 =:= 0 || N <- lists:seq(1, 8)], %% The compiler knows that all list elements are booleans, so it translates %% the expression below to a #b_br{} on the list head. %% %% This is fine, but since the value was only used in that branch, %% reserve_zregs/3 (pre_codegen) would place the variable in a z register, %% crashing the compiler in a later pass. ok = case BoolList of [true | _] -> error; [false | _] -> ok end. id(I) -> I. ================================================ FILE: test_data/test.core ================================================ module 'test' ['add'/2, 'add_two'/3, 'module_info'/0, 'module_info'/1, 'return_closure'/1] attributes [%% Line 1 'file' = %% Line 1 [{[116|[101|[115|[116|[46|[101|[114|[108]]]]]]]],1}]] 'add'/2 = %% Line 4 fun (_@c1,_@c0) -> %% Line 5 call 'erlang':'+' (_@c1, _@c0) 'add_two'/3 = %% Line 7 fun (_@c2,_@c1,_@c0) -> let = apply %% Line 8 'add'/2 (_@c2, _@c1) in %% Line 9 apply 'add'/2 (I, _@c0) 'return_closure'/1 = %% Line 11 fun (_@c0) -> %% Line 12 ( fun (_@c1) -> %% Line 13 apply 'add'/2 (_@c0, _@c1) -| [{'id',{0,0,'-return_closure/1-fun-0-'}}] ) 'module_info'/0 = fun () -> call 'erlang':'get_module_info' ('test') 'module_info'/1 = fun (_@c0) -> call 'erlang':'get_module_info' ('test', _@c0) end ================================================ FILE: test_data/test.erl ================================================ -module(test). -export([add/2, add_two/3, return_closure/1]). add(A, B) -> A + B. add_two(A, B, C) -> I = add(A, B), add(I, C). return_closure(I) -> fun(A) -> add(I, A) end. ================================================ FILE: test_data/testing.core ================================================ module 'test' ['add'/2, 'add_two'/3, 'module_info'/0, 'module_info'/1, 'return_closure'/1] attributes [%% Line 1 'file' = %% Line 1 [{[116|[101|[115|[116|[105|[110|[103|[46|[101|[114|[108]]]]]]]]]]],1}]] 'add'/2 = %% Line 4 fun (_1,_0) -> %% Line 5 call 'erlang':'+' (_1, _0) 'add_two'/3 = %% Line 7 fun (_2,_1,_0) -> let = apply %% Line 8 'add'/2 (_2, _1) in %% Line 9 apply 'add'/2 (I, _0) 'return_closure'/1 = %% Line 11 fun (_0) -> %% Line 12 ( fun (_1) -> %% Line 13 apply 'add'/2 (_0, _1) -| [{'id',{0,0,'-return_closure/1-fun-0-'}}] ) 'add_with_closure'/2 = %% Line 16 fun (_1,_0) -> let = apply %% Line 17 'return_closure'/1 (_1) in %% Line 18 apply F (_0) 'matching'/2 = %% Line 20 fun (_1,_0) -> case <_1,_0> of <[],[]> when 'true' -> %% Line 21 'one' %% Line 22 <[],_4> when 'true' -> %% Line 23 'two' %% Line 24 <_5,[]> when 'true' -> %% Line 25 'three' %% Line 26 when 'true' -> %% Line 27 {A,B} end 'module_info'/0 = fun () -> call 'erlang':'get_module_info' ('test') 'module_info'/1 = fun (_0) -> call 'erlang':'get_module_info' ('test', _0) end ================================================ FILE: test_data/testing.erl ================================================ -module(test). -export([add/2, add_two/3, return_closure/1]). add(A, B) -> A + B. add_two(A, B, C) -> I = add(A, B), add(I, C). return_closure(I) -> fun(A) -> add(I, A) end. add_with_closure(A, B) -> F = return_closure(A), F(B). matching([], []) -> one; matching([], _) -> two; matching(_, []) -> three; matching(A, B) -> {A, B}. ================================================ FILE: tools/Cargo.toml ================================================ [package] name = "tools" version = "0.1.0" authors = ["Hans Elias B. Josephsen "] edition = "2018" license = "MIT OR Apache-2.0" [[bin]] name = "eir_compile" path = "src/compile.rs" [dependencies] libeir_diagnostics = { path = "../libeir_diagnostics" } libeir_syntax_erl = { path = "../libeir_syntax_erl" } libeir_passes = { path = "../libeir_passes" } libeir_ir = { path = "../libeir_ir" } libeir_util_parse = { path = "../util/libeir_util_parse" } libeir_util_parse_listing = { path = "../util/libeir_util_parse_listing" } libeir_frontend = { path = "../libeir_frontend" } clap = "2.33.0" log = "0.4" fern = "0.5" ================================================ FILE: tools/src/compile.rs ================================================ use std::io::Write; use std::path::{Path, PathBuf}; use std::sync::Arc; use clap::{arg_enum, value_t, values_t, App, Arg, ArgMatches}; use libeir_diagnostics::term::{ self, termcolor::{ColorChoice, StandardStream}, }; use libeir_diagnostics::CodeMap; use libeir_frontend::{ abstr_erlang::AbstrErlangFrontend, eir::EirFrontend, erlang::ErlangFrontend, AnyFrontend, DynFrontend, }; use libeir_ir::FunctionIdent; use libeir_passes::PassManager; arg_enum! { #[derive(Debug, PartialEq, Eq)] pub enum OutputType { Eir, Dot, } } arg_enum! { #[derive(Debug, PartialEq, Eq)] pub enum InputType { Eir, Abstr, Erl, } } arg_enum! { #[derive(Debug)] pub enum CompileLevel { High, Normal, Custom, } } arg_enum! { #[derive(Debug)] pub enum CompilePass { CompilePatterns, SimplifyCfg, NaiveInlineClosures, Validate, } } arg_enum! { #[derive(Debug, Copy, Clone)] pub enum LogLevel { Error, Warn, Info, Debug, Trace, } } impl LogLevel { pub fn to_filter(self) -> log::LevelFilter { match self { LogLevel::Error => log::LevelFilter::Error, LogLevel::Warn => log::LevelFilter::Warn, LogLevel::Info => log::LevelFilter::Info, LogLevel::Debug => log::LevelFilter::Debug, LogLevel::Trace => log::LevelFilter::Trace, } } } fn make_erlang_frontend(codemap: Arc, matches: &ArgMatches) -> ErlangFrontend { use libeir_syntax_erl::ParseConfig; let mut config = ParseConfig::default(); if let Some(includes) = matches.values_of("INCLUDE_PATHS") { for include in includes { config.include_paths.push_front(PathBuf::from(include)); } } if let Some(includes) = matches.values_of("CODE_PATHS") { for include in includes { config.code_paths.push_front(PathBuf::from(include)); } } ErlangFrontend::new(config, codemap) } fn make_frontend(codemap: Arc, matches: &ArgMatches) -> AnyFrontend { match value_t!(matches, "IN_FORMAT", InputType).unwrap() { InputType::Erl => make_erlang_frontend(codemap, matches).into(), InputType::Abstr => AbstrErlangFrontend::new(codemap).into(), InputType::Eir => EirFrontend::new(codemap).into(), } } fn setup_logger(level: log::LevelFilter) { fern::Dispatch::new() .format(|out, message, record| { out.finish(format_args!( "[{}][{}] {}", record.target(), record.level(), message )) }) .level(level) .chain(std::io::stdout()) .apply() .unwrap(); } fn main() { let matches = App::new("Eir Compiler CLI") .version("alpha") .author("Hans Elias B. Josephsen") .about("CLI interface to various Eir compiler functionality") .arg( Arg::with_name("IN_FILE") .help("Input file for compiler") .required(true), ) .arg( Arg::from_usage(" -f,--in-format 'input format'") .default_value("erl") .required(true) .case_insensitive(true) .possible_values(&InputType::variants()), ) .arg( Arg::from_usage(" -p,--out-format 'output format'") .default_value("eir") .required(true) .case_insensitive(true) .possible_values(&OutputType::variants()), ) .arg( Arg::from_usage(" -i,--ident 'select single function'") .required(false), ) .arg(Arg::from_usage(" -o,--output 'output file'").required(false)) .arg(Arg::from_usage("-s,--to-stdout 'outputs to stdout'")) .arg(Arg::from_usage(" --run-dot ").required(false)) .arg( Arg::from_usage( " -l,--compile-level 'compilation level'", ) .default_value("normal") .required(false) .case_insensitive(true) .possible_values(&CompileLevel::variants()), ) .arg(Arg::from_usage( "[ANNOTATE_LIVE] --annotate-live 'annotate calculated live variables in ir", )) .arg( Arg::from_usage( " -I 'add include path for the erlang preprocessor'", ) .required(false) .multiple(true), ) .arg( Arg::from_usage( " -C 'add code path for the erlang preprocessor'", ) .required(false) .multiple(true), ) .arg( Arg::from_usage(" --pass 'run the given compilation pass'") .required(false) .multiple(true) .number_of_values(1) .possible_values(&CompilePass::variants()), ) .arg( Arg::from_usage(" -L,--log-level 'log level'") .default_value("info") .required(false) .case_insensitive(true) .possible_values(&LogLevel::variants()), ) .get_matches(); setup_logger( value_t!(matches, "LOG_LEVEL", LogLevel) .unwrap() .to_filter(), ); let codemap = Arc::new(CodeMap::new()); let frontend = make_frontend(codemap.clone(), &matches); let in_file_name = matches.value_of("IN_FILE").unwrap(); let in_file_path = Path::new(in_file_name); let (eir_res, diagnostics) = frontend.parse_file_dyn(&in_file_path); { let term_config = term::Config::default(); let mut out = StandardStream::stderr(ColorChoice::Auto); for diag in diagnostics.iter() { term::emit(&mut out, &term_config, &*codemap, diag).unwrap(); } } if eir_res.is_err() { return; } let mut eir = eir_res.unwrap(); match value_t!(matches, "COMPILE_LEVEL", CompileLevel).unwrap() { CompileLevel::High => {} CompileLevel::Normal => { let mut pass_manager = PassManager::default(); pass_manager.run(&mut eir); } CompileLevel::Custom => { let mut pass_manager = PassManager::new(); if matches.is_present("PASSES") { for pass_type in values_t!(matches.values_of("PASSES"), CompilePass).unwrap() { match pass_type { CompilePass::CompilePatterns => { pass_manager .push_function_pass(libeir_passes::CompilePatternPass::new()); } CompilePass::SimplifyCfg => { pass_manager.push_function_pass(libeir_passes::SimplifyCfgPass::new()); } CompilePass::NaiveInlineClosures => { pass_manager .push_function_pass(libeir_passes::NaiveInlineClosuresPass::new()); } CompilePass::Validate => { pass_manager.push_function_pass(libeir_passes::ValidatePass::new()); } } } } pass_manager.run(&mut eir); } } let selected_function = matches .value_of("FUN_IDENT") .map(|val| FunctionIdent::parse_with_module(val, eir.name().clone()).unwrap()); //if matches.is_present("ANNOTATE_LIVE") { // print_ctx.add_annotator(EirLiveValuesAnnotator::new()); //} let out_data; let out_ext; let out_type = value_t!(matches, "OUT_FORMAT", OutputType).unwrap(); match out_type { OutputType::Eir => { if let Some(selected) = selected_function { out_data = eir[&selected].function().to_text_standard(); } else { out_data = eir.to_text_standard(); } out_ext = "eir"; } OutputType::Dot => { let selected_function = selected_function.expect("Expected function ident with -i "); let fun_def = &eir[&selected_function]; let fun = fun_def.function(); out_data = ::libeir_ir::text::function_to_dot(&fun); out_ext = "dot"; } } let out_file_name = matches .value_of("OUT_FILE") .map(|s| s.to_string()) .unwrap_or_else(|| format!("{}.{}", in_file_name, out_ext)); println!("Writing to {}", out_file_name); let mut out = ::std::fs::File::create(&out_file_name).unwrap(); out.write(out_data.as_bytes()).unwrap(); if let Some(dot_format) = matches.value_of("DOT_FORMAT") { assert!(out_type == OutputType::Dot); println!("Running dot..."); let format_str = format!("-T{}", dot_format); let res = std::process::Command::new("dot") .arg(&format_str) .arg("-O") .arg(&out_file_name) .output() .expect("Failed to run dot"); assert!(res.status.success(), "Failed to run dot"); } } ================================================ FILE: util/any_map/Cargo.toml ================================================ [package] name = "any_map" version = "0.1.0" authors = ["Hans Elias B. Josephsen "] edition = "2018" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] fnv = "1.0.3" hashbrown = { git = "https://github.com/rust-lang/hashbrown.git", features = ["raw", "nightly"] } ================================================ FILE: util/any_map/src/any_any_map.rs ================================================ use crate::{AnyMap, DefaultBuildHasher}; use std::alloc::{Allocator, Global}; use std::any::Any; use std::hash::{BuildHasher, Hash}; pub trait AnyKey: Clone + Hash + Eq + 'static { type Value: Clone + 'static; } trait AnyValueTrait { fn clone(&self) -> Box; } impl AnyValueTrait for T where T: Clone + Any, { fn clone(&self) -> Box { Box::new(Clone::clone(self)) } } pub struct AnyAnyMap where A: Allocator + Clone, { inner: AnyMap, S, A>, } impl Default for AnyAnyMap where S: Default, A: Default + Allocator + Clone, { fn default() -> Self { AnyAnyMap { inner: Default::default(), } } } impl AnyAnyMap { pub fn new() -> Self { Default::default() } } impl AnyAnyMap where A: Allocator + Clone, S: BuildHasher, { pub fn insert(&mut self, k: K, v: K::Value) -> Option where K: AnyKey, { let ret = self.inner.insert(k, Box::new(v)); ret.map(|v| *v.downcast().unwrap()) } pub fn get(&self, k: &K) -> Option<&K::Value> { self.inner.get(k).map(|v| v.downcast_ref().unwrap()) } pub fn get_mut(&mut self, k: &K) -> Option<&mut K::Value> { self.inner.get_mut(k).map(|v| v.downcast_mut().unwrap()) } } ================================================ FILE: util/any_map/src/any_map.rs ================================================ use fnv::FnvBuildHasher; use hashbrown::raw::RawTable; use std::alloc::{Allocator, Global}; use std::any::{Any, TypeId}; use std::hash::{BuildHasher, Hash, Hasher}; use std::mem; pub type DefaultBuildHasher = FnvBuildHasher; trait AnyKeyTrait: 'static { fn clone(&self) -> Box; fn type_id(&self) -> TypeId; } impl AnyKeyTrait for T where T: Clone + Any, { fn clone(&self) -> Box { Box::new(Clone::clone(self)) } fn type_id(&self) -> TypeId { Any::type_id(self) } } impl dyn AnyKeyTrait { fn is(&self) -> bool { let t = TypeId::of::(); let st = self.type_id(); t == st } fn downcast_ref<'a, T: Any>(&'a self) -> Option<&'a T> { if self.is::() { unsafe { Some(&*(self as *const dyn AnyKeyTrait as *const T)) } } else { None } } } fn make_hash(hash_builder: &impl BuildHasher, val: &K) -> u64 { let mut state = hash_builder.build_hasher(); val.hash(&mut state); state.finish() } fn make_eq(k: &Q) -> impl Fn(&(AnyKey, V)) -> bool + '_ where Q: Eq + 'static, { move |x| x.0.eq_k(k) } struct AnyKey { key: Box, hash: u64, } impl Clone for AnyKey { fn clone(&self) -> Self { AnyKey { key: AnyKeyTrait::clone(&*self.key), hash: self.hash, } } } impl AnyKey { pub fn new(k: K, hb: &S) -> Self where K: AnyKeyTrait + Hash + 'static, S: BuildHasher, { AnyKey { hash: make_hash(hb, &k), key: Box::new(k), } } pub fn eq_k(&self, k: &K) -> bool where K: Eq + 'static, { if let Some(inner) = self.key.downcast_ref::() { inner == k } else { false } } } pub struct AnyMap where A: Allocator + Clone, { hash_builder: S, table: RawTable<(AnyKey, V), A>, } impl Default for AnyMap where S: Default, A: Default + Allocator + Clone, { fn default() -> Self { AnyMap { hash_builder: S::default(), table: RawTable::new_in(A::default()), } } } fn get_hash(data: &(AnyKey, V)) -> u64 { data.0.hash } impl AnyMap { pub fn new() -> Self { Default::default() } } impl AnyMap where S: BuildHasher, A: Allocator + Clone, { pub fn insert(&mut self, k: K, v: V) -> Option where K: Clone + Eq + Hash + 'static, { let hash = make_hash(&self.hash_builder, &k); if let Some((_, item)) = self.table.get_mut(hash, make_eq(&k)) { Some(mem::replace(item, v)) } else { let key = AnyKey::new(k, &self.hash_builder); self.table.insert(hash, (key, v), get_hash); None } } pub fn get(&self, k: &K) -> Option<&V> where K: Eq + Hash + 'static, { let hash = make_hash(&self.hash_builder, k); match self.table.get(hash, make_eq(k)) { Some(&(_, ref v)) => Some(v), None => None, } } pub fn get_mut(&mut self, k: &K) -> Option<&mut V> where K: Eq + Hash + 'static, { let hash = make_hash(&self.hash_builder, k); match self.table.get_mut(hash, make_eq(k)) { Some(&mut (_, ref mut v)) => Some(v), None => None, } } } #[cfg(test)] mod tests { use super::AnyMap; #[test] fn simple_usage() { let mut map = AnyMap::new(); map.insert(12, 5); assert!(*map.get(&12).unwrap() == 5); #[derive(Clone, Hash, PartialEq, Eq)] struct MyKey; map.insert(MyKey, 55); assert!(*map.get(&MyKey).unwrap() == 55); assert!(*map.get(&12).unwrap() == 5); for n in 0..1000 { map.insert(n, n); } for n in 0..1000 { assert!(*map.get(&n).unwrap() == n); } assert!(*map.get(&MyKey).unwrap() == 55); #[derive(Clone, Hash, PartialEq, Eq)] struct MyKeyI(usize); map.insert(MyKeyI(12), 15); assert!(*map.get(&MyKeyI(12)).unwrap() == 15); assert!(*map.get(&12).unwrap() == 12); assert!(map.get(&&12).is_none()); } } ================================================ FILE: util/any_map/src/lib.rs ================================================ #![feature(allocator_api)] mod any_map; pub use crate::any_map::{AnyMap, DefaultBuildHasher}; mod any_any_map; pub use crate::any_any_map::{AnyAnyMap, AnyKey}; ================================================ FILE: util/libeir_etf/Cargo.toml ================================================ [package] name = "libeir_etf" version = "0.1.0" authors = ["Hans Elias B. Josephsen "] edition = "2018" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] byteorder = "1.3" num-bigint = { git = "https://github.com/hansihe/num-bigint.git" } snafu = "0.5" libeir_intern = { path = "../../libeir_intern" } ================================================ FILE: util/libeir_etf/src/constants.rs ================================================ #[allow(dead_code)] pub mod tag { pub const ATOM_CACHE_REF: u8 = 82; /// Unsigned 8-bit integer pub const SMALL_INTEGER_EXT: u8 = 97; /// Signed 32-bit integer in big-endian format pub const INTEGER_EXT: u8 = 98; /// DEPRECATED /// Float stored as string pub const FLOAT_EXT: u8 = 99; /// (node:atom), (id:u32be as u28) (creation:u8 as u2) pub const PORT_EXT: u8 = 102; /// (node:atom), (id:u32be as u28) (creation:u32be) pub const NEW_PORT_EXT: u8 = 89; /// (node:atom), (id:u32be as u15) (serial:u32be as u13) (creation:u8 as u2) pub const PID_EXT: u8 = 103; /// (node:atom), (id:u32be as u15) (serial:u32be as u13) (creation:u32be) pub const NEW_PID_EXT: u8 = 88; /// (arity:u8), elements.. pub const SMALL_TUPLE_EXT: u8 = 104; /// (arity:u32be), elements.. pub const LARGE_TUPLE_EXT: u8 = 105; /// (arity:u32be), (key, value).. /// Duplicate keys not allowed. pub const MAP_EXT: u8 = 116; /// only tag pub const NIL_EXT: u8 = 106; /// (length:u16be), (chars:u8).. pub const STRING_EXT: u8 = 107; /// (length:u32be), (elements).., (tail) pub const LIST_EXT: u8 = 108; /// (length:u32be), (data).. pub const BINARY_EXT: u8 = 109; /// (data_len:u8), (is_neg:u8 as bool), (u8).. /// B = 256 /// (d0*B^0 + d1*B^1 + d2*B^2 + ... d(N-1)*B^(n-1)) pub const SMALL_BIG_EXT: u8 = 110; /// (data_len:u32be), (is_neg:u8 as bool), (u8).. /// Otherwise same as small pub const LARGE_BIG_EXT: u8 = 111; /// (id_len:u16be <= 3) (node:atom) (creation:u32be) (id:u32be).. pub const NEWER_REFERENCE_EXT: u8 = 90; /// (num_free:u32be) (pid:pid) (module:atom) (index:integer) (uniq:integer) (free).. /// uniq is parse hash pub const FUN_EXT: u8 = 117; /// (size:u32be) (arity:u8) (uniq:u128be) (index:u32be) (num_free:u32be) (module:atom) /// (old_index:integer) (old_uniq:integer) (pid:pid) (free).. /// size including itself pub const NEW_FUN_EXT: u8 = 112; /// (module:atom) (function:atom) (arity:small_integer_ext) pub const EXPORT_EXT: u8 = 113; /// (len:u32be) (bits:u8 <= 7) bytes.. pub const BIT_BINARY_EXT: u8 = 77; /// (num:f32) pub const NEW_FLOAT_EXT: u8 = 70; /// (len:u16be) name_bytes.. /// latin1 pub const ATOM_EXT: u8 = 100; /// (len:u8) name_bytes.. /// latin1 pub const SMALL_ATOM_EXT: u8 = 115; /// (len:u16be) name_bytes.. pub const ATOM_UTF8_EXT: u8 = 118; /// (len:u8) name_bytes.. pub const SMALL_ATOM_UTF8_EXT: u8 = 119; } ================================================ FILE: util/libeir_etf/src/decoder.rs ================================================ use crate::{RawTag, Reader}; use std::io::Read; use snafu::{ResultExt, Snafu}; #[derive(Debug, Snafu)] pub enum DecodeError { #[snafu(display("error from source: {}", source))] Source { source: std::io::Error }, #[snafu(display("tried to decode bad data"))] BadData, } pub trait Decoder: Sized { fn decode(reader: &mut Reader) -> Result; } macro_rules! impl_tuple_decoder { ($count:expr, ($($typ:ident),*)) => { impl<$($typ: Decoder, )*> Decoder for ($($typ, )*) { fn decode(reader: &mut Reader) -> Result { if let RawTag::Tuple { arity } = reader.raw_tag().context(Source)? { if arity == $count { return Ok(( $(<$typ as Decoder>::decode(reader)?,)* )); } } Err(DecodeError::BadData) } } }; } impl_tuple_decoder!(0, ()); impl_tuple_decoder!(1, (A)); impl_tuple_decoder!(2, (A, B)); impl_tuple_decoder!(3, (A, B, C)); impl_tuple_decoder!(4, (A, B, C, D)); impl_tuple_decoder!(5, (A, B, C, D, E)); impl_tuple_decoder!(6, (A, B, C, D, E, F)); impl_tuple_decoder!(7, (A, B, C, D, E, F, G)); impl_tuple_decoder!(8, (A, B, C, D, E, F, G, H)); impl_tuple_decoder!(9, (A, B, C, D, E, F, G, H, I)); impl_tuple_decoder!(10, (A, B, C, D, E, F, G, H, I, J)); macro_rules! ignore { {$a:tt} => {}; } #[macro_export] macro_rules! impl_record { ($struct:ident, $name:expr, {$($field:ident),*}) => { impl Decoder for $name { fn decode(reader: &mut Reader) -> Result { let num_fields = 1 $(+ 1 ignore!($field))*; if let RawTag::Tuple { arity } = reader.raw_tag().context(Source)? { if arity == num_fields { } } Err(DecodeError::BadData) } } }; } ================================================ FILE: util/libeir_etf/src/encoder.rs ================================================ use crate::{Term, Writer}; use num_bigint::BigInt; use std::collections::{BTreeMap, HashMap}; use std::convert::TryInto; use std::io::{Result, Write}; pub trait Encoder { fn encode(&self, writer: &mut Writer) -> Result<()>; } impl Encoder for Term { fn encode(&self, writer: &mut Writer) -> Result<()> { writer.term(self) } } impl Encoder for libeir_intern::Symbol { fn encode(&self, writer: &mut Writer) -> Result<()> { writer.atom(&self.as_str()) } } impl Encoder for &T { fn encode(&self, writer: &mut Writer) -> Result<()> { ::encode(*self, writer) } } #[derive(Debug, Copy, Clone)] pub struct A<'a>(pub &'a str); impl Encoder for A<'_> { fn encode(&self, writer: &mut Writer) -> Result<()> { writer.atom(self.0) } } macro_rules! impl_tuple_encoder { ($count:expr, ($(($typ:ident, $name:ident)),*)) => { impl<$($typ: Encoder, )*> Encoder for ($($typ, )*) { fn encode(&self, writer: &mut Writer) -> Result<()> { writer.tuple($count)?; let ($($name,)*) = self; $( $name.encode(writer)?; )* writer.pop(); Ok(()) } } }; } impl_tuple_encoder!(0, ()); impl_tuple_encoder!(1, ((A, a))); impl_tuple_encoder!(2, ((A, a), (B, b))); impl_tuple_encoder!(3, ((A, a), (B, b), (C, c))); impl_tuple_encoder!(4, ((A, a), (B, b), (C, c), (D, d))); impl_tuple_encoder!(5, ((A, a), (B, b), (C, c), (D, d), (E, e))); impl_tuple_encoder!(6, ((A, a), (B, b), (C, c), (D, d), (E, e), (F, f))); impl_tuple_encoder!(7, ((A, a), (B, b), (C, c), (D, d), (E, e), (F, f), (G, g))); impl_tuple_encoder!( 8, ( (A, a), (B, b), (C, c), (D, d), (E, e), (F, f), (G, g), (H, h) ) ); impl_tuple_encoder!( 9, ( (A, a), (B, b), (C, c), (D, d), (E, e), (F, f), (G, g), (H, h), (I, i) ) ); impl_tuple_encoder!( 10, ( (A, a), (B, b), (C, c), (D, d), (E, e), (F, f), (G, g), (H, h), (I, i), (J, j) ) ); //impl Encoder for T //where // T: crate::writer::WritableInteger, //{ // fn encode(&self, writer: &mut Writer) -> Result<()> { // writer.integer(self) // } //} impl Encoder for HashMap { fn encode(&self, writer: &mut Writer) -> Result<()> { let len = self.len(); writer.map(len)?; for (k, v) in self.iter() { k.encode(writer)?; v.encode(writer)?; writer.next_kv(); } writer.pop(); Ok(()) } } impl Encoder for BTreeMap { fn encode(&self, writer: &mut Writer) -> Result<()> { let len = self.len(); writer.map(len)?; for (k, v) in self.iter() { k.encode(writer)?; v.encode(writer)?; writer.next_kv(); } writer.pop(); Ok(()) } } impl Encoder for BigInt { fn encode(&self, writer: &mut Writer) -> Result<()> { writer.integer_big(self) } } impl Encoder for u8 { fn encode(&self, writer: &mut Writer) -> Result<()> { writer.raw_small_integer_ext(*self) } } impl Encoder for i8 { fn encode(&self, writer: &mut Writer) -> Result<()> { writer.raw_integer_ext(*self as i32) } } impl Encoder for u16 { fn encode(&self, writer: &mut Writer) -> Result<()> { writer.raw_integer_ext(*self as i32) } } impl Encoder for i16 { fn encode(&self, writer: &mut Writer) -> Result<()> { writer.raw_integer_ext(*self as i32) } } impl Encoder for u32 { fn encode(&self, writer: &mut Writer) -> Result<()> { if let Ok(num) = (*self).try_into() { writer.raw_integer_ext(num) } else { unimplemented!() } } } impl Encoder for i32 { fn encode(&self, writer: &mut Writer) -> Result<()> { writer.raw_integer_ext(*self) } } impl Encoder for u64 { fn encode(&self, writer: &mut Writer) -> Result<()> { if let Ok(num) = (*self).try_into() { writer.raw_integer_ext(num) } else { unimplemented!() } } } impl Encoder for i64 { fn encode(&self, writer: &mut Writer) -> Result<()> { if let Ok(num) = (*self).try_into() { writer.raw_integer_ext(num) } else { unimplemented!() } } } impl Encoder for usize { fn encode(&self, writer: &mut Writer) -> Result<()> { if let Ok(num) = (*self).try_into() { writer.raw_integer_ext(num) } else { unimplemented!() } } } impl Encoder for isize { fn encode(&self, writer: &mut Writer) -> Result<()> { if let Ok(num) = (*self).try_into() { writer.raw_integer_ext(num) } else { unimplemented!() } } } pub struct List + Copy, I: Encoder, T: Encoder>(pub H, pub usize, pub T); impl + Copy, I: Encoder, T: Encoder> Encoder for List { fn encode(&self, writer: &mut Writer) -> Result<()> { writer.list(self.1)?; for entry in self.0.into_iter() { entry.encode(writer)?; } writer.next_tail(); self.2.encode(writer)?; writer.pop(); Ok(()) } } ================================================ FILE: util/libeir_etf/src/lib.rs ================================================ mod constants; mod writer; pub use writer::Writer; mod reader; pub use reader::{RawTag, Reader}; mod term; pub use term::Term; mod encoder; pub use encoder::{Encoder, List, A}; mod decoder; pub use decoder::Decoder; #[cfg(test)] mod test; ================================================ FILE: util/libeir_etf/src/reader.rs ================================================ use crate::term::Term; use byteorder::{BigEndian, ReadBytesExt}; use std::io::{Read, Result, Seek}; use super::constants::tag; pub struct Reader { source: S, } impl Reader { pub fn new(source: S) -> Self { Reader { source } } } pub enum RawTag { AtomCacheRef { index: u8, }, SmallIntegerExt { int: u8, }, IntegerExt { int: i32, }, FloatExt, PortExt, NewPortExt, PidExt, NewPidExt, Tuple { arity: u32, }, MapExt { arity: u32, }, NilExt, StringExt { length: u16, }, ListExt { length: u32, }, BinaryExt { length: u32, }, SmallBigExt { data_len: u8, is_neg: bool, }, LargeBigExt { data_len: u32, is_neg: bool, }, NewerReferenceExt { id_len: u16, }, FunExt { num_free: u32, }, NewFunExt { size: u32, arity: u8, uniq: [u8; 16], index: u32, num_free: u32, }, ExportExt, BitBinaryExt { length: u32, bits: u8, }, NewFloatExt { num: f32, }, Atom { len: u16, }, AtomUtf8 { len: u16, }, } macro_rules! trace { ($target:expr) => { println!($target); }; } impl Reader { pub fn header(&mut self) -> Result<()> { let byte = self.source.read_u8()?; if byte != 131 { panic!("invalid header"); } Ok(()) } pub fn raw_tag(&mut self) -> Result { let tag_int = self.source.read_u8()?; let res = match tag_int { tag::ATOM_CACHE_REF => { trace!("atom_cache_ref"); let index = self.source.read_u8()?; RawTag::AtomCacheRef { index } } tag::SMALL_INTEGER_EXT => { trace!("small_integer_ext"); let int = self.source.read_u8()?; RawTag::SmallIntegerExt { int } } tag::INTEGER_EXT => { trace!("integer_ext"); let int = self.source.read_i32::()?; RawTag::IntegerExt { int } } tag::FLOAT_EXT => { trace!("float_ext"); RawTag::FloatExt } tag::PORT_EXT => { trace!("port_ext"); RawTag::PortExt } tag::NEW_PORT_EXT => { trace!("new_port_ext"); RawTag::NewPortExt } tag::PID_EXT => { trace!("pid_ext"); RawTag::PidExt } tag::NEW_PID_EXT => { trace!("new_pid_ext"); RawTag::NewPidExt } tag::SMALL_TUPLE_EXT => { trace!("small_tuple_ext"); let arity = self.source.read_u8()?; RawTag::Tuple { arity: arity as u32, } } tag::LARGE_TUPLE_EXT => { trace!("large_tuple_ext"); let arity = self.source.read_u32::()?; RawTag::Tuple { arity } } tag::MAP_EXT => { trace!("map_ext"); let arity = self.source.read_u32::()?; RawTag::MapExt { arity } } tag::NIL_EXT => { trace!("nil_ext"); RawTag::NilExt } tag::STRING_EXT => { trace!("string_ext"); let length = self.source.read_u16::()?; RawTag::StringExt { length } } tag::LIST_EXT => { trace!("list_ext"); let length = self.source.read_u32::()?; RawTag::ListExt { length } } tag::BINARY_EXT => { trace!("binary_ext"); let length = self.source.read_u32::()?; RawTag::BinaryExt { length } } tag::SMALL_BIG_EXT => { trace!("small_big_ext"); let data_len = self.source.read_u8()?; let is_neg = self.source.read_u8()? == 1; RawTag::SmallBigExt { data_len, is_neg } } tag::LARGE_BIG_EXT => { trace!("large_big_ext"); let data_len = self.source.read_u32::()?; let is_neg = self.source.read_u8()? == 1; RawTag::LargeBigExt { data_len, is_neg } } tag::NEWER_REFERENCE_EXT => { trace!("newer_reference_ext"); let id_len = self.source.read_u16::()?; RawTag::NewerReferenceExt { id_len } } tag::FUN_EXT => { trace!("fun_ext"); let num_free = self.source.read_u32::()?; RawTag::FunExt { num_free } } tag::NEW_FUN_EXT => { trace!("new_fun_ext"); let size = self.source.read_u32::()?; let arity = self.source.read_u8()?; let mut uniq = [0u8; 16]; self.source.read_exact(&mut uniq)?; let index = self.source.read_u32::()?; let num_free = self.source.read_u32::()?; RawTag::NewFunExt { size, arity, uniq, index, num_free, } } tag::EXPORT_EXT => { trace!("export_ext"); RawTag::ExportExt } tag::BIT_BINARY_EXT => { trace!("bit_binary_ext"); let length = self.source.read_u32::()?; let bits = self.source.read_u8()?; RawTag::BitBinaryExt { length, bits } } tag::NEW_FLOAT_EXT => { trace!("new_float_ext"); let num = self.source.read_f32::()?; RawTag::NewFloatExt { num } } tag::ATOM_EXT => { trace!("atom_ext"); let len = self.source.read_u16::()?; RawTag::Atom { len } } tag::SMALL_ATOM_EXT => { trace!("small_atom_ext"); let len = self.source.read_u8()?; RawTag::Atom { len: len as u16 } } tag::ATOM_UTF8_EXT => { trace!("atom_utf8_ext"); let len = self.source.read_u16::()?; RawTag::AtomUtf8 { len } } tag::SMALL_ATOM_UTF8_EXT => { trace!("small_atom_utf8_ext"); let len = self.source.read_u8()?; RawTag::AtomUtf8 { len: len as u16 } } tag => unreachable!("unknown tag {}", tag), }; Ok(res) } pub fn term(&mut self) -> Result { use RawTag::*; let res = match self.raw_tag()? { AtomUtf8 { len } => self.read_atom_term_utf8(len as usize)?, Atom { len } => self.read_atom_term_latin1(len as usize)?, SmallIntegerExt { int } => Term::Integer(int as i32), IntegerExt { int } => Term::Integer(int), NewFloatExt { num } => Term::Float(num), NilExt => Term::Nil, BinaryExt { length } => { let mut data = vec![0; length as usize]; self.source.read_exact(&mut data[..])?; Term::Binary(data) } BitBinaryExt { length, bits } => { let mut data = vec![0; length as usize]; self.source.read_exact(&mut data[..])?; Term::BitBinary(data, bits) } Tuple { arity } => { let terms = (0..arity).map(|_| self.term()).collect::>()?; Term::Tuple(terms) } MapExt { arity } => { let terms = (0..arity) .map(|_| Ok((self.term()?, self.term()?))) .collect::>()?; Term::Map(terms) } StringExt { length } => { let mut data = vec![0; length as usize]; self.source.read_exact(&mut data[..])?; Term::ByteList(data) } ListExt { length } => { let head = (0..length).map(|_| self.term()).collect::>()?; let tail = self.term()?; Term::List(head, Box::new(tail)) } _ => unimplemented!(), }; Ok(res) } fn read_atom_term_latin1(&mut self, len: usize) -> Result { let mut data = vec![0; len]; self.source.read_exact(&mut data[..])?; for byte in data.iter() { assert!(*byte < 128, "TODO latin1 characters"); } match String::from_utf8(data) { Ok(string) => Ok(Term::Atom(string)), _ => unreachable!(), } } fn read_atom_term_utf8(&mut self, len: usize) -> Result { let mut data = vec![0; len]; self.source.read_exact(&mut data[..])?; match String::from_utf8(data) { Ok(string) => Ok(Term::Atom(string)), _ => panic!("invalid atom"), } } } ================================================ FILE: util/libeir_etf/src/term.rs ================================================ use num_bigint::BigInt; trait TermTypes { type Atom; } #[derive(Debug, PartialEq)] pub enum Term { Integer(i32), Float(f32), Tuple(Vec), Map(Vec<(Term, Term)>), Nil, List(Vec, Box), ByteList(Vec), Binary(Vec), BitBinary(Vec, u8), BigInt(BigInt), Atom(String), } ================================================ FILE: util/libeir_etf/src/test/mod.rs ================================================ use crate::{Reader, Term}; macro_rules! make_reader { ($var:ident = $path:expr) => { let bin = std::fs::read($path).unwrap(); let mut cursor = std::io::Cursor::new(&bin); let mut $var = Reader::new(&mut cursor); }; } #[test] fn int_tuple() { make_reader!(reader = "test_data/int_tuple.etf"); reader.header().unwrap(); let term = reader.term().unwrap(); assert_eq!( term, Term::Tuple(vec![Term::Integer(1), Term::Integer(2), Term::Integer(3)]) ); } #[test] fn test_1() { make_reader!(reader = "test_data/test_1.etf"); reader.header().unwrap(); let term = reader.term().unwrap(); assert_eq!( term, Term::List( vec![ Term::Atom("hello".into()), Term::Integer(1), Term::Nil, Term::Integer(2222) ], Box::new(Term::Nil) ) ); } #[test] fn test_2() { make_reader!(reader = "test_data/test_2.etf"); reader.header().unwrap(); let term = reader.term().unwrap(); println!("{:?}", term); } ================================================ FILE: util/libeir_etf/src/writer.rs ================================================ use byteorder::{BigEndian, WriteBytesExt}; use num_bigint::{BigInt, Sign}; use std::convert::TryInto; use std::io::{Result, Write}; use super::constants::tag; use super::Term; pub struct Writer { sink: S, state: Vec, } #[derive(Debug, Copy, Clone)] enum WriterState { RemainingTerms(usize), RemainingMap(usize, u8), RemainingList(usize), RemainingData(usize), } impl WriterState { fn decr(&mut self) { match self { WriterState::RemainingTerms(n) if *n > 0 => *n -= 1, WriterState::RemainingMap(n, s) if *n > 0 && *s < 2 => *s += 1, WriterState::RemainingList(n) if *n > 0 => *n -= 1, _ => panic!("no term expected at current level"), } } } impl Writer { pub fn new(sink: S) -> Self { Writer { sink, state: vec![WriterState::RemainingTerms(1)], } } pub fn pop(&mut self) { match self.state.pop().expect("tried to pop empty stack") { WriterState::RemainingTerms(0) => (), _ => panic!("tried to pop invalid state"), } } pub fn next_kv(&mut self) { match self.state.last_mut().expect("tried to next on empty stack") { WriterState::RemainingMap(0, _) => panic!("no map keys left"), WriterState::RemainingMap(n, s @ 2) => { *n -= 1; *s = 0; } _ => panic!("tried to next on invalid state"), } } pub fn next_tail(&mut self) { match self.state.last_mut().expect("tried to next on empty stack") { a @ WriterState::RemainingList(0) => *a = WriterState::RemainingTerms(1), _ => panic!("tried to next on invalid state"), } } } /// Generic impl Writer { pub fn push_data(&mut self, data: &[u8]) -> Result<()> { let last_state = self.state.pop().unwrap(); if let WriterState::RemainingData(mut rem) = last_state { assert!(rem <= data.len()); rem -= data.len(); if rem > 0 { self.state.push(WriterState::RemainingData(rem)); } self.sink.write_all(data) } else { panic!() } } } /// Raw interface impl Writer { pub fn raw_small_integer_ext(&mut self, int: u8) -> Result<()> { self.state.last_mut().unwrap().decr(); self.sink.write_u8(tag::SMALL_INTEGER_EXT)?; self.sink.write_u8(int) } pub fn raw_integer_ext(&mut self, int: i32) -> Result<()> { self.state.last_mut().unwrap().decr(); self.sink.write_u8(tag::INTEGER_EXT)?; self.sink.write_i32::(int) } pub fn raw_big_ext(&mut self, int: &BigInt) -> Result<()> { self.state.last_mut().unwrap().decr(); let (sign, bytes) = int.to_bytes_be(); let bytes_len = bytes.len(); let sign_u8 = if sign == Sign::Minus { 1 } else { 0 }; if let Ok(len) = bytes_len.try_into() { self.sink.write_u8(tag::SMALL_BIG_EXT)?; self.sink.write_u8(len)?; self.sink.write_u8(sign_u8)?; self.sink.write_all(&bytes) } else if let Ok(len) = bytes_len.try_into() { self.sink.write_u8(tag::LARGE_BIG_EXT)?; self.sink.write_u32::(len)?; self.sink.write_u8(sign_u8)?; self.sink.write_all(&bytes) } else { panic!("number too large") } } pub fn raw_new_float_ext(&mut self, float: f32) -> Result<()> { self.state.last_mut().unwrap().decr(); self.sink.write_u8(tag::NEW_FLOAT_EXT)?; self.sink.write_f32::(float) } pub fn raw_nil(&mut self) -> Result<()> { self.state.last_mut().unwrap().decr(); self.sink.write_u8(tag::NIL_EXT) } pub fn raw_atom_utf8_ext(&mut self, data: &str) -> Result<()> { let bytes = data.as_bytes(); let len_u16: u16 = bytes.len().try_into().unwrap(); self.state.last_mut().unwrap().decr(); self.sink.write_u8(tag::ATOM_UTF8_EXT)?; self.sink.write_u16::(len_u16)?; self.sink.write_all(bytes) } pub fn raw_small_atom_utf8_ext(&mut self, data: &str) -> Result<()> { let bytes = data.as_bytes(); let len_u8: u8 = bytes.len().try_into().unwrap(); self.state.last_mut().unwrap().decr(); self.sink.write_u8(tag::SMALL_ATOM_UTF8_EXT)?; self.sink.write_u8(len_u8)?; self.sink.write_all(bytes) } pub fn raw_small_tuple_ext(&mut self, arity: u8) -> Result<()> { self.state.last_mut().unwrap().decr(); self.state.push(WriterState::RemainingTerms(arity as usize)); self.sink.write_u8(tag::SMALL_TUPLE_EXT)?; self.sink.write_u8(arity) } pub fn raw_large_tuple_ext(&mut self, arity: u16) -> Result<()> { self.state.last_mut().unwrap().decr(); self.state.push(WriterState::RemainingTerms(arity as usize)); self.sink.write_u8(tag::LARGE_TUPLE_EXT)?; self.sink.write_u16::(arity) } pub fn raw_map_ext(&mut self, size: u32) -> Result<()> { self.state.last_mut().unwrap().decr(); self.state.push(WriterState::RemainingMap(size as usize, 0)); self.sink.write_u8(tag::MAP_EXT)?; self.sink.write_u32::(size) } pub fn raw_list_ext(&mut self, length: u32) -> Result<()> { self.state.last_mut().unwrap().decr(); self.state.push(WriterState::RemainingList(length as usize)); self.sink.write_u8(tag::LIST_EXT)?; self.sink.write_u32::(length) } pub fn raw_binary_ext(&mut self, length: u32) -> Result<()> { self.state.last_mut().unwrap().decr(); self.state.push(WriterState::RemainingData(length as usize)); self.sink.write_u8(tag::BINARY_EXT)?; self.sink.write_u32::(length) } pub fn raw_bit_binary_ext(&mut self, length: u32, last_bits: u8) -> Result<()> { debug_assert!(last_bits <= 7); self.state.last_mut().unwrap().decr(); self.state.push(WriterState::RemainingData(length as usize)); self.sink.write_u8(tag::BIT_BINARY_EXT)?; self.sink.write_u32::(length)?; self.sink.write_u8(last_bits) } } /// Normal API for terminals impl Writer { pub fn integer_u8(&mut self, int: u8) -> Result<()> { self.raw_small_integer_ext(int) } pub fn integer_i32(&mut self, int: i32) -> Result<()> { self.raw_integer_ext(int) } pub fn integer_big(&mut self, int: &BigInt) -> Result<()> { self.raw_big_ext(int) } pub fn float(&mut self, num: f32) -> Result<()> { self.raw_new_float_ext(num) } pub fn nil(&mut self) -> Result<()> { self.raw_nil() } pub fn atom(&mut self, string: &str) -> Result<()> { let len = string.len(); if let Ok(_len) = TryInto::::try_into(len) { self.raw_small_atom_utf8_ext(string) } else if let Ok(_len) = TryInto::::try_into(len) { self.raw_atom_utf8_ext(string) } else { panic!("atom cannot be longer than 2^16"); } } pub fn tuple(&mut self, len: usize) -> Result<()> { if let Ok(len) = len.try_into() { self.raw_small_tuple_ext(len) } else if let Ok(len) = len.try_into() { self.raw_large_tuple_ext(len) } else { panic!("tuple cannot be longer than 2^16"); } } pub fn map>(&mut self, len: N) -> Result<()> { if let Ok(len) = len.try_into() { self.raw_map_ext(len) } else { panic!("map cannot be longer than 2^32"); } } pub fn list>(&mut self, len: N) -> Result<()> { if let Ok(len) = len.try_into() { self.raw_list_ext(len) } else { panic!("list cannot be longer than 2^32"); } } pub fn binary>(&mut self, len: N) -> Result<()> { if let Ok(len) = len.try_into() { self.raw_binary_ext(len) } else { panic!("binary cannot be longer than 2^32"); } } pub fn bit_binary>(&mut self, len: N, last_bits: u8) -> Result<()> { if let Ok(len) = len.try_into() { self.raw_bit_binary_ext(len, last_bits) } else { panic!("binary cannot be longer than 2^32"); } } } impl Writer { pub fn term(&mut self, term: &Term) -> Result<()> { match term { Term::Float(num) => self.float(*num), Term::Integer(int) => { if let Ok(int) = (*int).try_into() { self.integer_u8(int) } else if let Ok(int) = (*int).try_into() { self.integer_i32(int) } else { unimplemented!() } } Term::Nil => self.nil(), Term::Tuple(elems) => { self.tuple(elems.len())?; for elem in elems { self.term(elem)?; } self.pop(); Ok(()) } Term::List(elems, tail) => { self.list(elems.len())?; for elem in elems { self.term(elem)?; } self.next_tail(); self.term(tail)?; self.pop(); Ok(()) } Term::Map(elems) => { self.map(elems.len())?; for (k, v) in elems { self.term(k)?; self.term(v)?; self.next_kv(); } self.pop(); Ok(()) } _ => unimplemented!(), } } } ================================================ FILE: util/libeir_etf/test_data/generate.exs ================================================ :ok = File.write("int_tuple.etf", :erlang.term_to_binary({1, 2, 3})) :ok = File.write("test_1.etf", :erlang.term_to_binary([:hello, 1, [], 2222])) :ok = File.write("test_2.etf", :erlang.term_to_binary(%{"foo" => :bar, 1 => {}})) ================================================ FILE: util/libeir_etf/test_data/int_tuple.etf ================================================ haaa ================================================ FILE: util/libeir_util_binary/Cargo.toml ================================================ [package] name = "libeir_util_binary" version = "0.1.0" authors = ["Hans Elias B. Josephsen "] edition = "2018" license = "MIT OR Apache-2.0" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] num-traits = "0.2.8" num-bigint = { git = "https://github.com/hansihe/num-bigint.git" } ================================================ FILE: util/libeir_util_binary/src/bitvec.rs ================================================ use std::cmp::Ordering; use std::hash::{Hash, Hasher}; use super::BitSlice; use super::{BitCarrier, BitRead, BitWrite}; #[derive(Debug, Clone)] pub struct BitVec { buf: Vec, bit_size: usize, } impl BitVec { pub fn new() -> Self { BitVec { buf: vec![], bit_size: 0, } } pub fn with_size(size: usize) -> Self { let byte_len = (size + 7) / 8; BitVec { buf: vec![0; byte_len], bit_size: size, } } pub fn clear(&mut self) { self.buf.clear(); self.bit_size = 0; } pub fn empty(&mut self) -> bool { self.bit_size == 0 } pub fn try_as_byte_aligned_slice(&self) -> Option<&[u8]> { if self.bit_size % 8 == 0 { Some(&self.buf) } else { None } } pub fn len(&self) -> usize { self.buf.len() } pub fn as_ref(&self) -> &[u8] { &self.buf } pub fn get(&self, n: usize) -> Option { self.buf.get(n).cloned() } pub fn push(&mut self, from: R) where R: BitRead, { let needed = from.bit_len(); let availible = self.buf.len() * 8 - self.bit_size; if needed > availible { let needed_bytes = ((needed - availible) + 7) / 8; for _ in 0..needed_bytes { self.buf.push(0); } } let mut slice = BitSlice::<&mut [u8]>::with_offset_length(&mut self.buf[..], self.bit_size, needed); slice.write(from); self.bit_size += needed; } pub fn pop(&mut self, to: &mut R) -> Option<()> where R: BitWrite, { let to_size = to.bit_len(); let self_size = self.bit_size; if self_size < to_size { return None; } let slice = BitSlice::<&mut [u8]>::with_offset_length( &mut self.buf[..], self.bit_size - to_size, to_size, ); to.write(&slice); let unneeded = to_size / 8; for _ in 0..unneeded { self.buf.pop(); } self.bit_size -= to_size; debug_assert!(self.bit_size <= self.buf.len() * 8); Some(()) } pub fn iter_bytes(&self) -> BitVecBytesIterator { BitVecBytesIterator { vec: self, elem: 0, rem: self.bit_size + 8, } } } impl Default for BitVec { fn default() -> Self { BitVec::new() } } impl From> for BitVec { fn from(buf: Vec) -> BitVec { BitVec { bit_size: buf.len() * 8, buf, } } } pub struct BitVecBytesIterator<'a> { vec: &'a BitVec, elem: usize, rem: usize, } impl<'a> Iterator for BitVecBytesIterator<'a> { type Item = u8; fn next(&mut self) -> Option { if self.rem < 8 { None } else { self.rem -= 8; let mask = !(!0u8) .checked_shr(std::cmp::min(8, self.rem) as u32) .unwrap_or(0); let ret = self.vec.buf[self.elem] & mask; self.elem += 1; Some(ret) } } } //impl Eq for BitVec {} //impl PartialEq for BitVec { // fn eq(&self, other: &Self) -> bool { // if self.bit_size != other.bit_size { return false; } // self.iter_bytes().eq(other.iter_bytes()) // } //} // //impl Ord for BitVec { // fn cmp(&self, other: &Self) -> Ordering { // match self.iter_bytes().cmp(other.iter_bytes()) { // Ordering::Equal => (), // non_eq => return non_eq, // } // // self.bit_size.cmp(&other.bit_size) // } //} //impl PartialOrd for BitVec { // fn partial_cmp(&self, other: &Self) -> Option { // Some(self.cmp(other)) // } //} // //impl Hash for BitVec { // fn hash(&self, state: &mut H) where H: Hasher { // self.bit_size.hash(state); // for elem in self.iter_bytes() { // elem.hash(state); // } // } //} impl BitCarrier for BitVec { type T = u8; fn bit_len(&self) -> usize { self.bit_size } } impl BitRead for BitVec { fn read_word(&self, n: usize) -> u8 { self.buf.get(n).cloned().unwrap_or(0) } } impl BitWrite for BitVec { fn write_word(&mut self, n: usize, data: u8, mask: u8) { self.buf .get_mut(n) .map(|d| *d = (*d & !mask) | (data & mask)); } } impl Eq for BitVec {} impl PartialEq for BitVec where O: BitRead, { fn eq(&self, other: &O) -> bool { if self.bit_len() != other.bit_len() { return false; } self.iter_words().eq(other.iter_words()) } } impl PartialOrd for BitVec where O: BitRead, { fn partial_cmp(&self, other: &O) -> Option { match self.iter_words().cmp(other.iter_words()) { Ordering::Equal => (), non_eq => return Some(non_eq), } Some(self.bit_len().cmp(&other.bit_len())) } } impl Ord for BitVec { fn cmp(&self, other: &Self) -> Ordering { self.partial_cmp(other).unwrap() } } impl Hash for BitVec { fn hash(&self, state: &mut H) where H: Hasher, { self.bit_len().hash(state); for elem in self.iter_words() { elem.hash(state); } } } #[cfg(test)] mod test { use super::BitVec; #[test] fn basic_push_pop() { let mut vec = BitVec::new(); vec.push(1u32); assert!(vec.len() == 4); assert!(vec.get(0) == Some(0)); assert!(vec.get(1) == Some(0)); assert!(vec.get(2) == Some(0)); assert!(vec.get(3) == Some(1)); assert!(vec.get(4) == None); let mut ret: u32 = 0; vec.pop(&mut ret); assert!(vec.len() == 0); assert!(ret == 1); vec.clear(); vec.push(true); vec.push(1u32); assert!(vec.len() == 5); assert!(vec.get(0) == Some(128)); assert!(vec.get(1) == Some(0)); assert!(vec.get(2) == Some(0)); assert!(vec.get(3) == Some(0)); assert!(vec.get(4) == Some(128)); assert!(vec.get(5) == None); let mut ret: bool = false; vec.pop(&mut ret); assert!(ret == true); let mut ret: u32 = 0; vec.pop(&mut ret); assert!(ret == 0b10000000_00000000_00000000_00000000); } } ================================================ FILE: util/libeir_util_binary/src/extend.rs ================================================ use crate::{BitCarrier, BitTransport, BitRead, BitSlice}; /// Extends the inner carrier by the given number of words. /// /// Even if `head_extend` and `tail_extend` is 0, this will pad the length of /// inner to the next whole transport size. #[derive(Debug, Clone)] pub struct ExtendWords { pub(crate) inner: I, pub(crate) extend: I::T, pub(crate) head_extend: usize, pub(crate) tail_extend: usize, } impl BitCarrier for ExtendWords where I: BitCarrier, { type T = I::T; fn bit_len(&self) -> usize { (((self.inner.bit_len() + 7) / 8) + self.head_extend + self.tail_extend) * I::T::BIT_SIZE } } impl BitRead for ExtendWords where I: BitRead, { fn read_word(&self, n: usize) -> I::T { if n < self.head_extend { self.extend } else { let n = n - self.head_extend; let inner_bl = self.inner.bit_len(); let last_word = inner_bl / 8; let inner_bl_mod = inner_bl % I::T::BIT_SIZE; if inner_bl == 0 { self.extend } else if n < last_word || (n == last_word && inner_bl_mod == 0) { // We read a whole word, no funny business self.inner.read_word(n) } else if n == last_word { debug_assert!(inner_bl_mod != 0); // We read a partial word. // We need to extend the last bits. let word = self.inner.read_word(n); let mod_inv = I::T::BIT_SIZE - inner_bl_mod; let mask = I::T::MAX << mod_inv as u32; (word & mask) | (self.extend & !mask) } else if n > last_word { self.extend } else { unreachable!() } } } } pub type Extend = BitSlice>; pub fn extend_words_pad(inner: I, extend: I::T, head_words: usize, tail_words: usize) -> ExtendWords { ExtendWords { inner, extend, head_extend: head_words, tail_extend: tail_words, } } pub fn extend_bits(inner: I, extend: I::T, head_bits: usize, tail_bits: usize) -> Extend { let head_words = (head_bits + (I::T::BIT_SIZE - 1)) / I::T::BIT_SIZE; let tail_words = (tail_bits + (I::T::BIT_SIZE - 1)) / I::T::BIT_SIZE; let offset = (head_words * I::T::BIT_SIZE) - head_bits; let length = head_bits + inner.bit_len() + tail_bits; inner.extend_words_pad(extend, head_words, tail_words).slice_bits(offset, length) } #[cfg(test)] mod tests { use crate::{BitSlice, BitCarrier, BitRead}; #[test] fn extend_words_pad() { let bs = BitSlice::with_offset_length(0b10010110u8, 2, 6); let bse = (&bs).extend_words_pad(0xff, 0, 0); assert_eq!(bse.bit_len(), 8); assert_eq!(bse.read_word(0), 0b01011011); let bse = (&bs).extend_bits(0xff, 4, 4); assert_eq!(bse.bit_len(), 6 + 8); assert_eq!(bse.read_word(0), 0b11110101); assert_eq!(bse.read_word(1) & 0b11111100, 0b10111100); } } ================================================ FILE: util/libeir_util_binary/src/impls.rs ================================================ use super::{BitCarrier, BitRead, BitTransport, BitWrite}; macro_rules! impl_prim { ($typ:ty, $utyp:ty) => { impl BitCarrier for $typ { type T = u8; fn bit_len(&self) -> usize { std::mem::size_of::() * 8 } } impl BitRead for $typ { fn read_word(&self, n: usize) -> u8 { let size = std::mem::size_of::(); if n < size { ((*self as $utyp) >> (8 * (size - 1 - n))) as u8 } else { 0 } } } impl BitWrite for $typ { fn write_word(&mut self, n: usize, data: u8, mask: u8) { let size = std::mem::size_of::(); let offset = 8 * (size - 1 - n); *self = (((*self as $utyp) & !((mask as $utyp) << offset)) | ((data as $utyp) << offset)) as $typ; } } }; } macro_rules! impl_float { ($typ:ty, $utyp:ty) => { impl BitCarrier for $typ { type T = u8; fn bit_len(&self) -> usize { std::mem::size_of::() * 8 } } impl BitRead for $typ { fn read_word(&self, n: usize) -> u8 { let size = std::mem::size_of::(); if n < size { ((self.to_bits()) >> (8 * (size - 1 - n))) as u8 } else { 0 } } } impl BitWrite for $typ { fn write_word(&mut self, n: usize, data: u8, mask: u8) { let size = std::mem::size_of::(); let offset = 8 * (size - 1 - n); *self = Self::from_bits( ((self.to_bits()) & !((mask as $utyp) << offset)) | ((data as $utyp) << offset), ); } } }; } impl_prim!(u8, u8); impl_prim!(i8, u8); impl_prim!(u16, u16); impl_prim!(i16, u16); impl_prim!(u32, u32); impl_prim!(i32, u32); impl_prim!(u64, u64); impl_prim!(i64, u64); impl_prim!(u128, u128); impl_prim!(i128, u128); impl_float!(f32, u32); impl_float!(f64, u64); // Base u1 implementations impl BitCarrier for bool { type T = u8; fn bit_len(&self) -> usize { 1 } } impl BitRead for bool { fn read_word(&self, _n: usize) -> u8 { (*self as u8) << 7 } } impl BitWrite for bool { fn write_word(&mut self, n: usize, data: u8, mask: u8) { assert!(n == 0); if mask & 0b10000000 != 1 { *self = (data & 0b10000000) != 0; } else { panic!() } } } // Blanket implementations impl BitCarrier for &N where N: BitCarrier, Tr: BitTransport, { type T = Tr; fn bit_len(&self) -> usize { N::bit_len(self) } } impl BitRead for &N where N: BitRead, { fn read_word(&self, n: usize) -> Self::T { N::read_word(self, n) } } impl BitCarrier for &mut N where N: BitCarrier, Tr: BitTransport, { type T = Tr; fn bit_len(&self) -> usize { N::bit_len(self) } } impl BitRead for &mut N where N: BitRead, { fn read_word(&self, n: usize) -> Self::T { N::read_word(self, n) } } impl BitWrite for &mut N where N: BitWrite, { fn write_word(&mut self, n: usize, data: Self::T, mask: Self::T) { N::write_word(self, n, data, mask) } } //impl BitCarrier for &mut N where N: BitCarrier, T: BitTransport { // fn bit_len(&self) -> usize { // N::bit_len(self) // } //} //impl BitRead for &mut N where N: BitRead, T: BitTransport { // fn read_word(&self, n: usize) -> T { // N::read_word(self, n) // } //} impl BitCarrier for Vec where Tr: BitTransport, { type T = Tr; fn bit_len(&self) -> usize { (self as &[Self::T]).bit_len() } } impl BitRead for Vec where Tr: BitTransport, { fn read_word(&self, n: usize) -> Self::T { (self as &[Self::T]).read_word(n) } } impl BitWrite for Vec where Tr: BitTransport, { fn write_word(&mut self, n: usize, data: Self::T, mask: Self::T) { (self as &mut [Self::T]).write_word(n, data, mask) } } impl BitCarrier for &[Tr] where Tr: BitTransport, { type T = Tr; fn bit_len(&self) -> usize { self.len() * 8 } } impl BitRead for &[Tr] where Tr: BitTransport, { fn read_word(&self, n: usize) -> Self::T { self.get(n).cloned().unwrap_or(Self::T::ZERO) } } impl BitCarrier for &mut [Tr] where Tr: BitTransport, { type T = Tr; fn bit_len(&self) -> usize { self.len() * 8 } } impl BitRead for &mut [Tr] where Tr: BitTransport, { fn read_word(&self, n: usize) -> Self::T { self.get(n).cloned().unwrap_or(Self::T::ZERO) } } impl BitWrite for &mut [Tr] where Tr: BitTransport, { fn write_word(&mut self, n: usize, data: Self::T, mask: Self::T) { self.get_mut(n).map(|v| *v = (*v & !mask) | (data & mask)); } } impl BitCarrier for [Tr] where Tr: BitTransport, { type T = Tr; fn bit_len(&self) -> usize { self.len() * 8 } } impl BitRead for [Tr] where Tr: BitTransport, { fn read_word(&self, n: usize) -> Self::T { self.get(n).cloned().unwrap_or(Self::T::ZERO) } } impl BitWrite for [Tr] where Tr: BitTransport, { fn write_word(&mut self, n: usize, data: Self::T, mask: Self::T) { self.get_mut(n).map(|v| *v = (*v & !mask) | (data & mask)); } } //macro_rules! impl_traits { // (($($es:ty,),*), $typ:ty) => { // impl<$($es),*> Eq for $typ where {} // impl PartialEq for $typ where O: BitRead { // fn eq(&self, other: &Self) -> bool { // if self.bit_len() != other.bit_len() { return false; } // self.iter_words().eq(other.iter_words()) // } // } // // impl<$($es),*> Ord for $typ { // fn cmp(&self, other: &Self) -> Ordering { // match self.iter_words().cmp(other.iter_words()) { // Ordering::Equal => (), // non_eq => return non_eq, // } // // self.bit_len().cmp(&other.bit_len()) // } // } // impl<$($es),*> PartialOrd for $typ { // fn partial_cmp(&self, other: &Self) -> Option { // Some(self.cmp(other)) // } // } // // impl<$($es),*> Hash for $typ { // fn hash(&self, state: &mut H) where H: Hasher { // self.bit_len().hash(state); // for elem in self.iter_words() { // elem.hash(state); // } // } // } // // // } //} //impl_traits!((), BitSlice); //impl_traits!((), BitVec); ================================================ FILE: util/libeir_util_binary/src/integer.rs ================================================ //use rug::Integer; //use rug::integer::Order; use num_bigint::{BigInt, Sign}; use super::{BitRead, BitSlice, BitWrite, BitCarrier}; #[derive(Debug, Copy, Clone)] pub enum Endian { Big, Little, } //impl Endian { // fn to_order(&self) -> Order { // match self { // Endian::Big => Order::Msf, // Endian::Little => Order::Lsf, // } // } //} impl BitCarrier for BigInt { type T = u8; fn bit_len(&self) -> usize { let bits = self.bits() as usize; if self < &0 { bits + 1 } else { bits } } } pub fn integer_to_carrier(mut int: BigInt, bits: usize, endian: Endian) -> BitSlice> { let negative = int < 0; if negative { int += 1; } let keep_bytes = (bits + 7) / 8; let aux_bits = bits % 8; let (_sign, mut digits) = match endian { Endian::Big => int.to_bytes_be(), Endian::Little => int.to_bytes_le(), }; match endian { Endian::Big => { let mut new = Vec::new(); if keep_bytes > digits.len() { new.resize(keep_bytes - digits.len(), 0); new.extend(digits.iter()); } else { new.extend(digits.iter().skip(digits.len() - keep_bytes)); } digits = new; } Endian::Little => { digits.resize(keep_bytes, 0); } } if negative { for digit in digits.iter_mut() { *digit = !*digit; } } match endian { Endian::Big => { if aux_bits > 0 { digits[0] &= !(!0 << aux_bits); BitSlice::with_offset_length(digits, 8 - aux_bits, bits) } else { BitSlice::with_offset_length(digits, 0, bits) } } Endian::Little => { if aux_bits > 0 { digits[keep_bytes - 1] <<= 8 - aux_bits; } BitSlice::with_offset_length(digits, 0, bits) } } } fn carrier_to_buf(carrier: C, signed: bool, endian: Endian) -> (Vec, bool) where C: BitRead, { let bit_len = carrier.bit_len(); let num_bytes = (bit_len + 7) / 8; let aux_bits = bit_len % 8; let aux_bits_wrap = if aux_bits == 0 { 8 } else { aux_bits }; let offset = match endian { Endian::Big => 8 - aux_bits_wrap, Endian::Little => 0, }; let mut buf = vec![0; num_bytes]; { let mut slice = BitSlice::with_offset_length(&mut buf, offset, bit_len); slice.write(carrier); } let mut last = match endian { Endian::Big => buf[0], Endian::Little => buf[num_bytes - 1] >> aux_bits, }; // Sign extend let mut sign = false; if signed { sign = last & (1 << (aux_bits_wrap - 1)) != 0; if sign { last |= !(!0 >> (8 - aux_bits_wrap)); } } match endian { Endian::Big => buf[0] = last, Endian::Little => buf[num_bytes - 1] = last, } (buf, sign) } pub fn carrier_to_integer(carrier: C, signed: bool, endian: Endian) -> BigInt where C: BitRead, { let (mut buf, sign) = carrier_to_buf(carrier, signed, endian); if sign { for elem in buf.iter_mut() { *elem = !*elem; } let mut int = match endian { Endian::Big => BigInt::from_bytes_be(Sign::Plus, &buf), Endian::Little => BigInt::from_bytes_le(Sign::Plus, &buf), }; int *= -1; int -= 1; int } else { match endian { Endian::Big => BigInt::from_bytes_be(Sign::Plus, &buf), Endian::Little => BigInt::from_bytes_le(Sign::Plus, &buf), } } } #[cfg(test)] mod tests { use super::super::{BitSlice, BitWrite}; use super::{carrier_to_buf, carrier_to_integer, integer_to_carrier, Endian}; use num_bigint::BigInt; #[test] fn integer_adapter_basic() { let int = BigInt::from(0b00001111_00010000); { let conv = integer_to_carrier(int.clone(), 16, Endian::Little); let mut out: [u8; 2] = [0; 2]; out.write(&conv); assert!(out[0] == 0b00010000); assert!(out[1] == 0b00001111); } { let conv = integer_to_carrier(int.clone(), 16, Endian::Big); let mut out: [u8; 2] = [0; 2]; out.write(&conv); assert!(out[0] == 0b00001111); assert!(out[1] == 0b00010000); } } #[test] fn integer_adapter_unaligned() { let int = BigInt::from(0b00001111_00010000); { let conv = integer_to_carrier(int.clone(), 12, Endian::Little); let mut out: [u8; 2] = [0; 2]; { let mut slice = BitSlice::with_offset_length(&mut out as &mut [u8], 0, 12); slice.write(conv); } assert!(out[0] == 0b00010000); assert!(out[1] == 0b11110000); } { let conv = integer_to_carrier(int.clone(), 12, Endian::Big); let mut out: [u8; 2] = [0; 2]; { let mut slice = BitSlice::with_offset_length(&mut out as &mut [u8], 0, 12); slice.write(conv); } assert!(out[0] == 0b11110001); assert!(out[1] == 0b00000000); } } #[test] fn integer_adapter_negative() { { let int = BigInt::from(-5); let conv = integer_to_carrier(int.clone(), 16, Endian::Big); let mut out: i16 = 0; out.write(&conv); dbg!(out); assert!(out == -5); } { let int = BigInt::from(-10000); let conv = integer_to_carrier(int.clone(), 16, Endian::Big); let mut out: i16 = 0; out.write(&conv); dbg!(out); assert!(out == -10000); } } #[test] fn integer_carrier_to_buf() { { let int = BigInt::from(5); let conv = integer_to_carrier(int.clone(), 16, Endian::Big); let mut buf: [u8; 2] = [0; 2]; buf.write(&conv); let (out, sign) = carrier_to_buf(&buf as &[u8], false, Endian::Big); assert!(sign == false); assert!(out[0] == 0); assert!(out[1] == 5); let (out, sign) = carrier_to_buf(&buf as &[u8], true, Endian::Big); assert!(out[0] == 0); assert!(out[1] == 5); assert!(sign == false); } { let int = BigInt::from(0b00000101_01010101); let conv = integer_to_carrier(int.clone(), 12, Endian::Big); let mut buf: [u8; 2] = [0; 2]; let mut carrier = BitSlice::with_offset_length(&mut buf as &mut [u8], 0, 12); carrier.write(&conv); let (out, sign) = carrier_to_buf(&carrier, false, Endian::Big); assert!(out[0] == 0b00000101); assert!(out[1] == 0b01010101); assert!(sign == false); let (out, sign) = carrier_to_buf(&carrier, true, Endian::Big); assert!(out[0] == 0b00000101); assert!(out[1] == 0b01010101); assert!(sign == false); } { let int = BigInt::from(0b00001010_10101010); let conv = integer_to_carrier(int.clone(), 12, Endian::Big); let mut buf: [u8; 2] = [0; 2]; let mut carrier = BitSlice::with_offset_length(&mut buf as &mut [u8], 0, 12); carrier.write(&conv); let (out, sign) = carrier_to_buf(&carrier, false, Endian::Big); assert!(out[0] == 0b00001010); assert!(out[1] == 0b10101010); assert!(sign == false); let (out, sign) = carrier_to_buf(&carrier, true, Endian::Big); assert!(out[0] == 0b11111010); assert!(out[1] == 0b10101010); assert!(sign == true); } { let int = BigInt::from(0b00001010_10101010); let conv = integer_to_carrier(int.clone(), 12, Endian::Little); let mut buf: [u8; 2] = [0; 2]; let mut carrier = BitSlice::with_offset_length(&mut buf as &mut [u8], 0, 12); carrier.write(&conv); let (out, sign) = carrier_to_buf(&carrier, false, Endian::Little); assert!(out[0] == 0b10101010); assert!(out[1] == 0b00001010); assert!(sign == false); let (out, sign) = carrier_to_buf(&carrier, true, Endian::Little); assert!(out[0] == 0b10101010); assert!(out[1] == 0b11111010); assert!(sign == true); } } #[test] fn integer_round_trip_basic() { { let int = BigInt::from(5); let conv = integer_to_carrier(int.clone(), 16, Endian::Big); let mut buf: [u8; 2] = [0; 2]; buf.write(&conv); let back = carrier_to_integer(&buf as &[u8], true, Endian::Big); assert!(int == back); } { let int = BigInt::from(-5); let conv = integer_to_carrier(int.clone(), 16, Endian::Big); let mut buf: [u8; 2] = [0; 2]; buf.write(&conv); let back = carrier_to_integer(&buf as &[u8], true, Endian::Big); assert!(int == back); } { let int = BigInt::from(5); let conv = integer_to_carrier(int.clone(), 16, Endian::Little); let mut buf: [u8; 2] = [0; 2]; buf.write(&conv); let back = carrier_to_integer(&buf as &[u8], true, Endian::Little); assert!(int == back); } { let int = BigInt::from(-5); let conv = integer_to_carrier(int.clone(), 16, Endian::Little); let mut buf: [u8; 2] = [0; 2]; buf.write(&conv); let back = carrier_to_integer(&buf as &[u8], true, Endian::Little); assert!(int == back); } } #[test] fn integer_round_trip_unaligned() { { let int = BigInt::from(5); let conv = integer_to_carrier(int.clone(), 12, Endian::Big); let mut buf: [u8; 2] = [0; 2]; let mut carrier = BitSlice::with_offset_length(&mut buf as &mut [u8], 0, 12); carrier.write(&conv); let back = carrier_to_integer(&carrier, true, Endian::Big); assert!(int == back); } { let int = BigInt::from(5); let conv = integer_to_carrier(int.clone(), 12, Endian::Little); let mut buf: [u8; 2] = [0; 2]; let mut carrier = BitSlice::with_offset_length(&mut buf as &mut [u8], 0, 12); carrier.write(&conv); let back = carrier_to_integer(&carrier, true, Endian::Little); assert!(int == back); } { let int = BigInt::from(-5); let conv = integer_to_carrier(int.clone(), 12, Endian::Big); let mut buf: [u8; 2] = [0; 2]; let mut carrier = BitSlice::with_offset_length(&mut buf as &mut [u8], 0, 12); carrier.write(&conv); let back = carrier_to_integer(&carrier, true, Endian::Big); assert!(int == back); } { let int = BigInt::from(-5); let conv = integer_to_carrier(int.clone(), 12, Endian::Little); let mut buf: [u8; 2] = [0; 2]; let mut carrier = BitSlice::with_offset_length(&mut buf as &mut [u8], 0, 12); carrier.write(&conv); let back = carrier_to_integer(&carrier, true, Endian::Little); assert!(int == back); } } } ================================================ FILE: util/libeir_util_binary/src/lib.rs ================================================ use std::cmp::Ord; use std::fmt::Debug; use std::hash::Hash; use std::marker::PhantomData; use std::ops::{BitAnd, BitOr, Not}; use num_traits::{CheckedShl, CheckedShr}; mod impls; mod slice; pub use self::slice::BitSlice; mod bitvec; pub use self::bitvec::BitVec; mod integer; pub use self::integer::{carrier_to_integer, integer_to_carrier, Endian}; mod extend; pub use self::extend::{ExtendWords, Extend}; /// A primitive data type that can be used to store bits. /// Must be sized, copyable, and implement a set of /// elemental operations. pub trait BitTransport: Sized + Ord + Copy + Not + BitAnd + BitOr + CheckedShr + CheckedShl + Eq + Hash + Debug { const SIZE: usize; const BIT_SIZE: usize = Self::SIZE * 8; const ZERO: Self; const ONE: Self; const MAX: Self; } impl BitTransport for u8 { const SIZE: usize = 1; const ZERO: u8 = 0; const ONE: u8 = 0; const MAX: u8 = 0xff; } /// The base trait for bit carriers. /// Has a certain bit length. pub trait BitCarrier { type T: BitTransport; /// The total length in bits. fn bit_len(&self) -> usize; /// Total word length including partial word at the end. fn word_len(&self) -> usize { (self.bit_len() + (Self::T::BIT_SIZE - 1)) / Self::T::BIT_SIZE } /// Number of bits in the padding word at the end. fn partial_bit_len(&self) -> usize { let rem = self.bit_len() % Self::T::BIT_SIZE; if rem == 0 { Self::T::BIT_SIZE } else { rem } } fn extend_words_pad(self, extend: Self::T, head_words: usize, tail_words: usize) -> ExtendWords where Self: Sized, { crate::extend::extend_words_pad(self, extend, head_words, tail_words) } fn slice_bits(self, offset: usize, length: usize) -> BitSlice where Self: Sized, { BitSlice::with_offset_length(self, offset, length) } fn extend_bits(self, extend: Self::T, head_bits: usize, tail_bits: usize) -> Extend where Self: Sized, { crate::extend::extend_bits(self, extend, head_bits, tail_bits) } } pub trait BitRead: BitCarrier { /// Reads the nth word from the data type. /// The last word may be padded with arbitrary bits at the /// least significant digit side. fn read_word(&self, n: usize) -> Self::T; fn read_bit(&self, bit_n: usize) -> bool { let word_n = bit_n / Self::T::BIT_SIZE; let sub_bit_n = bit_n % Self::T::BIT_SIZE; let word = self.read_word(word_n); let offset = (Self::T::BIT_SIZE - 1 - sub_bit_n) as u32; (word & (Self::T::ONE << offset)) != Self::T::ZERO } fn read

(&self, to: &mut P) where Self: Sized, P: BitWrite, { to.write(self) } fn iter_words(&self) -> CarrierWordIter where Self: Sized, { CarrierWordIter { inner: self, _transport: PhantomData, idx: 0, rem: self.bit_len() + 8, } } } pub trait BitWrite: BitCarrier { /// Sets the masked bits of element n to data. /// Writes outside of the container with a non zero mask /// not allowed. fn write_word(&mut self, n: usize, data: Self::T, mask: Self::T); /// Writes one bit carrier into another bit carrier of the /// same length. fn write

(&mut self, from: P) where P: BitRead, { assert!(self.bit_len() == from.bit_len()); let mut len = self.bit_len() as isize; for n in 0..self.word_len() { let num_bits = std::cmp::min(len as usize, Self::T::BIT_SIZE) as u32; let mask = !((!Self::T::ZERO) .checked_shr(num_bits) .unwrap_or(Self::T::ZERO)); let read = from.read_word(n); self.write_word(n, read, mask); len -= Self::T::BIT_SIZE as isize; } } } pub fn copy(from: S, mut to: D) where S: BitRead, D: BitWrite, T: BitTransport, { to.write(from) } pub struct CarrierWordIter<'a, I, T> where I: BitRead, T: BitTransport, { inner: &'a I, _transport: PhantomData, idx: usize, rem: usize, } impl<'a, I, T> Iterator for CarrierWordIter<'a, I, T> where I: BitRead, T: BitTransport, { type Item = T; fn next(&mut self) -> Option { if self.rem < 8 { None } else { let res = self.inner.read_word(self.idx); self.rem -= 8; self.idx += 1; Some(res) } } } ================================================ FILE: util/libeir_util_binary/src/slice.rs ================================================ use std::cmp::{Ord, Ordering, PartialOrd}; use std::hash::{Hash, Hasher}; use num_traits::{CheckedShl, CheckedShr}; use super::{BitCarrier, BitRead, BitTransport, BitWrite}; /// Changes the alignment/length of a bit carrier. #[derive(Debug, Clone)] pub struct BitSlice { inner: I, word_offset: usize, bit_offset: u32, bit_length: usize, } impl BitCarrier for BitSlice where I: BitCarrier, Tr: BitTransport, { type T = Tr; fn bit_len(&self) -> usize { self.bit_length } } impl BitRead for BitSlice where I: BitRead, { fn read_word(&self, n: usize) -> Self::T { let p1 = self.inner.read_word(self.word_offset + n + 0); let p2 = self.inner.read_word(self.word_offset + n + 1); (p1.checked_shl(self.bit_offset).unwrap_or(Self::T::ZERO)) | (p2 .checked_shr(Self::T::BIT_SIZE as u32 - self.bit_offset) .unwrap_or(Self::T::ZERO)) } } impl BitWrite for BitSlice where I: BitWrite, { fn write_word(&mut self, n: usize, data: Self::T, mask: Self::T) { // TODO find a way to avoid branch? if mask == Self::T::ZERO { return; } if self.bit_offset == 0 { self.inner.write_word(self.word_offset + n, data, mask); } else { self.inner.write_word( self.word_offset + n + 0, data >> self.bit_offset, mask >> self.bit_offset, ); self.inner.write_word( self.word_offset + n + 1, data << (Self::T::BIT_SIZE as u32 - self.bit_offset), mask << (Self::T::BIT_SIZE as u32 - self.bit_offset), ); } } } impl BitSlice where I: BitCarrier, { pub fn with_offset_length(inner: I, bit_offset: usize, bit_len: usize) -> Self { assert!(bit_offset + bit_len <= inner.bit_len()); BitSlice { inner, word_offset: bit_offset / I::T::BIT_SIZE, bit_offset: (bit_offset % I::T::BIT_SIZE) as u32, bit_length: bit_len, } } } impl BitSlice where I: BitRead, { // Iterates over each underlying transport item in the slice //pub fn word_iter(&self) -> BitSliceWordIter { // BitSliceWordIter { // slice: self, // idx: 0, // rem: self.bit_length + 8, // } //} } impl Eq for BitSlice where I: BitRead {} impl PartialEq for BitSlice where I: BitRead, O: BitRead, T: BitTransport, { fn eq(&self, other: &O) -> bool { if self.bit_len() != other.bit_len() { return false; } self.iter_words().eq(other.iter_words()) } } impl PartialOrd for BitSlice where I: BitRead, O: BitRead, T: BitTransport, { fn partial_cmp(&self, other: &O) -> Option { match self.iter_words().cmp(other.iter_words()) { Ordering::Equal => (), non_eq => return Some(non_eq), } Some(self.bit_len().cmp(&other.bit_len())) } } impl Ord for BitSlice where I: BitRead, { fn cmp(&self, other: &Self) -> Ordering { self.partial_cmp(other).unwrap() } } impl Hash for BitSlice where I: BitRead, { fn hash(&self, state: &mut H) where H: Hasher, { self.bit_len().hash(state); for elem in self.iter_words() { elem.hash(state); } } } //impl Eq for BitSlice where I: BitRead, T: BitTransport {} //impl PartialEq for BitSlice where I: BitRead, T: BitTransport { // fn eq(&self, other: &Self) -> bool { // if self.bit_length != other.bit_length { return false; } // self.word_iter().eq(other.word_iter()) // } //} // //impl Ord for BitSlice where I: BitRead, T: BitTransport { // fn cmp(&self, other: &Self) -> Ordering { // match self.word_iter().cmp(other.word_iter()) { // Ordering::Equal => (), // non_eq => return non_eq, // } // // self.bit_length.cmp(&other.bit_length) // } //} //impl PartialOrd for BitSlice where I: BitRead, T: BitTransport { // fn partial_cmp(&self, other: &Self) -> Option { // Some(self.cmp(other)) // } //} // //impl Hash for BitSlice where I: BitRead, T: BitTransport { // fn hash(&self, state: &mut H) where H: Hasher { // self.bit_length.hash(state); // for elem in self.word_iter() { // elem.hash(state); // } // } //} ================================================ FILE: util/libeir_util_datastructures/Cargo.toml ================================================ [package] name = "libeir_util_datastructures" version = "0.1.0" authors = ["Hans Elias B. Josephsen "] edition = "2018" license = "MIT OR Apache-2.0" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] cranelift-entity = "0.56.0" cranelift-bforest = { git = "https://github.com/hansihe/wasmtime.git", branch = "main" } hashbrown = { git = "https://github.com/rust-lang/hashbrown.git", features = ["raw", "nightly"] } ================================================ FILE: util/libeir_util_datastructures/src/aux_hash_map.rs ================================================ use std::alloc::{Allocator, Global}; use std::borrow::Borrow; use std::collections::hash_map::RandomState; use std::fmt::Debug; use std::hash::{BuildHasher, Hasher}; use std::marker::PhantomData; use crate::aux_traits::{AuxEq, AuxHash}; //use cranelift_entity::{ListPool, EntityList, EntityRef}; //use cranelift_entity::packed_option::ReservedValue; use hashbrown::raw::{RawIter, RawTable}; //impl AuxHash for T where T: Hash { // fn aux_hash(&self, state: &mut H, _container: &C) { // self.hash(state) // } //} //impl AuxHash> for EntityList //where // E: EntityRef + ReservedValue + Hash //{ // fn aux_hash(&self, state: &mut H, container: &ListPool) { // self.as_slice(container).hash(state) // } //} //impl AuxEq for T where T: Eq { // fn aux_eq(&self, other: &Self, _container: &C) -> bool { // self.eq(other) // } // fn aux_ne(&self, other: &Self, _container: &C) -> bool { // self.ne(other) // } //} //impl AuxEq> for EntityList //where // E: EntityRef + ReservedValue + Eq //{ // fn aux_eq(&self, other: &Self, container: &ListPool) -> bool { // self.as_slice(container) == other.as_slice(container) // } //} /// Implementation of a HashMap where the hash/equality functions /// requires additional information. #[derive(Clone)] pub struct AuxHashMap where A: Clone + Allocator, { hash_builder: S, table: RawTable<(K, V), A>, aux: PhantomData, } impl AuxHashMap { #[inline] pub fn new() -> Self { Self::default() } } impl AuxHashMap { #[inline] pub fn with_hasher(hash_builder: S) -> Self { Self { hash_builder, table: RawTable::new_in(Global), aux: PhantomData, } } #[inline] pub fn iter(&self) -> Iter<'_, K, V> { unsafe { Iter { inner: self.table.iter(), marker: PhantomData, } } } } #[inline] fn make_hash + ?Sized>( hash_builder: &impl BuildHasher, container: &C, val: &K, ) -> u64 { let mut state = hash_builder.build_hasher(); val.aux_hash(&mut state, container); state.finish() } impl AuxHashMap where K: AuxEq + AuxHash, S: BuildHasher, { #[inline] pub fn try_insert(&mut self, k: K, v: V, container: &C) -> Result<(), ()> { let hash = make_hash(&self.hash_builder, container, &k); if let Some(_item) = self .table .find(hash, |x| k.aux_eq(&x.0, container, container)) { Err(()) } else { let hash_builder = &self.hash_builder; self.table .insert(hash, (k, v), |x| make_hash(hash_builder, container, &x.0)); Ok(()) } } #[inline] pub fn get(&self, k: &Q, container: &C) -> Option<&V> where K: Borrow, Q: AuxHash + AuxEq, { self.get_key_value(k, container).map(|(_, v)| v) } #[inline] pub fn get_key_value(&self, k: &Q, container: &C) -> Option<(&K, &V)> where K: Borrow, Q: AuxHash + AuxEq, { let hash = make_hash(&self.hash_builder, container, k); self.table .find(hash, |x| k.aux_eq(x.0.borrow(), container, container)) .map(|item| unsafe { let &(ref key, ref value) = item.as_ref(); (key, value) }) } } impl Default for AuxHashMap where S: BuildHasher + Default, { #[inline] fn default() -> Self { Self::with_hasher(Default::default()) } } impl Debug for AuxHashMap where K: Debug, V: Debug, S: BuildHasher, { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_map().entries(self.iter()).finish() } } #[derive(Clone)] pub struct Iter<'a, K, V> { inner: RawIter<(K, V)>, marker: PhantomData<(&'a K, &'a V)>, } impl<'a, K, V> Iterator for Iter<'a, K, V> { type Item = (&'a K, &'a V); #[inline] fn next(&mut self) -> Option<(&'a K, &'a V)> { self.inner.next().map(|x| unsafe { let r = x.as_ref(); (&r.0, &r.1) }) } #[inline] fn size_hint(&self) -> (usize, Option) { self.inner.size_hint() } } #[cfg(test)] mod tests { //use super::{ AuxHashMap, AuxHash }; //use std::hash::{ Hash, Hasher }; //#[test] //fn test_deduped_entity() { // #[derive(PartialEq, Eq)] // struct Key(usize); // impl AuxHash for Key { // fn aux_hash(&self, state: &mut H, container: &AuxData) { // assert!(container.0 == 11); // self.0.hash(state) // } // } // struct AuxData(usize); // let mut map: AuxHashMap = AuxHashMap::new(); // let aux = AuxData(11); // map.try_insert(Key(1), 1, &aux).unwrap(); // map.try_insert(Key(1), 1, &aux).err().unwrap(); // map.try_insert(Key(2), 2, &aux).unwrap(); // map.try_insert(Key(2), 2, &aux).err().unwrap(); // map.try_insert(Key(1), 1, &aux).err().unwrap(); // assert!(map.get(&Key(1), &aux) == Some(&1)); // assert!(map.get(&Key(2), &aux) == Some(&2)); //} } ================================================ FILE: util/libeir_util_datastructures/src/aux_traits/bforest_impl.rs ================================================ use super::{AuxDebug, AuxImpl, HasAux}; use cranelift_bforest::{Set, SetForest}; use std::fmt::{Formatter, Result as FmtResult}; impl, C: HasAux>> AuxDebug for Set { fn aux_fmt(&self, f: &mut Formatter<'_>, aux: &C) -> FmtResult { let iaux = aux.get_aux(); let mut b = f.debug_set(); for val in self.iter(iaux) { b.entry(&AuxImpl(&val, aux)); } b.finish() } } ================================================ FILE: util/libeir_util_datastructures/src/aux_traits/entity_impl.rs ================================================ use super::{AuxDebug, AuxImpl, HasAux}; use cranelift_entity::packed_option::ReservedValue; use cranelift_entity::{EntityList, EntityRef, ListPool, PrimaryMap, SecondaryMap}; use std::fmt::{Debug, Formatter, Result as FmtResult}; impl>, E: EntityRef + ReservedValue + Debug> AuxDebug for EntityList { fn aux_fmt(&self, f: &mut Formatter<'_>, aux: &C) -> FmtResult { let mut b = f.debug_list(); b.entries(self.as_slice(aux.get_aux())); b.finish() } } impl, C> AuxDebug for PrimaryMap { fn aux_fmt(&self, f: &mut Formatter<'_>, aux: &C) -> FmtResult { let mut b = f.debug_map(); b.entries(self.iter().map(|(k, v)| (k, AuxImpl(v, aux)))); b.finish() } } impl + Clone, C> AuxDebug for SecondaryMap { fn aux_fmt(&self, f: &mut Formatter<'_>, aux: &C) -> FmtResult { let mut b = f.debug_map(); b.entries(self.iter().map(|(k, v)| (k, AuxImpl(v, aux)))); b.finish() } } ================================================ FILE: util/libeir_util_datastructures/src/aux_traits/mod.rs ================================================ use std::fmt::{Debug, Formatter, Result as FmtResult}; use std::hash::{Hash, Hasher}; mod bforest_impl; mod entity_impl; mod std_impl; pub trait HasAux { fn get_aux(&self) -> &Inner; } impl HasAux for T { fn get_aux(&self) -> &Self { self } } impl HasAux for &T { fn get_aux(&self) -> &T { *self } } pub trait AuxDebug { fn aux_fmt(&self, f: &mut Formatter<'_>, container: &Aux) -> FmtResult; } /// Hashes a data type with access to auxiliary data pub trait AuxHash { fn aux_hash(&self, state: &mut H, container: &Aux); } /// Tests equality with access to auxiliary data pub trait AuxEq { fn aux_eq(&self, other: &Self, self_container: &Aux, other_container: &Aux) -> bool; fn aux_ne(&self, other: &Self, self_container: &Aux, other_container: &Aux) -> bool { !self.aux_eq(other, self_container, other_container) } } pub struct AuxImpl<'a, V, Aux>(pub &'a V, pub &'a Aux); impl<'a, V: AuxDebug, Aux> Debug for AuxImpl<'a, V, Aux> { fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { self.0.aux_fmt(f, self.1) } } impl<'a, V: AuxHash, Aux> Hash for AuxImpl<'a, V, Aux> { fn hash(&self, state: &mut H) { self.0.aux_hash(state, self.1) } } impl<'a, V: AuxEq, Aux> PartialEq for AuxImpl<'a, V, Aux> { fn eq(&self, rhs: &Self) -> bool { self.0.aux_eq(rhs.0, self.1, rhs.1) } } impl<'a, V: AuxEq, Aux> Eq for AuxImpl<'a, V, Aux> {} #[macro_export] macro_rules! aux_container_impl { ($typ:ty) => { impl std::fmt::Debug for $typ { fn debug(&self, formatter: std::fmt::Formatter) -> std::fmt::Result { $crate::aux_traits::AuxDebug::fmt(self, formatter, self) } } impl std::hash::Hash for $typ { fn hash(&self, hasher: &mut H) { $crate::aux_traits::AuxHash::fmt(self, hasher, self) } } impl PartialEq for $typ { fn eq(&self, other: &Self) { $crate::aux_traits::AuxEq::eq(self, other, self, other) } } impl Eq for $typ {} }; } ================================================ FILE: util/libeir_util_datastructures/src/aux_traits/std_impl/mod.rs ================================================ use super::{AuxDebug, AuxEq, AuxHash, AuxImpl, HasAux}; use std::collections::HashMap; use std::fmt::{Debug, Formatter, Result as FmtResult}; use std::hash::{Hash, Hasher}; impl, C> AuxDebug for Option { fn aux_fmt(&self, f: &mut Formatter<'_>, aux: &C) -> FmtResult { self.as_ref().map(|v| AuxImpl(v, aux)).fmt(f) } } impl, Aux> AuxHash for Option { fn aux_hash(&self, state: &mut H, aux: &Aux) { self.as_ref().map(|v| AuxImpl(v, aux)).hash(state) } } impl, Aux> AuxEq for Option { fn aux_eq(&self, other: &Self, self_aux: &Aux, other_aux: &Aux) -> bool { let l = self.as_ref().map(|v| AuxImpl(v, self_aux)); let r = other.as_ref().map(|v| AuxImpl(v, other_aux)); l.eq(&r) } } impl, V: AuxDebug> AuxDebug for HashMap { fn aux_fmt(&self, f: &mut Formatter<'_>, aux: &C) -> FmtResult { let mut b = f.debug_map(); b.entries( self.iter() .map(|(k, v)| (AuxImpl(k, aux.get_aux()), AuxImpl(v, aux.get_aux()))), ); b.finish() } } macro_rules! impl_regular { ($typ:ty) => { impl AuxDebug for $typ { fn aux_fmt(&self, f: &mut Formatter<'_>, _aux: &C) -> FmtResult { Debug::fmt(self, f) } } impl AuxHash for $typ { fn aux_hash(&self, f: &mut H, _aux: &C) { Hash::hash(self, f) } } impl AuxEq for $typ { fn aux_eq(&self, rhs: &$typ, _aux: &C, _rhs_aux: &C) -> bool { self.eq(rhs) } } }; } impl_regular!(()); impl_regular!(u8); impl_regular!(i8); impl_regular!(u16); impl_regular!(i16); impl_regular!(u32); impl_regular!(i32); impl_regular!(u64); impl_regular!(i64); impl_regular!(usize); impl_regular!(isize); impl_regular!(char); ================================================ FILE: util/libeir_util_datastructures/src/dedup_aux_primary_map.rs ================================================ use std::ops::Index; use cranelift_entity::{EntityRef, PrimaryMap}; use crate::aux_hash_map::AuxHashMap; use crate::aux_traits::{AuxEq, AuxHash}; pub type DedupPrimaryMap = DedupAuxPrimaryMap; #[derive(Debug, Clone)] pub struct DedupAuxPrimaryMap where K: EntityRef, V: AuxHash + AuxEq, { forward: PrimaryMap, backward: AuxHashMap, } impl DedupAuxPrimaryMap where K: EntityRef, V: AuxHash + AuxEq, { pub fn new() -> Self { DedupAuxPrimaryMap { forward: PrimaryMap::new(), backward: AuxHashMap::new(), } } pub fn push(&mut self, v: V, c: &C) -> K where V: Clone, { if let Some(k) = self.backward.get(&v, c) { *k } else { let k = self.forward.push(v.clone()); self.backward.try_insert(v, k, c).unwrap(); k } } } impl Index for DedupAuxPrimaryMap where K: EntityRef, V: AuxHash + AuxEq, { type Output = V; fn index(&self, key: K) -> &V { &self.forward[key] } } ================================================ FILE: util/libeir_util_datastructures/src/forest.rs ================================================ //use cranelift_bforest::{Set, SetForest}; // //pub struct BoundSet<'a, K: Copy, C> { // set: &'a Set, // forest: &'a SetForest, // comp: &'a C, //} // //impl BoundSet { // // pub fn // //} ================================================ FILE: util/libeir_util_datastructures/src/hashmap_stack.rs ================================================ use ::std::collections::HashMap; use ::std::fmt::Debug; use ::std::hash::Hash; use ::std::ops::Index; pub struct HashMapStack { stack: Vec>, } impl HashMapStack where K: Hash + Eq, { pub fn new() -> Self { HashMapStack { stack: vec![] } } pub fn push(&mut self) { self.stack.push(HashMap::new()); } pub fn pop(&mut self) { if self.stack.len() == 0 { panic!("attempt too pop from empty HashMapStack"); } self.stack.pop(); } pub fn layer(&self, n: usize) -> &HashMap { &self.stack[n] } pub fn insert(&mut self, key: K, value: V) { self.stack .last_mut() .expect("attempt to insert into empty HashMapStack") .insert(key, value); } pub fn get<'a>(&self, key: &K) -> Option<&V> { self.resolve_first(|l| l.get(key)) } pub fn contains_key(&self, key: &K) -> bool { let resolved = self.resolve_first(|l| match l.contains_key(key) { true => Some(()), false => None, }); resolved == Some(()) } pub fn height(&self) -> usize { self.stack.len() } pub fn resolve_first<'a, F, T>(&'a self, resolver: F) -> Option where F: Fn(&'a HashMap) -> Option, T: 'a, { for level in self.stack.iter().rev() { if let Some(inner) = resolver(level) { return Some(inner); } } None } pub fn flatten(&self) -> HashMap<&K, &V> { let mut out = HashMap::new(); for level in self.stack.iter() { for (key, value) in level { out.insert(key, value); } } out } } impl HashMapStack where K: Hash + Eq + Clone, V: Copy, { pub fn flatten_clone(&self) -> HashMap { let mut out = HashMap::new(); for level in self.stack.iter() { for (key, value) in level { out.insert(key.clone(), value.clone()); } } out } } impl<'a, K, V> Index<&'a K> for HashMapStack where K: Eq + Hash, { type Output = V; fn index(&self, index: &K) -> &V { self.get(index).expect("no entry found for key") } } impl Debug for HashMapStack where K: Debug + Hash + Eq, V: Debug, { fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { let flat = self.flatten(); write!(f, "{:?}", flat) } } #[cfg(test)] mod test { use super::HashMapStack; #[test] fn simple() { let mut hms = HashMapStack::new(); assert!(!hms.contains_key(&0)); hms.push(); hms.insert(0u32, 0u32); assert!(hms.contains_key(&0)); hms.push(); hms.insert(1, 0); assert!(hms.contains_key(&0)); assert!(hms[&0] == 0); hms.insert(0, 1); assert!(hms[&0] == 1); assert!(hms[&1] == 0); hms.pop(); assert!(hms[&0] == 0); assert!(!hms.contains_key(&1)); hms.pop(); assert!(!hms.contains_key(&0)); } #[test] #[should_panic] fn insert_in_empty() { let mut hms = HashMapStack::new(); hms.insert(0u32, 0u32); } #[test] fn flatten() { let mut hms = HashMapStack::new(); hms.push(); hms.insert(0u32, 0u32); hms.push(); hms.insert(1, 0); let flat = hms.flatten_clone(); assert!(flat.contains_key(&0)); assert!(flat.contains_key(&1)); } } ================================================ FILE: util/libeir_util_datastructures/src/lib.rs ================================================ #![deny(warnings)] #![feature(allocator_api)] pub mod aux_hash_map; pub mod aux_traits; pub mod dedup_aux_primary_map; pub mod forest; pub mod hashmap_stack; pub mod pooled_entity_set; ================================================ FILE: util/libeir_util_datastructures/src/pooled_entity_set.rs ================================================ use std::fmt::{Debug, Formatter}; use std::hash::{Hash, Hasher}; use std::marker::PhantomData; use cranelift_entity::packed_option::ReservedValue; use cranelift_entity::EntityList; use cranelift_entity::EntityRef; use cranelift_entity::ListPool; use crate::aux_traits::{AuxDebug, AuxEq, AuxHash, HasAux}; #[derive(Debug, Clone)] pub struct EntitySetPool { typ: PhantomData, pool: ListPool, } impl EntitySetPool { pub fn new() -> Self { EntitySetPool { typ: PhantomData, pool: ListPool::new(), } } } #[derive(Debug, Copy, Clone, PartialEq, Eq)] struct PooledSetValue(u64); impl ReservedValue for PooledSetValue { fn reserved_value() -> Self { PooledSetValue(std::u64::MAX) } } impl EntityRef for PooledSetValue { fn index(self) -> usize { self.0 as usize } fn new(n: usize) -> Self { debug_assert!(n < std::usize::MAX); PooledSetValue(n as u64) } } #[derive(Debug, Clone)] pub struct EntitySet where K: EntityRef, { list: EntityList, unused: PhantomData, } impl>, K: EntityRef + Debug> AuxDebug for EntitySet { fn aux_fmt(&self, f: &mut std::fmt::Formatter, aux: &C) -> std::fmt::Result { let mut b = f.debug_set(); b.entries(self.iter(aux.get_aux())); b.finish() } } impl>, K: EntityRef> AuxHash for EntitySet { fn aux_hash(&self, hasher: &mut H, aux: &C) { let mut n = 0; for key in self.iter(aux.get_aux()) { key.index().hash(hasher); n += 1; } n.hash(hasher); } } impl>, K: EntityRef> AuxEq for EntitySet { fn aux_eq(&self, other: &Self, self_aux: &C, other_aux: &C) -> bool { self.eq_other(other, self_aux.get_aux(), other_aux.get_aux()) } } impl Default for EntitySet { fn default() -> Self { Self { list: EntityList::new(), unused: PhantomData, } } } impl EntitySet where K: EntityRef, { pub fn new() -> Self { Self { list: EntityList::new(), unused: PhantomData, } } pub fn contains(&self, k: K, pool: &EntitySetPool) -> bool { let index = k.index(); let list_len = self.list.len(&pool.pool); let list_len_entries = list_len * 63; if index < list_len_entries { let list_val = self.list.get(index / 63, &pool.pool).unwrap(); list_val.0 & (1 << (index % 63)) != 0 } else { false } } pub fn size(&self, pool: &EntitySetPool) -> usize { let mut len = 0; for n in self.list.as_slice(&pool.pool) { debug_assert!(n.0 != std::u64::MAX); len += n.0.count_ones() as usize; } len } pub fn clear(&mut self, pool: &mut EntitySetPool) { self.list.clear(&mut pool.pool) } //pub fn keys(&self) -> Keys fn grow_to_pages(&mut self, pages: usize, pool: &mut EntitySetPool) { let len = self.list.len(&pool.pool); if len < pages { // TODO: grow in one go for _ in 0..(pages - len) { self.list.push(PooledSetValue(0), &mut pool.pool); } } } pub fn insert(&mut self, k: K, pool: &mut EntitySetPool) -> bool { let index = k.index(); let list_len = self.list.len(&pool.pool); let needed_list_len = (index / 63) + 1; //(index + 62) / 63; if list_len < needed_list_len { self.grow_to_pages(needed_list_len, pool); } let result = self.contains(k, pool); let val = self.list.get_mut(index / 63, &mut pool.pool).unwrap(); val.0 |= 1 << (index % 63); result } pub fn remove(&mut self, k: K, pool: &mut EntitySetPool) -> bool { let index = k.index(); let list_len = self.list.len(&mut pool.pool); let list_len_entries = list_len * 63; if index < list_len_entries { let list_val = self.list.get_mut(index / 63, &mut pool.pool).unwrap(); let bit_idx = 1 << (index % 63); let ret = list_val.0 & bit_idx != 0; list_val.0 &= !bit_idx; ret } else { false } } pub fn make_copy(&self, pool: &mut EntitySetPool) -> EntitySet { let mut new_list = EntityList::new(); let len = self.list.len(&pool.pool); for n in 0..len { let item = self.list.get(n, &pool.pool).unwrap(); new_list.push(item, &mut pool.pool); } EntitySet { list: new_list, unused: PhantomData, } } pub fn union(&mut self, other: &EntitySet, pool: &mut EntitySetPool) { let other_list = &other.list; let other_pages_len = other_list.len(&pool.pool); self.grow_to_pages(other_pages_len, pool); for n in 0..other_pages_len { let other_val = other_list.get(n, &pool.pool).unwrap(); let val_mut = self.list.get_mut(n, &mut pool.pool).unwrap(); debug_assert!(val_mut.0 != std::u64::MAX); debug_assert!(other_val.0 != std::u64::MAX); val_mut.0 |= other_val.0; } } pub fn iter<'a>(&self, pool: &'a EntitySetPool) -> EntitySetIter<'a, K> { EntitySetIter { pool: &pool.pool, list: self.list.clone(), unused: PhantomData, current_data: None, current: 0, finished: false, } } pub fn eq(&self, other: &EntitySet, pool: &EntitySetPool) -> bool { self.eq_other(other, pool, pool) } pub fn eq_other( &self, other: &EntitySet, pool: &EntitySetPool, other_pool: &EntitySetPool, ) -> bool { let self_list = self.list.as_slice(&pool.pool); let other_list = other.list.as_slice(&other_pool.pool); // Check common head for (a, b) in self_list.iter().zip(other_list) { debug_assert!(a.0 != std::u64::MAX); debug_assert!(b.0 != std::u64::MAX); if a != b { return false; } } // If the length differs, validate that the tail is empty match (self_list.len(), other_list.len()) { (a, b) if a > b => { for n in &self_list[b..] { debug_assert!(n.0 != std::u64::MAX); if n.0 != 0 { return false; } } } (a, b) if a < b => { for n in &other_list[a..] { debug_assert!(n.0 != std::u64::MAX); if n.0 != 0 { return false; } } } _ => (), } true } pub fn bind<'a>(&self, pool: &'a EntitySetPool) -> BoundEntitySet<'a, K> { BoundEntitySet { set: self.clone(), pool, } } } #[derive(Clone)] pub struct BoundEntitySet<'a, K: EntityRef> { set: EntitySet, pool: &'a EntitySetPool, } impl<'a, K: EntityRef> BoundEntitySet<'a, K> { pub fn contains(&self, k: K) -> bool { self.set.contains(k, self.pool) } pub fn size(&self) -> usize { self.set.size(self.pool) } pub fn iter(&self) -> EntitySetIter<'_, K> { self.set.iter(self.pool) } } impl<'a, K: EntityRef> IntoIterator for &'a BoundEntitySet<'a, K> { type Item = K; type IntoIter = EntitySetIter<'a, K>; fn into_iter(self) -> EntitySetIter<'a, K> { BoundEntitySet::iter(self) } } impl<'a, K> Debug for BoundEntitySet<'a, K> where K: EntityRef + Debug, { fn fmt(&self, f: &mut Formatter) -> std::fmt::Result { f.debug_set().entries(self.set.iter(self.pool)).finish() } } impl<'a, K: EntityRef> PartialEq for BoundEntitySet<'a, K> { fn eq(&self, rhs: &BoundEntitySet) -> bool { self.set.eq_other(&rhs.set, self.pool, &rhs.pool) } } impl<'a, K: EntityRef> Eq for BoundEntitySet<'a, K> {} pub struct EntitySetIter<'a, T> where T: EntityRef, { pool: &'a ListPool, list: EntityList, unused: PhantomData, current_data: Option, current: usize, finished: bool, } impl<'a, T> Iterator for EntitySetIter<'a, T> where T: EntityRef, { type Item = T; #[inline] fn next(&mut self) -> Option { loop { if self.finished { return None; } let rem = self.current % 63; if rem == 0 { self.current_data = self.list.get(self.current / 63, self.pool); if let Some(current_data) = self.current_data { if current_data.0 == 0 { self.current += 63; continue; } } else { self.finished = true; return None; } } if (self.current_data.unwrap().0 & (1 << rem)) != 0 { let ret = Some(T::new(self.current)); self.current += 1; return ret; } else { self.current += 1; } } } } #[cfg(test)] mod test { use super::EntitySet; use super::EntitySetPool; use ::cranelift_entity::entity_impl; /// Basic block in function #[derive(Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] pub struct TestEntity(u32); entity_impl!(TestEntity, "test_entity"); #[test] fn test_pooled_set() { let mut pool = EntitySetPool::new(); let mut set1: EntitySet = EntitySet::new(); assert!(!set1.contains(TestEntity(0), &mut pool)); assert!(!set1.contains(TestEntity(1), &mut pool)); assert!(!set1.contains(TestEntity(2), &mut pool)); assert!(!set1.contains(TestEntity(9999), &mut pool)); set1.insert(TestEntity(2), &mut pool); assert!(!set1.contains(TestEntity(0), &mut pool)); assert!(!set1.contains(TestEntity(1), &mut pool)); assert!(set1.contains(TestEntity(2), &mut pool)); assert!(!set1.contains(TestEntity(3), &mut pool)); set1.insert(TestEntity(62), &mut pool); set1.insert(TestEntity(63), &mut pool); set1.insert(TestEntity(200), &mut pool); assert!(!set1.contains(TestEntity(0), &mut pool)); assert!(set1.contains(TestEntity(2), &mut pool)); assert!(!set1.contains(TestEntity(199), &mut pool)); assert!(set1.contains(TestEntity(200), &mut pool)); assert!(!set1.contains(TestEntity(201), &mut pool)); set1.insert(TestEntity(10), &mut pool); assert!(set1.contains(TestEntity(200), &mut pool)); set1.remove(TestEntity(200), &mut pool); assert!(!set1.contains(TestEntity(200), &mut pool)); assert!(set1.contains(TestEntity(10), &mut pool)); assert!(!set1.contains(TestEntity(9), &mut pool)); assert!(set1.contains(TestEntity(2), &mut pool)); assert!(!set1.contains(TestEntity(200), &mut pool)); set1.remove(TestEntity(2), &mut pool); assert!(!set1.contains(TestEntity(2), &mut pool)); assert!(set1.contains(TestEntity(10), &mut pool)); let mut set2: EntitySet = EntitySet::new(); for i in 2..200 { println!("{}", i); assert!(!set2.contains(TestEntity(i - 1), &mut pool)); assert!(!set2.contains(TestEntity(i), &mut pool)); assert!(!set2.contains(TestEntity(i + 1), &mut pool)); set2.insert(TestEntity(i), &mut pool); assert!(!set2.contains(TestEntity(i - 1), &mut pool)); assert!(set2.contains(TestEntity(i), &mut pool)); assert!(!set2.contains(TestEntity(i + 1), &mut pool)); set2.remove(TestEntity(i), &mut pool); assert!(!set2.contains(TestEntity(i - 1), &mut pool)); assert!(!set2.contains(TestEntity(i), &mut pool)); assert!(!set2.contains(TestEntity(i + 1), &mut pool)); } } #[test] fn test_pooled_set_remove() { let mut pool = EntitySetPool::new(); let mut set1: EntitySet = EntitySet::new(); assert!(!set1.remove(TestEntity(2), &mut pool)); assert!(!set1.remove(TestEntity(100), &mut pool)); set1.insert(TestEntity(2), &mut pool); assert!(set1.remove(TestEntity(2), &mut pool)); assert!(!set1.remove(TestEntity(2), &mut pool)); set1.insert(TestEntity(100), &mut pool); assert!(!set1.remove(TestEntity(2), &mut pool)); assert!(set1.remove(TestEntity(100), &mut pool)); assert!(!set1.remove(TestEntity(99), &mut pool)); assert!(!set1.remove(TestEntity(2), &mut pool)); } #[test] fn test_pooled_set_eq() { let mut pool = EntitySetPool::new(); let mut set1: EntitySet = EntitySet::new(); let mut set2: EntitySet = EntitySet::new(); assert!(set1.eq(&set2, &pool)); set1.insert(TestEntity(2), &mut pool); assert!(!set1.eq(&set2, &pool)); assert!(!set2.eq(&set1, &pool)); set2.insert(TestEntity(2), &mut pool); assert!(set1.eq(&set2, &pool)); assert!(set2.eq(&set1, &pool)); set2.insert(TestEntity(100), &mut pool); assert!(!set1.eq(&set2, &pool)); assert!(!set2.eq(&set1, &pool)); set1.insert(TestEntity(100), &mut pool); assert!(set1.eq(&set2, &pool)); assert!(set2.eq(&set1, &pool)); } #[test] fn test_iterator() { let mut pool = EntitySetPool::new(); let mut set1: EntitySet = EntitySet::new(); set1.insert(TestEntity(5), &mut pool); set1.insert(TestEntity(62), &mut pool); set1.insert(TestEntity(63), &mut pool); set1.insert(TestEntity(64), &mut pool); set1.insert(TestEntity(500), &mut pool); set1.insert(TestEntity(501), &mut pool); set1.insert(TestEntity(502), &mut pool); set1.insert(TestEntity(503), &mut pool); set1.insert(TestEntity(504), &mut pool); set1.insert(TestEntity(505), &mut pool); set1.insert(TestEntity(506), &mut pool); set1.insert(TestEntity(507), &mut pool); set1.insert(TestEntity(508), &mut pool); set1.insert(TestEntity(509), &mut pool); set1.insert(TestEntity(510), &mut pool); set1.insert(TestEntity(511), &mut pool); set1.insert(TestEntity(512), &mut pool); let mut iter = set1.iter(&pool); assert!(iter.next() == Some(TestEntity(5))); assert!(iter.next() == Some(TestEntity(62))); assert!(iter.next() == Some(TestEntity(63))); assert!(iter.next() == Some(TestEntity(64))); assert!(iter.next() == Some(TestEntity(500))); assert!(iter.next() == Some(TestEntity(501))); assert!(iter.next() == Some(TestEntity(502))); assert!(iter.next() == Some(TestEntity(503))); assert!(iter.next() == Some(TestEntity(504))); assert!(iter.next() == Some(TestEntity(505))); assert!(iter.next() == Some(TestEntity(506))); assert!(iter.next() == Some(TestEntity(507))); assert!(iter.next() == Some(TestEntity(508))); assert!(iter.next() == Some(TestEntity(509))); assert!(iter.next() == Some(TestEntity(510))); assert!(iter.next() == Some(TestEntity(511))); assert!(iter.next() == Some(TestEntity(512))); assert!(iter.next() == None); assert!(iter.next() == None); } } ================================================ FILE: util/libeir_util_dot_graph/Cargo.toml ================================================ [package] name = "libeir_util_dot_graph" version = "0.1.0" authors = ["Hans Elias B. Josephsen "] edition = "2018" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] ================================================ FILE: util/libeir_util_dot_graph/src/lib.rs ================================================ #![feature(allocator_api)] use std::fmt::Display; use std::fmt::{Error, Write}; use std::path::Path; //mod tablegen; const DOT_BREAK: &str = "
"; fn format_label(label: &str, out: &mut String) { for c in label.chars() { match c { '{' => out.push_str("\\{"), '}' => out.push_str("\\}"), '|' => out.push_str("\\|"), '>' => out.push_str(">"), '<' => out.push_str("<"), '&' => out.push_str("&"), '"' => out.push_str("""), '\n' => out.push_str(DOT_BREAK), c => out.push(c), } } } pub trait NodeId { fn make_id(&self, out: &mut String); } impl NodeId for &str { fn make_id(&self, out: &mut String) { out.push_str(self); } } /// Newtype that implements NodeId for any Display type #[derive(Copy, Clone)] pub struct DisplayNid(pub I); impl NodeId for DisplayNid { fn make_id(&self, out: &mut String) { write!(out, "{}", self.0).unwrap(); } } /// Adds a prefix to a NodeId #[derive(Copy, Clone)] pub struct PrefixedNid(pub P, pub I); impl NodeId for PrefixedNid { fn make_id(&self, out: &mut String) { write!(out, "{}_", self.0).unwrap(); self.1.make_id(out); } } /// References a subpart of a node #[derive(Copy, Clone)] pub struct SubNid(pub I, pub S); impl NodeId for SubNid { fn make_id(&self, out: &mut String) { self.0.make_id(out); write!(out, ":{}", self.1).unwrap(); } } pub trait ContentFormatting { fn make_raw(&self, out: &mut String); } impl ContentFormatting for &str { fn make_raw(&self, out: &mut String) { format_label(self, out); } } pub trait Content { fn make_raw(&self, out: &mut String); } impl Content for &str { fn make_raw(&self, out: &mut String) { format_label(self, out); } } pub struct StructuredNode {} impl StructuredNode { pub fn text(&mut self, _content: F) {} pub fn vertical(&mut self, _cells: &[()]) {} pub fn horizontal(&mut self, _cells: &[()]) {} } pub struct GraphPrinter { out: O, id_buf: Option, error: Result<(), Error>, } impl GraphPrinter { pub fn new() -> Self { Self::with_out(String::new()) } pub fn finish_run_dot(self, out: &Path) { let dot_res = self.finish().unwrap(); let dir = std::env::temp_dir(); let mut dot_path = dir.clone(); dot_path.push("out.dot"); { let mut dot_file = std::fs::File::create(&dot_path).unwrap(); use std::io::Write; dot_file.write(dot_res.as_bytes()).unwrap(); } let ext = out.extension().unwrap(); use std::process::Command; let res = Command::new("dot") .args(&[ "-o", out.to_str().unwrap(), "-T", ext.to_str().unwrap(), dot_path.to_str().unwrap(), ]) .output() .expect("failed to execute dot"); if !res.status.success() { println!("status: {}", res.status); println!("stdout: {}", std::str::from_utf8(&res.stdout).unwrap()); println!("stderr: {}", std::str::from_utf8(&res.stderr).unwrap()); panic!(); } } } impl GraphPrinter { pub fn with_out(out: O) -> Self { let mut g = GraphPrinter { out, id_buf: Some(String::new()), error: Ok(()), }; g.w(|w| { write!(w, "digraph g {{\n")?; write!( w, "node [labeljust=\"l\", shape=record, fontname=\"Courier New\"]\n" )?; write!(w, "edge [fontname=\"Courier New\" ]\n\n")?; Ok(()) }); g } pub fn finish(mut self) -> Result { self.w(|w| { write!(w, "}}\n")?; Ok(()) }); let error = self.error; let out = self.out; error.map(|_| out) } pub fn node(&mut self, id: I, label: &str) where I: NodeId, { let mut id_buf = self.id_buf.take().unwrap(); id_buf.clear(); id.make_id(&mut id_buf); self.w(|w| { write!(w, "{} [ label=<", &id_buf)?; Ok(()) }); id_buf.clear(); format_label(label, &mut id_buf); self.w(|w| { write!(w, "{}> ];\n", &id_buf)?; Ok(()) }); self.id_buf = Some(id_buf); } pub fn edge(&mut self, from: I1, to: I2, label: &str) where I1: NodeId, I2: NodeId, { let mut id_buf = self.id_buf.take().unwrap(); id_buf.clear(); from.make_id(&mut id_buf); self.w(|w| { write!(w, "{} -> ", &id_buf)?; Ok(()) }); id_buf.clear(); to.make_id(&mut id_buf); self.w(|w| { write!(w, "{} ", &id_buf)?; Ok(()) }); id_buf.clear(); format_label(label, &mut id_buf); self.w(|w| { write!(w, "[ label=<{}> ];\n", id_buf)?; Ok(()) }); self.id_buf = Some(id_buf); } fn w(&mut self, f: F) where F: FnOnce(&mut O) -> Result<(), Error>, { if self.error.is_ok() { self.error = f(&mut self.out); } } } //#[allow(clippy::write_with_newline)] //pub fn function_to_dot(fun: &Function, w: &mut dyn Write) -> ::std::io::Result<()> { // let mut to_eir_ctx = ToEirTextContext::new(); // // write!(w, "digraph g {{\n")?; // write!(w, "node [labeljust=\"l\", shape=record, fontname=\"Courier New\"]\n")?; // write!(w, "edge [fontname=\"Courier New\" ]\n\n")?; // // let fun_name = format_label(&format!("{}", fun.ident())); // write!(w, "entry [ label= ];\n", // fun_name)?; // write!(w, "entry -> blk_{};\n\n", fun.block_entry())?; // // let mut buf = Vec::new(); // // write!(w, "constants [ label=<")?; // super::printer::print_constants(&mut to_eir_ctx, fun, 0, &mut buf)?; // let text = std::str::from_utf8(&buf).unwrap(); // let text = format_label(text); // write!(w, "{}", text)?; // write!(w, "> ];\n")?; // // let block_graph = fun.block_graph(); // let mut block_dfs = Dfs::new(&block_graph, fun.block_entry()); // // while let Some(block) = block_dfs.next(&block_graph) { // write!(w, "blk_{} [ label=<", block)?; // // buf.clear(); // block.to_eir_text_fun(&mut to_eir_ctx, fun, 0, &mut buf).unwrap(); // let text = std::str::from_utf8(&buf).unwrap(); // let text = format_label(text); // write!(w, "{}", text)?; // // write!(w, "> ];\n")?; // // for out in block_graph.neighbors(block) { // write!(w, "blk_{} -> blk_{};\n", block, out)?; // } // // write!(w, "\n")?; // } // // write!(w, "}}\n")?; // Ok(()) //} #[cfg(test)] mod test { use crate::{GraphPrinter, NodeId}; use std::path::Path; #[test] fn basic() { let mut p = GraphPrinter::new(); p.node("woo", "Something something"); p.node("hoo", "Something else"); p.edge("woo", "hoo", "Some edge"); let out = p.finish().unwrap(); } #[test] fn basic_to_file() { let mut p = GraphPrinter::new(); p.node("woo", "Something something"); p.node("hoo", "Something else"); p.edge("woo", "hoo", "Some edge"); p.finish_run_dot(Path::new("something.png")); std::fs::remove_file(Path::new("something.png")).unwrap(); } } ================================================ FILE: util/libeir_util_dot_graph/src/tablegen.rs ================================================ //! Convernient builder API for HTML tables. use std::alloc::Alloc; pub enum Cell { Terminal(T), Horizontal(Box, Box) } ================================================ FILE: util/libeir_util_number/Cargo.toml ================================================ [package] name = "libeir_util_number" version = "0.1.0" authors = ["Hans Elias B. Josephsen "] edition = "2018" license = "MIT OR Apache-2.0" [dependencies] num-traits = "0.2.8" num-bigint = { git = "https://github.com/hansihe/num-bigint.git" } libeir_util_binary = { path = "../libeir_util_binary" } ================================================ FILE: util/libeir_util_number/src/bigint_to_float.rs ================================================ use num_bigint::{BigInt, Sign}; /// https://github.com/erlang/otp/blob/0de9ecd561bdc964f1c6436d240729b3952cdf3a/erts/emulator/beam/big.c#L1642-L1667 pub fn bigint_to_double(big: &BigInt) -> f64 { let (sign, data) = big.to_bytes_be(); let mut d: f64 = 0.0; let dbase = ((!0u8) as f64) + 1.0; for digit in data.iter() { d = d * dbase + (*digit as f64); } if sign == Sign::Minus { -d } else { d } } #[cfg(test)] mod tests { use super::bigint_to_double; use num_bigint::BigInt; #[test] fn test_bigint_to_double() { let bi = BigInt::from(100); assert!(bigint_to_double(&bi) == 100.0); let bi = BigInt::from(10000000000i64); assert!(bigint_to_double(&bi) == 10000000000.0); let bi = BigInt::from(1000000000000000000i64); assert!(bigint_to_double(&bi) == 1000000000000000000.0); } } ================================================ FILE: util/libeir_util_number/src/binary.rs ================================================ use crate::Integer; use libeir_util_binary::{Endian, BitCarrier, BitRead, BitSlice, integer_to_carrier}; impl BitCarrier for Integer { type T = u8; fn bit_len(&self) -> usize { match self { Integer::Big(bi) => bi.bit_len(), Integer::Small(si) => si.bit_len(), } } } #[derive(Debug)] pub enum IntegerBits { //SmallBE(SmallIntCarrierBE), //SmallLE(SmallIntCarrierLE), Big(BitSlice>), } impl BitCarrier for IntegerBits { type T = u8; fn bit_len(&self) -> usize { match self { //Self::SmallBE(si) => si.bit_len(), //Self::SmallLE(si) => si.bit_len(), Self::Big(bi) => bi.bit_len(), } } } impl BitRead for IntegerBits { fn read_word(&self, n: usize) -> u8 { match self { //Self::SmallBE(si) => si.read_word(n), //Self::SmallLE(si) => si.read_word(n), Self::Big(bi) => bi.read_word(n), } } } impl Integer { pub fn encode_bitstring(&self, bits: usize, endian: Endian) -> IntegerBits { match self { Integer::Big(bi) => IntegerBits::Big(integer_to_carrier(bi.clone(), bits, endian)), Integer::Small(si) => { // TODO: Don't convert IntegerBits::Big(integer_to_carrier((*si).into(), bits, endian)) //let mask = if si < &0 { // 0xff //} else { // 0x00 //}; //match endian { // Endian::Big => { // IntegerBits::SmallBE(SmallIntCarrierBE { // data: *si as u64, // bits, // padding: mask, // bytes: (bits + 7) / 8, // }) // } // Endian::Little => { // IntegerBits::SmallLE(SmallIntCarrierLE { // data: *si as u64, // bits, // padding: mask, // }) // } //} } } } } //impl BitCarrier for IntegerBitVec { // type T = u8; // fn bit_len(&self) -> usize { // match self { // Self::Small(si) => i.bit_len(), // Self::Big(bi) => bi.bit_len(), // } // } //} // //impl BitRead for IntegerBitVec { // fn read_word(&self, n: usize) -> u8 { // match self { // Self::Small(si) => si.read_word(n), // Self::Big(bi) => bi.read_word(n), // } // } //} // //impl From for IntegerBitVec { // fn from(int: Integer) -> Self { // match int { // Integer::Big(bi) => Self::Big(libeir_util_binary::integer_to_carrier(bi, )), // Integer::Small(si) => Self::Small(si), // } // } //} //#[derive(Debug)] //pub struct SmallIntCarrierBE { // data: u64, // bits: usize, // padding: u8, // bytes: usize, //} //impl BitCarrier for SmallIntCarrierBE { // type T = u8; // fn bit_len(&self) -> usize { // self.bits // } //} //impl BitRead for SmallIntCarrierBE { // fn read_word(&self, n: usize) -> u8 { // if n >= self.bytes { // return self.padding; // } // // let inv = self.bytes - n - 1; // println!("inv: {:?}", inv); // // if inv >= 8 { // self.padding // } else { // let d1 = self.data.read_word(7 - inv); // let d2 = if inv == 7 { // self.padding // } else { // self.data.read_word(n) // }; // // self.data.read_word(7 - inv) // } // } //} // //#[derive(Debug)] //pub struct SmallIntCarrierLE { // data: u64, // bits: usize, // padding: u8, //} //impl BitCarrier for SmallIntCarrierLE { // type T = u8; // fn bit_len(&self) -> usize { // self.bits // } //} //impl BitRead for SmallIntCarrierLE { // fn read_word(&self, n: usize) -> u8 { // if n >= 8 { // self.padding // } else { // let offset = self.bits % 8; // let d = self.data.read_word(7 - n); // if offset == 0 { // d // } else { // d << (8 - offset) // } // } // } //} // <<20::big-size(12)>> -> <<1, 4::size(4)>> // <<20::little-size(12)>> -> <<20, 0::size(4)>> // <<-20::big-size(12)>> -> <<254, 12::size(4)>> // <<-20::little-size(12)>> -> <<236, 15::size(4)>> #[cfg(test)] mod tests { use crate::Integer; use libeir_util_binary::{Endian, BitVec}; #[test] fn unsigned_big_endian_bigint() { let num = 20; let bs1 = Integer::Big(num.into()).encode_bitstring(12, Endian::Big); let mut b1 = BitVec::new(); b1.push(&bs1); let parts = (b1.get(0).unwrap(), b1.get(1).unwrap()); assert_eq!(parts, (1, 4 << 4)); } #[test] fn unsigned_little_endian_bigint() { let num = 20; let bs1 = Integer::Big(num.into()).encode_bitstring(12, Endian::Little); let mut b1 = BitVec::new(); b1.push(&bs1); let parts = (b1.get(0).unwrap(), b1.get(1).unwrap()); assert_eq!(parts, (20, 0 << 4)); } #[test] fn signed_big_endian_bigint() { let num = -20; let bs1 = Integer::Big(num.into()).encode_bitstring(12, Endian::Big); let mut b1 = BitVec::new(); b1.push(&bs1); let parts = (b1.get(0).unwrap(), b1.get(1).unwrap()); assert_eq!(parts, (254, 12 << 4)); } #[test] fn signed_little_endian_bigint() { let num = -20; let bs1 = Integer::Big(num.into()).encode_bitstring(12, Endian::Little); let mut b1 = BitVec::new(); b1.push(&bs1); let parts = (b1.get(0).unwrap(), b1.get(1).unwrap()); assert_eq!(parts, (236, 15 << 4)); } #[test] fn unsigned_big_endian_smallint() { let num = 20; let bs1 = Integer::Small(num).encode_bitstring(12, Endian::Big); let mut b1 = BitVec::new(); b1.push(&bs1); let parts = (b1.get(0).unwrap(), b1.get(1).unwrap()); assert_eq!(parts, (1, 4 << 4)); } #[test] fn unsigned_little_endian_smallint() { let num = 20; let bs1 = Integer::Small(num).encode_bitstring(12, Endian::Little); let mut b1 = BitVec::new(); b1.push(&bs1); let parts = (b1.get(0).unwrap(), b1.get(1).unwrap()); assert_eq!(parts, (20, 0 << 4)); } #[test] fn signed_big_endian_smallint() { let num = -20; let bs1 = Integer::Small(num).encode_bitstring(12, Endian::Big); let mut b1 = BitVec::new(); b1.push(&bs1); let parts = (b1.get(0).unwrap(), b1.get(1).unwrap()); assert_eq!(parts, (254, 12 << 4)); } #[test] fn signed_little_endian_smallint() { let num = -20; let bs1 = Integer::Small(num).encode_bitstring(12, Endian::Little); let mut b1 = BitVec::new(); b1.push(&bs1); let parts = (b1.get(0).unwrap(), b1.get(1).unwrap()); assert_eq!(parts, (236, 15 << 4)); } #[test] fn num_to_bitstring() { let num = 0b101001101001; let bs1 = Integer::Small(num).encode_bitstring(12, Endian::Little); let mut b1 = BitVec::new(); b1.push(&bs1); let bs2 = Integer::Big(num.into()).encode_bitstring(12, Endian::Little); let mut b2 = BitVec::new(); b2.push(&bs2); println!("{:?}", b1); println!("{:?}", b2); assert_eq!(b1, b2); } } ================================================ FILE: util/libeir_util_number/src/float.rs ================================================ use crate::Integer; use std::cmp::Ordering; use std::hash::{Hash, Hasher}; use std::mem::transmute; use std::num::FpCategory; use std::ops::{Add, Div, Mul, Neg, Rem, Sub}; use num_bigint::BigInt; use num_traits::FromPrimitive; #[derive(Debug, Copy, Clone)] pub struct Float(f64); impl Float { pub fn new(float: f64) -> Result { FloatError::from_category(float.classify())?; Ok(Float(float)) } #[inline(always)] pub fn raw(&self) -> u64 { unsafe { transmute(self.0) } } pub fn inner(&self) -> f64 { self.0 } pub fn plus(&self) -> Float { if self.0 < 0.0 { Float::new(self.0 * -1.0).unwrap() } else { *self } } pub fn is_zero(&self) -> bool { self.0.classify() == FpCategory::Zero } pub fn to_integer(&self) -> Integer { Integer::Big(BigInt::from_f64(self.0).unwrap()).shrink() } /// Returns whether this float is more precise than an integer. /// If the float is precise, the other integer this is being compared to will /// be converted to a float. /// If the float is not precise, it will be converted to the integer. pub fn is_precise(&self) -> bool { self.0 > -9007199254740992.0 && self.0 < 9007199254740992.0 } } #[derive(Debug, Copy, Clone)] pub enum FloatError { Nan, Infinite, } impl FloatError { pub fn from_category(category: FpCategory) -> Result<(), Self> { match category { FpCategory::Nan => Err(FloatError::Nan), FpCategory::Infinite => Err(FloatError::Infinite), _ => Ok(()), } } } impl std::fmt::Display for FloatError { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { match self { FloatError::Nan => write!(f, "NaN"), FloatError::Infinite => write!(f, "Inf"), } } } impl std::error::Error for FloatError {} macro_rules! impl_op { ($trait:ident, $fun:ident) => { impl $trait for Float { type Output = Result; fn $fun(self, rhs: Float) -> Self::Output { Float::new($trait::$fun(self.0, rhs.0)) } } }; } impl Hash for Float { fn hash(&self, state: &mut H) { self.raw().hash(state) } } impl PartialEq for Float { fn eq(&self, rhs: &Float) -> bool { self.raw() == rhs.raw() } } impl Eq for Float {} impl PartialOrd for Float { fn partial_cmp(&self, rhs: &Float) -> Option { self.0.partial_cmp(&rhs.0) } } impl Ord for Float { fn cmp(&self, rhs: &Float) -> Ordering { self.partial_cmp(rhs).unwrap() } } impl_op!(Add, add); impl_op!(Sub, sub); impl_op!(Mul, mul); impl_op!(Div, div); impl_op!(Rem, rem); impl Neg for Float { type Output = Float; fn neg(self) -> Self::Output { Float::new(-self.0).unwrap() } } impl std::fmt::Display for Float { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { write!(f, "{}", self.0) } } impl Add<&Integer> for Float { type Output = Result; fn add(self, rhs: &Integer) -> Self::Output { self + rhs.to_efloat()? } } impl Add for &Integer { type Output = Result; fn add(self, rhs: Float) -> Self::Output { self.to_efloat()? + rhs } } impl Sub<&Integer> for Float { type Output = Result; fn sub(self, rhs: &Integer) -> Self::Output { self - rhs.to_efloat()? } } impl Sub for &Integer { type Output = Result; fn sub(self, rhs: Float) -> Self::Output { self.to_efloat()? - rhs } } impl Mul<&Integer> for Float { type Output = Result; fn mul(self, rhs: &Integer) -> Self::Output { self * rhs.to_efloat()? } } impl Mul for &Integer { type Output = Result; fn mul(self, rhs: Float) -> Self::Output { self.to_efloat()? * rhs } } impl Div<&Integer> for Float { type Output = Result; fn div(self, rhs: &Integer) -> Self::Output { self / rhs.to_efloat()? } } impl Div for &Integer { type Output = Result; fn div(self, rhs: Float) -> Self::Output { self.to_efloat()? / rhs } } impl Rem<&Integer> for Float { type Output = Result; fn rem(self, rhs: &Integer) -> Self::Output { self % rhs.to_efloat()? } } impl Rem for &Integer { type Output = Result; fn rem(self, rhs: Float) -> Self::Output { self.to_efloat()? % rhs } } ================================================ FILE: util/libeir_util_number/src/integer.rs ================================================ use crate::{DivisionError, Float, FloatError}; use std::cmp::Ordering; use std::convert::TryInto; use std::fmt::{Display, Formatter}; use std::ops::{Add, BitAnd, BitOr, BitXor, Div, Mul, Neg, Not, Rem, Shl, Shr, Sub}; use std::str::FromStr; use num_bigint::{BigInt, ParseBigIntError}; pub use num_traits::{FromPrimitive, ToPrimitive, Zero}; #[derive(Debug, Clone, Hash)] pub enum Integer { Small(i64), Big(BigInt), } impl Integer { pub fn is_zero(&self) -> bool { match self { Integer::Small(num) => *num == 0, Integer::Big(num) => num.is_zero(), } } pub fn plus(&self) -> Integer { match self { Integer::Small(num) if num < &0 => Integer::Small(-num), Integer::Big(num) if num < &0 => Integer::Big(-num.clone()), _ => self.clone(), } } pub fn to_float(&self) -> f64 { match self { Integer::Small(int) => *int as f64, Integer::Big(int) => crate::bigint_to_double(int), } } pub fn to_efloat(&self) -> Result { Float::new(self.to_float()) } pub fn to_bigint(self) -> BigInt { match self { Integer::Small(int) => int.into(), Integer::Big(int) => int, } } pub fn shrink(self) -> Self { match self { Integer::Small(int) => Integer::Small(int), Integer::Big(int) => { if let Some(small) = int.to_i64() { Integer::Small(small) } else { Integer::Big(int) } } } } pub fn from_string_radix(string: &str, radix: u32) -> Option { if let Ok(i) = i64::from_str_radix(string, radix) { return Some(Integer::Small(i)); } let bi = BigInt::parse_bytes(string.as_bytes(), radix)?; Some(Integer::Big(bi)) } pub fn to_u64(&self) -> Option { ToPrimitive::to_u64(self) } pub fn to_usize(&self) -> Option { ToPrimitive::to_usize(self) } } impl Display for Integer { fn fmt(&self, f: &mut Formatter) -> std::fmt::Result { match self { Integer::Small(int) => int.fmt(f), Integer::Big(int) => int.fmt(f), } } } impl FromStr for Integer { type Err = ParseBigIntError; fn from_str(s: &str) -> Result { match s.parse::() { Ok(int) => Ok(Integer::Small(int)), Err(_) => match s.parse::() { Ok(int) => Ok(Integer::Big(int)), Err(err) => Err(err), }, } } } impl PartialEq for Integer { fn eq(&self, rhs: &Integer) -> bool { match (self, rhs) { (Integer::Small(lhs), Integer::Small(rhs)) => lhs.eq(rhs), (Integer::Small(lhs), Integer::Big(rhs)) => lhs.eq(rhs), (Integer::Big(lhs), Integer::Small(rhs)) => lhs.eq(rhs), (Integer::Big(lhs), Integer::Big(rhs)) => lhs.eq(rhs), } } } impl Eq for Integer {} impl PartialOrd for Integer { fn partial_cmp(&self, rhs: &Integer) -> Option { match (self, rhs) { (Integer::Small(lhs), Integer::Small(rhs)) => lhs.partial_cmp(rhs), (Integer::Small(lhs), Integer::Big(rhs)) => lhs.partial_cmp(rhs), (Integer::Big(lhs), Integer::Small(rhs)) => lhs.partial_cmp(rhs), (Integer::Big(lhs), Integer::Big(rhs)) => lhs.partial_cmp(rhs), } } } impl Ord for Integer { fn cmp(&self, rhs: &Integer) -> Ordering { self.partial_cmp(rhs).unwrap() } } impl PartialEq for Integer { fn eq(&self, rhs: &f64) -> bool { match self { Integer::Small(lhs) => (*lhs as f64).eq(rhs), Integer::Big(lhs) => crate::bigint_to_double(lhs).eq(rhs), } } } impl PartialEq for f64 { fn eq(&self, rhs: &Integer) -> bool { rhs.eq(self) } } impl PartialOrd for Integer { fn partial_cmp(&self, rhs: &f64) -> Option { match self { Integer::Small(lhs) => (*lhs as f64).partial_cmp(rhs), Integer::Big(lhs) => crate::bigint_to_double(lhs).partial_cmp(rhs), } } } impl PartialOrd for f64 { fn partial_cmp(&self, rhs: &Integer) -> Option { rhs.partial_cmp(self).map(|v| v.reverse()) } } impl PartialEq for Integer { fn eq(&self, rhs: &char) -> bool { match self { Integer::Small(lhs) => lhs.eq(&(*rhs as i64)), Integer::Big(lhs) => lhs.eq(&(*rhs as i64)), } } } impl PartialEq for char { fn eq(&self, rhs: &Integer) -> bool { rhs.eq(self) } } impl PartialOrd for Integer { fn partial_cmp(&self, rhs: &char) -> Option { match self { Integer::Small(lhs) => lhs.partial_cmp(&(*rhs as i64)), Integer::Big(lhs) => lhs.partial_cmp(&(*rhs as i64)), } } } impl PartialOrd for char { fn partial_cmp(&self, rhs: &Integer) -> Option { rhs.partial_cmp(self).map(|v| v.reverse()) } } impl PartialEq for Integer { fn eq(&self, rhs: &i64) -> bool { match self { Integer::Small(lhs) => lhs.eq(rhs), Integer::Big(lhs) => lhs.eq(rhs), } } } impl PartialEq for i64 { fn eq(&self, rhs: &Integer) -> bool { rhs.eq(self) } } impl PartialOrd for Integer { fn partial_cmp(&self, rhs: &i64) -> Option { match self { Integer::Small(lhs) => lhs.partial_cmp(rhs), Integer::Big(lhs) => lhs.partial_cmp(rhs), } } } impl PartialOrd for i64 { fn partial_cmp(&self, rhs: &Integer) -> Option { rhs.partial_cmp(self).map(|v| v.reverse()) } } impl Shr for Integer { type Output = Integer; fn shr(self, num: u32) -> Integer { let big = self.to_bigint() >> (num as usize); Integer::Big(big).shrink() } } impl Shl for Integer { type Output = Integer; fn shl(self, num: u32) -> Integer { let big = self.to_bigint() << (num as usize); Integer::Big(big).shrink() } } impl Mul for Integer { type Output = Integer; fn mul(self, rhs: i64) -> Integer { match self { Integer::Small(lhs) => { let mut int: BigInt = lhs.into(); int = int * rhs; Integer::Big(int).shrink() } Integer::Big(lhs) => Integer::Big(lhs * rhs), } } } impl Mul<&Integer> for Integer { type Output = Integer; fn mul(self, rhs: &Integer) -> Integer { let mut lhs = self.to_bigint(); match rhs { Integer::Small(rhs) => lhs = lhs * rhs, Integer::Big(rhs) => lhs *= rhs, } Integer::Big(lhs).shrink() } } impl Div<&Integer> for Integer { type Output = Result; fn div(self, rhs: &Integer) -> Self::Output { if rhs.is_zero() { return Err(DivisionError); } let mut lhs = self.to_bigint(); match rhs { Integer::Small(rhs) => lhs = lhs / rhs, Integer::Big(rhs) => lhs /= rhs, } Ok(Integer::Big(lhs).shrink()) } } impl Add<&Integer> for Integer { type Output = Integer; fn add(self, rhs: &Integer) -> Integer { let mut lhs = self.to_bigint(); match rhs { Integer::Small(rhs) => lhs = lhs + rhs, Integer::Big(rhs) => lhs += rhs, } Integer::Big(lhs).shrink() } } impl Sub<&Integer> for Integer { type Output = Integer; fn sub(self, rhs: &Integer) -> Integer { let mut lhs = self.to_bigint(); match rhs { Integer::Small(rhs) => lhs = lhs - rhs, Integer::Big(rhs) => lhs -= rhs, } Integer::Big(lhs).shrink() } } impl Rem<&Integer> for Integer { type Output = Integer; fn rem(self, rhs: &Integer) -> Integer { let mut lhs = self.to_bigint(); match rhs { Integer::Small(rhs) => lhs = lhs % rhs, Integer::Big(rhs) => lhs %= rhs, } Integer::Big(lhs).shrink() } } impl BitAnd<&Integer> for Integer { type Output = Integer; fn bitand(self, rhs: &Integer) -> Integer { let l = self.to_bigint(); match rhs { Integer::Small(r) => l & BigInt::from(*r), Integer::Big(r) => l & r, } .into() } } impl BitOr<&Integer> for Integer { type Output = Integer; fn bitor(self, rhs: &Integer) -> Integer { let l = self.to_bigint(); match rhs { Integer::Small(r) => l | BigInt::from(*r), Integer::Big(r) => l | r, } .into() } } impl BitXor<&Integer> for Integer { type Output = Integer; fn bitxor(self, rhs: &Integer) -> Integer { let l = self.to_bigint(); match rhs { Integer::Small(r) => l ^ BigInt::from(*r), Integer::Big(r) => l ^ r, } .into() } } impl Neg for Integer { type Output = Integer; fn neg(self) -> Integer { match self { Integer::Small(int) => Integer::Small(-int), Integer::Big(int) => Integer::Big(-int), } } } impl Not for &Integer { type Output = Integer; fn not(self) -> Integer { match self { Integer::Small(int) => Integer::Small(!int), Integer::Big(int) => Integer::Big(!int), } } } impl ToPrimitive for Integer { fn to_i64(&self) -> Option { match self { Integer::Small(int) => int.to_i64(), Integer::Big(int) => int.to_i64(), } } fn to_u64(&self) -> Option { match self { Integer::Small(int) => int.to_u64(), Integer::Big(int) => int.to_u64(), } } } impl FromPrimitive for Integer { fn from_i64(n: i64) -> Option { Some(Integer::Small(n)) } fn from_u64(n: u64) -> Option { if let Ok(int) = n.try_into() { Some(Integer::Small(int)) } else { Some(Integer::Big(n.into())) } } } impl From for Integer { fn from(i: i64) -> Integer { Integer::from_i64(i).unwrap() } } impl From for Integer { fn from(i: u64) -> Integer { Integer::from_u64(i).unwrap() } } impl From for Integer { fn from(i: i32) -> Integer { Integer::from_i32(i).unwrap() } } impl From for Integer { fn from(i: usize) -> Integer { Integer::from_usize(i).unwrap() } } impl From for Integer { fn from(i: char) -> Integer { Integer::from_u64(i as u64).unwrap() } } impl From for Integer { fn from(i: BigInt) -> Integer { Integer::Big(i) } } ================================================ FILE: util/libeir_util_number/src/lib.rs ================================================ mod bigint_to_float; pub use bigint_to_float::bigint_to_double; mod integer; pub use integer::Integer; mod float; pub use float::{Float, FloatError}; mod number; pub use number::Number; mod binary; pub use num_bigint as bigint; pub use num_bigint::BigInt; pub use num_traits as traits; pub use num_traits::{cast, FromPrimitive, NumCast, ToPrimitive}; #[derive(Debug, Copy, Clone)] pub struct DivisionError; ================================================ FILE: util/libeir_util_number/src/number.rs ================================================ use std::cmp::Ordering; use std::ops::{Add, Div, Mul, Neg, Sub}; use crate::{Float, FloatError, Integer}; #[derive(Debug, Clone, Hash)] pub enum Number { Integer(Integer), Float(Float), } impl Number { pub fn is_zero(&self) -> bool { match self { Number::Integer(int) => int.is_zero(), Number::Float(float) => float.is_zero(), } } pub fn plus(self) -> Self { match self { Number::Integer(int) => int.plus().into(), Number::Float(float) => float.plus().into(), } } pub fn equals(&self, rhs: &Number, exact: bool) -> bool { match (self, rhs) { (Number::Integer(l), Number::Integer(r)) => l == r, (Number::Float(l), Number::Float(r)) => l == r, (Number::Integer(_l), Number::Float(_r)) if exact => false, (Number::Integer(l), Number::Float(r)) => { if r.is_precise() { l.to_float() == r.inner() } else { l == &r.to_integer() } } (Number::Float(_), Number::Integer(_)) => rhs.equals(self, exact), } } pub fn to_efloat(&self) -> Result { match self { Number::Integer(integer) => integer.to_efloat(), Number::Float(float) => Ok(*float), } } } impl PartialEq for Number { fn eq(&self, rhs: &Number) -> bool { self.equals(rhs, false) } } impl Eq for Number {} impl PartialOrd for Number { fn partial_cmp(&self, other: &Number) -> Option { Some(self.cmp(other)) } } impl Ord for Number { fn cmp(&self, other: &Number) -> Ordering { match (self, other) { (Number::Integer(l), Number::Integer(r)) => l.cmp(r), (Number::Float(l), Number::Float(r)) => l.cmp(r), (Number::Integer(l), Number::Float(r)) => { if r.is_precise() { l.to_float().partial_cmp(&r.inner()).unwrap() } else { l.cmp(&r.to_integer()) } } (Number::Float(l), Number::Integer(r)) => { if l.is_precise() { l.inner().partial_cmp(&r.to_float()).unwrap() } else { l.to_integer().cmp(r) } } } } } impl From for Number { fn from(int: Integer) -> Number { Number::Integer(int) } } impl From for Number { fn from(int: usize) -> Number { Number::Integer(int.into()) } } impl From for Number { fn from(float: Float) -> Number { Number::Float(float) } } impl Neg for Number { type Output = Number; fn neg(self) -> Number { match self { Number::Integer(int) => Number::Integer(-int), Number::Float(float) => Number::Float(-float), } } } impl Add<&Number> for &Number { type Output = Result; fn add(self, rhs: &Number) -> Self::Output { let res: Number = match (self, rhs) { (Number::Integer(l), Number::Integer(r)) => (l.clone() + r).into(), (Number::Integer(l), Number::Float(r)) => (l + *r)?.into(), (Number::Float(l), Number::Integer(r)) => (*l + r)?.into(), (Number::Float(l), Number::Float(r)) => (*l + *r)?.into(), }; Ok(res) } } impl Sub<&Number> for &Number { type Output = Result; fn sub(self, rhs: &Number) -> Self::Output { let res: Number = match (self, rhs) { (Number::Integer(l), Number::Integer(r)) => (l.clone() - r).into(), (Number::Integer(l), Number::Float(r)) => (l - *r)?.into(), (Number::Float(l), Number::Integer(r)) => (*l - r)?.into(), (Number::Float(l), Number::Float(r)) => (*l - *r)?.into(), }; Ok(res) } } impl Mul<&Number> for &Number { type Output = Result; fn mul(self, rhs: &Number) -> Self::Output { let res: Number = match (self, rhs) { (Number::Integer(l), Number::Integer(r)) => (l.clone() * r).into(), (Number::Integer(l), Number::Float(r)) => (l * *r)?.into(), (Number::Float(l), Number::Integer(r)) => (*l * r)?.into(), (Number::Float(l), Number::Float(r)) => (*l * *r)?.into(), }; Ok(res) } } impl Div<&Number> for &Number { type Output = Result; fn div(self, rhs: &Number) -> Self::Output { let res: Number = match (self, rhs) { (Number::Integer(l), Number::Integer(r)) => (l.to_efloat()? + r)?.into(), (Number::Integer(l), Number::Float(r)) => (l / *r)?.into(), (Number::Float(l), Number::Integer(r)) => (*l / r)?.into(), (Number::Float(l), Number::Float(r)) => (*l / *r)?.into(), }; Ok(res) } } ================================================ FILE: util/libeir_util_parse/Cargo.toml ================================================ [package] name = "libeir_util_parse" version = "0.1.0" authors = ["Hans Elias B. Josephsen "] edition = "2018" license = "MIT OR Apache-2.0" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] codespan-reporting = "0.9" scoped_cell = { path = "../scoped_cell" } snafu = "0.5" libeir_diagnostics = { path = "../../libeir_diagnostics" } [dev-dependencies] pretty_assertions = "0.5" ================================================ FILE: util/libeir_util_parse/src/errors.rs ================================================ use std::marker::PhantomData; use std::rc::Rc; use scoped_cell::{scoped_cell, ScopedCell}; use libeir_diagnostics::*; // TODO: I would like to do a lot of things differently here, but things are // tricky without GATs. Revisit once it lands. #[derive(Debug, Clone)] pub enum ErrorOrWarning { Error(E), Warning(W), } impl ToDiagnostic for ErrorOrWarning where E: ToDiagnostic, W: ToDiagnostic, { fn to_diagnostic(&self) -> Diagnostic { match self { ErrorOrWarning::Error(err) => err.to_diagnostic(), ErrorOrWarning::Warning(warn) => warn.to_diagnostic(), } } } #[derive(Clone)] pub struct Errors { pub errors: Vec>, failed: bool, } impl Errors { pub fn new() -> Self { Errors { errors: Vec::new(), failed: false, } } pub fn failed(&self) -> bool { self.failed } pub fn print(&self, codemap: &CodeMap) where E: ToDiagnostic, W: ToDiagnostic, { use term::termcolor::{ColorChoice, StandardStream}; use term::Config; let config = Config::default(); let mut out = StandardStream::stderr(ColorChoice::Auto); for diag in self.iter_diagnostics() { term::emit(&mut out, &config, codemap, &diag).unwrap(); } } pub fn iter_diagnostics<'a>(&'a self) -> impl Iterator + 'a where E: ToDiagnostic, W: ToDiagnostic, { self.errors.iter().map(|e| e.to_diagnostic()) } pub fn errors_from(&mut self, other: Errors) where IE: Into, IW: Into, { self.failed = self.failed | other.failed; for ew in other.errors { match ew { ErrorOrWarning::Error(err) => self.errors.push(ErrorOrWarning::Error(err.into())), ErrorOrWarning::Warning(warn) => { self.errors.push(ErrorOrWarning::Warning(warn.into())) } } } } } impl ErrorReceiver for Errors { type E = E; type W = W; fn is_failed(&self) -> bool { self.failed } fn warning(&mut self, warning: W) { self.errors.push(ErrorOrWarning::Warning(warning)); } fn error(&mut self, error: E) { self.errors.push(ErrorOrWarning::Error(error)); self.failed = true; } } pub struct MessageIgnore { failed: bool, _phantom: PhantomData<(E, W)>, } impl MessageIgnore { pub fn new() -> Self { MessageIgnore { failed: false, _phantom: PhantomData, } } pub fn failed(&self) -> bool { self.failed } } impl ErrorReceiver for MessageIgnore { type E = E; type W = W; fn is_failed(&self) -> bool { self.failed } fn warning(&mut self, _warning: W) {} fn error(&mut self, _error: E) { self.failed = true; } } pub trait ErrorReceiver { type E; type W; fn is_failed(&self) -> bool; fn warning(&mut self, warning: Self::W); fn error(&mut self, error: Self::E); } impl ErrorReceiver for &mut dyn ErrorReceiver { type E = E; type W = W; fn is_failed(&self) -> bool { (**self).is_failed() } fn warning(&mut self, warning: Self::W) { (**self).warning(warning) } fn error(&mut self, error: Self::E) { (**self).error(error) } } pub fn error_tee<'a, E, W, F, R>( receiver: &'a mut (dyn ErrorReceiver + 'a), fun: F, ) -> R where F: FnOnce(ErrorReceiverTee) -> R, { scoped_cell(receiver, |cell| { let tee = ErrorReceiverTee { cell }; fun(tee) }) } pub struct ErrorReceiverTee<'a, E, W> { cell: ScopedCell + 'a>, } impl<'a, E, W> Clone for ErrorReceiverTee<'a, E, W> { fn clone(&self) -> Self { ErrorReceiverTee { cell: self.cell.clone(), } } } impl<'a, E, W> ErrorReceiverTee<'a, E, W> { pub fn make_adapter( &mut self, error_adapter: FE, warning_adapter: FW, ) -> ErrorReceiverTeeAdapter<'a, E, W, NE, NW> where FE: Fn(NE) -> E + 'static, FW: Fn(NW) -> W + 'static, { ErrorReceiverTeeAdapter { cell: self.cell.clone(), error_adapter: Rc::new(error_adapter), warning_adapter: Rc::new(warning_adapter), phantom: PhantomData, } } pub fn make_into_adapter(&mut self) -> ErrorReceiverTeeAdapter<'a, E, W, NE, NW> where NE: Into, NW: Into, { ErrorReceiverTeeAdapter { cell: self.cell.clone(), error_adapter: Rc::new(|o| o.into()), warning_adapter: Rc::new(|o| o.into()), phantom: PhantomData, } } } impl<'a, E, W> ErrorReceiver for ErrorReceiverTee<'a, E, W> { type E = E; type W = W; fn is_failed(&self) -> bool { self.cell.borrow_mut(|inner| (*inner).is_failed()) } fn error(&mut self, error: E) { self.cell.borrow_mut(|inner| { inner.error(error); }); } fn warning(&mut self, warning: W) { self.cell.borrow_mut(|inner| { inner.warning(warning); }); } } pub struct ErrorReceiverTeeAdapter<'a, IE, IW, OE, OW> { cell: ScopedCell + 'a>, error_adapter: Rc IE>, warning_adapter: Rc IW>, phantom: PhantomData<(OE, OW)>, } impl<'a, IE, IW, OE, OW> ErrorReceiver for ErrorReceiverTeeAdapter<'a, IE, IW, OE, OW> { type E = OE; type W = OW; fn is_failed(&self) -> bool { self.cell.borrow_mut(|inner| (*inner).is_failed()) } fn error(&mut self, error: OE) { self.cell.borrow_mut(|inner| { inner.error((self.error_adapter)(error)); }); } fn warning(&mut self, warning: OW) { self.cell.borrow_mut(|inner| { inner.warning((self.warning_adapter)(warning)); }); } } impl<'a, IE, IW, OE, OW> Clone for ErrorReceiverTeeAdapter<'a, IE, IW, OE, OW> { fn clone(&self) -> Self { Self { cell: self.cell.clone(), error_adapter: self.error_adapter.clone(), warning_adapter: self.warning_adapter.clone(), phantom: PhantomData, } } } #[cfg(test)] mod tests { use super::{error_tee, ErrorReceiver, Errors}; #[test] fn basic_usage() { fn inner2(recv: &mut dyn ErrorReceiver) { error_tee(recv, |_tee| {}); } fn inner(recv: &mut dyn ErrorReceiver) { error_tee(recv, |mut tee| { let mut adapter = tee.make_into_adapter(); inner2(&mut adapter); }); } let mut errors = Errors::new(); inner(&mut errors); } } ================================================ FILE: util/libeir_util_parse/src/lib.rs ================================================ mod source; pub use source::*; mod scanner; pub use scanner::*; mod util; pub use util::*; mod result; pub use result::*; mod errors; pub use errors::*; mod parser; pub use parser::*; ================================================ FILE: util/libeir_util_parse/src/parser.rs ================================================ use std::path::{Path, PathBuf}; use std::sync::Arc; use libeir_diagnostics::*; use crate::ErrorReceiver; use crate::{FileMapSource, Source}; pub struct Parser { pub config: C, pub codemap: Arc, } impl Parser { pub fn new(config: C, codemap: Arc) -> Self { Self { config, codemap } } } impl Parser { pub fn parse<'a, T>( &self, errors: &'a mut (dyn ErrorReceiver::Error, W = ::Error> + 'a), source: Arc, ) -> Result where T: Parse, { >::parse(&self, errors, FileMapSource::new(source)) } pub fn parse_string<'a, T, S>( &self, errors: &'a mut (dyn ErrorReceiver::Error, W = ::Error> + 'a), source: S, ) -> Result where T: Parse, S: AsRef, { let id = self.codemap.add("nofile", source.as_ref().to_string()); let file = self.codemap.get(id).unwrap(); self.parse(errors, file) } pub fn parse_file<'a, T, S>( &self, errors: &'a mut (dyn ErrorReceiver::Error, W = ::Error> + 'a), source: S, ) -> Result where T: Parse, S: AsRef, { let path = source.as_ref(); match std::fs::read_to_string(path) { Err(err) => { errors.error(>::root_file_error(err, path.to_owned())); Err(()) } Ok(content) => { let id = self.codemap.add(path, content); let file = self.codemap.get(id).unwrap(); self.parse(errors, file) } } } } pub trait Parse { type Parser; type Error; type Config; type Token; fn root_file_error(err: std::io::Error, path: PathBuf) -> Self::Error; /// Initializes a token stream for the underlying parser and invokes parse_tokens fn parse<'a, S>( parser: &Parser, errors: &'a mut (dyn ErrorReceiver + 'a), source: S, ) -> Result where S: Source; /// Implemented by each parser, which should parse the token stream and produce a T fn parse_tokens<'a, S>( errors: &'a mut (dyn ErrorReceiver + 'a), tokens: S, ) -> Result where S: IntoIterator; } ================================================ FILE: util/libeir_util_parse/src/result.rs ================================================ /// A result of parsing. Can have one of three states: /// - Fail: Error only /// - Warn: Error and result /// - Ok: Result only pub enum ParseResult { Fail(E), Warn(E, R), Ok(R), } pub trait Print { fn print(&self); } impl ParseResult { pub fn unwrap(self) -> R { match self { ParseResult::Fail(_err) => { panic!(); } ParseResult::Warn(_err, res) => res, ParseResult::Ok(res) => res, } } pub fn unwrap_print(self) -> R where E: Print, { match self { ParseResult::Fail(err) => { err.print(); panic!(); } ParseResult::Warn(err, res) => { err.print(); res } ParseResult::Ok(res) => res, } } } ================================================ FILE: util/libeir_util_parse/src/scanner.rs ================================================ use std::convert::Into; use std::ops::Range; use libeir_diagnostics::*; use super::source::Source; /// An implementation of `Scanner` for general use /// /// source -> pending -> current /// /// ## pending /// `peek` returns pending without advancing /// /// ## current /// `pop` returns current and advances /// `read` returns current without advances pub struct Scanner { source: S, current: (SourceIndex, char), pending: (SourceIndex, char), start: SourceIndex, end: SourceIndex, } impl Scanner where S: Source, { pub fn new(mut source: S) -> Self { let span = source.span(); let start = span.start(); let end = span.end(); let current = source.read().unwrap_or((SourceIndex::UNKNOWN, '\0')); let pending = source.read().unwrap_or((SourceIndex::UNKNOWN, '\0')); Scanner { source, current, pending, start, end, } } pub fn start(&self) -> SourceIndex { self.start } /// Advance scanner pipeline by a single character. /// /// Current becomes pending, pending becomes next character from source. #[inline] pub fn advance(&mut self) { self.current = self.pending; self.pending = match self.source.read() { None => (self.end, '\0'), Some(ic) => ic, }; } /// Get current character and advance. #[inline] pub fn pop(&mut self) -> (SourceIndex, char) { let current = self.current; self.advance(); current } /// Get pending character. #[inline] pub fn peek(&self) -> (SourceIndex, char) { self.pending } /// Get the next character from the source. #[inline] pub fn peek_next(&mut self) -> (SourceIndex, char) { match self.source.peek() { None => (self.end, '\0'), Some((pos, c)) => (pos, c), } } /// Get current character. #[inline] pub fn read(&self) -> (SourceIndex, char) { self.current } #[inline] pub fn slice(&self, span: impl Into>) -> &str { self.source.slice(span) } } ================================================ FILE: util/libeir_util_parse/src/source.rs ================================================ use std::char; use std::ops::Range; use std::path::PathBuf; use std::sync::Arc; use snafu::Snafu; use libeir_diagnostics::*; pub type SourceResult = std::result::Result; pub trait Source: Sized { fn new(src: Arc) -> Self; fn read(&mut self) -> Option<(SourceIndex, char)>; fn peek(&mut self) -> Option<(SourceIndex, char)>; fn span(&self) -> SourceSpan; fn slice(&self, span: impl Into>) -> &str; } #[derive(Debug, Snafu)] pub enum SourceError { #[snafu(visibility(pub), display("{} while reading {:?}", source, path))] RootFileIO { source: std::io::Error, path: PathBuf, }, #[snafu(display("invalid source path"))] InvalidPath { reason: String }, #[snafu(display("{}", source))] PathVariableSubstitute { source: crate::util::PathVariableSubstituteError, }, } impl SourceError { pub fn to_diagnostic(&self) -> Diagnostic { match self { SourceError::RootFileIO { source, path: _ } => { Diagnostic::error().with_message(source.to_string()) } SourceError::InvalidPath { reason } => { Diagnostic::error().with_message(format!("invalid path: {}", reason)) } SourceError::PathVariableSubstitute { source } => source.to_diagnostic(), } } } /// A source which reads from a `diagnostics::SourceFile` pub struct FileMapSource { src: Arc, bytes: *const [u8], start: SourceIndex, peek: Option<(SourceIndex, char)>, end: usize, pos: usize, eof: bool, } impl FileMapSource { fn peek_char(&self) -> Option<(SourceIndex, char)> { self.peek } fn next_char(&mut self) -> Option<(SourceIndex, char)> { // If we've peeked a char already, return that let result = if self.peek.is_some() { std::mem::replace(&mut self.peek, None) } else { let next = unsafe { self.next_char_internal() }; match next { None => { self.eof = true; return None; } result => result, } }; // Reset peek self.peek = unsafe { self.next_char_internal() }; result } #[inline] unsafe fn next_char_internal(&mut self) -> Option<(SourceIndex, char)> { let mut pos = self.pos; let end = self.end; if pos == end { self.eof = true; } if self.eof { return None; } let start = self.start + pos; let bytes: &[u8] = &*self.bytes; // Decode UTF-8 let x = *bytes.get_unchecked(pos); if x < 128 { self.pos = pos + 1; return Some((start, char::from_u32_unchecked(x as u32))); } // Multibyte case follows // Decode from a byte combination out of: [[[x y] z] w] // NOTE: Performance is sensitive to the exact formulation here let init = Self::utf8_first_byte(x, 2); pos = pos + 1; let y = if pos == end { 0u8 } else { *bytes.get_unchecked(pos) }; let mut ch = Self::utf8_acc_cont_byte(init, y); if x >= 0xE0 { // [[x y z] w] case // 5th bit in 0xE0 .. 0xEF is always clear, so `init` is still valid pos = pos + 1; let z = if pos == end { 0u8 } else { *bytes.get_unchecked(pos) }; let y_z = Self::utf8_acc_cont_byte((y & Self::CONT_MASK) as u32, z); ch = init << 12 | y_z; if x >= 0xF0 { // [x y z w] case // use only the lower 3 bits of `init` pos = pos + 1; let w = if pos == end { 0u8 } else { *bytes.get_unchecked(pos) }; ch = (init & 7) << 18 | Self::utf8_acc_cont_byte(y_z, w); } } pos = pos + 1; if pos >= end { self.eof = true } self.pos = pos; Some((start, char::from_u32_unchecked(ch as u32))) } /// Returns the initial codepoint accumulator for the first byte. /// The first byte is special, only want bottom 5 bits for width 2, 4 bits /// for width 3, and 3 bits for width 4. #[inline] fn utf8_first_byte(byte: u8, width: u32) -> u32 { (byte & (0x7F >> width)) as u32 } /// Returns the value of `ch` updated with continuation byte `byte`. #[inline] fn utf8_acc_cont_byte(ch: u32, byte: u8) -> u32 { (ch << 6) | (byte & Self::CONT_MASK) as u32 } /// Mask of the value bits of a continuation byte. const CONT_MASK: u8 = 0b0011_1111; } impl Source for FileMapSource { fn new(src: Arc) -> Self { let start = SourceIndex::new(src.id(), ByteIndex(0)); let mut source = Self { src, bytes: &[], peek: None, start, end: 0, pos: 0, eof: false, }; let s = source.src.source(); let bytes = s.as_bytes(); source.end = bytes.len(); source.bytes = bytes; source.peek = unsafe { source.next_char_internal() }; source } #[inline] fn read(&mut self) -> Option<(SourceIndex, char)> { self.next_char() } #[inline] fn peek(&mut self) -> Option<(SourceIndex, char)> { self.peek_char() } #[inline] fn span(&self) -> SourceSpan { self.src.source_span() } #[inline] fn slice(&self, span: impl Into>) -> &str { self.src.source_slice(span).unwrap() } } impl Iterator for FileMapSource { type Item = (SourceIndex, char); fn next(&mut self) -> Option { self.read() } } #[cfg(test)] mod test { use pretty_assertions::assert_eq; use super::*; fn read_all_chars(source: FileMapSource) -> Vec { source.map(|result| result.1).collect() } #[test] fn file_source() { let expected = vec!['h', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd', '!']; let codemap = CodeMap::default(); let id1 = codemap.add("nofile", "hello world!".to_string()); let file1 = codemap.get(id1).unwrap(); let source1 = FileMapSource::new(file1); let chars = read_all_chars(source1); assert_eq!(expected, chars); let id2 = codemap.add("nofile", "hello world!".to_string()); let file2 = codemap.get(id2).unwrap(); let mut source2 = FileMapSource::new(file2); assert_eq!( Some((SourceIndex::new(id2, ByteIndex(0)), 'h')), source2.peek() ); assert_eq!( Some((SourceIndex::new(id2, ByteIndex(0)), 'h')), source2.next() ); let id3 = codemap.add("nofile", "éé".to_string()); let file3 = codemap.get(id3).unwrap(); let mut source3 = FileMapSource::new(file3); assert_eq!( Some((SourceIndex::new(id3, ByteIndex(0)), 'é')), source3.peek() ); assert_eq!( Some((SourceIndex::new(id3, ByteIndex(0)), 'é')), source3.next() ); assert_eq!( Some((SourceIndex::new(id3, ByteIndex(2)), 'é')), source3.peek() ); assert_eq!( Some((SourceIndex::new(id3, ByteIndex(2)), 'é')), source3.next() ); } } ================================================ FILE: util/libeir_util_parse/src/util.rs ================================================ use std::env; use std::path::{Path, PathBuf}; use libeir_diagnostics::Diagnostic; use snafu::Snafu; #[derive(Debug, Snafu)] pub enum PathVariableSubstituteError { InvalidPathVariable { variable: String, source: std::env::VarError, }, } impl PathVariableSubstituteError { pub fn to_diagnostic(&self) -> Diagnostic { match self { PathVariableSubstituteError::InvalidPathVariable { source: env::VarError::NotPresent, variable, } => Diagnostic::error().with_message(format!( "invalid environment variable '{}': not defined", variable, )), PathVariableSubstituteError::InvalidPathVariable { source: env::VarError::NotUnicode { .. }, variable, } => Diagnostic::error().with_message(format!( "invalid environment variable '{}': contains invalid unicode data", variable, )), } } } pub fn substitute_path_variables>( path: P, ) -> Result { let mut new = PathBuf::new(); for c in path.as_ref().components() { if let Some(s) = c.as_os_str().to_str() { if s.as_bytes().get(0) == Some(&b'$') { let var = s.split_at(1).1; match env::var(var) { Ok(c) => { new.push(c); continue; } Err(e) => { return Err(PathVariableSubstituteError::InvalidPathVariable { variable: var.to_owned(), source: e, }); } } } } new.push(c.as_os_str()); } Ok(new) } ================================================ FILE: util/libeir_util_parse_listing/Cargo.toml ================================================ [package] name = "libeir_util_parse_listing" version = "0.1.0" authors = ["Hans Elias B. Josephsen "] edition = "2018" build = "build.rs" license = "MIT OR Apache-2.0" [dependencies] libeir_util_parse = { path = "../libeir_util_parse" } libeir_ir = { path = "../../libeir_ir" } libeir_diagnostics = { path = "../../libeir_diagnostics" } libeir_intern = { path = "../../libeir_intern" } lalrpop-util = "0.17" [dev-dependencies] codespan-reporting = "0.9" [build-dependencies] lalrpop = "0.17" ================================================ FILE: util/libeir_util_parse_listing/build.rs ================================================ extern crate lalrpop; fn main() { lalrpop::Configuration::new() .use_cargo_dir_conventions() .process_file("src/grammar.lalrpop") .unwrap(); println!("cargo:rerun-if-changed=src/grammar.lalrpop"); } ================================================ FILE: util/libeir_util_parse_listing/src/ast.rs ================================================ use libeir_diagnostics::SourceSpan; use libeir_intern::Ident; use libeir_ir::Integer; #[derive(Debug)] pub struct Root { pub items: Vec, } impl Root { pub fn span(&self) -> SourceSpan { self.items .first() .map(|i| i.span()) .unwrap_or(SourceSpan::UNKNOWN) } } #[derive(Debug)] pub enum Item { Atom(Ident), String(Ident), Int(Int), Float(Float), Tuple(Tuple), List(List), } impl Item { pub fn tuple(&self) -> Option<&Tuple> { match self { Item::Tuple(inner) => Some(inner), _ => None, } } pub fn atom(&self) -> Option { match self { Item::Atom(inner) => Some(*inner), _ => None, } } pub fn string(&self) -> Option { match self { Item::String(inner) => Some(*inner), _ => None, } } pub fn integer(&self) -> Option<&Int> { match self { Item::Int(inner) => Some(inner), _ => None, } } pub fn float(&self) -> Option<&Float> { match self { Item::Float(inner) => Some(inner), _ => None, } } pub fn list(&self) -> Option<&List> { match self { Item::List(inner) => Some(inner), _ => None, } } pub fn list_iter(&self) -> Option> { self.list().map(|v| ListIterator { curr: Some(v), idx: 0, }) } pub fn span(&self) -> SourceSpan { match self { Item::Atom(ident) => ident.span, Item::String(ident) => ident.span, Item::Int(int) => int.span, Item::Tuple(tup) => tup.span, Item::List(list) => list.span, Item::Float(float) => float.span, } } } pub struct ListIterator<'a> { curr: Option<&'a List>, idx: usize, } impl<'a> Iterator for ListIterator<'a> { type Item = &'a Item; fn next(&mut self) -> Option { if let Some(list) = self.curr { if let Some(result) = list.heads.get(self.idx) { self.idx += 1; return Some(result); } else { self.idx = 0; if let Some(tail) = &list.tail { if let Some(tail_list) = tail.list() { self.curr = Some(tail_list); return self.next(); } else { unimplemented!() } } else { self.curr = None; return None; } } } else { None } } } #[derive(Debug)] pub struct Int { pub integer: Integer, pub span: SourceSpan, } #[derive(Debug)] pub struct Float { pub float: f64, pub span: SourceSpan, } #[derive(Debug)] pub struct Tuple { pub entries: Vec, pub span: SourceSpan, } #[derive(Debug)] pub struct List { pub heads: Vec, pub tail: Option>, pub span: SourceSpan, } ================================================ FILE: util/libeir_util_parse_listing/src/grammar.lalrpop ================================================ //-*- mode: rust -*- use libeir_ir::Integer; use libeir_intern::{Symbol, Ident}; use libeir_diagnostics::{SourceIndex, SourceSpan}; use super::super::token::{Token, Float as FloatToken}; use super::super::ast::*; grammar(); // Comma-delimited with zero or more elements CommaOpt: Vec = { ",")*> => { let mut vals = vals; vals.extend(last); vals }, }; pub Item: Item = { "{" > "}" => { Item::Tuple(Tuple { entries, span: SourceSpan::new(l, r), }) }, "[" > )?> "]" => { Item::List(List { heads, tail: tail.map(Box::new), span: SourceSpan::new(l, r), }) }, => { Item::Atom(Ident::new(v, SourceSpan::new(l, r))) }, => { Item::Int(Int { integer: v, span: SourceSpan::new(l, r), }) }, => { Item::String(Ident::new(v, SourceSpan::new(l, r))) }, => { Item::Float(Float { float: f.0, span: SourceSpan::new(l, r), }) }, }; pub Root: Root = { <( ".")*> => { Root { items: <>, } }, }; extern { type Location = SourceIndex; type Error = (); enum Token { atom => Token::Atom(), integer => Token::Integer(), string => Token::String(), float => Token::Float(), "," => Token::Comma, "." => Token::Dot, "|" => Token::Pipe, "[" => Token::SquareOpen, "]" => Token::SquareClose, "{" => Token::CurlyOpen, "}" => Token::CurlyClose, } } ================================================ FILE: util/libeir_util_parse_listing/src/lib.rs ================================================ #![deny(unused)] pub mod ast; pub mod parser; mod token; ================================================ FILE: util/libeir_util_parse_listing/src/parser.rs ================================================ use std::convert::From; use libeir_diagnostics::*; use libeir_util_parse::{ErrorReceiver, Parse, Parser, Scanner, Source}; use super::ast; use super::token::{Lexer, Token}; #[cfg_attr(rustfmt, rustfmt_skip)] #[allow(unknown_lints)] #[allow(clippy)] #[allow(unused)] pub(crate) mod grammar { // During the build step, `build.rs` will output the generated parser to `OUT_DIR` to avoid // adding it to the source directory, so we just directly include the generated parser here. // // Even with `.gitignore` and the `exclude` in the `Cargo.toml`, the generated parser can still // end up in the source directory. This could happen when `cargo build` builds the file out of // the Cargo cache (`$HOME/.cargo/registrysrc`), and the build script would then put its output // in that cached source directory because of https://github.com/lalrpop/lalrpop/issues/280. // Later runs of `cargo vendor` then copy the source from that directory, including the // generated file. include!(concat!(env!("OUT_DIR"), "/grammar.rs")); } #[derive(Debug)] pub enum ParseError { RootFileError { source: std::io::Error, path: std::path::PathBuf, }, LalrPop(lalrpop_util::ParseError), } impl ParseError { pub fn new(err: lalrpop_util::ParseError) -> Self { ParseError::LalrPop(err) } } impl From> for ParseError { fn from(err: lalrpop_util::ParseError) -> Self { Self::new(err) } } impl ToDiagnostic for ParseError { fn to_diagnostic(&self) -> Diagnostic { use lalrpop_util::ParseError::*; match self { Self::RootFileError { source, path } => Diagnostic::error() .with_message(format!("{} occurred when reading {:?}", source, path)), Self::LalrPop(InvalidToken { location }) => { let source_id = location.source_id(); let index = *location; Diagnostic::error() .with_message("invalid token") .with_labels(vec![Label::primary( source_id, SourceSpan::new(index, index), ) .with_message("invalid token encountered here")]) } Self::LalrPop(UnrecognizedEOF { location, expected }) => { let source_id = location.source_id(); let index = *location; Diagnostic::error() .with_message("unexpected end of file") .with_labels(vec![Label::primary( source_id, SourceSpan::new(index, index), ) .with_message(&format!("expected one of: {}", expected.join(", ")))]) } Self::LalrPop(ExtraToken { token: (l, _, r) }) => Diagnostic::error() .with_message("extra token") .with_labels(vec![Label::primary(l.source_id(), SourceSpan::new(*l, *r)) .with_message("did not expect this token")]), Self::LalrPop(UnrecognizedToken { token: (l, _, r), .. }) => Diagnostic::error() .with_message("unexpected token") .with_labels(vec![Label::primary(l.source_id(), SourceSpan::new(*l, *r)) .with_message("did not expect this token")]), Self::LalrPop(User { .. }) => Diagnostic::error().with_message("parsing failed"), } } } impl Parse for ast::Root { type Parser = grammar::RootParser; type Error = ParseError; type Config = (); type Token = Result<(SourceIndex, Token, SourceIndex), ()>; fn root_file_error(source: std::io::Error, path: std::path::PathBuf) -> Self::Error { ParseError::RootFileError { source, path } } fn parse( _parser: &Parser, errors: &mut dyn ErrorReceiver, source: S, ) -> Result where S: Source, { let scanner = Scanner::new(source); let lexer = Lexer::new(scanner); Self::parse_tokens(errors, lexer) } fn parse_tokens( errors: &mut dyn ErrorReceiver, tokens: S, ) -> Result where S: IntoIterator, { match Self::Parser::new().parse(tokens) { Ok(inner) => Ok(inner), Err(err) => { errors.error(err.into()); Err(()) } } } } #[cfg(test)] mod test { use std::sync::Arc; use super::ast::Root; use super::ParseError; use libeir_diagnostics::*; use libeir_util_parse::{Errors, Parse, Parser}; fn fail_with(errors: &Errors, codemap: &CodeMap) -> ! where E: ToDiagnostic, W: ToDiagnostic, { use term::termcolor::{ColorChoice, StandardStream}; let config = term::Config::default(); let mut out = StandardStream::stderr(ColorChoice::Always); for diagnostic in errors.iter_diagnostics() { term::emit(&mut out, &config, codemap, &diagnostic).unwrap(); } panic!(); } fn parse(input: S) -> T where T: Parse, S: AsRef, { let parser = Parser::new((), Arc::new(CodeMap::new())); let mut errors = Errors::new(); match parser.parse_string::(&mut errors, input) { Ok(ast) => return ast, Err(()) => fail_with(&errors, &parser.codemap), }; } #[test] fn simple() { let _: Root = parse( " {woo, '123fwoo', {}}. ", ); } #[test] fn basic_ast() { let _: Root = parse( " {attribute,1,file,{\"woo.erl\",1}}. {attribute,1,module,woo}. {attribute,3,export,[{foo,2},{bar,1},{barr,1}]}. {function,5,foo,2, [{clause,5, [{var,5,'A'},{var,5,'B'}], [], [{op,5,'+',{var,5,'A'},{var,5,'B'}}]}]}. {function,7,bar,1, [{clause,7,[{integer,7,1}],[],[{integer,7,2}]}, {clause,8,[{integer,8,2}],[],[{integer,8,4}]}, {clause,9,[{var,9,'N'}],[],[{var,9,'N'}]}]}. {function,11,barr,1, [{clause,11,[{integer,11,1}],[],[{integer,11,2}]}, {clause,12,[{integer,12,2}],[],[{integer,12,4}]}]}. {function,14,binary,0, [{clause,14,[],[], [{bin,14,[{bin_element,14,{string,14,\"woo\"},default,default}]}]}]}. {function,16,string,0,[{clause,16,[],[],[{string,16,\"woo\"}]}]}. {eof,17}. ", ); } } ================================================ FILE: util/libeir_util_parse_listing/src/token.rs ================================================ use std::str::FromStr; use libeir_diagnostics::*; use libeir_intern::Symbol; use libeir_ir::Integer; use libeir_util_parse::{Scanner, Source}; macro_rules! pop { ($lex:ident) => {{ $lex.skip(); }}; ($lex:ident, $code:expr) => {{ $lex.skip(); $code }}; } #[derive(Debug, Clone, PartialEq, Eq)] pub enum Token { EOF, Comma, Dot, Pipe, SquareOpen, SquareClose, CurlyOpen, CurlyClose, Atom(Symbol), String(Symbol), Integer(Integer), Float(Float), } #[derive(Debug, Clone, PartialEq, PartialOrd)] pub struct Float(pub f64); impl Eq for Float {} pub struct Lexer { scanner: Scanner, token: Token, token_start: SourceIndex, token_end: SourceIndex, eof: bool, str_buf: String, } impl Lexer where S: Source, { pub fn new(scanner: Scanner) -> Self { let start = scanner.start(); let mut lexer = Self { scanner, token: Token::EOF, token_start: start, token_end: start, eof: false, str_buf: String::new(), }; lexer.advance(); lexer } pub fn lex(&mut self) -> Option<::Item> { if self.eof && self.token == Token::EOF { return None; } let token = std::mem::replace(&mut self.token, Token::EOF); let result = Some(Ok(( self.token_start.clone(), token, self.token_end.clone(), ))); self.advance(); result } fn advance(&mut self) { self.advance_start(); self.token = self.tokenize(); } fn advance_start(&mut self) { let mut position: SourceIndex; loop { let (pos, c) = self.scanner.read(); position = pos; if c == '\0' { self.eof = true; return; } if c.is_whitespace() { self.scanner.advance(); continue; } break; } self.token_start = position; } fn pop(&mut self) -> char { let (pos, c) = self.scanner.pop(); self.token_end = pos + ByteOffset::from_char_len(c); c } fn peek(&mut self) -> char { self.scanner.peek().1 } fn read(&mut self) -> char { self.scanner.read().1 } fn skip(&mut self) { self.pop(); } pub fn span(&self) -> SourceSpan { SourceSpan::new(self.token_start, self.token_end) } fn slice(&self) -> &str { self.scanner.slice(self.span()) } fn skip_whitespace(&mut self) { while self.read().is_whitespace() { self.skip(); } } fn lex_unquoted_atom(&mut self) -> Token { let c = self.pop(); debug_assert!(c.is_ascii_lowercase()); loop { match self.read() { '_' => self.skip(), '@' => self.skip(), '0'..='9' => self.skip(), c if c.is_alphanumeric() => self.skip(), _ => break, } } Token::Atom(Symbol::intern(self.slice())) } fn lex_quoted_atom(&mut self) -> Token { let c = self.pop(); debug_assert!(c == '\''); self.str_buf.clear(); loop { match self.read() { '\\' => unimplemented!(), '\'' => { self.skip(); break; } c => { self.skip(); self.str_buf.push(c); } } } Token::Atom(Symbol::intern(&self.str_buf)) } fn lex_string(&mut self) -> Token { let c = self.pop(); debug_assert!(c == '"'); self.str_buf.clear(); loop { match self.read() { '\\' => unimplemented!(), '"' => { self.skip(); break; } c => { self.skip(); self.str_buf.push(c); } } } Token::String(Symbol::intern(&self.str_buf)) } fn lex_number(&mut self) -> Token { let c = self.pop(); debug_assert!(c == '-' || c == '+' || c.is_digit(10)); //let negative = c == '-'; while self.read().is_digit(10) { self.skip(); } let c = self.read(); if c == '.' { if self.peek().is_digit(10) { self.skip(); return self.lex_float(); } return Token::Integer(Integer::from_string_radix(self.slice(), 10).unwrap()); } // TODO Float return Token::Integer(Integer::from_string_radix(self.slice(), 10).unwrap()); } fn lex_float(&mut self) -> Token { let c = self.pop(); println!("{}", c); debug_assert!(c.is_digit(10)); while self.read().is_digit(10) { self.pop(); } match f64::from_str(self.slice()) { Ok(f) => Token::Float(Float(f)), Err(_e) => unimplemented!(), } } fn tokenize(&mut self) -> Token { let c = self.read(); if c == '\0' { self.eof = true; return Token::EOF; } if c.is_whitespace() { self.skip_whitespace(); } match self.read() { '{' => pop!(self, Token::CurlyOpen), '}' => pop!(self, Token::CurlyClose), '[' => pop!(self, Token::SquareOpen), ']' => pop!(self, Token::SquareClose), ',' => pop!(self, Token::Comma), '.' => pop!(self, Token::Dot), '|' => pop!(self, Token::Pipe), 'a'..='z' | 'A'..='Z' => self.lex_unquoted_atom(), '0'..='9' => self.lex_number(), '\'' => self.lex_quoted_atom(), '"' => self.lex_string(), c => unimplemented!("{}", c), } } } impl Iterator for Lexer where S: Source, { type Item = Result<(SourceIndex, Token, SourceIndex), ()>; fn next(&mut self) -> Option { self.lex() } } ================================================ FILE: util/libeir_util_pattern_compiler/Cargo.toml ================================================ [package] authors = ["HansiHE "] name = "libeir_util_pattern_compiler" version = "0.1.0" edition = "2018" license = "MIT OR Apache-2.0" description = "Utilities for compiling pattern matches into optimal decision trees" repository = "https://github.com/hansihe/core_erlang/tree/master/pattern-compiler" [features] debug_table_print = ["prettytable-rs"] #default = ["debug_table_print"] [dependencies] either = "1.5" petgraph = "0.4" derivative = "1.0" prettytable-rs = { version = "0.8", optional = true } itertools = "0.8.0" log = "0.4" ================================================ FILE: util/libeir_util_pattern_compiler/README.md ================================================ # Pattern compiler Implements a variant of http://www.cs.tufts.edu/~nr/cs257/archive/luc-maranget/jun08.pdf Crate that compiles pattern matching into optimal decision trees. ================================================ FILE: util/libeir_util_pattern_compiler/src/cfg/generate_dot.rs ================================================ use std::io::Write; use petgraph::visit::EdgeRef; use petgraph::Direction; use crate::cfg::PatternCfg; use crate::pattern::PatternProvider; const DOT_BREAK: &str = "
"; fn format_label(label: &str) -> String { label .replace("{", "\\{") .replace("}", "\\}") .replace("\n", DOT_BREAK) } impl

PatternCfg

where P: PatternProvider, { pub fn to_dot(&self, w: &mut dyn Write) -> ::std::io::Result<()> { write!(w, "digraph g {{\n")?; write!( w, "node [labeljust=\"l\", shape=record, fontname=\"Courier New\"]\n" )?; write!(w, "edge [fontname=\"Courier New\" ]\n\n")?; for index in self.graph.node_indices() { let node = &self.graph[index]; //println!("{:?}", node); let label = format_label(&format!("{:?}", node)); write!( w, "node_{} [ label=<{}: {}", index.index(), index.index(), label )?; if let Some(bindings) = self.leaf_bindings.get(&index) { write!( w, "{} {}", DOT_BREAK, format_label(&format!("{:#?}", bindings)) )?; } write!(w, "> ]\n")?; for edge in self.graph.edges_directed(index, Direction::Outgoing) { let label = format_label(&format!("{:?}", edge.weight())); write!( w, "node_{} -> node_{} [ label=<{}> ]\n", edge.source().index(), edge.target().index(), label )?; } write!(w, "\n")?; } write!(w, "}}\n")?; Ok(()) } } ================================================ FILE: util/libeir_util_pattern_compiler/src/cfg/mod.rs ================================================ use ::std::collections::HashMap; use ::petgraph::graph::NodeIndex; use ::petgraph::Graph; mod generate_dot; use super::pattern::PatternProvider; pub type CfgNodeIndex = NodeIndex; //#[derive(Debug, Clone)] //pub struct Leaf

where P: PatternProvider { // bindings: HashMap, //} #[derive(Debug, Clone)] pub struct PatternCfg

where P: PatternProvider, { pub entry: CfgNodeIndex, pub graph: Graph, CfgEdge

>, pub leaf_bindings: HashMap>, } impl

PatternCfg

where P: PatternProvider, { pub(crate) fn new() -> Self { let mut graph = Graph::new(); PatternCfg { entry: graph.add_node(CfgNodeKind::Root), graph: graph, leaf_bindings: HashMap::new(), } } pub(crate) fn add_fail(&mut self) -> CfgNodeIndex { self.graph.add_node(CfgNodeKind::Fail) } pub(crate) fn add_leaf( &mut self, parent: CfgNodeIndex, leaf_num: usize, edge: CfgEdge

, binds: HashMap, ) -> CfgNodeIndex { let index = self.graph.add_node(CfgNodeKind::Leaf(leaf_num)); self.graph.add_edge(parent, index, edge); self.leaf_bindings.insert(index, binds); index } pub fn get_entry(&self) -> CfgNodeIndex { self.entry } //pub fn add_node(&mut self, var: P::CfgVariable) -> CfgNodeIndex { // self.graph.add_node(CfgNodeKind::Match(var)) //} pub(crate) fn add_edge(&mut self, parent: CfgNodeIndex, child: CfgNodeIndex, edge: CfgEdge

) { self.graph.add_edge(parent, child, edge); } pub(crate) fn add_child( &mut self, parent: CfgNodeIndex, typ: CfgEdge

, var: P::CfgVariable, binds: HashMap, ) -> CfgNodeIndex { let child = self.graph.add_node(CfgNodeKind::Match(var)); self.graph.add_edge(parent, child, typ); self.leaf_bindings.insert(child, binds); child } } #[derive(Clone)] pub struct CfgEdge

where P: PatternProvider, { //_provider: ::std::marker::PhantomData

, pub kind: Option, pub variable_binds: Vec, //pub pattern_node: super::pattern::PatternNodeIndex, } impl

::std::fmt::Debug for CfgEdge

where P: PatternProvider, { fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { if let Some(kind) = self.kind { write!(f, "{:?} {:?}", kind, self.variable_binds) } else { write!(f, "") } } } #[derive(Debug, Clone, PartialEq, Eq)] pub enum CfgNodeKind { Root, Match(CVT), Fail, Leaf(usize), } ================================================ FILE: util/libeir_util_pattern_compiler/src/lib.rs ================================================ #![deny(warnings)] // Implements a variant of // http://www.cs.tufts.edu/~nr/cs257/archive/luc-maranget/jun08.pdf #[macro_use] extern crate derivative; pub use petgraph::visit::EdgeRef; mod pattern; pub use self::pattern::{ExpandedClauseNodes, PatternProvider}; mod cfg; pub use self::cfg::{CfgEdge, CfgNodeIndex, CfgNodeKind, PatternCfg}; mod matrix; pub mod simple_pattern; pub use ::petgraph::graph::NodeIndex; #[cfg(feature = "debug_table_print")] use log::trace; #[cfg(feature = "debug_table_print")] const TARGET: &'static str = "pattern_compiler"; #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] struct LeafId(usize); #[derive(Debug)] pub struct MatchCompileContext<'a, P> where P: pattern::PatternProvider + 'a, { pattern: &'a mut P, cfg: cfg::PatternCfg

, root_matrix: matrix::MatchMatrix

, fail_leaf: NodeIndex, } impl<'a, P> MatchCompileContext<'a, P> where P: PatternProvider, { pub fn new(pattern: &'a mut P) -> Self { let root = pattern.get_root(); let mut cfg = cfg::PatternCfg::new(); let fail_leaf = cfg.add_fail(); let leaves: Vec = (0..(root.clauses)).map(|idx| LeafId(idx)).collect(); let root_matrix = matrix::MatchMatrix::new(&root.nodes, leaves, root.variables); MatchCompileContext { pattern: pattern, cfg: cfg, root_matrix: root_matrix, fail_leaf: fail_leaf, } } fn root_matrix(&self) -> &matrix::MatchMatrix

{ &self.root_matrix } } fn matrix_to_decision_tree

( parent: cfg::CfgNodeIndex, ctx: &mut MatchCompileContext

, spec: Option, matrix: &matrix::MatchMatrix

, introduced_vars: Vec, level: usize, ) where P: PatternProvider, { #[cfg(feature = "debug_table_print")] { let mut buf = String::new(); for _ in 0..level { write!(buf, " =="); } write!(buf, " MATRIX AT LEVEL {}", level); trace!(target: TARGET, "{}", buf); } let edge = cfg::CfgEdge { kind: spec.clone(), variable_binds: introduced_vars, }; // Matrix is empty, no specializations can be done. if matrix.is_empty() { ctx.cfg.add_edge(parent, ctx.fail_leaf, edge); return; } // If the head of the matrix has only wildcards, none of the other rows // can happen. if let Some(node_id) = matrix.has_wildcard_head(&ctx.pattern) { let binds = matrix.binds_for(node_id).unwrap(); let node = ctx.cfg.add_leaf(parent, node_id.0, edge, binds.clone()); let new_mat = matrix.without_head(); matrix_to_decision_tree(node, ctx, None, &new_mat, vec![], level + 1); return; } // Select the variable we should specialize on. // This will be the column with the most consecutive non-wildcards // at the head. let specialize_variable = matrix.select_specialize_variable(&ctx.pattern); let specialize_variable_cfg_var = matrix.get_var(specialize_variable); // Add new CFG node for current let cfg_node = ctx.cfg.add_child( parent, edge, specialize_variable_cfg_var, matrix.binds_for_head().clone(), ); // Find what pattern types we have as children, so that we can // specialize and branch to them in the CFG let specialization_types = matrix.collect_specialization_types(&ctx.pattern, specialize_variable); // Specialize on specific matrices for specialization in specialization_types.iter() { let (introduced, specialized) = matrix.specialize(ctx, specialize_variable, *specialization); matrix_to_decision_tree( cfg_node, ctx, Some(*specialization), &specialized, introduced, level + 1, ); } // Specialize on default matrix let (introduced, default) = matrix.default(ctx, specialize_variable); let wildcard = ctx.pattern.get_wildcard(); matrix_to_decision_tree( cfg_node, ctx, Some(wildcard), &default, introduced, level + 1, ); } pub fn to_decision_tree

(pattern: &mut P) -> cfg::PatternCfg

where P: PatternProvider, { let mut context = MatchCompileContext::new(pattern); let root: matrix::MatchMatrix

= (*context.root_matrix()).clone(); let root_cfg = context.cfg.get_entry(); let wildcard = context.pattern.get_wildcard(); matrix_to_decision_tree( root_cfg, &mut context, Some(wildcard), &root, root.variables.clone(), 0, ); let cfg = context.cfg; assert!(!::petgraph::algo::is_cyclic_directed(&cfg.graph)); cfg } ================================================ FILE: util/libeir_util_pattern_compiler/src/matrix.rs ================================================ use std::collections::{HashMap, HashSet}; #[cfg(feature = "debug_table_print")] use prettytable::Table; #[cfg(feature = "debug_table_print")] use super::TARGET; #[cfg(feature = "debug_table_print")] use log::trace; use super::pattern::PatternProvider; use super::LeafId; #[derive(Debug, Derivative)] #[derivative(Clone(bound = ""))] pub(crate) struct MatchMatrix

where P: PatternProvider, { pub data: Vec>, pub variables: Vec, pub clause_leaves: Vec, pub leaf_bindings: Vec>, } #[derive(Debug, Derivative)] #[derivative(Clone(bound = ""))] pub struct MatchMatrixElement

where P: PatternProvider, { pub node: P::PatternNodeKey, pub variable_num: usize, pub clause_num: usize, } //fn chunks_len<'a, T>(entities: &'a [T], chunk_len: usize, num_chunks: usize) // -> impl Iterator + 'a { // // assert!(entities.len() == (chunk_len * num_chunks)); // let ret = if chunk_len == 0 { // Either::Left((0..num_chunks).map(|_| [].as_ref())) // } else { // Either::Right(entities.chunks(chunk_len)) // }; // ret //} impl

MatchMatrix

where P: PatternProvider, { pub fn new( nodes: &[P::PatternNodeKey], leaves: Vec, vars: Vec, ) -> Self { let binds = (0..leaves.len()).map(|_| HashMap::new()).collect(); MatchMatrix::with_bindings(nodes, leaves, vars, binds) } fn with_bindings( nodes: &[P::PatternNodeKey], leaves: Vec, vars: Vec, mut leaf_bindings: Vec>, ) -> Self { assert!(vars.len() * leaves.len() == nodes.len()); assert!(leaf_bindings.len() == leaves.len()); let data = if vars.len() == 0 { vec![] } else { nodes .chunks(vars.len()) .enumerate() .flat_map(|(clause_idx, clause)| { clause .iter() .enumerate() .map(move |(variable_idx, pat)| MatchMatrixElement { variable_num: variable_idx, clause_num: clause_idx, node: *pat, }) }) .collect() }; // Insert all bindings if nodes.len() > 0 { for (idx, chunk) in data.chunks(vars.len()).enumerate() { for (elem, var) in chunk.iter().zip(vars.iter()) { leaf_bindings[idx].insert(elem.node, *var); } } } MatchMatrix { data: data, variables: vars, clause_leaves: leaves, leaf_bindings: leaf_bindings, } } /// Selects which variable should be specialized on in this matrix. /// This will always select the variable which has the most consecutive /// wildcards from the top, as this will minimize the amount of /// comparisons we will have to perform. pub fn select_specialize_variable(&self, pattern: &P) -> usize { let mut sums = vec![(0, true); self.variables.len()]; let clauses = self.data.chunks(self.variables.len()); for clause in clauses { for variable_pattern in clause.iter() { if pattern.is_wildcard(pattern.get_kind(variable_pattern.node)) { sums[variable_pattern.variable_num].1 = false; } else { if sums[variable_pattern.variable_num].1 { sums[variable_pattern.variable_num].0 += 1; } } } } sums.iter() .enumerate() .max_by_key(|&(_, s)| s.0) .map(|(i, _)| i) .unwrap() } pub fn get_var(&self, var: usize) -> P::CfgVariable { self.variables[var] } /// Constructs a set of all node kinds in the given variable in the given pattern pub fn collect_specialization_types<'a>( &self, pattern: &'a P, variable: usize, ) -> HashSet { let mut types = HashSet::new(); let clauses = self.data.chunks(self.variables.len()); for clause in clauses { let variable_pattern = &clause[variable]; types.insert(pattern.get_kind(variable_pattern.node)); } types.remove(&pattern.get_wildcard()); types } pub fn specialize( &self, ctx: &mut super::MatchCompileContext

, variable: usize, on: P::PatternNodeKind, ) -> (Vec, MatchMatrix

) { #[cfg(feature = "debug_table_print")] { trace!( target: TARGET, "Specialize variable #{} on {:?}", variable, on ); trace!(target: TARGET, "{}", self.to_table(&ctx.pattern)); trace!(target: TARGET, "binds: {:#?}", self.leaf_bindings); } // 1. Determine how we want to handle the different clauses #[derive(Debug, Copy, Clone, PartialEq, Eq)] enum ClauseMode { /// The clause is included in the kind we specialize on Expand, /// The clause is a wildcard, expand into wildcards Wildcard, /// Clause is not included Skip, } let clause_modes: Vec = self .data .chunks(self.variables.len()) .map(|nodes| { let n = nodes[variable].node; if ctx.pattern.kind_includes(on, n) { ClauseMode::Expand } else if ctx.pattern.is_wildcard(ctx.pattern.get_kind(n)) { ClauseMode::Wildcard } else { ClauseMode::Skip } }) .collect(); // 2. Expand nodes let expanded = { let nodes: Vec<_> = clause_modes .iter() .cloned() .zip(self.data.chunks(self.variables.len())) .filter(|(mode, _)| *mode == ClauseMode::Expand) .map(|(_, nodes)| nodes[variable].node) .collect(); let nodes_len = nodes.len(); let res = ctx.pattern.expand_clause_nodes(nodes, on); assert!(res.clauses == nodes_len); assert!(res.nodes.len() == res.clauses * res.variables.len()); res }; let expanded_var_num = expanded.variables.len(); // 3. Merge expanded with wildcard expansions and residuals let merged = { let mut out = Vec::new(); // Because .chunks does not accept 0 as a chunk length, // we do this workaround let mut expanded_iter = if expanded.nodes.len() > 0 { Some(expanded.nodes.chunks(expanded_var_num)) } else { None }; let mut residual_iter = clause_modes .iter() .cloned() .zip(self.data.chunks(self.variables.len())) .filter(|(mode, _)| *mode != ClauseMode::Skip) .map(|(_, elems)| { elems .iter() .filter(|elem| elem.variable_num != variable) .map(|elem| elem.node) }); for mode in clause_modes.iter() { // Append expanded match mode { ClauseMode::Expand => { if let Some(ref mut inner) = expanded_iter { let expanded_nodes = inner.next().unwrap(); out.extend(expanded_nodes.iter().cloned()); } else { assert!(expanded.nodes.len() == 0); } } ClauseMode::Wildcard => { for _ in 0..expanded_var_num { out.push(ctx.pattern.get_wildcard_node()); } } ClauseMode::Skip => continue, } // Append residual let residuals = residual_iter.next().unwrap(); out.extend(residuals); } if let Some(ref mut inner) = expanded_iter { assert!(inner.next().is_none()); } assert!(residual_iter.next().is_none()); out }; let new_variables: Vec<_> = { let rest_variables = self .variables .iter() .enumerate() .filter(|&(var_num, _)| var_num != variable) .map(|(_, var)| *var); expanded .variables .iter() .map(|var| *var) .chain(rest_variables) .collect() }; let new_clause_leaves: Vec<_> = clause_modes .iter() .cloned() .zip(self.clause_leaves.iter()) .filter(|(mode, _)| *mode != ClauseMode::Skip) .map(|(_, clause)| *clause) .collect(); let new_leaf_bindings: Vec<_> = clause_modes .iter() .zip(self.leaf_bindings.iter()) .filter(|(mode, _)| **mode != ClauseMode::Skip) .map(|(_, binds)| binds.clone()) .collect(); let matrix = Self::with_bindings(&merged, new_clause_leaves, new_variables, new_leaf_bindings); (expanded.variables, matrix) } pub fn without_head<'a>(&'a self) -> MatchMatrix

{ // TODO move to actual new instead of this // This just removes the top row of the table. // Since data is unrolled, remove the n first entries // where n is the number of variables // Then remove first clause leaf let mut new = self.clone(); for _ in 0..(new.variables.len()) { new.data.remove(0); } new.clause_leaves.remove(0); for entry in new.data.iter_mut() { entry.clause_num -= 1; } new.leaf_bindings.remove(0); new } pub(crate) fn binds_for<'a>( &'a self, leaf: LeafId, ) -> Option<&'a HashMap> { self.clause_leaves .iter() .enumerate() .find(|(_, l)| **l == leaf) .map(|(idx, _)| &self.leaf_bindings[idx]) } pub(crate) fn binds_for_head<'a>(&'a self) -> &'a HashMap { &self.leaf_bindings[0] } //pub(crate) fn iterate_clauses<'a>(&'a self) -> impl Iterator])> + 'a { // let iter = self.clause_leaves.iter().map(|l| *l) // .zip(chunks_len(&self.data, self.variables.len(), self.clause_leaves.len())); // Box::new(iter) //} pub fn default( &self, ctx: &mut super::MatchCompileContext

, variable: usize, ) -> (Vec, MatchMatrix

) { let wildcard = ctx.pattern.get_wildcard(); self.specialize(ctx, variable, wildcard) } pub fn is_empty(&self) -> bool { self.clause_leaves.len() == 0 } pub(crate) fn has_wildcard_head(&self, pattern: &P) -> Option { assert!(self.clause_leaves.len() > 0); if self.variables.len() == 0 { Some(self.clause_leaves[0]) } else { let has_wildcard_head = self .data .chunks(self.variables.len()) .next() .unwrap() .iter() .all(|p| pattern.is_wildcard(pattern.get_kind(p.node))); if has_wildcard_head { Some(self.clause_leaves[0]) } else { None } } } #[cfg(feature = "debug_table_print")] pub fn to_table(&self, pat: &P) -> Table { use ::prettytable::Cell; let mut table = Table::new(); { let head_row = table.add_empty_row(); head_row.add_cell(Cell::new(&format!( "{}*{}=={}", self.variables.len(), self.clause_leaves.len(), self.data.len() ))); for variable in self.variables.iter() { let var_str = format!("{:?}", variable); head_row.add_cell(Cell::new(&var_str)); } } for row_idx in 0..self.clause_leaves.len() { let t_row = table.add_empty_row(); let leaf_id = format!("{:?}", self.clause_leaves[row_idx]); t_row.add_cell(Cell::new(&leaf_id)); let row_start = row_idx * self.variables.len(); for col in &self.data[row_start..(row_start + self.variables.len())] { let node = pat.get_kind(col.node); let cell_fmt = format!("{:?}", node); let cell = Cell::new(&cell_fmt); t_row.add_cell(cell); } } table } } ================================================ FILE: util/libeir_util_pattern_compiler/src/pattern.rs ================================================ use std::fmt::Debug; use std::hash::Hash; /// Length of `nodes` should ALWAYS be `variables.len() * clauses` #[derive(Debug)] pub struct ExpandedClauseNodes { pub variables: Vec, pub clauses: usize, pub nodes: Vec, } pub trait PatternProvider: Debug { /// A reference to a unique node in the pattern graph. /// Every `PatternNodeKey` should belong to ONE and ONLY one /// `PatternNodeKind`. type PatternNodeKey: Copy + Hash + Debug + PartialEq + Eq; /// The type of pattern node. type PatternNodeKind: Copy + Hash + Debug + PartialEq + Eq; /// A variable in the output CFG. /// The provider is responsible for creating these as specializations /// are performed by `expand_clause_nodes`. type CfgVariable: Copy + Hash + Debug + PartialEq + Eq; const WILDCARD: Self::PatternNodeKind; fn get_root(&self) -> ExpandedClauseNodes; /// Used to determine if the given `key` should be included in the /// specialization on `kind`. /// /// When passed a wildcard as kind, we are specializing on the default /// matrix. It should match wildcards ONLY. /// /// ## Invariants /// * Every `PatternNodeKey` should match on one and ONLY one /// `PatternNodeKind`. fn kind_includes(&self, kind: Self::PatternNodeKind, key: Self::PatternNodeKey) -> bool; /// After clauses have been selected for specialization, this will /// be called with the set of all nodes that should be specialized on. /// fn expand_clause_nodes( &mut self, clause_nodes: Vec, kind: Self::PatternNodeKind, ) -> ExpandedClauseNodes; fn get_wildcard_node(&self) -> Self::PatternNodeKey; /// Every `PatternNodeKey` should belong to one and only one /// `PatternNodeKind`. fn get_kind(&self, key: Self::PatternNodeKey) -> Self::PatternNodeKind; fn is_wildcard(&self, kind: Self::PatternNodeKind) -> bool { kind == Self::WILDCARD } fn get_wildcard(&self) -> Self::PatternNodeKind { Self::WILDCARD } } ================================================ FILE: util/libeir_util_pattern_compiler/src/simple_pattern/mod.rs ================================================ #[cfg(test)] mod test; use crate::{ExpandedClauseNodes, PatternProvider}; use petgraph::graph::NodeIndex; use petgraph::{Direction, Graph}; #[derive(Copy, Clone, Hash, PartialEq, Eq)] pub struct CfgVar(usize); use ::std::fmt; impl fmt::Debug for CfgVar { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { write!(fmt, "${}", self.0) } } #[derive(Copy, Clone, Hash, Debug, PartialEq, Eq)] pub enum NodeKind { Tuple, ListCell, Terminal, RootValues, Wildcard, } #[derive(Debug, Clone)] pub struct SimplePatternProvider { pattern: Graph, roots: Vec, root_var: CfgVar, curr_var: CfgVar, wildcard: NodeIndex, } impl SimplePatternProvider { pub fn new() -> Self { let mut graph = Graph::new(); let wildcard = graph.add_node(NodeKind::Wildcard); SimplePatternProvider { pattern: graph, roots: Vec::new(), root_var: CfgVar(0), curr_var: CfgVar(0), wildcard, } } pub fn add_child(&mut self, node: NodeIndex, kind: NodeKind) -> NodeIndex { let res = self.pattern.add_node(kind); self.pattern.add_edge(node, res, ()); res } pub fn add_clause(&mut self, kind: NodeKind) -> NodeIndex { let res = self.pattern.add_node(kind); self.roots.push(res); res } } impl PatternProvider for SimplePatternProvider { type PatternNodeKey = NodeIndex; type PatternNodeKind = NodeKind; type CfgVariable = CfgVar; const WILDCARD: NodeKind = NodeKind::Wildcard; fn get_root(&self) -> ExpandedClauseNodes { ExpandedClauseNodes { variables: vec![self.root_var], clauses: self.roots.len(), nodes: self.roots.clone(), } } fn kind_includes(&self, kind: Self::PatternNodeKind, key: Self::PatternNodeKey) -> bool { self.pattern[key] == kind } fn expand_clause_nodes( &mut self, clause_nodes: Vec, kind: Self::PatternNodeKind, ) -> ExpandedClauseNodes { if clause_nodes.len() == 0 { return ExpandedClauseNodes { clauses: 0, variables: vec![], nodes: vec![], }; } let base_len = self .pattern .edges_directed(clause_nodes[0], Direction::Outgoing) .count(); for node in &clause_nodes { assert!( self.pattern .edges_directed(clause_nodes[0], Direction::Outgoing) .count() == base_len ); assert!(self.pattern[*node] == kind); } let mut curr_var = self.curr_var; let mut exp = ExpandedClauseNodes { clauses: clause_nodes.len(), variables: self .pattern .edges_directed(clause_nodes[0], Direction::Outgoing) .map(|_| { curr_var.0 += 1; curr_var }) .collect(), nodes: vec![], }; self.curr_var = curr_var; match kind { NodeKind::RootValues => { for node in &clause_nodes { for child in self.pattern.edges_directed(*node, Direction::Outgoing) { use ::petgraph::visit::EdgeRef; exp.nodes.push(child.target()); } } } NodeKind::ListCell => { for node in &clause_nodes { for child in self.pattern.edges_directed(*node, Direction::Outgoing) { use ::petgraph::visit::EdgeRef; exp.nodes.push(child.target()); } } } NodeKind::Wildcard => {} NodeKind::Terminal => {} typ => unimplemented!("{:?}", typ), } println!("{:?}", exp); exp } fn get_kind(&self, key: Self::PatternNodeKey) -> Self::PatternNodeKind { self.pattern[key] } fn get_wildcard_node(&self) -> Self::PatternNodeKey { self.wildcard } } ================================================ FILE: util/libeir_util_pattern_compiler/src/simple_pattern/test.rs ================================================ use super::{NodeKind, SimplePatternProvider}; #[test] fn list_merge_pattern() { // fn ([], _) // fn (_, []) // fn ([_, _], [_, _]) let mut pattern = SimplePatternProvider::new(); { let clause = pattern.add_clause(NodeKind::RootValues); pattern.add_child(clause, NodeKind::Wildcard); pattern.add_child(clause, NodeKind::Wildcard); } { let clause = pattern.add_clause(NodeKind::RootValues); pattern.add_child(clause, NodeKind::Terminal); pattern.add_child(clause, NodeKind::Wildcard); } { let clause = pattern.add_clause(NodeKind::RootValues); pattern.add_child(clause, NodeKind::Terminal); pattern.add_child(clause, NodeKind::Wildcard); } { let clause = pattern.add_clause(NodeKind::RootValues); pattern.add_child(clause, NodeKind::Wildcard); pattern.add_child(clause, NodeKind::Terminal); } { let clause = pattern.add_clause(NodeKind::RootValues); let list_cell_1 = pattern.add_child(clause, NodeKind::ListCell); pattern.add_child(list_cell_1, NodeKind::Wildcard); pattern.add_child(list_cell_1, NodeKind::Wildcard); let list_cell_2 = pattern.add_child(clause, NodeKind::ListCell); pattern.add_child(list_cell_2, NodeKind::Wildcard); pattern.add_child(list_cell_2, NodeKind::Wildcard); } let res = crate::to_decision_tree(&mut pattern); let mut file = ::std::fs::File::create("cfg.dot").unwrap(); res.to_dot(&mut file).unwrap(); println!("{:?}", res); //println!("{:#?}", res.leaf_bindings); } ================================================ FILE: util/libeir_util_prof/Cargo.toml ================================================ [package] name = "libeir_util_prof" version = "0.1.0" authors = ["Hans Elias B. Josephsen "] edition = "2018" license = "MIT OR Apache-2.0" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] bumpalo = { git = "https://github.com/hansihe/bumpalo", features = ["nightly"] } ================================================ FILE: util/libeir_util_prof/src/lib.rs ================================================ use std::time::Instant; use std::thread::ThreadId; pub struct Event { instant: Instant, thread: ThreadId, kind: EventKind, } pub enum EventKind { Begin { }, End { }, } pub struct Tracer { start: Instant, events: Vec, } ================================================ FILE: util/meta_table/Cargo.toml ================================================ [package] name = "meta_table" version = "0.1.0" authors = ["Hans Elias B. Josephsen "] edition = "2018" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] hashbrown = { git = "https://github.com/rust-lang/hashbrown.git", features = ["raw", "nightly"] } ================================================ FILE: util/meta_table/src/lib.rs ================================================ use std::{any::TypeId, marker::PhantomData}; use hashbrown::HashMap; /// This implements `Send` and `Sync` unconditionally. /// (the trait itself doesn't need to have these bounds and the /// resources are already guaranteed to fulfill it). struct Invariant(*mut T); unsafe impl Send for Invariant where T: ?Sized {} unsafe impl Sync for Invariant where T: ?Sized {} pub trait MetaEntry: 'static { fn get_type_id(&self) -> TypeId; } #[macro_export] macro_rules! impl_meta_entry { ($typ:ty) => { impl $crate::MetaEntry for $typ { fn get_type_id(&self) -> std::any::TypeId { std::any::TypeId::of::<$typ>() } } }; } /// Helper trait for the `MetaTable`. /// This trait is required to be implemented for a trait to be compatible with /// the meta table. /// /// # Memory safety /// /// Not casting `self` but e.g. a field to the trait object can result in severe /// memory safety issues. /// /// # Examples /// /// ``` /// use meta_table::{CastFrom, impl_cast_from}; /// /// trait Foo { /// fn foo1(&self); /// fn foo2(&mut self, x: i32) -> i32; /// } /// /// impl_cast_from!(Foo); /// ``` pub unsafe trait CastFrom { /// Casts an immutable `T` reference to a trait object. fn cast(t: &T) -> &Self; /// Casts a mutable `T` reference to a trait object. fn cast_mut(t: &mut T) -> &mut Self; fn vtable() -> Fat; } #[macro_export] macro_rules! impl_cast_from { ($typ:tt) => { unsafe impl $crate::CastFrom for dyn $typ where T: $typ + 'static, { fn cast(t: &T) -> &(dyn $typ + 'static) { t } fn cast_mut(t: &mut T) -> &mut (dyn $typ + 'static) { t } fn vtable() -> $crate::Fat { let from: *const T = std::ptr::null(); let object_ptr: *const Self = from; unsafe { $crate::Fat::from_ptr(object_ptr) } } } }; } pub struct Fat(usize); impl Fat { pub unsafe fn from_ptr(t: *const T) -> Self { use std::ptr::read; assert_unsized::(); let fat_ptr = &t as *const *const T as *const usize; // Memory layout: // [object pointer, vtable pointer] // ^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^ // 8 bytes | 8 bytes // (on 32-bit both have 4 bytes) let vtable = read::(fat_ptr.offset(1)); Fat(vtable) } pub unsafe fn create_ptr(&self, ptr: *const ()) -> *const T { let fat_ptr: (*const (), usize) = (ptr, self.0); *(&fat_ptr as *const (*const (), usize) as *const *const T) } pub unsafe fn create_mut_ptr(&self, ptr: *mut ()) -> *mut T { let fat_ptr: (*mut (), usize) = (ptr, self.0); *(&fat_ptr as *const (*mut (), usize) as *const *mut T) } } /// The `MetaTable` which allows to store object-safe trait implementations for /// resources. /// /// For example, you have a trait `Foo` that is implemented by several /// resources. You can register all the implementors using /// `MetaTable::register`. Later on, you can iterate over all resources that /// implement `Foo` without knowing their specific type. /// /// # Examples /// /// ``` /// use meta_table::{MetaTable, impl_cast_from, impl_meta_entry}; /// /// trait Object { /// fn method1(&self) -> i32; /// /// fn method2(&mut self, x: i32); /// } /// impl_cast_from!(Object); /// /// struct ImplementorA(i32); /// impl_meta_entry!(ImplementorA); /// /// impl Object for ImplementorA { /// fn method1(&self) -> i32 { /// self.0 /// } /// /// fn method2(&mut self, x: i32) { /// self.0 += x; /// } /// } /// /// struct ImplementorB(i32); /// impl_meta_entry!(ImplementorB); /// /// impl Object for ImplementorB { /// fn method1(&self) -> i32 { /// self.0 /// } /// /// fn method2(&mut self, x: i32) { /// self.0 *= x; /// } /// } /// /// let mut table = MetaTable::::new(); /// table.register::(); /// table.register::(); /// /// assert!(table.get(&ImplementorA(12)).unwrap().method1() == 12); /// assert!(table.get(&ImplementorB(13)).unwrap().method1() == 13); /// ``` pub struct MetaTable { fat: Vec, indices: HashMap, tys: Vec, // `MetaTable` is invariant over `T` marker: PhantomData>, } impl MetaTable { /// Creates a new `MetaTable`. pub fn new() -> Self { assert_unsized::(); Default::default() } /// Registers a resource `R` that implements the trait `T`. pub fn register(&mut self) where R: MetaEntry, T: CastFrom + 'static, { use hashbrown::hash_map::Entry; let fat = T::vtable(); let ty_id = std::any::TypeId::of::(); // Important: ensure no entry exists twice! let len = self.indices.len(); match self.indices.entry(ty_id) { Entry::Occupied(occ) => { let ind = *occ.get(); self.fat[ind] = fat; } Entry::Vacant(vac) => { vac.insert(len); self.fat.push(fat); self.tys.push(ty_id); } } } /// Tries to convert `world` to a trait object of type `&T`. /// If `world` doesn't have an implementation for `T` (or it wasn't /// registered), this will return `None`. pub fn get<'a>(&self, res: &'a dyn MetaEntry) -> Option<&'a T> { unsafe { self.indices .get(&res.get_type_id()) .map(move |&ind| &*self.fat[ind].create_ptr(res as *const _ as *const ())) } } /// Tries to convert `world` to a trait object of type `&mut T`. /// If `world` doesn't have an implementation for `T` (or it wasn't /// registered), this will return `None`. pub fn get_mut<'a>(&self, res: &'a mut dyn MetaEntry) -> Option<&'a mut T> { unsafe { self.indices .get(&res.get_type_id()) .map(move |&ind| &mut *self.fat[ind].create_mut_ptr(res as *mut _ as *mut ())) } } } impl Default for MetaTable where T: ?Sized, { fn default() -> Self { MetaTable { fat: Default::default(), indices: Default::default(), tys: Default::default(), marker: Default::default(), } } } pub fn assert_unsized() { use std::mem::size_of; assert_eq!(size_of::<&T>(), 2 * size_of::()); } #[cfg(test)] mod tests { use super::*; trait Object: MetaEntry { fn method1(&self) -> i32; fn method2(&mut self, x: i32); } impl_cast_from!(Object); struct ImplementorA(i32); impl_meta_entry!(ImplementorA); impl Object for ImplementorA { fn method1(&self) -> i32 { self.0 } fn method2(&mut self, x: i32) { self.0 += x; } } struct ImplementorB(i32); impl_meta_entry!(ImplementorB); impl Object for ImplementorB { fn method1(&self) -> i32 { self.0 } fn method2(&mut self, x: i32) { self.0 *= x; } } //#[test] //fn test_iter_all() { // let mut world = World::empty(); // world.insert(ImplementorA(3)); // world.insert(ImplementorB(1)); // let mut table = MetaTable::::new(); // table.register(&ImplementorA(125)); // table.register(&ImplementorB(111_111)); // { // let mut iter = table.iter(&world); // assert_eq!(iter.next().unwrap().method1(), 3); // assert_eq!(iter.next().unwrap().method1(), 1); // } // { // let mut iter_mut = table.iter_mut(&world); // let obj = iter_mut.next().unwrap(); // obj.method2(3); // assert_eq!(obj.method1(), 6); // let obj = iter_mut.next().unwrap(); // obj.method2(4); // assert_eq!(obj.method1(), 4); // } //} //#[test] //fn test_iter_all_after_removal() { // let mut world = World::empty(); // world.insert(ImplementorA(3)); // world.insert(ImplementorB(1)); // let mut table = MetaTable::::new(); // table.register(&ImplementorA(125)); // table.register(&ImplementorB(111_111)); // { // let mut iter = table.iter(&world); // assert_eq!(iter.next().unwrap().method1(), 3); // assert_eq!(iter.next().unwrap().method1(), 1); // } // world.remove::().unwrap(); // { // let mut iter = table.iter(&world); // assert_eq!(iter.next().unwrap().method1(), 1); // } // world.remove::().unwrap(); //} struct ImplementorC; impl_meta_entry!(ImplementorC); impl Object for ImplementorC { fn method1(&self) -> i32 { 33 } fn method2(&mut self, _x: i32) { unimplemented!() } } struct ImplementorD; impl_meta_entry!(ImplementorD); impl Object for ImplementorD { fn method1(&self) -> i32 { 42 } fn method2(&mut self, _x: i32) { unimplemented!() } } #[test] fn get() { let mut table = MetaTable::::new(); table.register::(); table.register::(); let t1 = ImplementorC; let t1d: &dyn MetaEntry = &t1; let t2 = ImplementorD; let t2d: &dyn MetaEntry = &t2; assert_eq!(table.get(t1d).unwrap().method1(), 33); assert_eq!(table.get(t2d).unwrap().method1(), 42); } } ================================================ FILE: util/scoped_cell/Cargo.toml ================================================ [package] name = "scoped_cell" version = "0.1.0" authors = ["Hans Elias B. Josephsen "] edition = "2018" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] ================================================ FILE: util/scoped_cell/src/lib.rs ================================================ use std::alloc::{alloc, dealloc, Layout}; use std::marker::PhantomData; use std::ptr::NonNull; #[derive(Debug, Copy, Clone, PartialEq, Eq)] pub struct BorrowMutError; struct ScopedCellGuard<'a, T: ?Sized>(&'a ScopedCell); impl<'a, T: ?Sized> Drop for ScopedCellGuard<'a, T> { fn drop(&mut self) { unsafe { let inner = self.0.inner_mut(); debug_assert!(inner.active); inner.active = false; } } } pub struct ScopedCell { ptr: NonNull>, //phantom: PhantomData>, } impl ScopedCell { pub fn borrow_mut(&self, fun: F) -> R where F: FnOnce(&mut T) -> R, { unsafe { let inner_ptr; { let inner = self.inner_mut(); if inner.active { panic!("ScopedCell already borrowed"); } if inner.inner.is_none() { panic!("Tried to borrow ScopedCell outside of creating scope"); } inner.active = true; inner_ptr = inner.inner.unwrap(); } // This guard will take care of setting active to false when we // leave the inner scope. let _guard = ScopedCellGuard(self); fun(&mut *inner_ptr.as_ptr()) } } pub fn try_borrow_mut(&self, fun: F) -> Result where F: FnOnce(&mut T) -> R, { unsafe { let inner_ptr; { let inner = self.inner_mut(); if inner.active { return Err(BorrowMutError); } if inner.inner.is_none() { return Err(BorrowMutError); } inner.active = true; inner_ptr = inner.inner.unwrap(); } // This guard will take care of setting active to false when we // leave the inner scope. let _guard = ScopedCellGuard(self); Ok(fun(&mut *inner_ptr.as_ptr())) } } /// # Safety /// This may only be called by internal functions. /// A reference to this may only be held while control flow is controlled by the scoped cell. /// Only one reference to inner may be obtained at the time. unsafe fn inner_mut(&self) -> &mut ScopedCellInner { &mut *(self.ptr.as_ptr() as *mut _) } } impl Clone for ScopedCell { fn clone(&self) -> Self { unsafe { let inner = self.inner_mut(); inner.references += 1; } ScopedCell { ptr: self.ptr, //phantom: PhantomData, } } } impl Drop for ScopedCell { fn drop(&mut self) { unsafe { let is_zero; let active; { let inner = self.inner_mut(); inner.references -= 1; is_zero = inner.references == 0; active = inner.active; } if is_zero { debug_assert!(!active); dealloc( self.ptr.as_ptr().cast(), Layout::for_value(self.ptr.as_ref()), ) } } } } pub struct ScopedCellInner { /// Number of `ScopedCell`s that exist at any given time. /// This is incremented on creation/cloning of a new `ScopedCell`, and /// decremented in the drop implementation. /// When this reaches 0, this struct is deallocated. references: usize, /// When this is true, a `&mut T` exists active: bool, /// Pointer to the thing this ScopedCell references. /// If this is `Some`, the creator guard of this scoped cell is still in /// scope. /// If this is `None`, the creator guard has been dropped and any future /// borrow attempts will fail. inner: Option>, } /// The guard must not be dropped while a borrow of a related cell is in /// progress. If this happens, the whole process will be aborted. pub fn new<'a, T: ?Sized + 'a>(value: &'a mut T) -> ScopedCellCreatorGuard<'a, T> { // Because we are using the value reference in a `PhantomData`, the // reference will be concidered used, while not actually existing in a // usable form until this guard stuct is dropped. // // This should make things sound when we create a mutable reference from // the pointer we have stored in `ScopedCellInner`, because that can only // be done while the actual value reference is tied up in the PhantomData // of this guard. unsafe { let inner_layout = Layout::new::>(); let inner_ptr_u8 = alloc(inner_layout); let inner_ptr = NonNull::new(inner_ptr_u8 as *mut _).unwrap(); std::ptr::write( inner_ptr.as_ptr(), ScopedCellInner { references: 1, active: false, inner: Some(NonNull::new(value as *mut _).unwrap()), }, ); let cell = ScopedCell { ptr: inner_ptr, //phantom: PhantomData, }; ScopedCellCreatorGuard { cell, life: PhantomData, } } } pub struct ScopedCellCreatorGuard<'a, T: ?Sized> { cell: ScopedCell, life: PhantomData<&'a mut T>, } impl<'a, T: ?Sized> Drop for ScopedCellCreatorGuard<'a, T> { fn drop(&mut self) { unsafe { let inner = self.cell.inner_mut(); if inner.active { println!( "FATAL: ScopedCell borrow active while ScopedCellCreatorGuard was dropped" ); std::process::abort(); } inner.inner = None; } } } impl<'a, T: ?Sized> ScopedCellCreatorGuard<'a, T> { pub fn clone_cell(&self) -> ScopedCell { self.cell.clone() } } pub fn scoped_cell(value: &mut T, fun: F) -> R where F: FnOnce(ScopedCell) -> R, { let guard = new(value); let cell = guard.clone_cell(); fun(cell) } #[cfg(test)] mod tests { use super::{new, scoped_cell}; #[test] fn creation() { let mut a: u32 = 0; scoped_cell(&mut a, |_ac| {}); } #[test] fn basic_usage() { let mut a: u32 = 0; fn inner(a: &mut u32) { scoped_cell(a, |ac| { let ac2 = ac.clone(); ac.borrow_mut(|v| { *v += 1; }); ac2.borrow_mut(|v| { *v += 1; }); }); } inner(&mut a); assert!(a == 2); } //#[test] //fn miri_fail() { // use std::marker::PhantomData; // struct Guard<'a>(PhantomData<&'a u8>); // fn new<'a>(_val: &'a mut u8) -> Guard<'a> { // Guard(PhantomData) // } // let mut a = 0u8; // let a_ptr = &mut a as *mut _; // // Should be sound: // { // let guard = new(&mut a); // // Compiler is aware that `a` is borrowed mutably at this point, but // // no actual reference exists. Therefore there will only be one active // // mutable reference when we create one from the pointer. // let inner_ref = unsafe { &mut *a_ptr }; // *inner_ref += 1u8; // std::mem::drop(inner_ref); // std::mem::drop(guard); // } //} #[test] fn raw_usage() { let mut a: u32 = 0; let aco; { let sc = new(&mut a); let ac1 = sc.clone_cell(); let ac2 = sc.clone_cell(); aco = ac2.clone(); ac1.borrow_mut(|_i| { assert!(ac2.try_borrow_mut(|_i| ()).is_err()); }); } assert!(aco.try_borrow_mut(|_i| ()).is_err()); } #[test] fn double_borrow_fails() { let mut a: u32 = 0; scoped_cell(&mut a, |ac| { let ac2 = ac.clone(); ac.borrow_mut(|_i| { assert!(ac2.try_borrow_mut(|_i| ()).is_err()); }); }); } }